diff options
author | Jack Lloyd <[email protected]> | 2017-12-21 15:37:39 -0500 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2018-01-28 12:14:07 -0500 |
commit | b2b55e6c2fdb824f49923b60d2c3ffff8f0fb99a (patch) | |
tree | 8d5650816329cbe176a4e1fee639094c9387b260 /src/lib/tls/tls_handshake_state.cpp | |
parent | 1c667d34bf71336d33bb76309176a993f13a2aac (diff) |
Use enums to represent TLS signature and kex algorithms.
Adds support for PSS signatures (currently verifying only).
Diffstat (limited to 'src/lib/tls/tls_handshake_state.cpp')
-rw-r--r-- | src/lib/tls/tls_handshake_state.cpp | 213 |
1 files changed, 92 insertions, 121 deletions
diff --git a/src/lib/tls/tls_handshake_state.cpp b/src/lib/tls/tls_handshake_state.cpp index 0fcf0d2ab..ab023834b 100644 --- a/src/lib/tls/tls_handshake_state.cpp +++ b/src/lib/tls/tls_handshake_state.cpp @@ -341,7 +341,7 @@ std::string Handshake_State::srp_identifier() const { #if defined(BOTAN_HAS_SRP6) // Authenticated via the successful key exchange - if(ciphersuite().valid() && ciphersuite().kex_algo() == "SRP_SHA") + if(ciphersuite().valid() && ciphersuite().kex_method() == Kex_Algo::SRP_SHA) return client_hello()->srp_identifier(); #endif @@ -373,93 +373,70 @@ KDF* Handshake_State::protocol_specific_prf() const return get_kdf("TLS-PRF"); } -namespace { - -std::string choose_hash(const std::string& sig_algo, - std::vector<std::pair<std::string, std::string>>& supported_algos, - Protocol_Version negotiated_version, - const Policy& policy) +std::pair<std::string, Signature_Format> +Handshake_State::choose_sig_format(const Private_Key& key, + Signature_Scheme& chosen_scheme, + bool for_client_auth, + const Policy& policy) const { - if(!negotiated_version.supports_negotiable_signature_algorithms()) - { - if(sig_algo == "RSA") - return "Parallel(MD5,SHA-160)"; + const std::string sig_algo = key.algo_name(); - if(sig_algo == "DSA") - return "SHA-1"; + if(this->version().supports_negotiable_signature_algorithms()) + { + const std::vector<Signature_Scheme> allowed = policy.allowed_signature_schemes(); - if(sig_algo == "ECDSA") - return "SHA-1"; + std::vector<Signature_Scheme> schemes = + (for_client_auth) ? cert_req()->signature_schemes() : client_hello()->signature_schemes(); - throw Internal_Error("Unknown TLS signature algo " + sig_algo); - } - - if(!supported_algos.empty()) - { - const std::vector<std::string> hashes = policy.allowed_signature_hashes(); + if(schemes.empty()) + { + // Implicit SHA-1 + schemes.push_back(Signature_Scheme::RSA_PKCS1_SHA1); + schemes.push_back(Signature_Scheme::ECDSA_SHA1); + schemes.push_back(Signature_Scheme::DSA_SHA1); + } - /* - * Choose our most preferred hash that the counterparty supports - * in pairing with the signature algorithm we want to use. - */ - for(std::string hash : hashes) + for(Signature_Scheme scheme : schemes) { - for(auto algo : supported_algos) + if(signature_algorithm_of_scheme(scheme) == sig_algo) { - if(algo.first == hash && algo.second == sig_algo) - return hash; + if(std::find(allowed.begin(), allowed.end(), scheme) != allowed.end()) + { + chosen_scheme = scheme; + break; + } } } - } - // TLS v1.2 default hash if the counterparty sent nothing - return "SHA-1"; - } + const std::string hash = hash_function_of_scheme(chosen_scheme); -} - -std::pair<std::string, Signature_Format> -Handshake_State::choose_sig_format(const Private_Key& key, - std::string& hash_algo_out, - std::string& sig_algo_out, - bool for_client_auth, - const Policy& policy) const - { - const std::string sig_algo = key.algo_name(); - - std::vector<std::pair<std::string, std::string>> supported_algos = - (for_client_auth) ? cert_req()->supported_algos() : client_hello()->supported_algos(); - - const std::string hash_algo = choose_hash(sig_algo, - supported_algos, - this->version(), - policy); - - if(this->version().supports_negotiable_signature_algorithms()) - { - // We skip this check for v1.0 since you're stuck with SHA-1 regardless - - if(!policy.allowed_signature_hash(hash_algo)) + if(!policy.allowed_signature_hash(hash)) { throw TLS_Exception(Alert::HANDSHAKE_FAILURE, "Policy refuses to accept signing with any hash supported by peer"); } - 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); + if(sig_algo == "RSA") + { + return std::make_pair(padding_string_for_scheme(chosen_scheme), IEEE_1363); + } + else if(sig_algo == "DSA" || sig_algo == "ECDSA") + { + return std::make_pair(padding_string_for_scheme(chosen_scheme), DER_SEQUENCE); + } } - else if(sig_algo == "DSA" || sig_algo == "ECDSA") + else { - const std::string padding = "EMSA1(" + hash_algo + ")"; - - return std::make_pair(padding, DER_SEQUENCE); + if(sig_algo == "RSA") + { + const std::string padding = "EMSA3(Parallel(MD5,SHA-160))"; + return std::make_pair(padding, IEEE_1363); + } + else if(sig_algo == "DSA" || sig_algo == "ECDSA") + { + const std::string padding = "EMSA1(SHA-1)"; + return std::make_pair(padding, DER_SEQUENCE); + } } throw Invalid_Argument(sig_algo + " is invalid/unknown for TLS signatures"); @@ -468,13 +445,14 @@ Handshake_State::choose_sig_format(const Private_Key& key, namespace { bool supported_algos_include( - const std::vector<std::pair<std::string, std::string>>& algos, + const std::vector<Signature_Scheme>& schemes, const std::string& key_type, const std::string& hash_type) { - for(auto&& algo : algos) + for(Signature_Scheme scheme : schemes) { - if(algo.first == hash_type && algo.second == key_type) + if(hash_function_of_scheme(scheme) == hash_type && + signature_algorithm_of_scheme(scheme) == key_type) { return true; } @@ -487,8 +465,7 @@ bool supported_algos_include( std::pair<std::string, Signature_Format> Handshake_State::parse_sig_format(const Public_Key& key, - const std::string& input_hash_algo, - const std::string& input_sig_algo, + Signature_Scheme scheme, bool for_client_auth, const Policy& policy) const { @@ -500,73 +477,67 @@ Handshake_State::parse_sig_format(const Public_Key& key, "Rejecting " + key_type + " signature"); } - std::string hash_algo; - - if(this->version().supports_negotiable_signature_algorithms()) + if(this->version().supports_negotiable_signature_algorithms() == false) { - if(input_sig_algo != key_type) - throw Decoding_Error("Counterparty sent inconsistent key and sig types"); - - if(input_hash_algo == "") - throw Decoding_Error("Counterparty did not send hash/sig IDS"); - - hash_algo = input_hash_algo; - - if(for_client_auth && !cert_req()) - { - throw TLS_Exception(Alert::HANDSHAKE_FAILURE, - "No certificate verify set"); - } + if(scheme != Signature_Scheme::NONE) + throw Decoding_Error("Counterparty sent hash/sig IDs with old version"); /* - Confirm the signature type we just received against the - supported_algos list that we sent; it better be there. + There is no check on the acceptability of a v1.0/v1.1 hash type, + since it's implicit with use of the protocol */ - const auto supported_algos = - for_client_auth ? cert_req()->supported_algos() : - client_hello()->supported_algos(); - - if(!supported_algos_include(supported_algos, key_type, hash_algo)) - { - throw TLS_Exception(Alert::HANDSHAKE_FAILURE, - "TLS signature extension did not allow for " + - key_type + "/" + hash_algo + " signature"); - } - } - else - { - if(input_hash_algo != "" || input_sig_algo != "") - throw Decoding_Error("Counterparty sent hash/sig IDs with old version"); - if(key_type == "RSA") { - hash_algo = "Parallel(MD5,SHA-160)"; + const std::string padding = "EMSA3(Parallel(MD5,SHA-160))"; + return std::make_pair(padding, IEEE_1363); } else if(key_type == "DSA" || key_type == "ECDSA") { - hash_algo = "SHA-1"; + const std::string padding = "EMSA1(SHA-1)"; + return std::make_pair(padding, DER_SEQUENCE); } else - { throw Invalid_Argument(key_type + " is invalid/unknown for TLS signatures"); - } + } - /* - There is no check on the acceptability of a v1.0/v1.1 hash type, - since it's implicit with use of the protocol - */ + if(scheme == Signature_Scheme::NONE) + throw Decoding_Error("Counterparty did not send hash/sig IDS"); + + if(key_type != signature_algorithm_of_scheme(scheme)) + throw Decoding_Error("Counterparty sent inconsistent key and sig types"); + + if(for_client_auth && !cert_req()) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "No certificate verify set"); + } + + /* + Confirm the signature type we just received against the + supported_algos list that we sent; it better be there. + */ + + const std::vector<Signature_Scheme> supported_algos = + for_client_auth ? cert_req()->signature_schemes() : + client_hello()->signature_schemes(); + + const std::string hash_algo = hash_function_of_scheme(scheme); + + if(!supported_algos_include(supported_algos, key_type, hash_algo)) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "TLS signature extension did not allow for " + + key_type + "/" + hash_algo + " signature"); } if(key_type == "RSA") { - const std::string padding = "EMSA3(" + hash_algo + ")"; - return std::make_pair(padding, IEEE_1363); + return std::make_pair(padding_string_for_scheme(scheme), IEEE_1363); } else if(key_type == "DSA" || key_type == "ECDSA") { - const std::string padding = "EMSA1(" + hash_algo + ")"; - return std::make_pair(padding, DER_SEQUENCE); + return std::make_pair(padding_string_for_scheme(scheme), DER_SEQUENCE); } throw Invalid_Argument(key_type + " is invalid/unknown for TLS signatures"); |