Mercurial > hg > nginx-quic
comparison src/event/ngx_event_quic.c @ 8098:d0d3fc0697a0 quic
QUIC: packet processing refactoring.
All packet header parsing is now performed by ngx_quic_parse_packet()
function, located in the ngx_quic_transport.c file.
The packet processing is centralized in the ngx_quic_process_packet()
function which decides if the packet should be accepted, ignored or
connection should be closed, depending on the connection state.
As a result of refactoring, behavior has changed in some places:
- minimal size of Initial packet is now always tested
- connection IDs are always tested in existing connections
- old keys are discarded on encryption level switch
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Wed, 30 Sep 2020 15:14:09 +0300 |
parents | a89a58c642ef |
children | b4ef79ef1c23 |
comparison
equal
deleted
inserted
replaced
8097:a89a58c642ef | 8098:d0d3fc0697a0 |
---|---|
185 static ngx_int_t ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, | 185 static ngx_int_t ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, |
186 ngx_quic_conf_t *conf, ngx_quic_header_t *pkt); | 186 ngx_quic_conf_t *conf, ngx_quic_header_t *pkt); |
187 static ngx_int_t ngx_quic_negotiate_version(ngx_connection_t *c, | 187 static ngx_int_t ngx_quic_negotiate_version(ngx_connection_t *c, |
188 ngx_quic_header_t *inpkt); | 188 ngx_quic_header_t *inpkt); |
189 static ngx_int_t ngx_quic_new_dcid(ngx_connection_t *c, ngx_str_t *odcid); | 189 static ngx_int_t ngx_quic_new_dcid(ngx_connection_t *c, ngx_str_t *odcid); |
190 static ngx_int_t ngx_quic_retry(ngx_connection_t *c); | 190 static ngx_int_t ngx_quic_send_retry(ngx_connection_t *c); |
191 static ngx_int_t ngx_quic_new_token(ngx_connection_t *c, ngx_str_t *token); | 191 static ngx_int_t ngx_quic_new_token(ngx_connection_t *c, ngx_str_t *token); |
192 static ngx_int_t ngx_quic_validate_token(ngx_connection_t *c, | 192 static ngx_int_t ngx_quic_validate_token(ngx_connection_t *c, |
193 ngx_quic_header_t *pkt); | 193 ngx_quic_header_t *pkt); |
194 static ngx_int_t ngx_quic_init_connection(ngx_connection_t *c); | 194 static ngx_int_t ngx_quic_init_connection(ngx_connection_t *c); |
195 static ngx_inline size_t ngx_quic_max_udp_payload(ngx_connection_t *c); | 195 static ngx_inline size_t ngx_quic_max_udp_payload(ngx_connection_t *c); |
199 static ngx_int_t ngx_quic_close_quic(ngx_connection_t *c, ngx_int_t rc); | 199 static ngx_int_t ngx_quic_close_quic(ngx_connection_t *c, ngx_int_t rc); |
200 static void ngx_quic_close_timer_handler(ngx_event_t *ev); | 200 static void ngx_quic_close_timer_handler(ngx_event_t *ev); |
201 static ngx_int_t ngx_quic_close_streams(ngx_connection_t *c, | 201 static ngx_int_t ngx_quic_close_streams(ngx_connection_t *c, |
202 ngx_quic_connection_t *qc); | 202 ngx_quic_connection_t *qc); |
203 | 203 |
204 static ngx_int_t ngx_quic_input(ngx_connection_t *c, ngx_buf_t *b); | 204 static ngx_int_t ngx_quic_input(ngx_connection_t *c, ngx_buf_t *b, |
205 static ngx_inline u_char *ngx_quic_skip_zero_padding(ngx_buf_t *b); | 205 ngx_ssl_t *ssl, ngx_quic_conf_t *conf); |
206 static ngx_int_t ngx_quic_retry_input(ngx_connection_t *c, | 206 static ngx_int_t ngx_quic_process_packet(ngx_connection_t *c, ngx_ssl_t *ssl, |
207 ngx_quic_header_t *pkt); | 207 ngx_quic_conf_t *conf, ngx_quic_header_t *pkt); |
208 static ngx_int_t ngx_quic_initial_input(ngx_connection_t *c, | 208 static void ngx_quic_discard_ctx(ngx_connection_t *c, |
209 ngx_quic_header_t *pkt); | 209 enum ssl_encryption_level_t level); |
210 static ngx_int_t ngx_quic_handshake_input(ngx_connection_t *c, | |
211 ngx_quic_header_t *pkt); | |
212 static ngx_int_t ngx_quic_early_input(ngx_connection_t *c, | |
213 ngx_quic_header_t *pkt); | |
214 static ngx_int_t ngx_quic_check_peer(ngx_quic_connection_t *qc, | 210 static ngx_int_t ngx_quic_check_peer(ngx_quic_connection_t *qc, |
215 ngx_quic_header_t *pkt); | |
216 static ngx_int_t ngx_quic_app_input(ngx_connection_t *c, | |
217 ngx_quic_header_t *pkt); | 211 ngx_quic_header_t *pkt); |
218 static ngx_int_t ngx_quic_payload_handler(ngx_connection_t *c, | 212 static ngx_int_t ngx_quic_payload_handler(ngx_connection_t *c, |
219 ngx_quic_header_t *pkt); | 213 ngx_quic_header_t *pkt); |
220 static ngx_int_t ngx_quic_send_ack(ngx_connection_t *c, ngx_quic_header_t *pkt); | 214 static ngx_int_t ngx_quic_send_ack(ngx_connection_t *c, ngx_quic_header_t *pkt); |
221 static ngx_int_t ngx_quic_ack_delay(ngx_connection_t *c, | 215 static ngx_int_t ngx_quic_ack_delay(ngx_connection_t *c, |
628 | 622 |
629 | 623 |
630 void | 624 void |
631 ngx_quic_run(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_conf_t *conf) | 625 ngx_quic_run(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_conf_t *conf) |
632 { | 626 { |
633 ngx_int_t rc; | 627 ngx_int_t rc; |
634 ngx_buf_t *b; | |
635 ngx_quic_header_t pkt; | |
636 | 628 |
637 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic run"); | 629 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic run"); |
638 | 630 |
639 c->log->action = "QUIC initialization"; | 631 c->log->action = "QUIC initialization"; |
640 | 632 |
641 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); | 633 rc = ngx_quic_input(c, c->buffer, ssl, conf); |
642 | |
643 b = c->buffer; | |
644 | |
645 pkt.log = c->log; | |
646 pkt.raw = b; | |
647 pkt.data = b->start; | |
648 pkt.len = b->last - b->start; | |
649 | |
650 rc = ngx_quic_new_connection(c, ssl, conf, &pkt); | |
651 if (rc != NGX_OK) { | 634 if (rc != NGX_OK) { |
652 ngx_quic_close_connection(c, rc == NGX_DECLINED ? NGX_DONE : NGX_ERROR); | 635 ngx_quic_close_connection(c, rc == NGX_DECLINED ? NGX_DONE : NGX_ERROR); |
653 return; | 636 return; |
654 } | 637 } |
655 | 638 |
664 | 647 |
665 static ngx_int_t | 648 static ngx_int_t |
666 ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, | 649 ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, |
667 ngx_quic_conf_t *conf, ngx_quic_header_t *pkt) | 650 ngx_quic_conf_t *conf, ngx_quic_header_t *pkt) |
668 { | 651 { |
669 ngx_int_t rc; | |
670 ngx_uint_t i; | 652 ngx_uint_t i; |
671 ngx_quic_tp_t *ctp; | 653 ngx_quic_tp_t *ctp; |
672 ngx_quic_secrets_t *keys; | |
673 ngx_quic_send_ctx_t *ctx; | |
674 ngx_quic_client_id_t *cid; | 654 ngx_quic_client_id_t *cid; |
675 ngx_quic_connection_t *qc; | 655 ngx_quic_connection_t *qc; |
676 static u_char buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | |
677 | |
678 if (ngx_buf_size(pkt->raw) < NGX_QUIC_MIN_INITIAL_SIZE) { | |
679 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
680 "quic UDP datagram is too small for initial packet"); | |
681 return NGX_ERROR; | |
682 } | |
683 | |
684 if (ngx_quic_parse_long_header(pkt) != NGX_OK) { | |
685 return NGX_ERROR; | |
686 } | |
687 | |
688 if (pkt->version != NGX_QUIC_VERSION) { | |
689 return ngx_quic_negotiate_version(c, pkt); | |
690 } | |
691 | |
692 if (!ngx_quic_pkt_in(pkt->flags)) { | |
693 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
694 "quic invalid initial packet: 0x%xd", pkt->flags); | |
695 return NGX_ERROR; | |
696 } | |
697 | |
698 if (ngx_quic_parse_initial_header(pkt) != NGX_OK) { | |
699 return NGX_ERROR; | |
700 } | |
701 | |
702 if (pkt->dcid.len < NGX_QUIC_CID_LEN_MIN) { | |
703 /* 7.2. Negotiating Connection IDs */ | |
704 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
705 "quic too short dcid in initial packet: length %i", | |
706 pkt->dcid.len); | |
707 return NGX_ERROR; | |
708 } | |
709 | 656 |
710 c->log->action = "creating new quic connection"; | 657 c->log->action = "creating new quic connection"; |
711 | 658 |
712 qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t)); | 659 qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t)); |
713 if (qc == NULL) { | 660 if (qc == NULL) { |
802 | 749 |
803 ngx_queue_insert_tail(&qc->client_ids, &cid->queue); | 750 ngx_queue_insert_tail(&qc->client_ids, &cid->queue); |
804 qc->nclient_ids++; | 751 qc->nclient_ids++; |
805 qc->curr_seqnum = 0; | 752 qc->curr_seqnum = 0; |
806 | 753 |
807 keys = &c->quic->keys[ssl_encryption_initial]; | |
808 | |
809 if (ngx_quic_set_initial_secret(c->pool, &keys->client, &keys->server, | |
810 &qc->odcid) | |
811 != NGX_OK) | |
812 { | |
813 return NGX_ERROR; | |
814 } | |
815 | |
816 qc->initialized = 1; | 754 qc->initialized = 1; |
817 | 755 |
818 if (ngx_terminate || ngx_exiting) { | 756 if (ngx_terminate || ngx_exiting) { |
819 qc->error = NGX_QUIC_ERR_CONNECTION_REFUSED; | 757 qc->error = NGX_QUIC_ERR_CONNECTION_REFUSED; |
820 return NGX_ERROR; | 758 return NGX_ERROR; |
821 } | 759 } |
822 | |
823 if (pkt->token.len) { | |
824 rc = ngx_quic_validate_token(c, pkt); | |
825 | |
826 if (rc == NGX_ERROR) { | |
827 ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic invalid token"); | |
828 return NGX_ERROR; | |
829 } | |
830 | |
831 if (rc == NGX_DECLINED) { | |
832 ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic expired token"); | |
833 return ngx_quic_retry(c); | |
834 } | |
835 | |
836 /* NGX_OK */ | |
837 qc->validated = 1; | |
838 | |
839 } else if (conf->retry) { | |
840 return ngx_quic_retry(c); | |
841 } | |
842 | |
843 pkt->secret = &keys->client; | |
844 pkt->level = ssl_encryption_initial; | |
845 pkt->plaintext = buf; | |
846 | |
847 ctx = ngx_quic_get_send_ctx(qc, pkt->level); | |
848 | |
849 rc = ngx_quic_decrypt(pkt, NULL, &ctx->largest_pn); | |
850 if (rc != NGX_OK) { | |
851 qc->error = pkt->error; | |
852 qc->error_reason = "failed to decrypt packet"; | |
853 return rc; | |
854 } | |
855 | |
856 if (ngx_quic_init_connection(c) != NGX_OK) { | |
857 return NGX_ERROR; | |
858 } | |
859 | |
860 if (ngx_quic_payload_handler(c, pkt) != NGX_OK) { | |
861 return NGX_ERROR; | |
862 } | |
863 | |
864 /* pos is at header end, adjust by actual packet length */ | |
865 pkt->raw->pos += pkt->len; | |
866 | |
867 (void) ngx_quic_skip_zero_padding(pkt->raw); | |
868 | |
869 rc = ngx_quic_input(c, pkt->raw); | |
870 | |
871 if (rc == NGX_ERROR) { | |
872 return NGX_ERROR; | |
873 } | |
874 | |
875 /* rc == NGX_OK || rc == NGX_DECLINED */ | |
876 | 760 |
877 return NGX_OK; | 761 return NGX_OK; |
878 } | 762 } |
879 | 763 |
880 | 764 |
937 return NGX_OK; | 821 return NGX_OK; |
938 } | 822 } |
939 | 823 |
940 | 824 |
941 static ngx_int_t | 825 static ngx_int_t |
942 ngx_quic_retry(ngx_connection_t *c) | 826 ngx_quic_send_retry(ngx_connection_t *c) |
943 { | 827 { |
944 ssize_t len; | 828 ssize_t len; |
945 ngx_str_t res, token; | 829 ngx_str_t res, token; |
946 ngx_quic_header_t pkt; | 830 ngx_quic_header_t pkt; |
947 u_char buf[NGX_QUIC_RETRY_BUFFER_SIZE]; | 831 u_char buf[NGX_QUIC_RETRY_BUFFER_SIZE]; |
1192 } | 1076 } |
1193 | 1077 |
1194 ngx_memcpy(&msec, tdec + len, sizeof(msec)); | 1078 ngx_memcpy(&msec, tdec + len, sizeof(msec)); |
1195 | 1079 |
1196 if (ngx_current_msec - msec > NGX_QUIC_RETRY_LIFETIME) { | 1080 if (ngx_current_msec - msec > NGX_QUIC_RETRY_LIFETIME) { |
1081 ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic expired token"); | |
1197 return NGX_DECLINED; | 1082 return NGX_DECLINED; |
1198 } | 1083 } |
1199 | 1084 |
1200 return NGX_OK; | 1085 return NGX_OK; |
1201 | 1086 |
1202 bad_token: | 1087 bad_token: |
1088 | |
1089 ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic invalid token"); | |
1203 | 1090 |
1204 qc->error = NGX_QUIC_ERR_INVALID_TOKEN; | 1091 qc->error = NGX_QUIC_ERR_INVALID_TOKEN; |
1205 qc->error_reason = "invalid_token"; | 1092 qc->error_reason = "invalid_token"; |
1206 | 1093 |
1207 return NGX_ERROR; | 1094 return NGX_ERROR; |
1337 } | 1224 } |
1338 | 1225 |
1339 b.last += n; | 1226 b.last += n; |
1340 qc->received += n; | 1227 qc->received += n; |
1341 | 1228 |
1342 rc = ngx_quic_input(c, &b); | 1229 rc = ngx_quic_input(c, &b, NULL, NULL); |
1343 | 1230 |
1344 if (rc == NGX_ERROR) { | 1231 if (rc == NGX_ERROR) { |
1345 ngx_quic_close_connection(c, NGX_ERROR); | 1232 ngx_quic_close_connection(c, NGX_ERROR); |
1346 return; | 1233 return; |
1347 } | 1234 } |
1601 return NGX_AGAIN; | 1488 return NGX_AGAIN; |
1602 } | 1489 } |
1603 | 1490 |
1604 | 1491 |
1605 static ngx_int_t | 1492 static ngx_int_t |
1606 ngx_quic_input(ngx_connection_t *c, ngx_buf_t *b) | 1493 ngx_quic_input(ngx_connection_t *c, ngx_buf_t *b, ngx_ssl_t *ssl, |
1494 ngx_quic_conf_t *conf) | |
1607 { | 1495 { |
1608 u_char *p; | 1496 u_char *p; |
1609 ngx_int_t rc; | 1497 ngx_int_t rc; |
1610 ngx_uint_t good; | 1498 ngx_uint_t good; |
1611 ngx_quic_header_t pkt; | 1499 ngx_quic_header_t pkt; |
1623 pkt.len = b->last - p; | 1511 pkt.len = b->last - p; |
1624 pkt.log = c->log; | 1512 pkt.log = c->log; |
1625 pkt.flags = p[0]; | 1513 pkt.flags = p[0]; |
1626 pkt.raw->pos++; | 1514 pkt.raw->pos++; |
1627 | 1515 |
1628 if (c->quic->in_retry) { | 1516 rc = ngx_quic_process_packet(c, ssl, conf, &pkt); |
1629 rc = ngx_quic_retry_input(c, &pkt); | |
1630 | |
1631 } else if (ngx_quic_long_pkt(pkt.flags)) { | |
1632 | |
1633 if (ngx_quic_pkt_in(pkt.flags)) { | |
1634 rc = ngx_quic_initial_input(c, &pkt); | |
1635 | |
1636 } else if (ngx_quic_pkt_hs(pkt.flags)) { | |
1637 rc = ngx_quic_handshake_input(c, &pkt); | |
1638 | |
1639 } else if (ngx_quic_pkt_zrtt(pkt.flags)) { | |
1640 rc = ngx_quic_early_input(c, &pkt); | |
1641 | |
1642 } else { | |
1643 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1644 "quic unknown long packet type"); | |
1645 rc = NGX_DECLINED; | |
1646 } | |
1647 | |
1648 } else { | |
1649 rc = ngx_quic_app_input(c, &pkt); | |
1650 } | |
1651 | 1517 |
1652 if (rc == NGX_ERROR) { | 1518 if (rc == NGX_ERROR) { |
1653 return NGX_ERROR; | 1519 return NGX_ERROR; |
1654 } | 1520 } |
1655 | 1521 |
1676 * or cannot be parsed properly. | 1542 * or cannot be parsed properly. |
1677 */ | 1543 */ |
1678 | 1544 |
1679 /* b->pos is at header end, adjust by actual packet length */ | 1545 /* b->pos is at header end, adjust by actual packet length */ |
1680 b->pos = pkt.data + pkt.len; | 1546 b->pos = pkt.data + pkt.len; |
1681 p = ngx_quic_skip_zero_padding(b); | 1547 |
1548 /* firefox workaround: skip zero padding at the end of quic packet */ | |
1549 while (b->pos < b->last && *(b->pos) == 0) { | |
1550 b->pos++; | |
1551 } | |
1552 | |
1553 p = b->pos; | |
1682 } | 1554 } |
1683 | 1555 |
1684 return good ? NGX_OK : NGX_DECLINED; | 1556 return good ? NGX_OK : NGX_DECLINED; |
1685 } | 1557 } |
1686 | 1558 |
1687 | 1559 |
1688 /* firefox workaround: skip zero padding at the end of quic packet */ | |
1689 static ngx_inline u_char * | |
1690 ngx_quic_skip_zero_padding(ngx_buf_t *b) | |
1691 { | |
1692 while (b->pos < b->last && *(b->pos) == 0) { | |
1693 b->pos++; | |
1694 } | |
1695 | |
1696 return b->pos; | |
1697 } | |
1698 | |
1699 | |
1700 static ngx_int_t | 1560 static ngx_int_t |
1701 ngx_quic_retry_input(ngx_connection_t *c, ngx_quic_header_t *pkt) | 1561 ngx_quic_process_packet(ngx_connection_t *c, ngx_ssl_t *ssl, |
1562 ngx_quic_conf_t *conf, ngx_quic_header_t *pkt) | |
1702 { | 1563 { |
1703 ngx_int_t rc; | 1564 ngx_int_t rc; |
1704 ngx_quic_secrets_t *keys; | 1565 ngx_ssl_conn_t *ssl_conn; |
1566 ngx_quic_secrets_t *keys, *next, tmp; | |
1705 ngx_quic_send_ctx_t *ctx; | 1567 ngx_quic_send_ctx_t *ctx; |
1706 ngx_quic_connection_t *qc; | 1568 ngx_quic_connection_t *qc; |
1569 | |
1707 static u_char buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | 1570 static u_char buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; |
1708 | 1571 |
1709 c->log->action = "retrying quic connection"; | 1572 rc = ngx_quic_parse_packet(pkt); |
1710 | 1573 |
1711 if (ngx_buf_size(pkt->raw) < NGX_QUIC_MIN_INITIAL_SIZE) { | 1574 if (rc == NGX_DECLINED || rc == NGX_ERROR) { |
1575 return rc; | |
1576 } | |
1577 | |
1578 qc = c->quic; | |
1579 | |
1580 if (qc) { | |
1581 | |
1582 if (rc == NGX_ABORT) { | |
1583 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1584 "quic unsupported version: 0x%xD", pkt->version); | |
1585 return NGX_DECLINED; | |
1586 } | |
1587 | |
1588 if (ngx_quic_check_peer(qc, pkt) != NGX_OK) { | |
1589 return NGX_DECLINED; | |
1590 } | |
1591 | |
1592 if (qc->in_retry) { | |
1593 | |
1594 c->log->action = "retrying quic connection"; | |
1595 | |
1596 if (pkt->level != ssl_encryption_initial) { | |
1597 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1598 "quic discard late retry packet"); | |
1599 return NGX_DECLINED; | |
1600 } | |
1601 | |
1602 if (!pkt->token.len) { | |
1603 return NGX_DECLINED; | |
1604 } | |
1605 | |
1606 if (ngx_quic_new_dcid(c, &pkt->dcid) != NGX_OK) { | |
1607 return NGX_ERROR; | |
1608 } | |
1609 | |
1610 qc->tp.initial_scid = qc->dcid; | |
1611 qc->in_retry = 0; | |
1612 | |
1613 keys = &qc->keys[ssl_encryption_initial]; | |
1614 | |
1615 if (ngx_quic_set_initial_secret(c->pool, &keys->client, | |
1616 &keys->server, &qc->odcid) | |
1617 != NGX_OK) | |
1618 { | |
1619 return NGX_ERROR; | |
1620 } | |
1621 | |
1622 if (ngx_quic_validate_token(c, pkt) != NGX_OK) { | |
1623 return NGX_ERROR; | |
1624 } | |
1625 | |
1626 qc->validated = 1; | |
1627 } | |
1628 | |
1629 } else { | |
1630 | |
1631 if (rc == NGX_ABORT) { | |
1632 return ngx_quic_negotiate_version(c, pkt); | |
1633 } | |
1634 | |
1635 if (pkt->level == ssl_encryption_initial) { | |
1636 | |
1637 if (pkt->dcid.len < NGX_QUIC_CID_LEN_MIN) { | |
1638 /* 7.2. Negotiating Connection IDs */ | |
1639 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1640 "quic too short dcid in initial" | |
1641 " packet: length %i", pkt->dcid.len); | |
1642 return NGX_ERROR; | |
1643 } | |
1644 | |
1645 rc = ngx_quic_new_connection(c, ssl, conf, pkt); | |
1646 if (rc != NGX_OK) { | |
1647 return rc; | |
1648 } | |
1649 | |
1650 if (pkt->token.len) { | |
1651 if (ngx_quic_validate_token(c, pkt) != NGX_OK) { | |
1652 return NGX_ERROR; | |
1653 } | |
1654 | |
1655 } else if (conf->retry) { | |
1656 return ngx_quic_send_retry(c); | |
1657 } | |
1658 | |
1659 qc = c->quic; | |
1660 | |
1661 keys = &qc->keys[ssl_encryption_initial]; | |
1662 | |
1663 if (ngx_quic_set_initial_secret(c->pool, &keys->client, | |
1664 &keys->server, &qc->odcid) | |
1665 != NGX_OK) | |
1666 { | |
1667 return NGX_ERROR; | |
1668 } | |
1669 | |
1670 } else if (pkt->level == ssl_encryption_application) { | |
1671 return NGX_DECLINED; | |
1672 | |
1673 } else { | |
1674 return NGX_ERROR; | |
1675 } | |
1676 } | |
1677 | |
1678 keys = &qc->keys[pkt->level]; | |
1679 | |
1680 if (keys->client.key.len == 0) { | |
1712 ngx_log_error(NGX_LOG_INFO, c->log, 0, | 1681 ngx_log_error(NGX_LOG_INFO, c->log, 0, |
1713 "quic UDP datagram is too small for initial packet"); | 1682 "quic no level %d keys yet, ignoring packet", pkt->level); |
1714 return NGX_DECLINED; | 1683 return NGX_DECLINED; |
1715 } | 1684 } |
1716 | 1685 |
1717 if (ngx_quic_parse_long_header(pkt) != NGX_OK) { | 1686 next = &qc->next_key; |
1718 return NGX_DECLINED; | |
1719 } | |
1720 | |
1721 if (pkt->version != NGX_QUIC_VERSION) { | |
1722 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1723 "quic unsupported version: 0x%xD", pkt->version); | |
1724 return NGX_DECLINED; | |
1725 } | |
1726 | |
1727 if (ngx_quic_pkt_zrtt(pkt->flags)) { | |
1728 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1729 "quic discard inflight 0-RTT packet"); | |
1730 return NGX_DECLINED; | |
1731 } | |
1732 | |
1733 if (!ngx_quic_pkt_in(pkt->flags)) { | |
1734 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1735 "quic invalid initial packet: 0x%xd", pkt->flags); | |
1736 return NGX_DECLINED; | |
1737 } | |
1738 | |
1739 if (ngx_quic_parse_initial_header(pkt) != NGX_OK) { | |
1740 return NGX_DECLINED; | |
1741 } | |
1742 | |
1743 if (!pkt->token.len) { | |
1744 return NGX_DECLINED; | |
1745 } | |
1746 | |
1747 if (ngx_quic_new_dcid(c, &pkt->dcid) != NGX_OK) { | |
1748 return NGX_ERROR; | |
1749 } | |
1750 | |
1751 qc = c->quic; | |
1752 qc->tp.initial_scid = c->quic->dcid; | |
1753 | |
1754 keys = &c->quic->keys[ssl_encryption_initial]; | |
1755 | |
1756 if (ngx_quic_set_initial_secret(c->pool, &keys->client, &keys->server, | |
1757 &qc->odcid) | |
1758 != NGX_OK) | |
1759 { | |
1760 return NGX_ERROR; | |
1761 } | |
1762 | |
1763 c->quic->in_retry = 0; | |
1764 | |
1765 if (ngx_quic_validate_token(c, pkt) != NGX_OK) { | |
1766 ngx_log_error(NGX_LOG_INFO, c->log, 0, "quic invalid token"); | |
1767 return NGX_ERROR; | |
1768 } | |
1769 | |
1770 qc->validated = 1; | |
1771 | 1687 |
1772 pkt->secret = &keys->client; | 1688 pkt->secret = &keys->client; |
1773 pkt->level = ssl_encryption_initial; | 1689 pkt->next = &next->client; |
1690 pkt->key_phase = qc->key_phase; | |
1774 pkt->plaintext = buf; | 1691 pkt->plaintext = buf; |
1775 | 1692 |
1776 ctx = ngx_quic_get_send_ctx(qc, pkt->level); | 1693 ctx = ngx_quic_get_send_ctx(qc, pkt->level); |
1777 | 1694 |
1778 rc = ngx_quic_decrypt(pkt, NULL, &ctx->largest_pn); | 1695 ssl_conn = c->ssl ? c->ssl->connection : NULL; |
1779 if (rc != NGX_OK) { | |
1780 qc->error = pkt->error; | |
1781 qc->error_reason = "failed to decrypt packet"; | |
1782 return rc; | |
1783 } | |
1784 | |
1785 if (ngx_quic_init_connection(c) != NGX_OK) { | |
1786 return NGX_ERROR; | |
1787 } | |
1788 | |
1789 if (ngx_quic_payload_handler(c, pkt) != NGX_OK) { | |
1790 return NGX_ERROR; | |
1791 } | |
1792 | |
1793 return NGX_OK; | |
1794 } | |
1795 | |
1796 | |
1797 static ngx_int_t | |
1798 ngx_quic_initial_input(ngx_connection_t *c, ngx_quic_header_t *pkt) | |
1799 { | |
1800 ngx_int_t rc; | |
1801 ngx_ssl_conn_t *ssl_conn; | |
1802 ngx_quic_secrets_t *keys; | |
1803 ngx_quic_send_ctx_t *ctx; | |
1804 ngx_quic_connection_t *qc; | |
1805 static u_char buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | |
1806 | |
1807 c->log->action = "processing initial quic packet"; | |
1808 | |
1809 ssl_conn = c->ssl->connection; | |
1810 | |
1811 if (ngx_quic_parse_long_header(pkt) != NGX_OK) { | |
1812 return NGX_DECLINED; | |
1813 } | |
1814 | |
1815 if (pkt->version != NGX_QUIC_VERSION) { | |
1816 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1817 "quic unsupported version: 0x%xD", pkt->version); | |
1818 return NGX_DECLINED; | |
1819 } | |
1820 | |
1821 qc = c->quic; | |
1822 | |
1823 if (ngx_quic_check_peer(qc, pkt) != NGX_OK) { | |
1824 return NGX_DECLINED; | |
1825 } | |
1826 | |
1827 if (ngx_quic_parse_initial_header(pkt) != NGX_OK) { | |
1828 return NGX_DECLINED; | |
1829 } | |
1830 | |
1831 keys = &qc->keys[ssl_encryption_initial]; | |
1832 | |
1833 pkt->secret = &keys->client; | |
1834 pkt->level = ssl_encryption_initial; | |
1835 pkt->plaintext = buf; | |
1836 | |
1837 ctx = ngx_quic_get_send_ctx(qc, pkt->level); | |
1838 | 1696 |
1839 rc = ngx_quic_decrypt(pkt, ssl_conn, &ctx->largest_pn); | 1697 rc = ngx_quic_decrypt(pkt, ssl_conn, &ctx->largest_pn); |
1840 if (rc != NGX_OK) { | 1698 if (rc != NGX_OK) { |
1841 qc->error = pkt->error; | 1699 qc->error = pkt->error; |
1842 qc->error_reason = "failed to decrypt packet"; | 1700 qc->error_reason = "failed to decrypt packet"; |
1843 return rc; | 1701 return rc; |
1844 } | 1702 } |
1845 | 1703 |
1846 return ngx_quic_payload_handler(c, pkt); | 1704 if (c->ssl == NULL) { |
1847 } | 1705 if (ngx_quic_init_connection(c) != NGX_OK) { |
1848 | 1706 return NGX_ERROR; |
1849 | 1707 } |
1850 static ngx_int_t | 1708 } |
1851 ngx_quic_handshake_input(ngx_connection_t *c, ngx_quic_header_t *pkt) | 1709 |
1852 { | 1710 if (pkt->level == ssl_encryption_handshake) { |
1853 ngx_int_t rc; | 1711 /* |
1712 * 4.10.1. The successful use of Handshake packets indicates | |
1713 * that no more Initial packets need to be exchanged | |
1714 */ | |
1715 ngx_quic_discard_ctx(c, ssl_encryption_initial); | |
1716 qc->validated = 1; | |
1717 } | |
1718 | |
1719 if (pkt->level != ssl_encryption_application) { | |
1720 return ngx_quic_payload_handler(c, pkt); | |
1721 } | |
1722 | |
1723 ngx_gettimeofday(&pkt->received); | |
1724 | |
1725 /* switch keys on Key Phase change */ | |
1726 | |
1727 if (pkt->key_update) { | |
1728 qc->key_phase ^= 1; | |
1729 | |
1730 tmp = *keys; | |
1731 *keys = *next; | |
1732 *next = tmp; | |
1733 } | |
1734 | |
1735 rc = ngx_quic_payload_handler(c, pkt); | |
1736 if (rc != NGX_OK) { | |
1737 return rc; | |
1738 } | |
1739 | |
1740 /* generate next keys */ | |
1741 | |
1742 if (pkt->key_update) { | |
1743 if (ngx_quic_key_update(c, keys, next) != NGX_OK) { | |
1744 return NGX_ERROR; | |
1745 } | |
1746 } | |
1747 | |
1748 return NGX_OK; | |
1749 } | |
1750 | |
1751 | |
1752 static void | |
1753 ngx_quic_discard_ctx(ngx_connection_t *c, enum ssl_encryption_level_t level) | |
1754 { | |
1854 ngx_queue_t *q; | 1755 ngx_queue_t *q; |
1855 ngx_quic_frame_t *f; | 1756 ngx_quic_frame_t *f; |
1856 ngx_quic_secrets_t *keys; | |
1857 ngx_quic_send_ctx_t *ctx; | 1757 ngx_quic_send_ctx_t *ctx; |
1858 ngx_quic_connection_t *qc; | 1758 ngx_quic_connection_t *qc; |
1859 static u_char buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | |
1860 | |
1861 c->log->action = "processing handshake quic packet"; | |
1862 | 1759 |
1863 qc = c->quic; | 1760 qc = c->quic; |
1864 | 1761 |
1865 keys = &c->quic->keys[ssl_encryption_handshake]; | 1762 if (qc->keys[level].client.key.len == 0) { |
1866 | 1763 return; |
1867 if (keys->client.key.len == 0) { | 1764 } |
1868 ngx_log_error(NGX_LOG_INFO, c->log, 0, | 1765 |
1869 "quic no read keys yet, packet ignored"); | 1766 qc->keys[level].client.key.len = 0; |
1870 return NGX_DECLINED; | 1767 qc->pto_count = 0; |
1871 } | 1768 |
1872 | 1769 ctx = ngx_quic_get_send_ctx(qc, level); |
1873 /* extract cleartext data into pkt */ | |
1874 if (ngx_quic_parse_long_header(pkt) != NGX_OK) { | |
1875 return NGX_DECLINED; | |
1876 } | |
1877 | |
1878 if (pkt->version != NGX_QUIC_VERSION) { | |
1879 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1880 "quic unsupported version: 0x%xD", pkt->version); | |
1881 return NGX_DECLINED; | |
1882 } | |
1883 | |
1884 if (ngx_quic_check_peer(qc, pkt) != NGX_OK) { | |
1885 return NGX_DECLINED; | |
1886 } | |
1887 | |
1888 if (ngx_quic_parse_handshake_header(pkt) != NGX_OK) { | |
1889 return NGX_DECLINED; | |
1890 } | |
1891 | |
1892 pkt->secret = &keys->client; | |
1893 pkt->level = ssl_encryption_handshake; | |
1894 pkt->plaintext = buf; | |
1895 | |
1896 ctx = ngx_quic_get_send_ctx(qc, pkt->level); | |
1897 | |
1898 rc = ngx_quic_decrypt(pkt, c->ssl->connection, &ctx->largest_pn); | |
1899 if (rc != NGX_OK) { | |
1900 qc->error = pkt->error; | |
1901 qc->error_reason = "failed to decrypt packet"; | |
1902 return rc; | |
1903 } | |
1904 | |
1905 /* | |
1906 * 4.10.1. The successful use of Handshake packets indicates | |
1907 * that no more Initial packets need to be exchanged | |
1908 */ | |
1909 ctx = ngx_quic_get_send_ctx(c->quic, ssl_encryption_initial); | |
1910 | 1770 |
1911 while (!ngx_queue_empty(&ctx->sent)) { | 1771 while (!ngx_queue_empty(&ctx->sent)) { |
1912 q = ngx_queue_head(&ctx->sent); | 1772 q = ngx_queue_head(&ctx->sent); |
1913 ngx_queue_remove(q); | 1773 ngx_queue_remove(q); |
1914 | 1774 |
1915 f = ngx_queue_data(q, ngx_quic_frame_t, queue); | 1775 f = ngx_queue_data(q, ngx_quic_frame_t, queue); |
1916 ngx_quic_congestion_ack(c, f); | 1776 ngx_quic_congestion_ack(c, f); |
1917 ngx_quic_free_frame(c, f); | 1777 ngx_quic_free_frame(c, f); |
1918 } | 1778 } |
1919 | |
1920 qc->validated = 1; | |
1921 qc->pto_count = 0; | |
1922 | |
1923 return ngx_quic_payload_handler(c, pkt); | |
1924 } | |
1925 | |
1926 | |
1927 static ngx_int_t | |
1928 ngx_quic_early_input(ngx_connection_t *c, ngx_quic_header_t *pkt) | |
1929 { | |
1930 ngx_int_t rc; | |
1931 ngx_quic_secrets_t *keys; | |
1932 ngx_quic_send_ctx_t *ctx; | |
1933 ngx_quic_connection_t *qc; | |
1934 static u_char buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | |
1935 | |
1936 c->log->action = "processing early data quic packet"; | |
1937 | |
1938 qc = c->quic; | |
1939 | |
1940 /* extract cleartext data into pkt */ | |
1941 if (ngx_quic_parse_long_header(pkt) != NGX_OK) { | |
1942 return NGX_DECLINED; | |
1943 } | |
1944 | |
1945 if (pkt->version != NGX_QUIC_VERSION) { | |
1946 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1947 "quic unsupported version: 0x%xD", pkt->version); | |
1948 return NGX_DECLINED; | |
1949 } | |
1950 | |
1951 if (ngx_quic_check_peer(qc, pkt) != NGX_OK) { | |
1952 return NGX_DECLINED; | |
1953 } | |
1954 | |
1955 if (ngx_quic_parse_handshake_header(pkt) != NGX_OK) { | |
1956 return NGX_DECLINED; | |
1957 } | |
1958 | |
1959 keys = &c->quic->keys[ssl_encryption_early_data]; | |
1960 | |
1961 if (keys->client.key.len == 0) { | |
1962 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1963 "quic no 0-RTT keys yet, packet ignored"); | |
1964 return NGX_DECLINED; | |
1965 } | |
1966 | |
1967 | |
1968 pkt->secret = &keys->client; | |
1969 pkt->level = ssl_encryption_early_data; | |
1970 pkt->plaintext = buf; | |
1971 | |
1972 ctx = ngx_quic_get_send_ctx(qc, pkt->level); | |
1973 | |
1974 rc = ngx_quic_decrypt(pkt, c->ssl->connection, &ctx->largest_pn); | |
1975 if (rc != NGX_OK) { | |
1976 qc->error = pkt->error; | |
1977 qc->error_reason = "failed to decrypt packet"; | |
1978 return rc; | |
1979 } | |
1980 | |
1981 return ngx_quic_payload_handler(c, pkt); | |
1982 } | 1779 } |
1983 | 1780 |
1984 | 1781 |
1985 static ngx_int_t | 1782 static ngx_int_t |
1986 ngx_quic_check_peer(ngx_quic_connection_t *qc, ngx_quic_header_t *pkt) | 1783 ngx_quic_check_peer(ngx_quic_connection_t *qc, ngx_quic_header_t *pkt) |
1987 { | 1784 { |
1785 ngx_str_t *dcid; | |
1988 ngx_queue_t *q; | 1786 ngx_queue_t *q; |
1989 ngx_quic_send_ctx_t *ctx; | 1787 ngx_quic_send_ctx_t *ctx; |
1990 ngx_quic_client_id_t *cid; | 1788 ngx_quic_client_id_t *cid; |
1991 | 1789 |
1790 dcid = (pkt->level == ssl_encryption_early_data) ? &qc->odcid : &qc->dcid; | |
1791 | |
1792 if (pkt->dcid.len == dcid->len | |
1793 && ngx_memcmp(pkt->dcid.data, dcid->data, dcid->len) == 0) | |
1794 { | |
1795 if (pkt->level == ssl_encryption_application) { | |
1796 return NGX_OK; | |
1797 } | |
1798 | |
1799 goto found; | |
1800 } | |
1801 | |
1802 /* | |
1803 * a packet sent in response to an initial client packet might be lost, | |
1804 * thus check also for old dcid | |
1805 */ | |
1992 ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_initial); | 1806 ctx = ngx_quic_get_send_ctx(qc, ssl_encryption_initial); |
1993 | 1807 |
1994 if (ngx_quic_pkt_zrtt(pkt->flags) | 1808 if (pkt->level == ssl_encryption_initial |
1995 || (ngx_quic_pkt_in(pkt->flags) && ctx->largest_ack == (uint64_t) -1)) | 1809 && ctx->largest_ack == (uint64_t) -1) |
1996 { | 1810 { |
1997 if (pkt->dcid.len == qc->odcid.len | 1811 if (pkt->dcid.len == qc->odcid.len |
1998 && ngx_memcmp(pkt->dcid.data, qc->odcid.data, qc->odcid.len) == 0) | 1812 && ngx_memcmp(pkt->dcid.data, qc->odcid.data, qc->odcid.len) == 0) |
1999 { | 1813 { |
2000 goto found; | 1814 goto found; |
2001 } | 1815 } |
2002 } | 1816 } |
2003 | 1817 |
2004 if (!ngx_quic_pkt_zrtt(pkt->flags)) { | |
2005 if (pkt->dcid.len == qc->dcid.len | |
2006 && ngx_memcmp(pkt->dcid.data, qc->dcid.data, qc->dcid.len) == 0) | |
2007 { | |
2008 goto found; | |
2009 } | |
2010 } | |
2011 | |
2012 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic unexpected quic dcid"); | 1818 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic unexpected quic dcid"); |
2013 return NGX_ERROR; | 1819 return NGX_ERROR; |
2014 | 1820 |
2015 found: | 1821 found: |
2016 | 1822 |
2025 { | 1831 { |
2026 return NGX_OK; | 1832 return NGX_OK; |
2027 } | 1833 } |
2028 } | 1834 } |
2029 | 1835 |
2030 | 1836 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic unexpected quic scid"); |
2031 ngx_log_error(NGX_LOG_INFO, pkt->log, 0, "quic unexpected quic scid"); | 1837 return NGX_ERROR; |
2032 return NGX_ERROR; | |
2033 } | |
2034 | |
2035 | |
2036 static ngx_int_t | |
2037 ngx_quic_app_input(ngx_connection_t *c, ngx_quic_header_t *pkt) | |
2038 { | |
2039 ngx_int_t rc; | |
2040 ngx_quic_secrets_t *keys, *next, tmp; | |
2041 ngx_quic_send_ctx_t *ctx; | |
2042 ngx_quic_connection_t *qc; | |
2043 static u_char buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | |
2044 | |
2045 c->log->action = "processing application data quic packet"; | |
2046 | |
2047 qc = c->quic; | |
2048 | |
2049 keys = &c->quic->keys[ssl_encryption_application]; | |
2050 next = &c->quic->next_key; | |
2051 | |
2052 if (keys->client.key.len == 0) { | |
2053 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
2054 "quic no read keys yet, packet ignored"); | |
2055 return NGX_DECLINED; | |
2056 } | |
2057 | |
2058 if (ngx_quic_parse_short_header(pkt, &qc->dcid) != NGX_OK) { | |
2059 return NGX_DECLINED; | |
2060 } | |
2061 | |
2062 pkt->secret = &keys->client; | |
2063 pkt->next = &next->client; | |
2064 pkt->key_phase = c->quic->key_phase; | |
2065 pkt->level = ssl_encryption_application; | |
2066 pkt->plaintext = buf; | |
2067 | |
2068 ctx = ngx_quic_get_send_ctx(qc, pkt->level); | |
2069 | |
2070 rc = ngx_quic_decrypt(pkt, c->ssl->connection, &ctx->largest_pn); | |
2071 if (rc != NGX_OK) { | |
2072 qc->error = pkt->error; | |
2073 qc->error_reason = "failed to decrypt packet"; | |
2074 return rc; | |
2075 } | |
2076 | |
2077 ngx_gettimeofday(&pkt->received); | |
2078 | |
2079 /* switch keys on Key Phase change */ | |
2080 | |
2081 if (pkt->key_update) { | |
2082 c->quic->key_phase ^= 1; | |
2083 | |
2084 tmp = *keys; | |
2085 *keys = *next; | |
2086 *next = tmp; | |
2087 } | |
2088 | |
2089 rc = ngx_quic_payload_handler(c, pkt); | |
2090 | |
2091 if (rc == NGX_ERROR) { | |
2092 return NGX_ERROR; | |
2093 } | |
2094 | |
2095 /* generate next keys */ | |
2096 | |
2097 if (pkt->key_update) { | |
2098 if (ngx_quic_key_update(c, keys, next) != NGX_OK) { | |
2099 return NGX_ERROR; | |
2100 } | |
2101 } | |
2102 | |
2103 return rc; | |
2104 } | 1838 } |
2105 | 1839 |
2106 | 1840 |
2107 static ngx_int_t | 1841 static ngx_int_t |
2108 ngx_quic_payload_handler(ngx_connection_t *c, ngx_quic_header_t *pkt) | 1842 ngx_quic_payload_handler(ngx_connection_t *c, ngx_quic_header_t *pkt) |
2979 | 2713 |
2980 static ngx_int_t | 2714 static ngx_int_t |
2981 ngx_quic_crypto_input(ngx_connection_t *c, ngx_quic_frame_t *frame, void *data) | 2715 ngx_quic_crypto_input(ngx_connection_t *c, ngx_quic_frame_t *frame, void *data) |
2982 { | 2716 { |
2983 int n, sslerr; | 2717 int n, sslerr; |
2984 ngx_queue_t *q; | |
2985 ngx_ssl_conn_t *ssl_conn; | 2718 ngx_ssl_conn_t *ssl_conn; |
2986 ngx_quic_send_ctx_t *ctx; | |
2987 ngx_quic_crypto_frame_t *f; | 2719 ngx_quic_crypto_frame_t *f; |
2988 | 2720 |
2989 f = &frame->u.crypto; | 2721 f = &frame->u.crypto; |
2990 | 2722 |
2991 ssl_conn = c->ssl->connection; | 2723 ssl_conn = c->ssl->connection; |
3058 | 2790 |
3059 /* | 2791 /* |
3060 * 4.10.2 An endpoint MUST discard its handshake keys | 2792 * 4.10.2 An endpoint MUST discard its handshake keys |
3061 * when the TLS handshake is confirmed | 2793 * when the TLS handshake is confirmed |
3062 */ | 2794 */ |
3063 ctx = ngx_quic_get_send_ctx(c->quic, ssl_encryption_handshake); | 2795 ngx_quic_discard_ctx(c, ssl_encryption_handshake); |
3064 | |
3065 while (!ngx_queue_empty(&ctx->sent)) { | |
3066 q = ngx_queue_head(&ctx->sent); | |
3067 ngx_queue_remove(q); | |
3068 | |
3069 frame = ngx_queue_data(q, ngx_quic_frame_t, queue); | |
3070 ngx_quic_congestion_ack(c, frame); | |
3071 ngx_quic_free_frame(c, frame); | |
3072 } | |
3073 | |
3074 c->quic->pto_count = 0; | |
3075 } | 2796 } |
3076 | 2797 |
3077 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | 2798 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, |
3078 "quic SSL_quic_read_level: %d, SSL_quic_write_level: %d", | 2799 "quic SSL_quic_read_level: %d, SSL_quic_write_level: %d", |
3079 (int) SSL_quic_read_level(ssl_conn), | 2800 (int) SSL_quic_read_level(ssl_conn), |