From: Viktor Dukhovni Date: Tue, 7 Apr 2026 11:46:58 +0000 (+1000) Subject: Precompute some helper objects in each SSL_CTX X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f45bb9967069bdb37edfad9737d6b9d07ffb7db1;p=thirdparty%2Fopenssl.git Precompute some helper objects in each SSL_CTX Instead of repeated fetching, precompute the below per the library context and properties of the SSL_CTX and use them for the lifetime of the SSL_CTX. - HMAC algorithm handle (session ticket HMAC) - SHA2-256 algorithm handle (session ticket HMAC) - AES_256-CBC algorithm handle (session ticket en/decryption) - TLS1 PRF (when TLS <= 1.2 is supported) The "sha1" and "md5" handles are no longer used, and those fields are removed. The `SSL_HMAC` objects used internally are now stack allocated, and the associated "new" and "free" functions are now called "construct" and "destruct" respectively. Reviewed-by: Matt Caswell Reviewed-by: Nikola Pajkovsky MergeDate: Mon Apr 13 09:03:45 2026 (Merged from https://github.com/openssl/openssl/pull/30696) --- diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 1b7fe8cb6b..8fb76e96ad 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -4262,6 +4263,17 @@ SSL_CTX *SSL_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq, goto err; } + if ((ret->hmac = EVP_MAC_fetch(libctx, "HMAC", propq)) == NULL) + goto err; + if ((ret->sha256 = EVP_MD_fetch(libctx, "SHA2-256", propq)) == NULL) + goto err; + if ((ret->tktenc = EVP_CIPHER_fetch(libctx, "AES-256-CBC", propq)) == NULL) + goto err; +#if defined(OPENSSL_HAVE_TLS1PRF) + if ((ret->tls1prf = EVP_KDF_fetch(libctx, OSSL_KDF_NAME_TLS1_PRF, propq)) == NULL) + goto err; +#endif + ret->method = meth; ret->min_proto_version = 0; ret->max_proto_version = 0; @@ -4339,15 +4351,6 @@ SSL_CTX *SSL_CTX_new_ex(OSSL_LIB_CTX *libctx, const char *propq, goto err; } - /* - * If these aren't available from the provider we'll get NULL returns. - * That's fine but will cause errors later if SSLv3 is negotiated - */ - ERR_set_mark(); - ret->md5 = EVP_MD_fetch(libctx, "MD5", propq); - ret->sha1 = EVP_MD_fetch(libctx, "SHA1", propq); - ERR_pop_to_mark(); - if ((ret->ca_names = sk_X509_NAME_new_null()) == NULL) { ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB); goto err; @@ -4589,6 +4592,13 @@ void SSL_CTX_free(SSL_CTX *a) if (a->sessions != NULL) SSL_CTX_flush_sessions_ex(a, 0); + EVP_MAC_free(a->hmac); + EVP_MD_free(a->sha256); + EVP_CIPHER_free(a->tktenc); +#ifdef OPENSSL_HAVE_TLS1PRF + EVP_KDF_free(a->tls1prf); +#endif + CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_CTX, a, &a->ex_data); lh_SSL_SESSION_free(a->sessions); X509_STORE_free(a->cert_store); @@ -4617,9 +4627,6 @@ void SSL_CTX_free(SSL_CTX *a) OPENSSL_free(a->ext.alpn); OPENSSL_secure_clear_free(a->ext.secure, sizeof(*a->ext.secure)); - ssl_evp_md_free(a->md5); - ssl_evp_md_free(a->sha1); - for (j = 0; j < SSL_ENC_NUM_IDX; j++) ssl_evp_cipher_free(a->ssl_cipher_methods[j]); for (j = 0; j < SSL_MD_NUM_IDX; j++) diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index a7159d3c19..7edef0bd40 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -740,8 +740,8 @@ typedef struct ssl_hmac_st { #endif } SSL_HMAC; -SSL_HMAC *ssl_hmac_new(const SSL_CTX *ctx); -void ssl_hmac_free(SSL_HMAC *ctx); +SSL_HMAC *ssl_hmac_construct(const SSL_CTX *ctx, SSL_HMAC *hctx); +void ssl_hmac_destruct(SSL_HMAC *ctx); #ifndef OPENSSL_NO_DEPRECATED_3_0 HMAC_CTX *ssl_hmac_get0_HMAC_CTX(SSL_HMAC *ctx); #endif @@ -807,6 +807,14 @@ typedef struct { #define TLS_GROUP_FFDHE_FOR_TLS1_3 (TLS_GROUP_FFDHE | TLS_GROUP_ONLY_FOR_TLS1_3) +#if !defined(OPENSSL_NO_TLS1) \ + || !defined(OPENSSL_NO_TLS1_1) \ + || !defined(OPENSSL_NO_TLS1_2) \ + || !defined(OPENSSL_NO_DTLS1) \ + || !defined(OPENSSL_NO_DTLS1_2) +#define OPENSSL_HAVE_TLS1PRF +#endif + struct ssl_ctx_st { OSSL_LIB_CTX *libctx; @@ -818,6 +826,12 @@ struct ssl_ctx_st { STACK_OF(SSL_CIPHER) *tls13_ciphersuites; struct x509_store_st /* X509_STORE */ *cert_store; LHASH_OF(SSL_SESSION) *sessions; + EVP_MAC *hmac; + EVP_MD *sha256; + EVP_CIPHER *tktenc; +#ifdef OPENSSL_HAVE_TLS1PRF + EVP_KDF *tls1prf; +#endif /* * Most session-ids that will be cached, default is * SSL_SESSION_CACHE_MAX_SIZE_DEFAULT. 0 is unlimited. @@ -2923,8 +2937,8 @@ void ssl_evp_cipher_free(const EVP_CIPHER *cipher); int ssl_evp_md_up_ref(const EVP_MD *md); void ssl_evp_md_free(const EVP_MD *md); -int ssl_hmac_old_new(SSL_HMAC *ret); -void ssl_hmac_old_free(SSL_HMAC *ctx); +SSL_HMAC *ssl_hmac_old_construct(SSL_HMAC *ret); +void ssl_hmac_old_destruct(SSL_HMAC *ctx); int ssl_hmac_old_init(SSL_HMAC *ctx, void *key, size_t len, char *md); int ssl_hmac_old_update(SSL_HMAC *ctx, const unsigned char *data, size_t len); int ssl_hmac_old_final(SSL_HMAC *ctx, unsigned char *md, size_t *len); diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index 36c698c163..538094478b 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c @@ -3088,7 +3088,6 @@ MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL_CONNECTION *s, unsigned int sess_len; RAW_EXTENSION *exts = NULL; PACKET nonce; - EVP_MD *sha256 = NULL; SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s); PACKET_null_init(&nonce); @@ -3198,25 +3197,16 @@ MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL_CONNECTION *s, * We choose the former approach because this fits in with assumptions * elsewhere in OpenSSL. The session ID is set to the SHA256 hash of the * ticket. - */ - sha256 = EVP_MD_fetch(sctx->libctx, "SHA2-256", sctx->propq); - if (sha256 == NULL) { - /* Error is already recorded */ - SSLfatal_alert(s, SSL_AD_INTERNAL_ERROR); - goto err; - } - /* + * * We use sess_len here because EVP_Digest expects an int * but s->session->session_id_length is a size_t */ if (!EVP_Digest(s->session->ext.tick, ticklen, s->session->session_id, &sess_len, - sha256, NULL)) { + sctx->sha256, NULL)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB); goto err; } - EVP_MD_free(sha256); - sha256 = NULL; s->session->session_id_length = sess_len; s->session->not_resumable = 0; @@ -3255,7 +3245,6 @@ MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL_CONNECTION *s, return MSG_PROCESS_CONTINUE_READING; err: - EVP_MD_free(sha256); OPENSSL_free(exts); return MSG_PROCESS_ERROR; } diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index 8197b60530..97455842ec 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -4247,7 +4247,7 @@ static CON_FUNC_RETURN construct_stateless_ticket(SSL_CONNECTION *s, { unsigned char *senc = NULL; EVP_CIPHER_CTX *ctx = NULL; - SSL_HMAC *hctx = NULL; + SSL_HMAC hctx, *constructed_hctx = NULL; unsigned char *p, *encdata1, *encdata2, *macdata1, *macdata2; const unsigned char *const_p; int len, slen_full, slen, lenfinal; @@ -4283,8 +4283,7 @@ static CON_FUNC_RETURN construct_stateless_ticket(SSL_CONNECTION *s, SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_EVP_LIB); goto err; } - hctx = ssl_hmac_new(tctx); - if (hctx == NULL) { + if ((constructed_hctx = ssl_hmac_construct(tctx, &hctx)) == NULL) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_SSL_LIB); goto err; } @@ -4335,13 +4334,13 @@ static CON_FUNC_RETURN construct_stateless_ticket(SSL_CONNECTION *s, if (tctx->ext.ticket_key_evp_cb != NULL) ret = tctx->ext.ticket_key_evp_cb(ssl, key_name, iv, ctx, - ssl_hmac_get0_EVP_MAC_CTX(hctx), + ssl_hmac_get0_EVP_MAC_CTX(&hctx), 1); #ifndef OPENSSL_NO_DEPRECATED_3_0 else if (tctx->ext.ticket_key_cb != NULL) /* if 0 is returned, write an empty ticket */ ret = tctx->ext.ticket_key_cb(ssl, key_name, iv, ctx, - ssl_hmac_get0_HMAC_CTX(hctx), 1); + ssl_hmac_get0_HMAC_CTX(&hctx), 1); #endif if (ret == 0) { @@ -4362,7 +4361,7 @@ static CON_FUNC_RETURN construct_stateless_ticket(SSL_CONNECTION *s, } OPENSSL_free(senc); EVP_CIPHER_CTX_free(ctx); - ssl_hmac_free(hctx); + ssl_hmac_destruct(constructed_hctx); return CON_FUNC_SUCCESS; } if (ret < 0) { @@ -4375,28 +4374,17 @@ static CON_FUNC_RETURN construct_stateless_ticket(SSL_CONNECTION *s, goto err; } } else { - EVP_CIPHER *cipher = EVP_CIPHER_fetch(sctx->libctx, "AES-256-CBC", - sctx->propq); - - if (cipher == NULL) { - /* Error is already recorded */ - SSLfatal_alert(s, SSL_AD_INTERNAL_ERROR); - goto err; - } - - iv_len = EVP_CIPHER_get_iv_length(cipher); + iv_len = EVP_CIPHER_get_iv_length(sctx->tktenc); if (iv_len < 0 || RAND_bytes_ex(sctx->libctx, iv, iv_len, 0) <= 0 - || !EVP_EncryptInit_ex(ctx, cipher, NULL, + || !EVP_EncryptInit_ex(ctx, sctx->tktenc, NULL, tctx->ext.secure->tick_aes_key, iv) - || !ssl_hmac_init(hctx, tctx->ext.secure->tick_hmac_key, + || !ssl_hmac_init(&hctx, tctx->ext.secure->tick_hmac_key, sizeof(tctx->ext.secure->tick_hmac_key), "SHA256")) { - EVP_CIPHER_free(cipher); SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); goto err; } - EVP_CIPHER_free(cipher); memcpy(key_name, tctx->ext.tick_key_name, sizeof(tctx->ext.tick_key_name)); } @@ -4422,11 +4410,11 @@ static CON_FUNC_RETURN construct_stateless_ticket(SSL_CONNECTION *s, || encdata1 + len != encdata2 || len + lenfinal > slen + EVP_MAX_BLOCK_LENGTH || !WPACKET_get_total_written(pkt, &macendoffset) - || !ssl_hmac_update(hctx, + || !ssl_hmac_update(&hctx, (unsigned char *)s->init_buf->data + macoffset, macendoffset - macoffset) || !WPACKET_reserve_bytes(pkt, EVP_MAX_MD_SIZE, &macdata1) - || !ssl_hmac_final(hctx, macdata1, &hlen, EVP_MAX_MD_SIZE) + || !ssl_hmac_final(&hctx, macdata1, &hlen, EVP_MAX_MD_SIZE) || hlen > EVP_MAX_MD_SIZE || !WPACKET_allocate_bytes(pkt, hlen, &macdata2) || macdata1 != macdata2) { @@ -4444,7 +4432,7 @@ static CON_FUNC_RETURN construct_stateless_ticket(SSL_CONNECTION *s, err: OPENSSL_free(senc); EVP_CIPHER_CTX_free(ctx); - ssl_hmac_free(hctx); + ssl_hmac_destruct(constructed_hctx); return ok; } diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c index fe5c0d8be3..bcd3082d6b 100644 --- a/ssl/t1_enc.c +++ b/ssl/t1_enc.c @@ -33,10 +33,7 @@ static int tls1_PRF(SSL_CONNECTION *s, unsigned char *out, size_t olen, int fatal) { const EVP_MD *md = ssl_prf_md(s); - EVP_KDF *kdf; EVP_KDF_CTX *kctx = NULL; - OSSL_PARAM params[9], *p = params; - const char *mdname; if (md == NULL) { /* Should never happen */ @@ -46,16 +43,13 @@ static int tls1_PRF(SSL_CONNECTION *s, ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); return 0; } - kdf = EVP_KDF_fetch(SSL_CONNECTION_GET_CTX(s)->libctx, - OSSL_KDF_NAME_TLS1_PRF, - SSL_CONNECTION_GET_CTX(s)->propq); - if (kdf == NULL) - goto err; - kctx = EVP_KDF_CTX_new(kdf); - EVP_KDF_free(kdf); +#ifdef OPENSSL_HAVE_TLS1PRF + kctx = EVP_KDF_CTX_new(SSL_CONNECTION_GET_CTX(s)->tls1prf); if (kctx == NULL) goto err; - mdname = EVP_MD_get0_name(md); + + const char *mdname = EVP_MD_get0_name(md); + OSSL_PARAM params[9], *p = params; *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, (char *)mdname, 0); *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_SECRET, @@ -85,6 +79,7 @@ static int tls1_PRF(SSL_CONNECTION *s, } err: +#endif if (fatal) SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR); else diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index ee33c43be6..e21664b8ee 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -3208,7 +3208,7 @@ SSL_TICKET_STATUS tls_decrypt_ticket(SSL_CONNECTION *s, SSL_TICKET_STATUS ret = SSL_TICKET_FATAL_ERR_OTHER; size_t mlen; unsigned char tick_hmac[EVP_MAX_MD_SIZE]; - SSL_HMAC *hctx = NULL; + SSL_HMAC hctx, *constructed_hctx = NULL; EVP_CIPHER_CTX *ctx = NULL; SSL_CTX *tctx = s->session_ctx; SSL_CTX *sctx = SSL_CONNECTION_GET_CTX(s); @@ -3239,8 +3239,8 @@ SSL_TICKET_STATUS tls_decrypt_ticket(SSL_CONNECTION *s, } /* Initialize session ticket encryption and HMAC contexts */ - hctx = ssl_hmac_new(tctx); - if (hctx == NULL) { + + if ((constructed_hctx = ssl_hmac_construct(tctx, &hctx)) == NULL) { ret = SSL_TICKET_FATAL_ERR_MALLOC; goto end; } @@ -3263,14 +3263,14 @@ SSL_TICKET_STATUS tls_decrypt_ticket(SSL_CONNECTION *s, nctick, nctick + TLSEXT_KEYNAME_LENGTH, ctx, - ssl_hmac_get0_EVP_MAC_CTX(hctx), + ssl_hmac_get0_EVP_MAC_CTX(&hctx), 0); #ifndef OPENSSL_NO_DEPRECATED_3_0 else if (tctx->ext.ticket_key_cb != NULL) /* if 0 is returned, write an empty ticket */ rv = tctx->ext.ticket_key_cb(SSL_CONNECTION_GET_USER_SSL(s), nctick, nctick + TLSEXT_KEYNAME_LENGTH, - ctx, ssl_hmac_get0_HMAC_CTX(hctx), 0); + ctx, ssl_hmac_get0_HMAC_CTX(&hctx), 0); #endif if (rv < 0) { ret = SSL_TICKET_FATAL_ERR_OTHER; @@ -3283,8 +3283,6 @@ SSL_TICKET_STATUS tls_decrypt_ticket(SSL_CONNECTION *s, if (rv == 2) renew_ticket = 1; } else { - EVP_CIPHER *aes256cbc = NULL; - /* Check key name matches */ if (memcmp(etick, tctx->ext.tick_key_name, TLSEXT_KEYNAME_LENGTH) @@ -3293,22 +3291,16 @@ SSL_TICKET_STATUS tls_decrypt_ticket(SSL_CONNECTION *s, goto end; } - aes256cbc = EVP_CIPHER_fetch(sctx->libctx, "AES-256-CBC", - sctx->propq); - if (aes256cbc == NULL - || ssl_hmac_init(hctx, tctx->ext.secure->tick_hmac_key, - sizeof(tctx->ext.secure->tick_hmac_key), - "SHA256") + if (ssl_hmac_init(&hctx, tctx->ext.secure->tick_hmac_key, + sizeof(tctx->ext.secure->tick_hmac_key), "SHA256") <= 0 - || EVP_DecryptInit_ex(ctx, aes256cbc, NULL, + || EVP_DecryptInit_ex(ctx, tctx->tktenc, NULL, tctx->ext.secure->tick_aes_key, etick + TLSEXT_KEYNAME_LENGTH) <= 0) { - EVP_CIPHER_free(aes256cbc); ret = SSL_TICKET_FATAL_ERR_OTHER; goto end; } - EVP_CIPHER_free(aes256cbc); if (SSL_CONNECTION_IS_TLS13(s)) renew_ticket = 1; } @@ -3316,7 +3308,7 @@ SSL_TICKET_STATUS tls_decrypt_ticket(SSL_CONNECTION *s, * Attempt to process session ticket, first conduct sanity and integrity * checks on ticket. */ - mlen = ssl_hmac_size(hctx); + mlen = ssl_hmac_size(&hctx); if (mlen == 0) { ret = SSL_TICKET_FATAL_ERR_OTHER; goto end; @@ -3335,8 +3327,8 @@ SSL_TICKET_STATUS tls_decrypt_ticket(SSL_CONNECTION *s, } eticklen -= mlen; /* Check HMAC of encrypted ticket */ - if (ssl_hmac_update(hctx, etick, eticklen) <= 0 - || ssl_hmac_final(hctx, tick_hmac, NULL, sizeof(tick_hmac)) <= 0) { + if (ssl_hmac_update(&hctx, etick, eticklen) <= 0 + || ssl_hmac_final(&hctx, tick_hmac, NULL, sizeof(tick_hmac)) <= 0) { ret = SSL_TICKET_FATAL_ERR_OTHER; goto end; } @@ -3398,7 +3390,7 @@ SSL_TICKET_STATUS tls_decrypt_ticket(SSL_CONNECTION *s, end: EVP_CIPHER_CTX_free(ctx); - ssl_hmac_free(hctx); + ssl_hmac_destruct(constructed_hctx); /* * If set, the decrypt_ticket_cb() is called unless a fatal error was @@ -5012,41 +5004,28 @@ uint8_t SSL_SESSION_get_max_fragment_length(const SSL_SESSION *session) /* * Helper functions for HMAC access with legacy support included. */ -SSL_HMAC *ssl_hmac_new(const SSL_CTX *ctx) +SSL_HMAC *ssl_hmac_construct(const SSL_CTX *ctx, SSL_HMAC *hctx) { - SSL_HMAC *ret = OPENSSL_zalloc(sizeof(*ret)); - EVP_MAC *mac = NULL; - - if (ret == NULL) + if (hctx == NULL) return NULL; + hctx->ctx = NULL; #ifndef OPENSSL_NO_DEPRECATED_3_0 + hctx->old_ctx = NULL; if (ctx->ext.ticket_key_evp_cb == NULL - && ctx->ext.ticket_key_cb != NULL) { - if (!ssl_hmac_old_new(ret)) - goto err; - return ret; - } + && ctx->ext.ticket_key_cb != NULL) + return ssl_hmac_old_construct(hctx); #endif - mac = EVP_MAC_fetch(ctx->libctx, "HMAC", ctx->propq); - if (mac == NULL || (ret->ctx = EVP_MAC_CTX_new(mac)) == NULL) - goto err; - EVP_MAC_free(mac); - return ret; -err: - EVP_MAC_CTX_free(ret->ctx); - EVP_MAC_free(mac); - OPENSSL_free(ret); - return NULL; + hctx->ctx = EVP_MAC_CTX_new(ctx->hmac); + return hctx->ctx != NULL ? hctx : NULL; } -void ssl_hmac_free(SSL_HMAC *ctx) +void ssl_hmac_destruct(SSL_HMAC *ctx) { if (ctx != NULL) { EVP_MAC_CTX_free(ctx->ctx); #ifndef OPENSSL_NO_DEPRECATED_3_0 - ssl_hmac_old_free(ctx); + ssl_hmac_old_destruct(ctx); #endif - OPENSSL_free(ctx); } } diff --git a/ssl/tls_depr.c b/ssl/tls_depr.c index 71d0c42495..194e06b33b 100644 --- a/ssl/tls_depr.c +++ b/ssl/tls_depr.c @@ -22,16 +22,13 @@ * be removed. */ #ifndef OPENSSL_NO_DEPRECATED_3_0 -int ssl_hmac_old_new(SSL_HMAC *ret) +SSL_HMAC *ssl_hmac_old_construct(SSL_HMAC *ret) { ret->old_ctx = HMAC_CTX_new(); - if (ret->old_ctx == NULL) - return 0; - - return 1; + return ret->old_ctx != NULL ? ret : NULL; } -void ssl_hmac_old_free(SSL_HMAC *ctx) +void ssl_hmac_old_destruct(SSL_HMAC *ctx) { HMAC_CTX_free(ctx->old_ctx); }