Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 1 | /* Copyright (c) 2016, Google Inc. |
| 2 | * |
| 3 | * Permission to use, copy, modify, and/or distribute this software for any |
| 4 | * purpose with or without fee is hereby granted, provided that the above |
| 5 | * copyright notice and this permission notice appear in all copies. |
| 6 | * |
| 7 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 8 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 9 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
| 10 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 11 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
| 12 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
| 13 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ |
| 14 | |
| 15 | #include <openssl/ssl.h> |
| 16 | |
| 17 | #include <assert.h> |
| 18 | #include <string.h> |
| 19 | |
David Benjamin | e530ea3 | 2019-08-16 19:28:00 -0400 | [diff] [blame] | 20 | #include <algorithm> |
David Benjamin | cfc11c2 | 2017-07-18 22:45:18 -0400 | [diff] [blame] | 21 | #include <utility> |
| 22 | |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 23 | #include <openssl/aead.h> |
| 24 | #include <openssl/bytestring.h> |
| 25 | #include <openssl/digest.h> |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 26 | #include <openssl/hkdf.h> |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 27 | #include <openssl/hmac.h> |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 28 | #include <openssl/mem.h> |
| 29 | |
Adam Langley | 480344d | 2023-04-13 02:09:12 +0000 | [diff] [blame] | 30 | #include "../crypto/fipsmodule/tls/internal.h" |
David Benjamin | 17cf2cb | 2016-12-13 01:07:13 -0500 | [diff] [blame] | 31 | #include "../crypto/internal.h" |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 32 | #include "internal.h" |
| 33 | |
| 34 | |
Joshua Liebow-Feeser | 8c7c635 | 2018-08-26 18:53:36 -0700 | [diff] [blame] | 35 | BSSL_NAMESPACE_BEGIN |
David Benjamin | 86e95b8 | 2017-07-18 16:34:25 -0400 | [diff] [blame] | 36 | |
David Benjamin | 83a4993 | 2021-05-20 15:57:09 -0400 | [diff] [blame] | 37 | static bool init_key_schedule(SSL_HANDSHAKE *hs, SSLTranscript *transcript, |
| 38 | uint16_t version, const SSL_CIPHER *cipher) { |
| 39 | if (!transcript->InitHash(version, cipher)) { |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 40 | return false; |
Steven Valdez | 908ac19 | 2017-01-12 13:17:07 -0500 | [diff] [blame] | 41 | } |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 42 | |
David Benjamin | c11ea942 | 2017-08-29 16:33:21 -0400 | [diff] [blame] | 43 | // Initialize the secret to the zero key. |
David Benjamin | 83a4993 | 2021-05-20 15:57:09 -0400 | [diff] [blame] | 44 | hs->ResizeSecrets(transcript->DigestLen()); |
David Benjamin | e530ea3 | 2019-08-16 19:28:00 -0400 | [diff] [blame] | 45 | OPENSSL_memset(hs->secret().data(), 0, hs->secret().size()); |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 46 | |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 47 | return true; |
Steven Valdez | 2d85062 | 2017-01-11 11:34:52 -0500 | [diff] [blame] | 48 | } |
| 49 | |
David Benjamin | 83a4993 | 2021-05-20 15:57:09 -0400 | [diff] [blame] | 50 | static bool hkdf_extract_to_secret(SSL_HANDSHAKE *hs, |
| 51 | const SSLTranscript &transcript, |
| 52 | Span<const uint8_t> in) { |
David Benjamin | e530ea3 | 2019-08-16 19:28:00 -0400 | [diff] [blame] | 53 | size_t len; |
David Benjamin | 83a4993 | 2021-05-20 15:57:09 -0400 | [diff] [blame] | 54 | if (!HKDF_extract(hs->secret().data(), &len, transcript.Digest(), in.data(), |
| 55 | in.size(), hs->secret().data(), hs->secret().size())) { |
David Benjamin | e530ea3 | 2019-08-16 19:28:00 -0400 | [diff] [blame] | 56 | return false; |
| 57 | } |
| 58 | assert(len == hs->secret().size()); |
| 59 | return true; |
| 60 | } |
| 61 | |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 62 | bool tls13_init_key_schedule(SSL_HANDSHAKE *hs, Span<const uint8_t> psk) { |
David Benjamin | 83a4993 | 2021-05-20 15:57:09 -0400 | [diff] [blame] | 63 | if (!init_key_schedule(hs, &hs->transcript, ssl_protocol_version(hs->ssl), |
| 64 | hs->new_cipher)) { |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 65 | return false; |
Steven Valdez | 2d85062 | 2017-01-11 11:34:52 -0500 | [diff] [blame] | 66 | } |
| 67 | |
Matthew Braithwaite | cc0c286 | 2019-11-26 18:00:21 -0800 | [diff] [blame] | 68 | // Handback includes the whole handshake transcript, so we cannot free the |
| 69 | // transcript buffer in the handback case. |
| 70 | if (!hs->handback) { |
| 71 | hs->transcript.FreeBuffer(); |
| 72 | } |
David Benjamin | 83a4993 | 2021-05-20 15:57:09 -0400 | [diff] [blame] | 73 | return hkdf_extract_to_secret(hs, hs->transcript, psk); |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 74 | } |
| 75 | |
David Benjamin | 83a4993 | 2021-05-20 15:57:09 -0400 | [diff] [blame] | 76 | bool tls13_init_early_key_schedule(SSL_HANDSHAKE *hs, |
| 77 | const SSL_SESSION *session) { |
| 78 | assert(!hs->ssl->server); |
| 79 | // When offering ECH, early data is associated with ClientHelloInner, not |
| 80 | // ClientHelloOuter. |
| 81 | SSLTranscript *transcript = |
| 82 | hs->selected_ech_config ? &hs->inner_transcript : &hs->transcript; |
| 83 | return init_key_schedule(hs, transcript, |
| 84 | ssl_session_protocol_version(session), |
| 85 | session->cipher) && |
| 86 | hkdf_extract_to_secret( |
| 87 | hs, *transcript, |
| 88 | MakeConstSpan(session->secret, session->secret_length)); |
Steven Valdez | 2d85062 | 2017-01-11 11:34:52 -0500 | [diff] [blame] | 89 | } |
| 90 | |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 91 | static Span<const char> label_to_span(const char *label) { |
| 92 | return MakeConstSpan(label, strlen(label)); |
| 93 | } |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 94 | |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 95 | static bool hkdf_expand_label(Span<uint8_t> out, const EVP_MD *digest, |
| 96 | Span<const uint8_t> secret, |
| 97 | Span<const char> label, |
| 98 | Span<const uint8_t> hash) { |
Adam Langley | 480344d | 2023-04-13 02:09:12 +0000 | [diff] [blame] | 99 | return CRYPTO_tls13_hkdf_expand_label( |
| 100 | out.data(), out.size(), digest, secret.data(), secret.size(), |
| 101 | reinterpret_cast<const uint8_t *>(label.data()), label.size(), |
| 102 | hash.data(), hash.size()) == 1; |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 103 | } |
| 104 | |
Steven Valdez | cd8470f | 2017-10-11 12:29:36 -0400 | [diff] [blame] | 105 | static const char kTLS13LabelDerived[] = "derived"; |
| 106 | |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 107 | bool tls13_advance_key_schedule(SSL_HANDSHAKE *hs, Span<const uint8_t> in) { |
Steven Valdez | 7e5dd25 | 2018-01-22 15:20:31 -0500 | [diff] [blame] | 108 | uint8_t derive_context[EVP_MAX_MD_SIZE]; |
| 109 | unsigned derive_context_len; |
David Benjamin | e530ea3 | 2019-08-16 19:28:00 -0400 | [diff] [blame] | 110 | return EVP_Digest(nullptr, 0, derive_context, &derive_context_len, |
| 111 | hs->transcript.Digest(), nullptr) && |
| 112 | hkdf_expand_label(hs->secret(), hs->transcript.Digest(), hs->secret(), |
| 113 | label_to_span(kTLS13LabelDerived), |
| 114 | MakeConstSpan(derive_context, derive_context_len)) && |
David Benjamin | 83a4993 | 2021-05-20 15:57:09 -0400 | [diff] [blame] | 115 | hkdf_extract_to_secret(hs, hs->transcript, in); |
Steven Valdez | cd8470f | 2017-10-11 12:29:36 -0400 | [diff] [blame] | 116 | } |
| 117 | |
David Benjamin | 83a4993 | 2021-05-20 15:57:09 -0400 | [diff] [blame] | 118 | // derive_secret_with_transcript derives a secret of length |out.size()| and |
| 119 | // writes the result in |out| with the given label, the current base secret, and |
| 120 | // the state of |transcript|. It returns true on success and false on error. |
| 121 | static bool derive_secret_with_transcript(const SSL_HANDSHAKE *hs, |
| 122 | Span<uint8_t> out, |
| 123 | const SSLTranscript &transcript, |
| 124 | Span<const char> label) { |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 125 | uint8_t context_hash[EVP_MAX_MD_SIZE]; |
| 126 | size_t context_hash_len; |
David Benjamin | 83a4993 | 2021-05-20 15:57:09 -0400 | [diff] [blame] | 127 | if (!transcript.GetHash(context_hash, &context_hash_len)) { |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 128 | return false; |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 129 | } |
| 130 | |
David Benjamin | 83a4993 | 2021-05-20 15:57:09 -0400 | [diff] [blame] | 131 | return hkdf_expand_label(out, transcript.Digest(), hs->secret(), label, |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 132 | MakeConstSpan(context_hash, context_hash_len)); |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 133 | } |
| 134 | |
David Benjamin | 83a4993 | 2021-05-20 15:57:09 -0400 | [diff] [blame] | 135 | static bool derive_secret(SSL_HANDSHAKE *hs, Span<uint8_t> out, |
| 136 | Span<const char> label) { |
| 137 | return derive_secret_with_transcript(hs, out, hs->transcript, label); |
| 138 | } |
| 139 | |
Steven Valdez | c8e0f90 | 2018-07-14 11:23:01 -0400 | [diff] [blame] | 140 | bool tls13_set_traffic_key(SSL *ssl, enum ssl_encryption_level_t level, |
| 141 | enum evp_aead_direction_t direction, |
David Benjamin | 754d4c9 | 2020-02-11 16:27:21 -0500 | [diff] [blame] | 142 | const SSL_SESSION *session, |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 143 | Span<const uint8_t> traffic_secret) { |
David Benjamin | a4bafd3 | 2017-10-03 15:06:29 -0400 | [diff] [blame] | 144 | uint16_t version = ssl_session_protocol_version(session); |
Steven Valdez | c8e0f90 | 2018-07-14 11:23:01 -0400 | [diff] [blame] | 145 | UniquePtr<SSLAEADContext> traffic_aead; |
David Benjamin | 5298ef9 | 2020-03-13 12:17:30 -0400 | [diff] [blame] | 146 | Span<const uint8_t> secret_for_quic; |
David Benjamin | 1e85905 | 2020-02-09 16:04:58 -0500 | [diff] [blame] | 147 | if (ssl->quic_method != nullptr) { |
David Benjamin | 1e85905 | 2020-02-09 16:04:58 -0500 | [diff] [blame] | 148 | // Install a placeholder SSLAEADContext so that SSL accessors work. The |
| 149 | // encryption itself will be handled by the SSL_QUIC_METHOD. |
| 150 | traffic_aead = |
| 151 | SSLAEADContext::CreatePlaceholderForQUIC(version, session->cipher); |
David Benjamin | 5298ef9 | 2020-03-13 12:17:30 -0400 | [diff] [blame] | 152 | secret_for_quic = traffic_secret; |
David Benjamin | 1e85905 | 2020-02-09 16:04:58 -0500 | [diff] [blame] | 153 | } else { |
Steven Valdez | c8e0f90 | 2018-07-14 11:23:01 -0400 | [diff] [blame] | 154 | // Look up cipher suite properties. |
| 155 | const EVP_AEAD *aead; |
| 156 | size_t discard; |
| 157 | if (!ssl_cipher_get_evp_aead(&aead, &discard, &discard, session->cipher, |
| 158 | version, SSL_is_dtls(ssl))) { |
| 159 | return false; |
| 160 | } |
| 161 | |
| 162 | const EVP_MD *digest = ssl_session_get_digest(session); |
| 163 | |
| 164 | // Derive the key. |
| 165 | size_t key_len = EVP_AEAD_key_length(aead); |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 166 | uint8_t key_buf[EVP_AEAD_MAX_KEY_LENGTH]; |
| 167 | auto key = MakeSpan(key_buf, key_len); |
| 168 | if (!hkdf_expand_label(key, digest, traffic_secret, label_to_span("key"), |
| 169 | {})) { |
Steven Valdez | c8e0f90 | 2018-07-14 11:23:01 -0400 | [diff] [blame] | 170 | return false; |
| 171 | } |
| 172 | |
| 173 | // Derive the IV. |
| 174 | size_t iv_len = EVP_AEAD_nonce_length(aead); |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 175 | uint8_t iv_buf[EVP_AEAD_MAX_NONCE_LENGTH]; |
| 176 | auto iv = MakeSpan(iv_buf, iv_len); |
| 177 | if (!hkdf_expand_label(iv, digest, traffic_secret, label_to_span("iv"), |
| 178 | {})) { |
Steven Valdez | c8e0f90 | 2018-07-14 11:23:01 -0400 | [diff] [blame] | 179 | return false; |
| 180 | } |
| 181 | |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 182 | traffic_aead = SSLAEADContext::Create(direction, session->ssl_version, |
| 183 | SSL_is_dtls(ssl), session->cipher, |
| 184 | key, Span<const uint8_t>(), iv); |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 185 | } |
| 186 | |
David Benjamin | cfc11c2 | 2017-07-18 22:45:18 -0400 | [diff] [blame] | 187 | if (!traffic_aead) { |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 188 | return false; |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 189 | } |
| 190 | |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 191 | if (traffic_secret.size() > |
| 192 | OPENSSL_ARRAY_SIZE(ssl->s3->read_traffic_secret) || |
| 193 | traffic_secret.size() > |
| 194 | OPENSSL_ARRAY_SIZE(ssl->s3->write_traffic_secret)) { |
| 195 | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); |
| 196 | return false; |
| 197 | } |
David Benjamin | b092192 | 2020-02-20 12:33:28 -0500 | [diff] [blame] | 198 | |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 199 | if (direction == evp_aead_open) { |
David Benjamin | 5298ef9 | 2020-03-13 12:17:30 -0400 | [diff] [blame] | 200 | if (!ssl->method->set_read_state(ssl, level, std::move(traffic_aead), |
| 201 | secret_for_quic)) { |
David Benjamin | b092192 | 2020-02-20 12:33:28 -0500 | [diff] [blame] | 202 | return false; |
| 203 | } |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 204 | OPENSSL_memmove(ssl->s3->read_traffic_secret, traffic_secret.data(), |
| 205 | traffic_secret.size()); |
| 206 | ssl->s3->read_traffic_secret_len = traffic_secret.size(); |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 207 | } else { |
David Benjamin | 5298ef9 | 2020-03-13 12:17:30 -0400 | [diff] [blame] | 208 | if (!ssl->method->set_write_state(ssl, level, std::move(traffic_aead), |
| 209 | secret_for_quic)) { |
David Benjamin | b092192 | 2020-02-20 12:33:28 -0500 | [diff] [blame] | 210 | return false; |
| 211 | } |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 212 | OPENSSL_memmove(ssl->s3->write_traffic_secret, traffic_secret.data(), |
| 213 | traffic_secret.size()); |
| 214 | ssl->s3->write_traffic_secret_len = traffic_secret.size(); |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 215 | } |
| 216 | |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 217 | return true; |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 218 | } |
| 219 | |
Steven Valdez | 2d85062 | 2017-01-11 11:34:52 -0500 | [diff] [blame] | 220 | |
Steven Valdez | 7e5dd25 | 2018-01-22 15:20:31 -0500 | [diff] [blame] | 221 | static const char kTLS13LabelExporter[] = "exp master"; |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 222 | |
Steven Valdez | 7e5dd25 | 2018-01-22 15:20:31 -0500 | [diff] [blame] | 223 | static const char kTLS13LabelClientEarlyTraffic[] = "c e traffic"; |
| 224 | static const char kTLS13LabelClientHandshakeTraffic[] = "c hs traffic"; |
| 225 | static const char kTLS13LabelServerHandshakeTraffic[] = "s hs traffic"; |
| 226 | static const char kTLS13LabelClientApplicationTraffic[] = "c ap traffic"; |
| 227 | static const char kTLS13LabelServerApplicationTraffic[] = "s ap traffic"; |
Steven Valdez | cd8470f | 2017-10-11 12:29:36 -0400 | [diff] [blame] | 228 | |
David Benjamin | d634357 | 2019-08-15 17:29:02 -0400 | [diff] [blame] | 229 | bool tls13_derive_early_secret(SSL_HANDSHAKE *hs) { |
Steven Valdez | 2d85062 | 2017-01-11 11:34:52 -0500 | [diff] [blame] | 230 | SSL *const ssl = hs->ssl; |
David Benjamin | 83a4993 | 2021-05-20 15:57:09 -0400 | [diff] [blame] | 231 | // When offering ECH on the client, early data is associated with |
| 232 | // ClientHelloInner, not ClientHelloOuter. |
| 233 | const SSLTranscript &transcript = (!ssl->server && hs->selected_ech_config) |
| 234 | ? hs->inner_transcript |
| 235 | : hs->transcript; |
| 236 | if (!derive_secret_with_transcript( |
| 237 | hs, hs->early_traffic_secret(), transcript, |
| 238 | label_to_span(kTLS13LabelClientEarlyTraffic)) || |
David Benjamin | 650d8c3 | 2017-12-08 17:05:06 -0500 | [diff] [blame] | 239 | !ssl_log_secret(ssl, "CLIENT_EARLY_TRAFFIC_SECRET", |
David Benjamin | e530ea3 | 2019-08-16 19:28:00 -0400 | [diff] [blame] | 240 | hs->early_traffic_secret())) { |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 241 | return false; |
David Benjamin | 650d8c3 | 2017-12-08 17:05:06 -0500 | [diff] [blame] | 242 | } |
David Benjamin | d634357 | 2019-08-15 17:29:02 -0400 | [diff] [blame] | 243 | return true; |
| 244 | } |
Steven Valdez | c8e0f90 | 2018-07-14 11:23:01 -0400 | [diff] [blame] | 245 | |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 246 | bool tls13_derive_handshake_secrets(SSL_HANDSHAKE *hs) { |
David Benjamin | 6e4fc33 | 2016-11-17 16:43:08 +0900 | [diff] [blame] | 247 | SSL *const ssl = hs->ssl; |
David Benjamin | e530ea3 | 2019-08-16 19:28:00 -0400 | [diff] [blame] | 248 | if (!derive_secret(hs, hs->client_handshake_secret(), |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 249 | label_to_span(kTLS13LabelClientHandshakeTraffic)) || |
David Benjamin | e530ea3 | 2019-08-16 19:28:00 -0400 | [diff] [blame] | 250 | !ssl_log_secret(ssl, "CLIENT_HANDSHAKE_TRAFFIC_SECRET", |
| 251 | hs->client_handshake_secret()) || |
| 252 | !derive_secret(hs, hs->server_handshake_secret(), |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 253 | label_to_span(kTLS13LabelServerHandshakeTraffic)) || |
David Benjamin | e530ea3 | 2019-08-16 19:28:00 -0400 | [diff] [blame] | 254 | !ssl_log_secret(ssl, "SERVER_HANDSHAKE_TRAFFIC_SECRET", |
David Benjamin | 1e85905 | 2020-02-09 16:04:58 -0500 | [diff] [blame] | 255 | hs->server_handshake_secret())) { |
Steven Valdez | c8e0f90 | 2018-07-14 11:23:01 -0400 | [diff] [blame] | 256 | return false; |
| 257 | } |
| 258 | |
Steven Valdez | c8e0f90 | 2018-07-14 11:23:01 -0400 | [diff] [blame] | 259 | return true; |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 260 | } |
| 261 | |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 262 | bool tls13_derive_application_secrets(SSL_HANDSHAKE *hs) { |
David Benjamin | 6e4fc33 | 2016-11-17 16:43:08 +0900 | [diff] [blame] | 263 | SSL *const ssl = hs->ssl; |
David Benjamin | e530ea3 | 2019-08-16 19:28:00 -0400 | [diff] [blame] | 264 | ssl->s3->exporter_secret_len = hs->transcript.DigestLen(); |
| 265 | if (!derive_secret(hs, hs->client_traffic_secret_0(), |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 266 | label_to_span(kTLS13LabelClientApplicationTraffic)) || |
David Benjamin | e530ea3 | 2019-08-16 19:28:00 -0400 | [diff] [blame] | 267 | !ssl_log_secret(ssl, "CLIENT_TRAFFIC_SECRET_0", |
| 268 | hs->client_traffic_secret_0()) || |
| 269 | !derive_secret(hs, hs->server_traffic_secret_0(), |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 270 | label_to_span(kTLS13LabelServerApplicationTraffic)) || |
David Benjamin | e530ea3 | 2019-08-16 19:28:00 -0400 | [diff] [blame] | 271 | !ssl_log_secret(ssl, "SERVER_TRAFFIC_SECRET_0", |
| 272 | hs->server_traffic_secret_0()) || |
David Benjamin | b244e3a | 2019-08-16 19:33:15 -0400 | [diff] [blame] | 273 | !derive_secret( |
| 274 | hs, MakeSpan(ssl->s3->exporter_secret, ssl->s3->exporter_secret_len), |
| 275 | label_to_span(kTLS13LabelExporter)) || |
| 276 | !ssl_log_secret(ssl, "EXPORTER_SECRET", |
| 277 | MakeConstSpan(ssl->s3->exporter_secret, |
David Benjamin | 1e85905 | 2020-02-09 16:04:58 -0500 | [diff] [blame] | 278 | ssl->s3->exporter_secret_len))) { |
Steven Valdez | c8e0f90 | 2018-07-14 11:23:01 -0400 | [diff] [blame] | 279 | return false; |
| 280 | } |
| 281 | |
Steven Valdez | c8e0f90 | 2018-07-14 11:23:01 -0400 | [diff] [blame] | 282 | return true; |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 283 | } |
| 284 | |
Steven Valdez | 7e5dd25 | 2018-01-22 15:20:31 -0500 | [diff] [blame] | 285 | static const char kTLS13LabelApplicationTraffic[] = "traffic upd"; |
Steven Valdez | c4aa727 | 2016-10-03 12:25:56 -0400 | [diff] [blame] | 286 | |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 287 | bool tls13_rotate_traffic_key(SSL *ssl, enum evp_aead_direction_t direction) { |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 288 | Span<uint8_t> secret; |
Steven Valdez | 1dc53d2 | 2016-07-26 12:27:38 -0400 | [diff] [blame] | 289 | if (direction == evp_aead_open) { |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 290 | secret = MakeSpan(ssl->s3->read_traffic_secret, |
| 291 | ssl->s3->read_traffic_secret_len); |
Steven Valdez | 1dc53d2 | 2016-07-26 12:27:38 -0400 | [diff] [blame] | 292 | } else { |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 293 | secret = MakeSpan(ssl->s3->write_traffic_secret, |
| 294 | ssl->s3->write_traffic_secret_len); |
Steven Valdez | 1dc53d2 | 2016-07-26 12:27:38 -0400 | [diff] [blame] | 295 | } |
| 296 | |
David Benjamin | 754d4c9 | 2020-02-11 16:27:21 -0500 | [diff] [blame] | 297 | const SSL_SESSION *session = SSL_get_session(ssl); |
| 298 | const EVP_MD *digest = ssl_session_get_digest(session); |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 299 | return hkdf_expand_label(secret, digest, secret, |
| 300 | label_to_span(kTLS13LabelApplicationTraffic), {}) && |
| 301 | tls13_set_traffic_key(ssl, ssl_encryption_application, direction, |
David Benjamin | 754d4c9 | 2020-02-11 16:27:21 -0500 | [diff] [blame] | 302 | session, secret); |
Steven Valdez | 1dc53d2 | 2016-07-26 12:27:38 -0400 | [diff] [blame] | 303 | } |
| 304 | |
Steven Valdez | 7e5dd25 | 2018-01-22 15:20:31 -0500 | [diff] [blame] | 305 | static const char kTLS13LabelResumption[] = "res master"; |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 306 | |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 307 | bool tls13_derive_resumption_secret(SSL_HANDSHAKE *hs) { |
David Benjamin | e530ea3 | 2019-08-16 19:28:00 -0400 | [diff] [blame] | 308 | if (hs->transcript.DigestLen() > SSL_MAX_MASTER_KEY_LENGTH) { |
David Benjamin | 3d622e5 | 2016-11-23 12:39:29 -0500 | [diff] [blame] | 309 | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 310 | return false; |
David Benjamin | 3d622e5 | 2016-11-23 12:39:29 -0500 | [diff] [blame] | 311 | } |
David Benjamin | 5351c8b | 2020-11-19 00:25:29 -0500 | [diff] [blame] | 312 | hs->new_session->secret_length = hs->transcript.DigestLen(); |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 313 | return derive_secret( |
David Benjamin | 5351c8b | 2020-11-19 00:25:29 -0500 | [diff] [blame] | 314 | hs, MakeSpan(hs->new_session->secret, hs->new_session->secret_length), |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 315 | label_to_span(kTLS13LabelResumption)); |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 316 | } |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 317 | |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 318 | static const char kTLS13LabelFinished[] = "finished"; |
| 319 | |
David Benjamin | c11ea942 | 2017-08-29 16:33:21 -0400 | [diff] [blame] | 320 | // tls13_verify_data sets |out| to be the HMAC of |context| using a derived |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 321 | // Finished key for both Finished messages and the PSK binder. |out| must have |
| 322 | // space available for |EVP_MAX_MD_SIZE| bytes. |
| 323 | static bool tls13_verify_data(uint8_t *out, size_t *out_len, |
| 324 | const EVP_MD *digest, uint16_t version, |
| 325 | Span<const uint8_t> secret, |
| 326 | Span<const uint8_t> context) { |
| 327 | uint8_t key_buf[EVP_MAX_MD_SIZE]; |
| 328 | auto key = MakeSpan(key_buf, EVP_MD_size(digest)); |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 329 | unsigned len; |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 330 | if (!hkdf_expand_label(key, digest, secret, |
| 331 | label_to_span(kTLS13LabelFinished), {}) || |
| 332 | HMAC(digest, key.data(), key.size(), context.data(), context.size(), out, |
| 333 | &len) == nullptr) { |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 334 | return false; |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 335 | } |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 336 | *out_len = len; |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 337 | return true; |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 338 | } |
| 339 | |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 340 | bool tls13_finished_mac(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len, |
| 341 | bool is_server) { |
David Benjamin | e530ea3 | 2019-08-16 19:28:00 -0400 | [diff] [blame] | 342 | Span<const uint8_t> traffic_secret = |
| 343 | is_server ? hs->server_handshake_secret() : hs->client_handshake_secret(); |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 344 | |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 345 | uint8_t context_hash[EVP_MAX_MD_SIZE]; |
| 346 | size_t context_hash_len; |
David Benjamin | 6dc8bf6 | 2017-07-19 16:38:21 -0400 | [diff] [blame] | 347 | if (!hs->transcript.GetHash(context_hash, &context_hash_len) || |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 348 | !tls13_verify_data(out, out_len, hs->transcript.Digest(), |
| 349 | hs->ssl->version, traffic_secret, |
| 350 | MakeConstSpan(context_hash, context_hash_len))) { |
Anton Bikineev | 50e7ea5 | 2022-01-23 22:35:48 +0100 | [diff] [blame] | 351 | return false; |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 352 | } |
Anton Bikineev | 50e7ea5 | 2022-01-23 22:35:48 +0100 | [diff] [blame] | 353 | return true; |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 354 | } |
| 355 | |
Steven Valdez | cd8470f | 2017-10-11 12:29:36 -0400 | [diff] [blame] | 356 | static const char kTLS13LabelResumptionPSK[] = "resumption"; |
| 357 | |
Alessandro Ghedini | 2cc6f44 | 2018-12-11 11:35:17 +0000 | [diff] [blame] | 358 | bool tls13_derive_session_psk(SSL_SESSION *session, Span<const uint8_t> nonce) { |
Steven Valdez | cd8470f | 2017-10-11 12:29:36 -0400 | [diff] [blame] | 359 | const EVP_MD *digest = ssl_session_get_digest(session); |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 360 | // The session initially stores the resumption_master_secret, which we |
| 361 | // override with the PSK. |
David Benjamin | 5351c8b | 2020-11-19 00:25:29 -0500 | [diff] [blame] | 362 | auto session_secret = MakeSpan(session->secret, session->secret_length); |
| 363 | return hkdf_expand_label(session_secret, digest, session_secret, |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 364 | label_to_span(kTLS13LabelResumptionPSK), nonce); |
Steven Valdez | cd8470f | 2017-10-11 12:29:36 -0400 | [diff] [blame] | 365 | } |
| 366 | |
| 367 | static const char kTLS13LabelExportKeying[] = "exporter"; |
| 368 | |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 369 | bool tls13_export_keying_material(SSL *ssl, Span<uint8_t> out, |
| 370 | Span<const uint8_t> secret, |
| 371 | Span<const char> label, |
| 372 | Span<const uint8_t> context) { |
David Benjamin | 650d8c3 | 2017-12-08 17:05:06 -0500 | [diff] [blame] | 373 | if (secret.empty()) { |
| 374 | assert(0); |
| 375 | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 376 | return false; |
Steven Valdez | cd8470f | 2017-10-11 12:29:36 -0400 | [diff] [blame] | 377 | } |
| 378 | |
David Benjamin | a4bafd3 | 2017-10-03 15:06:29 -0400 | [diff] [blame] | 379 | const EVP_MD *digest = ssl_session_get_digest(SSL_get_session(ssl)); |
Steven Valdez | cd8470f | 2017-10-11 12:29:36 -0400 | [diff] [blame] | 380 | |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 381 | uint8_t hash_buf[EVP_MAX_MD_SIZE]; |
| 382 | uint8_t export_context_buf[EVP_MAX_MD_SIZE]; |
Steven Valdez | cd8470f | 2017-10-11 12:29:36 -0400 | [diff] [blame] | 383 | unsigned hash_len; |
| 384 | unsigned export_context_len; |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 385 | if (!EVP_Digest(context.data(), context.size(), hash_buf, &hash_len, digest, |
| 386 | nullptr) || |
| 387 | !EVP_Digest(nullptr, 0, export_context_buf, &export_context_len, digest, |
| 388 | nullptr)) { |
| 389 | return false; |
| 390 | } |
| 391 | |
| 392 | auto hash = MakeConstSpan(hash_buf, hash_len); |
| 393 | auto export_context = MakeConstSpan(export_context_buf, export_context_len); |
| 394 | uint8_t derived_secret_buf[EVP_MAX_MD_SIZE]; |
| 395 | auto derived_secret = MakeSpan(derived_secret_buf, EVP_MD_size(digest)); |
| 396 | return hkdf_expand_label(derived_secret, digest, secret, label, |
| 397 | export_context) && |
| 398 | hkdf_expand_label(out, digest, derived_secret, |
| 399 | label_to_span(kTLS13LabelExportKeying), hash); |
Steven Valdez | 143e8b3 | 2016-07-11 13:19:03 -0400 | [diff] [blame] | 400 | } |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 401 | |
Steven Valdez | 7e5dd25 | 2018-01-22 15:20:31 -0500 | [diff] [blame] | 402 | static const char kTLS13LabelPSKBinder[] = "res binder"; |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 403 | |
David Benjamin | b32aa05 | 2021-06-02 17:05:00 -0400 | [diff] [blame] | 404 | static bool tls13_psk_binder(uint8_t *out, size_t *out_len, |
| 405 | const SSL_SESSION *session, |
| 406 | const SSLTranscript &transcript, |
| 407 | Span<const uint8_t> client_hello, |
| 408 | size_t binders_len) { |
| 409 | const EVP_MD *digest = ssl_session_get_digest(session); |
| 410 | |
| 411 | // Compute the binder key. |
| 412 | // |
| 413 | // TODO(davidben): Ideally we wouldn't recompute early secret and the binder |
| 414 | // key each time. |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 415 | uint8_t binder_context[EVP_MAX_MD_SIZE]; |
| 416 | unsigned binder_context_len; |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 417 | uint8_t early_secret[EVP_MAX_MD_SIZE] = {0}; |
| 418 | size_t early_secret_len; |
David Benjamin | b32aa05 | 2021-06-02 17:05:00 -0400 | [diff] [blame] | 419 | uint8_t binder_key_buf[EVP_MAX_MD_SIZE] = {0}; |
| 420 | auto binder_key = MakeSpan(binder_key_buf, EVP_MD_size(digest)); |
| 421 | if (!EVP_Digest(nullptr, 0, binder_context, &binder_context_len, digest, |
| 422 | nullptr) || |
| 423 | !HKDF_extract(early_secret, &early_secret_len, digest, session->secret, |
| 424 | session->secret_length, nullptr, 0) || |
| 425 | !hkdf_expand_label(binder_key, digest, |
| 426 | MakeConstSpan(early_secret, early_secret_len), |
| 427 | label_to_span(kTLS13LabelPSKBinder), |
| 428 | MakeConstSpan(binder_context, binder_context_len))) { |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 429 | return false; |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 430 | } |
| 431 | |
David Benjamin | b32aa05 | 2021-06-02 17:05:00 -0400 | [diff] [blame] | 432 | // Hash the transcript and truncated ClientHello. |
| 433 | if (client_hello.size() < binders_len) { |
| 434 | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); |
| 435 | return false; |
| 436 | } |
| 437 | auto truncated = client_hello.subspan(0, client_hello.size() - binders_len); |
| 438 | uint8_t context[EVP_MAX_MD_SIZE]; |
| 439 | unsigned context_len; |
| 440 | ScopedEVP_MD_CTX ctx; |
| 441 | if (!transcript.CopyToHashContext(ctx.get(), digest) || |
| 442 | !EVP_DigestUpdate(ctx.get(), truncated.data(), |
| 443 | truncated.size()) || |
| 444 | !EVP_DigestFinal_ex(ctx.get(), context, &context_len)) { |
| 445 | return false; |
| 446 | } |
| 447 | |
| 448 | if (!tls13_verify_data(out, out_len, digest, session->ssl_version, binder_key, |
| 449 | MakeConstSpan(context, context_len))) { |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 450 | return false; |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 451 | } |
| 452 | |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 453 | assert(*out_len == EVP_MD_size(digest)); |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 454 | return true; |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 455 | } |
| 456 | |
David Benjamin | b32aa05 | 2021-06-02 17:05:00 -0400 | [diff] [blame] | 457 | bool tls13_write_psk_binder(const SSL_HANDSHAKE *hs, |
David Benjamin | 83a4993 | 2021-05-20 15:57:09 -0400 | [diff] [blame] | 458 | const SSLTranscript &transcript, Span<uint8_t> msg, |
| 459 | size_t *out_binder_len) { |
David Benjamin | b32aa05 | 2021-06-02 17:05:00 -0400 | [diff] [blame] | 460 | const SSL *const ssl = hs->ssl; |
David Benjamin | 50596f8 | 2018-07-02 19:47:27 -0400 | [diff] [blame] | 461 | const EVP_MD *digest = ssl_session_get_digest(ssl->session.get()); |
David Benjamin | b32aa05 | 2021-06-02 17:05:00 -0400 | [diff] [blame] | 462 | const size_t hash_len = EVP_MD_size(digest); |
| 463 | // We only offer one PSK, so the binders are a u16 and u8 length |
| 464 | // prefix, followed by the binder. The caller is assumed to have constructed |
| 465 | // |msg| with placeholder binders. |
| 466 | const size_t binders_len = 3 + hash_len; |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 467 | uint8_t verify_data[EVP_MAX_MD_SIZE]; |
| 468 | size_t verify_data_len; |
David Benjamin | b32aa05 | 2021-06-02 17:05:00 -0400 | [diff] [blame] | 469 | if (!tls13_psk_binder(verify_data, &verify_data_len, ssl->session.get(), |
David Benjamin | 83a4993 | 2021-05-20 15:57:09 -0400 | [diff] [blame] | 470 | transcript, msg, binders_len) || |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 471 | verify_data_len != hash_len) { |
| 472 | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 473 | return false; |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 474 | } |
| 475 | |
David Benjamin | 006f20a | 2021-06-22 23:00:49 -0400 | [diff] [blame] | 476 | auto msg_binder = msg.last(verify_data_len); |
| 477 | OPENSSL_memcpy(msg_binder.data(), verify_data, verify_data_len); |
David Benjamin | 83a4993 | 2021-05-20 15:57:09 -0400 | [diff] [blame] | 478 | if (out_binder_len != nullptr) { |
| 479 | *out_binder_len = verify_data_len; |
| 480 | } |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 481 | return true; |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 482 | } |
| 483 | |
David Benjamin | b32aa05 | 2021-06-02 17:05:00 -0400 | [diff] [blame] | 484 | bool tls13_verify_psk_binder(const SSL_HANDSHAKE *hs, |
| 485 | const SSL_SESSION *session, const SSLMessage &msg, |
| 486 | CBS *binders) { |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 487 | uint8_t verify_data[EVP_MAX_MD_SIZE]; |
| 488 | size_t verify_data_len; |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 489 | CBS binder; |
David Benjamin | b32aa05 | 2021-06-02 17:05:00 -0400 | [diff] [blame] | 490 | // The binders are computed over |msg| with |binders| and its u16 length |
| 491 | // prefix removed. The caller is assumed to have parsed |msg|, extracted |
| 492 | // |binders|, and verified the PSK extension is last. |
| 493 | if (!tls13_psk_binder(verify_data, &verify_data_len, session, hs->transcript, |
| 494 | msg.raw, 2 + CBS_len(binders)) || |
David Benjamin | c11ea942 | 2017-08-29 16:33:21 -0400 | [diff] [blame] | 495 | // We only consider the first PSK, so compare against the first binder. |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 496 | !CBS_get_u8_length_prefixed(binders, &binder)) { |
| 497 | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 498 | return false; |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 499 | } |
| 500 | |
David Benjamin | 79b8b3a | 2019-08-16 18:58:13 -0400 | [diff] [blame] | 501 | bool binder_ok = |
| 502 | CBS_len(&binder) == verify_data_len && |
| 503 | CRYPTO_memcmp(CBS_data(&binder), verify_data, verify_data_len) == 0; |
David Benjamin | 32b47a5 | 2016-11-14 21:19:17 +0900 | [diff] [blame] | 504 | #if defined(BORINGSSL_UNSAFE_FUZZER_MODE) |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 505 | binder_ok = true; |
David Benjamin | 32b47a5 | 2016-11-14 21:19:17 +0900 | [diff] [blame] | 506 | #endif |
| 507 | if (!binder_ok) { |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 508 | OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED); |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 509 | return false; |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 510 | } |
| 511 | |
David Benjamin | 8525ff3 | 2018-09-05 18:44:15 -0500 | [diff] [blame] | 512 | return true; |
Steven Valdez | a833c35 | 2016-11-01 13:39:36 -0400 | [diff] [blame] | 513 | } |
David Benjamin | 86e95b8 | 2017-07-18 16:34:25 -0400 | [diff] [blame] | 514 | |
David Benjamin | 83a4993 | 2021-05-20 15:57:09 -0400 | [diff] [blame] | 515 | size_t ssl_ech_confirmation_signal_hello_offset(const SSL *ssl) { |
| 516 | static_assert(ECH_CONFIRMATION_SIGNAL_LEN < SSL3_RANDOM_SIZE, |
| 517 | "the confirmation signal is a suffix of the random"); |
| 518 | const size_t header_len = |
| 519 | SSL_is_dtls(ssl) ? DTLS1_HM_HEADER_LENGTH : SSL3_HM_HEADER_LENGTH; |
| 520 | return header_len + 2 /* version */ + SSL3_RANDOM_SIZE - |
| 521 | ECH_CONFIRMATION_SIGNAL_LEN; |
| 522 | } |
| 523 | |
David Benjamin | 18b6836 | 2021-06-18 23:13:46 -0400 | [diff] [blame] | 524 | bool ssl_ech_accept_confirmation(const SSL_HANDSHAKE *hs, Span<uint8_t> out, |
| 525 | Span<const uint8_t> client_random, |
| 526 | const SSLTranscript &transcript, bool is_hrr, |
| 527 | Span<const uint8_t> msg, size_t offset) { |
| 528 | // See draft-ietf-tls-esni-13, sections 7.2 and 7.2.1. |
| 529 | static const uint8_t kZeros[EVP_MAX_MD_SIZE] = {0}; |
| 530 | |
| 531 | // We hash |msg|, with bytes from |offset| zeroed. |
| 532 | if (msg.size() < offset + ECH_CONFIRMATION_SIGNAL_LEN) { |
David Benjamin | 83a4993 | 2021-05-20 15:57:09 -0400 | [diff] [blame] | 533 | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); |
| 534 | return false; |
| 535 | } |
| 536 | |
David Benjamin | 18b6836 | 2021-06-18 23:13:46 -0400 | [diff] [blame] | 537 | auto before_zeros = msg.subspan(0, offset); |
| 538 | auto after_zeros = msg.subspan(offset + ECH_CONFIRMATION_SIGNAL_LEN); |
| 539 | uint8_t context[EVP_MAX_MD_SIZE]; |
| 540 | unsigned context_len; |
Dan McArdle | c295935 | 2020-10-29 14:31:31 -0400 | [diff] [blame] | 541 | ScopedEVP_MD_CTX ctx; |
David Benjamin | 83a4993 | 2021-05-20 15:57:09 -0400 | [diff] [blame] | 542 | if (!transcript.CopyToHashContext(ctx.get(), transcript.Digest()) || |
David Benjamin | 18b6836 | 2021-06-18 23:13:46 -0400 | [diff] [blame] | 543 | !EVP_DigestUpdate(ctx.get(), before_zeros.data(), before_zeros.size()) || |
| 544 | !EVP_DigestUpdate(ctx.get(), kZeros, ECH_CONFIRMATION_SIGNAL_LEN) || |
| 545 | !EVP_DigestUpdate(ctx.get(), after_zeros.data(), after_zeros.size()) || |
| 546 | !EVP_DigestFinal_ex(ctx.get(), context, &context_len)) { |
Dan McArdle | c295935 | 2020-10-29 14:31:31 -0400 | [diff] [blame] | 547 | return false; |
| 548 | } |
| 549 | |
David Benjamin | 18b6836 | 2021-06-18 23:13:46 -0400 | [diff] [blame] | 550 | uint8_t secret[EVP_MAX_MD_SIZE]; |
| 551 | size_t secret_len; |
David Benjamin | 19fe794 | 2021-09-02 13:07:24 -0400 | [diff] [blame] | 552 | if (!HKDF_extract(secret, &secret_len, transcript.Digest(), |
| 553 | client_random.data(), client_random.size(), kZeros, |
| 554 | transcript.DigestLen())) { |
Dan McArdle | c295935 | 2020-10-29 14:31:31 -0400 | [diff] [blame] | 555 | return false; |
| 556 | } |
| 557 | |
David Benjamin | 18b6836 | 2021-06-18 23:13:46 -0400 | [diff] [blame] | 558 | assert(out.size() == ECH_CONFIRMATION_SIGNAL_LEN); |
| 559 | return hkdf_expand_label(out, transcript.Digest(), |
| 560 | MakeConstSpan(secret, secret_len), |
| 561 | is_hrr ? label_to_span("hrr ech accept confirmation") |
| 562 | : label_to_span("ech accept confirmation"), |
| 563 | MakeConstSpan(context, context_len)); |
Dan McArdle | c295935 | 2020-10-29 14:31:31 -0400 | [diff] [blame] | 564 | } |
| 565 | |
Joshua Liebow-Feeser | 8c7c635 | 2018-08-26 18:53:36 -0700 | [diff] [blame] | 566 | BSSL_NAMESPACE_END |