# HG changeset patch # User Vladimir Homutov # Date 1658927733 -14400 # Node ID d8b3851f172ccefcebc7623ae5ab907269ad71c1 # Parent b30bec3d71d6278cc3aca0569bab82c1d4c90843 QUIC: fixed-length buffers for secrets. diff --git a/src/event/quic/ngx_event_quic_protection.c b/src/event/quic/ngx_event_quic_protection.c --- a/src/event/quic/ngx_event_quic_protection.c +++ b/src/event/quic/ngx_event_quic_protection.c @@ -17,6 +17,9 @@ #define NGX_QUIC_AES_128_KEY_LEN 16 +/* largest hash used in TLS is SHA-384 */ +#define NGX_QUIC_MAX_MD_SIZE 48 + #define NGX_AES_128_GCM_SHA256 0x1301 #define NGX_AES_256_GCM_SHA384 0x1302 #define NGX_CHACHA20_POLY1305_SHA256 0x1303 @@ -30,6 +33,18 @@ typedef struct { + size_t len; + u_char data[NGX_QUIC_MAX_MD_SIZE]; +} ngx_quic_md_t; + + +typedef struct { + size_t len; + u_char data[NGX_QUIC_IV_LEN]; +} ngx_quic_iv_t; + + +typedef struct { const ngx_quic_cipher_t *c; const EVP_CIPHER *hp; const EVP_MD *d; @@ -37,10 +52,10 @@ typedef struct { typedef struct ngx_quic_secret_s { - ngx_str_t secret; - ngx_str_t key; - ngx_str_t iv; - ngx_str_t hp; + ngx_quic_md_t secret; + ngx_quic_md_t key; + ngx_quic_iv_t iv; + ngx_quic_md_t hp; } ngx_quic_secret_t; @@ -57,6 +72,25 @@ struct ngx_quic_keys_s { }; +typedef struct { + size_t out_len; + u_char *out; + + size_t prk_len; + const uint8_t *prk; + + size_t label_len; + const u_char *label; +} ngx_quic_hkdf_t; + +#define ngx_quic_hkdf_set(label, out, prk) \ + { \ + (out)->len, (out)->data, \ + (prk)->len, (prk)->data, \ + (sizeof(label) - 1), (u_char *)(label), \ + } + + static ngx_int_t ngx_hkdf_expand(u_char *out_key, size_t out_len, const EVP_MD *digest, const u_char *prk, size_t prk_len, const u_char *info, size_t info_len); @@ -78,8 +112,8 @@ static ngx_int_t ngx_quic_tls_seal(const ngx_str_t *ad, ngx_log_t *log); static ngx_int_t ngx_quic_tls_hp(ngx_log_t *log, const EVP_CIPHER *cipher, ngx_quic_secret_t *s, u_char *out, u_char *in); -static ngx_int_t ngx_quic_hkdf_expand(ngx_pool_t *pool, const EVP_MD *digest, - ngx_str_t *out, ngx_str_t *label, const uint8_t *prk, size_t prk_len); +static ngx_int_t ngx_quic_hkdf_expand(ngx_quic_hkdf_t *hkdf, + const EVP_MD *digest, ngx_pool_t *pool); static ngx_int_t ngx_quic_create_packet(ngx_quic_header_t *pkt, ngx_str_t *res); @@ -204,28 +238,20 @@ ngx_quic_keys_set_initial_secret(ngx_poo client->iv.len = NGX_QUIC_IV_LEN; server->iv.len = NGX_QUIC_IV_LEN; - struct { - ngx_str_t label; - ngx_str_t *key; - ngx_str_t *prk; - } seq[] = { + ngx_quic_hkdf_t seq[] = { /* labels per RFC 9001, 5.1. Packet Protection Keys */ - { ngx_string("tls13 client in"), &client->secret, &iss }, - { ngx_string("tls13 quic key"), &client->key, &client->secret }, - { ngx_string("tls13 quic iv"), &client->iv, &client->secret }, - { ngx_string("tls13 quic hp"), &client->hp, &client->secret }, - { ngx_string("tls13 server in"), &server->secret, &iss }, - { ngx_string("tls13 quic key"), &server->key, &server->secret }, - { ngx_string("tls13 quic iv"), &server->iv, &server->secret }, - { ngx_string("tls13 quic hp"), &server->hp, &server->secret }, + ngx_quic_hkdf_set("tls13 client in", &client->secret, &iss), + ngx_quic_hkdf_set("tls13 quic key", &client->key, &client->secret), + ngx_quic_hkdf_set("tls13 quic iv", &client->iv, &client->secret), + ngx_quic_hkdf_set("tls13 quic hp", &client->hp, &client->secret), + ngx_quic_hkdf_set("tls13 server in", &server->secret, &iss), + ngx_quic_hkdf_set("tls13 quic key", &server->key, &server->secret), + ngx_quic_hkdf_set("tls13 quic iv", &server->iv, &server->secret), + ngx_quic_hkdf_set("tls13 quic hp", &server->hp, &server->secret), }; for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) { - - if (ngx_quic_hkdf_expand(pool, digest, seq[i].key, &seq[i].label, - seq[i].prk->data, seq[i].prk->len) - != NGX_OK) - { + if (ngx_quic_hkdf_expand(&seq[i], digest, pool) != NGX_OK) { return NGX_ERROR; } } @@ -235,40 +261,34 @@ ngx_quic_keys_set_initial_secret(ngx_poo static ngx_int_t -ngx_quic_hkdf_expand(ngx_pool_t *pool, const EVP_MD *digest, ngx_str_t *out, - ngx_str_t *label, const uint8_t *prk, size_t prk_len) +ngx_quic_hkdf_expand(ngx_quic_hkdf_t *h, const EVP_MD *digest, ngx_pool_t *pool) { size_t info_len; uint8_t *p; uint8_t info[20]; - if (out->data == NULL) { - out->data = ngx_pnalloc(pool, out->len); - if (out->data == NULL) { - return NGX_ERROR; - } - } - - info_len = 2 + 1 + label->len + 1; + info_len = 2 + 1 + h->label_len + 1; info[0] = 0; - info[1] = out->len; - info[2] = label->len; - p = ngx_cpymem(&info[3], label->data, label->len); + info[1] = h->out_len; + info[2] = h->label_len; + + p = ngx_cpymem(&info[3], h->label, h->label_len); *p = '\0'; - if (ngx_hkdf_expand(out->data, out->len, digest, - prk, prk_len, info, info_len) + if (ngx_hkdf_expand(h->out, h->out_len, digest, + h->prk, h->prk_len, info, info_len) != NGX_OK) { ngx_ssl_error(NGX_LOG_INFO, pool->log, 0, - "ngx_hkdf_expand(%V) failed", label); + "ngx_hkdf_expand(%*s) failed", h->label_len, h->label); return NGX_ERROR; } #ifdef NGX_QUIC_DEBUG_CRYPTO - ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pool->log, 0, - "quic expand %V key len:%uz %xV", label, out->len, out); + ngx_log_debug5(NGX_LOG_DEBUG_EVENT, pool->log, 0, + "quic expand \"%*s\" len:%uz %*xs", + h->label_len, h->label, h->out_len, h->out_len, h->out); #endif return NGX_OK; @@ -652,6 +672,7 @@ ngx_quic_keys_set_encryption_secret(ngx_ const SSL_CIPHER *cipher, const uint8_t *secret, size_t secret_len) { ngx_int_t key_len; + ngx_str_t secret_str; ngx_uint_t i; ngx_quic_secret_t *peer_secret; ngx_quic_ciphers_t ciphers; @@ -668,8 +689,9 @@ ngx_quic_keys_set_encryption_secret(ngx_ return NGX_ERROR; } - peer_secret->secret.data = ngx_pnalloc(pool, secret_len); - if (peer_secret->secret.data == NULL) { + if (sizeof(peer_secret->secret.data) < secret_len) { + ngx_log_error(NGX_LOG_ALERT, pool->log, 0, + "unexpected secret len: %uz", secret_len); return NGX_ERROR; } @@ -680,22 +702,17 @@ ngx_quic_keys_set_encryption_secret(ngx_ peer_secret->iv.len = NGX_QUIC_IV_LEN; peer_secret->hp.len = key_len; - struct { - ngx_str_t label; - ngx_str_t *key; - const uint8_t *secret; - } seq[] = { - { ngx_string("tls13 quic key"), &peer_secret->key, secret }, - { ngx_string("tls13 quic iv"), &peer_secret->iv, secret }, - { ngx_string("tls13 quic hp"), &peer_secret->hp, secret }, + secret_str.len = secret_len; + secret_str.data = (u_char *) secret; + + ngx_quic_hkdf_t seq[] = { + ngx_quic_hkdf_set("tls13 quic key", &peer_secret->key, &secret_str), + ngx_quic_hkdf_set("tls13 quic iv", &peer_secret->iv, &secret_str), + ngx_quic_hkdf_set("tls13 quic hp", &peer_secret->hp, &secret_str), }; for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) { - - if (ngx_quic_hkdf_expand(pool, ciphers.d, seq[i].key, &seq[i].label, - seq[i].secret, secret_len) - != NGX_OK) - { + if (ngx_quic_hkdf_expand(&seq[i], ciphers.d, pool) != NGX_OK) { return NGX_ERROR; } } @@ -769,49 +786,23 @@ ngx_quic_keys_update(ngx_connection_t *c next->server.iv.len = NGX_QUIC_IV_LEN; next->server.hp = current->server.hp; - struct { - ngx_str_t label; - ngx_str_t *key; - ngx_str_t *secret; - } seq[] = { - { - ngx_string("tls13 quic ku"), - &next->client.secret, - ¤t->client.secret, - }, - { - ngx_string("tls13 quic key"), - &next->client.key, - &next->client.secret, - }, - { - ngx_string("tls13 quic iv"), - &next->client.iv, - &next->client.secret, - }, - { - ngx_string("tls13 quic ku"), - &next->server.secret, - ¤t->server.secret, - }, - { - ngx_string("tls13 quic key"), - &next->server.key, - &next->server.secret, - }, - { - ngx_string("tls13 quic iv"), - &next->server.iv, - &next->server.secret, - }, + ngx_quic_hkdf_t seq[] = { + ngx_quic_hkdf_set("tls13 quic ku", + &next->client.secret, ¤t->client.secret), + ngx_quic_hkdf_set("tls13 quic key", + &next->client.key, &next->client.secret), + ngx_quic_hkdf_set("tls13 quic iv", + &next->client.iv, &next->client.secret), + ngx_quic_hkdf_set("tls13 quic ku", + &next->server.secret, ¤t->server.secret), + ngx_quic_hkdf_set("tls13 quic key", + &next->server.key, &next->server.secret), + ngx_quic_hkdf_set("tls13 quic iv", + &next->server.iv, &next->server.secret), }; for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) { - - if (ngx_quic_hkdf_expand(c->pool, ciphers.d, seq[i].key, &seq[i].label, - seq[i].secret->data, seq[i].secret->len) - != NGX_OK) - { + if (ngx_quic_hkdf_expand(&seq[i], ciphers.d, c->pool) != NGX_OK) { return NGX_ERROR; } } @@ -909,7 +900,7 @@ ngx_quic_create_retry_packet(ngx_quic_he } secret.key.len = sizeof(key); - secret.key.data = key; + ngx_memcpy(secret.key.data, key, sizeof(key)); secret.iv.len = NGX_QUIC_IV_LEN; if (ngx_quic_tls_seal(ciphers.c, &secret, &itag, nonce, &in, &ad, pkt->log)