{
char *prep_password = NULL;
pg_saslprep_rc rc;
- char saltbuf[SCRAM_SALT_LEN];
+ char saltbuf[SCRAM_DEFAULT_SALT_LEN];
+ uint8 salted_password[SCRAM_KEY_LEN];
uint8 keybuf[SCRAM_KEY_LEN];
char *encoded_salt;
char *encoded_storedkey;
password = (const char *) prep_password;
if (iterations <= 0)
- iterations = SCRAM_ITERATIONS_DEFAULT;
+ iterations = SCRAM_DEFAULT_ITERATIONS;
/* Generate salt, and encode it in base64 */
- if (!pg_backend_random(saltbuf, SCRAM_SALT_LEN))
+ if (!pg_backend_random(saltbuf, SCRAM_DEFAULT_SALT_LEN))
{
ereport(LOG,
(errcode(ERRCODE_INTERNAL_ERROR),
return NULL;
}
- encoded_salt = palloc(pg_b64_enc_len(SCRAM_SALT_LEN) + 1);
- encoded_len = pg_b64_encode(saltbuf, SCRAM_SALT_LEN, encoded_salt);
+ encoded_salt = palloc(pg_b64_enc_len(SCRAM_DEFAULT_SALT_LEN) + 1);
+ encoded_len = pg_b64_encode(saltbuf, SCRAM_DEFAULT_SALT_LEN, encoded_salt);
encoded_salt[encoded_len] = '\0';
/* Calculate StoredKey, and encode it in base64 */
- scram_ClientOrServerKey(password, saltbuf, SCRAM_SALT_LEN,
- iterations, SCRAM_CLIENT_KEY_NAME, keybuf);
+ scram_SaltedPassword(password, saltbuf, SCRAM_DEFAULT_SALT_LEN,
+ iterations, salted_password);
+ scram_ClientKey(salted_password, keybuf);
scram_H(keybuf, SCRAM_KEY_LEN, keybuf); /* StoredKey */
encoded_storedkey = palloc(pg_b64_enc_len(SCRAM_KEY_LEN) + 1);
encoded_storedkey[encoded_len] = '\0';
/* And same for ServerKey */
- scram_ClientOrServerKey(password, saltbuf, SCRAM_SALT_LEN, iterations,
- SCRAM_SERVER_KEY_NAME, keybuf);
+ scram_ServerKey(salted_password, keybuf);
encoded_serverkey = palloc(pg_b64_enc_len(SCRAM_KEY_LEN) + 1);
encoded_len = pg_b64_encode((const char *) keybuf, SCRAM_KEY_LEN,
char *salt;
int saltlen;
int iterations;
+ uint8 salted_password[SCRAM_KEY_LEN];
uint8 stored_key[SCRAM_KEY_LEN];
uint8 server_key[SCRAM_KEY_LEN];
uint8 computed_key[SCRAM_KEY_LEN];
if (rc == SASLPREP_SUCCESS)
password = prep_password;
- /* Compute Server key based on the user-supplied plaintext password */
- scram_ClientOrServerKey(password, salt, saltlen, iterations,
- SCRAM_SERVER_KEY_NAME, computed_key);
+ /* 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 (prep_password)
pfree(prep_password);
/* Generate deterministic salt */
raw_salt = scram_MockSalt(username);
- encoded_salt = (char *) palloc(pg_b64_enc_len(SCRAM_SALT_LEN) + 1);
- encoded_len = pg_b64_encode(raw_salt, SCRAM_SALT_LEN, encoded_salt);
+ encoded_salt = (char *) palloc(pg_b64_enc_len(SCRAM_DEFAULT_SALT_LEN) + 1);
+ encoded_len = pg_b64_encode(raw_salt, SCRAM_DEFAULT_SALT_LEN, encoded_salt);
encoded_salt[encoded_len] = '\0';
*salt = encoded_salt;
- *iterations = SCRAM_ITERATIONS_DEFAULT;
+ *iterations = SCRAM_DEFAULT_ITERATIONS;
/* StoredKey and ServerKey are not used in a doomed authentication */
memset(stored_key, 0, SCRAM_KEY_LEN);
/*
* Determinisitcally 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_SALT_LEN.
+ * pointer to a static buffer of size SCRAM_DEFAULT_SALT_LEN.
*/
static char *
scram_MockSalt(const char *username)
* not larger the SHA256 digest length. If the salt is smaller, the caller
* will just ignore the extra data))
*/
- StaticAssertStmt(PG_SHA256_DIGEST_LENGTH >= SCRAM_SALT_LEN,
+ StaticAssertStmt(PG_SHA256_DIGEST_LENGTH >= SCRAM_DEFAULT_SALT_LEN,
"salt length greater than SHA256 digest length");
pg_sha256_init(&ctx);
}
/*
- * Iterate hash calculation of HMAC entry using given salt.
- * scram_Hi() is essentially PBKDF2 (see RFC2898) with HMAC() as the
- * pseudorandom function.
+ * Calculate SaltedPassword.
+ *
+ * The password should already be normalized by SASLprep.
*/
-static void
-scram_Hi(const char *str, const char *salt, int saltlen, int iterations, uint8 *result)
+void
+scram_SaltedPassword(const char *password,
+ const char *salt, int saltlen, int iterations,
+ uint8 *result)
{
- int str_len = strlen(str);
+ int password_len = strlen(password);
uint32 one = htonl(1);
int i,
j;
uint8 Ui_prev[SCRAM_KEY_LEN];
scram_HMAC_ctx hmac_ctx;
+ /*
+ * Iterate hash calculation of HMAC entry using given salt. This is
+ * essentially PBKDF2 (see RFC2898) with HMAC() as the pseudorandom
+ * function.
+ */
+
/* First iteration */
- scram_HMAC_init(&hmac_ctx, (uint8 *) str, str_len);
+ 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);
/* Subsequent iterations */
for (i = 2; i <= iterations; i++)
{
- scram_HMAC_init(&hmac_ctx, (uint8 *) str, str_len);
+ 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);
for (j = 0; j < SCRAM_KEY_LEN; j++)
}
/*
- * Calculate ClientKey or ServerKey.
- *
- * The password should already be normalized by SASLprep.
+ * Calculate ClientKey.
*/
void
-scram_ClientOrServerKey(const char *password,
- const char *salt, int saltlen, int iterations,
- const char *keystr, uint8 *result)
+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);
+}
+
+/*
+ * Calculate ServerKey.
+ */
+void
+scram_ServerKey(const uint8 *salted_password, uint8 *result)
{
- uint8 keybuf[SCRAM_KEY_LEN];
scram_HMAC_ctx ctx;
- scram_Hi(password, salt, saltlen, iterations, keybuf);
- scram_HMAC_init(&ctx, keybuf, SCRAM_KEY_LEN);
- scram_HMAC_update(&ctx, keystr, strlen(keystr));
+ scram_HMAC_init(&ctx, salted_password, SCRAM_KEY_LEN);
+ scram_HMAC_update(&ctx, "Server Key", strlen("Server Key"));
scram_HMAC_final(result, &ctx);
}
#define SCRAM_RAW_NONCE_LEN 10
/* length of salt when generating new verifiers */
-#define SCRAM_SALT_LEN 10
+#define SCRAM_DEFAULT_SALT_LEN 10
/* default number of iterations when generating verifier */
-#define SCRAM_ITERATIONS_DEFAULT 4096
-
-/* Base name of keys used for proof generation */
-#define SCRAM_SERVER_KEY_NAME "Server Key"
-#define SCRAM_CLIENT_KEY_NAME "Client Key"
+#define SCRAM_DEFAULT_ITERATIONS 4096
/*
* Context data for HMAC used in SCRAM authentication.
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 void 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_ClientOrServerKey(const char *password, const char *salt,
- int saltlen, int iterations,
- const char *keystr, uint8 *result);
+extern void scram_ClientKey(const uint8 *salted_password, uint8 *result);
+extern void scram_ServerKey(const uint8 *salted_password, uint8 *result);
#endif /* SCRAM_COMMON_H */
char *password;
/* We construct these */
+ uint8 SaltedPassword[SCRAM_KEY_LEN];
char *client_nonce;
char *client_first_message_bare;
char *client_final_message_without_proof;
/* These come from the server-final message */
char *server_final_message;
- char ServerProof[SCRAM_KEY_LEN];
+ char ServerSignature[SCRAM_KEY_LEN];
} fe_scram_state;
static bool read_server_first_message(fe_scram_state *state, char *input,
PQExpBuffer errormessage);
static char *build_client_final_message(fe_scram_state *state,
PQExpBuffer errormessage);
-static bool verify_server_proof(fe_scram_state *state);
+static bool verify_server_signature(fe_scram_state *state);
static void calculate_client_proof(fe_scram_state *state,
const char *client_final_message_without_proof,
uint8 *result);
goto error;
/*
- * Verify server proof, to make sure we're talking to the genuine
- * server. XXX: A fake server could simply not require
+ * Verify server signature, to make sure we're talking to the
+ * genuine server. XXX: A fake server could simply not require
* authentication, though. There is currently no option in libpq
* to reject a connection, if SCRAM authentication did not happen.
*/
- if (verify_server_proof(state))
+ if (verify_server_signature(state))
*success = true;
else
{
* Read the final exchange message coming from the server.
*/
static bool
-read_server_final_message(fe_scram_state *state,
- char *input,
+read_server_final_message(fe_scram_state *state, char *input,
PQExpBuffer errormessage)
{
- char *encoded_server_proof;
- int server_proof_len;
+ char *encoded_server_signature;
+ int server_signature_len;
state->server_final_message = strdup(input);
if (!state->server_final_message)
}
/* Parse the message. */
- encoded_server_proof = read_attr_value(&input, 'v', errormessage);
- if (encoded_server_proof == NULL)
+ encoded_server_signature = read_attr_value(&input, 'v', errormessage);
+ if (encoded_server_signature == NULL)
{
/* read_attr_value() has generated an error message */
return false;
printfPQExpBuffer(errormessage,
libpq_gettext("malformed SCRAM message (garbage at end of server-final-message)\n"));
- server_proof_len = pg_b64_decode(encoded_server_proof,
- strlen(encoded_server_proof),
- state->ServerProof);
- if (server_proof_len != SCRAM_KEY_LEN)
+ server_signature_len = pg_b64_decode(encoded_server_signature,
+ strlen(encoded_server_signature),
+ state->ServerSignature);
+ if (server_signature_len != SCRAM_KEY_LEN)
{
printfPQExpBuffer(errormessage,
- libpq_gettext("malformed SCRAM message (invalid server proof)\n"));
+ libpq_gettext("malformed SCRAM message (invalid server signature)\n"));
return false;
}
int i;
scram_HMAC_ctx ctx;
- scram_ClientOrServerKey(state->password, state->salt, state->saltlen,
- state->iterations, SCRAM_CLIENT_KEY_NAME, ClientKey);
+ /*
+ * 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);
}
/*
- * Validate the server proof, received as part of the final exchange message
- * received from the server.
+ * Validate the server signature, received as part of the final exchange
+ * message received from the server.
*/
static bool
-verify_server_proof(fe_scram_state *state)
+verify_server_signature(fe_scram_state *state)
{
- uint8 ServerSignature[SCRAM_KEY_LEN];
+ uint8 expected_ServerSignature[SCRAM_KEY_LEN];
uint8 ServerKey[SCRAM_KEY_LEN];
scram_HMAC_ctx ctx;
- scram_ClientOrServerKey(state->password, state->salt, state->saltlen,
- state->iterations, SCRAM_SERVER_KEY_NAME,
- ServerKey);
+ scram_ServerKey(state->SaltedPassword, ServerKey);
/* calculate ServerSignature */
scram_HMAC_init(&ctx, ServerKey, SCRAM_KEY_LEN);
scram_HMAC_update(&ctx,
state->client_final_message_without_proof,
strlen(state->client_final_message_without_proof));
- scram_HMAC_final(ServerSignature, &ctx);
+ scram_HMAC_final(expected_ServerSignature, &ctx);
- if (memcmp(ServerSignature, state->ServerProof, SCRAM_KEY_LEN) != 0)
+ if (memcmp(expected_ServerSignature, state->ServerSignature, SCRAM_KEY_LEN) != 0)
return false;
return true;