PostgreSQL Source Code  git master
scram.h File Reference
#include "lib/stringinfo.h"
#include "libpq/libpq-be.h"
#include "libpq/sasl.h"
Include dependency graph for scram.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

char * pg_be_scram_build_secret (const char *password)
 
bool parse_scram_secret (const char *secret, int *iterations, char **salt, uint8 *stored_key, uint8 *server_key)
 
bool scram_verify_plain_password (const char *username, const char *password, const char *secret)
 

Variables

PGDLLIMPORT const pg_be_sasl_mech pg_be_scram_mech
 

Function Documentation

◆ parse_scram_secret()

bool parse_scram_secret ( const char *  secret,
int *  iterations,
char **  salt,
uint8 stored_key,
uint8 server_key 
)

Definition at line 574 of file auth-scram.c.

576 {
577  char *v;
578  char *p;
579  char *scheme_str;
580  char *salt_str;
581  char *iterations_str;
582  char *storedkey_str;
583  char *serverkey_str;
584  int decoded_len;
585  char *decoded_salt_buf;
586  char *decoded_stored_buf;
587  char *decoded_server_buf;
588 
589  /*
590  * The secret is of form:
591  *
592  * SCRAM-SHA-256$<iterations>:<salt>$<storedkey>:<serverkey>
593  */
594  v = pstrdup(secret);
595  if ((scheme_str = strtok(v, "$")) == NULL)
596  goto invalid_secret;
597  if ((iterations_str = strtok(NULL, ":")) == NULL)
598  goto invalid_secret;
599  if ((salt_str = strtok(NULL, "$")) == NULL)
600  goto invalid_secret;
601  if ((storedkey_str = strtok(NULL, ":")) == NULL)
602  goto invalid_secret;
603  if ((serverkey_str = strtok(NULL, "")) == NULL)
604  goto invalid_secret;
605 
606  /* Parse the fields */
607  if (strcmp(scheme_str, "SCRAM-SHA-256") != 0)
608  goto invalid_secret;
609 
610  errno = 0;
611  *iterations = strtol(iterations_str, &p, 10);
612  if (*p || errno != 0)
613  goto invalid_secret;
614 
615  /*
616  * Verify that the salt is in Base64-encoded format, by decoding it,
617  * although we return the encoded version to the caller.
618  */
619  decoded_len = pg_b64_dec_len(strlen(salt_str));
620  decoded_salt_buf = palloc(decoded_len);
621  decoded_len = pg_b64_decode(salt_str, strlen(salt_str),
622  decoded_salt_buf, decoded_len);
623  if (decoded_len < 0)
624  goto invalid_secret;
625  *salt = pstrdup(salt_str);
626 
627  /*
628  * Decode StoredKey and ServerKey.
629  */
630  decoded_len = pg_b64_dec_len(strlen(storedkey_str));
631  decoded_stored_buf = palloc(decoded_len);
632  decoded_len = pg_b64_decode(storedkey_str, strlen(storedkey_str),
633  decoded_stored_buf, decoded_len);
634  if (decoded_len != SCRAM_KEY_LEN)
635  goto invalid_secret;
636  memcpy(stored_key, decoded_stored_buf, SCRAM_KEY_LEN);
637 
638  decoded_len = pg_b64_dec_len(strlen(serverkey_str));
639  decoded_server_buf = palloc(decoded_len);
640  decoded_len = pg_b64_decode(serverkey_str, strlen(serverkey_str),
641  decoded_server_buf, decoded_len);
642  if (decoded_len != SCRAM_KEY_LEN)
643  goto invalid_secret;
644  memcpy(server_key, decoded_server_buf, SCRAM_KEY_LEN);
645 
646  return true;
647 
648 invalid_secret:
649  *salt = NULL;
650  return false;
651 }
int pg_b64_decode(const char *src, int len, char *dst, int dstlen)
Definition: base64.c:116
int pg_b64_dec_len(int srclen)
Definition: base64.c:239
char * pstrdup(const char *in)
Definition: mcxt.c:1305
void * palloc(Size size)
Definition: mcxt.c:1068
#define SCRAM_KEY_LEN
Definition: scram-common.h:24

References palloc(), pg_b64_dec_len(), pg_b64_decode(), pstrdup(), and SCRAM_KEY_LEN.

Referenced by get_password_type(), scram_init(), and scram_verify_plain_password().

◆ pg_be_scram_build_secret()

char* pg_be_scram_build_secret ( const char *  password)

Definition at line 462 of file auth-scram.c.

463 {
464  char *prep_password;
465  pg_saslprep_rc rc;
466  char saltbuf[SCRAM_DEFAULT_SALT_LEN];
467  char *result;
468  const char *errstr = NULL;
469 
470  /*
471  * Normalize the password with SASLprep. If that doesn't work, because
472  * the password isn't valid UTF-8 or contains prohibited characters, just
473  * proceed with the original password. (See comments at top of file.)
474  */
475  rc = pg_saslprep(password, &prep_password);
476  if (rc == SASLPREP_SUCCESS)
477  password = (const char *) prep_password;
478 
479  /* Generate random salt */
481  ereport(ERROR,
482  (errcode(ERRCODE_INTERNAL_ERROR),
483  errmsg("could not generate random salt")));
484 
485  result = scram_build_secret(saltbuf, SCRAM_DEFAULT_SALT_LEN,
487  &errstr);
488 
489  if (prep_password)
490  pfree(prep_password);
491 
492  return result;
493 }
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
#define ereport(elevel,...)
Definition: elog.h:143
void pfree(void *pointer)
Definition: mcxt.c:1175
bool pg_strong_random(void *buf, size_t len)
pg_saslprep_rc pg_saslprep(const char *input, char **output)
Definition: saslprep.c:1044
pg_saslprep_rc
Definition: saslprep.h:21
@ SASLPREP_SUCCESS
Definition: saslprep.h:22
char * scram_build_secret(const char *salt, int saltlen, int iterations, const char *password, const char **errstr)
Definition: scram-common.c:195
#define SCRAM_DEFAULT_ITERATIONS
Definition: scram-common.h:47
#define SCRAM_DEFAULT_SALT_LEN
Definition: scram-common.h:41
static char * password
Definition: streamutil.c:53

References ereport, errcode(), errmsg(), ERROR, password, pfree(), pg_saslprep(), pg_strong_random(), SASLPREP_SUCCESS, scram_build_secret(), SCRAM_DEFAULT_ITERATIONS, and SCRAM_DEFAULT_SALT_LEN.

Referenced by encrypt_password().

◆ scram_verify_plain_password()

bool scram_verify_plain_password ( const char *  username,
const char *  password,
const char *  secret 
)

Definition at line 501 of file auth-scram.c.

503 {
504  char *encoded_salt;
505  char *salt;
506  int saltlen;
507  int iterations;
508  uint8 salted_password[SCRAM_KEY_LEN];
509  uint8 stored_key[SCRAM_KEY_LEN];
510  uint8 server_key[SCRAM_KEY_LEN];
511  uint8 computed_key[SCRAM_KEY_LEN];
512  char *prep_password;
513  pg_saslprep_rc rc;
514  const char *errstr = NULL;
515 
516  if (!parse_scram_secret(secret, &iterations, &encoded_salt,
517  stored_key, server_key))
518  {
519  /*
520  * The password looked like a SCRAM secret, but could not be parsed.
521  */
522  ereport(LOG,
523  (errmsg("invalid SCRAM secret for user \"%s\"", username)));
524  return false;
525  }
526 
527  saltlen = pg_b64_dec_len(strlen(encoded_salt));
528  salt = palloc(saltlen);
529  saltlen = pg_b64_decode(encoded_salt, strlen(encoded_salt), salt,
530  saltlen);
531  if (saltlen < 0)
532  {
533  ereport(LOG,
534  (errmsg("invalid SCRAM secret for user \"%s\"", username)));
535  return false;
536  }
537 
538  /* Normalize the password */
539  rc = pg_saslprep(password, &prep_password);
540  if (rc == SASLPREP_SUCCESS)
541  password = prep_password;
542 
543  /* Compute Server Key based on the user-supplied plaintext password */
544  if (scram_SaltedPassword(password, salt, saltlen, iterations,
545  salted_password, &errstr) < 0 ||
546  scram_ServerKey(salted_password, computed_key, &errstr) < 0)
547  {
548  elog(ERROR, "could not compute server key: %s", errstr);
549  }
550 
551  if (prep_password)
552  pfree(prep_password);
553 
554  /*
555  * Compare the secret's Server Key with the one computed from the
556  * user-supplied password.
557  */
558  return memcmp(computed_key, server_key, SCRAM_KEY_LEN) == 0;
559 }
bool parse_scram_secret(const char *secret, int *iterations, char **salt, uint8 *stored_key, uint8 *server_key)
Definition: auth-scram.c:574
unsigned char uint8
Definition: c.h:439
#define LOG
Definition: elog.h:25
#define elog(elevel,...)
Definition: elog.h:218
const char * username
Definition: pgbench.c:309
int scram_SaltedPassword(const char *password, const char *salt, int saltlen, int iterations, uint8 *result, const char **errstr)
Definition: scram-common.c:35
int scram_ServerKey(const uint8 *salted_password, uint8 *result, const char **errstr)
Definition: scram-common.c:158

References elog, ereport, errmsg(), ERROR, LOG, palloc(), parse_scram_secret(), password, pfree(), pg_b64_dec_len(), pg_b64_decode(), pg_saslprep(), SASLPREP_SUCCESS, SCRAM_KEY_LEN, scram_SaltedPassword(), scram_ServerKey(), and username.

Referenced by plain_crypt_verify().

Variable Documentation

◆ pg_be_scram_mech

PGDLLIMPORT const pg_be_sasl_mech pg_be_scram_mech
extern

Definition at line 118 of file auth-scram.c.

Referenced by CheckPWChallengeAuth().