summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeikki Linnakangas2017-03-17 09:33:27 +0000
committerHeikki Linnakangas2017-03-17 09:33:27 +0000
commitc6305a9c572aaf3509ea90eec5127340dab89546 (patch)
tree223f8e369247138091852efa1576cfff1fae0440
parentff30aec759bdc4de78912d91f650ec8fd95ff6bc (diff)
Allow plaintext 'password' authentication when user has a SCRAM verifier.
Oversight in the main SCRAM patch.
-rw-r--r--src/backend/libpq/auth-scram.c46
-rw-r--r--src/backend/libpq/crypt.c61
-rw-r--r--src/include/libpq/scram.h2
3 files changed, 87 insertions, 22 deletions
diff --git a/src/backend/libpq/auth-scram.c b/src/backend/libpq/auth-scram.c
index 9f78e57aae5..db15a2fac6c 100644
--- a/src/backend/libpq/auth-scram.c
+++ b/src/backend/libpq/auth-scram.c
@@ -364,6 +364,52 @@ scram_build_verifier(const char *username, const char *password,
return psprintf("scram-sha-256:%s:%d:%s:%s", encoded_salt, iterations, storedkey_hex, serverkey_hex);
}
+/*
+ * Verify a plaintext password against a SCRAM verifier. This is used when
+ * performing plaintext password authentication for a user that has a SCRAM
+ * verifier stored in pg_authid.
+ */
+bool
+scram_verify_plain_password(const char *username, const char *password,
+ const char *verifier)
+{
+ char *encoded_salt;
+ char *salt;
+ int saltlen;
+ int iterations;
+ uint8 stored_key[SCRAM_KEY_LEN];
+ uint8 server_key[SCRAM_KEY_LEN];
+ uint8 computed_key[SCRAM_KEY_LEN];
+
+ if (!parse_scram_verifier(verifier, &encoded_salt, &iterations,
+ stored_key, server_key))
+ {
+ /*
+ * The password looked like a SCRAM verifier, but could not be
+ * parsed.
+ */
+ elog(LOG, "invalid SCRAM verifier for user \"%s\"", username);
+ return false;
+ }
+
+ salt = palloc(pg_b64_dec_len(strlen(encoded_salt)));
+ saltlen = pg_b64_decode(encoded_salt, strlen(encoded_salt), salt);
+ if (saltlen == -1)
+ {
+ elog(LOG, "invalid SCRAM verifier for user \"%s\"", username);
+ return false;
+ }
+
+ /* Compute Server key based on the user-supplied plaintext password */
+ scram_ClientOrServerKey(password, salt, saltlen, iterations,
+ SCRAM_SERVER_KEY_NAME, computed_key);
+
+ /*
+ * Compare the verifier's Server Key with the one computed from the
+ * user-supplied password.
+ */
+ return memcmp(computed_key, server_key, SCRAM_KEY_LEN) == 0;
+}
/*
* Check if given verifier can be used for SCRAM authentication.
diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c
index 9f0ae15b00e..ac10751ec20 100644
--- a/src/backend/libpq/crypt.c
+++ b/src/backend/libpq/crypt.c
@@ -283,7 +283,6 @@ plain_crypt_verify(const char *role, const char *shadow_pass,
const char *client_pass,
char **logdetail)
{
- int retval;
char crypt_client_pass[MD5_PASSWD_LEN + 1];
/*
@@ -293,6 +292,21 @@ plain_crypt_verify(const char *role, const char *shadow_pass,
*/
switch (get_password_type(shadow_pass))
{
+ case PASSWORD_TYPE_SCRAM:
+ if (scram_verify_plain_password(role,
+ client_pass,
+ shadow_pass))
+ {
+ return STATUS_OK;
+ }
+ else
+ {
+ *logdetail = psprintf(_("Password does not match for user \"%s\"."),
+ role);
+ return STATUS_ERROR;
+ }
+ break;
+
case PASSWORD_TYPE_MD5:
if (!pg_md5_encrypt(client_pass,
role,
@@ -307,30 +321,33 @@ plain_crypt_verify(const char *role, const char *shadow_pass,
*/
return STATUS_ERROR;
}
- client_pass = crypt_client_pass;
+ if (strcmp(crypt_client_pass, shadow_pass) == 0)
+ return STATUS_OK;
+ else
+ {
+ *logdetail = psprintf(_("Password does not match for user \"%s\"."),
+ role);
+ return STATUS_ERROR;
+ }
break;
+
case PASSWORD_TYPE_PLAINTEXT:
+ if (strcmp(client_pass, shadow_pass) == 0)
+ return STATUS_OK;
+ else
+ {
+ *logdetail = psprintf(_("Password does not match for user \"%s\"."),
+ role);
+ return STATUS_ERROR;
+ }
break;
-
- default:
-
- /*
- * This shouldn't happen. Plain "password" authentication should
- * be possible with any kind of stored password hash.
- */
- *logdetail = psprintf(_("Password of user \"%s\" is in unrecognized format."),
- role);
- return STATUS_ERROR;
}
- if (strcmp(client_pass, shadow_pass) == 0)
- retval = STATUS_OK;
- else
- {
- *logdetail = psprintf(_("Password does not match for user \"%s\"."),
- role);
- retval = STATUS_ERROR;
- }
-
- return retval;
+ /*
+ * This shouldn't happen. Plain "password" authentication is possible
+ * with any kind of stored password hash.
+ */
+ *logdetail = psprintf(_("Password of user \"%s\" is in unrecognized format."),
+ role);
+ return STATUS_ERROR;
}
diff --git a/src/include/libpq/scram.h b/src/include/libpq/scram.h
index 78a52db6841..fb21e056c81 100644
--- a/src/include/libpq/scram.h
+++ b/src/include/libpq/scram.h
@@ -31,5 +31,7 @@ extern char *scram_build_verifier(const char *username,
const char *password,
int iterations);
extern bool is_scram_verifier(const char *verifier);
+extern bool scram_verify_plain_password(const char *username,
+ const char *password, const char *verifier);
#endif /* PG_SCRAM_H */