From 805bb27dff20e491e76142db2b5fe1bd586d4788 Mon Sep 17 00:00:00 2001 From: Harry Reimann Date: Wed, 29 Nov 2017 08:35:27 +0100 Subject: Make support for certificate status messages optional via policy Don't postpone the verification of a server certificate if certificate status messages are not expected in client handshake. When using an external crypto device it may be necessary to verify the certificate before using the public key for verification of the signature in the server key exchange message. --- src/lib/tls/msg_client_hello.cpp | 3 ++- src/lib/tls/msg_server_hello.cpp | 9 ++------- src/lib/tls/tls_client.cpp | 24 ++++++++++++++++++++++-- src/lib/tls/tls_policy.cpp | 2 ++ src/lib/tls/tls_policy.h | 7 +++++++ src/lib/tls/tls_text_policy.cpp | 5 +++++ src/tests/unit_tls.cpp | 3 +++ 7 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/lib/tls/msg_client_hello.cpp b/src/lib/tls/msg_client_hello.cpp index 3b13cf21d..bcd8397e8 100644 --- a/src/lib/tls/msg_client_hello.cpp +++ b/src/lib/tls/msg_client_hello.cpp @@ -105,7 +105,8 @@ Client_Hello::Client_Hello(Handshake_IO& io, m_extensions.add(new Renegotiation_Extension(reneg_info)); m_extensions.add(new Server_Name_Indicator(client_settings.hostname())); - m_extensions.add(new Certificate_Status_Request({}, {})); + if(policy.support_cert_status_message()) + m_extensions.add(new Certificate_Status_Request({}, {})); if(reneg_info.empty() && !next_protocols.empty()) m_extensions.add(new Application_Layer_Protocol_Notification(next_protocols)); diff --git a/src/lib/tls/msg_server_hello.cpp b/src/lib/tls/msg_server_hello.cpp index 67c3d530f..81f9e1f62 100644 --- a/src/lib/tls/msg_server_hello.cpp +++ b/src/lib/tls/msg_server_hello.cpp @@ -37,7 +37,7 @@ Server_Hello::Server_Hello(Handshake_IO& io, m_extensions.add(new Extended_Master_Secret); // Sending the extension back does not commit us to sending a stapled response - if(client_hello.supports_cert_status_message()) + if(client_hello.supports_cert_status_message() && policy.support_cert_status_message()) m_extensions.add(new Certificate_Status_Request); Ciphersuite c = Ciphersuite::by_id(m_ciphersuite); @@ -105,7 +105,7 @@ Server_Hello::Server_Hello(Handshake_IO& io, m_extensions.add(new Extended_Master_Secret); // Sending the extension back does not commit us to sending a stapled response - if(client_hello.supports_cert_status_message()) + if(client_hello.supports_cert_status_message() && policy.support_cert_status_message()) m_extensions.add(new Certificate_Status_Request); if(client_hello.supports_encrypt_then_mac() && policy.negotiate_encrypt_then_mac()) @@ -115,11 +115,6 @@ Server_Hello::Server_Hello(Handshake_IO& io, m_extensions.add(new Encrypt_then_MAC); } - if(client_hello.supports_cert_status_message()) - { - m_extensions.add(new Certificate_Status_Request); - } - if(resumed_session.ciphersuite().ecc_ciphersuite()) { m_extensions.add(new Supported_Point_Formats(policy.use_ecc_point_compression())); diff --git a/src/lib/tls/tls_client.cpp b/src/lib/tls/tls_client.cpp index 0e620a279..a1b71841d 100644 --- a/src/lib/tls/tls_client.cpp +++ b/src/lib/tls/tls_client.cpp @@ -386,7 +386,8 @@ void Client::process_handshake_msg(const Handshake_State* active_state, "Client: No certificates sent by server"); /* - Certificate verification happens after we receive the server hello done, + If the server supports certificate status messages, + certificate verification happens after we receive the server hello done, in case an OCSP response was also available */ @@ -412,6 +413,24 @@ void Client::process_handshake_msg(const Handshake_State* active_state, { state.set_expected_next(CERTIFICATE_STATUS); // optional } + else + { + try + { + auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-client", m_info.hostname()); + + callbacks().tls_verify_cert_chain(server_certs, + {}, + trusted_CAs, + Usage_Type::TLS_SERVER_AUTH, + m_info.hostname(), + policy()); + } + catch(std::exception& e) + { + throw TLS_Exception(Alert::BAD_CERTIFICATE, e.what()); + } + } } else if(type == CERTIFICATE_STATUS) { @@ -459,7 +478,8 @@ void Client::process_handshake_msg(const Handshake_State* active_state, { state.server_hello_done(new Server_Hello_Done(contents)); - if(state.server_certs() != nullptr) + if(state.server_certs() != nullptr && + state.server_hello()->supports_certificate_status_message()) { try { diff --git a/src/lib/tls/tls_policy.cpp b/src/lib/tls/tls_policy.cpp index 5d82eee0c..1c6be6620 100644 --- a/src/lib/tls/tls_policy.cpp +++ b/src/lib/tls/tls_policy.cpp @@ -341,6 +341,7 @@ bool Policy::include_time_in_hello_random() const { return true; } bool Policy::hide_unknown_users() const { return false; } bool Policy::server_uses_own_ciphersuite_preferences() const { return true; } bool Policy::negotiate_encrypt_then_mac() const { return true; } +bool Policy::support_cert_status_message() const { return true; } // 1 second initial timeout, 60 second max - see RFC 6347 sec 4.2.4.1 size_t Policy::dtls_initial_timeout() const { return 1*1000; } @@ -552,6 +553,7 @@ void Policy::print(std::ostream& o) const print_bool(o, "hide_unknown_users", hide_unknown_users()); print_bool(o, "server_uses_own_ciphersuite_preferences", server_uses_own_ciphersuite_preferences()); print_bool(o, "negotiate_encrypt_then_mac", negotiate_encrypt_then_mac()); + print_bool(o, "support_cert_status_message", support_cert_status_message()); o << "session_ticket_lifetime = " << session_ticket_lifetime() << '\n'; o << "dh_group = " << dh_group() << '\n'; o << "minimum_dh_group_size = " << minimum_dh_group_size() << '\n'; diff --git a/src/lib/tls/tls_policy.h b/src/lib/tls/tls_policy.h index db2cbb3bb..fe7e50f8d 100644 --- a/src/lib/tls/tls_policy.h +++ b/src/lib/tls/tls_policy.h @@ -287,6 +287,11 @@ class BOTAN_PUBLIC_API(2,0) Policy */ virtual bool negotiate_encrypt_then_mac() const; + /** + * Indicates whether certificate status messages should be supported + */ + virtual bool support_cert_status_message() const; + /** * Return allowed ciphersuites, in order of preference */ @@ -502,6 +507,8 @@ class BOTAN_PUBLIC_API(2,0) Text_Policy : public Policy bool negotiate_encrypt_then_mac() const override; + bool support_cert_status_message() const override; + std::string dh_group() const override; size_t minimum_ecdh_group_size() const override; diff --git a/src/lib/tls/tls_text_policy.cpp b/src/lib/tls/tls_text_policy.cpp index 345e6005f..1f93b1e0f 100644 --- a/src/lib/tls/tls_text_policy.cpp +++ b/src/lib/tls/tls_text_policy.cpp @@ -103,6 +103,11 @@ bool Text_Policy::negotiate_encrypt_then_mac() const return get_bool("negotiate_encrypt_then_mac", Policy::negotiate_encrypt_then_mac()); } +bool Text_Policy::support_cert_status_message() const + { + return get_bool("support_cert_status_message", Policy::support_cert_status_message()); + } + std::string Text_Policy::dh_group() const { return get_str("dh_group", Policy::dh_group()); diff --git a/src/tests/unit_tls.cpp b/src/tests/unit_tls.cpp index b22028a0e..026eeb62d 100644 --- a/src/tests/unit_tls.cpp +++ b/src/tests/unit_tls.cpp @@ -1308,6 +1308,9 @@ class TLS_Unit_Tests final : public Test test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD", { { "signature_methods", "RSA" } }); + test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD", + { { "support_cert_status_message", "false" } }); + #if defined(BOTAN_HAS_DSA) test_modern_versions(results, *client_ses, *server_ses, *creds, "DH", "AES-128/GCM", "AEAD", { { "signature_methods", "DSA" } }); -- cgit v1.2.3