Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit c6305a9

Browse files
committed
Allow plaintext 'password' authentication when user has a SCRAM verifier.
Oversight in the main SCRAM patch.
1 parent ff30aec commit c6305a9

File tree

3 files changed

+87
-22
lines changed

3 files changed

+87
-22
lines changed

src/backend/libpq/auth-scram.c

+46
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,52 @@ scram_build_verifier(const char *username, const char *password,
364364
return psprintf("scram-sha-256:%s:%d:%s:%s", encoded_salt, iterations, storedkey_hex, serverkey_hex);
365365
}
366366

367+
/*
368+
* Verify a plaintext password against a SCRAM verifier. This is used when
369+
* performing plaintext password authentication for a user that has a SCRAM
370+
* verifier stored in pg_authid.
371+
*/
372+
bool
373+
scram_verify_plain_password(const char *username, const char *password,
374+
const char *verifier)
375+
{
376+
char *encoded_salt;
377+
char *salt;
378+
int saltlen;
379+
int iterations;
380+
uint8 stored_key[SCRAM_KEY_LEN];
381+
uint8 server_key[SCRAM_KEY_LEN];
382+
uint8 computed_key[SCRAM_KEY_LEN];
383+
384+
if (!parse_scram_verifier(verifier, &encoded_salt, &iterations,
385+
stored_key, server_key))
386+
{
387+
/*
388+
* The password looked like a SCRAM verifier, but could not be
389+
* parsed.
390+
*/
391+
elog(LOG, "invalid SCRAM verifier for user \"%s\"", username);
392+
return false;
393+
}
394+
395+
salt = palloc(pg_b64_dec_len(strlen(encoded_salt)));
396+
saltlen = pg_b64_decode(encoded_salt, strlen(encoded_salt), salt);
397+
if (saltlen == -1)
398+
{
399+
elog(LOG, "invalid SCRAM verifier for user \"%s\"", username);
400+
return false;
401+
}
402+
403+
/* Compute Server key based on the user-supplied plaintext password */
404+
scram_ClientOrServerKey(password, salt, saltlen, iterations,
405+
SCRAM_SERVER_KEY_NAME, computed_key);
406+
407+
/*
408+
* Compare the verifier's Server Key with the one computed from the
409+
* user-supplied password.
410+
*/
411+
return memcmp(computed_key, server_key, SCRAM_KEY_LEN) == 0;
412+
}
367413

368414
/*
369415
* Check if given verifier can be used for SCRAM authentication.

src/backend/libpq/crypt.c

+39-22
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,6 @@ plain_crypt_verify(const char *role, const char *shadow_pass,
283283
const char *client_pass,
284284
char **logdetail)
285285
{
286-
int retval;
287286
char crypt_client_pass[MD5_PASSWD_LEN + 1];
288287

289288
/*
@@ -293,6 +292,21 @@ plain_crypt_verify(const char *role, const char *shadow_pass,
293292
*/
294293
switch (get_password_type(shadow_pass))
295294
{
295+
case PASSWORD_TYPE_SCRAM:
296+
if (scram_verify_plain_password(role,
297+
client_pass,
298+
shadow_pass))
299+
{
300+
return STATUS_OK;
301+
}
302+
else
303+
{
304+
*logdetail = psprintf(_("Password does not match for user \"%s\"."),
305+
role);
306+
return STATUS_ERROR;
307+
}
308+
break;
309+
296310
case PASSWORD_TYPE_MD5:
297311
if (!pg_md5_encrypt(client_pass,
298312
role,
@@ -307,30 +321,33 @@ plain_crypt_verify(const char *role, const char *shadow_pass,
307321
*/
308322
return STATUS_ERROR;
309323
}
310-
client_pass = crypt_client_pass;
324+
if (strcmp(crypt_client_pass, shadow_pass) == 0)
325+
return STATUS_OK;
326+
else
327+
{
328+
*logdetail = psprintf(_("Password does not match for user \"%s\"."),
329+
role);
330+
return STATUS_ERROR;
331+
}
311332
break;
333+
312334
case PASSWORD_TYPE_PLAINTEXT:
335+
if (strcmp(client_pass, shadow_pass) == 0)
336+
return STATUS_OK;
337+
else
338+
{
339+
*logdetail = psprintf(_("Password does not match for user \"%s\"."),
340+
role);
341+
return STATUS_ERROR;
342+
}
313343
break;
314-
315-
default:
316-
317-
/*
318-
* This shouldn't happen. Plain "password" authentication should
319-
* be possible with any kind of stored password hash.
320-
*/
321-
*logdetail = psprintf(_("Password of user \"%s\" is in unrecognized format."),
322-
role);
323-
return STATUS_ERROR;
324344
}
325345

326-
if (strcmp(client_pass, shadow_pass) == 0)
327-
retval = STATUS_OK;
328-
else
329-
{
330-
*logdetail = psprintf(_("Password does not match for user \"%s\"."),
331-
role);
332-
retval = STATUS_ERROR;
333-
}
334-
335-
return retval;
346+
/*
347+
* This shouldn't happen. Plain "password" authentication is possible
348+
* with any kind of stored password hash.
349+
*/
350+
*logdetail = psprintf(_("Password of user \"%s\" is in unrecognized format."),
351+
role);
352+
return STATUS_ERROR;
336353
}

src/include/libpq/scram.h

+2
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,7 @@ extern char *scram_build_verifier(const char *username,
3131
const char *password,
3232
int iterations);
3333
extern bool is_scram_verifier(const char *verifier);
34+
extern bool scram_verify_plain_password(const char *username,
35+
const char *password, const char *verifier);
3436

3537
#endif /* PG_SCRAM_H */

0 commit comments

Comments
 (0)