gfe-relnote: Add SessionCache to TlsClientHandshaker, protected by reloadable flag quic_supports_tls_handshake

PiperOrigin-RevId: 279800830
Change-Id: Ib7b49726c14208f63c5b3a8c552cff36cb5d89bf
diff --git a/quic/core/crypto/quic_crypto_client_config.cc b/quic/core/crypto/quic_crypto_client_config.cc
index 6813f7c..6b00c4c 100644
--- a/quic/core/crypto/quic_crypto_client_config.cc
+++ b/quic/core/crypto/quic_crypto_client_config.cc
@@ -61,7 +61,13 @@
 
 QuicCryptoClientConfig::QuicCryptoClientConfig(
     std::unique_ptr<ProofVerifier> proof_verifier)
+    : QuicCryptoClientConfig(std::move(proof_verifier), nullptr) {}
+
+QuicCryptoClientConfig::QuicCryptoClientConfig(
+    std::unique_ptr<ProofVerifier> proof_verifier,
+    std::unique_ptr<SessionCache> session_cache)
     : proof_verifier_(std::move(proof_verifier)),
+      session_cache_(std::move(session_cache)),
       ssl_ctx_(TlsClientConnection::CreateSslCtx()) {
   DCHECK(proof_verifier_.get());
   SetDefaults();
@@ -850,6 +856,10 @@
   return proof_verifier_.get();
 }
 
+SessionCache* QuicCryptoClientConfig::session_cache() const {
+  return session_cache_.get();
+}
+
 SSL_CTX* QuicCryptoClientConfig::ssl_ctx() const {
   return ssl_ctx_.get();
 }
diff --git a/quic/core/crypto/quic_crypto_client_config.h b/quic/core/crypto/quic_crypto_client_config.h
index d3e627d..a3e1bcd 100644
--- a/quic/core/crypto/quic_crypto_client_config.h
+++ b/quic/core/crypto/quic_crypto_client_config.h
@@ -12,8 +12,10 @@
 #include <vector>
 
 #include "third_party/boringssl/src/include/openssl/base.h"
+#include "third_party/boringssl/src/include/openssl/ssl.h"
 #include "net/third_party/quiche/src/quic/core/crypto/crypto_handshake.h"
 #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
+#include "net/third_party/quiche/src/quic/core/crypto/transport_parameters.h"
 #include "net/third_party/quiche/src/quic/core/quic_packets.h"
 #include "net/third_party/quiche/src/quic/core/quic_server_id.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
@@ -27,6 +29,53 @@
 class ProofVerifyDetails;
 class QuicRandom;
 
+// QuicResumptionState stores the state a client needs for performing connection
+// resumption.
+struct QUIC_EXPORT_PRIVATE QuicResumptionState {
+  // |tls_session| holds the cryptographic state necessary for a resumption. It
+  // includes the ALPN negotiated on the connection where the ticket was
+  // received.
+  bssl::UniquePtr<SSL_SESSION> tls_session;
+
+  // If the application using QUIC doesn't support 0-RTT handshakes or the
+  // client didn't receive a 0-RTT capable session ticket from the server,
+  // |transport_params| will be null. Otherwise, it will contain the transport
+  // parameters received from the server on the original connection.
+  std::unique_ptr<TransportParameters> transport_params;
+
+  // If |transport_params| is null, then |application_state| is ignored and
+  // should be empty. |application_state| contains serialized state that the
+  // client received from the server at the application layer that the client
+  // needs to remember when performing a 0-RTT handshake.
+  std::vector<uint8_t> application_state;
+};
+
+// SessionCache is an interface for managing storing and retrieving
+// QuicResumptionState structs.
+class QUIC_EXPORT_PRIVATE SessionCache {
+ public:
+  virtual ~SessionCache() {}
+
+  // Inserts |state| into the cache, keyed by |server_id|. Insert is called
+  // after a session ticket is received. If the session ticket is valid for
+  // 0-RTT, there may be a delay between its receipt and the call to Insert
+  // while waiting for application state for |state|.
+  //
+  // Insert may be called multiple times per connection. SessionCache
+  // implementations should support storing multiple entries per server ID.
+  virtual void Insert(const QuicServerId& server_id,
+                      std::unique_ptr<QuicResumptionState> state) = 0;
+
+  // Lookup is called once at the beginning of each TLS handshake to potentially
+  // provide the saved state both for the TLS handshake and for sending 0-RTT
+  // data (if supported). Lookup may return a nullptr. Implementations should
+  // delete cache entries after returning them in Lookup so that session tickets
+  // are used only once.
+  virtual std::unique_ptr<QuicResumptionState> Lookup(
+      const QuicServerId& server_id,
+      const SSL_CTX* ctx) = 0;
+};
+
 // QuicCryptoClientConfig contains crypto-related configuration settings for a
 // client. Note that this object isn't thread-safe. It's designed to be used on
 // a single thread at a time.
@@ -203,8 +252,11 @@
     virtual bool Matches(const QuicServerId& server_id) const = 0;
   };
 
+  // DEPRECATED: Use the constructor below instead.
   explicit QuicCryptoClientConfig(
       std::unique_ptr<ProofVerifier> proof_verifier);
+  QuicCryptoClientConfig(std::unique_ptr<ProofVerifier> proof_verifier,
+                         std::unique_ptr<SessionCache> session_cache);
   QuicCryptoClientConfig(const QuicCryptoClientConfig&) = delete;
   QuicCryptoClientConfig& operator=(const QuicCryptoClientConfig&) = delete;
   ~QuicCryptoClientConfig();
@@ -309,7 +361,7 @@
       std::string* error_details);
 
   ProofVerifier* proof_verifier() const;
-
+  SessionCache* session_cache() const;
   SSL_CTX* ssl_ctx() const;
 
   // Initialize the CachedState from |canonical_crypto_config| for the
@@ -388,6 +440,7 @@
   std::vector<std::string> canonical_suffixes_;
 
   std::unique_ptr<ProofVerifier> proof_verifier_;
+  std::unique_ptr<SessionCache> session_cache_;
   bssl::UniquePtr<SSL_CTX> ssl_ctx_;
 
   // The |user_agent_id_| passed in QUIC's CHLO message.
diff --git a/quic/core/crypto/tls_client_connection.cc b/quic/core/crypto/tls_client_connection.cc
index f28af66..98aa6e7 100644
--- a/quic/core/crypto/tls_client_connection.cc
+++ b/quic/core/crypto/tls_client_connection.cc
@@ -19,6 +19,11 @@
   // certificate after the connection is complete. We need to re-verify on
   // resumption in case of expiration or revocation/distrust.
   SSL_CTX_set_custom_verify(ssl_ctx.get(), SSL_VERIFY_PEER, &VerifyCallback);
+
+  // Configure session caching.
+  SSL_CTX_set_session_cache_mode(
+      ssl_ctx.get(), SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL);
+  SSL_CTX_sess_set_new_cb(ssl_ctx.get(), NewSessionCallback);
   return ssl_ctx;
 }
 
@@ -30,4 +35,11 @@
       ->delegate_->VerifyCert(out_alert);
 }
 
+// static
+int TlsClientConnection::NewSessionCallback(SSL* ssl, SSL_SESSION* session) {
+  static_cast<TlsClientConnection*>(ConnectionFromSsl(ssl))
+      ->delegate_->InsertSession(bssl::UniquePtr<SSL_SESSION>(session));
+  return 1;
+}
+
 }  // namespace quic
diff --git a/quic/core/crypto/tls_client_connection.h b/quic/core/crypto/tls_client_connection.h
index 6660343..035f420 100644
--- a/quic/core/crypto/tls_client_connection.h
+++ b/quic/core/crypto/tls_client_connection.h
@@ -26,6 +26,9 @@
     // or ssl_verify_retry if verification is happening asynchronously.
     virtual enum ssl_verify_result_t VerifyCert(uint8_t* out_alert) = 0;
 
+    // Called when a NewSessionTicket is received from the server.
+    virtual void InsertSession(bssl::UniquePtr<SSL_SESSION> session) = 0;
+
     // Provides the delegate for callbacks that are shared between client and
     // server.
     virtual TlsConnection::Delegate* ConnectionDelegate() = 0;
@@ -43,6 +46,10 @@
   // implementation is delegated to Delegate::VerifyCert.
   static enum ssl_verify_result_t VerifyCallback(SSL* ssl, uint8_t* out_alert);
 
+  // Registered as the callback for SSL_CTX_sess_set_new_cb, which calls
+  // Delegate::InsertSession.
+  static int NewSessionCallback(SSL* ssl, SSL_SESSION* session);
+
   Delegate* delegate_;
 };
 
diff --git a/quic/core/crypto/tls_server_connection.cc b/quic/core/crypto/tls_server_connection.cc
index 927c75a..f539a08 100644
--- a/quic/core/crypto/tls_server_connection.cc
+++ b/quic/core/crypto/tls_server_connection.cc
@@ -16,6 +16,7 @@
   SSL_CTX_set_tlsext_servername_callback(ssl_ctx.get(),
                                          &SelectCertificateCallback);
   SSL_CTX_set_alpn_select_cb(ssl_ctx.get(), &SelectAlpnCallback, nullptr);
+  SSL_CTX_set_options(ssl_ctx.get(), SSL_OP_NO_TICKET);
   return ssl_ctx;
 }