aboutsummaryrefslogtreecommitdiff
path: root/src/interfaces/libpq/fe-auth-scram.c
diff options
context:
space:
mode:
authorPeter Eisentraut <peter@eisentraut.org>2025-01-15 17:55:18 +0100
committerPeter Eisentraut <peter@eisentraut.org>2025-01-15 17:58:05 +0100
commit761c79508e7fbc33c1b11754bdde4bd03ce9cbb3 (patch)
tree5b76973b71b307fbdc2cd3989edee4dd44e56064 /src/interfaces/libpq/fe-auth-scram.c
parentb6463ea6ef3e46b32be96a23f3a9f47357847ce4 (diff)
downloadpostgresql-761c79508e7fbc33c1b11754bdde4bd03ce9cbb3.tar.gz
postgresql-761c79508e7fbc33c1b11754bdde4bd03ce9cbb3.zip
postgres_fdw: SCRAM authentication pass-through
This enables SCRAM authentication for postgres_fdw when connecting to a foreign server without having to store a plain-text password on user mapping options. This is done by saving the SCRAM ClientKey and ServeryKey from the client authentication and using those instead of the plain-text password for the server-side SCRAM exchange. The new foreign-server or user-mapping option "use_scram_passthrough" enables this. Co-authored-by: Matheus Alcantara <mths.dev@pm.me> Co-authored-by: Peter Eisentraut <peter@eisentraut.org> Discussion: https://www.postgresql.org/message-id/flat/27b29a35-9b96-46a9-bc1a-914140869dac@gmail.com
Diffstat (limited to 'src/interfaces/libpq/fe-auth-scram.c')
-rw-r--r--src/interfaces/libpq/fe-auth-scram.c83
1 files changed, 52 insertions, 31 deletions
diff --git a/src/interfaces/libpq/fe-auth-scram.c b/src/interfaces/libpq/fe-auth-scram.c
index 59bf87d2213..557e9c568b6 100644
--- a/src/interfaces/libpq/fe-auth-scram.c
+++ b/src/interfaces/libpq/fe-auth-scram.c
@@ -119,25 +119,28 @@ scram_init(PGconn *conn,
return NULL;
}
- /* Normalize the password with SASLprep, if possible */
- rc = pg_saslprep(password, &prep_password);
- if (rc == SASLPREP_OOM)
- {
- free(state->sasl_mechanism);
- free(state);
- return NULL;
- }
- if (rc != SASLPREP_SUCCESS)
+ if (password)
{
- prep_password = strdup(password);
- if (!prep_password)
+ /* Normalize the password with SASLprep, if possible */
+ rc = pg_saslprep(password, &prep_password);
+ if (rc == SASLPREP_OOM)
{
free(state->sasl_mechanism);
free(state);
return NULL;
}
+ if (rc != SASLPREP_SUCCESS)
+ {
+ prep_password = strdup(password);
+ if (!prep_password)
+ {
+ free(state->sasl_mechanism);
+ free(state);
+ return NULL;
+ }
+ }
+ state->password = prep_password;
}
- state->password = prep_password;
return state;
}
@@ -775,20 +778,31 @@ calculate_client_proof(fe_scram_state *state,
return false;
}
- /*
- * Calculate SaltedPassword, and store it in 'state' so that we can reuse
- * it later in verify_server_signature.
- */
- if (scram_SaltedPassword(state->password, state->hash_type,
- state->key_length, state->salt, state->saltlen,
- state->iterations, state->SaltedPassword,
- errstr) < 0 ||
- scram_ClientKey(state->SaltedPassword, state->hash_type,
- state->key_length, ClientKey, errstr) < 0 ||
- scram_H(ClientKey, state->hash_type, state->key_length,
- StoredKey, errstr) < 0)
- {
- /* errstr is already filled here */
+ if (state->conn->scram_client_key_binary)
+ {
+ memcpy(ClientKey, state->conn->scram_client_key_binary, SCRAM_MAX_KEY_LEN);
+ }
+ else
+ {
+ /*
+ * Calculate SaltedPassword, and store it in 'state' so that we can
+ * reuse it later in verify_server_signature.
+ */
+ if (scram_SaltedPassword(state->password, state->hash_type,
+ state->key_length, state->salt, state->saltlen,
+ state->iterations, state->SaltedPassword,
+ errstr) < 0 ||
+ scram_ClientKey(state->SaltedPassword, state->hash_type,
+ state->key_length, ClientKey, errstr) < 0)
+ {
+ /* errstr is already filled here */
+ pg_hmac_free(ctx);
+ return false;
+ }
+ }
+
+ if (scram_H(ClientKey, state->hash_type, state->key_length, StoredKey, errstr) < 0)
+ {
pg_hmac_free(ctx);
return false;
}
@@ -841,12 +855,19 @@ verify_server_signature(fe_scram_state *state, bool *match,
return false;
}
- if (scram_ServerKey(state->SaltedPassword, state->hash_type,
- state->key_length, ServerKey, errstr) < 0)
+ if (state->conn->scram_server_key_binary)
{
- /* errstr is filled already */
- pg_hmac_free(ctx);
- return false;
+ memcpy(ServerKey, state->conn->scram_server_key_binary, SCRAM_MAX_KEY_LEN);
+ }
+ else
+ {
+ if (scram_ServerKey(state->SaltedPassword, state->hash_type,
+ state->key_length, ServerKey, errstr) < 0)
+ {
+ /* errstr is filled already */
+ pg_hmac_free(ctx);
+ return false;
+ }
}
/* calculate ServerSignature */