From cb79fc1b3d492af60404b5be1c0cb1c8c8065801 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?louiz=E2=80=99?= Date: Sun, 4 Dec 2016 22:17:37 +0100 Subject: Update the verify_certificate_chain code to work with botan >= 1.11.34 as well ref #3245 --- louloulibs/network/credentials_manager.cpp | 35 +++++++++++++++++++++++------- louloulibs/network/credentials_manager.hpp | 15 +++++++++++++ louloulibs/network/tcp_socket_handler.cpp | 25 +++++++++++++++++++++ louloulibs/network/tcp_socket_handler.hpp | 9 ++++++++ 4 files changed, 76 insertions(+), 8 deletions(-) diff --git a/louloulibs/network/credentials_manager.cpp b/louloulibs/network/credentials_manager.cpp index ed04d24..289307b 100644 --- a/louloulibs/network/credentials_manager.cpp +++ b/louloulibs/network/credentials_manager.cpp @@ -37,6 +37,28 @@ void BasicCredentialsManager::set_trusted_fingerprint(const std::string& fingerp this->trusted_fingerprint = fingerprint; } +const std::string& BasicCredentialsManager::get_trusted_fingerprint() const +{ + return this->trusted_fingerprint; +} + +void check_tls_certificate(const std::vector& certs, + const std::string& hostname, const std::string& trusted_fingerprint, + std::exception_ptr exc) +{ + + if (!trusted_fingerprint.empty() && !certs.empty() && + trusted_fingerprint == certs[0].fingerprint() && + certs[0].matches_dns_name(hostname)) + // We trust the certificate, based on the trusted fingerprint and + // the fact that the hostname matches + return; + + if (exc) + std::rethrow_exception(exc); +} + +#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,34) void BasicCredentialsManager::verify_certificate_chain(const std::string& type, const std::string& purported_hostname, const std::vector& certs) @@ -50,17 +72,14 @@ void BasicCredentialsManager::verify_certificate_chain(const std::string& type, catch (const std::exception& tls_exception) { log_warning("TLS certificate check failed: ", tls_exception.what()); - if (!this->trusted_fingerprint.empty() && !certs.empty() && - this->trusted_fingerprint == certs[0].fingerprint() && - certs[0].matches_dns_name(purported_hostname)) - // We trust the certificate, based on the trusted fingerprint and - // the fact that the hostname matches - return; - + std::exception_ptr exception_ptr{}; if (this->socket_handler->abort_on_invalid_cert()) - throw; + exception_ptr = std::current_exception(); + + check_tls_certificate(certs, purported_hostname, this->trusted_fingerprint, exception_ptr); } } +#endif bool BasicCredentialsManager::try_to_open_one_ca_bundle(const std::vector& paths) { diff --git a/louloulibs/network/credentials_manager.hpp b/louloulibs/network/credentials_manager.hpp index 7557372..29ee024 100644 --- a/louloulibs/network/credentials_manager.hpp +++ b/louloulibs/network/credentials_manager.hpp @@ -9,6 +9,18 @@ class TCPSocketHandler; +/** + * If the given cert isn’t valid, based on the given hostname + * and fingerprint, then throws the exception if it’s non-empty. + * + * Must be called after the standard (from Botan) way of + * checking the certificate, if we want to also accept certificates based + * on a trusted fingerprint. + */ +void check_tls_certificate(const std::vector& certs, + const std::string& hostname, const std::string& trusted_fingerprint, + std::exception_ptr exc); + class BasicCredentialsManager: public Botan::Credentials_Manager { public: @@ -19,12 +31,15 @@ public: BasicCredentialsManager& operator=(const BasicCredentialsManager&) = delete; BasicCredentialsManager& operator=(BasicCredentialsManager&&) = delete; +#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,34) void verify_certificate_chain(const std::string& type, const std::string& purported_hostname, const std::vector&) override final; +#endif std::vector trusted_certificate_authorities(const std::string& type, const std::string& context) override final; void set_trusted_fingerprint(const std::string& fingerprint); + const std::string& get_trusted_fingerprint() const; private: const TCPSocketHandler* const socket_handler; diff --git a/louloulibs/network/tcp_socket_handler.cpp b/louloulibs/network/tcp_socket_handler.cpp index d509a63..d9ec226 100644 --- a/louloulibs/network/tcp_socket_handler.cpp +++ b/louloulibs/network/tcp_socket_handler.cpp @@ -509,6 +509,31 @@ bool TCPSocketHandler::tls_session_established(const Botan::TLS::Session& sessio return true; } +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,34) +void TCPSocketHandler::tls_verify_cert_chain(const std::vector& cert_chain, + const std::vector>& ocsp_responses, + const std::vector& trusted_roots, + Botan::Usage_Type usage, const std::string& hostname, + const Botan::TLS::Policy& policy) +{ + log_debug("Checking remote certificate for hostname ", hostname); + try + { + Botan::TLS::Callbacks::tls_verify_cert_chain(cert_chain, ocsp_responses, trusted_roots, usage, hostname, policy); + log_debug("Certificate is valid"); + } + catch (const std::exception& tls_exception) + { + log_warning("TLS certificate check failed: ", tls_exception.what()); + std::exception_ptr exception_ptr{}; + if (this->abort_on_invalid_cert()) + exception_ptr = std::current_exception(); + + check_tls_certificate(cert_chain, hostname, this->credential_manager.get_trusted_fingerprint(), exception_ptr); + } +} +#endif + void TCPSocketHandler::on_tls_activated() { this->send_data({}); diff --git a/louloulibs/network/tcp_socket_handler.hpp b/louloulibs/network/tcp_socket_handler.hpp index 40532f0..8baa1d1 100644 --- a/louloulibs/network/tcp_socket_handler.hpp +++ b/louloulibs/network/tcp_socket_handler.hpp @@ -196,6 +196,15 @@ private: * anything here appart from logging the TLS session information. */ bool tls_session_established(const Botan::TLS::Session& session) BOTAN_TLS_CALLBACKS_OVERRIDE; + +#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,11,34) + void tls_verify_cert_chain(const std::vector& cert_chain, + const std::vector>& ocsp_responses, + const std::vector& trusted_roots, + Botan::Usage_Type usage, + const std::string& hostname, + const Botan::TLS::Policy& policy) BOTAN_TLS_CALLBACKS_OVERRIDE; +#endif /** * Called whenever the tls session goes from inactive to active. This * means that the handshake has just been successfully done, and we can -- cgit v1.2.3