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 }