LCOV - code coverage report
Current view: top level - asio/ssl - client_verify.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 100.0 % 52 52
Test Date: 2026-11-10 10:38:07 Functions: 100.0 % 10 10

            Line data    Source code
       1              : #include "client_verify.hpp"
       2              : #include "../../util/logger.hpp"
       3              : #include <boost/asio/ssl/context.hpp>
       4              : #include <openssl/evp.h>
       5              : #include <openssl/x509.h>
       6              : #include <string>
       7              : 
       8              : namespace thinger::asio {
       9              : 
      10              : namespace {
      11              : 
      12              :     // Deferred validation: any chain is accepted here, the application validates it. OpenSSL
      13              :     // still checks the signature of the client (CertificateVerify): it holds the key of the leaf
      14          402 :     int accept_chain(int /*preverified*/, X509_STORE_CTX* /*context*/) {
      15          402 :         return 1;
      16              :     }
      17              : 
      18         5466 :     int policy_index() {
      19         5466 :         static const int index = SSL_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
      20         5466 :         return index;
      21              :     }
      22              : 
      23              :     // The trusted CAs of a PEM, read as the CAs of a context (Boost.Asio's reader): none if
      24              :     // there is none, or one cannot be read
      25           36 :     X509_STORE* load_store(const std::string& pem) {
      26           36 :         boost::asio::ssl::context context(boost::asio::ssl::context::tls_server);
      27              :         try {
      28           36 :             context.add_certificate_authority(boost::asio::buffer(pem));
      29            6 :         } catch (const boost::system::system_error& e) {
      30            6 :             LOG_ERROR("cannot read the trusted CAs of the client certificates: {}", e.code().message());
      31            6 :             return nullptr;
      32            6 :         }
      33           30 :         X509_STORE* store = SSL_CTX_get_cert_store(context.native_handle());
      34           30 :         X509_STORE_up_ref(store);
      35           30 :         return store;
      36           36 :     }
      37              : 
      38              : }
      39              : 
      40         3861 : client_verify_policy::client_verify_policy(client_verify_options options) : options_(std::move(options)) {
      41              :     // What identifies the policy, as the context of its sessions (SHA-256: 32 bytes, the most
      42              :     // OpenSSL takes)
      43         7722 :     std::string identity = std::to_string(static_cast<int>(options_.mode)) + ":" + std::to_string(options_.max_depth) +
      44        11583 :                            ":" + std::to_string(options_.max_cert_list) + ":" + options_.trusted_cas;
      45         3861 :     unsigned int size = 0;
      46         7722 :     EVP_Digest(identity.data(), identity.size(), session_id_context_.data(), &size, EVP_sha256(), nullptr);
      47         3861 : }
      48              : 
      49         3861 : client_verify_policy::~client_verify_policy() {
      50         3861 :     X509_STORE_free(store_);
      51         3861 : }
      52              : 
      53         3831 : std::shared_ptr<const client_verify_policy> client_verify_policy::create(const client_verify_options& options) {
      54         3831 :     std::shared_ptr<client_verify_policy> policy(new client_verify_policy(options));
      55         3831 :     if (options.mode != client_verify::none && !options.trusted_cas.empty()) {
      56           36 :         policy->store_ = load_store(options.trusted_cas);
      57           36 :         if (!policy->store_) return nullptr;
      58              :     }
      59         3825 :     return policy;
      60         3831 : }
      61              : 
      62           99 : const client_verify_policy& client_verify_policy::deferred() {
      63           99 :     static const client_verify_policy policy{client_verify_options{}};
      64           99 :     return policy;
      65              : }
      66              : 
      67         8292 : void client_verify_policy::apply(SSL* ssl) const {
      68         8292 :     if (options_.mode == client_verify::none) return;
      69          237 :     SSL_set_ex_data(ssl, policy_index(), const_cast<client_verify_policy*>(this));
      70          474 :     SSL_set_session_id_context(ssl, session_id_context_.data(), session_id_context_.size());
      71          237 :     set_mode(ssl, options_.mode);
      72              : }
      73              : 
      74          573 : void client_verify_policy::set_mode(SSL* ssl, client_verify mode) const {
      75          573 :     if (mode == client_verify::none) {
      76           30 :         SSL_set_verify(ssl, SSL_VERIFY_NONE, nullptr);
      77           30 :         return;
      78              :     }
      79          543 :     int flags = SSL_VERIFY_PEER;
      80          543 :     if (mode == client_verify::required) flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
      81          543 :     SSL_set_verify(ssl, flags, store_ ? nullptr : accept_chain);
      82          543 :     SSL_set_verify_depth(ssl, options_.max_depth);
      83          543 :     SSL_set_max_cert_list(ssl, static_cast<long>(options_.max_cert_list));
      84          543 :     if (store_) SSL_set1_verify_cert_store(ssl, store_);
      85              : }
      86              : 
      87         5229 : const client_verify_policy* client_verify_policy::of(const SSL* ssl) {
      88         5229 :     return static_cast<const client_verify_policy*>(SSL_get_ex_data(ssl, policy_index()));
      89              : }
      90              : 
      91              : } // namespace thinger::asio
        

Generated by: LCOV version 2.0-1