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