diff --git a/src/core/nginx.h b/src/core/nginx.h index e302526..5385f83 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1025001 -#define NGINX_VERSION "1.25.1" +#define nginx_version 1025002 +#define NGINX_VERSION "1.25.2" #define NGINX_VER "nginx/" NGINX_VERSION " by Hakase" #ifndef NGINX_SERVER diff --git a/src/event/quic/ngx_event_quic_openssl_compat.c b/src/event/quic/ngx_event_quic_openssl_compat.c index 63d380e..318feda 100644 --- a/src/event/quic/ngx_event_quic_openssl_compat.c +++ b/src/event/quic/ngx_event_quic_openssl_compat.c @@ -445,7 +445,7 @@ SSL_provide_quic_data(SSL *ssl, enum ssl_encryption_level_t level, u_char in[NGX_QUIC_COMPAT_RECORD_SIZE + 1]; u_char out[NGX_QUIC_COMPAT_RECORD_SIZE + 1 + SSL3_RT_HEADER_LENGTH - + EVP_GCM_TLS_TAG_LEN]; + + NGX_QUIC_TAG_LEN]; c = ngx_ssl_get_connection(ssl); @@ -528,7 +528,7 @@ ngx_quic_compat_create_header(ngx_quic_compat_record_t *rec, u_char *out, } else { type = SSL3_RT_APPLICATION_DATA; - len += EVP_GCM_TLS_TAG_LEN; + len += NGX_QUIC_TAG_LEN; } out[0] = type; @@ -552,7 +552,7 @@ ngx_quic_compat_create_record(ngx_quic_compat_record_t *rec, ngx_str_t *res) ad.data = res->data; ad.len = ngx_quic_compat_create_header(rec, ad.data, 0); - out.len = rec->payload.len + EVP_GCM_TLS_TAG_LEN; + out.len = rec->payload.len + NGX_QUIC_TAG_LEN; out.data = res->data + ad.len; #ifdef NGX_QUIC_DEBUG_CRYPTO diff --git a/src/event/quic/ngx_event_quic_protection.c b/src/event/quic/ngx_event_quic_protection.c index 7f77201..ecac6f5 100644 --- a/src/event/quic/ngx_event_quic_protection.c +++ b/src/event/quic/ngx_event_quic_protection.c @@ -15,13 +15,6 @@ #define NGX_QUIC_AES_128_KEY_LEN 16 -#ifndef TLS1_3_CK_AES_128_GCM_SHA256 -#define TLS1_3_CK_AES_128_GCM_SHA256 0x03001301 -#define TLS1_3_CK_AES_256_GCM_SHA384 0x03001302 -#define TLS1_3_CK_CHACHA20_POLY1305_SHA256 \ - 0x03001303 -#endif - 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, @@ -94,6 +87,15 @@ ngx_quic_ciphers(ngx_uint_t id, ngx_quic_ciphers_t *ciphers, len = 32; break; +#ifndef OPENSSL_IS_BORINGSSL + case TLS1_3_CK_AES_128_CCM_SHA256: + ciphers->c = EVP_aes_128_ccm(); + ciphers->hp = EVP_aes_128_ctr(); + ciphers->d = EVP_sha256(); + len = 16; + break; +#endif + default: return NGX_ERROR; } @@ -343,8 +345,7 @@ failed: static ngx_int_t ngx_quic_tls_open(const ngx_quic_cipher_t *cipher, ngx_quic_secret_t *s, - ngx_str_t *out, u_char *nonce, ngx_str_t *in, ngx_str_t *ad, - ngx_log_t *log) + ngx_str_t *out, u_char *nonce, ngx_str_t *in, ngx_str_t *ad, ngx_log_t *log) { #ifdef OPENSSL_IS_BORINGSSL @@ -369,7 +370,6 @@ ngx_quic_tls_open(const ngx_quic_cipher_t *cipher, ngx_quic_secret_t *s, EVP_AEAD_CTX_free(ctx); #else int len; - u_char *tag; EVP_CIPHER_CTX *ctx; ctx = EVP_CIPHER_CTX_new(); @@ -384,12 +384,24 @@ ngx_quic_tls_open(const ngx_quic_cipher_t *cipher, ngx_quic_secret_t *s, return NGX_ERROR; } - if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, s->iv.len, NULL) + in->len -= NGX_QUIC_TAG_LEN; + + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, NGX_QUIC_TAG_LEN, + in->data + in->len) == 0) { EVP_CIPHER_CTX_free(ctx); ngx_ssl_error(NGX_LOG_INFO, log, 0, - "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_IVLEN) failed"); + "EVP_CIPHER_CTX_ctrl(EVP_CTRL_AEAD_SET_TAG) failed"); + return NGX_ERROR; + } + + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, s->iv.len, NULL) + == 0) + { + EVP_CIPHER_CTX_free(ctx); + ngx_ssl_error(NGX_LOG_INFO, log, 0, + "EVP_CIPHER_CTX_ctrl(EVP_CTRL_AEAD_SET_IVLEN) failed"); return NGX_ERROR; } @@ -399,34 +411,29 @@ ngx_quic_tls_open(const ngx_quic_cipher_t *cipher, ngx_quic_secret_t *s, return NGX_ERROR; } + if (EVP_CIPHER_mode(cipher) == EVP_CIPH_CCM_MODE + && EVP_DecryptUpdate(ctx, NULL, &len, NULL, in->len) != 1) + { + EVP_CIPHER_CTX_free(ctx); + ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_DecryptUpdate() failed"); + return NGX_ERROR; + } + if (EVP_DecryptUpdate(ctx, NULL, &len, ad->data, ad->len) != 1) { EVP_CIPHER_CTX_free(ctx); ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_DecryptUpdate() failed"); return NGX_ERROR; } - if (EVP_DecryptUpdate(ctx, out->data, &len, in->data, - in->len - EVP_GCM_TLS_TAG_LEN) - != 1) - { + if (EVP_DecryptUpdate(ctx, out->data, &len, in->data, in->len) != 1) { EVP_CIPHER_CTX_free(ctx); ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_DecryptUpdate() failed"); return NGX_ERROR; } out->len = len; - tag = in->data + in->len - EVP_GCM_TLS_TAG_LEN; - if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, EVP_GCM_TLS_TAG_LEN, tag) - == 0) - { - EVP_CIPHER_CTX_free(ctx); - ngx_ssl_error(NGX_LOG_INFO, log, 0, - "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_TAG) failed"); - return NGX_ERROR; - } - - if (EVP_DecryptFinal_ex(ctx, out->data + len, &len) <= 0) { + if (EVP_DecryptFinal_ex(ctx, out->data + out->len, &len) <= 0) { EVP_CIPHER_CTX_free(ctx); ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_DecryptFinal_ex failed"); return NGX_ERROR; @@ -482,12 +489,23 @@ ngx_quic_tls_seal(const ngx_quic_cipher_t *cipher, ngx_quic_secret_t *s, return NGX_ERROR; } - if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, s->iv.len, NULL) + if (EVP_CIPHER_mode(cipher) == EVP_CIPH_CCM_MODE + && EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, NGX_QUIC_TAG_LEN, + NULL) + == 0) + { + EVP_CIPHER_CTX_free(ctx); + ngx_ssl_error(NGX_LOG_INFO, log, 0, + "EVP_CIPHER_CTX_ctrl(EVP_CTRL_AEAD_SET_TAG) failed"); + return NGX_ERROR; + } + + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, s->iv.len, NULL) == 0) { EVP_CIPHER_CTX_free(ctx); ngx_ssl_error(NGX_LOG_INFO, log, 0, - "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_IVLEN) failed"); + "EVP_CIPHER_CTX_ctrl(EVP_CTRL_AEAD_SET_IVLEN) failed"); return NGX_ERROR; } @@ -497,6 +515,14 @@ ngx_quic_tls_seal(const ngx_quic_cipher_t *cipher, ngx_quic_secret_t *s, return NGX_ERROR; } + if (EVP_CIPHER_mode(cipher) == EVP_CIPH_CCM_MODE + && EVP_EncryptUpdate(ctx, NULL, &len, NULL, in->len) != 1) + { + EVP_CIPHER_CTX_free(ctx); + ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_EncryptUpdate() failed"); + return NGX_ERROR; + } + if (EVP_EncryptUpdate(ctx, NULL, &len, ad->data, ad->len) != 1) { EVP_CIPHER_CTX_free(ctx); ngx_ssl_error(NGX_LOG_INFO, log, 0, "EVP_EncryptUpdate() failed"); @@ -519,20 +545,21 @@ ngx_quic_tls_seal(const ngx_quic_cipher_t *cipher, ngx_quic_secret_t *s, out->len += len; - if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, EVP_GCM_TLS_TAG_LEN, - out->data + in->len) + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, NGX_QUIC_TAG_LEN, + out->data + out->len) == 0) { EVP_CIPHER_CTX_free(ctx); ngx_ssl_error(NGX_LOG_INFO, log, 0, - "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_GET_TAG) failed"); + "EVP_CIPHER_CTX_ctrl(EVP_CTRL_AEAD_GET_TAG) failed"); return NGX_ERROR; } - EVP_CIPHER_CTX_free(ctx); + out->len += NGX_QUIC_TAG_LEN; - out->len += EVP_GCM_TLS_TAG_LEN; + EVP_CIPHER_CTX_free(ctx); #endif + return NGX_OK; } @@ -738,7 +765,7 @@ ngx_quic_create_packet(ngx_quic_header_t *pkt, ngx_str_t *res) ad.data = res->data; ad.len = ngx_quic_create_header(pkt, ad.data, &pnp); - out.len = pkt->payload.len + EVP_GCM_TLS_TAG_LEN; + out.len = pkt->payload.len + NGX_QUIC_TAG_LEN; out.data = res->data + ad.len; #ifdef NGX_QUIC_DEBUG_CRYPTO @@ -802,7 +829,7 @@ ngx_quic_create_retry_packet(ngx_quic_header_t *pkt, ngx_str_t *res) ad.len = ngx_quic_create_retry_itag(pkt, ad.data, &start); itag.data = ad.data + ad.len; - itag.len = EVP_GCM_TLS_TAG_LEN; + itag.len = NGX_QUIC_TAG_LEN; #ifdef NGX_QUIC_DEBUG_CRYPTO ngx_log_debug2(NGX_LOG_DEBUG_EVENT, pkt->log, 0, @@ -979,7 +1006,7 @@ ngx_quic_decrypt(ngx_quic_header_t *pkt, uint64_t *largest_pn) * AES and ChaCha20 algorithms sample 16 bytes */ - if (len < EVP_GCM_TLS_TAG_LEN + 4) { + if (len < NGX_QUIC_TAG_LEN + 4) { return NGX_DECLINED; } @@ -1039,7 +1066,7 @@ ngx_quic_decrypt(ngx_quic_header_t *pkt, uint64_t *largest_pn) "quic ad len:%uz %xV", ad.len, &ad); #endif - pkt->payload.len = in.len - EVP_GCM_TLS_TAG_LEN; + pkt->payload.len = in.len - NGX_QUIC_TAG_LEN; pkt->payload.data = pkt->plaintext + ad.len; rc = ngx_quic_tls_open(ciphers.c, secret, &pkt->payload, diff --git a/src/event/quic/ngx_event_quic_protection.h b/src/event/quic/ngx_event_quic_protection.h index 27f8617..4e56ea9 100644 --- a/src/event/quic/ngx_event_quic_protection.h +++ b/src/event/quic/ngx_event_quic_protection.h @@ -16,8 +16,9 @@ #define NGX_QUIC_ENCRYPTION_LAST ((ssl_encryption_application) + 1) -/* RFC 5116, 5.1 and RFC 8439, 2.3 for all supported ciphers */ +/* RFC 5116, 5.1/5.3 and RFC 8439, 2.3/2.5 for all supported ciphers */ #define NGX_QUIC_IV_LEN 12 +#define NGX_QUIC_TAG_LEN 16 /* largest hash used in TLS is SHA-384 */ #define NGX_QUIC_MAX_MD_SIZE 48 diff --git a/src/event/quic/ngx_event_quic_tokens.c b/src/event/quic/ngx_event_quic_tokens.c index e67825a..c1da0d4 100644 --- a/src/event/quic/ngx_event_quic_tokens.c +++ b/src/event/quic/ngx_event_quic_tokens.c @@ -69,11 +69,10 @@ ngx_quic_new_token(ngx_log_t *log, struct sockaddr *sockaddr, len = p - in; - cipher = EVP_aes_256_cbc(); - iv_len = NGX_QUIC_AES_256_CBC_IV_LEN; + cipher = EVP_aes_256_gcm(); + iv_len = NGX_QUIC_AES_256_GCM_IV_LEN; - if ((size_t) (iv_len + len + NGX_QUIC_AES_256_CBC_BLOCK_SIZE) > token->len) - { + if ((size_t) (iv_len + len + NGX_QUIC_AES_256_GCM_TAG_LEN) > token->len) { ngx_log_error(NGX_LOG_ALERT, log, 0, "quic token buffer is too small"); return NGX_ERROR; } @@ -108,6 +107,17 @@ ngx_quic_new_token(ngx_log_t *log, struct sockaddr *sockaddr, token->len += len; + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, + NGX_QUIC_AES_256_GCM_TAG_LEN, + token->data + token->len) + == 0) + { + EVP_CIPHER_CTX_free(ctx); + return NGX_ERROR; + } + + token->len += NGX_QUIC_AES_256_GCM_TAG_LEN; + EVP_CIPHER_CTX_free(ctx); #ifdef NGX_QUIC_DEBUG_PACKETS @@ -184,17 +194,19 @@ ngx_quic_validate_token(ngx_connection_t *c, u_char *key, /* Retry token or NEW_TOKEN in a previous connection */ - cipher = EVP_aes_256_cbc(); + cipher = EVP_aes_256_gcm(); iv = pkt->token.data; - iv_len = NGX_QUIC_AES_256_CBC_IV_LEN; + iv_len = NGX_QUIC_AES_256_GCM_IV_LEN; /* sanity checks */ - if (pkt->token.len < (size_t) iv_len + NGX_QUIC_AES_256_CBC_BLOCK_SIZE) { + if (pkt->token.len < (size_t) iv_len + NGX_QUIC_AES_256_GCM_TAG_LEN) { goto garbage; } - if (pkt->token.len > (size_t) iv_len + NGX_QUIC_MAX_TOKEN_SIZE) { + if (pkt->token.len > (size_t) iv_len + NGX_QUIC_MAX_TOKEN_SIZE + + NGX_QUIC_AES_256_GCM_TAG_LEN) + { goto garbage; } @@ -209,15 +221,23 @@ ngx_quic_validate_token(ngx_connection_t *c, u_char *key, } p = pkt->token.data + iv_len; - len = pkt->token.len - iv_len; + len = pkt->token.len - iv_len - NGX_QUIC_AES_256_GCM_TAG_LEN; - if (EVP_DecryptUpdate(ctx, tdec, &len, p, len) != 1) { + if (EVP_DecryptUpdate(ctx, tdec, &tlen, p, len) != 1) { EVP_CIPHER_CTX_free(ctx); goto garbage; } - total = len; + total = tlen; - if (EVP_DecryptFinal_ex(ctx, tdec + len, &tlen) <= 0) { + if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, + NGX_QUIC_AES_256_GCM_TAG_LEN, p + len) + == 0) + { + EVP_CIPHER_CTX_free(ctx); + goto garbage; + } + + if (EVP_DecryptFinal_ex(ctx, tdec + tlen, &tlen) <= 0) { EVP_CIPHER_CTX_free(ctx); goto garbage; } diff --git a/src/event/quic/ngx_event_quic_tokens.h b/src/event/quic/ngx_event_quic_tokens.h index 4a40f7b..ee3fe5b 100644 --- a/src/event/quic/ngx_event_quic_tokens.h +++ b/src/event/quic/ngx_event_quic_tokens.h @@ -15,13 +15,12 @@ #define NGX_QUIC_MAX_TOKEN_SIZE 64 /* SHA-1(addr)=20 + sizeof(time_t) + retry(1) + odcid.len(1) + odcid */ -/* RFC 3602, 2.1 and 2.4 for AES-CBC block size and IV length */ -#define NGX_QUIC_AES_256_CBC_IV_LEN 16 -#define NGX_QUIC_AES_256_CBC_BLOCK_SIZE 16 +#define NGX_QUIC_AES_256_GCM_IV_LEN 12 +#define NGX_QUIC_AES_256_GCM_TAG_LEN 16 -#define NGX_QUIC_TOKEN_BUF_SIZE (NGX_QUIC_AES_256_CBC_IV_LEN \ +#define NGX_QUIC_TOKEN_BUF_SIZE (NGX_QUIC_AES_256_GCM_IV_LEN \ + NGX_QUIC_MAX_TOKEN_SIZE \ - + NGX_QUIC_AES_256_CBC_BLOCK_SIZE) + + NGX_QUIC_AES_256_GCM_TAG_LEN) ngx_int_t ngx_quic_new_sr_token(ngx_connection_t *c, ngx_str_t *cid, diff --git a/src/event/quic/ngx_event_quic_transport.c b/src/event/quic/ngx_event_quic_transport.c index b663efb..fafe85f 100644 --- a/src/event/quic/ngx_event_quic_transport.c +++ b/src/event/quic/ngx_event_quic_transport.c @@ -578,7 +578,7 @@ ngx_quic_payload_size(ngx_quic_header_t *pkt, size_t pkt_len) if (ngx_quic_short_pkt(pkt->flags)) { - len = 1 + pkt->dcid.len + pkt->num_len + EVP_GCM_TLS_TAG_LEN; + len = 1 + pkt->dcid.len + pkt->num_len + NGX_QUIC_TAG_LEN; if (len > pkt_len) { return 0; } @@ -596,7 +596,7 @@ ngx_quic_payload_size(ngx_quic_header_t *pkt, size_t pkt_len) /* (pkt_len - len) is 'remainder' packet length (see RFC 9000, 17.2) */ len += ngx_quic_varint_len(pkt_len - len) - + pkt->num_len + EVP_GCM_TLS_TAG_LEN; + + pkt->num_len + NGX_QUIC_TAG_LEN; if (len > pkt_len) { return 0; @@ -622,7 +622,7 @@ ngx_quic_create_long_header(ngx_quic_header_t *pkt, u_char *out, size_t rem_len; u_char *p, *start; - rem_len = pkt->num_len + pkt->payload.len + EVP_GCM_TLS_TAG_LEN; + rem_len = pkt->num_len + pkt->payload.len + NGX_QUIC_TAG_LEN; if (out == NULL) { return 5 + 2 + pkt->dcid.len + pkt->scid.len