aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2017-08-31 19:09:22 -0400
committerJack Lloyd <[email protected]>2017-08-31 19:20:10 -0400
commitd42bbd3540f09dd154123e97032f5bfc0b110c4e (patch)
tree0f3676a25963544b06d7c6c339f9828d95f36363 /src
parentc53cfda7b5e2f57927041c67be9db10b18b2ba8a (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.
Diffstat (limited to 'src')
-rw-r--r--src/cli/tls_server.cpp2
-rw-r--r--src/lib/tls/tls_handshake_state.cpp38
-rw-r--r--src/lib/tls/tls_policy.cpp5
-rw-r--r--src/lib/tls/tls_policy.h1
-rw-r--r--src/lib/tls/tls_server.cpp34
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