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