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