From 87fd27adfe84478c52186107fc383890544eeeba Mon Sep 17 00:00:00 2001 From: lloyd Date: Fri, 20 Jan 2012 22:21:12 +0000 Subject: When generating a signature in TLS 1.2, respect the request of the counterparty by using the highest preference hash they have available for the signature type we are generating. This does mean we will do stupid things, if the counterparty is stupid (for instance some versions of GnuTLS will prefer SHA-1 over the SHA-2s - likely someone misread the spec and ordered the list backwards). But because we filter out MD5 we'll never use that; even in the worst case, if someone requests only MD5, we'll skip over it and use SHA-1 as the fallback algorithm. Theoretically this is against the spec because we "MUST" send something compatible, but seriously, fuck em. Right in the eye. --- src/tls/c_hello.cpp | 3 +- src/tls/cert_req.cpp | 19 ++++++++++-- src/tls/s_kex.cpp | 2 +- src/tls/tls_handshake_state.cpp | 64 +++++++++++++++++------------------------ src/tls/tls_messages.h | 6 ++++ src/tls/tls_policy.cpp | 3 ++ src/tls/tls_policy.h | 2 +- src/tls/tls_suites.cpp | 31 ++++++++++---------- 8 files changed, 73 insertions(+), 57 deletions(-) diff --git a/src/tls/c_hello.cpp b/src/tls/c_hello.cpp index d821482fd..2d94de462 100644 --- a/src/tls/c_hello.cpp +++ b/src/tls/c_hello.cpp @@ -301,6 +301,7 @@ void Client_Hello::deserialize(const MemoryRegion& buf) */ m_supported_algos.push_back(std::make_pair("SHA-1", "RSA")); m_supported_algos.push_back(std::make_pair("SHA-1", "DSA")); + m_supported_algos.push_back(std::make_pair("SHA-1", "ECDSA")); } else { @@ -308,8 +309,8 @@ void Client_Hello::deserialize(const MemoryRegion& buf) m_supported_algos.push_back(std::make_pair("TLS.Digest.0", "RSA")); m_supported_algos.push_back(std::make_pair("SHA-1", "DSA")); + m_supported_algos.push_back(std::make_pair("SHA-1", "ECDSA")); } - } if(value_exists(m_suites, static_cast(TLS_EMPTY_RENEGOTIATION_INFO_SCSV))) diff --git a/src/tls/cert_req.cpp b/src/tls/cert_req.cpp index 4e86a3270..7fbe2a809 100644 --- a/src/tls/cert_req.cpp +++ b/src/tls/cert_req.cpp @@ -60,9 +60,24 @@ Certificate_Req::Certificate_Req(const MemoryRegion& buf, if(version >= TLS_V12) { - std::vector sig_hash_algs = reader.get_range_vector(2, 2, 65534); + std::vector sig_hash_algs = reader.get_range_vector(2, 2, 65534); - // FIXME, do something with this + if(sig_hash_algs.size() % 2 != 0) + throw Decoding_Error("Bad length for signature IDs in certificate request"); + + for(size_t i = 0; i != sig_hash_algs.size(); i += 2) + { + std::string hash = Signature_Algorithms::hash_algo_name(sig_hash_algs[i]); + std::string sig = Signature_Algorithms::sig_algo_name(sig_hash_algs[i+1]); + m_supported_algos.push_back(std::make_pair(hash, sig)); + } + } + else + { + // The hardcoded settings from previous protocol versions + m_supported_algos.push_back(std::make_pair("TLS.Digest.0", "RSA")); + m_supported_algos.push_back(std::make_pair("SHA-1", "DSA")); + m_supported_algos.push_back(std::make_pair("SHA-1", "ECDSA")); } u16bit purported_size = reader.get_u16bit(); diff --git a/src/tls/s_kex.cpp b/src/tls/s_kex.cpp index 9ec35e19b..71e40f01c 100644 --- a/src/tls/s_kex.cpp +++ b/src/tls/s_kex.cpp @@ -55,7 +55,7 @@ MemoryVector Server_Key_Exchange::serialize() const { MemoryVector buf = serialize_params(); - // NEEDS VERSION CHECK + // This should be an explicit version check if(m_hash_algo != "" && m_sig_algo != "") { buf.push_back(Signature_Algorithms::hash_algo_code(m_hash_algo)); diff --git a/src/tls/tls_handshake_state.cpp b/src/tls/tls_handshake_state.cpp index dfa320cda..c424c9726 100644 --- a/src/tls/tls_handshake_state.cpp +++ b/src/tls/tls_handshake_state.cpp @@ -7,6 +7,7 @@ #include #include +#include namespace Botan { @@ -137,55 +138,42 @@ TLS_Handshake_State::choose_sig_format(const Private_Key* key, { const std::string sig_algo = key->algo_name(); - /* - FIXME: This should respect the algo preferences in the client hello - (or certificate request, depending on value of for_client_auth). - */ + const std::vector > supported_algos = + (for_client_auth) ? cert_req->supported_algos() : client_hello->supported_algos(); - if(sig_algo == "RSA") - { - std::string hash_algo; + std::string hash_algo; - if(for_client_auth && this->version == SSL_V3) - { - hash_algo = "Raw"; - } - else if(this->version < TLS_V12) + for(size_t i = 0; i != supported_algos.size(); ++i) + { + if(supported_algos[i].second == sig_algo) { - hash_algo = "TLS.Digest.0"; + hash_algo = supported_algos[i].first; + break; } - else - { - hash_algo = "SHA-256"; // should be policy + } - sig_algo_out = sig_algo; - hash_algo_out = hash_algo; - } + if(for_client_auth && this->version == SSL_V3) + hash_algo = "Raw"; + if(hash_algo == "" && this->version == TLS_V12) + hash_algo = "SHA-1"; // TLS 1.2 but no compatible hashes set (?) + + BOTAN_ASSERT(hash_algo != "", "Couldn't figure out hash to use"); + + if(this->version >= TLS_V12) + { + hash_algo_out = hash_algo; + sig_algo_out = sig_algo; + } + + if(sig_algo == "RSA") + { const std::string padding = "EMSA3(" + hash_algo + ")"; return std::make_pair(padding, IEEE_1363); } else if(sig_algo == "DSA") { - std::string hash_algo; - - if(for_client_auth && this->version == SSL_V3) - { - hash_algo = "Raw"; - } - else if(this->version < TLS_V12) - { - hash_algo = "SHA-1"; - } - else - { - hash_algo = "SHA-1"; // should be policy - - sig_algo_out = sig_algo; - hash_algo_out = hash_algo; - } - const std::string padding = "EMSA1(" + hash_algo + ")"; return std::make_pair(padding, DER_SEQUENCE); @@ -206,6 +194,8 @@ TLS_Handshake_State::understand_sig_format(const Public_Key* key, FIXME: This should check what was sent against the client hello preferences, or the certificate request, to ensure it was allowed by those restrictions. + + Or not? */ if(this->version < TLS_V12) diff --git a/src/tls/tls_messages.h b/src/tls/tls_messages.h index c86d71045..ffc325a89 100644 --- a/src/tls/tls_messages.h +++ b/src/tls/tls_messages.h @@ -58,6 +58,9 @@ class Client_Hello : public Handshake_Message return v; } + std::vector > supported_algos() const + { return m_supported_algos; } + std::vector ciphersuites() const { return m_suites; } std::vector compression_methods() const { return m_comp_methods; } @@ -257,6 +260,9 @@ class Certificate_Req : public Handshake_Message std::vector acceptable_types() const { return cert_types; } std::vector acceptable_CAs() const { return names; } + std::vector > supported_algos() const + { return m_supported_algos; } + Certificate_Req(Record_Writer& writer, TLS_Handshake_Hash& hash, const TLS_Policy& policy, diff --git a/src/tls/tls_policy.cpp b/src/tls/tls_policy.cpp index 90fa88c82..c02f35a9a 100644 --- a/src/tls/tls_policy.cpp +++ b/src/tls/tls_policy.cpp @@ -197,6 +197,9 @@ u16bit TLS_Policy::choose_suite(const std::vector& client_suites, if(suite.kex_algo() == "ECDH") continue; // not currently supported + if(suite.kex_algo() == "ECDH") + continue; // not yet supported + if(suite.sig_algo() == "RSA" && have_rsa) return suite_id; else if(suite.sig_algo() == "DSA" && have_dsa) diff --git a/src/tls/tls_policy.h b/src/tls/tls_policy.h index c14709e7e..5bf60742b 100644 --- a/src/tls/tls_policy.h +++ b/src/tls/tls_policy.h @@ -75,7 +75,7 @@ class BOTAN_DLL TLS_Policy /* * @return the version we would prefer to negotiate */ - virtual Version_Code pref_version() const { return TLS_V11; } + virtual Version_Code pref_version() const { return TLS_V12; } virtual ~TLS_Policy() {} }; diff --git a/src/tls/tls_suites.cpp b/src/tls/tls_suites.cpp index 9c63cd593..d49cfe097 100644 --- a/src/tls/tls_suites.cpp +++ b/src/tls/tls_suites.cpp @@ -43,7 +43,7 @@ TLS_Ciphersuite TLS_Ciphersuite::lookup_ciphersuite(u16bit suite) case TLS_RSA_WITH_AES_256_CBC_SHA256: return TLS_Ciphersuite("RSA", "", "SHA-256", "AES-256", 32); - // DHE/DSS ciphersuites + // DH/DSS ciphersuites case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: return TLS_Ciphersuite("DSA", "DH", "SHA-1", "TripleDES", 24); @@ -66,7 +66,7 @@ TLS_Ciphersuite TLS_Ciphersuite::lookup_ciphersuite(u16bit suite) case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: return TLS_Ciphersuite("DSA", "DH", "SHA-256", "AES-256", 32); - // DHE/RSA ciphersuites + // DH/RSA ciphersuites case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: return TLS_Ciphersuite("RSA", "DH", "SHA-1", "TripleDES", 24); @@ -86,6 +86,19 @@ TLS_Ciphersuite TLS_Ciphersuite::lookup_ciphersuite(u16bit suite) case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: return TLS_Ciphersuite("RSA", "DH", "SHA-256", "AES-256", 32); + // ECDH/RSA ciphersuites + case TLS_ECDHE_RSA_WITH_RC4_128_SHA: + return TLS_Ciphersuite("RSA", "ECDH", "SHA-1", "ARC4", 16); + + case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: + return TLS_Ciphersuite("RSA", "ECDH", "SHA-1", "TripleDES", 24); + + case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: + return TLS_Ciphersuite("RSA", "ECDH", "SHA-1", "AES-128", 16); + + case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: + return TLS_Ciphersuite("RSA", "ECDH", "SHA-1", "AES-256", 32); + // SRP ciphersuites case TLS_SRP_SHA_RSA_WITH_3DES_EDE_SHA: @@ -106,7 +119,7 @@ TLS_Ciphersuite TLS_Ciphersuite::lookup_ciphersuite(u16bit suite) case TLS_SRP_SHA_DSS_WITH_AES_256_SHA: return TLS_Ciphersuite("DSA", "SRP", "SHA-1", "AES-256", 32); - // ECC ciphersuites + // ECDH/ECDSA ciphersuites case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: return TLS_Ciphersuite("ECDSA", "ECDH", "SHA-1", "ARC4", 16); @@ -126,18 +139,6 @@ TLS_Ciphersuite TLS_Ciphersuite::lookup_ciphersuite(u16bit suite) case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: return TLS_Ciphersuite("ECDSA", "ECDH", "SHA-384", "AES-256", 32); - case TLS_ECDHE_RSA_WITH_RC4_128_SHA: - return TLS_Ciphersuite("RSA", "ECDH", "SHA-1", "ARC4", 16); - - case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: - return TLS_Ciphersuite("RSA", "ECDH", "SHA-1", "TripleDES", 24); - - case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: - return TLS_Ciphersuite("RSA", "ECDH", "SHA-1", "AES-128", 16); - - case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: - return TLS_Ciphersuite("RSA", "ECDH", "SHA-1", "AES-256", 32); - case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: return TLS_Ciphersuite("ECDSA", "ECDH", "SHA-256", "AES-128", 16); -- cgit v1.2.3