Mercurial > hg > nginx-quic
comparison src/event/ngx_event_quic.c @ 8191:9c3be23ddbe7 quic
QUIC: refactored key handling.
All key handling functionality is moved into ngx_quic_protection.c.
Public structures from ngx_quic_protection.h are now private and new
methods are available to manipulate keys.
A negotiated cipher is cached in QUIC connection from the set secret callback
to avoid calling SSL_get_current_cipher() on each encrypt/decrypt operation.
This also reduces the number of unwanted c->ssl->connection occurrences.
author | Sergey Kandaurov <pluknet@nginx.com> |
---|---|
date | Mon, 02 Nov 2020 18:21:34 +0300 |
parents | d10118e38943 |
children | 183275308d9a |
comparison
equal
deleted
inserted
replaced
8190:d10118e38943 | 8191:9c3be23ddbe7 |
---|---|
92 * can be processed and acknowledged. Initial packets can only be sent | 92 * can be processed and acknowledged. Initial packets can only be sent |
93 * with Initial packet protection keys and acknowledged in packets which | 93 * with Initial packet protection keys and acknowledged in packets which |
94 * are also Initial packets. | 94 * are also Initial packets. |
95 */ | 95 */ |
96 typedef struct { | 96 typedef struct { |
97 ngx_quic_secret_t client_secret; | |
98 ngx_quic_secret_t server_secret; | |
99 | |
100 enum ssl_encryption_level_t level; | 97 enum ssl_encryption_level_t level; |
101 | 98 |
102 uint64_t pnum; /* to be sent */ | 99 uint64_t pnum; /* to be sent */ |
103 uint64_t largest_ack; /* received from peer */ | 100 uint64_t largest_ack; /* received from peer */ |
104 uint64_t largest_pn; /* received from peer */ | 101 uint64_t largest_pn; /* received from peer */ |
132 ngx_uint_t client_tp_done; | 129 ngx_uint_t client_tp_done; |
133 ngx_quic_tp_t tp; | 130 ngx_quic_tp_t tp; |
134 ngx_quic_tp_t ctp; | 131 ngx_quic_tp_t ctp; |
135 | 132 |
136 ngx_quic_send_ctx_t send_ctx[NGX_QUIC_SEND_CTX_LAST]; | 133 ngx_quic_send_ctx_t send_ctx[NGX_QUIC_SEND_CTX_LAST]; |
137 ngx_quic_secrets_t keys[NGX_QUIC_ENCRYPTION_LAST]; | 134 |
138 ngx_quic_secrets_t next_key; | |
139 ngx_quic_frames_stream_t crypto[NGX_QUIC_ENCRYPTION_LAST]; | 135 ngx_quic_frames_stream_t crypto[NGX_QUIC_ENCRYPTION_LAST]; |
136 | |
137 ngx_quic_keys_t *keys; | |
140 | 138 |
141 ngx_quic_conf_t *conf; | 139 ngx_quic_conf_t *conf; |
142 | 140 |
143 ngx_event_t push; | 141 ngx_event_t push; |
144 ngx_event_t pto; | 142 ngx_event_t pto; |
641 static int | 639 static int |
642 ngx_quic_set_read_secret(ngx_ssl_conn_t *ssl_conn, | 640 ngx_quic_set_read_secret(ngx_ssl_conn_t *ssl_conn, |
643 enum ssl_encryption_level_t level, const SSL_CIPHER *cipher, | 641 enum ssl_encryption_level_t level, const SSL_CIPHER *cipher, |
644 const uint8_t *rsecret, size_t secret_len) | 642 const uint8_t *rsecret, size_t secret_len) |
645 { | 643 { |
646 ngx_connection_t *c; | 644 ngx_connection_t *c; |
647 ngx_quic_secrets_t *keys; | |
648 | 645 |
649 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | 646 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); |
650 | 647 |
651 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | 648 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, |
652 "quic ngx_quic_set_read_secret() level:%d", level); | 649 "quic ngx_quic_set_read_secret() level:%d", level); |
653 #ifdef NGX_QUIC_DEBUG_CRYPTO | 650 #ifdef NGX_QUIC_DEBUG_CRYPTO |
654 ngx_quic_hexdump(c->log, "quic read secret", rsecret, secret_len); | 651 ngx_quic_hexdump(c->log, "quic read secret", rsecret, secret_len); |
655 #endif | 652 #endif |
656 | 653 |
657 keys = &c->quic->keys[level]; | 654 return ngx_quic_keys_set_encryption_secret(c->pool, 0, c->quic->keys, level, |
658 | 655 cipher, rsecret, secret_len); |
659 return ngx_quic_set_encryption_secret(c->pool, ssl_conn, level, | |
660 rsecret, secret_len, | |
661 &keys->client); | |
662 } | 656 } |
663 | 657 |
664 | 658 |
665 static int | 659 static int |
666 ngx_quic_set_write_secret(ngx_ssl_conn_t *ssl_conn, | 660 ngx_quic_set_write_secret(ngx_ssl_conn_t *ssl_conn, |
667 enum ssl_encryption_level_t level, const SSL_CIPHER *cipher, | 661 enum ssl_encryption_level_t level, const SSL_CIPHER *cipher, |
668 const uint8_t *wsecret, size_t secret_len) | 662 const uint8_t *wsecret, size_t secret_len) |
669 { | 663 { |
670 ngx_connection_t *c; | 664 ngx_connection_t *c; |
671 ngx_quic_secrets_t *keys; | |
672 | 665 |
673 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | 666 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); |
674 | 667 |
675 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | 668 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, |
676 "quic ngx_quic_set_write_secret() level:%d", level); | 669 "quic ngx_quic_set_write_secret() level:%d", level); |
677 #ifdef NGX_QUIC_DEBUG_CRYPTO | 670 #ifdef NGX_QUIC_DEBUG_CRYPTO |
678 ngx_quic_hexdump(c->log, "quic write secret", wsecret, secret_len); | 671 ngx_quic_hexdump(c->log, "quic write secret", wsecret, secret_len); |
679 #endif | 672 #endif |
680 | 673 |
681 keys = &c->quic->keys[level]; | 674 return ngx_quic_keys_set_encryption_secret(c->pool, 1, c->quic->keys, level, |
682 | 675 cipher, wsecret, secret_len); |
683 return ngx_quic_set_encryption_secret(c->pool, ssl_conn, level, | |
684 wsecret, secret_len, | |
685 &keys->server); | |
686 } | 676 } |
687 | 677 |
688 #else | 678 #else |
689 | 679 |
690 static int | 680 static int |
691 ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn, | 681 ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn, |
692 enum ssl_encryption_level_t level, const uint8_t *rsecret, | 682 enum ssl_encryption_level_t level, const uint8_t *rsecret, |
693 const uint8_t *wsecret, size_t secret_len) | 683 const uint8_t *wsecret, size_t secret_len) |
694 { | 684 { |
695 ngx_int_t rc; | 685 ngx_connection_t *c; |
696 ngx_connection_t *c; | 686 const SSL_CIPHER *cipher; |
697 ngx_quic_secrets_t *keys; | |
698 | 687 |
699 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | 688 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); |
700 | 689 |
701 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | 690 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, |
702 "quic ngx_quic_set_encryption_secrets() level:%d", level); | 691 "quic ngx_quic_set_encryption_secrets() level:%d", level); |
703 #ifdef NGX_QUIC_DEBUG_CRYPTO | 692 #ifdef NGX_QUIC_DEBUG_CRYPTO |
704 ngx_quic_hexdump(c->log, "quic read", rsecret, secret_len); | 693 ngx_quic_hexdump(c->log, "quic read secret", rsecret, secret_len); |
705 #endif | 694 #endif |
706 | 695 |
707 keys = &c->quic->keys[level]; | 696 cipher = SSL_get_current_cipher(ssl_conn); |
708 | 697 |
709 rc = ngx_quic_set_encryption_secret(c->pool, ssl_conn, level, | 698 if (ngx_quic_keys_set_encryption_secret(c->pool, 0, c->quic->keys, level, |
710 rsecret, secret_len, | 699 cipher, rsecret, secret_len) |
711 &keys->client); | 700 != 1) |
712 if (rc != 1) { | 701 { |
713 return rc; | 702 return 0; |
714 } | 703 } |
715 | 704 |
716 if (level == ssl_encryption_early_data) { | 705 if (level == ssl_encryption_early_data) { |
717 return 1; | 706 return 1; |
718 } | 707 } |
719 | 708 |
720 #ifdef NGX_QUIC_DEBUG_CRYPTO | 709 #ifdef NGX_QUIC_DEBUG_CRYPTO |
721 ngx_quic_hexdump(c->log, "quic write", wsecret, secret_len); | 710 ngx_quic_hexdump(c->log, "quic write secret", wsecret, secret_len); |
722 #endif | 711 #endif |
723 | 712 |
724 return ngx_quic_set_encryption_secret(c->pool, ssl_conn, level, | 713 return ngx_quic_keys_set_encryption_secret(c->pool, 1, c->quic->keys, level, |
725 wsecret, secret_len, | 714 cipher, wsecret, secret_len); |
726 &keys->server); | |
727 } | 715 } |
728 | 716 |
729 #endif | 717 #endif |
730 | 718 |
731 | 719 |
963 qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t)); | 951 qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t)); |
964 if (qc == NULL) { | 952 if (qc == NULL) { |
965 return NULL; | 953 return NULL; |
966 } | 954 } |
967 | 955 |
956 qc->keys = ngx_quic_keys_new(c->pool); | |
957 if (qc->keys == NULL) { | |
958 return NULL; | |
959 } | |
960 | |
968 ngx_rbtree_init(&qc->streams.tree, &qc->streams.sentinel, | 961 ngx_rbtree_init(&qc->streams.tree, &qc->streams.sentinel, |
969 ngx_quic_rbtree_insert_stream); | 962 ngx_quic_rbtree_insert_stream); |
970 | 963 |
971 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { | 964 for (i = 0; i < NGX_QUIC_SEND_CTX_LAST; i++) { |
972 ngx_queue_init(&qc->send_ctx[i].frames); | 965 ngx_queue_init(&qc->send_ctx[i].frames); |
1237 pkt.scid = c->quic->dcid; | 1230 pkt.scid = c->quic->dcid; |
1238 pkt.token = token; | 1231 pkt.token = token; |
1239 | 1232 |
1240 res.data = buf; | 1233 res.data = buf; |
1241 | 1234 |
1242 if (ngx_quic_encrypt(&pkt, NULL, &res) != NGX_OK) { | 1235 if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { |
1243 return NGX_ERROR; | 1236 return NGX_ERROR; |
1244 } | 1237 } |
1245 | 1238 |
1246 #ifdef NGX_QUIC_DEBUG_PACKETS | 1239 #ifdef NGX_QUIC_DEBUG_PACKETS |
1247 ngx_quic_hexdump(c->log, "quic packet to send", res.data, res.len); | 1240 ngx_quic_hexdump(c->log, "quic packet to send", res.data, res.len); |
1988 static ngx_int_t | 1981 static ngx_int_t |
1989 ngx_quic_process_packet(ngx_connection_t *c, ngx_quic_conf_t *conf, | 1982 ngx_quic_process_packet(ngx_connection_t *c, ngx_quic_conf_t *conf, |
1990 ngx_quic_header_t *pkt) | 1983 ngx_quic_header_t *pkt) |
1991 { | 1984 { |
1992 ngx_int_t rc; | 1985 ngx_int_t rc; |
1993 ngx_ssl_conn_t *ssl_conn; | |
1994 ngx_quic_secrets_t *keys, *next, tmp; | |
1995 ngx_quic_send_ctx_t *ctx; | 1986 ngx_quic_send_ctx_t *ctx; |
1996 ngx_quic_connection_t *qc; | 1987 ngx_quic_connection_t *qc; |
1997 | 1988 |
1998 static u_char buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | 1989 static u_char buf[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; |
1999 | 1990 |
2133 } | 2124 } |
2134 } | 2125 } |
2135 | 2126 |
2136 c->log->action = "decrypting packet"; | 2127 c->log->action = "decrypting packet"; |
2137 | 2128 |
2138 keys = &qc->keys[pkt->level]; | 2129 if (!ngx_quic_keys_available(qc->keys, pkt->level)) { |
2139 | |
2140 if (keys->client.key.len == 0) { | |
2141 ngx_log_error(NGX_LOG_INFO, c->log, 0, | 2130 ngx_log_error(NGX_LOG_INFO, c->log, 0, |
2142 "quic no level %d keys yet, ignoring packet", pkt->level); | 2131 "quic no level %d keys yet, ignoring packet", pkt->level); |
2143 return NGX_DECLINED; | 2132 return NGX_DECLINED; |
2144 } | 2133 } |
2145 | 2134 |
2146 next = &qc->next_key; | 2135 pkt->keys = qc->keys; |
2147 | |
2148 pkt->secret = &keys->client; | |
2149 pkt->next = &next->client; | |
2150 pkt->key_phase = qc->key_phase; | 2136 pkt->key_phase = qc->key_phase; |
2151 pkt->plaintext = buf; | 2137 pkt->plaintext = buf; |
2152 | 2138 |
2153 ctx = ngx_quic_get_send_ctx(qc, pkt->level); | 2139 ctx = ngx_quic_get_send_ctx(qc, pkt->level); |
2154 | 2140 |
2155 ssl_conn = c->ssl ? c->ssl->connection : NULL; | 2141 rc = ngx_quic_decrypt(pkt, &ctx->largest_pn); |
2156 | |
2157 rc = ngx_quic_decrypt(pkt, ssl_conn, &ctx->largest_pn); | |
2158 if (rc != NGX_OK) { | 2142 if (rc != NGX_OK) { |
2159 qc->error = pkt->error; | 2143 qc->error = pkt->error; |
2160 qc->error_reason = "failed to decrypt packet"; | 2144 qc->error_reason = "failed to decrypt packet"; |
2161 return rc; | 2145 return rc; |
2162 } | 2146 } |
2188 | 2172 |
2189 if (pkt->level != ssl_encryption_application) { | 2173 if (pkt->level != ssl_encryption_application) { |
2190 return ngx_quic_payload_handler(c, pkt); | 2174 return ngx_quic_payload_handler(c, pkt); |
2191 } | 2175 } |
2192 | 2176 |
2193 /* switch keys on Key Phase change */ | 2177 if (!pkt->key_update) { |
2194 | 2178 return ngx_quic_payload_handler(c, pkt); |
2195 if (pkt->key_update) { | 2179 } |
2196 qc->key_phase ^= 1; | 2180 |
2197 | 2181 /* switch keys and generate next on Key Phase change */ |
2198 tmp = *keys; | 2182 |
2199 *keys = *next; | 2183 qc->key_phase ^= 1; |
2200 *next = tmp; | 2184 ngx_quic_keys_switch(c, qc->keys); |
2201 } | |
2202 | 2185 |
2203 rc = ngx_quic_payload_handler(c, pkt); | 2186 rc = ngx_quic_payload_handler(c, pkt); |
2204 if (rc != NGX_OK) { | 2187 if (rc != NGX_OK) { |
2205 return rc; | 2188 return rc; |
2206 } | 2189 } |
2207 | 2190 |
2208 /* generate next keys */ | 2191 return ngx_quic_keys_update(c, qc->keys); |
2209 | |
2210 if (pkt->key_update) { | |
2211 if (ngx_quic_key_update(c, keys, next) != NGX_OK) { | |
2212 return NGX_ERROR; | |
2213 } | |
2214 } | |
2215 | |
2216 return NGX_OK; | |
2217 } | 2192 } |
2218 | 2193 |
2219 | 2194 |
2220 static ngx_int_t | 2195 static ngx_int_t |
2221 ngx_quic_init_secrets(ngx_connection_t *c) | 2196 ngx_quic_init_secrets(ngx_connection_t *c) |
2222 { | 2197 { |
2223 ngx_quic_secrets_t *keys; | |
2224 ngx_quic_connection_t *qc; | 2198 ngx_quic_connection_t *qc; |
2225 | 2199 |
2226 qc =c->quic; | 2200 qc = c->quic; |
2227 keys = &qc->keys[ssl_encryption_initial]; | 2201 |
2228 | 2202 if (ngx_quic_keys_set_initial_secret(c->pool, qc->keys, &qc->odcid) |
2229 if (ngx_quic_set_initial_secret(c->pool, &keys->client, &keys->server, | |
2230 &qc->odcid) | |
2231 != NGX_OK) | 2203 != NGX_OK) |
2232 { | 2204 { |
2233 return NGX_ERROR; | 2205 return NGX_ERROR; |
2234 } | 2206 } |
2235 | 2207 |
2247 ngx_quic_send_ctx_t *ctx; | 2219 ngx_quic_send_ctx_t *ctx; |
2248 ngx_quic_connection_t *qc; | 2220 ngx_quic_connection_t *qc; |
2249 | 2221 |
2250 qc = c->quic; | 2222 qc = c->quic; |
2251 | 2223 |
2252 if (qc->keys[level].client.key.len == 0) { | 2224 if (!ngx_quic_keys_available(qc->keys, level)) { |
2253 return; | 2225 return; |
2254 } | 2226 } |
2255 | 2227 |
2256 qc->keys[level].client.key.len = 0; | 2228 ngx_quic_keys_discard(qc->keys, level); |
2229 | |
2257 qc->pto_count = 0; | 2230 qc->pto_count = 0; |
2258 | 2231 |
2259 ctx = ngx_quic_get_send_ctx(qc, level); | 2232 ctx = ngx_quic_get_send_ctx(qc, level); |
2260 | 2233 |
2261 while (!ngx_queue_empty(&ctx->sent)) { | 2234 while (!ngx_queue_empty(&ctx->sent)) { |
3632 /* | 3605 /* |
3633 * Generating next keys before a key update is received. | 3606 * Generating next keys before a key update is received. |
3634 * See quic-tls 9.4 Header Protection Timing Side-Channels. | 3607 * See quic-tls 9.4 Header Protection Timing Side-Channels. |
3635 */ | 3608 */ |
3636 | 3609 |
3637 if (ngx_quic_key_update(c, &c->quic->keys[ssl_encryption_application], | 3610 if (ngx_quic_keys_update(c, c->quic->keys) != NGX_OK) { |
3638 &c->quic->next_key) | |
3639 != NGX_OK) | |
3640 { | |
3641 return NGX_ERROR; | 3611 return NGX_ERROR; |
3642 } | 3612 } |
3643 | 3613 |
3644 /* | 3614 /* |
3645 * 4.10.2 An endpoint MUST discard its handshake keys | 3615 * 4.10.2 An endpoint MUST discard its handshake keys |
4501 size_t pad_len; | 4471 size_t pad_len; |
4502 ssize_t len; | 4472 ssize_t len; |
4503 ngx_str_t out, res; | 4473 ngx_str_t out, res; |
4504 ngx_msec_t now; | 4474 ngx_msec_t now; |
4505 ngx_queue_t *q; | 4475 ngx_queue_t *q; |
4506 ngx_ssl_conn_t *ssl_conn; | |
4507 ngx_quic_frame_t *f, *start; | 4476 ngx_quic_frame_t *f, *start; |
4508 ngx_quic_header_t pkt; | 4477 ngx_quic_header_t pkt; |
4509 ngx_quic_secrets_t *keys; | |
4510 ngx_quic_connection_t *qc; | 4478 ngx_quic_connection_t *qc; |
4511 static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | 4479 static u_char src[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; |
4512 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; | 4480 static u_char dst[NGX_QUIC_MAX_UDP_PAYLOAD_SIZE]; |
4513 | 4481 |
4514 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | 4482 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, |
4515 "quic ngx_quic_send_frames"); | 4483 "quic ngx_quic_send_frames"); |
4516 | |
4517 ssl_conn = c->ssl ? c->ssl->connection : NULL; | |
4518 | 4484 |
4519 q = ngx_queue_head(frames); | 4485 q = ngx_queue_head(frames); |
4520 start = ngx_queue_data(q, ngx_quic_frame_t, queue); | 4486 start = ngx_queue_data(q, ngx_quic_frame_t, queue); |
4521 | 4487 |
4522 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); | 4488 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); |
4552 | 4518 |
4553 out.len = p - out.data; | 4519 out.len = p - out.data; |
4554 | 4520 |
4555 qc = c->quic; | 4521 qc = c->quic; |
4556 | 4522 |
4557 keys = &c->quic->keys[start->level]; | 4523 pkt.keys = qc->keys; |
4558 | |
4559 pkt.secret = &keys->server; | |
4560 | 4524 |
4561 pkt.flags = NGX_QUIC_PKT_FIXED_BIT; | 4525 pkt.flags = NGX_QUIC_PKT_FIXED_BIT; |
4562 | 4526 |
4563 if (start->level == ssl_encryption_initial) { | 4527 if (start->level == ssl_encryption_initial) { |
4564 pkt.flags |= NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_INITIAL; | 4528 pkt.flags |= NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_INITIAL; |
4601 "quic packet tx %s bytes:%ui" | 4565 "quic packet tx %s bytes:%ui" |
4602 " need_ack:%d number:%L encoded nl:%d trunc:0x%xD", | 4566 " need_ack:%d number:%L encoded nl:%d trunc:0x%xD", |
4603 ngx_quic_level_name(start->level), out.len, pkt.need_ack, | 4567 ngx_quic_level_name(start->level), out.len, pkt.need_ack, |
4604 pkt.number, pkt.num_len, pkt.trunc); | 4568 pkt.number, pkt.num_len, pkt.trunc); |
4605 | 4569 |
4606 if (ngx_quic_encrypt(&pkt, ssl_conn, &res) != NGX_OK) { | 4570 if (ngx_quic_encrypt(&pkt, &res) != NGX_OK) { |
4607 ngx_quic_free_frames(c, frames); | 4571 ngx_quic_free_frames(c, frames); |
4608 return NGX_ERROR; | 4572 return NGX_ERROR; |
4609 } | 4573 } |
4610 | 4574 |
4611 len = c->send(c, res.data, res.len); | 4575 len = c->send(c, res.data, res.len); |