diff options
author | lloyd <[email protected]> | 2010-04-28 22:31:20 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2010-04-28 22:31:20 +0000 |
commit | 0f47cb60e703ca2de56286f07b4c9d91c7bba071 (patch) | |
tree | 5304fd84516c79f55e213755b2b2b99e6e65c9e0 /src/ssl | |
parent | 6eec50d372143afcb3188f21d0991ace3e0d5e9e (diff) | |
parent | 50fc7b15553d888d95bee72972e53eae27a82c1f (diff) |
propagate from branch 'net.randombit.botan' (head a5f25a3b954f24c5d07fa0dab6c4d76f63767165)
to branch 'net.randombit.botan.c++0x' (head a365694b70b4b84ca713272d56d496acca351cb5)
Diffstat (limited to 'src/ssl')
-rw-r--r-- | src/ssl/c_kex.cpp | 4 | ||||
-rw-r--r-- | src/ssl/hello.cpp | 39 | ||||
-rw-r--r-- | src/ssl/rec_read.cpp | 29 | ||||
-rw-r--r-- | src/ssl/tls_client.cpp | 21 | ||||
-rw-r--r-- | src/ssl/tls_magic.h | 90 | ||||
-rw-r--r-- | src/ssl/tls_messages.h | 19 | ||||
-rw-r--r-- | src/ssl/tls_policy.cpp | 29 | ||||
-rw-r--r-- | src/ssl/tls_server.cpp | 29 | ||||
-rw-r--r-- | src/ssl/tls_suites.cpp | 286 | ||||
-rw-r--r-- | src/ssl/tls_suites.h | 16 |
10 files changed, 458 insertions, 104 deletions
diff --git a/src/ssl/c_kex.cpp b/src/ssl/c_kex.cpp index e09e18ce1..db2198627 100644 --- a/src/ssl/c_kex.cpp +++ b/src/ssl/c_kex.cpp @@ -67,9 +67,7 @@ Client_Key_Exchange::Client_Key_Exchange(const MemoryRegion<byte>& contents, { include_length = true; - if(using_version == SSL_V3 && - (suite.kex_type() == CipherSuite::NO_KEX || - suite.kex_type() == CipherSuite::RSA_KEX)) + if(using_version == SSL_V3 && (suite.kex_type() == TLS_ALGO_KEYEXCH_RSA)) include_length = false; deserialize(contents); diff --git a/src/ssl/hello.cpp b/src/ssl/hello.cpp index a23d51c24..5b3c32278 100644 --- a/src/ssl/hello.cpp +++ b/src/ssl/hello.cpp @@ -106,6 +106,40 @@ SecureVector<byte> Client_Hello::serialize() const return buf; } +void Client_Hello::deserialize_sslv2(const MemoryRegion<byte>& buf) + { + if(buf.size() < 12 || buf[0] != 1) + throw Decoding_Error("Client_Hello: SSLv2 hello corrupted"); + + const u32bit cipher_spec_len = make_u16bit(buf[3], buf[4]); + const u32bit sess_id_len = make_u16bit(buf[5], buf[6]); + const u32bit challenge_len = make_u16bit(buf[7], buf[8]); + + const u32bit 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(u32bit 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<Version_Code>(make_u16bit(buf[1], buf[2])); + + c_random.set(&buf[9+cipher_spec_len+sess_id_len], challenge_len); + } + /** * Deserialize a Client Hello message */ @@ -207,6 +241,11 @@ Server_Hello::Server_Hello(RandomNumberGenerator& rng, } 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; diff --git a/src/ssl/rec_read.cpp b/src/ssl/rec_read.cpp index 8f8e5dc1e..f07744c2a 100644 --- a/src/ssl/rec_read.cpp +++ b/src/ssl/rec_read.cpp @@ -124,6 +124,35 @@ u32bit Record_Reader::get_record(byte& msg_type, */ input_queue.peek(header, sizeof(header)); + // SSLv2-format client hello? + if(header[0] & 0x80 && header[2] == 1 && header[3] == 3) + { + u32bit 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]); diff --git a/src/ssl/tls_client.cpp b/src/ssl/tls_client.cpp index fbad1f838..8a4275d93 100644 --- a/src/ssl/tls_client.cpp +++ b/src/ssl/tls_client.cpp @@ -123,6 +123,7 @@ TLS_Client::~TLS_Client() */ void TLS_Client::initialize() { + std::string error_str; Alert_Type error_type = NO_ALERT_TYPE; try { @@ -133,10 +134,12 @@ void TLS_Client::initialize() } catch(TLS_Exception& e) { + error_str = e.what(); error_type = e.type(); } catch(std::exception& e) { + error_str = e.what(); error_type = HANDSHAKE_FAILURE; } @@ -157,7 +160,7 @@ void TLS_Client::initialize() state = 0; } - throw Stream_IO_Error("TLS_Client: Handshake failed"); + throw Stream_IO_Error("TLS_Client: Handshake failed: " + error_str); } } @@ -360,6 +363,8 @@ void TLS_Client::read_handshake(byte rec_type, void TLS_Client::process_handshake_msg(Handshake_Type type, const MemoryRegion<byte>& contents) { + rng.add_entropy(&contents[0], contents.size()); + if(type == HELLO_REQUEST) { if(state == 0) @@ -419,7 +424,7 @@ void TLS_Client::process_handshake_msg(Handshake_Type type, { client_check_state(type, state); - if(state->suite.sig_type() == CipherSuite::NO_SIG) + if(state->suite.sig_type() == TLS_ALGO_SIGNER_ANON) throw Unexpected_Message("Recived certificate from anonymous server"); state->server_certs = new Certificate(contents); @@ -445,8 +450,8 @@ void TLS_Client::process_handshake_msg(Handshake_Type type, throw TLS_Exception(UNSUPPORTED_CERTIFICATE, "Unknown key type recieved in server kex"); - if((is_dsa && state->suite.sig_type() != CipherSuite::DSA_SIG) || - (is_rsa && state->suite.sig_type() != CipherSuite::RSA_SIG)) + 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"); } @@ -454,7 +459,7 @@ void TLS_Client::process_handshake_msg(Handshake_Type type, { client_check_state(type, state); - if(state->suite.kex_type() == CipherSuite::NO_KEX) + 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); @@ -474,12 +479,12 @@ void TLS_Client::process_handshake_msg(Handshake_Type type, throw TLS_Exception(HANDSHAKE_FAILURE, "Unknown key type recieved in server kex"); - if((is_dh && state->suite.kex_type() != CipherSuite::DH_KEX) || - (is_rsa && state->suite.kex_type() != CipherSuite::RSA_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() != CipherSuite::NO_SIG) + if(state->suite.sig_type() != TLS_ALGO_SIGNER_ANON) { if(!state->server_kex->verify(peer_certs[0], state->client_hello->random(), diff --git a/src/ssl/tls_magic.h b/src/ssl/tls_magic.h index a6ca1f8d6..93b56d96d 100644 --- a/src/ssl/tls_magic.h +++ b/src/ssl/tls_magic.h @@ -1,6 +1,6 @@ /** -* SSL/TLS Protocol Constants -* (C) 2004-2006 Jack Lloyd +* SSL/TLS Protocol Constants +* (C) 2004-2010 Jack Lloyd * * Released under the terms of the Botan license */ @@ -40,6 +40,7 @@ enum Record_Type { 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, @@ -96,19 +97,75 @@ enum Certificate_Type { }; enum Ciphersuite_Code { - RSA_RC4_MD5 = 0x0004, - RSA_RC4_SHA = 0x0005, - RSA_3DES_SHA = 0x000A, - RSA_AES128_SHA = 0x002F, - RSA_AES256_SHA = 0x0035, - - DHE_RSA_3DES_SHA = 0x0016, - DHE_RSA_AES128_SHA = 0x0033, - DHE_RSA_AES256_SHA = 0x0039, - - DHE_DSS_3DES_SHA = 0x0013, - DHE_DSS_AES128_SHA = 0x0032, - DHE_DSS_AES256_SHA = 0x0038 + 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 { @@ -122,6 +179,9 @@ enum TLS_Handshake_Extension_Type { TLSEXT_TRUSTED_CA_KEYS = 3, TLSEXT_TRUNCATED_HMAC = 4, + TLSEXT_USABLE_ELLIPTIC_CURVES = 10, + TLSEXT_EC_POINT_FORMATS = 11, + TLSEXT_CERTIFICATE_TYPES = 9, TLSEXT_SESSION_TICKET = 35, }; diff --git a/src/ssl/tls_messages.h b/src/ssl/tls_messages.h index 1f72c05f7..5c0c06c88 100644 --- a/src/ssl/tls_messages.h +++ b/src/ssl/tls_messages.h @@ -43,11 +43,11 @@ class BOTAN_DLL Client_Hello : public HandshakeMessage public: Handshake_Type type() const { return CLIENT_HELLO; } Version_Code version() const { return c_version; } - SecureVector<byte> session_id() const { return sess_id; } + const SecureVector<byte>& session_id() const { return sess_id; } std::vector<u16bit> ciphersuites() const { return suites; } std::vector<byte> compression_algos() const { return comp_algos; } - SecureVector<byte> random() const { return c_random; } + const SecureVector<byte>& random() const { return c_random; } std::string hostname() const { return requested_hostname; } @@ -56,10 +56,19 @@ class BOTAN_DLL Client_Hello : public HandshakeMessage Client_Hello(RandomNumberGenerator& rng, Record_Writer&, const TLS_Policy*, HandshakeHash&); - Client_Hello(const MemoryRegion<byte>& buf) { deserialize(buf); } + Client_Hello(const MemoryRegion<byte>& buf, + Handshake_Type type) + { + if(type == CLIENT_HELLO) + deserialize(buf); + else + deserialize_sslv2(buf); + } + private: SecureVector<byte> serialize() const; void deserialize(const MemoryRegion<byte>&); + void deserialize_sslv2(const MemoryRegion<byte>&); Version_Code c_version; SecureVector<byte> sess_id, c_random; @@ -216,11 +225,11 @@ class BOTAN_DLL Server_Hello : public HandshakeMessage public: Handshake_Type type() const { return SERVER_HELLO; } Version_Code version() { return s_version; } - SecureVector<byte> session_id() const { return sess_id; } + const SecureVector<byte>& session_id() const { return sess_id; } u16bit ciphersuite() const { return suite; } byte compression_algo() const { return comp_algo; } - SecureVector<byte> random() const { return s_random; } + const SecureVector<byte>& random() const { return s_random; } Server_Hello(RandomNumberGenerator& rng, Record_Writer&, const TLS_Policy*, diff --git a/src/ssl/tls_policy.cpp b/src/ssl/tls_policy.cpp index 6138ae193..57fcdb5cc 100644 --- a/src/ssl/tls_policy.cpp +++ b/src/ssl/tls_policy.cpp @@ -1,6 +1,6 @@ /** -* Policies -* (C) 2004-2006 Jack Lloyd +* Policies for TLS +* (C) 2004-2010 Jack Lloyd * * Released under the terms of the Botan license */ @@ -29,25 +29,28 @@ std::vector<u16bit> TLS_Policy::suite_list(bool use_rsa, if(use_edh_dsa) { - suites.push_back(DHE_DSS_AES256_SHA); - suites.push_back(DHE_DSS_AES128_SHA); - suites.push_back(DHE_DSS_3DES_SHA); + 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(DHE_RSA_AES256_SHA); - suites.push_back(DHE_RSA_AES128_SHA); - suites.push_back(DHE_RSA_3DES_SHA); + 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(RSA_AES256_SHA); - suites.push_back(RSA_AES128_SHA); - suites.push_back(RSA_3DES_SHA); - suites.push_back(RSA_RC4_SHA); - suites.push_back(RSA_RC4_MD5); + 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) diff --git a/src/ssl/tls_server.cpp b/src/ssl/tls_server.cpp index 47902a71c..a4cfcf7de 100644 --- a/src/ssl/tls_server.cpp +++ b/src/ssl/tls_server.cpp @@ -43,7 +43,7 @@ void server_check_state(Handshake_Type new_msg, Handshake_State* state) Unexpected_Message("State transition error from " + err) {} }; - if(new_msg == CLIENT_HELLO) + if(new_msg == CLIENT_HELLO || new_msg == CLIENT_HELLO_SSLV2) { if(state->server_hello) throw State_Transition_Error("ClientHello"); @@ -325,23 +325,30 @@ void TLS_Server::read_handshake(byte rec_type, void TLS_Server::process_handshake_msg(Handshake_Type type, const MemoryRegion<byte>& contents) { + rng.add_entropy(&contents[0], contents.size()); + if(state == 0) throw Unexpected_Message("Unexpected handshake message"); if(type != HANDSHAKE_CCS && type != FINISHED) { - state->hash.update(static_cast<byte>(type)); - u32bit record_length = contents.size(); - for(u32bit j = 0; j != 3; j++) - state->hash.update(get_byte(j+1, record_length)); + + if(type != CLIENT_HELLO_SSLV2) + { + state->hash.update(static_cast<byte>(type)); + u32bit record_length = contents.size(); + for(u32bit j = 0; j != 3; j++) + state->hash.update(get_byte(j+1, record_length)); + } + state->hash.update(contents); } - if(type == CLIENT_HELLO) + if(type == CLIENT_HELLO || type == CLIENT_HELLO_SSLV2) { server_check_state(type, state); - state->client_hello = new Client_Hello(contents); + state->client_hello = new Client_Hello(contents, type); client_requested_hostname = state->client_hello->hostname(); @@ -358,7 +365,7 @@ void TLS_Server::process_handshake_msg(Handshake_Type type, state->suite = CipherSuite(state->server_hello->ciphersuite()); - if(state->suite.sig_type() != CipherSuite::NO_SIG) + 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, @@ -366,14 +373,14 @@ void TLS_Server::process_handshake_msg(Handshake_Type type, } state->kex_priv = PKCS8::copy_key(*private_key, rng); - if(state->suite.kex_type() != CipherSuite::NO_KEX) + if(state->suite.kex_type() != TLS_ALGO_KEYEXCH_NOKEX) { - if(state->suite.kex_type() == CipherSuite::RSA_KEX) + 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() == CipherSuite::DH_KEX) + else if(state->suite.kex_type() == TLS_ALGO_KEYEXCH_DH) { state->kex_priv = new DH_PrivateKey(rng, policy->dh_group()); } diff --git a/src/ssl/tls_suites.cpp b/src/ssl/tls_suites.cpp index a168dac0a..ccc4ab502 100644 --- a/src/ssl/tls_suites.cpp +++ b/src/ssl/tls_suites.cpp @@ -1,40 +1,254 @@ /** -* TLS Cipher Suites -* (C) 2004-2006 Jack Lloyd +* TLS Cipher Suites +* (C) 2004-2010 Jack Lloyd * * Released under the terms of the Botan license */ #include <botan/tls_suites.h> #include <botan/tls_exceptn.h> -#include <botan/parsing.h> -#include <vector> -#include <string> namespace Botan { -namespace { - /** -* Convert an SSL/TLS ciphersuite to a string +* Convert an SSL/TLS ciphersuite to algorithm fields */ -std::string lookup_ciphersuite(u16bit suite) +TLS_Ciphersuite_Algos CipherSuite::lookup_ciphersuite(u16bit suite) { - if(suite == RSA_RC4_MD5) return "RSA/NONE/ARC4/16/MD5"; - if(suite == RSA_RC4_SHA) return "RSA/NONE/ARC4/16/SHA1"; - if(suite == RSA_3DES_SHA) return "RSA/NONE/3DES/24/SHA1"; - if(suite == RSA_AES128_SHA) return "RSA/NONE/AES/16/SHA1"; - if(suite == RSA_AES256_SHA) return "RSA/NONE/AES/32/SHA1"; + 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 == DHE_RSA_3DES_SHA) return "RSA/DH/3DES/24/SHA1"; - if(suite == DHE_RSA_AES128_SHA) return "RSA/DH/AES/16/SHA1"; - if(suite == DHE_RSA_AES256_SHA) return "RSA/DH/AES/32/SHA1"; + 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 == DHE_DSS_3DES_SHA) return "DSA/DH/3DES/24/SHA1"; - if(suite == DHE_DSS_AES128_SHA) return "DSA/DH/AES/16/SHA1"; - if(suite == DHE_DSS_AES256_SHA) return "DSA/DH/AES/32/SHA1"; + 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); - return ""; + 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<std::string, u32bit> cipher_code_to_name(TLS_Ciphersuite_Algos algo) + { + if((algo & TLS_ALGO_CIPHER_MASK) == TLS_ALGO_CIPHER_RC4_128) + return std::make_pair("RC4", 128); + + 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)); } } @@ -47,31 +261,21 @@ CipherSuite::CipherSuite(u16bit suite_code) if(suite_code == 0) return; - std::string suite_string = lookup_ciphersuite(suite_code); + TLS_Ciphersuite_Algos algos = lookup_ciphersuite(suite_code); + + if(algos == 0) + throw Invalid_Argument("Unknown ciphersuite: " + to_string(suite_code)); - if(suite_string == "") - throw Invalid_Argument("Unknown ciphersuite: " + - std::to_string(suite_code)); + sig_algo = TLS_Ciphersuite_Algos(algos & TLS_ALGO_SIGNER_MASK); - std::vector<std::string> suite_info = split_on(suite_string, '/'); + kex_algo = TLS_Ciphersuite_Algos(algos & TLS_ALGO_KEYEXCH_MASK); - if(suite_info[0] == "RSA") sig_algo = RSA_SIG; - else if(suite_info[0] == "DSA") sig_algo = DSA_SIG; - else if(suite_info[0] == "NONE") sig_algo = NO_SIG; - else - throw TLS_Exception(INTERNAL_ERROR, - "CipherSuite: Unknown sig type " + suite_info[0]); + std::pair<std::string, u32bit> cipher_info = cipher_code_to_name(algos); - if(suite_info[1] == "DH") kex_algo = DH_KEX; - else if(suite_info[1] == "RSA") kex_algo = RSA_KEX; - else if(suite_info[1] == "NONE") kex_algo = NO_KEX; - else - throw TLS_Exception(INTERNAL_ERROR, - "CipherSuite: Unknown kex type " + suite_info[1]); + cipher = cipher_info.first; + cipher_key_length = cipher_info.second; - cipher = suite_info[2]; - cipher_key_length = to_u32bit(suite_info[3]); - mac = suite_info[4]; + mac = mac_code_to_name(algos); } } diff --git a/src/ssl/tls_suites.h b/src/ssl/tls_suites.h index b7008e8db..fa015c28f 100644 --- a/src/ssl/tls_suites.h +++ b/src/ssl/tls_suites.h @@ -1,6 +1,6 @@ /** -* Cipher Suites -* (C) 2004-2006 Jack Lloyd +* Cipher Suites +* (C) 2004-2010 Jack Lloyd * * Released under the terms of the Botan license */ @@ -9,6 +9,7 @@ #define BOTAN_TLS_CIPHERSUITES_H__ #include <botan/types.h> +#include <botan/tls_magic.h> #include <string> namespace Botan { @@ -19,20 +20,19 @@ namespace Botan { class BOTAN_DLL CipherSuite { public: - enum Kex_Type { NO_KEX, RSA_KEX, DH_KEX }; - enum Sig_Type { NO_SIG, RSA_SIG, DSA_SIG }; + static TLS_Ciphersuite_Algos lookup_ciphersuite(u16bit suite); std::string cipher_algo() const { return cipher; } std::string mac_algo() const { return mac; } u32bit cipher_keylen() const { return cipher_key_length; } - Kex_Type kex_type() const { return kex_algo; } - Sig_Type sig_type() const { return sig_algo; } + + TLS_Ciphersuite_Algos kex_type() const { return kex_algo; } + TLS_Ciphersuite_Algos sig_type() const { return sig_algo; } CipherSuite(u16bit = 0); private: - Kex_Type kex_algo; - Sig_Type sig_algo; + TLS_Ciphersuite_Algos kex_algo, sig_algo; std::string cipher, mac; u32bit cipher_key_length; }; |