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

          Line data    Source code
       1             : #include "source/common/quic/envoy_quic_proof_source.h"
       2             : 
       3             : #include <openssl/bio.h>
       4             : 
       5             : #include "envoy/ssl/tls_certificate_config.h"
       6             : 
       7             : #include "source/common/quic/envoy_quic_utils.h"
       8             : #include "source/common/quic/quic_io_handle_wrapper.h"
       9             : #include "source/common/stream_info/stream_info_impl.h"
      10             : 
      11             : #include "openssl/bytestring.h"
      12             : #include "quiche/quic/core/crypto/certificate_view.h"
      13             : 
      14             : namespace Envoy {
      15             : namespace Quic {
      16             : 
      17             : quiche::QuicheReferenceCountedPointer<quic::ProofSource::Chain>
      18             : EnvoyQuicProofSource::GetCertChain(const quic::QuicSocketAddress& server_address,
      19             :                                    const quic::QuicSocketAddress& client_address,
      20           0 :                                    const std::string& hostname, bool* cert_matched_sni) {
      21             :   // TODO(DavidSchinazi) parse the certificate to correctly fill in |cert_matched_sni|.
      22           0 :   *cert_matched_sni = false;
      23             : 
      24           0 :   CertConfigWithFilterChain res =
      25           0 :       getTlsCertConfigAndFilterChain(server_address, client_address, hostname);
      26           0 :   absl::optional<std::reference_wrapper<const Envoy::Ssl::TlsCertificateConfig>> cert_config_ref =
      27           0 :       res.cert_config_;
      28           0 :   if (!cert_config_ref.has_value()) {
      29           0 :     return nullptr;
      30           0 :   }
      31           0 :   auto& cert_config = cert_config_ref.value().get();
      32           0 :   const std::string& chain_str = cert_config.certificateChain();
      33           0 :   std::stringstream pem_stream(chain_str);
      34           0 :   std::vector<std::string> chain = quic::CertificateView::LoadPemFromStream(&pem_stream);
      35             : 
      36           0 :   quiche::QuicheReferenceCountedPointer<quic::ProofSource::Chain> cert_chain(
      37           0 :       new quic::ProofSource::Chain(chain));
      38           0 :   std::string error_details;
      39           0 :   bssl::UniquePtr<X509> cert = parseDERCertificate(cert_chain->certs[0], &error_details);
      40           0 :   if (cert == nullptr) {
      41           0 :     ENVOY_LOG(warn, absl::StrCat("Invalid leaf cert: ", error_details));
      42           0 :     return nullptr;
      43           0 :   }
      44             : 
      45           0 :   bssl::UniquePtr<EVP_PKEY> pub_key(X509_get_pubkey(cert.get()));
      46           0 :   int sign_alg = deduceSignatureAlgorithmFromPublicKey(pub_key.get(), &error_details);
      47           0 :   if (sign_alg == 0) {
      48           0 :     ENVOY_LOG(warn, absl::StrCat("Failed to deduce signature algorithm from public key: ",
      49           0 :                                  error_details));
      50           0 :     return nullptr;
      51           0 :   }
      52           0 :   return cert_chain;
      53           0 : }
      54             : 
      55             : void EnvoyQuicProofSource::signPayload(
      56             :     const quic::QuicSocketAddress& server_address, const quic::QuicSocketAddress& client_address,
      57             :     const std::string& hostname, uint16_t signature_algorithm, absl::string_view in,
      58           0 :     std::unique_ptr<quic::ProofSource::SignatureCallback> callback) {
      59           0 :   CertConfigWithFilterChain res =
      60           0 :       getTlsCertConfigAndFilterChain(server_address, client_address, hostname);
      61           0 :   absl::optional<std::reference_wrapper<const Envoy::Ssl::TlsCertificateConfig>> cert_config_ref =
      62           0 :       res.cert_config_;
      63           0 :   if (!cert_config_ref.has_value()) {
      64           0 :     ENVOY_LOG(warn, "No matching filter chain found for handshake.");
      65           0 :     callback->Run(false, "", nullptr);
      66           0 :     return;
      67           0 :   }
      68           0 :   auto& cert_config = cert_config_ref.value().get();
      69             :   // Load private key.
      70           0 :   const std::string& pkey = cert_config.privateKey();
      71           0 :   std::stringstream pem_str(pkey);
      72           0 :   std::unique_ptr<quic::CertificatePrivateKey> pem_key =
      73           0 :       quic::CertificatePrivateKey::LoadPemFromStream(&pem_str);
      74           0 :   if (pem_key == nullptr) {
      75           0 :     ENVOY_LOG(warn, "Failed to load private key.");
      76           0 :     callback->Run(false, "", nullptr);
      77           0 :     return;
      78           0 :   }
      79             :   // Verify the signature algorithm is as expected.
      80           0 :   std::string error_details;
      81           0 :   int sign_alg = deduceSignatureAlgorithmFromPublicKey(pem_key->private_key(), &error_details);
      82           0 :   if (sign_alg != signature_algorithm) {
      83           0 :     ENVOY_LOG(warn,
      84           0 :               fmt::format("The signature algorithm {} from the private key is not expected: {}",
      85           0 :                           sign_alg, error_details));
      86           0 :     callback->Run(false, "", nullptr);
      87           0 :     return;
      88           0 :   }
      89             : 
      90             :   // Sign.
      91           0 :   std::string sig = pem_key->Sign(in, signature_algorithm);
      92           0 :   bool success = !sig.empty();
      93           0 :   ASSERT(res.filter_chain_.has_value());
      94           0 :   callback->Run(success, sig,
      95           0 :                 std::make_unique<EnvoyQuicProofSourceDetails>(res.filter_chain_.value().get()));
      96           0 : }
      97             : 
      98             : EnvoyQuicProofSource::CertConfigWithFilterChain
      99             : EnvoyQuicProofSource::getTlsCertConfigAndFilterChain(const quic::QuicSocketAddress& server_address,
     100             :                                                      const quic::QuicSocketAddress& client_address,
     101           0 :                                                      const std::string& hostname) {
     102           0 :   ENVOY_LOG(trace, "Getting cert chain for {}", hostname);
     103             :   // TODO(danzh) modify QUICHE to make quic session or ALPN accessible to avoid hard-coded ALPN.
     104           0 :   Network::ConnectionSocketPtr connection_socket = createServerConnectionSocket(
     105           0 :       listen_socket_.ioHandle(), server_address, client_address, hostname, "h3");
     106           0 :   StreamInfo::StreamInfoImpl info(time_source_,
     107           0 :                                   connection_socket->connectionInfoProviderSharedPtr());
     108           0 :   const Network::FilterChain* filter_chain =
     109           0 :       filter_chain_manager_->findFilterChain(*connection_socket, info);
     110             : 
     111           0 :   if (filter_chain == nullptr) {
     112           0 :     listener_stats_.no_filter_chain_match_.inc();
     113           0 :     ENVOY_LOG(warn, "No matching filter chain found for handshake.");
     114           0 :     return {absl::nullopt, absl::nullopt};
     115           0 :   }
     116           0 :   ENVOY_LOG(trace, "Got a matching cert chain {}", filter_chain->name());
     117             : 
     118           0 :   auto& transport_socket_factory =
     119           0 :       dynamic_cast<const QuicServerTransportSocketFactory&>(filter_chain->transportSocketFactory());
     120             : 
     121           0 :   std::vector<std::reference_wrapper<const Envoy::Ssl::TlsCertificateConfig>> tls_cert_configs =
     122           0 :       transport_socket_factory.getTlsCertificates();
     123           0 :   if (tls_cert_configs.empty()) {
     124           0 :     ENVOY_LOG(warn, "No certificate is configured in transport socket config.");
     125           0 :     return {absl::nullopt, absl::nullopt};
     126           0 :   }
     127             :   // Only return the first TLS cert config.
     128             :   // TODO(danzh) Choose based on supported cipher suites in TLS1.3 CHLO and prefer EC
     129             :   // certs if supported.
     130           0 :   return {tls_cert_configs[0].get(), *filter_chain};
     131           0 : }
     132             : 
     133             : void EnvoyQuicProofSource::updateFilterChainManager(
     134           0 :     Network::FilterChainManager& filter_chain_manager) {
     135           0 :   filter_chain_manager_ = &filter_chain_manager;
     136           0 : }
     137             : 
     138             : } // namespace Quic
     139             : } // namespace Envoy

Generated by: LCOV version 1.15