diff --git a/contrib/pgcrypto/internal-sha2.c b/contrib/pgcrypto/internal-sha2.c index 9fa940b5bb..0fe53e15af 100644 --- a/contrib/pgcrypto/internal-sha2.c +++ b/contrib/pgcrypto/internal-sha2.c @@ -33,6 +33,7 @@ #include +#include "common/cryptohash.h" #include "common/sha2.h" #include "px.h" @@ -42,7 +43,6 @@ void init_sha384(PX_MD *h); void init_sha512(PX_MD *h); /* SHA224 */ - static unsigned int_sha224_len(PX_MD *h) { @@ -55,42 +55,7 @@ int_sha224_block_len(PX_MD *h) return PG_SHA224_BLOCK_LENGTH; } -static void -int_sha224_update(PX_MD *h, const uint8 *data, unsigned dlen) -{ - pg_sha224_ctx *ctx = (pg_sha224_ctx *) h->p.ptr; - - pg_sha224_update(ctx, data, dlen); -} - -static void -int_sha224_reset(PX_MD *h) -{ - pg_sha224_ctx *ctx = (pg_sha224_ctx *) h->p.ptr; - - pg_sha224_init(ctx); -} - -static void -int_sha224_finish(PX_MD *h, uint8 *dst) -{ - pg_sha224_ctx *ctx = (pg_sha224_ctx *) h->p.ptr; - - pg_sha224_final(ctx, dst); -} - -static void -int_sha224_free(PX_MD *h) -{ - pg_sha224_ctx *ctx = (pg_sha224_ctx *) h->p.ptr; - - px_memset(ctx, 0, sizeof(*ctx)); - pfree(ctx); - pfree(h); -} - /* SHA256 */ - static unsigned int_sha256_len(PX_MD *h) { @@ -103,42 +68,7 @@ int_sha256_block_len(PX_MD *h) return PG_SHA256_BLOCK_LENGTH; } -static void -int_sha256_update(PX_MD *h, const uint8 *data, unsigned dlen) -{ - pg_sha256_ctx *ctx = (pg_sha256_ctx *) h->p.ptr; - - pg_sha256_update(ctx, data, dlen); -} - -static void -int_sha256_reset(PX_MD *h) -{ - pg_sha256_ctx *ctx = (pg_sha256_ctx *) h->p.ptr; - - pg_sha256_init(ctx); -} - -static void -int_sha256_finish(PX_MD *h, uint8 *dst) -{ - pg_sha256_ctx *ctx = (pg_sha256_ctx *) h->p.ptr; - - pg_sha256_final(ctx, dst); -} - -static void -int_sha256_free(PX_MD *h) -{ - pg_sha256_ctx *ctx = (pg_sha256_ctx *) h->p.ptr; - - px_memset(ctx, 0, sizeof(*ctx)); - pfree(ctx); - pfree(h); -} - /* SHA384 */ - static unsigned int_sha384_len(PX_MD *h) { @@ -151,42 +81,7 @@ int_sha384_block_len(PX_MD *h) return PG_SHA384_BLOCK_LENGTH; } -static void -int_sha384_update(PX_MD *h, const uint8 *data, unsigned dlen) -{ - pg_sha384_ctx *ctx = (pg_sha384_ctx *) h->p.ptr; - - pg_sha384_update(ctx, data, dlen); -} - -static void -int_sha384_reset(PX_MD *h) -{ - pg_sha384_ctx *ctx = (pg_sha384_ctx *) h->p.ptr; - - pg_sha384_init(ctx); -} - -static void -int_sha384_finish(PX_MD *h, uint8 *dst) -{ - pg_sha384_ctx *ctx = (pg_sha384_ctx *) h->p.ptr; - - pg_sha384_final(ctx, dst); -} - -static void -int_sha384_free(PX_MD *h) -{ - pg_sha384_ctx *ctx = (pg_sha384_ctx *) h->p.ptr; - - px_memset(ctx, 0, sizeof(*ctx)); - pfree(ctx); - pfree(h); -} - /* SHA512 */ - static unsigned int_sha512_len(PX_MD *h) { @@ -199,37 +94,40 @@ int_sha512_block_len(PX_MD *h) return PG_SHA512_BLOCK_LENGTH; } +/* Generic interface for all SHA2 methods */ static void -int_sha512_update(PX_MD *h, const uint8 *data, unsigned dlen) +int_sha2_update(PX_MD *h, const uint8 *data, unsigned dlen) { - pg_sha512_ctx *ctx = (pg_sha512_ctx *) h->p.ptr; + pg_cryptohash_ctx *ctx = (pg_cryptohash_ctx *) h->p.ptr; - pg_sha512_update(ctx, data, dlen); + if (pg_cryptohash_update(ctx, data, dlen) < 0) + elog(ERROR, "could not update %s context", "SHA2"); } static void -int_sha512_reset(PX_MD *h) +int_sha2_reset(PX_MD *h) { - pg_sha512_ctx *ctx = (pg_sha512_ctx *) h->p.ptr; + pg_cryptohash_ctx *ctx = (pg_cryptohash_ctx *) h->p.ptr; - pg_sha512_init(ctx); + if (pg_cryptohash_init(ctx) < 0) + elog(ERROR, "could not initialize %s context", "SHA2"); } static void -int_sha512_finish(PX_MD *h, uint8 *dst) +int_sha2_finish(PX_MD *h, uint8 *dst) { - pg_sha512_ctx *ctx = (pg_sha512_ctx *) h->p.ptr; + pg_cryptohash_ctx *ctx = (pg_cryptohash_ctx *) h->p.ptr; - pg_sha512_final(ctx, dst); + if (pg_cryptohash_final(ctx, dst) < 0) + elog(ERROR, "could not finalize %s context", "SHA2"); } static void -int_sha512_free(PX_MD *h) +int_sha2_free(PX_MD *h) { - pg_sha512_ctx *ctx = (pg_sha512_ctx *) h->p.ptr; + pg_cryptohash_ctx *ctx = (pg_cryptohash_ctx *) h->p.ptr; - px_memset(ctx, 0, sizeof(*ctx)); - pfree(ctx); + pg_cryptohash_free(ctx); pfree(h); } @@ -238,18 +136,17 @@ int_sha512_free(PX_MD *h) void init_sha224(PX_MD *md) { - pg_sha224_ctx *ctx; - - ctx = palloc0(sizeof(*ctx)); + pg_cryptohash_ctx *ctx; + ctx = pg_cryptohash_create(PG_SHA224); md->p.ptr = ctx; md->result_size = int_sha224_len; md->block_size = int_sha224_block_len; - md->reset = int_sha224_reset; - md->update = int_sha224_update; - md->finish = int_sha224_finish; - md->free = int_sha224_free; + md->reset = int_sha2_reset; + md->update = int_sha2_update; + md->finish = int_sha2_finish; + md->free = int_sha2_free; md->reset(md); } @@ -257,18 +154,17 @@ init_sha224(PX_MD *md) void init_sha256(PX_MD *md) { - pg_sha256_ctx *ctx; - - ctx = palloc0(sizeof(*ctx)); + pg_cryptohash_ctx *ctx; + ctx = pg_cryptohash_create(PG_SHA256); md->p.ptr = ctx; md->result_size = int_sha256_len; md->block_size = int_sha256_block_len; - md->reset = int_sha256_reset; - md->update = int_sha256_update; - md->finish = int_sha256_finish; - md->free = int_sha256_free; + md->reset = int_sha2_reset; + md->update = int_sha2_update; + md->finish = int_sha2_finish; + md->free = int_sha2_free; md->reset(md); } @@ -276,18 +172,17 @@ init_sha256(PX_MD *md) void init_sha384(PX_MD *md) { - pg_sha384_ctx *ctx; - - ctx = palloc0(sizeof(*ctx)); + pg_cryptohash_ctx *ctx; + ctx = pg_cryptohash_create(PG_SHA384); md->p.ptr = ctx; md->result_size = int_sha384_len; md->block_size = int_sha384_block_len; - md->reset = int_sha384_reset; - md->update = int_sha384_update; - md->finish = int_sha384_finish; - md->free = int_sha384_free; + md->reset = int_sha2_reset; + md->update = int_sha2_update; + md->finish = int_sha2_finish; + md->free = int_sha2_free; md->reset(md); } @@ -295,18 +190,17 @@ init_sha384(PX_MD *md) void init_sha512(PX_MD *md) { - pg_sha512_ctx *ctx; - - ctx = palloc0(sizeof(*ctx)); + pg_cryptohash_ctx *ctx; + ctx = pg_cryptohash_create(PG_SHA512); md->p.ptr = ctx; md->result_size = int_sha512_len; md->block_size = int_sha512_block_len; - md->reset = int_sha512_reset; - md->update = int_sha512_update; - md->finish = int_sha512_finish; - md->free = int_sha512_free; + md->reset = int_sha2_reset; + md->update = int_sha2_update; + md->finish = int_sha2_finish; + md->free = int_sha2_free; md->reset(md); } diff --git a/src/backend/libpq/auth-scram.c b/src/backend/libpq/auth-scram.c index 0f79b28bb5..6879a81618 100644 --- a/src/backend/libpq/auth-scram.c +++ b/src/backend/libpq/auth-scram.c @@ -527,8 +527,12 @@ scram_verify_plain_password(const char *username, const char *password, password = prep_password; /* Compute Server Key based on the user-supplied plaintext password */ - scram_SaltedPassword(password, salt, saltlen, iterations, salted_password); - scram_ServerKey(salted_password, computed_key); + if (scram_SaltedPassword(password, salt, saltlen, iterations, + salted_password) < 0 || + scram_ServerKey(salted_password, computed_key) < 0) + { + elog(ERROR, "could not compute server key"); + } if (prep_password) pfree(prep_password); @@ -651,8 +655,17 @@ mock_scram_secret(const char *username, int *iterations, char **salt, char *encoded_salt; int encoded_len; - /* Generate deterministic salt */ + /* + * Generate deterministic salt. + * + * Note that we cannot reveal any information to an attacker here so the + * error messages need to remain generic. This should never fail anyway + * as the salt generated for mock authentication uses the cluster's nonce + * value. + */ raw_salt = scram_mock_salt(username); + if (raw_salt == NULL) + elog(ERROR, "could not encode salt"); encoded_len = pg_b64_enc_len(SCRAM_DEFAULT_SALT_LEN); /* don't forget the zero-terminator */ @@ -660,12 +673,6 @@ mock_scram_secret(const char *username, int *iterations, char **salt, encoded_len = pg_b64_encode(raw_salt, SCRAM_DEFAULT_SALT_LEN, encoded_salt, encoded_len); - /* - * Note that we cannot reveal any information to an attacker here so the - * error message needs to remain generic. This should never fail anyway - * as the salt generated for mock authentication uses the cluster's nonce - * value. - */ if (encoded_len < 0) elog(ERROR, "could not encode salt"); encoded_salt[encoded_len] = '\0'; @@ -1084,7 +1091,8 @@ verify_final_nonce(scram_state *state) /* * Verify the client proof contained in the last message received from - * client in an exchange. + * client in an exchange. Returns true if the verification is a success, + * or false for a failure. */ static bool verify_client_proof(scram_state *state) @@ -1095,27 +1103,35 @@ verify_client_proof(scram_state *state) scram_HMAC_ctx ctx; int i; - /* calculate ClientSignature */ - scram_HMAC_init(&ctx, state->StoredKey, SCRAM_KEY_LEN); - scram_HMAC_update(&ctx, - state->client_first_message_bare, - strlen(state->client_first_message_bare)); - scram_HMAC_update(&ctx, ",", 1); - scram_HMAC_update(&ctx, - state->server_first_message, - strlen(state->server_first_message)); - scram_HMAC_update(&ctx, ",", 1); - scram_HMAC_update(&ctx, - state->client_final_message_without_proof, - strlen(state->client_final_message_without_proof)); - scram_HMAC_final(ClientSignature, &ctx); + /* + * Calculate ClientSignature. Note that we don't log directly a failure + * 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) + { + elog(ERROR, "could not calculate client signature"); + } /* 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]; /* Hash it one more time, and compare with StoredKey */ - scram_H(ClientKey, SCRAM_KEY_LEN, client_StoredKey); + if (scram_H(ClientKey, SCRAM_KEY_LEN, client_StoredKey) < 0) + elog(ERROR, "could not hash stored key"); if (memcmp(client_StoredKey, state->StoredKey, SCRAM_KEY_LEN) != 0) return false; @@ -1346,19 +1362,22 @@ build_server_final_message(scram_state *state) scram_HMAC_ctx ctx; /* calculate ServerSignature */ - scram_HMAC_init(&ctx, state->ServerKey, SCRAM_KEY_LEN); - scram_HMAC_update(&ctx, - state->client_first_message_bare, - strlen(state->client_first_message_bare)); - scram_HMAC_update(&ctx, ",", 1); - scram_HMAC_update(&ctx, - state->server_first_message, - strlen(state->server_first_message)); - scram_HMAC_update(&ctx, ",", 1); - scram_HMAC_update(&ctx, - state->client_final_message_without_proof, - strlen(state->client_final_message_without_proof)); - scram_HMAC_final(ServerSignature, &ctx); + 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) + { + elog(ERROR, "could not calculate server signature"); + } siglen = pg_b64_enc_len(SCRAM_KEY_LEN); /* don't forget the zero-terminator */ @@ -1388,12 +1407,12 @@ build_server_final_message(scram_state *state) /* * Deterministically generate salt for mock authentication, using a SHA256 * hash based on the username and a cluster-level secret key. Returns a - * pointer to a static buffer of size SCRAM_DEFAULT_SALT_LEN. + * pointer to a static buffer of size SCRAM_DEFAULT_SALT_LEN, or NULL. */ static char * scram_mock_salt(const char *username) { - pg_sha256_ctx ctx; + pg_cryptohash_ctx *ctx; static uint8 sha_digest[PG_SHA256_DIGEST_LENGTH]; char *mock_auth_nonce = GetMockAuthenticationNonce(); @@ -1406,10 +1425,16 @@ scram_mock_salt(const char *username) StaticAssertStmt(PG_SHA256_DIGEST_LENGTH >= SCRAM_DEFAULT_SALT_LEN, "salt length greater than SHA256 digest length"); - pg_sha256_init(&ctx); - pg_sha256_update(&ctx, (uint8 *) username, strlen(username)); - pg_sha256_update(&ctx, (uint8 *) mock_auth_nonce, MOCK_AUTH_NONCE_LEN); - pg_sha256_final(&ctx, sha_digest); + ctx = pg_cryptohash_create(PG_SHA256); + 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_free(ctx); + return NULL; + } + pg_cryptohash_free(ctx); return (char *) sha_digest; } diff --git a/src/backend/replication/backup_manifest.c b/src/backend/replication/backup_manifest.c index bab5e2f53b..c3f339c556 100644 --- a/src/backend/replication/backup_manifest.c +++ b/src/backend/replication/backup_manifest.c @@ -65,7 +65,9 @@ InitializeBackupManifest(backup_manifest_info *manifest, else { manifest->buffile = BufFileCreateTemp(false); - pg_sha256_init(&manifest->manifest_ctx); + manifest->manifest_ctx = pg_cryptohash_create(PG_SHA256); + if (pg_cryptohash_init(manifest->manifest_ctx) < 0) + elog(ERROR, "failed to initialize checksum of backup manifest"); } manifest->manifest_size = UINT64CONST(0); @@ -79,6 +81,16 @@ InitializeBackupManifest(backup_manifest_info *manifest, "\"Files\": ["); } +/* + * Free resources assigned to a backup manifest constructed. + */ +void +FreeBackupManifest(backup_manifest_info *manifest) +{ + pg_cryptohash_free(manifest->manifest_ctx); + manifest->manifest_ctx = NULL; +} + /* * Add an entry to the backup manifest for a file. */ @@ -166,6 +178,9 @@ AddFileToBackupManifest(backup_manifest_info *manifest, const char *spcoid, int checksumlen; checksumlen = pg_checksum_final(checksum_ctx, checksumbuf); + if (checksumlen < 0) + elog(ERROR, "could not finalize checksum of file \"%s\"", + pathname); appendStringInfo(&buf, ", \"Checksum-Algorithm\": \"%s\", \"Checksum\": \"", @@ -310,7 +325,8 @@ SendBackupManifest(backup_manifest_info *manifest) * twice. */ manifest->still_checksumming = false; - pg_sha256_final(&manifest->manifest_ctx, checksumbuf); + if (pg_cryptohash_final(manifest->manifest_ctx, checksumbuf) < 0) + elog(ERROR, "failed to finalize checksum of backup manifest"); AppendStringToManifest(manifest, "\"Manifest-Checksum\": \""); hex_encode((char *) checksumbuf, sizeof checksumbuf, checksumstringbuf); checksumstringbuf[PG_SHA256_DIGEST_STRING_LENGTH - 1] = '\0'; @@ -373,7 +389,10 @@ AppendStringToManifest(backup_manifest_info *manifest, char *s) Assert(manifest != NULL); if (manifest->still_checksumming) - pg_sha256_update(&manifest->manifest_ctx, (uint8 *) s, len); + { + if (pg_cryptohash_update(manifest->manifest_ctx, (uint8 *) s, len) < 0) + elog(ERROR, "failed to update checksum of backup manifest"); + } BufFileWrite(manifest->buffile, s, len); manifest->manifest_size += len; } diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c index b89df01fa7..22be7ca9d5 100644 --- a/src/backend/replication/basebackup.c +++ b/src/backend/replication/basebackup.c @@ -733,6 +733,7 @@ perform_base_backup(basebackup_options *opt) WalSndResourceCleanup(true); pgstat_progress_end_command(); + FreeBackupManifest(&manifest); } /* @@ -1094,7 +1095,9 @@ sendFileWithContent(const char *filename, const char *content, len; pg_checksum_context checksum_ctx; - pg_checksum_init(&checksum_ctx, manifest->checksum_type); + if (pg_checksum_init(&checksum_ctx, manifest->checksum_type) < 0) + elog(ERROR, "could not initialize checksum of file \"%s\"", + filename); len = strlen(content); @@ -1130,7 +1133,10 @@ sendFileWithContent(const char *filename, const char *content, update_basebackup_progress(pad); } - pg_checksum_update(&checksum_ctx, (uint8 *) content, len); + if (pg_checksum_update(&checksum_ctx, (uint8 *) content, len) < 0) + elog(ERROR, "could not update checksum of file \"%s\"", + filename); + AddFileToBackupManifest(manifest, NULL, filename, len, (pg_time_t) statbuf.st_mtime, &checksum_ctx); } @@ -1584,7 +1590,9 @@ sendFile(const char *readfilename, const char *tarfilename, bool verify_checksum = false; pg_checksum_context checksum_ctx; - pg_checksum_init(&checksum_ctx, manifest->checksum_type); + if (pg_checksum_init(&checksum_ctx, manifest->checksum_type) < 0) + elog(ERROR, "could not initialize checksum of file \"%s\"", + readfilename); fd = OpenTransientFile(readfilename, O_RDONLY | PG_BINARY); if (fd < 0) @@ -1758,7 +1766,8 @@ sendFile(const char *readfilename, const char *tarfilename, update_basebackup_progress(cnt); /* Also feed it to the checksum machinery. */ - pg_checksum_update(&checksum_ctx, (uint8 *) buf, cnt); + if (pg_checksum_update(&checksum_ctx, (uint8 *) buf, cnt) < 0) + elog(ERROR, "could not update checksum of base backup"); len += cnt; throttle(cnt); @@ -1772,7 +1781,8 @@ sendFile(const char *readfilename, const char *tarfilename, { cnt = Min(sizeof(buf), statbuf->st_size - len); pq_putmessage('d', buf, cnt); - pg_checksum_update(&checksum_ctx, (uint8 *) buf, cnt); + if (pg_checksum_update(&checksum_ctx, (uint8 *) buf, cnt) < 0) + elog(ERROR, "could not update checksum of base backup"); update_basebackup_progress(cnt); len += cnt; throttle(cnt); @@ -1780,8 +1790,8 @@ sendFile(const char *readfilename, const char *tarfilename, } /* - * Pad to a block boundary, per tar format requirements. (This small - * piece of data is probably not worth throttling, and is not checksummed + * Pad to a block boundary, per tar format requirements. (This small piece + * of data is probably not worth throttling, and is not checksummed * because it's not actually part of the file.) */ pad = tarPaddingBytesRequired(len); diff --git a/src/backend/utils/adt/cryptohashes.c b/src/backend/utils/adt/cryptohashes.c index e897660927..5de294a7fd 100644 --- a/src/backend/utils/adt/cryptohashes.c +++ b/src/backend/utils/adt/cryptohashes.c @@ -13,6 +13,7 @@ */ #include "postgres.h" +#include "common/cryptohash.h" #include "common/md5.h" #include "common/sha2.h" #include "utils/builtins.h" @@ -78,16 +79,21 @@ sha224_bytea(PG_FUNCTION_ARGS) bytea *in = PG_GETARG_BYTEA_PP(0); const uint8 *data; size_t len; - pg_sha224_ctx ctx; + pg_cryptohash_ctx *ctx; unsigned char buf[PG_SHA224_DIGEST_LENGTH]; bytea *result; len = VARSIZE_ANY_EXHDR(in); data = (unsigned char *) VARDATA_ANY(in); - pg_sha224_init(&ctx); - pg_sha224_update(&ctx, data, len); - pg_sha224_final(&ctx, buf); + ctx = pg_cryptohash_create(PG_SHA224); + if (pg_cryptohash_init(ctx) < 0) + elog(ERROR, "could not initialize %s context", "SHA224"); + if (pg_cryptohash_update(ctx, data, len) < 0) + elog(ERROR, "could not update %s context", "SHA224"); + if (pg_cryptohash_final(ctx, buf) < 0) + elog(ERROR, "could not finalize %s context", "SHA224"); + pg_cryptohash_free(ctx); result = palloc(sizeof(buf) + VARHDRSZ); SET_VARSIZE(result, sizeof(buf) + VARHDRSZ); @@ -102,16 +108,21 @@ sha256_bytea(PG_FUNCTION_ARGS) bytea *in = PG_GETARG_BYTEA_PP(0); const uint8 *data; size_t len; - pg_sha256_ctx ctx; + pg_cryptohash_ctx *ctx; unsigned char buf[PG_SHA256_DIGEST_LENGTH]; bytea *result; len = VARSIZE_ANY_EXHDR(in); data = (unsigned char *) VARDATA_ANY(in); - pg_sha256_init(&ctx); - pg_sha256_update(&ctx, data, len); - pg_sha256_final(&ctx, buf); + ctx = pg_cryptohash_create(PG_SHA256); + if (pg_cryptohash_init(ctx) < 0) + elog(ERROR, "could not initialize %s context", "SHA256"); + if (pg_cryptohash_update(ctx, data, len) < 0) + elog(ERROR, "could not update %s context", "SHA256"); + if (pg_cryptohash_final(ctx, buf) < 0) + elog(ERROR, "could not finalize %s context", "SHA256"); + pg_cryptohash_free(ctx); result = palloc(sizeof(buf) + VARHDRSZ); SET_VARSIZE(result, sizeof(buf) + VARHDRSZ); @@ -126,16 +137,21 @@ sha384_bytea(PG_FUNCTION_ARGS) bytea *in = PG_GETARG_BYTEA_PP(0); const uint8 *data; size_t len; - pg_sha384_ctx ctx; + pg_cryptohash_ctx *ctx; unsigned char buf[PG_SHA384_DIGEST_LENGTH]; bytea *result; len = VARSIZE_ANY_EXHDR(in); data = (unsigned char *) VARDATA_ANY(in); - pg_sha384_init(&ctx); - pg_sha384_update(&ctx, data, len); - pg_sha384_final(&ctx, buf); + ctx = pg_cryptohash_create(PG_SHA384); + if (pg_cryptohash_init(ctx) < 0) + elog(ERROR, "could not initialize %s context", "SHA384"); + if (pg_cryptohash_update(ctx, data, len) < 0) + elog(ERROR, "could not update %s context", "SHA384"); + if (pg_cryptohash_final(ctx, buf) < 0) + elog(ERROR, "could not finalize %s context", "SHA384"); + pg_cryptohash_free(ctx); result = palloc(sizeof(buf) + VARHDRSZ); SET_VARSIZE(result, sizeof(buf) + VARHDRSZ); @@ -150,16 +166,21 @@ sha512_bytea(PG_FUNCTION_ARGS) bytea *in = PG_GETARG_BYTEA_PP(0); const uint8 *data; size_t len; - pg_sha512_ctx ctx; + pg_cryptohash_ctx *ctx; unsigned char buf[PG_SHA512_DIGEST_LENGTH]; bytea *result; len = VARSIZE_ANY_EXHDR(in); data = (unsigned char *) VARDATA_ANY(in); - pg_sha512_init(&ctx); - pg_sha512_update(&ctx, data, len); - pg_sha512_final(&ctx, buf); + ctx = pg_cryptohash_create(PG_SHA512); + if (pg_cryptohash_init(ctx) < 0) + elog(ERROR, "could not initialize %s context", "SHA512"); + if (pg_cryptohash_update(ctx, data, len) < 0) + elog(ERROR, "could not update %s context", "SHA512"); + if (pg_cryptohash_final(ctx, buf) < 0) + elog(ERROR, "could not finalize %s context", "SHA512"); + pg_cryptohash_free(ctx); result = palloc(sizeof(buf) + VARHDRSZ); SET_VARSIZE(result, sizeof(buf) + VARHDRSZ); diff --git a/src/bin/pg_verifybackup/parse_manifest.c b/src/bin/pg_verifybackup/parse_manifest.c index 608e23538b..5b4ce28837 100644 --- a/src/bin/pg_verifybackup/parse_manifest.c +++ b/src/bin/pg_verifybackup/parse_manifest.c @@ -624,7 +624,7 @@ verify_manifest_checksum(JsonManifestParseState *parse, char *buffer, size_t number_of_newlines = 0; size_t ultimate_newline = 0; size_t penultimate_newline = 0; - pg_sha256_ctx manifest_ctx; + pg_cryptohash_ctx *manifest_ctx; uint8 manifest_checksum_actual[PG_SHA256_DIGEST_LENGTH]; uint8 manifest_checksum_expected[PG_SHA256_DIGEST_LENGTH]; @@ -652,9 +652,15 @@ verify_manifest_checksum(JsonManifestParseState *parse, char *buffer, "last line not newline-terminated"); /* Checksum the rest. */ - pg_sha256_init(&manifest_ctx); - pg_sha256_update(&manifest_ctx, (uint8 *) buffer, penultimate_newline + 1); - pg_sha256_final(&manifest_ctx, manifest_checksum_actual); + manifest_ctx = pg_cryptohash_create(PG_SHA256); + if (manifest_ctx == NULL) + context->error_cb(context, "out of memory"); + if (pg_cryptohash_init(manifest_ctx) < 0) + 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) + context->error_cb(context, "could not finalize checksum of manifest"); /* Now verify it. */ if (parse->manifest_checksum == NULL) @@ -667,6 +673,7 @@ verify_manifest_checksum(JsonManifestParseState *parse, char *buffer, if (memcmp(manifest_checksum_actual, manifest_checksum_expected, PG_SHA256_DIGEST_LENGTH) != 0) context->error_cb(context, "manifest checksum mismatch"); + pg_cryptohash_free(manifest_ctx); } /* diff --git a/src/bin/pg_verifybackup/pg_verifybackup.c b/src/bin/pg_verifybackup/pg_verifybackup.c index bb3733b57e..07320d3699 100644 --- a/src/bin/pg_verifybackup/pg_verifybackup.c +++ b/src/bin/pg_verifybackup/pg_verifybackup.c @@ -726,13 +726,26 @@ verify_file_checksum(verifier_context *context, manifest_file *m, } /* Initialize checksum context. */ - pg_checksum_init(&checksum_ctx, m->checksum_type); + if (pg_checksum_init(&checksum_ctx, m->checksum_type) < 0) + { + report_backup_error(context, "could not initialize checksum of file \"%s\"", + relpath); + return; + } /* Read the file chunk by chunk, updating the checksum as we go. */ while ((rc = read(fd, buffer, READ_CHUNK_SIZE)) > 0) { bytes_read += rc; - pg_checksum_update(&checksum_ctx, buffer, rc); + if (pg_checksum_update(&checksum_ctx, buffer, rc) < 0) + { + report_backup_error(context, "could not update checksum of file \"%s\"", + relpath); + close(fd); + return; + } + + } if (rc < 0) report_backup_error(context, "could not read file \"%s\": %m", @@ -767,6 +780,13 @@ verify_file_checksum(verifier_context *context, manifest_file *m, /* Get the final checksum. */ checksumlen = pg_checksum_final(&checksum_ctx, checksumbuf); + if (checksumlen < 0) + { + report_backup_error(context, + "could not finalize checksum of file \"%s\"", + relpath); + return; + } /* And check it against the manifest. */ if (checksumlen != m->checksum_length) diff --git a/src/common/Makefile b/src/common/Makefile index 25c55bd642..b8f5187282 100644 --- a/src/common/Makefile +++ b/src/common/Makefile @@ -82,9 +82,11 @@ OBJS_COMMON = \ ifeq ($(with_openssl),yes) OBJS_COMMON += \ protocol_openssl.o \ - sha2_openssl.o + cryptohash_openssl.o else -OBJS_COMMON += sha2.o +OBJS_COMMON += \ + cryptohash.o \ + sha2.o endif # A few files are currently only built for frontend, not server diff --git a/src/common/checksum_helper.c b/src/common/checksum_helper.c index 79a9a7447b..8e06524cd3 100644 --- a/src/common/checksum_helper.c +++ b/src/common/checksum_helper.c @@ -77,8 +77,9 @@ pg_checksum_type_name(pg_checksum_type type) /* * Initialize a checksum context for checksums of the given type. + * Returns 0 for a success, -1 for a failure. */ -void +int pg_checksum_init(pg_checksum_context *context, pg_checksum_type type) { context->type = type; @@ -92,24 +93,55 @@ pg_checksum_init(pg_checksum_context *context, pg_checksum_type type) INIT_CRC32C(context->raw_context.c_crc32c); break; case CHECKSUM_TYPE_SHA224: - pg_sha224_init(&context->raw_context.c_sha224); + context->raw_context.c_sha224 = pg_cryptohash_create(PG_SHA224); + if (context->raw_context.c_sha224 == NULL) + return -1; + if (pg_cryptohash_init(context->raw_context.c_sha224) < 0) + { + pg_cryptohash_free(context->raw_context.c_sha224); + return -1; + } break; case CHECKSUM_TYPE_SHA256: - pg_sha256_init(&context->raw_context.c_sha256); + context->raw_context.c_sha256 = pg_cryptohash_create(PG_SHA256); + if (context->raw_context.c_sha256 == NULL) + return -1; + if (pg_cryptohash_init(context->raw_context.c_sha256) < 0) + { + pg_cryptohash_free(context->raw_context.c_sha256); + return -1; + } break; case CHECKSUM_TYPE_SHA384: - pg_sha384_init(&context->raw_context.c_sha384); + context->raw_context.c_sha384 = pg_cryptohash_create(PG_SHA384); + if (context->raw_context.c_sha384 == NULL) + return -1; + if (pg_cryptohash_init(context->raw_context.c_sha384) < 0) + { + pg_cryptohash_free(context->raw_context.c_sha384); + return -1; + } break; case CHECKSUM_TYPE_SHA512: - pg_sha512_init(&context->raw_context.c_sha512); + context->raw_context.c_sha512 = pg_cryptohash_create(PG_SHA512); + if (context->raw_context.c_sha512 == NULL) + return -1; + if (pg_cryptohash_init(context->raw_context.c_sha512) < 0) + { + pg_cryptohash_free(context->raw_context.c_sha512); + return -1; + } break; } + + return 0; } /* * Update a checksum context with new data. + * Returns 0 for a success, -1 for a failure. */ -void +int pg_checksum_update(pg_checksum_context *context, const uint8 *input, size_t len) { @@ -122,25 +154,32 @@ pg_checksum_update(pg_checksum_context *context, const uint8 *input, COMP_CRC32C(context->raw_context.c_crc32c, input, len); break; case CHECKSUM_TYPE_SHA224: - pg_sha224_update(&context->raw_context.c_sha224, input, len); + if (pg_cryptohash_update(context->raw_context.c_sha224, input, len) < 0) + return -1; break; case CHECKSUM_TYPE_SHA256: - pg_sha256_update(&context->raw_context.c_sha256, input, len); + if (pg_cryptohash_update(context->raw_context.c_sha256, input, len) < 0) + return -1; break; case CHECKSUM_TYPE_SHA384: - pg_sha384_update(&context->raw_context.c_sha384, input, len); + if (pg_cryptohash_update(context->raw_context.c_sha384, input, len) < 0) + return -1; break; case CHECKSUM_TYPE_SHA512: - pg_sha512_update(&context->raw_context.c_sha512, input, len); + if (pg_cryptohash_update(context->raw_context.c_sha512, input, len) < 0) + return -1; break; } + + return 0; } /* * Finalize a checksum computation and write the result to an output buffer. * * The caller must ensure that the buffer is at least PG_CHECKSUM_MAX_LENGTH - * bytes in length. The return value is the number of bytes actually written. + * bytes in length. The return value is the number of bytes actually written, + * or -1 for a failure. */ int pg_checksum_final(pg_checksum_context *context, uint8 *output) @@ -168,19 +207,27 @@ pg_checksum_final(pg_checksum_context *context, uint8 *output) memcpy(output, &context->raw_context.c_crc32c, retval); break; case CHECKSUM_TYPE_SHA224: - pg_sha224_final(&context->raw_context.c_sha224, output); + if (pg_cryptohash_final(context->raw_context.c_sha224, output) < 0) + return -1; + pg_cryptohash_free(context->raw_context.c_sha224); retval = PG_SHA224_DIGEST_LENGTH; break; case CHECKSUM_TYPE_SHA256: - pg_sha256_final(&context->raw_context.c_sha256, output); - retval = PG_SHA256_DIGEST_LENGTH; + if (pg_cryptohash_final(context->raw_context.c_sha256, output) < 0) + return -1; + pg_cryptohash_free(context->raw_context.c_sha256); + retval = PG_SHA224_DIGEST_LENGTH; break; case CHECKSUM_TYPE_SHA384: - pg_sha384_final(&context->raw_context.c_sha384, output); + if (pg_cryptohash_final(context->raw_context.c_sha384, output) < 0) + return -1; + pg_cryptohash_free(context->raw_context.c_sha384); retval = PG_SHA384_DIGEST_LENGTH; break; case CHECKSUM_TYPE_SHA512: - pg_sha512_final(&context->raw_context.c_sha512, output); + if (pg_cryptohash_final(context->raw_context.c_sha512, output) < 0) + return -1; + pg_cryptohash_free(context->raw_context.c_sha512); retval = PG_SHA512_DIGEST_LENGTH; break; } diff --git a/src/common/cryptohash.c b/src/common/cryptohash.c new file mode 100644 index 0000000000..a61091f456 --- /dev/null +++ b/src/common/cryptohash.c @@ -0,0 +1,190 @@ +/*------------------------------------------------------------------------- + * + * cryptohash.c + * Fallback implementations for cryptographic hash functions. + * + * This is the set of in-core functions used when there are no other + * alternative options like OpenSSL. + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/common/cryptohash.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include + +#include "common/cryptohash.h" +#include "sha2_int.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 + +/* + * pg_cryptohash_create + * + * Allocate a hash context. Returns NULL on failure for an OOM. The + * backend issues an error, without returning. + */ +pg_cryptohash_ctx * +pg_cryptohash_create(pg_cryptohash_type type) +{ + pg_cryptohash_ctx *ctx; + + ctx = ALLOC(sizeof(pg_cryptohash_ctx)); + if (ctx == NULL) + return NULL; + + ctx->type = type; + + switch (type) + { + case PG_SHA224: + ctx->data = ALLOC(sizeof(pg_sha224_ctx)); + break; + case PG_SHA256: + ctx->data = ALLOC(sizeof(pg_sha256_ctx)); + break; + case PG_SHA384: + ctx->data = ALLOC(sizeof(pg_sha384_ctx)); + break; + case PG_SHA512: + ctx->data = ALLOC(sizeof(pg_sha512_ctx)); + break; + } + + if (ctx->data == NULL) + { + explicit_bzero(ctx, sizeof(pg_cryptohash_ctx)); + FREE(ctx); + return NULL; + } + + return ctx; +} + +/* + * pg_cryptohash_init + * + * Initialize a hash context. Note that this implementation is designed + * to never fail, so this always returns 0. + */ +int +pg_cryptohash_init(pg_cryptohash_ctx *ctx) +{ + if (ctx == NULL) + return 0; + + switch (ctx->type) + { + case PG_SHA224: + pg_sha224_init((pg_sha224_ctx *) ctx->data); + break; + case PG_SHA256: + pg_sha256_init((pg_sha256_ctx *) ctx->data); + break; + case PG_SHA384: + pg_sha384_init((pg_sha384_ctx *) ctx->data); + break; + case PG_SHA512: + pg_sha512_init((pg_sha512_ctx *) ctx->data); + break; + } + + return 0; +} + +/* + * pg_cryptohash_update + * + * Update a hash context. Note that this implementation is designed + * to never fail, so this always returns 0. + */ +int +pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len) +{ + if (ctx == NULL) + return 0; + + switch (ctx->type) + { + case PG_SHA224: + pg_sha224_update((pg_sha224_ctx *) ctx->data, data, len); + break; + case PG_SHA256: + pg_sha256_update((pg_sha256_ctx *) ctx->data, data, len); + break; + case PG_SHA384: + pg_sha384_update((pg_sha384_ctx *) ctx->data, data, len); + break; + case PG_SHA512: + pg_sha512_update((pg_sha512_ctx *) ctx->data, data, len); + break; + } + + return 0; +} + +/* + * pg_cryptohash_final + * + * Finalize a hash context. Note that this implementation is designed + * to never fail, so this always returns 0. + */ +int +pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest) +{ + if (ctx == NULL) + return 0; + + switch (ctx->type) + { + case PG_SHA224: + pg_sha224_final((pg_sha224_ctx *) ctx->data, dest); + break; + case PG_SHA256: + pg_sha256_final((pg_sha256_ctx *) ctx->data, dest); + break; + case PG_SHA384: + pg_sha384_final((pg_sha384_ctx *) ctx->data, dest); + break; + case PG_SHA512: + pg_sha512_final((pg_sha512_ctx *) ctx->data, dest); + break; + } + + return 0; +} + +/* + * pg_cryptohash_free + * + * Free a hash context. + */ +void +pg_cryptohash_free(pg_cryptohash_ctx *ctx) +{ + if (ctx == NULL) + return; + FREE(ctx->data); + explicit_bzero(ctx, sizeof(pg_cryptohash_ctx)); + FREE(ctx); +} diff --git a/src/common/cryptohash_openssl.c b/src/common/cryptohash_openssl.c new file mode 100644 index 0000000000..8e2c69b48b --- /dev/null +++ b/src/common/cryptohash_openssl.c @@ -0,0 +1,197 @@ +/*------------------------------------------------------------------------- + * + * cryptohash_openssl.c + * Set of wrapper routines on top of OpenSSL to support cryptographic + * hash functions. + * + * 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/cryptohash_openssl.c + * + *------------------------------------------------------------------------- + */ + +#ifndef FRONTEND +#include "postgres.h" +#else +#include "postgres_fe.h" +#endif + +#include + +#include "common/cryptohash.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 + +/* + * pg_cryptohash_create + * + * Allocate a hash context. Returns NULL on failure for an OOM. The + * backend issues an error, without returning. + */ +pg_cryptohash_ctx * +pg_cryptohash_create(pg_cryptohash_type type) +{ + pg_cryptohash_ctx *ctx; + + 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) + { + explicit_bzero(ctx, sizeof(pg_cryptohash_ctx)); + FREE(ctx); + return NULL; + } + + return ctx; +} + +/* + * pg_cryptohash_init + * + * Initialize a hash context. Returns 0 on success, and -1 on failure. + */ +int +pg_cryptohash_init(pg_cryptohash_ctx *ctx) +{ + int status = 0; + + if (ctx == NULL) + return 0; + + switch (ctx->type) + { + case PG_SHA224: + status = SHA224_Init((SHA256_CTX *) ctx->data); + break; + case PG_SHA256: + status = SHA256_Init((SHA256_CTX *) ctx->data); + break; + case PG_SHA384: + status = SHA384_Init((SHA512_CTX *) ctx->data); + break; + case PG_SHA512: + status = SHA512_Init((SHA512_CTX *) ctx->data); + break; + } + + /* OpenSSL internals return 1 on success, 0 on failure */ + if (status <= 0) + return -1; + return 0; +} + +/* + * pg_cryptohash_update + * + * Update a hash context. Returns 0 on success, and -1 on failure. + */ +int +pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len) +{ + int status; + + 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; + } + + /* OpenSSL internals return 1 on success, 0 on failure */ + if (status <= 0) + return -1; + return 0; +} + +/* + * pg_cryptohash_final + * + * Finalize a hash context. Returns 0 on success, and -1 on failure. + */ +int +pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest) +{ + int status; + + 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; + } + + /* OpenSSL internals return 1 on success, 0 on failure */ + if (status <= 0) + return -1; + return 0; +} + +/* + * pg_cryptohash_free + * + * Free a hash context. + */ +void +pg_cryptohash_free(pg_cryptohash_ctx *ctx) +{ + if (ctx == NULL) + return; + FREE(ctx->data); + explicit_bzero(ctx, sizeof(pg_cryptohash_ctx)); + FREE(ctx); +} diff --git a/src/common/scram-common.c b/src/common/scram-common.c index 4971134b22..caab68926d 100644 --- a/src/common/scram-common.c +++ b/src/common/scram-common.c @@ -29,9 +29,9 @@ /* * Calculate HMAC per RFC2104. * - * The hash function used is SHA-256. + * The hash function used is SHA-256. Returns 0 on success, -1 on failure. */ -void +int scram_HMAC_init(scram_HMAC_ctx *ctx, const uint8 *key, int keylen) { uint8 k_ipad[SHA256_HMAC_B]; @@ -44,13 +44,21 @@ scram_HMAC_init(scram_HMAC_ctx *ctx, const uint8 *key, int keylen) */ if (keylen > SHA256_HMAC_B) { - pg_sha256_ctx sha256_ctx; + pg_cryptohash_ctx *sha256_ctx; - pg_sha256_init(&sha256_ctx); - pg_sha256_update(&sha256_ctx, key, keylen); - pg_sha256_final(&sha256_ctx, keybuf); + 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) < 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); @@ -62,45 +70,75 @@ scram_HMAC_init(scram_HMAC_ctx *ctx, const uint8 *key, int keylen) 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) */ - pg_sha256_init(&ctx->sha256ctx); - pg_sha256_update(&ctx->sha256ctx, k_ipad, SHA256_HMAC_B); + 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. + * The hash function used is SHA-256. Returns 0 on success, -1 on failure. */ -void +int scram_HMAC_update(scram_HMAC_ctx *ctx, const char *str, int slen) { - pg_sha256_update(&ctx->sha256ctx, (const uint8 *) str, 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. + * The hash function used is SHA-256. Returns 0 on success, -1 on failure. */ -void +int scram_HMAC_final(uint8 *result, scram_HMAC_ctx *ctx) { uint8 h[SCRAM_KEY_LEN]; - pg_sha256_final(&ctx->sha256ctx, h); + Assert(ctx->sha256ctx != NULL); + + if (pg_cryptohash_final(ctx->sha256ctx, h) < 0) + { + pg_cryptohash_free(ctx->sha256ctx); + return -1; + } /* H(K XOR opad, tmp) */ - pg_sha256_init(&ctx->sha256ctx); - pg_sha256_update(&ctx->sha256ctx, ctx->k_opad, SHA256_HMAC_B); - pg_sha256_update(&ctx->sha256ctx, h, SCRAM_KEY_LEN); - pg_sha256_final(&ctx->sha256ctx, result); + 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_free(ctx->sha256ctx); + return -1; + } + + pg_cryptohash_free(ctx->sha256ctx); + return 0; } /* * Calculate SaltedPassword. * - * The password should already be normalized by SASLprep. + * The password should already be normalized by SASLprep. Returns 0 on + * success, -1 on failure. */ -void +int scram_SaltedPassword(const char *password, const char *salt, int saltlen, int iterations, uint8 *result) @@ -120,63 +158,94 @@ scram_SaltedPassword(const char *password, */ /* First iteration */ - scram_HMAC_init(&hmac_ctx, (uint8 *) password, password_len); - scram_HMAC_update(&hmac_ctx, salt, saltlen); - scram_HMAC_update(&hmac_ctx, (char *) &one, sizeof(uint32)); - scram_HMAC_final(Ui_prev, &hmac_ctx); + 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) + { + return -1; + } + memcpy(result, Ui_prev, SCRAM_KEY_LEN); /* Subsequent iterations */ for (i = 2; i <= iterations; i++) { - scram_HMAC_init(&hmac_ctx, (uint8 *) password, password_len); - scram_HMAC_update(&hmac_ctx, (const char *) Ui_prev, SCRAM_KEY_LEN); - scram_HMAC_final(Ui, &hmac_ctx); + 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) + { + return -1; + } + for (j = 0; j < SCRAM_KEY_LEN; j++) result[j] ^= Ui[j]; memcpy(Ui_prev, Ui, SCRAM_KEY_LEN); } + + return 0; } /* * Calculate SHA-256 hash for a NULL-terminated string. (The NULL terminator is - * not included in the hash). + * not included in the hash). Returns 0 on success, -1 on failure. */ -void +int scram_H(const uint8 *input, int len, uint8 *result) { - pg_sha256_ctx ctx; + pg_cryptohash_ctx *ctx; - pg_sha256_init(&ctx); - pg_sha256_update(&ctx, input, len); - pg_sha256_final(&ctx, result); + ctx = pg_cryptohash_create(PG_SHA256); + if (ctx == NULL) + return -1; + + if (pg_cryptohash_init(ctx) < 0 || + pg_cryptohash_update(ctx, input, len) < 0 || + pg_cryptohash_final(ctx, result) < 0) + { + pg_cryptohash_free(ctx); + return -1; + } + + pg_cryptohash_free(ctx); + return 0; } /* - * Calculate ClientKey. + * Calculate ClientKey. Returns 0 on success, -1 on failure. */ -void +int scram_ClientKey(const uint8 *salted_password, uint8 *result) { scram_HMAC_ctx ctx; - scram_HMAC_init(&ctx, salted_password, SCRAM_KEY_LEN); - scram_HMAC_update(&ctx, "Client Key", strlen("Client Key")); - scram_HMAC_final(result, &ctx); + 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) + { + return -1; + } + + return 0; } /* - * Calculate ServerKey. + * Calculate ServerKey. Returns 0 on success, -1 on failure. */ -void +int scram_ServerKey(const uint8 *salted_password, uint8 *result) { scram_HMAC_ctx ctx; - scram_HMAC_init(&ctx, salted_password, SCRAM_KEY_LEN); - scram_HMAC_update(&ctx, "Server Key", strlen("Server Key")); - scram_HMAC_final(result, &ctx); + 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) + { + return -1; + } + + return 0; } @@ -207,12 +276,18 @@ scram_build_secret(const char *salt, int saltlen, int iterations, iterations = SCRAM_DEFAULT_ITERATIONS; /* Calculate StoredKey and ServerKey */ - scram_SaltedPassword(password, salt, saltlen, iterations, - salted_password); - scram_ClientKey(salted_password, stored_key); - scram_H(stored_key, SCRAM_KEY_LEN, stored_key); - - scram_ServerKey(salted_password, server_key); + if (scram_SaltedPassword(password, salt, saltlen, iterations, + salted_password) < 0 || + scram_ClientKey(salted_password, stored_key) < 0 || + scram_H(stored_key, SCRAM_KEY_LEN, stored_key) < 0 || + scram_ServerKey(salted_password, server_key) < 0) + { +#ifdef FRONTEND + return NULL; +#else + elog(ERROR, "could not calculate stored key and server key"); +#endif + } /*---------- * The format is: diff --git a/src/common/sha2.c b/src/common/sha2.c index 0d329bb238..1a462accc5 100644 --- a/src/common/sha2.c +++ b/src/common/sha2.c @@ -1,12 +1,13 @@ /*------------------------------------------------------------------------- * * sha2.c - * Set of SHA functions for SHA-224, SHA-256, SHA-384 and SHA-512. + * SHA functions for SHA-224, SHA-256, SHA-384 and SHA-512. * - * This is the set of in-core functions used when there are no other - * alternative options like OpenSSL. + * This includes the fallback implementation for SHA2 cryptographic + * hashes. * - * Portions Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION * src/common/sha2.c @@ -56,9 +57,19 @@ #include "postgres_fe.h" #endif -#include +#include "sha2_int.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 /* * UNROLLED TRANSFORM LOOP NOTE: diff --git a/src/common/sha2_int.h b/src/common/sha2_int.h new file mode 100644 index 0000000000..96db773f96 --- /dev/null +++ b/src/common/sha2_int.h @@ -0,0 +1,91 @@ +/*------------------------------------------------------------------------- + * + * sha2_int.h + * Internal headers for fallback implementation of SHA{224,256,384,512} + * + * Portions Copyright (c) 2016-2020, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/common/sha2_int.h + * + *------------------------------------------------------------------------- + */ + +/* $OpenBSD: sha2.h,v 1.2 2004/04/28 23:11:57 millert Exp $ */ + +/* + * FILE: sha2.h + * AUTHOR: Aaron D. Gifford + * + * Copyright (c) 2000-2001, Aaron D. Gifford + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $From: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $ + */ + +#ifndef PG_SHA2_INT_H +#define PG_SHA2_INT_H + +#include "common/sha2.h" + +typedef struct pg_sha256_ctx +{ + uint32 state[8]; + uint64 bitcount; + uint8 buffer[PG_SHA256_BLOCK_LENGTH]; +} pg_sha256_ctx; +typedef struct pg_sha512_ctx +{ + uint64 state[8]; + uint64 bitcount[2]; + uint8 buffer[PG_SHA512_BLOCK_LENGTH]; +} pg_sha512_ctx; +typedef struct pg_sha256_ctx pg_sha224_ctx; +typedef struct pg_sha512_ctx pg_sha384_ctx; + +/* Interface routines for SHA224/256/384/512 */ +extern void pg_sha224_init(pg_sha224_ctx *ctx); +extern void pg_sha224_update(pg_sha224_ctx *ctx, const uint8 *input0, + size_t len); +extern void pg_sha224_final(pg_sha224_ctx *ctx, uint8 *dest); + +extern void pg_sha256_init(pg_sha256_ctx *ctx); +extern void pg_sha256_update(pg_sha256_ctx *ctx, const uint8 *input0, + size_t len); +extern void pg_sha256_final(pg_sha256_ctx *ctx, uint8 *dest); + +extern void pg_sha384_init(pg_sha384_ctx *ctx); +extern void pg_sha384_update(pg_sha384_ctx *ctx, + const uint8 *, size_t len); +extern void pg_sha384_final(pg_sha384_ctx *ctx, uint8 *dest); + +extern void pg_sha512_init(pg_sha512_ctx *ctx); +extern void pg_sha512_update(pg_sha512_ctx *ctx, const uint8 *input0, + size_t len); +extern void pg_sha512_final(pg_sha512_ctx *ctx, uint8 *dest); + +#endif /* PG_SHA2_INT_H */ diff --git a/src/common/sha2_openssl.c b/src/common/sha2_openssl.c deleted file mode 100644 index 41673b3a88..0000000000 --- a/src/common/sha2_openssl.c +++ /dev/null @@ -1,102 +0,0 @@ -/*------------------------------------------------------------------------- - * - * sha2_openssl.c - * Set of wrapper routines on top of OpenSSL to support SHA-224 - * SHA-256, SHA-384 and SHA-512 functions. - * - * This should only be used if code is compiled with OpenSSL support. - * - * Portions Copyright (c) 2016-2020, PostgreSQL Global Development Group - * - * IDENTIFICATION - * src/common/sha2_openssl.c - * - *------------------------------------------------------------------------- - */ - -#ifndef FRONTEND -#include "postgres.h" -#else -#include "postgres_fe.h" -#endif - -#include - -#include "common/sha2.h" - - -/* Interface routines for SHA-256 */ -void -pg_sha256_init(pg_sha256_ctx *ctx) -{ - SHA256_Init((SHA256_CTX *) ctx); -} - -void -pg_sha256_update(pg_sha256_ctx *ctx, const uint8 *data, size_t len) -{ - SHA256_Update((SHA256_CTX *) ctx, data, len); -} - -void -pg_sha256_final(pg_sha256_ctx *ctx, uint8 *dest) -{ - SHA256_Final(dest, (SHA256_CTX *) ctx); -} - -/* Interface routines for SHA-512 */ -void -pg_sha512_init(pg_sha512_ctx *ctx) -{ - SHA512_Init((SHA512_CTX *) ctx); -} - -void -pg_sha512_update(pg_sha512_ctx *ctx, const uint8 *data, size_t len) -{ - SHA512_Update((SHA512_CTX *) ctx, data, len); -} - -void -pg_sha512_final(pg_sha512_ctx *ctx, uint8 *dest) -{ - SHA512_Final(dest, (SHA512_CTX *) ctx); -} - -/* Interface routines for SHA-384 */ -void -pg_sha384_init(pg_sha384_ctx *ctx) -{ - SHA384_Init((SHA512_CTX *) ctx); -} - -void -pg_sha384_update(pg_sha384_ctx *ctx, const uint8 *data, size_t len) -{ - SHA384_Update((SHA512_CTX *) ctx, data, len); -} - -void -pg_sha384_final(pg_sha384_ctx *ctx, uint8 *dest) -{ - SHA384_Final(dest, (SHA512_CTX *) ctx); -} - -/* Interface routines for SHA-224 */ -void -pg_sha224_init(pg_sha224_ctx *ctx) -{ - SHA224_Init((SHA256_CTX *) ctx); -} - -void -pg_sha224_update(pg_sha224_ctx *ctx, const uint8 *data, size_t len) -{ - SHA224_Update((SHA256_CTX *) ctx, data, len); -} - -void -pg_sha224_final(pg_sha224_ctx *ctx, uint8 *dest) -{ - SHA224_Final(dest, (SHA256_CTX *) ctx); -} diff --git a/src/include/common/checksum_helper.h b/src/include/common/checksum_helper.h index 48b0745dad..b07a34e7e4 100644 --- a/src/include/common/checksum_helper.h +++ b/src/include/common/checksum_helper.h @@ -14,6 +14,7 @@ #ifndef CHECKSUM_HELPER_H #define CHECKSUM_HELPER_H +#include "common/cryptohash.h" #include "common/sha2.h" #include "port/pg_crc32c.h" @@ -41,10 +42,10 @@ typedef enum pg_checksum_type typedef union pg_checksum_raw_context { pg_crc32c c_crc32c; - pg_sha224_ctx c_sha224; - pg_sha256_ctx c_sha256; - pg_sha384_ctx c_sha384; - pg_sha512_ctx c_sha512; + pg_cryptohash_ctx *c_sha224; + pg_cryptohash_ctx *c_sha256; + pg_cryptohash_ctx *c_sha384; + pg_cryptohash_ctx *c_sha512; } pg_checksum_raw_context; /* @@ -66,8 +67,8 @@ typedef struct pg_checksum_context extern bool pg_checksum_parse_type(char *name, pg_checksum_type *); extern char *pg_checksum_type_name(pg_checksum_type); -extern void pg_checksum_init(pg_checksum_context *, pg_checksum_type); -extern void pg_checksum_update(pg_checksum_context *, const uint8 *input, +extern int pg_checksum_init(pg_checksum_context *, pg_checksum_type); +extern int pg_checksum_update(pg_checksum_context *, const uint8 *input, size_t len); extern int pg_checksum_final(pg_checksum_context *, uint8 *output); diff --git a/src/include/common/cryptohash.h b/src/include/common/cryptohash.h new file mode 100644 index 0000000000..0e4a6631a3 --- /dev/null +++ b/src/include/common/cryptohash.h @@ -0,0 +1,40 @@ +/*------------------------------------------------------------------------- + * + * cryptohash.h + * Generic headers for cryptographic hash functions. + * + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/common/cryptohash.h + * + *------------------------------------------------------------------------- + */ + +#ifndef PG_CRYPTOHASH_H +#define PG_CRYPTOHASH_H + +/* Context Structures for each hash function */ +typedef enum +{ + PG_SHA224 = 0, + PG_SHA256, + PG_SHA384, + PG_SHA512 +} pg_cryptohash_type; + +typedef struct pg_cryptohash_ctx +{ + pg_cryptohash_type type; + /* private area used by each hash implementation */ + void *data; +} 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 void pg_cryptohash_free(pg_cryptohash_ctx *ctx); + +#endif /* PG_CRYPTOHASH_H */ diff --git a/src/include/common/scram-common.h b/src/include/common/scram-common.h index 2edae2dd3c..f4a7c60725 100644 --- a/src/include/common/scram-common.h +++ b/src/include/common/scram-common.h @@ -13,6 +13,7 @@ #ifndef SCRAM_COMMON_H #define SCRAM_COMMON_H +#include "common/cryptohash.h" #include "common/sha2.h" /* Name of SCRAM mechanisms per IANA */ @@ -50,19 +51,19 @@ */ typedef struct { - pg_sha256_ctx sha256ctx; + pg_cryptohash_ctx *sha256ctx; uint8 k_opad[SHA256_HMAC_B]; } scram_HMAC_ctx; -extern void scram_HMAC_init(scram_HMAC_ctx *ctx, const uint8 *key, int keylen); -extern void scram_HMAC_update(scram_HMAC_ctx *ctx, const char *str, int slen); -extern void scram_HMAC_final(uint8 *result, scram_HMAC_ctx *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 void scram_SaltedPassword(const char *password, const char *salt, +extern int scram_SaltedPassword(const char *password, const char *salt, int saltlen, int iterations, uint8 *result); -extern void scram_H(const uint8 *str, int len, uint8 *result); -extern void scram_ClientKey(const uint8 *salted_password, uint8 *result); -extern void scram_ServerKey(const uint8 *salted_password, uint8 *result); +extern int scram_H(const uint8 *str, int len, uint8 *result); +extern int scram_ClientKey(const uint8 *salted_password, uint8 *result); +extern int scram_ServerKey(const uint8 *salted_password, uint8 *result); extern char *scram_build_secret(const char *salt, int saltlen, int iterations, const char *password); diff --git a/src/include/common/sha2.h b/src/include/common/sha2.h index 9c4abf777d..c8b9096043 100644 --- a/src/include/common/sha2.h +++ b/src/include/common/sha2.h @@ -1,9 +1,10 @@ /*------------------------------------------------------------------------- * * sha2.h - * Generic headers for SHA224, 256, 384 AND 512 functions of PostgreSQL. + * Constants related to SHA224, 256, 384 AND 512. * - * Portions Copyright (c) 2016-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION * src/include/common/sha2.h @@ -11,49 +12,9 @@ *------------------------------------------------------------------------- */ -/* $OpenBSD: sha2.h,v 1.2 2004/04/28 23:11:57 millert Exp $ */ - -/* - * FILE: sha2.h - * AUTHOR: Aaron D. Gifford - * - * Copyright (c) 2000-2001, Aaron D. Gifford - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the copyright holder nor the names of contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTOR(S) ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTOR(S) BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $From: sha2.h,v 1.1 2001/11/08 00:02:01 adg Exp adg $ - */ - #ifndef _PG_SHA2_H_ #define _PG_SHA2_H_ -#ifdef USE_OPENSSL -#include -#endif - /*** SHA224/256/384/512 Various Length Definitions ***********************/ #define PG_SHA224_BLOCK_LENGTH 64 #define PG_SHA224_DIGEST_LENGTH 28 @@ -68,48 +29,4 @@ #define PG_SHA512_DIGEST_LENGTH 64 #define PG_SHA512_DIGEST_STRING_LENGTH (PG_SHA512_DIGEST_LENGTH * 2 + 1) -/* Context Structures for SHA224/256/384/512 */ -#ifdef USE_OPENSSL -typedef SHA256_CTX pg_sha256_ctx; -typedef SHA512_CTX pg_sha512_ctx; -typedef SHA256_CTX pg_sha224_ctx; -typedef SHA512_CTX pg_sha384_ctx; -#else -typedef struct pg_sha256_ctx -{ - uint32 state[8]; - uint64 bitcount; - uint8 buffer[PG_SHA256_BLOCK_LENGTH]; -} pg_sha256_ctx; -typedef struct pg_sha512_ctx -{ - uint64 state[8]; - uint64 bitcount[2]; - uint8 buffer[PG_SHA512_BLOCK_LENGTH]; -} pg_sha512_ctx; -typedef struct pg_sha256_ctx pg_sha224_ctx; -typedef struct pg_sha512_ctx pg_sha384_ctx; -#endif /* USE_OPENSSL */ - -/* Interface routines for SHA224/256/384/512 */ -extern void pg_sha224_init(pg_sha224_ctx *ctx); -extern void pg_sha224_update(pg_sha224_ctx *ctx, const uint8 *input0, - size_t len); -extern void pg_sha224_final(pg_sha224_ctx *ctx, uint8 *dest); - -extern void pg_sha256_init(pg_sha256_ctx *ctx); -extern void pg_sha256_update(pg_sha256_ctx *ctx, const uint8 *input0, - size_t len); -extern void pg_sha256_final(pg_sha256_ctx *ctx, uint8 *dest); - -extern void pg_sha384_init(pg_sha384_ctx *ctx); -extern void pg_sha384_update(pg_sha384_ctx *ctx, - const uint8 *, size_t len); -extern void pg_sha384_final(pg_sha384_ctx *ctx, uint8 *dest); - -extern void pg_sha512_init(pg_sha512_ctx *ctx); -extern void pg_sha512_update(pg_sha512_ctx *ctx, const uint8 *input0, - size_t len); -extern void pg_sha512_final(pg_sha512_ctx *ctx, uint8 *dest); - #endif /* _PG_SHA2_H_ */ diff --git a/src/include/replication/backup_manifest.h b/src/include/replication/backup_manifest.h index fb1291cbe4..e7c4047497 100644 --- a/src/include/replication/backup_manifest.h +++ b/src/include/replication/backup_manifest.h @@ -28,7 +28,7 @@ typedef struct backup_manifest_info { BufFile *buffile; pg_checksum_type checksum_type; - pg_sha256_ctx manifest_ctx; + pg_cryptohash_ctx *manifest_ctx; uint64 manifest_size; bool force_encode; bool first_file; @@ -48,5 +48,6 @@ extern void AddWALInfoToBackupManifest(backup_manifest_info *manifest, TimeLineID starttli, XLogRecPtr endptr, TimeLineID endtli); extern void SendBackupManifest(backup_manifest_info *manifest); +extern void FreeBackupManifest(backup_manifest_info *manifest); #endif diff --git a/src/interfaces/libpq/fe-auth-scram.c b/src/interfaces/libpq/fe-auth-scram.c index 6d266e9796..6dcf574f62 100644 --- a/src/interfaces/libpq/fe-auth-scram.c +++ b/src/interfaces/libpq/fe-auth-scram.c @@ -63,8 +63,8 @@ static bool read_server_first_message(fe_scram_state *state, char *input); static bool read_server_final_message(fe_scram_state *state, char *input); static char *build_client_first_message(fe_scram_state *state); static char *build_client_final_message(fe_scram_state *state); -static bool verify_server_signature(fe_scram_state *state); -static void calculate_client_proof(fe_scram_state *state, +static bool verify_server_signature(fe_scram_state *state, bool *match); +static bool calculate_client_proof(fe_scram_state *state, const char *client_final_message_without_proof, uint8 *result); @@ -256,11 +256,15 @@ pg_fe_scram_exchange(void *opaq, char *input, int inputlen, * Verify server signature, to make sure we're talking to the * genuine server. */ - if (verify_server_signature(state)) - *success = true; - else + if (!verify_server_signature(state, success)) + { + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("could not verify server signature\n")); + goto error; + } + + if (!*success) { - *success = false; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("incorrect server signature\n")); } @@ -544,9 +548,15 @@ build_client_final_message(fe_scram_state *state) goto oom_error; /* Append proof to it, to form client-final-message. */ - calculate_client_proof(state, - state->client_final_message_without_proof, - client_proof); + if (!calculate_client_proof(state, + state->client_final_message_without_proof, + client_proof)) + { + termPQExpBuffer(&buf); + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("could not calculate client proof\n")); + return NULL; + } appendPQExpBufferStr(&buf, ",p="); encoded_len = pg_b64_enc_len(SCRAM_KEY_LEN); @@ -745,9 +755,9 @@ read_server_final_message(fe_scram_state *state, char *input) /* * Calculate the client proof, part of the final exchange message sent - * by the client. + * by the client. Returns true on success, false on failure. */ -static void +static bool calculate_client_proof(fe_scram_state *state, const char *client_final_message_without_proof, uint8 *result) @@ -762,60 +772,70 @@ calculate_client_proof(fe_scram_state *state, * Calculate SaltedPassword, and store it in 'state' so that we can reuse * it later in verify_server_signature. */ - scram_SaltedPassword(state->password, state->salt, state->saltlen, - state->iterations, state->SaltedPassword); - - scram_ClientKey(state->SaltedPassword, ClientKey); - scram_H(ClientKey, SCRAM_KEY_LEN, StoredKey); - - scram_HMAC_init(&ctx, StoredKey, SCRAM_KEY_LEN); - scram_HMAC_update(&ctx, - state->client_first_message_bare, - strlen(state->client_first_message_bare)); - scram_HMAC_update(&ctx, ",", 1); - scram_HMAC_update(&ctx, - state->server_first_message, - strlen(state->server_first_message)); - scram_HMAC_update(&ctx, ",", 1); - scram_HMAC_update(&ctx, - client_final_message_without_proof, - strlen(client_final_message_without_proof)); - scram_HMAC_final(ClientSignature, &ctx); + if (scram_SaltedPassword(state->password, state->salt, state->saltlen, + 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) + { + return false; + } for (i = 0; i < SCRAM_KEY_LEN; i++) result[i] = ClientKey[i] ^ ClientSignature[i]; + + return true; } /* * Validate the server signature, received as part of the final exchange - * message received from the server. + * message received from the server. *match tracks if the server signature + * matched or not. Returns true if the server signature got verified, and + * false for a processing error. */ static bool -verify_server_signature(fe_scram_state *state) +verify_server_signature(fe_scram_state *state, bool *match) { uint8 expected_ServerSignature[SCRAM_KEY_LEN]; uint8 ServerKey[SCRAM_KEY_LEN]; scram_HMAC_ctx ctx; - scram_ServerKey(state->SaltedPassword, ServerKey); - + if (scram_ServerKey(state->SaltedPassword, ServerKey) < 0 || /* calculate ServerSignature */ - scram_HMAC_init(&ctx, ServerKey, SCRAM_KEY_LEN); - scram_HMAC_update(&ctx, - state->client_first_message_bare, - strlen(state->client_first_message_bare)); - scram_HMAC_update(&ctx, ",", 1); - scram_HMAC_update(&ctx, - state->server_first_message, - strlen(state->server_first_message)); - scram_HMAC_update(&ctx, ",", 1); - scram_HMAC_update(&ctx, - state->client_final_message_without_proof, - strlen(state->client_final_message_without_proof)); - scram_HMAC_final(expected_ServerSignature, &ctx); - - if (memcmp(expected_ServerSignature, state->ServerSignature, SCRAM_KEY_LEN) != 0) + 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) + { return false; + } + + /* signature processed, so now check after it */ + if (memcmp(expected_ServerSignature, state->ServerSignature, SCRAM_KEY_LEN) != 0) + *match = false; + else + *match = true; return true; } diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index 90594bd41b..720b55142b 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -129,11 +129,12 @@ sub mkvcbuild if ($solution->{options}->{openssl}) { - push(@pgcommonallfiles, 'sha2_openssl.c'); + push(@pgcommonallfiles, 'cryptohash_openssl.c'); push(@pgcommonallfiles, 'protocol_openssl.c'); } else { + push(@pgcommonallfiles, 'cryptohash.c'); push(@pgcommonallfiles, 'sha2.c'); } diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index b8ca8cffd9..04464c2e76 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -3179,6 +3179,8 @@ pg_conn_host_type pg_conv_map pg_crc32 pg_crc32c +pg_cryptohash_ctx +pg_cryptohash_type pg_ctype_cache pg_enc pg_enc2gettext