From b91f79cd08abba7a800d3faf79bb96e8adc8752e Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Mon, 10 Aug 2026 09:00:38 +0900 Subject: [PATCH] Use explicit fetching for digests in cryptohash (OpenSSL >= 3.0) cryptohash_openssl.c initialized the EVP_MD_CTX with the implicit static digest objects (EVP_sha256() and friends). These do not dispatch through a loaded provider. OpenSSL 3.0 and newer versions recommend to switch to an explicit fetch, using EVP_MD_fetch(), the older routines being deprecated, available for backward-compatibility purposes. Now, when building with OpenSSL 3.0 or a newer bersion, we fetch the digest by name with EVP_MD_fetch(), cache it in the context, and free it on teardown. This has as consequence to feed the hash from a provider. The implicit path is kept for older OpenSSL, 1.1.1 being the oldest version still supported on HEAD, and for LibreSSL. This is a slight change in the hashing logic. No backpatch is done as that looks safer, and the code in the back-branches is also able to work. This has been locally tested across OpenSSL 1.1.1 up to 3.5, so hopefully nothing is broken. Note: The submitted code was clearly AI-generated. I have spend a bit of time cleaning it up, making it more consistent with the project style in terms of coding, adjusting a few more things on the way. Author: Mark Atwood Co-authored-by: Michael Paquier Discussion: https://postgr.es/m/178596055358.1584287.8485463954311014881@reviewcommit.com --- src/common/cryptohash_openssl.c | 47 +++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/common/cryptohash_openssl.c b/src/common/cryptohash_openssl.c index 51b7e040933..fdbd7d59c5a 100644 --- a/src/common/cryptohash_openssl.c +++ b/src/common/cryptohash_openssl.c @@ -67,6 +67,9 @@ struct pg_cryptohash_ctx const char *errreason; EVP_MD_CTX *evpctx; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_MD *algo; +#endif #ifndef FRONTEND ResourceOwner resowner; @@ -178,10 +181,50 @@ int pg_cryptohash_init(pg_cryptohash_ctx *ctx) { int status = 0; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + const char *name = NULL; +#endif if (ctx == NULL) return -1; +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + + /* + * Fetch the digest implementation so that it is served by the loaded + * provider. + */ + switch (ctx->type) + { + case PG_MD5: + name = "MD5"; + break; + case PG_SHA1: + name = "SHA1"; + break; + case PG_SHA224: + name = "SHA224"; + break; + case PG_SHA256: + name = "SHA256"; + break; + case PG_SHA384: + name = "SHA384"; + break; + case PG_SHA512: + name = "SHA512"; + break; + } + + /* + * Call EVP_MD_fetch() only once for each context, as provider lookups can + * be expensive. + */ + if (ctx->algo == NULL) + ctx->algo = EVP_MD_fetch(NULL, name, NULL); + if (ctx->algo != NULL) + status = EVP_DigestInit_ex(ctx->evpctx, ctx->algo, NULL); +#else switch (ctx->type) { case PG_MD5: @@ -203,6 +246,7 @@ pg_cryptohash_init(pg_cryptohash_ctx *ctx) status = EVP_DigestInit_ex(ctx->evpctx, EVP_sha512(), NULL); break; } +#endif /* OpenSSL internals return 1 on success, 0 on failure */ if (status <= 0) @@ -329,6 +373,9 @@ pg_cryptohash_free(pg_cryptohash_ctx *ctx) return; EVP_MD_CTX_destroy(ctx->evpctx); +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + EVP_MD_free(ctx->algo); +#endif #ifndef FRONTEND if (ctx->resowner)