Mercurial > hg > nginx-quic
comparison src/event/quic/ngx_event_quic_protection.c @ 8915:d8b3851f172c quic
QUIC: fixed-length buffers for secrets.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Wed, 27 Jul 2022 17:15:33 +0400 |
parents | d8865baab732 |
children | f2925c80401c |
comparison
equal
deleted
inserted
replaced
8914:b30bec3d71d6 | 8915:d8b3851f172c |
---|---|
15 /* RFC 9001, 5.4.1. Header Protection Application: 5-byte mask */ | 15 /* RFC 9001, 5.4.1. Header Protection Application: 5-byte mask */ |
16 #define NGX_QUIC_HP_LEN 5 | 16 #define NGX_QUIC_HP_LEN 5 |
17 | 17 |
18 #define NGX_QUIC_AES_128_KEY_LEN 16 | 18 #define NGX_QUIC_AES_128_KEY_LEN 16 |
19 | 19 |
20 /* largest hash used in TLS is SHA-384 */ | |
21 #define NGX_QUIC_MAX_MD_SIZE 48 | |
22 | |
20 #define NGX_AES_128_GCM_SHA256 0x1301 | 23 #define NGX_AES_128_GCM_SHA256 0x1301 |
21 #define NGX_AES_256_GCM_SHA384 0x1302 | 24 #define NGX_AES_256_GCM_SHA384 0x1302 |
22 #define NGX_CHACHA20_POLY1305_SHA256 0x1303 | 25 #define NGX_CHACHA20_POLY1305_SHA256 0x1303 |
23 | 26 |
24 | 27 |
25 #ifdef OPENSSL_IS_BORINGSSL | 28 #ifdef OPENSSL_IS_BORINGSSL |
26 #define ngx_quic_cipher_t EVP_AEAD | 29 #define ngx_quic_cipher_t EVP_AEAD |
27 #else | 30 #else |
28 #define ngx_quic_cipher_t EVP_CIPHER | 31 #define ngx_quic_cipher_t EVP_CIPHER |
29 #endif | 32 #endif |
33 | |
34 | |
35 typedef struct { | |
36 size_t len; | |
37 u_char data[NGX_QUIC_MAX_MD_SIZE]; | |
38 } ngx_quic_md_t; | |
39 | |
40 | |
41 typedef struct { | |
42 size_t len; | |
43 u_char data[NGX_QUIC_IV_LEN]; | |
44 } ngx_quic_iv_t; | |
30 | 45 |
31 | 46 |
32 typedef struct { | 47 typedef struct { |
33 const ngx_quic_cipher_t *c; | 48 const ngx_quic_cipher_t *c; |
34 const EVP_CIPHER *hp; | 49 const EVP_CIPHER *hp; |
35 const EVP_MD *d; | 50 const EVP_MD *d; |
36 } ngx_quic_ciphers_t; | 51 } ngx_quic_ciphers_t; |
37 | 52 |
38 | 53 |
39 typedef struct ngx_quic_secret_s { | 54 typedef struct ngx_quic_secret_s { |
40 ngx_str_t secret; | 55 ngx_quic_md_t secret; |
41 ngx_str_t key; | 56 ngx_quic_md_t key; |
42 ngx_str_t iv; | 57 ngx_quic_iv_t iv; |
43 ngx_str_t hp; | 58 ngx_quic_md_t hp; |
44 } ngx_quic_secret_t; | 59 } ngx_quic_secret_t; |
45 | 60 |
46 | 61 |
47 typedef struct { | 62 typedef struct { |
48 ngx_quic_secret_t client; | 63 ngx_quic_secret_t client; |
53 struct ngx_quic_keys_s { | 68 struct ngx_quic_keys_s { |
54 ngx_quic_secrets_t secrets[NGX_QUIC_ENCRYPTION_LAST]; | 69 ngx_quic_secrets_t secrets[NGX_QUIC_ENCRYPTION_LAST]; |
55 ngx_quic_secrets_t next_key; | 70 ngx_quic_secrets_t next_key; |
56 ngx_uint_t cipher; | 71 ngx_uint_t cipher; |
57 }; | 72 }; |
73 | |
74 | |
75 typedef struct { | |
76 size_t out_len; | |
77 u_char *out; | |
78 | |
79 size_t prk_len; | |
80 const uint8_t *prk; | |
81 | |
82 size_t label_len; | |
83 const u_char *label; | |
84 } ngx_quic_hkdf_t; | |
85 | |
86 #define ngx_quic_hkdf_set(label, out, prk) \ | |
87 { \ | |
88 (out)->len, (out)->data, \ | |
89 (prk)->len, (prk)->data, \ | |
90 (sizeof(label) - 1), (u_char *)(label), \ | |
91 } | |
58 | 92 |
59 | 93 |
60 static ngx_int_t ngx_hkdf_expand(u_char *out_key, size_t out_len, | 94 static ngx_int_t ngx_hkdf_expand(u_char *out_key, size_t out_len, |
61 const EVP_MD *digest, const u_char *prk, size_t prk_len, | 95 const EVP_MD *digest, const u_char *prk, size_t prk_len, |
62 const u_char *info, size_t info_len); | 96 const u_char *info, size_t info_len); |
76 static ngx_int_t ngx_quic_tls_seal(const ngx_quic_cipher_t *cipher, | 110 static ngx_int_t ngx_quic_tls_seal(const ngx_quic_cipher_t *cipher, |
77 ngx_quic_secret_t *s, ngx_str_t *out, u_char *nonce, ngx_str_t *in, | 111 ngx_quic_secret_t *s, ngx_str_t *out, u_char *nonce, ngx_str_t *in, |
78 ngx_str_t *ad, ngx_log_t *log); | 112 ngx_str_t *ad, ngx_log_t *log); |
79 static ngx_int_t ngx_quic_tls_hp(ngx_log_t *log, const EVP_CIPHER *cipher, | 113 static ngx_int_t ngx_quic_tls_hp(ngx_log_t *log, const EVP_CIPHER *cipher, |
80 ngx_quic_secret_t *s, u_char *out, u_char *in); | 114 ngx_quic_secret_t *s, u_char *out, u_char *in); |
81 static ngx_int_t ngx_quic_hkdf_expand(ngx_pool_t *pool, const EVP_MD *digest, | 115 static ngx_int_t ngx_quic_hkdf_expand(ngx_quic_hkdf_t *hkdf, |
82 ngx_str_t *out, ngx_str_t *label, const uint8_t *prk, size_t prk_len); | 116 const EVP_MD *digest, ngx_pool_t *pool); |
83 | 117 |
84 static ngx_int_t ngx_quic_create_packet(ngx_quic_header_t *pkt, | 118 static ngx_int_t ngx_quic_create_packet(ngx_quic_header_t *pkt, |
85 ngx_str_t *res); | 119 ngx_str_t *res); |
86 static ngx_int_t ngx_quic_create_retry_packet(ngx_quic_header_t *pkt, | 120 static ngx_int_t ngx_quic_create_retry_packet(ngx_quic_header_t *pkt, |
87 ngx_str_t *res); | 121 ngx_str_t *res); |
202 server->hp.len = NGX_QUIC_AES_128_KEY_LEN; | 236 server->hp.len = NGX_QUIC_AES_128_KEY_LEN; |
203 | 237 |
204 client->iv.len = NGX_QUIC_IV_LEN; | 238 client->iv.len = NGX_QUIC_IV_LEN; |
205 server->iv.len = NGX_QUIC_IV_LEN; | 239 server->iv.len = NGX_QUIC_IV_LEN; |
206 | 240 |
207 struct { | 241 ngx_quic_hkdf_t seq[] = { |
208 ngx_str_t label; | |
209 ngx_str_t *key; | |
210 ngx_str_t *prk; | |
211 } seq[] = { | |
212 /* labels per RFC 9001, 5.1. Packet Protection Keys */ | 242 /* labels per RFC 9001, 5.1. Packet Protection Keys */ |
213 { ngx_string("tls13 client in"), &client->secret, &iss }, | 243 ngx_quic_hkdf_set("tls13 client in", &client->secret, &iss), |
214 { ngx_string("tls13 quic key"), &client->key, &client->secret }, | 244 ngx_quic_hkdf_set("tls13 quic key", &client->key, &client->secret), |
215 { ngx_string("tls13 quic iv"), &client->iv, &client->secret }, | 245 ngx_quic_hkdf_set("tls13 quic iv", &client->iv, &client->secret), |
216 { ngx_string("tls13 quic hp"), &client->hp, &client->secret }, | 246 ngx_quic_hkdf_set("tls13 quic hp", &client->hp, &client->secret), |
217 { ngx_string("tls13 server in"), &server->secret, &iss }, | 247 ngx_quic_hkdf_set("tls13 server in", &server->secret, &iss), |
218 { ngx_string("tls13 quic key"), &server->key, &server->secret }, | 248 ngx_quic_hkdf_set("tls13 quic key", &server->key, &server->secret), |
219 { ngx_string("tls13 quic iv"), &server->iv, &server->secret }, | 249 ngx_quic_hkdf_set("tls13 quic iv", &server->iv, &server->secret), |
220 { ngx_string("tls13 quic hp"), &server->hp, &server->secret }, | 250 ngx_quic_hkdf_set("tls13 quic hp", &server->hp, &server->secret), |
221 }; | 251 }; |
222 | 252 |
223 for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) { | 253 for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) { |
224 | 254 if (ngx_quic_hkdf_expand(&seq[i], digest, pool) != NGX_OK) { |
225 if (ngx_quic_hkdf_expand(pool, digest, seq[i].key, &seq[i].label, | |
226 seq[i].prk->data, seq[i].prk->len) | |
227 != NGX_OK) | |
228 { | |
229 return NGX_ERROR; | 255 return NGX_ERROR; |
230 } | 256 } |
231 } | 257 } |
232 | 258 |
233 return NGX_OK; | 259 return NGX_OK; |
234 } | 260 } |
235 | 261 |
236 | 262 |
237 static ngx_int_t | 263 static ngx_int_t |
238 ngx_quic_hkdf_expand(ngx_pool_t *pool, const EVP_MD *digest, ngx_str_t *out, | 264 ngx_quic_hkdf_expand(ngx_quic_hkdf_t *h, const EVP_MD *digest, ngx_pool_t *pool) |
239 ngx_str_t *label, const uint8_t *prk, size_t prk_len) | |
240 { | 265 { |
241 size_t info_len; | 266 size_t info_len; |
242 uint8_t *p; | 267 uint8_t *p; |
243 uint8_t info[20]; | 268 uint8_t info[20]; |
244 | 269 |
245 if (out->data == NULL) { | 270 info_len = 2 + 1 + h->label_len + 1; |
246 out->data = ngx_pnalloc(pool, out->len); | |
247 if (out->data == NULL) { | |
248 return NGX_ERROR; | |
249 } | |
250 } | |
251 | |
252 info_len = 2 + 1 + label->len + 1; | |
253 | 271 |
254 info[0] = 0; | 272 info[0] = 0; |
255 info[1] = out->len; | 273 info[1] = h->out_len; |
256 info[2] = label->len; | 274 info[2] = h->label_len; |
257 p = ngx_cpymem(&info[3], label->data, label->len); | 275 |
276 p = ngx_cpymem(&info[3], h->label, h->label_len); | |
258 *p = '\0'; | 277 *p = '\0'; |
259 | 278 |
260 if (ngx_hkdf_expand(out->data, out->len, digest, | 279 if (ngx_hkdf_expand(h->out, h->out_len, digest, |
261 prk, prk_len, info, info_len) | 280 h->prk, h->prk_len, info, info_len) |
262 != NGX_OK) | 281 != NGX_OK) |
263 { | 282 { |
264 ngx_ssl_error(NGX_LOG_INFO, pool->log, 0, | 283 ngx_ssl_error(NGX_LOG_INFO, pool->log, 0, |
265 "ngx_hkdf_expand(%V) failed", label); | 284 "ngx_hkdf_expand(%*s) failed", h->label_len, h->label); |
266 return NGX_ERROR; | 285 return NGX_ERROR; |
267 } | 286 } |
268 | 287 |
269 #ifdef NGX_QUIC_DEBUG_CRYPTO | 288 #ifdef NGX_QUIC_DEBUG_CRYPTO |
270 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pool->log, 0, | 289 ngx_log_debug5(NGX_LOG_DEBUG_EVENT, pool->log, 0, |
271 "quic expand %V key len:%uz %xV", label, out->len, out); | 290 "quic expand \"%*s\" len:%uz %*xs", |
291 h->label_len, h->label, h->out_len, h->out_len, h->out); | |
272 #endif | 292 #endif |
273 | 293 |
274 return NGX_OK; | 294 return NGX_OK; |
275 } | 295 } |
276 | 296 |
650 ngx_quic_keys_set_encryption_secret(ngx_pool_t *pool, ngx_uint_t is_write, | 670 ngx_quic_keys_set_encryption_secret(ngx_pool_t *pool, ngx_uint_t is_write, |
651 ngx_quic_keys_t *keys, enum ssl_encryption_level_t level, | 671 ngx_quic_keys_t *keys, enum ssl_encryption_level_t level, |
652 const SSL_CIPHER *cipher, const uint8_t *secret, size_t secret_len) | 672 const SSL_CIPHER *cipher, const uint8_t *secret, size_t secret_len) |
653 { | 673 { |
654 ngx_int_t key_len; | 674 ngx_int_t key_len; |
675 ngx_str_t secret_str; | |
655 ngx_uint_t i; | 676 ngx_uint_t i; |
656 ngx_quic_secret_t *peer_secret; | 677 ngx_quic_secret_t *peer_secret; |
657 ngx_quic_ciphers_t ciphers; | 678 ngx_quic_ciphers_t ciphers; |
658 | 679 |
659 peer_secret = is_write ? &keys->secrets[level].server | 680 peer_secret = is_write ? &keys->secrets[level].server |
666 if (key_len == NGX_ERROR) { | 687 if (key_len == NGX_ERROR) { |
667 ngx_ssl_error(NGX_LOG_INFO, pool->log, 0, "unexpected cipher"); | 688 ngx_ssl_error(NGX_LOG_INFO, pool->log, 0, "unexpected cipher"); |
668 return NGX_ERROR; | 689 return NGX_ERROR; |
669 } | 690 } |
670 | 691 |
671 peer_secret->secret.data = ngx_pnalloc(pool, secret_len); | 692 if (sizeof(peer_secret->secret.data) < secret_len) { |
672 if (peer_secret->secret.data == NULL) { | 693 ngx_log_error(NGX_LOG_ALERT, pool->log, 0, |
694 "unexpected secret len: %uz", secret_len); | |
673 return NGX_ERROR; | 695 return NGX_ERROR; |
674 } | 696 } |
675 | 697 |
676 peer_secret->secret.len = secret_len; | 698 peer_secret->secret.len = secret_len; |
677 ngx_memcpy(peer_secret->secret.data, secret, secret_len); | 699 ngx_memcpy(peer_secret->secret.data, secret, secret_len); |
678 | 700 |
679 peer_secret->key.len = key_len; | 701 peer_secret->key.len = key_len; |
680 peer_secret->iv.len = NGX_QUIC_IV_LEN; | 702 peer_secret->iv.len = NGX_QUIC_IV_LEN; |
681 peer_secret->hp.len = key_len; | 703 peer_secret->hp.len = key_len; |
682 | 704 |
683 struct { | 705 secret_str.len = secret_len; |
684 ngx_str_t label; | 706 secret_str.data = (u_char *) secret; |
685 ngx_str_t *key; | 707 |
686 const uint8_t *secret; | 708 ngx_quic_hkdf_t seq[] = { |
687 } seq[] = { | 709 ngx_quic_hkdf_set("tls13 quic key", &peer_secret->key, &secret_str), |
688 { ngx_string("tls13 quic key"), &peer_secret->key, secret }, | 710 ngx_quic_hkdf_set("tls13 quic iv", &peer_secret->iv, &secret_str), |
689 { ngx_string("tls13 quic iv"), &peer_secret->iv, secret }, | 711 ngx_quic_hkdf_set("tls13 quic hp", &peer_secret->hp, &secret_str), |
690 { ngx_string("tls13 quic hp"), &peer_secret->hp, secret }, | |
691 }; | 712 }; |
692 | 713 |
693 for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) { | 714 for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) { |
694 | 715 if (ngx_quic_hkdf_expand(&seq[i], ciphers.d, pool) != NGX_OK) { |
695 if (ngx_quic_hkdf_expand(pool, ciphers.d, seq[i].key, &seq[i].label, | |
696 seq[i].secret, secret_len) | |
697 != NGX_OK) | |
698 { | |
699 return NGX_ERROR; | 716 return NGX_ERROR; |
700 } | 717 } |
701 } | 718 } |
702 | 719 |
703 return NGX_OK; | 720 return NGX_OK; |
767 next->server.secret.len = current->server.secret.len; | 784 next->server.secret.len = current->server.secret.len; |
768 next->server.key.len = current->server.key.len; | 785 next->server.key.len = current->server.key.len; |
769 next->server.iv.len = NGX_QUIC_IV_LEN; | 786 next->server.iv.len = NGX_QUIC_IV_LEN; |
770 next->server.hp = current->server.hp; | 787 next->server.hp = current->server.hp; |
771 | 788 |
772 struct { | 789 ngx_quic_hkdf_t seq[] = { |
773 ngx_str_t label; | 790 ngx_quic_hkdf_set("tls13 quic ku", |
774 ngx_str_t *key; | 791 &next->client.secret, ¤t->client.secret), |
775 ngx_str_t *secret; | 792 ngx_quic_hkdf_set("tls13 quic key", |
776 } seq[] = { | 793 &next->client.key, &next->client.secret), |
777 { | 794 ngx_quic_hkdf_set("tls13 quic iv", |
778 ngx_string("tls13 quic ku"), | 795 &next->client.iv, &next->client.secret), |
779 &next->client.secret, | 796 ngx_quic_hkdf_set("tls13 quic ku", |
780 ¤t->client.secret, | 797 &next->server.secret, ¤t->server.secret), |
781 }, | 798 ngx_quic_hkdf_set("tls13 quic key", |
782 { | 799 &next->server.key, &next->server.secret), |
783 ngx_string("tls13 quic key"), | 800 ngx_quic_hkdf_set("tls13 quic iv", |
784 &next->client.key, | 801 &next->server.iv, &next->server.secret), |
785 &next->client.secret, | |
786 }, | |
787 { | |
788 ngx_string("tls13 quic iv"), | |
789 &next->client.iv, | |
790 &next->client.secret, | |
791 }, | |
792 { | |
793 ngx_string("tls13 quic ku"), | |
794 &next->server.secret, | |
795 ¤t->server.secret, | |
796 }, | |
797 { | |
798 ngx_string("tls13 quic key"), | |
799 &next->server.key, | |
800 &next->server.secret, | |
801 }, | |
802 { | |
803 ngx_string("tls13 quic iv"), | |
804 &next->server.iv, | |
805 &next->server.secret, | |
806 }, | |
807 }; | 802 }; |
808 | 803 |
809 for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) { | 804 for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) { |
810 | 805 if (ngx_quic_hkdf_expand(&seq[i], ciphers.d, c->pool) != NGX_OK) { |
811 if (ngx_quic_hkdf_expand(c->pool, ciphers.d, seq[i].key, &seq[i].label, | |
812 seq[i].secret->data, seq[i].secret->len) | |
813 != NGX_OK) | |
814 { | |
815 return NGX_ERROR; | 806 return NGX_ERROR; |
816 } | 807 } |
817 } | 808 } |
818 | 809 |
819 return NGX_OK; | 810 return NGX_OK; |
907 if (ngx_quic_ciphers(0, &ciphers, pkt->level) == NGX_ERROR) { | 898 if (ngx_quic_ciphers(0, &ciphers, pkt->level) == NGX_ERROR) { |
908 return NGX_ERROR; | 899 return NGX_ERROR; |
909 } | 900 } |
910 | 901 |
911 secret.key.len = sizeof(key); | 902 secret.key.len = sizeof(key); |
912 secret.key.data = key; | 903 ngx_memcpy(secret.key.data, key, sizeof(key)); |
913 secret.iv.len = NGX_QUIC_IV_LEN; | 904 secret.iv.len = NGX_QUIC_IV_LEN; |
914 | 905 |
915 if (ngx_quic_tls_seal(ciphers.c, &secret, &itag, nonce, &in, &ad, pkt->log) | 906 if (ngx_quic_tls_seal(ciphers.c, &secret, &itag, nonce, &in, &ad, pkt->log) |
916 != NGX_OK) | 907 != NGX_OK) |
917 { | 908 { |