mirror of
https://github.com/postgres/postgres.git
synced 2025-07-09 22:41:56 +03:00
Change SHA2 implementation based on OpenSSL to use EVP digest routines
The use of low-level hash routines is not recommended by upstream OpenSSL since 2000, and pgcrypto already switched to EVP as of5ff4a67
. This takes advantage of the refactoring done in87ae969
that has introduced the allocation and free routines for cryptographic hashes. Since 1.1.0, OpenSSL does not publish the contents of the cryptohash contexts, forcing any consumers to rely on OpenSSL for all allocations. Hence, the resource owner callback mechanism gains a new set of routines to track and free cryptohash contexts when using OpenSSL, preventing any risks of leaks in the backend. Nothing is needed in the frontend thanks to the refactoring of87ae969
, and the resowner knowledge is isolated into cryptohash_openssl.c. Note that this also fixes a failure with SCRAM authentication when using FIPS in OpenSSL, but as there have been few complaints about this problem and as this causes an ABI breakage, no backpatch is done. Author: Michael Paquier Reviewed-by: Daniel Gustafsson, Heikki Linnakangas Discussion: https://postgr.es/m/20200924025314.GE7405@paquier.xyz Discussion: https://postgr.es/m/20180911030250.GA27115@paquier.xyz
This commit is contained in:
@ -21,9 +21,14 @@
|
||||
#include "postgres_fe.h"
|
||||
#endif
|
||||
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "common/cryptohash.h"
|
||||
#ifndef FRONTEND
|
||||
#include "utils/memutils.h"
|
||||
#include "utils/resowner.h"
|
||||
#include "utils/resowner_private.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* In backend, use palloc/pfree to ease the error handling. In frontend,
|
||||
@ -37,6 +42,21 @@
|
||||
#define FREE(ptr) free(ptr)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Internal structure for pg_cryptohash_ctx->data.
|
||||
*
|
||||
* This tracks the resource owner associated to each EVP context data
|
||||
* for the backend.
|
||||
*/
|
||||
typedef struct pg_cryptohash_state
|
||||
{
|
||||
EVP_MD_CTX *evpctx;
|
||||
|
||||
#ifndef FRONTEND
|
||||
ResourceOwner resowner;
|
||||
#endif
|
||||
} pg_cryptohash_state;
|
||||
|
||||
/*
|
||||
* pg_cryptohash_create
|
||||
*
|
||||
@ -47,32 +67,53 @@ pg_cryptohash_ctx *
|
||||
pg_cryptohash_create(pg_cryptohash_type type)
|
||||
{
|
||||
pg_cryptohash_ctx *ctx;
|
||||
pg_cryptohash_state *state;
|
||||
|
||||
ctx = ALLOC(sizeof(pg_cryptohash_ctx));
|
||||
if (ctx == NULL)
|
||||
return NULL;
|
||||
|
||||
ctx->type = type;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case PG_SHA224:
|
||||
case PG_SHA256:
|
||||
ctx->data = ALLOC(sizeof(SHA256_CTX));
|
||||
break;
|
||||
case PG_SHA384:
|
||||
case PG_SHA512:
|
||||
ctx->data = ALLOC(sizeof(SHA512_CTX));
|
||||
break;
|
||||
}
|
||||
|
||||
if (ctx->data == NULL)
|
||||
state = ALLOC(sizeof(pg_cryptohash_state));
|
||||
if (state == NULL)
|
||||
{
|
||||
explicit_bzero(ctx, sizeof(pg_cryptohash_ctx));
|
||||
FREE(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->data = state;
|
||||
ctx->type = type;
|
||||
|
||||
#ifndef FRONTEND
|
||||
ResourceOwnerEnlargeCryptoHash(CurrentResourceOwner);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initialization takes care of assigning the correct type for OpenSSL.
|
||||
*/
|
||||
state->evpctx = EVP_MD_CTX_create();
|
||||
|
||||
if (state->evpctx == NULL)
|
||||
{
|
||||
explicit_bzero(state, sizeof(pg_cryptohash_state));
|
||||
explicit_bzero(ctx, sizeof(pg_cryptohash_ctx));
|
||||
#ifndef FRONTEND
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("out of memory")));
|
||||
#else
|
||||
FREE(state);
|
||||
FREE(ctx);
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef FRONTEND
|
||||
state->resowner = CurrentResourceOwner;
|
||||
ResourceOwnerRememberCryptoHash(CurrentResourceOwner,
|
||||
PointerGetDatum(ctx));
|
||||
#endif
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
@ -85,23 +126,26 @@ int
|
||||
pg_cryptohash_init(pg_cryptohash_ctx *ctx)
|
||||
{
|
||||
int status = 0;
|
||||
pg_cryptohash_state *state;
|
||||
|
||||
if (ctx == NULL)
|
||||
return 0;
|
||||
|
||||
state = (pg_cryptohash_state *) ctx->data;
|
||||
|
||||
switch (ctx->type)
|
||||
{
|
||||
case PG_SHA224:
|
||||
status = SHA224_Init((SHA256_CTX *) ctx->data);
|
||||
status = EVP_DigestInit_ex(state->evpctx, EVP_sha224(), NULL);
|
||||
break;
|
||||
case PG_SHA256:
|
||||
status = SHA256_Init((SHA256_CTX *) ctx->data);
|
||||
status = EVP_DigestInit_ex(state->evpctx, EVP_sha256(), NULL);
|
||||
break;
|
||||
case PG_SHA384:
|
||||
status = SHA384_Init((SHA512_CTX *) ctx->data);
|
||||
status = EVP_DigestInit_ex(state->evpctx, EVP_sha384(), NULL);
|
||||
break;
|
||||
case PG_SHA512:
|
||||
status = SHA512_Init((SHA512_CTX *) ctx->data);
|
||||
status = EVP_DigestInit_ex(state->evpctx, EVP_sha512(), NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -120,25 +164,13 @@ int
|
||||
pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len)
|
||||
{
|
||||
int status = 0;
|
||||
pg_cryptohash_state *state;
|
||||
|
||||
if (ctx == NULL)
|
||||
return 0;
|
||||
|
||||
switch (ctx->type)
|
||||
{
|
||||
case PG_SHA224:
|
||||
status = SHA224_Update((SHA256_CTX *) ctx->data, data, len);
|
||||
break;
|
||||
case PG_SHA256:
|
||||
status = SHA256_Update((SHA256_CTX *) ctx->data, data, len);
|
||||
break;
|
||||
case PG_SHA384:
|
||||
status = SHA384_Update((SHA512_CTX *) ctx->data, data, len);
|
||||
break;
|
||||
case PG_SHA512:
|
||||
status = SHA512_Update((SHA512_CTX *) ctx->data, data, len);
|
||||
break;
|
||||
}
|
||||
state = (pg_cryptohash_state *) ctx->data;
|
||||
status = EVP_DigestUpdate(state->evpctx, data, len);
|
||||
|
||||
/* OpenSSL internals return 1 on success, 0 on failure */
|
||||
if (status <= 0)
|
||||
@ -155,25 +187,13 @@ int
|
||||
pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest)
|
||||
{
|
||||
int status = 0;
|
||||
pg_cryptohash_state *state;
|
||||
|
||||
if (ctx == NULL)
|
||||
return 0;
|
||||
|
||||
switch (ctx->type)
|
||||
{
|
||||
case PG_SHA224:
|
||||
status = SHA224_Final(dest, (SHA256_CTX *) ctx->data);
|
||||
break;
|
||||
case PG_SHA256:
|
||||
status = SHA256_Final(dest, (SHA256_CTX *) ctx->data);
|
||||
break;
|
||||
case PG_SHA384:
|
||||
status = SHA384_Final(dest, (SHA512_CTX *) ctx->data);
|
||||
break;
|
||||
case PG_SHA512:
|
||||
status = SHA512_Final(dest, (SHA512_CTX *) ctx->data);
|
||||
break;
|
||||
}
|
||||
state = (pg_cryptohash_state *) ctx->data;
|
||||
status = EVP_DigestFinal_ex(state->evpctx, dest, 0);
|
||||
|
||||
/* OpenSSL internals return 1 on success, 0 on failure */
|
||||
if (status <= 0)
|
||||
@ -189,9 +209,21 @@ pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest)
|
||||
void
|
||||
pg_cryptohash_free(pg_cryptohash_ctx *ctx)
|
||||
{
|
||||
pg_cryptohash_state *state;
|
||||
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
FREE(ctx->data);
|
||||
|
||||
state = (pg_cryptohash_state *) ctx->data;
|
||||
EVP_MD_CTX_destroy(state->evpctx);
|
||||
|
||||
#ifndef FRONTEND
|
||||
ResourceOwnerForgetCryptoHash(state->resowner,
|
||||
PointerGetDatum(ctx));
|
||||
#endif
|
||||
|
||||
explicit_bzero(state, sizeof(pg_cryptohash_state));
|
||||
explicit_bzero(ctx, sizeof(pg_cryptohash_ctx));
|
||||
FREE(state);
|
||||
FREE(ctx);
|
||||
}
|
||||
|
Reference in New Issue
Block a user