Project import generated by Copybara.
PiperOrigin-RevId: 237361882
Change-Id: I109a68f44db867b20f8c6a7732b0ce657133e52a
diff --git a/quic/core/tls_handshaker.cc b/quic/core/tls_handshaker.cc
new file mode 100644
index 0000000..d6207bb
--- /dev/null
+++ b/quic/core/tls_handshaker.cc
@@ -0,0 +1,241 @@
+// Copyright (c) 2017 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/tls_handshaker.h"
+
+#include "third_party/boringssl/src/include/openssl/crypto.h"
+#include "third_party/boringssl/src/include/openssl/ssl.h"
+#include "net/third_party/quiche/src/quic/core/quic_crypto_stream.h"
+#include "net/third_party/quiche/src/quic/core/tls_client_handshaker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_arraysize.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+
+namespace quic {
+
+namespace {
+
+class SslIndexSingleton {
+ public:
+ static SslIndexSingleton* GetInstance() {
+ static SslIndexSingleton* instance = new SslIndexSingleton();
+ return instance;
+ }
+
+ int HandshakerIndex() const { return ssl_ex_data_index_handshaker_; }
+
+ private:
+ SslIndexSingleton() {
+ CRYPTO_library_init();
+ ssl_ex_data_index_handshaker_ =
+ SSL_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
+ CHECK_LE(0, ssl_ex_data_index_handshaker_);
+ }
+
+ SslIndexSingleton(const SslIndexSingleton&) = delete;
+ SslIndexSingleton& operator=(const SslIndexSingleton&) = delete;
+
+ int ssl_ex_data_index_handshaker_;
+};
+
+} // namespace
+
+TlsHandshaker::TlsHandshaker(QuicCryptoStream* stream,
+ QuicSession* session,
+ SSL_CTX* ssl_ctx)
+ : stream_(stream), session_(session) {
+ ssl_.reset(SSL_new(ssl_ctx));
+ SSL_set_ex_data(ssl(), SslIndexSingleton::GetInstance()->HandshakerIndex(),
+ this);
+}
+
+TlsHandshaker::~TlsHandshaker() {}
+
+bool TlsHandshaker::ProcessInput(QuicStringPiece input, EncryptionLevel level) {
+ if (parser_error_ != QUIC_NO_ERROR) {
+ return false;
+ }
+ // TODO(nharper): Call SSL_quic_read_level(ssl()) and check whether the
+ // encryption level BoringSSL expects matches the encryption level that we
+ // just received input at. If they mismatch, should ProcessInput return true
+ // or false? If data is for a future encryption level, it should be queued for
+ // later?
+ if (SSL_provide_quic_data(ssl(), BoringEncryptionLevel(level),
+ reinterpret_cast<const uint8_t*>(input.data()),
+ input.size()) != 1) {
+ // SSL_provide_quic_data can fail for 3 reasons:
+ // - API misuse (calling it before SSL_set_custom_quic_method, which we
+ // call in the TlsHandshaker c'tor)
+ // - Memory exhaustion when appending data to its buffer
+ // - Data provided at the wrong encryption level
+ //
+ // Of these, the only sensible error to handle is data provided at the wrong
+ // encryption level.
+ //
+ // Note: the error provided below has a good-sounding enum value, although
+ // it doesn't match the description as it's a QUIC Crypto specific error.
+ parser_error_ = QUIC_INVALID_CRYPTO_MESSAGE_TYPE;
+ parser_error_detail_ = "TLS stack failed to receive data";
+ return false;
+ }
+ AdvanceHandshake();
+ return true;
+}
+
+// static
+bssl::UniquePtr<SSL_CTX> TlsHandshaker::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
+TlsHandshaker* TlsHandshaker::HandshakerFromSsl(const SSL* ssl) {
+ return reinterpret_cast<TlsHandshaker*>(SSL_get_ex_data(
+ ssl, SslIndexSingleton::GetInstance()->HandshakerIndex()));
+}
+
+// static
+EncryptionLevel TlsHandshaker::QuicEncryptionLevel(
+ enum ssl_encryption_level_t level) {
+ switch (level) {
+ case ssl_encryption_initial:
+ return ENCRYPTION_NONE;
+ case ssl_encryption_early_data:
+ case ssl_encryption_handshake:
+ return ENCRYPTION_ZERO_RTT;
+ case ssl_encryption_application:
+ return ENCRYPTION_FORWARD_SECURE;
+ }
+}
+
+// static
+enum ssl_encryption_level_t TlsHandshaker::BoringEncryptionLevel(
+ EncryptionLevel level) {
+ switch (level) {
+ case ENCRYPTION_NONE:
+ return ssl_encryption_initial;
+ case ENCRYPTION_ZERO_RTT:
+ return ssl_encryption_handshake;
+ case ENCRYPTION_FORWARD_SECURE:
+ return ssl_encryption_application;
+ default:
+ QUIC_BUG << "Invalid encryption level " << level;
+ return ssl_encryption_initial;
+ }
+}
+
+const EVP_MD* TlsHandshaker::Prf() {
+ return EVP_get_digestbynid(
+ SSL_CIPHER_get_prf_nid(SSL_get_pending_cipher(ssl())));
+}
+
+std::unique_ptr<QuicEncrypter> TlsHandshaker::CreateEncrypter(
+ const std::vector<uint8_t>& pp_secret) {
+ std::unique_ptr<QuicEncrypter> encrypter =
+ QuicEncrypter::CreateFromCipherSuite(
+ SSL_CIPHER_get_id(SSL_get_pending_cipher(ssl())));
+ CryptoUtils::SetKeyAndIV(Prf(), pp_secret, encrypter.get());
+ return encrypter;
+}
+
+std::unique_ptr<QuicDecrypter> TlsHandshaker::CreateDecrypter(
+ const std::vector<uint8_t>& pp_secret) {
+ std::unique_ptr<QuicDecrypter> decrypter =
+ QuicDecrypter::CreateFromCipherSuite(
+ SSL_CIPHER_get_id(SSL_get_pending_cipher(ssl())));
+ CryptoUtils::SetKeyAndIV(Prf(), pp_secret, decrypter.get());
+ return decrypter;
+}
+
+const SSL_QUIC_METHOD TlsHandshaker::kSslQuicMethod{
+ TlsHandshaker::SetEncryptionSecretCallback,
+ TlsHandshaker::WriteMessageCallback, TlsHandshaker::FlushFlightCallback,
+ TlsHandshaker::SendAlertCallback};
+
+// static
+int TlsHandshaker::SetEncryptionSecretCallback(
+ SSL* ssl,
+ enum ssl_encryption_level_t level,
+ const uint8_t* read_key,
+ const uint8_t* write_key,
+ size_t secret_len) {
+ // 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(secret_len), write_secret(secret_len);
+ memcpy(read_secret.data(), read_key, secret_len);
+ memcpy(write_secret.data(), write_key, secret_len);
+ HandshakerFromSsl(ssl)->SetEncryptionSecret(QuicEncryptionLevel(level),
+ read_secret, write_secret);
+ return 1;
+}
+
+// static
+int TlsHandshaker::WriteMessageCallback(SSL* ssl,
+ enum ssl_encryption_level_t level,
+ const uint8_t* data,
+ size_t len) {
+ HandshakerFromSsl(ssl)->WriteMessage(
+ QuicEncryptionLevel(level),
+ QuicStringPiece(reinterpret_cast<const char*>(data), len));
+ return 1;
+}
+
+// static
+int TlsHandshaker::FlushFlightCallback(SSL* ssl) {
+ HandshakerFromSsl(ssl)->FlushFlight();
+ return 1;
+}
+
+// static
+int TlsHandshaker::SendAlertCallback(SSL* ssl,
+ enum ssl_encryption_level_t level,
+ uint8_t desc) {
+ HandshakerFromSsl(ssl)->SendAlert(QuicEncryptionLevel(level), desc);
+ return 1;
+}
+
+void TlsHandshaker::SetEncryptionSecret(
+ EncryptionLevel level,
+ const std::vector<uint8_t>& read_secret,
+ const std::vector<uint8_t>& write_secret) {
+ std::unique_ptr<QuicEncrypter> encrypter = CreateEncrypter(write_secret);
+ session()->connection()->SetEncrypter(level, std::move(encrypter));
+ if (level != ENCRYPTION_FORWARD_SECURE) {
+ std::unique_ptr<QuicDecrypter> decrypter = CreateDecrypter(read_secret);
+ session()->connection()->SetDecrypter(level, std::move(decrypter));
+ } else {
+ // When forward-secure read keys are available, they get set as the
+ // alternative decrypter instead of the primary decrypter. One reason for
+ // this is that after the forward secure keys become available, the server
+ // still has crypto handshake messages to read at the handshake encryption
+ // level, meaning that both the ENCRYPTION_ZERO_RTT and
+ // ENCRYPTION_FORWARD_SECURE decrypters need to be available. (Tests also
+ // assume that an alternative decrypter gets set, so at some point we need
+ // to call SetAlternativeDecrypter.)
+ std::unique_ptr<QuicDecrypter> decrypter = CreateDecrypter(read_secret);
+ session()->connection()->SetAlternativeDecrypter(
+ level, std::move(decrypter), /*latch_once_used*/ true);
+ }
+}
+
+void TlsHandshaker::WriteMessage(EncryptionLevel level, QuicStringPiece data) {
+ stream_->WriteCryptoData(level, data);
+}
+
+void TlsHandshaker::FlushFlight() {}
+
+void TlsHandshaker::SendAlert(EncryptionLevel level, uint8_t desc) {
+ // TODO(nharper): Alerts should be sent on the wire as a 16-bit QUIC error
+ // code computed to be 0x100 | desc (draft-ietf-quic-tls-14, section 4.8).
+ // This puts it in the range reserved for CRYPTO_ERROR
+ // (draft-ietf-quic-transport-14, section 11.3). However, according to
+ // quic_error_codes.h, this QUIC implementation only sends 1-byte error codes
+ // right now.
+ CloseConnection(QUIC_HANDSHAKE_FAILED, "TLS handshake failure");
+}
+
+} // namespace quic