PostgreSQL Source Code  git master
auth-scram.c File Reference
#include "postgres.h"
#include <unistd.h>
#include "access/xlog.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_control.h"
#include "common/base64.h"
#include "common/hmac.h"
#include "common/saslprep.h"
#include "common/scram-common.h"
#include "common/sha2.h"
#include "libpq/auth.h"
#include "libpq/crypt.h"
#include "libpq/sasl.h"
#include "libpq/scram.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/timestamp.h"
Include dependency graph for auth-scram.c:

Go to the source code of this file.

Data Structures

struct  scram_state
 

Enumerations

enum  scram_state_enum { SCRAM_AUTH_INIT , SCRAM_AUTH_SALT_SENT , SCRAM_AUTH_FINISHED }
 

Functions

static void scram_get_mechanisms (Port *port, StringInfo buf)
 
static void * scram_init (Port *port, const char *selected_mech, const char *shadow_pass)
 
static int scram_exchange (void *opaq, const char *input, int inputlen, char **output, int *outputlen, const char **logdetail)
 
static void read_client_first_message (scram_state *state, const char *input)
 
static void read_client_final_message (scram_state *state, const char *input)
 
static char * build_server_first_message (scram_state *state)
 
static char * build_server_final_message (scram_state *state)
 
static bool verify_client_proof (scram_state *state)
 
static bool verify_final_nonce (scram_state *state)
 
static void mock_scram_secret (const char *username, pg_cryptohash_type *hash_type, int *iterations, int *key_length, char **salt, uint8 *stored_key, uint8 *server_key)
 
static bool is_scram_printable (char *p)
 
static char * sanitize_char (char c)
 
static char * sanitize_str (const char *s)
 
static char * scram_mock_salt (const char *username, pg_cryptohash_type hash_type, int key_length)
 
char * pg_be_scram_build_secret (const char *password)
 
bool scram_verify_plain_password (const char *username, const char *password, const char *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)
 
static char * read_attr_value (char **input, char attr)
 
static char * read_any_attr (char **input, char *attr_p)
 

Variables

const pg_be_sasl_mech pg_be_scram_mech
 

Enumeration Type Documentation

◆ scram_state_enum

Enumerator
SCRAM_AUTH_INIT 
SCRAM_AUTH_SALT_SENT 
SCRAM_AUTH_FINISHED 

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

129 {
scram_state_enum
Definition: auth-scram.c:129
@ SCRAM_AUTH_SALT_SENT
Definition: auth-scram.c:131
@ SCRAM_AUTH_FINISHED
Definition: auth-scram.c:132
@ SCRAM_AUTH_INIT
Definition: auth-scram.c:130

Function Documentation

◆ build_server_final_message()

static char * build_server_final_message ( scram_state state)
static

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

1402 {
1403  uint8 ServerSignature[SCRAM_MAX_KEY_LEN];
1404  char *server_signature_base64;
1405  int siglen;
1406  pg_hmac_ctx *ctx = pg_hmac_create(state->hash_type);
1407 
1408  /* calculate ServerSignature */
1409  if (pg_hmac_init(ctx, state->ServerKey, state->key_length) < 0 ||
1410  pg_hmac_update(ctx,
1411  (uint8 *) state->client_first_message_bare,
1412  strlen(state->client_first_message_bare)) < 0 ||
1413  pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
1414  pg_hmac_update(ctx,
1415  (uint8 *) state->server_first_message,
1416  strlen(state->server_first_message)) < 0 ||
1417  pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
1418  pg_hmac_update(ctx,
1419  (uint8 *) state->client_final_message_without_proof,
1420  strlen(state->client_final_message_without_proof)) < 0 ||
1421  pg_hmac_final(ctx, ServerSignature, state->key_length) < 0)
1422  {
1423  elog(ERROR, "could not calculate server signature: %s",
1424  pg_hmac_error(ctx));
1425  }
1426 
1427  pg_hmac_free(ctx);
1428 
1429  siglen = pg_b64_enc_len(state->key_length);
1430  /* don't forget the zero-terminator */
1431  server_signature_base64 = palloc(siglen + 1);
1432  siglen = pg_b64_encode((const char *) ServerSignature,
1433  state->key_length, server_signature_base64,
1434  siglen);
1435  if (siglen < 0)
1436  elog(ERROR, "could not encode server signature");
1437  server_signature_base64[siglen] = '\0';
1438 
1439  /*------
1440  * The syntax for the server-final-message is: (RFC 5802)
1441  *
1442  * verifier = "v=" base64
1443  * ;; base-64 encoded ServerSignature.
1444  *
1445  * server-final-message = (server-error / verifier)
1446  * ["," extensions]
1447  *
1448  *------
1449  */
1450  return psprintf("v=%s", server_signature_base64);
1451 }
int pg_b64_enc_len(int srclen)
Definition: base64.c:224
int pg_b64_encode(const char *src, int len, char *dst, int dstlen)
Definition: base64.c:49
unsigned char uint8
Definition: c.h:488
#define ERROR
Definition: elog.h:39
pg_hmac_ctx * pg_hmac_create(pg_cryptohash_type type)
Definition: hmac.c:77
const char * pg_hmac_error(pg_hmac_ctx *ctx)
Definition: hmac.c:306
void pg_hmac_free(pg_hmac_ctx *ctx)
Definition: hmac.c:289
int pg_hmac_update(pg_hmac_ctx *ctx, const uint8 *data, size_t len)
Definition: hmac.c:223
int pg_hmac_init(pg_hmac_ctx *ctx, const uint8 *key, size_t len)
Definition: hmac.c:138
int pg_hmac_final(pg_hmac_ctx *ctx, uint8 *dest, size_t len)
Definition: hmac.c:244
void * palloc(Size size)
Definition: mcxt.c:1210
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
#define SCRAM_MAX_KEY_LEN
Definition: scram-common.h:30
Definition: regguts.h:318

References elog(), ERROR, palloc(), pg_b64_enc_len(), pg_b64_encode(), pg_hmac_create(), pg_hmac_error(), pg_hmac_final(), pg_hmac_free(), pg_hmac_init(), pg_hmac_update(), psprintf(), and SCRAM_MAX_KEY_LEN.

Referenced by scram_exchange().

◆ build_server_first_message()

static char * build_server_first_message ( scram_state state)
static

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

1192 {
1193  /*------
1194  * The syntax for the server-first-message is: (RFC 5802)
1195  *
1196  * server-first-message =
1197  * [reserved-mext ","] nonce "," salt ","
1198  * iteration-count ["," extensions]
1199  *
1200  * nonce = "r=" c-nonce [s-nonce]
1201  * ;; Second part provided by server.
1202  *
1203  * c-nonce = printable
1204  *
1205  * s-nonce = printable
1206  *
1207  * salt = "s=" base64
1208  *
1209  * iteration-count = "i=" posit-number
1210  * ;; A positive number.
1211  *
1212  * Example:
1213  *
1214  * r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096
1215  *------
1216  */
1217 
1218  /*
1219  * Per the spec, the nonce may consist of any printable ASCII characters.
1220  * For convenience, however, we don't use the whole range available,
1221  * rather, we generate some random bytes, and base64 encode them.
1222  */
1223  char raw_nonce[SCRAM_RAW_NONCE_LEN];
1224  int encoded_len;
1225 
1226  if (!pg_strong_random(raw_nonce, SCRAM_RAW_NONCE_LEN))
1227  ereport(ERROR,
1228  (errcode(ERRCODE_INTERNAL_ERROR),
1229  errmsg("could not generate random nonce")));
1230 
1231  encoded_len = pg_b64_enc_len(SCRAM_RAW_NONCE_LEN);
1232  /* don't forget the zero-terminator */
1233  state->server_nonce = palloc(encoded_len + 1);
1234  encoded_len = pg_b64_encode(raw_nonce, SCRAM_RAW_NONCE_LEN,
1235  state->server_nonce, encoded_len);
1236  if (encoded_len < 0)
1237  ereport(ERROR,
1238  (errcode(ERRCODE_INTERNAL_ERROR),
1239  errmsg("could not encode random nonce")));
1240  state->server_nonce[encoded_len] = '\0';
1241 
1242  state->server_first_message =
1243  psprintf("r=%s%s,s=%s,i=%d",
1244  state->client_nonce, state->server_nonce,
1245  state->salt, state->iterations);
1246 
1247  return pstrdup(state->server_first_message);
1248 }
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ereport(elevel,...)
Definition: elog.h:149
char * pstrdup(const char *in)
Definition: mcxt.c:1624
bool pg_strong_random(void *buf, size_t len)
#define SCRAM_RAW_NONCE_LEN
Definition: scram-common.h:37

References ereport, errcode(), errmsg(), ERROR, palloc(), pg_b64_enc_len(), pg_b64_encode(), pg_strong_random(), psprintf(), pstrdup(), and SCRAM_RAW_NONCE_LEN.

Referenced by scram_exchange().

◆ is_scram_printable()

static bool is_scram_printable ( char *  p)
static

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

768 {
769  /*------
770  * Printable characters, as defined by SCRAM spec: (RFC 5802)
771  *
772  * printable = %x21-2B / %x2D-7E
773  * ;; Printable ASCII except ",".
774  * ;; Note that any "printable" is also
775  * ;; a valid "value".
776  *------
777  */
778  for (; *p; p++)
779  {
780  if (*p < 0x21 || *p > 0x7E || *p == 0x2C /* comma */ )
781  return false;
782  }
783  return true;
784 }

Referenced by read_client_first_message().

◆ mock_scram_secret()

static void mock_scram_secret ( const char *  username,
pg_cryptohash_type hash_type,
int *  iterations,
int *  key_length,
char **  salt,
uint8 stored_key,
uint8 server_key 
)
static

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

688 {
689  char *raw_salt;
690  char *encoded_salt;
691  int encoded_len;
692 
693  /* Enforce the use of SHA-256, which would be realistic enough */
694  *hash_type = PG_SHA256;
695  *key_length = SCRAM_SHA_256_KEY_LEN;
696 
697  /*
698  * Generate deterministic salt.
699  *
700  * Note that we cannot reveal any information to an attacker here so the
701  * error messages need to remain generic. This should never fail anyway
702  * as the salt generated for mock authentication uses the cluster's nonce
703  * value.
704  */
705  raw_salt = scram_mock_salt(username, *hash_type, *key_length);
706  if (raw_salt == NULL)
707  elog(ERROR, "could not encode salt");
708 
709  encoded_len = pg_b64_enc_len(SCRAM_DEFAULT_SALT_LEN);
710  /* don't forget the zero-terminator */
711  encoded_salt = (char *) palloc(encoded_len + 1);
712  encoded_len = pg_b64_encode(raw_salt, SCRAM_DEFAULT_SALT_LEN, encoded_salt,
713  encoded_len);
714 
715  if (encoded_len < 0)
716  elog(ERROR, "could not encode salt");
717  encoded_salt[encoded_len] = '\0';
718 
719  *salt = encoded_salt;
720  *iterations = SCRAM_DEFAULT_ITERATIONS;
721 
722  /* StoredKey and ServerKey are not used in a doomed authentication */
723  memset(stored_key, 0, SCRAM_MAX_KEY_LEN);
724  memset(server_key, 0, SCRAM_MAX_KEY_LEN);
725 }
static char * scram_mock_salt(const char *username, pg_cryptohash_type hash_type, int key_length)
Definition: auth-scram.c:1460
@ PG_SHA256
Definition: cryptohash.h:24
const char * username
Definition: pgbench.c:306
#define SCRAM_DEFAULT_ITERATIONS
Definition: scram-common.h:50
#define SCRAM_DEFAULT_SALT_LEN
Definition: scram-common.h:44
#define SCRAM_SHA_256_KEY_LEN
Definition: scram-common.h:24

References elog(), ERROR, palloc(), pg_b64_enc_len(), pg_b64_encode(), PG_SHA256, SCRAM_DEFAULT_ITERATIONS, SCRAM_DEFAULT_SALT_LEN, SCRAM_MAX_KEY_LEN, scram_mock_salt(), SCRAM_SHA_256_KEY_LEN, and username.

Referenced by scram_init().

◆ 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 591 of file auth-scram.c.

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

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 474 of file auth-scram.c.

475 {
476  char *prep_password;
477  pg_saslprep_rc rc;
478  char saltbuf[SCRAM_DEFAULT_SALT_LEN];
479  char *result;
480  const char *errstr = NULL;
481 
482  /*
483  * Normalize the password with SASLprep. If that doesn't work, because
484  * the password isn't valid UTF-8 or contains prohibited characters, just
485  * proceed with the original password. (See comments at top of file.)
486  */
487  rc = pg_saslprep(password, &prep_password);
488  if (rc == SASLPREP_SUCCESS)
489  password = (const char *) prep_password;
490 
491  /* Generate random salt */
493  ereport(ERROR,
494  (errcode(ERRCODE_INTERNAL_ERROR),
495  errmsg("could not generate random salt")));
496 
498  saltbuf, SCRAM_DEFAULT_SALT_LEN,
500  &errstr);
501 
502  if (prep_password)
503  pfree(prep_password);
504 
505  return result;
506 }
void pfree(void *pointer)
Definition: mcxt.c:1436
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
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_ITERATIONS, SCRAM_DEFAULT_SALT_LEN, and SCRAM_SHA_256_KEY_LEN.

Referenced by encrypt_password().

◆ read_any_attr()

static char* read_any_attr ( char **  input,
char *  attr_p 
)
static

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

844 {
845  char *begin = *input;
846  char *end;
847  char attr = *begin;
848 
849  if (attr == '\0')
850  ereport(ERROR,
851  (errcode(ERRCODE_PROTOCOL_VIOLATION),
852  errmsg("malformed SCRAM message"),
853  errdetail("Attribute expected, but found end of string.")));
854 
855  /*------
856  * attr-val = ALPHA "=" value
857  * ;; Generic syntax of any attribute sent
858  * ;; by server or client
859  *------
860  */
861  if (!((attr >= 'A' && attr <= 'Z') ||
862  (attr >= 'a' && attr <= 'z')))
863  ereport(ERROR,
864  (errcode(ERRCODE_PROTOCOL_VIOLATION),
865  errmsg("malformed SCRAM message"),
866  errdetail("Attribute expected, but found invalid character \"%s\".",
867  sanitize_char(attr))));
868  if (attr_p)
869  *attr_p = attr;
870  begin++;
871 
872  if (*begin != '=')
873  ereport(ERROR,
874  (errcode(ERRCODE_PROTOCOL_VIOLATION),
875  errmsg("malformed SCRAM message"),
876  errdetail("Expected character \"=\" for attribute \"%c\".", attr)));
877  begin++;
878 
879  end = begin;
880  while (*end && *end != ',')
881  end++;
882 
883  if (*end)
884  {
885  *end = '\0';
886  *input = end + 1;
887  }
888  else
889  *input = end;
890 
891  return begin;
892 }
static char * sanitize_char(char c)
Definition: auth-scram.c:795
int errdetail(const char *fmt,...)
Definition: elog.c:1202

References ereport, errcode(), errdetail(), errmsg(), ERROR, and sanitize_char().

Referenced by read_client_final_message(), and read_client_first_message().

◆ read_attr_value()

static char* read_attr_value ( char **  input,
char  attr 
)
static

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

732 {
733  char *begin = *input;
734  char *end;
735 
736  if (*begin != attr)
737  ereport(ERROR,
738  (errcode(ERRCODE_PROTOCOL_VIOLATION),
739  errmsg("malformed SCRAM message"),
740  errdetail("Expected attribute \"%c\" but found \"%s\".",
741  attr, sanitize_char(*begin))));
742  begin++;
743 
744  if (*begin != '=')
745  ereport(ERROR,
746  (errcode(ERRCODE_PROTOCOL_VIOLATION),
747  errmsg("malformed SCRAM message"),
748  errdetail("Expected character \"=\" for attribute \"%c\".", attr)));
749  begin++;
750 
751  end = begin;
752  while (*end && *end != ',')
753  end++;
754 
755  if (*end)
756  {
757  *end = '\0';
758  *input = end + 1;
759  }
760  else
761  *input = end;
762 
763  return begin;
764 }

References ereport, errcode(), errdetail(), errmsg(), ERROR, and sanitize_char().

Referenced by read_client_final_message(), and read_client_first_message().

◆ read_client_final_message()

static void read_client_final_message ( scram_state state,
const char *  input 
)
static

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

1256 {
1257  char attr;
1258  char *channel_binding;
1259  char *value;
1260  char *begin,
1261  *proof;
1262  char *p;
1263  char *client_proof;
1264  int client_proof_len;
1265 
1266  begin = p = pstrdup(input);
1267 
1268  /*------
1269  * The syntax for the server-first-message is: (RFC 5802)
1270  *
1271  * gs2-header = gs2-cbind-flag "," [ authzid ] ","
1272  * ;; GS2 header for SCRAM
1273  * ;; (the actual GS2 header includes an optional
1274  * ;; flag to indicate that the GSS mechanism is not
1275  * ;; "standard", but since SCRAM is "standard", we
1276  * ;; don't include that flag).
1277  *
1278  * cbind-input = gs2-header [ cbind-data ]
1279  * ;; cbind-data MUST be present for
1280  * ;; gs2-cbind-flag of "p" and MUST be absent
1281  * ;; for "y" or "n".
1282  *
1283  * channel-binding = "c=" base64
1284  * ;; base64 encoding of cbind-input.
1285  *
1286  * proof = "p=" base64
1287  *
1288  * client-final-message-without-proof =
1289  * channel-binding "," nonce [","
1290  * extensions]
1291  *
1292  * client-final-message =
1293  * client-final-message-without-proof "," proof
1294  *------
1295  */
1296 
1297  /*
1298  * Read channel binding. This repeats the channel-binding flags and is
1299  * then followed by the actual binding data depending on the type.
1300  */
1301  channel_binding = read_attr_value(&p, 'c');
1302  if (state->channel_binding_in_use)
1303  {
1304 #ifdef HAVE_BE_TLS_GET_CERTIFICATE_HASH
1305  const char *cbind_data = NULL;
1306  size_t cbind_data_len = 0;
1307  size_t cbind_header_len;
1308  char *cbind_input;
1309  size_t cbind_input_len;
1310  char *b64_message;
1311  int b64_message_len;
1312 
1313  Assert(state->cbind_flag == 'p');
1314 
1315  /* Fetch hash data of server's SSL certificate */
1316  cbind_data = be_tls_get_certificate_hash(state->port,
1317  &cbind_data_len);
1318 
1319  /* should not happen */
1320  if (cbind_data == NULL || cbind_data_len == 0)
1321  elog(ERROR, "could not get server certificate hash");
1322 
1323  cbind_header_len = strlen("p=tls-server-end-point,,"); /* p=type,, */
1324  cbind_input_len = cbind_header_len + cbind_data_len;
1325  cbind_input = palloc(cbind_input_len);
1326  snprintf(cbind_input, cbind_input_len, "p=tls-server-end-point,,");
1327  memcpy(cbind_input + cbind_header_len, cbind_data, cbind_data_len);
1328 
1329  b64_message_len = pg_b64_enc_len(cbind_input_len);
1330  /* don't forget the zero-terminator */
1331  b64_message = palloc(b64_message_len + 1);
1332  b64_message_len = pg_b64_encode(cbind_input, cbind_input_len,
1333  b64_message, b64_message_len);
1334  if (b64_message_len < 0)
1335  elog(ERROR, "could not encode channel binding data");
1336  b64_message[b64_message_len] = '\0';
1337 
1338  /*
1339  * Compare the value sent by the client with the value expected by the
1340  * server.
1341  */
1342  if (strcmp(channel_binding, b64_message) != 0)
1343  ereport(ERROR,
1344  (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
1345  errmsg("SCRAM channel binding check failed")));
1346 #else
1347  /* shouldn't happen, because we checked this earlier already */
1348  elog(ERROR, "channel binding not supported by this build");
1349 #endif
1350  }
1351  else
1352  {
1353  /*
1354  * If we are not using channel binding, the binding data is expected
1355  * to always be "biws", which is "n,," base64-encoded, or "eSws",
1356  * which is "y,,". We also have to check whether the flag is the same
1357  * one that the client originally sent.
1358  */
1359  if (!(strcmp(channel_binding, "biws") == 0 && state->cbind_flag == 'n') &&
1360  !(strcmp(channel_binding, "eSws") == 0 && state->cbind_flag == 'y'))
1361  ereport(ERROR,
1362  (errcode(ERRCODE_PROTOCOL_VIOLATION),
1363  errmsg("unexpected SCRAM channel-binding attribute in client-final-message")));
1364  }
1365 
1366  state->client_final_nonce = read_attr_value(&p, 'r');
1367 
1368  /* ignore optional extensions, read until we find "p" attribute */
1369  do
1370  {
1371  proof = p - 1;
1372  value = read_any_attr(&p, &attr);
1373  } while (attr != 'p');
1374 
1375  client_proof_len = pg_b64_dec_len(strlen(value));
1376  client_proof = palloc(client_proof_len);
1377  if (pg_b64_decode(value, strlen(value), client_proof,
1378  client_proof_len) != state->key_length)
1379  ereport(ERROR,
1380  (errcode(ERRCODE_PROTOCOL_VIOLATION),
1381  errmsg("malformed SCRAM message"),
1382  errdetail("Malformed proof in client-final-message.")));
1383  memcpy(state->ClientProof, client_proof, state->key_length);
1384  pfree(client_proof);
1385 
1386  if (*p != '\0')
1387  ereport(ERROR,
1388  (errcode(ERRCODE_PROTOCOL_VIOLATION),
1389  errmsg("malformed SCRAM message"),
1390  errdetail("Garbage found at the end of client-final-message.")));
1391 
1392  state->client_final_message_without_proof = palloc(proof - begin + 1);
1393  memcpy(state->client_final_message_without_proof, input, proof - begin);
1394  state->client_final_message_without_proof[proof - begin] = '\0';
1395 }
static char * read_attr_value(char **input, char attr)
Definition: auth-scram.c:731
static char * read_any_attr(char **input, char *attr_p)
Definition: auth-scram.c:843
static struct @143 value
Assert(fmt[strlen(fmt) - 1] !='\n')
#define snprintf
Definition: port.h:238

References Assert(), elog(), ereport, errcode(), errdetail(), errmsg(), ERROR, palloc(), pfree(), pg_b64_dec_len(), pg_b64_decode(), pg_b64_enc_len(), pg_b64_encode(), pstrdup(), read_any_attr(), read_attr_value(), snprintf, and value.

Referenced by scram_exchange().

◆ read_client_first_message()

static void read_client_first_message ( scram_state state,
const char *  input 
)
static

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

902 {
903  char *p = pstrdup(input);
904  char *channel_binding_type;
905 
906 
907  /*------
908  * The syntax for the client-first-message is: (RFC 5802)
909  *
910  * saslname = 1*(value-safe-char / "=2C" / "=3D")
911  * ;; Conforms to <value>.
912  *
913  * authzid = "a=" saslname
914  * ;; Protocol specific.
915  *
916  * cb-name = 1*(ALPHA / DIGIT / "." / "-")
917  * ;; See RFC 5056, Section 7.
918  * ;; E.g., "tls-server-end-point" or
919  * ;; "tls-unique".
920  *
921  * gs2-cbind-flag = ("p=" cb-name) / "n" / "y"
922  * ;; "n" -> client doesn't support channel binding.
923  * ;; "y" -> client does support channel binding
924  * ;; but thinks the server does not.
925  * ;; "p" -> client requires channel binding.
926  * ;; The selected channel binding follows "p=".
927  *
928  * gs2-header = gs2-cbind-flag "," [ authzid ] ","
929  * ;; GS2 header for SCRAM
930  * ;; (the actual GS2 header includes an optional
931  * ;; flag to indicate that the GSS mechanism is not
932  * ;; "standard", but since SCRAM is "standard", we
933  * ;; don't include that flag).
934  *
935  * username = "n=" saslname
936  * ;; Usernames are prepared using SASLprep.
937  *
938  * reserved-mext = "m=" 1*(value-char)
939  * ;; Reserved for signaling mandatory extensions.
940  * ;; The exact syntax will be defined in
941  * ;; the future.
942  *
943  * nonce = "r=" c-nonce [s-nonce]
944  * ;; Second part provided by server.
945  *
946  * c-nonce = printable
947  *
948  * client-first-message-bare =
949  * [reserved-mext ","]
950  * username "," nonce ["," extensions]
951  *
952  * client-first-message =
953  * gs2-header client-first-message-bare
954  *
955  * For example:
956  * n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL
957  *
958  * The "n,," in the beginning means that the client doesn't support
959  * channel binding, and no authzid is given. "n=user" is the username.
960  * However, in PostgreSQL the username is sent in the startup packet, and
961  * the username in the SCRAM exchange is ignored. libpq always sends it
962  * as an empty string. The last part, "r=fyko+d2lbbFgONRv9qkxdawL" is
963  * the client nonce.
964  *------
965  */
966 
967  /*
968  * Read gs2-cbind-flag. (For details see also RFC 5802 Section 6 "Channel
969  * Binding".)
970  */
971  state->cbind_flag = *p;
972  switch (*p)
973  {
974  case 'n':
975 
976  /*
977  * The client does not support channel binding or has simply
978  * decided to not use it. In that case just let it go.
979  */
980  if (state->channel_binding_in_use)
981  ereport(ERROR,
982  (errcode(ERRCODE_PROTOCOL_VIOLATION),
983  errmsg("malformed SCRAM message"),
984  errdetail("The client selected SCRAM-SHA-256-PLUS, but the SCRAM message does not include channel binding data.")));
985 
986  p++;
987  if (*p != ',')
988  ereport(ERROR,
989  (errcode(ERRCODE_PROTOCOL_VIOLATION),
990  errmsg("malformed SCRAM message"),
991  errdetail("Comma expected, but found character \"%s\".",
992  sanitize_char(*p))));
993  p++;
994  break;
995  case 'y':
996 
997  /*
998  * The client supports channel binding and thinks that the server
999  * does not. In this case, the server must fail authentication if
1000  * it supports channel binding.
1001  */
1002  if (state->channel_binding_in_use)
1003  ereport(ERROR,
1004  (errcode(ERRCODE_PROTOCOL_VIOLATION),
1005  errmsg("malformed SCRAM message"),
1006  errdetail("The client selected SCRAM-SHA-256-PLUS, but the SCRAM message does not include channel binding data.")));
1007 
1008 #ifdef HAVE_BE_TLS_GET_CERTIFICATE_HASH
1009  if (state->port->ssl_in_use)
1010  ereport(ERROR,
1011  (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
1012  errmsg("SCRAM channel binding negotiation error"),
1013  errdetail("The client supports SCRAM channel binding but thinks the server does not. "
1014  "However, this server does support channel binding.")));
1015 #endif
1016  p++;
1017  if (*p != ',')
1018  ereport(ERROR,
1019  (errcode(ERRCODE_PROTOCOL_VIOLATION),
1020  errmsg("malformed SCRAM message"),
1021  errdetail("Comma expected, but found character \"%s\".",
1022  sanitize_char(*p))));
1023  p++;
1024  break;
1025  case 'p':
1026 
1027  /*
1028  * The client requires channel binding. Channel binding type
1029  * follows, e.g., "p=tls-server-end-point".
1030  */
1031  if (!state->channel_binding_in_use)
1032  ereport(ERROR,
1033  (errcode(ERRCODE_PROTOCOL_VIOLATION),
1034  errmsg("malformed SCRAM message"),
1035  errdetail("The client selected SCRAM-SHA-256 without channel binding, but the SCRAM message includes channel binding data.")));
1036 
1037  channel_binding_type = read_attr_value(&p, 'p');
1038 
1039  /*
1040  * The only channel binding type we support is
1041  * tls-server-end-point.
1042  */
1043  if (strcmp(channel_binding_type, "tls-server-end-point") != 0)
1044  ereport(ERROR,
1045  (errcode(ERRCODE_PROTOCOL_VIOLATION),
1046  errmsg("unsupported SCRAM channel-binding type \"%s\"",
1047  sanitize_str(channel_binding_type))));
1048  break;
1049  default:
1050  ereport(ERROR,
1051  (errcode(ERRCODE_PROTOCOL_VIOLATION),
1052  errmsg("malformed SCRAM message"),
1053  errdetail("Unexpected channel-binding flag \"%s\".",
1054  sanitize_char(*p))));
1055  }
1056 
1057  /*
1058  * Forbid optional authzid (authorization identity). We don't support it.
1059  */
1060  if (*p == 'a')
1061  ereport(ERROR,
1062  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1063  errmsg("client uses authorization identity, but it is not supported")));
1064  if (*p != ',')
1065  ereport(ERROR,
1066  (errcode(ERRCODE_PROTOCOL_VIOLATION),
1067  errmsg("malformed SCRAM message"),
1068  errdetail("Unexpected attribute \"%s\" in client-first-message.",
1069  sanitize_char(*p))));
1070  p++;
1071 
1072  state->client_first_message_bare = pstrdup(p);
1073 
1074  /*
1075  * Any mandatory extensions would go here. We don't support any.
1076  *
1077  * RFC 5802 specifies error code "e=extensions-not-supported" for this,
1078  * but it can only be sent in the server-final message. We prefer to fail
1079  * immediately (which the RFC also allows).
1080  */
1081  if (*p == 'm')
1082  ereport(ERROR,
1083  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1084  errmsg("client requires an unsupported SCRAM extension")));
1085 
1086  /*
1087  * Read username. Note: this is ignored. We use the username from the
1088  * startup message instead, still it is kept around if provided as it
1089  * proves to be useful for debugging purposes.
1090  */
1091  state->client_username = read_attr_value(&p, 'n');
1092 
1093  /* read nonce and check that it is made of only printable characters */
1094  state->client_nonce = read_attr_value(&p, 'r');
1095  if (!is_scram_printable(state->client_nonce))
1096  ereport(ERROR,
1097  (errcode(ERRCODE_PROTOCOL_VIOLATION),
1098  errmsg("non-printable characters in SCRAM nonce")));
1099 
1100  /*
1101  * There can be any number of optional extensions after this. We don't
1102  * support any extensions, so ignore them.
1103  */
1104  while (*p != '\0')
1105  read_any_attr(&p, NULL);
1106 
1107  /* success! */
1108 }
static char * sanitize_str(const char *s)
Definition: auth-scram.c:815
static bool is_scram_printable(char *p)
Definition: auth-scram.c:767

References ereport, errcode(), errdetail(), errmsg(), ERROR, is_scram_printable(), pstrdup(), read_any_attr(), read_attr_value(), sanitize_char(), and sanitize_str().

Referenced by scram_exchange().

◆ sanitize_char()

static char * sanitize_char ( char  c)
static

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

796 {
797  static char buf[5];
798 
799  if (c >= 0x21 && c <= 0x7E)
800  snprintf(buf, sizeof(buf), "'%c'", c);
801  else
802  snprintf(buf, sizeof(buf), "0x%02x", (unsigned char) c);
803  return buf;
804 }
static char * buf
Definition: pg_test_fsync.c:67
char * c

References buf, and snprintf.

Referenced by read_any_attr(), read_attr_value(), and read_client_first_message().

◆ sanitize_str()

static char * sanitize_str ( const char *  s)
static

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

816 {
817  static char buf[30 + 1];
818  int i;
819 
820  for (i = 0; i < sizeof(buf) - 1; i++)
821  {
822  char c = s[i];
823 
824  if (c == '\0')
825  break;
826 
827  if (c >= 0x21 && c <= 0x7E)
828  buf[i] = c;
829  else
830  buf[i] = '?';
831  }
832  buf[i] = '\0';
833  return buf;
834 }
int i
Definition: isn.c:73

References buf, and i.

Referenced by read_client_first_message().

◆ scram_exchange()

static int scram_exchange ( void *  opaq,
const char *  input,
int  inputlen,
char **  output,
int *  outputlen,
const char **  logdetail 
)
static

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

352 {
353  scram_state *state = (scram_state *) opaq;
354  int result;
355 
356  *output = NULL;
357 
358  /*
359  * If the client didn't include an "Initial Client Response" in the
360  * SASLInitialResponse message, send an empty challenge, to which the
361  * client will respond with the same data that usually comes in the
362  * Initial Client Response.
363  */
364  if (input == NULL)
365  {
366  Assert(state->state == SCRAM_AUTH_INIT);
367 
368  *output = pstrdup("");
369  *outputlen = 0;
371  }
372 
373  /*
374  * Check that the input length agrees with the string length of the input.
375  * We can ignore inputlen after this.
376  */
377  if (inputlen == 0)
378  ereport(ERROR,
379  (errcode(ERRCODE_PROTOCOL_VIOLATION),
380  errmsg("malformed SCRAM message"),
381  errdetail("The message is empty.")));
382  if (inputlen != strlen(input))
383  ereport(ERROR,
384  (errcode(ERRCODE_PROTOCOL_VIOLATION),
385  errmsg("malformed SCRAM message"),
386  errdetail("Message length does not match input length.")));
387 
388  switch (state->state)
389  {
390  case SCRAM_AUTH_INIT:
391 
392  /*
393  * Initialization phase. Receive the first message from client
394  * and be sure that it parsed correctly. Then send the challenge
395  * to the client.
396  */
398 
399  /* prepare message to send challenge */
401 
402  state->state = SCRAM_AUTH_SALT_SENT;
403  result = PG_SASL_EXCHANGE_CONTINUE;
404  break;
405 
407 
408  /*
409  * Final phase for the server. Receive the response to the
410  * challenge previously sent, verify, and let the client know that
411  * everything went well (or not).
412  */
414 
416  ereport(ERROR,
417  (errcode(ERRCODE_PROTOCOL_VIOLATION),
418  errmsg("invalid SCRAM response"),
419  errdetail("Nonce does not match.")));
420 
421  /*
422  * Now check the final nonce and the client proof.
423  *
424  * If we performed a "mock" authentication that we knew would fail
425  * from the get go, this is where we fail.
426  *
427  * The SCRAM specification includes an error code,
428  * "invalid-proof", for authentication failure, but it also allows
429  * erroring out in an application-specific way. We choose to do
430  * the latter, so that the error message for invalid password is
431  * the same for all authentication methods. The caller will call
432  * ereport(), when we return PG_SASL_EXCHANGE_FAILURE with no
433  * output.
434  *
435  * NB: the order of these checks is intentional. We calculate the
436  * client proof even in a mock authentication, even though it's
437  * bound to fail, to thwart timing attacks to determine if a role
438  * with the given name exists or not.
439  */
440  if (!verify_client_proof(state) || state->doomed)
441  {
442  result = PG_SASL_EXCHANGE_FAILURE;
443  break;
444  }
445 
446  /* Build final message for client */
448 
449  /* Success! */
450  result = PG_SASL_EXCHANGE_SUCCESS;
451  state->state = SCRAM_AUTH_FINISHED;
452  break;
453 
454  default:
455  elog(ERROR, "invalid SCRAM exchange state");
456  result = PG_SASL_EXCHANGE_FAILURE;
457  }
458 
459  if (result == PG_SASL_EXCHANGE_FAILURE && state->logdetail && logdetail)
460  *logdetail = state->logdetail;
461 
462  if (*output)
463  *outputlen = strlen(*output);
464 
465  return result;
466 }
static char * build_server_first_message(scram_state *state)
Definition: auth-scram.c:1191
static void read_client_first_message(scram_state *state, const char *input)
Definition: auth-scram.c:901
static bool verify_client_proof(scram_state *state)
Definition: auth-scram.c:1137
static bool verify_final_nonce(scram_state *state)
Definition: auth-scram.c:1115
static void read_client_final_message(scram_state *state, const char *input)
Definition: auth-scram.c:1255
static char * build_server_final_message(scram_state *state)
Definition: auth-scram.c:1401
static void output(uint64 loop_count)
#define PG_SASL_EXCHANGE_FAILURE
Definition: sasl.h:27
#define PG_SASL_EXCHANGE_CONTINUE
Definition: sasl.h:25
#define PG_SASL_EXCHANGE_SUCCESS
Definition: sasl.h:26

References Assert(), build_server_final_message(), build_server_first_message(), elog(), ereport, errcode(), errdetail(), errmsg(), ERROR, output(), PG_SASL_EXCHANGE_CONTINUE, PG_SASL_EXCHANGE_FAILURE, PG_SASL_EXCHANGE_SUCCESS, pstrdup(), read_client_final_message(), read_client_first_message(), SCRAM_AUTH_FINISHED, SCRAM_AUTH_INIT, SCRAM_AUTH_SALT_SENT, verify_client_proof(), and verify_final_nonce().

◆ scram_get_mechanisms()

static void scram_get_mechanisms ( Port port,
StringInfo  buf 
)
static

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

203 {
204  /*
205  * Advertise the mechanisms in decreasing order of importance. So the
206  * channel-binding variants go first, if they are supported. Channel
207  * binding is only supported with SSL, and only if the SSL implementation
208  * has a function to get the certificate's hash.
209  */
210 #ifdef HAVE_BE_TLS_GET_CERTIFICATE_HASH
211  if (port->ssl_in_use)
212  {
214  appendStringInfoChar(buf, '\0');
215  }
216 #endif
218  appendStringInfoChar(buf, '\0');
219 }
static int port
Definition: pg_regress.c:90
#define SCRAM_SHA_256_PLUS_NAME
Definition: scram-common.h:21
#define SCRAM_SHA_256_NAME
Definition: scram-common.h:20
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188

References appendStringInfoChar(), appendStringInfoString(), buf, port, SCRAM_SHA_256_NAME, and SCRAM_SHA_256_PLUS_NAME.

◆ scram_init()

static void * scram_init ( Port port,
const char *  selected_mech,
const char *  shadow_pass 
)
static

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

238 {
240  bool got_secret;
241 
242  state = (scram_state *) palloc0(sizeof(scram_state));
243  state->port = port;
244  state->state = SCRAM_AUTH_INIT;
245 
246  /*
247  * Parse the selected mechanism.
248  *
249  * Note that if we don't support channel binding, either because the SSL
250  * implementation doesn't support it or we're not using SSL at all, we
251  * would not have advertised the PLUS variant in the first place. If the
252  * client nevertheless tries to select it, it's a protocol violation like
253  * selecting any other SASL mechanism we don't support.
254  */
255 #ifdef HAVE_BE_TLS_GET_CERTIFICATE_HASH
256  if (strcmp(selected_mech, SCRAM_SHA_256_PLUS_NAME) == 0 && port->ssl_in_use)
257  state->channel_binding_in_use = true;
258  else
259 #endif
260  if (strcmp(selected_mech, SCRAM_SHA_256_NAME) == 0)
261  state->channel_binding_in_use = false;
262  else
263  ereport(ERROR,
264  (errcode(ERRCODE_PROTOCOL_VIOLATION),
265  errmsg("client selected an invalid SASL authentication mechanism")));
266 
267  /*
268  * Parse the stored secret.
269  */
270  if (shadow_pass)
271  {
272  int password_type = get_password_type(shadow_pass);
273 
274  if (password_type == PASSWORD_TYPE_SCRAM_SHA_256)
275  {
276  if (parse_scram_secret(shadow_pass, &state->iterations,
277  &state->hash_type, &state->key_length,
278  &state->salt,
279  state->StoredKey,
280  state->ServerKey))
281  got_secret = true;
282  else
283  {
284  /*
285  * The password looked like a SCRAM secret, but could not be
286  * parsed.
287  */
288  ereport(LOG,
289  (errmsg("invalid SCRAM secret for user \"%s\"",
290  state->port->user_name)));
291  got_secret = false;
292  }
293  }
294  else
295  {
296  /*
297  * The user doesn't have SCRAM secret. (You cannot do SCRAM
298  * authentication with an MD5 hash.)
299  */
300  state->logdetail = psprintf(_("User \"%s\" does not have a valid SCRAM secret."),
301  state->port->user_name);
302  got_secret = false;
303  }
304  }
305  else
306  {
307  /*
308  * The caller requested us to perform a dummy authentication. This is
309  * considered normal, since the caller requested it, so don't set log
310  * detail.
311  */
312  got_secret = false;
313  }
314 
315  /*
316  * If the user did not have a valid SCRAM secret, we still go through the
317  * motions with a mock one, and fail as if the client supplied an
318  * incorrect password. This is to avoid revealing information to an
319  * attacker.
320  */
321  if (!got_secret)
322  {
323  mock_scram_secret(state->port->user_name, &state->hash_type,
324  &state->iterations, &state->key_length,
325  &state->salt,
326  state->StoredKey, state->ServerKey);
327  state->doomed = true;
328  }
329 
330  return state;
331 }
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:591
static void mock_scram_secret(const char *username, pg_cryptohash_type *hash_type, int *iterations, int *key_length, char **salt, uint8 *stored_key, uint8 *server_key)
Definition: auth-scram.c:685
PasswordType get_password_type(const char *shadow_pass)
Definition: crypt.c:89
@ PASSWORD_TYPE_SCRAM_SHA_256
Definition: crypt.h:31
#define _(x)
Definition: elog.c:91
#define LOG
Definition: elog.h:31
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
void * palloc0(Size size)
Definition: mcxt.c:1241

References _, ereport, errcode(), errmsg(), ERROR, get_password_type(), if(), LOG, mock_scram_secret(), palloc0(), parse_scram_secret(), PASSWORD_TYPE_SCRAM_SHA_256, port, psprintf(), SCRAM_AUTH_INIT, SCRAM_SHA_256_NAME, and SCRAM_SHA_256_PLUS_NAME.

◆ scram_mock_salt()

static char * scram_mock_salt ( const char *  username,
pg_cryptohash_type  hash_type,
int  key_length 
)
static

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

1462 {
1463  pg_cryptohash_ctx *ctx;
1464  static uint8 sha_digest[SCRAM_MAX_KEY_LEN];
1465  char *mock_auth_nonce = GetMockAuthenticationNonce();
1466 
1467  /*
1468  * Generate salt using a SHA256 hash of the username and the cluster's
1469  * mock authentication nonce. (This works as long as the salt length is
1470  * not larger than the SHA256 digest length. If the salt is smaller, the
1471  * caller will just ignore the extra data.)
1472  */
1474  "salt length greater than SHA256 digest length");
1475 
1476  /*
1477  * This may be worth refreshing if support for more hash methods is\
1478  * added.
1479  */
1480  Assert(hash_type == PG_SHA256);
1481 
1482  ctx = pg_cryptohash_create(hash_type);
1483  if (pg_cryptohash_init(ctx) < 0 ||
1484  pg_cryptohash_update(ctx, (uint8 *) username, strlen(username)) < 0 ||
1485  pg_cryptohash_update(ctx, (uint8 *) mock_auth_nonce, MOCK_AUTH_NONCE_LEN) < 0 ||
1486  pg_cryptohash_final(ctx, sha_digest, key_length) < 0)
1487  {
1488  pg_cryptohash_free(ctx);
1489  return NULL;
1490  }
1491  pg_cryptohash_free(ctx);
1492 
1493  return (char *) sha_digest;
1494 }
#define StaticAssertDecl(condition, errmessage)
Definition: c.h:920
int pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len)
Definition: cryptohash.c:139
int pg_cryptohash_init(pg_cryptohash_ctx *ctx)
Definition: cryptohash.c:101
void pg_cryptohash_free(pg_cryptohash_ctx *ctx)
Definition: cryptohash.c:243
pg_cryptohash_ctx * pg_cryptohash_create(pg_cryptohash_type type)
Definition: cryptohash.c:74
int pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest, size_t len)
Definition: cryptohash.c:177
#define MOCK_AUTH_NONCE_LEN
Definition: pg_control.h:28
#define PG_SHA256_DIGEST_LENGTH
Definition: sha2.h:23
char * GetMockAuthenticationNonce(void)
Definition: xlog.c:4184

References Assert(), GetMockAuthenticationNonce(), MOCK_AUTH_NONCE_LEN, pg_cryptohash_create(), pg_cryptohash_final(), pg_cryptohash_free(), pg_cryptohash_init(), pg_cryptohash_update(), PG_SHA256, PG_SHA256_DIGEST_LENGTH, SCRAM_DEFAULT_SALT_LEN, SCRAM_MAX_KEY_LEN, StaticAssertDecl, and username.

Referenced by mock_scram_secret().

◆ scram_verify_plain_password()

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

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

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

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().

◆ verify_client_proof()

static bool verify_client_proof ( scram_state state)
static

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

1138 {
1139  uint8 ClientSignature[SCRAM_MAX_KEY_LEN];
1140  uint8 ClientKey[SCRAM_MAX_KEY_LEN];
1141  uint8 client_StoredKey[SCRAM_MAX_KEY_LEN];
1142  pg_hmac_ctx *ctx = pg_hmac_create(state->hash_type);
1143  int i;
1144  const char *errstr = NULL;
1145 
1146  /*
1147  * Calculate ClientSignature. Note that we don't log directly a failure
1148  * here even when processing the calculations as this could involve a mock
1149  * authentication.
1150  */
1151  if (pg_hmac_init(ctx, state->StoredKey, state->key_length) < 0 ||
1152  pg_hmac_update(ctx,
1153  (uint8 *) state->client_first_message_bare,
1154  strlen(state->client_first_message_bare)) < 0 ||
1155  pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
1156  pg_hmac_update(ctx,
1157  (uint8 *) state->server_first_message,
1158  strlen(state->server_first_message)) < 0 ||
1159  pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
1160  pg_hmac_update(ctx,
1161  (uint8 *) state->client_final_message_without_proof,
1162  strlen(state->client_final_message_without_proof)) < 0 ||
1163  pg_hmac_final(ctx, ClientSignature, state->key_length) < 0)
1164  {
1165  elog(ERROR, "could not calculate client signature: %s",
1166  pg_hmac_error(ctx));
1167  }
1168 
1169  pg_hmac_free(ctx);
1170 
1171  /* Extract the ClientKey that the client calculated from the proof */
1172  for (i = 0; i < state->key_length; i++)
1173  ClientKey[i] = state->ClientProof[i] ^ ClientSignature[i];
1174 
1175  /* Hash it one more time, and compare with StoredKey */
1176  if (scram_H(ClientKey, state->hash_type, state->key_length,
1177  client_StoredKey, &errstr) < 0)
1178  elog(ERROR, "could not hash stored key: %s", errstr);
1179 
1180  if (memcmp(client_StoredKey, state->StoredKey, state->key_length) != 0)
1181  return false;
1182 
1183  return true;
1184 }
int scram_H(const uint8 *input, pg_cryptohash_type hash_type, int key_length, uint8 *result, const char **errstr)
Definition: scram-common.c:101

References elog(), ERROR, i, if(), pg_hmac_create(), pg_hmac_error(), pg_hmac_final(), pg_hmac_free(), pg_hmac_init(), pg_hmac_update(), scram_H(), and SCRAM_MAX_KEY_LEN.

Referenced by scram_exchange().

◆ verify_final_nonce()

static bool verify_final_nonce ( scram_state state)
static

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

1116 {
1117  int client_nonce_len = strlen(state->client_nonce);
1118  int server_nonce_len = strlen(state->server_nonce);
1119  int final_nonce_len = strlen(state->client_final_nonce);
1120 
1121  if (final_nonce_len != client_nonce_len + server_nonce_len)
1122  return false;
1123  if (memcmp(state->client_final_nonce, state->client_nonce, client_nonce_len) != 0)
1124  return false;
1125  if (memcmp(state->client_final_nonce + client_nonce_len, state->server_nonce, server_nonce_len) != 0)
1126  return false;
1127 
1128  return true;
1129 }

Referenced by scram_exchange().

Variable Documentation

◆ pg_be_scram_mech

const pg_be_sasl_mech pg_be_scram_mech
Initial value:
= {
}
static void * scram_init(Port *port, const char *selected_mech, const char *shadow_pass)
Definition: auth-scram.c:237
static int scram_exchange(void *opaq, const char *input, int inputlen, char **output, int *outputlen, const char **logdetail)
Definition: auth-scram.c:350
static void scram_get_mechanisms(Port *port, StringInfo buf)
Definition: auth-scram.c:202

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

Referenced by CheckPWChallengeAuth().