comparison src/event/ngx_event_quic.c @ 8184:ec1f84996990 quic

Split frame and packet generation into separate steps. While there, a number of QUIC constants from spec defined and magic numbers were replaced.
author Vladimir Homutov <vl@nginx.com>
date Tue, 03 Mar 2020 13:30:30 +0300
parents 6091506af0f7
children 6a76d9657772
comparison
equal deleted inserted replaced
8183:6091506af0f7 8184:ec1f84996990
72 72
73 #define ngx_quic_hexdump0(log, fmt, data, len) \ 73 #define ngx_quic_hexdump0(log, fmt, data, len) \
74 ngx_quic_hexdump(log, fmt "%s", data, len, "") \ 74 ngx_quic_hexdump(log, fmt "%s", data, len, "") \
75 75
76 76
77 /* 17.2. Long Header Packets */
78
79 #define NGX_QUIC_PKT_LONG 0x80
80
81 #define NGX_QUIC_PKT_INITIAL 0xc0
82 #define NGX_QUIC_PKT_HANDSHAKE 0xe0
83
84 /* 12.4. Frames and Frame Types */
85 #define NGX_QUIC_FT_PADDING 0x00
86 #define NGX_QUIC_FT_PING 0x01
87 #define NGX_QUIC_FT_ACK 0x02
88 #define NGX_QUIC_FT_ACK_ECN 0x03
89 #define NGX_QUIC_FT_RESET_STREAM 0x04
90 #define NGX_QUIC_FT_STOP_SENDING 0x05
91 #define NGX_QUIC_FT_CRYPTO 0x06
92 #define NGX_QUIC_FT_NEW_TOKEN 0x07
93 #define NGX_QUIC_FT_STREAM 0x08 // - 0x0f
94 #define NGX_QUIC_FT_MAX_DATA 0x10
95 #define NGX_QUIC_FT_MAX_STREAM_DATA 0x11
96 #define NGX_QUIC_FT_MAX_STREAMS 0x12
97 #define NGX_QUIC_FT_MAX_STREAMS2 0x13 // XXX
98 #define NGX_QUIC_FT_DATA_BLOCKED 0x14
99 #define NGX_QUIC_FT_STREAM_DATA_BLOCKED 0x15
100 #define NGX_QUIC_FT_STREAMS_BLOCKED 0x16
101 #define NGX_QUIC_FT_STREAMS_BLOCKED2 0x17 // XXX
102 #define NGX_QUIC_FT_NEW_CONNECTION_ID 0x18
103 #define NGX_QUIC_FT_RETIRE_CONNECTION_ID 0x19
104 #define NGX_QUIC_FT_PATH_CHALLENGE 0x1a
105 #define NGX_QUIC_FT_PATH_RESPONSE 0x1b
106 #define NGX_QUIC_FT_CONNECTION_CLOSE 0x1c
107 #define NGX_QUIC_FT_CONNECTION_CLOSE2 0x1d // XXX
108 #define NGX_QUIC_FT_HANDSHAKE_DONE 0x1e
109
77 110
78 /* TODO: real states, these are stubs */ 111 /* TODO: real states, these are stubs */
79 typedef enum { 112 typedef enum {
80 NGX_QUIC_ST_INITIAL, 113 NGX_QUIC_ST_INITIAL,
81 NGX_QUIC_ST_HANDSHAKE, 114 NGX_QUIC_ST_HANDSHAKE,
99 ngx_str_t out; // stub for some kind of output queue 132 ngx_str_t out; // stub for some kind of output queue
100 133
101 ngx_str_t scid; 134 ngx_str_t scid;
102 ngx_str_t dcid; 135 ngx_str_t dcid;
103 ngx_str_t token; 136 ngx_str_t token;
137
138 /* current packet numbers for each namespace */
139 ngx_uint_t initial_pn;
140 ngx_uint_t handshake_pn;
141 ngx_uint_t appdata_pn;
104 142
105 ngx_quic_secret_t client_in; 143 ngx_quic_secret_t client_in;
106 ngx_quic_secret_t client_hs; 144 ngx_quic_secret_t client_hs;
107 ngx_quic_secret_t client_ad; 145 ngx_quic_secret_t client_ad;
108 ngx_quic_secret_t server_in; 146 ngx_quic_secret_t server_in;
109 ngx_quic_secret_t server_hs; 147 ngx_quic_secret_t server_hs;
110 ngx_quic_secret_t server_ad; 148 ngx_quic_secret_t server_ad;
111 }; 149 };
112 150
113 151
152 typedef enum ssl_encryption_level_t ngx_quic_level_t;
153
154 typedef struct {
155 ngx_quic_secret_t *secret;
156 ngx_uint_t type;
157 ngx_uint_t *number;
158 ngx_uint_t flags;
159 ngx_uint_t version;
160 ngx_str_t *token;
161 ngx_quic_level_t level;
162 } ngx_quic_header_t;
163
164
114 static ngx_int_t ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, 165 static ngx_int_t ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl,
115 ngx_buf_t *b); 166 ngx_buf_t *b);
116 static ngx_int_t ngx_quic_handshake_input(ngx_connection_t *c, ngx_buf_t *b); 167 static ngx_int_t ngx_quic_handshake_input(ngx_connection_t *c, ngx_buf_t *b);
117 168
118 static int ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn, 169 static int ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn,
119 enum ssl_encryption_level_t level, const uint8_t *read_secret, 170 enum ssl_encryption_level_t level, const uint8_t *read_secret,
120 const uint8_t *write_secret, size_t secret_len); 171 const uint8_t *write_secret, size_t secret_len);
121 static int ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, 172 static int ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn,
122 enum ssl_encryption_level_t level, const uint8_t *data, size_t len); 173 enum ssl_encryption_level_t level, const uint8_t *data, size_t len);
174 static ngx_int_t ngx_quic_create_long_packet(ngx_connection_t *c,
175 ngx_ssl_conn_t *ssl_conn, ngx_quic_header_t *pkt, ngx_str_t *in,
176 ngx_str_t *res);
123 static int ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn); 177 static int ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn);
124 static int ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, 178 static int ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn,
125 enum ssl_encryption_level_t level, uint8_t alert); 179 enum ssl_encryption_level_t level, uint8_t alert);
126 180
127 static uint64_t ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask); 181 static uint64_t ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask);
286 340
287 return 1; 341 return 1;
288 } 342 }
289 343
290 344
345 static ngx_int_t
346 ngx_quic_create_long_packet(ngx_connection_t *c, ngx_ssl_conn_t *ssl_conn,
347 ngx_quic_header_t *pkt, ngx_str_t *payload, ngx_str_t *res)
348 {
349 u_char *p, *pnp, *name, *nonce, *sample, *packet;
350 ngx_str_t ad, out;
351 const EVP_CIPHER *cipher;
352 ngx_quic_connection_t *qc;
353
354 u_char mask[16];
355
356 qc = c->quic;
357
358 out.len = payload->len + EVP_GCM_TLS_TAG_LEN;
359
360 ad.data = ngx_alloc(346 /*max header*/, c->log);
361 if (ad.data == 0) {
362 return NGX_ERROR;
363 }
364
365 p = ad.data;
366
367 *p++ = pkt->flags;
368
369 p = ngx_quic_write_uint32(p, quic_version);
370
371 *p++ = qc->scid.len;
372 p = ngx_cpymem(p, qc->scid.data, qc->scid.len);
373
374 *p++ = qc->dcid.len;
375 p = ngx_cpymem(p, qc->dcid.data, qc->dcid.len);
376
377 if (pkt->token) { // if pkt->flags & initial ?
378 ngx_quic_build_int(&p, pkt->token->len);
379 }
380
381 ngx_quic_build_int(&p, out.len + 1); // length (inc. pnl)
382 pnp = p;
383
384 *p++ = (*pkt->number)++;
385
386 ad.len = p - ad.data;
387
388 ngx_quic_hexdump0(c->log, "ad", ad.data, ad.len);
389
390 name = (u_char *) SSL_get_cipher(ssl_conn);
391
392 if (ngx_strcasecmp(name, (u_char *) "TLS_AES_128_GCM_SHA256") == 0
393 || ngx_strcasecmp(name, (u_char *) "(NONE)") == 0)
394 {
395 cipher = EVP_aes_128_gcm();
396
397 } else if (ngx_strcasecmp(name, (u_char *) "TLS_AES_256_GCM_SHA384") == 0) {
398 cipher = EVP_aes_256_gcm();
399
400 } else {
401 return NGX_ERROR;
402 }
403
404 nonce = ngx_pstrdup(c->pool, &pkt->secret->iv);
405 if (pkt->level == ssl_encryption_handshake) {
406 nonce[11] ^= (*pkt->number - 1);
407 }
408
409 ngx_quic_hexdump0(c->log, "server_iv", pkt->secret->iv.data, 12);
410 ngx_quic_hexdump0(c->log, "nonce", nonce, 12);
411
412 if (ngx_quic_tls_seal(c, cipher, pkt->secret, &out, nonce, payload, &ad) != NGX_OK) {
413 return NGX_ERROR;
414 }
415
416 sample = &out.data[3]; // pnl=0
417 if (ngx_quic_tls_hp(c, EVP_aes_128_ecb(), pkt->secret, mask, sample) != NGX_OK) {
418 return NGX_ERROR;
419 }
420
421 ngx_quic_hexdump0(c->log, "sample", sample, 16);
422 ngx_quic_hexdump0(c->log, "mask", mask, 16);
423 ngx_quic_hexdump0(c->log, "hp_key", pkt->secret->hp.data, 16);
424
425 // header protection, pnl = 0
426 ad.data[0] ^= mask[0] & 0x0f;
427 *pnp ^= mask[1];
428
429 packet = ngx_alloc(ad.len + out.len, c->log);
430 if (packet == 0) {
431 return NGX_ERROR;
432 }
433
434 p = ngx_cpymem(packet, ad.data, ad.len);
435 p = ngx_cpymem(p, out.data, out.len);
436
437 res->data = packet;
438 res->len = p - packet;
439
440 return NGX_OK;
441 }
442
443
444 static void
445 ngx_quic_create_ack(u_char **p)
446 {
447 ngx_quic_build_int(p, NGX_QUIC_FT_ACK);
448 ngx_quic_build_int(p, 0);
449 ngx_quic_build_int(p, 0);
450 ngx_quic_build_int(p, 0);
451 ngx_quic_build_int(p, 0);
452 }
453
454
455 static void
456 ngx_quic_create_crypto(u_char **p, u_char *data, size_t len)
457 {
458 ngx_quic_build_int(p, NGX_QUIC_FT_CRYPTO);
459 ngx_quic_build_int(p, 0);
460 ngx_quic_build_int(p, len);
461 *p = ngx_cpymem(*p, data, len);
462 }
463
464
465
291 static int 466 static int
292 ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, 467 ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn,
293 enum ssl_encryption_level_t level, const uint8_t *data, size_t len) 468 enum ssl_encryption_level_t level, const uint8_t *data, size_t len)
294 { 469 {
295 u_char *p, *pnp, *name, *nonce, *sample; 470 u_char *p;
296 ngx_str_t in, out, ad; 471 ngx_str_t payload, res;
297 static int pn;
298 const EVP_CIPHER *cipher;
299 ngx_connection_t *c; 472 ngx_connection_t *c;
300 ngx_quic_secret_t *secret; 473 ngx_quic_header_t pkt;
301 ngx_quic_connection_t *qc; 474 ngx_quic_connection_t *qc;
302 u_char mask[16]; 475
476 ngx_str_t initial_token = ngx_null_string;
303 477
304 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); 478 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
305 qc = c->quic; 479 qc = c->quic;
306 480
307 //ngx_ssl_handshake_log(c); // TODO: enable again 481 //ngx_ssl_handshake_log(c); // TODO: enable again
308 482
309 switch (level) { 483 ngx_memzero(&pkt, sizeof(ngx_quic_header_t));
310 484
311 case ssl_encryption_initial: 485 pkt.level = level;
312 secret = &qc->server_in; 486
313 break; 487 payload.data = ngx_alloc(4 + len + 5 /*minimal ACK*/, c->log);
314 488 if (payload.data == 0) {
315 case ssl_encryption_handshake:
316 secret = &qc->server_hs;
317 break;
318
319 default:
320 return 0; 489 return 0;
321 } 490 }
322 491 p = payload.data;
323 ngx_quic_hexdump(c->log, "level:%d read", data, len, level); 492
324 493 ngx_quic_create_crypto(&p, (u_char *) data, len);
325 in.data = ngx_alloc(4 + len + 5 /*minimal ACK*/, c->log); 494
326 if (in.data == 0) { 495 if (level == ssl_encryption_initial) {
496 ngx_quic_create_ack(&p);
497
498 pkt.number = &qc->initial_pn;
499 pkt.flags = NGX_QUIC_PKT_INITIAL;
500 pkt.secret = &qc->server_in;
501
502 pkt.token = &initial_token;
503
504 } else if (level == ssl_encryption_handshake) {
505 pkt.number = &qc->handshake_pn;
506 pkt.flags = NGX_QUIC_PKT_HANDSHAKE;
507 pkt.secret = &qc->server_hs;
508
509 pkt.token = NULL;
510
511 } else {
512 pkt.number = &qc->appdata_pn;
513 }
514
515 payload.len = p - payload.data;
516
517 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
518 "ngx_quic_add_handshake_data: clear_len:%uz",
519 payload.len);
520
521 if (ngx_quic_create_long_packet(c, ssl_conn, &pkt, &payload, &res)
522 != NGX_OK)
523 {
327 return 0; 524 return 0;
328 } 525 }
329 526
330 p = in.data;
331 ngx_quic_build_int(&p, 6); // crypto frame
332 ngx_quic_build_int(&p, 0);
333 ngx_quic_build_int(&p, len);
334 p = ngx_cpymem(p, data, len);
335
336 if (level == ssl_encryption_initial) {
337 ngx_quic_build_int(&p, 2); // ack frame
338 ngx_quic_build_int(&p, 0);
339 ngx_quic_build_int(&p, 0);
340 ngx_quic_build_int(&p, 0);
341 ngx_quic_build_int(&p, 0);
342 }
343
344 in.len = p - in.data;
345 out.len = in.len + EVP_GCM_TLS_TAG_LEN;
346
347 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
348 "ngx_quic_add_handshake_data: clear_len:%uz, ciphertext_len:%uz",
349 in.len, out.len);
350
351 ad.data = ngx_alloc(346 /*max header*/, c->log);
352 if (ad.data == 0) {
353 return 0;
354 }
355
356 p = ad.data;
357 if (level == ssl_encryption_initial) {
358 *p++ = 0xc0; // initial, packet number len
359 } else if (level == ssl_encryption_handshake) {
360 *p++ = 0xe0; // handshake, packet number len
361 }
362 p = ngx_quic_write_uint32(p, quic_version);
363 *p++ = qc->scid.len;
364 p = ngx_cpymem(p, qc->scid.data, qc->scid.len);
365 *p++ = qc->dcid.len;
366 p = ngx_cpymem(p, qc->dcid.data, qc->dcid.len);
367 if (level == ssl_encryption_initial) {
368 ngx_quic_build_int(&p, 0); // token length
369 }
370 ngx_quic_build_int(&p, out.len + 1); // length (inc. pnl)
371 pnp = p;
372
373 if (level == ssl_encryption_initial) {
374 *p++ = 0; // packet number 0
375
376 } else if (level == ssl_encryption_handshake) {
377 *p++ = pn++;
378 }
379
380 ad.len = p - ad.data;
381
382 ngx_quic_hexdump0(c->log, "ad", data, len);
383
384 name = (u_char *) SSL_get_cipher(ssl_conn);
385
386 if (ngx_strcasecmp(name, (u_char *) "TLS_AES_128_GCM_SHA256") == 0
387 || ngx_strcasecmp(name, (u_char *) "(NONE)") == 0)
388 {
389 cipher = EVP_aes_128_gcm();
390
391 } else if (ngx_strcasecmp(name, (u_char *) "TLS_AES_256_GCM_SHA384") == 0) {
392 cipher = EVP_aes_256_gcm();
393
394 } else {
395 return 0;
396 }
397
398 nonce = ngx_pstrdup(c->pool, &secret->iv);
399 if (level == ssl_encryption_handshake) {
400 nonce[11] ^= (pn - 1);
401 }
402
403 ngx_quic_hexdump0(c->log, "server_iv", secret->iv.data, 12);
404 ngx_quic_hexdump(c->log, "sample: n=%d nonce", nonce, 12, pn - 1);
405
406 if (ngx_quic_tls_seal(c, cipher, secret, &out, nonce, &in, &ad) != NGX_OK)
407 {
408 return 0;
409 }
410
411 sample = &out.data[3]; // pnl=0
412 if (ngx_quic_tls_hp(c, EVP_aes_128_ecb(), secret, mask, sample) != NGX_OK) {
413 return 0;
414 }
415
416 ngx_quic_hexdump0(c->log, "sample", sample, 16);
417 ngx_quic_hexdump0(c->log, "mask", mask, 16);
418 ngx_quic_hexdump0(c->log, "hp_key", secret->hp.data, 16);
419
420 // header protection, pnl = 0
421 ad.data[0] ^= mask[0] & 0x0f;
422 *pnp ^= mask[1];
423
424 u_char *packet = ngx_alloc(ad.len + out.len, c->log);
425 if (packet == 0) {
426 return 0;
427 }
428
429 p = ngx_cpymem(packet, ad.data, ad.len);
430 p = ngx_cpymem(p, out.data, out.len);
431
432 ngx_quic_hexdump0(c->log, "packet", packet, p - packet);
433
434 // TODO: save state of data to send into qc (push into queue) 527 // TODO: save state of data to send into qc (push into queue)
435 528 qc->out = res;
436 qc->out.data = packet;
437 qc->out.len = p - packet;
438 529
439 if (ngx_quic_output(c) != NGX_OK) { 530 if (ngx_quic_output(c) != NGX_OK) {
440 return 0; 531 return 0;
441 } 532 }
442 533
477 ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_buf_t *b) 568 ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_buf_t *b)
478 { 569 {
479 int n, sslerr; 570 int n, sslerr;
480 ngx_quic_connection_t *qc; 571 ngx_quic_connection_t *qc;
481 572
482 if ((b->pos[0] & 0xf0) != 0xc0) { 573 if ((b->pos[0] & 0xf0) != NGX_QUIC_PKT_INITIAL) {
483 ngx_log_error(NGX_LOG_INFO, c->log, 0, "invalid initial packet"); 574 ngx_log_error(NGX_LOG_INFO, c->log, 0, "invalid initial packet");
484 return NGX_ERROR; 575 return NGX_ERROR;
485 } 576 }
486 577
487 if (ngx_buf_size(b) < 1200) { 578 if (ngx_buf_size(b) < 1200) {
805 p = bb->pos; 896 p = bb->pos;
806 b = bb->start; 897 b = bb->start;
807 898
808 ngx_quic_hexdump0(c->log, "input", buf, n); 899 ngx_quic_hexdump0(c->log, "input", buf, n);
809 900
810 if ((p[0] & 0xf0) != 0xe0) { 901 if ((p[0] & 0xf0) != NGX_QUIC_PKT_HANDSHAKE) {
811 ngx_log_error(NGX_LOG_INFO, c->log, 0, "invalid packet type"); 902 ngx_log_error(NGX_LOG_INFO, c->log, 0, "invalid packet type");
812 return NGX_ERROR; 903 return NGX_ERROR;
813 } 904 }
814 905
815 ngx_int_t flags = *p++; 906 ngx_int_t flags = *p++;