# HG changeset patch # User Sergey Kandaurov # Date 1582884591 -10800 # Node ID bd006bd520a9a5d443eb0a6f32da45233763bb84 # Parent b507592c15a7b843163939cb73f640b07729a509 QUIC set_encryption_secrets callback. diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -89,6 +89,7 @@ static void *ngx_openssl_create_conf(ngx static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static void ngx_openssl_exit(ngx_cycle_t *cycle); + #if NGX_OPENSSL_QUIC static int @@ -96,8 +97,11 @@ quic_set_encryption_secrets(ngx_ssl_conn enum ssl_encryption_level_t level, const uint8_t *read_secret, const uint8_t *write_secret, size_t secret_len) { - size_t *len; + size_t *rlen, *wlen; uint8_t **rsec, **wsec; + const char *name; + const EVP_MD *digest; + const EVP_AEAD *aead; ngx_connection_t *c; c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); @@ -111,50 +115,245 @@ quic_set_encryption_secrets(ngx_ssl_conn m = ngx_hex_dump(buf, (u_char *) read_secret, secret_len) - buf; ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, - "set_encryption_secrets: %*s, len: %uz, level:%d", + "set_encryption_secrets: read %*s, len: %uz, level:%d", m, buf, secret_len, (int) level); m = ngx_hex_dump(buf, (u_char *) write_secret, secret_len) - buf; ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, - "set_encryption_secrets: %*s, len: %uz, level:%d", + "set_encryption_secrets: write %*s, len: %uz, level:%d", m, buf, secret_len, (int) level); } #endif + name = SSL_get_cipher(ssl_conn); + + if (OPENSSL_strcasecmp(name, "TLS_AES_128_GCM_SHA256") == 0) { + aead = EVP_aead_aes_128_gcm(); + digest = EVP_sha256(); + + } else if (OPENSSL_strcasecmp(name, "TLS_AES_256_GCM_SHA384") == 0) { + aead = EVP_aead_aes_256_gcm(); + digest = EVP_sha384(); + + } else { + return 0; + } + + size_t hkdfl_len; + uint8_t hkdfl[20]; + uint8_t *p; + const char *label; + + ngx_str_t *client_key, *client_iv, *client_hp; + ngx_str_t *server_key, *server_iv, *server_hp; + switch (level) { case ssl_encryption_handshake: - len = &c->quic->handshake_secret_len; - rsec = &c->quic->handshake_read_secret; - wsec = &c->quic->handshake_write_secret; + rlen = &c->quic->client_hs.len; + rsec = &c->quic->client_hs.data; + wlen = &c->quic->server_hs.len; + wsec = &c->quic->server_hs.data; + + client_key = &c->quic->client_hs_key; + client_iv = &c->quic->client_hs_iv; + client_hp = &c->quic->client_hs_hp; + + server_key = &c->quic->server_hs_key; + server_iv = &c->quic->server_hs_iv; + server_hp = &c->quic->server_hs_hp; + break; case ssl_encryption_application: - len = &c->quic->application_secret_len; - rsec = &c->quic->application_read_secret; - wsec = &c->quic->application_write_secret; + rlen = &c->quic->client_ad.len; + rsec = &c->quic->client_ad.data; + wlen = &c->quic->server_ad.len; + wsec = &c->quic->server_ad.data; + + client_key = &c->quic->client_ad_key; + client_iv = &c->quic->client_ad_iv; + client_hp = &c->quic->client_ad_hp; + + server_key = &c->quic->server_ad_key; + server_iv = &c->quic->server_ad_iv; + server_hp = &c->quic->server_ad_hp; + break; default: return 0; } - *len = secret_len; + *rlen = *wlen = secret_len; *rsec = ngx_pnalloc(c->pool, secret_len); if (*rsec == NULL) { - return NGX_ERROR; + return 0; } ngx_memcpy(*rsec, read_secret, secret_len); *wsec = ngx_pnalloc(c->pool, secret_len); if (*wsec == NULL) { - return NGX_ERROR; + return 0; } ngx_memcpy(*wsec, write_secret, secret_len); + // client keys + + client_key->len = EVP_AEAD_key_length(aead); + client_key->data = ngx_pnalloc(c->pool, client_key->len); + if (client_key->data == NULL) { + return 0; + } + + label = "tls13 quic key"; + hkdfl_len = 2 + 1 + sizeof(label) - 1 + 1; + hkdfl[0] = client_key->len / 256; + hkdfl[1] = client_key->len % 256; + hkdfl[2] = sizeof(label) - 1; + p = ngx_cpymem(&hkdfl[3], label, sizeof(label) - 1); + *p = '\0'; + + if (HKDF_expand(client_key->data, client_key->len, + digest, *rsec, *rlen, + hkdfl, hkdfl_len) + == 0) + { + ngx_ssl_error(NGX_LOG_INFO, c->log, 0, + "HKDF_expand(client_key) failed"); + return 0; + } + + + client_iv->len = EVP_AEAD_nonce_length(aead); + client_iv->data = ngx_pnalloc(c->pool, client_iv->len); + if (client_iv->data == NULL) { + return 0; + } + + label = "tls13 quic iv"; + hkdfl_len = 2 + 1 + sizeof(label) - 1 + 1; + hkdfl[0] = client_iv->len / 256; + hkdfl[1] = client_iv->len % 256; + hkdfl[2] = sizeof(label) - 1; + p = ngx_cpymem(&hkdfl[3], label, sizeof(label) - 1); + *p = '\0'; + + if (HKDF_expand(client_iv->data, client_iv->len, + digest, *rsec, *rlen, + hkdfl, hkdfl_len) + == 0) + { + ngx_ssl_error(NGX_LOG_INFO, c->log, 0, + "HKDF_expand(client_iv) failed"); + return 0; + } + + + client_hp->len = EVP_AEAD_key_length(aead); + client_hp->data = ngx_pnalloc(c->pool, client_hp->len); + if (client_hp->data == NULL) { + return 0; + } + + label = "tls13 quic hp"; + hkdfl_len = 2 + 1 + sizeof(label) - 1 + 1; + hkdfl[0] = client_hp->len / 256; + hkdfl[1] = client_hp->len % 256; + hkdfl[2] = sizeof(label) - 1; + p = ngx_cpymem(&hkdfl[3], label, sizeof(label) - 1); + *p = '\0'; + + if (HKDF_expand(client_hp->data, client_hp->len, + digest, *rsec, *rlen, + hkdfl, hkdfl_len) + == 0) + { + ngx_ssl_error(NGX_LOG_INFO, c->log, 0, + "HKDF_expand(client_hp) failed"); + return 0; + } + + + // server keys + + server_key->len = EVP_AEAD_key_length(aead); + server_key->data = ngx_pnalloc(c->pool, server_key->len); + if (server_key->data == NULL) { + return 0; + } + + label = "tls13 quic key"; + hkdfl_len = 2 + 1 + sizeof(label) - 1 + 1; + hkdfl[0] = server_key->len / 256; + hkdfl[1] = server_key->len % 256; + hkdfl[2] = sizeof(label) - 1; + p = ngx_cpymem(&hkdfl[3], label, sizeof(label) - 1); + *p = '\0'; + + if (HKDF_expand(server_key->data, server_key->len, + digest, *wsec, *wlen, + hkdfl, hkdfl_len) + == 0) + { + ngx_ssl_error(NGX_LOG_INFO, c->log, 0, + "HKDF_expand(server_key) failed"); + return 0; + } + + + server_iv->len = EVP_AEAD_nonce_length(aead); + server_iv->data = ngx_pnalloc(c->pool, server_iv->len); + if (server_iv->data == NULL) { + return 0; + } + + label = "tls13 quic iv"; + hkdfl_len = 2 + 1 + sizeof(label) - 1 + 1; + hkdfl[0] = server_iv->len / 256; + hkdfl[1] = server_iv->len % 256; + hkdfl[2] = sizeof(label) - 1; + p = ngx_cpymem(&hkdfl[3], label, sizeof(label) - 1); + *p = '\0'; + + if (HKDF_expand(server_iv->data, server_iv->len, + digest, *wsec, *wlen, + hkdfl, hkdfl_len) + == 0) + { + ngx_ssl_error(NGX_LOG_INFO, c->log, 0, + "HKDF_expand(server_iv) failed"); + return 0; + } + + + server_hp->len = EVP_AEAD_key_length(aead); + server_hp->data = ngx_pnalloc(c->pool, server_hp->len); + if (server_hp->data == NULL) { + return 0; + } + + label = "tls13 quic hp"; + hkdfl_len = 2 + 1 + sizeof(label) - 1 + 1; + hkdfl[0] = server_hp->len / 256; + hkdfl[1] = server_hp->len % 256; + hkdfl[2] = sizeof(label) - 1; + p = ngx_cpymem(&hkdfl[3], label, sizeof(label) - 1); + *p = '\0'; + + if (HKDF_expand(server_hp->data, server_hp->len, + digest, *wsec, *wlen, + hkdfl, hkdfl_len) + == 0) + { + ngx_ssl_error(NGX_LOG_INFO, c->log, 0, + "HKDF_expand(server_hp) failed"); + return 0; + } + return 1; } diff --git a/src/event/ngx_event_quic.h b/src/event/ngx_event_quic.h --- a/src/event/ngx_event_quic.h +++ b/src/event/ngx_event_quic.h @@ -23,13 +23,25 @@ struct ngx_quic_connection_s { ngx_str_t server_in_iv; ngx_str_t server_in_hp; - size_t handshake_secret_len; - uint8_t *handshake_read_secret; - uint8_t *handshake_write_secret; + ngx_str_t client_hs; + ngx_str_t client_hs_key; + ngx_str_t client_hs_iv; + ngx_str_t client_hs_hp; + + ngx_str_t server_hs; + ngx_str_t server_hs_key; + ngx_str_t server_hs_iv; + ngx_str_t server_hs_hp; - size_t application_secret_len; - uint8_t *application_read_secret; - uint8_t *application_write_secret; + ngx_str_t client_ad; + ngx_str_t client_ad_key; + ngx_str_t client_ad_iv; + ngx_str_t client_ad_hp; + + ngx_str_t server_ad; + ngx_str_t server_ad_key; + ngx_str_t server_ad_iv; + ngx_str_t server_ad_hp; }; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -783,8 +783,8 @@ ngx_http_quic_handshake(ngx_event_t *rev uint64_t plen = ngx_quic_parse_int(&b->pos); /* draft-ietf-quic-tls-23#section-5.4.2: * the Packet Number field is assumed to be 4 bytes long - * draft-ietf-quic-tls-23#section-5.4.3: - * AES-Based header protection samples 16 bytes + * draft-ietf-quic-tls-23#section-5.4.[34]: + * AES-Based and ChaCha20-Based header protections sample 16 bytes */ u_char *sample = b->pos + 4;