nharper | 6ebe83b | 2019-06-13 17:43:52 -0700 | [diff] [blame] | 1 | // Copyright (c) 2019 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "net/third_party/quiche/src/quic/core/crypto/tls_connection.h" |
| 6 | |
| 7 | #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h" |
dmcardle | 904ef18 | 2019-12-13 08:34:33 -0800 | [diff] [blame] | 8 | #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h" |
nharper | 6ebe83b | 2019-06-13 17:43:52 -0700 | [diff] [blame] | 9 | |
| 10 | namespace quic { |
| 11 | |
| 12 | namespace { |
| 13 | |
| 14 | // BoringSSL allows storing extra data off of some of its data structures, |
| 15 | // including the SSL struct. To allow for multiple callers to store data, each |
| 16 | // caller can use a different index for setting and getting data. These indices |
| 17 | // are globals handed out by calling SSL_get_ex_new_index. |
| 18 | // |
| 19 | // SslIndexSingleton calls SSL_get_ex_new_index on its construction, and then |
| 20 | // provides this index to be used in calls to SSL_get_ex_data/SSL_set_ex_data. |
| 21 | // This is used to store in the SSL struct a pointer to the TlsConnection which |
| 22 | // owns it. |
| 23 | class SslIndexSingleton { |
| 24 | public: |
| 25 | static SslIndexSingleton* GetInstance() { |
| 26 | static SslIndexSingleton* instance = new SslIndexSingleton(); |
| 27 | return instance; |
| 28 | } |
| 29 | |
| 30 | int ssl_ex_data_index_connection() const { |
| 31 | return ssl_ex_data_index_connection_; |
| 32 | } |
| 33 | |
| 34 | private: |
| 35 | SslIndexSingleton() { |
| 36 | CRYPTO_library_init(); |
| 37 | ssl_ex_data_index_connection_ = |
| 38 | SSL_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr); |
| 39 | CHECK_LE(0, ssl_ex_data_index_connection_); |
| 40 | } |
| 41 | |
| 42 | SslIndexSingleton(const SslIndexSingleton&) = delete; |
| 43 | SslIndexSingleton& operator=(const SslIndexSingleton&) = delete; |
| 44 | |
| 45 | // The index to supply to SSL_get_ex_data/SSL_set_ex_data for getting/setting |
| 46 | // the TlsConnection pointer. |
| 47 | int ssl_ex_data_index_connection_; |
| 48 | }; |
| 49 | |
| 50 | } // namespace |
| 51 | |
| 52 | // static |
| 53 | EncryptionLevel TlsConnection::QuicEncryptionLevel( |
| 54 | enum ssl_encryption_level_t level) { |
| 55 | switch (level) { |
| 56 | case ssl_encryption_initial: |
| 57 | return ENCRYPTION_INITIAL; |
| 58 | case ssl_encryption_early_data: |
| 59 | return ENCRYPTION_ZERO_RTT; |
| 60 | case ssl_encryption_handshake: |
| 61 | return ENCRYPTION_HANDSHAKE; |
| 62 | case ssl_encryption_application: |
| 63 | return ENCRYPTION_FORWARD_SECURE; |
| 64 | default: |
| 65 | QUIC_BUG << "Invalid ssl_encryption_level_t " << static_cast<int>(level); |
| 66 | return ENCRYPTION_INITIAL; |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | // static |
| 71 | enum ssl_encryption_level_t TlsConnection::BoringEncryptionLevel( |
| 72 | EncryptionLevel level) { |
| 73 | switch (level) { |
| 74 | case ENCRYPTION_INITIAL: |
| 75 | return ssl_encryption_initial; |
| 76 | case ENCRYPTION_HANDSHAKE: |
| 77 | return ssl_encryption_handshake; |
| 78 | case ENCRYPTION_ZERO_RTT: |
| 79 | return ssl_encryption_early_data; |
| 80 | case ENCRYPTION_FORWARD_SECURE: |
| 81 | return ssl_encryption_application; |
| 82 | default: |
| 83 | QUIC_BUG << "Invalid encryption level " << static_cast<int>(level); |
| 84 | return ssl_encryption_initial; |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | TlsConnection::TlsConnection(SSL_CTX* ssl_ctx, |
| 89 | TlsConnection::Delegate* delegate) |
| 90 | : delegate_(delegate), ssl_(SSL_new(ssl_ctx)) { |
| 91 | SSL_set_ex_data( |
| 92 | ssl(), SslIndexSingleton::GetInstance()->ssl_ex_data_index_connection(), |
| 93 | this); |
| 94 | } |
| 95 | // static |
| 96 | bssl::UniquePtr<SSL_CTX> TlsConnection::CreateSslCtx() { |
| 97 | CRYPTO_library_init(); |
| 98 | bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_with_buffers_method())); |
| 99 | SSL_CTX_set_min_proto_version(ssl_ctx.get(), TLS1_3_VERSION); |
| 100 | SSL_CTX_set_max_proto_version(ssl_ctx.get(), TLS1_3_VERSION); |
| 101 | SSL_CTX_set_quic_method(ssl_ctx.get(), &kSslQuicMethod); |
| 102 | return ssl_ctx; |
| 103 | } |
| 104 | |
| 105 | // static |
| 106 | TlsConnection* TlsConnection::ConnectionFromSsl(const SSL* ssl) { |
| 107 | return reinterpret_cast<TlsConnection*>(SSL_get_ex_data( |
| 108 | ssl, SslIndexSingleton::GetInstance()->ssl_ex_data_index_connection())); |
| 109 | } |
| 110 | |
| 111 | const SSL_QUIC_METHOD TlsConnection::kSslQuicMethod{ |
| 112 | TlsConnection::SetEncryptionSecretCallback, |
| 113 | TlsConnection::WriteMessageCallback, TlsConnection::FlushFlightCallback, |
| 114 | TlsConnection::SendAlertCallback}; |
| 115 | |
| 116 | // static |
| 117 | int TlsConnection::SetEncryptionSecretCallback( |
| 118 | SSL* ssl, |
| 119 | enum ssl_encryption_level_t level, |
| 120 | const uint8_t* read_key, |
| 121 | const uint8_t* write_key, |
| 122 | size_t key_length) { |
| 123 | // TODO(nharper): replace these vectors and memcpys with spans (which |
| 124 | // unfortunately doesn't yet exist in quic/platform/api). |
| 125 | std::vector<uint8_t> read_secret(key_length), write_secret(key_length); |
| 126 | memcpy(read_secret.data(), read_key, key_length); |
| 127 | memcpy(write_secret.data(), write_key, key_length); |
fayang | d286652 | 2020-02-12 11:15:27 -0800 | [diff] [blame] | 128 | if (!ConnectionFromSsl(ssl)->delegate_->SetEncryptionSecret( |
| 129 | QuicEncryptionLevel(level), read_secret, write_secret)) { |
| 130 | return 0; |
| 131 | } |
nharper | 6ebe83b | 2019-06-13 17:43:52 -0700 | [diff] [blame] | 132 | return 1; |
| 133 | } |
| 134 | |
| 135 | // static |
| 136 | int TlsConnection::WriteMessageCallback(SSL* ssl, |
| 137 | enum ssl_encryption_level_t level, |
| 138 | const uint8_t* data, |
| 139 | size_t len) { |
| 140 | ConnectionFromSsl(ssl)->delegate_->WriteMessage( |
| 141 | QuicEncryptionLevel(level), |
dmcardle | 904ef18 | 2019-12-13 08:34:33 -0800 | [diff] [blame] | 142 | quiche::QuicheStringPiece(reinterpret_cast<const char*>(data), len)); |
nharper | 6ebe83b | 2019-06-13 17:43:52 -0700 | [diff] [blame] | 143 | return 1; |
| 144 | } |
| 145 | |
| 146 | // static |
| 147 | int TlsConnection::FlushFlightCallback(SSL* ssl) { |
| 148 | ConnectionFromSsl(ssl)->delegate_->FlushFlight(); |
| 149 | return 1; |
| 150 | } |
| 151 | |
| 152 | // static |
| 153 | int TlsConnection::SendAlertCallback(SSL* ssl, |
| 154 | enum ssl_encryption_level_t level, |
| 155 | uint8_t desc) { |
| 156 | ConnectionFromSsl(ssl)->delegate_->SendAlert(QuicEncryptionLevel(level), |
| 157 | desc); |
| 158 | return 1; |
| 159 | } |
| 160 | |
| 161 | } // namespace quic |