blob: 51602b42daa70110175ed6e85eeeae70acc1c0be [file] [log] [blame] [edit]
// 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_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;
}
}
// static
enum ssl_encryption_level_t TlsHandshaker::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 " << 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));
std::unique_ptr<QuicDecrypter> decrypter = CreateDecrypter(read_secret);
session()->connection()->InstallDecrypter(level, std::move(decrypter));
}
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.
QUIC_DLOG(INFO) << "TLS failing handshake due to alert "
<< static_cast<int>(desc);
CloseConnection(QUIC_HANDSHAKE_FAILED, "TLS handshake failure");
}
} // namespace quic