Refactor TlsHandshaker classes

QuicCryptoClientConfig and QuicCryptoServerConfig each own an SSL_CTX,
which is currently created by TlsHandshaker. Those crypto config classes
can't take a dependency on TlsHandshaker (because TlsHandshaker depends on
classes have a dependency in the other direction), resulting in the SSL_CTX
being passed into the crypto config constructors. The SSL_CTX shouldn't be
exposed like this, as it's essentially an implementation detail of the
crypto handshake.

This CL splits TlsHandshaker in two. TlsConnection (and its subclasses) are
in quic/core/crypto, and handle the callbacks from BoringSSL. In turn, it
passes the implementation of those callbacks to a delegate. TlsHandshaker
implements this delegate and owns the TlsConnection.

gfe-relnote: refactor TLS handshake classes in QUIC; not flag protected
PiperOrigin-RevId: 253140899
Change-Id: Ie907a7f61798c29a385be15ea0f53403b86508ab
diff --git a/quic/core/crypto/crypto_server_test.cc b/quic/core/crypto/crypto_server_test.cc
index 8663832..92f774c 100644
--- a/quic/core/crypto/crypto_server_test.cc
+++ b/quic/core/crypto/crypto_server_test.cc
@@ -20,7 +20,6 @@
 #include "net/third_party/quiche/src/quic/core/proto/crypto_server_config.pb.h"
 #include "net/third_party/quiche/src/quic/core/quic_socket_address_coder.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
-#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
@@ -93,8 +92,7 @@
         config_(QuicCryptoServerConfig::TESTING,
                 rand_,
                 crypto_test_utils::ProofSourceForTesting(),
-                KeyExchangeSource::Default(),
-                TlsServerHandshaker::CreateSslCtx()),
+                KeyExchangeSource::Default()),
         peer_(&config_),
         compressed_certs_cache_(
             QuicCompressedCertsCache::kQuicCompressedCertsCacheSize),
@@ -972,12 +970,10 @@
 
   QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a,
                            crypto_test_utils::ProofSourceForTesting(),
-                           KeyExchangeSource::Default(),
-                           TlsServerHandshaker::CreateSslCtx());
+                           KeyExchangeSource::Default());
   QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b,
                            crypto_test_utils::ProofSourceForTesting(),
-                           KeyExchangeSource::Default(),
-                           TlsServerHandshaker::CreateSslCtx());
+                           KeyExchangeSource::Default());
   std::unique_ptr<CryptoHandshakeMessage> scfg_a(
       a.AddDefaultConfig(&rand_a, &clock, options));
   std::unique_ptr<CryptoHandshakeMessage> scfg_b(
@@ -996,13 +992,11 @@
 
   QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a,
                            crypto_test_utils::ProofSourceForTesting(),
-                           KeyExchangeSource::Default(),
-                           TlsServerHandshaker::CreateSslCtx());
+                           KeyExchangeSource::Default());
   rand_b.ChangeValue();
   QuicCryptoServerConfig b(QuicCryptoServerConfig::TESTING, &rand_b,
                            crypto_test_utils::ProofSourceForTesting(),
-                           KeyExchangeSource::Default(),
-                           TlsServerHandshaker::CreateSslCtx());
+                           KeyExchangeSource::Default());
   std::unique_ptr<CryptoHandshakeMessage> scfg_a(
       a.AddDefaultConfig(&rand_a, &clock, options));
   std::unique_ptr<CryptoHandshakeMessage> scfg_b(
@@ -1022,8 +1016,7 @@
 
   QuicCryptoServerConfig a(QuicCryptoServerConfig::TESTING, &rand_a,
                            crypto_test_utils::ProofSourceForTesting(),
-                           KeyExchangeSource::Default(),
-                           TlsServerHandshaker::CreateSslCtx());
+                           KeyExchangeSource::Default());
   std::unique_ptr<CryptoHandshakeMessage> scfg(
       a.AddDefaultConfig(&rand_a, &clock, options));
 
diff --git a/quic/core/crypto/quic_crypto_client_config.cc b/quic/core/crypto/quic_crypto_client_config.cc
index c967b17..14f1347 100644
--- a/quic/core/crypto/quic_crypto_client_config.cc
+++ b/quic/core/crypto/quic_crypto_client_config.cc
@@ -21,6 +21,7 @@
 #include "net/third_party/quiche/src/quic/core/crypto/proof_verifier.h"
 #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
 #include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
+#include "net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h"
 #include "net/third_party/quiche/src/quic/core/quic_connection_id.h"
 #include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
@@ -59,6 +60,11 @@
 }  // namespace
 
 QuicCryptoClientConfig::QuicCryptoClientConfig(
+    std::unique_ptr<ProofVerifier> proof_verifier)
+    : QuicCryptoClientConfig(std::move(proof_verifier),
+                             TlsClientConnection::CreateSslCtx()) {}
+
+QuicCryptoClientConfig::QuicCryptoClientConfig(
     std::unique_ptr<ProofVerifier> proof_verifier,
     bssl::UniquePtr<SSL_CTX> ssl_ctx)
     : proof_verifier_(std::move(proof_verifier)), ssl_ctx_(std::move(ssl_ctx)) {
diff --git a/quic/core/crypto/quic_crypto_client_config.h b/quic/core/crypto/quic_crypto_client_config.h
index 2918a23..2d95103 100644
--- a/quic/core/crypto/quic_crypto_client_config.h
+++ b/quic/core/crypto/quic_crypto_client_config.h
@@ -203,6 +203,9 @@
     virtual bool Matches(const QuicServerId& server_id) const = 0;
   };
 
+  explicit QuicCryptoClientConfig(
+      std::unique_ptr<ProofVerifier> proof_verifier);
+  // Deprecated. Use the single-arg constructor instead.
   QuicCryptoClientConfig(std::unique_ptr<ProofVerifier> proof_verifier,
                          bssl::UniquePtr<SSL_CTX> ssl_ctx);
   QuicCryptoClientConfig(const QuicCryptoClientConfig&) = delete;
diff --git a/quic/core/crypto/quic_crypto_client_config_test.cc b/quic/core/crypto/quic_crypto_client_config_test.cc
index 563c7f1..7b473de 100644
--- a/quic/core/crypto/quic_crypto_client_config_test.cc
+++ b/quic/core/crypto/quic_crypto_client_config_test.cc
@@ -10,7 +10,6 @@
 #include "net/third_party/quiche/src/quic/core/quic_server_id.h"
 #include "net/third_party/quiche/src/quic/core/quic_types.h"
 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
-#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_endian.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
 #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
@@ -178,8 +177,7 @@
 
 TEST_F(QuicCryptoClientConfigTest, InchoateChlo) {
   QuicCryptoClientConfig::CachedState state;
-  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(),
-                                TlsClientHandshaker::CreateSslCtx());
+  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting());
   config.set_user_agent_id("quic-tester");
   config.set_alpn("hq");
   QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params(
@@ -208,8 +206,7 @@
 
 TEST_F(QuicCryptoClientConfigTest, InchoateChloIsNotPadded) {
   QuicCryptoClientConfig::CachedState state;
-  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(),
-                                TlsClientHandshaker::CreateSslCtx());
+  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting());
   config.set_pad_inchoate_hello(false);
   config.set_user_agent_id("quic-tester");
   config.set_alpn("hq");
@@ -227,8 +224,7 @@
 // Make sure AES-GCM is the preferred encryption algorithm if it has hardware
 // acceleration.
 TEST_F(QuicCryptoClientConfigTest, PreferAesGcm) {
-  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(),
-                                TlsClientHandshaker::CreateSslCtx());
+  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting());
   if (EVP_has_aes_hardware() == 1) {
     EXPECT_EQ(kAESG, config.aead[0]);
   } else {
@@ -238,8 +234,7 @@
 
 TEST_F(QuicCryptoClientConfigTest, InchoateChloSecure) {
   QuicCryptoClientConfig::CachedState state;
-  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(),
-                                TlsClientHandshaker::CreateSslCtx());
+  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting());
   QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params(
       new QuicCryptoNegotiatedParameters);
   CryptoHandshakeMessage msg;
@@ -268,8 +263,7 @@
   state.SetServerConfig(scfg.GetSerialized().AsStringPiece(), now, expiry,
                         &details);
 
-  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(),
-                                TlsClientHandshaker::CreateSslCtx());
+  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting());
   QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params(
       new QuicCryptoNegotiatedParameters);
   CryptoHandshakeMessage msg;
@@ -295,8 +289,7 @@
                         QuicWallTime::FromUNIXSeconds(1),
                         QuicWallTime::FromUNIXSeconds(0), &details);
 
-  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(),
-                                TlsClientHandshaker::CreateSslCtx());
+  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting());
   QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params(
       new QuicCryptoNegotiatedParameters);
   CryptoHandshakeMessage msg;
@@ -312,8 +305,7 @@
 
 TEST_F(QuicCryptoClientConfigTest, FillClientHello) {
   QuicCryptoClientConfig::CachedState state;
-  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(),
-                                TlsClientHandshaker::CreateSslCtx());
+  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting());
   QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params(
       new QuicCryptoNegotiatedParameters);
   QuicConnectionId kConnectionId = TestConnectionId(1234);
@@ -333,8 +325,7 @@
 
 TEST_F(QuicCryptoClientConfigTest, FillClientHelloNoPadding) {
   QuicCryptoClientConfig::CachedState state;
-  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(),
-                                TlsClientHandshaker::CreateSslCtx());
+  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting());
   config.set_pad_full_hello(false);
   QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> params(
       new QuicCryptoNegotiatedParameters);
@@ -374,8 +365,7 @@
   QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params(
       new QuicCryptoNegotiatedParameters);
   std::string error;
-  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(),
-                                TlsClientHandshaker::CreateSslCtx());
+  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting());
   EXPECT_EQ(QUIC_VERSION_NEGOTIATION_MISMATCH,
             config.ProcessServerHello(
                 msg, EmptyQuicConnectionId(), supported_versions.front(),
@@ -384,8 +374,7 @@
 }
 
 TEST_F(QuicCryptoClientConfigTest, InitializeFrom) {
-  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(),
-                                TlsClientHandshaker::CreateSslCtx());
+  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting());
   QuicServerId canonical_server_id("www.google.com", 443, false);
   QuicCryptoClientConfig::CachedState* state =
       config.LookupOrCreate(canonical_server_id);
@@ -405,8 +394,7 @@
 }
 
 TEST_F(QuicCryptoClientConfigTest, Canonical) {
-  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(),
-                                TlsClientHandshaker::CreateSslCtx());
+  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting());
   config.AddCanonicalSuffix(".google.com");
   QuicServerId canonical_id1("www.google.com", 443, false);
   QuicServerId canonical_id2("mail.google.com", 443, false);
@@ -430,8 +418,7 @@
 }
 
 TEST_F(QuicCryptoClientConfigTest, CanonicalNotUsedIfNotValid) {
-  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(),
-                                TlsClientHandshaker::CreateSslCtx());
+  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting());
   config.AddCanonicalSuffix(".google.com");
   QuicServerId canonical_id1("www.google.com", 443, false);
   QuicServerId canonical_id2("mail.google.com", 443, false);
@@ -446,8 +433,7 @@
 }
 
 TEST_F(QuicCryptoClientConfigTest, ClearCachedStates) {
-  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(),
-                                TlsClientHandshaker::CreateSslCtx());
+  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting());
 
   // Create two states on different origins.
   struct TestCase {
@@ -542,8 +528,7 @@
   QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params(
       new QuicCryptoNegotiatedParameters);
   std::string error;
-  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(),
-                                TlsClientHandshaker::CreateSslCtx());
+  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting());
   EXPECT_EQ(QUIC_NO_ERROR,
             config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0),
                                     AllSupportedTransportVersions().front(), "",
@@ -564,8 +549,7 @@
   QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params(
       new QuicCryptoNegotiatedParameters);
   std::string error;
-  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(),
-                                TlsClientHandshaker::CreateSslCtx());
+  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting());
   EXPECT_EQ(QUIC_NO_ERROR,
             config.ProcessRejection(rej, QuicWallTime::FromUNIXSeconds(0),
                                     AllSupportedTransportVersions().front(), "",
@@ -588,8 +572,7 @@
   supported_versions.push_back(version);
   msg.SetVersionVector(kVER, supported_versions);
 
-  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting(),
-                                TlsClientHandshaker::CreateSslCtx());
+  QuicCryptoClientConfig config(crypto_test_utils::ProofVerifierForTesting());
   QuicCryptoClientConfig::CachedState cached;
   QuicReferenceCountedPointer<QuicCryptoNegotiatedParameters> out_params(
       new QuicCryptoNegotiatedParameters);
diff --git a/quic/core/crypto/quic_crypto_server_config.cc b/quic/core/crypto/quic_crypto_server_config.cc
index 9d70641..24d0500 100644
--- a/quic/core/crypto/quic_crypto_server_config.cc
+++ b/quic/core/crypto/quic_crypto_server_config.cc
@@ -27,6 +27,7 @@
 #include "net/third_party/quiche/src/quic/core/crypto/quic_encrypter.h"
 #include "net/third_party/quiche/src/quic/core/crypto/quic_hkdf.h"
 #include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
+#include "net/third_party/quiche/src/quic/core/crypto/tls_server_connection.h"
 #include "net/third_party/quiche/src/quic/core/proto/crypto_server_config.pb.h"
 #include "net/third_party/quiche/src/quic/core/proto/source_address_token.pb.h"
 #include "net/third_party/quiche/src/quic/core/quic_packets.h"
@@ -231,6 +232,17 @@
     QuicStringPiece source_address_token_secret,
     QuicRandom* server_nonce_entropy,
     std::unique_ptr<ProofSource> proof_source,
+    std::unique_ptr<KeyExchangeSource> key_exchange_source)
+    : QuicCryptoServerConfig(source_address_token_secret,
+                             server_nonce_entropy,
+                             std::move(proof_source),
+                             std::move(key_exchange_source),
+                             TlsServerConnection::CreateSslCtx()) {}
+
+QuicCryptoServerConfig::QuicCryptoServerConfig(
+    QuicStringPiece source_address_token_secret,
+    QuicRandom* server_nonce_entropy,
+    std::unique_ptr<ProofSource> proof_source,
     std::unique_ptr<KeyExchangeSource> key_exchange_source,
     bssl::UniquePtr<SSL_CTX> ssl_ctx)
     : replay_protection_(true),
diff --git a/quic/core/crypto/quic_crypto_server_config.h b/quic/core/crypto/quic_crypto_server_config.h
index 503b377..85edc0e 100644
--- a/quic/core/crypto/quic_crypto_server_config.h
+++ b/quic/core/crypto/quic_crypto_server_config.h
@@ -218,6 +218,11 @@
                          std::unique_ptr<ProofSource> proof_source,
                          std::unique_ptr<KeyExchangeSource> key_exchange_source,
                          bssl::UniquePtr<SSL_CTX> ssl_ctx);
+  QuicCryptoServerConfig(
+      QuicStringPiece source_address_token_secret,
+      QuicRandom* server_nonce_entropy,
+      std::unique_ptr<ProofSource> proof_source,
+      std::unique_ptr<KeyExchangeSource> key_exchange_source);
   QuicCryptoServerConfig(const QuicCryptoServerConfig&) = delete;
   QuicCryptoServerConfig& operator=(const QuicCryptoServerConfig&) = delete;
   ~QuicCryptoServerConfig();
diff --git a/quic/core/crypto/quic_crypto_server_config_test.cc b/quic/core/crypto/quic_crypto_server_config_test.cc
index b3f8f77..90da3cd 100644
--- a/quic/core/crypto/quic_crypto_server_config_test.cc
+++ b/quic/core/crypto/quic_crypto_server_config_test.cc
@@ -16,7 +16,6 @@
 #include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
 #include "net/third_party/quiche/src/quic/core/proto/crypto_server_config.pb.h"
 #include "net/third_party/quiche/src/quic/core/quic_time.h"
-#include "net/third_party/quiche/src/quic/core/tls_server_handshaker.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
 #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h"
@@ -43,8 +42,7 @@
   QuicRandom* rand = QuicRandom::GetInstance();
   QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand,
                                 crypto_test_utils::ProofSourceForTesting(),
-                                KeyExchangeSource::Default(),
-                                TlsServerHandshaker::CreateSslCtx());
+                                KeyExchangeSource::Default());
   MockClock clock;
 
   std::unique_ptr<CryptoHandshakeMessage> message(server.AddDefaultConfig(
@@ -65,8 +63,7 @@
   QuicRandom* rand = QuicRandom::GetInstance();
   QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand,
                                 crypto_test_utils::ProofSourceForTesting(),
-                                KeyExchangeSource::Default(),
-                                TlsServerHandshaker::CreateSslCtx());
+                                KeyExchangeSource::Default());
   QuicCryptoServerConfigPeer peer(&server);
 
   std::vector<std::string> certs = {"testcert"};
@@ -86,8 +83,7 @@
   QuicRandom* rand = QuicRandom::GetInstance();
   QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand,
                                 crypto_test_utils::ProofSourceForTesting(),
-                                KeyExchangeSource::Default(),
-                                TlsServerHandshaker::CreateSslCtx());
+                                KeyExchangeSource::Default());
   QuicCryptoServerConfigPeer peer(&server);
 
   // Compress the certs for the first time.
@@ -117,8 +113,7 @@
   QuicRandom* rand = QuicRandom::GetInstance();
   QuicCryptoServerConfig server(QuicCryptoServerConfig::TESTING, rand,
                                 crypto_test_utils::ProofSourceForTesting(),
-                                KeyExchangeSource::Default(),
-                                TlsServerHandshaker::CreateSslCtx());
+                                KeyExchangeSource::Default());
   QuicCryptoServerConfigPeer peer(&server);
 
   std::vector<std::string> certs = {"testcert"};
@@ -162,8 +157,7 @@
         server_(QuicCryptoServerConfig::TESTING,
                 rand_,
                 crypto_test_utils::ProofSourceForTesting(),
-                KeyExchangeSource::Default(),
-                TlsServerHandshaker::CreateSslCtx()),
+                KeyExchangeSource::Default()),
         peer_(&server_) {
     // Advance the clock to some non-zero time.
     clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1000000));
@@ -305,8 +299,7 @@
         config_(QuicCryptoServerConfig::TESTING,
                 rand_,
                 crypto_test_utils::ProofSourceForTesting(),
-                KeyExchangeSource::Default(),
-                TlsServerHandshaker::CreateSslCtx()),
+                KeyExchangeSource::Default()),
         test_peer_(&config_) {}
 
   void SetUp() override {
diff --git a/quic/core/crypto/tls_client_connection.cc b/quic/core/crypto/tls_client_connection.cc
new file mode 100644
index 0000000..f28af66
--- /dev/null
+++ b/quic/core/crypto/tls_client_connection.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/crypto/tls_client_connection.h"
+
+namespace quic {
+
+TlsClientConnection::TlsClientConnection(SSL_CTX* ssl_ctx, Delegate* delegate)
+    : TlsConnection(ssl_ctx, delegate->ConnectionDelegate()),
+      delegate_(delegate) {}
+
+// static
+bssl::UniquePtr<SSL_CTX> TlsClientConnection::CreateSslCtx() {
+  bssl::UniquePtr<SSL_CTX> ssl_ctx = TlsConnection::CreateSslCtx();
+  // Configure certificate verification.
+  // TODO(nharper): This only verifies certs on initial connection, not on
+  // resumption. Chromium has this callback be a no-op and verifies the
+  // 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);
+  return ssl_ctx;
+}
+
+// static
+enum ssl_verify_result_t TlsClientConnection::VerifyCallback(
+    SSL* ssl,
+    uint8_t* out_alert) {
+  return static_cast<TlsClientConnection*>(ConnectionFromSsl(ssl))
+      ->delegate_->VerifyCert(out_alert);
+}
+
+}  // namespace quic
diff --git a/quic/core/crypto/tls_client_connection.h b/quic/core/crypto/tls_client_connection.h
new file mode 100644
index 0000000..c741389
--- /dev/null
+++ b/quic/core/crypto/tls_client_connection.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_CORE_CRYPTO_TLS_CLIENT_CONNECTION_H_
+#define QUICHE_QUIC_CORE_CRYPTO_TLS_CLIENT_CONNECTION_H_
+
+#include "net/third_party/quiche/src/quic/core/crypto/tls_connection.h"
+
+namespace quic {
+
+// TlsClientConnection receives calls for client-specific BoringSSL callbacks
+// and calls its Delegate for the implementation of those callbacks.
+class TlsClientConnection : public TlsConnection {
+ public:
+  // A TlsClientConnection::Delegate implements the client-specific methods that
+  // are set as callbacks for an SSL object.
+  class Delegate {
+   public:
+    virtual ~Delegate() {}
+
+   protected:
+    // Verifies the peer's certificate chain. It may use
+    // SSL_get0_peer_certificates to get the cert chain. This method returns
+    // ssl_verify_ok if the cert is valid, ssl_verify_invalid if it is invalid,
+    // or ssl_verify_retry if verification is happening asynchronously.
+    virtual enum ssl_verify_result_t VerifyCert(uint8_t* out_alert) = 0;
+
+    // Provides the delegate for callbacks that are shared between client and
+    // server.
+    virtual TlsConnection::Delegate* ConnectionDelegate() = 0;
+
+    friend class TlsClientConnection;
+  };
+
+  TlsClientConnection(SSL_CTX* ssl_ctx, Delegate* delegate);
+
+  // Creates and configures an SSL_CTX that is appropriate for clients to use.
+  static bssl::UniquePtr<SSL_CTX> CreateSslCtx();
+
+ private:
+  // Registered as the callback for SSL_CTX_set_custom_verify. The
+  // implementation is delegated to Delegate::VerifyCert.
+  static enum ssl_verify_result_t VerifyCallback(SSL* ssl, uint8_t* out_alert);
+
+  Delegate* delegate_;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_CRYPTO_TLS_CLIENT_CONNECTION_H_
diff --git a/quic/core/crypto/tls_connection.cc b/quic/core/crypto/tls_connection.cc
new file mode 100644
index 0000000..d28db22
--- /dev/null
+++ b/quic/core/crypto/tls_connection.cc
@@ -0,0 +1,158 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/crypto/tls_connection.h"
+
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+
+namespace quic {
+
+namespace {
+
+// BoringSSL allows storing extra data off of some of its data structures,
+// including the SSL struct. To allow for multiple callers to store data, each
+// caller can use a different index for setting and getting data. These indices
+// are globals handed out by calling SSL_get_ex_new_index.
+//
+// SslIndexSingleton calls SSL_get_ex_new_index on its construction, and then
+// provides this index to be used in calls to SSL_get_ex_data/SSL_set_ex_data.
+// This is used to store in the SSL struct a pointer to the TlsConnection which
+// owns it.
+class SslIndexSingleton {
+ public:
+  static SslIndexSingleton* GetInstance() {
+    static SslIndexSingleton* instance = new SslIndexSingleton();
+    return instance;
+  }
+
+  int ssl_ex_data_index_connection() const {
+    return ssl_ex_data_index_connection_;
+  }
+
+ private:
+  SslIndexSingleton() {
+    CRYPTO_library_init();
+    ssl_ex_data_index_connection_ =
+        SSL_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
+    CHECK_LE(0, ssl_ex_data_index_connection_);
+  }
+
+  SslIndexSingleton(const SslIndexSingleton&) = delete;
+  SslIndexSingleton& operator=(const SslIndexSingleton&) = delete;
+
+  // The index to supply to SSL_get_ex_data/SSL_set_ex_data for getting/setting
+  // the TlsConnection pointer.
+  int ssl_ex_data_index_connection_;
+};
+
+}  // namespace
+
+// static
+EncryptionLevel TlsConnection::QuicEncryptionLevel(
+    enum ssl_encryption_level_t level) {
+  switch (level) {
+    case ssl_encryption_initial:
+      return ENCRYPTION_INITIAL;
+    case ssl_encryption_early_data:
+      return ENCRYPTION_ZERO_RTT;
+    case ssl_encryption_handshake:
+      return ENCRYPTION_HANDSHAKE;
+    case ssl_encryption_application:
+      return ENCRYPTION_FORWARD_SECURE;
+    default:
+      QUIC_BUG << "Invalid ssl_encryption_level_t " << static_cast<int>(level);
+      return ENCRYPTION_INITIAL;
+  }
+}
+
+// static
+enum ssl_encryption_level_t TlsConnection::BoringEncryptionLevel(
+    EncryptionLevel level) {
+  switch (level) {
+    case ENCRYPTION_INITIAL:
+      return ssl_encryption_initial;
+    case ENCRYPTION_HANDSHAKE:
+      return ssl_encryption_handshake;
+    case ENCRYPTION_ZERO_RTT:
+      return ssl_encryption_early_data;
+    case ENCRYPTION_FORWARD_SECURE:
+      return ssl_encryption_application;
+    default:
+      QUIC_BUG << "Invalid encryption level " << static_cast<int>(level);
+      return ssl_encryption_initial;
+  }
+}
+
+TlsConnection::TlsConnection(SSL_CTX* ssl_ctx,
+                             TlsConnection::Delegate* delegate)
+    : delegate_(delegate), ssl_(SSL_new(ssl_ctx)) {
+  SSL_set_ex_data(
+      ssl(), SslIndexSingleton::GetInstance()->ssl_ex_data_index_connection(),
+      this);
+}
+// static
+bssl::UniquePtr<SSL_CTX> TlsConnection::CreateSslCtx() {
+  CRYPTO_library_init();
+  bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_with_buffers_method()));
+  SSL_CTX_set_min_proto_version(ssl_ctx.get(), TLS1_3_VERSION);
+  SSL_CTX_set_max_proto_version(ssl_ctx.get(), TLS1_3_VERSION);
+  SSL_CTX_set_quic_method(ssl_ctx.get(), &kSslQuicMethod);
+  return ssl_ctx;
+}
+
+// static
+TlsConnection* TlsConnection::ConnectionFromSsl(const SSL* ssl) {
+  return reinterpret_cast<TlsConnection*>(SSL_get_ex_data(
+      ssl, SslIndexSingleton::GetInstance()->ssl_ex_data_index_connection()));
+}
+
+const SSL_QUIC_METHOD TlsConnection::kSslQuicMethod{
+    TlsConnection::SetEncryptionSecretCallback,
+    TlsConnection::WriteMessageCallback, TlsConnection::FlushFlightCallback,
+    TlsConnection::SendAlertCallback};
+
+// static
+int TlsConnection::SetEncryptionSecretCallback(
+    SSL* ssl,
+    enum ssl_encryption_level_t level,
+    const uint8_t* read_key,
+    const uint8_t* write_key,
+    size_t key_length) {
+  // TODO(nharper): replace these vectors and memcpys with spans (which
+  // unfortunately doesn't yet exist in quic/platform/api).
+  std::vector<uint8_t> read_secret(key_length), write_secret(key_length);
+  memcpy(read_secret.data(), read_key, key_length);
+  memcpy(write_secret.data(), write_key, key_length);
+  ConnectionFromSsl(ssl)->delegate_->SetEncryptionSecret(
+      QuicEncryptionLevel(level), read_secret, write_secret);
+  return 1;
+}
+
+// static
+int TlsConnection::WriteMessageCallback(SSL* ssl,
+                                        enum ssl_encryption_level_t level,
+                                        const uint8_t* data,
+                                        size_t len) {
+  ConnectionFromSsl(ssl)->delegate_->WriteMessage(
+      QuicEncryptionLevel(level),
+      QuicStringPiece(reinterpret_cast<const char*>(data), len));
+  return 1;
+}
+
+// static
+int TlsConnection::FlushFlightCallback(SSL* ssl) {
+  ConnectionFromSsl(ssl)->delegate_->FlushFlight();
+  return 1;
+}
+
+// static
+int TlsConnection::SendAlertCallback(SSL* ssl,
+                                     enum ssl_encryption_level_t level,
+                                     uint8_t desc) {
+  ConnectionFromSsl(ssl)->delegate_->SendAlert(QuicEncryptionLevel(level),
+                                               desc);
+  return 1;
+}
+
+}  // namespace quic
diff --git a/quic/core/crypto/tls_connection.h b/quic/core/crypto/tls_connection.h
new file mode 100644
index 0000000..15c2b67
--- /dev/null
+++ b/quic/core/crypto/tls_connection.h
@@ -0,0 +1,116 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_CORE_CRYPTO_TLS_CONNECTION_H_
+#define QUICHE_QUIC_CORE_CRYPTO_TLS_CONNECTION_H_
+
+#include <vector>
+
+#include "third_party/boringssl/src/include/openssl/ssl.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string_piece.h"
+
+namespace quic {
+
+// TlsConnection wraps BoringSSL's SSL object which represents a single TLS
+// connection. Callbacks set in BoringSSL which are called with an SSL* argument
+// will get dispatched to the TlsConnection object owning that SSL. In turn, the
+// TlsConnection will delegate the implementation of that callback to its
+// Delegate.
+//
+// The owner of the TlsConnection is responsible for driving the TLS handshake
+// (and other interactions with the SSL*). This class only handles mapping
+// callbacks to the correct instance.
+class TlsConnection {
+ public:
+  // A TlsConnection::Delegate implements the methods that are set as callbacks
+  // of TlsConnection.
+  class Delegate {
+   public:
+    virtual ~Delegate() {}
+
+   protected:
+    // SetEncryptionSecret provides the encryption secrets to use at a
+    // particular encryption level |level|. The secrets provided here are the
+    // ones from the TLS 1.3 key schedule (RFC 8446 section 7.1), in particular
+    // the handshake traffic secrets and application traffic secrets. For a
+    // given level |level|, |read_secret| is the secret used for reading data,
+    // and |write_secret| is the secret used for writing data.
+    virtual void SetEncryptionSecret(
+        EncryptionLevel level,
+        const std::vector<uint8_t>& read_secret,
+        const std::vector<uint8_t>& write_secret) = 0;
+
+    // WriteMessage is called when there is |data| from the TLS stack ready for
+    // the QUIC stack to write in a crypto frame. The data must be transmitted
+    // at encryption level |level|.
+    virtual void WriteMessage(EncryptionLevel level, QuicStringPiece data) = 0;
+
+    // FlushFlight is called to signal that the current flight of messages have
+    // all been written (via calls to WriteMessage) and can be flushed to the
+    // underlying transport.
+    virtual void FlushFlight() = 0;
+
+    // SendAlert causes this TlsConnection to close the QUIC connection with an
+    // error code corersponding to the TLS alert description |desc| sent at
+    // level |level|.
+    virtual void SendAlert(EncryptionLevel level, uint8_t desc) = 0;
+
+    friend class TlsConnection;
+  };
+
+  TlsConnection(const TlsConnection&) = delete;
+  TlsConnection& operator=(const TlsConnection&) = delete;
+
+  // Functions to convert between BoringSSL's enum ssl_encryption_level_t and
+  // QUIC's EncryptionLevel.
+  static EncryptionLevel QuicEncryptionLevel(enum ssl_encryption_level_t level);
+  static enum ssl_encryption_level_t BoringEncryptionLevel(
+      EncryptionLevel level);
+
+  SSL* ssl() { return ssl_.get(); }
+
+ protected:
+  // TlsConnection does not take ownership of any of its arguments; they must
+  // outlive the TlsConnection object.
+  TlsConnection(SSL_CTX* ssl_ctx, Delegate* delegate);
+
+  // Creates an SSL_CTX and configures it with the options that are appropriate
+  // for both client and server. The caller is responsible for ownership of the
+  // newly created struct.
+  static bssl::UniquePtr<SSL_CTX> CreateSslCtx();
+
+  // From a given SSL* |ssl|, returns a pointer to the TlsConnection that it
+  // belongs to. This helper method allows the callbacks set in BoringSSL to be
+  // dispatched to the correct TlsConnection from the SSL* passed into the
+  // callback.
+  static TlsConnection* ConnectionFromSsl(const SSL* ssl);
+
+ private:
+  // TlsConnection implements SSL_QUIC_METHOD, which provides the interface
+  // between BoringSSL's TLS stack and a QUIC implementation.
+  static const SSL_QUIC_METHOD kSslQuicMethod;
+
+  // The following static functions make up the members of kSslQuicMethod:
+  static int SetEncryptionSecretCallback(SSL* ssl,
+                                         enum ssl_encryption_level_t level,
+                                         const uint8_t* read_key,
+                                         const uint8_t* write_key,
+                                         size_t key_length);
+  static int WriteMessageCallback(SSL* ssl,
+                                  enum ssl_encryption_level_t level,
+                                  const uint8_t* data,
+                                  size_t len);
+  static int FlushFlightCallback(SSL* ssl);
+  static int SendAlertCallback(SSL* ssl,
+                               enum ssl_encryption_level_t level,
+                               uint8_t desc);
+
+  Delegate* delegate_;
+  bssl::UniquePtr<SSL> ssl_;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_CRYPTO_TLS_CONNECTION_H_
diff --git a/quic/core/crypto/tls_server_connection.cc b/quic/core/crypto/tls_server_connection.cc
new file mode 100644
index 0000000..a3a1815
--- /dev/null
+++ b/quic/core/crypto/tls_server_connection.cc
@@ -0,0 +1,81 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/crypto/tls_server_connection.h"
+
+namespace quic {
+
+TlsServerConnection::TlsServerConnection(SSL_CTX* ssl_ctx, Delegate* delegate)
+    : TlsConnection(ssl_ctx, delegate->ConnectionDelegate()),
+      delegate_(delegate) {}
+
+// static
+bssl::UniquePtr<SSL_CTX> TlsServerConnection::CreateSslCtx() {
+  bssl::UniquePtr<SSL_CTX> ssl_ctx = TlsConnection::CreateSslCtx();
+  SSL_CTX_set_tlsext_servername_callback(ssl_ctx.get(),
+                                         &SelectCertificateCallback);
+  SSL_CTX_set_alpn_select_cb(ssl_ctx.get(), &SelectAlpnCallback, nullptr);
+  return ssl_ctx;
+}
+
+void TlsServerConnection::SetCertChain(
+    const std::vector<CRYPTO_BUFFER*>& cert_chain) {
+  SSL_set_chain_and_key(ssl(), cert_chain.data(), cert_chain.size(), nullptr,
+                        &TlsServerConnection::kPrivateKeyMethod);
+}
+
+const SSL_PRIVATE_KEY_METHOD TlsServerConnection::kPrivateKeyMethod{
+    &TlsServerConnection::PrivateKeySign,
+    nullptr,  // decrypt
+    &TlsServerConnection::PrivateKeyComplete,
+};
+
+// static
+TlsServerConnection* TlsServerConnection::ConnectionFromSsl(SSL* ssl) {
+  return static_cast<TlsServerConnection*>(
+      TlsConnection::ConnectionFromSsl(ssl));
+}
+
+// static
+int TlsServerConnection::SelectCertificateCallback(SSL* ssl,
+                                                   int* out_alert,
+                                                   void* arg) {
+  return ConnectionFromSsl(ssl)->delegate_->SelectCertificate(out_alert);
+}
+
+// static
+int TlsServerConnection::SelectAlpnCallback(SSL* ssl,
+                                            const uint8_t** out,
+                                            uint8_t* out_len,
+                                            const uint8_t* in,
+                                            unsigned in_len,
+                                            void* arg) {
+  return ConnectionFromSsl(ssl)->delegate_->SelectAlpn(out, out_len, in,
+                                                       in_len);
+}
+
+// static
+ssl_private_key_result_t TlsServerConnection::PrivateKeySign(SSL* ssl,
+                                                             uint8_t* out,
+                                                             size_t* out_len,
+                                                             size_t max_out,
+                                                             uint16_t sig_alg,
+                                                             const uint8_t* in,
+                                                             size_t in_len) {
+  return ConnectionFromSsl(ssl)->delegate_->PrivateKeySign(
+      out, out_len, max_out, sig_alg,
+      QuicStringPiece(reinterpret_cast<const char*>(in), in_len));
+}
+
+// static
+ssl_private_key_result_t TlsServerConnection::PrivateKeyComplete(
+    SSL* ssl,
+    uint8_t* out,
+    size_t* out_len,
+    size_t max_out) {
+  return ConnectionFromSsl(ssl)->delegate_->PrivateKeyComplete(out, out_len,
+                                                               max_out);
+}
+
+}  // namespace quic
diff --git a/quic/core/crypto/tls_server_connection.h b/quic/core/crypto/tls_server_connection.h
new file mode 100644
index 0000000..a5d087c
--- /dev/null
+++ b/quic/core/crypto/tls_server_connection.h
@@ -0,0 +1,111 @@
+// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_CORE_CRYPTO_TLS_SERVER_CONNECTION_H_
+#define QUICHE_QUIC_CORE_CRYPTO_TLS_SERVER_CONNECTION_H_
+
+#include "net/third_party/quiche/src/quic/core/crypto/tls_connection.h"
+
+namespace quic {
+
+// TlsServerConnection receives calls for client-specific BoringSSL callbacks
+// and calls its Delegate for the implementation of those callbacks.
+class TlsServerConnection : public TlsConnection {
+ public:
+  // A TlsServerConnection::Delegate implement the server-specific methods that
+  // are set as callbacks for an SSL object.
+  class Delegate {
+   public:
+    virtual ~Delegate() {}
+
+   protected:
+    // Configures the certificate to use on |ssl_| based on the SNI sent by the
+    // client. Returns an SSL_TLSEXT_ERR_* value (see
+    // https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_tlsext_servername_callback).
+    //
+    // If SelectCertificate returns SSL_TLSEXT_ERR_ALERT_FATAL, then it puts in
+    // |*out_alert| the TLS alert value that the server will send.
+    virtual int SelectCertificate(int* out_alert) = 0;
+
+    // Selects which ALPN to use based on the list sent by the client.
+    virtual int SelectAlpn(const uint8_t** out,
+                           uint8_t* out_len,
+                           const uint8_t* in,
+                           unsigned in_len) = 0;
+
+    // Signs |in| using the signature algorithm specified by |sig_alg| (an
+    // SSL_SIGN_* value). If the signing operation cannot be completed
+    // synchronously, ssl_private_key_retry is returned. If there is an error
+    // signing, or if the signature is longer than |max_out|, then
+    // ssl_private_key_failure is returned. Otherwise, ssl_private_key_success
+    // is returned with the signature put in |*out| and the length in
+    // |*out_len|.
+    virtual ssl_private_key_result_t PrivateKeySign(uint8_t* out,
+                                                    size_t* out_len,
+                                                    size_t max_out,
+                                                    uint16_t sig_alg,
+                                                    QuicStringPiece in) = 0;
+
+    // When PrivateKeySign returns ssl_private_key_retry, PrivateKeyComplete
+    // will be called after the async sign operation has completed.
+    // PrivateKeyComplete puts the resulting signature in |*out| and length in
+    // |*out_len|. If the length is greater than |max_out| or if there was an
+    // error in signing, then ssl_private_key_failure is returned. Otherwise,
+    // ssl_private_key_success is returned.
+    virtual ssl_private_key_result_t PrivateKeyComplete(uint8_t* out,
+                                                        size_t* out_len,
+                                                        size_t max_out) = 0;
+
+    // Provides the delegate for callbacks that are shared between client and
+    // server.
+    virtual TlsConnection::Delegate* ConnectionDelegate() = 0;
+
+    friend class TlsServerConnection;
+  };
+
+  TlsServerConnection(SSL_CTX* ssl_ctx, Delegate* delegate);
+
+  // Creates and configures an SSL_CTX that is appropriate for servers to use.
+  static bssl::UniquePtr<SSL_CTX> CreateSslCtx();
+
+  void SetCertChain(const std::vector<CRYPTO_BUFFER*>& cert_chain);
+
+ private:
+  // Specialization of TlsConnection::ConnectionFromSsl.
+  static TlsServerConnection* ConnectionFromSsl(SSL* ssl);
+
+  // These functions are registered as callbacks in BoringSSL and delegate their
+  // implementation to the matching methods in Delegate above.
+  static int SelectCertificateCallback(SSL* ssl, int* out_alert, void* arg);
+  static int SelectAlpnCallback(SSL* ssl,
+                                const uint8_t** out,
+                                uint8_t* out_len,
+                                const uint8_t* in,
+                                unsigned in_len,
+                                void* arg);
+
+  // |kPrivateKeyMethod| is a vtable pointing to PrivateKeySign and
+  // PrivateKeyComplete used by the TLS stack to compute the signature for the
+  // CertificateVerify message (using the server's private key).
+  static const SSL_PRIVATE_KEY_METHOD kPrivateKeyMethod;
+
+  // The following functions make up the contents of |kPrivateKeyMethod|.
+  static ssl_private_key_result_t PrivateKeySign(SSL* ssl,
+                                                 uint8_t* out,
+                                                 size_t* out_len,
+                                                 size_t max_out,
+                                                 uint16_t sig_alg,
+                                                 const uint8_t* in,
+                                                 size_t in_len);
+  static ssl_private_key_result_t PrivateKeyComplete(SSL* ssl,
+                                                     uint8_t* out,
+                                                     size_t* out_len,
+                                                     size_t max_out);
+
+  Delegate* delegate_;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_CRYPTO_TLS_SERVER_CONNECTION_H_