/src/boringssl/ssl/encrypted_client_hello.cc
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (c) 2021, 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 | | |
20 | | #include <algorithm> |
21 | | #include <utility> |
22 | | |
23 | | #include <openssl/aead.h> |
24 | | #include <openssl/bytestring.h> |
25 | | #include <openssl/curve25519.h> |
26 | | #include <openssl/err.h> |
27 | | #include <openssl/hkdf.h> |
28 | | #include <openssl/hpke.h> |
29 | | #include <openssl/rand.h> |
30 | | |
31 | | #include "internal.h" |
32 | | |
33 | | |
34 | | BSSL_NAMESPACE_BEGIN |
35 | | |
36 | | // ECH reuses the extension code point for the version number. |
37 | | static constexpr uint16_t kECHConfigVersion = |
38 | | TLSEXT_TYPE_encrypted_client_hello; |
39 | | |
40 | | static const decltype(&EVP_hpke_aes_128_gcm) kSupportedAEADs[] = { |
41 | | &EVP_hpke_aes_128_gcm, |
42 | | &EVP_hpke_aes_256_gcm, |
43 | | &EVP_hpke_chacha20_poly1305, |
44 | | }; |
45 | | |
46 | 1.39k | static const EVP_HPKE_AEAD *get_ech_aead(uint16_t aead_id) { |
47 | 2.86k | for (const auto aead_func : kSupportedAEADs) { |
48 | 2.86k | const EVP_HPKE_AEAD *aead = aead_func(); |
49 | 2.86k | if (aead_id == EVP_HPKE_AEAD_id(aead)) { |
50 | 1.03k | return aead; |
51 | 1.03k | } |
52 | 2.86k | } |
53 | 359 | return nullptr; |
54 | 1.39k | } |
55 | | |
56 | | // ssl_client_hello_write_without_extensions serializes |client_hello| into |
57 | | // |out|, omitting the length-prefixed extensions. It serializes individual |
58 | | // fields, starting with |client_hello->version|, and ignores the |
59 | | // |client_hello->client_hello| field. It returns true on success and false on |
60 | | // failure. |
61 | | static bool ssl_client_hello_write_without_extensions( |
62 | 438 | const SSL_CLIENT_HELLO *client_hello, CBB *out) { |
63 | 438 | CBB cbb; |
64 | 438 | if (!CBB_add_u16(out, client_hello->version) || |
65 | 438 | !CBB_add_bytes(out, client_hello->random, client_hello->random_len) || |
66 | 438 | !CBB_add_u8_length_prefixed(out, &cbb) || |
67 | 438 | !CBB_add_bytes(&cbb, client_hello->session_id, |
68 | 438 | client_hello->session_id_len) || |
69 | 438 | !CBB_add_u16_length_prefixed(out, &cbb) || |
70 | 438 | !CBB_add_bytes(&cbb, client_hello->cipher_suites, |
71 | 438 | client_hello->cipher_suites_len) || |
72 | 438 | !CBB_add_u8_length_prefixed(out, &cbb) || |
73 | 438 | !CBB_add_bytes(&cbb, client_hello->compression_methods, |
74 | 438 | client_hello->compression_methods_len) || |
75 | 438 | !CBB_flush(out)) { |
76 | 0 | return false; |
77 | 0 | } |
78 | 438 | return true; |
79 | 438 | } |
80 | | |
81 | | static bool is_valid_client_hello_inner(SSL *ssl, uint8_t *out_alert, |
82 | 322 | Span<const uint8_t> body) { |
83 | | // See draft-ietf-tls-esni-13, section 7.1. |
84 | 322 | SSL_CLIENT_HELLO client_hello; |
85 | 322 | CBS extension; |
86 | 322 | if (!ssl_client_hello_init(ssl, &client_hello, body) || |
87 | 322 | !ssl_client_hello_get_extension(&client_hello, &extension, |
88 | 318 | TLSEXT_TYPE_encrypted_client_hello) || |
89 | 322 | CBS_len(&extension) != 1 || // |
90 | 322 | CBS_data(&extension)[0] != ECH_CLIENT_INNER || |
91 | 322 | !ssl_client_hello_get_extension(&client_hello, &extension, |
92 | 201 | TLSEXT_TYPE_supported_versions)) { |
93 | 135 | *out_alert = SSL_AD_ILLEGAL_PARAMETER; |
94 | 135 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_CLIENT_HELLO_INNER); |
95 | 135 | return false; |
96 | 135 | } |
97 | | // Parse supported_versions and reject TLS versions prior to TLS 1.3. Older |
98 | | // versions are incompatible with ECH. |
99 | 187 | CBS versions; |
100 | 187 | if (!CBS_get_u8_length_prefixed(&extension, &versions) || |
101 | 187 | CBS_len(&extension) != 0 || // |
102 | 187 | CBS_len(&versions) == 0) { |
103 | 16 | *out_alert = SSL_AD_DECODE_ERROR; |
104 | 16 | OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); |
105 | 16 | return false; |
106 | 16 | } |
107 | 815 | while (CBS_len(&versions) != 0) { |
108 | 679 | uint16_t version; |
109 | 679 | if (!CBS_get_u16(&versions, &version)) { |
110 | 13 | *out_alert = SSL_AD_DECODE_ERROR; |
111 | 13 | OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); |
112 | 13 | return false; |
113 | 13 | } |
114 | 666 | if (version == SSL3_VERSION || version == TLS1_VERSION || |
115 | 666 | version == TLS1_1_VERSION || version == TLS1_2_VERSION || |
116 | 666 | version == DTLS1_VERSION || version == DTLS1_2_VERSION) { |
117 | 22 | *out_alert = SSL_AD_ILLEGAL_PARAMETER; |
118 | 22 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_CLIENT_HELLO_INNER); |
119 | 22 | return false; |
120 | 22 | } |
121 | 666 | } |
122 | 136 | return true; |
123 | 171 | } |
124 | | |
125 | | bool ssl_decode_client_hello_inner( |
126 | | SSL *ssl, uint8_t *out_alert, Array<uint8_t> *out_client_hello_inner, |
127 | | Span<const uint8_t> encoded_client_hello_inner, |
128 | 633 | const SSL_CLIENT_HELLO *client_hello_outer) { |
129 | 633 | SSL_CLIENT_HELLO client_hello_inner; |
130 | 633 | CBS cbs = encoded_client_hello_inner; |
131 | 633 | if (!ssl_parse_client_hello_with_trailing_data(ssl, &cbs, |
132 | 633 | &client_hello_inner)) { |
133 | 151 | OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); |
134 | 151 | return false; |
135 | 151 | } |
136 | | // The remaining data is padding. |
137 | 482 | uint8_t padding; |
138 | 4.60k | while (CBS_get_u8(&cbs, &padding)) { |
139 | 4.14k | if (padding != 0) { |
140 | 22 | OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); |
141 | 22 | *out_alert = SSL_AD_ILLEGAL_PARAMETER; |
142 | 22 | return false; |
143 | 22 | } |
144 | 4.14k | } |
145 | | |
146 | | // TLS 1.3 ClientHellos must have extensions, and EncodedClientHelloInners use |
147 | | // ClientHelloOuter's session_id. |
148 | 460 | if (client_hello_inner.extensions_len == 0 || |
149 | 460 | client_hello_inner.session_id_len != 0) { |
150 | 22 | OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); |
151 | 22 | return false; |
152 | 22 | } |
153 | 438 | client_hello_inner.session_id = client_hello_outer->session_id; |
154 | 438 | client_hello_inner.session_id_len = client_hello_outer->session_id_len; |
155 | | |
156 | | // Begin serializing a message containing the ClientHelloInner in |cbb|. |
157 | 438 | ScopedCBB cbb; |
158 | 438 | CBB body, extensions_cbb; |
159 | 438 | if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_CLIENT_HELLO) || |
160 | 438 | !ssl_client_hello_write_without_extensions(&client_hello_inner, &body) || |
161 | 438 | !CBB_add_u16_length_prefixed(&body, &extensions_cbb)) { |
162 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); |
163 | 0 | return false; |
164 | 0 | } |
165 | | |
166 | 438 | auto inner_extensions = MakeConstSpan(client_hello_inner.extensions, |
167 | 438 | client_hello_inner.extensions_len); |
168 | 438 | CBS ext_list_wrapper; |
169 | 438 | if (!ssl_client_hello_get_extension(&client_hello_inner, &ext_list_wrapper, |
170 | 438 | TLSEXT_TYPE_ech_outer_extensions)) { |
171 | | // No ech_outer_extensions. Copy everything. |
172 | 296 | if (!CBB_add_bytes(&extensions_cbb, inner_extensions.data(), |
173 | 296 | inner_extensions.size())) { |
174 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); |
175 | 0 | return false; |
176 | 0 | } |
177 | 296 | } else { |
178 | 142 | const size_t offset = CBS_data(&ext_list_wrapper) - inner_extensions.data(); |
179 | 142 | auto inner_extensions_before = |
180 | 142 | inner_extensions.subspan(0, offset - 4 /* extension header */); |
181 | 142 | auto inner_extensions_after = |
182 | 142 | inner_extensions.subspan(offset + CBS_len(&ext_list_wrapper)); |
183 | 142 | if (!CBB_add_bytes(&extensions_cbb, inner_extensions_before.data(), |
184 | 142 | inner_extensions_before.size())) { |
185 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); |
186 | 0 | return false; |
187 | 0 | } |
188 | | |
189 | | // Expand ech_outer_extensions. See draft-ietf-tls-esni-13, Appendix B. |
190 | 142 | CBS ext_list; |
191 | 142 | if (!CBS_get_u8_length_prefixed(&ext_list_wrapper, &ext_list) || |
192 | 142 | CBS_len(&ext_list) == 0 || CBS_len(&ext_list_wrapper) != 0) { |
193 | 53 | OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); |
194 | 53 | return false; |
195 | 53 | } |
196 | 89 | CBS outer_extensions; |
197 | 89 | CBS_init(&outer_extensions, client_hello_outer->extensions, |
198 | 89 | client_hello_outer->extensions_len); |
199 | 176 | while (CBS_len(&ext_list) != 0) { |
200 | | // Find the next extension to copy. |
201 | 150 | uint16_t want; |
202 | 150 | if (!CBS_get_u16(&ext_list, &want)) { |
203 | 2 | OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); |
204 | 2 | return false; |
205 | 2 | } |
206 | | // The ECH extension itself is not in the AAD and may not be referenced. |
207 | 148 | if (want == TLSEXT_TYPE_encrypted_client_hello) { |
208 | 4 | *out_alert = SSL_AD_ILLEGAL_PARAMETER; |
209 | 4 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_OUTER_EXTENSION); |
210 | 4 | return false; |
211 | 4 | } |
212 | | // Seek to |want| in |outer_extensions|. |ext_list| is required to match |
213 | | // ClientHelloOuter in order. |
214 | 144 | uint16_t found; |
215 | 144 | CBS ext_body; |
216 | 314 | do { |
217 | 314 | if (CBS_len(&outer_extensions) == 0) { |
218 | 57 | *out_alert = SSL_AD_ILLEGAL_PARAMETER; |
219 | 57 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_OUTER_EXTENSION); |
220 | 57 | return false; |
221 | 57 | } |
222 | 257 | if (!CBS_get_u16(&outer_extensions, &found) || |
223 | 257 | !CBS_get_u16_length_prefixed(&outer_extensions, &ext_body)) { |
224 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); |
225 | 0 | return false; |
226 | 0 | } |
227 | 257 | } while (found != want); |
228 | | // Copy the extension. |
229 | 87 | if (!CBB_add_u16(&extensions_cbb, found) || |
230 | 87 | !CBB_add_u16(&extensions_cbb, CBS_len(&ext_body)) || |
231 | 87 | !CBB_add_bytes(&extensions_cbb, CBS_data(&ext_body), |
232 | 87 | CBS_len(&ext_body))) { |
233 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); |
234 | 0 | return false; |
235 | 0 | } |
236 | 87 | } |
237 | | |
238 | 26 | if (!CBB_add_bytes(&extensions_cbb, inner_extensions_after.data(), |
239 | 26 | inner_extensions_after.size())) { |
240 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); |
241 | 0 | return false; |
242 | 0 | } |
243 | 26 | } |
244 | 322 | if (!CBB_flush(&body)) { |
245 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); |
246 | 0 | return false; |
247 | 0 | } |
248 | | |
249 | 322 | if (!is_valid_client_hello_inner( |
250 | 322 | ssl, out_alert, MakeConstSpan(CBB_data(&body), CBB_len(&body)))) { |
251 | 186 | return false; |
252 | 186 | } |
253 | | |
254 | 136 | if (!ssl->method->finish_message(ssl, cbb.get(), out_client_hello_inner)) { |
255 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); |
256 | 0 | return false; |
257 | 0 | } |
258 | 136 | return true; |
259 | 136 | } |
260 | | |
261 | | bool ssl_client_hello_decrypt(SSL_HANDSHAKE *hs, uint8_t *out_alert, |
262 | | bool *out_is_decrypt_error, Array<uint8_t> *out, |
263 | | const SSL_CLIENT_HELLO *client_hello_outer, |
264 | 232 | Span<const uint8_t> payload) { |
265 | 232 | *out_is_decrypt_error = false; |
266 | | |
267 | | // The ClientHelloOuterAAD is |client_hello_outer| with |payload| (which must |
268 | | // point within |client_hello_outer->extensions|) replaced with zeros. See |
269 | | // draft-ietf-tls-esni-13, section 5.2. |
270 | 232 | Array<uint8_t> aad; |
271 | 232 | if (!aad.CopyFrom(MakeConstSpan(client_hello_outer->client_hello, |
272 | 232 | client_hello_outer->client_hello_len))) { |
273 | 0 | *out_alert = SSL_AD_INTERNAL_ERROR; |
274 | 0 | return false; |
275 | 0 | } |
276 | | |
277 | | // We assert with |uintptr_t| because the comparison would be UB if they |
278 | | // didn't alias. |
279 | 232 | assert(reinterpret_cast<uintptr_t>(client_hello_outer->extensions) <= |
280 | 232 | reinterpret_cast<uintptr_t>(payload.data())); |
281 | 0 | assert(reinterpret_cast<uintptr_t>(client_hello_outer->extensions + |
282 | 232 | client_hello_outer->extensions_len) >= |
283 | 232 | reinterpret_cast<uintptr_t>(payload.data() + payload.size())); |
284 | 0 | Span<uint8_t> payload_aad = MakeSpan(aad).subspan( |
285 | 232 | payload.data() - client_hello_outer->client_hello, payload.size()); |
286 | 232 | OPENSSL_memset(payload_aad.data(), 0, payload_aad.size()); |
287 | | |
288 | | // Decrypt the EncodedClientHelloInner. |
289 | 232 | Array<uint8_t> encoded; |
290 | 232 | #if defined(BORINGSSL_UNSAFE_FUZZER_MODE) |
291 | | // In fuzzer mode, disable encryption to improve coverage. We reserve a short |
292 | | // input to signal decryption failure, so the fuzzer can explore fallback to |
293 | | // ClientHelloOuter. |
294 | 232 | const uint8_t kBadPayload[] = {0xff}; |
295 | 232 | if (payload == kBadPayload) { |
296 | 14 | *out_alert = SSL_AD_DECRYPT_ERROR; |
297 | 14 | *out_is_decrypt_error = true; |
298 | 14 | OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED); |
299 | 14 | return false; |
300 | 14 | } |
301 | 218 | if (!encoded.CopyFrom(payload)) { |
302 | 0 | *out_alert = SSL_AD_INTERNAL_ERROR; |
303 | 0 | return false; |
304 | 0 | } |
305 | | #else |
306 | | if (!encoded.Init(payload.size())) { |
307 | | *out_alert = SSL_AD_INTERNAL_ERROR; |
308 | | return false; |
309 | | } |
310 | | size_t len; |
311 | | if (!EVP_HPKE_CTX_open(hs->ech_hpke_ctx.get(), encoded.data(), &len, |
312 | | encoded.size(), payload.data(), payload.size(), |
313 | | aad.data(), aad.size())) { |
314 | | *out_alert = SSL_AD_DECRYPT_ERROR; |
315 | | *out_is_decrypt_error = true; |
316 | | OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED); |
317 | | return false; |
318 | | } |
319 | | encoded.Shrink(len); |
320 | | #endif |
321 | | |
322 | 218 | if (!ssl_decode_client_hello_inner(hs->ssl, out_alert, out, encoded, |
323 | 218 | client_hello_outer)) { |
324 | 136 | return false; |
325 | 136 | } |
326 | | |
327 | 82 | ssl_do_msg_callback(hs->ssl, /*is_write=*/0, SSL3_RT_CLIENT_HELLO_INNER, |
328 | 82 | *out); |
329 | 82 | return true; |
330 | 218 | } |
331 | | |
332 | 3.57k | static bool is_hex_component(Span<const uint8_t> in) { |
333 | 3.57k | if (in.size() < 2 || in[0] != '0' || (in[1] != 'x' && in[1] != 'X')) { |
334 | 2.48k | return false; |
335 | 2.48k | } |
336 | 3.51k | for (uint8_t b : in.subspan(2)) { |
337 | 3.51k | if (!OPENSSL_isxdigit(b)) { |
338 | 639 | return false; |
339 | 639 | } |
340 | 3.51k | } |
341 | 456 | return true; |
342 | 1.09k | } |
343 | | |
344 | 3.12k | static bool is_decimal_component(Span<const uint8_t> in) { |
345 | 3.12k | if (in.empty()) { |
346 | 0 | return false; |
347 | 0 | } |
348 | 5.08k | for (uint8_t b : in) { |
349 | 5.08k | if (!('0' <= b && b <= '9')) { |
350 | 2.77k | return false; |
351 | 2.77k | } |
352 | 5.08k | } |
353 | 343 | return true; |
354 | 3.12k | } |
355 | | |
356 | 4.80k | bool ssl_is_valid_ech_public_name(Span<const uint8_t> public_name) { |
357 | | // See draft-ietf-tls-esni-13, Section 4 and RFC 5890, Section 2.3.1. The |
358 | | // public name must be a dot-separated sequence of LDH labels and not begin or |
359 | | // end with a dot. |
360 | 4.80k | auto remaining = public_name; |
361 | 4.80k | if (remaining.empty()) { |
362 | 0 | return false; |
363 | 0 | } |
364 | 4.80k | Span<const uint8_t> last; |
365 | 8.68k | while (!remaining.empty()) { |
366 | | // Find the next dot-separated component. |
367 | 5.10k | auto dot = std::find(remaining.begin(), remaining.end(), '.'); |
368 | 5.10k | Span<const uint8_t> component; |
369 | 5.10k | if (dot == remaining.end()) { |
370 | 4.23k | component = remaining; |
371 | 4.23k | last = component; |
372 | 4.23k | remaining = Span<const uint8_t>(); |
373 | 4.23k | } else { |
374 | 867 | component = remaining.subspan(0, dot - remaining.begin()); |
375 | | // Skip the dot. |
376 | 867 | remaining = remaining.subspan(dot - remaining.begin() + 1); |
377 | 867 | if (remaining.empty()) { |
378 | | // Trailing dots are not allowed. |
379 | 272 | return false; |
380 | 272 | } |
381 | 867 | } |
382 | | // |component| must be a valid LDH label. Checking for empty components also |
383 | | // rejects leading dots. |
384 | 4.83k | if (component.empty() || component.size() > 63 || |
385 | 4.83k | component.front() == '-' || component.back() == '-') { |
386 | 703 | return false; |
387 | 703 | } |
388 | 12.8k | for (uint8_t c : component) { |
389 | 12.8k | if (!OPENSSL_isalnum(c) && c != '-') { |
390 | 252 | return false; |
391 | 252 | } |
392 | 12.8k | } |
393 | 4.12k | } |
394 | | |
395 | | // The WHATWG URL parser additionally does not allow any DNS names that end in |
396 | | // a numeric component. See: |
397 | | // https://url.spec.whatwg.org/#concept-host-parser |
398 | | // https://url.spec.whatwg.org/#ends-in-a-number-checker |
399 | | // |
400 | | // The WHATWG parser is formulated in terms of parsing decimal, octal, and |
401 | | // hex, along with a separate ASCII digits check. The ASCII digits check |
402 | | // subsumes the decimal and octal check, so we only need to check two cases. |
403 | 3.57k | return !is_hex_component(last) && !is_decimal_component(last); |
404 | 4.80k | } |
405 | | |
406 | | static bool parse_ech_config(CBS *cbs, ECHConfig *out, bool *out_supported, |
407 | 11.7k | bool all_extensions_mandatory) { |
408 | 11.7k | uint16_t version; |
409 | 11.7k | CBS orig = *cbs; |
410 | 11.7k | CBS contents; |
411 | 11.7k | if (!CBS_get_u16(cbs, &version) || |
412 | 11.7k | !CBS_get_u16_length_prefixed(cbs, &contents)) { |
413 | 3.96k | OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); |
414 | 3.96k | return false; |
415 | 3.96k | } |
416 | | |
417 | 7.79k | if (version != kECHConfigVersion) { |
418 | 296 | *out_supported = false; |
419 | 296 | return true; |
420 | 296 | } |
421 | | |
422 | | // Make a copy of the ECHConfig and parse from it, so the results alias into |
423 | | // the saved copy. |
424 | 7.49k | if (!out->raw.CopyFrom( |
425 | 7.49k | MakeConstSpan(CBS_data(&orig), CBS_len(&orig) - CBS_len(cbs)))) { |
426 | 0 | return false; |
427 | 0 | } |
428 | | |
429 | 7.49k | CBS ech_config(out->raw); |
430 | 7.49k | CBS public_name, public_key, cipher_suites, extensions; |
431 | 7.49k | if (!CBS_skip(&ech_config, 2) || // version |
432 | 7.49k | !CBS_get_u16_length_prefixed(&ech_config, &contents) || |
433 | 7.49k | !CBS_get_u8(&contents, &out->config_id) || |
434 | 7.49k | !CBS_get_u16(&contents, &out->kem_id) || |
435 | 7.49k | !CBS_get_u16_length_prefixed(&contents, &public_key) || |
436 | 7.49k | CBS_len(&public_key) == 0 || |
437 | 7.49k | !CBS_get_u16_length_prefixed(&contents, &cipher_suites) || |
438 | 7.49k | CBS_len(&cipher_suites) == 0 || CBS_len(&cipher_suites) % 4 != 0 || |
439 | 7.49k | !CBS_get_u8(&contents, &out->maximum_name_length) || |
440 | 7.49k | !CBS_get_u8_length_prefixed(&contents, &public_name) || |
441 | 7.49k | CBS_len(&public_name) == 0 || |
442 | 7.49k | !CBS_get_u16_length_prefixed(&contents, &extensions) || |
443 | 7.49k | CBS_len(&contents) != 0) { |
444 | 2.69k | OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); |
445 | 2.69k | return false; |
446 | 2.69k | } |
447 | | |
448 | 4.80k | if (!ssl_is_valid_ech_public_name(public_name)) { |
449 | | // TODO(https://crbug.com/boringssl/275): The draft says ECHConfigs with |
450 | | // invalid public names should be ignored, but LDH syntax failures are |
451 | | // unambiguously invalid. |
452 | 2.02k | *out_supported = false; |
453 | 2.02k | return true; |
454 | 2.02k | } |
455 | | |
456 | 2.77k | out->public_key = public_key; |
457 | 2.77k | out->public_name = public_name; |
458 | | // This function does not ensure |out->kem_id| and |out->cipher_suites| use |
459 | | // supported algorithms. The caller must do this. |
460 | 2.77k | out->cipher_suites = cipher_suites; |
461 | | |
462 | 2.77k | bool has_unknown_mandatory_extension = false; |
463 | 4.43k | while (CBS_len(&extensions) != 0) { |
464 | 2.56k | uint16_t type; |
465 | 2.56k | CBS body; |
466 | 2.56k | if (!CBS_get_u16(&extensions, &type) || |
467 | 2.56k | !CBS_get_u16_length_prefixed(&extensions, &body)) { |
468 | 905 | OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); |
469 | 905 | return false; |
470 | 905 | } |
471 | | // We currently do not support any extensions. |
472 | 1.66k | if (type & 0x8000 || all_extensions_mandatory) { |
473 | | // Extension numbers with the high bit set are mandatory. Continue parsing |
474 | | // to enforce syntax, but we will ultimately ignore this ECHConfig as a |
475 | | // client and reject it as a server. |
476 | 1.66k | has_unknown_mandatory_extension = true; |
477 | 1.66k | } |
478 | 1.66k | } |
479 | | |
480 | 1.87k | *out_supported = !has_unknown_mandatory_extension; |
481 | 1.87k | return true; |
482 | 2.77k | } |
483 | | |
484 | | bool ECHServerConfig::Init(Span<const uint8_t> ech_config, |
485 | 11.7k | const EVP_HPKE_KEY *key, bool is_retry_config) { |
486 | 11.7k | is_retry_config_ = is_retry_config; |
487 | | |
488 | | // Parse the ECHConfig, rejecting all unsupported parameters and extensions. |
489 | | // Unlike most server options, ECH's server configuration is serialized and |
490 | | // configured in both the server and DNS. If the caller configures an |
491 | | // unsupported parameter, this is a deployment error. To catch these errors, |
492 | | // we fail early. |
493 | 11.7k | CBS cbs = ech_config; |
494 | 11.7k | bool supported; |
495 | 11.7k | if (!parse_ech_config(&cbs, &ech_config_, &supported, |
496 | 11.7k | /*all_extensions_mandatory=*/true)) { |
497 | 7.56k | return false; |
498 | 7.56k | } |
499 | 4.19k | if (CBS_len(&cbs) != 0) { |
500 | 461 | OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); |
501 | 461 | return false; |
502 | 461 | } |
503 | 3.73k | if (!supported) { |
504 | 2.18k | OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_ECH_SERVER_CONFIG); |
505 | 2.18k | return false; |
506 | 2.18k | } |
507 | | |
508 | 1.54k | CBS cipher_suites = ech_config_.cipher_suites; |
509 | 2.10k | while (CBS_len(&cipher_suites) > 0) { |
510 | 1.55k | uint16_t kdf_id, aead_id; |
511 | 1.55k | if (!CBS_get_u16(&cipher_suites, &kdf_id) || |
512 | 1.55k | !CBS_get_u16(&cipher_suites, &aead_id)) { |
513 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); |
514 | 0 | return false; |
515 | 0 | } |
516 | | // The server promises to support every option in the ECHConfig, so reject |
517 | | // any unsupported cipher suites. |
518 | 1.55k | if (kdf_id != EVP_HPKE_HKDF_SHA256 || get_ech_aead(aead_id) == nullptr) { |
519 | 993 | OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_ECH_SERVER_CONFIG); |
520 | 993 | return false; |
521 | 993 | } |
522 | 1.55k | } |
523 | | |
524 | | // Check the public key in the ECHConfig matches |key|. |
525 | 555 | uint8_t expected_public_key[EVP_HPKE_MAX_PUBLIC_KEY_LENGTH]; |
526 | 555 | size_t expected_public_key_len; |
527 | 555 | if (!EVP_HPKE_KEY_public_key(key, expected_public_key, |
528 | 555 | &expected_public_key_len, |
529 | 555 | sizeof(expected_public_key))) { |
530 | 0 | return false; |
531 | 0 | } |
532 | 555 | if (ech_config_.kem_id != EVP_HPKE_KEM_id(EVP_HPKE_KEY_kem(key)) || |
533 | 555 | MakeConstSpan(expected_public_key, expected_public_key_len) != |
534 | 551 | ech_config_.public_key) { |
535 | 551 | OPENSSL_PUT_ERROR(SSL, SSL_R_ECH_SERVER_CONFIG_AND_PRIVATE_KEY_MISMATCH); |
536 | 551 | return false; |
537 | 551 | } |
538 | | |
539 | 4 | if (!EVP_HPKE_KEY_copy(key_.get(), key)) { |
540 | 0 | return false; |
541 | 0 | } |
542 | | |
543 | 4 | return true; |
544 | 4 | } |
545 | | |
546 | | bool ECHServerConfig::SetupContext(EVP_HPKE_CTX *ctx, uint16_t kdf_id, |
547 | | uint16_t aead_id, |
548 | 271 | Span<const uint8_t> enc) const { |
549 | | // Check the cipher suite is supported by this ECHServerConfig. |
550 | 271 | CBS cbs(ech_config_.cipher_suites); |
551 | 271 | bool cipher_ok = false; |
552 | 395 | while (CBS_len(&cbs) != 0) { |
553 | 363 | uint16_t supported_kdf_id, supported_aead_id; |
554 | 363 | if (!CBS_get_u16(&cbs, &supported_kdf_id) || |
555 | 363 | !CBS_get_u16(&cbs, &supported_aead_id)) { |
556 | 0 | return false; |
557 | 0 | } |
558 | 363 | if (kdf_id == supported_kdf_id && aead_id == supported_aead_id) { |
559 | 239 | cipher_ok = true; |
560 | 239 | break; |
561 | 239 | } |
562 | 363 | } |
563 | 271 | if (!cipher_ok) { |
564 | 32 | return false; |
565 | 32 | } |
566 | | |
567 | 239 | static const uint8_t kInfoLabel[] = "tls ech"; |
568 | 239 | ScopedCBB info_cbb; |
569 | 239 | if (!CBB_init(info_cbb.get(), sizeof(kInfoLabel) + ech_config_.raw.size()) || |
570 | 239 | !CBB_add_bytes(info_cbb.get(), kInfoLabel, |
571 | 239 | sizeof(kInfoLabel) /* includes trailing NUL */) || |
572 | 239 | !CBB_add_bytes(info_cbb.get(), ech_config_.raw.data(), |
573 | 239 | ech_config_.raw.size())) { |
574 | 0 | return false; |
575 | 0 | } |
576 | | |
577 | 239 | assert(kdf_id == EVP_HPKE_HKDF_SHA256); |
578 | 0 | assert(get_ech_aead(aead_id) != NULL); |
579 | 0 | return EVP_HPKE_CTX_setup_recipient( |
580 | 239 | ctx, key_.get(), EVP_hpke_hkdf_sha256(), get_ech_aead(aead_id), enc.data(), |
581 | 239 | enc.size(), CBB_data(info_cbb.get()), CBB_len(info_cbb.get())); |
582 | 239 | } |
583 | | |
584 | 0 | bool ssl_is_valid_ech_config_list(Span<const uint8_t> ech_config_list) { |
585 | 0 | CBS cbs = ech_config_list, child; |
586 | 0 | if (!CBS_get_u16_length_prefixed(&cbs, &child) || // |
587 | 0 | CBS_len(&child) == 0 || // |
588 | 0 | CBS_len(&cbs) > 0) { |
589 | 0 | return false; |
590 | 0 | } |
591 | 0 | while (CBS_len(&child) > 0) { |
592 | 0 | ECHConfig ech_config; |
593 | 0 | bool supported; |
594 | 0 | if (!parse_ech_config(&child, &ech_config, &supported, |
595 | 0 | /*all_extensions_mandatory=*/false)) { |
596 | 0 | return false; |
597 | 0 | } |
598 | 0 | } |
599 | 0 | return true; |
600 | 0 | } |
601 | | |
602 | | static bool select_ech_cipher_suite(const EVP_HPKE_KDF **out_kdf, |
603 | | const EVP_HPKE_AEAD **out_aead, |
604 | | Span<const uint8_t> cipher_suites, |
605 | 0 | const bool has_aes_hardware) { |
606 | 0 | const EVP_HPKE_AEAD *aead = nullptr; |
607 | 0 | CBS cbs = cipher_suites; |
608 | 0 | while (CBS_len(&cbs) != 0) { |
609 | 0 | uint16_t kdf_id, aead_id; |
610 | 0 | if (!CBS_get_u16(&cbs, &kdf_id) || // |
611 | 0 | !CBS_get_u16(&cbs, &aead_id)) { |
612 | 0 | return false; |
613 | 0 | } |
614 | | // Pick the first common cipher suite, but prefer ChaCha20-Poly1305 if we |
615 | | // don't have AES hardware. |
616 | 0 | const EVP_HPKE_AEAD *candidate = get_ech_aead(aead_id); |
617 | 0 | if (kdf_id != EVP_HPKE_HKDF_SHA256 || candidate == nullptr) { |
618 | 0 | continue; |
619 | 0 | } |
620 | 0 | if (aead == nullptr || |
621 | 0 | (!has_aes_hardware && aead_id == EVP_HPKE_CHACHA20_POLY1305)) { |
622 | 0 | aead = candidate; |
623 | 0 | } |
624 | 0 | } |
625 | 0 | if (aead == nullptr) { |
626 | 0 | return false; |
627 | 0 | } |
628 | | |
629 | 0 | *out_kdf = EVP_hpke_hkdf_sha256(); |
630 | 0 | *out_aead = aead; |
631 | 0 | return true; |
632 | 0 | } |
633 | | |
634 | | bool ssl_select_ech_config(SSL_HANDSHAKE *hs, Span<uint8_t> out_enc, |
635 | 65.9k | size_t *out_enc_len) { |
636 | 65.9k | *out_enc_len = 0; |
637 | 65.9k | if (hs->max_version < TLS1_3_VERSION) { |
638 | | // ECH requires TLS 1.3. |
639 | 3.88k | return true; |
640 | 3.88k | } |
641 | | |
642 | 62.0k | if (!hs->config->client_ech_config_list.empty()) { |
643 | 0 | CBS cbs = MakeConstSpan(hs->config->client_ech_config_list); |
644 | 0 | CBS child; |
645 | 0 | if (!CBS_get_u16_length_prefixed(&cbs, &child) || // |
646 | 0 | CBS_len(&child) == 0 || // |
647 | 0 | CBS_len(&cbs) > 0) { |
648 | 0 | return false; |
649 | 0 | } |
650 | | // Look for the first ECHConfig with supported parameters. |
651 | 0 | while (CBS_len(&child) > 0) { |
652 | 0 | ECHConfig ech_config; |
653 | 0 | bool supported; |
654 | 0 | if (!parse_ech_config(&child, &ech_config, &supported, |
655 | 0 | /*all_extensions_mandatory=*/false)) { |
656 | 0 | return false; |
657 | 0 | } |
658 | 0 | const EVP_HPKE_KEM *kem = EVP_hpke_x25519_hkdf_sha256(); |
659 | 0 | const EVP_HPKE_KDF *kdf; |
660 | 0 | const EVP_HPKE_AEAD *aead; |
661 | 0 | if (supported && // |
662 | 0 | ech_config.kem_id == EVP_HPKE_DHKEM_X25519_HKDF_SHA256 && |
663 | 0 | select_ech_cipher_suite(&kdf, &aead, ech_config.cipher_suites, |
664 | 0 | hs->ssl->config->aes_hw_override |
665 | 0 | ? hs->ssl->config->aes_hw_override_value |
666 | 0 | : EVP_has_aes_hardware())) { |
667 | 0 | ScopedCBB info; |
668 | 0 | static const uint8_t kInfoLabel[] = "tls ech"; // includes trailing NUL |
669 | 0 | if (!CBB_init(info.get(), sizeof(kInfoLabel) + ech_config.raw.size()) || |
670 | 0 | !CBB_add_bytes(info.get(), kInfoLabel, sizeof(kInfoLabel)) || |
671 | 0 | !CBB_add_bytes(info.get(), ech_config.raw.data(), |
672 | 0 | ech_config.raw.size())) { |
673 | 0 | return false; |
674 | 0 | } |
675 | | |
676 | 0 | if (!EVP_HPKE_CTX_setup_sender( |
677 | 0 | hs->ech_hpke_ctx.get(), out_enc.data(), out_enc_len, |
678 | 0 | out_enc.size(), kem, kdf, aead, ech_config.public_key.data(), |
679 | 0 | ech_config.public_key.size(), CBB_data(info.get()), |
680 | 0 | CBB_len(info.get())) || |
681 | 0 | !hs->inner_transcript.Init()) { |
682 | 0 | return false; |
683 | 0 | } |
684 | | |
685 | 0 | hs->selected_ech_config = MakeUnique<ECHConfig>(std::move(ech_config)); |
686 | 0 | return hs->selected_ech_config != nullptr; |
687 | 0 | } |
688 | 0 | } |
689 | 0 | } |
690 | | |
691 | 62.0k | return true; |
692 | 62.0k | } |
693 | | |
694 | 0 | static size_t aead_overhead(const EVP_HPKE_AEAD *aead) { |
695 | 0 | #if defined(BORINGSSL_UNSAFE_FUZZER_MODE) |
696 | | // TODO(https://crbug.com/boringssl/275): Having to adjust the overhead |
697 | | // everywhere is tedious. Change fuzzer mode to append a fake tag but still |
698 | | // otherwise be cleartext, refresh corpora, and then inline this function. |
699 | 0 | return 0; |
700 | | #else |
701 | | return EVP_AEAD_max_overhead(EVP_HPKE_AEAD_aead(aead)); |
702 | | #endif |
703 | 0 | } |
704 | | |
705 | | // random_size returns a random value between |min| and |max|, inclusive. |
706 | 0 | static size_t random_size(size_t min, size_t max) { |
707 | 0 | assert(min < max); |
708 | 0 | size_t value; |
709 | 0 | RAND_bytes(reinterpret_cast<uint8_t *>(&value), sizeof(value)); |
710 | 0 | return value % (max - min + 1) + min; |
711 | 0 | } |
712 | | |
713 | 65.9k | static bool setup_ech_grease(SSL_HANDSHAKE *hs) { |
714 | 65.9k | assert(!hs->selected_ech_config); |
715 | 65.9k | if (hs->max_version < TLS1_3_VERSION || !hs->config->ech_grease_enabled) { |
716 | 65.9k | return true; |
717 | 65.9k | } |
718 | | |
719 | 0 | const uint16_t kdf_id = EVP_HPKE_HKDF_SHA256; |
720 | 0 | const bool has_aes_hw = hs->ssl->config->aes_hw_override |
721 | 0 | ? hs->ssl->config->aes_hw_override_value |
722 | 0 | : EVP_has_aes_hardware(); |
723 | 0 | const EVP_HPKE_AEAD *aead = |
724 | 0 | has_aes_hw ? EVP_hpke_aes_128_gcm() : EVP_hpke_chacha20_poly1305(); |
725 | 0 | static_assert(ssl_grease_ech_config_id < sizeof(hs->grease_seed), |
726 | 0 | "hs->grease_seed is too small"); |
727 | 0 | uint8_t config_id = hs->grease_seed[ssl_grease_ech_config_id]; |
728 | |
|
729 | 0 | uint8_t enc[X25519_PUBLIC_VALUE_LEN]; |
730 | 0 | uint8_t private_key_unused[X25519_PRIVATE_KEY_LEN]; |
731 | 0 | X25519_keypair(enc, private_key_unused); |
732 | | |
733 | | // To determine a plausible length for the payload, we estimate the size of a |
734 | | // typical EncodedClientHelloInner without resumption: |
735 | | // |
736 | | // 2+32+1+2 version, random, legacy_session_id, legacy_compression_methods |
737 | | // 2+4*2 cipher_suites (three TLS 1.3 ciphers, GREASE) |
738 | | // 2 extensions prefix |
739 | | // 5 inner encrypted_client_hello |
740 | | // 4+1+2*2 supported_versions (TLS 1.3, GREASE) |
741 | | // 4+1+10*2 outer_extensions (key_share, sigalgs, sct, alpn, |
742 | | // supported_groups, status_request, psk_key_exchange_modes, |
743 | | // compress_certificate, GREASE x2) |
744 | | // |
745 | | // The server_name extension has an overhead of 9 bytes. For now, arbitrarily |
746 | | // estimate maximum_name_length to be between 32 and 100 bytes. Then round up |
747 | | // to a multiple of 32, to match draft-ietf-tls-esni-13, section 6.1.3. |
748 | 0 | const size_t payload_len = |
749 | 0 | 32 * random_size(128 / 32, 224 / 32) + aead_overhead(aead); |
750 | 0 | bssl::ScopedCBB cbb; |
751 | 0 | CBB enc_cbb, payload_cbb; |
752 | 0 | uint8_t *payload; |
753 | 0 | if (!CBB_init(cbb.get(), 256) || |
754 | 0 | !CBB_add_u16(cbb.get(), kdf_id) || |
755 | 0 | !CBB_add_u16(cbb.get(), EVP_HPKE_AEAD_id(aead)) || |
756 | 0 | !CBB_add_u8(cbb.get(), config_id) || |
757 | 0 | !CBB_add_u16_length_prefixed(cbb.get(), &enc_cbb) || |
758 | 0 | !CBB_add_bytes(&enc_cbb, enc, sizeof(enc)) || |
759 | 0 | !CBB_add_u16_length_prefixed(cbb.get(), &payload_cbb) || |
760 | 0 | !CBB_add_space(&payload_cbb, &payload, payload_len) || |
761 | 0 | !RAND_bytes(payload, payload_len) || |
762 | 0 | !CBBFinishArray(cbb.get(), &hs->ech_client_outer)) { |
763 | 0 | return false; |
764 | 0 | } |
765 | 0 | return true; |
766 | 0 | } |
767 | | |
768 | 65.9k | bool ssl_encrypt_client_hello(SSL_HANDSHAKE *hs, Span<const uint8_t> enc) { |
769 | 65.9k | SSL *const ssl = hs->ssl; |
770 | 65.9k | if (!hs->selected_ech_config) { |
771 | 65.9k | return setup_ech_grease(hs); |
772 | 65.9k | } |
773 | | |
774 | | // Construct ClientHelloInner and EncodedClientHelloInner. See |
775 | | // draft-ietf-tls-esni-13, sections 5.1 and 6.1. |
776 | 0 | ScopedCBB cbb, encoded_cbb; |
777 | 0 | CBB body; |
778 | 0 | bool needs_psk_binder; |
779 | 0 | Array<uint8_t> hello_inner; |
780 | 0 | if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_CLIENT_HELLO) || |
781 | 0 | !CBB_init(encoded_cbb.get(), 256) || |
782 | 0 | !ssl_write_client_hello_without_extensions(hs, &body, |
783 | 0 | ssl_client_hello_inner, |
784 | 0 | /*empty_session_id=*/false) || |
785 | 0 | !ssl_write_client_hello_without_extensions(hs, encoded_cbb.get(), |
786 | 0 | ssl_client_hello_inner, |
787 | 0 | /*empty_session_id=*/true) || |
788 | 0 | !ssl_add_clienthello_tlsext(hs, &body, encoded_cbb.get(), |
789 | 0 | &needs_psk_binder, ssl_client_hello_inner, |
790 | 0 | CBB_len(&body)) || |
791 | 0 | !ssl->method->finish_message(ssl, cbb.get(), &hello_inner)) { |
792 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); |
793 | 0 | return false; |
794 | 0 | } |
795 | | |
796 | 0 | if (needs_psk_binder) { |
797 | 0 | size_t binder_len; |
798 | 0 | if (!tls13_write_psk_binder(hs, hs->inner_transcript, MakeSpan(hello_inner), |
799 | 0 | &binder_len)) { |
800 | 0 | return false; |
801 | 0 | } |
802 | | // Also update the EncodedClientHelloInner. |
803 | 0 | auto encoded_binder = |
804 | 0 | MakeSpan(const_cast<uint8_t *>(CBB_data(encoded_cbb.get())), |
805 | 0 | CBB_len(encoded_cbb.get())) |
806 | 0 | .last(binder_len); |
807 | 0 | auto hello_inner_binder = MakeConstSpan(hello_inner).last(binder_len); |
808 | 0 | OPENSSL_memcpy(encoded_binder.data(), hello_inner_binder.data(), |
809 | 0 | binder_len); |
810 | 0 | } |
811 | | |
812 | 0 | ssl_do_msg_callback(ssl, /*is_write=*/1, SSL3_RT_CLIENT_HELLO_INNER, |
813 | 0 | hello_inner); |
814 | 0 | if (!hs->inner_transcript.Update(hello_inner)) { |
815 | 0 | return false; |
816 | 0 | } |
817 | | |
818 | | // Pad the EncodedClientHelloInner. See draft-ietf-tls-esni-13, section 6.1.3. |
819 | 0 | size_t padding_len = 0; |
820 | 0 | size_t maximum_name_length = hs->selected_ech_config->maximum_name_length; |
821 | 0 | if (ssl->hostname) { |
822 | 0 | size_t hostname_len = strlen(ssl->hostname.get()); |
823 | 0 | if (hostname_len <= maximum_name_length) { |
824 | 0 | padding_len = maximum_name_length - hostname_len; |
825 | 0 | } |
826 | 0 | } else { |
827 | | // No SNI. Pad up to |maximum_name_length|, including server_name extension |
828 | | // overhead. |
829 | 0 | padding_len = 9 + maximum_name_length; |
830 | 0 | } |
831 | | // Pad the whole thing to a multiple of 32 bytes. |
832 | 0 | padding_len += 31 - ((CBB_len(encoded_cbb.get()) + padding_len - 1) % 32); |
833 | 0 | Array<uint8_t> encoded; |
834 | 0 | if (!CBB_add_zeros(encoded_cbb.get(), padding_len) || |
835 | 0 | !CBBFinishArray(encoded_cbb.get(), &encoded)) { |
836 | 0 | return false; |
837 | 0 | } |
838 | | |
839 | | // Encrypt |encoded|. See draft-ietf-tls-esni-13, section 6.1.1. First, |
840 | | // assemble the extension with a placeholder value for ClientHelloOuterAAD. |
841 | | // See draft-ietf-tls-esni-13, section 5.2. |
842 | 0 | const EVP_HPKE_KDF *kdf = EVP_HPKE_CTX_kdf(hs->ech_hpke_ctx.get()); |
843 | 0 | const EVP_HPKE_AEAD *aead = EVP_HPKE_CTX_aead(hs->ech_hpke_ctx.get()); |
844 | 0 | size_t payload_len = encoded.size() + aead_overhead(aead); |
845 | 0 | CBB enc_cbb, payload_cbb; |
846 | 0 | if (!CBB_init(cbb.get(), 256) || |
847 | 0 | !CBB_add_u16(cbb.get(), EVP_HPKE_KDF_id(kdf)) || |
848 | 0 | !CBB_add_u16(cbb.get(), EVP_HPKE_AEAD_id(aead)) || |
849 | 0 | !CBB_add_u8(cbb.get(), hs->selected_ech_config->config_id) || |
850 | 0 | !CBB_add_u16_length_prefixed(cbb.get(), &enc_cbb) || |
851 | 0 | !CBB_add_bytes(&enc_cbb, enc.data(), enc.size()) || |
852 | 0 | !CBB_add_u16_length_prefixed(cbb.get(), &payload_cbb) || |
853 | 0 | !CBB_add_zeros(&payload_cbb, payload_len) || |
854 | 0 | !CBBFinishArray(cbb.get(), &hs->ech_client_outer)) { |
855 | 0 | return false; |
856 | 0 | } |
857 | | |
858 | | // Construct ClientHelloOuterAAD. |
859 | | // TODO(https://crbug.com/boringssl/275): This ends up constructing the |
860 | | // ClientHelloOuter twice. Instead, reuse |aad| for the ClientHello, now that |
861 | | // draft-12 made the length prefixes match. |
862 | 0 | bssl::ScopedCBB aad; |
863 | 0 | if (!CBB_init(aad.get(), 256) || |
864 | 0 | !ssl_write_client_hello_without_extensions(hs, aad.get(), |
865 | 0 | ssl_client_hello_outer, |
866 | 0 | /*empty_session_id=*/false) || |
867 | 0 | !ssl_add_clienthello_tlsext(hs, aad.get(), /*out_encoded=*/nullptr, |
868 | 0 | &needs_psk_binder, ssl_client_hello_outer, |
869 | 0 | CBB_len(aad.get()))) { |
870 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); |
871 | 0 | return false; |
872 | 0 | } |
873 | | |
874 | | // ClientHelloOuter may not require a PSK binder. Otherwise, we have a |
875 | | // circular dependency. |
876 | 0 | assert(!needs_psk_binder); |
877 | | |
878 | | // Replace the payload in |hs->ech_client_outer| with the encrypted value. |
879 | 0 | auto payload_span = MakeSpan(hs->ech_client_outer).last(payload_len); |
880 | 0 | #if defined(BORINGSSL_UNSAFE_FUZZER_MODE) |
881 | | // In fuzzer mode, the server expects a cleartext payload. |
882 | 0 | assert(payload_span.size() == encoded.size()); |
883 | 0 | OPENSSL_memcpy(payload_span.data(), encoded.data(), encoded.size()); |
884 | | #else |
885 | | if (!EVP_HPKE_CTX_seal(hs->ech_hpke_ctx.get(), payload_span.data(), |
886 | | &payload_len, payload_span.size(), encoded.data(), |
887 | | encoded.size(), CBB_data(aad.get()), |
888 | | CBB_len(aad.get())) || |
889 | | payload_len != payload_span.size()) { |
890 | | return false; |
891 | | } |
892 | | #endif // BORINGSSL_UNSAFE_FUZZER_MODE |
893 | |
|
894 | 0 | return true; |
895 | 0 | } |
896 | | |
897 | | BSSL_NAMESPACE_END |
898 | | |
899 | | using namespace bssl; |
900 | | |
901 | 0 | void SSL_set_enable_ech_grease(SSL *ssl, int enable) { |
902 | 0 | if (!ssl->config) { |
903 | 0 | return; |
904 | 0 | } |
905 | 0 | ssl->config->ech_grease_enabled = !!enable; |
906 | 0 | } |
907 | | |
908 | | int SSL_set1_ech_config_list(SSL *ssl, const uint8_t *ech_config_list, |
909 | 0 | size_t ech_config_list_len) { |
910 | 0 | if (!ssl->config) { |
911 | 0 | return 0; |
912 | 0 | } |
913 | | |
914 | 0 | auto span = MakeConstSpan(ech_config_list, ech_config_list_len); |
915 | 0 | if (!ssl_is_valid_ech_config_list(span)) { |
916 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_ECH_CONFIG_LIST); |
917 | 0 | return 0; |
918 | 0 | } |
919 | 0 | return ssl->config->client_ech_config_list.CopyFrom(span); |
920 | 0 | } |
921 | | |
922 | | void SSL_get0_ech_name_override(const SSL *ssl, const char **out_name, |
923 | 6.22k | size_t *out_name_len) { |
924 | | // When ECH is rejected, we use the public name. Note that, if |
925 | | // |SSL_CTX_set_reverify_on_resume| is enabled, we reverify the certificate |
926 | | // before the 0-RTT point. If also offering ECH, we verify as if |
927 | | // ClientHelloInner was accepted and do not override. This works because, at |
928 | | // this point, |ech_status| will be |ssl_ech_none|. See the |
929 | | // ECH-Client-Reject-EarlyDataReject-OverrideNameOnRetry tests in runner.go. |
930 | 6.22k | const SSL_HANDSHAKE *hs = ssl->s3->hs.get(); |
931 | 6.22k | if (!ssl->server && hs && ssl->s3->ech_status == ssl_ech_rejected) { |
932 | 0 | *out_name = reinterpret_cast<const char *>( |
933 | 0 | hs->selected_ech_config->public_name.data()); |
934 | 0 | *out_name_len = hs->selected_ech_config->public_name.size(); |
935 | 6.22k | } else { |
936 | 6.22k | *out_name = nullptr; |
937 | 6.22k | *out_name_len = 0; |
938 | 6.22k | } |
939 | 6.22k | } |
940 | | |
941 | | void SSL_get0_ech_retry_configs( |
942 | | const SSL *ssl, const uint8_t **out_retry_configs, |
943 | 0 | size_t *out_retry_configs_len) { |
944 | 0 | const SSL_HANDSHAKE *hs = ssl->s3->hs.get(); |
945 | 0 | if (!hs || !hs->ech_authenticated_reject) { |
946 | | // It is an error to call this function except in response to |
947 | | // |SSL_R_ECH_REJECTED|. Returning an empty string risks the caller |
948 | | // mistakenly believing the server has disabled ECH. Instead, return a |
949 | | // non-empty ECHConfigList with a syntax error, so the subsequent |
950 | | // |SSL_set1_ech_config_list| call will fail. |
951 | 0 | assert(0); |
952 | 0 | static const uint8_t kPlaceholder[] = { |
953 | 0 | kECHConfigVersion >> 8, kECHConfigVersion & 0xff, 0xff, 0xff, 0xff}; |
954 | 0 | *out_retry_configs = kPlaceholder; |
955 | 0 | *out_retry_configs_len = sizeof(kPlaceholder); |
956 | 0 | return; |
957 | 0 | } |
958 | | |
959 | 0 | *out_retry_configs = hs->ech_retry_configs.data(); |
960 | 0 | *out_retry_configs_len = hs->ech_retry_configs.size(); |
961 | 0 | } |
962 | | |
963 | | int SSL_marshal_ech_config(uint8_t **out, size_t *out_len, uint8_t config_id, |
964 | | const EVP_HPKE_KEY *key, const char *public_name, |
965 | 4 | size_t max_name_len) { |
966 | 4 | Span<const uint8_t> public_name_u8 = MakeConstSpan( |
967 | 4 | reinterpret_cast<const uint8_t *>(public_name), strlen(public_name)); |
968 | 4 | if (!ssl_is_valid_ech_public_name(public_name_u8)) { |
969 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_ECH_PUBLIC_NAME); |
970 | 0 | return 0; |
971 | 0 | } |
972 | | |
973 | | // The maximum name length is encoded in one byte. |
974 | 4 | if (max_name_len > 0xff) { |
975 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_LENGTH); |
976 | 0 | return 0; |
977 | 0 | } |
978 | | |
979 | | // See draft-ietf-tls-esni-13, section 4. |
980 | 4 | ScopedCBB cbb; |
981 | 4 | CBB contents, child; |
982 | 4 | uint8_t *public_key; |
983 | 4 | size_t public_key_len; |
984 | 4 | if (!CBB_init(cbb.get(), 128) || // |
985 | 4 | !CBB_add_u16(cbb.get(), kECHConfigVersion) || |
986 | 4 | !CBB_add_u16_length_prefixed(cbb.get(), &contents) || |
987 | 4 | !CBB_add_u8(&contents, config_id) || |
988 | 4 | !CBB_add_u16(&contents, EVP_HPKE_KEM_id(EVP_HPKE_KEY_kem(key))) || |
989 | 4 | !CBB_add_u16_length_prefixed(&contents, &child) || |
990 | 4 | !CBB_reserve(&child, &public_key, EVP_HPKE_MAX_PUBLIC_KEY_LENGTH) || |
991 | 4 | !EVP_HPKE_KEY_public_key(key, public_key, &public_key_len, |
992 | 4 | EVP_HPKE_MAX_PUBLIC_KEY_LENGTH) || |
993 | 4 | !CBB_did_write(&child, public_key_len) || |
994 | 4 | !CBB_add_u16_length_prefixed(&contents, &child) || |
995 | | // Write a default cipher suite configuration. |
996 | 4 | !CBB_add_u16(&child, EVP_HPKE_HKDF_SHA256) || |
997 | 4 | !CBB_add_u16(&child, EVP_HPKE_AES_128_GCM) || |
998 | 4 | !CBB_add_u16(&child, EVP_HPKE_HKDF_SHA256) || |
999 | 4 | !CBB_add_u16(&child, EVP_HPKE_CHACHA20_POLY1305) || |
1000 | 4 | !CBB_add_u8(&contents, max_name_len) || |
1001 | 4 | !CBB_add_u8_length_prefixed(&contents, &child) || |
1002 | 4 | !CBB_add_bytes(&child, public_name_u8.data(), public_name_u8.size()) || |
1003 | | // TODO(https://crbug.com/boringssl/275): Reserve some GREASE extensions |
1004 | | // and include some. |
1005 | 4 | !CBB_add_u16(&contents, 0 /* no extensions */) || |
1006 | 4 | !CBB_finish(cbb.get(), out, out_len)) { |
1007 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); |
1008 | 0 | return 0; |
1009 | 0 | } |
1010 | 4 | return 1; |
1011 | 4 | } |
1012 | | |
1013 | 14.9k | SSL_ECH_KEYS *SSL_ECH_KEYS_new() { return New<SSL_ECH_KEYS>(); } |
1014 | | |
1015 | 302 | void SSL_ECH_KEYS_up_ref(SSL_ECH_KEYS *keys) { |
1016 | 302 | CRYPTO_refcount_inc(&keys->references); |
1017 | 302 | } |
1018 | | |
1019 | 15.2k | void SSL_ECH_KEYS_free(SSL_ECH_KEYS *keys) { |
1020 | 15.2k | if (keys == nullptr || |
1021 | 15.2k | !CRYPTO_refcount_dec_and_test_zero(&keys->references)) { |
1022 | 302 | return; |
1023 | 302 | } |
1024 | | |
1025 | 14.9k | keys->~ssl_ech_keys_st(); |
1026 | 14.9k | OPENSSL_free(keys); |
1027 | 14.9k | } |
1028 | | |
1029 | | int SSL_ECH_KEYS_add(SSL_ECH_KEYS *configs, int is_retry_config, |
1030 | | const uint8_t *ech_config, size_t ech_config_len, |
1031 | 11.7k | const EVP_HPKE_KEY *key) { |
1032 | 11.7k | UniquePtr<ECHServerConfig> parsed_config = MakeUnique<ECHServerConfig>(); |
1033 | 11.7k | if (!parsed_config) { |
1034 | 0 | return 0; |
1035 | 0 | } |
1036 | 11.7k | if (!parsed_config->Init(MakeConstSpan(ech_config, ech_config_len), key, |
1037 | 11.7k | !!is_retry_config)) { |
1038 | 11.7k | OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); |
1039 | 11.7k | return 0; |
1040 | 11.7k | } |
1041 | 4 | if (!configs->configs.Push(std::move(parsed_config))) { |
1042 | 0 | return 0; |
1043 | 0 | } |
1044 | 4 | return 1; |
1045 | 4 | } |
1046 | | |
1047 | 0 | int SSL_ECH_KEYS_has_duplicate_config_id(const SSL_ECH_KEYS *keys) { |
1048 | 0 | bool seen[256] = {false}; |
1049 | 0 | for (const auto &config : keys->configs) { |
1050 | 0 | if (seen[config->ech_config().config_id]) { |
1051 | 0 | return 1; |
1052 | 0 | } |
1053 | 0 | seen[config->ech_config().config_id] = true; |
1054 | 0 | } |
1055 | 0 | return 0; |
1056 | 0 | } |
1057 | | |
1058 | | int SSL_ECH_KEYS_marshal_retry_configs(const SSL_ECH_KEYS *keys, uint8_t **out, |
1059 | 0 | size_t *out_len) { |
1060 | 0 | ScopedCBB cbb; |
1061 | 0 | CBB child; |
1062 | 0 | if (!CBB_init(cbb.get(), 128) || |
1063 | 0 | !CBB_add_u16_length_prefixed(cbb.get(), &child)) { |
1064 | 0 | return false; |
1065 | 0 | } |
1066 | 0 | for (const auto &config : keys->configs) { |
1067 | 0 | if (config->is_retry_config() && |
1068 | 0 | !CBB_add_bytes(&child, config->ech_config().raw.data(), |
1069 | 0 | config->ech_config().raw.size())) { |
1070 | 0 | return false; |
1071 | 0 | } |
1072 | 0 | } |
1073 | 0 | return CBB_finish(cbb.get(), out, out_len); |
1074 | 0 | } |
1075 | | |
1076 | 4 | int SSL_CTX_set1_ech_keys(SSL_CTX *ctx, SSL_ECH_KEYS *keys) { |
1077 | 4 | bool has_retry_config = false; |
1078 | 4 | for (const auto &config : keys->configs) { |
1079 | 4 | if (config->is_retry_config()) { |
1080 | 4 | has_retry_config = true; |
1081 | 4 | break; |
1082 | 4 | } |
1083 | 4 | } |
1084 | 4 | if (!has_retry_config) { |
1085 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_ECH_SERVER_WOULD_HAVE_NO_RETRY_CONFIGS); |
1086 | 0 | return 0; |
1087 | 0 | } |
1088 | 4 | UniquePtr<SSL_ECH_KEYS> owned_keys = UpRef(keys); |
1089 | 4 | MutexWriteLock lock(&ctx->lock); |
1090 | 4 | ctx->ech_keys.swap(owned_keys); |
1091 | 4 | return 1; |
1092 | 4 | } |
1093 | | |
1094 | 0 | int SSL_ech_accepted(const SSL *ssl) { |
1095 | 0 | if (SSL_in_early_data(ssl) && !ssl->server) { |
1096 | | // In the client early data state, we report properties as if the server |
1097 | | // accepted early data. The server can only accept early data with |
1098 | | // ClientHelloInner. |
1099 | 0 | return ssl->s3->hs->selected_ech_config != nullptr; |
1100 | 0 | } |
1101 | | |
1102 | 0 | return ssl->s3->ech_status == ssl_ech_accepted; |
1103 | 0 | } |