mirror of
https://github.com/postgres/postgres.git
synced 2025-07-02 09:02:37 +03:00
Remove hardcoded dependency to cryptohash type in the internals of SCRAM
SCRAM_KEY_LEN was a variable used in the internal routines of SCRAM to size a set of fixed-sized arrays used in the SHA and HMAC computations during the SASL exchange or when building a SCRAM password. This had a hard dependency on SHA-256, reducing the flexibility of SCRAM when it comes to the addition of more hash methods. A second issue was that SHA-256 is assumed as the cryptohash method to use all the time. This commit renames SCRAM_KEY_LEN to a more generic SCRAM_KEY_MAX_LEN, which is used as the size of the buffers used by the internal routines of SCRAM. This is aimed at tracking centrally the maximum size necessary for all the hash methods supported by SCRAM. A global variable has the advantage of keeping the code in its simplest form, reducing the need of more alloc/free logic for all the buffers used in the hash calculations. A second change is that the key length (SHA digest length) and hash types are now tracked by the state data in the backend and the frontend, the common portions being extended to handle these as arguments by the internal routines of SCRAM. There are a few RFC proposals floating around to extend the SCRAM protocol, including some to use stronger cryptohash algorithms, so this lifts some of the existing restrictions in the code. The code in charge of parsing and building SCRAM secrets is extended to rely on the key length and on the cryptohash type used for the exchange, assuming currently that only SHA-256 is supported for the moment. Note that the mock authentication simply enforces SHA-256. Author: Michael Paquier Reviewed-by: Peter Eisentraut, Jonathan Katz Discussion: https://postgr.es/m/Y5k3Qiweo/1g9CG6@paquier.xyz
This commit is contained in:
@ -58,8 +58,12 @@ typedef struct
|
||||
char *password;
|
||||
char *sasl_mechanism;
|
||||
|
||||
/* State data depending on the hash type */
|
||||
pg_cryptohash_type hash_type;
|
||||
int key_length;
|
||||
|
||||
/* We construct these */
|
||||
uint8 SaltedPassword[SCRAM_KEY_LEN];
|
||||
uint8 SaltedPassword[SCRAM_MAX_KEY_LEN];
|
||||
char *client_nonce;
|
||||
char *client_first_message_bare;
|
||||
char *client_final_message_without_proof;
|
||||
@ -73,7 +77,7 @@ typedef struct
|
||||
|
||||
/* These come from the server-final message */
|
||||
char *server_final_message;
|
||||
char ServerSignature[SCRAM_KEY_LEN];
|
||||
char ServerSignature[SCRAM_MAX_KEY_LEN];
|
||||
} fe_scram_state;
|
||||
|
||||
static bool read_server_first_message(fe_scram_state *state, char *input);
|
||||
@ -106,8 +110,10 @@ scram_init(PGconn *conn,
|
||||
memset(state, 0, sizeof(fe_scram_state));
|
||||
state->conn = conn;
|
||||
state->state = FE_SCRAM_INIT;
|
||||
state->sasl_mechanism = strdup(sasl_mechanism);
|
||||
state->key_length = SCRAM_SHA_256_KEY_LEN;
|
||||
state->hash_type = PG_SHA256;
|
||||
|
||||
state->sasl_mechanism = strdup(sasl_mechanism);
|
||||
if (!state->sasl_mechanism)
|
||||
{
|
||||
free(state);
|
||||
@ -450,7 +456,7 @@ build_client_final_message(fe_scram_state *state)
|
||||
{
|
||||
PQExpBufferData buf;
|
||||
PGconn *conn = state->conn;
|
||||
uint8 client_proof[SCRAM_KEY_LEN];
|
||||
uint8 client_proof[SCRAM_MAX_KEY_LEN];
|
||||
char *result;
|
||||
int encoded_len;
|
||||
const char *errstr = NULL;
|
||||
@ -565,11 +571,11 @@ build_client_final_message(fe_scram_state *state)
|
||||
}
|
||||
|
||||
appendPQExpBufferStr(&buf, ",p=");
|
||||
encoded_len = pg_b64_enc_len(SCRAM_KEY_LEN);
|
||||
encoded_len = pg_b64_enc_len(state->key_length);
|
||||
if (!enlargePQExpBuffer(&buf, encoded_len))
|
||||
goto oom_error;
|
||||
encoded_len = pg_b64_encode((char *) client_proof,
|
||||
SCRAM_KEY_LEN,
|
||||
state->key_length,
|
||||
buf.data + buf.len,
|
||||
encoded_len);
|
||||
if (encoded_len < 0)
|
||||
@ -738,13 +744,14 @@ read_server_final_message(fe_scram_state *state, char *input)
|
||||
strlen(encoded_server_signature),
|
||||
decoded_server_signature,
|
||||
server_signature_len);
|
||||
if (server_signature_len != SCRAM_KEY_LEN)
|
||||
if (server_signature_len != state->key_length)
|
||||
{
|
||||
free(decoded_server_signature);
|
||||
libpq_append_conn_error(conn, "malformed SCRAM message (invalid server signature)");
|
||||
return false;
|
||||
}
|
||||
memcpy(state->ServerSignature, decoded_server_signature, SCRAM_KEY_LEN);
|
||||
memcpy(state->ServerSignature, decoded_server_signature,
|
||||
state->key_length);
|
||||
free(decoded_server_signature);
|
||||
|
||||
return true;
|
||||
@ -760,13 +767,13 @@ calculate_client_proof(fe_scram_state *state,
|
||||
const char *client_final_message_without_proof,
|
||||
uint8 *result, const char **errstr)
|
||||
{
|
||||
uint8 StoredKey[SCRAM_KEY_LEN];
|
||||
uint8 ClientKey[SCRAM_KEY_LEN];
|
||||
uint8 ClientSignature[SCRAM_KEY_LEN];
|
||||
uint8 StoredKey[SCRAM_MAX_KEY_LEN];
|
||||
uint8 ClientKey[SCRAM_MAX_KEY_LEN];
|
||||
uint8 ClientSignature[SCRAM_MAX_KEY_LEN];
|
||||
int i;
|
||||
pg_hmac_ctx *ctx;
|
||||
|
||||
ctx = pg_hmac_create(PG_SHA256);
|
||||
ctx = pg_hmac_create(state->hash_type);
|
||||
if (ctx == NULL)
|
||||
{
|
||||
*errstr = pg_hmac_error(NULL); /* returns OOM */
|
||||
@ -777,18 +784,21 @@ 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.
|
||||
*/
|
||||
if (scram_SaltedPassword(state->password, state->salt, state->saltlen,
|
||||
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, ClientKey, errstr) < 0 ||
|
||||
scram_H(ClientKey, SCRAM_KEY_LEN, StoredKey, 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 */
|
||||
pg_hmac_free(ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pg_hmac_init(ctx, StoredKey, SCRAM_KEY_LEN) < 0 ||
|
||||
if (pg_hmac_init(ctx, StoredKey, state->key_length) < 0 ||
|
||||
pg_hmac_update(ctx,
|
||||
(uint8 *) state->client_first_message_bare,
|
||||
strlen(state->client_first_message_bare)) < 0 ||
|
||||
@ -800,14 +810,14 @@ calculate_client_proof(fe_scram_state *state,
|
||||
pg_hmac_update(ctx,
|
||||
(uint8 *) client_final_message_without_proof,
|
||||
strlen(client_final_message_without_proof)) < 0 ||
|
||||
pg_hmac_final(ctx, ClientSignature, sizeof(ClientSignature)) < 0)
|
||||
pg_hmac_final(ctx, ClientSignature, state->key_length) < 0)
|
||||
{
|
||||
*errstr = pg_hmac_error(ctx);
|
||||
pg_hmac_free(ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < SCRAM_KEY_LEN; i++)
|
||||
for (i = 0; i < state->key_length; i++)
|
||||
result[i] = ClientKey[i] ^ ClientSignature[i];
|
||||
|
||||
pg_hmac_free(ctx);
|
||||
@ -825,18 +835,19 @@ static bool
|
||||
verify_server_signature(fe_scram_state *state, bool *match,
|
||||
const char **errstr)
|
||||
{
|
||||
uint8 expected_ServerSignature[SCRAM_KEY_LEN];
|
||||
uint8 ServerKey[SCRAM_KEY_LEN];
|
||||
uint8 expected_ServerSignature[SCRAM_MAX_KEY_LEN];
|
||||
uint8 ServerKey[SCRAM_MAX_KEY_LEN];
|
||||
pg_hmac_ctx *ctx;
|
||||
|
||||
ctx = pg_hmac_create(PG_SHA256);
|
||||
ctx = pg_hmac_create(state->hash_type);
|
||||
if (ctx == NULL)
|
||||
{
|
||||
*errstr = pg_hmac_error(NULL); /* returns OOM */
|
||||
return false;
|
||||
}
|
||||
|
||||
if (scram_ServerKey(state->SaltedPassword, ServerKey, errstr) < 0)
|
||||
if (scram_ServerKey(state->SaltedPassword, state->hash_type,
|
||||
state->key_length, ServerKey, errstr) < 0)
|
||||
{
|
||||
/* errstr is filled already */
|
||||
pg_hmac_free(ctx);
|
||||
@ -844,7 +855,7 @@ verify_server_signature(fe_scram_state *state, bool *match,
|
||||
}
|
||||
|
||||
/* calculate ServerSignature */
|
||||
if (pg_hmac_init(ctx, ServerKey, SCRAM_KEY_LEN) < 0 ||
|
||||
if (pg_hmac_init(ctx, ServerKey, state->key_length) < 0 ||
|
||||
pg_hmac_update(ctx,
|
||||
(uint8 *) state->client_first_message_bare,
|
||||
strlen(state->client_first_message_bare)) < 0 ||
|
||||
@ -857,7 +868,7 @@ verify_server_signature(fe_scram_state *state, bool *match,
|
||||
(uint8 *) state->client_final_message_without_proof,
|
||||
strlen(state->client_final_message_without_proof)) < 0 ||
|
||||
pg_hmac_final(ctx, expected_ServerSignature,
|
||||
sizeof(expected_ServerSignature)) < 0)
|
||||
state->key_length) < 0)
|
||||
{
|
||||
*errstr = pg_hmac_error(ctx);
|
||||
pg_hmac_free(ctx);
|
||||
@ -867,7 +878,8 @@ verify_server_signature(fe_scram_state *state, bool *match,
|
||||
pg_hmac_free(ctx);
|
||||
|
||||
/* signature processed, so now check after it */
|
||||
if (memcmp(expected_ServerSignature, state->ServerSignature, SCRAM_KEY_LEN) != 0)
|
||||
if (memcmp(expected_ServerSignature, state->ServerSignature,
|
||||
state->key_length) != 0)
|
||||
*match = false;
|
||||
else
|
||||
*match = true;
|
||||
@ -912,7 +924,8 @@ pg_fe_scram_build_secret(const char *password, const char **errstr)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result = scram_build_secret(saltbuf, SCRAM_DEFAULT_SALT_LEN,
|
||||
result = scram_build_secret(PG_SHA256, SCRAM_SHA_256_KEY_LEN, saltbuf,
|
||||
SCRAM_DEFAULT_SALT_LEN,
|
||||
SCRAM_DEFAULT_ITERATIONS, password,
|
||||
errstr);
|
||||
|
||||
|
Reference in New Issue
Block a user