Mercurial > hg > nginx
comparison src/event/quic/ngx_event_quic_ssl.c @ 8753:46161c610919 quic
QUIC: separate files for SSL library interfaces.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Wed, 14 Apr 2021 14:47:04 +0300 |
parents | |
children | 4117aa7fa38e |
comparison
equal
deleted
inserted
replaced
8752:e19723c40d28 | 8753:46161c610919 |
---|---|
1 | |
2 /* | |
3 * Copyright (C) Nginx, Inc. | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_event.h> | |
10 #include <ngx_event_quic_connection.h> | |
11 | |
12 | |
13 /* | |
14 * 7.4. Cryptographic Message Buffering | |
15 * Implementations MUST support buffering at least 4096 bytes of data | |
16 */ | |
17 #define NGX_QUIC_MAX_BUFFERED 65535 | |
18 | |
19 | |
20 #if BORINGSSL_API_VERSION >= 10 | |
21 static int ngx_quic_set_read_secret(ngx_ssl_conn_t *ssl_conn, | |
22 enum ssl_encryption_level_t level, const SSL_CIPHER *cipher, | |
23 const uint8_t *secret, size_t secret_len); | |
24 static int ngx_quic_set_write_secret(ngx_ssl_conn_t *ssl_conn, | |
25 enum ssl_encryption_level_t level, const SSL_CIPHER *cipher, | |
26 const uint8_t *secret, size_t secret_len); | |
27 #else | |
28 static int ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn, | |
29 enum ssl_encryption_level_t level, const uint8_t *read_secret, | |
30 const uint8_t *write_secret, size_t secret_len); | |
31 #endif | |
32 | |
33 static int ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, | |
34 enum ssl_encryption_level_t level, const uint8_t *data, size_t len); | |
35 static int ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn); | |
36 | |
37 | |
38 static SSL_QUIC_METHOD quic_method = { | |
39 #if BORINGSSL_API_VERSION >= 10 | |
40 ngx_quic_set_read_secret, | |
41 ngx_quic_set_write_secret, | |
42 #else | |
43 ngx_quic_set_encryption_secrets, | |
44 #endif | |
45 ngx_quic_add_handshake_data, | |
46 ngx_quic_flush_flight, | |
47 ngx_quic_send_alert, | |
48 }; | |
49 | |
50 | |
51 #if BORINGSSL_API_VERSION >= 10 | |
52 | |
53 static int | |
54 ngx_quic_set_read_secret(ngx_ssl_conn_t *ssl_conn, | |
55 enum ssl_encryption_level_t level, const SSL_CIPHER *cipher, | |
56 const uint8_t *rsecret, size_t secret_len) | |
57 { | |
58 ngx_connection_t *c; | |
59 ngx_quic_connection_t *qc; | |
60 | |
61 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | |
62 qc = ngx_quic_get_connection(c); | |
63 | |
64 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
65 "quic ngx_quic_set_read_secret() level:%d", level); | |
66 #ifdef NGX_QUIC_DEBUG_CRYPTO | |
67 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
68 "quic read secret len:%uz %*xs", secret_len, | |
69 secret_len, rsecret); | |
70 #endif | |
71 | |
72 return ngx_quic_keys_set_encryption_secret(c->pool, 0, qc->keys, level, | |
73 cipher, rsecret, secret_len); | |
74 } | |
75 | |
76 | |
77 static int | |
78 ngx_quic_set_write_secret(ngx_ssl_conn_t *ssl_conn, | |
79 enum ssl_encryption_level_t level, const SSL_CIPHER *cipher, | |
80 const uint8_t *wsecret, size_t secret_len) | |
81 { | |
82 ngx_connection_t *c; | |
83 ngx_quic_connection_t *qc; | |
84 | |
85 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | |
86 qc = ngx_quic_get_connection(c); | |
87 | |
88 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
89 "quic ngx_quic_set_write_secret() level:%d", level); | |
90 #ifdef NGX_QUIC_DEBUG_CRYPTO | |
91 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
92 "quic write secret len:%uz %*xs", secret_len, | |
93 secret_len, wsecret); | |
94 #endif | |
95 | |
96 return ngx_quic_keys_set_encryption_secret(c->pool, 1, qc->keys, level, | |
97 cipher, wsecret, secret_len); | |
98 } | |
99 | |
100 #else | |
101 | |
102 static int | |
103 ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn, | |
104 enum ssl_encryption_level_t level, const uint8_t *rsecret, | |
105 const uint8_t *wsecret, size_t secret_len) | |
106 { | |
107 ngx_connection_t *c; | |
108 const SSL_CIPHER *cipher; | |
109 ngx_quic_connection_t *qc; | |
110 | |
111 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | |
112 qc = ngx_quic_get_connection(c); | |
113 | |
114 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
115 "quic ngx_quic_set_encryption_secrets() level:%d", level); | |
116 #ifdef NGX_QUIC_DEBUG_CRYPTO | |
117 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
118 "quic read secret len:%uz %*xs", secret_len, | |
119 secret_len, rsecret); | |
120 #endif | |
121 | |
122 cipher = SSL_get_current_cipher(ssl_conn); | |
123 | |
124 if (ngx_quic_keys_set_encryption_secret(c->pool, 0, qc->keys, level, | |
125 cipher, rsecret, secret_len) | |
126 != 1) | |
127 { | |
128 return 0; | |
129 } | |
130 | |
131 if (level == ssl_encryption_early_data) { | |
132 return 1; | |
133 } | |
134 | |
135 #ifdef NGX_QUIC_DEBUG_CRYPTO | |
136 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
137 "quic write secret len:%uz %*xs", secret_len, | |
138 secret_len, wsecret); | |
139 #endif | |
140 | |
141 return ngx_quic_keys_set_encryption_secret(c->pool, 1, qc->keys, level, | |
142 cipher, wsecret, secret_len); | |
143 } | |
144 | |
145 #endif | |
146 | |
147 | |
148 static int | |
149 ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, | |
150 enum ssl_encryption_level_t level, const uint8_t *data, size_t len) | |
151 { | |
152 u_char *p, *end; | |
153 size_t client_params_len; | |
154 const uint8_t *client_params; | |
155 ngx_quic_tp_t ctp; | |
156 ngx_quic_frame_t *frame; | |
157 ngx_connection_t *c; | |
158 ngx_quic_connection_t *qc; | |
159 ngx_quic_frames_stream_t *fs; | |
160 | |
161 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | |
162 qc = ngx_quic_get_connection(c); | |
163 | |
164 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
165 "quic ngx_quic_add_handshake_data"); | |
166 | |
167 if (!qc->client_tp_done) { | |
168 /* | |
169 * things to do once during handshake: check ALPN and transport | |
170 * parameters; we want to break handshake if something is wrong | |
171 * here; | |
172 */ | |
173 | |
174 #if defined(TLSEXT_TYPE_application_layer_protocol_negotiation) | |
175 if (qc->conf->require_alpn) { | |
176 unsigned int len; | |
177 const unsigned char *data; | |
178 | |
179 SSL_get0_alpn_selected(ssl_conn, &data, &len); | |
180 | |
181 if (len == 0) { | |
182 qc->error = 0x100 + SSL_AD_NO_APPLICATION_PROTOCOL; | |
183 qc->error_reason = "unsupported protocol in ALPN extension"; | |
184 | |
185 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
186 "quic unsupported protocol in ALPN extension"); | |
187 return 0; | |
188 } | |
189 } | |
190 #endif | |
191 | |
192 SSL_get_peer_quic_transport_params(ssl_conn, &client_params, | |
193 &client_params_len); | |
194 | |
195 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
196 "quic SSL_get_peer_quic_transport_params():" | |
197 " params_len:%ui", client_params_len); | |
198 | |
199 if (client_params_len == 0) { | |
200 /* quic-tls 8.2 */ | |
201 qc->error = NGX_QUIC_ERR_CRYPTO(SSL_AD_MISSING_EXTENSION); | |
202 qc->error_reason = "missing transport parameters"; | |
203 | |
204 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
205 "missing transport parameters"); | |
206 return 0; | |
207 } | |
208 | |
209 p = (u_char *) client_params; | |
210 end = p + client_params_len; | |
211 | |
212 /* defaults for parameters not sent by client */ | |
213 ngx_memcpy(&ctp, &qc->ctp, sizeof(ngx_quic_tp_t)); | |
214 | |
215 if (ngx_quic_parse_transport_params(p, end, &ctp, c->log) | |
216 != NGX_OK) | |
217 { | |
218 qc->error = NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR; | |
219 qc->error_reason = "failed to process transport parameters"; | |
220 | |
221 return 0; | |
222 } | |
223 | |
224 if (ngx_quic_apply_transport_params(c, &ctp) != NGX_OK) { | |
225 return 0; | |
226 } | |
227 | |
228 qc->client_tp_done = 1; | |
229 } | |
230 | |
231 fs = &qc->crypto[level]; | |
232 | |
233 frame = ngx_quic_alloc_frame(c); | |
234 if (frame == NULL) { | |
235 return 0; | |
236 } | |
237 | |
238 frame->data = ngx_quic_copy_buf(c, (u_char *) data, len); | |
239 if (frame->data == NGX_CHAIN_ERROR) { | |
240 return 0; | |
241 } | |
242 | |
243 frame->level = level; | |
244 frame->type = NGX_QUIC_FT_CRYPTO; | |
245 frame->u.crypto.offset = fs->sent; | |
246 frame->u.crypto.length = len; | |
247 | |
248 fs->sent += len; | |
249 | |
250 ngx_quic_queue_frame(qc, frame); | |
251 | |
252 return 1; | |
253 } | |
254 | |
255 | |
256 static int | |
257 ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn) | |
258 { | |
259 #if (NGX_DEBUG) | |
260 ngx_connection_t *c; | |
261 | |
262 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | |
263 | |
264 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
265 "quic ngx_quic_flush_flight()"); | |
266 #endif | |
267 return 1; | |
268 } | |
269 | |
270 | |
271 ngx_int_t | |
272 ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt, | |
273 ngx_quic_frame_t *frame) | |
274 { | |
275 uint64_t last; | |
276 ngx_int_t rc; | |
277 ngx_quic_send_ctx_t *ctx; | |
278 ngx_quic_connection_t *qc; | |
279 ngx_quic_crypto_frame_t *f; | |
280 ngx_quic_frames_stream_t *fs; | |
281 | |
282 qc = ngx_quic_get_connection(c); | |
283 fs = &qc->crypto[pkt->level]; | |
284 f = &frame->u.crypto; | |
285 | |
286 /* no overflow since both values are 62-bit */ | |
287 last = f->offset + f->length; | |
288 | |
289 if (last > fs->received && last - fs->received > NGX_QUIC_MAX_BUFFERED) { | |
290 qc->error = NGX_QUIC_ERR_CRYPTO_BUFFER_EXCEEDED; | |
291 return NGX_ERROR; | |
292 } | |
293 | |
294 rc = ngx_quic_handle_ordered_frame(c, fs, frame, ngx_quic_crypto_input, | |
295 NULL); | |
296 if (rc != NGX_DECLINED) { | |
297 return rc; | |
298 } | |
299 | |
300 /* speeding up handshake completion */ | |
301 | |
302 if (pkt->level == ssl_encryption_initial) { | |
303 ctx = ngx_quic_get_send_ctx(qc, pkt->level); | |
304 | |
305 if (!ngx_queue_empty(&ctx->sent)) { | |
306 ngx_quic_resend_frames(c, ctx); | |
307 | |
308 ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_handshake); | |
309 while (!ngx_queue_empty(&ctx->sent)) { | |
310 ngx_quic_resend_frames(c, ctx); | |
311 } | |
312 } | |
313 } | |
314 | |
315 return NGX_OK; | |
316 } | |
317 | |
318 | |
319 ngx_int_t | |
320 ngx_quic_crypto_input(ngx_connection_t *c, ngx_quic_frame_t *frame, void *data) | |
321 { | |
322 int n, sslerr; | |
323 ngx_buf_t *b; | |
324 ngx_chain_t *cl; | |
325 ngx_ssl_conn_t *ssl_conn; | |
326 ngx_quic_connection_t *qc; | |
327 | |
328 qc = ngx_quic_get_connection(c); | |
329 | |
330 ssl_conn = c->ssl->connection; | |
331 | |
332 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
333 "quic SSL_quic_read_level:%d SSL_quic_write_level:%d", | |
334 (int) SSL_quic_read_level(ssl_conn), | |
335 (int) SSL_quic_write_level(ssl_conn)); | |
336 | |
337 for (cl = frame->data; cl; cl = cl->next) { | |
338 b = cl->buf; | |
339 | |
340 if (!SSL_provide_quic_data(ssl_conn, SSL_quic_read_level(ssl_conn), | |
341 b->pos, b->last - b->pos)) | |
342 { | |
343 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, | |
344 "SSL_provide_quic_data() failed"); | |
345 return NGX_ERROR; | |
346 } | |
347 } | |
348 | |
349 n = SSL_do_handshake(ssl_conn); | |
350 | |
351 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
352 "quic SSL_quic_read_level:%d SSL_quic_write_level:%d", | |
353 (int) SSL_quic_read_level(ssl_conn), | |
354 (int) SSL_quic_write_level(ssl_conn)); | |
355 | |
356 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n); | |
357 | |
358 if (n <= 0) { | |
359 sslerr = SSL_get_error(ssl_conn, n); | |
360 | |
361 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", | |
362 sslerr); | |
363 | |
364 if (sslerr != SSL_ERROR_WANT_READ) { | |
365 ngx_ssl_error(NGX_LOG_ERR, c->log, 0, "SSL_do_handshake() failed"); | |
366 return NGX_ERROR; | |
367 } | |
368 | |
369 return NGX_OK; | |
370 } | |
371 | |
372 if (SSL_in_init(ssl_conn)) { | |
373 return NGX_OK; | |
374 } | |
375 | |
376 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
377 "quic ssl cipher:%s", SSL_get_cipher(ssl_conn)); | |
378 | |
379 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
380 "quic handshake completed successfully"); | |
381 | |
382 c->ssl->handshaked = 1; | |
383 | |
384 frame = ngx_quic_alloc_frame(c); | |
385 if (frame == NULL) { | |
386 return NGX_ERROR; | |
387 } | |
388 | |
389 /* 12.4 Frames and frame types, figure 8 */ | |
390 frame->level = ssl_encryption_application; | |
391 frame->type = NGX_QUIC_FT_HANDSHAKE_DONE; | |
392 ngx_quic_queue_frame(qc, frame); | |
393 | |
394 if (ngx_quic_send_new_token(c) != NGX_OK) { | |
395 return NGX_ERROR; | |
396 } | |
397 | |
398 /* | |
399 * Generating next keys before a key update is received. | |
400 * See quic-tls 9.4 Header Protection Timing Side-Channels. | |
401 */ | |
402 | |
403 if (ngx_quic_keys_update(c, qc->keys) != NGX_OK) { | |
404 return NGX_ERROR; | |
405 } | |
406 | |
407 /* | |
408 * 4.10.2 An endpoint MUST discard its handshake keys | |
409 * when the TLS handshake is confirmed | |
410 */ | |
411 ngx_quic_discard_ctx(c, ssl_encryption_handshake); | |
412 | |
413 if (ngx_quic_issue_server_ids(c) != NGX_OK) { | |
414 return NGX_ERROR; | |
415 } | |
416 | |
417 return NGX_OK; | |
418 } | |
419 | |
420 | |
421 ngx_int_t | |
422 ngx_quic_init_connection(ngx_connection_t *c) | |
423 { | |
424 u_char *p; | |
425 size_t clen; | |
426 ssize_t len; | |
427 ngx_ssl_conn_t *ssl_conn; | |
428 ngx_quic_connection_t *qc; | |
429 | |
430 qc = ngx_quic_get_connection(c); | |
431 | |
432 if (ngx_ssl_create_connection(qc->conf->ssl, c, NGX_SSL_BUFFER) != NGX_OK) { | |
433 return NGX_ERROR; | |
434 } | |
435 | |
436 c->ssl->no_wait_shutdown = 1; | |
437 | |
438 ssl_conn = c->ssl->connection; | |
439 | |
440 if (SSL_set_quic_method(ssl_conn, &quic_method) == 0) { | |
441 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
442 "quic SSL_set_quic_method() failed"); | |
443 return NGX_ERROR; | |
444 } | |
445 | |
446 #ifdef SSL_READ_EARLY_DATA_SUCCESS | |
447 if (SSL_CTX_get_max_early_data(qc->conf->ssl->ctx)) { | |
448 SSL_set_quic_early_data_enabled(ssl_conn, 1); | |
449 } | |
450 #endif | |
451 | |
452 #if BORINGSSL_API_VERSION >= 13 | |
453 SSL_set_quic_use_legacy_codepoint(ssl_conn, qc->version != 1); | |
454 #endif | |
455 | |
456 if (ngx_quic_new_sr_token(c, &qc->dcid, qc->conf->sr_token_key, | |
457 qc->tp.sr_token) | |
458 != NGX_OK) | |
459 { | |
460 return NGX_ERROR; | |
461 } | |
462 | |
463 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
464 "quic stateless reset token %*xs", | |
465 (size_t) NGX_QUIC_SR_TOKEN_LEN, qc->tp.sr_token); | |
466 | |
467 len = ngx_quic_create_transport_params(NULL, NULL, &qc->tp, &clen); | |
468 /* always succeeds */ | |
469 | |
470 p = ngx_pnalloc(c->pool, len); | |
471 if (p == NULL) { | |
472 return NGX_ERROR; | |
473 } | |
474 | |
475 len = ngx_quic_create_transport_params(p, p + len, &qc->tp, NULL); | |
476 if (len < 0) { | |
477 return NGX_ERROR; | |
478 } | |
479 | |
480 #ifdef NGX_QUIC_DEBUG_PACKETS | |
481 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
482 "quic transport parameters len:%uz %*xs", len, len, p); | |
483 #endif | |
484 | |
485 if (SSL_set_quic_transport_params(ssl_conn, p, len) == 0) { | |
486 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
487 "quic SSL_set_quic_transport_params() failed"); | |
488 return NGX_ERROR; | |
489 } | |
490 | |
491 #if NGX_OPENSSL_QUIC_ZRTT_CTX | |
492 if (SSL_set_quic_early_data_context(ssl_conn, p, clen) == 0) { | |
493 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
494 "quic SSL_set_quic_early_data_context() failed"); | |
495 return NGX_ERROR; | |
496 } | |
497 #endif | |
498 | |
499 return NGX_OK; | |
500 } |