LCOV - code coverage report
Current view: top level - source/common/quic - envoy_quic_proof_verifier.cc (source / functions) Hit Total Coverage
Test: coverage.dat Lines: 0 77 0.0 %
Date: 2024-01-05 06:35:25 Functions: 0 5 0.0 %

          Line data    Source code
       1             : #include "source/common/quic/envoy_quic_proof_verifier.h"
       2             : 
       3             : #include <openssl/ssl.h>
       4             : 
       5             : #include <cstdint>
       6             : #include <memory>
       7             : 
       8             : #include "source/common/quic/envoy_quic_utils.h"
       9             : #include "source/common/runtime/runtime_features.h"
      10             : #include "source/extensions/transport_sockets/tls/utility.h"
      11             : 
      12             : #include "quiche/quic/core/crypto/certificate_view.h"
      13             : 
      14             : namespace Envoy {
      15             : namespace Quic {
      16             : 
      17             : using ValidationResults = Envoy::Extensions::TransportSockets::Tls::ValidationResults;
      18             : 
      19             : namespace {
      20             : 
      21             : // Returns true if hostname matches one of the Subject Alt Names in cert_view. Returns false and
      22             : // sets error_details otherwise
      23             : bool verifyLeafCertMatchesHostname(quic::CertificateView& cert_view, const std::string& hostname,
      24           0 :                                    std::string* error_details) {
      25           0 :   for (const absl::string_view& config_san : cert_view.subject_alt_name_domains()) {
      26           0 :     if (Extensions::TransportSockets::Tls::Utility::dnsNameMatch(hostname, config_san)) {
      27           0 :       return true;
      28           0 :     }
      29           0 :   }
      30           0 :   *error_details = absl::StrCat("Leaf certificate doesn't match hostname: ", hostname);
      31           0 :   return false;
      32           0 : }
      33             : 
      34             : class QuicValidateResultCallback : public Ssl::ValidateResultCallback {
      35             : public:
      36             :   QuicValidateResultCallback(Event::Dispatcher& dispatcher,
      37             :                              std::unique_ptr<quic::ProofVerifierCallback>&& quic_callback,
      38             :                              const std::string& hostname, const std::string& leaf_cert)
      39             :       : dispatcher_(dispatcher), quic_callback_(std::move(quic_callback)), hostname_(hostname),
      40           0 :         leaf_cert_(leaf_cert) {}
      41             : 
      42           0 :   Event::Dispatcher& dispatcher() override { return dispatcher_; }
      43             : 
      44             :   void onCertValidationResult(bool succeeded, Ssl::ClientValidationStatus /*detailed_status*/,
      45           0 :                               const std::string& error_details, uint8_t /*tls_alert*/) override {
      46           0 :     std::string error;
      47           0 :     if (!succeeded) {
      48           0 :       error = error_details;
      49           0 :     } else {
      50           0 :       std::unique_ptr<quic::CertificateView> cert_view =
      51           0 :           quic::CertificateView::ParseSingleCertificate(leaf_cert_);
      52           0 :       succeeded = verifyLeafCertMatchesHostname(*cert_view, hostname_, &error);
      53           0 :     }
      54           0 :     std::unique_ptr<quic::ProofVerifyDetails> details =
      55           0 :         std::make_unique<CertVerifyResult>(succeeded);
      56           0 :     quic_callback_->Run(succeeded, error, &details);
      57           0 :   }
      58             : 
      59             : private:
      60             :   Event::Dispatcher& dispatcher_;
      61             :   std::unique_ptr<quic::ProofVerifierCallback> quic_callback_;
      62             :   const std::string hostname_;
      63             :   // Leaf cert needs to be retained in case of asynchronous validation.
      64             :   std::string leaf_cert_;
      65             : };
      66             : 
      67             : } // namespace
      68             : 
      69             : quic::QuicAsyncStatus EnvoyQuicProofVerifier::VerifyCertChain(
      70             :     const std::string& hostname, const uint16_t /*port*/, const std::vector<std::string>& certs,
      71             :     const std::string& /*ocsp_response*/, const std::string& /*cert_sct*/,
      72             :     const quic::ProofVerifyContext* context, std::string* error_details,
      73             :     std::unique_ptr<quic::ProofVerifyDetails>* details, uint8_t* out_alert,
      74           0 :     std::unique_ptr<quic::ProofVerifierCallback> callback) {
      75           0 :   ASSERT(details != nullptr);
      76           0 :   ASSERT(!certs.empty());
      77           0 :   auto* verify_context = dynamic_cast<const EnvoyQuicProofVerifyContext*>(context);
      78           0 :   if (verify_context == nullptr) {
      79           0 :     IS_ENVOY_BUG("QUIC proof verify context was not setup correctly.");
      80           0 :     return quic::QUIC_FAILURE;
      81           0 :   }
      82           0 :   ENVOY_BUG(!verify_context->isServer(), "Client certificates are not supported in QUIC yet.");
      83             : 
      84           0 :   bssl::UniquePtr<STACK_OF(X509)> cert_chain(sk_X509_new_null());
      85           0 :   for (const auto& cert_str : certs) {
      86           0 :     bssl::UniquePtr<X509> cert = parseDERCertificate(cert_str, error_details);
      87           0 :     if (!cert || !bssl::PushToStack(cert_chain.get(), std::move(cert))) {
      88           0 :       return quic::QUIC_FAILURE;
      89           0 :     }
      90           0 :   }
      91           0 :   std::unique_ptr<quic::CertificateView> cert_view =
      92           0 :       quic::CertificateView::ParseSingleCertificate(certs[0]);
      93           0 :   ASSERT(cert_view != nullptr);
      94           0 :   int sign_alg = deduceSignatureAlgorithmFromPublicKey(cert_view->public_key(), error_details);
      95           0 :   if (sign_alg == 0) {
      96           0 :     return quic::QUIC_FAILURE;
      97           0 :   }
      98             : 
      99           0 :   auto envoy_callback = std::make_unique<QuicValidateResultCallback>(
     100           0 :       verify_context->dispatcher(), std::move(callback), hostname, certs[0]);
     101           0 :   ASSERT(dynamic_cast<Extensions::TransportSockets::Tls::ClientContextImpl*>(context_.get()) !=
     102           0 :          nullptr);
     103             :   // We down cast rather than add customVerifyCertChainForQuic to Envoy::Ssl::Context because
     104             :   // verifyCertChain uses a bunch of SSL-specific structs which we want to keep out of the interface
     105             :   // definition.
     106           0 :   ValidationResults result =
     107           0 :       static_cast<Extensions::TransportSockets::Tls::ClientContextImpl*>(context_.get())
     108           0 :           ->customVerifyCertChainForQuic(*cert_chain, std::move(envoy_callback),
     109           0 :                                          verify_context->isServer(),
     110           0 :                                          verify_context->transportSocketOptions(),
     111           0 :                                          verify_context->extraValidationContext(), hostname);
     112           0 :   if (result.status == ValidationResults::ValidationStatus::Pending) {
     113           0 :     return quic::QUIC_PENDING;
     114           0 :   }
     115           0 :   if (result.status == ValidationResults::ValidationStatus::Successful) {
     116           0 :     if (verifyLeafCertMatchesHostname(*cert_view, hostname, error_details)) {
     117           0 :       *details = std::make_unique<CertVerifyResult>(true);
     118           0 :       return quic::QUIC_SUCCESS;
     119           0 :     }
     120           0 :   } else {
     121           0 :     ASSERT(result.status == ValidationResults::ValidationStatus::Failed);
     122           0 :     if (result.error_details.has_value() && error_details) {
     123           0 :       *error_details = std::move(result.error_details.value());
     124           0 :     }
     125           0 :     if (result.tls_alert.has_value() && out_alert) {
     126           0 :       *out_alert = result.tls_alert.value();
     127           0 :     }
     128           0 :   }
     129             : 
     130           0 :   *details = std::make_unique<CertVerifyResult>(false);
     131           0 :   return quic::QUIC_FAILURE;
     132           0 : }
     133             : 
     134             : } // namespace Quic
     135             : } // namespace Envoy

Generated by: LCOV version 1.15