diff options
Diffstat (limited to 'src/lib/tls')
-rw-r--r-- | src/lib/tls/tls_ciphersuite.cpp | 41 | ||||
-rw-r--r-- | src/lib/tls/tls_ciphersuite.h | 11 | ||||
-rw-r--r-- | src/lib/tls/tls_policy.cpp | 1 | ||||
-rw-r--r-- | src/lib/tls/tls_record.cpp | 142 | ||||
-rw-r--r-- | src/lib/tls/tls_record.h | 9 | ||||
-rw-r--r-- | src/lib/tls/tls_session_key.cpp | 2 | ||||
-rw-r--r-- | src/lib/tls/tls_suite_info.cpp | 11 |
7 files changed, 122 insertions, 95 deletions
diff --git a/src/lib/tls/tls_ciphersuite.cpp b/src/lib/tls/tls_ciphersuite.cpp index e6a69126c..2ed5d24e6 100644 --- a/src/lib/tls/tls_ciphersuite.cpp +++ b/src/lib/tls/tls_ciphersuite.cpp @@ -66,8 +66,8 @@ Ciphersuite::Ciphersuite(u16bit ciphersuite_code, const char* kex_algo, const char* cipher_algo, size_t cipher_keylen, - size_t exp_nonce_bytes, - size_t imp_nonce_bytes, + size_t nonce_bytes_from_handshake, + size_t nonce_bytes_from_record, const char* mac_algo, size_t mac_keylen, const char* prf_algo) : @@ -77,8 +77,8 @@ Ciphersuite::Ciphersuite(u16bit ciphersuite_code, m_prf_algo(prf_algo), m_cipher_algo(cipher_algo), m_cipher_keylen(cipher_keylen), - m_explicit_nonce_bytes(exp_nonce_bytes), - m_implicit_nonce_bytes(imp_nonce_bytes), + m_nonce_bytes_from_handshake(nonce_bytes_from_handshake), + m_nonce_bytes_from_record(nonce_bytes_from_record), m_mac_algo(mac_algo), m_mac_keylen(mac_keylen) { @@ -108,27 +108,36 @@ bool Ciphersuite::valid() const if(mac_algo() == "AEAD") { - auto cipher_and_mode = split_on(cipher_algo(), '/'); - BOTAN_ASSERT(cipher_and_mode.size() == 2, "Expected format for AEAD algo"); - if(!af.prototype_block_cipher(cipher_and_mode[0])) + if(cipher_algo() == "ChaCha20Poly1305") + { +#if !defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305) return false; +#endif + } + else + { + auto cipher_and_mode = split_on(cipher_algo(), '/'); + BOTAN_ASSERT(cipher_and_mode.size() == 2, "Expected format for AEAD algo"); + if(!af.prototype_block_cipher(cipher_and_mode[0])) + return false; - const auto mode = cipher_and_mode[1]; + const auto mode = cipher_and_mode[1]; #if !defined(BOTAN_HAS_AEAD_CCM) - if(mode == "CCM" || mode == "CCM-8") - return false; + if(mode == "CCM" || mode == "CCM-8") + return false; #endif #if !defined(BOTAN_HAS_AEAD_GCM) - if(mode == "GCM") - return false; + if(mode == "GCM") + return false; #endif #if !defined(BOTAN_HAS_AEAD_OCB) - if(mode == "OCB") - return false; + if(mode == "OCB") + return false; #endif + } } else { @@ -213,6 +222,10 @@ std::string Ciphersuite::to_string() const { out << "RC4_128_"; } + else if(cipher_algo() == "ChaCha20Poly1305") + { + out << "CHACHA20_POLY1305_"; + } else { if(cipher_algo() == "3DES") diff --git a/src/lib/tls/tls_ciphersuite.h b/src/lib/tls/tls_ciphersuite.h index e92eafd5f..bff5b0d9d 100644 --- a/src/lib/tls/tls_ciphersuite.h +++ b/src/lib/tls/tls_ciphersuite.h @@ -99,9 +99,9 @@ class BOTAN_DLL Ciphersuite */ size_t cipher_keylen() const { return m_cipher_keylen; } - size_t explicit_nonce_bytes() const { return m_explicit_nonce_bytes; } + size_t nonce_bytes_from_record() const { return m_nonce_bytes_from_record; } - size_t implicit_nonce_bytes() const { return m_implicit_nonce_bytes; } + size_t nonce_bytes_from_handshake() const { return m_nonce_bytes_from_handshake; } size_t mac_keylen() const { return m_mac_keylen; } @@ -119,8 +119,8 @@ class BOTAN_DLL Ciphersuite const char* kex_algo, const char* cipher_algo, size_t cipher_keylen, - size_t explicit_nonce_bytes, - size_t implicit_nonce_bytes, + size_t nonce_bytes_from_handshake, + size_t nonce_bytes_from_record, const char* mac_algo, size_t mac_keylen, const char* prf_algo = ""); @@ -133,7 +133,8 @@ class BOTAN_DLL Ciphersuite std::string m_cipher_algo; size_t m_cipher_keylen = 0; - size_t m_explicit_nonce_bytes = 0, m_implicit_nonce_bytes = 0; + size_t m_nonce_bytes_from_handshake = 0; + size_t m_nonce_bytes_from_record = 0; std::string m_mac_algo; size_t m_mac_keylen = 0; diff --git a/src/lib/tls/tls_policy.cpp b/src/lib/tls/tls_policy.cpp index 0f2190562..d0e227d2e 100644 --- a/src/lib/tls/tls_policy.cpp +++ b/src/lib/tls/tls_policy.cpp @@ -18,6 +18,7 @@ namespace TLS { std::vector<std::string> Policy::allowed_ciphers() const { return std::vector<std::string>({ + "ChaCha20Poly1305", "AES-256/GCM", "AES-128/GCM", "AES-256/CCM", diff --git a/src/lib/tls/tls_record.cpp b/src/lib/tls/tls_record.cpp index 0b356fad3..5f3801024 100644 --- a/src/lib/tls/tls_record.cpp +++ b/src/lib/tls/tls_record.cpp @@ -25,8 +25,8 @@ Connection_Cipher_State::Connection_Cipher_State(Protocol_Version version, const Ciphersuite& suite, const Session_Keys& keys) : m_start_time(std::chrono::system_clock::now()), - m_implicit_nonce_size(suite.implicit_nonce_bytes()), - m_explicit_nonce_size(suite.explicit_nonce_bytes()), + m_nonce_bytes_from_handshake(suite.nonce_bytes_from_handshake()), + m_nonce_bytes_from_record(suite.nonce_bytes_from_record()), m_is_ssl3(version == Protocol_Version::SSL_V3) { SymmetricKey mac_key, cipher_key; @@ -53,9 +53,13 @@ Connection_Cipher_State::Connection_Cipher_State(Protocol_Version version, m_aead.reset(aead); m_aead->set_key(cipher_key + mac_key); - BOTAN_ASSERT(iv.length() == explicit_nonce_bytes(), "Matching nonce sizes"); + BOTAN_ASSERT_EQUAL(iv.length(), nonce_bytes_from_handshake(), "Matching nonce sizes"); m_nonce = iv.bits_of(); - m_nonce.resize(implicit_nonce_bytes() + explicit_nonce_bytes()); + + BOTAN_ASSERT(nonce_bytes_from_record() == 0 || nonce_bytes_from_record() == 8, + "Ciphersuite uses implemented IV length"); + + m_nonce.resize(m_nonce.size() + 8); return; } @@ -89,15 +93,27 @@ Connection_Cipher_State::Connection_Cipher_State(Protocol_Version version, const secure_vector<byte>& Connection_Cipher_State::aead_nonce(u64bit seq) { - store_be(seq, &m_nonce[explicit_nonce_bytes()]); + store_be(seq, &m_nonce[nonce_bytes_from_handshake()]); return m_nonce; } const secure_vector<byte>& -Connection_Cipher_State::aead_nonce(const byte record[], size_t record_len) +Connection_Cipher_State::aead_nonce(const byte record[], size_t record_len, u64bit seq) { - BOTAN_ASSERT(record_len >= implicit_nonce_bytes(), "Record includes nonce"); - copy_mem(&m_nonce[explicit_nonce_bytes()], record, implicit_nonce_bytes()); + if(nonce_bytes_from_record()) + { + if(record_len < nonce_bytes_from_record()) + throw Decoding_Error("Invalid AEAD packet too short to be valid"); + copy_mem(&m_nonce[nonce_bytes_from_handshake()], record, nonce_bytes_from_record()); + } + else + { + /* + nonce_len == 0 is assumed to mean no nonce in the message but + instead the AEAD uses the seq number in network order. + */ + store_be(seq, &m_nonce[nonce_bytes_from_handshake()]); + } return m_nonce; } @@ -127,8 +143,8 @@ Connection_Cipher_State::format_ad(u64bit msg_sequence, void write_record(secure_vector<byte>& output, byte msg_type, const byte msg[], size_t msg_length, Protocol_Version version, - u64bit msg_sequence, - Connection_Cipher_State* cipherstate, + u64bit seq, + Connection_Cipher_State* cs, RandomNumberGenerator& rng) { output.clear(); @@ -140,10 +156,10 @@ void write_record(secure_vector<byte>& output, if(version.is_datagram_protocol()) { for(size_t i = 0; i != 8; ++i) - output.push_back(get_byte(i, msg_sequence)); + output.push_back(get_byte(i, seq)); } - if(!cipherstate) // initial unencrypted handshake records + if(!cs) // initial unencrypted handshake records { output.push_back(get_byte<u16bit>(0, msg_length)); output.push_back(get_byte<u16bit>(1, msg_length)); @@ -153,30 +169,22 @@ void write_record(secure_vector<byte>& output, return; } - if(AEAD_Mode* aead = cipherstate->aead()) + if(AEAD_Mode* aead = cs->aead()) { const size_t ctext_size = aead->output_length(msg_length); - auto nonce = cipherstate->aead_nonce(msg_sequence); - const size_t implicit_nonce_bytes = cipherstate->implicit_nonce_bytes(); - const size_t explicit_nonce_bytes = cipherstate->explicit_nonce_bytes(); - - BOTAN_ASSERT(nonce.size() == implicit_nonce_bytes + explicit_nonce_bytes, - "Expected nonce size"); + const secure_vector<byte>& nonce = cs->aead_nonce(seq); // wrong if start returns something - const size_t rec_size = ctext_size + implicit_nonce_bytes; + const size_t rec_size = ctext_size + cs->nonce_bytes_from_record(); BOTAN_ASSERT(rec_size <= 0xFFFF, "Ciphertext length fits in field"); - output.push_back(get_byte<u16bit>(0, rec_size)); output.push_back(get_byte<u16bit>(1, rec_size)); - aead->set_associated_data_vec( - cipherstate->format_ad(msg_sequence, msg_type, version, msg_length) - ); + aead->set_ad(cs->format_ad(seq, msg_type, version, msg_length)); - output += std::make_pair(&nonce[explicit_nonce_bytes], implicit_nonce_bytes); + output += std::make_pair(&nonce[cs->nonce_bytes_from_handshake()], cs->nonce_bytes_from_record()); BOTAN_ASSERT(aead->start(nonce).empty(), "AEAD doesn't return anything from start"); const size_t offset = output.size(); @@ -190,15 +198,13 @@ void write_record(secure_vector<byte>& output, return; } - cipherstate->mac()->update( - cipherstate->format_ad(msg_sequence, msg_type, version, msg_length) - ); + cs->mac()->update(cs->format_ad(seq, msg_type, version, msg_length)); - cipherstate->mac()->update(msg, msg_length); + cs->mac()->update(msg, msg_length); - const size_t block_size = cipherstate->block_size(); - const size_t iv_size = cipherstate->iv_size(); - const size_t mac_size = cipherstate->mac_size(); + const size_t block_size = cs->block_size(); + const size_t iv_size = cs->iv_size(); + const size_t mac_size = cs->mac_size(); const size_t buf_size = round_up( iv_size + msg_length + mac_size + (block_size ? 1 : 0), @@ -221,7 +227,7 @@ void write_record(secure_vector<byte>& output, output.insert(output.end(), &msg[0], &msg[msg_length]); output.resize(output.size() + mac_size); - cipherstate->mac()->final(&output[output.size() - mac_size]); + cs->mac()->final(&output[output.size() - mac_size]); if(block_size) { @@ -235,16 +241,16 @@ void write_record(secure_vector<byte>& output, if(buf_size > MAX_CIPHERTEXT_SIZE) throw Internal_Error("Produced ciphertext larger than protocol allows"); - BOTAN_ASSERT(buf_size + header_size == output.size(), - "Output buffer is sized properly"); + BOTAN_ASSERT_EQUAL(buf_size + header_size, output.size(), + "Output buffer is sized properly"); - if(StreamCipher* sc = cipherstate->stream_cipher()) + if(StreamCipher* sc = cs->stream_cipher()) { sc->cipher1(&output[header_size], buf_size); } - else if(BlockCipher* bc = cipherstate->block_cipher()) + else if(BlockCipher* bc = cs->block_cipher()) { - secure_vector<byte>& cbc_state = cipherstate->cbc_state(); + secure_vector<byte>& cbc_state = cs->cbc_state(); BOTAN_ASSERT(buf_size % block_size == 0, "Buffer is an even multiple of block size"); @@ -343,10 +349,10 @@ size_t tls_padding_check(bool sslv3_padding, } void cbc_decrypt_record(byte record_contents[], size_t record_len, - Connection_Cipher_State& cipherstate, + Connection_Cipher_State& cs, const BlockCipher& bc) { - const size_t block_size = cipherstate.block_size(); + const size_t block_size = cs.block_size(); BOTAN_ASSERT(record_len % block_size == 0, "Buffer is an even multiple of block size"); @@ -361,7 +367,7 @@ void cbc_decrypt_record(byte record_contents[], size_t record_len, copy_mem(&last_ciphertext[0], &buf[0], block_size); bc.decrypt(&buf[0]); - xor_buf(&buf[0], &cipherstate.cbc_state()[0], block_size); + xor_buf(&buf[0], &cs.cbc_state()[0], block_size); secure_vector<byte> last_ciphertext2; @@ -373,7 +379,7 @@ void cbc_decrypt_record(byte record_contents[], size_t record_len, std::swap(last_ciphertext, last_ciphertext2); } - cipherstate.cbc_state() = last_ciphertext; + cs.cbc_state() = last_ciphertext; } void decrypt_record(secure_vector<byte>& output, @@ -381,21 +387,18 @@ void decrypt_record(secure_vector<byte>& output, u64bit record_sequence, Protocol_Version record_version, Record_Type record_type, - Connection_Cipher_State& cipherstate) + Connection_Cipher_State& cs) { - if(AEAD_Mode* aead = cipherstate.aead()) + if(AEAD_Mode* aead = cs.aead()) { - auto nonce = cipherstate.aead_nonce(record_contents, record_len); - const size_t nonce_length = cipherstate.implicit_nonce_bytes(); - - BOTAN_ASSERT(record_len > nonce_length, "Have data past the nonce"); - const byte* msg = &record_contents[nonce_length]; - const size_t msg_length = record_len - nonce_length; + const secure_vector<byte>& nonce = cs.aead_nonce(record_contents, record_len, record_sequence); + const byte* msg = &record_contents[cs.nonce_bytes_from_record()]; + const size_t msg_length = record_len - cs.nonce_bytes_from_record(); const size_t ptext_size = aead->output_length(msg_length); aead->set_associated_data_vec( - cipherstate.format_ad(record_sequence, record_type, record_version, ptext_size) + cs.format_ad(record_sequence, record_type, record_version, ptext_size) ); output += aead->start(nonce); @@ -413,17 +416,17 @@ void decrypt_record(secure_vector<byte>& output, volatile bool padding_bad = false; size_t pad_size = 0; - if(StreamCipher* sc = cipherstate.stream_cipher()) + if(StreamCipher* sc = cs.stream_cipher()) { sc->cipher1(record_contents, record_len); // no padding to check or remove } - else if(BlockCipher* bc = cipherstate.block_cipher()) + else if(BlockCipher* bc = cs.block_cipher()) { - cbc_decrypt_record(record_contents, record_len, cipherstate, *bc); + cbc_decrypt_record(record_contents, record_len, cs, *bc); - pad_size = tls_padding_check(cipherstate.cipher_padding_single_byte(), - cipherstate.block_size(), + pad_size = tls_padding_check(cs.cipher_padding_single_byte(), + cs.block_size(), record_contents, record_len); padding_bad = (pad_size == 0); @@ -433,8 +436,8 @@ void decrypt_record(secure_vector<byte>& output, throw Internal_Error("No cipher state set but needed to decrypt"); } - const size_t mac_size = cipherstate.mac_size(); - const size_t iv_size = cipherstate.iv_size(); + const size_t mac_size = cs.mac_size(); + const size_t iv_size = cs.iv_size(); const size_t mac_pad_iv_size = mac_size + pad_size + iv_size; @@ -444,14 +447,14 @@ void decrypt_record(secure_vector<byte>& output, const byte* plaintext_block = &record_contents[iv_size]; const u16bit plaintext_length = record_len - mac_pad_iv_size; - cipherstate.mac()->update( - cipherstate.format_ad(record_sequence, record_type, record_version, plaintext_length) + cs.mac()->update( + cs.format_ad(record_sequence, record_type, record_version, plaintext_length) ); - cipherstate.mac()->update(plaintext_block, plaintext_length); + cs.mac()->update(plaintext_block, plaintext_length); std::vector<byte> mac_buf(mac_size); - cipherstate.mac()->final(&mac_buf[0]); + cs.mac()->final(&mac_buf[0]); const size_t mac_offset = record_len - (mac_size + pad_size); @@ -484,8 +487,7 @@ size_t read_tls_record(secure_vector<byte>& readbuf, TLS_HEADER_SIZE)) return needed; - BOTAN_ASSERT_EQUAL(readbuf.size(), TLS_HEADER_SIZE, - "Have an entire header"); + BOTAN_ASSERT_EQUAL(readbuf.size(), TLS_HEADER_SIZE, "Have an entire header"); } // Possible SSLv2 format client hello @@ -571,9 +573,9 @@ size_t read_tls_record(secure_vector<byte>& readbuf, } // Otherwise, decrypt, check MAC, return plaintext - auto cipherstate = get_cipherstate(epoch); + auto cs = get_cipherstate(epoch); - BOTAN_ASSERT(cipherstate, "Have cipherstate for this epoch"); + BOTAN_ASSERT(cs, "Have cipherstate for this epoch"); decrypt_record(record, record_contents, @@ -581,7 +583,7 @@ size_t read_tls_record(secure_vector<byte>& readbuf, *record_sequence, *record_version, *record_type, - *cipherstate); + *cs); if(sequence_numbers) sequence_numbers->read_accept(*record_sequence); @@ -660,9 +662,9 @@ size_t read_dtls_record(secure_vector<byte>& readbuf, try { // Otherwise, decrypt, check MAC, return plaintext - auto cipherstate = get_cipherstate(epoch); + auto cs = get_cipherstate(epoch); - BOTAN_ASSERT(cipherstate, "Have cipherstate for this epoch"); + BOTAN_ASSERT(cs, "Have cipherstate for this epoch"); decrypt_record(record, record_contents, @@ -670,7 +672,7 @@ size_t read_dtls_record(secure_vector<byte>& readbuf, *record_sequence, *record_version, *record_type, - *cipherstate); + *cs); } catch(std::exception) { diff --git a/src/lib/tls/tls_record.h b/src/lib/tls/tls_record.h index 2dae96164..d7e85dcab 100644 --- a/src/lib/tls/tls_record.h +++ b/src/lib/tls/tls_record.h @@ -45,7 +45,7 @@ class Connection_Cipher_State const secure_vector<byte>& aead_nonce(u64bit seq); - const secure_vector<byte>& aead_nonce(const byte record[], size_t record_len); + const secure_vector<byte>& aead_nonce(const byte record[], size_t record_len, u64bit seq); const secure_vector<byte>& format_ad(u64bit seq, byte type, Protocol_Version version, @@ -65,9 +65,9 @@ class Connection_Cipher_State size_t iv_size() const { return m_iv_size; } - size_t implicit_nonce_bytes() const { return m_implicit_nonce_size; } + size_t nonce_bytes_from_record() const { return m_nonce_bytes_from_record; } - size_t explicit_nonce_bytes() const { return m_explicit_nonce_size; } + size_t nonce_bytes_from_handshake() const { return m_nonce_bytes_from_handshake; } bool cipher_padding_single_byte() const { return m_is_ssl3; } @@ -91,7 +91,8 @@ class Connection_Cipher_State secure_vector<byte> m_nonce, m_ad; size_t m_block_size = 0; - size_t m_implicit_nonce_size = 0, m_explicit_nonce_size = 0; + size_t m_nonce_bytes_from_handshake; + size_t m_nonce_bytes_from_record; size_t m_iv_size = 0; bool m_is_ssl3 = false; }; diff --git a/src/lib/tls/tls_session_key.cpp b/src/lib/tls/tls_session_key.cpp index 4c09b29fd..3ea80ecb0 100644 --- a/src/lib/tls/tls_session_key.cpp +++ b/src/lib/tls/tls_session_key.cpp @@ -22,7 +22,7 @@ Session_Keys::Session_Keys(const Handshake_State* state, { const size_t cipher_keylen = state->ciphersuite().cipher_keylen(); const size_t mac_keylen = state->ciphersuite().mac_keylen(); - const size_t cipher_nonce_bytes = state->ciphersuite().explicit_nonce_bytes(); + const size_t cipher_nonce_bytes = state->ciphersuite().nonce_bytes_from_handshake(); const size_t prf_gen = 2 * (mac_keylen + cipher_keylen + cipher_nonce_bytes); diff --git a/src/lib/tls/tls_suite_info.cpp b/src/lib/tls/tls_suite_info.cpp index b19986dff..90ff2ae61 100644 --- a/src/lib/tls/tls_suite_info.cpp +++ b/src/lib/tls/tls_suite_info.cpp @@ -3,7 +3,7 @@ * * This file was automatically generated from the IANA assignments * (tls-parameters.txt hash 4bc98b6f75ad5b63952b5f457fa7adbfef60f095) -* by ./src/scripts/tls_suite_info.py on 2014-11-03 +* by ./src/scripts/tls_suite_info.py on 2014-12-31 * * Released under the terms of the Botan license */ @@ -156,6 +156,9 @@ Ciphersuite Ciphersuite::by_id(u16bit suite) case 0xC07D: // DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 return Ciphersuite(0xC07D, "RSA", "DH", "Camellia-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384"); + case 0xCC15: // DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + return Ciphersuite(0xCC15, "RSA", "DH", "ChaCha20Poly1305", 32, 0, 0, "AEAD", 0, "SHA-256"); + case 0x009A: // DHE_RSA_WITH_SEED_CBC_SHA return Ciphersuite(0x009A, "RSA", "DH", "SEED", 16, 16, 0, "SHA-1", 20); @@ -249,6 +252,9 @@ Ciphersuite Ciphersuite::by_id(u16bit suite) case 0xC087: // ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 return Ciphersuite(0xC087, "ECDSA", "ECDH", "Camellia-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384"); + case 0xCC14: // ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 + return Ciphersuite(0xCC14, "ECDSA", "ECDH", "ChaCha20Poly1305", 32, 0, 0, "AEAD", 0, "SHA-256"); + case 0xC007: // ECDHE_ECDSA_WITH_RC4_128_SHA return Ciphersuite(0xC007, "ECDSA", "ECDH", "RC4", 16, 0, 0, "SHA-1", 20); @@ -309,6 +315,9 @@ Ciphersuite Ciphersuite::by_id(u16bit suite) case 0xC08B: // ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 return Ciphersuite(0xC08B, "RSA", "ECDH", "Camellia-256/GCM", 32, 4, 8, "AEAD", 0, "SHA-384"); + case 0xCC13: // ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + return Ciphersuite(0xCC13, "RSA", "ECDH", "ChaCha20Poly1305", 32, 0, 0, "AEAD", 0, "SHA-256"); + case 0xC011: // ECDHE_RSA_WITH_RC4_128_SHA return Ciphersuite(0xC011, "RSA", "ECDH", "RC4", 16, 0, 0, "SHA-1", 20); |