aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/tls/tls_ciphersuite.cpp41
-rw-r--r--src/lib/tls/tls_ciphersuite.h11
-rw-r--r--src/lib/tls/tls_policy.cpp1
-rw-r--r--src/lib/tls/tls_record.cpp142
-rw-r--r--src/lib/tls/tls_record.h9
-rw-r--r--src/lib/tls/tls_session_key.cpp2
-rw-r--r--src/lib/tls/tls_suite_info.cpp11
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);