diff options
author | Peter Eisentraut <peter@eisentraut.org> | 2025-01-15 17:55:18 +0100 |
---|---|---|
committer | Peter Eisentraut <peter@eisentraut.org> | 2025-01-15 17:58:05 +0100 |
commit | 761c79508e7fbc33c1b11754bdde4bd03ce9cbb3 (patch) | |
tree | 5b76973b71b307fbdc2cd3989edee4dd44e56064 /src/interfaces/libpq/fe-auth-scram.c | |
parent | b6463ea6ef3e46b32be96a23f3a9f47357847ce4 (diff) | |
download | postgresql-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.c | 83 |
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 */ |