comparison src/event/quic/ngx_event_quic.c @ 8686:dffb66fb783b quic

QUIC: stateless retry. Previously, quic connection object was created when Retry packet was sent. This is neither necessary nor convenient, and contradicts the idea of retry: protecting from bad clients and saving server resources. Now, the connection is not created, token is verified cryptographically instead of holding it in connection.
author Vladimir Homutov <vl@nginx.com>
date Fri, 29 Jan 2021 15:53:47 +0300
parents 7df607cb2d11
children 1c6343bd7933
comparison
equal deleted inserted replaced
8685:dbe33ef9cd9a 8686:dffb66fb783b
7 #include <ngx_config.h> 7 #include <ngx_config.h>
8 #include <ngx_core.h> 8 #include <ngx_core.h>
9 #include <ngx_event.h> 9 #include <ngx_event.h>
10 #include <ngx_event_quic_transport.h> 10 #include <ngx_event_quic_transport.h>
11 #include <ngx_event_quic_protection.h> 11 #include <ngx_event_quic_protection.h>
12 #include <ngx_sha1.h>
12 13
13 14
14 /* 0-RTT and 1-RTT data exist in the same packet number space, 15 /* 0-RTT and 1-RTT data exist in the same packet number space,
15 * so we have 3 packet number spaces: 16 * so we have 3 packet number spaces:
16 * 17 *
111 112
112 uint32_t version; 113 uint32_t version;
113 ngx_str_t scid; /* initial client ID */ 114 ngx_str_t scid; /* initial client ID */
114 ngx_str_t dcid; /* server (our own) ID */ 115 ngx_str_t dcid; /* server (our own) ID */
115 ngx_str_t odcid; /* original server ID */ 116 ngx_str_t odcid; /* original server ID */
116 ngx_str_t token;
117 117
118 struct sockaddr *sockaddr; 118 struct sockaddr *sockaddr;
119 socklen_t socklen; 119 socklen_t socklen;
120 120
121 ngx_queue_t client_ids; 121 ngx_queue_t client_ids;
173 unsigned error_app:1; 173 unsigned error_app:1;
174 unsigned send_timer_set:1; 174 unsigned send_timer_set:1;
175 unsigned closing:1; 175 unsigned closing:1;
176 unsigned draining:1; 176 unsigned draining:1;
177 unsigned key_phase:1; 177 unsigned key_phase:1;
178 unsigned in_retry:1;
179 unsigned initialized:1;
180 unsigned validated:1; 178 unsigned validated:1;
181 } ngx_quic_connection_t; 179 } ngx_quic_connection_t;
182 180
183 181
184 typedef struct { 182 typedef struct {
233 ngx_quic_header_t *inpkt); 231 ngx_quic_header_t *inpkt);
234 static ngx_int_t ngx_quic_create_server_id(ngx_connection_t *c, u_char *id); 232 static ngx_int_t ngx_quic_create_server_id(ngx_connection_t *c, u_char *id);
235 #if (NGX_QUIC_BPF) 233 #if (NGX_QUIC_BPF)
236 static ngx_int_t ngx_quic_bpf_attach_id(ngx_connection_t *c, u_char *id); 234 static ngx_int_t ngx_quic_bpf_attach_id(ngx_connection_t *c, u_char *id);
237 #endif 235 #endif
238 static ngx_int_t ngx_quic_send_retry(ngx_connection_t *c); 236 static ngx_int_t ngx_quic_send_retry(ngx_connection_t *c,
239 static ngx_int_t ngx_quic_new_token(ngx_connection_t *c, ngx_str_t *token); 237 ngx_quic_conf_t *conf, ngx_quic_header_t *pkt);
238 static ngx_int_t ngx_quic_new_token(ngx_connection_t *c, u_char *key,
239 ngx_str_t *token, ngx_str_t *odcid, time_t expires, ngx_uint_t is_retry);
240 static void ngx_quic_address_hash(ngx_connection_t *c, ngx_uint_t no_port,
241 u_char buf[20]);
240 static ngx_int_t ngx_quic_validate_token(ngx_connection_t *c, 242 static ngx_int_t ngx_quic_validate_token(ngx_connection_t *c,
241 ngx_quic_header_t *pkt); 243 u_char *key, ngx_quic_header_t *pkt);
242 static ngx_int_t ngx_quic_init_connection(ngx_connection_t *c); 244 static ngx_int_t ngx_quic_init_connection(ngx_connection_t *c);
243 static ngx_inline size_t ngx_quic_max_udp_payload(ngx_connection_t *c); 245 static ngx_inline size_t ngx_quic_max_udp_payload(ngx_connection_t *c);
244 static void ngx_quic_input_handler(ngx_event_t *rev); 246 static void ngx_quic_input_handler(ngx_event_t *rev);
245 247
246 static void ngx_quic_close_connection(ngx_connection_t *c, ngx_int_t rc); 248 static void ngx_quic_close_connection(ngx_connection_t *c, ngx_int_t rc);
251 253
252 static ngx_int_t ngx_quic_input(ngx_connection_t *c, ngx_buf_t *b, 254 static ngx_int_t ngx_quic_input(ngx_connection_t *c, ngx_buf_t *b,
253 ngx_quic_conf_t *conf); 255 ngx_quic_conf_t *conf);
254 static ngx_int_t ngx_quic_process_packet(ngx_connection_t *c, 256 static ngx_int_t ngx_quic_process_packet(ngx_connection_t *c,
255 ngx_quic_conf_t *conf, ngx_quic_header_t *pkt); 257 ngx_quic_conf_t *conf, ngx_quic_header_t *pkt);
256 static ngx_int_t ngx_quic_init_secrets(ngx_connection_t *c); 258 static ngx_int_t ngx_quic_send_early_cc(ngx_connection_t *c,
259 ngx_quic_header_t *inpkt, ngx_uint_t err, const char *reason);
257 static void ngx_quic_discard_ctx(ngx_connection_t *c, 260 static void ngx_quic_discard_ctx(ngx_connection_t *c,
258 enum ssl_encryption_level_t level); 261 enum ssl_encryption_level_t level);
259 static ngx_int_t ngx_quic_check_peer(ngx_quic_connection_t *qc, 262 static ngx_int_t ngx_quic_check_peer(ngx_quic_connection_t *qc,
260 ngx_quic_header_t *pkt); 263 ngx_quic_header_t *pkt);
261 static ngx_int_t ngx_quic_payload_handler(ngx_connection_t *c, 264 static ngx_int_t ngx_quic_payload_handler(ngx_connection_t *c,
671 } 674 }
672 675
673 p = ngx_slprintf(p, last, "%s", qc->closing ? " closing" : ""); 676 p = ngx_slprintf(p, last, "%s", qc->closing ? " closing" : "");
674 p = ngx_slprintf(p, last, "%s", qc->draining ? " draining" : ""); 677 p = ngx_slprintf(p, last, "%s", qc->draining ? " draining" : "");
675 p = ngx_slprintf(p, last, "%s", qc->key_phase ? " kp" : ""); 678 p = ngx_slprintf(p, last, "%s", qc->key_phase ? " kp" : "");
676 p = ngx_slprintf(p, last, "%s", qc->in_retry ? " retry" : "");
677 p = ngx_slprintf(p, last, "%s", qc->validated? " valid" : ""); 679 p = ngx_slprintf(p, last, "%s", qc->validated? " valid" : "");
678 680
679 } else { 681 } else {
680 p = ngx_slprintf(p, last, " early"); 682 p = ngx_slprintf(p, last, " early");
681 } 683 }
1012 return; 1014 return;
1013 } 1015 }
1014 1016
1015 qc = ngx_quic_get_connection(c); 1017 qc = ngx_quic_get_connection(c);
1016 1018
1017 ngx_add_timer(c->read, qc->in_retry ? NGX_QUIC_RETRY_TIMEOUT 1019 if (qc == NULL) {
1018 : qc->tp.max_idle_timeout); 1020 ngx_quic_close_connection(c, NGX_DONE);
1021 return;
1022 }
1023
1024 ngx_add_timer(c->read, qc->tp.max_idle_timeout);
1025 ngx_quic_connstate_dbg(c);
1019 1026
1020 c->read->handler = ngx_quic_input_handler; 1027 c->read->handler = ngx_quic_input_handler;
1021 1028
1022 ngx_quic_connstate_dbg(c);
1023 return; 1029 return;
1024 } 1030 }
1025 1031
1026 1032
1027 static ngx_quic_connection_t * 1033 static ngx_quic_connection_t *
1121 ngx_max(2 * qc->tp.max_udp_payload_size, 1127 ngx_max(2 * qc->tp.max_udp_payload_size,
1122 14720)); 1128 14720));
1123 qc->congestion.ssthresh = (size_t) -1; 1129 qc->congestion.ssthresh = (size_t) -1;
1124 qc->congestion.recovery_start = ngx_current_msec; 1130 qc->congestion.recovery_start = ngx_current_msec;
1125 1131
1126 qc->odcid.len = pkt->dcid.len; 1132 qc->odcid.len = pkt->odcid.len;
1127 qc->odcid.data = ngx_pstrdup(c->pool, &pkt->dcid); 1133 qc->odcid.data = ngx_pstrdup(c->pool, &pkt->odcid);
1128 if (qc->odcid.data == NULL) { 1134 if (qc->odcid.data == NULL) {
1129 return NULL; 1135 return NULL;
1130 } 1136 }
1131 1137
1132 qc->dcid.len = NGX_QUIC_SERVER_CID_LEN; 1138 qc->dcid.len = NGX_QUIC_SERVER_CID_LEN;
1142 #if (NGX_QUIC_DRAFT_VERSION >= 28) 1148 #if (NGX_QUIC_DRAFT_VERSION >= 28)
1143 qc->tp.original_dcid = qc->odcid; 1149 qc->tp.original_dcid = qc->odcid;
1144 #endif 1150 #endif
1145 qc->tp.initial_scid = qc->dcid; 1151 qc->tp.initial_scid = qc->dcid;
1146 1152
1153 if (pkt->validated && pkt->retried) {
1154 qc->tp.retry_scid.len = pkt->dcid.len;
1155 qc->tp.retry_scid.data = ngx_pstrdup(c->pool, &pkt->dcid);
1156 if (qc->tp.retry_scid.data == NULL) {
1157 return NULL;
1158 }
1159 }
1160
1147 qc->scid.len = pkt->scid.len; 1161 qc->scid.len = pkt->scid.len;
1148 qc->scid.data = ngx_pnalloc(c->pool, qc->scid.len); 1162 qc->scid.data = ngx_pstrdup(c->pool, &pkt->scid);
1149 if (qc->scid.data == NULL) { 1163 if (qc->scid.data == NULL) {
1150 return NULL; 1164 return NULL;
1151 } 1165 }
1152 ngx_memcpy(qc->scid.data, pkt->scid.data, qc->scid.len);
1153 1166
1154 cid = ngx_quic_alloc_client_id(c, qc); 1167 cid = ngx_quic_alloc_client_id(c, qc);
1155 if (cid == NULL) { 1168 if (cid == NULL) {
1156 return NULL; 1169 return NULL;
1157 } 1170 }
1163 ngx_queue_insert_tail(&qc->client_ids, &cid->queue); 1176 ngx_queue_insert_tail(&qc->client_ids, &cid->queue);
1164 qc->nclient_ids++; 1177 qc->nclient_ids++;
1165 qc->client_seqnum = 0; 1178 qc->client_seqnum = 0;
1166 1179
1167 qc->server_seqnum = NGX_QUIC_UNSET_PN; 1180 qc->server_seqnum = NGX_QUIC_UNSET_PN;
1181
1182 if (ngx_quic_keys_set_initial_secret(c->pool, qc->keys, &pkt->dcid)
1183 != NGX_OK)
1184 {
1185 return NULL;
1186 }
1187
1188 c->udp = &qc->udp;
1189
1190 if (ngx_quic_insert_server_id(c, &qc->odcid) == NULL) {
1191 return NULL;
1192 }
1193
1194 qc->server_seqnum = 0;
1195
1196 if (ngx_quic_insert_server_id(c, &qc->dcid) == NULL) {
1197 return NULL;
1198 }
1199
1200 qc->validated = pkt->validated;
1168 1201
1169 return qc; 1202 return qc;
1170 } 1203 }
1171 1204
1172 1205
1342 1375
1343 #endif 1376 #endif
1344 1377
1345 1378
1346 static ngx_int_t 1379 static ngx_int_t
1347 ngx_quic_send_retry(ngx_connection_t *c) 1380 ngx_quic_send_retry(ngx_connection_t *c, ngx_quic_conf_t *conf,
1348 { 1381 ngx_quic_header_t *inpkt)
1349 ssize_t len; 1382 {
1350 ngx_str_t res, token; 1383 time_t expires;
1351 ngx_quic_header_t pkt; 1384 ssize_t len;
1352 ngx_quic_connection_t *qc; 1385 ngx_str_t res, token;
1353 u_char buf[NGX_QUIC_RETRY_BUFFER_SIZE]; 1386 ngx_quic_header_t pkt;
1354 1387
1355 qc = ngx_quic_get_connection(c); 1388 u_char buf[NGX_QUIC_RETRY_BUFFER_SIZE];
1356 1389 u_char dcid[NGX_QUIC_SERVER_CID_LEN];
1357 if (ngx_quic_new_token(c, &token) != NGX_OK) { 1390
1391 expires = ngx_time() + NGX_QUIC_RETRY_LIFETIME;
1392
1393 if (ngx_quic_new_token(c, conf->token_key, &token, &inpkt->dcid, expires, 1)
1394 != NGX_OK)
1395 {
1358 return NGX_ERROR; 1396 return NGX_ERROR;
1359 } 1397 }
1360 1398
1361 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); 1399 ngx_memzero(&pkt, sizeof(ngx_quic_header_t));
1362 pkt.flags = NGX_QUIC_PKT_FIXED_BIT | NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_RETRY; 1400 pkt.flags = NGX_QUIC_PKT_FIXED_BIT | NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_RETRY;
1363 pkt.version = qc->version; 1401 pkt.version = inpkt->version;
1364 pkt.log = c->log; 1402 pkt.log = c->log;
1365 pkt.odcid = qc->odcid; 1403
1366 pkt.dcid = qc->scid; 1404 pkt.odcid = inpkt->dcid;
1367 pkt.scid = qc->dcid; 1405 pkt.dcid = inpkt->scid;
1406
1407 /* TODO: generate routable dcid */
1408 if (RAND_bytes(dcid, NGX_QUIC_SERVER_CID_LEN) != 1) {
1409 return NGX_ERROR;
1410 }
1411
1412 pkt.scid.len = NGX_QUIC_SERVER_CID_LEN;
1413 pkt.scid.data = dcid;
1414
1368 pkt.token = token; 1415 pkt.token = token;
1369 1416
1370 res.data = buf; 1417 res.data = buf;
1371 1418
1372 if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { 1419 if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) {
1381 len = ngx_quic_send(c, res.data, res.len); 1428 len = ngx_quic_send(c, res.data, res.len);
1382 if (len == NGX_ERROR) { 1429 if (len == NGX_ERROR) {
1383 return NGX_ERROR; 1430 return NGX_ERROR;
1384 } 1431 }
1385 1432
1386 qc->token = token; 1433 ngx_log_debug(NGX_LOG_DEBUG_EVENT, c->log, 0,
1387 #if (NGX_QUIC_DRAFT_VERSION < 28) 1434 "quic retry packet sent to %xV", &pkt.dcid);
1388 qc->tp.original_dcid = qc->odcid; 1435
1389 #endif 1436 /*
1390 qc->tp.retry_scid = qc->dcid; 1437 * quic-transport 17.2.5.1: A server MUST NOT send more than one Retry
1391 qc->in_retry = 1; 1438 * packet in response to a single UDP datagram.
1392 1439 * NGX_DONE will stop quic_input() from processing further
1393 if (ngx_quic_insert_server_id(c, &qc->dcid) == NULL) { 1440 */
1394 return NGX_ERROR; 1441 return NGX_DONE;
1395 }
1396
1397 return NGX_OK;
1398 } 1442 }
1399 1443
1400 1444
1401 static ngx_int_t 1445 static ngx_int_t
1402 ngx_quic_new_token(ngx_connection_t *c, ngx_str_t *token) 1446 ngx_quic_new_token(ngx_connection_t *c, u_char *key, ngx_str_t *token,
1403 { 1447 ngx_str_t *odcid, time_t exp, ngx_uint_t is_retry)
1404 int len, iv_len; 1448 {
1405 u_char *data, *p, *key, *iv; 1449 int len, iv_len;
1406 ngx_msec_t now; 1450 u_char *p, *iv;
1407 EVP_CIPHER_CTX *ctx; 1451 EVP_CIPHER_CTX *ctx;
1408 const EVP_CIPHER *cipher; 1452 const EVP_CIPHER *cipher;
1409 struct sockaddr_in *sin; 1453
1410 #if (NGX_HAVE_INET6) 1454 u_char in[NGX_QUIC_MAX_TOKEN_SIZE];
1411 struct sockaddr_in6 *sin6; 1455
1412 #endif 1456 ngx_quic_address_hash(c, !is_retry, in);
1413 ngx_quic_connection_t *qc; 1457
1414 u_char in[NGX_QUIC_MAX_TOKEN_SIZE]; 1458 p = in + 20;
1415 1459
1416 switch (c->sockaddr->sa_family) { 1460 p = ngx_cpymem(p, &exp, sizeof(time_t));
1417 1461
1418 #if (NGX_HAVE_INET6) 1462 *p++ = is_retry ? 1 : 0;
1419 case AF_INET6: 1463
1420 sin6 = (struct sockaddr_in6 *) c->sockaddr; 1464 if (odcid) {
1421 1465 *p++ = odcid->len;
1422 len = sizeof(struct in6_addr); 1466 p = ngx_cpymem(p, odcid->data, odcid->len);
1423 data = sin6->sin6_addr.s6_addr; 1467
1424 1468 } else {
1425 break; 1469 *p++ = 0;
1426 #endif 1470 }
1427 1471
1428 #if (NGX_HAVE_UNIX_DOMAIN) 1472 len = p - in;
1429 case AF_UNIX:
1430
1431 len = ngx_min(c->addr_text.len, NGX_QUIC_MAX_TOKEN_SIZE - sizeof(now));
1432 data = c->addr_text.data;
1433
1434 break;
1435 #endif
1436
1437 default: /* AF_INET */
1438 sin = (struct sockaddr_in *) c->sockaddr;
1439
1440 len = sizeof(in_addr_t);
1441 data = (u_char *) &sin->sin_addr;
1442
1443 break;
1444 }
1445
1446 p = ngx_cpymem(in, data, len);
1447
1448 now = ngx_current_msec;
1449 len += sizeof(now);
1450 ngx_memcpy(p, &now, sizeof(now));
1451 1473
1452 cipher = EVP_aes_256_cbc(); 1474 cipher = EVP_aes_256_cbc();
1453 iv_len = EVP_CIPHER_iv_length(cipher); 1475 iv_len = EVP_CIPHER_iv_length(cipher);
1454 1476
1455 token->len = iv_len + len + EVP_CIPHER_block_size(cipher); 1477 token->len = iv_len + len + EVP_CIPHER_block_size(cipher);
1461 ctx = EVP_CIPHER_CTX_new(); 1483 ctx = EVP_CIPHER_CTX_new();
1462 if (ctx == NULL) { 1484 if (ctx == NULL) {
1463 return NGX_ERROR; 1485 return NGX_ERROR;
1464 } 1486 }
1465 1487
1466 qc = ngx_quic_get_connection(c);
1467 key = qc->conf->token_key;
1468 iv = token->data; 1488 iv = token->data;
1469 1489
1470 if (RAND_bytes(iv, iv_len) <= 0 1490 if (RAND_bytes(iv, iv_len) <= 0
1471 || !EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv)) 1491 || !EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv))
1472 { 1492 {
1499 1519
1500 return NGX_OK; 1520 return NGX_OK;
1501 } 1521 }
1502 1522
1503 1523
1524 static void
1525 ngx_quic_address_hash(ngx_connection_t *c, ngx_uint_t no_port, u_char buf[20])
1526 {
1527 size_t len;
1528 u_char *data;
1529 ngx_sha1_t sha1;
1530 struct sockaddr_in *sin;
1531 #if (NGX_HAVE_INET6)
1532 struct sockaddr_in6 *sin6;
1533 #endif
1534
1535 len = (size_t) c->socklen;
1536 data = (u_char *) c->sockaddr;
1537
1538 if (no_port) {
1539 switch (c->sockaddr->sa_family) {
1540
1541 #if (NGX_HAVE_INET6)
1542 case AF_INET6:
1543 sin6 = (struct sockaddr_in6 *) c->sockaddr;
1544
1545 len = sizeof(struct in6_addr);
1546 data = sin6->sin6_addr.s6_addr;
1547
1548 break;
1549 #endif
1550
1551 case AF_INET:
1552 sin = (struct sockaddr_in *) c->sockaddr;
1553
1554 len = sizeof(in_addr_t);
1555 data = (u_char *) &sin->sin_addr;
1556
1557 break;
1558 }
1559 }
1560
1561 ngx_sha1_init(&sha1);
1562 ngx_sha1_update(&sha1, data, len);
1563 ngx_sha1_final(buf, &sha1);
1564 }
1565
1566
1504 static ngx_int_t 1567 static ngx_int_t
1505 ngx_quic_validate_token(ngx_connection_t *c, ngx_quic_header_t *pkt) 1568 ngx_quic_validate_token(ngx_connection_t *c, u_char *key,
1506 { 1569 ngx_quic_header_t *pkt)
1507 int len, tlen, iv_len; 1570 {
1508 u_char *key, *iv, *p, *data; 1571 int len, tlen, iv_len;
1509 ngx_msec_t msec; 1572 u_char *iv, *p;
1510 EVP_CIPHER_CTX *ctx; 1573 time_t now, exp;
1511 const EVP_CIPHER *cipher; 1574 size_t total;
1512 struct sockaddr_in *sin; 1575 ngx_str_t odcid;
1513 #if (NGX_HAVE_INET6) 1576 EVP_CIPHER_CTX *ctx;
1514 struct sockaddr_in6 *sin6; 1577 const EVP_CIPHER *cipher;
1515 #endif 1578
1516 ngx_quic_connection_t *qc; 1579 u_char addr_hash[20];
1517 u_char tdec[NGX_QUIC_MAX_TOKEN_SIZE]; 1580 u_char tdec[NGX_QUIC_MAX_TOKEN_SIZE];
1518 1581
1519 qc = ngx_quic_get_connection(c); 1582 /* Retry token or NEW_TOKEN in a previous connection */
1520
1521 /* Retry token */
1522
1523 if (qc->token.len) {
1524 if (pkt->token.len != qc->token.len) {
1525 goto bad_token;
1526 }
1527
1528 if (ngx_memcmp(pkt->token.data, qc->token.data, pkt->token.len) != 0) {
1529 goto bad_token;
1530 }
1531
1532 return NGX_OK;
1533 }
1534
1535 /* NEW_TOKEN in a previous connection */
1536 1583
1537 cipher = EVP_aes_256_cbc(); 1584 cipher = EVP_aes_256_cbc();
1538 key = qc->conf->token_key;
1539 iv = pkt->token.data; 1585 iv = pkt->token.data;
1540 iv_len = EVP_CIPHER_iv_length(cipher); 1586 iv_len = EVP_CIPHER_iv_length(cipher);
1541 1587
1542 /* sanity checks */ 1588 /* sanity checks */
1543 1589
1544 if (pkt->token.len < (size_t) iv_len + EVP_CIPHER_block_size(cipher)) { 1590 if (pkt->token.len < (size_t) iv_len + EVP_CIPHER_block_size(cipher)) {
1545 goto bad_token; 1591 goto garbage;
1546 } 1592 }
1547 1593
1548 if (pkt->token.len > (size_t) iv_len + NGX_QUIC_MAX_TOKEN_SIZE) { 1594 if (pkt->token.len > (size_t) iv_len + NGX_QUIC_MAX_TOKEN_SIZE) {
1549 goto bad_token; 1595 goto garbage;
1550 } 1596 }
1551 1597
1552 ctx = EVP_CIPHER_CTX_new(); 1598 ctx = EVP_CIPHER_CTX_new();
1553 if (ctx == NULL) { 1599 if (ctx == NULL) {
1554 return NGX_ERROR; 1600 return NGX_ERROR;
1562 p = pkt->token.data + iv_len; 1608 p = pkt->token.data + iv_len;
1563 len = pkt->token.len - iv_len; 1609 len = pkt->token.len - iv_len;
1564 1610
1565 if (EVP_DecryptUpdate(ctx, tdec, &len, p, len) != 1) { 1611 if (EVP_DecryptUpdate(ctx, tdec, &len, p, len) != 1) {
1566 EVP_CIPHER_CTX_free(ctx); 1612 EVP_CIPHER_CTX_free(ctx);
1567 goto bad_token; 1613 goto garbage;
1568 } 1614 }
1615 total = len;
1569 1616
1570 if (EVP_DecryptFinal_ex(ctx, tdec + len, &tlen) <= 0) { 1617 if (EVP_DecryptFinal_ex(ctx, tdec + len, &tlen) <= 0) {
1571 EVP_CIPHER_CTX_free(ctx); 1618 EVP_CIPHER_CTX_free(ctx);
1619 goto garbage;
1620 }
1621 total += tlen;
1622
1623 EVP_CIPHER_CTX_free(ctx);
1624
1625 if (total < (20 + sizeof(time_t) + 2)) {
1626 goto garbage;
1627 }
1628
1629 p = tdec + 20;
1630
1631 ngx_memcpy(&exp, p, sizeof(time_t));
1632 p += sizeof(time_t);
1633
1634 pkt->retried = (*p++ == 1);
1635
1636 ngx_quic_address_hash(c, !pkt->retried, addr_hash);
1637
1638 if (ngx_memcmp(tdec, addr_hash, 20) != 0) {
1572 goto bad_token; 1639 goto bad_token;
1573 } 1640 }
1574 1641
1575 EVP_CIPHER_CTX_free(ctx); 1642 odcid.len = *p++;
1576 1643 if (odcid.len) {
1577 switch (c->sockaddr->sa_family) { 1644 if (odcid.len > NGX_QUIC_MAX_CID_LEN) {
1578 1645 goto bad_token;
1579 #if (NGX_HAVE_INET6) 1646 }
1580 case AF_INET6: 1647
1581 sin6 = (struct sockaddr_in6 *) c->sockaddr; 1648 if ((size_t)(tdec + total - p) < odcid.len) {
1582 1649 goto bad_token;
1583 len = sizeof(struct in6_addr); 1650 }
1584 data = sin6->sin6_addr.s6_addr; 1651
1585 1652 odcid.data = p;
1586 break; 1653 p += odcid.len;
1587 #endif 1654 }
1588 1655
1589 #if (NGX_HAVE_UNIX_DOMAIN) 1656 now = ngx_time();
1590 case AF_UNIX: 1657
1591 1658 if (now > exp) {
1592 len = ngx_min(c->addr_text.len, NGX_QUIC_MAX_TOKEN_SIZE - sizeof(msec));
1593 data = c->addr_text.data;
1594
1595 break;
1596 #endif
1597
1598 default: /* AF_INET */
1599 sin = (struct sockaddr_in *) c->sockaddr;
1600
1601 len = sizeof(in_addr_t);
1602 data = (u_char *) &sin->sin_addr;
1603
1604 break;
1605 }
1606
1607 if (ngx_memcmp(tdec, data, len) != 0) {
1608 goto bad_token;
1609 }
1610
1611 ngx_memcpy(&msec, tdec + len, sizeof(msec));
1612
1613 if (ngx_current_msec - msec > NGX_QUIC_RETRY_LIFETIME) {
1614 ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic expired token"); 1659 ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic expired token");
1615 return NGX_DECLINED; 1660 return NGX_DECLINED;
1616 } 1661 }
1617 1662
1663 if (odcid.len) {
1664 pkt->odcid.len = odcid.len;
1665 pkt->odcid.data = ngx_pstrdup(c->pool, &odcid);
1666 if (pkt->odcid.data == NULL) {
1667 return NGX_ERROR;
1668 }
1669
1670 } else {
1671 pkt->odcid = pkt->dcid;
1672 }
1673
1674 pkt->validated = 1;
1675
1618 return NGX_OK; 1676 return NGX_OK;
1619 1677
1678 garbage:
1679
1680 ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic garbage token");
1681
1682 return NGX_ABORT;
1683
1620 bad_token: 1684 bad_token:
1621 1685
1622 ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic invalid token"); 1686 ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic invalid token");
1623
1624 qc->error = NGX_QUIC_ERR_INVALID_TOKEN;
1625 qc->error_reason = "invalid_token";
1626 1687
1627 return NGX_DECLINED; 1688 return NGX_DECLINED;
1628 } 1689 }
1629 1690
1630 1691
1815 "quic ngx_quic_close_connection rc:%i", rc); 1876 "quic ngx_quic_close_connection rc:%i", rc);
1816 1877
1817 qc = ngx_quic_get_connection(c); 1878 qc = ngx_quic_get_connection(c);
1818 1879
1819 if (qc == NULL) { 1880 if (qc == NULL) {
1820 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, 1881 if (rc == NGX_ERROR) {
1821 "quic close connection early error"); 1882 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
1883 "quic close connection early error");
1884 }
1822 1885
1823 } else if (ngx_quic_close_quic(c, rc) == NGX_AGAIN) { 1886 } else if (ngx_quic_close_quic(c, rc) == NGX_AGAIN) {
1824 return; 1887 return;
1825 } 1888 }
1826 1889
2097 } 2160 }
2098 #endif 2161 #endif
2099 2162
2100 if (rc == NGX_ERROR) { 2163 if (rc == NGX_ERROR) {
2101 return NGX_ERROR; 2164 return NGX_ERROR;
2165 }
2166
2167 if (rc == NGX_DONE) {
2168 /* stop further processing */
2169 return NGX_DECLINED;
2102 } 2170 }
2103 2171
2104 if (rc == NGX_OK) { 2172 if (rc == NGX_OK) {
2105 good = 1; 2173 good = 1;
2106 } 2174 }
2214 } 2282 }
2215 2283
2216 return NGX_DECLINED; 2284 return NGX_DECLINED;
2217 } 2285 }
2218 2286
2219 if (qc->in_retry) {
2220
2221 c->log->action = "retrying quic connection";
2222
2223 if (pkt->level != ssl_encryption_initial) {
2224 ngx_log_error(NGX_LOG_INFO, c->log, 0,
2225 "quic discard late retry packet");
2226 return NGX_DECLINED;
2227 }
2228
2229 if (!pkt->token.len) {
2230 ngx_log_error(NGX_LOG_INFO, c->log, 0,
2231 "quic discard retry packet without token");
2232 return NGX_DECLINED;
2233 }
2234
2235 qc->odcid.len = pkt->dcid.len;
2236 qc->odcid.data = ngx_pstrdup(c->pool, &pkt->dcid);
2237 if (qc->odcid.data == NULL) {
2238 return NGX_ERROR;
2239 }
2240
2241 ngx_quic_clear_temp_server_ids(c);
2242
2243 qc->dcid.len = NGX_QUIC_SERVER_CID_LEN;
2244 qc->dcid.data = ngx_pnalloc(c->pool, qc->dcid.len);
2245 if (qc->dcid.data == NULL) {
2246 return NGX_ERROR;
2247 }
2248
2249 if (ngx_quic_create_server_id(c, qc->dcid.data) != NGX_OK) {
2250 return NGX_ERROR;
2251 }
2252
2253 qc->server_seqnum = 0;
2254
2255 if (ngx_quic_insert_server_id(c, &qc->dcid) == NULL) {
2256 return NGX_ERROR;
2257 }
2258
2259 qc->tp.initial_scid = qc->dcid;
2260 qc->in_retry = 0;
2261
2262 if (ngx_quic_init_secrets(c) != NGX_OK) {
2263 return NGX_ERROR;
2264 }
2265
2266 if (ngx_quic_validate_token(c, pkt) != NGX_OK) {
2267 return NGX_ERROR;
2268 }
2269
2270 qc->validated = 1;
2271 }
2272
2273 } else { 2287 } else {
2274 2288
2275 if (rc == NGX_ABORT) { 2289 if (rc == NGX_ABORT) {
2276 return ngx_quic_negotiate_version(c, pkt); 2290 return ngx_quic_negotiate_version(c, pkt);
2277 } 2291 }
2278 2292
2279 if (pkt->level == ssl_encryption_initial) { 2293 if (pkt->level == ssl_encryption_initial) {
2280 2294 c->log->action = "processing initial packet";
2281 c->log->action = "creating quic connection";
2282 2295
2283 if (pkt->dcid.len < NGX_QUIC_CID_LEN_MIN) { 2296 if (pkt->dcid.len < NGX_QUIC_CID_LEN_MIN) {
2284 /* 7.2. Negotiating Connection IDs */ 2297 /* 7.2. Negotiating Connection IDs */
2285 ngx_log_error(NGX_LOG_INFO, c->log, 0, 2298 ngx_log_error(NGX_LOG_INFO, c->log, 0,
2286 "quic too short dcid in initial" 2299 "quic too short dcid in initial"
2287 " packet: len:%i", pkt->dcid.len); 2300 " packet: len:%i", pkt->dcid.len);
2288 return NGX_ERROR; 2301 return NGX_ERROR;
2289 } 2302 }
2290 2303
2304 /* process retry and initialize connection IDs */
2305
2306 if (pkt->token.len) {
2307
2308 rc = ngx_quic_validate_token(c, conf->token_key, pkt);
2309
2310 if (rc == NGX_ERROR) {
2311 /* internal error */
2312 return NGX_ERROR;
2313
2314 } else if (rc == NGX_ABORT) {
2315 /* token cannot be decrypted */
2316 return ngx_quic_send_early_cc(c, pkt,
2317 NGX_QUIC_ERR_INVALID_TOKEN,
2318 "cannot decrypt token");
2319 } else if (rc == NGX_DECLINED) {
2320 /* token is invalid */
2321
2322 if (pkt->retried) {
2323 /* invalid Retry token */
2324 return ngx_quic_send_early_cc(c, pkt,
2325 NGX_QUIC_ERR_INVALID_TOKEN,
2326 "invalid token");
2327 } else if (conf->retry) {
2328 /* invalid NEW_TOKEN */
2329 return ngx_quic_send_retry(c, conf, pkt);
2330 }
2331 }
2332
2333 /* NGX_OK */
2334
2335 } else if (conf->retry) {
2336 return ngx_quic_send_retry(c, conf, pkt);
2337
2338 } else {
2339 pkt->odcid = pkt->dcid;
2340 }
2341
2342 if (ngx_terminate || ngx_exiting) {
2343 if (conf->retry) {
2344 return ngx_quic_send_retry(c, conf, pkt);
2345 }
2346
2347 return NGX_ERROR;
2348 }
2349
2350 c->log->action = "creating quic connection";
2351
2291 qc = ngx_quic_new_connection(c, conf, pkt); 2352 qc = ngx_quic_new_connection(c, conf, pkt);
2292 if (qc == NULL) { 2353 if (qc == NULL) {
2293 return NGX_ERROR;
2294 }
2295
2296 c->udp = &qc->udp;
2297
2298 if (ngx_terminate || ngx_exiting) {
2299 qc->error = NGX_QUIC_ERR_CONNECTION_REFUSED;
2300 return NGX_ERROR;
2301 }
2302
2303 if (pkt->token.len) {
2304 rc = ngx_quic_validate_token(c, pkt);
2305
2306 if (rc == NGX_OK) {
2307 qc->validated = 1;
2308
2309 } else if (rc == NGX_ERROR) {
2310 return NGX_ERROR;
2311
2312 } else {
2313 /* NGX_DECLINED */
2314 if (conf->retry) {
2315 return ngx_quic_send_retry(c);
2316 }
2317 }
2318
2319 } else if (conf->retry) {
2320 return ngx_quic_send_retry(c);
2321 }
2322
2323 if (ngx_quic_init_secrets(c) != NGX_OK) {
2324 return NGX_ERROR;
2325 }
2326
2327 if (ngx_quic_insert_server_id(c, &qc->odcid) == NULL) {
2328 return NGX_ERROR;
2329 }
2330
2331 qc->server_seqnum = 0;
2332
2333 if (ngx_quic_insert_server_id(c, &qc->dcid) == NULL) {
2334 return NGX_ERROR; 2354 return NGX_ERROR;
2335 } 2355 }
2336 2356
2337 } else if (pkt->level == ssl_encryption_application) { 2357 } else if (pkt->level == ssl_encryption_application) {
2338 return ngx_quic_send_stateless_reset(c, conf, pkt); 2358 return ngx_quic_send_stateless_reset(c, conf, pkt);
2409 return ngx_quic_keys_update(c, qc->keys); 2429 return ngx_quic_keys_update(c, qc->keys);
2410 } 2430 }
2411 2431
2412 2432
2413 static ngx_int_t 2433 static ngx_int_t
2414 ngx_quic_init_secrets(ngx_connection_t *c) 2434 ngx_quic_send_early_cc(ngx_connection_t *c, ngx_quic_header_t *inpkt,
2415 { 2435 ngx_uint_t err, const char *reason)
2416 ngx_quic_connection_t *qc; 2436 {
2417 2437 ssize_t len;
2418 qc = ngx_quic_get_connection(c); 2438 ngx_str_t res;
2419 2439 ngx_quic_frame_t frame;
2420 if (ngx_quic_keys_set_initial_secret(c->pool, qc->keys, &qc->odcid) 2440 ngx_quic_header_t pkt;
2441
2442 static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
2443 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE];
2444
2445 ngx_memzero(&frame, sizeof(ngx_quic_frame_t));
2446 ngx_memzero(&pkt, sizeof(ngx_quic_header_t));
2447
2448 frame.level = inpkt->level;
2449 frame.type = NGX_QUIC_FT_CONNECTION_CLOSE;
2450 frame.u.close.error_code = err;
2451
2452 frame.u.close.reason.data = (u_char *) reason;
2453 frame.u.close.reason.len = ngx_strlen(reason);
2454
2455 len = ngx_quic_create_frame(NULL, &frame);
2456 if (len > NGX_QUIC_MAX_UDP_PAYLOAD_SIZE) {
2457 return NGX_ERROR;
2458 }
2459
2460 ngx_quic_log_frame(c->log, &frame, 1);
2461
2462 len = ngx_quic_create_frame(src, &frame);
2463 if (len == -1) {
2464 return NGX_ERROR;
2465 }
2466
2467 pkt.keys = ngx_quic_keys_new(c->pool);
2468 if (pkt.keys == NULL) {
2469 return NGX_ERROR;
2470 }
2471
2472 if (ngx_quic_keys_set_initial_secret(c->pool, pkt.keys, &inpkt->dcid)
2421 != NGX_OK) 2473 != NGX_OK)
2422 { 2474 {
2423 return NGX_ERROR; 2475 return NGX_ERROR;
2424 } 2476 }
2425 2477
2426 qc->initialized = 1; 2478 pkt.flags = NGX_QUIC_PKT_FIXED_BIT | NGX_QUIC_PKT_LONG
2479 | NGX_QUIC_PKT_INITIAL;
2480
2481 pkt.num_len = 1;
2482 /*
2483 * pkt.num = 0;
2484 * pkt.trunc = 0;
2485 */
2486
2487 pkt.version = inpkt->version;
2488 pkt.log = c->log;
2489 pkt.level = inpkt->level;
2490 pkt.dcid = inpkt->scid;
2491 pkt.scid = inpkt->dcid;
2492 pkt.payload.data = src;
2493 pkt.payload.len = len;
2494
2495 res.data = dst;
2496
2497 if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) {
2498 return NGX_ERROR;
2499 }
2500
2501 if (ngx_quic_send(c, res.data, res.len) == NGX_ERROR) {
2502 return NGX_ERROR;
2503 }
2427 2504
2428 return NGX_OK; 2505 return NGX_OK;
2429 } 2506 }
2430 2507
2431 2508
3154 3231
3155 if (qc->draining) { 3232 if (qc->draining) {
3156 return NGX_OK; 3233 return NGX_OK;
3157 } 3234 }
3158 3235
3159 if (!qc->initialized) {
3160 /* try to initialize secrets to send an early error */
3161 if (ngx_quic_init_secrets(c) != NGX_OK) {
3162 return NGX_OK;
3163 }
3164 }
3165
3166 if (qc->closing 3236 if (qc->closing
3167 && ngx_current_msec - qc->last_cc < NGX_QUIC_CC_MIN_INTERVAL) 3237 && ngx_current_msec - qc->last_cc < NGX_QUIC_CC_MIN_INTERVAL)
3168 { 3238 {
3169 /* dot not send CC too often */ 3239 /* dot not send CC too often */
3170 return NGX_OK; 3240 return NGX_OK;
3195 3265
3196 3266
3197 static ngx_int_t 3267 static ngx_int_t
3198 ngx_quic_send_new_token(ngx_connection_t *c) 3268 ngx_quic_send_new_token(ngx_connection_t *c)
3199 { 3269 {
3270 time_t expires;
3200 ngx_str_t token; 3271 ngx_str_t token;
3201 ngx_quic_frame_t *frame; 3272 ngx_quic_frame_t *frame;
3202 ngx_quic_connection_t *qc; 3273 ngx_quic_connection_t *qc;
3203 3274
3204 qc = ngx_quic_get_connection(c); 3275 qc = ngx_quic_get_connection(c);
3205 3276
3206 if (!qc->conf->retry) { 3277 if (!qc->conf->retry) {
3207 return NGX_OK; 3278 return NGX_OK;
3208 } 3279 }
3209 3280
3210 if (ngx_quic_new_token(c, &token) != NGX_OK) { 3281 expires = ngx_time() + NGX_QUIC_NEW_TOKEN_LIFETIME;
3282
3283 if (ngx_quic_new_token(c, qc->conf->token_key, &token, NULL, expires, 0)
3284 != NGX_OK)
3285 {
3211 return NGX_ERROR; 3286 return NGX_ERROR;
3212 } 3287 }
3213 3288
3214 frame = ngx_quic_alloc_frame(c); 3289 frame = ngx_quic_alloc_frame(c);
3215 if (frame == NULL) { 3290 if (frame == NULL) {