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

Function Documentation

◆ build_server_final_message()

static char * build_server_final_message ( scram_state state)
static

Definition at line 1360 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(), pg_hmac_create(), pg_hmac_final(), pg_hmac_free(), pg_hmac_init(), pg_hmac_update(), PG_SHA256, psprintf(), SCRAM_KEY_LEN, scram_state::server_first_message, and scram_state::ServerKey.

Referenced by pg_be_scram_exchange().

1361 {
1362  uint8 ServerSignature[SCRAM_KEY_LEN];
1363  char *server_signature_base64;
1364  int siglen;
1366 
1367  /* calculate ServerSignature */
1368  if (pg_hmac_init(ctx, state->ServerKey, SCRAM_KEY_LEN) < 0 ||
1369  pg_hmac_update(ctx,
1370  (uint8 *) state->client_first_message_bare,
1371  strlen(state->client_first_message_bare)) < 0 ||
1372  pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
1373  pg_hmac_update(ctx,
1374  (uint8 *) state->server_first_message,
1375  strlen(state->server_first_message)) < 0 ||
1376  pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
1377  pg_hmac_update(ctx,
1379  strlen(state->client_final_message_without_proof)) < 0 ||
1380  pg_hmac_final(ctx, ServerSignature, sizeof(ServerSignature)) < 0)
1381  {
1382  elog(ERROR, "could not calculate server signature");
1383  }
1384 
1385  pg_hmac_free(ctx);
1386 
1387  siglen = pg_b64_enc_len(SCRAM_KEY_LEN);
1388  /* don't forget the zero-terminator */
1389  server_signature_base64 = palloc(siglen + 1);
1390  siglen = pg_b64_encode((const char *) ServerSignature,
1391  SCRAM_KEY_LEN, server_signature_base64,
1392  siglen);
1393  if (siglen < 0)
1394  elog(ERROR, "could not encode server signature");
1395  server_signature_base64[siglen] = '\0';
1396 
1397  /*------
1398  * The syntax for the server-final-message is: (RFC 5802)
1399  *
1400  * verifier = "v=" base64
1401  * ;; base-64 encoded ServerSignature.
1402  *
1403  * server-final-message = (server-error / verifier)
1404  * ["," extensions]
1405  *
1406  *------
1407  */
1408  return psprintf("v=%s", server_signature_base64);
1409 }
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
pg_hmac_ctx * pg_hmac_create(pg_cryptohash_type type)
Definition: hmac.c:69
char * client_final_message_without_proof
Definition: auth-scram.c:141
#define ERROR
Definition: elog.h:46
int pg_hmac_update(pg_hmac_ctx *ctx, const uint8 *data, size_t len)
Definition: hmac.c:205
char * server_first_message
Definition: auth-scram.c:146
int pg_hmac_init(pg_hmac_ctx *ctx, const uint8 *key, size_t len)
Definition: hmac.c:128
void pg_hmac_free(pg_hmac_ctx *ctx)
Definition: hmac.c:255
int pg_b64_enc_len(int srclen)
Definition: base64.c:224
void * palloc(Size size)
Definition: mcxt.c:1062
#define elog(elevel,...)
Definition: elog.h:232
uint8 ServerKey[SCRAM_KEY_LEN]
Definition: auth-scram.c:132
#define SCRAM_KEY_LEN
Definition: scram-common.h:24
int pg_hmac_final(pg_hmac_ctx *ctx, uint8 *dest, size_t len)
Definition: hmac.c:222
char * client_first_message_bare
Definition: auth-scram.c:136

◆ build_server_first_message()

static char * build_server_first_message ( scram_state state)
static

Definition at line 1150 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().

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

◆ is_scram_printable()

static bool is_scram_printable ( char *  p)
static

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

Referenced by read_client_first_message().

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

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

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

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

453 {
454  char *prep_password;
455  pg_saslprep_rc rc;
456  char saltbuf[SCRAM_DEFAULT_SALT_LEN];
457  char *result;
458 
459  /*
460  * Normalize the password with SASLprep. If that doesn't work, because
461  * the password isn't valid UTF-8 or contains prohibited characters, just
462  * proceed with the original password. (See comments at top of file.)
463  */
464  rc = pg_saslprep(password, &prep_password);
465  if (rc == SASLPREP_SUCCESS)
466  password = (const char *) prep_password;
467 
468  /* Generate random salt */
470  ereport(ERROR,
471  (errcode(ERRCODE_INTERNAL_ERROR),
472  errmsg("could not generate random salt")));
473 
474  result = scram_build_secret(saltbuf, SCRAM_DEFAULT_SALT_LEN,
476 
477  if (prep_password)
478  pfree(prep_password);
479 
480  return result;
481 }
int errcode(int sqlerrcode)
Definition: elog.c:698
char * scram_build_secret(const char *salt, int saltlen, int iterations, const char *password)
Definition: scram-common.c:169
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:1169
#define ERROR
Definition: elog.h:46
static char * password
Definition: streamutil.c:53
#define SCRAM_DEFAULT_SALT_LEN
Definition: scram-common.h:41
#define ereport(elevel,...)
Definition: elog.h:157
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:909

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

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

183 {
184  /*
185  * Advertise the mechanisms in decreasing order of importance. So the
186  * channel-binding variants go first, if they are supported. Channel
187  * binding is only supported with SSL, and only if the SSL implementation
188  * has a function to get the certificate's hash.
189  */
190 #ifdef HAVE_BE_TLS_GET_CERTIFICATE_HASH
191  if (port->ssl_in_use)
192  {
194  appendStringInfoChar(buf, '\0');
195  }
196 #endif
198  appendStringInfoChar(buf, '\0');
199 }
#define SCRAM_SHA_256_NAME
Definition: scram-common.h:20
bool ssl_in_use
Definition: libpq-be.h:209
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 219 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().

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

◆ read_any_attr()

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

Definition at line 805 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().

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

◆ read_attr_value()

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

Definition at line 693 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().

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

◆ read_client_final_message()

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

Definition at line 1214 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().

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

◆ read_client_first_message()

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

Definition at line 863 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().

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

◆ sanitize_char()

static char * sanitize_char ( char  c)
static

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

References buf, and snprintf.

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

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

◆ sanitize_str()

static char * sanitize_str ( const char *  s)
static

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

References buf, and i.

Referenced by read_client_first_message().

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

1419 {
1420  pg_cryptohash_ctx *ctx;
1421  static uint8 sha_digest[PG_SHA256_DIGEST_LENGTH];
1422  char *mock_auth_nonce = GetMockAuthenticationNonce();
1423 
1424  /*
1425  * Generate salt using a SHA256 hash of the username and the cluster's
1426  * mock authentication nonce. (This works as long as the salt length is
1427  * not larger than the SHA256 digest length. If the salt is smaller, the
1428  * caller will just ignore the extra data.)
1429  */
1431  "salt length greater than SHA256 digest length");
1432 
1434  if (pg_cryptohash_init(ctx) < 0 ||
1435  pg_cryptohash_update(ctx, (uint8 *) username, strlen(username)) < 0 ||
1436  pg_cryptohash_update(ctx, (uint8 *) mock_auth_nonce, MOCK_AUTH_NONCE_LEN) < 0 ||
1437  pg_cryptohash_final(ctx, sha_digest, sizeof(sha_digest)) < 0)
1438  {
1439  pg_cryptohash_free(ctx);
1440  return NULL;
1441  }
1442  pg_cryptohash_free(ctx);
1443 
1444  return (char *) sha_digest;
1445 }
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
const char * username
Definition: pgbench.c:280
#define SCRAM_DEFAULT_SALT_LEN
Definition: scram-common.h:41
pg_cryptohash_ctx * pg_cryptohash_create(pg_cryptohash_type type)
Definition: cryptohash.c:66
char * GetMockAuthenticationNonce(void)
Definition: xlog.c:4975
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 489 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().

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

◆ verify_client_proof()

static bool verify_client_proof ( scram_state state)
static

Definition at line 1099 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, pg_hmac_create(), pg_hmac_final(), pg_hmac_free(), pg_hmac_init(), pg_hmac_update(), PG_SHA256, scram_H(), SCRAM_KEY_LEN, scram_state::server_first_message, and scram_state::StoredKey.

Referenced by pg_be_scram_exchange().

1100 {
1101  uint8 ClientSignature[SCRAM_KEY_LEN];
1102  uint8 ClientKey[SCRAM_KEY_LEN];
1103  uint8 client_StoredKey[SCRAM_KEY_LEN];
1105  int i;
1106 
1107  /*
1108  * Calculate ClientSignature. Note that we don't log directly a failure
1109  * here even when processing the calculations as this could involve a mock
1110  * authentication.
1111  */
1112  if (pg_hmac_init(ctx, state->StoredKey, SCRAM_KEY_LEN) < 0 ||
1113  pg_hmac_update(ctx,
1114  (uint8 *) state->client_first_message_bare,
1115  strlen(state->client_first_message_bare)) < 0 ||
1116  pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
1117  pg_hmac_update(ctx,
1118  (uint8 *) state->server_first_message,
1119  strlen(state->server_first_message)) < 0 ||
1120  pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
1121  pg_hmac_update(ctx,
1123  strlen(state->client_final_message_without_proof)) < 0 ||
1124  pg_hmac_final(ctx, ClientSignature, sizeof(ClientSignature)) < 0)
1125  {
1126  elog(ERROR, "could not calculate client signature");
1127  }
1128 
1129  pg_hmac_free(ctx);
1130 
1131  /* Extract the ClientKey that the client calculated from the proof */
1132  for (i = 0; i < SCRAM_KEY_LEN; i++)
1133  ClientKey[i] = state->ClientProof[i] ^ ClientSignature[i];
1134 
1135  /* Hash it one more time, and compare with StoredKey */
1136  if (scram_H(ClientKey, SCRAM_KEY_LEN, client_StoredKey) < 0)
1137  elog(ERROR, "could not hash stored key");
1138 
1139  if (memcmp(client_StoredKey, state->StoredKey, SCRAM_KEY_LEN) != 0)
1140  return false;
1141 
1142  return true;
1143 }
uint8 StoredKey[SCRAM_KEY_LEN]
Definition: auth-scram.c:131
unsigned char uint8
Definition: c.h:439
char ClientProof[SCRAM_KEY_LEN]
Definition: auth-scram.c:143
pg_hmac_ctx * pg_hmac_create(pg_cryptohash_type type)
Definition: hmac.c:69
char * client_final_message_without_proof
Definition: auth-scram.c:141
int scram_H(const uint8 *input, int len, uint8 *result)
Definition: scram-common.c:93
#define ERROR
Definition: elog.h:46
int pg_hmac_update(pg_hmac_ctx *ctx, const uint8 *data, size_t len)
Definition: hmac.c:205
char * server_first_message
Definition: auth-scram.c:146
int pg_hmac_init(pg_hmac_ctx *ctx, const uint8 *key, size_t len)
Definition: hmac.c:128
void pg_hmac_free(pg_hmac_ctx *ctx)
Definition: hmac.c:255
#define elog(elevel,...)
Definition: elog.h:232
int i
#define SCRAM_KEY_LEN
Definition: scram-common.h:24
int pg_hmac_final(pg_hmac_ctx *ctx, uint8 *dest, size_t len)
Definition: hmac.c:222
char * client_first_message_bare
Definition: auth-scram.c:136

◆ verify_final_nonce()

static bool verify_final_nonce ( scram_state state)
static

Definition at line 1077 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().

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