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_