comparison src/event/quic/ngx_event_quic_protection.c @ 9023: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
9022:b30bec3d71d6 9023: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, &current->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 &current->client.secret, 797 &next->server.secret, &current->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 &current->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 {