From d363602f95f1514b4b595d9912fba2e503edcb21 Mon Sep 17 00:00:00 2001 From: lloyd Date: Fri, 23 Dec 2011 16:14:45 +0000 Subject: First stab at an event driven TLS client. --- src/ssl/info.txt | 1 - 1 file changed, 1 deletion(-) (limited to 'src/ssl/info.txt') diff --git a/src/ssl/info.txt b/src/ssl/info.txt index f920a733d..1170fef45 100644 --- a/src/ssl/info.txt +++ b/src/ssl/info.txt @@ -9,7 +9,6 @@ uses_tr1 yes tls_client.h -tls_connection.h tls_exceptn.h tls_magic.h tls_policy.h -- cgit v1.2.3 From 67c1645ae151f5dd0f2bafce926ff8690fd97f19 Mon Sep 17 00:00:00 2001 From: lloyd Date: Fri, 23 Dec 2011 16:17:29 +0000 Subject: Rename ssl module to tls --- src/ssl/c_kex.cpp | 165 -------------- src/ssl/cert_req.cpp | 151 ------------- src/ssl/cert_ver.cpp | 98 -------- src/ssl/finished.cpp | 100 --------- src/ssl/hello.cpp | 331 --------------------------- src/ssl/info.txt | 66 ------ src/ssl/rec_read.cpp | 255 --------------------- src/ssl/rec_wri.cpp | 270 ---------------------- src/ssl/s_kex.cpp | 180 --------------- src/ssl/tls_alerts.h | 54 ----- src/ssl/tls_client.cpp | 499 ----------------------------------------- src/ssl/tls_client.h | 87 ------- src/ssl/tls_exceptn.h | 43 ---- src/ssl/tls_handshake_hash.cpp | 70 ------ src/ssl/tls_handshake_hash.h | 40 ---- src/ssl/tls_magic.h | 192 ---------------- src/ssl/tls_messages.h | 297 ------------------------ src/ssl/tls_policy.cpp | 118 ---------- src/ssl/tls_policy.h | 63 ------ src/ssl/tls_reader.h | 186 --------------- src/ssl/tls_record.h | 119 ---------- src/ssl/tls_server.cpp | 494 ---------------------------------------- src/ssl/tls_server.h | 76 ------- src/ssl/tls_session_key.cpp | 170 -------------- src/ssl/tls_session_key.h | 52 ----- src/ssl/tls_state.cpp | 59 ----- src/ssl/tls_state.h | 53 ----- src/ssl/tls_suites.cpp | 281 ----------------------- src/ssl/tls_suites.h | 42 ---- src/tls/c_kex.cpp | 165 ++++++++++++++ src/tls/cert_req.cpp | 151 +++++++++++++ src/tls/cert_ver.cpp | 98 ++++++++ src/tls/finished.cpp | 100 +++++++++ src/tls/hello.cpp | 331 +++++++++++++++++++++++++++ src/tls/info.txt | 66 ++++++ src/tls/rec_read.cpp | 255 +++++++++++++++++++++ src/tls/rec_wri.cpp | 270 ++++++++++++++++++++++ src/tls/s_kex.cpp | 180 +++++++++++++++ src/tls/tls_alerts.h | 54 +++++ src/tls/tls_client.cpp | 499 +++++++++++++++++++++++++++++++++++++++++ src/tls/tls_client.h | 87 +++++++ src/tls/tls_exceptn.h | 43 ++++ src/tls/tls_handshake_hash.cpp | 70 ++++++ src/tls/tls_handshake_hash.h | 40 ++++ src/tls/tls_magic.h | 192 ++++++++++++++++ src/tls/tls_messages.h | 297 ++++++++++++++++++++++++ src/tls/tls_policy.cpp | 118 ++++++++++ src/tls/tls_policy.h | 63 ++++++ src/tls/tls_reader.h | 186 +++++++++++++++ src/tls/tls_record.h | 119 ++++++++++ src/tls/tls_server.cpp | 494 ++++++++++++++++++++++++++++++++++++++++ src/tls/tls_server.h | 76 +++++++ src/tls/tls_session_key.cpp | 170 ++++++++++++++ src/tls/tls_session_key.h | 52 +++++ src/tls/tls_state.cpp | 59 +++++ src/tls/tls_state.h | 53 +++++ src/tls/tls_suites.cpp | 281 +++++++++++++++++++++++ src/tls/tls_suites.h | 42 ++++ 58 files changed, 4611 insertions(+), 4611 deletions(-) delete mode 100644 src/ssl/c_kex.cpp delete mode 100644 src/ssl/cert_req.cpp delete mode 100644 src/ssl/cert_ver.cpp delete mode 100644 src/ssl/finished.cpp delete mode 100644 src/ssl/hello.cpp delete mode 100644 src/ssl/info.txt delete mode 100644 src/ssl/rec_read.cpp delete mode 100644 src/ssl/rec_wri.cpp delete mode 100644 src/ssl/s_kex.cpp delete mode 100644 src/ssl/tls_alerts.h delete mode 100644 src/ssl/tls_client.cpp delete mode 100644 src/ssl/tls_client.h delete mode 100644 src/ssl/tls_exceptn.h delete mode 100644 src/ssl/tls_handshake_hash.cpp delete mode 100644 src/ssl/tls_handshake_hash.h delete mode 100644 src/ssl/tls_magic.h delete mode 100644 src/ssl/tls_messages.h delete mode 100644 src/ssl/tls_policy.cpp delete mode 100644 src/ssl/tls_policy.h delete mode 100644 src/ssl/tls_reader.h delete mode 100644 src/ssl/tls_record.h delete mode 100644 src/ssl/tls_server.cpp delete mode 100644 src/ssl/tls_server.h delete mode 100644 src/ssl/tls_session_key.cpp delete mode 100644 src/ssl/tls_session_key.h delete mode 100644 src/ssl/tls_state.cpp delete mode 100644 src/ssl/tls_state.h delete mode 100644 src/ssl/tls_suites.cpp delete mode 100644 src/ssl/tls_suites.h create mode 100644 src/tls/c_kex.cpp create mode 100644 src/tls/cert_req.cpp create mode 100644 src/tls/cert_ver.cpp create mode 100644 src/tls/finished.cpp create mode 100644 src/tls/hello.cpp create mode 100644 src/tls/info.txt create mode 100644 src/tls/rec_read.cpp create mode 100644 src/tls/rec_wri.cpp create mode 100644 src/tls/s_kex.cpp create mode 100644 src/tls/tls_alerts.h create mode 100644 src/tls/tls_client.cpp create mode 100644 src/tls/tls_client.h create mode 100644 src/tls/tls_exceptn.h create mode 100644 src/tls/tls_handshake_hash.cpp create mode 100644 src/tls/tls_handshake_hash.h create mode 100644 src/tls/tls_magic.h create mode 100644 src/tls/tls_messages.h create mode 100644 src/tls/tls_policy.cpp create mode 100644 src/tls/tls_policy.h create mode 100644 src/tls/tls_reader.h create mode 100644 src/tls/tls_record.h create mode 100644 src/tls/tls_server.cpp create mode 100644 src/tls/tls_server.h create mode 100644 src/tls/tls_session_key.cpp create mode 100644 src/tls/tls_session_key.h create mode 100644 src/tls/tls_state.cpp create mode 100644 src/tls/tls_state.h create mode 100644 src/tls/tls_suites.cpp create mode 100644 src/tls/tls_suites.h (limited to 'src/ssl/info.txt') diff --git a/src/ssl/c_kex.cpp b/src/ssl/c_kex.cpp deleted file mode 100644 index 0f20b819c..000000000 --- a/src/ssl/c_kex.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* -* Client Key Exchange Message -* (C) 2004-2010 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Botan { - -/** -* Create a new Client Key Exchange message -*/ -Client_Key_Exchange::Client_Key_Exchange(RandomNumberGenerator& rng, - Record_Writer& writer, - HandshakeHash& hash, - const Public_Key* pub_key, - Version_Code using_version, - Version_Code pref_version) - { - include_length = true; - - if(const DH_PublicKey* dh_pub = dynamic_cast(pub_key)) - { - DH_PrivateKey priv_key(rng, dh_pub->get_domain()); - - PK_Key_Agreement ka(priv_key, "Raw"); - - pre_master = ka.derive_key(0, dh_pub->public_value()).bits_of(); - - key_material = priv_key.public_value(); - } - else if(const RSA_PublicKey* rsa_pub = dynamic_cast(pub_key)) - { - pre_master = rng.random_vec(48); - pre_master[0] = (pref_version >> 8) & 0xFF; - pre_master[1] = (pref_version ) & 0xFF; - - PK_Encryptor_EME encryptor(*rsa_pub, "PKCS1v15"); - - key_material = encryptor.encrypt(pre_master, rng); - - if(using_version == SSL_V3) - include_length = false; - } - else - throw Invalid_Argument("Client_Key_Exchange: Key not RSA or DH"); - - send(writer, hash); - } - -/** -* Read a Client Key Exchange message -*/ -Client_Key_Exchange::Client_Key_Exchange(const MemoryRegion& contents, - const CipherSuite& suite, - Version_Code using_version) - { - include_length = true; - - if(using_version == SSL_V3 && (suite.kex_type() == TLS_ALGO_KEYEXCH_RSA)) - include_length = false; - - deserialize(contents); - } - -/** -* Serialize a Client Key Exchange message -*/ -SecureVector Client_Key_Exchange::serialize() const - { - if(include_length) - { - SecureVector buf; - append_tls_length_value(buf, key_material, 2); - return buf; - } - else - return key_material; - } - -/** -* Deserialize a Client Key Exchange message -*/ -void Client_Key_Exchange::deserialize(const MemoryRegion& buf) - { - if(include_length) - { - TLS_Data_Reader reader(buf); - key_material = reader.get_range(2, 0, 65535); - } - else - key_material = buf; - } - -/** -* Return the pre_master_secret -*/ -SecureVector -Client_Key_Exchange::pre_master_secret(RandomNumberGenerator& rng, - const Private_Key* priv_key, - Version_Code version) - { - - if(const DH_PrivateKey* dh_priv = dynamic_cast(priv_key)) - { - try { - PK_Key_Agreement ka(*dh_priv, "Raw"); - - pre_master = ka.derive_key(0, key_material).bits_of(); - } - catch(...) - { - /* - * Something failed in the DH computation. To avoid possible - * timing attacks, randomize the pre-master output and carry - * on, allowing the protocol to fail later in the finished - * checks. - */ - pre_master = rng.random_vec(dh_priv->public_value().size()); - } - - return pre_master; - } - else if(const RSA_PrivateKey* rsa_priv = dynamic_cast(priv_key)) - { - PK_Decryptor_EME decryptor(*rsa_priv, "PKCS1v15"); - - try { - pre_master = decryptor.decrypt(key_material); - - if(pre_master.size() != 48 || - make_u16bit(pre_master[0], pre_master[1]) != version) - throw Decoding_Error("Client_Key_Exchange: Secret corrupted"); - } - catch(...) - { - pre_master = rng.random_vec(48); - pre_master[0] = (version >> 8) & 0xFF; - pre_master[1] = (version ) & 0xFF; - } - - return pre_master; - } - else - throw Invalid_Argument("Client_Key_Exchange: Bad key for decrypt"); - } - -/** -* Return the pre_master_secret -*/ -SecureVector Client_Key_Exchange::pre_master_secret() const - { - return pre_master; - } - -} diff --git a/src/ssl/cert_req.cpp b/src/ssl/cert_req.cpp deleted file mode 100644 index b8b2624bf..000000000 --- a/src/ssl/cert_req.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* -* Certificate Request Message -* (C) 2004-2006 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include -#include -#include -#include -#include -#include - -namespace Botan { - -/** -* Create a new Certificate Request message -*/ -Certificate_Req::Certificate_Req(Record_Writer& writer, - HandshakeHash& hash, - const std::vector& certs) - { - for(size_t i = 0; i != certs.size(); ++i) - names.push_back(certs[i].subject_dn()); - - // FIXME: should be able to choose what to ask for - types.push_back(RSA_CERT); - types.push_back(DSS_CERT); - - send(writer, hash); - } - -/** -* Serialize a Certificate Request message -*/ -SecureVector Certificate_Req::serialize() const - { - SecureVector buf; - - append_tls_length_value(buf, types, 1); - - DER_Encoder encoder; - for(size_t i = 0; i != names.size(); ++i) - encoder.encode(names[i]); - - append_tls_length_value(buf, encoder.get_contents(), 2); - - return buf; - } - -/** -* Deserialize a Certificate Request message -*/ -void Certificate_Req::deserialize(const MemoryRegion& buf) - { - if(buf.size() < 4) - throw Decoding_Error("Certificate_Req: Bad certificate request"); - - size_t types_size = buf[0]; - - if(buf.size() < types_size + 3) - throw Decoding_Error("Certificate_Req: Bad certificate request"); - - for(size_t i = 0; i != types_size; ++i) - types.push_back(static_cast(buf[i+1])); - - size_t names_size = make_u16bit(buf[types_size+2], buf[types_size+3]); - - if(buf.size() != names_size + types_size + 3) - throw Decoding_Error("Certificate_Req: Bad certificate request"); - - BER_Decoder decoder(&buf[types_size + 3], names_size); - - while(decoder.more_items()) - { - X509_DN name; - decoder.decode(name); - names.push_back(name); - } - } - -/** -* Create a new Certificate message -*/ -Certificate::Certificate(Record_Writer& writer, - const std::vector& cert_list, - HandshakeHash& hash) - { - certs = cert_list; - send(writer, hash); - } - -/** -* Serialize a Certificate message -*/ -SecureVector Certificate::serialize() const - { - SecureVector buf(3); - - for(size_t i = 0; i != certs.size(); ++i) - { - SecureVector raw_cert = certs[i].BER_encode(); - const size_t cert_size = raw_cert.size(); - for(size_t i = 0; i != 3; ++i) - buf.push_back(get_byte(i+1, cert_size)); - buf += raw_cert; - } - - const size_t buf_size = buf.size() - 3; - for(size_t i = 0; i != 3; ++i) - buf[i] = get_byte(i+1, buf_size); - - return buf; - } - -/** -* Deserialize a Certificate message -*/ -void Certificate::deserialize(const MemoryRegion& buf) - { - if(buf.size() < 3) - throw Decoding_Error("Certificate: Message malformed"); - - const size_t total_size = make_u32bit(0, buf[0], buf[1], buf[2]); - - SecureQueue queue; - queue.write(&buf[3], buf.size() - 3); - - if(queue.size() != total_size) - throw Decoding_Error("Certificate: Message malformed"); - - while(queue.size()) - { - if(queue.size() < 3) - throw Decoding_Error("Certificate: Message malformed"); - - byte len[3]; - queue.read(len, 3); - - const size_t cert_size = make_u32bit(0, len[0], len[1], len[2]); - const size_t original_size = queue.size(); - - X509_Certificate cert(queue); - if(queue.size() + cert_size != original_size) - throw Decoding_Error("Certificate: Message malformed"); - certs.push_back(cert); - } - } - -} diff --git a/src/ssl/cert_ver.cpp b/src/ssl/cert_ver.cpp deleted file mode 100644 index 3220a8c9e..000000000 --- a/src/ssl/cert_ver.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* -* Certificate Verify Message -* (C) 2004-2010 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include -#include -#include -#include -#include -#include -#include - -namespace Botan { - -/** -* Create a new Certificate Verify message -*/ -Certificate_Verify::Certificate_Verify(RandomNumberGenerator& rng, - Record_Writer& writer, - HandshakeHash& hash, - const Private_Key* priv_key) - { - std::string padding = ""; - Signature_Format format = IEEE_1363; - - if(priv_key->algo_name() == "RSA") - padding = "EMSA3(TLS.Digest.0)"; - else if(priv_key->algo_name() == "DSA") - { - padding == "EMSA1(SHA-1)"; - format = DER_SEQUENCE; - } - else - throw Invalid_Argument(priv_key->algo_name() + - " is invalid/unknown for TLS signatures"); - - PK_Signer signer(*priv_key, padding, format); - - signature = signer.sign_message(hash.final(), rng); - send(writer, hash); - } - -/** -* Serialize a Certificate Verify message -*/ -SecureVector Certificate_Verify::serialize() const - { - SecureVector buf; - - const u16bit sig_len = signature.size(); - buf.push_back(get_byte(0, sig_len)); - buf.push_back(get_byte(1, sig_len)); - buf += signature; - - return buf; - } - -/** -* Deserialize a Certificate Verify message -*/ -void Certificate_Verify::deserialize(const MemoryRegion& buf) - { - TLS_Data_Reader reader(buf); - signature = reader.get_range(2, 0, 65535); - } - -/** -* Verify a Certificate Verify message -*/ -bool Certificate_Verify::verify(const X509_Certificate& cert, - HandshakeHash& hash) - { - // FIXME: duplicate of Server_Key_Exchange::verify - - std::auto_ptr key(cert.subject_public_key()); - - std::string padding = ""; - Signature_Format format = IEEE_1363; - - if(key->algo_name() == "RSA") - padding = "EMSA3(TLS.Digest.0)"; - else if(key->algo_name() == "DSA") - { - padding == "EMSA1(SHA-1)"; - format = DER_SEQUENCE; - } - else - throw Invalid_Argument(key->algo_name() + - " is invalid/unknown for TLS signatures"); - - PK_Verifier verifier(*key, padding, format); - return verifier.verify_message(hash.final(), signature); - } - -} diff --git a/src/ssl/finished.cpp b/src/ssl/finished.cpp deleted file mode 100644 index d76fbd884..000000000 --- a/src/ssl/finished.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/* -* Finished Message -* (C) 2004-2006 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include -#include - -namespace Botan { - -/** -* Create a new Finished message -*/ -Finished::Finished(Record_Writer& writer, - Version_Code version, Connection_Side side, - const MemoryRegion& master_secret, - HandshakeHash& hash) - { - verification_data = compute_verify(master_secret, hash, side, version); - send(writer, hash); - } - -/** -* Serialize a Finished message -*/ -SecureVector Finished::serialize() const - { - return verification_data; - } - -/** -* Deserialize a Finished message -*/ -void Finished::deserialize(const MemoryRegion& buf) - { - verification_data = buf; - } - -/** -* Verify a Finished message -*/ -bool Finished::verify(const MemoryRegion& secret, Version_Code version, - const HandshakeHash& hash, Connection_Side side) - { - SecureVector computed = compute_verify(secret, hash, side, version); - if(computed == verification_data) - return true; - return false; - } - -/** -* Compute the verify_data -*/ -SecureVector Finished::compute_verify(const MemoryRegion& secret, - HandshakeHash hash, - Connection_Side side, - Version_Code version) - { - if(version == SSL_V3) - { - const byte SSL_CLIENT_LABEL[] = { 0x43, 0x4C, 0x4E, 0x54 }; - const byte SSL_SERVER_LABEL[] = { 0x53, 0x52, 0x56, 0x52 }; - - SecureVector ssl3_finished; - - if(side == CLIENT) - hash.update(SSL_CLIENT_LABEL, sizeof(SSL_CLIENT_LABEL)); - else - hash.update(SSL_SERVER_LABEL, sizeof(SSL_SERVER_LABEL)); - - return hash.final_ssl3(secret); - } - else if(version == TLS_V10 || version == TLS_V11) - { - const byte TLS_CLIENT_LABEL[] = { - 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x20, 0x66, 0x69, 0x6E, 0x69, - 0x73, 0x68, 0x65, 0x64 }; - - const byte TLS_SERVER_LABEL[] = { - 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x66, 0x69, 0x6E, 0x69, - 0x73, 0x68, 0x65, 0x64 }; - - TLS_PRF prf; - - SecureVector input; - if(side == CLIENT) - input += std::make_pair(TLS_CLIENT_LABEL, sizeof(TLS_CLIENT_LABEL)); - else - input += std::make_pair(TLS_SERVER_LABEL, sizeof(TLS_SERVER_LABEL)); - input += hash.final(); - - return prf.derive_key(12, secret, input); - } - else - throw Invalid_Argument("Finished message: Unknown protocol version"); - } - -} diff --git a/src/ssl/hello.cpp b/src/ssl/hello.cpp deleted file mode 100644 index ae0d9607b..000000000 --- a/src/ssl/hello.cpp +++ /dev/null @@ -1,331 +0,0 @@ -/* -* TLS Hello Messages -* (C) 2004-2010 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include -#include - -namespace Botan { - -/* -* Encode and send a Handshake message -*/ -void HandshakeMessage::send(Record_Writer& writer, HandshakeHash& hash) const - { - SecureVector buf = serialize(); - SecureVector send_buf(4); - - const size_t buf_size = buf.size(); - - send_buf[0] = type(); - - for(size_t i = 1; i != 4; ++i) - send_buf[i] = get_byte(i, buf_size); - - send_buf += buf; - - hash.update(send_buf); - - writer.send(HANDSHAKE, &send_buf[0], send_buf.size()); - writer.flush(); - } - -/* -* Create a new Hello Request message -*/ -Hello_Request::Hello_Request(Record_Writer& writer) - { - HandshakeHash dummy; // FIXME: *UGLY* - send(writer, dummy); - } - -/* -* Serialize a Hello Request message -*/ -SecureVector Hello_Request::serialize() const - { - return SecureVector(); - } - -/* -* Deserialize a Hello Request message -*/ -void Hello_Request::deserialize(const MemoryRegion& buf) - { - if(buf.size()) - throw Decoding_Error("Hello_Request: Must be empty, and is not"); - } - -/* -* Create a new Client Hello message -*/ -Client_Hello::Client_Hello(RandomNumberGenerator& rng, - Record_Writer& writer, - const TLS_Policy& policy, - HandshakeHash& hash) - { - c_random = rng.random_vec(32); - - suites = policy.ciphersuites(); - comp_algos = policy.compression(); - c_version = policy.pref_version(); - - send(writer, hash); - } - -/* -* Serialize a Client Hello message -*/ -SecureVector Client_Hello::serialize() const - { - SecureVector buf; - - buf.push_back(static_cast(c_version >> 8)); - buf.push_back(static_cast(c_version )); - buf += c_random; - - append_tls_length_value(buf, sess_id, 1); - append_tls_length_value(buf, suites, 2); - append_tls_length_value(buf, comp_algos, 1); - - return buf; - } - -void Client_Hello::deserialize_sslv2(const MemoryRegion& buf) - { - if(buf.size() < 12 || buf[0] != 1) - throw Decoding_Error("Client_Hello: SSLv2 hello corrupted"); - - const size_t cipher_spec_len = make_u16bit(buf[3], buf[4]); - const size_t sess_id_len = make_u16bit(buf[5], buf[6]); - const size_t challenge_len = make_u16bit(buf[7], buf[8]); - - const size_t expected_size = - (9 + sess_id_len + cipher_spec_len + challenge_len); - - if(buf.size() != expected_size) - throw Decoding_Error("Client_Hello: SSLv2 hello corrupted"); - - if(sess_id_len != 0 || cipher_spec_len % 3 != 0 || - (challenge_len < 16 || challenge_len > 32)) - { - throw Decoding_Error("Client_Hello: SSLv2 hello corrupted"); - } - - for(size_t i = 9; i != 9 + cipher_spec_len; i += 3) - { - if(buf[i] != 0) // a SSLv2 cipherspec; ignore it - continue; - - suites.push_back(make_u16bit(buf[i+1], buf[i+2])); - } - - c_version = static_cast(make_u16bit(buf[1], buf[2])); - - c_random.resize(challenge_len); - copy_mem(&c_random[0], &buf[9+cipher_spec_len+sess_id_len], challenge_len); - } - -/* -* Deserialize a Client Hello message -*/ -void Client_Hello::deserialize(const MemoryRegion& buf) - { - if(buf.size() == 0) - throw Decoding_Error("Client_Hello: Packet corrupted"); - - if(buf.size() < 41) - throw Decoding_Error("Client_Hello: Packet corrupted"); - - TLS_Data_Reader reader(buf); - - c_version = static_cast(reader.get_u16bit()); - c_random = reader.get_fixed(32); - - sess_id = reader.get_range(1, 0, 32); - - suites = reader.get_range_vector(2, 1, 32767); - - comp_algos = reader.get_range_vector(1, 1, 255); - - if(reader.has_remaining()) - { - const u16bit all_extn_size = reader.get_u16bit(); - - if(reader.remaining_bytes() != all_extn_size) - throw Decoding_Error("Client_Hello: Bad extension size"); - - while(reader.has_remaining()) - { - const u16bit extension_code = reader.get_u16bit(); - const u16bit extension_size = reader.get_u16bit(); - - if(extension_code == TLSEXT_SERVER_NAME_INDICATION) - { - u16bit name_bytes = reader.get_u16bit(); - - while(name_bytes) - { - byte name_type = reader.get_byte(); - name_bytes--; - - if(name_type == 0) // DNS - { - std::vector name = - reader.get_range_vector(2, 1, 65535); - - requested_hostname.assign( - reinterpret_cast(&name[0]), - name.size()); - - name_bytes -= (2 + name.size()); - } - else - { - reader.discard_next(name_bytes); - name_bytes = 0; - } - } - } - else if(extension_code == TLSEXT_SRP_IDENTIFIER) - { - std::vector name = reader.get_range_vector(1, 1, 255); - - requested_srp_id.assign( - reinterpret_cast(&name[0]), - name.size()); - } - else - { - reader.discard_next(extension_size); - } - } - } - } - -/* -* Check if we offered this ciphersuite -*/ -bool Client_Hello::offered_suite(u16bit ciphersuite) const - { - for(size_t i = 0; i != suites.size(); ++i) - if(suites[i] == ciphersuite) - return true; - return false; - } - -/* -* Create a new Server Hello message -*/ -Server_Hello::Server_Hello(RandomNumberGenerator& rng, - Record_Writer& writer, - const TLS_Policy& policy, - const std::vector& certs, - const Client_Hello& c_hello, - Version_Code ver, - HandshakeHash& hash) - { - bool have_rsa = false, have_dsa = false; - - for(size_t i = 0; i != certs.size(); ++i) - { - Public_Key* key = certs[i].subject_public_key(); - if(key->algo_name() == "RSA") - have_rsa = true; - - if(key->algo_name() == "DSA") - have_dsa = true; - } - - suite = policy.choose_suite(c_hello.ciphersuites(), have_rsa, have_dsa); - - if(suite == 0) - throw TLS_Exception(PROTOCOL_VERSION, - "Can't agree on a ciphersuite with client"); - - comp_algo = policy.choose_compression(c_hello.compression_algos()); - - s_version = ver; - s_random = rng.random_vec(32); - - send(writer, hash); - } - -/* -* Serialize a Server Hello message -*/ -SecureVector Server_Hello::serialize() const - { - SecureVector buf; - - buf.push_back(static_cast(s_version >> 8)); - buf.push_back(static_cast(s_version )); - buf += s_random; - - append_tls_length_value(buf, sess_id, 1); - - buf.push_back(get_byte(0, suite)); - buf.push_back(get_byte(1, suite)); - - buf.push_back(comp_algo); - - return buf; - } - -/* -* Deserialize a Server Hello message -*/ -void Server_Hello::deserialize(const MemoryRegion& buf) - { - if(buf.size() < 38) - throw Decoding_Error("Server_Hello: Packet corrupted"); - - TLS_Data_Reader reader(buf); - - s_version = static_cast(reader.get_u16bit()); - - if(s_version != SSL_V3 && s_version != TLS_V10 && s_version != TLS_V11) - { - throw TLS_Exception(PROTOCOL_VERSION, - "Server_Hello: Unsupported server version"); - } - - s_random = reader.get_fixed(32); - - sess_id = reader.get_range(1, 0, 32); - - suite = reader.get_u16bit(); - - comp_algo = reader.get_byte(); - } - -/* -* Create a new Server Hello Done message -*/ -Server_Hello_Done::Server_Hello_Done(Record_Writer& writer, - HandshakeHash& hash) - { - send(writer, hash); - } - -/* -* Serialize a Server Hello Done message -*/ -SecureVector Server_Hello_Done::serialize() const - { - return SecureVector(); - } - -/* -* Deserialize a Server Hello Done message -*/ -void Server_Hello_Done::deserialize(const MemoryRegion& buf) - { - if(buf.size()) - throw Decoding_Error("Server_Hello_Done: Must be empty, and is not"); - } - -} diff --git a/src/ssl/info.txt b/src/ssl/info.txt deleted file mode 100644 index 1170fef45..000000000 --- a/src/ssl/info.txt +++ /dev/null @@ -1,66 +0,0 @@ -define SSL_TLS - - -The SSL/TLS code is complex, new, and not yet reviewed, there may be -serious bugs or security issues. - - -uses_tr1 yes - - -tls_client.h -tls_exceptn.h -tls_magic.h -tls_policy.h -tls_record.h -tls_server.h -tls_session_key.h -tls_suites.h - - - -tls_alerts.h -tls_handshake_hash.h -tls_messages.h -tls_reader.h -tls_state.h - - - -c_kex.cpp -cert_req.cpp -cert_ver.cpp -finished.cpp -tls_handshake_hash.cpp -hello.cpp -rec_read.cpp -rec_wri.cpp -s_kex.cpp -tls_client.cpp -tls_policy.cpp -tls_server.cpp -tls_session_key.cpp -tls_state.cpp -tls_suites.cpp - - - -aes -arc4 -asn1 -des -dh -dsa -eme_pkcs -emsa3 -filters -hmac -md5 -prf_ssl3 -prf_tls -rng -rsa -sha1 -ssl3mac -x509cert - diff --git a/src/ssl/rec_read.cpp b/src/ssl/rec_read.cpp deleted file mode 100644 index 4e5b69780..000000000 --- a/src/ssl/rec_read.cpp +++ /dev/null @@ -1,255 +0,0 @@ -/* -* TLS Record Reading -* (C) 2004-2010 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include -#include -#include - -namespace Botan { - -/* -* Reset the state -*/ -void Record_Reader::reset() - { - cipher.reset(); - - delete mac; - mac = 0; - - mac_size = 0; - block_size = 0; - iv_size = 0; - major = minor = 0; - seq_no = 0; - } - -/* -* Set the version to use -*/ -void Record_Reader::set_version(Version_Code version) - { - if(version != SSL_V3 && version != TLS_V10 && version != TLS_V11) - throw Invalid_Argument("Record_Reader: Invalid protocol version"); - - major = (version >> 8) & 0xFF; - minor = (version & 0xFF); - } - -/* -* Set the keys for reading -*/ -void Record_Reader::set_keys(const CipherSuite& suite, const SessionKeys& keys, - Connection_Side side) - { - cipher.reset(); - delete mac; - mac = 0; - - SymmetricKey mac_key, cipher_key; - InitializationVector iv; - - if(side == CLIENT) - { - cipher_key = keys.server_cipher_key(); - iv = keys.server_iv(); - mac_key = keys.server_mac_key(); - } - else - { - cipher_key = keys.client_cipher_key(); - iv = keys.client_iv(); - mac_key = keys.client_mac_key(); - } - - const std::string cipher_algo = suite.cipher_algo(); - const std::string mac_algo = suite.mac_algo(); - - if(have_block_cipher(cipher_algo)) - { - cipher.append(get_cipher( - cipher_algo + "/CBC/NoPadding", - cipher_key, iv, DECRYPTION) - ); - block_size = block_size_of(cipher_algo); - - if(major > 3 || (major == 3 && minor >= 2)) - iv_size = block_size; - else - iv_size = 0; - } - else if(have_stream_cipher(cipher_algo)) - { - cipher.append(get_cipher(cipher_algo, cipher_key, DECRYPTION)); - block_size = 0; - iv_size = 0; - } - else - throw Invalid_Argument("Record_Reader: Unknown cipher " + cipher_algo); - - if(have_hash(mac_algo)) - { - Algorithm_Factory& af = global_state().algorithm_factory(); - - if(major == 3 && minor == 0) - mac = af.make_mac("SSL3-MAC(" + mac_algo + ")"); - else - mac = af.make_mac("HMAC(" + mac_algo + ")"); - - mac->set_key(mac_key); - mac_size = mac->output_length(); - } - else - throw Invalid_Argument("Record_Reader: Unknown hash " + mac_algo); - } - -void Record_Reader::add_input(const byte input[], size_t input_size) - { - input_queue.write(input, input_size); - } - -/* -* Retrieve the next record -*/ -size_t Record_Reader::get_record(byte& msg_type, - MemoryRegion& output) - { - byte header[5] = { 0 }; - - const size_t have_in_queue = input_queue.size(); - - if(have_in_queue < sizeof(header)) - return (sizeof(header) - have_in_queue); - - /* - * We peek first to make sure we have the full record - */ - input_queue.peek(header, sizeof(header)); - - // SSLv2-format client hello? - if(header[0] & 0x80 && header[2] == 1 && header[3] == 3) - { - size_t record_len = make_u16bit(header[0], header[1]) & 0x7FFF; - - if(have_in_queue < record_len + 2) - return (record_len + 2 - have_in_queue); - - msg_type = HANDSHAKE; - output.resize(record_len + 4); - - input_queue.read(&output[2], record_len + 2); - output[0] = CLIENT_HELLO_SSLV2; - output[1] = 0; - output[2] = header[0] & 0x7F; - output[3] = header[1]; - - return 0; - } - - if(header[0] != CHANGE_CIPHER_SPEC && - header[0] != ALERT && - header[0] != HANDSHAKE && - header[0] != APPLICATION_DATA) - { - throw TLS_Exception(UNEXPECTED_MESSAGE, - "Record_Reader: Unknown record type"); - } - - const u16bit version = make_u16bit(header[1], header[2]); - const u16bit record_len = make_u16bit(header[3], header[4]); - - if(major && (header[1] != major || header[2] != minor)) - throw TLS_Exception(PROTOCOL_VERSION, - "Record_Reader: Got unexpected version"); - - // If insufficient data, return without doing anything - if(have_in_queue < (sizeof(header) + record_len)) - return (sizeof(header) + record_len - have_in_queue); - - SecureVector buffer(record_len); - - input_queue.read(header, sizeof(header)); // pull off the header - input_queue.read(&buffer[0], buffer.size()); - - /* - * We are handshaking, no crypto to do so return as-is - * TODO: Check msg_type to confirm a handshake? - */ - if(mac_size == 0) - { - msg_type = header[0]; - output = buffer; - return 0; // got a full record - } - - // Otherwise, decrypt, check MAC, return plaintext - - cipher.process_msg(buffer); - SecureVector plaintext = cipher.read_all(Pipe::LAST_MESSAGE); - - size_t pad_size = 0; - - if(block_size) - { - byte pad_value = plaintext[plaintext.size()-1]; - pad_size = pad_value + 1; - - /* - * Check the padding; if it is wrong, then say we have 0 bytes of - * padding, which should ensure that the MAC check below does not - * suceed. This hides a timing channel. - * - * This particular countermeasure is recommended in the TLS 1.2 - * spec (RFC 5246) in section 6.2.3.2 - */ - if(version == SSL_V3) - { - if(pad_value > block_size) - pad_size = 0; - } - else - { - for(size_t i = 0; i != pad_size; ++i) - if(plaintext[plaintext.size()-i-1] != pad_value) - pad_size = 0; - } - } - - if(plaintext.size() < mac_size + pad_size + iv_size) - throw Decoding_Error("Record_Reader: Record truncated"); - - const size_t mac_offset = plaintext.size() - (mac_size + pad_size); - SecureVector received_mac(&plaintext[mac_offset], - mac_size); - - const u16bit plain_length = plaintext.size() - (mac_size + pad_size + iv_size); - - mac->update_be(seq_no); - mac->update(header[0]); // msg_type - - if(version != SSL_V3) - for(size_t i = 0; i != 2; ++i) - mac->update(get_byte(i, version)); - - mac->update_be(plain_length); - mac->update(&plaintext[iv_size], plain_length); - - ++seq_no; - - SecureVector computed_mac = mac->final(); - - if(received_mac != computed_mac) - throw TLS_Exception(BAD_RECORD_MAC, "Record_Reader: MAC failure"); - - msg_type = header[0]; - - output.resize(plain_length); - copy_mem(&output[0], &plaintext[iv_size], plain_length); - return 0; - } - -} diff --git a/src/ssl/rec_wri.cpp b/src/ssl/rec_wri.cpp deleted file mode 100644 index d3a5c13f7..000000000 --- a/src/ssl/rec_wri.cpp +++ /dev/null @@ -1,270 +0,0 @@ -/* -* TLS Record Writing -* (C) 2004-2010 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include -#include -#include -#include -#include - -namespace Botan { - -/** -* Record_Writer Constructor -*/ -Record_Writer::Record_Writer(std::tr1::function out) : - output_fn(out), - buffer(DEFAULT_BUFFERSIZE) - { - mac = 0; - reset(); - } - -/** -* Reset the state -*/ -void Record_Writer::reset() - { - cipher.reset(); - - delete mac; - mac = 0; - - zeroise(buffer); - buf_pos = 0; - - major = minor = buf_type = 0; - block_size = 0; - mac_size = 0; - iv_size = 0; - - seq_no = 0; - } - -/** -* Set the version to use -*/ -void Record_Writer::set_version(Version_Code version) - { - if(version != SSL_V3 && version != TLS_V10 && version != TLS_V11) - throw Invalid_Argument("Record_Writer: Invalid protocol version"); - - major = (version >> 8) & 0xFF; - minor = (version & 0xFF); - } - -/** -* Set the keys for writing -*/ -void Record_Writer::set_keys(const CipherSuite& suite, const SessionKeys& keys, - Connection_Side side) - { - cipher.reset(); - delete mac; - mac = 0; - - SymmetricKey mac_key, cipher_key; - InitializationVector iv; - - if(side == CLIENT) - { - cipher_key = keys.client_cipher_key(); - iv = keys.client_iv(); - mac_key = keys.client_mac_key(); - } - else - { - cipher_key = keys.server_cipher_key(); - iv = keys.server_iv(); - mac_key = keys.server_mac_key(); - } - - const std::string cipher_algo = suite.cipher_algo(); - const std::string mac_algo = suite.mac_algo(); - - if(have_block_cipher(cipher_algo)) - { - cipher.append(get_cipher( - cipher_algo + "/CBC/NoPadding", - cipher_key, iv, ENCRYPTION) - ); - block_size = block_size_of(cipher_algo); - - if(major > 3 || (major == 3 && minor >= 2)) - iv_size = block_size; - else - iv_size = 0; - } - else if(have_stream_cipher(cipher_algo)) - { - cipher.append(get_cipher(cipher_algo, cipher_key, ENCRYPTION)); - block_size = 0; - iv_size = 0; - } - else - throw Invalid_Argument("Record_Writer: Unknown cipher " + cipher_algo); - - if(have_hash(mac_algo)) - { - Algorithm_Factory& af = global_state().algorithm_factory(); - - if(major == 3 && minor == 0) - mac = af.make_mac("SSL3-MAC(" + mac_algo + ")"); - else - mac = af.make_mac("HMAC(" + mac_algo + ")"); - - mac->set_key(mac_key); - mac_size = mac->output_length(); - } - else - throw Invalid_Argument("Record_Writer: Unknown hash " + mac_algo); - } - -/** -* Send one or more records to the other side -*/ -void Record_Writer::send(byte type, const byte input[], size_t length) - { - if(type != buf_type) - flush(); - - const size_t BUFFER_SIZE = buffer.size(); - buf_type = type; - - // FIXME: compression right here - - buffer.copy(buf_pos, input, length); - if(buf_pos + length >= BUFFER_SIZE) - { - send_record(buf_type, &buffer[0], length); - input += (BUFFER_SIZE - buf_pos); - length -= (BUFFER_SIZE - buf_pos); - while(length >= BUFFER_SIZE) - { - send_record(buf_type, input, BUFFER_SIZE); - input += BUFFER_SIZE; - length -= BUFFER_SIZE; - } - buffer.copy(input, length); - buf_pos = 0; - } - buf_pos += length; - } - -/** -* Split buffer into records, and send them all -*/ -void Record_Writer::flush() - { - const byte* buf_ptr = &buffer[0]; - size_t offset = 0; - - while(offset != buf_pos) - { - size_t record_size = buf_pos - offset; - if(record_size > MAX_PLAINTEXT_SIZE) - record_size = MAX_PLAINTEXT_SIZE; - - send_record(buf_type, buf_ptr + offset, record_size); - offset += record_size; - } - buf_type = 0; - buf_pos = 0; - } - -/** -* Encrypt and send the record -*/ -void Record_Writer::send_record(byte type, const byte buf[], size_t length) - { - if(length >= MAX_COMPRESSED_SIZE) - throw TLS_Exception(INTERNAL_ERROR, - "Record_Writer: Compressed packet is too big"); - - if(mac_size == 0) - send_record(type, major, minor, buf, length); - else - { - mac->update_be(seq_no); - mac->update(type); - - if(major > 3 || (major == 3 && minor != 0)) - { - mac->update(major); - mac->update(minor); - } - - mac->update(get_byte(0, length)); - mac->update(get_byte(1, length)); - mac->update(buf, length); - - SecureVector buf_mac = mac->final(); - - // TODO: This could all use a single buffer - cipher.start_msg(); - - if(iv_size) - { - RandomNumberGenerator& rng = global_state().global_rng(); - - SecureVector random_iv(iv_size); - - rng.randomize(&random_iv[0], random_iv.size()); - - cipher.write(random_iv); - } - - cipher.write(buf, length); - cipher.write(buf_mac); - - if(block_size) - { - const size_t pad_val = - (block_size - (1 + length + buf_mac.size())) % block_size; - - for(size_t i = 0; i != pad_val + 1; ++i) - cipher.write(pad_val); - } - cipher.end_msg(); - - SecureVector output = cipher.read_all(Pipe::LAST_MESSAGE); - - send_record(type, major, minor, &output[0], output.size()); - - seq_no++; - } - } - -/** -* Send a final record packet -*/ -void Record_Writer::send_record(byte type, byte major, byte minor, - const byte out[], size_t length) - { - if(length >= MAX_CIPHERTEXT_SIZE) - throw TLS_Exception(INTERNAL_ERROR, - "Record_Writer: Record is too big"); - - byte header[5] = { type, major, minor, 0 }; - for(size_t i = 0; i != 2; ++i) - header[i+3] = get_byte(i, length); - - output_fn(header, 5); - output_fn(out, length); - } - -/** -* Send an alert -*/ -void Record_Writer::alert(Alert_Level level, Alert_Type type) - { - byte alert[2] = { level, type }; - send(ALERT, alert, sizeof(alert)); - flush(); - } - -} diff --git a/src/ssl/s_kex.cpp b/src/ssl/s_kex.cpp deleted file mode 100644 index 1e7de31d0..000000000 --- a/src/ssl/s_kex.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* -* Server Key Exchange Message -* (C) 2004-2010 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Botan { - -/** -* Create a new Server Key Exchange message -*/ -Server_Key_Exchange::Server_Key_Exchange(RandomNumberGenerator& rng, - Record_Writer& writer, - const Public_Key* kex_key, - const Private_Key* priv_key, - const MemoryRegion& c_random, - const MemoryRegion& s_random, - HandshakeHash& hash) - { - const DH_PublicKey* dh_pub = dynamic_cast(kex_key); - const RSA_PublicKey* rsa_pub = dynamic_cast(kex_key); - - if(dh_pub) - { - params.push_back(dh_pub->get_domain().get_p()); - params.push_back(dh_pub->get_domain().get_g()); - params.push_back(BigInt::decode(dh_pub->public_value())); - } - else if(rsa_pub) - { - params.push_back(rsa_pub->get_n()); - params.push_back(rsa_pub->get_e()); - } - else - throw Invalid_Argument("Bad key for TLS key exchange: not DH or RSA"); - - - std::string padding = ""; - Signature_Format format = IEEE_1363; - - if(priv_key->algo_name() == "RSA") - padding = "EMSA3(TLS.Digest.0)"; - else if(priv_key->algo_name() == "DSA") - { - padding = "EMSA1(SHA-1)"; - format = DER_SEQUENCE; - } - else - throw Invalid_Argument(priv_key->algo_name() + - " is invalid/unknown for TLS signatures"); - - PK_Signer signer(*priv_key, padding, format); - - signer.update(c_random); - signer.update(s_random); - signer.update(serialize_params()); - signature = signer.signature(rng); - - send(writer, hash); - } - -/** -* Serialize a Server Key Exchange message -*/ -SecureVector Server_Key_Exchange::serialize() const - { - SecureVector buf = serialize_params(); - append_tls_length_value(buf, signature, 2); - return buf; - } - -/** -* Serialize the ServerParams structure -*/ -SecureVector Server_Key_Exchange::serialize_params() const - { - SecureVector buf; - - for(size_t i = 0; i != params.size(); ++i) - append_tls_length_value(buf, BigInt::encode(params[i]), 2); - - return buf; - } - -/** -* Deserialize a Server Key Exchange message -*/ -void Server_Key_Exchange::deserialize(const MemoryRegion& buf) - { - if(buf.size() < 6) - throw Decoding_Error("Server_Key_Exchange: Packet corrupted"); - - SecureVector values[4]; - size_t so_far = 0; - - for(size_t i = 0; i != 4; ++i) - { - const u16bit len = make_u16bit(buf[so_far], buf[so_far+1]); - so_far += 2; - - if(len + so_far > buf.size()) - throw Decoding_Error("Server_Key_Exchange: Packet corrupted"); - - values[i].resize(len); - copy_mem(&values[i][0], &buf[so_far], len); - so_far += len; - - if(i == 2 && so_far == buf.size()) - break; - } - - params.push_back(BigInt::decode(values[0])); - params.push_back(BigInt::decode(values[1])); - if(values[3].size()) - { - params.push_back(BigInt::decode(values[2])); - signature = values[3]; - } - else - signature = values[2]; - } - -/** -* Return the public key -*/ -Public_Key* Server_Key_Exchange::key() const - { - if(params.size() == 2) - return new RSA_PublicKey(params[0], params[1]); - else if(params.size() == 3) - return new DH_PublicKey(DL_Group(params[0], params[1]), params[2]); - else - throw Internal_Error("Server_Key_Exchange::key: No key set"); - } - -/** -* Verify a Server Key Exchange message -*/ -bool Server_Key_Exchange::verify(const X509_Certificate& cert, - const MemoryRegion& c_random, - const MemoryRegion& s_random) const - { - - std::auto_ptr key(cert.subject_public_key()); - - std::string padding = ""; - Signature_Format format = IEEE_1363; - - if(key->algo_name() == "RSA") - padding = "EMSA3(TLS.Digest.0)"; - else if(key->algo_name() == "DSA") - { - padding == "EMSA1(SHA-1)"; - format = DER_SEQUENCE; - } - else - throw Invalid_Argument(key->algo_name() + - " is invalid/unknown for TLS signatures"); - - PK_Verifier verifier(*key, padding, format); - - SecureVector params_got = serialize_params(); - verifier.update(c_random); - verifier.update(s_random); - verifier.update(params_got); - - return verifier.check_signature(signature); - } - -} diff --git a/src/ssl/tls_alerts.h b/src/ssl/tls_alerts.h deleted file mode 100644 index 241599aa8..000000000 --- a/src/ssl/tls_alerts.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -* Alert Message -* (C) 2004-2006 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_ALERT_H__ -#define BOTAN_TLS_ALERT_H__ - -#include - -namespace Botan { - -/** -* SSL/TLS Alert Message -*/ -class Alert - { - public: - /** - * @return if this alert is a fatal one or not - */ - bool is_fatal() const { return fatal; } - - /** - * @return type of alert - */ - Alert_Type type() const { return type_code; } - - /** - * Deserialize an Alert message - * @param buf the serialized alert - */ - Alert(const MemoryRegion& buf) - { - if(buf.size() != 2) - throw Decoding_Error("Alert: Bad size for alert message"); - - if(buf[0] == 1) fatal = false; - else if(buf[0] == 2) fatal = true; - else - throw Decoding_Error("Alert: Bad type code for alert level"); - - type_code = static_cast(buf[1]); - } - private: - bool fatal; - Alert_Type type_code; - }; - -} - -#endif diff --git a/src/ssl/tls_client.cpp b/src/ssl/tls_client.cpp deleted file mode 100644 index cfa86881c..000000000 --- a/src/ssl/tls_client.cpp +++ /dev/null @@ -1,499 +0,0 @@ -/* -* TLS Client -* (C) 2004-2011 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include -#include -#include -#include -#include -#include -#include - -namespace Botan { - -namespace { - -/** -* Verify the state transition is allowed -* FIXME: checks are wrong for session reuse (add a flag for that) -*/ -void client_check_state(Handshake_Type new_msg, Handshake_State* state) - { - class State_Transition_Error : public Unexpected_Message - { - public: - State_Transition_Error(const std::string& err) : - Unexpected_Message("State transition error from " + err) {} - }; - - if(new_msg == HELLO_REQUEST) - { - if(state->client_hello) - throw State_Transition_Error("HelloRequest"); - } - else if(new_msg == SERVER_HELLO) - { - if(!state->client_hello || state->server_hello) - throw State_Transition_Error("ServerHello"); - } - else if(new_msg == CERTIFICATE) - { - if(!state->server_hello || state->server_kex || - state->cert_req || state->server_hello_done) - throw State_Transition_Error("ServerCertificate"); - } - else if(new_msg == SERVER_KEX) - { - if(!state->server_hello || state->server_kex || - state->cert_req || state->server_hello_done) - throw State_Transition_Error("ServerKeyExchange"); - } - else if(new_msg == CERTIFICATE_REQUEST) - { - if(!state->server_certs || state->cert_req || state->server_hello_done) - throw State_Transition_Error("CertificateRequest"); - } - else if(new_msg == SERVER_HELLO_DONE) - { - if(!state->server_hello || state->server_hello_done) - throw State_Transition_Error("ServerHelloDone"); - } - else if(new_msg == HANDSHAKE_CCS) - { - if(!state->client_finished || state->server_finished) - throw State_Transition_Error("ServerChangeCipherSpec"); - } - else if(new_msg == FINISHED) - { - if(!state->got_server_ccs) - throw State_Transition_Error("ServerFinished"); - } - else - throw Unexpected_Message("Unexpected message in handshake"); - } - -} - -/** -* TLS Client Constructor -*/ -TLS_Client::TLS_Client(std::tr1::function socket_output_fn, - std::tr1::function process_fn, - const TLS_Policy& policy, - RandomNumberGenerator& rng) : - policy(policy), - rng(rng), - proc_fn(process_fn), - writer(socket_output_fn), - state(0), - active(false) - { - writer.set_version(policy.pref_version()); - - state = new Handshake_State; - state->client_hello = new Client_Hello(rng, writer, policy, state->hash); - } - -void TLS_Client::add_client_cert(const X509_Certificate& cert, - Private_Key* cert_key) - { - certs.push_back(std::make_pair(cert, cert_key)); - } - -/** -* TLS Client Destructor -*/ -TLS_Client::~TLS_Client() - { - close(); - for(size_t i = 0; i != certs.size(); i++) - delete certs[i].second; - delete state; - } - -size_t TLS_Client::received_data(const byte buf[], size_t buf_size) - { - try - { - reader.add_input(buf, buf_size); - - byte rec_type = CONNECTION_CLOSED; - SecureVector record; - - while(!reader.currently_empty()) - { - const size_t bytes_needed = reader.get_record(rec_type, record); - - if(bytes_needed > 0) - return bytes_needed; - - if(rec_type == APPLICATION_DATA) - { - if(active) - { - proc_fn(&record[0], record.size(), NO_ALERT_TYPE); - } - else - { - throw Unexpected_Message("Application data before handshake done"); - } - } - else if(rec_type == HANDSHAKE || rec_type == CHANGE_CIPHER_SPEC) - { - read_handshake(rec_type, record); - } - else if(rec_type == ALERT) - { - Alert alert(record); - - proc_fn(0, 0, alert.type()); - - if(alert.is_fatal() || alert.type() == CLOSE_NOTIFY) - { - if(alert.type() == CLOSE_NOTIFY) - { - writer.alert(WARNING, CLOSE_NOTIFY); - } - - close(FATAL, NO_ALERT_TYPE); - } - } - else - throw Unexpected_Message("Unknown message type received"); - } - - return 0; // on a record boundary - } - catch(TLS_Exception& e) - { - close(FATAL, e.type()); - throw; - } - catch(std::exception& e) - { - close(FATAL, INTERNAL_ERROR); - throw; - } - } - -void TLS_Client::queue_for_sending(const byte buf[], size_t buf_size) - { - if(active) - { - while(!pre_handshake_write_queue.end_of_data()) - { - SecureVector q_buf(1024); - const size_t got = pre_handshake_write_queue.read(&q_buf[0], q_buf.size()); - writer.send(APPLICATION_DATA, &q_buf[0], got); - } - - writer.send(APPLICATION_DATA, buf, buf_size); - writer.flush(); - } - else - pre_handshake_write_queue.write(buf, buf_size); - } - -/** -* Close a TLS connection -*/ -void TLS_Client::close() - { - close(WARNING, CLOSE_NOTIFY); - } - -/** -* Close a TLS connection -*/ -void TLS_Client::close(Alert_Level level, Alert_Type alert_code) - { - if(active) - { - active = false; - - if(alert_code != NO_ALERT_TYPE) - { - try - { - writer.alert(level, alert_code); - writer.flush(); - } - catch(...) { /* swallow it */ } - } - - reader.reset(); - writer.reset(); - } - } - -/** -* Split up and process handshake messages -*/ -void TLS_Client::read_handshake(byte rec_type, - const MemoryRegion& rec_buf) - { - if(rec_type == HANDSHAKE) - state->queue.write(&rec_buf[0], rec_buf.size()); - - while(true) - { - Handshake_Type type = HANDSHAKE_NONE; - SecureVector contents; - - if(rec_type == HANDSHAKE) - { - if(state->queue.size() >= 4) - { - byte head[4] = { 0 }; - state->queue.peek(head, 4); - - const size_t length = make_u32bit(0, head[1], head[2], head[3]); - - if(state->queue.size() >= length + 4) - { - type = static_cast(head[0]); - contents.resize(length); - state->queue.read(head, 4); - state->queue.read(&contents[0], contents.size()); - } - } - } - else if(rec_type == CHANGE_CIPHER_SPEC) - { - if(state->queue.size() == 0 && rec_buf.size() == 1 && rec_buf[0] == 1) - type = HANDSHAKE_CCS; - else - throw Decoding_Error("Malformed ChangeCipherSpec message"); - } - else - throw Decoding_Error("Unknown message type in handshake processing"); - - if(type == HANDSHAKE_NONE) - break; - - process_handshake_msg(type, contents); - - if(type == HANDSHAKE_CCS || !state) - break; - } - } - -/** -* Process a handshake message -*/ -void TLS_Client::process_handshake_msg(Handshake_Type type, - const MemoryRegion& contents) - { - rng.add_entropy(&contents[0], contents.size()); - - if(type == HELLO_REQUEST) - { - if(state == 0) - state = new Handshake_State(); - else - return; - } - - if(state == 0) - throw Unexpected_Message("Unexpected handshake message"); - - if(type != HANDSHAKE_CCS && type != HELLO_REQUEST && type != FINISHED) - { - state->hash.update(static_cast(type)); - const size_t record_length = contents.size(); - for(size_t i = 0; i != 3; i++) - state->hash.update(get_byte(i+1, record_length)); - state->hash.update(contents); - } - - if(type == HELLO_REQUEST) - { - client_check_state(type, state); - - Hello_Request hello_request(contents); - state->client_hello = new Client_Hello(rng, writer, policy, state->hash); - } - else if(type == SERVER_HELLO) - { - client_check_state(type, state); - - state->server_hello = new Server_Hello(contents); - - if(!state->client_hello->offered_suite( - state->server_hello->ciphersuite() - ) - ) - throw TLS_Exception(HANDSHAKE_FAILURE, - "TLS_Client: Server replied with bad ciphersuite"); - - state->version = state->server_hello->version(); - - if(state->version > state->client_hello->version()) - throw TLS_Exception(HANDSHAKE_FAILURE, - "TLS_Client: Server replied with bad version"); - - if(state->version < policy.min_version()) - throw TLS_Exception(PROTOCOL_VERSION, - "TLS_Client: Server is too old for specified policy"); - - writer.set_version(state->version); - reader.set_version(state->version); - - state->suite = CipherSuite(state->server_hello->ciphersuite()); - } - else if(type == CERTIFICATE) - { - client_check_state(type, state); - - if(state->suite.sig_type() == TLS_ALGO_SIGNER_ANON) - throw Unexpected_Message("Recived certificate from anonymous server"); - - state->server_certs = new Certificate(contents); - - peer_certs = state->server_certs->cert_chain(); - if(peer_certs.size() == 0) - throw TLS_Exception(HANDSHAKE_FAILURE, - "TLS_Client: No certificates sent by server"); - - if(!policy.check_cert(peer_certs)) - throw TLS_Exception(BAD_CERTIFICATE, - "TLS_Client: Server certificate is not valid"); - - state->kex_pub = peer_certs[0].subject_public_key(); - - bool is_dsa = false, is_rsa = false; - - if(dynamic_cast(state->kex_pub)) - is_dsa = true; - else if(dynamic_cast(state->kex_pub)) - is_rsa = true; - else - throw TLS_Exception(UNSUPPORTED_CERTIFICATE, - "Unknown key type received in server kex"); - - if((is_dsa && state->suite.sig_type() != TLS_ALGO_SIGNER_DSA) || - (is_rsa && state->suite.sig_type() != TLS_ALGO_SIGNER_RSA)) - throw TLS_Exception(ILLEGAL_PARAMETER, - "Certificate key type did not match ciphersuite"); - } - else if(type == SERVER_KEX) - { - client_check_state(type, state); - - if(state->suite.kex_type() == TLS_ALGO_KEYEXCH_NOKEX) - throw Unexpected_Message("Unexpected key exchange from server"); - - state->server_kex = new Server_Key_Exchange(contents); - - if(state->kex_pub) - delete state->kex_pub; - - state->kex_pub = state->server_kex->key(); - - bool is_dh = false, is_rsa = false; - - if(dynamic_cast(state->kex_pub)) - is_dh = true; - else if(dynamic_cast(state->kex_pub)) - is_rsa = true; - else - throw TLS_Exception(HANDSHAKE_FAILURE, - "Unknown key type received in server kex"); - - if((is_dh && state->suite.kex_type() != TLS_ALGO_KEYEXCH_DH) || - (is_rsa && state->suite.kex_type() != TLS_ALGO_KEYEXCH_RSA)) - throw TLS_Exception(ILLEGAL_PARAMETER, - "Certificate key type did not match ciphersuite"); - - if(state->suite.sig_type() != TLS_ALGO_SIGNER_ANON) - { - if(!state->server_kex->verify(peer_certs[0], - state->client_hello->random(), - state->server_hello->random())) - throw TLS_Exception(DECRYPT_ERROR, - "Bad signature on server key exchange"); - } - } - else if(type == CERTIFICATE_REQUEST) - { - client_check_state(type, state); - - state->cert_req = new Certificate_Req(contents); - state->do_client_auth = true; - } - else if(type == SERVER_HELLO_DONE) - { - client_check_state(type, state); - - state->server_hello_done = new Server_Hello_Done(contents); - - if(state->do_client_auth) - { - std::vector send_certs; - - std::vector types = - state->cert_req->acceptable_types(); - - // FIXME: Fill in useful certs here, if any - state->client_certs = new Certificate(writer, send_certs, - state->hash); - } - - state->client_kex = - new Client_Key_Exchange(rng, writer, state->hash, - state->kex_pub, state->version, - state->client_hello->version()); - - if(state->do_client_auth) - { - Private_Key* key_matching_cert = 0; // FIXME - state->client_verify = new Certificate_Verify(rng, - writer, state->hash, - key_matching_cert); - } - - state->keys = SessionKeys(state->suite, state->version, - state->client_kex->pre_master_secret(), - state->client_hello->random(), - state->server_hello->random()); - - writer.send(CHANGE_CIPHER_SPEC, 1); - writer.flush(); - - writer.set_keys(state->suite, state->keys, CLIENT); - - state->client_finished = new Finished(writer, state->version, CLIENT, - state->keys.master_secret(), - state->hash); - } - else if(type == HANDSHAKE_CCS) - { - client_check_state(type, state); - - reader.set_keys(state->suite, state->keys, CLIENT); - state->got_server_ccs = true; - } - else if(type == FINISHED) - { - client_check_state(type, state); - - state->server_finished = new Finished(contents); - - if(!state->server_finished->verify(state->keys.master_secret(), - state->version, state->hash, SERVER)) - throw TLS_Exception(DECRYPT_ERROR, - "Finished message didn't verify"); - - delete state; - state = 0; - active = true; - } - else - throw Unexpected_Message("Unknown handshake message received"); - } - -} diff --git a/src/ssl/tls_client.h b/src/ssl/tls_client.h deleted file mode 100644 index 6d613be33..000000000 --- a/src/ssl/tls_client.h +++ /dev/null @@ -1,87 +0,0 @@ -/* -* TLS Client -* (C) 2004-2011 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_CLIENT_H__ -#define BOTAN_TLS_CLIENT_H__ - -#include -#include -#include -#include - -namespace Botan { - -/** -* SSL/TLS Client -*/ -class BOTAN_DLL TLS_Client - { - public: - /** - * Set up a new TLS client session - */ - TLS_Client(std::tr1::function socket_output_fn, - std::tr1::function proc_fn, - const TLS_Policy& policy, - RandomNumberGenerator& rng); - - /** - * Inject TLS traffic received from counterparty - - * @return a hint as the how many more bytes we need to process the - current record (this may be 0 if on a record boundary) - */ - size_t received_data(const byte buf[], size_t buf_size); - - /** - * Inject plaintext intended for counterparty - */ - void queue_for_sending(const byte buf[], size_t buf_size); - - void close(); - - bool handshake_complete() const { return active; } - - std::vector peer_cert_chain() const { return peer_certs; } - - void add_client_cert(const X509_Certificate& cert, - Private_Key* cert_key); - - ~TLS_Client(); - private: - void close(Alert_Level, Alert_Type); - - size_t get_pending_socket_input(byte output[], size_t length); - - void initialize(); - void do_handshake(); - - void state_machine(); - void read_handshake(byte, const MemoryRegion&); - void process_handshake_msg(Handshake_Type, const MemoryRegion&); - - const TLS_Policy& policy; - RandomNumberGenerator& rng; - - std::tr1::function proc_fn; - - Record_Writer writer; - Record_Reader reader; - - SecureQueue pre_handshake_write_queue; - - std::vector peer_certs; - std::vector > certs; - - class Handshake_State* state; - //SecureVector session_id; - bool active; - }; - -} - -#endif diff --git a/src/ssl/tls_exceptn.h b/src/ssl/tls_exceptn.h deleted file mode 100644 index 37b9c0d27..000000000 --- a/src/ssl/tls_exceptn.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -* Exceptions -* (C) 2004-2006 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_EXCEPTION_H__ -#define BOTAN_TLS_EXCEPTION_H__ - -#include -#include - -namespace Botan { - -/** -* Exception Base Class -*/ -class BOTAN_DLL TLS_Exception : public Exception - { - public: - Alert_Type type() const throw() { return alert_type; } - - TLS_Exception(Alert_Type type, - const std::string& err_msg = "Unknown error") : - Exception(err_msg), alert_type(type) {} - - private: - Alert_Type alert_type; - }; - -/** -* Unexpected_Message Exception -*/ -struct BOTAN_DLL Unexpected_Message : public TLS_Exception - { - Unexpected_Message(const std::string& err) : - TLS_Exception(UNEXPECTED_MESSAGE, err) {} - }; - -} - -#endif diff --git a/src/ssl/tls_handshake_hash.cpp b/src/ssl/tls_handshake_hash.cpp deleted file mode 100644 index 7c1e2e385..000000000 --- a/src/ssl/tls_handshake_hash.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* -* TLS Handshake Hash -* (C) 2004-2006 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include -#include -#include -#include - -namespace Botan { - -/** -* Return a TLS Handshake Hash -*/ -SecureVector HandshakeHash::final() - { - MD5 md5; - SHA_160 sha1; - - md5.update(data); - sha1.update(data); - - SecureVector output; - output += md5.final(); - output += sha1.final(); - return output; - } - -/** -* Return a SSLv3 Handshake Hash -*/ -SecureVector HandshakeHash::final_ssl3(const MemoryRegion& secret) - { - const byte PAD_INNER = 0x36, PAD_OUTER = 0x5C; - - MD5 md5; - SHA_160 sha1; - - md5.update(data); - sha1.update(data); - - md5.update(secret); - sha1.update(secret); - - for(size_t i = 0; i != 48; ++i) - md5.update(PAD_INNER); - for(size_t i = 0; i != 40; ++i) - sha1.update(PAD_INNER); - - SecureVector inner_md5 = md5.final(), inner_sha1 = sha1.final(); - - md5.update(secret); - sha1.update(secret); - for(size_t i = 0; i != 48; ++i) - md5.update(PAD_OUTER); - for(size_t i = 0; i != 40; ++i) - sha1.update(PAD_OUTER); - md5.update(inner_md5); - sha1.update(inner_sha1); - - SecureVector output; - output += md5.final(); - output += sha1.final(); - return output; - } - -} diff --git a/src/ssl/tls_handshake_hash.h b/src/ssl/tls_handshake_hash.h deleted file mode 100644 index cea612a71..000000000 --- a/src/ssl/tls_handshake_hash.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -* TLS Handshake Hash -* (C) 2004-2006 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_HANDSHAKE_HASH_H__ -#define BOTAN_TLS_HANDSHAKE_HASH_H__ - -#include - -namespace Botan { - -using namespace Botan; - -/** -* TLS Handshake Hash -*/ -class HandshakeHash - { - public: - void update(const byte in[], size_t length) - { data += std::make_pair(in, length); } - - void update(const MemoryRegion& in) - { data += in; } - - void update(byte in) - { data.push_back(in); } - - SecureVector final(); - SecureVector final_ssl3(const MemoryRegion&); - private: - SecureVector data; - }; - -} - -#endif diff --git a/src/ssl/tls_magic.h b/src/ssl/tls_magic.h deleted file mode 100644 index 00898738e..000000000 --- a/src/ssl/tls_magic.h +++ /dev/null @@ -1,192 +0,0 @@ -/* -* SSL/TLS Protocol Constants -* (C) 2004-2010 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_PROTOCOL_MAGIC_H__ -#define BOTAN_TLS_PROTOCOL_MAGIC_H__ - -namespace Botan { - -/** -* Protocol Constants for SSL/TLS -*/ -enum Size_Limits { - MAX_PLAINTEXT_SIZE = 16*1024, - MAX_COMPRESSED_SIZE = MAX_PLAINTEXT_SIZE + 1024, - MAX_CIPHERTEXT_SIZE = MAX_COMPRESSED_SIZE + 1024 -}; - -enum Version_Code { - NO_VERSION_SET = 0x0000, - SSL_V3 = 0x0300, - TLS_V10 = 0x0301, - TLS_V11 = 0x0302 -}; - -enum Connection_Side { CLIENT, SERVER }; - -enum Record_Type { - CONNECTION_CLOSED = 0, - - CHANGE_CIPHER_SPEC = 20, - ALERT = 21, - HANDSHAKE = 22, - APPLICATION_DATA = 23 -}; - -enum Handshake_Type { - HELLO_REQUEST = 0, - CLIENT_HELLO = 1, - CLIENT_HELLO_SSLV2 = 255, // not a wire value - SERVER_HELLO = 2, - CERTIFICATE = 11, - SERVER_KEX = 12, - CERTIFICATE_REQUEST = 13, - SERVER_HELLO_DONE = 14, - CERTIFICATE_VERIFY = 15, - CLIENT_KEX = 16, - FINISHED = 20, - - HANDSHAKE_CCS = 100, - HANDSHAKE_NONE = 101 -}; - -enum Alert_Level { - WARNING = 1, - FATAL = 2 -}; - -enum Alert_Type { - CLOSE_NOTIFY = 0, - UNEXPECTED_MESSAGE = 10, - BAD_RECORD_MAC = 20, - DECRYPTION_FAILED = 21, - RECORD_OVERFLOW = 22, - DECOMPRESSION_FAILURE = 30, - HANDSHAKE_FAILURE = 40, - BAD_CERTIFICATE = 42, - UNSUPPORTED_CERTIFICATE = 43, - CERTIFICATE_REVOKED = 44, - CERTIFICATE_EXPIRED = 45, - CERTIFICATE_UNKNOWN = 46, - ILLEGAL_PARAMETER = 47, - UNKNOWN_CA = 48, - ACCESS_DENIED = 49, - DECODE_ERROR = 50, - DECRYPT_ERROR = 51, - EXPORT_RESTRICTION = 60, - PROTOCOL_VERSION = 70, - INSUFFICIENT_SECURITY = 71, - INTERNAL_ERROR = 80, - USER_CANCELED = 90, - NO_RENEGOTIATION = 100, - - UNKNOWN_PSK_IDENTITY = 115, - - NO_ALERT_TYPE = 0xFFFF -}; - -enum Certificate_Type { - RSA_CERT = 1, - DSS_CERT = 2, - DH_RSA_CERT = 3, - DH_DSS_CERT = 4 -}; - -enum Ciphersuite_Code { - TLS_RSA_WITH_RC4_128_MD5 = 0x0004, - TLS_RSA_WITH_RC4_128_SHA = 0x0005, - - TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A, - TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F, - TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035, - TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003C, - TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x003D, - TLS_RSA_WITH_SEED_CBC_SHA = 0x0096, - - TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013, - TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032, - TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x0038, - TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x0040, - TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = 0x006A, - TLS_DHE_DSS_WITH_SEED_CBC_SHA = 0x0099, - - TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016, - TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033, - TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039, - TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067, - TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B, - TLS_DHE_RSA_WITH_SEED_CBC_SHA = 0x009A, - - TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = 0xC007, - TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC008, - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009, - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A, - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023, - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024, - - TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xC011, - TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = 0xC012, - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013, - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014, - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027, - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028 -}; - -/* -* Form of the ciphersuites broken down by field instead of -* being randomly assigned codepoints. -*/ -enum TLS_Ciphersuite_Algos { - TLS_ALGO_SIGNER_MASK = 0xFF000000, - TLS_ALGO_SIGNER_ANON = 0x01000000, - TLS_ALGO_SIGNER_RSA = 0x02000000, - TLS_ALGO_SIGNER_DSA = 0x03000000, - TLS_ALGO_SIGNER_ECDSA = 0x04000000, - - TLS_ALGO_KEYEXCH_MASK = 0x00FF0000, - TLS_ALGO_KEYEXCH_NOKEX = 0x00010000, - TLS_ALGO_KEYEXCH_RSA = 0x00020000, - TLS_ALGO_KEYEXCH_DH = 0x00030000, - TLS_ALGO_KEYEXCH_ECDH = 0x00040000, - - TLS_ALGO_MAC_MASK = 0x0000FF00, - TLS_ALGO_MAC_MD5 = 0x00000100, - TLS_ALGO_MAC_SHA1 = 0x00000200, - TLS_ALGO_MAC_SHA256 = 0x00000300, - TLS_ALGO_MAC_SHA384 = 0x00000400, - - TLS_ALGO_CIPHER_MASK = 0x000000FF, - TLS_ALGO_CIPHER_RC4_128 = 0x00000001, - TLS_ALGO_CIPHER_3DES_CBC = 0x00000002, - TLS_ALGO_CIPHER_AES128_CBC = 0x00000003, - TLS_ALGO_CIPHER_AES256_CBC = 0x00000004, - TLS_ALGO_CIPHER_SEED_CBC = 0x00000005 -}; - -enum Compression_Algo { - NO_COMPRESSION = 0x00 -}; - -enum TLS_Handshake_Extension_Type { - TLSEXT_SERVER_NAME_INDICATION = 0, - TLSEXT_MAX_FRAGMENT_LENGTH = 1, - TLSEXT_CLIENT_CERT_URL = 2, - TLSEXT_TRUSTED_CA_KEYS = 3, - TLSEXT_TRUNCATED_HMAC = 4, - - TLSEXT_USABLE_ELLIPTIC_CURVES = 10, - TLSEXT_EC_POINT_FORMATS = 11, - - TLSEXT_SRP_IDENTIFIER = 12, - - TLSEXT_CERTIFICATE_TYPES = 9, - TLSEXT_SESSION_TICKET = 35 -}; - -} - -#endif diff --git a/src/ssl/tls_messages.h b/src/ssl/tls_messages.h deleted file mode 100644 index e7eaa56e1..000000000 --- a/src/ssl/tls_messages.h +++ /dev/null @@ -1,297 +0,0 @@ -/* -* TLS Messages -* (C) 2004-2010 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_MESSAGES_H__ -#define BOTAN_TLS_MESSAGES_H__ - -#include -#include -#include -#include -#include -#include -#include - -namespace Botan { - -/** -* TLS Handshake Message Base Class -*/ -class HandshakeMessage - { - public: - void send(Record_Writer&, HandshakeHash&) const; - - virtual Handshake_Type type() const = 0; - - virtual ~HandshakeMessage() {} - private: - HandshakeMessage& operator=(const HandshakeMessage&) { return (*this); } - virtual SecureVector serialize() const = 0; - virtual void deserialize(const MemoryRegion&) = 0; - }; - -/** -* Client Hello Message -*/ -class Client_Hello : public HandshakeMessage - { - public: - Handshake_Type type() const { return CLIENT_HELLO; } - Version_Code version() const { return c_version; } - const SecureVector& session_id() const { return sess_id; } - std::vector ciphersuites() const { return suites; } - std::vector compression_algos() const { return comp_algos; } - - const SecureVector& random() const { return c_random; } - - std::string hostname() const { return requested_hostname; } - - std::string srp_identifier() const { return requested_srp_id; } - - bool offered_suite(u16bit) const; - - Client_Hello(RandomNumberGenerator& rng, - Record_Writer&, const TLS_Policy&, HandshakeHash&); - - Client_Hello(const MemoryRegion& buf, - Handshake_Type type) - { - if(type == CLIENT_HELLO) - deserialize(buf); - else - deserialize_sslv2(buf); - } - - private: - SecureVector serialize() const; - void deserialize(const MemoryRegion&); - void deserialize_sslv2(const MemoryRegion&); - - Version_Code c_version; - SecureVector sess_id, c_random; - std::vector suites; - std::vector comp_algos; - std::string requested_hostname; - std::string requested_srp_id; - }; - -/** -* Client Key Exchange Message -*/ -class Client_Key_Exchange : public HandshakeMessage - { - public: - Handshake_Type type() const { return CLIENT_KEX; } - - SecureVector pre_master_secret() const; - - SecureVector pre_master_secret(RandomNumberGenerator& rng, - const Private_Key* key, - Version_Code version); - - Client_Key_Exchange(RandomNumberGenerator& rng, - Record_Writer& output, - HandshakeHash& hash, - const Public_Key* my_key, - Version_Code using_version, - Version_Code pref_version); - - Client_Key_Exchange(const MemoryRegion& buf, - const CipherSuite& suite, - Version_Code using_version); - private: - SecureVector serialize() const; - void deserialize(const MemoryRegion&); - - SecureVector key_material, pre_master; - bool include_length; - }; - -/** -* Certificate Message -*/ -class Certificate : public HandshakeMessage - { - public: - Handshake_Type type() const { return CERTIFICATE; } - std::vector cert_chain() const { return certs; } - - Certificate(Record_Writer&, const std::vector&, - HandshakeHash&); - Certificate(const MemoryRegion& buf) { deserialize(buf); } - private: - SecureVector serialize() const; - void deserialize(const MemoryRegion&); - std::vector certs; - }; - -/** -* Certificate Request Message -*/ -class Certificate_Req : public HandshakeMessage - { - public: - Handshake_Type type() const { return CERTIFICATE_REQUEST; } - - std::vector acceptable_types() const { return types; } - std::vector acceptable_CAs() const { return names; } - - /* TODO - Certificate_Req(Record_Writer&, HandshakeHash&, - const X509_Certificate&); - */ - Certificate_Req(Record_Writer&, HandshakeHash&, - const std::vector&); - - Certificate_Req(const MemoryRegion& buf) { deserialize(buf); } - private: - SecureVector serialize() const; - void deserialize(const MemoryRegion&); - - std::vector names; - std::vector types; - }; - -/** -* Certificate Verify Message -*/ -class Certificate_Verify : public HandshakeMessage - { - public: - Handshake_Type type() const { return CERTIFICATE_VERIFY; } - - bool verify(const X509_Certificate&, HandshakeHash&); - - Certificate_Verify(RandomNumberGenerator& rng, - Record_Writer&, HandshakeHash&, - const Private_Key*); - - Certificate_Verify(const MemoryRegion& buf) { deserialize(buf); } - private: - SecureVector serialize() const; - void deserialize(const MemoryRegion&); - - SecureVector signature; - }; - -/** -* Finished Message -*/ -class Finished : public HandshakeMessage - { - public: - Handshake_Type type() const { return FINISHED; } - - bool verify(const MemoryRegion&, Version_Code, - const HandshakeHash&, Connection_Side); - - Finished(Record_Writer&, Version_Code, Connection_Side, - const MemoryRegion&, HandshakeHash&); - Finished(const MemoryRegion& buf) { deserialize(buf); } - private: - SecureVector serialize() const; - void deserialize(const MemoryRegion&); - - SecureVector compute_verify(const MemoryRegion&, - HandshakeHash, Connection_Side, - Version_Code); - - Connection_Side side; - SecureVector verification_data; - }; - -/** -* Hello Request Message -*/ -class Hello_Request : public HandshakeMessage - { - public: - Handshake_Type type() const { return HELLO_REQUEST; } - - Hello_Request(Record_Writer&); - Hello_Request(const MemoryRegion& buf) { deserialize(buf); } - private: - SecureVector serialize() const; - void deserialize(const MemoryRegion&); - }; - -/** -* Server Hello Message -*/ -class Server_Hello : public HandshakeMessage - { - public: - Handshake_Type type() const { return SERVER_HELLO; } - Version_Code version() { return s_version; } - const SecureVector& session_id() const { return sess_id; } - u16bit ciphersuite() const { return suite; } - byte compression_algo() const { return comp_algo; } - - const SecureVector& random() const { return s_random; } - - Server_Hello(RandomNumberGenerator& rng, - Record_Writer&, const TLS_Policy&, - const std::vector&, - const Client_Hello&, Version_Code, HandshakeHash&); - - Server_Hello(const MemoryRegion& buf) { deserialize(buf); } - private: - SecureVector serialize() const; - void deserialize(const MemoryRegion&); - - Version_Code s_version; - SecureVector sess_id, s_random; - u16bit suite; - byte comp_algo; - }; - -/** -* Server Key Exchange Message -*/ -class Server_Key_Exchange : public HandshakeMessage - { - public: - Handshake_Type type() const { return SERVER_KEX; } - Public_Key* key() const; - - bool verify(const X509_Certificate&, const MemoryRegion&, - const MemoryRegion&) const; - - Server_Key_Exchange(RandomNumberGenerator& rng, - Record_Writer&, const Public_Key*, - const Private_Key*, const MemoryRegion&, - const MemoryRegion&, HandshakeHash&); - - Server_Key_Exchange(const MemoryRegion& buf) { deserialize(buf); } - private: - SecureVector serialize() const; - SecureVector serialize_params() const; - void deserialize(const MemoryRegion&); - - std::vector params; - SecureVector signature; - }; - -/** -* Server Hello Done Message -*/ -class Server_Hello_Done : public HandshakeMessage - { - public: - Handshake_Type type() const { return SERVER_HELLO_DONE; } - - Server_Hello_Done(Record_Writer&, HandshakeHash&); - Server_Hello_Done(const MemoryRegion& buf) { deserialize(buf); } - private: - SecureVector serialize() const; - void deserialize(const MemoryRegion&); - }; - -} - -#endif diff --git a/src/ssl/tls_policy.cpp b/src/ssl/tls_policy.cpp deleted file mode 100644 index b73ff7850..000000000 --- a/src/ssl/tls_policy.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* -* Policies for TLS -* (C) 2004-2010 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include -#include - -namespace Botan { - -/* -* Return allowed ciphersuites -*/ -std::vector TLS_Policy::ciphersuites() const - { - return suite_list(allow_static_rsa(), allow_edh_rsa(), allow_edh_dsa()); - } - -/* -* Return allowed ciphersuites -*/ -std::vector TLS_Policy::suite_list(bool use_rsa, - bool use_edh_rsa, - bool use_edh_dsa) const - { - std::vector suites; - - if(use_edh_dsa) - { - suites.push_back(TLS_DHE_DSS_WITH_AES_256_CBC_SHA); - suites.push_back(TLS_DHE_DSS_WITH_AES_128_CBC_SHA); - suites.push_back(TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA); - suites.push_back(TLS_DHE_DSS_WITH_SEED_CBC_SHA); - } - - if(use_edh_rsa) - { - suites.push_back(TLS_DHE_RSA_WITH_AES_256_CBC_SHA); - suites.push_back(TLS_DHE_RSA_WITH_AES_128_CBC_SHA); - suites.push_back(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA); - suites.push_back(TLS_DHE_RSA_WITH_SEED_CBC_SHA); - } - - if(use_rsa) - { - suites.push_back(TLS_RSA_WITH_AES_256_CBC_SHA); - suites.push_back(TLS_RSA_WITH_AES_128_CBC_SHA); - suites.push_back(TLS_RSA_WITH_3DES_EDE_CBC_SHA); - suites.push_back(TLS_RSA_WITH_SEED_CBC_SHA); - suites.push_back(TLS_RSA_WITH_RC4_128_SHA); - suites.push_back(TLS_RSA_WITH_RC4_128_MD5); - } - - if(suites.size() == 0) - throw TLS_Exception(INTERNAL_ERROR, - "TLS_Policy error: All ciphersuites disabled"); - - return suites; - } - -/* -* Return allowed compression algorithms -*/ -std::vector TLS_Policy::compression() const - { - std::vector algs; - algs.push_back(NO_COMPRESSION); - return algs; - } - -/* -* Choose which ciphersuite to use -*/ -u16bit TLS_Policy::choose_suite(const std::vector& c_suites, - bool have_rsa, - bool have_dsa) const - { - bool use_static_rsa = allow_static_rsa() && have_rsa; - bool use_edh_rsa = allow_edh_rsa() && have_rsa; - bool use_edh_dsa = allow_edh_dsa() && have_dsa; - - std::vector s_suites = suite_list(use_static_rsa, use_edh_rsa, - use_edh_dsa); - - for(size_t i = 0; i != s_suites.size(); ++i) - for(size_t j = 0; j != c_suites.size(); ++j) - if(s_suites[i] == c_suites[j]) - return s_suites[i]; - - return 0; - } - -/* -* Choose which compression algorithm to use -*/ -byte TLS_Policy::choose_compression(const std::vector& c_comp) const - { - std::vector s_comp = compression(); - - for(size_t i = 0; i != s_comp.size(); ++i) - for(size_t j = 0; j != c_comp.size(); ++j) - if(s_comp[i] == c_comp[j]) - return s_comp[i]; - - return NO_COMPRESSION; - } - -/* -* Return the group to use for empheral DH -*/ -DL_Group TLS_Policy::dh_group() const - { - return DL_Group("modp/ietf/1024"); - } - -} diff --git a/src/ssl/tls_policy.h b/src/ssl/tls_policy.h deleted file mode 100644 index 461164d2f..000000000 --- a/src/ssl/tls_policy.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -* Policies -* (C) 2004-2006 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_POLICY_H__ -#define BOTAN_TLS_POLICY_H__ - -#include -#include -#include -#include - -namespace Botan { - -/** -* TLS Policy Base Class -* Inherit and overload as desired to suite local policy concerns -*/ -class BOTAN_DLL TLS_Policy - { - public: - std::vector ciphersuites() const; - virtual std::vector compression() const; - - virtual u16bit choose_suite(const std::vector& client_suites, - bool rsa_ok, - bool dsa_ok) const; - - virtual byte choose_compression(const std::vector& client) const; - - virtual bool allow_static_rsa() const { return true; } - virtual bool allow_edh_rsa() const { return true; } - virtual bool allow_edh_dsa() const { return true; } - virtual bool require_client_auth() const { return false; } - - virtual DL_Group dh_group() const; - virtual size_t rsa_export_keysize() const { return 512; } - - /* - * @return the minimum version that we will negotiate - */ - virtual Version_Code min_version() const { return SSL_V3; } - - /* - * @return the version we would prefer to negotiate - */ - virtual Version_Code pref_version() const { return TLS_V11; } - - virtual bool check_cert(const std::vector& cert_chain) const = 0; - - virtual ~TLS_Policy() {} - private: - virtual std::vector suite_list(bool use_rsa, - bool use_edh_rsa, - bool use_edh_dsa) const; - }; - -} - -#endif diff --git a/src/ssl/tls_reader.h b/src/ssl/tls_reader.h deleted file mode 100644 index 3a45235b5..000000000 --- a/src/ssl/tls_reader.h +++ /dev/null @@ -1,186 +0,0 @@ -/* -* TLS Data Reader -* (C) 2010 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_READER_H__ -#define BOTAN_TLS_READER_H__ - -#include -#include - -namespace Botan { - -/** -* Helper class for decoding TLS protocol messages -*/ -class TLS_Data_Reader - { - public: - TLS_Data_Reader(const MemoryRegion& buf_in) : - buf(buf_in), offset(0) {} - - size_t remaining_bytes() const - { - return buf.size() - offset; - } - - bool has_remaining() const - { - return (remaining_bytes() > 0); - } - - void discard_next(size_t bytes) - { - assert_at_least(bytes); - offset += bytes; - } - - u16bit get_u16bit() - { - assert_at_least(2); - u16bit result = make_u16bit(buf[offset], buf[offset+1]); - offset += 2; - return result; - } - - byte get_byte() - { - assert_at_least(1); - byte result = buf[offset]; - offset += 1; - return result; - } - - template - Container get_elem(size_t num_elems) - { - assert_at_least(num_elems * sizeof(T)); - - Container result(num_elems); - - for(size_t i = 0; i != num_elems; ++i) - result[i] = load_be(&buf[offset], i); - - offset += num_elems * sizeof(T); - - return result; - } - - template - SecureVector get_range(size_t len_bytes, - size_t min_elems, - size_t max_elems) - { - const size_t num_elems = - get_num_elems(len_bytes, sizeof(T), min_elems, max_elems); - - return get_elem >(num_elems); - } - - template - std::vector get_range_vector(size_t len_bytes, - size_t min_elems, - size_t max_elems) - { - const size_t num_elems = - get_num_elems(len_bytes, sizeof(T), min_elems, max_elems); - - return get_elem >(num_elems); - } - - template - SecureVector get_fixed(size_t size) - { - return get_elem >(size); - } - - private: - size_t get_length_field(size_t len_bytes) - { - assert_at_least(len_bytes); - - if(len_bytes == 1) - return get_byte(); - else if(len_bytes == 2) - return get_u16bit(); - - throw Decoding_Error("TLS_Data_Reader: Bad length size"); - } - - size_t get_num_elems(size_t len_bytes, - size_t T_size, - size_t min_elems, - size_t max_elems) - { - const size_t byte_length = get_length_field(len_bytes); - - if(byte_length % T_size != 0) - throw Decoding_Error("TLS_Data_Reader: Size isn't multiple of T"); - - const size_t num_elems = byte_length / T_size; - - if(num_elems < min_elems || num_elems > max_elems) - throw Decoding_Error("TLS_Data_Reader: Range outside paramaters"); - - return num_elems; - } - - void assert_at_least(size_t n) const - { - if(buf.size() - offset < n) - throw Decoding_Error("TLS_Data_Reader: Corrupt packet"); - } - - const MemoryRegion& buf; - size_t offset; - }; - -/** -* Helper function for encoding length-tagged vectors -*/ -template -void append_tls_length_value(MemoryRegion& buf, - const T* vals, - size_t vals_size, - size_t tag_size) - { - const size_t T_size = sizeof(T); - const size_t val_bytes = T_size * vals_size; - - if(tag_size != 1 && tag_size != 2) - throw std::invalid_argument("append_tls_length_value: invalid tag size"); - - if((tag_size == 1 && val_bytes > 255) || - (tag_size == 2 && val_bytes > 65535)) - throw std::invalid_argument("append_tls_length_value: value too large"); - - for(size_t i = 0; i != tag_size; ++i) - buf.push_back(get_byte(sizeof(val_bytes)-tag_size+i, val_bytes)); - - for(size_t i = 0; i != vals_size; ++i) - for(size_t j = 0; j != T_size; ++j) - buf.push_back(get_byte(j, vals[i])); - } - -template -void append_tls_length_value(MemoryRegion& buf, - const MemoryRegion& vals, - size_t tag_size) - { - append_tls_length_value(buf, &vals[0], vals.size(), tag_size); - } - -template -void append_tls_length_value(MemoryRegion& buf, - const std::vector& vals, - size_t tag_size) - { - append_tls_length_value(buf, &vals[0], vals.size(), tag_size); - } - -} - -#endif diff --git a/src/ssl/tls_record.h b/src/ssl/tls_record.h deleted file mode 100644 index 6d5dd057d..000000000 --- a/src/ssl/tls_record.h +++ /dev/null @@ -1,119 +0,0 @@ -/* -* TLS Record Handling -* (C) 2004-2010 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_RECORDS_H__ -#define BOTAN_TLS_RECORDS_H__ - -#include -#include -#include -#include -#include -#include - -#if defined(BOTAN_USE_STD_TR1) - -#if defined(BOTAN_BUILD_COMPILER_IS_MSVC) - #include -#else - #include -#endif - -#elif defined(BOTAN_USE_BOOST_TR1) - #include -#else - #error "No TR1 library defined for use" -#endif - -namespace Botan { - -using namespace std::tr1::placeholders; - -/** -* TLS Record Writer -*/ -class BOTAN_DLL Record_Writer - { - public: - void send(byte type, const byte input[], size_t length); - void send(byte type, byte val) { send(type, &val, 1); } - - void flush(); - - void alert(Alert_Level, Alert_Type); - - void set_keys(const CipherSuite&, const SessionKeys&, Connection_Side); - - void set_version(Version_Code); - - void reset(); - - Record_Writer(std::tr1::function output_fn); - - ~Record_Writer() { delete mac; } - private: - void send_record(byte type, const byte input[], size_t length); - void send_record(byte type, byte major, byte minor, - const byte input[], size_t length); - - std::tr1::function output_fn; - Pipe cipher; - MessageAuthenticationCode* mac; - - SecureVector buffer; - size_t buf_pos; - - size_t block_size, mac_size, iv_size; - - u64bit seq_no; - byte major, minor, buf_type; - }; - -/** -* TLS Record Reader -*/ -class BOTAN_DLL Record_Reader - { - public: - void add_input(const byte input[], size_t input_size); - - /** - * @param msg_type (output variable) - * @param buffer (output variable) - * @return Number of bytes still needed (minimum), or 0 if success - */ - size_t get_record(byte& msg_type, - MemoryRegion& buffer); - - SecureVector get_record(byte& msg_type); - - void set_keys(const CipherSuite& suite, - const SessionKeys& keys, - Connection_Side side); - - void set_version(Version_Code version); - - void reset(); - - bool currently_empty() const { return input_queue.size() == 0; } - - Record_Reader() { mac = 0; reset(); } - - ~Record_Reader() { delete mac; } - private: - SecureQueue input_queue; - - Pipe cipher; - MessageAuthenticationCode* mac; - size_t block_size, mac_size, iv_size; - u64bit seq_no; - byte major, minor; - }; - -} - -#endif diff --git a/src/ssl/tls_server.cpp b/src/ssl/tls_server.cpp deleted file mode 100644 index 8964be3d7..000000000 --- a/src/ssl/tls_server.cpp +++ /dev/null @@ -1,494 +0,0 @@ -/* -* TLS Server -* (C) 2004-2010 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include -#include -#include -#include -#include -#include - -namespace Botan { - -namespace { - -/* -* Choose what version to respond with -*/ -Version_Code choose_version(Version_Code client, Version_Code minimum) - { - if(client < minimum) - throw TLS_Exception(PROTOCOL_VERSION, - "Client version is unacceptable by policy"); - - if(client == SSL_V3 || client == TLS_V10 || client == TLS_V11) - return client; - return TLS_V11; - } - -// FIXME: checks are wrong for session reuse (add a flag for that) -/* -* Verify the state transition is allowed -*/ -void server_check_state(Handshake_Type new_msg, Handshake_State* state) - { - class State_Transition_Error : public Unexpected_Message - { - public: - State_Transition_Error(const std::string& err) : - Unexpected_Message("State transition error from " + err) {} - }; - - if(new_msg == CLIENT_HELLO || new_msg == CLIENT_HELLO_SSLV2) - { - if(state->server_hello) - throw State_Transition_Error("ClientHello"); - } - else if(new_msg == CERTIFICATE) - { - if(!state->do_client_auth || !state->cert_req || - !state->server_hello_done || state->client_kex) - throw State_Transition_Error("ClientCertificate"); - } - else if(new_msg == CLIENT_KEX) - { - if(!state->server_hello_done || state->client_verify || - state->got_client_ccs) - throw State_Transition_Error("ClientKeyExchange"); - } - else if(new_msg == CERTIFICATE_VERIFY) - { - if(!state->cert_req || !state->client_certs || !state->client_kex || - state->got_client_ccs) - throw State_Transition_Error("CertificateVerify"); - } - else if(new_msg == HANDSHAKE_CCS) - { - if(!state->client_kex || state->client_finished) - throw State_Transition_Error("ClientChangeCipherSpec"); - } - else if(new_msg == FINISHED) - { - if(!state->got_client_ccs) - throw State_Transition_Error("ClientFinished"); - } - else - throw Unexpected_Message("Unexpected message in handshake"); - } - -} - -/* -* TLS Server Constructor -*/ -TLS_Server::TLS_Server(std::tr1::function input_fn, - std::tr1::function output_fn, - const TLS_Policy& policy, - RandomNumberGenerator& rng, - const X509_Certificate& cert, - const Private_Key& cert_key) : - input_fn(input_fn), - policy(policy), - rng(rng), - writer(output_fn) - { - state = 0; - - cert_chain.push_back(cert); - private_key = PKCS8::copy_key(cert_key, rng); - - try { - active = false; - writer.set_version(TLS_V10); - do_handshake(); - active = true; - } - catch(std::exception& e) - { - if(state) - { - delete state; - state = 0; - } - - writer.alert(FATAL, HANDSHAKE_FAILURE); - throw Stream_IO_Error(std::string("TLS_Server: Handshake failed: ") + - e.what()); - } - } - -/* -* TLS Server Destructor -*/ -TLS_Server::~TLS_Server() - { - close(); - delete private_key; - delete state; - } - -/* -* Return the peer's certificate chain -*/ -std::vector TLS_Server::peer_cert_chain() const - { - return peer_certs; - } - -/* -* Write to a TLS connection -*/ -void TLS_Server::write(const byte buf[], size_t length) - { - if(!active) - throw Internal_Error("TLS_Server::write called while closed"); - - writer.send(APPLICATION_DATA, buf, length); - } - -/* -* Read from a TLS connection -*/ -size_t TLS_Server::read(byte out[], size_t length) - { - if(!active) - throw Internal_Error("TLS_Server::read called while closed"); - - writer.flush(); - - while(read_buf.size() == 0) - { - state_machine(); - if(active == false) - break; - } - - size_t got = std::min(read_buf.size(), length); - read_buf.read(out, got); - return got; - } - -/* -* Check connection status -*/ -bool TLS_Server::is_closed() const - { - if(!active) - return true; - return false; - } - -/* -* Close a TLS connection -*/ -void TLS_Server::close() - { - close(WARNING, CLOSE_NOTIFY); - } - -/* -* Close a TLS connection -*/ -void TLS_Server::close(Alert_Level level, Alert_Type alert_code) - { - if(active) - { - try { - active = false; - writer.alert(level, alert_code); - writer.flush(); - } - catch(...) {} - } - } - -/* -* Iterate the TLS state machine -*/ -void TLS_Server::state_machine() - { - byte rec_type = CONNECTION_CLOSED; - SecureVector record(1024); - - size_t bytes_needed = reader.get_record(rec_type, record); - - while(bytes_needed) - { - size_t to_get = std::min(record.size(), bytes_needed); - size_t got = input_fn(&record[0], to_get); - - if(got == 0) - { - rec_type = CONNECTION_CLOSED; - break; - } - - reader.add_input(&record[0], got); - - bytes_needed = reader.get_record(rec_type, record); - } - - if(rec_type == CONNECTION_CLOSED) - { - active = false; - reader.reset(); - writer.reset(); - } - else if(rec_type == APPLICATION_DATA) - { - if(active) - read_buf.write(&record[0], record.size()); - else - throw Unexpected_Message("Application data before handshake done"); - } - else if(rec_type == HANDSHAKE || rec_type == CHANGE_CIPHER_SPEC) - read_handshake(rec_type, record); - else if(rec_type == ALERT) - { - Alert alert(record); - - if(alert.is_fatal() || alert.type() == CLOSE_NOTIFY) - { - if(alert.type() == CLOSE_NOTIFY) - writer.alert(WARNING, CLOSE_NOTIFY); - - reader.reset(); - writer.reset(); - active = false; - } - } - else - throw Unexpected_Message("Unknown message type received"); - } - -/* -* Split up and process handshake messages -*/ -void TLS_Server::read_handshake(byte rec_type, - const MemoryRegion& rec_buf) - { - if(rec_type == HANDSHAKE) - { - if(!state) - state = new Handshake_State; - state->queue.write(&rec_buf[0], rec_buf.size()); - } - - while(true) - { - Handshake_Type type = HANDSHAKE_NONE; - SecureVector contents; - - if(rec_type == HANDSHAKE) - { - if(state->queue.size() >= 4) - { - byte head[4] = { 0 }; - state->queue.peek(head, 4); - - const size_t length = make_u32bit(0, head[1], head[2], head[3]); - - if(state->queue.size() >= length + 4) - { - type = static_cast(head[0]); - contents.resize(length); - state->queue.read(head, 4); - state->queue.read(&contents[0], contents.size()); - } - } - } - else if(rec_type == CHANGE_CIPHER_SPEC) - { - if(state->queue.size() == 0 && rec_buf.size() == 1 && rec_buf[0] == 1) - type = HANDSHAKE_CCS; - else - throw Decoding_Error("Malformed ChangeCipherSpec message"); - } - else - throw Decoding_Error("Unknown message type in handshake processing"); - - if(type == HANDSHAKE_NONE) - break; - - process_handshake_msg(type, contents); - - if(type == HANDSHAKE_CCS || !state) - break; - } - } - -/* -* Process a handshake message -*/ -void TLS_Server::process_handshake_msg(Handshake_Type type, - const MemoryRegion& contents) - { - rng.add_entropy(&contents[0], contents.size()); - - if(state == 0) - throw Unexpected_Message("Unexpected handshake message"); - - if(type != HANDSHAKE_CCS && type != FINISHED) - { - if(type != CLIENT_HELLO_SSLV2) - { - state->hash.update(static_cast(type)); - - const size_t record_length = contents.size(); - for(size_t i = 0; i != 3; i++) - state->hash.update(get_byte(i+1, record_length)); - } - - state->hash.update(contents); - } - - if(type == CLIENT_HELLO || type == CLIENT_HELLO_SSLV2) - { - server_check_state(type, state); - - state->client_hello = new Client_Hello(contents, type); - - client_requested_hostname = state->client_hello->hostname(); - - state->version = choose_version(state->client_hello->version(), - policy.min_version()); - - writer.set_version(state->version); - reader.set_version(state->version); - - state->server_hello = new Server_Hello(rng, writer, - policy, cert_chain, - *(state->client_hello), - state->version, state->hash); - - state->suite = CipherSuite(state->server_hello->ciphersuite()); - - if(state->suite.sig_type() != TLS_ALGO_SIGNER_ANON) - { - // FIXME: should choose certs based on sig type - state->server_certs = new Certificate(writer, cert_chain, - state->hash); - } - - state->kex_priv = PKCS8::copy_key(*private_key, rng); - if(state->suite.kex_type() != TLS_ALGO_KEYEXCH_NOKEX) - { - if(state->suite.kex_type() == TLS_ALGO_KEYEXCH_RSA) - { - state->kex_priv = new RSA_PrivateKey(rng, - policy.rsa_export_keysize()); - } - else if(state->suite.kex_type() == TLS_ALGO_KEYEXCH_DH) - { - state->kex_priv = new DH_PrivateKey(rng, policy.dh_group()); - } - else - throw Internal_Error("TLS_Server: Unknown ciphersuite kex type"); - - state->server_kex = - new Server_Key_Exchange(rng, writer, - state->kex_priv, private_key, - state->client_hello->random(), - state->server_hello->random(), - state->hash); - } - - if(policy.require_client_auth()) - { - state->do_client_auth = true; - throw Internal_Error("Client auth not implemented"); - // FIXME: send client auth request here - } - - state->server_hello_done = new Server_Hello_Done(writer, state->hash); - } - else if(type == CERTIFICATE) - { - server_check_state(type, state); - // FIXME: process this - } - else if(type == CLIENT_KEX) - { - server_check_state(type, state); - - state->client_kex = new Client_Key_Exchange(contents, state->suite, - state->version); - - SecureVector pre_master = - state->client_kex->pre_master_secret(rng, state->kex_priv, - state->server_hello->version()); - - state->keys = SessionKeys(state->suite, state->version, pre_master, - state->client_hello->random(), - state->server_hello->random()); - } - else if(type == CERTIFICATE_VERIFY) - { - server_check_state(type, state); - // FIXME: process this - } - else if(type == HANDSHAKE_CCS) - { - server_check_state(type, state); - - reader.set_keys(state->suite, state->keys, SERVER); - state->got_client_ccs = true; - } - else if(type == FINISHED) - { - server_check_state(type, state); - - state->client_finished = new Finished(contents); - - if(!state->client_finished->verify(state->keys.master_secret(), - state->version, state->hash, CLIENT)) - throw TLS_Exception(DECRYPT_ERROR, - "Finished message didn't verify"); - - state->hash.update(static_cast(type)); - - const size_t record_length = contents.size(); - for(size_t i = 0; i != 3; i++) - state->hash.update(get_byte(i+1, record_length)); - - state->hash.update(contents); - - writer.send(CHANGE_CIPHER_SPEC, 1); - writer.flush(); - - writer.set_keys(state->suite, state->keys, SERVER); - - state->server_finished = new Finished(writer, state->version, SERVER, - state->keys.master_secret(), - state->hash); - - delete state; - state = 0; - active = true; - } - else - throw Unexpected_Message("Unknown handshake message received"); - } - -/* -* Perform a server-side TLS handshake -*/ -void TLS_Server::do_handshake() - { - while(true) - { - if(active && !state) - break; - - state_machine(); - - if(!active && !state) - throw TLS_Exception(HANDSHAKE_FAILURE, "TLS_Server: Handshake failed"); - } - } - -} diff --git a/src/ssl/tls_server.h b/src/ssl/tls_server.h deleted file mode 100644 index 510ad15a7..000000000 --- a/src/ssl/tls_server.h +++ /dev/null @@ -1,76 +0,0 @@ -/* -* TLS Server -* (C) 2004-2011 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_SERVER_H__ -#define BOTAN_TLS_SERVER_H__ - -#include -#include -#include - -namespace Botan { - -/** -* TLS Server -*/ -class BOTAN_DLL TLS_Server - { - public: - size_t read(byte buf[], size_t buf_len); - void write(const byte buf[], size_t buf_len); - - std::vector peer_cert_chain() const; - - std::string requested_hostname() const - { return client_requested_hostname; } - - void close(); - bool is_closed() const; - - /* - * FIXME: support cert chains (!) - * FIXME: support anonymous servers - */ - TLS_Server(std::tr1::function input_fn, - std::tr1::function output_fn, - const TLS_Policy& policy, - RandomNumberGenerator& rng, - const X509_Certificate& cert, - const Private_Key& cert_key); - - ~TLS_Server(); - private: - void close(Alert_Level, Alert_Type); - - void do_handshake(); - void state_machine(); - void read_handshake(byte, const MemoryRegion&); - - void process_handshake_msg(Handshake_Type, const MemoryRegion&); - - std::tr1::function input_fn; - - const TLS_Policy& policy; - RandomNumberGenerator& rng; - - Record_Writer writer; - Record_Reader reader; - - // FIXME: rename to match TLS_Client - std::vector cert_chain, peer_certs; - Private_Key* private_key; - - class Handshake_State* state; - SecureVector session_id; - SecureQueue read_buf; - std::string client_requested_hostname; - bool active; - }; - -} - -#endif diff --git a/src/ssl/tls_session_key.cpp b/src/ssl/tls_session_key.cpp deleted file mode 100644 index 7c75d1758..000000000 --- a/src/ssl/tls_session_key.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* -* TLS Session Key -* (C) 2004-2006 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include -#include -#include -#include - -namespace Botan { - -/** -* Return the client cipher key -*/ -SymmetricKey SessionKeys::client_cipher_key() const - { - return c_cipher; - } - -/** -* Return the server cipher key -*/ -SymmetricKey SessionKeys::server_cipher_key() const - { - return s_cipher; - } - -/** -* Return the client MAC key -*/ -SymmetricKey SessionKeys::client_mac_key() const - { - return c_mac; - } - -/** -* Return the server MAC key -*/ -SymmetricKey SessionKeys::server_mac_key() const - { - return s_mac; - } - -/** -* Return the client cipher IV -*/ -InitializationVector SessionKeys::client_iv() const - { - return c_iv; - } - -/** -* Return the server cipher IV -*/ -InitializationVector SessionKeys::server_iv() const - { - return s_iv; - } - -/** -* Return the TLS master secret -*/ -SecureVector SessionKeys::master_secret() const - { - return master_sec; - } - -/** -* Generate SSLv3 session keys -*/ -SymmetricKey SessionKeys::ssl3_keygen(size_t prf_gen, - const MemoryRegion& pre_master, - const MemoryRegion& client_random, - const MemoryRegion& server_random) - { - SSL3_PRF prf; - - SecureVector salt; - salt += client_random; - salt += server_random; - - master_sec = prf.derive_key(48, pre_master, salt); - - salt.clear(); - salt += server_random; - salt += client_random; - - return prf.derive_key(prf_gen, master_sec, salt); - } - -/** -* Generate TLS 1.0 session keys -*/ -SymmetricKey SessionKeys::tls1_keygen(size_t prf_gen, - const MemoryRegion& pre_master, - const MemoryRegion& client_random, - const MemoryRegion& server_random) - { - const byte MASTER_SECRET_MAGIC[] = { - 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, - 0x74 }; - const byte KEY_GEN_MAGIC[] = { - 0x6B, 0x65, 0x79, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6E, 0x73, 0x69, 0x6F, - 0x6E }; - - TLS_PRF prf; - - SecureVector salt; - salt += std::make_pair(MASTER_SECRET_MAGIC, sizeof(MASTER_SECRET_MAGIC)); - salt += client_random; - salt += server_random; - - master_sec = prf.derive_key(48, pre_master, salt); - - salt.clear(); - salt += std::make_pair(KEY_GEN_MAGIC, sizeof(KEY_GEN_MAGIC)); - salt += server_random; - salt += client_random; - - return prf.derive_key(prf_gen, master_sec, salt); - } - -/** -* SessionKeys Constructor -*/ -SessionKeys::SessionKeys(const CipherSuite& suite, Version_Code version, - const MemoryRegion& pre_master_secret, - const MemoryRegion& c_random, - const MemoryRegion& s_random) - { - if(version != SSL_V3 && version != TLS_V10 && version != TLS_V11) - throw Invalid_Argument("SessionKeys: Unknown version code"); - - const size_t mac_keylen = output_length_of(suite.mac_algo()); - const size_t cipher_keylen = suite.cipher_keylen(); - - size_t cipher_ivlen = 0; - if(have_block_cipher(suite.cipher_algo())) - cipher_ivlen = block_size_of(suite.cipher_algo()); - - const size_t prf_gen = 2 * (mac_keylen + cipher_keylen + cipher_ivlen); - - SymmetricKey keyblock = (version == SSL_V3) ? - ssl3_keygen(prf_gen, pre_master_secret, c_random, s_random) : - tls1_keygen(prf_gen, pre_master_secret, c_random, s_random); - - const byte* key_data = keyblock.begin(); - - c_mac = SymmetricKey(key_data, mac_keylen); - key_data += mac_keylen; - - s_mac = SymmetricKey(key_data, mac_keylen); - key_data += mac_keylen; - - c_cipher = SymmetricKey(key_data, cipher_keylen); - key_data += cipher_keylen; - - s_cipher = SymmetricKey(key_data, cipher_keylen); - key_data += cipher_keylen; - - c_iv = InitializationVector(key_data, cipher_ivlen); - key_data += cipher_ivlen; - - s_iv = InitializationVector(key_data, cipher_ivlen); - } - -} diff --git a/src/ssl/tls_session_key.h b/src/ssl/tls_session_key.h deleted file mode 100644 index 51397984b..000000000 --- a/src/ssl/tls_session_key.h +++ /dev/null @@ -1,52 +0,0 @@ -/* -* TLS Session Key -* (C) 2004-2006 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_SESSION_KEYS_H__ -#define BOTAN_TLS_SESSION_KEYS_H__ - -#include -#include -#include - -namespace Botan { - -/** -* TLS Session Keys -*/ -class BOTAN_DLL SessionKeys - { - public: - SymmetricKey client_cipher_key() const; - SymmetricKey server_cipher_key() const; - - SymmetricKey client_mac_key() const; - SymmetricKey server_mac_key() const; - - InitializationVector client_iv() const; - InitializationVector server_iv() const; - - SecureVector master_secret() const; - - SessionKeys() {} - SessionKeys(const CipherSuite&, Version_Code, const MemoryRegion&, - const MemoryRegion&, const MemoryRegion&); - private: - SymmetricKey ssl3_keygen(size_t, const MemoryRegion&, - const MemoryRegion&, - const MemoryRegion&); - SymmetricKey tls1_keygen(size_t, const MemoryRegion&, - const MemoryRegion&, - const MemoryRegion&); - - SecureVector master_sec; - SymmetricKey c_cipher, s_cipher, c_mac, s_mac; - InitializationVector c_iv, s_iv; - }; - -} - -#endif diff --git a/src/ssl/tls_state.cpp b/src/ssl/tls_state.cpp deleted file mode 100644 index 6aaf5e201..000000000 --- a/src/ssl/tls_state.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* -* TLS Handshaking -* (C) 2004-2006 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include - -namespace Botan { - -/** -* Initialize the SSL/TLS Handshake State -*/ -Handshake_State::Handshake_State() - { - client_hello = 0; - server_hello = 0; - server_certs = 0; - server_kex = 0; - cert_req = 0; - server_hello_done = 0; - - client_certs = 0; - client_kex = 0; - client_verify = 0; - client_finished = 0; - server_finished = 0; - - kex_pub = 0; - kex_priv = 0; - - do_client_auth = got_client_ccs = got_server_ccs = false; - version = SSL_V3; - } - -/** -* Destroy the SSL/TLS Handshake State -*/ -Handshake_State::~Handshake_State() - { - delete client_hello; - delete server_hello; - delete server_certs; - delete server_kex; - delete cert_req; - delete server_hello_done; - - delete client_certs; - delete client_kex; - delete client_verify; - delete client_finished; - delete server_finished; - - delete kex_pub; - delete kex_priv; - } - -} diff --git a/src/ssl/tls_state.h b/src/ssl/tls_state.h deleted file mode 100644 index e2728198f..000000000 --- a/src/ssl/tls_state.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -* TLS Handshake State -* (C) 2004-2006 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_HANDSHAKE_H__ -#define BOTAN_TLS_HANDSHAKE_H__ - -#include -#include - -namespace Botan { - -/** -* SSL/TLS Handshake State -*/ -class Handshake_State - { - public: - Client_Hello* client_hello; - Server_Hello* server_hello; - Certificate* server_certs; - Server_Key_Exchange* server_kex; - Certificate_Req* cert_req; - Server_Hello_Done* server_hello_done; - - Certificate* client_certs; - Client_Key_Exchange* client_kex; - Certificate_Verify* client_verify; - Finished* client_finished; - Finished* server_finished; - - Public_Key* kex_pub; - Private_Key* kex_priv; - - CipherSuite suite; - SessionKeys keys; - HandshakeHash hash; - - SecureQueue queue; - - Version_Code version; - bool got_client_ccs, got_server_ccs, do_client_auth; - - Handshake_State(); - ~Handshake_State(); - }; - -} - -#endif diff --git a/src/ssl/tls_suites.cpp b/src/ssl/tls_suites.cpp deleted file mode 100644 index 07cbec608..000000000 --- a/src/ssl/tls_suites.cpp +++ /dev/null @@ -1,281 +0,0 @@ -/* -* TLS Cipher Suites -* (C) 2004-2010 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#include -#include - -namespace Botan { - -/** -* Convert an SSL/TLS ciphersuite to algorithm fields -*/ -TLS_Ciphersuite_Algos CipherSuite::lookup_ciphersuite(u16bit suite) - { - if(suite == TLS_RSA_WITH_RC4_128_MD5) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | - TLS_ALGO_KEYEXCH_NOKEX | - TLS_ALGO_MAC_MD5 | - TLS_ALGO_CIPHER_RC4_128); - - if(suite == TLS_RSA_WITH_RC4_128_SHA) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | - TLS_ALGO_KEYEXCH_NOKEX | - TLS_ALGO_MAC_SHA1 | - TLS_ALGO_CIPHER_RC4_128); - - if(suite == TLS_RSA_WITH_3DES_EDE_CBC_SHA) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | - TLS_ALGO_KEYEXCH_NOKEX | - TLS_ALGO_MAC_SHA1 | - TLS_ALGO_CIPHER_3DES_CBC); - - if(suite == TLS_RSA_WITH_AES_128_CBC_SHA) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | - TLS_ALGO_KEYEXCH_NOKEX | - TLS_ALGO_MAC_SHA1 | - TLS_ALGO_CIPHER_AES128_CBC); - - if(suite == TLS_RSA_WITH_AES_256_CBC_SHA) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | - TLS_ALGO_KEYEXCH_NOKEX | - TLS_ALGO_MAC_SHA1 | - TLS_ALGO_CIPHER_AES256_CBC); - - if(suite == TLS_RSA_WITH_SEED_CBC_SHA) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | - TLS_ALGO_KEYEXCH_NOKEX | - TLS_ALGO_MAC_SHA1 | - TLS_ALGO_CIPHER_SEED_CBC); - - if(suite == TLS_RSA_WITH_AES_128_CBC_SHA256) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | - TLS_ALGO_KEYEXCH_NOKEX | - TLS_ALGO_MAC_SHA256 | - TLS_ALGO_CIPHER_AES128_CBC); - - if(suite == TLS_RSA_WITH_AES_256_CBC_SHA256) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | - TLS_ALGO_KEYEXCH_NOKEX | - TLS_ALGO_MAC_SHA256 | - TLS_ALGO_CIPHER_AES256_CBC); - - if(suite == TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA | - TLS_ALGO_KEYEXCH_DH | - TLS_ALGO_MAC_SHA1 | - TLS_ALGO_CIPHER_3DES_CBC); - - if(suite == TLS_DHE_DSS_WITH_AES_128_CBC_SHA) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA | - TLS_ALGO_KEYEXCH_DH | - TLS_ALGO_MAC_SHA1 | - TLS_ALGO_CIPHER_AES128_CBC); - - if(suite == TLS_DHE_DSS_WITH_SEED_CBC_SHA) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA | - TLS_ALGO_KEYEXCH_DH | - TLS_ALGO_MAC_SHA1 | - TLS_ALGO_CIPHER_SEED_CBC); - - if(suite == TLS_DHE_DSS_WITH_AES_256_CBC_SHA) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA | - TLS_ALGO_KEYEXCH_DH | - TLS_ALGO_MAC_SHA1 | - TLS_ALGO_CIPHER_AES256_CBC); - - if(suite == TLS_DHE_DSS_WITH_AES_128_CBC_SHA256) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA | - TLS_ALGO_KEYEXCH_DH | - TLS_ALGO_MAC_SHA256 | - TLS_ALGO_CIPHER_AES128_CBC); - - if(suite == TLS_DHE_DSS_WITH_AES_256_CBC_SHA256) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA | - TLS_ALGO_KEYEXCH_DH | - TLS_ALGO_MAC_SHA256 | - TLS_ALGO_CIPHER_AES256_CBC); - - if(suite == TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | - TLS_ALGO_KEYEXCH_DH | - TLS_ALGO_MAC_SHA1 | - TLS_ALGO_CIPHER_3DES_CBC); - - if(suite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | - TLS_ALGO_KEYEXCH_DH | - TLS_ALGO_MAC_SHA1 | - TLS_ALGO_CIPHER_AES128_CBC); - - if(suite == TLS_DHE_DSS_WITH_SEED_CBC_SHA) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | - TLS_ALGO_KEYEXCH_DH | - TLS_ALGO_MAC_SHA1 | - TLS_ALGO_CIPHER_SEED_CBC); - - if(suite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | - TLS_ALGO_KEYEXCH_DH | - TLS_ALGO_MAC_SHA1 | - TLS_ALGO_CIPHER_AES256_CBC); - - if(suite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA256) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | - TLS_ALGO_KEYEXCH_DH | - TLS_ALGO_MAC_SHA256 | - TLS_ALGO_CIPHER_AES128_CBC); - - if(suite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA256) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | - TLS_ALGO_KEYEXCH_DH | - TLS_ALGO_MAC_SHA256 | - TLS_ALGO_CIPHER_AES256_CBC); - - if(suite == TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | - TLS_ALGO_KEYEXCH_ECDH | - TLS_ALGO_MAC_SHA1 | - TLS_ALGO_CIPHER_RC4_128); - - if(suite == TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | - TLS_ALGO_KEYEXCH_ECDH | - TLS_ALGO_MAC_SHA1 | - TLS_ALGO_CIPHER_3DES_CBC); - - if(suite == TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | - TLS_ALGO_KEYEXCH_ECDH | - TLS_ALGO_MAC_SHA1 | - TLS_ALGO_CIPHER_AES128_CBC); - - if(suite == TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | - TLS_ALGO_KEYEXCH_ECDH | - TLS_ALGO_MAC_SHA1 | - TLS_ALGO_CIPHER_AES256_CBC); - - if(suite == TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | - TLS_ALGO_KEYEXCH_ECDH | - TLS_ALGO_MAC_SHA256 | - TLS_ALGO_CIPHER_AES128_CBC); - - if(suite == TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | - TLS_ALGO_KEYEXCH_ECDH | - TLS_ALGO_MAC_SHA384 | - TLS_ALGO_CIPHER_AES256_CBC); - - if(suite == TLS_ECDHE_RSA_WITH_RC4_128_SHA) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | - TLS_ALGO_KEYEXCH_ECDH | - TLS_ALGO_MAC_SHA1 | - TLS_ALGO_CIPHER_RC4_128); - - if(suite == TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | - TLS_ALGO_KEYEXCH_ECDH | - TLS_ALGO_MAC_SHA1 | - TLS_ALGO_CIPHER_3DES_CBC); - - if(suite == TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | - TLS_ALGO_KEYEXCH_ECDH | - TLS_ALGO_MAC_SHA1 | - TLS_ALGO_CIPHER_AES128_CBC); - - if(suite == TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | - TLS_ALGO_KEYEXCH_ECDH | - TLS_ALGO_MAC_SHA1 | - TLS_ALGO_CIPHER_AES256_CBC); - - if(suite == TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | - TLS_ALGO_KEYEXCH_ECDH | - TLS_ALGO_MAC_SHA256 | - TLS_ALGO_CIPHER_AES128_CBC); - - if(suite == TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) - return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | - TLS_ALGO_KEYEXCH_ECDH | - TLS_ALGO_MAC_SHA384 | - TLS_ALGO_CIPHER_AES256_CBC); - - return TLS_Ciphersuite_Algos(0); - } - -namespace { - -std::pair cipher_code_to_name(TLS_Ciphersuite_Algos algo) - { - if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_RC4_128) - return std::make_pair("ARC4", 16); - - if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_3DES_CBC) - return std::make_pair("3DES", 24); - - if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_AES128_CBC) - return std::make_pair("AES-128", 16); - - if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_AES256_CBC) - return std::make_pair("AES-256", 32); - - if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_SEED_CBC) - return std::make_pair("SEED", 16); - - throw TLS_Exception(INTERNAL_ERROR, - "CipherSuite: Unknown cipher type " + to_string(algo)); - } - -std::string mac_code_to_name(TLS_Ciphersuite_Algos algo) - { - if((algo & TLS_ALGO_MAC_MASK) == TLS_ALGO_MAC_MD5) - return "MD5"; - - if((algo & TLS_ALGO_MAC_MASK) == TLS_ALGO_MAC_SHA1) - return "SHA-1"; - - if((algo & TLS_ALGO_MAC_MASK) == TLS_ALGO_MAC_SHA256) - return "SHA-256"; - - if((algo & TLS_ALGO_MAC_MASK) == TLS_ALGO_MAC_SHA384) - return "SHA-384"; - - throw TLS_Exception(INTERNAL_ERROR, - "CipherSuite: Unknown MAC type " + to_string(algo)); - } - -} - -/** -* CipherSuite Constructor -*/ -CipherSuite::CipherSuite(u16bit suite_code) - { - if(suite_code == 0) - return; - - TLS_Ciphersuite_Algos algos = lookup_ciphersuite(suite_code); - - if(algos == 0) - throw Invalid_Argument("Unknown ciphersuite: " + to_string(suite_code)); - - sig_algo = TLS_Ciphersuite_Algos(algos & TLS_ALGO_SIGNER_MASK); - - kex_algo = TLS_Ciphersuite_Algos(algos & TLS_ALGO_KEYEXCH_MASK); - - std::pair cipher_info = cipher_code_to_name(algos); - - cipher = cipher_info.first; - cipher_key_length = cipher_info.second; - - mac = mac_code_to_name(algos); - } - -} diff --git a/src/ssl/tls_suites.h b/src/ssl/tls_suites.h deleted file mode 100644 index 8d6db0e8b..000000000 --- a/src/ssl/tls_suites.h +++ /dev/null @@ -1,42 +0,0 @@ -/* -* Cipher Suites -* (C) 2004-2010 Jack Lloyd -* -* Released under the terms of the Botan license -*/ - -#ifndef BOTAN_TLS_CIPHERSUITES_H__ -#define BOTAN_TLS_CIPHERSUITES_H__ - -#include -#include -#include - -namespace Botan { - -/** -* Ciphersuite Information -*/ -class BOTAN_DLL CipherSuite - { - public: - static TLS_Ciphersuite_Algos lookup_ciphersuite(u16bit suite); - - std::string cipher_algo() const { return cipher; } - std::string mac_algo() const { return mac; } - - size_t cipher_keylen() const { return cipher_key_length; } - - TLS_Ciphersuite_Algos kex_type() const { return kex_algo; } - TLS_Ciphersuite_Algos sig_type() const { return sig_algo; } - - CipherSuite(u16bit = 0); - private: - TLS_Ciphersuite_Algos kex_algo, sig_algo; - std::string cipher, mac; - size_t cipher_key_length; - }; - -} - -#endif diff --git a/src/tls/c_kex.cpp b/src/tls/c_kex.cpp new file mode 100644 index 000000000..0f20b819c --- /dev/null +++ b/src/tls/c_kex.cpp @@ -0,0 +1,165 @@ +/* +* Client Key Exchange Message +* (C) 2004-2010 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* Create a new Client Key Exchange message +*/ +Client_Key_Exchange::Client_Key_Exchange(RandomNumberGenerator& rng, + Record_Writer& writer, + HandshakeHash& hash, + const Public_Key* pub_key, + Version_Code using_version, + Version_Code pref_version) + { + include_length = true; + + if(const DH_PublicKey* dh_pub = dynamic_cast(pub_key)) + { + DH_PrivateKey priv_key(rng, dh_pub->get_domain()); + + PK_Key_Agreement ka(priv_key, "Raw"); + + pre_master = ka.derive_key(0, dh_pub->public_value()).bits_of(); + + key_material = priv_key.public_value(); + } + else if(const RSA_PublicKey* rsa_pub = dynamic_cast(pub_key)) + { + pre_master = rng.random_vec(48); + pre_master[0] = (pref_version >> 8) & 0xFF; + pre_master[1] = (pref_version ) & 0xFF; + + PK_Encryptor_EME encryptor(*rsa_pub, "PKCS1v15"); + + key_material = encryptor.encrypt(pre_master, rng); + + if(using_version == SSL_V3) + include_length = false; + } + else + throw Invalid_Argument("Client_Key_Exchange: Key not RSA or DH"); + + send(writer, hash); + } + +/** +* Read a Client Key Exchange message +*/ +Client_Key_Exchange::Client_Key_Exchange(const MemoryRegion& contents, + const CipherSuite& suite, + Version_Code using_version) + { + include_length = true; + + if(using_version == SSL_V3 && (suite.kex_type() == TLS_ALGO_KEYEXCH_RSA)) + include_length = false; + + deserialize(contents); + } + +/** +* Serialize a Client Key Exchange message +*/ +SecureVector Client_Key_Exchange::serialize() const + { + if(include_length) + { + SecureVector buf; + append_tls_length_value(buf, key_material, 2); + return buf; + } + else + return key_material; + } + +/** +* Deserialize a Client Key Exchange message +*/ +void Client_Key_Exchange::deserialize(const MemoryRegion& buf) + { + if(include_length) + { + TLS_Data_Reader reader(buf); + key_material = reader.get_range(2, 0, 65535); + } + else + key_material = buf; + } + +/** +* Return the pre_master_secret +*/ +SecureVector +Client_Key_Exchange::pre_master_secret(RandomNumberGenerator& rng, + const Private_Key* priv_key, + Version_Code version) + { + + if(const DH_PrivateKey* dh_priv = dynamic_cast(priv_key)) + { + try { + PK_Key_Agreement ka(*dh_priv, "Raw"); + + pre_master = ka.derive_key(0, key_material).bits_of(); + } + catch(...) + { + /* + * Something failed in the DH computation. To avoid possible + * timing attacks, randomize the pre-master output and carry + * on, allowing the protocol to fail later in the finished + * checks. + */ + pre_master = rng.random_vec(dh_priv->public_value().size()); + } + + return pre_master; + } + else if(const RSA_PrivateKey* rsa_priv = dynamic_cast(priv_key)) + { + PK_Decryptor_EME decryptor(*rsa_priv, "PKCS1v15"); + + try { + pre_master = decryptor.decrypt(key_material); + + if(pre_master.size() != 48 || + make_u16bit(pre_master[0], pre_master[1]) != version) + throw Decoding_Error("Client_Key_Exchange: Secret corrupted"); + } + catch(...) + { + pre_master = rng.random_vec(48); + pre_master[0] = (version >> 8) & 0xFF; + pre_master[1] = (version ) & 0xFF; + } + + return pre_master; + } + else + throw Invalid_Argument("Client_Key_Exchange: Bad key for decrypt"); + } + +/** +* Return the pre_master_secret +*/ +SecureVector Client_Key_Exchange::pre_master_secret() const + { + return pre_master; + } + +} diff --git a/src/tls/cert_req.cpp b/src/tls/cert_req.cpp new file mode 100644 index 000000000..b8b2624bf --- /dev/null +++ b/src/tls/cert_req.cpp @@ -0,0 +1,151 @@ +/* +* Certificate Request Message +* (C) 2004-2006 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* Create a new Certificate Request message +*/ +Certificate_Req::Certificate_Req(Record_Writer& writer, + HandshakeHash& hash, + const std::vector& certs) + { + for(size_t i = 0; i != certs.size(); ++i) + names.push_back(certs[i].subject_dn()); + + // FIXME: should be able to choose what to ask for + types.push_back(RSA_CERT); + types.push_back(DSS_CERT); + + send(writer, hash); + } + +/** +* Serialize a Certificate Request message +*/ +SecureVector Certificate_Req::serialize() const + { + SecureVector buf; + + append_tls_length_value(buf, types, 1); + + DER_Encoder encoder; + for(size_t i = 0; i != names.size(); ++i) + encoder.encode(names[i]); + + append_tls_length_value(buf, encoder.get_contents(), 2); + + return buf; + } + +/** +* Deserialize a Certificate Request message +*/ +void Certificate_Req::deserialize(const MemoryRegion& buf) + { + if(buf.size() < 4) + throw Decoding_Error("Certificate_Req: Bad certificate request"); + + size_t types_size = buf[0]; + + if(buf.size() < types_size + 3) + throw Decoding_Error("Certificate_Req: Bad certificate request"); + + for(size_t i = 0; i != types_size; ++i) + types.push_back(static_cast(buf[i+1])); + + size_t names_size = make_u16bit(buf[types_size+2], buf[types_size+3]); + + if(buf.size() != names_size + types_size + 3) + throw Decoding_Error("Certificate_Req: Bad certificate request"); + + BER_Decoder decoder(&buf[types_size + 3], names_size); + + while(decoder.more_items()) + { + X509_DN name; + decoder.decode(name); + names.push_back(name); + } + } + +/** +* Create a new Certificate message +*/ +Certificate::Certificate(Record_Writer& writer, + const std::vector& cert_list, + HandshakeHash& hash) + { + certs = cert_list; + send(writer, hash); + } + +/** +* Serialize a Certificate message +*/ +SecureVector Certificate::serialize() const + { + SecureVector buf(3); + + for(size_t i = 0; i != certs.size(); ++i) + { + SecureVector raw_cert = certs[i].BER_encode(); + const size_t cert_size = raw_cert.size(); + for(size_t i = 0; i != 3; ++i) + buf.push_back(get_byte(i+1, cert_size)); + buf += raw_cert; + } + + const size_t buf_size = buf.size() - 3; + for(size_t i = 0; i != 3; ++i) + buf[i] = get_byte(i+1, buf_size); + + return buf; + } + +/** +* Deserialize a Certificate message +*/ +void Certificate::deserialize(const MemoryRegion& buf) + { + if(buf.size() < 3) + throw Decoding_Error("Certificate: Message malformed"); + + const size_t total_size = make_u32bit(0, buf[0], buf[1], buf[2]); + + SecureQueue queue; + queue.write(&buf[3], buf.size() - 3); + + if(queue.size() != total_size) + throw Decoding_Error("Certificate: Message malformed"); + + while(queue.size()) + { + if(queue.size() < 3) + throw Decoding_Error("Certificate: Message malformed"); + + byte len[3]; + queue.read(len, 3); + + const size_t cert_size = make_u32bit(0, len[0], len[1], len[2]); + const size_t original_size = queue.size(); + + X509_Certificate cert(queue); + if(queue.size() + cert_size != original_size) + throw Decoding_Error("Certificate: Message malformed"); + certs.push_back(cert); + } + } + +} diff --git a/src/tls/cert_ver.cpp b/src/tls/cert_ver.cpp new file mode 100644 index 000000000..3220a8c9e --- /dev/null +++ b/src/tls/cert_ver.cpp @@ -0,0 +1,98 @@ +/* +* Certificate Verify Message +* (C) 2004-2010 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* Create a new Certificate Verify message +*/ +Certificate_Verify::Certificate_Verify(RandomNumberGenerator& rng, + Record_Writer& writer, + HandshakeHash& hash, + const Private_Key* priv_key) + { + std::string padding = ""; + Signature_Format format = IEEE_1363; + + if(priv_key->algo_name() == "RSA") + padding = "EMSA3(TLS.Digest.0)"; + else if(priv_key->algo_name() == "DSA") + { + padding == "EMSA1(SHA-1)"; + format = DER_SEQUENCE; + } + else + throw Invalid_Argument(priv_key->algo_name() + + " is invalid/unknown for TLS signatures"); + + PK_Signer signer(*priv_key, padding, format); + + signature = signer.sign_message(hash.final(), rng); + send(writer, hash); + } + +/** +* Serialize a Certificate Verify message +*/ +SecureVector Certificate_Verify::serialize() const + { + SecureVector buf; + + const u16bit sig_len = signature.size(); + buf.push_back(get_byte(0, sig_len)); + buf.push_back(get_byte(1, sig_len)); + buf += signature; + + return buf; + } + +/** +* Deserialize a Certificate Verify message +*/ +void Certificate_Verify::deserialize(const MemoryRegion& buf) + { + TLS_Data_Reader reader(buf); + signature = reader.get_range(2, 0, 65535); + } + +/** +* Verify a Certificate Verify message +*/ +bool Certificate_Verify::verify(const X509_Certificate& cert, + HandshakeHash& hash) + { + // FIXME: duplicate of Server_Key_Exchange::verify + + std::auto_ptr key(cert.subject_public_key()); + + std::string padding = ""; + Signature_Format format = IEEE_1363; + + if(key->algo_name() == "RSA") + padding = "EMSA3(TLS.Digest.0)"; + else if(key->algo_name() == "DSA") + { + padding == "EMSA1(SHA-1)"; + format = DER_SEQUENCE; + } + else + throw Invalid_Argument(key->algo_name() + + " is invalid/unknown for TLS signatures"); + + PK_Verifier verifier(*key, padding, format); + return verifier.verify_message(hash.final(), signature); + } + +} diff --git a/src/tls/finished.cpp b/src/tls/finished.cpp new file mode 100644 index 000000000..d76fbd884 --- /dev/null +++ b/src/tls/finished.cpp @@ -0,0 +1,100 @@ +/* +* Finished Message +* (C) 2004-2006 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/** +* Create a new Finished message +*/ +Finished::Finished(Record_Writer& writer, + Version_Code version, Connection_Side side, + const MemoryRegion& master_secret, + HandshakeHash& hash) + { + verification_data = compute_verify(master_secret, hash, side, version); + send(writer, hash); + } + +/** +* Serialize a Finished message +*/ +SecureVector Finished::serialize() const + { + return verification_data; + } + +/** +* Deserialize a Finished message +*/ +void Finished::deserialize(const MemoryRegion& buf) + { + verification_data = buf; + } + +/** +* Verify a Finished message +*/ +bool Finished::verify(const MemoryRegion& secret, Version_Code version, + const HandshakeHash& hash, Connection_Side side) + { + SecureVector computed = compute_verify(secret, hash, side, version); + if(computed == verification_data) + return true; + return false; + } + +/** +* Compute the verify_data +*/ +SecureVector Finished::compute_verify(const MemoryRegion& secret, + HandshakeHash hash, + Connection_Side side, + Version_Code version) + { + if(version == SSL_V3) + { + const byte SSL_CLIENT_LABEL[] = { 0x43, 0x4C, 0x4E, 0x54 }; + const byte SSL_SERVER_LABEL[] = { 0x53, 0x52, 0x56, 0x52 }; + + SecureVector ssl3_finished; + + if(side == CLIENT) + hash.update(SSL_CLIENT_LABEL, sizeof(SSL_CLIENT_LABEL)); + else + hash.update(SSL_SERVER_LABEL, sizeof(SSL_SERVER_LABEL)); + + return hash.final_ssl3(secret); + } + else if(version == TLS_V10 || version == TLS_V11) + { + const byte TLS_CLIENT_LABEL[] = { + 0x63, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x20, 0x66, 0x69, 0x6E, 0x69, + 0x73, 0x68, 0x65, 0x64 }; + + const byte TLS_SERVER_LABEL[] = { + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x66, 0x69, 0x6E, 0x69, + 0x73, 0x68, 0x65, 0x64 }; + + TLS_PRF prf; + + SecureVector input; + if(side == CLIENT) + input += std::make_pair(TLS_CLIENT_LABEL, sizeof(TLS_CLIENT_LABEL)); + else + input += std::make_pair(TLS_SERVER_LABEL, sizeof(TLS_SERVER_LABEL)); + input += hash.final(); + + return prf.derive_key(12, secret, input); + } + else + throw Invalid_Argument("Finished message: Unknown protocol version"); + } + +} diff --git a/src/tls/hello.cpp b/src/tls/hello.cpp new file mode 100644 index 000000000..ae0d9607b --- /dev/null +++ b/src/tls/hello.cpp @@ -0,0 +1,331 @@ +/* +* TLS Hello Messages +* (C) 2004-2010 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Encode and send a Handshake message +*/ +void HandshakeMessage::send(Record_Writer& writer, HandshakeHash& hash) const + { + SecureVector buf = serialize(); + SecureVector send_buf(4); + + const size_t buf_size = buf.size(); + + send_buf[0] = type(); + + for(size_t i = 1; i != 4; ++i) + send_buf[i] = get_byte(i, buf_size); + + send_buf += buf; + + hash.update(send_buf); + + writer.send(HANDSHAKE, &send_buf[0], send_buf.size()); + writer.flush(); + } + +/* +* Create a new Hello Request message +*/ +Hello_Request::Hello_Request(Record_Writer& writer) + { + HandshakeHash dummy; // FIXME: *UGLY* + send(writer, dummy); + } + +/* +* Serialize a Hello Request message +*/ +SecureVector Hello_Request::serialize() const + { + return SecureVector(); + } + +/* +* Deserialize a Hello Request message +*/ +void Hello_Request::deserialize(const MemoryRegion& buf) + { + if(buf.size()) + throw Decoding_Error("Hello_Request: Must be empty, and is not"); + } + +/* +* Create a new Client Hello message +*/ +Client_Hello::Client_Hello(RandomNumberGenerator& rng, + Record_Writer& writer, + const TLS_Policy& policy, + HandshakeHash& hash) + { + c_random = rng.random_vec(32); + + suites = policy.ciphersuites(); + comp_algos = policy.compression(); + c_version = policy.pref_version(); + + send(writer, hash); + } + +/* +* Serialize a Client Hello message +*/ +SecureVector Client_Hello::serialize() const + { + SecureVector buf; + + buf.push_back(static_cast(c_version >> 8)); + buf.push_back(static_cast(c_version )); + buf += c_random; + + append_tls_length_value(buf, sess_id, 1); + append_tls_length_value(buf, suites, 2); + append_tls_length_value(buf, comp_algos, 1); + + return buf; + } + +void Client_Hello::deserialize_sslv2(const MemoryRegion& buf) + { + if(buf.size() < 12 || buf[0] != 1) + throw Decoding_Error("Client_Hello: SSLv2 hello corrupted"); + + const size_t cipher_spec_len = make_u16bit(buf[3], buf[4]); + const size_t sess_id_len = make_u16bit(buf[5], buf[6]); + const size_t challenge_len = make_u16bit(buf[7], buf[8]); + + const size_t expected_size = + (9 + sess_id_len + cipher_spec_len + challenge_len); + + if(buf.size() != expected_size) + throw Decoding_Error("Client_Hello: SSLv2 hello corrupted"); + + if(sess_id_len != 0 || cipher_spec_len % 3 != 0 || + (challenge_len < 16 || challenge_len > 32)) + { + throw Decoding_Error("Client_Hello: SSLv2 hello corrupted"); + } + + for(size_t i = 9; i != 9 + cipher_spec_len; i += 3) + { + if(buf[i] != 0) // a SSLv2 cipherspec; ignore it + continue; + + suites.push_back(make_u16bit(buf[i+1], buf[i+2])); + } + + c_version = static_cast(make_u16bit(buf[1], buf[2])); + + c_random.resize(challenge_len); + copy_mem(&c_random[0], &buf[9+cipher_spec_len+sess_id_len], challenge_len); + } + +/* +* Deserialize a Client Hello message +*/ +void Client_Hello::deserialize(const MemoryRegion& buf) + { + if(buf.size() == 0) + throw Decoding_Error("Client_Hello: Packet corrupted"); + + if(buf.size() < 41) + throw Decoding_Error("Client_Hello: Packet corrupted"); + + TLS_Data_Reader reader(buf); + + c_version = static_cast(reader.get_u16bit()); + c_random = reader.get_fixed(32); + + sess_id = reader.get_range(1, 0, 32); + + suites = reader.get_range_vector(2, 1, 32767); + + comp_algos = reader.get_range_vector(1, 1, 255); + + if(reader.has_remaining()) + { + const u16bit all_extn_size = reader.get_u16bit(); + + if(reader.remaining_bytes() != all_extn_size) + throw Decoding_Error("Client_Hello: Bad extension size"); + + while(reader.has_remaining()) + { + const u16bit extension_code = reader.get_u16bit(); + const u16bit extension_size = reader.get_u16bit(); + + if(extension_code == TLSEXT_SERVER_NAME_INDICATION) + { + u16bit name_bytes = reader.get_u16bit(); + + while(name_bytes) + { + byte name_type = reader.get_byte(); + name_bytes--; + + if(name_type == 0) // DNS + { + std::vector name = + reader.get_range_vector(2, 1, 65535); + + requested_hostname.assign( + reinterpret_cast(&name[0]), + name.size()); + + name_bytes -= (2 + name.size()); + } + else + { + reader.discard_next(name_bytes); + name_bytes = 0; + } + } + } + else if(extension_code == TLSEXT_SRP_IDENTIFIER) + { + std::vector name = reader.get_range_vector(1, 1, 255); + + requested_srp_id.assign( + reinterpret_cast(&name[0]), + name.size()); + } + else + { + reader.discard_next(extension_size); + } + } + } + } + +/* +* Check if we offered this ciphersuite +*/ +bool Client_Hello::offered_suite(u16bit ciphersuite) const + { + for(size_t i = 0; i != suites.size(); ++i) + if(suites[i] == ciphersuite) + return true; + return false; + } + +/* +* Create a new Server Hello message +*/ +Server_Hello::Server_Hello(RandomNumberGenerator& rng, + Record_Writer& writer, + const TLS_Policy& policy, + const std::vector& certs, + const Client_Hello& c_hello, + Version_Code ver, + HandshakeHash& hash) + { + bool have_rsa = false, have_dsa = false; + + for(size_t i = 0; i != certs.size(); ++i) + { + Public_Key* key = certs[i].subject_public_key(); + if(key->algo_name() == "RSA") + have_rsa = true; + + if(key->algo_name() == "DSA") + have_dsa = true; + } + + suite = policy.choose_suite(c_hello.ciphersuites(), have_rsa, have_dsa); + + if(suite == 0) + throw TLS_Exception(PROTOCOL_VERSION, + "Can't agree on a ciphersuite with client"); + + comp_algo = policy.choose_compression(c_hello.compression_algos()); + + s_version = ver; + s_random = rng.random_vec(32); + + send(writer, hash); + } + +/* +* Serialize a Server Hello message +*/ +SecureVector Server_Hello::serialize() const + { + SecureVector buf; + + buf.push_back(static_cast(s_version >> 8)); + buf.push_back(static_cast(s_version )); + buf += s_random; + + append_tls_length_value(buf, sess_id, 1); + + buf.push_back(get_byte(0, suite)); + buf.push_back(get_byte(1, suite)); + + buf.push_back(comp_algo); + + return buf; + } + +/* +* Deserialize a Server Hello message +*/ +void Server_Hello::deserialize(const MemoryRegion& buf) + { + if(buf.size() < 38) + throw Decoding_Error("Server_Hello: Packet corrupted"); + + TLS_Data_Reader reader(buf); + + s_version = static_cast(reader.get_u16bit()); + + if(s_version != SSL_V3 && s_version != TLS_V10 && s_version != TLS_V11) + { + throw TLS_Exception(PROTOCOL_VERSION, + "Server_Hello: Unsupported server version"); + } + + s_random = reader.get_fixed(32); + + sess_id = reader.get_range(1, 0, 32); + + suite = reader.get_u16bit(); + + comp_algo = reader.get_byte(); + } + +/* +* Create a new Server Hello Done message +*/ +Server_Hello_Done::Server_Hello_Done(Record_Writer& writer, + HandshakeHash& hash) + { + send(writer, hash); + } + +/* +* Serialize a Server Hello Done message +*/ +SecureVector Server_Hello_Done::serialize() const + { + return SecureVector(); + } + +/* +* Deserialize a Server Hello Done message +*/ +void Server_Hello_Done::deserialize(const MemoryRegion& buf) + { + if(buf.size()) + throw Decoding_Error("Server_Hello_Done: Must be empty, and is not"); + } + +} diff --git a/src/tls/info.txt b/src/tls/info.txt new file mode 100644 index 000000000..1170fef45 --- /dev/null +++ b/src/tls/info.txt @@ -0,0 +1,66 @@ +define SSL_TLS + + +The SSL/TLS code is complex, new, and not yet reviewed, there may be +serious bugs or security issues. + + +uses_tr1 yes + + +tls_client.h +tls_exceptn.h +tls_magic.h +tls_policy.h +tls_record.h +tls_server.h +tls_session_key.h +tls_suites.h + + + +tls_alerts.h +tls_handshake_hash.h +tls_messages.h +tls_reader.h +tls_state.h + + + +c_kex.cpp +cert_req.cpp +cert_ver.cpp +finished.cpp +tls_handshake_hash.cpp +hello.cpp +rec_read.cpp +rec_wri.cpp +s_kex.cpp +tls_client.cpp +tls_policy.cpp +tls_server.cpp +tls_session_key.cpp +tls_state.cpp +tls_suites.cpp + + + +aes +arc4 +asn1 +des +dh +dsa +eme_pkcs +emsa3 +filters +hmac +md5 +prf_ssl3 +prf_tls +rng +rsa +sha1 +ssl3mac +x509cert + diff --git a/src/tls/rec_read.cpp b/src/tls/rec_read.cpp new file mode 100644 index 000000000..4e5b69780 --- /dev/null +++ b/src/tls/rec_read.cpp @@ -0,0 +1,255 @@ +/* +* TLS Record Reading +* (C) 2004-2010 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include + +namespace Botan { + +/* +* Reset the state +*/ +void Record_Reader::reset() + { + cipher.reset(); + + delete mac; + mac = 0; + + mac_size = 0; + block_size = 0; + iv_size = 0; + major = minor = 0; + seq_no = 0; + } + +/* +* Set the version to use +*/ +void Record_Reader::set_version(Version_Code version) + { + if(version != SSL_V3 && version != TLS_V10 && version != TLS_V11) + throw Invalid_Argument("Record_Reader: Invalid protocol version"); + + major = (version >> 8) & 0xFF; + minor = (version & 0xFF); + } + +/* +* Set the keys for reading +*/ +void Record_Reader::set_keys(const CipherSuite& suite, const SessionKeys& keys, + Connection_Side side) + { + cipher.reset(); + delete mac; + mac = 0; + + SymmetricKey mac_key, cipher_key; + InitializationVector iv; + + if(side == CLIENT) + { + cipher_key = keys.server_cipher_key(); + iv = keys.server_iv(); + mac_key = keys.server_mac_key(); + } + else + { + cipher_key = keys.client_cipher_key(); + iv = keys.client_iv(); + mac_key = keys.client_mac_key(); + } + + const std::string cipher_algo = suite.cipher_algo(); + const std::string mac_algo = suite.mac_algo(); + + if(have_block_cipher(cipher_algo)) + { + cipher.append(get_cipher( + cipher_algo + "/CBC/NoPadding", + cipher_key, iv, DECRYPTION) + ); + block_size = block_size_of(cipher_algo); + + if(major > 3 || (major == 3 && minor >= 2)) + iv_size = block_size; + else + iv_size = 0; + } + else if(have_stream_cipher(cipher_algo)) + { + cipher.append(get_cipher(cipher_algo, cipher_key, DECRYPTION)); + block_size = 0; + iv_size = 0; + } + else + throw Invalid_Argument("Record_Reader: Unknown cipher " + cipher_algo); + + if(have_hash(mac_algo)) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(major == 3 && minor == 0) + mac = af.make_mac("SSL3-MAC(" + mac_algo + ")"); + else + mac = af.make_mac("HMAC(" + mac_algo + ")"); + + mac->set_key(mac_key); + mac_size = mac->output_length(); + } + else + throw Invalid_Argument("Record_Reader: Unknown hash " + mac_algo); + } + +void Record_Reader::add_input(const byte input[], size_t input_size) + { + input_queue.write(input, input_size); + } + +/* +* Retrieve the next record +*/ +size_t Record_Reader::get_record(byte& msg_type, + MemoryRegion& output) + { + byte header[5] = { 0 }; + + const size_t have_in_queue = input_queue.size(); + + if(have_in_queue < sizeof(header)) + return (sizeof(header) - have_in_queue); + + /* + * We peek first to make sure we have the full record + */ + input_queue.peek(header, sizeof(header)); + + // SSLv2-format client hello? + if(header[0] & 0x80 && header[2] == 1 && header[3] == 3) + { + size_t record_len = make_u16bit(header[0], header[1]) & 0x7FFF; + + if(have_in_queue < record_len + 2) + return (record_len + 2 - have_in_queue); + + msg_type = HANDSHAKE; + output.resize(record_len + 4); + + input_queue.read(&output[2], record_len + 2); + output[0] = CLIENT_HELLO_SSLV2; + output[1] = 0; + output[2] = header[0] & 0x7F; + output[3] = header[1]; + + return 0; + } + + if(header[0] != CHANGE_CIPHER_SPEC && + header[0] != ALERT && + header[0] != HANDSHAKE && + header[0] != APPLICATION_DATA) + { + throw TLS_Exception(UNEXPECTED_MESSAGE, + "Record_Reader: Unknown record type"); + } + + const u16bit version = make_u16bit(header[1], header[2]); + const u16bit record_len = make_u16bit(header[3], header[4]); + + if(major && (header[1] != major || header[2] != minor)) + throw TLS_Exception(PROTOCOL_VERSION, + "Record_Reader: Got unexpected version"); + + // If insufficient data, return without doing anything + if(have_in_queue < (sizeof(header) + record_len)) + return (sizeof(header) + record_len - have_in_queue); + + SecureVector buffer(record_len); + + input_queue.read(header, sizeof(header)); // pull off the header + input_queue.read(&buffer[0], buffer.size()); + + /* + * We are handshaking, no crypto to do so return as-is + * TODO: Check msg_type to confirm a handshake? + */ + if(mac_size == 0) + { + msg_type = header[0]; + output = buffer; + return 0; // got a full record + } + + // Otherwise, decrypt, check MAC, return plaintext + + cipher.process_msg(buffer); + SecureVector plaintext = cipher.read_all(Pipe::LAST_MESSAGE); + + size_t pad_size = 0; + + if(block_size) + { + byte pad_value = plaintext[plaintext.size()-1]; + pad_size = pad_value + 1; + + /* + * Check the padding; if it is wrong, then say we have 0 bytes of + * padding, which should ensure that the MAC check below does not + * suceed. This hides a timing channel. + * + * This particular countermeasure is recommended in the TLS 1.2 + * spec (RFC 5246) in section 6.2.3.2 + */ + if(version == SSL_V3) + { + if(pad_value > block_size) + pad_size = 0; + } + else + { + for(size_t i = 0; i != pad_size; ++i) + if(plaintext[plaintext.size()-i-1] != pad_value) + pad_size = 0; + } + } + + if(plaintext.size() < mac_size + pad_size + iv_size) + throw Decoding_Error("Record_Reader: Record truncated"); + + const size_t mac_offset = plaintext.size() - (mac_size + pad_size); + SecureVector received_mac(&plaintext[mac_offset], + mac_size); + + const u16bit plain_length = plaintext.size() - (mac_size + pad_size + iv_size); + + mac->update_be(seq_no); + mac->update(header[0]); // msg_type + + if(version != SSL_V3) + for(size_t i = 0; i != 2; ++i) + mac->update(get_byte(i, version)); + + mac->update_be(plain_length); + mac->update(&plaintext[iv_size], plain_length); + + ++seq_no; + + SecureVector computed_mac = mac->final(); + + if(received_mac != computed_mac) + throw TLS_Exception(BAD_RECORD_MAC, "Record_Reader: MAC failure"); + + msg_type = header[0]; + + output.resize(plain_length); + copy_mem(&output[0], &plaintext[iv_size], plain_length); + return 0; + } + +} diff --git a/src/tls/rec_wri.cpp b/src/tls/rec_wri.cpp new file mode 100644 index 000000000..d3a5c13f7 --- /dev/null +++ b/src/tls/rec_wri.cpp @@ -0,0 +1,270 @@ +/* +* TLS Record Writing +* (C) 2004-2010 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* Record_Writer Constructor +*/ +Record_Writer::Record_Writer(std::tr1::function out) : + output_fn(out), + buffer(DEFAULT_BUFFERSIZE) + { + mac = 0; + reset(); + } + +/** +* Reset the state +*/ +void Record_Writer::reset() + { + cipher.reset(); + + delete mac; + mac = 0; + + zeroise(buffer); + buf_pos = 0; + + major = minor = buf_type = 0; + block_size = 0; + mac_size = 0; + iv_size = 0; + + seq_no = 0; + } + +/** +* Set the version to use +*/ +void Record_Writer::set_version(Version_Code version) + { + if(version != SSL_V3 && version != TLS_V10 && version != TLS_V11) + throw Invalid_Argument("Record_Writer: Invalid protocol version"); + + major = (version >> 8) & 0xFF; + minor = (version & 0xFF); + } + +/** +* Set the keys for writing +*/ +void Record_Writer::set_keys(const CipherSuite& suite, const SessionKeys& keys, + Connection_Side side) + { + cipher.reset(); + delete mac; + mac = 0; + + SymmetricKey mac_key, cipher_key; + InitializationVector iv; + + if(side == CLIENT) + { + cipher_key = keys.client_cipher_key(); + iv = keys.client_iv(); + mac_key = keys.client_mac_key(); + } + else + { + cipher_key = keys.server_cipher_key(); + iv = keys.server_iv(); + mac_key = keys.server_mac_key(); + } + + const std::string cipher_algo = suite.cipher_algo(); + const std::string mac_algo = suite.mac_algo(); + + if(have_block_cipher(cipher_algo)) + { + cipher.append(get_cipher( + cipher_algo + "/CBC/NoPadding", + cipher_key, iv, ENCRYPTION) + ); + block_size = block_size_of(cipher_algo); + + if(major > 3 || (major == 3 && minor >= 2)) + iv_size = block_size; + else + iv_size = 0; + } + else if(have_stream_cipher(cipher_algo)) + { + cipher.append(get_cipher(cipher_algo, cipher_key, ENCRYPTION)); + block_size = 0; + iv_size = 0; + } + else + throw Invalid_Argument("Record_Writer: Unknown cipher " + cipher_algo); + + if(have_hash(mac_algo)) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(major == 3 && minor == 0) + mac = af.make_mac("SSL3-MAC(" + mac_algo + ")"); + else + mac = af.make_mac("HMAC(" + mac_algo + ")"); + + mac->set_key(mac_key); + mac_size = mac->output_length(); + } + else + throw Invalid_Argument("Record_Writer: Unknown hash " + mac_algo); + } + +/** +* Send one or more records to the other side +*/ +void Record_Writer::send(byte type, const byte input[], size_t length) + { + if(type != buf_type) + flush(); + + const size_t BUFFER_SIZE = buffer.size(); + buf_type = type; + + // FIXME: compression right here + + buffer.copy(buf_pos, input, length); + if(buf_pos + length >= BUFFER_SIZE) + { + send_record(buf_type, &buffer[0], length); + input += (BUFFER_SIZE - buf_pos); + length -= (BUFFER_SIZE - buf_pos); + while(length >= BUFFER_SIZE) + { + send_record(buf_type, input, BUFFER_SIZE); + input += BUFFER_SIZE; + length -= BUFFER_SIZE; + } + buffer.copy(input, length); + buf_pos = 0; + } + buf_pos += length; + } + +/** +* Split buffer into records, and send them all +*/ +void Record_Writer::flush() + { + const byte* buf_ptr = &buffer[0]; + size_t offset = 0; + + while(offset != buf_pos) + { + size_t record_size = buf_pos - offset; + if(record_size > MAX_PLAINTEXT_SIZE) + record_size = MAX_PLAINTEXT_SIZE; + + send_record(buf_type, buf_ptr + offset, record_size); + offset += record_size; + } + buf_type = 0; + buf_pos = 0; + } + +/** +* Encrypt and send the record +*/ +void Record_Writer::send_record(byte type, const byte buf[], size_t length) + { + if(length >= MAX_COMPRESSED_SIZE) + throw TLS_Exception(INTERNAL_ERROR, + "Record_Writer: Compressed packet is too big"); + + if(mac_size == 0) + send_record(type, major, minor, buf, length); + else + { + mac->update_be(seq_no); + mac->update(type); + + if(major > 3 || (major == 3 && minor != 0)) + { + mac->update(major); + mac->update(minor); + } + + mac->update(get_byte(0, length)); + mac->update(get_byte(1, length)); + mac->update(buf, length); + + SecureVector buf_mac = mac->final(); + + // TODO: This could all use a single buffer + cipher.start_msg(); + + if(iv_size) + { + RandomNumberGenerator& rng = global_state().global_rng(); + + SecureVector random_iv(iv_size); + + rng.randomize(&random_iv[0], random_iv.size()); + + cipher.write(random_iv); + } + + cipher.write(buf, length); + cipher.write(buf_mac); + + if(block_size) + { + const size_t pad_val = + (block_size - (1 + length + buf_mac.size())) % block_size; + + for(size_t i = 0; i != pad_val + 1; ++i) + cipher.write(pad_val); + } + cipher.end_msg(); + + SecureVector output = cipher.read_all(Pipe::LAST_MESSAGE); + + send_record(type, major, minor, &output[0], output.size()); + + seq_no++; + } + } + +/** +* Send a final record packet +*/ +void Record_Writer::send_record(byte type, byte major, byte minor, + const byte out[], size_t length) + { + if(length >= MAX_CIPHERTEXT_SIZE) + throw TLS_Exception(INTERNAL_ERROR, + "Record_Writer: Record is too big"); + + byte header[5] = { type, major, minor, 0 }; + for(size_t i = 0; i != 2; ++i) + header[i+3] = get_byte(i, length); + + output_fn(header, 5); + output_fn(out, length); + } + +/** +* Send an alert +*/ +void Record_Writer::alert(Alert_Level level, Alert_Type type) + { + byte alert[2] = { level, type }; + send(ALERT, alert, sizeof(alert)); + flush(); + } + +} diff --git a/src/tls/s_kex.cpp b/src/tls/s_kex.cpp new file mode 100644 index 000000000..1e7de31d0 --- /dev/null +++ b/src/tls/s_kex.cpp @@ -0,0 +1,180 @@ +/* +* Server Key Exchange Message +* (C) 2004-2010 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* Create a new Server Key Exchange message +*/ +Server_Key_Exchange::Server_Key_Exchange(RandomNumberGenerator& rng, + Record_Writer& writer, + const Public_Key* kex_key, + const Private_Key* priv_key, + const MemoryRegion& c_random, + const MemoryRegion& s_random, + HandshakeHash& hash) + { + const DH_PublicKey* dh_pub = dynamic_cast(kex_key); + const RSA_PublicKey* rsa_pub = dynamic_cast(kex_key); + + if(dh_pub) + { + params.push_back(dh_pub->get_domain().get_p()); + params.push_back(dh_pub->get_domain().get_g()); + params.push_back(BigInt::decode(dh_pub->public_value())); + } + else if(rsa_pub) + { + params.push_back(rsa_pub->get_n()); + params.push_back(rsa_pub->get_e()); + } + else + throw Invalid_Argument("Bad key for TLS key exchange: not DH or RSA"); + + + std::string padding = ""; + Signature_Format format = IEEE_1363; + + if(priv_key->algo_name() == "RSA") + padding = "EMSA3(TLS.Digest.0)"; + else if(priv_key->algo_name() == "DSA") + { + padding = "EMSA1(SHA-1)"; + format = DER_SEQUENCE; + } + else + throw Invalid_Argument(priv_key->algo_name() + + " is invalid/unknown for TLS signatures"); + + PK_Signer signer(*priv_key, padding, format); + + signer.update(c_random); + signer.update(s_random); + signer.update(serialize_params()); + signature = signer.signature(rng); + + send(writer, hash); + } + +/** +* Serialize a Server Key Exchange message +*/ +SecureVector Server_Key_Exchange::serialize() const + { + SecureVector buf = serialize_params(); + append_tls_length_value(buf, signature, 2); + return buf; + } + +/** +* Serialize the ServerParams structure +*/ +SecureVector Server_Key_Exchange::serialize_params() const + { + SecureVector buf; + + for(size_t i = 0; i != params.size(); ++i) + append_tls_length_value(buf, BigInt::encode(params[i]), 2); + + return buf; + } + +/** +* Deserialize a Server Key Exchange message +*/ +void Server_Key_Exchange::deserialize(const MemoryRegion& buf) + { + if(buf.size() < 6) + throw Decoding_Error("Server_Key_Exchange: Packet corrupted"); + + SecureVector values[4]; + size_t so_far = 0; + + for(size_t i = 0; i != 4; ++i) + { + const u16bit len = make_u16bit(buf[so_far], buf[so_far+1]); + so_far += 2; + + if(len + so_far > buf.size()) + throw Decoding_Error("Server_Key_Exchange: Packet corrupted"); + + values[i].resize(len); + copy_mem(&values[i][0], &buf[so_far], len); + so_far += len; + + if(i == 2 && so_far == buf.size()) + break; + } + + params.push_back(BigInt::decode(values[0])); + params.push_back(BigInt::decode(values[1])); + if(values[3].size()) + { + params.push_back(BigInt::decode(values[2])); + signature = values[3]; + } + else + signature = values[2]; + } + +/** +* Return the public key +*/ +Public_Key* Server_Key_Exchange::key() const + { + if(params.size() == 2) + return new RSA_PublicKey(params[0], params[1]); + else if(params.size() == 3) + return new DH_PublicKey(DL_Group(params[0], params[1]), params[2]); + else + throw Internal_Error("Server_Key_Exchange::key: No key set"); + } + +/** +* Verify a Server Key Exchange message +*/ +bool Server_Key_Exchange::verify(const X509_Certificate& cert, + const MemoryRegion& c_random, + const MemoryRegion& s_random) const + { + + std::auto_ptr key(cert.subject_public_key()); + + std::string padding = ""; + Signature_Format format = IEEE_1363; + + if(key->algo_name() == "RSA") + padding = "EMSA3(TLS.Digest.0)"; + else if(key->algo_name() == "DSA") + { + padding == "EMSA1(SHA-1)"; + format = DER_SEQUENCE; + } + else + throw Invalid_Argument(key->algo_name() + + " is invalid/unknown for TLS signatures"); + + PK_Verifier verifier(*key, padding, format); + + SecureVector params_got = serialize_params(); + verifier.update(c_random); + verifier.update(s_random); + verifier.update(params_got); + + return verifier.check_signature(signature); + } + +} diff --git a/src/tls/tls_alerts.h b/src/tls/tls_alerts.h new file mode 100644 index 000000000..241599aa8 --- /dev/null +++ b/src/tls/tls_alerts.h @@ -0,0 +1,54 @@ +/* +* Alert Message +* (C) 2004-2006 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_ALERT_H__ +#define BOTAN_TLS_ALERT_H__ + +#include + +namespace Botan { + +/** +* SSL/TLS Alert Message +*/ +class Alert + { + public: + /** + * @return if this alert is a fatal one or not + */ + bool is_fatal() const { return fatal; } + + /** + * @return type of alert + */ + Alert_Type type() const { return type_code; } + + /** + * Deserialize an Alert message + * @param buf the serialized alert + */ + Alert(const MemoryRegion& buf) + { + if(buf.size() != 2) + throw Decoding_Error("Alert: Bad size for alert message"); + + if(buf[0] == 1) fatal = false; + else if(buf[0] == 2) fatal = true; + else + throw Decoding_Error("Alert: Bad type code for alert level"); + + type_code = static_cast(buf[1]); + } + private: + bool fatal; + Alert_Type type_code; + }; + +} + +#endif diff --git a/src/tls/tls_client.cpp b/src/tls/tls_client.cpp new file mode 100644 index 000000000..cfa86881c --- /dev/null +++ b/src/tls/tls_client.cpp @@ -0,0 +1,499 @@ +/* +* TLS Client +* (C) 2004-2011 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/** +* Verify the state transition is allowed +* FIXME: checks are wrong for session reuse (add a flag for that) +*/ +void client_check_state(Handshake_Type new_msg, Handshake_State* state) + { + class State_Transition_Error : public Unexpected_Message + { + public: + State_Transition_Error(const std::string& err) : + Unexpected_Message("State transition error from " + err) {} + }; + + if(new_msg == HELLO_REQUEST) + { + if(state->client_hello) + throw State_Transition_Error("HelloRequest"); + } + else if(new_msg == SERVER_HELLO) + { + if(!state->client_hello || state->server_hello) + throw State_Transition_Error("ServerHello"); + } + else if(new_msg == CERTIFICATE) + { + if(!state->server_hello || state->server_kex || + state->cert_req || state->server_hello_done) + throw State_Transition_Error("ServerCertificate"); + } + else if(new_msg == SERVER_KEX) + { + if(!state->server_hello || state->server_kex || + state->cert_req || state->server_hello_done) + throw State_Transition_Error("ServerKeyExchange"); + } + else if(new_msg == CERTIFICATE_REQUEST) + { + if(!state->server_certs || state->cert_req || state->server_hello_done) + throw State_Transition_Error("CertificateRequest"); + } + else if(new_msg == SERVER_HELLO_DONE) + { + if(!state->server_hello || state->server_hello_done) + throw State_Transition_Error("ServerHelloDone"); + } + else if(new_msg == HANDSHAKE_CCS) + { + if(!state->client_finished || state->server_finished) + throw State_Transition_Error("ServerChangeCipherSpec"); + } + else if(new_msg == FINISHED) + { + if(!state->got_server_ccs) + throw State_Transition_Error("ServerFinished"); + } + else + throw Unexpected_Message("Unexpected message in handshake"); + } + +} + +/** +* TLS Client Constructor +*/ +TLS_Client::TLS_Client(std::tr1::function socket_output_fn, + std::tr1::function process_fn, + const TLS_Policy& policy, + RandomNumberGenerator& rng) : + policy(policy), + rng(rng), + proc_fn(process_fn), + writer(socket_output_fn), + state(0), + active(false) + { + writer.set_version(policy.pref_version()); + + state = new Handshake_State; + state->client_hello = new Client_Hello(rng, writer, policy, state->hash); + } + +void TLS_Client::add_client_cert(const X509_Certificate& cert, + Private_Key* cert_key) + { + certs.push_back(std::make_pair(cert, cert_key)); + } + +/** +* TLS Client Destructor +*/ +TLS_Client::~TLS_Client() + { + close(); + for(size_t i = 0; i != certs.size(); i++) + delete certs[i].second; + delete state; + } + +size_t TLS_Client::received_data(const byte buf[], size_t buf_size) + { + try + { + reader.add_input(buf, buf_size); + + byte rec_type = CONNECTION_CLOSED; + SecureVector record; + + while(!reader.currently_empty()) + { + const size_t bytes_needed = reader.get_record(rec_type, record); + + if(bytes_needed > 0) + return bytes_needed; + + if(rec_type == APPLICATION_DATA) + { + if(active) + { + proc_fn(&record[0], record.size(), NO_ALERT_TYPE); + } + else + { + throw Unexpected_Message("Application data before handshake done"); + } + } + else if(rec_type == HANDSHAKE || rec_type == CHANGE_CIPHER_SPEC) + { + read_handshake(rec_type, record); + } + else if(rec_type == ALERT) + { + Alert alert(record); + + proc_fn(0, 0, alert.type()); + + if(alert.is_fatal() || alert.type() == CLOSE_NOTIFY) + { + if(alert.type() == CLOSE_NOTIFY) + { + writer.alert(WARNING, CLOSE_NOTIFY); + } + + close(FATAL, NO_ALERT_TYPE); + } + } + else + throw Unexpected_Message("Unknown message type received"); + } + + return 0; // on a record boundary + } + catch(TLS_Exception& e) + { + close(FATAL, e.type()); + throw; + } + catch(std::exception& e) + { + close(FATAL, INTERNAL_ERROR); + throw; + } + } + +void TLS_Client::queue_for_sending(const byte buf[], size_t buf_size) + { + if(active) + { + while(!pre_handshake_write_queue.end_of_data()) + { + SecureVector q_buf(1024); + const size_t got = pre_handshake_write_queue.read(&q_buf[0], q_buf.size()); + writer.send(APPLICATION_DATA, &q_buf[0], got); + } + + writer.send(APPLICATION_DATA, buf, buf_size); + writer.flush(); + } + else + pre_handshake_write_queue.write(buf, buf_size); + } + +/** +* Close a TLS connection +*/ +void TLS_Client::close() + { + close(WARNING, CLOSE_NOTIFY); + } + +/** +* Close a TLS connection +*/ +void TLS_Client::close(Alert_Level level, Alert_Type alert_code) + { + if(active) + { + active = false; + + if(alert_code != NO_ALERT_TYPE) + { + try + { + writer.alert(level, alert_code); + writer.flush(); + } + catch(...) { /* swallow it */ } + } + + reader.reset(); + writer.reset(); + } + } + +/** +* Split up and process handshake messages +*/ +void TLS_Client::read_handshake(byte rec_type, + const MemoryRegion& rec_buf) + { + if(rec_type == HANDSHAKE) + state->queue.write(&rec_buf[0], rec_buf.size()); + + while(true) + { + Handshake_Type type = HANDSHAKE_NONE; + SecureVector contents; + + if(rec_type == HANDSHAKE) + { + if(state->queue.size() >= 4) + { + byte head[4] = { 0 }; + state->queue.peek(head, 4); + + const size_t length = make_u32bit(0, head[1], head[2], head[3]); + + if(state->queue.size() >= length + 4) + { + type = static_cast(head[0]); + contents.resize(length); + state->queue.read(head, 4); + state->queue.read(&contents[0], contents.size()); + } + } + } + else if(rec_type == CHANGE_CIPHER_SPEC) + { + if(state->queue.size() == 0 && rec_buf.size() == 1 && rec_buf[0] == 1) + type = HANDSHAKE_CCS; + else + throw Decoding_Error("Malformed ChangeCipherSpec message"); + } + else + throw Decoding_Error("Unknown message type in handshake processing"); + + if(type == HANDSHAKE_NONE) + break; + + process_handshake_msg(type, contents); + + if(type == HANDSHAKE_CCS || !state) + break; + } + } + +/** +* Process a handshake message +*/ +void TLS_Client::process_handshake_msg(Handshake_Type type, + const MemoryRegion& contents) + { + rng.add_entropy(&contents[0], contents.size()); + + if(type == HELLO_REQUEST) + { + if(state == 0) + state = new Handshake_State(); + else + return; + } + + if(state == 0) + throw Unexpected_Message("Unexpected handshake message"); + + if(type != HANDSHAKE_CCS && type != HELLO_REQUEST && type != FINISHED) + { + state->hash.update(static_cast(type)); + const size_t record_length = contents.size(); + for(size_t i = 0; i != 3; i++) + state->hash.update(get_byte(i+1, record_length)); + state->hash.update(contents); + } + + if(type == HELLO_REQUEST) + { + client_check_state(type, state); + + Hello_Request hello_request(contents); + state->client_hello = new Client_Hello(rng, writer, policy, state->hash); + } + else if(type == SERVER_HELLO) + { + client_check_state(type, state); + + state->server_hello = new Server_Hello(contents); + + if(!state->client_hello->offered_suite( + state->server_hello->ciphersuite() + ) + ) + throw TLS_Exception(HANDSHAKE_FAILURE, + "TLS_Client: Server replied with bad ciphersuite"); + + state->version = state->server_hello->version(); + + if(state->version > state->client_hello->version()) + throw TLS_Exception(HANDSHAKE_FAILURE, + "TLS_Client: Server replied with bad version"); + + if(state->version < policy.min_version()) + throw TLS_Exception(PROTOCOL_VERSION, + "TLS_Client: Server is too old for specified policy"); + + writer.set_version(state->version); + reader.set_version(state->version); + + state->suite = CipherSuite(state->server_hello->ciphersuite()); + } + else if(type == CERTIFICATE) + { + client_check_state(type, state); + + if(state->suite.sig_type() == TLS_ALGO_SIGNER_ANON) + throw Unexpected_Message("Recived certificate from anonymous server"); + + state->server_certs = new Certificate(contents); + + peer_certs = state->server_certs->cert_chain(); + if(peer_certs.size() == 0) + throw TLS_Exception(HANDSHAKE_FAILURE, + "TLS_Client: No certificates sent by server"); + + if(!policy.check_cert(peer_certs)) + throw TLS_Exception(BAD_CERTIFICATE, + "TLS_Client: Server certificate is not valid"); + + state->kex_pub = peer_certs[0].subject_public_key(); + + bool is_dsa = false, is_rsa = false; + + if(dynamic_cast(state->kex_pub)) + is_dsa = true; + else if(dynamic_cast(state->kex_pub)) + is_rsa = true; + else + throw TLS_Exception(UNSUPPORTED_CERTIFICATE, + "Unknown key type received in server kex"); + + if((is_dsa && state->suite.sig_type() != TLS_ALGO_SIGNER_DSA) || + (is_rsa && state->suite.sig_type() != TLS_ALGO_SIGNER_RSA)) + throw TLS_Exception(ILLEGAL_PARAMETER, + "Certificate key type did not match ciphersuite"); + } + else if(type == SERVER_KEX) + { + client_check_state(type, state); + + if(state->suite.kex_type() == TLS_ALGO_KEYEXCH_NOKEX) + throw Unexpected_Message("Unexpected key exchange from server"); + + state->server_kex = new Server_Key_Exchange(contents); + + if(state->kex_pub) + delete state->kex_pub; + + state->kex_pub = state->server_kex->key(); + + bool is_dh = false, is_rsa = false; + + if(dynamic_cast(state->kex_pub)) + is_dh = true; + else if(dynamic_cast(state->kex_pub)) + is_rsa = true; + else + throw TLS_Exception(HANDSHAKE_FAILURE, + "Unknown key type received in server kex"); + + if((is_dh && state->suite.kex_type() != TLS_ALGO_KEYEXCH_DH) || + (is_rsa && state->suite.kex_type() != TLS_ALGO_KEYEXCH_RSA)) + throw TLS_Exception(ILLEGAL_PARAMETER, + "Certificate key type did not match ciphersuite"); + + if(state->suite.sig_type() != TLS_ALGO_SIGNER_ANON) + { + if(!state->server_kex->verify(peer_certs[0], + state->client_hello->random(), + state->server_hello->random())) + throw TLS_Exception(DECRYPT_ERROR, + "Bad signature on server key exchange"); + } + } + else if(type == CERTIFICATE_REQUEST) + { + client_check_state(type, state); + + state->cert_req = new Certificate_Req(contents); + state->do_client_auth = true; + } + else if(type == SERVER_HELLO_DONE) + { + client_check_state(type, state); + + state->server_hello_done = new Server_Hello_Done(contents); + + if(state->do_client_auth) + { + std::vector send_certs; + + std::vector types = + state->cert_req->acceptable_types(); + + // FIXME: Fill in useful certs here, if any + state->client_certs = new Certificate(writer, send_certs, + state->hash); + } + + state->client_kex = + new Client_Key_Exchange(rng, writer, state->hash, + state->kex_pub, state->version, + state->client_hello->version()); + + if(state->do_client_auth) + { + Private_Key* key_matching_cert = 0; // FIXME + state->client_verify = new Certificate_Verify(rng, + writer, state->hash, + key_matching_cert); + } + + state->keys = SessionKeys(state->suite, state->version, + state->client_kex->pre_master_secret(), + state->client_hello->random(), + state->server_hello->random()); + + writer.send(CHANGE_CIPHER_SPEC, 1); + writer.flush(); + + writer.set_keys(state->suite, state->keys, CLIENT); + + state->client_finished = new Finished(writer, state->version, CLIENT, + state->keys.master_secret(), + state->hash); + } + else if(type == HANDSHAKE_CCS) + { + client_check_state(type, state); + + reader.set_keys(state->suite, state->keys, CLIENT); + state->got_server_ccs = true; + } + else if(type == FINISHED) + { + client_check_state(type, state); + + state->server_finished = new Finished(contents); + + if(!state->server_finished->verify(state->keys.master_secret(), + state->version, state->hash, SERVER)) + throw TLS_Exception(DECRYPT_ERROR, + "Finished message didn't verify"); + + delete state; + state = 0; + active = true; + } + else + throw Unexpected_Message("Unknown handshake message received"); + } + +} diff --git a/src/tls/tls_client.h b/src/tls/tls_client.h new file mode 100644 index 000000000..6d613be33 --- /dev/null +++ b/src/tls/tls_client.h @@ -0,0 +1,87 @@ +/* +* TLS Client +* (C) 2004-2011 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_CLIENT_H__ +#define BOTAN_TLS_CLIENT_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* SSL/TLS Client +*/ +class BOTAN_DLL TLS_Client + { + public: + /** + * Set up a new TLS client session + */ + TLS_Client(std::tr1::function socket_output_fn, + std::tr1::function proc_fn, + const TLS_Policy& policy, + RandomNumberGenerator& rng); + + /** + * Inject TLS traffic received from counterparty + + * @return a hint as the how many more bytes we need to process the + current record (this may be 0 if on a record boundary) + */ + size_t received_data(const byte buf[], size_t buf_size); + + /** + * Inject plaintext intended for counterparty + */ + void queue_for_sending(const byte buf[], size_t buf_size); + + void close(); + + bool handshake_complete() const { return active; } + + std::vector peer_cert_chain() const { return peer_certs; } + + void add_client_cert(const X509_Certificate& cert, + Private_Key* cert_key); + + ~TLS_Client(); + private: + void close(Alert_Level, Alert_Type); + + size_t get_pending_socket_input(byte output[], size_t length); + + void initialize(); + void do_handshake(); + + void state_machine(); + void read_handshake(byte, const MemoryRegion&); + void process_handshake_msg(Handshake_Type, const MemoryRegion&); + + const TLS_Policy& policy; + RandomNumberGenerator& rng; + + std::tr1::function proc_fn; + + Record_Writer writer; + Record_Reader reader; + + SecureQueue pre_handshake_write_queue; + + std::vector peer_certs; + std::vector > certs; + + class Handshake_State* state; + //SecureVector session_id; + bool active; + }; + +} + +#endif diff --git a/src/tls/tls_exceptn.h b/src/tls/tls_exceptn.h new file mode 100644 index 000000000..37b9c0d27 --- /dev/null +++ b/src/tls/tls_exceptn.h @@ -0,0 +1,43 @@ +/* +* Exceptions +* (C) 2004-2006 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_EXCEPTION_H__ +#define BOTAN_TLS_EXCEPTION_H__ + +#include +#include + +namespace Botan { + +/** +* Exception Base Class +*/ +class BOTAN_DLL TLS_Exception : public Exception + { + public: + Alert_Type type() const throw() { return alert_type; } + + TLS_Exception(Alert_Type type, + const std::string& err_msg = "Unknown error") : + Exception(err_msg), alert_type(type) {} + + private: + Alert_Type alert_type; + }; + +/** +* Unexpected_Message Exception +*/ +struct BOTAN_DLL Unexpected_Message : public TLS_Exception + { + Unexpected_Message(const std::string& err) : + TLS_Exception(UNEXPECTED_MESSAGE, err) {} + }; + +} + +#endif diff --git a/src/tls/tls_handshake_hash.cpp b/src/tls/tls_handshake_hash.cpp new file mode 100644 index 000000000..7c1e2e385 --- /dev/null +++ b/src/tls/tls_handshake_hash.cpp @@ -0,0 +1,70 @@ +/* +* TLS Handshake Hash +* (C) 2004-2006 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +/** +* Return a TLS Handshake Hash +*/ +SecureVector HandshakeHash::final() + { + MD5 md5; + SHA_160 sha1; + + md5.update(data); + sha1.update(data); + + SecureVector output; + output += md5.final(); + output += sha1.final(); + return output; + } + +/** +* Return a SSLv3 Handshake Hash +*/ +SecureVector HandshakeHash::final_ssl3(const MemoryRegion& secret) + { + const byte PAD_INNER = 0x36, PAD_OUTER = 0x5C; + + MD5 md5; + SHA_160 sha1; + + md5.update(data); + sha1.update(data); + + md5.update(secret); + sha1.update(secret); + + for(size_t i = 0; i != 48; ++i) + md5.update(PAD_INNER); + for(size_t i = 0; i != 40; ++i) + sha1.update(PAD_INNER); + + SecureVector inner_md5 = md5.final(), inner_sha1 = sha1.final(); + + md5.update(secret); + sha1.update(secret); + for(size_t i = 0; i != 48; ++i) + md5.update(PAD_OUTER); + for(size_t i = 0; i != 40; ++i) + sha1.update(PAD_OUTER); + md5.update(inner_md5); + sha1.update(inner_sha1); + + SecureVector output; + output += md5.final(); + output += sha1.final(); + return output; + } + +} diff --git a/src/tls/tls_handshake_hash.h b/src/tls/tls_handshake_hash.h new file mode 100644 index 000000000..cea612a71 --- /dev/null +++ b/src/tls/tls_handshake_hash.h @@ -0,0 +1,40 @@ +/* +* TLS Handshake Hash +* (C) 2004-2006 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_HANDSHAKE_HASH_H__ +#define BOTAN_TLS_HANDSHAKE_HASH_H__ + +#include + +namespace Botan { + +using namespace Botan; + +/** +* TLS Handshake Hash +*/ +class HandshakeHash + { + public: + void update(const byte in[], size_t length) + { data += std::make_pair(in, length); } + + void update(const MemoryRegion& in) + { data += in; } + + void update(byte in) + { data.push_back(in); } + + SecureVector final(); + SecureVector final_ssl3(const MemoryRegion&); + private: + SecureVector data; + }; + +} + +#endif diff --git a/src/tls/tls_magic.h b/src/tls/tls_magic.h new file mode 100644 index 000000000..00898738e --- /dev/null +++ b/src/tls/tls_magic.h @@ -0,0 +1,192 @@ +/* +* SSL/TLS Protocol Constants +* (C) 2004-2010 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_PROTOCOL_MAGIC_H__ +#define BOTAN_TLS_PROTOCOL_MAGIC_H__ + +namespace Botan { + +/** +* Protocol Constants for SSL/TLS +*/ +enum Size_Limits { + MAX_PLAINTEXT_SIZE = 16*1024, + MAX_COMPRESSED_SIZE = MAX_PLAINTEXT_SIZE + 1024, + MAX_CIPHERTEXT_SIZE = MAX_COMPRESSED_SIZE + 1024 +}; + +enum Version_Code { + NO_VERSION_SET = 0x0000, + SSL_V3 = 0x0300, + TLS_V10 = 0x0301, + TLS_V11 = 0x0302 +}; + +enum Connection_Side { CLIENT, SERVER }; + +enum Record_Type { + CONNECTION_CLOSED = 0, + + CHANGE_CIPHER_SPEC = 20, + ALERT = 21, + HANDSHAKE = 22, + APPLICATION_DATA = 23 +}; + +enum Handshake_Type { + HELLO_REQUEST = 0, + CLIENT_HELLO = 1, + CLIENT_HELLO_SSLV2 = 255, // not a wire value + SERVER_HELLO = 2, + CERTIFICATE = 11, + SERVER_KEX = 12, + CERTIFICATE_REQUEST = 13, + SERVER_HELLO_DONE = 14, + CERTIFICATE_VERIFY = 15, + CLIENT_KEX = 16, + FINISHED = 20, + + HANDSHAKE_CCS = 100, + HANDSHAKE_NONE = 101 +}; + +enum Alert_Level { + WARNING = 1, + FATAL = 2 +}; + +enum Alert_Type { + CLOSE_NOTIFY = 0, + UNEXPECTED_MESSAGE = 10, + BAD_RECORD_MAC = 20, + DECRYPTION_FAILED = 21, + RECORD_OVERFLOW = 22, + DECOMPRESSION_FAILURE = 30, + HANDSHAKE_FAILURE = 40, + BAD_CERTIFICATE = 42, + UNSUPPORTED_CERTIFICATE = 43, + CERTIFICATE_REVOKED = 44, + CERTIFICATE_EXPIRED = 45, + CERTIFICATE_UNKNOWN = 46, + ILLEGAL_PARAMETER = 47, + UNKNOWN_CA = 48, + ACCESS_DENIED = 49, + DECODE_ERROR = 50, + DECRYPT_ERROR = 51, + EXPORT_RESTRICTION = 60, + PROTOCOL_VERSION = 70, + INSUFFICIENT_SECURITY = 71, + INTERNAL_ERROR = 80, + USER_CANCELED = 90, + NO_RENEGOTIATION = 100, + + UNKNOWN_PSK_IDENTITY = 115, + + NO_ALERT_TYPE = 0xFFFF +}; + +enum Certificate_Type { + RSA_CERT = 1, + DSS_CERT = 2, + DH_RSA_CERT = 3, + DH_DSS_CERT = 4 +}; + +enum Ciphersuite_Code { + TLS_RSA_WITH_RC4_128_MD5 = 0x0004, + TLS_RSA_WITH_RC4_128_SHA = 0x0005, + + TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x000A, + TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F, + TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035, + TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003C, + TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x003D, + TLS_RSA_WITH_SEED_CBC_SHA = 0x0096, + + TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x0013, + TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x0032, + TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x0038, + TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x0040, + TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = 0x006A, + TLS_DHE_DSS_WITH_SEED_CBC_SHA = 0x0099, + + TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x0016, + TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033, + TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039, + TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067, + TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B, + TLS_DHE_RSA_WITH_SEED_CBC_SHA = 0x009A, + + TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = 0xC007, + TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA = 0xC008, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009, + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023, + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024, + + TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xC011, + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = 0xC012, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013, + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027, + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028 +}; + +/* +* Form of the ciphersuites broken down by field instead of +* being randomly assigned codepoints. +*/ +enum TLS_Ciphersuite_Algos { + TLS_ALGO_SIGNER_MASK = 0xFF000000, + TLS_ALGO_SIGNER_ANON = 0x01000000, + TLS_ALGO_SIGNER_RSA = 0x02000000, + TLS_ALGO_SIGNER_DSA = 0x03000000, + TLS_ALGO_SIGNER_ECDSA = 0x04000000, + + TLS_ALGO_KEYEXCH_MASK = 0x00FF0000, + TLS_ALGO_KEYEXCH_NOKEX = 0x00010000, + TLS_ALGO_KEYEXCH_RSA = 0x00020000, + TLS_ALGO_KEYEXCH_DH = 0x00030000, + TLS_ALGO_KEYEXCH_ECDH = 0x00040000, + + TLS_ALGO_MAC_MASK = 0x0000FF00, + TLS_ALGO_MAC_MD5 = 0x00000100, + TLS_ALGO_MAC_SHA1 = 0x00000200, + TLS_ALGO_MAC_SHA256 = 0x00000300, + TLS_ALGO_MAC_SHA384 = 0x00000400, + + TLS_ALGO_CIPHER_MASK = 0x000000FF, + TLS_ALGO_CIPHER_RC4_128 = 0x00000001, + TLS_ALGO_CIPHER_3DES_CBC = 0x00000002, + TLS_ALGO_CIPHER_AES128_CBC = 0x00000003, + TLS_ALGO_CIPHER_AES256_CBC = 0x00000004, + TLS_ALGO_CIPHER_SEED_CBC = 0x00000005 +}; + +enum Compression_Algo { + NO_COMPRESSION = 0x00 +}; + +enum TLS_Handshake_Extension_Type { + TLSEXT_SERVER_NAME_INDICATION = 0, + TLSEXT_MAX_FRAGMENT_LENGTH = 1, + TLSEXT_CLIENT_CERT_URL = 2, + TLSEXT_TRUSTED_CA_KEYS = 3, + TLSEXT_TRUNCATED_HMAC = 4, + + TLSEXT_USABLE_ELLIPTIC_CURVES = 10, + TLSEXT_EC_POINT_FORMATS = 11, + + TLSEXT_SRP_IDENTIFIER = 12, + + TLSEXT_CERTIFICATE_TYPES = 9, + TLSEXT_SESSION_TICKET = 35 +}; + +} + +#endif diff --git a/src/tls/tls_messages.h b/src/tls/tls_messages.h new file mode 100644 index 000000000..e7eaa56e1 --- /dev/null +++ b/src/tls/tls_messages.h @@ -0,0 +1,297 @@ +/* +* TLS Messages +* (C) 2004-2010 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_MESSAGES_H__ +#define BOTAN_TLS_MESSAGES_H__ + +#include +#include +#include +#include +#include +#include +#include + +namespace Botan { + +/** +* TLS Handshake Message Base Class +*/ +class HandshakeMessage + { + public: + void send(Record_Writer&, HandshakeHash&) const; + + virtual Handshake_Type type() const = 0; + + virtual ~HandshakeMessage() {} + private: + HandshakeMessage& operator=(const HandshakeMessage&) { return (*this); } + virtual SecureVector serialize() const = 0; + virtual void deserialize(const MemoryRegion&) = 0; + }; + +/** +* Client Hello Message +*/ +class Client_Hello : public HandshakeMessage + { + public: + Handshake_Type type() const { return CLIENT_HELLO; } + Version_Code version() const { return c_version; } + const SecureVector& session_id() const { return sess_id; } + std::vector ciphersuites() const { return suites; } + std::vector compression_algos() const { return comp_algos; } + + const SecureVector& random() const { return c_random; } + + std::string hostname() const { return requested_hostname; } + + std::string srp_identifier() const { return requested_srp_id; } + + bool offered_suite(u16bit) const; + + Client_Hello(RandomNumberGenerator& rng, + Record_Writer&, const TLS_Policy&, HandshakeHash&); + + Client_Hello(const MemoryRegion& buf, + Handshake_Type type) + { + if(type == CLIENT_HELLO) + deserialize(buf); + else + deserialize_sslv2(buf); + } + + private: + SecureVector serialize() const; + void deserialize(const MemoryRegion&); + void deserialize_sslv2(const MemoryRegion&); + + Version_Code c_version; + SecureVector sess_id, c_random; + std::vector suites; + std::vector comp_algos; + std::string requested_hostname; + std::string requested_srp_id; + }; + +/** +* Client Key Exchange Message +*/ +class Client_Key_Exchange : public HandshakeMessage + { + public: + Handshake_Type type() const { return CLIENT_KEX; } + + SecureVector pre_master_secret() const; + + SecureVector pre_master_secret(RandomNumberGenerator& rng, + const Private_Key* key, + Version_Code version); + + Client_Key_Exchange(RandomNumberGenerator& rng, + Record_Writer& output, + HandshakeHash& hash, + const Public_Key* my_key, + Version_Code using_version, + Version_Code pref_version); + + Client_Key_Exchange(const MemoryRegion& buf, + const CipherSuite& suite, + Version_Code using_version); + private: + SecureVector serialize() const; + void deserialize(const MemoryRegion&); + + SecureVector key_material, pre_master; + bool include_length; + }; + +/** +* Certificate Message +*/ +class Certificate : public HandshakeMessage + { + public: + Handshake_Type type() const { return CERTIFICATE; } + std::vector cert_chain() const { return certs; } + + Certificate(Record_Writer&, const std::vector&, + HandshakeHash&); + Certificate(const MemoryRegion& buf) { deserialize(buf); } + private: + SecureVector serialize() const; + void deserialize(const MemoryRegion&); + std::vector certs; + }; + +/** +* Certificate Request Message +*/ +class Certificate_Req : public HandshakeMessage + { + public: + Handshake_Type type() const { return CERTIFICATE_REQUEST; } + + std::vector acceptable_types() const { return types; } + std::vector acceptable_CAs() const { return names; } + + /* TODO + Certificate_Req(Record_Writer&, HandshakeHash&, + const X509_Certificate&); + */ + Certificate_Req(Record_Writer&, HandshakeHash&, + const std::vector&); + + Certificate_Req(const MemoryRegion& buf) { deserialize(buf); } + private: + SecureVector serialize() const; + void deserialize(const MemoryRegion&); + + std::vector names; + std::vector types; + }; + +/** +* Certificate Verify Message +*/ +class Certificate_Verify : public HandshakeMessage + { + public: + Handshake_Type type() const { return CERTIFICATE_VERIFY; } + + bool verify(const X509_Certificate&, HandshakeHash&); + + Certificate_Verify(RandomNumberGenerator& rng, + Record_Writer&, HandshakeHash&, + const Private_Key*); + + Certificate_Verify(const MemoryRegion& buf) { deserialize(buf); } + private: + SecureVector serialize() const; + void deserialize(const MemoryRegion&); + + SecureVector signature; + }; + +/** +* Finished Message +*/ +class Finished : public HandshakeMessage + { + public: + Handshake_Type type() const { return FINISHED; } + + bool verify(const MemoryRegion&, Version_Code, + const HandshakeHash&, Connection_Side); + + Finished(Record_Writer&, Version_Code, Connection_Side, + const MemoryRegion&, HandshakeHash&); + Finished(const MemoryRegion& buf) { deserialize(buf); } + private: + SecureVector serialize() const; + void deserialize(const MemoryRegion&); + + SecureVector compute_verify(const MemoryRegion&, + HandshakeHash, Connection_Side, + Version_Code); + + Connection_Side side; + SecureVector verification_data; + }; + +/** +* Hello Request Message +*/ +class Hello_Request : public HandshakeMessage + { + public: + Handshake_Type type() const { return HELLO_REQUEST; } + + Hello_Request(Record_Writer&); + Hello_Request(const MemoryRegion& buf) { deserialize(buf); } + private: + SecureVector serialize() const; + void deserialize(const MemoryRegion&); + }; + +/** +* Server Hello Message +*/ +class Server_Hello : public HandshakeMessage + { + public: + Handshake_Type type() const { return SERVER_HELLO; } + Version_Code version() { return s_version; } + const SecureVector& session_id() const { return sess_id; } + u16bit ciphersuite() const { return suite; } + byte compression_algo() const { return comp_algo; } + + const SecureVector& random() const { return s_random; } + + Server_Hello(RandomNumberGenerator& rng, + Record_Writer&, const TLS_Policy&, + const std::vector&, + const Client_Hello&, Version_Code, HandshakeHash&); + + Server_Hello(const MemoryRegion& buf) { deserialize(buf); } + private: + SecureVector serialize() const; + void deserialize(const MemoryRegion&); + + Version_Code s_version; + SecureVector sess_id, s_random; + u16bit suite; + byte comp_algo; + }; + +/** +* Server Key Exchange Message +*/ +class Server_Key_Exchange : public HandshakeMessage + { + public: + Handshake_Type type() const { return SERVER_KEX; } + Public_Key* key() const; + + bool verify(const X509_Certificate&, const MemoryRegion&, + const MemoryRegion&) const; + + Server_Key_Exchange(RandomNumberGenerator& rng, + Record_Writer&, const Public_Key*, + const Private_Key*, const MemoryRegion&, + const MemoryRegion&, HandshakeHash&); + + Server_Key_Exchange(const MemoryRegion& buf) { deserialize(buf); } + private: + SecureVector serialize() const; + SecureVector serialize_params() const; + void deserialize(const MemoryRegion&); + + std::vector params; + SecureVector signature; + }; + +/** +* Server Hello Done Message +*/ +class Server_Hello_Done : public HandshakeMessage + { + public: + Handshake_Type type() const { return SERVER_HELLO_DONE; } + + Server_Hello_Done(Record_Writer&, HandshakeHash&); + Server_Hello_Done(const MemoryRegion& buf) { deserialize(buf); } + private: + SecureVector serialize() const; + void deserialize(const MemoryRegion&); + }; + +} + +#endif diff --git a/src/tls/tls_policy.cpp b/src/tls/tls_policy.cpp new file mode 100644 index 000000000..b73ff7850 --- /dev/null +++ b/src/tls/tls_policy.cpp @@ -0,0 +1,118 @@ +/* +* Policies for TLS +* (C) 2004-2010 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/* +* Return allowed ciphersuites +*/ +std::vector TLS_Policy::ciphersuites() const + { + return suite_list(allow_static_rsa(), allow_edh_rsa(), allow_edh_dsa()); + } + +/* +* Return allowed ciphersuites +*/ +std::vector TLS_Policy::suite_list(bool use_rsa, + bool use_edh_rsa, + bool use_edh_dsa) const + { + std::vector suites; + + if(use_edh_dsa) + { + suites.push_back(TLS_DHE_DSS_WITH_AES_256_CBC_SHA); + suites.push_back(TLS_DHE_DSS_WITH_AES_128_CBC_SHA); + suites.push_back(TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA); + suites.push_back(TLS_DHE_DSS_WITH_SEED_CBC_SHA); + } + + if(use_edh_rsa) + { + suites.push_back(TLS_DHE_RSA_WITH_AES_256_CBC_SHA); + suites.push_back(TLS_DHE_RSA_WITH_AES_128_CBC_SHA); + suites.push_back(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA); + suites.push_back(TLS_DHE_RSA_WITH_SEED_CBC_SHA); + } + + if(use_rsa) + { + suites.push_back(TLS_RSA_WITH_AES_256_CBC_SHA); + suites.push_back(TLS_RSA_WITH_AES_128_CBC_SHA); + suites.push_back(TLS_RSA_WITH_3DES_EDE_CBC_SHA); + suites.push_back(TLS_RSA_WITH_SEED_CBC_SHA); + suites.push_back(TLS_RSA_WITH_RC4_128_SHA); + suites.push_back(TLS_RSA_WITH_RC4_128_MD5); + } + + if(suites.size() == 0) + throw TLS_Exception(INTERNAL_ERROR, + "TLS_Policy error: All ciphersuites disabled"); + + return suites; + } + +/* +* Return allowed compression algorithms +*/ +std::vector TLS_Policy::compression() const + { + std::vector algs; + algs.push_back(NO_COMPRESSION); + return algs; + } + +/* +* Choose which ciphersuite to use +*/ +u16bit TLS_Policy::choose_suite(const std::vector& c_suites, + bool have_rsa, + bool have_dsa) const + { + bool use_static_rsa = allow_static_rsa() && have_rsa; + bool use_edh_rsa = allow_edh_rsa() && have_rsa; + bool use_edh_dsa = allow_edh_dsa() && have_dsa; + + std::vector s_suites = suite_list(use_static_rsa, use_edh_rsa, + use_edh_dsa); + + for(size_t i = 0; i != s_suites.size(); ++i) + for(size_t j = 0; j != c_suites.size(); ++j) + if(s_suites[i] == c_suites[j]) + return s_suites[i]; + + return 0; + } + +/* +* Choose which compression algorithm to use +*/ +byte TLS_Policy::choose_compression(const std::vector& c_comp) const + { + std::vector s_comp = compression(); + + for(size_t i = 0; i != s_comp.size(); ++i) + for(size_t j = 0; j != c_comp.size(); ++j) + if(s_comp[i] == c_comp[j]) + return s_comp[i]; + + return NO_COMPRESSION; + } + +/* +* Return the group to use for empheral DH +*/ +DL_Group TLS_Policy::dh_group() const + { + return DL_Group("modp/ietf/1024"); + } + +} diff --git a/src/tls/tls_policy.h b/src/tls/tls_policy.h new file mode 100644 index 000000000..461164d2f --- /dev/null +++ b/src/tls/tls_policy.h @@ -0,0 +1,63 @@ +/* +* Policies +* (C) 2004-2006 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_POLICY_H__ +#define BOTAN_TLS_POLICY_H__ + +#include +#include +#include +#include + +namespace Botan { + +/** +* TLS Policy Base Class +* Inherit and overload as desired to suite local policy concerns +*/ +class BOTAN_DLL TLS_Policy + { + public: + std::vector ciphersuites() const; + virtual std::vector compression() const; + + virtual u16bit choose_suite(const std::vector& client_suites, + bool rsa_ok, + bool dsa_ok) const; + + virtual byte choose_compression(const std::vector& client) const; + + virtual bool allow_static_rsa() const { return true; } + virtual bool allow_edh_rsa() const { return true; } + virtual bool allow_edh_dsa() const { return true; } + virtual bool require_client_auth() const { return false; } + + virtual DL_Group dh_group() const; + virtual size_t rsa_export_keysize() const { return 512; } + + /* + * @return the minimum version that we will negotiate + */ + virtual Version_Code min_version() const { return SSL_V3; } + + /* + * @return the version we would prefer to negotiate + */ + virtual Version_Code pref_version() const { return TLS_V11; } + + virtual bool check_cert(const std::vector& cert_chain) const = 0; + + virtual ~TLS_Policy() {} + private: + virtual std::vector suite_list(bool use_rsa, + bool use_edh_rsa, + bool use_edh_dsa) const; + }; + +} + +#endif diff --git a/src/tls/tls_reader.h b/src/tls/tls_reader.h new file mode 100644 index 000000000..3a45235b5 --- /dev/null +++ b/src/tls/tls_reader.h @@ -0,0 +1,186 @@ +/* +* TLS Data Reader +* (C) 2010 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_READER_H__ +#define BOTAN_TLS_READER_H__ + +#include +#include + +namespace Botan { + +/** +* Helper class for decoding TLS protocol messages +*/ +class TLS_Data_Reader + { + public: + TLS_Data_Reader(const MemoryRegion& buf_in) : + buf(buf_in), offset(0) {} + + size_t remaining_bytes() const + { + return buf.size() - offset; + } + + bool has_remaining() const + { + return (remaining_bytes() > 0); + } + + void discard_next(size_t bytes) + { + assert_at_least(bytes); + offset += bytes; + } + + u16bit get_u16bit() + { + assert_at_least(2); + u16bit result = make_u16bit(buf[offset], buf[offset+1]); + offset += 2; + return result; + } + + byte get_byte() + { + assert_at_least(1); + byte result = buf[offset]; + offset += 1; + return result; + } + + template + Container get_elem(size_t num_elems) + { + assert_at_least(num_elems * sizeof(T)); + + Container result(num_elems); + + for(size_t i = 0; i != num_elems; ++i) + result[i] = load_be(&buf[offset], i); + + offset += num_elems * sizeof(T); + + return result; + } + + template + SecureVector get_range(size_t len_bytes, + size_t min_elems, + size_t max_elems) + { + const size_t num_elems = + get_num_elems(len_bytes, sizeof(T), min_elems, max_elems); + + return get_elem >(num_elems); + } + + template + std::vector get_range_vector(size_t len_bytes, + size_t min_elems, + size_t max_elems) + { + const size_t num_elems = + get_num_elems(len_bytes, sizeof(T), min_elems, max_elems); + + return get_elem >(num_elems); + } + + template + SecureVector get_fixed(size_t size) + { + return get_elem >(size); + } + + private: + size_t get_length_field(size_t len_bytes) + { + assert_at_least(len_bytes); + + if(len_bytes == 1) + return get_byte(); + else if(len_bytes == 2) + return get_u16bit(); + + throw Decoding_Error("TLS_Data_Reader: Bad length size"); + } + + size_t get_num_elems(size_t len_bytes, + size_t T_size, + size_t min_elems, + size_t max_elems) + { + const size_t byte_length = get_length_field(len_bytes); + + if(byte_length % T_size != 0) + throw Decoding_Error("TLS_Data_Reader: Size isn't multiple of T"); + + const size_t num_elems = byte_length / T_size; + + if(num_elems < min_elems || num_elems > max_elems) + throw Decoding_Error("TLS_Data_Reader: Range outside paramaters"); + + return num_elems; + } + + void assert_at_least(size_t n) const + { + if(buf.size() - offset < n) + throw Decoding_Error("TLS_Data_Reader: Corrupt packet"); + } + + const MemoryRegion& buf; + size_t offset; + }; + +/** +* Helper function for encoding length-tagged vectors +*/ +template +void append_tls_length_value(MemoryRegion& buf, + const T* vals, + size_t vals_size, + size_t tag_size) + { + const size_t T_size = sizeof(T); + const size_t val_bytes = T_size * vals_size; + + if(tag_size != 1 && tag_size != 2) + throw std::invalid_argument("append_tls_length_value: invalid tag size"); + + if((tag_size == 1 && val_bytes > 255) || + (tag_size == 2 && val_bytes > 65535)) + throw std::invalid_argument("append_tls_length_value: value too large"); + + for(size_t i = 0; i != tag_size; ++i) + buf.push_back(get_byte(sizeof(val_bytes)-tag_size+i, val_bytes)); + + for(size_t i = 0; i != vals_size; ++i) + for(size_t j = 0; j != T_size; ++j) + buf.push_back(get_byte(j, vals[i])); + } + +template +void append_tls_length_value(MemoryRegion& buf, + const MemoryRegion& vals, + size_t tag_size) + { + append_tls_length_value(buf, &vals[0], vals.size(), tag_size); + } + +template +void append_tls_length_value(MemoryRegion& buf, + const std::vector& vals, + size_t tag_size) + { + append_tls_length_value(buf, &vals[0], vals.size(), tag_size); + } + +} + +#endif diff --git a/src/tls/tls_record.h b/src/tls/tls_record.h new file mode 100644 index 000000000..6d5dd057d --- /dev/null +++ b/src/tls/tls_record.h @@ -0,0 +1,119 @@ +/* +* TLS Record Handling +* (C) 2004-2010 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_RECORDS_H__ +#define BOTAN_TLS_RECORDS_H__ + +#include +#include +#include +#include +#include +#include + +#if defined(BOTAN_USE_STD_TR1) + +#if defined(BOTAN_BUILD_COMPILER_IS_MSVC) + #include +#else + #include +#endif + +#elif defined(BOTAN_USE_BOOST_TR1) + #include +#else + #error "No TR1 library defined for use" +#endif + +namespace Botan { + +using namespace std::tr1::placeholders; + +/** +* TLS Record Writer +*/ +class BOTAN_DLL Record_Writer + { + public: + void send(byte type, const byte input[], size_t length); + void send(byte type, byte val) { send(type, &val, 1); } + + void flush(); + + void alert(Alert_Level, Alert_Type); + + void set_keys(const CipherSuite&, const SessionKeys&, Connection_Side); + + void set_version(Version_Code); + + void reset(); + + Record_Writer(std::tr1::function output_fn); + + ~Record_Writer() { delete mac; } + private: + void send_record(byte type, const byte input[], size_t length); + void send_record(byte type, byte major, byte minor, + const byte input[], size_t length); + + std::tr1::function output_fn; + Pipe cipher; + MessageAuthenticationCode* mac; + + SecureVector buffer; + size_t buf_pos; + + size_t block_size, mac_size, iv_size; + + u64bit seq_no; + byte major, minor, buf_type; + }; + +/** +* TLS Record Reader +*/ +class BOTAN_DLL Record_Reader + { + public: + void add_input(const byte input[], size_t input_size); + + /** + * @param msg_type (output variable) + * @param buffer (output variable) + * @return Number of bytes still needed (minimum), or 0 if success + */ + size_t get_record(byte& msg_type, + MemoryRegion& buffer); + + SecureVector get_record(byte& msg_type); + + void set_keys(const CipherSuite& suite, + const SessionKeys& keys, + Connection_Side side); + + void set_version(Version_Code version); + + void reset(); + + bool currently_empty() const { return input_queue.size() == 0; } + + Record_Reader() { mac = 0; reset(); } + + ~Record_Reader() { delete mac; } + private: + SecureQueue input_queue; + + Pipe cipher; + MessageAuthenticationCode* mac; + size_t block_size, mac_size, iv_size; + u64bit seq_no; + byte major, minor; + }; + +} + +#endif diff --git a/src/tls/tls_server.cpp b/src/tls/tls_server.cpp new file mode 100644 index 000000000..8964be3d7 --- /dev/null +++ b/src/tls/tls_server.cpp @@ -0,0 +1,494 @@ +/* +* TLS Server +* (C) 2004-2010 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +/* +* Choose what version to respond with +*/ +Version_Code choose_version(Version_Code client, Version_Code minimum) + { + if(client < minimum) + throw TLS_Exception(PROTOCOL_VERSION, + "Client version is unacceptable by policy"); + + if(client == SSL_V3 || client == TLS_V10 || client == TLS_V11) + return client; + return TLS_V11; + } + +// FIXME: checks are wrong for session reuse (add a flag for that) +/* +* Verify the state transition is allowed +*/ +void server_check_state(Handshake_Type new_msg, Handshake_State* state) + { + class State_Transition_Error : public Unexpected_Message + { + public: + State_Transition_Error(const std::string& err) : + Unexpected_Message("State transition error from " + err) {} + }; + + if(new_msg == CLIENT_HELLO || new_msg == CLIENT_HELLO_SSLV2) + { + if(state->server_hello) + throw State_Transition_Error("ClientHello"); + } + else if(new_msg == CERTIFICATE) + { + if(!state->do_client_auth || !state->cert_req || + !state->server_hello_done || state->client_kex) + throw State_Transition_Error("ClientCertificate"); + } + else if(new_msg == CLIENT_KEX) + { + if(!state->server_hello_done || state->client_verify || + state->got_client_ccs) + throw State_Transition_Error("ClientKeyExchange"); + } + else if(new_msg == CERTIFICATE_VERIFY) + { + if(!state->cert_req || !state->client_certs || !state->client_kex || + state->got_client_ccs) + throw State_Transition_Error("CertificateVerify"); + } + else if(new_msg == HANDSHAKE_CCS) + { + if(!state->client_kex || state->client_finished) + throw State_Transition_Error("ClientChangeCipherSpec"); + } + else if(new_msg == FINISHED) + { + if(!state->got_client_ccs) + throw State_Transition_Error("ClientFinished"); + } + else + throw Unexpected_Message("Unexpected message in handshake"); + } + +} + +/* +* TLS Server Constructor +*/ +TLS_Server::TLS_Server(std::tr1::function input_fn, + std::tr1::function output_fn, + const TLS_Policy& policy, + RandomNumberGenerator& rng, + const X509_Certificate& cert, + const Private_Key& cert_key) : + input_fn(input_fn), + policy(policy), + rng(rng), + writer(output_fn) + { + state = 0; + + cert_chain.push_back(cert); + private_key = PKCS8::copy_key(cert_key, rng); + + try { + active = false; + writer.set_version(TLS_V10); + do_handshake(); + active = true; + } + catch(std::exception& e) + { + if(state) + { + delete state; + state = 0; + } + + writer.alert(FATAL, HANDSHAKE_FAILURE); + throw Stream_IO_Error(std::string("TLS_Server: Handshake failed: ") + + e.what()); + } + } + +/* +* TLS Server Destructor +*/ +TLS_Server::~TLS_Server() + { + close(); + delete private_key; + delete state; + } + +/* +* Return the peer's certificate chain +*/ +std::vector TLS_Server::peer_cert_chain() const + { + return peer_certs; + } + +/* +* Write to a TLS connection +*/ +void TLS_Server::write(const byte buf[], size_t length) + { + if(!active) + throw Internal_Error("TLS_Server::write called while closed"); + + writer.send(APPLICATION_DATA, buf, length); + } + +/* +* Read from a TLS connection +*/ +size_t TLS_Server::read(byte out[], size_t length) + { + if(!active) + throw Internal_Error("TLS_Server::read called while closed"); + + writer.flush(); + + while(read_buf.size() == 0) + { + state_machine(); + if(active == false) + break; + } + + size_t got = std::min(read_buf.size(), length); + read_buf.read(out, got); + return got; + } + +/* +* Check connection status +*/ +bool TLS_Server::is_closed() const + { + if(!active) + return true; + return false; + } + +/* +* Close a TLS connection +*/ +void TLS_Server::close() + { + close(WARNING, CLOSE_NOTIFY); + } + +/* +* Close a TLS connection +*/ +void TLS_Server::close(Alert_Level level, Alert_Type alert_code) + { + if(active) + { + try { + active = false; + writer.alert(level, alert_code); + writer.flush(); + } + catch(...) {} + } + } + +/* +* Iterate the TLS state machine +*/ +void TLS_Server::state_machine() + { + byte rec_type = CONNECTION_CLOSED; + SecureVector record(1024); + + size_t bytes_needed = reader.get_record(rec_type, record); + + while(bytes_needed) + { + size_t to_get = std::min(record.size(), bytes_needed); + size_t got = input_fn(&record[0], to_get); + + if(got == 0) + { + rec_type = CONNECTION_CLOSED; + break; + } + + reader.add_input(&record[0], got); + + bytes_needed = reader.get_record(rec_type, record); + } + + if(rec_type == CONNECTION_CLOSED) + { + active = false; + reader.reset(); + writer.reset(); + } + else if(rec_type == APPLICATION_DATA) + { + if(active) + read_buf.write(&record[0], record.size()); + else + throw Unexpected_Message("Application data before handshake done"); + } + else if(rec_type == HANDSHAKE || rec_type == CHANGE_CIPHER_SPEC) + read_handshake(rec_type, record); + else if(rec_type == ALERT) + { + Alert alert(record); + + if(alert.is_fatal() || alert.type() == CLOSE_NOTIFY) + { + if(alert.type() == CLOSE_NOTIFY) + writer.alert(WARNING, CLOSE_NOTIFY); + + reader.reset(); + writer.reset(); + active = false; + } + } + else + throw Unexpected_Message("Unknown message type received"); + } + +/* +* Split up and process handshake messages +*/ +void TLS_Server::read_handshake(byte rec_type, + const MemoryRegion& rec_buf) + { + if(rec_type == HANDSHAKE) + { + if(!state) + state = new Handshake_State; + state->queue.write(&rec_buf[0], rec_buf.size()); + } + + while(true) + { + Handshake_Type type = HANDSHAKE_NONE; + SecureVector contents; + + if(rec_type == HANDSHAKE) + { + if(state->queue.size() >= 4) + { + byte head[4] = { 0 }; + state->queue.peek(head, 4); + + const size_t length = make_u32bit(0, head[1], head[2], head[3]); + + if(state->queue.size() >= length + 4) + { + type = static_cast(head[0]); + contents.resize(length); + state->queue.read(head, 4); + state->queue.read(&contents[0], contents.size()); + } + } + } + else if(rec_type == CHANGE_CIPHER_SPEC) + { + if(state->queue.size() == 0 && rec_buf.size() == 1 && rec_buf[0] == 1) + type = HANDSHAKE_CCS; + else + throw Decoding_Error("Malformed ChangeCipherSpec message"); + } + else + throw Decoding_Error("Unknown message type in handshake processing"); + + if(type == HANDSHAKE_NONE) + break; + + process_handshake_msg(type, contents); + + if(type == HANDSHAKE_CCS || !state) + break; + } + } + +/* +* Process a handshake message +*/ +void TLS_Server::process_handshake_msg(Handshake_Type type, + const MemoryRegion& contents) + { + rng.add_entropy(&contents[0], contents.size()); + + if(state == 0) + throw Unexpected_Message("Unexpected handshake message"); + + if(type != HANDSHAKE_CCS && type != FINISHED) + { + if(type != CLIENT_HELLO_SSLV2) + { + state->hash.update(static_cast(type)); + + const size_t record_length = contents.size(); + for(size_t i = 0; i != 3; i++) + state->hash.update(get_byte(i+1, record_length)); + } + + state->hash.update(contents); + } + + if(type == CLIENT_HELLO || type == CLIENT_HELLO_SSLV2) + { + server_check_state(type, state); + + state->client_hello = new Client_Hello(contents, type); + + client_requested_hostname = state->client_hello->hostname(); + + state->version = choose_version(state->client_hello->version(), + policy.min_version()); + + writer.set_version(state->version); + reader.set_version(state->version); + + state->server_hello = new Server_Hello(rng, writer, + policy, cert_chain, + *(state->client_hello), + state->version, state->hash); + + state->suite = CipherSuite(state->server_hello->ciphersuite()); + + if(state->suite.sig_type() != TLS_ALGO_SIGNER_ANON) + { + // FIXME: should choose certs based on sig type + state->server_certs = new Certificate(writer, cert_chain, + state->hash); + } + + state->kex_priv = PKCS8::copy_key(*private_key, rng); + if(state->suite.kex_type() != TLS_ALGO_KEYEXCH_NOKEX) + { + if(state->suite.kex_type() == TLS_ALGO_KEYEXCH_RSA) + { + state->kex_priv = new RSA_PrivateKey(rng, + policy.rsa_export_keysize()); + } + else if(state->suite.kex_type() == TLS_ALGO_KEYEXCH_DH) + { + state->kex_priv = new DH_PrivateKey(rng, policy.dh_group()); + } + else + throw Internal_Error("TLS_Server: Unknown ciphersuite kex type"); + + state->server_kex = + new Server_Key_Exchange(rng, writer, + state->kex_priv, private_key, + state->client_hello->random(), + state->server_hello->random(), + state->hash); + } + + if(policy.require_client_auth()) + { + state->do_client_auth = true; + throw Internal_Error("Client auth not implemented"); + // FIXME: send client auth request here + } + + state->server_hello_done = new Server_Hello_Done(writer, state->hash); + } + else if(type == CERTIFICATE) + { + server_check_state(type, state); + // FIXME: process this + } + else if(type == CLIENT_KEX) + { + server_check_state(type, state); + + state->client_kex = new Client_Key_Exchange(contents, state->suite, + state->version); + + SecureVector pre_master = + state->client_kex->pre_master_secret(rng, state->kex_priv, + state->server_hello->version()); + + state->keys = SessionKeys(state->suite, state->version, pre_master, + state->client_hello->random(), + state->server_hello->random()); + } + else if(type == CERTIFICATE_VERIFY) + { + server_check_state(type, state); + // FIXME: process this + } + else if(type == HANDSHAKE_CCS) + { + server_check_state(type, state); + + reader.set_keys(state->suite, state->keys, SERVER); + state->got_client_ccs = true; + } + else if(type == FINISHED) + { + server_check_state(type, state); + + state->client_finished = new Finished(contents); + + if(!state->client_finished->verify(state->keys.master_secret(), + state->version, state->hash, CLIENT)) + throw TLS_Exception(DECRYPT_ERROR, + "Finished message didn't verify"); + + state->hash.update(static_cast(type)); + + const size_t record_length = contents.size(); + for(size_t i = 0; i != 3; i++) + state->hash.update(get_byte(i+1, record_length)); + + state->hash.update(contents); + + writer.send(CHANGE_CIPHER_SPEC, 1); + writer.flush(); + + writer.set_keys(state->suite, state->keys, SERVER); + + state->server_finished = new Finished(writer, state->version, SERVER, + state->keys.master_secret(), + state->hash); + + delete state; + state = 0; + active = true; + } + else + throw Unexpected_Message("Unknown handshake message received"); + } + +/* +* Perform a server-side TLS handshake +*/ +void TLS_Server::do_handshake() + { + while(true) + { + if(active && !state) + break; + + state_machine(); + + if(!active && !state) + throw TLS_Exception(HANDSHAKE_FAILURE, "TLS_Server: Handshake failed"); + } + } + +} diff --git a/src/tls/tls_server.h b/src/tls/tls_server.h new file mode 100644 index 000000000..510ad15a7 --- /dev/null +++ b/src/tls/tls_server.h @@ -0,0 +1,76 @@ +/* +* TLS Server +* (C) 2004-2011 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_SERVER_H__ +#define BOTAN_TLS_SERVER_H__ + +#include +#include +#include + +namespace Botan { + +/** +* TLS Server +*/ +class BOTAN_DLL TLS_Server + { + public: + size_t read(byte buf[], size_t buf_len); + void write(const byte buf[], size_t buf_len); + + std::vector peer_cert_chain() const; + + std::string requested_hostname() const + { return client_requested_hostname; } + + void close(); + bool is_closed() const; + + /* + * FIXME: support cert chains (!) + * FIXME: support anonymous servers + */ + TLS_Server(std::tr1::function input_fn, + std::tr1::function output_fn, + const TLS_Policy& policy, + RandomNumberGenerator& rng, + const X509_Certificate& cert, + const Private_Key& cert_key); + + ~TLS_Server(); + private: + void close(Alert_Level, Alert_Type); + + void do_handshake(); + void state_machine(); + void read_handshake(byte, const MemoryRegion&); + + void process_handshake_msg(Handshake_Type, const MemoryRegion&); + + std::tr1::function input_fn; + + const TLS_Policy& policy; + RandomNumberGenerator& rng; + + Record_Writer writer; + Record_Reader reader; + + // FIXME: rename to match TLS_Client + std::vector cert_chain, peer_certs; + Private_Key* private_key; + + class Handshake_State* state; + SecureVector session_id; + SecureQueue read_buf; + std::string client_requested_hostname; + bool active; + }; + +} + +#endif diff --git a/src/tls/tls_session_key.cpp b/src/tls/tls_session_key.cpp new file mode 100644 index 000000000..7c75d1758 --- /dev/null +++ b/src/tls/tls_session_key.cpp @@ -0,0 +1,170 @@ +/* +* TLS Session Key +* (C) 2004-2006 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include +#include +#include + +namespace Botan { + +/** +* Return the client cipher key +*/ +SymmetricKey SessionKeys::client_cipher_key() const + { + return c_cipher; + } + +/** +* Return the server cipher key +*/ +SymmetricKey SessionKeys::server_cipher_key() const + { + return s_cipher; + } + +/** +* Return the client MAC key +*/ +SymmetricKey SessionKeys::client_mac_key() const + { + return c_mac; + } + +/** +* Return the server MAC key +*/ +SymmetricKey SessionKeys::server_mac_key() const + { + return s_mac; + } + +/** +* Return the client cipher IV +*/ +InitializationVector SessionKeys::client_iv() const + { + return c_iv; + } + +/** +* Return the server cipher IV +*/ +InitializationVector SessionKeys::server_iv() const + { + return s_iv; + } + +/** +* Return the TLS master secret +*/ +SecureVector SessionKeys::master_secret() const + { + return master_sec; + } + +/** +* Generate SSLv3 session keys +*/ +SymmetricKey SessionKeys::ssl3_keygen(size_t prf_gen, + const MemoryRegion& pre_master, + const MemoryRegion& client_random, + const MemoryRegion& server_random) + { + SSL3_PRF prf; + + SecureVector salt; + salt += client_random; + salt += server_random; + + master_sec = prf.derive_key(48, pre_master, salt); + + salt.clear(); + salt += server_random; + salt += client_random; + + return prf.derive_key(prf_gen, master_sec, salt); + } + +/** +* Generate TLS 1.0 session keys +*/ +SymmetricKey SessionKeys::tls1_keygen(size_t prf_gen, + const MemoryRegion& pre_master, + const MemoryRegion& client_random, + const MemoryRegion& server_random) + { + const byte MASTER_SECRET_MAGIC[] = { + 0x6D, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x73, 0x65, 0x63, 0x72, 0x65, + 0x74 }; + const byte KEY_GEN_MAGIC[] = { + 0x6B, 0x65, 0x79, 0x20, 0x65, 0x78, 0x70, 0x61, 0x6E, 0x73, 0x69, 0x6F, + 0x6E }; + + TLS_PRF prf; + + SecureVector salt; + salt += std::make_pair(MASTER_SECRET_MAGIC, sizeof(MASTER_SECRET_MAGIC)); + salt += client_random; + salt += server_random; + + master_sec = prf.derive_key(48, pre_master, salt); + + salt.clear(); + salt += std::make_pair(KEY_GEN_MAGIC, sizeof(KEY_GEN_MAGIC)); + salt += server_random; + salt += client_random; + + return prf.derive_key(prf_gen, master_sec, salt); + } + +/** +* SessionKeys Constructor +*/ +SessionKeys::SessionKeys(const CipherSuite& suite, Version_Code version, + const MemoryRegion& pre_master_secret, + const MemoryRegion& c_random, + const MemoryRegion& s_random) + { + if(version != SSL_V3 && version != TLS_V10 && version != TLS_V11) + throw Invalid_Argument("SessionKeys: Unknown version code"); + + const size_t mac_keylen = output_length_of(suite.mac_algo()); + const size_t cipher_keylen = suite.cipher_keylen(); + + size_t cipher_ivlen = 0; + if(have_block_cipher(suite.cipher_algo())) + cipher_ivlen = block_size_of(suite.cipher_algo()); + + const size_t prf_gen = 2 * (mac_keylen + cipher_keylen + cipher_ivlen); + + SymmetricKey keyblock = (version == SSL_V3) ? + ssl3_keygen(prf_gen, pre_master_secret, c_random, s_random) : + tls1_keygen(prf_gen, pre_master_secret, c_random, s_random); + + const byte* key_data = keyblock.begin(); + + c_mac = SymmetricKey(key_data, mac_keylen); + key_data += mac_keylen; + + s_mac = SymmetricKey(key_data, mac_keylen); + key_data += mac_keylen; + + c_cipher = SymmetricKey(key_data, cipher_keylen); + key_data += cipher_keylen; + + s_cipher = SymmetricKey(key_data, cipher_keylen); + key_data += cipher_keylen; + + c_iv = InitializationVector(key_data, cipher_ivlen); + key_data += cipher_ivlen; + + s_iv = InitializationVector(key_data, cipher_ivlen); + } + +} diff --git a/src/tls/tls_session_key.h b/src/tls/tls_session_key.h new file mode 100644 index 000000000..51397984b --- /dev/null +++ b/src/tls/tls_session_key.h @@ -0,0 +1,52 @@ +/* +* TLS Session Key +* (C) 2004-2006 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_SESSION_KEYS_H__ +#define BOTAN_TLS_SESSION_KEYS_H__ + +#include +#include +#include + +namespace Botan { + +/** +* TLS Session Keys +*/ +class BOTAN_DLL SessionKeys + { + public: + SymmetricKey client_cipher_key() const; + SymmetricKey server_cipher_key() const; + + SymmetricKey client_mac_key() const; + SymmetricKey server_mac_key() const; + + InitializationVector client_iv() const; + InitializationVector server_iv() const; + + SecureVector master_secret() const; + + SessionKeys() {} + SessionKeys(const CipherSuite&, Version_Code, const MemoryRegion&, + const MemoryRegion&, const MemoryRegion&); + private: + SymmetricKey ssl3_keygen(size_t, const MemoryRegion&, + const MemoryRegion&, + const MemoryRegion&); + SymmetricKey tls1_keygen(size_t, const MemoryRegion&, + const MemoryRegion&, + const MemoryRegion&); + + SecureVector master_sec; + SymmetricKey c_cipher, s_cipher, c_mac, s_mac; + InitializationVector c_iv, s_iv; + }; + +} + +#endif diff --git a/src/tls/tls_state.cpp b/src/tls/tls_state.cpp new file mode 100644 index 000000000..6aaf5e201 --- /dev/null +++ b/src/tls/tls_state.cpp @@ -0,0 +1,59 @@ +/* +* TLS Handshaking +* (C) 2004-2006 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include + +namespace Botan { + +/** +* Initialize the SSL/TLS Handshake State +*/ +Handshake_State::Handshake_State() + { + client_hello = 0; + server_hello = 0; + server_certs = 0; + server_kex = 0; + cert_req = 0; + server_hello_done = 0; + + client_certs = 0; + client_kex = 0; + client_verify = 0; + client_finished = 0; + server_finished = 0; + + kex_pub = 0; + kex_priv = 0; + + do_client_auth = got_client_ccs = got_server_ccs = false; + version = SSL_V3; + } + +/** +* Destroy the SSL/TLS Handshake State +*/ +Handshake_State::~Handshake_State() + { + delete client_hello; + delete server_hello; + delete server_certs; + delete server_kex; + delete cert_req; + delete server_hello_done; + + delete client_certs; + delete client_kex; + delete client_verify; + delete client_finished; + delete server_finished; + + delete kex_pub; + delete kex_priv; + } + +} diff --git a/src/tls/tls_state.h b/src/tls/tls_state.h new file mode 100644 index 000000000..e2728198f --- /dev/null +++ b/src/tls/tls_state.h @@ -0,0 +1,53 @@ +/* +* TLS Handshake State +* (C) 2004-2006 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_HANDSHAKE_H__ +#define BOTAN_TLS_HANDSHAKE_H__ + +#include +#include + +namespace Botan { + +/** +* SSL/TLS Handshake State +*/ +class Handshake_State + { + public: + Client_Hello* client_hello; + Server_Hello* server_hello; + Certificate* server_certs; + Server_Key_Exchange* server_kex; + Certificate_Req* cert_req; + Server_Hello_Done* server_hello_done; + + Certificate* client_certs; + Client_Key_Exchange* client_kex; + Certificate_Verify* client_verify; + Finished* client_finished; + Finished* server_finished; + + Public_Key* kex_pub; + Private_Key* kex_priv; + + CipherSuite suite; + SessionKeys keys; + HandshakeHash hash; + + SecureQueue queue; + + Version_Code version; + bool got_client_ccs, got_server_ccs, do_client_auth; + + Handshake_State(); + ~Handshake_State(); + }; + +} + +#endif diff --git a/src/tls/tls_suites.cpp b/src/tls/tls_suites.cpp new file mode 100644 index 000000000..07cbec608 --- /dev/null +++ b/src/tls/tls_suites.cpp @@ -0,0 +1,281 @@ +/* +* TLS Cipher Suites +* (C) 2004-2010 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#include +#include + +namespace Botan { + +/** +* Convert an SSL/TLS ciphersuite to algorithm fields +*/ +TLS_Ciphersuite_Algos CipherSuite::lookup_ciphersuite(u16bit suite) + { + if(suite == TLS_RSA_WITH_RC4_128_MD5) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_NOKEX | + TLS_ALGO_MAC_MD5 | + TLS_ALGO_CIPHER_RC4_128); + + if(suite == TLS_RSA_WITH_RC4_128_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_NOKEX | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_RC4_128); + + if(suite == TLS_RSA_WITH_3DES_EDE_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_NOKEX | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_3DES_CBC); + + if(suite == TLS_RSA_WITH_AES_128_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_NOKEX | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_AES128_CBC); + + if(suite == TLS_RSA_WITH_AES_256_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_NOKEX | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_AES256_CBC); + + if(suite == TLS_RSA_WITH_SEED_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_NOKEX | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_SEED_CBC); + + if(suite == TLS_RSA_WITH_AES_128_CBC_SHA256) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_NOKEX | + TLS_ALGO_MAC_SHA256 | + TLS_ALGO_CIPHER_AES128_CBC); + + if(suite == TLS_RSA_WITH_AES_256_CBC_SHA256) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_NOKEX | + TLS_ALGO_MAC_SHA256 | + TLS_ALGO_CIPHER_AES256_CBC); + + if(suite == TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_3DES_CBC); + + if(suite == TLS_DHE_DSS_WITH_AES_128_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_AES128_CBC); + + if(suite == TLS_DHE_DSS_WITH_SEED_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_SEED_CBC); + + if(suite == TLS_DHE_DSS_WITH_AES_256_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_AES256_CBC); + + if(suite == TLS_DHE_DSS_WITH_AES_128_CBC_SHA256) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA256 | + TLS_ALGO_CIPHER_AES128_CBC); + + if(suite == TLS_DHE_DSS_WITH_AES_256_CBC_SHA256) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_DSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA256 | + TLS_ALGO_CIPHER_AES256_CBC); + + if(suite == TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_3DES_CBC); + + if(suite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_AES128_CBC); + + if(suite == TLS_DHE_DSS_WITH_SEED_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_SEED_CBC); + + if(suite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_AES256_CBC); + + if(suite == TLS_DHE_RSA_WITH_AES_128_CBC_SHA256) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA256 | + TLS_ALGO_CIPHER_AES128_CBC); + + if(suite == TLS_DHE_RSA_WITH_AES_256_CBC_SHA256) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_DH | + TLS_ALGO_MAC_SHA256 | + TLS_ALGO_CIPHER_AES256_CBC); + + if(suite == TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_RC4_128); + + if(suite == TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_3DES_CBC); + + if(suite == TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_AES128_CBC); + + if(suite == TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_AES256_CBC); + + if(suite == TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA256 | + TLS_ALGO_CIPHER_AES128_CBC); + + if(suite == TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA384 | + TLS_ALGO_CIPHER_AES256_CBC); + + if(suite == TLS_ECDHE_RSA_WITH_RC4_128_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_RC4_128); + + if(suite == TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_3DES_CBC); + + if(suite == TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_AES128_CBC); + + if(suite == TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_RSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA1 | + TLS_ALGO_CIPHER_AES256_CBC); + + if(suite == TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA256 | + TLS_ALGO_CIPHER_AES128_CBC); + + if(suite == TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) + return TLS_Ciphersuite_Algos(TLS_ALGO_SIGNER_ECDSA | + TLS_ALGO_KEYEXCH_ECDH | + TLS_ALGO_MAC_SHA384 | + TLS_ALGO_CIPHER_AES256_CBC); + + return TLS_Ciphersuite_Algos(0); + } + +namespace { + +std::pair cipher_code_to_name(TLS_Ciphersuite_Algos algo) + { + if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_RC4_128) + return std::make_pair("ARC4", 16); + + if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_3DES_CBC) + return std::make_pair("3DES", 24); + + if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_AES128_CBC) + return std::make_pair("AES-128", 16); + + if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_AES256_CBC) + return std::make_pair("AES-256", 32); + + if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_SEED_CBC) + return std::make_pair("SEED", 16); + + throw TLS_Exception(INTERNAL_ERROR, + "CipherSuite: Unknown cipher type " + to_string(algo)); + } + +std::string mac_code_to_name(TLS_Ciphersuite_Algos algo) + { + if((algo & TLS_ALGO_MAC_MASK) == TLS_ALGO_MAC_MD5) + return "MD5"; + + if((algo & TLS_ALGO_MAC_MASK) == TLS_ALGO_MAC_SHA1) + return "SHA-1"; + + if((algo & TLS_ALGO_MAC_MASK) == TLS_ALGO_MAC_SHA256) + return "SHA-256"; + + if((algo & TLS_ALGO_MAC_MASK) == TLS_ALGO_MAC_SHA384) + return "SHA-384"; + + throw TLS_Exception(INTERNAL_ERROR, + "CipherSuite: Unknown MAC type " + to_string(algo)); + } + +} + +/** +* CipherSuite Constructor +*/ +CipherSuite::CipherSuite(u16bit suite_code) + { + if(suite_code == 0) + return; + + TLS_Ciphersuite_Algos algos = lookup_ciphersuite(suite_code); + + if(algos == 0) + throw Invalid_Argument("Unknown ciphersuite: " + to_string(suite_code)); + + sig_algo = TLS_Ciphersuite_Algos(algos & TLS_ALGO_SIGNER_MASK); + + kex_algo = TLS_Ciphersuite_Algos(algos & TLS_ALGO_KEYEXCH_MASK); + + std::pair cipher_info = cipher_code_to_name(algos); + + cipher = cipher_info.first; + cipher_key_length = cipher_info.second; + + mac = mac_code_to_name(algos); + } + +} diff --git a/src/tls/tls_suites.h b/src/tls/tls_suites.h new file mode 100644 index 000000000..8d6db0e8b --- /dev/null +++ b/src/tls/tls_suites.h @@ -0,0 +1,42 @@ +/* +* Cipher Suites +* (C) 2004-2010 Jack Lloyd +* +* Released under the terms of the Botan license +*/ + +#ifndef BOTAN_TLS_CIPHERSUITES_H__ +#define BOTAN_TLS_CIPHERSUITES_H__ + +#include +#include +#include + +namespace Botan { + +/** +* Ciphersuite Information +*/ +class BOTAN_DLL CipherSuite + { + public: + static TLS_Ciphersuite_Algos lookup_ciphersuite(u16bit suite); + + std::string cipher_algo() const { return cipher; } + std::string mac_algo() const { return mac; } + + size_t cipher_keylen() const { return cipher_key_length; } + + TLS_Ciphersuite_Algos kex_type() const { return kex_algo; } + TLS_Ciphersuite_Algos sig_type() const { return sig_algo; } + + CipherSuite(u16bit = 0); + private: + TLS_Ciphersuite_Algos kex_algo, sig_algo; + std::string cipher, mac; + size_t cipher_key_length; + }; + +} + +#endif -- cgit v1.2.3