No public description

PiperOrigin-RevId: 606821319
diff --git a/quiche/quic/core/crypto/proof_source.h b/quiche/quic/core/crypto/proof_source.h
index b963034..b2a9738 100644
--- a/quiche/quic/core/crypto/proof_source.h
+++ b/quiche/quic/core/crypto/proof_source.h
@@ -5,17 +5,26 @@
 #ifndef QUICHE_QUIC_CORE_CRYPTO_PROOF_SOURCE_H_
 #define QUICHE_QUIC_CORE_CRYPTO_PROOF_SOURCE_H_
 
+#include <cstddef>
+#include <cstdint>
 #include <memory>
+#include <optional>
 #include <string>
 #include <vector>
 
+#include "absl/status/status.h"
 #include "absl/strings/string_view.h"
+#include "absl/types/variant.h"
+#include "openssl/base.h"
+#include "openssl/pool.h"
 #include "openssl/ssl.h"
 #include "quiche/quic/core/crypto/certificate_view.h"
 #include "quiche/quic/core/crypto/quic_crypto_proof.h"
+#include "quiche/quic/core/quic_connection_id.h"
+#include "quiche/quic/core/quic_types.h"
 #include "quiche/quic/core/quic_versions.h"
-#include "quiche/quic/platform/api/quic_export.h"
 #include "quiche/quic/platform/api/quic_socket_address.h"
+#include "quiche/common/platform/api/quiche_export.h"
 #include "quiche/common/platform/api/quiche_reference_counted.h"
 
 namespace quic {
@@ -245,27 +254,44 @@
  public:
   virtual ~ProofSourceHandleCallback() = default;
 
+  // Configuration to use for configuring the SSL object when handshaking
+  // locally.
+  struct LocalSSLConfig {
+    const ProofSource::Chain* chain;
+    QuicDelayedSSLConfig delayed_ssl_config;
+  };
+
+  // Functor to call to configure the SSL object.  This functor must not be
+  // called more than once.
+  using ConfigureSSLFunc =
+      std::function<absl::Status(SSL& ssl, const SSL_PRIVATE_KEY_METHOD& key)>;
+
+  // Configuration to use for configuring the SSL object when using a
+  // handshake-hints server.
+  struct HintsSSLConfig {
+    ConfigureSSLFunc configure_ssl;
+    QuicDelayedSSLConfig delayed_ssl_config;
+  };
+
+  using SSLConfig = absl::variant<LocalSSLConfig, HintsSSLConfig>;
+
   // Called when a ProofSourceHandle::SelectCertificate operation completes.
   // |ok| indicates whether the operation was successful.
   // |is_sync| indicates whether the operation completed synchronously, i.e.
   //      whether it is completed before ProofSourceHandle::SelectCertificate
   //      returned.
-  // |chain| the certificate chain in leaf-first order.
-  // |handshake_hints| (optional) handshake hints that can be used by
-  //      SSL_set_handshake_hints.
+  // |ssl_config| configuration used to configure the SSL object.
   // |ticket_encryption_key| (optional) encryption key to be used for minting
   //      TLS resumption tickets.
   // |cert_matched_sni| is true if the certificate matched the SNI hostname,
   //      false if a non-matching default cert was used.
-  // |delayed_ssl_config| contains SSL configs to be applied on the SSL object.
   //
   // When called asynchronously(is_sync=false), this method will be responsible
   // to continue the handshake from where it left off.
-  virtual void OnSelectCertificateDone(
-      bool ok, bool is_sync, const ProofSource::Chain* chain,
-      absl::string_view handshake_hints,
-      absl::string_view ticket_encryption_key, bool cert_matched_sni,
-      QuicDelayedSSLConfig delayed_ssl_config) = 0;
+  virtual void OnSelectCertificateDone(bool ok, bool is_sync,
+                                       SSLConfig ssl_config,
+                                       absl::string_view ticket_encryption_key,
+                                       bool cert_matched_sni) = 0;
 
   // Called when a ProofSourceHandle::ComputeSignature operation completes.
   virtual void OnComputeSignatureDone(
diff --git a/quiche/quic/core/crypto/tls_server_connection.cc b/quiche/quic/core/crypto/tls_server_connection.cc
index 51311bc..9bf6dca 100644
--- a/quiche/quic/core/crypto/tls_server_connection.cc
+++ b/quiche/quic/core/crypto/tls_server_connection.cc
@@ -4,12 +4,20 @@
 
 #include "quiche/quic/core/crypto/tls_server_connection.h"
 
+#include <cstddef>
+#include <cstdint>
+#include <utility>
+#include <vector>
+
+#include "absl/status/status.h"
 #include "absl/strings/string_view.h"
+#include "openssl/base.h"
 #include "openssl/ssl.h"
 #include "quiche/quic/core/crypto/proof_source.h"
+#include "quiche/quic/core/crypto/tls_connection.h"
 #include "quiche/quic/core/quic_types.h"
 #include "quiche/quic/platform/api/quic_flag_utils.h"
-#include "quiche/quic/platform/api/quic_flags.h"
+#include "quiche/common/platform/api/quiche_logging.h"
 
 namespace quic {
 
@@ -59,6 +67,12 @@
   return ssl_ctx;
 }
 
+absl::Status TlsServerConnection::ConfigureSSL(
+    ProofSourceHandleCallback::ConfigureSSLFunc configure_ssl) {
+  return std::move(configure_ssl)(*ssl(),  // never nullptr
+                                  TlsServerConnection::kPrivateKeyMethod);
+}
+
 void TlsServerConnection::SetCertChain(
     const std::vector<CRYPTO_BUFFER*>& cert_chain) {
   SSL_set_chain_and_key(ssl(), cert_chain.data(), cert_chain.size(), nullptr,
diff --git a/quiche/quic/core/crypto/tls_server_connection.h b/quiche/quic/core/crypto/tls_server_connection.h
index bdb58be..9301f2c 100644
--- a/quiche/quic/core/crypto/tls_server_connection.h
+++ b/quiche/quic/core/crypto/tls_server_connection.h
@@ -5,9 +5,18 @@
 #ifndef QUICHE_QUIC_CORE_CRYPTO_TLS_SERVER_CONNECTION_H_
 #define QUICHE_QUIC_CORE_CRYPTO_TLS_SERVER_CONNECTION_H_
 
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
+#include "absl/status/status.h"
 #include "absl/strings/string_view.h"
+#include "openssl/base.h"
+#include "openssl/ssl.h"
 #include "quiche/quic/core/crypto/proof_source.h"
 #include "quiche/quic/core/crypto/tls_connection.h"
+#include "quiche/quic/core/quic_types.h"
+#include "quiche/common/platform/api/quiche_export.h"
 
 namespace quic {
 
@@ -120,6 +129,10 @@
   // Creates and configures an SSL_CTX that is appropriate for servers to use.
   static bssl::UniquePtr<SSL_CTX> CreateSslCtx(ProofSource* proof_source);
 
+  // Invoke |configure_ssl| to configure the SSL object.
+  absl::Status ConfigureSSL(
+      ProofSourceHandleCallback::ConfigureSSLFunc configure_ssl);
+
   void SetCertChain(const std::vector<CRYPTO_BUFFER*>& cert_chain);
 
   // Set the client cert mode to be used on this connection. This should be
diff --git a/quiche/quic/core/tls_server_handshaker.cc b/quiche/quic/core/tls_server_handshaker.cc
index d819703..bc378fc 100644
--- a/quiche/quic/core/tls_server_handshaker.cc
+++ b/quiche/quic/core/tls_server_handshaker.cc
@@ -4,25 +4,56 @@
 
 #include "quiche/quic/core/tls_server_handshaker.h"
 
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
 #include <memory>
+#include <optional>
 #include <string>
+#include <utility>
+#include <variant>
+#include <vector>
 
-#include "absl/base/macros.h"
+#include "absl/status/status.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/string_view.h"
-#include "openssl/pool.h"
+#include "absl/types/span.h"
+#include "absl/types/variant.h"
+#include "openssl/base.h"
+#include "openssl/bytestring.h"
 #include "openssl/ssl.h"
+#include "openssl/tls1.h"
+#include "quiche/quic/core/crypto/crypto_handshake.h"
+#include "quiche/quic/core/crypto/crypto_message_parser.h"
+#include "quiche/quic/core/crypto/crypto_utils.h"
+#include "quiche/quic/core/crypto/proof_source.h"
+#include "quiche/quic/core/crypto/proof_verifier.h"
 #include "quiche/quic/core/crypto/quic_crypto_server_config.h"
+#include "quiche/quic/core/crypto/quic_decrypter.h"
+#include "quiche/quic/core/crypto/quic_encrypter.h"
 #include "quiche/quic/core/crypto/transport_parameters.h"
 #include "quiche/quic/core/http/http_encoder.h"
 #include "quiche/quic/core/http/http_frames.h"
+#include "quiche/quic/core/quic_config.h"
+#include "quiche/quic/core/quic_connection.h"
+#include "quiche/quic/core/quic_connection_context.h"
+#include "quiche/quic/core/quic_connection_id.h"
+#include "quiche/quic/core/quic_connection_stats.h"
+#include "quiche/quic/core/quic_crypto_server_stream_base.h"
+#include "quiche/quic/core/quic_error_codes.h"
+#include "quiche/quic/core/quic_session.h"
 #include "quiche/quic/core/quic_time.h"
+#include "quiche/quic/core/quic_time_accumulator.h"
 #include "quiche/quic/core/quic_types.h"
+#include "quiche/quic/core/quic_versions.h"
+#include "quiche/quic/core/tls_handshaker.h"
+#include "quiche/quic/platform/api/quic_bug_tracker.h"
 #include "quiche/quic/platform/api/quic_flag_utils.h"
 #include "quiche/quic/platform/api/quic_flags.h"
 #include "quiche/quic/platform/api/quic_hostname_utils.h"
 #include "quiche/quic/platform/api/quic_logging.h"
 #include "quiche/quic/platform/api/quic_server_stats.h"
+#include "quiche/quic/platform/api/quic_socket_address.h"
 
 #define RECORD_LATENCY_IN_US(stat_name, latency, comment)                   \
   do {                                                                      \
@@ -81,10 +112,10 @@
                                   &cert_matched_sni);
 
   handshaker_->OnSelectCertificateDone(
-      /*ok=*/true, /*is_sync=*/true, chain.get(),
-      /*handshake_hints=*/absl::string_view(),
-      /*ticket_encryption_key=*/absl::string_view(), cert_matched_sni,
-      QuicDelayedSSLConfig());
+      /*ok=*/true, /*is_sync=*/true,
+      ProofSourceHandleCallback::LocalSSLConfig{chain.get(),
+                                                QuicDelayedSSLConfig()},
+      /*ticket_encryption_key=*/absl::string_view(), cert_matched_sni);
   if (!handshaker_->select_cert_status().has_value()) {
     QUIC_BUG(quic_bug_12423_1)
         << "select_cert_status() has no value after a synchronous select cert";
@@ -1007,13 +1038,10 @@
 }
 
 void TlsServerHandshaker::OnSelectCertificateDone(
-    bool ok, bool is_sync, const ProofSource::Chain* chain,
-    absl::string_view handshake_hints, absl::string_view ticket_encryption_key,
-    bool cert_matched_sni, QuicDelayedSSLConfig delayed_ssl_config) {
+    bool ok, bool is_sync, SSLConfig ssl_config,
+    absl::string_view ticket_encryption_key, bool cert_matched_sni) {
   QUIC_DVLOG(1) << "OnSelectCertificateDone. ok:" << ok
-                << ", is_sync:" << is_sync
-                << ", len(handshake_hints):" << handshake_hints.size()
-                << ", len(ticket_encryption_key):"
+                << ", is_sync:" << is_sync << ", len(ticket_encryption_key):"
                 << ticket_encryption_key.size();
   std::optional<QuicConnectionContextSwitcher> context_switcher;
   if (!is_sync) {
@@ -1022,14 +1050,17 @@
 
   QUIC_TRACESTRING(absl::StrCat(
       "TLS select certificate done: ok:", ok,
-      ", certs_found:", (chain != nullptr && !chain->certs.empty()),
-      ", len(handshake_hints):", handshake_hints.size(),
       ", len(ticket_encryption_key):", ticket_encryption_key.size()));
 
   ticket_encryption_key_ = std::string(ticket_encryption_key);
   select_cert_status_ = QUIC_FAILURE;
   cert_matched_sni_ = cert_matched_sni;
 
+  // Extract the delayed SSL config from either LocalSSLConfig or
+  // HintsSSLConfig.
+  const QuicDelayedSSLConfig& delayed_ssl_config = absl::visit(
+      [](const auto& config) { return config.delayed_ssl_config; }, ssl_config);
+
   if (delayed_ssl_config.quic_transport_parameters.has_value()) {
     // In case of any error the SSL object is still valid. Handshaker may need
     // to call ComputeSignature but otherwise can proceed.
@@ -1053,25 +1084,33 @@
   }
 
   if (ok) {
-    if (chain && !chain->certs.empty()) {
-      tls_connection_.SetCertChain(chain->ToCryptoBuffers().value);
-      if (!handshake_hints.empty() &&
-          !SSL_set_handshake_hints(
-              ssl(), reinterpret_cast<const uint8_t*>(handshake_hints.data()),
-              handshake_hints.size())) {
-        // If |SSL_set_handshake_hints| fails, the ssl() object will remain
-        // intact, it is as if we didn't call it. The handshaker will
-        // continue to compute signature/decrypt ticket as normal.
-        QUIC_CODE_COUNT(quic_tls_server_set_handshake_hints_failed);
-        QUIC_DVLOG(1) << "SSL_set_handshake_hints failed";
+    if (auto* local_config = std::get_if<LocalSSLConfig>(&ssl_config);
+        local_config != nullptr) {
+      if (local_config->chain && !local_config->chain->certs.empty()) {
+        tls_connection_.SetCertChain(
+            local_config->chain->ToCryptoBuffers().value);
+        select_cert_status_ = QUIC_SUCCESS;
+      } else {
+        QUIC_DLOG(ERROR) << "No certs provided for host '"
+                         << crypto_negotiated_params_->sni
+                         << "', server_address:"
+                         << session()->connection()->self_address()
+                         << ", client_address:"
+                         << session()->connection()->peer_address();
       }
-      select_cert_status_ = QUIC_SUCCESS;
+    } else if (auto* hints_config = std::get_if<HintsSSLConfig>(&ssl_config);
+               hints_config != nullptr) {
+      if (hints_config->configure_ssl) {
+        if (const absl::Status status = tls_connection_.ConfigureSSL(
+                std::move(hints_config->configure_ssl));
+            !status.ok()) {
+          QUIC_CODE_COUNT(quic_tls_server_set_handshake_hints_failed);
+          QUIC_DVLOG(1) << "SSL_set_handshake_hints failed: " << status;
+        }
+        select_cert_status_ = QUIC_SUCCESS;
+      }
     } else {
-      QUIC_DLOG(ERROR) << "No certs provided for host '"
-                       << crypto_negotiated_params_->sni << "', server_address:"
-                       << session()->connection()->self_address()
-                       << ", client_address:"
-                       << session()->connection()->peer_address();
+      QUIC_DLOG(FATAL) << "Neither branch hit";
     }
   }
 
diff --git a/quiche/quic/core/tls_server_handshaker.h b/quiche/quic/core/tls_server_handshaker.h
index 5f571ed..2e0351e 100644
--- a/quiche/quic/core/tls_server_handshaker.h
+++ b/quiche/quic/core/tls_server_handshaker.h
@@ -5,23 +5,40 @@
 #ifndef QUICHE_QUIC_CORE_TLS_SERVER_HANDSHAKER_H_
 #define QUICHE_QUIC_CORE_TLS_SERVER_HANDSHAKER_H_
 
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <optional>
 #include <string>
+#include <utility>
+#include <vector>
 
 #include "absl/strings/string_view.h"
-#include "openssl/pool.h"
+#include "absl/types/span.h"
+#include "openssl/base.h"
 #include "openssl/ssl.h"
+#include "quiche/quic/core/crypto/crypto_handshake.h"
+#include "quiche/quic/core/crypto/crypto_message_parser.h"
+#include "quiche/quic/core/crypto/proof_source.h"
+#include "quiche/quic/core/crypto/proof_verifier.h"
 #include "quiche/quic/core/crypto/quic_crypto_server_config.h"
+#include "quiche/quic/core/crypto/quic_decrypter.h"
+#include "quiche/quic/core/crypto/quic_encrypter.h"
+#include "quiche/quic/core/crypto/tls_connection.h"
 #include "quiche/quic/core/crypto/tls_server_connection.h"
-#include "quiche/quic/core/proto/cached_network_parameters_proto.h"
+#include "quiche/quic/core/crypto/transport_parameters.h"
+#include "quiche/quic/core/quic_config.h"
+#include "quiche/quic/core/quic_connection_context.h"
 #include "quiche/quic/core/quic_connection_id.h"
+#include "quiche/quic/core/quic_connection_stats.h"
 #include "quiche/quic/core/quic_crypto_server_stream_base.h"
 #include "quiche/quic/core/quic_crypto_stream.h"
+#include "quiche/quic/core/quic_error_codes.h"
+#include "quiche/quic/core/quic_time.h"
 #include "quiche/quic/core/quic_time_accumulator.h"
 #include "quiche/quic/core/quic_types.h"
 #include "quiche/quic/core/tls_handshaker.h"
-#include "quiche/quic/platform/api/quic_export.h"
-#include "quiche/quic/platform/api/quic_flag_utils.h"
-#include "quiche/quic/platform/api/quic_flags.h"
+#include "quiche/quic/platform/api/quic_socket_address.h"
 
 namespace quic {
 
@@ -178,11 +195,9 @@
   bool HasValidSignature(size_t max_signature_size) const;
 
   // ProofSourceHandleCallback implementation:
-  void OnSelectCertificateDone(
-      bool ok, bool is_sync, const ProofSource::Chain* chain,
-      absl::string_view handshake_hints,
-      absl::string_view ticket_encryption_key, bool cert_matched_sni,
-      QuicDelayedSSLConfig delayed_ssl_config) override;
+  void OnSelectCertificateDone(bool ok, bool is_sync, SSLConfig ssl_config,
+                               absl::string_view ticket_encryption_key,
+                               bool cert_matched_sni) override;
 
   void OnComputeSignatureDone(
       bool ok, bool is_sync, std::string signature,
diff --git a/quiche/quic/test_tools/fake_proof_source_handle.cc b/quiche/quic/test_tools/fake_proof_source_handle.cc
index 9ab13ce..0f95d00 100644
--- a/quiche/quic/test_tools/fake_proof_source_handle.cc
+++ b/quiche/quic/test_tools/fake_proof_source_handle.cc
@@ -4,9 +4,22 @@
 
 #include "quiche/quic/test_tools/fake_proof_source_handle.h"
 
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <optional>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "quiche/quic/core/crypto/proof_source.h"
 #include "quiche/quic/core/quic_connection_id.h"
 #include "quiche/quic/core/quic_types.h"
 #include "quiche/quic/platform/api/quic_bug_tracker.h"
+#include "quiche/quic/platform/api/quic_socket_address.h"
+#include "quiche/common/platform/api/quiche_logging.h"
+#include "quiche/common/platform/api/quiche_reference_counted.h"
 
 namespace quic {
 namespace test {
@@ -93,9 +106,10 @@
              select_cert_action_ == Action::FAIL_SYNC_DO_NOT_CHECK_CLOSED) {
     callback()->OnSelectCertificateDone(
         /*ok=*/false,
-        /*is_sync=*/true, nullptr, /*handshake_hints=*/absl::string_view(),
+        /*is_sync=*/true,
+        ProofSourceHandleCallback::LocalSSLConfig{nullptr, delayed_ssl_config_},
         /*ticket_encryption_key=*/absl::string_view(),
-        /*cert_matched_sni=*/false, delayed_ssl_config_);
+        /*cert_matched_sni=*/false);
     return QUIC_FAILURE;
   }
 
@@ -107,10 +121,11 @@
 
   bool ok = chain && !chain->certs.empty();
   callback_->OnSelectCertificateDone(
-      ok, /*is_sync=*/true, chain.get(),
-      /*handshake_hints=*/absl::string_view(),
+      ok, /*is_sync=*/true,
+      ProofSourceHandleCallback::LocalSSLConfig{chain.get(),
+                                                delayed_ssl_config_},
       /*ticket_encryption_key=*/absl::string_view(),
-      /*cert_matched_sni=*/cert_matched_sni, delayed_ssl_config_);
+      /*cert_matched_sni=*/cert_matched_sni);
   return ok ? QUIC_SUCCESS : QUIC_FAILURE;
 }
 
@@ -186,10 +201,10 @@
   if (action_ == Action::FAIL_ASYNC) {
     callback_->OnSelectCertificateDone(
         /*ok=*/false,
-        /*is_sync=*/false, nullptr,
-        /*handshake_hints=*/absl::string_view(),
+        /*is_sync=*/false,
+        ProofSourceHandleCallback::LocalSSLConfig{nullptr, delayed_ssl_config_},
         /*ticket_encryption_key=*/absl::string_view(),
-        /*cert_matched_sni=*/false, delayed_ssl_config_);
+        /*cert_matched_sni=*/false);
   } else if (action_ == Action::DELEGATE_ASYNC) {
     bool cert_matched_sni;
     quiche::QuicheReferenceCountedPointer<ProofSource::Chain> chain =
@@ -197,10 +212,11 @@
                                 args_.hostname, &cert_matched_sni);
     bool ok = chain && !chain->certs.empty();
     callback_->OnSelectCertificateDone(
-        ok, /*is_sync=*/false, chain.get(),
-        /*handshake_hints=*/absl::string_view(),
+        ok, /*is_sync=*/false,
+        ProofSourceHandleCallback::LocalSSLConfig{chain.get(),
+                                                  delayed_ssl_config_},
         /*ticket_encryption_key=*/absl::string_view(),
-        /*cert_matched_sni=*/cert_matched_sni, delayed_ssl_config_);
+        /*cert_matched_sni=*/cert_matched_sni);
   } else {
     QUIC_BUG(quic_bug_10139_1)
         << "Unexpected action: " << static_cast<int>(action_);