PostgreSQL Source Code  git master
scram.h File Reference
#include "common/cryptohash.h"
#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, pg_cryptohash_type *hash_type, int *key_length, char **salt, uint8 *stored_key, uint8 *server_key)
 
bool scram_verify_plain_password (const char *username, const char *password, const char *secret)
 

Variables

PGDLLIMPORT int scram_sha_256_iterations
 
PGDLLIMPORT const pg_be_sasl_mech pg_be_scram_mech
 

Function Documentation

◆ parse_scram_secret()

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

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

599 {
600  char *v;
601  char *p;
602  char *scheme_str;
603  char *salt_str;
604  char *iterations_str;
605  char *storedkey_str;
606  char *serverkey_str;
607  int decoded_len;
608  char *decoded_salt_buf;
609  char *decoded_stored_buf;
610  char *decoded_server_buf;
611 
612  /*
613  * The secret is of form:
614  *
615  * SCRAM-SHA-256$<iterations>:<salt>$<storedkey>:<serverkey>
616  */
617  v = pstrdup(secret);
618  if ((scheme_str = strtok(v, "$")) == NULL)
619  goto invalid_secret;
620  if ((iterations_str = strtok(NULL, ":")) == NULL)
621  goto invalid_secret;
622  if ((salt_str = strtok(NULL, "$")) == NULL)
623  goto invalid_secret;
624  if ((storedkey_str = strtok(NULL, ":")) == NULL)
625  goto invalid_secret;
626  if ((serverkey_str = strtok(NULL, "")) == NULL)
627  goto invalid_secret;
628 
629  /* Parse the fields */
630  if (strcmp(scheme_str, "SCRAM-SHA-256") != 0)
631  goto invalid_secret;
632  *hash_type = PG_SHA256;
633  *key_length = SCRAM_SHA_256_KEY_LEN;
634 
635  errno = 0;
636  *iterations = strtol(iterations_str, &p, 10);
637  if (*p || errno != 0)
638  goto invalid_secret;
639 
640  /*
641  * Verify that the salt is in Base64-encoded format, by decoding it,
642  * although we return the encoded version to the caller.
643  */
644  decoded_len = pg_b64_dec_len(strlen(salt_str));
645  decoded_salt_buf = palloc(decoded_len);
646  decoded_len = pg_b64_decode(salt_str, strlen(salt_str),
647  decoded_salt_buf, decoded_len);
648  if (decoded_len < 0)
649  goto invalid_secret;
650  *salt = pstrdup(salt_str);
651 
652  /*
653  * Decode StoredKey and ServerKey.
654  */
655  decoded_len = pg_b64_dec_len(strlen(storedkey_str));
656  decoded_stored_buf = palloc(decoded_len);
657  decoded_len = pg_b64_decode(storedkey_str, strlen(storedkey_str),
658  decoded_stored_buf, decoded_len);
659  if (decoded_len != *key_length)
660  goto invalid_secret;
661  memcpy(stored_key, decoded_stored_buf, *key_length);
662 
663  decoded_len = pg_b64_dec_len(strlen(serverkey_str));
664  decoded_server_buf = palloc(decoded_len);
665  decoded_len = pg_b64_decode(serverkey_str, strlen(serverkey_str),
666  decoded_server_buf, decoded_len);
667  if (decoded_len != *key_length)
668  goto invalid_secret;
669  memcpy(server_key, decoded_server_buf, *key_length);
670 
671  return true;
672 
673 invalid_secret:
674  *salt = NULL;
675  return false;
676 }
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
@ PG_SHA256
Definition: cryptohash.h:24
char * pstrdup(const char *in)
Definition: mcxt.c:1624
void * palloc(Size size)
Definition: mcxt.c:1210
#define SCRAM_SHA_256_KEY_LEN
Definition: scram-common.h:24

References palloc(), pg_b64_dec_len(), pg_b64_decode(), PG_SHA256, pstrdup(), and SCRAM_SHA_256_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 479 of file auth-scram.c.

480 {
481  char *prep_password;
482  pg_saslprep_rc rc;
483  char saltbuf[SCRAM_DEFAULT_SALT_LEN];
484  char *result;
485  const char *errstr = NULL;
486 
487  /*
488  * Normalize the password with SASLprep. If that doesn't work, because
489  * the password isn't valid UTF-8 or contains prohibited characters, just
490  * proceed with the original password. (See comments at top of file.)
491  */
492  rc = pg_saslprep(password, &prep_password);
493  if (rc == SASLPREP_SUCCESS)
494  password = (const char *) prep_password;
495 
496  /* Generate random salt */
498  ereport(ERROR,
499  (errcode(ERRCODE_INTERNAL_ERROR),
500  errmsg("could not generate random salt")));
501 
503  saltbuf, SCRAM_DEFAULT_SALT_LEN,
505  &errstr);
506 
507  if (prep_password)
508  pfree(prep_password);
509 
510  return result;
511 }
int scram_sha_256_iterations
Definition: auth-scram.c:197
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
void pfree(void *pointer)
Definition: mcxt.c:1436
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(pg_cryptohash_type hash_type, int key_length, const char *salt, int saltlen, int iterations, const char *password, const char **errstr)
Definition: scram-common.c:199
#define SCRAM_DEFAULT_SALT_LEN
Definition: scram-common.h:44
static char * password
Definition: streamutil.c:53

References ereport, errcode(), errmsg(), ERROR, password, pfree(), pg_saslprep(), PG_SHA256, pg_strong_random(), SASLPREP_SUCCESS, scram_build_secret(), SCRAM_DEFAULT_SALT_LEN, scram_sha_256_iterations, and SCRAM_SHA_256_KEY_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 519 of file auth-scram.c.

521 {
522  char *encoded_salt;
523  char *salt;
524  int saltlen;
525  int iterations;
526  int key_length = 0;
527  pg_cryptohash_type hash_type;
528  uint8 salted_password[SCRAM_MAX_KEY_LEN];
529  uint8 stored_key[SCRAM_MAX_KEY_LEN];
530  uint8 server_key[SCRAM_MAX_KEY_LEN];
531  uint8 computed_key[SCRAM_MAX_KEY_LEN];
532  char *prep_password;
533  pg_saslprep_rc rc;
534  const char *errstr = NULL;
535 
536  if (!parse_scram_secret(secret, &iterations, &hash_type, &key_length,
537  &encoded_salt, stored_key, server_key))
538  {
539  /*
540  * The password looked like a SCRAM secret, but could not be parsed.
541  */
542  ereport(LOG,
543  (errmsg("invalid SCRAM secret for user \"%s\"", username)));
544  return false;
545  }
546 
547  saltlen = pg_b64_dec_len(strlen(encoded_salt));
548  salt = palloc(saltlen);
549  saltlen = pg_b64_decode(encoded_salt, strlen(encoded_salt), salt,
550  saltlen);
551  if (saltlen < 0)
552  {
553  ereport(LOG,
554  (errmsg("invalid SCRAM secret for user \"%s\"", username)));
555  return false;
556  }
557 
558  /* Normalize the password */
559  rc = pg_saslprep(password, &prep_password);
560  if (rc == SASLPREP_SUCCESS)
561  password = prep_password;
562 
563  /* Compute Server Key based on the user-supplied plaintext password */
564  if (scram_SaltedPassword(password, hash_type, key_length,
565  salt, saltlen, iterations,
566  salted_password, &errstr) < 0 ||
567  scram_ServerKey(salted_password, hash_type, key_length,
568  computed_key, &errstr) < 0)
569  {
570  elog(ERROR, "could not compute server key: %s", errstr);
571  }
572 
573  if (prep_password)
574  pfree(prep_password);
575 
576  /*
577  * Compare the secret's Server Key with the one computed from the
578  * user-supplied password.
579  */
580  return memcmp(computed_key, server_key, key_length) == 0;
581 }
bool parse_scram_secret(const char *secret, int *iterations, pg_cryptohash_type *hash_type, int *key_length, char **salt, uint8 *stored_key, uint8 *server_key)
Definition: auth-scram.c:596
unsigned char uint8
Definition: c.h:488
pg_cryptohash_type
Definition: cryptohash.h:20
#define LOG
Definition: elog.h:31
const char * username
Definition: pgbench.c:306
int scram_ServerKey(const uint8 *salted_password, pg_cryptohash_type hash_type, int key_length, uint8 *result, const char **errstr)
Definition: scram-common.c:161
int scram_SaltedPassword(const char *password, pg_cryptohash_type hash_type, int key_length, const char *salt, int saltlen, int iterations, uint8 *result, const char **errstr)
Definition: scram-common.c:35
#define SCRAM_MAX_KEY_LEN
Definition: scram-common.h:30

References elog(), ereport, errmsg(), ERROR, LOG, palloc(), parse_scram_secret(), password, pfree(), pg_b64_dec_len(), pg_b64_decode(), pg_saslprep(), SASLPREP_SUCCESS, SCRAM_MAX_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().

◆ scram_sha_256_iterations

PGDLLIMPORT int scram_sha_256_iterations
extern

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

Referenced by pg_be_scram_build_secret().