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/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