diff options
author | Jack Lloyd <[email protected]> | 2017-08-31 19:09:22 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2017-08-31 19:20:10 -0400 |
commit | d42bbd3540f09dd154123e97032f5bfc0b110c4e (patch) | |
tree | 0f3676a25963544b06d7c6c339f9828d95f36363 | |
parent | c53cfda7b5e2f57927041c67be9db10b18b2ba8a (diff) |
Enforce signature hash policy properly
Previously if the client did not send signature_algorithms, or if
it only included algos not in the policy, we would just fallback to
the hardcoded SHA-1 default of TLS v1.2
Instead check the policy before accepting anything.
-rw-r--r-- | src/cli/tls_server.cpp | 2 | ||||
-rw-r--r-- | src/lib/tls/tls_handshake_state.cpp | 38 | ||||
-rw-r--r-- | src/lib/tls/tls_policy.cpp | 5 | ||||
-rw-r--r-- | src/lib/tls/tls_policy.h | 1 | ||||
-rw-r--r-- | src/lib/tls/tls_server.cpp | 34 |
5 files changed, 62 insertions, 18 deletions
diff --git a/src/cli/tls_server.cpp b/src/cli/tls_server.cpp index 22e592f29..82b2f5e2f 100644 --- a/src/cli/tls_server.cpp +++ b/src/cli/tls_server.cpp @@ -218,7 +218,7 @@ class TLS_Server final : public Command } catch(std::exception& e) { - std::cout << "Connection1 problem: " << e.what() << std::endl; + std::cout << "Connection problem: " << e.what() << std::endl; if(is_tcp) { ::close(fd); diff --git a/src/lib/tls/tls_handshake_state.cpp b/src/lib/tls/tls_handshake_state.cpp index d87af7305..35973b359 100644 --- a/src/lib/tls/tls_handshake_state.cpp +++ b/src/lib/tls/tls_handshake_state.cpp @@ -372,11 +372,9 @@ KDF* Handshake_State::protocol_specific_prf() const 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, - bool for_client_auth, - const Client_Hello* client_hello, - const Certificate_Req* cert_req) + const Policy& policy) { if(!negotiated_version.supports_negotiable_signature_algorithms()) { @@ -392,19 +390,15 @@ std::string choose_hash(const std::string& sig_algo, throw Internal_Error("Unknown TLS signature algo " + sig_algo); } - const auto supported_algos = for_client_auth ? - cert_req->supported_algos() : - client_hello->supported_algos(); - if(!supported_algos.empty()) { - const auto hashes = policy.allowed_signature_hashes(); + const std::vector<std::string> hashes = policy.allowed_signature_hashes(); /* * Choose our most preferred hash that the counterparty supports * in pairing with the signature algorithm we want to use. */ - for(auto hash : hashes) + for(std::string hash : hashes) { for(auto algo : supported_algos) { @@ -429,16 +423,26 @@ Handshake_State::choose_sig_format(const Private_Key& key, { const std::string sig_algo = key.algo_name(); - const std::string hash_algo = - choose_hash(sig_algo, - this->version(), - policy, - for_client_auth, - client_hello(), - cert_req()); + 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 + + std::vector<std::string> allowed_hashes = policy.allowed_signature_hashes(); + + if(!policy.allowed_signature_hash(hash_algo)) + { + 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; } diff --git a/src/lib/tls/tls_policy.cpp b/src/lib/tls/tls_policy.cpp index 60f8957c0..ac71024ee 100644 --- a/src/lib/tls/tls_policy.cpp +++ b/src/lib/tls/tls_policy.cpp @@ -93,6 +93,11 @@ bool Policy::allowed_signature_method(const std::string& sig_method) const return value_exists(allowed_signature_methods(), sig_method); } +bool Policy::allowed_signature_hash(const std::string& sig_hash) const + { + return value_exists(allowed_signature_hashes(), sig_hash); + } + std::vector<std::string> Policy::allowed_ecc_curves() const { // Default list is ordered by performance diff --git a/src/lib/tls/tls_policy.h b/src/lib/tls/tls_policy.h index 35d439399..d36a20aad 100644 --- a/src/lib/tls/tls_policy.h +++ b/src/lib/tls/tls_policy.h @@ -74,6 +74,7 @@ class BOTAN_DLL Policy virtual bool require_cert_revocation_info() const; bool allowed_signature_method(const std::string& sig_method) const; + bool allowed_signature_hash(const std::string& hash) const; /** * Return list of ECC curves we are willing to use in order of preference diff --git a/src/lib/tls/tls_server.cpp b/src/lib/tls/tls_server.cpp index f509122a8..8265a2846 100644 --- a/src/lib/tls/tls_server.cpp +++ b/src/lib/tls/tls_server.cpp @@ -205,6 +205,40 @@ uint16_t choose_ciphersuite( continue; } + if(version.supports_negotiable_signature_algorithms()) + { + const std::vector<std::pair<std::string, std::string>> client_sig_hash_pairs = + client_hello.supported_algos(); + + if(client_hello.supported_algos().empty() == false) + { + bool we_support_some_hash_by_client = false; + + for(auto&& hash_and_sig : client_hello.supported_algos()) + { + if(hash_and_sig.second == suite.sig_algo() && + policy.allowed_signature_hash(hash_and_sig.first)) + { + we_support_some_hash_by_client = true; + break; + } + } + + if(we_support_some_hash_by_client == false) + { + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Policy does not accept any hash function supported by client"); + } + } + else + { + if(policy.allowed_signature_hash("SHA-1") == false) + throw TLS_Exception(Alert::HANDSHAKE_FAILURE, + "Client did not send signature_algorithms extension " + "and policy prohibits SHA-1 fallback"); + } + } + #if defined(BOTAN_HAS_SRP6) /* The client may offer SRP cipher suites in the hello message but |