diff options
-rw-r--r-- | doc/manual/credentials_manager.rst | 34 | ||||
-rw-r--r-- | doc/manual/tls.rst | 30 | ||||
-rw-r--r-- | src/cli/credentials.h | 18 | ||||
-rw-r--r-- | src/cli/tls_client.cpp | 26 | ||||
-rw-r--r-- | src/lib/tls/credentials_manager.cpp | 49 | ||||
-rw-r--r-- | src/lib/tls/credentials_manager.h | 19 | ||||
-rw-r--r-- | src/lib/tls/tls_callbacks.cpp | 53 | ||||
-rw-r--r-- | src/lib/tls/tls_callbacks.h | 45 | ||||
-rw-r--r-- | src/lib/tls/tls_channel.cpp | 12 | ||||
-rw-r--r-- | src/lib/tls/tls_client.cpp | 7 | ||||
-rw-r--r-- | src/lib/tls/tls_server.cpp | 8 | ||||
-rw-r--r-- | src/tests/unit_tls.cpp | 10 |
12 files changed, 173 insertions, 138 deletions
diff --git a/doc/manual/credentials_manager.rst b/doc/manual/credentials_manager.rst index 04e9e3f2e..006d47343 100644 --- a/doc/manual/credentials_manager.rst +++ b/doc/manual/credentials_manager.rst @@ -29,31 +29,6 @@ implementation. The default implementation returns an empty list. - .. cpp::function:: void verify_certificate_chain( \ - const std::string& type, \ - const std::string& hostname, \ - const std::vector<X509_Certificate>& cert_chain) - - Verifies the certificate chain in *cert_chain*, assuming the - leaf certificate is the first element. - - If *hostname* is set, additionally ``verify_certificate_chain`` - will check that the leaf certificate has a DNS entry matching - *hostname*. - - In the default implementation the *type* argument is passed, - along with *hostname*, to ``trusted_certificate_authorities`` to - find out what root(s) should be trusted for verifying this - certificate. - - This function indicates a validation failure by throwing an - exception. - - This function has a default implementation that probably - sufficies for most uses, however can be overrided for - implementing extra validation routines such as public key - pinning. - .. cpp:function:: std::vector<X509_Certificate> cert_chain( \ const std::vector<std::string>& cert_key_types, \ const std::string& type, \ @@ -78,6 +53,15 @@ implementation. the leaf cert of a chain returned previously by ``cert_chain`` or ``cert_chain_single_type``. +In versions before 1.11.34, there was an additional function on `Credentials_Manager` + + .. cpp::function:: void verify_certificate_chain( \ + const std::string& type, \ + const std::string& hostname, \ + const std::vector<X509_Certificate>& cert_chain) + +This function has been replaced by `TLS::Callbacks::tls_verify_cert_chain`. + SRP Authentication ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/manual/tls.rst b/doc/manual/tls.rst index 8508b0a70..2c8b7cf70 100644 --- a/doc/manual/tls.rst +++ b/doc/manual/tls.rst @@ -66,12 +66,12 @@ information about the connection. For DTLS, it is possible to receive records with the `rec_no` field out of order, or with gaps, cooresponding to reordered or lost datagrams. - .. cpp:function:: void tls_alert(Alert alert) + .. cpp:function:: void tls_alert(Alert alert) Mandatory. Called when an alert is received from the peer. Note that alerts received before the handshake is complete are not authenticated and could have been inserted by a MITM attacker. - + .. cpp:function:: bool tls_session_established(const TLS::Session& session) Mandatory. Called whenever a negotiation completes. This can happen more @@ -85,6 +85,32 @@ information about the connection. exception which will send a close message to the counterparty and reset the connection state. + .. cpp::function:: void tls_verify_cert_chain(const std::vector<X509_Certificate>& cert_chain, \ + const std::vector<Certificate_Store*>& trusted_roots, \ + Usage_Type usage, \ + const std::string& hostname) + + Optional - default implementation should work for many users. + It can be overrided for implementing extra validation routines + such as public key pinning. + + Verifies the certificate chain in *cert_chain*, assuming the + leaf certificate is the first element. + + If usage is `Usage_Type::TLS_SERVER_AUTH`, then *hostname* should + match the information in the server certificate. If usage is + `TLS_CLIENT_AUTH`, then *hostname* specifies the host the client + is authenticating against (from SNI); the callback can use this for + any special site specific auth logic. + + The `trusted_roots` parameter was returned by a call from the + associated `Credentials_Manager`. + + .. cpp::function:: std::chrono::milliseconds tls_verify_cert_chain_ocsp_timeout() const + + Called by default `tls_verify_cert_cert` to set timeout for OCSP requests. + Return 0 to disable OCSP. Current default is 0. + .. cpp:function:: std::string tls_server_choose_app_protocol(const std::vector<std::string>& client_protos) Optional. Called by the server when a client includes a list of protocols in the ALPN extension. diff --git a/src/cli/credentials.h b/src/cli/credentials.h index 95bbd5aa4..71acdc83d 100644 --- a/src/cli/credentials.h +++ b/src/cli/credentials.h @@ -92,24 +92,6 @@ class Basic_Credentials_Manager : public Botan::Credentials_Manager return v; } - void verify_certificate_chain( - const std::string& type, - const std::string& purported_hostname, - const std::vector<Botan::X509_Certificate>& cert_chain) override - { - try - { - Credentials_Manager::verify_certificate_chain(type, - purported_hostname, - cert_chain); - } - catch(std::exception& e) - { - std::cout << e.what() << std::endl; - //throw; - } - } - std::vector<Botan::X509_Certificate> cert_chain( const std::vector<std::string>& algos, const std::string& type, diff --git a/src/cli/tls_client.cpp b/src/cli/tls_client.cpp index 0d96f3348..fdbc21ec9 100644 --- a/src/cli/tls_client.cpp +++ b/src/cli/tls_client.cpp @@ -10,6 +10,7 @@ #if defined(BOTAN_HAS_TLS) && defined(BOTAN_TARGET_OS_HAS_SOCKETS) #include <botan/tls_client.h> +#include <botan/x509path.h> #include <botan/hex.h> #if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER) @@ -250,6 +251,31 @@ class TLS_Client final : public Command, public Botan::TLS::Callbacks return fd; } + void tls_verify_cert_chain( + const std::vector<Botan::X509_Certificate>& cert_chain, + const std::vector<Botan::Certificate_Store*>& trusted_roots, + Botan::Usage_Type usage, + const std::string& hostname) override + { + if(cert_chain.empty()) + throw std::invalid_argument("Certificate chain was empty"); + + Botan::Path_Validation_Restrictions restrictions(true, 80); + + auto ocsp_timeout = std::chrono::milliseconds(300); + + Botan::Path_Validation_Result result = + Botan::x509_path_validate(cert_chain, + restrictions, + trusted_roots, + hostname, + usage, + std::chrono::system_clock::now(), + ocsp_timeout); + + std::cout << "Certificate validation status: " << result.result_string() << "\n"; + } + bool tls_session_established(const Botan::TLS::Session& session) override { output() << "Handshake complete, " << session.version().to_string() diff --git a/src/lib/tls/credentials_manager.cpp b/src/lib/tls/credentials_manager.cpp index 650d922ce..a42fb5789 100644 --- a/src/lib/tls/credentials_manager.cpp +++ b/src/lib/tls/credentials_manager.cpp @@ -93,53 +93,4 @@ Credentials_Manager::trusted_certificate_authorities( return std::vector<Certificate_Store*>(); } -namespace { - -bool cert_in_some_store(const std::vector<Certificate_Store*>& trusted_CAs, - const X509_Certificate& trust_root) - { - for(auto CAs : trusted_CAs) - if(CAs->certificate_known(trust_root)) - return true; - return false; - } - -Usage_Type choose_leaf_usage(const std::string& ctx) - { - // These are reversed because ctx is denoting the current perspective - if(ctx == "tls-client") - return Usage_Type::TLS_SERVER_AUTH; - else if(ctx == "tls-server") - return Usage_Type::TLS_CLIENT_AUTH; - else - return Usage_Type::UNSPECIFIED; - } - -} - -void Credentials_Manager::verify_certificate_chain( - const std::string& type, - const std::string& purported_hostname, - const std::vector<X509_Certificate>& cert_chain) - { - if(cert_chain.empty()) - throw Invalid_Argument("Certificate chain was empty"); - - auto trusted_CAs = trusted_certificate_authorities(type, purported_hostname); - - Path_Validation_Restrictions restrictions; - - Path_Validation_Result result = x509_path_validate(cert_chain, - restrictions, - trusted_CAs, - purported_hostname, - choose_leaf_usage(type)); - - if(!result.successful_validation()) - throw Exception("Certificate validation failure: " + result.result_string()); - - if(!cert_in_some_store(trusted_CAs, result.trust_root())) - throw Exception("Certificate chain roots in unknown/untrusted CA"); - } - } diff --git a/src/lib/tls/credentials_manager.h b/src/lib/tls/credentials_manager.h index 96e840d13..0e2fe0dea 100644 --- a/src/lib/tls/credentials_manager.h +++ b/src/lib/tls/credentials_manager.h @@ -44,25 +44,6 @@ class BOTAN_DLL Credentials_Manager const std::string& context); /** - * Check the certificate chain is valid up to a trusted root, and - * optionally (if hostname != "") that the hostname given is - * consistent with the leaf certificate. - * - * This function should throw an exception derived from - * std::exception with an informative what() result if the - * certificate chain cannot be verified. - - * @param type specifies the type of operation occurring - * @param hostname specifies the purported hostname - * @param cert_chain specifies a certificate chain leading to a - * trusted root CA certificate. - */ - virtual void verify_certificate_chain( - const std::string& type, - const std::string& hostname, - const std::vector<X509_Certificate>& cert_chain); - - /** * Return a cert chain we can use, ordered from leaf to root, * or else an empty vector. * diff --git a/src/lib/tls/tls_callbacks.cpp b/src/lib/tls/tls_callbacks.cpp new file mode 100644 index 000000000..1bf1af6a3 --- /dev/null +++ b/src/lib/tls/tls_callbacks.cpp @@ -0,0 +1,53 @@ +/* +* TLS Callbacks +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/tls_callbacks.h> +#include <botan/x509path.h> +#include <botan/ocsp.h> +#include <botan/certstor.h> + +namespace Botan { + +TLS::Callbacks::~Callbacks() {} + +void TLS::Callbacks::tls_inspect_handshake_msg(const Handshake_Message&) + { + // default is no op + } + +std::string TLS::Callbacks::tls_server_choose_app_protocol(const std::vector<std::string>&) + { + return ""; + } + +void TLS::Callbacks::tls_verify_cert_chain( + const std::vector<X509_Certificate>& cert_chain, + const std::vector<Certificate_Store*>& trusted_roots, + Usage_Type usage, + const std::string& hostname) + { + if(cert_chain.empty()) + throw Invalid_Argument("Certificate chain was empty"); + + Path_Validation_Restrictions restrictions; + + auto ocsp_timeout = std::chrono::milliseconds(300); + + Path_Validation_Result result = + x509_path_validate(cert_chain, + restrictions, + trusted_roots, + (usage == Usage_Type::TLS_SERVER_AUTH ? hostname : ""), + usage, + std::chrono::system_clock::now(), + ocsp_timeout); + + if(!result.successful_validation()) + throw Exception("Certificate validation failure: " + result.result_string()); + } + +} diff --git a/src/lib/tls/tls_callbacks.h b/src/lib/tls/tls_callbacks.h index f81071a05..9de7710f4 100644 --- a/src/lib/tls/tls_callbacks.h +++ b/src/lib/tls/tls_callbacks.h @@ -11,8 +11,18 @@ #include <botan/tls_session.h> #include <botan/tls_alert.h> + namespace Botan { +class Certificate_Store; +class X509_Certificate; + +namespace OCSP { + +class Response; + +} + namespace TLS { class Handshake_Message; @@ -53,7 +63,7 @@ class BOTAN_DLL Callbacks virtual void tls_record_received(u64bit seq_no, const uint8_t data[], size_t size) = 0; /** - * Mandary callback: alert received + * Mandatory callback: alert received * Called when an alert is received from the peer * If fatal, the connection is closing. If not fatal, the connection may * still be closing (depending on the error and the peer). @@ -81,6 +91,39 @@ class BOTAN_DLL Callbacks virtual void tls_session_activated() {} /** + * Optional callback with default impl: verify cert chain + * + * Default implementation performs a standard PKIX validation + * and initiates network OCSP request for end-entity cert. + * Override to provide different behavior. + * + * Check the certificate chain is valid up to a trusted root, and + * optionally (if hostname != "") that the hostname given is + * consistent with the leaf certificate. + * + * This function should throw an exception derived from + * std::exception with an informative what() result if the + * certificate chain cannot be verified. + * + * @param cert_chain specifies a certificate chain leading to a + * trusted root CA certificate. + + * @param usage what this cert chain is being used for + * Usage_Type::TLS_SERVER_AUTH for server chains, + * Usage_Type::TLS_CLIENT_AUTH for client chains, + * Usage_Type::UNSPECIFIED for other uses + * @param hostname when authenticating a server, this is the hostname + * the client requested (eg via SNI). When authenticating a client, + * this is the server name the client is authenticating *to*. + * Empty in other cases or if no hostname was used. + */ + virtual void tls_verify_cert_chain( + const std::vector<X509_Certificate>& cert_chain, + const std::vector<Certificate_Store*>& trusted_roots, + Usage_Type usage, + const std::string& hostname); + + /** * Optional callback: inspect handshake message * Throw an exception to abort the handshake. * Default simply ignores the message. diff --git a/src/lib/tls/tls_channel.cpp b/src/lib/tls/tls_channel.cpp index 95b151ad2..c8fe407e2 100644 --- a/src/lib/tls/tls_channel.cpp +++ b/src/lib/tls/tls_channel.cpp @@ -19,18 +19,6 @@ namespace Botan { namespace TLS { -Callbacks::~Callbacks() {} - -void Callbacks::tls_inspect_handshake_msg(const Handshake_Message&) - { - // default is no op - } - -std::string Callbacks::tls_server_choose_app_protocol(const std::vector<std::string>&) - { - return ""; - } - size_t TLS::Channel::IO_BUF_DEFAULT_SIZE = 10*1024; Channel::Channel(Callbacks& callbacks, diff --git a/src/lib/tls/tls_client.cpp b/src/lib/tls/tls_client.cpp index 183886c66..99b4ac731 100644 --- a/src/lib/tls/tls_client.cpp +++ b/src/lib/tls/tls_client.cpp @@ -391,7 +391,12 @@ void Client::process_handshake_msg(const Handshake_State* active_state, try { - m_creds.verify_certificate_chain("tls-client", m_info.hostname(), server_certs); + 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()); } catch(std::exception& e) { diff --git a/src/lib/tls/tls_server.cpp b/src/lib/tls/tls_server.cpp index 5e3b222f1..abe22df3c 100644 --- a/src/lib/tls/tls_server.cpp +++ b/src/lib/tls/tls_server.cpp @@ -523,7 +523,13 @@ void Server::process_certificate_verify_msg(Server_Handshake_State& pending_stat try { - m_creds.verify_certificate_chain ( "tls-server", "", client_certs ); + const std::string sni_hostname = pending_state.client_hello()->sni_hostname(); + auto trusted_CAs = m_creds.trusted_certificate_authorities("tls-server", sni_hostname); + + callbacks().tls_verify_cert_chain(client_certs, + trusted_CAs, + Usage_Type::TLS_CLIENT_AUTH, + sni_hostname); } catch ( std::exception& e ) { diff --git a/src/tests/unit_tls.cpp b/src/tests/unit_tls.cpp index b69f97cca..df58f7311 100644 --- a/src/tests/unit_tls.cpp +++ b/src/tests/unit_tls.cpp @@ -97,16 +97,6 @@ class Credentials_Manager_Test : public Botan::Credentials_Manager return chain; } - void verify_certificate_chain( - const std::string& type, - const std::string& purported_hostname, - const std::vector<Botan::X509_Certificate>& cert_chain) override - { - Credentials_Manager::verify_certificate_chain(type, - purported_hostname, - cert_chain); - } - Botan::Private_Key* private_key_for(const Botan::X509_Certificate& crt, const std::string&, const std::string&) override |