[PATCH 5 of 8] QUIC: reusing crypto contexts for packet protection
Sergey Kandaurov
pluknet at nginx.com
Mon Oct 23 22:37:58 UTC 2023
> On 13 Oct 2023, at 19:13, Sergey Kandaurov <pluknet at nginx.com> wrote:
>
> [..]
>
> I was pondering on reusing a static crypto context
> to make generating Retry packets more lightweight.
> Known fixed values for key and nonce make it possible to create
> a single context and reuse it over all Retry packets.
>
> Note that the context memory is kept for reuse after the first
> retry, it will be freed eventually on process exit,
> the operating system will take care of it.
> Not sure though this is a good solution.
>
> 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
> @@ -872,7 +872,6 @@ ngx_quic_create_retry_packet(ngx_quic_he
> {
> u_char *start;
> ngx_str_t ad, itag;
> - ngx_quic_secret_t secret;
> ngx_quic_ciphers_t ciphers;
>
> /* 5.8. Retry Packet Integrity */
> @@ -882,6 +881,8 @@ ngx_quic_create_retry_packet(ngx_quic_he
> "\x46\x15\x99\xd3\x5d\x63\x2b\xf2\x23\x98\x25\xbb";
> static ngx_str_t in = ngx_string("");
>
> + static ngx_quic_secret_t secret;
> +
> ad.data = res->data;
> ad.len = ngx_quic_create_retry_itag(pkt, ad.data, &start);
>
> @@ -893,6 +894,10 @@ ngx_quic_create_retry_packet(ngx_quic_he
> "quic retry itag len:%uz %xV", ad.len, &ad);
> #endif
>
> + if (secret.ctx) {
> + goto seal;
> + }
> +
> if (ngx_quic_ciphers(0, &ciphers, pkt->level) == NGX_ERROR) {
> return NGX_ERROR;
> }
> @@ -905,14 +910,14 @@ ngx_quic_create_retry_packet(ngx_quic_he
> return NGX_ERROR;
> }
>
> +seal:
> +
> if (ngx_quic_crypto_seal(&secret, &itag, nonce, &in, &ad, pkt->log)
> != NGX_OK)
> {
> return NGX_ERROR;
> }
>
> - ngx_quic_crypto_cleanup(&secret);
> -
> res->len = itag.data + itag.len - start;
> res->data = start;
>
>
Another approach is to create a single context in the master process,
used to cleanup the context in explicit manner on process shutdown.
Note that ngx_quic_conf_t is already taken, had to pick a new one.
# HG changeset patch
# User Sergey Kandaurov <pluknet at nginx.com>
# Date 1698099112 -14400
# Tue Oct 24 02:11:52 2023 +0400
# Node ID acdb54a32cdebf5cd987cf343b5e836e12d50967
# Parent af5ab04c7037f33960efc595cd76b4f4a0bf4a86
QUIC: reusing crypto context for Retry packets.
diff --git a/src/event/quic/ngx_event_quic.c b/src/event/quic/ngx_event_quic.c
--- a/src/event/quic/ngx_event_quic.c
+++ b/src/event/quic/ngx_event_quic.c
@@ -30,10 +30,13 @@ static ngx_int_t ngx_quic_handle_frames(
static void ngx_quic_push_handler(ngx_event_t *ev);
+static void *ngx_quic_create_conf(ngx_cycle_t *cycle);
+static void ngx_quic_cleanup(void *data);
+
static ngx_core_module_t ngx_quic_module_ctx = {
ngx_string("quic"),
- NULL,
+ ngx_quic_create_conf,
NULL
};
@@ -1454,3 +1457,52 @@ ngx_quic_shutdown_quic(ngx_connection_t
ngx_quic_finalize_connection(c, qc->shutdown_code, qc->shutdown_reason);
}
}
+
+
+static void *
+ngx_quic_create_conf(ngx_cycle_t *cycle)
+{
+ ngx_quic_ciphers_t ciphers;
+ ngx_pool_cleanup_t *cln;
+ ngx_quic_module_conf_t *qcf;
+
+ /* RFC 9001, 5.8. Retry Packet Integrity */
+ static ngx_quic_md_t key = {
+ NGX_QUIC_AES_128_KEY_LEN,
+ "\xbe\x0c\x69\x0b\x9f\x66\x57\x5a\x1d\x76\x6b\x54\xe3\x68\xc8\x4e"
+ };
+
+ qcf = ngx_pcalloc(cycle->pool, sizeof(ngx_quic_module_conf_t));
+ if (qcf == NULL) {
+ return NULL;
+ }
+
+ if (ngx_quic_ciphers(NGX_QUIC_INITIAL_CIPHER, &ciphers) == NGX_ERROR) {
+ return NULL;
+ }
+
+ cln = ngx_pool_cleanup_add(cycle->pool, 0);
+ if (cln == NULL) {
+ return NULL;
+ }
+
+ cln->handler = ngx_quic_cleanup;
+ cln->data = qcf;
+
+ if (ngx_quic_crypto_init(ciphers.c, &qcf->retry, &key, 1, cycle->log)
+ == NGX_ERROR)
+ {
+ return NULL;
+ }
+
+ return qcf;
+}
+
+
+static void
+ngx_quic_cleanup(void *data)
+{
+ ngx_quic_module_conf_t *qcf = data;
+
+ ngx_quic_crypto_cleanup(&qcf->retry);
+}
diff --git a/src/event/quic/ngx_event_quic_connection.h b/src/event/quic/ngx_event_quic_connection.h
--- a/src/event/quic/ngx_event_quic_connection.h
+++ b/src/event/quic/ngx_event_quic_connection.h
@@ -41,6 +41,11 @@ typedef struct ngx_quic_keys_s ng
#include <ngx_event_quic_socket.h>
+typedef struct {
+ ngx_quic_secret_t retry;
+} ngx_quic_module_conf_t;
+
+
/* RFC 9002, 6.2.2. Handshakes and New Paths: kInitialRtt */
#define NGX_QUIC_INITIAL_RTT 333 /* ms */
@@ -293,4 +298,8 @@ void ngx_quic_connstate_dbg(ngx_connecti
#define ngx_quic_connstate_dbg(c)
#endif
+
+extern ngx_module_t ngx_quic_module;
+
+
#endif /* _NGX_EVENT_QUIC_CONNECTION_H_INCLUDED_ */
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
@@ -13,10 +13,6 @@
/* RFC 9001, 5.4.1. Header Protection Application: 5-byte mask */
#define NGX_QUIC_HP_LEN 5
-#define NGX_QUIC_AES_128_KEY_LEN 16
-
-#define NGX_QUIC_INITIAL_CIPHER TLS1_3_CK_AES_128_GCM_SHA256
-
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,
@@ -929,15 +925,11 @@ ngx_quic_create_packet(ngx_quic_header_t
static ngx_int_t
ngx_quic_create_retry_packet(ngx_quic_header_t *pkt, ngx_str_t *res)
{
- u_char *start;
- ngx_str_t ad, itag;
- ngx_quic_md_t key;
- ngx_quic_secret_t secret;
- ngx_quic_ciphers_t ciphers;
+ u_char *start;
+ ngx_str_t ad, itag;
+ ngx_quic_module_conf_t *qcf;
- /* 5.8. Retry Packet Integrity */
- static u_char key_data[16] =
- "\xbe\x0c\x69\x0b\x9f\x66\x57\x5a\x1d\x76\x6b\x54\xe3\x68\xc8\x4e";
+ /* RFC 9001, 5.8. Retry Packet Integrity */
static u_char nonce[NGX_QUIC_IV_LEN] =
"\x46\x15\x99\xd3\x5d\x63\x2b\xf2\x23\x98\x25\xbb";
static ngx_str_t in = ngx_string("");
@@ -953,28 +945,15 @@ ngx_quic_create_retry_packet(ngx_quic_he
"quic retry itag len:%uz %xV", ad.len, &ad);
#endif
- if (ngx_quic_ciphers(NGX_QUIC_INITIAL_CIPHER, &ciphers) == NGX_ERROR) {
- return NGX_ERROR;
- }
+ qcf = (ngx_quic_module_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
+ ngx_quic_module);
- key.len = sizeof(key_data);
- ngx_memcpy(key.data, key_data, sizeof(key_data));
-
- if (ngx_quic_crypto_init(ciphers.c, &secret, &key, 1, pkt->log)
- == NGX_ERROR)
+ if (ngx_quic_crypto_seal(&qcf->retry, &itag, nonce, &in, &ad, pkt->log)
+ != NGX_OK)
{
return NGX_ERROR;
}
- if (ngx_quic_crypto_seal(&secret, &itag, nonce, &in, &ad, pkt->log)
- != NGX_OK)
- {
- ngx_quic_crypto_cleanup(&secret);
- return NGX_ERROR;
- }
-
- ngx_quic_crypto_cleanup(&secret);
-
res->len = itag.data + itag.len - start;
res->data = start;
diff --git a/src/event/quic/ngx_event_quic_protection.h b/src/event/quic/ngx_event_quic_protection.h
--- a/src/event/quic/ngx_event_quic_protection.h
+++ b/src/event/quic/ngx_event_quic_protection.h
@@ -23,6 +23,10 @@
/* largest hash used in TLS is SHA-384 */
#define NGX_QUIC_MAX_MD_SIZE 48
+#define NGX_QUIC_AES_128_KEY_LEN 16
+
+#define NGX_QUIC_INITIAL_CIPHER TLS1_3_CK_AES_128_GCM_SHA256
+
#ifdef OPENSSL_IS_BORINGSSL
#define ngx_quic_cipher_t EVP_AEAD
--
Sergey Kandaurov
More information about the nginx-devel
mailing list