On Sat, Jan 23, 2021 at 01:43:20PM +0900, Michael Paquier wrote:
> Rebased patch is attached wiht SHA1 added as of a8ed6bb.  Now that
> SHA1 is part of the set of options for cryptohashes, a lot of code of
> pgcrypto can be cleaned up thanks to the refactoring done here, but
> I am leaving that as a separate item to address later.

Again a new rebase, giving v5:
- Fixed the APIs to return -1 if the caller gives NULL in input, to be
consistent with cryptohash.
- Added a length argument to pg_hmac_final(), wiht sanity checks.
--
Michael
From 3980f5c191d03f76d339f66a4df8a1377368d71b Mon Sep 17 00:00:00 2001
From: Michael Paquier <mich...@paquier.xyz>
Date: Mon, 15 Feb 2021 20:23:05 +0900
Subject: [PATCH v5] Refactor HMAC implementations

---
 src/include/common/hmac.h             |  29 +++
 src/include/common/md5.h              |   2 +
 src/include/common/scram-common.h     |  13 --
 src/include/common/sha1.h             |   2 +
 src/include/pg_config.h.in            |   6 +
 src/include/utils/resowner_private.h  |   7 +
 src/backend/libpq/auth-scram.c        |  61 +++---
 src/backend/utils/resowner/resowner.c |  61 ++++++
 src/common/Makefile                   |   4 +-
 src/common/hmac.c                     | 263 ++++++++++++++++++++++++++
 src/common/hmac_openssl.c             | 256 +++++++++++++++++++++++++
 src/common/scram-common.c             | 158 ++++------------
 src/interfaces/libpq/fe-auth-scram.c  |  71 ++++---
 configure                             |   2 +-
 configure.ac                          |   2 +-
 src/tools/msvc/Mkvcbuild.pm           |   2 +
 src/tools/msvc/Solution.pm            |   4 +
 src/tools/pgindent/typedefs.list      |   2 +-
 18 files changed, 747 insertions(+), 198 deletions(-)
 create mode 100644 src/include/common/hmac.h
 create mode 100644 src/common/hmac.c
 create mode 100644 src/common/hmac_openssl.c

diff --git a/src/include/common/hmac.h b/src/include/common/hmac.h
new file mode 100644
index 0000000000..ea0343a9da
--- /dev/null
+++ b/src/include/common/hmac.h
@@ -0,0 +1,29 @@
+/*-------------------------------------------------------------------------
+ *
+ * hmac.h
+ *	  Generic headers for HMAC
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *		  src/include/common/hmac.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef PG_HMAC_H
+#define PG_HMAC_H
+
+#include "common/cryptohash.h"
+
+/* opaque context, private to each HMAC implementation */
+typedef struct pg_hmac_ctx pg_hmac_ctx;
+
+extern pg_hmac_ctx *pg_hmac_create(pg_cryptohash_type type);
+extern int	pg_hmac_init(pg_hmac_ctx *ctx, const uint8 *key, size_t len);
+extern int	pg_hmac_update(pg_hmac_ctx *ctx, const uint8 *data, size_t len);
+extern int	pg_hmac_final(pg_hmac_ctx *ctx, uint8 *dest, size_t len);
+extern void pg_hmac_free(pg_hmac_ctx *ctx);
+
+#endif							/* PG_HMAC_H */
diff --git a/src/include/common/md5.h b/src/include/common/md5.h
index 6d100f5cfc..62a31e6ed4 100644
--- a/src/include/common/md5.h
+++ b/src/include/common/md5.h
@@ -18,6 +18,8 @@
 
 /* Size of result generated by MD5 computation */
 #define MD5_DIGEST_LENGTH 16
+/* Block size for MD5 */
+#define MD5_BLOCK_SIZE	64
 
 /* password-related data */
 #define MD5_PASSWD_CHARSET	"0123456789abcdef"
diff --git a/src/include/common/scram-common.h b/src/include/common/scram-common.h
index 9d684b41e8..5777ce9fe3 100644
--- a/src/include/common/scram-common.h
+++ b/src/include/common/scram-common.h
@@ -46,19 +46,6 @@
  */
 #define SCRAM_DEFAULT_ITERATIONS	4096
 
-/*
- * Context data for HMAC used in SCRAM authentication.
- */
-typedef struct
-{
-	pg_cryptohash_ctx *sha256ctx;
-	uint8		k_opad[SHA256_HMAC_B];
-} scram_HMAC_ctx;
-
-extern int	scram_HMAC_init(scram_HMAC_ctx *ctx, const uint8 *key, int keylen);
-extern int	scram_HMAC_update(scram_HMAC_ctx *ctx, const char *str, int slen);
-extern int	scram_HMAC_final(uint8 *result, scram_HMAC_ctx *ctx);
-
 extern int	scram_SaltedPassword(const char *password, const char *salt,
 								 int saltlen, int iterations, uint8 *result);
 extern int	scram_H(const uint8 *str, int len, uint8 *result);
diff --git a/src/include/common/sha1.h b/src/include/common/sha1.h
index a61bc47ded..b1ee36f8ea 100644
--- a/src/include/common/sha1.h
+++ b/src/include/common/sha1.h
@@ -15,5 +15,7 @@
 
 /* Size of result generated by SHA1 computation */
 #define SHA1_DIGEST_LENGTH 20
+/* Block size for SHA1 */
+#define SHA1_BLOCK_SIZE 64
 
 #endif							/* PG_SHA1_H */
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 55cab4d2bf..781f747434 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -268,6 +268,12 @@
 /* Define to 1 if you have the `history_truncate_file' function. */
 #undef HAVE_HISTORY_TRUNCATE_FILE
 
+/* Define to 1 if you have the `HMAC_CTX_free' function. */
+#undef HAVE_HMAC_CTX_FREE
+
+/* Define to 1 if you have the `HMAC_CTX_new' function. */
+#undef HAVE_HMAC_CTX_NEW
+
 /* Define to 1 if you have the <ifaddrs.h> header file. */
 #undef HAVE_IFADDRS_H
 
diff --git a/src/include/utils/resowner_private.h b/src/include/utils/resowner_private.h
index c480a1a24b..6dafc87e28 100644
--- a/src/include/utils/resowner_private.h
+++ b/src/include/utils/resowner_private.h
@@ -102,4 +102,11 @@ extern void ResourceOwnerRememberCryptoHash(ResourceOwner owner,
 extern void ResourceOwnerForgetCryptoHash(ResourceOwner owner,
 										  Datum handle);
 
+/* support for HMAC context management */
+extern void ResourceOwnerEnlargeHMAC(ResourceOwner owner);
+extern void ResourceOwnerRememberHMAC(ResourceOwner owner,
+									  Datum handle);
+extern void ResourceOwnerForgetHMAC(ResourceOwner owner,
+									Datum handle);
+
 #endif							/* RESOWNER_PRIVATE_H */
diff --git a/src/backend/libpq/auth-scram.c b/src/backend/libpq/auth-scram.c
index b9b6d464a0..f9e1026a12 100644
--- a/src/backend/libpq/auth-scram.c
+++ b/src/backend/libpq/auth-scram.c
@@ -95,6 +95,7 @@
 #include "catalog/pg_authid.h"
 #include "catalog/pg_control.h"
 #include "common/base64.h"
+#include "common/hmac.h"
 #include "common/saslprep.h"
 #include "common/scram-common.h"
 #include "common/sha2.h"
@@ -1100,7 +1101,7 @@ verify_client_proof(scram_state *state)
 	uint8		ClientSignature[SCRAM_KEY_LEN];
 	uint8		ClientKey[SCRAM_KEY_LEN];
 	uint8		client_StoredKey[SCRAM_KEY_LEN];
-	scram_HMAC_ctx ctx;
+	pg_hmac_ctx *ctx = pg_hmac_create(PG_SHA256);
 	int			i;
 
 	/*
@@ -1108,23 +1109,25 @@ verify_client_proof(scram_state *state)
 	 * here even when processing the calculations as this could involve a mock
 	 * authentication.
 	 */
-	if (scram_HMAC_init(&ctx, state->StoredKey, SCRAM_KEY_LEN) < 0 ||
-		scram_HMAC_update(&ctx,
-						  state->client_first_message_bare,
-						  strlen(state->client_first_message_bare)) < 0 ||
-		scram_HMAC_update(&ctx, ",", 1) < 0 ||
-		scram_HMAC_update(&ctx,
-						  state->server_first_message,
-						  strlen(state->server_first_message)) < 0 ||
-		scram_HMAC_update(&ctx, ",", 1) < 0 ||
-		scram_HMAC_update(&ctx,
-						  state->client_final_message_without_proof,
-						  strlen(state->client_final_message_without_proof)) < 0 ||
-		scram_HMAC_final(ClientSignature, &ctx) < 0)
+	if (pg_hmac_init(ctx, state->StoredKey, SCRAM_KEY_LEN) < 0 ||
+		pg_hmac_update(ctx,
+					   (uint8 *) state->client_first_message_bare,
+					   strlen(state->client_first_message_bare)) < 0 ||
+		pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
+		pg_hmac_update(ctx,
+					   (uint8 *) state->server_first_message,
+					   strlen(state->server_first_message)) < 0 ||
+		pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
+		pg_hmac_update(ctx,
+					   (uint8 *) state->client_final_message_without_proof,
+					   strlen(state->client_final_message_without_proof)) < 0 ||
+		pg_hmac_final(ctx, ClientSignature, sizeof(ClientSignature)) < 0)
 	{
 		elog(ERROR, "could not calculate client signature");
 	}
 
+	pg_hmac_free(ctx);
+
 	/* Extract the ClientKey that the client calculated from the proof */
 	for (i = 0; i < SCRAM_KEY_LEN; i++)
 		ClientKey[i] = state->ClientProof[i] ^ ClientSignature[i];
@@ -1359,26 +1362,28 @@ build_server_final_message(scram_state *state)
 	uint8		ServerSignature[SCRAM_KEY_LEN];
 	char	   *server_signature_base64;
 	int			siglen;
-	scram_HMAC_ctx ctx;
+	pg_hmac_ctx *ctx = pg_hmac_create(PG_SHA256);
 
 	/* calculate ServerSignature */
-	if (scram_HMAC_init(&ctx, state->ServerKey, SCRAM_KEY_LEN) < 0 ||
-		scram_HMAC_update(&ctx,
-						  state->client_first_message_bare,
-						  strlen(state->client_first_message_bare)) < 0 ||
-		scram_HMAC_update(&ctx, ",", 1) < 0 ||
-		scram_HMAC_update(&ctx,
-						  state->server_first_message,
-						  strlen(state->server_first_message)) < 0 ||
-		scram_HMAC_update(&ctx, ",", 1) < 0 ||
-		scram_HMAC_update(&ctx,
-						  state->client_final_message_without_proof,
-						  strlen(state->client_final_message_without_proof)) < 0 ||
-		scram_HMAC_final(ServerSignature, &ctx) < 0)
+	if (pg_hmac_init(ctx, state->ServerKey, SCRAM_KEY_LEN) < 0 ||
+		pg_hmac_update(ctx,
+					   (uint8 *) state->client_first_message_bare,
+					   strlen(state->client_first_message_bare)) < 0 ||
+		pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
+		pg_hmac_update(ctx,
+					   (uint8 *) state->server_first_message,
+					   strlen(state->server_first_message)) < 0 ||
+		pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
+		pg_hmac_update(ctx,
+					   (uint8 *) state->client_final_message_without_proof,
+					   strlen(state->client_final_message_without_proof)) < 0 ||
+		pg_hmac_final(ctx, ServerSignature, sizeof(ServerSignature)) < 0)
 	{
 		elog(ERROR, "could not calculate server signature");
 	}
 
+	pg_hmac_free(ctx);
+
 	siglen = pg_b64_enc_len(SCRAM_KEY_LEN);
 	/* don't forget the zero-terminator */
 	server_signature_base64 = palloc(siglen + 1);
diff --git a/src/backend/utils/resowner/resowner.c b/src/backend/utils/resowner/resowner.c
index a171df573c..e24f00f060 100644
--- a/src/backend/utils/resowner/resowner.c
+++ b/src/backend/utils/resowner/resowner.c
@@ -22,6 +22,7 @@
 
 #include "common/cryptohash.h"
 #include "common/hashfn.h"
+#include "common/hmac.h"
 #include "jit/jit.h"
 #include "storage/bufmgr.h"
 #include "storage/ipc.h"
@@ -130,6 +131,7 @@ typedef struct ResourceOwnerData
 	ResourceArray dsmarr;		/* dynamic shmem segments */
 	ResourceArray jitarr;		/* JIT contexts */
 	ResourceArray cryptohasharr;	/* cryptohash contexts */
+	ResourceArray hmacarr;		/* HMAC contexts */
 
 	/* We can remember up to MAX_RESOWNER_LOCKS references to local locks. */
 	int			nlocks;			/* number of owned locks */
@@ -178,6 +180,7 @@ static void PrintSnapshotLeakWarning(Snapshot snapshot);
 static void PrintFileLeakWarning(File file);
 static void PrintDSMLeakWarning(dsm_segment *seg);
 static void PrintCryptoHashLeakWarning(Datum handle);
+static void PrintHMACLeakWarning(Datum handle);
 
 
 /*****************************************************************************
@@ -448,6 +451,7 @@ ResourceOwnerCreate(ResourceOwner parent, const char *name)
 	ResourceArrayInit(&(owner->dsmarr), PointerGetDatum(NULL));
 	ResourceArrayInit(&(owner->jitarr), PointerGetDatum(NULL));
 	ResourceArrayInit(&(owner->cryptohasharr), PointerGetDatum(NULL));
+	ResourceArrayInit(&(owner->hmacarr), PointerGetDatum(NULL));
 
 	return owner;
 }
@@ -568,6 +572,16 @@ ResourceOwnerReleaseInternal(ResourceOwner owner,
 				PrintCryptoHashLeakWarning(foundres);
 			pg_cryptohash_free(context);
 		}
+
+		/* Ditto for HMAC contexts */
+		while (ResourceArrayGetAny(&(owner->hmacarr), &foundres))
+		{
+			pg_hmac_ctx *context = (pg_hmac_ctx *) PointerGetDatum(foundres);
+
+			if (isCommit)
+				PrintHMACLeakWarning(foundres);
+			pg_hmac_free(context);
+		}
 	}
 	else if (phase == RESOURCE_RELEASE_LOCKS)
 	{
@@ -737,6 +751,7 @@ ResourceOwnerDelete(ResourceOwner owner)
 	Assert(owner->dsmarr.nitems == 0);
 	Assert(owner->jitarr.nitems == 0);
 	Assert(owner->cryptohasharr.nitems == 0);
+	Assert(owner->hmacarr.nitems == 0);
 	Assert(owner->nlocks == 0 || owner->nlocks == MAX_RESOWNER_LOCKS + 1);
 
 	/*
@@ -765,6 +780,7 @@ ResourceOwnerDelete(ResourceOwner owner)
 	ResourceArrayFree(&(owner->dsmarr));
 	ResourceArrayFree(&(owner->jitarr));
 	ResourceArrayFree(&(owner->cryptohasharr));
+	ResourceArrayFree(&(owner->hmacarr));
 
 	pfree(owner);
 }
@@ -1428,3 +1444,48 @@ PrintCryptoHashLeakWarning(Datum handle)
 	elog(WARNING, "cryptohash context reference leak: context %p still referenced",
 		 DatumGetPointer(handle));
 }
+
+/*
+ * Make sure there is room for at least one more entry in a ResourceOwner's
+ * hmac context reference array.
+ *
+ * This is separate from actually inserting an entry because if we run out of
+ * memory, it's critical to do so *before* acquiring the resource.
+ */
+void
+ResourceOwnerEnlargeHMAC(ResourceOwner owner)
+{
+	ResourceArrayEnlarge(&(owner->hmacarr));
+}
+
+/*
+ * Remember that a HMAC context is owned by a ResourceOwner
+ *
+ * Caller must have previously done ResourceOwnerEnlargeHMAC()
+ */
+void
+ResourceOwnerRememberHMAC(ResourceOwner owner, Datum handle)
+{
+	ResourceArrayAdd(&(owner->hmacarr), handle);
+}
+
+/*
+ * Forget that a HMAC context is owned by a ResourceOwner
+ */
+void
+ResourceOwnerForgetHMAC(ResourceOwner owner, Datum handle)
+{
+	if (!ResourceArrayRemove(&(owner->hmacarr), handle))
+		elog(ERROR, "HMAC context %p is not owned by resource owner %s",
+			 DatumGetPointer(handle), owner->name);
+}
+
+/*
+ * Debugging subroutine
+ */
+static void
+PrintHMACLeakWarning(Datum handle)
+{
+	elog(WARNING, "HMAC context reference leak: context %p still referenced",
+		 DatumGetPointer(handle));
+}
diff --git a/src/common/Makefile b/src/common/Makefile
index 5422579a6a..38a8599337 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -83,10 +83,12 @@ OBJS_COMMON = \
 ifeq ($(with_ssl),openssl)
 OBJS_COMMON += \
 	protocol_openssl.o \
-	cryptohash_openssl.o
+	cryptohash_openssl.o \
+	hmac_openssl.o
 else
 OBJS_COMMON += \
 	cryptohash.o \
+	hmac.o \
 	md5.o \
 	sha1.o \
 	sha2.o
diff --git a/src/common/hmac.c b/src/common/hmac.c
new file mode 100644
index 0000000000..af3e46971b
--- /dev/null
+++ b/src/common/hmac.c
@@ -0,0 +1,263 @@
+/*-------------------------------------------------------------------------
+ *
+ * hmac.c
+ *	  Implements Keyed-Hashing for Message Authentication (HMAC)
+ *
+ * Fallback implementation of HMAC, as specified in RFC 2104.
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *	  src/common/hmac.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include "common/cryptohash.h"
+#include "common/hmac.h"
+#include "common/md5.h"
+#include "common/sha1.h"
+#include "common/sha2.h"
+
+/*
+ * In backend, use palloc/pfree to ease the error handling.  In frontend,
+ * use malloc to be able to return a failure status back to the caller.
+ */
+#ifndef FRONTEND
+#define ALLOC(size) palloc(size)
+#define FREE(ptr) pfree(ptr)
+#else
+#define ALLOC(size) malloc(size)
+#define FREE(ptr) free(ptr)
+#endif
+
+/*
+ * Internal structure for pg_hmac_ctx->data with this implementation.
+ */
+struct pg_hmac_ctx
+{
+	pg_cryptohash_ctx *hash;
+	pg_cryptohash_type type;
+	int			block_size;
+	int			digest_size;
+
+	/*
+	 * Use the largest block size among supported options.  This wastes
+	 * some memory but simplifies the allocation logic.
+	 */
+	uint8		k_ipad[PG_SHA512_BLOCK_LENGTH];
+	uint8		k_opad[PG_SHA512_BLOCK_LENGTH];
+};
+
+#define HMAC_IPAD 0x36
+#define HMAC_OPAD 0x5C
+
+/*
+ * pg_hmac_create
+ *
+ * Allocate a hash context.  Returns NULL on failure for an OOM.  The
+ * backend issues an error, without returning.
+ */
+pg_hmac_ctx *
+pg_hmac_create(pg_cryptohash_type type)
+{
+	pg_hmac_ctx *ctx;
+
+	ctx = ALLOC(sizeof(pg_hmac_ctx));
+	if (ctx == NULL)
+		return NULL;
+	memset(ctx, 0, sizeof(pg_hmac_ctx));
+	ctx->type = type;
+
+	/*
+	 * Initialize the context data.  This requires to know the digest and
+	 * block lengths, that depend on the type of hash used.
+	 */
+	switch (type)
+	{
+		case PG_MD5:
+			ctx->digest_size = MD5_DIGEST_LENGTH;
+			ctx->block_size = MD5_BLOCK_SIZE;
+			break;
+		case PG_SHA1:
+			ctx->digest_size = SHA1_DIGEST_LENGTH;
+			ctx->block_size = SHA1_BLOCK_SIZE;
+			break;
+		case PG_SHA224:
+			ctx->digest_size = PG_SHA224_DIGEST_LENGTH;
+			ctx->block_size = PG_SHA224_BLOCK_LENGTH;
+			break;
+		case PG_SHA256:
+			ctx->digest_size = PG_SHA256_DIGEST_LENGTH;
+			ctx->block_size = PG_SHA256_BLOCK_LENGTH;
+			break;
+		case PG_SHA384:
+			ctx->digest_size = PG_SHA384_DIGEST_LENGTH;
+			ctx->block_size = PG_SHA384_BLOCK_LENGTH;
+			break;
+		case PG_SHA512:
+			ctx->digest_size = PG_SHA512_DIGEST_LENGTH;
+			ctx->block_size = PG_SHA512_BLOCK_LENGTH;
+			break;
+	}
+
+	ctx->hash = pg_cryptohash_create(type);
+	if (ctx->hash == NULL)
+	{
+		explicit_bzero(ctx, sizeof(pg_hmac_ctx));
+		FREE(ctx);
+		return NULL;
+	}
+
+	return ctx;
+}
+
+/*
+ * pg_hmac_init
+ *
+ * Initialize a HMAC context.  Returns 0 on success, -1 on failure.
+ */
+int
+pg_hmac_init(pg_hmac_ctx *ctx, const uint8 *key, size_t len)
+{
+	int			i;
+	int			digest_size;
+	int			block_size;
+	uint8	   *shrinkbuf = NULL;
+
+	if (ctx == NULL)
+		return -1;
+
+	digest_size = ctx->digest_size;
+	block_size = ctx->block_size;
+
+	memset(ctx->k_opad, HMAC_OPAD, ctx->block_size);
+	memset(ctx->k_ipad, HMAC_IPAD, ctx->block_size);
+
+	/*
+	 * If the key is longer than the block size, pass it through the hash once
+	 * to shrink it down.
+	 */
+	if (len > block_size)
+	{
+		pg_cryptohash_ctx *hash_ctx;
+
+		/* temporary buffer for one-time shrink */
+		shrinkbuf = ALLOC(digest_size);
+		if (shrinkbuf == NULL)
+			return -1;
+		memset(shrinkbuf, 0, digest_size);
+
+		hash_ctx = pg_cryptohash_create(ctx->type);
+		if (hash_ctx == NULL)
+		{
+			FREE(shrinkbuf);
+			return -1;
+		}
+
+		if (pg_cryptohash_init(hash_ctx) < 0 ||
+			pg_cryptohash_update(hash_ctx, key, len) < 0 ||
+			pg_cryptohash_final(hash_ctx, shrinkbuf, digest_size) < 0)
+		{
+			pg_cryptohash_free(hash_ctx);
+			FREE(shrinkbuf);
+			return -1;
+		}
+
+		key = shrinkbuf;
+		len = digest_size;
+		pg_cryptohash_free(hash_ctx);
+	}
+
+	for (i = 0; i < len; i++)
+	{
+		ctx->k_ipad[i] ^= key[i];
+		ctx->k_opad[i] ^= key[i];
+	}
+
+	/* tmp = H(K XOR ipad, text) */
+	if (pg_cryptohash_init(ctx->hash) < 0 ||
+		pg_cryptohash_update(ctx->hash, ctx->k_ipad, ctx->block_size) < 0)
+	{
+		if (shrinkbuf)
+			FREE(shrinkbuf);
+		return -1;
+	}
+
+	if (shrinkbuf)
+		FREE(shrinkbuf);
+	return 0;
+}
+
+/*
+ * pg_hmac_update
+ *
+ * Update a HMAC context.  Returns 0 on success, -1 on failure.
+ */
+int
+pg_hmac_update(pg_hmac_ctx *ctx, const uint8 *data, size_t len)
+{
+	if (ctx == NULL)
+		return -1;
+
+	if (pg_cryptohash_update(ctx->hash, data, len) < 0)
+		return -1;
+
+	return 0;
+}
+
+/*
+ * pg_hmac_final
+ *
+ * Finalize a HMAC context.  Returns 0 on success, -1 on failure.
+ */
+int
+pg_hmac_final(pg_hmac_ctx *ctx, uint8 *dest, size_t len)
+{
+	uint8	   *h;
+
+	if (ctx == NULL)
+		return -1;
+
+	h = ALLOC(ctx->digest_size);
+	if (h == NULL)
+		return -1;
+	memset(h, 0, ctx->digest_size);
+
+	if (pg_cryptohash_final(ctx->hash, h, ctx->digest_size) < 0)
+		return -1;
+
+	/* H(K XOR opad, tmp) */
+	if (pg_cryptohash_init(ctx->hash) < 0 ||
+		pg_cryptohash_update(ctx->hash, ctx->k_opad, ctx->block_size) < 0 ||
+		pg_cryptohash_update(ctx->hash, h, ctx->digest_size) < 0 ||
+		pg_cryptohash_final(ctx->hash, dest, len) < 0)
+	{
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * pg_hmac_free
+ *
+ * Free a HMAC context.
+ */
+void
+pg_hmac_free(pg_hmac_ctx *ctx)
+{
+	if (ctx == NULL)
+		return;
+
+	pg_cryptohash_free(ctx->hash);
+	explicit_bzero(ctx, sizeof(pg_hmac_ctx));
+	FREE(ctx);
+}
diff --git a/src/common/hmac_openssl.c b/src/common/hmac_openssl.c
new file mode 100644
index 0000000000..cc0745d66f
--- /dev/null
+++ b/src/common/hmac_openssl.c
@@ -0,0 +1,256 @@
+/*-------------------------------------------------------------------------
+ *
+ * hmac_openssl.c
+ *	  Implementation of HMAC with OpenSSL.
+ *
+ * This should only be used if code is compiled with OpenSSL support.
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ *	  src/common/hmac_openssl.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef FRONTEND
+#include "postgres.h"
+#else
+#include "postgres_fe.h"
+#endif
+
+#include <openssl/hmac.h>
+
+#include "common/hmac.h"
+#include "common/md5.h"
+#include "common/sha1.h"
+#include "common/sha2.h"
+#ifndef FRONTEND
+#include "utils/memutils.h"
+#include "utils/resowner.h"
+#include "utils/resowner_private.h"
+#endif
+
+/*
+ * In backend, use an allocation in TopMemoryContext to count for resowner
+ * cleanup handling if necesary.  For versions of OpenSSL where HMAC_CTX is
+ * known, just use palloc().  In frontend, use malloc to be able to return
+ * a failure status back to the caller.
+ */
+#ifndef FRONTEND
+#ifdef HAVE_HMAC_CTX_NEW
+#define ALLOC(size) MemoryContextAlloc(TopMemoryContext, size)
+#else
+#define ALLOC(size) palloc(size)
+#endif
+#define FREE(ptr) pfree(ptr)
+#else		/* FRONTEND */
+#define ALLOC(size) malloc(size)
+#define FREE(ptr) free(ptr)
+#endif		/* FRONTEND */
+
+/*
+ * Internal structure for pg_hmac_ctx->data with this implementation.
+ */
+struct pg_hmac_ctx
+{
+	HMAC_CTX   *hmacctx;
+	pg_cryptohash_type type;
+
+#ifndef FRONTEND
+	ResourceOwner resowner;
+#endif
+};
+
+/*
+ * pg_hmac_create
+ *
+ * Allocate a hash context.  Returns NULL on failure for an OOM.  The
+ * backend issues an error, without returning.
+ */
+pg_hmac_ctx *
+pg_hmac_create(pg_cryptohash_type type)
+{
+	pg_hmac_ctx *ctx;
+
+	ctx = ALLOC(sizeof(pg_hmac_ctx));
+	if (ctx == NULL)
+		return NULL;
+	memset(ctx, 0, sizeof(pg_hmac_ctx));
+
+	ctx->type = type;
+
+	/*
+	 * Initialization takes care of assigning the correct type for OpenSSL.
+	 */
+#ifdef HAVE_HMAC_CTX_NEW
+#ifndef FRONTEND
+	ResourceOwnerEnlargeHMAC(CurrentResourceOwner);
+#endif
+	ctx->hmacctx = HMAC_CTX_new();
+#else
+	ctx->hmacctx = ALLOC(sizeof(HMAC_CTX));
+#endif
+
+	if (ctx->hmacctx == NULL)
+	{
+		explicit_bzero(ctx, sizeof(pg_hmac_ctx));
+		FREE(ctx);
+#ifndef FRONTEND
+		ereport(ERROR,
+				(errcode(ERRCODE_OUT_OF_MEMORY),
+				 errmsg("out of memory")));
+#endif
+		return NULL;
+	}
+
+#ifdef HAVE_HMAC_CTX_NEW
+#ifndef FRONTEND
+	ctx->resowner = CurrentResourceOwner;
+	ResourceOwnerRememberHMAC(CurrentResourceOwner, PointerGetDatum(ctx));
+#endif
+#else
+	memset(ctx->hmacctx, 0, sizeof(HMAC_CTX));
+#endif		/* HAVE_HMAC_CTX_NEW */
+
+	return ctx;
+}
+
+/*
+ * pg_hmac_init
+ *
+ * Initialize a HMAC context.  Returns 0 on success, -1 on failure.
+ */
+int
+pg_hmac_init(pg_hmac_ctx *ctx, const uint8 *key, size_t len)
+{
+	int			status = 0;
+
+	if (ctx == NULL)
+		return -1;
+
+	switch (ctx->type)
+	{
+		case PG_MD5:
+			status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_md5(), NULL);
+			break;
+		case PG_SHA1:
+			status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha1(), NULL);
+			break;
+		case PG_SHA224:
+			status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha224(), NULL);
+			break;
+		case PG_SHA256:
+			status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha256(), NULL);
+			break;
+		case PG_SHA384:
+			status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha384(), NULL);
+			break;
+		case PG_SHA512:
+			status = HMAC_Init_ex(ctx->hmacctx, key, len, EVP_sha512(), NULL);
+			break;
+	}
+
+	/* OpenSSL internals return 1 on success, 0 on failure */
+	if (status <= 0)
+		return -1;
+
+	return 0;
+}
+
+/*
+ * pg_hmac_update
+ *
+ * Update a HMAC context.  Returns 0 on success, -1 on failure.
+ */
+int
+pg_hmac_update(pg_hmac_ctx *ctx, const uint8 *data, size_t len)
+{
+	int			status = 0;
+
+	if (ctx == NULL)
+		return -1;
+
+	status = HMAC_Update(ctx->hmacctx, data, len);
+
+	/* OpenSSL internals return 1 on success, 0 on failure */
+	if (status <= 0)
+		return -1;
+	return 0;
+}
+
+/*
+ * pg_hmac_final
+ *
+ * Finalize a HMAC context.  Returns 0 on success, -1 on failure.
+ */
+int
+pg_hmac_final(pg_hmac_ctx *ctx, uint8 *dest, size_t len)
+{
+	int			status = 0;
+	uint32		outlen;
+
+	if (ctx == NULL)
+		return -1;
+
+	switch (ctx->type)
+	{
+		case PG_MD5:
+			if (len < MD5_DIGEST_LENGTH)
+				return -1;
+			break;
+		case PG_SHA1:
+			if (len < SHA1_DIGEST_LENGTH)
+				return -1;
+			break;
+		case PG_SHA224:
+			if (len < PG_SHA224_DIGEST_LENGTH)
+				return -1;
+			break;
+		case PG_SHA256:
+			if (len < PG_SHA256_DIGEST_LENGTH)
+				return -1;
+			break;
+		case PG_SHA384:
+			if (len < PG_SHA384_DIGEST_LENGTH)
+				return -1;
+			break;
+		case PG_SHA512:
+			if (len < PG_SHA512_DIGEST_LENGTH)
+				return -1;
+			break;
+	}
+
+	status = HMAC_Final(ctx->hmacctx, dest, &outlen);
+
+	/* OpenSSL internals return 1 on success, 0 on failure */
+	if (status <= 0)
+		return -1;
+	return 0;
+}
+
+/*
+ * pg_hmac_free
+ *
+ * Free a HMAC context.
+ */
+void
+pg_hmac_free(pg_hmac_ctx *ctx)
+{
+	if (ctx == NULL)
+		return;
+
+#ifdef HAVE_HMAC_CTX_FREE
+	HMAC_CTX_free(ctx->hmacctx);
+#ifndef FRONTEND
+	ResourceOwnerForgetHMAC(ctx->resowner, PointerGetDatum(ctx));
+#endif
+#else
+	explicit_bzero(ctx->hmacctx, sizeof(HMAC_CTX));
+	FREE(ctx->hmacctx);
+#endif
+
+	explicit_bzero(ctx, sizeof(pg_hmac_ctx));
+	FREE(ctx);
+}
diff --git a/src/common/scram-common.c b/src/common/scram-common.c
index 0b9557376e..69a96f65f6 100644
--- a/src/common/scram-common.c
+++ b/src/common/scram-common.c
@@ -20,118 +20,10 @@
 #endif
 
 #include "common/base64.h"
+#include "common/hmac.h"
 #include "common/scram-common.h"
 #include "port/pg_bswap.h"
 
-#define HMAC_IPAD 0x36
-#define HMAC_OPAD 0x5C
-
-/*
- * Calculate HMAC per RFC2104.
- *
- * The hash function used is SHA-256.  Returns 0 on success, -1 on failure.
- */
-int
-scram_HMAC_init(scram_HMAC_ctx *ctx, const uint8 *key, int keylen)
-{
-	uint8		k_ipad[SHA256_HMAC_B];
-	int			i;
-	uint8		keybuf[SCRAM_KEY_LEN];
-
-	/*
-	 * If the key is longer than the block size (64 bytes for SHA-256), pass
-	 * it through SHA-256 once to shrink it down.
-	 */
-	if (keylen > SHA256_HMAC_B)
-	{
-		pg_cryptohash_ctx *sha256_ctx;
-
-		sha256_ctx = pg_cryptohash_create(PG_SHA256);
-		if (sha256_ctx == NULL)
-			return -1;
-		if (pg_cryptohash_init(sha256_ctx) < 0 ||
-			pg_cryptohash_update(sha256_ctx, key, keylen) < 0 ||
-			pg_cryptohash_final(sha256_ctx, keybuf, sizeof(keybuf)) < 0)
-		{
-			pg_cryptohash_free(sha256_ctx);
-			return -1;
-		}
-		key = keybuf;
-		keylen = SCRAM_KEY_LEN;
-		pg_cryptohash_free(sha256_ctx);
-	}
-
-	memset(k_ipad, HMAC_IPAD, SHA256_HMAC_B);
-	memset(ctx->k_opad, HMAC_OPAD, SHA256_HMAC_B);
-
-	for (i = 0; i < keylen; i++)
-	{
-		k_ipad[i] ^= key[i];
-		ctx->k_opad[i] ^= key[i];
-	}
-
-	ctx->sha256ctx = pg_cryptohash_create(PG_SHA256);
-	if (ctx->sha256ctx == NULL)
-		return -1;
-
-	/* tmp = H(K XOR ipad, text) */
-	if (pg_cryptohash_init(ctx->sha256ctx) < 0 ||
-		pg_cryptohash_update(ctx->sha256ctx, k_ipad, SHA256_HMAC_B) < 0)
-	{
-		pg_cryptohash_free(ctx->sha256ctx);
-		return -1;
-	}
-
-	return 0;
-}
-
-/*
- * Update HMAC calculation
- * The hash function used is SHA-256.  Returns 0 on success, -1 on failure.
- */
-int
-scram_HMAC_update(scram_HMAC_ctx *ctx, const char *str, int slen)
-{
-	Assert(ctx->sha256ctx != NULL);
-	if (pg_cryptohash_update(ctx->sha256ctx, (const uint8 *) str, slen) < 0)
-	{
-		pg_cryptohash_free(ctx->sha256ctx);
-		return -1;
-	}
-	return 0;
-}
-
-/*
- * Finalize HMAC calculation.
- * The hash function used is SHA-256.  Returns 0 on success, -1 on failure.
- */
-int
-scram_HMAC_final(uint8 *result, scram_HMAC_ctx *ctx)
-{
-	uint8		h[SCRAM_KEY_LEN];
-
-	Assert(ctx->sha256ctx != NULL);
-
-	if (pg_cryptohash_final(ctx->sha256ctx, h, sizeof(h)) < 0)
-	{
-		pg_cryptohash_free(ctx->sha256ctx);
-		return -1;
-	}
-
-	/* H(K XOR opad, tmp) */
-	if (pg_cryptohash_init(ctx->sha256ctx) < 0 ||
-		pg_cryptohash_update(ctx->sha256ctx, ctx->k_opad, SHA256_HMAC_B) < 0 ||
-		pg_cryptohash_update(ctx->sha256ctx, h, SCRAM_KEY_LEN) < 0 ||
-		pg_cryptohash_final(ctx->sha256ctx, result, SCRAM_KEY_LEN) < 0)
-	{
-		pg_cryptohash_free(ctx->sha256ctx);
-		return -1;
-	}
-
-	pg_cryptohash_free(ctx->sha256ctx);
-	return 0;
-}
-
 /*
  * Calculate SaltedPassword.
  *
@@ -149,7 +41,10 @@ scram_SaltedPassword(const char *password,
 				j;
 	uint8		Ui[SCRAM_KEY_LEN];
 	uint8		Ui_prev[SCRAM_KEY_LEN];
-	scram_HMAC_ctx hmac_ctx;
+	pg_hmac_ctx *hmac_ctx = pg_hmac_create(PG_SHA256);
+
+	if (hmac_ctx == NULL)
+		return -1;
 
 	/*
 	 * Iterate hash calculation of HMAC entry using given salt.  This is
@@ -158,11 +53,12 @@ scram_SaltedPassword(const char *password,
 	 */
 
 	/* First iteration */
-	if (scram_HMAC_init(&hmac_ctx, (uint8 *) password, password_len) < 0 ||
-		scram_HMAC_update(&hmac_ctx, salt, saltlen) < 0 ||
-		scram_HMAC_update(&hmac_ctx, (char *) &one, sizeof(uint32)) < 0 ||
-		scram_HMAC_final(Ui_prev, &hmac_ctx) < 0)
+	if (pg_hmac_init(hmac_ctx, (uint8 *) password, password_len) < 0 ||
+		pg_hmac_update(hmac_ctx, (uint8 *) salt, saltlen) < 0 ||
+		pg_hmac_update(hmac_ctx, (uint8 *) &one, sizeof(uint32)) < 0 ||
+		pg_hmac_final(hmac_ctx, Ui_prev, sizeof(Ui_prev)) < 0)
 	{
+		pg_hmac_free(hmac_ctx);
 		return -1;
 	}
 
@@ -171,10 +67,11 @@ scram_SaltedPassword(const char *password,
 	/* Subsequent iterations */
 	for (i = 2; i <= iterations; i++)
 	{
-		if (scram_HMAC_init(&hmac_ctx, (uint8 *) password, password_len) < 0 ||
-			scram_HMAC_update(&hmac_ctx, (const char *) Ui_prev, SCRAM_KEY_LEN) < 0 ||
-			scram_HMAC_final(Ui, &hmac_ctx) < 0)
+		if (pg_hmac_init(hmac_ctx, (uint8 *) password, password_len) < 0 ||
+			pg_hmac_update(hmac_ctx, (uint8 *) Ui_prev, SCRAM_KEY_LEN) < 0 ||
+			pg_hmac_final(hmac_ctx, Ui, sizeof(Ui)) < 0)
 		{
+			pg_hmac_free(hmac_ctx);
 			return -1;
 		}
 
@@ -183,6 +80,7 @@ scram_SaltedPassword(const char *password,
 		memcpy(Ui_prev, Ui, SCRAM_KEY_LEN);
 	}
 
+	pg_hmac_free(hmac_ctx);
 	return 0;
 }
 
@@ -218,15 +116,20 @@ scram_H(const uint8 *input, int len, uint8 *result)
 int
 scram_ClientKey(const uint8 *salted_password, uint8 *result)
 {
-	scram_HMAC_ctx ctx;
+	pg_hmac_ctx *ctx = pg_hmac_create(PG_SHA256);
 
-	if (scram_HMAC_init(&ctx, salted_password, SCRAM_KEY_LEN) < 0 ||
-		scram_HMAC_update(&ctx, "Client Key", strlen("Client Key")) < 0 ||
-		scram_HMAC_final(result, &ctx) < 0)
+	if (ctx == NULL)
+		return -1;
+
+	if (pg_hmac_init(ctx, salted_password, SCRAM_KEY_LEN) < 0 ||
+		pg_hmac_update(ctx, (uint8 *) "Client Key", strlen("Client Key")) < 0 ||
+		pg_hmac_final(ctx, result, SCRAM_KEY_LEN) < 0)
 	{
+		pg_hmac_free(ctx);
 		return -1;
 	}
 
+	pg_hmac_free(ctx);
 	return 0;
 }
 
@@ -236,15 +139,20 @@ scram_ClientKey(const uint8 *salted_password, uint8 *result)
 int
 scram_ServerKey(const uint8 *salted_password, uint8 *result)
 {
-	scram_HMAC_ctx ctx;
+	pg_hmac_ctx *ctx = pg_hmac_create(PG_SHA256);
 
-	if (scram_HMAC_init(&ctx, salted_password, SCRAM_KEY_LEN) < 0 ||
-		scram_HMAC_update(&ctx, "Server Key", strlen("Server Key")) < 0 ||
-		scram_HMAC_final(result, &ctx) < 0)
+	if (ctx == NULL)
+		return -1;
+
+	if (pg_hmac_init(ctx, salted_password, SCRAM_KEY_LEN) < 0 ||
+		pg_hmac_update(ctx, (uint8 *) "Server Key", strlen("Server Key")) < 0 ||
+		pg_hmac_final(ctx, result, SCRAM_KEY_LEN) < 0)
 	{
+		pg_hmac_free(ctx);
 		return -1;
 	}
 
+	pg_hmac_free(ctx);
 	return 0;
 }
 
diff --git a/src/interfaces/libpq/fe-auth-scram.c b/src/interfaces/libpq/fe-auth-scram.c
index 002469540a..5881386e37 100644
--- a/src/interfaces/libpq/fe-auth-scram.c
+++ b/src/interfaces/libpq/fe-auth-scram.c
@@ -15,6 +15,7 @@
 #include "postgres_fe.h"
 
 #include "common/base64.h"
+#include "common/hmac.h"
 #include "common/saslprep.h"
 #include "common/scram-common.h"
 #include "fe-auth.h"
@@ -776,7 +777,11 @@ calculate_client_proof(fe_scram_state *state,
 	uint8		ClientKey[SCRAM_KEY_LEN];
 	uint8		ClientSignature[SCRAM_KEY_LEN];
 	int			i;
-	scram_HMAC_ctx ctx;
+	pg_hmac_ctx *ctx;
+
+	ctx = pg_hmac_create(PG_SHA256);
+	if (ctx == NULL)
+		return false;
 
 	/*
 	 * Calculate SaltedPassword, and store it in 'state' so that we can reuse
@@ -786,26 +791,28 @@ calculate_client_proof(fe_scram_state *state,
 							 state->iterations, state->SaltedPassword) < 0 ||
 		scram_ClientKey(state->SaltedPassword, ClientKey) < 0 ||
 		scram_H(ClientKey, SCRAM_KEY_LEN, StoredKey) < 0 ||
-		scram_HMAC_init(&ctx, StoredKey, SCRAM_KEY_LEN) < 0 ||
-		scram_HMAC_update(&ctx,
-						  state->client_first_message_bare,
-						  strlen(state->client_first_message_bare)) < 0 ||
-		scram_HMAC_update(&ctx, ",", 1) < 0 ||
-		scram_HMAC_update(&ctx,
-						  state->server_first_message,
-						  strlen(state->server_first_message)) < 0 ||
-		scram_HMAC_update(&ctx, ",", 1) < 0 ||
-		scram_HMAC_update(&ctx,
-						  client_final_message_without_proof,
-						  strlen(client_final_message_without_proof)) < 0 ||
-		scram_HMAC_final(ClientSignature, &ctx) < 0)
+		pg_hmac_init(ctx, StoredKey, SCRAM_KEY_LEN) < 0 ||
+		pg_hmac_update(ctx,
+					   (uint8 *) state->client_first_message_bare,
+					   strlen(state->client_first_message_bare)) < 0 ||
+		pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
+		pg_hmac_update(ctx,
+					   (uint8 *) state->server_first_message,
+					   strlen(state->server_first_message)) < 0 ||
+		pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
+		pg_hmac_update(ctx,
+					   (uint8 *) client_final_message_without_proof,
+					   strlen(client_final_message_without_proof)) < 0 ||
+		pg_hmac_final(ctx, ClientSignature, sizeof(ClientSignature)) < 0)
 	{
+		pg_hmac_free(ctx);
 		return false;
 	}
 
 	for (i = 0; i < SCRAM_KEY_LEN; i++)
 		result[i] = ClientKey[i] ^ ClientSignature[i];
 
+	pg_hmac_free(ctx);
 	return true;
 }
 
@@ -820,27 +827,35 @@ verify_server_signature(fe_scram_state *state, bool *match)
 {
 	uint8		expected_ServerSignature[SCRAM_KEY_LEN];
 	uint8		ServerKey[SCRAM_KEY_LEN];
-	scram_HMAC_ctx ctx;
+	pg_hmac_ctx *ctx;
+
+	ctx = pg_hmac_create(PG_SHA256);
+	if (ctx == NULL)
+		return false;
 
 	if (scram_ServerKey(state->SaltedPassword, ServerKey) < 0 ||
 	/* calculate ServerSignature */
-		scram_HMAC_init(&ctx, ServerKey, SCRAM_KEY_LEN) < 0 ||
-		scram_HMAC_update(&ctx,
-						  state->client_first_message_bare,
-						  strlen(state->client_first_message_bare)) < 0 ||
-		scram_HMAC_update(&ctx, ",", 1) < 0 ||
-		scram_HMAC_update(&ctx,
-						  state->server_first_message,
-						  strlen(state->server_first_message)) < 0 ||
-		scram_HMAC_update(&ctx, ",", 1) < 0 ||
-		scram_HMAC_update(&ctx,
-						  state->client_final_message_without_proof,
-						  strlen(state->client_final_message_without_proof)) < 0 ||
-		scram_HMAC_final(expected_ServerSignature, &ctx) < 0)
+		pg_hmac_init(ctx, ServerKey, SCRAM_KEY_LEN) < 0 ||
+		pg_hmac_update(ctx,
+					   (uint8 *) state->client_first_message_bare,
+					   strlen(state->client_first_message_bare)) < 0 ||
+		pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
+		pg_hmac_update(ctx,
+					   (uint8 *) state->server_first_message,
+					   strlen(state->server_first_message)) < 0 ||
+		pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
+		pg_hmac_update(ctx,
+					   (uint8 *) state->client_final_message_without_proof,
+					   strlen(state->client_final_message_without_proof)) < 0 ||
+		pg_hmac_final(ctx, expected_ServerSignature,
+					  sizeof(expected_ServerSignature)) < 0)
 	{
+		pg_hmac_free(ctx);
 		return false;
 	}
 
+	pg_hmac_free(ctx);
+
 	/* signature processed, so now check after it */
 	if (memcmp(expected_ServerSignature, state->ServerSignature, SCRAM_KEY_LEN) != 0)
 		*match = false;
diff --git a/configure b/configure
index ce9ea36999..0ddda03710 100755
--- a/configure
+++ b/configure
@@ -12433,7 +12433,7 @@ done
   # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
   # doesn't have these OpenSSL 1.1.0 functions. So check for individual
   # functions.
-  for ac_func in OPENSSL_init_ssl BIO_get_data BIO_meth_new ASN1_STRING_get0_data
+  for ac_func in OPENSSL_init_ssl BIO_get_data BIO_meth_new ASN1_STRING_get0_data HMAC_CTX_new HMAC_CTX_free
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
diff --git a/configure.ac b/configure.ac
index 07da84d401..5a00bc1702 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1229,7 +1229,7 @@ if test "$with_ssl" = openssl ; then
   # defines OPENSSL_VERSION_NUMBER to claim version 2.0.0, even though it
   # doesn't have these OpenSSL 1.1.0 functions. So check for individual
   # functions.
-  AC_CHECK_FUNCS([OPENSSL_init_ssl BIO_get_data BIO_meth_new ASN1_STRING_get0_data])
+  AC_CHECK_FUNCS([OPENSSL_init_ssl BIO_get_data BIO_meth_new ASN1_STRING_get0_data HMAC_CTX_new HMAC_CTX_free])
   # OpenSSL versions before 1.1.0 required setting callback functions, for
   # thread-safety. In 1.1.0, it's no longer required, and CRYPTO_lock()
   # function was removed.
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 49614106dc..3f54c6efa6 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -130,11 +130,13 @@ sub mkvcbuild
 	if ($solution->{options}->{openssl})
 	{
 		push(@pgcommonallfiles, 'cryptohash_openssl.c');
+		push(@pgcommonallfiles, 'hmac_openssl.c');
 		push(@pgcommonallfiles, 'protocol_openssl.c');
 	}
 	else
 	{
 		push(@pgcommonallfiles, 'cryptohash.c');
+		push(@pgcommonallfiles, 'hmac.c');
 		push(@pgcommonallfiles, 'md5.c');
 		push(@pgcommonallfiles, 'sha1.c');
 		push(@pgcommonallfiles, 'sha2.c');
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
index 2aa062b2c9..120edb8c34 100644
--- a/src/tools/msvc/Solution.pm
+++ b/src/tools/msvc/Solution.pm
@@ -279,6 +279,8 @@ sub GenerateFiles
 		HAVE_GETTIMEOFDAY                           => undef,
 		HAVE_GSSAPI_GSSAPI_H                        => undef,
 		HAVE_GSSAPI_H                               => undef,
+		HAVE_HMAC_CTX_FREE                          => undef,
+		HAVE_HMAC_CTX_NEW                           => undef,
 		HAVE_HISTORY_H                              => undef,
 		HAVE_HISTORY_TRUNCATE_FILE                  => undef,
 		HAVE_IFADDRS_H                              => undef,
@@ -537,6 +539,8 @@ sub GenerateFiles
 			$define{HAVE_ASN1_STRING_GET0_DATA} = 1;
 			$define{HAVE_BIO_GET_DATA}          = 1;
 			$define{HAVE_BIO_METH_NEW}          = 1;
+			$define{HAVE_HMAC_CTX_FREE}         = 1;
+			$define{HAVE_HMAC_CTX_NEW}          = 1;
 			$define{HAVE_OPENSSL_INIT_SSL}      = 1;
 		}
 	}
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index bab4f3adb3..4e0bcf5fd1 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -3207,6 +3207,7 @@ pg_enc2gettext
 pg_enc2name
 pg_encname
 pg_gssinfo
+pg_hmac_ctx
 pg_int64
 pg_local_to_utf_combined
 pg_locale_t
@@ -3351,7 +3352,6 @@ role_auth_extra
 row_security_policy_hook_type
 rsv_callback
 save_buffer
-scram_HMAC_ctx
 scram_state
 scram_state_enum
 sem_t
-- 
2.30.0

Attachment: signature.asc
Description: PGP signature

Reply via email to