diff --git a/src/include/common/cryptohash.h b/src/include/common/cryptohash.h
index 32d7784ca5..541dc844c8 100644
--- a/src/include/common/cryptohash.h
+++ b/src/include/common/cryptohash.h
@@ -32,7 +32,7 @@ typedef struct pg_cryptohash_ctx pg_cryptohash_ctx;
 extern pg_cryptohash_ctx *pg_cryptohash_create(pg_cryptohash_type type);
 extern int	pg_cryptohash_init(pg_cryptohash_ctx *ctx);
 extern int	pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len);
-extern int	pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest);
+extern int	pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest, size_t len);
 extern void pg_cryptohash_free(pg_cryptohash_ctx *ctx);
 
 #endif							/* PG_CRYPTOHASH_H */
diff --git a/src/backend/libpq/auth-scram.c b/src/backend/libpq/auth-scram.c
index 8d857f39df..b9b6d464a0 100644
--- a/src/backend/libpq/auth-scram.c
+++ b/src/backend/libpq/auth-scram.c
@@ -1429,7 +1429,7 @@ scram_mock_salt(const char *username)
 	if (pg_cryptohash_init(ctx) < 0 ||
 		pg_cryptohash_update(ctx, (uint8 *) username, strlen(username)) < 0 ||
 		pg_cryptohash_update(ctx, (uint8 *) mock_auth_nonce, MOCK_AUTH_NONCE_LEN) < 0 ||
-		pg_cryptohash_final(ctx, sha_digest) < 0)
+		pg_cryptohash_final(ctx, sha_digest, sizeof(sha_digest)) < 0)
 	{
 		pg_cryptohash_free(ctx);
 		return NULL;
diff --git a/src/backend/replication/backup_manifest.c b/src/backend/replication/backup_manifest.c
index 0cefd181b5..32bb0efb3d 100644
--- a/src/backend/replication/backup_manifest.c
+++ b/src/backend/replication/backup_manifest.c
@@ -330,12 +330,13 @@ SendBackupManifest(backup_manifest_info *manifest)
 	 * twice.
 	 */
 	manifest->still_checksumming = false;
-	if (pg_cryptohash_final(manifest->manifest_ctx, checksumbuf) < 0)
+	if (pg_cryptohash_final(manifest->manifest_ctx, checksumbuf,
+							sizeof(checksumbuf)) < 0)
 		elog(ERROR, "failed to finalize checksum of backup manifest");
 	AppendStringToManifest(manifest, "\"Manifest-Checksum\": \"");
-	dstlen = pg_hex_enc_len(PG_SHA256_DIGEST_LENGTH);
+	dstlen = pg_hex_enc_len(sizeof(checksumbuf));
 	checksumstringbuf = palloc0(dstlen + 1);	/* includes \0 */
-	pg_hex_encode((char *) checksumbuf, sizeof checksumbuf,
+	pg_hex_encode((char *) checksumbuf, sizeof(checksumbuf),
 				  checksumstringbuf, dstlen);
 	checksumstringbuf[dstlen] = '\0';
 	AppendStringToManifest(manifest, checksumstringbuf);
diff --git a/src/backend/utils/adt/cryptohashfuncs.c b/src/backend/utils/adt/cryptohashfuncs.c
index 152adcbfb4..6a0f0258e6 100644
--- a/src/backend/utils/adt/cryptohashfuncs.c
+++ b/src/backend/utils/adt/cryptohashfuncs.c
@@ -114,7 +114,8 @@ cryptohash_internal(pg_cryptohash_type type, bytea *input)
 		elog(ERROR, "could not initialize %s context", typestr);
 	if (pg_cryptohash_update(ctx, data, len) < 0)
 		elog(ERROR, "could not update %s context", typestr);
-	if (pg_cryptohash_final(ctx, (unsigned char *) VARDATA(result)) < 0)
+	if (pg_cryptohash_final(ctx, (unsigned char *) VARDATA(result),
+							digest_len) < 0)
 		elog(ERROR, "could not finalize %s context", typestr);
 	pg_cryptohash_free(ctx);
 
diff --git a/src/common/checksum_helper.c b/src/common/checksum_helper.c
index a895e2e285..431e247d59 100644
--- a/src/common/checksum_helper.c
+++ b/src/common/checksum_helper.c
@@ -198,28 +198,32 @@ pg_checksum_final(pg_checksum_context *context, uint8 *output)
 			memcpy(output, &context->raw_context.c_crc32c, retval);
 			break;
 		case CHECKSUM_TYPE_SHA224:
-			if (pg_cryptohash_final(context->raw_context.c_sha2, output) < 0)
+			retval = PG_SHA224_DIGEST_LENGTH;
+			if (pg_cryptohash_final(context->raw_context.c_sha2,
+									output, retval) < 0)
 				return -1;
 			pg_cryptohash_free(context->raw_context.c_sha2);
-			retval = PG_SHA224_DIGEST_LENGTH;
 			break;
 		case CHECKSUM_TYPE_SHA256:
-			if (pg_cryptohash_final(context->raw_context.c_sha2, output) < 0)
+			retval = PG_SHA256_DIGEST_LENGTH;
+			if (pg_cryptohash_final(context->raw_context.c_sha2,
+									output, retval) < 0)
 				return -1;
 			pg_cryptohash_free(context->raw_context.c_sha2);
-			retval = PG_SHA256_DIGEST_LENGTH;
 			break;
 		case CHECKSUM_TYPE_SHA384:
-			if (pg_cryptohash_final(context->raw_context.c_sha2, output) < 0)
+			retval = PG_SHA384_DIGEST_LENGTH;
+			if (pg_cryptohash_final(context->raw_context.c_sha2,
+									output, retval) < 0)
 				return -1;
 			pg_cryptohash_free(context->raw_context.c_sha2);
-			retval = PG_SHA384_DIGEST_LENGTH;
 			break;
 		case CHECKSUM_TYPE_SHA512:
-			if (pg_cryptohash_final(context->raw_context.c_sha2, output) < 0)
+			retval = PG_SHA512_DIGEST_LENGTH;
+			if (pg_cryptohash_final(context->raw_context.c_sha2,
+									output, retval) < 0)
 				return -1;
 			pg_cryptohash_free(context->raw_context.c_sha2);
-			retval = PG_SHA512_DIGEST_LENGTH;
 			break;
 	}
 
diff --git a/src/common/cryptohash.c b/src/common/cryptohash.c
index 5b2c050d79..9ab36003c9 100644
--- a/src/common/cryptohash.c
+++ b/src/common/cryptohash.c
@@ -161,11 +161,11 @@ pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len)
  * pg_cryptohash_final
  *
  * Finalize a hash context.  Note that this implementation is designed
- * to never fail, so this always returns 0 except if the caller has
- * given a NULL context.
+ * to never fail, but note that this would fail if the destination buffer
+ * is not large enough.
  */
 int
-pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest)
+pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest, size_t len)
 {
 	if (ctx == NULL)
 		return -1;
@@ -173,21 +173,33 @@ pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest)
 	switch (ctx->type)
 	{
 		case PG_MD5:
+			if (len < MD5_DIGEST_LENGTH)
+				return -1;
 			pg_md5_final(&ctx->data.md5, dest);
 			break;
 		case PG_SHA1:
+			if (len < SHA1_DIGEST_LENGTH)
+				return -1;
 			pg_sha1_final(&ctx->data.sha1, dest);
 			break;
 		case PG_SHA224:
+			if (len < PG_SHA224_DIGEST_LENGTH)
+				return -1;
 			pg_sha224_final(&ctx->data.sha224, dest);
 			break;
 		case PG_SHA256:
+			if (len < PG_SHA256_DIGEST_LENGTH)
+				return -1;
 			pg_sha256_final(&ctx->data.sha256, dest);
 			break;
 		case PG_SHA384:
+			if (len < PG_SHA384_DIGEST_LENGTH)
+				return -1;
 			pg_sha384_final(&ctx->data.sha384, dest);
 			break;
 		case PG_SHA512:
+			if (len < PG_SHA512_DIGEST_LENGTH)
+				return -1;
 			pg_sha512_final(&ctx->data.sha512, dest);
 			break;
 	}
diff --git a/src/common/cryptohash_openssl.c b/src/common/cryptohash_openssl.c
index 006e867403..643cc7aea2 100644
--- a/src/common/cryptohash_openssl.c
+++ b/src/common/cryptohash_openssl.c
@@ -24,6 +24,9 @@
 #include <openssl/evp.h>
 
 #include "common/cryptohash.h"
+#include "common/md5.h"
+#include "common/sha1.h"
+#include "common/sha2.h"
 #ifndef FRONTEND
 #include "utils/memutils.h"
 #include "utils/resowner.h"
@@ -181,13 +184,41 @@ pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len)
  * Finalize a hash context.  Returns 0 on success, and -1 on failure.
  */
 int
-pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest)
+pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest, size_t len)
 {
 	int			status = 0;
 
 	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 = EVP_DigestFinal_ex(ctx->evpctx, dest, 0);
 
 	/* OpenSSL internals return 1 on success, 0 on failure */
diff --git a/src/common/md5_common.c b/src/common/md5_common.c
index b01c95ebb6..2114890eff 100644
--- a/src/common/md5_common.c
+++ b/src/common/md5_common.c
@@ -78,7 +78,7 @@ pg_md5_hash(const void *buff, size_t len, char *hexsum)
 
 	if (pg_cryptohash_init(ctx) < 0 ||
 		pg_cryptohash_update(ctx, buff, len) < 0 ||
-		pg_cryptohash_final(ctx, sum) < 0)
+		pg_cryptohash_final(ctx, sum, sizeof(sum)) < 0)
 	{
 		pg_cryptohash_free(ctx);
 		return false;
@@ -100,7 +100,7 @@ pg_md5_binary(const void *buff, size_t len, void *outbuf)
 
 	if (pg_cryptohash_init(ctx) < 0 ||
 		pg_cryptohash_update(ctx, buff, len) < 0 ||
-		pg_cryptohash_final(ctx, outbuf) < 0)
+		pg_cryptohash_final(ctx, outbuf, MD5_DIGEST_LENGTH) < 0)
 	{
 		pg_cryptohash_free(ctx);
 		return false;
diff --git a/src/common/scram-common.c b/src/common/scram-common.c
index 3f406d4e4d..0b9557376e 100644
--- a/src/common/scram-common.c
+++ b/src/common/scram-common.c
@@ -51,7 +51,7 @@ scram_HMAC_init(scram_HMAC_ctx *ctx, const uint8 *key, int keylen)
 			return -1;
 		if (pg_cryptohash_init(sha256_ctx) < 0 ||
 			pg_cryptohash_update(sha256_ctx, key, keylen) < 0 ||
-			pg_cryptohash_final(sha256_ctx, keybuf) < 0)
+			pg_cryptohash_final(sha256_ctx, keybuf, sizeof(keybuf)) < 0)
 		{
 			pg_cryptohash_free(sha256_ctx);
 			return -1;
@@ -112,7 +112,7 @@ scram_HMAC_final(uint8 *result, scram_HMAC_ctx *ctx)
 
 	Assert(ctx->sha256ctx != NULL);
 
-	if (pg_cryptohash_final(ctx->sha256ctx, h) < 0)
+	if (pg_cryptohash_final(ctx->sha256ctx, h, sizeof(h)) < 0)
 	{
 		pg_cryptohash_free(ctx->sha256ctx);
 		return -1;
@@ -122,7 +122,7 @@ scram_HMAC_final(uint8 *result, scram_HMAC_ctx *ctx)
 	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) < 0)
+		pg_cryptohash_final(ctx->sha256ctx, result, SCRAM_KEY_LEN) < 0)
 	{
 		pg_cryptohash_free(ctx->sha256ctx);
 		return -1;
@@ -202,7 +202,7 @@ scram_H(const uint8 *input, int len, uint8 *result)
 
 	if (pg_cryptohash_init(ctx) < 0 ||
 		pg_cryptohash_update(ctx, input, len) < 0 ||
-		pg_cryptohash_final(ctx, result) < 0)
+		pg_cryptohash_final(ctx, result, SCRAM_KEY_LEN) < 0)
 	{
 		pg_cryptohash_free(ctx);
 		return -1;
diff --git a/src/bin/pg_verifybackup/parse_manifest.c b/src/bin/pg_verifybackup/parse_manifest.c
index db2fa90cfe..3b13ae5b84 100644
--- a/src/bin/pg_verifybackup/parse_manifest.c
+++ b/src/bin/pg_verifybackup/parse_manifest.c
@@ -659,7 +659,8 @@ verify_manifest_checksum(JsonManifestParseState *parse, char *buffer,
 		context->error_cb(context, "could not initialize checksum of manifest");
 	if (pg_cryptohash_update(manifest_ctx, (uint8 *) buffer, penultimate_newline + 1) < 0)
 		context->error_cb(context, "could not update checksum of manifest");
-	if (pg_cryptohash_final(manifest_ctx, manifest_checksum_actual) < 0)
+	if (pg_cryptohash_final(manifest_ctx, manifest_checksum_actual,
+							sizeof(manifest_checksum_actual)) < 0)
 		context->error_cb(context, "could not finalize checksum of manifest");
 
 	/* Now verify it. */
diff --git a/contrib/pgcrypto/internal-sha2.c b/contrib/pgcrypto/internal-sha2.c
index 0fe53e15af..ecf3004e95 100644
--- a/contrib/pgcrypto/internal-sha2.c
+++ b/contrib/pgcrypto/internal-sha2.c
@@ -118,7 +118,7 @@ int_sha2_finish(PX_MD *h, uint8 *dst)
 {
 	pg_cryptohash_ctx *ctx = (pg_cryptohash_ctx *) h->p.ptr;
 
-	if (pg_cryptohash_final(ctx, dst) < 0)
+	if (pg_cryptohash_final(ctx, dst, h->result_size(h)) < 0)
 		elog(ERROR, "could not finalize %s context", "SHA2");
 }
 
diff --git a/contrib/pgcrypto/internal.c b/contrib/pgcrypto/internal.c
index ef6ce2fb1e..dd45fee7ed 100644
--- a/contrib/pgcrypto/internal.c
+++ b/contrib/pgcrypto/internal.c
@@ -106,7 +106,7 @@ int_md5_finish(PX_MD *h, uint8 *dst)
 {
 	pg_cryptohash_ctx *ctx = (pg_cryptohash_ctx *) h->p.ptr;
 
-	if (pg_cryptohash_final(ctx, dst) < 0)
+	if (pg_cryptohash_final(ctx, dst, h->result_size(h)) < 0)
 		elog(ERROR, "could not finalize %s context", "MD5");
 }
 
@@ -156,7 +156,7 @@ int_sha1_finish(PX_MD *h, uint8 *dst)
 {
 	pg_cryptohash_ctx *ctx = (pg_cryptohash_ctx *) h->p.ptr;
 
-	if (pg_cryptohash_final(ctx, dst) < 0)
+	if (pg_cryptohash_final(ctx, dst, h->result_size(h)) < 0)
 		elog(ERROR, "could not finalize %s context", "SHA1");
 }
 
diff --git a/contrib/uuid-ossp/uuid-ossp.c b/contrib/uuid-ossp/uuid-ossp.c
index 49a4a59264..f9335f2863 100644
--- a/contrib/uuid-ossp/uuid-ossp.c
+++ b/contrib/uuid-ossp/uuid-ossp.c
@@ -324,7 +324,8 @@ uuid_generate_internal(int v, unsigned char *ns, const char *ptr, int len)
 						pg_cryptohash_update(ctx, (unsigned char *) ptr, len) < 0)
 						elog(ERROR, "could not update %s context", "MD5");
 					/* we assume sizeof MD5 result is 16, same as UUID size */
-					if (pg_cryptohash_final(ctx, (unsigned char *) &uu) < 0)
+					if (pg_cryptohash_final(ctx, (unsigned char *) &uu,
+											sizeof(uu)) < 0)
 						elog(ERROR, "could not finalize %s context", "MD5");
 					pg_cryptohash_free(ctx);
 				}
@@ -338,7 +339,7 @@ uuid_generate_internal(int v, unsigned char *ns, const char *ptr, int len)
 					if (pg_cryptohash_update(ctx, ns, sizeof(uu)) < 0 ||
 						pg_cryptohash_update(ctx, (unsigned char *) ptr, len) < 0)
 						elog(ERROR, "could not update %s context", "SHA1");
-					if (pg_cryptohash_final(ctx, sha1result) < 0)
+					if (pg_cryptohash_final(ctx, sha1result, sizeof(sha1result)) < 0)
 						elog(ERROR, "could not finalize %s context", "SHA1");
 					pg_cryptohash_free(ctx);
 
