1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-23 13:29:09 +03:00

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 <mark@reviewcommit.com>
Co-authored-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/178596055358.1584287.8485463954311014881@reviewcommit.com
This commit is contained in:
Michael Paquier
2026-08-10 09:00:38 +09:00
parent 127ce77698
commit b91f79cd08

View File

@@ -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)