diff --git a/contrib/pgcrypto/internal-sha2.c b/contrib/pgcrypto/internal-sha2.c index 0fe53e15afa..ecf3004e95b 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 ef6ce2fb1ef..dd45fee7ed6 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 49a4a592645..f9335f28631 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); diff --git a/src/backend/libpq/auth-scram.c b/src/backend/libpq/auth-scram.c index 8d857f39df5..b9b6d464a05 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 0cefd181b5a..32bb0efb3da 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 152adcbfb4a..6a0f0258e60 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/bin/pg_verifybackup/parse_manifest.c b/src/bin/pg_verifybackup/parse_manifest.c index db2fa90cfec..3b13ae5b846 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/src/common/checksum_helper.c b/src/common/checksum_helper.c index a895e2e2855..431e247d59d 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 5b2c050d799..0dab74a094b 100644 --- a/src/common/cryptohash.c +++ b/src/common/cryptohash.c @@ -160,12 +160,12 @@ 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. + * Finalize a hash context. Note that this implementation is designed to + * never fail, so this always returns 0 except 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 006e867403e..643cc7aea2c 100644 --- a/src/common/cryptohash_openssl.c +++ b/src/common/cryptohash_openssl.c @@ -24,6 +24,9 @@ #include #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 b01c95ebb6e..2114890effe 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 3f406d4e4dc..0b9557376e9 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/include/common/cryptohash.h b/src/include/common/cryptohash.h index 32d7784ca5b..541dc844c8b 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 */