From 20686bf5fde227d857dc757ffd791353bb99256e Mon Sep 17 00:00:00 2001 From: Frederic Lecaille Date: Wed, 14 Oct 2026 17:22:11 +0200 Subject: [PATCH] OPTIM: quic: use native HKDF APIs where available QUIC key and token derivation currently uses EVP_PKEY for all HKDF operations, creating and configuring a context for each derivation. Use HKDF_extract(), HKDF_expand() and HKDF() directly with AWS-LC and BoringSSL. With OpenSSL 3, use EVP_KDF directly to bypass the EVP_PKEY compatibility layer and pass the parameters in a single call. Keep the EVP_PKEY approach for the other SSL libraries. Centralize the three HKDF modes in a common helper and make the extract and expand wrappers private to quic_tls.c. Local HTTP/3 tests with an unchanged HALoad client, one full handshake per request and empty responses showed these median request rates and paired gains: SSL library HATerm HEAD HATerm patched Paired gain OpenSSL 3.5.4 486 540 +11% AWS-LC 5.9.0 903 950 +4% without session resumption. Validated with RFC 5869 and RFC 9001 vectors and full QUIC handshakes. --- include/haproxy/quic_tls.h | 5 - src/quic_tls.c | 206 +++++++++++++++++++++++++------------ 2 files changed, 142 insertions(+), 69 deletions(-) diff --git a/include/haproxy/quic_tls.h b/include/haproxy/quic_tls.h index b128b5ea7..e0abc2355 100644 --- a/include/haproxy/quic_tls.h +++ b/include/haproxy/quic_tls.h @@ -97,11 +97,6 @@ int quic_tls_derive_token_secret(const EVP_MD *md, const unsigned char *salt, size_t saltlen, const unsigned char *secret, size_t secretlen); -int quic_hkdf_expand(const EVP_MD *md, - unsigned char *buf, size_t buflen, - const unsigned char *key, size_t keylen, - const unsigned char *label, size_t labellen); - int quic_hkdf_expand_label(const EVP_MD *md, unsigned char *buf, size_t buflen, const unsigned char *key, size_t keylen, diff --git a/src/quic_tls.c b/src/quic_tls.c index 5d32d8cfa..47721ee47 100644 --- a/src/quic_tls.c +++ b/src/quic_tls.c @@ -6,6 +6,13 @@ #include #include +#if defined(OPENSSL_IS_AWSLC) || defined(OPENSSL_IS_BORINGSSL) +#include +#elif OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER) +#include +#include +#endif + #include #include #include @@ -314,58 +321,148 @@ void qc_enc_level_free(struct quic_conn *qc, struct quic_enc_level **qel) *qel = NULL; } -int quic_hkdf_extract(const EVP_MD *md, - unsigned char *buf, size_t buflen, - const unsigned char *key, size_t keylen, - const unsigned char *salt, size_t saltlen) -{ - EVP_PKEY_CTX *ctx; +enum quic_hkdf_mode { + QUIC_HKDF_EXTRACT, + QUIC_HKDF_EXPAND, + QUIC_HKDF_EXTRACT_AND_EXPAND, +}; - ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); - if (!ctx) - return 0; - - if (EVP_PKEY_derive_init(ctx) <= 0 || - EVP_PKEY_CTX_hkdf_mode(ctx, EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY) <= 0 || - EVP_PKEY_CTX_set_hkdf_md(ctx, md) <= 0 || - EVP_PKEY_CTX_set1_hkdf_salt(ctx, salt, saltlen) <= 0 || - EVP_PKEY_CTX_set1_hkdf_key(ctx, key, keylen) <= 0 || - EVP_PKEY_derive(ctx, buf, &buflen) <= 0) - goto err; - - EVP_PKEY_CTX_free(ctx); - return 1; - - err: - EVP_PKEY_CTX_free(ctx); - return 0; -} - -int quic_hkdf_expand(const EVP_MD *md, +/* Run the HKDF operation with as hash function and as input + * key. Extract uses , expand uses