1/*-------------------------------------------------------------------------
4 * Set of wrapper routines on top of OpenSSL to support cryptographic
7 * This should only be used if code is compiled with OpenSSL support.
9 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
10 * Portions Copyright (c) 1994, Regents of the University of California
13 * src/common/cryptohash_openssl.c
15 *-------------------------------------------------------------------------
24#include <openssl/err.h>
25#include <openssl/evp.h>
37 * In the backend, use an allocation in TopMemoryContext to count for
38 * resowner cleanup handling. In the frontend, use malloc to be able
39 * to return a failure status back to the caller.
42 #define ALLOC(size) MemoryContextAlloc(TopMemoryContext, size)
43 #define FREE(ptr) pfree(ptr)
45#define ALLOC(size) malloc(size)
46#define FREE(ptr) free(ptr)
49/* Set of error states */
58 * Internal pg_cryptohash_ctx structure.
60 * This tracks the resource owner associated to each EVP context data
76/* ResourceOwner callbacks to hold cryptohash contexts */
82 .
name =
"OpenSSL cryptohash context",
86 .DebugPrint = NULL
/* the default message is fine */
89/* Convenience wrappers over ResourceOwnerRemember/Forget */
109 * This may return NULL, but we would fall back to a default error path if
110 * that were the case.
112 return ERR_reason_error_string(ecode);
116 * pg_cryptohash_create
118 * Allocate a hash context. Returns NULL on failure for an OOM. The
119 * backend issues an error, without returning.
127 * Make sure that the resource owner has space to remember this reference.
128 * This can error out with "out of memory", so do this before any other
129 * allocation to avoid leaking.
144 * Initialization takes care of assigning the correct type for OpenSSL.
145 * Also ensure that there aren't any unconsumed errors in the queue from
149 ctx->
evpctx = EVP_MD_CTX_create();
157 (
errcode(ERRCODE_OUT_OF_MEMORY),
158 errmsg(
"out of memory")));
175 * Initialize a hash context. Returns 0 on success, and -1 on failure.
188 status = EVP_DigestInit_ex(ctx->
evpctx, EVP_md5(), NULL);
191 status = EVP_DigestInit_ex(ctx->
evpctx, EVP_sha1(), NULL);
194 status = EVP_DigestInit_ex(ctx->
evpctx, EVP_sha224(), NULL);
197 status = EVP_DigestInit_ex(ctx->
evpctx, EVP_sha256(), NULL);
200 status = EVP_DigestInit_ex(ctx->
evpctx, EVP_sha384(), NULL);
203 status = EVP_DigestInit_ex(ctx->
evpctx, EVP_sha512(), NULL);
207 /* OpenSSL internals return 1 on success, 0 on failure */
214 * The OpenSSL error queue should normally be empty since we've
215 * consumed an error, but cipher initialization can in FIPS-enabled
216 * OpenSSL builds generate two errors so clear the queue here as well.
225 * pg_cryptohash_update
227 * Update a hash context. Returns 0 on success, and -1 on failure.
239 /* OpenSSL internals return 1 on success, 0 on failure */
250 * pg_cryptohash_final
252 * Finalize a hash context. Returns 0 on success, and -1 on failure.
308 status = EVP_DigestFinal_ex(ctx->
evpctx,
dest, 0);
310 /* OpenSSL internals return 1 on success, 0 on failure */
323 * Free a hash context.
331 EVP_MD_CTX_destroy(ctx->
evpctx);
343 * pg_cryptohash_error
345 * Returns a static string providing details about an error that
346 * happened during a computation.
352 * This implementation would never fail because of an out-of-memory error,
353 * except when creating the context.
356 return _(
"out of memory");
359 * If a reason is provided, rely on it, else fallback to any error code
370 return _(
"destination buffer too small");
372 return _(
"OpenSSL failure");
375 Assert(
false);
/* cannot be reached */
379/* ResourceOwner callbacks */
const char * pg_cryptohash_error(pg_cryptohash_ctx *ctx)
static void ResOwnerReleaseCryptoHash(Datum res)
static const char * SSLerrmessage(unsigned long ecode)
int pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len)
pg_cryptohash_ctx * pg_cryptohash_create(pg_cryptohash_type type)
int pg_cryptohash_init(pg_cryptohash_ctx *ctx)
static void ResourceOwnerForgetCryptoHash(ResourceOwner owner, pg_cryptohash_ctx *ctx)
static const ResourceOwnerDesc cryptohash_resowner_desc
@ PG_CRYPTOHASH_ERROR_DEST_LEN
@ PG_CRYPTOHASH_ERROR_NONE
@ PG_CRYPTOHASH_ERROR_OPENSSL
static void ResourceOwnerRememberCryptoHash(ResourceOwner owner, pg_cryptohash_ctx *ctx)
void pg_cryptohash_free(pg_cryptohash_ctx *ctx)
int pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest, size_t len)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
Assert(PointerIsAligned(start, uint64))
#define MD5_DIGEST_LENGTH
void explicit_bzero(void *buf, size_t len)
static Datum PointerGetDatum(const void *X)
static Pointer DatumGetPointer(Datum X)
ResourceOwner CurrentResourceOwner
void ResourceOwnerForget(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
void ResourceOwnerRemember(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
void ResourceOwnerEnlarge(ResourceOwner owner)
@ RESOURCE_RELEASE_BEFORE_LOCKS
#define RELEASE_PRIO_CRYPTOHASH_CONTEXTS
#define SHA1_DIGEST_LENGTH
#define PG_SHA256_DIGEST_LENGTH
#define PG_SHA384_DIGEST_LENGTH
#define PG_SHA512_DIGEST_LENGTH
#define PG_SHA224_DIGEST_LENGTH
pg_cryptohash_errno error