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/saslprep.h"
#include "common/scram-common.h"
#include "common/sha2.h"
#include "libpq/auth.h"
#include "libpq/crypt.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 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, int *iterations, 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)
 
void pg_be_scram_get_mechanisms (Port *port, StringInfo buf)
 
void * pg_be_scram_init (Port *port, const char *selected_mech, const char *shadow_pass)
 
int pg_be_scram_exchange (void *opaq, const char *input, int inputlen, char **output, int *outputlen, char **logdetail)
 
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, 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)
 

Enumeration Type Documentation

◆ scram_state_enum

Enumerator
SCRAM_AUTH_INIT 
SCRAM_AUTH_SALT_SENT 
SCRAM_AUTH_FINISHED 

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

Function Documentation

◆ build_server_final_message()

static char * build_server_final_message ( scram_state state)
static

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

References scram_state::client_final_message_without_proof, scram_state::client_first_message_bare, elog, ERROR, palloc(), pg_b64_enc_len(), pg_b64_encode(), psprintf(), scram_HMAC_final(), scram_HMAC_init(), scram_HMAC_update(), SCRAM_KEY_LEN, scram_state::server_first_message, and scram_state::ServerKey.

Referenced by pg_be_scram_exchange().

1358 {
1359  uint8 ServerSignature[SCRAM_KEY_LEN];
1360  char *server_signature_base64;
1361  int siglen;
1362  scram_HMAC_ctx ctx;
1363 
1364  /* calculate ServerSignature */
1365  if (scram_HMAC_init(&ctx, state->ServerKey, SCRAM_KEY_LEN) < 0 ||
1366  scram_HMAC_update(&ctx,
1368  strlen(state->client_first_message_bare)) < 0 ||
1369  scram_HMAC_update(&ctx, ",", 1) < 0 ||
1370  scram_HMAC_update(&ctx,
1371  state->server_first_message,
1372  strlen(state->server_first_message)) < 0 ||
1373  scram_HMAC_update(&ctx, ",", 1) < 0 ||
1374  scram_HMAC_update(&ctx,
1376  strlen(state->client_final_message_without_proof)) < 0 ||
1377  scram_HMAC_final(ServerSignature, &ctx) < 0)
1378  {
1379  elog(ERROR, "could not calculate server signature");
1380  }
1381 
1382  siglen = pg_b64_enc_len(SCRAM_KEY_LEN);
1383  /* don't forget the zero-terminator */
1384  server_signature_base64 = palloc(siglen + 1);
1385  siglen = pg_b64_encode((const char *) ServerSignature,
1386  SCRAM_KEY_LEN, server_signature_base64,
1387  siglen);
1388  if (siglen < 0)
1389  elog(ERROR, "could not encode server signature");
1390  server_signature_base64[siglen] = '\0';
1391 
1392  /*------
1393  * The syntax for the server-final-message is: (RFC 5802)
1394  *
1395  * verifier = "v=" base64
1396  * ;; base-64 encoded ServerSignature.
1397  *
1398  * server-final-message = (server-error / verifier)
1399  * ["," extensions]
1400  *
1401  *------
1402  */
1403  return psprintf("v=%s", server_signature_base64);
1404 }
int pg_b64_encode(const char *src, int len, char *dst, int dstlen)
Definition: base64.c:49
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
unsigned char uint8
Definition: c.h:439
char * client_final_message_without_proof
Definition: auth-scram.c:140
#define ERROR
Definition: elog.h:45
char * server_first_message
Definition: auth-scram.c:145
int scram_HMAC_init(scram_HMAC_ctx *ctx, const uint8 *key, int keylen)
Definition: scram-common.c:35
int scram_HMAC_final(uint8 *result, scram_HMAC_ctx *ctx)
Definition: scram-common.c:109
int pg_b64_enc_len(int srclen)
Definition: base64.c:224
int scram_HMAC_update(scram_HMAC_ctx *ctx, const char *str, int slen)
Definition: scram-common.c:93
void * palloc(Size size)
Definition: mcxt.c:950
#define elog(elevel,...)
Definition: elog.h:228
uint8 ServerKey[SCRAM_KEY_LEN]
Definition: auth-scram.c:131
#define SCRAM_KEY_LEN
Definition: scram-common.h:24
char * client_first_message_bare
Definition: auth-scram.c:135

◆ build_server_first_message()

static char * build_server_first_message ( scram_state state)
static

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

References scram_state::client_nonce, ereport, errcode(), errmsg(), ERROR, scram_state::iterations, palloc(), pg_b64_enc_len(), pg_b64_encode(), pg_strong_random(), psprintf(), pstrdup(), scram_state::salt, SCRAM_RAW_NONCE_LEN, scram_state::server_first_message, and scram_state::server_nonce.

Referenced by pg_be_scram_exchange().

1148 {
1149  /*------
1150  * The syntax for the server-first-message is: (RFC 5802)
1151  *
1152  * server-first-message =
1153  * [reserved-mext ","] nonce "," salt ","
1154  * iteration-count ["," extensions]
1155  *
1156  * nonce = "r=" c-nonce [s-nonce]
1157  * ;; Second part provided by server.
1158  *
1159  * c-nonce = printable
1160  *
1161  * s-nonce = printable
1162  *
1163  * salt = "s=" base64
1164  *
1165  * iteration-count = "i=" posit-number
1166  * ;; A positive number.
1167  *
1168  * Example:
1169  *
1170  * r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096
1171  *------
1172  */
1173 
1174  /*
1175  * Per the spec, the nonce may consist of any printable ASCII characters.
1176  * For convenience, however, we don't use the whole range available,
1177  * rather, we generate some random bytes, and base64 encode them.
1178  */
1179  char raw_nonce[SCRAM_RAW_NONCE_LEN];
1180  int encoded_len;
1181 
1182  if (!pg_strong_random(raw_nonce, SCRAM_RAW_NONCE_LEN))
1183  ereport(ERROR,
1184  (errcode(ERRCODE_INTERNAL_ERROR),
1185  errmsg("could not generate random nonce")));
1186 
1187  encoded_len = pg_b64_enc_len(SCRAM_RAW_NONCE_LEN);
1188  /* don't forget the zero-terminator */
1189  state->server_nonce = palloc(encoded_len + 1);
1190  encoded_len = pg_b64_encode(raw_nonce, SCRAM_RAW_NONCE_LEN,
1191  state->server_nonce, encoded_len);
1192  if (encoded_len < 0)
1193  ereport(ERROR,
1194  (errcode(ERRCODE_INTERNAL_ERROR),
1195  errmsg("could not encode random nonce")));
1196  state->server_nonce[encoded_len] = '\0';
1197 
1198  state->server_first_message =
1199  psprintf("r=%s%s,s=%s,i=%u",
1200  state->client_nonce, state->server_nonce,
1201  state->salt, state->iterations);
1202 
1203  return pstrdup(state->server_first_message);
1204 }
int pg_b64_encode(const char *src, int len, char *dst, int dstlen)
Definition: base64.c:49
char * pstrdup(const char *in)
Definition: mcxt.c:1187
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
int errcode(int sqlerrcode)
Definition: elog.c:704
char * client_nonce
Definition: auth-scram.c:137
#define ERROR
Definition: elog.h:45
int iterations
Definition: auth-scram.c:128
char * salt
Definition: auth-scram.c:129
char * server_first_message
Definition: auth-scram.c:145
#define ereport(elevel,...)
Definition: elog.h:155
#define SCRAM_RAW_NONCE_LEN
Definition: scram-common.h:34
bool pg_strong_random(void *buf, size_t len)
char * server_nonce
Definition: auth-scram.c:146
int pg_b64_enc_len(int srclen)
Definition: base64.c:224
void * palloc(Size size)
Definition: mcxt.c:950
int errmsg(const char *fmt,...)
Definition: elog.c:915

◆ is_scram_printable()

static bool is_scram_printable ( char *  p)
static

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

Referenced by read_client_first_message().

729 {
730  /*------
731  * Printable characters, as defined by SCRAM spec: (RFC 5802)
732  *
733  * printable = %x21-2B / %x2D-7E
734  * ;; Printable ASCII except ",".
735  * ;; Note that any "printable" is also
736  * ;; a valid "value".
737  *------
738  */
739  for (; *p; p++)
740  {
741  if (*p < 0x21 || *p > 0x7E || *p == 0x2C /* comma */ )
742  return false;
743  }
744  return true;
745 }

◆ mock_scram_secret()

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

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

References elog, ERROR, palloc(), pg_b64_enc_len(), pg_b64_encode(), SCRAM_DEFAULT_ITERATIONS, SCRAM_DEFAULT_SALT_LEN, SCRAM_KEY_LEN, and scram_mock_salt().

Referenced by pg_be_scram_init().

653 {
654  char *raw_salt;
655  char *encoded_salt;
656  int encoded_len;
657 
658  /*
659  * Generate deterministic salt.
660  *
661  * Note that we cannot reveal any information to an attacker here so the
662  * error messages need to remain generic. This should never fail anyway
663  * as the salt generated for mock authentication uses the cluster's nonce
664  * value.
665  */
666  raw_salt = scram_mock_salt(username);
667  if (raw_salt == NULL)
668  elog(ERROR, "could not encode salt");
669 
670  encoded_len = pg_b64_enc_len(SCRAM_DEFAULT_SALT_LEN);
671  /* don't forget the zero-terminator */
672  encoded_salt = (char *) palloc(encoded_len + 1);
673  encoded_len = pg_b64_encode(raw_salt, SCRAM_DEFAULT_SALT_LEN, encoded_salt,
674  encoded_len);
675 
676  if (encoded_len < 0)
677  elog(ERROR, "could not encode salt");
678  encoded_salt[encoded_len] = '\0';
679 
680  *salt = encoded_salt;
681  *iterations = SCRAM_DEFAULT_ITERATIONS;
682 
683  /* StoredKey and ServerKey are not used in a doomed authentication */
684  memset(stored_key, 0, SCRAM_KEY_LEN);
685  memset(server_key, 0, SCRAM_KEY_LEN);
686 }
static char * scram_mock_salt(const char *username)
Definition: auth-scram.c:1413
int pg_b64_encode(const char *src, int len, char *dst, int dstlen)
Definition: base64.c:49
#define ERROR
Definition: elog.h:45
#define SCRAM_DEFAULT_SALT_LEN
Definition: scram-common.h:41
static char * username
Definition: initdb.c:134
#define SCRAM_DEFAULT_ITERATIONS
Definition: scram-common.h:47
int pg_b64_enc_len(int srclen)
Definition: base64.c:224
void * palloc(Size size)
Definition: mcxt.c:950
#define elog(elevel,...)
Definition: elog.h:228
#define SCRAM_KEY_LEN
Definition: scram-common.h:24

◆ parse_scram_secret()

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

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

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

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

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

◆ pg_be_scram_build_secret()

char* pg_be_scram_build_secret ( const char *  password)

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

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

Referenced by encrypt_password().

452 {
453  char *prep_password;
454  pg_saslprep_rc rc;
455  char saltbuf[SCRAM_DEFAULT_SALT_LEN];
456  char *result;
457 
458  /*
459  * Normalize the password with SASLprep. If that doesn't work, because
460  * the password isn't valid UTF-8 or contains prohibited characters, just
461  * proceed with the original password. (See comments at top of file.)
462  */
463  rc = pg_saslprep(password, &prep_password);
464  if (rc == SASLPREP_SUCCESS)
465  password = (const char *) prep_password;
466 
467  /* Generate random salt */
469  ereport(ERROR,
470  (errcode(ERRCODE_INTERNAL_ERROR),
471  errmsg("could not generate random salt")));
472 
473  result = scram_build_secret(saltbuf, SCRAM_DEFAULT_SALT_LEN,
475 
476  if (prep_password)
477  pfree(prep_password);
478 
479  return result;
480 }
int errcode(int sqlerrcode)
Definition: elog.c:704
char * scram_build_secret(const char *salt, int saltlen, int iterations, const char *password)
Definition: scram-common.c:261
pg_saslprep_rc pg_saslprep(const char *input, char **output)
Definition: saslprep.c:1044
pg_saslprep_rc
Definition: saslprep.h:20
void pfree(void *pointer)
Definition: mcxt.c:1057
#define ERROR
Definition: elog.h:45
static char * password
Definition: streamutil.c:53
#define SCRAM_DEFAULT_SALT_LEN
Definition: scram-common.h:41
#define ereport(elevel,...)
Definition: elog.h:155
bool pg_strong_random(void *buf, size_t len)
#define SCRAM_DEFAULT_ITERATIONS
Definition: scram-common.h:47
int errmsg(const char *fmt,...)
Definition: elog.c:915

◆ pg_be_scram_exchange()

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

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

References Assert, build_server_final_message(), build_server_first_message(), scram_state::doomed, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, scram_state::logdetail, pstrdup(), read_client_final_message(), read_client_first_message(), SASL_EXCHANGE_CONTINUE, SASL_EXCHANGE_FAILURE, SASL_EXCHANGE_SUCCESS, SCRAM_AUTH_FINISHED, SCRAM_AUTH_INIT, SCRAM_AUTH_SALT_SENT, scram_state::state, verify_client_proof(), and verify_final_nonce().

Referenced by CheckSCRAMAuth().

330 {
331  scram_state *state = (scram_state *) opaq;
332  int result;
333 
334  *output = NULL;
335 
336  /*
337  * If the client didn't include an "Initial Client Response" in the
338  * SASLInitialResponse message, send an empty challenge, to which the
339  * client will respond with the same data that usually comes in the
340  * Initial Client Response.
341  */
342  if (input == NULL)
343  {
344  Assert(state->state == SCRAM_AUTH_INIT);
345 
346  *output = pstrdup("");
347  *outputlen = 0;
348  return SASL_EXCHANGE_CONTINUE;
349  }
350 
351  /*
352  * Check that the input length agrees with the string length of the input.
353  * We can ignore inputlen after this.
354  */
355  if (inputlen == 0)
356  ereport(ERROR,
357  (errcode(ERRCODE_PROTOCOL_VIOLATION),
358  errmsg("malformed SCRAM message"),
359  errdetail("The message is empty.")));
360  if (inputlen != strlen(input))
361  ereport(ERROR,
362  (errcode(ERRCODE_PROTOCOL_VIOLATION),
363  errmsg("malformed SCRAM message"),
364  errdetail("Message length does not match input length.")));
365 
366  switch (state->state)
367  {
368  case SCRAM_AUTH_INIT:
369 
370  /*
371  * Initialization phase. Receive the first message from client
372  * and be sure that it parsed correctly. Then send the challenge
373  * to the client.
374  */
375  read_client_first_message(state, input);
376 
377  /* prepare message to send challenge */
379 
380  state->state = SCRAM_AUTH_SALT_SENT;
381  result = SASL_EXCHANGE_CONTINUE;
382  break;
383 
385 
386  /*
387  * Final phase for the server. Receive the response to the
388  * challenge previously sent, verify, and let the client know that
389  * everything went well (or not).
390  */
391  read_client_final_message(state, input);
392 
393  if (!verify_final_nonce(state))
394  ereport(ERROR,
395  (errcode(ERRCODE_PROTOCOL_VIOLATION),
396  errmsg("invalid SCRAM response"),
397  errdetail("Nonce does not match.")));
398 
399  /*
400  * Now check the final nonce and the client proof.
401  *
402  * If we performed a "mock" authentication that we knew would fail
403  * from the get go, this is where we fail.
404  *
405  * The SCRAM specification includes an error code,
406  * "invalid-proof", for authentication failure, but it also allows
407  * erroring out in an application-specific way. We choose to do
408  * the latter, so that the error message for invalid password is
409  * the same for all authentication methods. The caller will call
410  * ereport(), when we return SASL_EXCHANGE_FAILURE with no output.
411  *
412  * NB: the order of these checks is intentional. We calculate the
413  * client proof even in a mock authentication, even though it's
414  * bound to fail, to thwart timing attacks to determine if a role
415  * with the given name exists or not.
416  */
417  if (!verify_client_proof(state) || state->doomed)
418  {
419  result = SASL_EXCHANGE_FAILURE;
420  break;
421  }
422 
423  /* Build final message for client */
425 
426  /* Success! */
427  result = SASL_EXCHANGE_SUCCESS;
428  state->state = SCRAM_AUTH_FINISHED;
429  break;
430 
431  default:
432  elog(ERROR, "invalid SCRAM exchange state");
433  result = SASL_EXCHANGE_FAILURE;
434  }
435 
436  if (result == SASL_EXCHANGE_FAILURE && state->logdetail && logdetail)
437  *logdetail = state->logdetail;
438 
439  if (*output)
440  *outputlen = strlen(*output);
441 
442  return result;
443 }
static void output(uint64 loop_count)
char * pstrdup(const char *in)
Definition: mcxt.c:1187
#define SASL_EXCHANGE_FAILURE
Definition: scram.h:22
#define SASL_EXCHANGE_SUCCESS
Definition: scram.h:21
int errcode(int sqlerrcode)
Definition: elog.c:704
#define ERROR
Definition: elog.h:45
static void read_client_first_message(scram_state *state, const char *input)
Definition: auth-scram.c:862
static bool verify_client_proof(scram_state *state)
Definition: auth-scram.c:1098
int errdetail(const char *fmt,...)
Definition: elog.c:1048
scram_state_enum state
Definition: auth-scram.c:121
#define ereport(elevel,...)
Definition: elog.h:155
#define Assert(condition)
Definition: c.h:804
Definition: regguts.h:317
static char * build_server_final_message(scram_state *state)
Definition: auth-scram.c:1357
static void read_client_final_message(scram_state *state, const char *input)
Definition: auth-scram.c:1211
int errmsg(const char *fmt,...)
Definition: elog.c:915
#define elog(elevel,...)
Definition: elog.h:228
static bool verify_final_nonce(scram_state *state)
Definition: auth-scram.c:1076
char * logdetail
Definition: auth-scram.c:155
static char * build_server_first_message(scram_state *state)
Definition: auth-scram.c:1147
#define SASL_EXCHANGE_CONTINUE
Definition: scram.h:20

◆ pg_be_scram_get_mechanisms()

void pg_be_scram_get_mechanisms ( Port port,
StringInfo  buf 
)

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

References appendStringInfoChar(), appendStringInfoString(), SCRAM_SHA_256_NAME, SCRAM_SHA_256_PLUS_NAME, and Port::ssl_in_use.

Referenced by CheckSCRAMAuth().

182 {
183  /*
184  * Advertise the mechanisms in decreasing order of importance. So the
185  * channel-binding variants go first, if they are supported. Channel
186  * binding is only supported with SSL, and only if the SSL implementation
187  * has a function to get the certificate's hash.
188  */
189 #ifdef HAVE_BE_TLS_GET_CERTIFICATE_HASH
190  if (port->ssl_in_use)
191  {
193  appendStringInfoChar(buf, '\0');
194  }
195 #endif
197  appendStringInfoChar(buf, '\0');
198 }
#define SCRAM_SHA_256_NAME
Definition: scram-common.h:20
bool ssl_in_use
Definition: libpq-be.h:191
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
#define SCRAM_SHA_256_PLUS_NAME
Definition: scram-common.h:21
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188

◆ pg_be_scram_init()

void* pg_be_scram_init ( Port port,
const char *  selected_mech,
const char *  shadow_pass 
)

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

References _, scram_state::channel_binding_in_use, scram_state::doomed, ereport, errcode(), errmsg(), ERROR, get_password_type(), scram_state::iterations, LOG, scram_state::logdetail, mock_scram_secret(), palloc0(), parse_scram_secret(), PASSWORD_TYPE_SCRAM_SHA_256, port, scram_state::port, psprintf(), scram_state::salt, SCRAM_AUTH_INIT, SCRAM_SHA_256_NAME, SCRAM_SHA_256_PLUS_NAME, scram_state::ServerKey, Port::ssl_in_use, scram_state::state, scram_state::StoredKey, and Port::user_name.

Referenced by CheckSCRAMAuth().

221 {
223  bool got_secret;
224 
225  state = (scram_state *) palloc0(sizeof(scram_state));
226  state->port = port;
227  state->state = SCRAM_AUTH_INIT;
228 
229  /*
230  * Parse the selected mechanism.
231  *
232  * Note that if we don't support channel binding, either because the SSL
233  * implementation doesn't support it or we're not using SSL at all, we
234  * would not have advertised the PLUS variant in the first place. If the
235  * client nevertheless tries to select it, it's a protocol violation like
236  * selecting any other SASL mechanism we don't support.
237  */
238 #ifdef HAVE_BE_TLS_GET_CERTIFICATE_HASH
239  if (strcmp(selected_mech, SCRAM_SHA_256_PLUS_NAME) == 0 && port->ssl_in_use)
240  state->channel_binding_in_use = true;
241  else
242 #endif
243  if (strcmp(selected_mech, SCRAM_SHA_256_NAME) == 0)
244  state->channel_binding_in_use = false;
245  else
246  ereport(ERROR,
247  (errcode(ERRCODE_PROTOCOL_VIOLATION),
248  errmsg("client selected an invalid SASL authentication mechanism")));
249 
250  /*
251  * Parse the stored secret.
252  */
253  if (shadow_pass)
254  {
255  int password_type = get_password_type(shadow_pass);
256 
257  if (password_type == PASSWORD_TYPE_SCRAM_SHA_256)
258  {
259  if (parse_scram_secret(shadow_pass, &state->iterations, &state->salt,
260  state->StoredKey, state->ServerKey))
261  got_secret = true;
262  else
263  {
264  /*
265  * The password looked like a SCRAM secret, but could not be
266  * parsed.
267  */
268  ereport(LOG,
269  (errmsg("invalid SCRAM secret for user \"%s\"",
270  state->port->user_name)));
271  got_secret = false;
272  }
273  }
274  else
275  {
276  /*
277  * The user doesn't have SCRAM secret. (You cannot do SCRAM
278  * authentication with an MD5 hash.)
279  */
280  state->logdetail = psprintf(_("User \"%s\" does not have a valid SCRAM secret."),
281  state->port->user_name);
282  got_secret = false;
283  }
284  }
285  else
286  {
287  /*
288  * The caller requested us to perform a dummy authentication. This is
289  * considered normal, since the caller requested it, so don't set log
290  * detail.
291  */
292  got_secret = false;
293  }
294 
295  /*
296  * If the user did not have a valid SCRAM secret, we still go through the
297  * motions with a mock one, and fail as if the client supplied an
298  * incorrect password. This is to avoid revealing information to an
299  * attacker.
300  */
301  if (!got_secret)
302  {
303  mock_scram_secret(state->port->user_name, &state->iterations,
304  &state->salt, state->StoredKey, state->ServerKey);
305  state->doomed = true;
306  }
307 
308  return state;
309 }
Port * port
Definition: auth-scram.c:125
static void mock_scram_secret(const char *username, int *iterations, char **salt, uint8 *stored_key, uint8 *server_key)
Definition: auth-scram.c:651
#define SCRAM_SHA_256_NAME
Definition: scram-common.h:20
uint8 StoredKey[SCRAM_KEY_LEN]
Definition: auth-scram.c:130
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
int errcode(int sqlerrcode)
Definition: elog.c:704
bool ssl_in_use
Definition: libpq-be.h:191
#define LOG
Definition: elog.h:26
#define ERROR
Definition: elog.h:45
int iterations
Definition: auth-scram.c:128
char * salt
Definition: auth-scram.c:129
#define SCRAM_SHA_256_PLUS_NAME
Definition: scram-common.h:21
char * user_name
Definition: libpq-be.h:141
static int port
Definition: pg_regress.c:92
scram_state_enum state
Definition: auth-scram.c:121
void * palloc0(Size size)
Definition: mcxt.c:981
#define ereport(elevel,...)
Definition: elog.h:155
Definition: regguts.h:317
bool parse_scram_secret(const char *secret, int *iterations, char **salt, uint8 *stored_key, uint8 *server_key)
Definition: auth-scram.c:560
int errmsg(const char *fmt,...)
Definition: elog.c:915
PasswordType get_password_type(const char *shadow_pass)
Definition: crypt.c:89
char * logdetail
Definition: auth-scram.c:155
bool channel_binding_in_use
Definition: auth-scram.c:126
uint8 ServerKey[SCRAM_KEY_LEN]
Definition: auth-scram.c:131
#define _(x)
Definition: elog.c:89

◆ read_any_attr()

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

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

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

Referenced by read_client_final_message(), and read_client_first_message().

805 {
806  char *begin = *input;
807  char *end;
808  char attr = *begin;
809 
810  if (attr == '\0')
811  ereport(ERROR,
812  (errcode(ERRCODE_PROTOCOL_VIOLATION),
813  errmsg("malformed SCRAM message"),
814  errdetail("Attribute expected, but found end of string.")));
815 
816  /*------
817  * attr-val = ALPHA "=" value
818  * ;; Generic syntax of any attribute sent
819  * ;; by server or client
820  *------
821  */
822  if (!((attr >= 'A' && attr <= 'Z') ||
823  (attr >= 'a' && attr <= 'z')))
824  ereport(ERROR,
825  (errcode(ERRCODE_PROTOCOL_VIOLATION),
826  errmsg("malformed SCRAM message"),
827  errdetail("Attribute expected, but found invalid character \"%s\".",
828  sanitize_char(attr))));
829  if (attr_p)
830  *attr_p = attr;
831  begin++;
832 
833  if (*begin != '=')
834  ereport(ERROR,
835  (errcode(ERRCODE_PROTOCOL_VIOLATION),
836  errmsg("malformed SCRAM message"),
837  errdetail("Expected character \"=\" for attribute \"%c\".", attr)));
838  begin++;
839 
840  end = begin;
841  while (*end && *end != ',')
842  end++;
843 
844  if (*end)
845  {
846  *end = '\0';
847  *input = end + 1;
848  }
849  else
850  *input = end;
851 
852  return begin;
853 }
int errcode(int sqlerrcode)
Definition: elog.c:704
#define ERROR
Definition: elog.h:45
int errdetail(const char *fmt,...)
Definition: elog.c:1048
#define ereport(elevel,...)
Definition: elog.h:155
static char * sanitize_char(char c)
Definition: auth-scram.c:756
int errmsg(const char *fmt,...)
Definition: elog.c:915

◆ read_attr_value()

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

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

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

Referenced by read_client_final_message(), and read_client_first_message().

693 {
694  char *begin = *input;
695  char *end;
696 
697  if (*begin != attr)
698  ereport(ERROR,
699  (errcode(ERRCODE_PROTOCOL_VIOLATION),
700  errmsg("malformed SCRAM message"),
701  errdetail("Expected attribute \"%c\" but found \"%s\".",
702  attr, sanitize_char(*begin))));
703  begin++;
704 
705  if (*begin != '=')
706  ereport(ERROR,
707  (errcode(ERRCODE_PROTOCOL_VIOLATION),
708  errmsg("malformed SCRAM message"),
709  errdetail("Expected character \"=\" for attribute \"%c\".", attr)));
710  begin++;
711 
712  end = begin;
713  while (*end && *end != ',')
714  end++;
715 
716  if (*end)
717  {
718  *end = '\0';
719  *input = end + 1;
720  }
721  else
722  *input = end;
723 
724  return begin;
725 }
int errcode(int sqlerrcode)
Definition: elog.c:704
#define ERROR
Definition: elog.h:45
int errdetail(const char *fmt,...)
Definition: elog.c:1048
#define ereport(elevel,...)
Definition: elog.h:155
static char * sanitize_char(char c)
Definition: auth-scram.c:756
int errmsg(const char *fmt,...)
Definition: elog.c:915

◆ read_client_final_message()

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

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

References Assert, scram_state::cbind_flag, scram_state::channel_binding_in_use, scram_state::client_final_message_without_proof, scram_state::client_final_nonce, scram_state::ClientProof, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, palloc(), pfree(), pg_b64_dec_len(), pg_b64_decode(), pg_b64_enc_len(), pg_b64_encode(), scram_state::port, pstrdup(), read_any_attr(), read_attr_value(), SCRAM_KEY_LEN, snprintf, and value.

Referenced by pg_be_scram_exchange().

1212 {
1213  char attr;
1214  char *channel_binding;
1215  char *value;
1216  char *begin,
1217  *proof;
1218  char *p;
1219  char *client_proof;
1220  int client_proof_len;
1221 
1222  begin = p = pstrdup(input);
1223 
1224  /*------
1225  * The syntax for the server-first-message is: (RFC 5802)
1226  *
1227  * gs2-header = gs2-cbind-flag "," [ authzid ] ","
1228  * ;; GS2 header for SCRAM
1229  * ;; (the actual GS2 header includes an optional
1230  * ;; flag to indicate that the GSS mechanism is not
1231  * ;; "standard", but since SCRAM is "standard", we
1232  * ;; don't include that flag).
1233  *
1234  * cbind-input = gs2-header [ cbind-data ]
1235  * ;; cbind-data MUST be present for
1236  * ;; gs2-cbind-flag of "p" and MUST be absent
1237  * ;; for "y" or "n".
1238  *
1239  * channel-binding = "c=" base64
1240  * ;; base64 encoding of cbind-input.
1241  *
1242  * proof = "p=" base64
1243  *
1244  * client-final-message-without-proof =
1245  * channel-binding "," nonce [","
1246  * extensions]
1247  *
1248  * client-final-message =
1249  * client-final-message-without-proof "," proof
1250  *------
1251  */
1252 
1253  /*
1254  * Read channel binding. This repeats the channel-binding flags and is
1255  * then followed by the actual binding data depending on the type.
1256  */
1257  channel_binding = read_attr_value(&p, 'c');
1258  if (state->channel_binding_in_use)
1259  {
1260 #ifdef HAVE_BE_TLS_GET_CERTIFICATE_HASH
1261  const char *cbind_data = NULL;
1262  size_t cbind_data_len = 0;
1263  size_t cbind_header_len;
1264  char *cbind_input;
1265  size_t cbind_input_len;
1266  char *b64_message;
1267  int b64_message_len;
1268 
1269  Assert(state->cbind_flag == 'p');
1270 
1271  /* Fetch hash data of server's SSL certificate */
1272  cbind_data = be_tls_get_certificate_hash(state->port,
1273  &cbind_data_len);
1274 
1275  /* should not happen */
1276  if (cbind_data == NULL || cbind_data_len == 0)
1277  elog(ERROR, "could not get server certificate hash");
1278 
1279  cbind_header_len = strlen("p=tls-server-end-point,,"); /* p=type,, */
1280  cbind_input_len = cbind_header_len + cbind_data_len;
1281  cbind_input = palloc(cbind_input_len);
1282  snprintf(cbind_input, cbind_input_len, "p=tls-server-end-point,,");
1283  memcpy(cbind_input + cbind_header_len, cbind_data, cbind_data_len);
1284 
1285  b64_message_len = pg_b64_enc_len(cbind_input_len);
1286  /* don't forget the zero-terminator */
1287  b64_message = palloc(b64_message_len + 1);
1288  b64_message_len = pg_b64_encode(cbind_input, cbind_input_len,
1289  b64_message, b64_message_len);
1290  if (b64_message_len < 0)
1291  elog(ERROR, "could not encode channel binding data");
1292  b64_message[b64_message_len] = '\0';
1293 
1294  /*
1295  * Compare the value sent by the client with the value expected by the
1296  * server.
1297  */
1298  if (strcmp(channel_binding, b64_message) != 0)
1299  ereport(ERROR,
1300  (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
1301  errmsg("SCRAM channel binding check failed")));
1302 #else
1303  /* shouldn't happen, because we checked this earlier already */
1304  elog(ERROR, "channel binding not supported by this build");
1305 #endif
1306  }
1307  else
1308  {
1309  /*
1310  * If we are not using channel binding, the binding data is expected
1311  * to always be "biws", which is "n,," base64-encoded, or "eSws",
1312  * which is "y,,". We also have to check whether the flag is the same
1313  * one that the client originally sent.
1314  */
1315  if (!(strcmp(channel_binding, "biws") == 0 && state->cbind_flag == 'n') &&
1316  !(strcmp(channel_binding, "eSws") == 0 && state->cbind_flag == 'y'))
1317  ereport(ERROR,
1318  (errcode(ERRCODE_PROTOCOL_VIOLATION),
1319  errmsg("unexpected SCRAM channel-binding attribute in client-final-message")));
1320  }
1321 
1322  state->client_final_nonce = read_attr_value(&p, 'r');
1323 
1324  /* ignore optional extensions, read until we find "p" attribute */
1325  do
1326  {
1327  proof = p - 1;
1328  value = read_any_attr(&p, &attr);
1329  } while (attr != 'p');
1330 
1331  client_proof_len = pg_b64_dec_len(strlen(value));
1332  client_proof = palloc(client_proof_len);
1333  if (pg_b64_decode(value, strlen(value), client_proof,
1334  client_proof_len) != SCRAM_KEY_LEN)
1335  ereport(ERROR,
1336  (errcode(ERRCODE_PROTOCOL_VIOLATION),
1337  errmsg("malformed SCRAM message"),
1338  errdetail("Malformed proof in client-final-message.")));
1339  memcpy(state->ClientProof, client_proof, SCRAM_KEY_LEN);
1340  pfree(client_proof);
1341 
1342  if (*p != '\0')
1343  ereport(ERROR,
1344  (errcode(ERRCODE_PROTOCOL_VIOLATION),
1345  errmsg("malformed SCRAM message"),
1346  errdetail("Garbage found at the end of client-final-message.")));
1347 
1348  state->client_final_message_without_proof = palloc(proof - begin + 1);
1349  memcpy(state->client_final_message_without_proof, input, proof - begin);
1350  state->client_final_message_without_proof[proof - begin] = '\0';
1351 }
Port * port
Definition: auth-scram.c:125
int pg_b64_encode(const char *src, int len, char *dst, int dstlen)
Definition: base64.c:49
char * pstrdup(const char *in)
Definition: mcxt.c:1187
int errcode(int sqlerrcode)
Definition: elog.c:704
char ClientProof[SCRAM_KEY_LEN]
Definition: auth-scram.c:142
char * client_final_message_without_proof
Definition: auth-scram.c:140
int pg_b64_dec_len(int srclen)
Definition: base64.c:239
static struct @141 value
void pfree(void *pointer)
Definition: mcxt.c:1057
#define ERROR
Definition: elog.h:45
int errdetail(const char *fmt,...)
Definition: elog.c:1048
int pg_b64_decode(const char *src, int len, char *dst, int dstlen)
Definition: base64.c:116
char cbind_flag
Definition: auth-scram.c:134
char * client_final_nonce
Definition: auth-scram.c:141
#define ereport(elevel,...)
Definition: elog.h:155
#define Assert(condition)
Definition: c.h:804
static char * read_any_attr(char **input, char *attr_p)
Definition: auth-scram.c:804
int pg_b64_enc_len(int srclen)
Definition: base64.c:224
static char * read_attr_value(char **input, char attr)
Definition: auth-scram.c:692
void * palloc(Size size)
Definition: mcxt.c:950
int errmsg(const char *fmt,...)
Definition: elog.c:915
#define elog(elevel,...)
Definition: elog.h:228
bool channel_binding_in_use
Definition: auth-scram.c:126
#define SCRAM_KEY_LEN
Definition: scram-common.h:24
#define snprintf
Definition: port.h:215

◆ read_client_first_message()

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

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

References scram_state::cbind_flag, scram_state::channel_binding_in_use, scram_state::client_first_message_bare, scram_state::client_nonce, scram_state::client_username, ereport, errcode(), errdetail(), errmsg(), ERROR, is_scram_printable(), scram_state::port, pstrdup(), read_any_attr(), read_attr_value(), sanitize_char(), sanitize_str(), and Port::ssl_in_use.

Referenced by pg_be_scram_exchange().

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

◆ sanitize_char()

static char * sanitize_char ( char  c)
static

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

References buf, and snprintf.

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

757 {
758  static char buf[5];
759 
760  if (c >= 0x21 && c <= 0x7E)
761  snprintf(buf, sizeof(buf), "'%c'", c);
762  else
763  snprintf(buf, sizeof(buf), "0x%02x", (unsigned char) c);
764  return buf;
765 }
char * c
static char * buf
Definition: pg_test_fsync.c:68
#define snprintf
Definition: port.h:215

◆ sanitize_str()

static char * sanitize_str ( const char *  s)
static

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

References buf, and i.

Referenced by read_client_first_message().

777 {
778  static char buf[30 + 1];
779  int i;
780 
781  for (i = 0; i < sizeof(buf) - 1; i++)
782  {
783  char c = s[i];
784 
785  if (c == '\0')
786  break;
787 
788  if (c >= 0x21 && c <= 0x7E)
789  buf[i] = c;
790  else
791  buf[i] = '?';
792  }
793  buf[i] = '\0';
794  return buf;
795 }
char * c
static char * buf
Definition: pg_test_fsync.c:68
int i

◆ scram_mock_salt()

static char * scram_mock_salt ( const char *  username)
static

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

References 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, and StaticAssertStmt.

Referenced by mock_scram_secret().

1414 {
1415  pg_cryptohash_ctx *ctx;
1416  static uint8 sha_digest[PG_SHA256_DIGEST_LENGTH];
1417  char *mock_auth_nonce = GetMockAuthenticationNonce();
1418 
1419  /*
1420  * Generate salt using a SHA256 hash of the username and the cluster's
1421  * mock authentication nonce. (This works as long as the salt length is
1422  * not larger than the SHA256 digest length. If the salt is smaller, the
1423  * caller will just ignore the extra data.)
1424  */
1426  "salt length greater than SHA256 digest length");
1427 
1429  if (pg_cryptohash_init(ctx) < 0 ||
1430  pg_cryptohash_update(ctx, (uint8 *) username, strlen(username)) < 0 ||
1431  pg_cryptohash_update(ctx, (uint8 *) mock_auth_nonce, MOCK_AUTH_NONCE_LEN) < 0 ||
1432  pg_cryptohash_final(ctx, sha_digest, sizeof(sha_digest)) < 0)
1433  {
1434  pg_cryptohash_free(ctx);
1435  return NULL;
1436  }
1437  pg_cryptohash_free(ctx);
1438 
1439  return (char *) sha_digest;
1440 }
int pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest, size_t len)
Definition: cryptohash.c:168
#define PG_SHA256_DIGEST_LENGTH
Definition: sha2.h:22
unsigned char uint8
Definition: c.h:439
#define MOCK_AUTH_NONCE_LEN
Definition: pg_control.h:28
#define StaticAssertStmt(condition, errmessage)
Definition: c.h:918
#define SCRAM_DEFAULT_SALT_LEN
Definition: scram-common.h:41
static char * username
Definition: initdb.c:134
pg_cryptohash_ctx * pg_cryptohash_create(pg_cryptohash_type type)
Definition: cryptohash.c:66
char * GetMockAuthenticationNonce(void)
Definition: xlog.c:4941
int pg_cryptohash_init(pg_cryptohash_ctx *ctx)
Definition: cryptohash.c:92
int pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len)
Definition: cryptohash.c:130
void pg_cryptohash_free(pg_cryptohash_ctx *ctx)
Definition: cryptohash.c:216

◆ scram_verify_plain_password()

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

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

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

Referenced by plain_crypt_verify().

490 {
491  char *encoded_salt;
492  char *salt;
493  int saltlen;
494  int iterations;
495  uint8 salted_password[SCRAM_KEY_LEN];
496  uint8 stored_key[SCRAM_KEY_LEN];
497  uint8 server_key[SCRAM_KEY_LEN];
498  uint8 computed_key[SCRAM_KEY_LEN];
499  char *prep_password;
500  pg_saslprep_rc rc;
501 
502  if (!parse_scram_secret(secret, &iterations, &encoded_salt,
503  stored_key, server_key))
504  {
505  /*
506  * The password looked like a SCRAM secret, but could not be parsed.
507  */
508  ereport(LOG,
509  (errmsg("invalid SCRAM secret for user \"%s\"", username)));
510  return false;
511  }
512 
513  saltlen = pg_b64_dec_len(strlen(encoded_salt));
514  salt = palloc(saltlen);
515  saltlen = pg_b64_decode(encoded_salt, strlen(encoded_salt), salt,
516  saltlen);
517  if (saltlen < 0)
518  {
519  ereport(LOG,
520  (errmsg("invalid SCRAM secret for user \"%s\"", username)));
521  return false;
522  }
523 
524  /* Normalize the password */
525  rc = pg_saslprep(password, &prep_password);
526  if (rc == SASLPREP_SUCCESS)
527  password = prep_password;
528 
529  /* Compute Server Key based on the user-supplied plaintext password */
530  if (scram_SaltedPassword(password, salt, saltlen, iterations,
531  salted_password) < 0 ||
532  scram_ServerKey(salted_password, computed_key) < 0)
533  {
534  elog(ERROR, "could not compute server key");
535  }
536 
537  if (prep_password)
538  pfree(prep_password);
539 
540  /*
541  * Compare the secret's Server Key with the one computed from the
542  * user-supplied password.
543  */
544  return memcmp(computed_key, server_key, SCRAM_KEY_LEN) == 0;
545 }
unsigned char uint8
Definition: c.h:439
pg_saslprep_rc pg_saslprep(const char *input, char **output)
Definition: saslprep.c:1044
#define LOG
Definition: elog.h:26
int scram_ServerKey(const uint8 *salted_password, uint8 *result)
Definition: scram-common.c:237
int pg_b64_dec_len(int srclen)
Definition: base64.c:239
pg_saslprep_rc
Definition: saslprep.h:20
void pfree(void *pointer)
Definition: mcxt.c:1057
#define ERROR
Definition: elog.h:45
static char * password
Definition: streamutil.c:53
int pg_b64_decode(const char *src, int len, char *dst, int dstlen)
Definition: base64.c:116
static char * username
Definition: initdb.c:134
#define ereport(elevel,...)
Definition: elog.h:155
int scram_SaltedPassword(const char *password, const char *salt, int saltlen, int iterations, uint8 *result)
Definition: scram-common.c:142
bool parse_scram_secret(const char *secret, int *iterations, char **salt, uint8 *stored_key, uint8 *server_key)
Definition: auth-scram.c:560
void * palloc(Size size)
Definition: mcxt.c:950
int errmsg(const char *fmt,...)
Definition: elog.c:915
#define elog(elevel,...)
Definition: elog.h:228
#define SCRAM_KEY_LEN
Definition: scram-common.h:24

◆ verify_client_proof()

static bool verify_client_proof ( scram_state state)
static

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

References scram_state::client_final_message_without_proof, scram_state::client_first_message_bare, scram_state::ClientProof, elog, ERROR, i, scram_H(), scram_HMAC_final(), scram_HMAC_init(), scram_HMAC_update(), SCRAM_KEY_LEN, scram_state::server_first_message, and scram_state::StoredKey.

Referenced by pg_be_scram_exchange().

1099 {
1100  uint8 ClientSignature[SCRAM_KEY_LEN];
1101  uint8 ClientKey[SCRAM_KEY_LEN];
1102  uint8 client_StoredKey[SCRAM_KEY_LEN];
1103  scram_HMAC_ctx ctx;
1104  int i;
1105 
1106  /*
1107  * Calculate ClientSignature. Note that we don't log directly a failure
1108  * here even when processing the calculations as this could involve a mock
1109  * authentication.
1110  */
1111  if (scram_HMAC_init(&ctx, state->StoredKey, SCRAM_KEY_LEN) < 0 ||
1112  scram_HMAC_update(&ctx,
1114  strlen(state->client_first_message_bare)) < 0 ||
1115  scram_HMAC_update(&ctx, ",", 1) < 0 ||
1116  scram_HMAC_update(&ctx,
1117  state->server_first_message,
1118  strlen(state->server_first_message)) < 0 ||
1119  scram_HMAC_update(&ctx, ",", 1) < 0 ||
1120  scram_HMAC_update(&ctx,
1122  strlen(state->client_final_message_without_proof)) < 0 ||
1123  scram_HMAC_final(ClientSignature, &ctx) < 0)
1124  {
1125  elog(ERROR, "could not calculate client signature");
1126  }
1127 
1128  /* Extract the ClientKey that the client calculated from the proof */
1129  for (i = 0; i < SCRAM_KEY_LEN; i++)
1130  ClientKey[i] = state->ClientProof[i] ^ ClientSignature[i];
1131 
1132  /* Hash it one more time, and compare with StoredKey */
1133  if (scram_H(ClientKey, SCRAM_KEY_LEN, client_StoredKey) < 0)
1134  elog(ERROR, "could not hash stored key");
1135 
1136  if (memcmp(client_StoredKey, state->StoredKey, SCRAM_KEY_LEN) != 0)
1137  return false;
1138 
1139  return true;
1140 }
uint8 StoredKey[SCRAM_KEY_LEN]
Definition: auth-scram.c:130
unsigned char uint8
Definition: c.h:439
char ClientProof[SCRAM_KEY_LEN]
Definition: auth-scram.c:142
char * client_final_message_without_proof
Definition: auth-scram.c:140
int scram_H(const uint8 *input, int len, uint8 *result)
Definition: scram-common.c:195
#define ERROR
Definition: elog.h:45
char * server_first_message
Definition: auth-scram.c:145
int scram_HMAC_init(scram_HMAC_ctx *ctx, const uint8 *key, int keylen)
Definition: scram-common.c:35
int scram_HMAC_final(uint8 *result, scram_HMAC_ctx *ctx)
Definition: scram-common.c:109
int scram_HMAC_update(scram_HMAC_ctx *ctx, const char *str, int slen)
Definition: scram-common.c:93
#define elog(elevel,...)
Definition: elog.h:228
int i
#define SCRAM_KEY_LEN
Definition: scram-common.h:24
char * client_first_message_bare
Definition: auth-scram.c:135

◆ verify_final_nonce()

static bool verify_final_nonce ( scram_state state)
static

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

References scram_state::client_final_nonce, scram_state::client_nonce, and scram_state::server_nonce.

Referenced by pg_be_scram_exchange().

1077 {
1078  int client_nonce_len = strlen(state->client_nonce);
1079  int server_nonce_len = strlen(state->server_nonce);
1080  int final_nonce_len = strlen(state->client_final_nonce);
1081 
1082  if (final_nonce_len != client_nonce_len + server_nonce_len)
1083  return false;
1084  if (memcmp(state->client_final_nonce, state->client_nonce, client_nonce_len) != 0)
1085  return false;
1086  if (memcmp(state->client_final_nonce + client_nonce_len, state->server_nonce, server_nonce_len) != 0)
1087  return false;
1088 
1089  return true;
1090 }
char * client_nonce
Definition: auth-scram.c:137
char * client_final_nonce
Definition: auth-scram.c:141
char * server_nonce
Definition: auth-scram.c:146