aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/libpq/auth-scram.c113
-rw-r--r--src/backend/replication/backup_manifest.c25
-rw-r--r--src/backend/replication/basebackup.c24
-rw-r--r--src/backend/utils/adt/cryptohashes.c53
-rw-r--r--src/bin/pg_verifybackup/parse_manifest.c15
-rw-r--r--src/bin/pg_verifybackup/pg_verifybackup.c24
-rw-r--r--src/common/Makefile6
-rw-r--r--src/common/checksum_helper.c79
-rw-r--r--src/common/cryptohash.c190
-rw-r--r--src/common/cryptohash_openssl.c197
-rw-r--r--src/common/scram-common.c175
-rw-r--r--src/common/sha2.c23
-rw-r--r--src/common/sha2_int.h91
-rw-r--r--src/common/sha2_openssl.c102
-rw-r--r--src/include/common/checksum_helper.h13
-rw-r--r--src/include/common/cryptohash.h40
-rw-r--r--src/include/common/scram-common.h17
-rw-r--r--src/include/common/sha2.h89
-rw-r--r--src/include/replication/backup_manifest.h3
-rw-r--r--src/interfaces/libpq/fe-auth-scram.c116
-rw-r--r--src/tools/msvc/Mkvcbuild.pm3
-rw-r--r--src/tools/pgindent/typedefs.list2
22 files changed, 998 insertions, 402 deletions
diff --git a/src/backend/libpq/auth-scram.c b/src/backend/libpq/auth-scram.c
index 0f79b28bb5a..6879a816183 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 bab5e2f53b0..c3f339c5563 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);
@@ -80,6 +82,16 @@ InitializeBackupManifest(backup_manifest_info *manifest,
}
/*
+ * 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.
*/
void
@@ -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 b89df01fa76..22be7ca9d5f 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 e897660927f..5de294a7fda 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 608e23538ba..5b4ce288371 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 bb3733b57e2..07320d36997 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 25c55bd6423..b8f51872826 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 79a9a7447b3..8e06524cd3c 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 00000000000..a61091f456e
--- /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 <sys/param.h>
+
+#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 00000000000..8e2c69b48bb
--- /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 <openssl/sha.h>
+
+#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 4971134b22a..caab68926d2 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_sha256_init(&sha256_ctx);
- pg_sha256_update(&sha256_ctx, key, keylen);
- pg_sha256_final(&sha256_ctx, keybuf);
+ pg_cryptohash_ctx *sha256_ctx;
+
+ sha256_ctx = pg_cryptohash_create(PG_SHA256);
+ if (sha256_ctx == NULL)
+ return -1;
+ if (pg_cryptohash_init(sha256_ctx) < 0 ||
+ pg_cryptohash_update(sha256_ctx, key, keylen) < 0 ||
+ pg_cryptohash_final(sha256_ctx, keybuf) < 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 0d329bb2389..1a462accc51 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 <sys/param.h>
+#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 00000000000..96db773f969
--- /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 <me@aarongifford.com>
+ *
+ * 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 41673b3a888..00000000000
--- 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 <openssl/sha.h>
-
-#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 48b0745dadd..b07a34e7e49 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 00000000000..0e4a6631a38
--- /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 2edae2dd3c0..f4a7c60725b 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 9c4abf777d4..c8b9096043f 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 <me@aarongifford.com>
- *
- * 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 <openssl/sha.h>
-#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 fb1291cbe4d..e7c40474972 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 6d266e97965..6dcf574f62f 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);
+ 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)
- return false;
+ *match = false;
+ else
+ *match = true;
return true;
}
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 90594bd41ba..720b55142b3 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 b8ca8cffd91..04464c2e768 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