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

Go to the source code of this file.

Data Structures

struct  scram_state
 

Enumerations

enum  scram_state_enum { SCRAM_AUTH_INIT, SCRAM_AUTH_SALT_SENT, SCRAM_AUTH_FINISHED }
 

Functions

static void scram_get_mechanisms (Port *port, StringInfo buf)
 
static void * scram_init (Port *port, const char *selected_mech, const char *shadow_pass)
 
static int scram_exchange (void *opaq, const char *input, int inputlen, char **output, int *outputlen, char **logdetail)
 
static void read_client_first_message (scram_state *state, const char *input)
 
static void read_client_final_message (scram_state *state, const char *input)
 
static char * build_server_first_message (scram_state *state)
 
static char * build_server_final_message (scram_state *state)
 
static bool verify_client_proof (scram_state *state)
 
static bool verify_final_nonce (scram_state *state)
 
static void mock_scram_secret (const char *username, 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)
 
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)
 

Variables

const pg_be_sasl_mech pg_be_scram_mech
 

Enumeration Type Documentation

◆ scram_state_enum

Enumerator
SCRAM_AUTH_INIT 
SCRAM_AUTH_SALT_SENT 
SCRAM_AUTH_FINISHED 

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

Function Documentation

◆ build_server_final_message()

static char * build_server_final_message ( scram_state state)
static

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

1370 {
1371  uint8 ServerSignature[SCRAM_KEY_LEN];
1372  char *server_signature_base64;
1373  int siglen;
1375 
1376  /* calculate ServerSignature */
1377  if (pg_hmac_init(ctx, state->ServerKey, SCRAM_KEY_LEN) < 0 ||
1378  pg_hmac_update(ctx,
1379  (uint8 *) state->client_first_message_bare,
1380  strlen(state->client_first_message_bare)) < 0 ||
1381  pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
1382  pg_hmac_update(ctx,
1383  (uint8 *) state->server_first_message,
1384  strlen(state->server_first_message)) < 0 ||
1385  pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
1386  pg_hmac_update(ctx,
1388  strlen(state->client_final_message_without_proof)) < 0 ||
1389  pg_hmac_final(ctx, ServerSignature, sizeof(ServerSignature)) < 0)
1390  {
1391  elog(ERROR, "could not calculate server signature");
1392  }
1393 
1394  pg_hmac_free(ctx);
1395 
1396  siglen = pg_b64_enc_len(SCRAM_KEY_LEN);
1397  /* don't forget the zero-terminator */
1398  server_signature_base64 = palloc(siglen + 1);
1399  siglen = pg_b64_encode((const char *) ServerSignature,
1400  SCRAM_KEY_LEN, server_signature_base64,
1401  siglen);
1402  if (siglen < 0)
1403  elog(ERROR, "could not encode server signature");
1404  server_signature_base64[siglen] = '\0';
1405 
1406  /*------
1407  * The syntax for the server-final-message is: (RFC 5802)
1408  *
1409  * verifier = "v=" base64
1410  * ;; base-64 encoded ServerSignature.
1411  *
1412  * server-final-message = (server-error / verifier)
1413  * ["," extensions]
1414  *
1415  *------
1416  */
1417  return psprintf("v=%s", server_signature_base64);
1418 }
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:155
#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:160
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:260
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:146
#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:150

◆ build_server_first_message()

static char * build_server_first_message ( scram_state state)
static

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

1160 {
1161  /*------
1162  * The syntax for the server-first-message is: (RFC 5802)
1163  *
1164  * server-first-message =
1165  * [reserved-mext ","] nonce "," salt ","
1166  * iteration-count ["," extensions]
1167  *
1168  * nonce = "r=" c-nonce [s-nonce]
1169  * ;; Second part provided by server.
1170  *
1171  * c-nonce = printable
1172  *
1173  * s-nonce = printable
1174  *
1175  * salt = "s=" base64
1176  *
1177  * iteration-count = "i=" posit-number
1178  * ;; A positive number.
1179  *
1180  * Example:
1181  *
1182  * r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096
1183  *------
1184  */
1185 
1186  /*
1187  * Per the spec, the nonce may consist of any printable ASCII characters.
1188  * For convenience, however, we don't use the whole range available,
1189  * rather, we generate some random bytes, and base64 encode them.
1190  */
1191  char raw_nonce[SCRAM_RAW_NONCE_LEN];
1192  int encoded_len;
1193 
1194  if (!pg_strong_random(raw_nonce, SCRAM_RAW_NONCE_LEN))
1195  ereport(ERROR,
1196  (errcode(ERRCODE_INTERNAL_ERROR),
1197  errmsg("could not generate random nonce")));
1198 
1199  encoded_len = pg_b64_enc_len(SCRAM_RAW_NONCE_LEN);
1200  /* don't forget the zero-terminator */
1201  state->server_nonce = palloc(encoded_len + 1);
1202  encoded_len = pg_b64_encode(raw_nonce, SCRAM_RAW_NONCE_LEN,
1203  state->server_nonce, encoded_len);
1204  if (encoded_len < 0)
1205  ereport(ERROR,
1206  (errcode(ERRCODE_INTERNAL_ERROR),
1207  errmsg("could not encode random nonce")));
1208  state->server_nonce[encoded_len] = '\0';
1209 
1210  state->server_first_message =
1211  psprintf("r=%s%s,s=%s,i=%d",
1212  state->client_nonce, state->server_nonce,
1213  state->salt, state->iterations);
1214 
1215  return pstrdup(state->server_first_message);
1216 }
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:152
#define ERROR
Definition: elog.h:46
int iterations
Definition: auth-scram.c:143
char * salt
Definition: auth-scram.c:144
char * server_first_message
Definition: auth-scram.c:160
#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:161
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 738 of file auth-scram.c.

Referenced by read_client_first_message().

739 {
740  /*------
741  * Printable characters, as defined by SCRAM spec: (RFC 5802)
742  *
743  * printable = %x21-2B / %x2D-7E
744  * ;; Printable ASCII except ",".
745  * ;; Note that any "printable" is also
746  * ;; a valid "value".
747  *------
748  */
749  for (; *p; p++)
750  {
751  if (*p < 0x21 || *p > 0x7E || *p == 0x2C /* comma */ )
752  return false;
753  }
754  return true;
755 }

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

663 {
664  char *raw_salt;
665  char *encoded_salt;
666  int encoded_len;
667 
668  /*
669  * Generate deterministic salt.
670  *
671  * Note that we cannot reveal any information to an attacker here so the
672  * error messages need to remain generic. This should never fail anyway
673  * as the salt generated for mock authentication uses the cluster's nonce
674  * value.
675  */
676  raw_salt = scram_mock_salt(username);
677  if (raw_salt == NULL)
678  elog(ERROR, "could not encode salt");
679 
680  encoded_len = pg_b64_enc_len(SCRAM_DEFAULT_SALT_LEN);
681  /* don't forget the zero-terminator */
682  encoded_salt = (char *) palloc(encoded_len + 1);
683  encoded_len = pg_b64_encode(raw_salt, SCRAM_DEFAULT_SALT_LEN, encoded_salt,
684  encoded_len);
685 
686  if (encoded_len < 0)
687  elog(ERROR, "could not encode salt");
688  encoded_salt[encoded_len] = '\0';
689 
690  *salt = encoded_salt;
691  *iterations = SCRAM_DEFAULT_ITERATIONS;
692 
693  /* StoredKey and ServerKey are not used in a doomed authentication */
694  memset(stored_key, 0, SCRAM_KEY_LEN);
695  memset(server_key, 0, SCRAM_KEY_LEN);
696 }
static char * scram_mock_salt(const char *username)
Definition: auth-scram.c:1427
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:282
#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 570 of file auth-scram.c.

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

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

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

462 {
463  char *prep_password;
464  pg_saslprep_rc rc;
465  char saltbuf[SCRAM_DEFAULT_SALT_LEN];
466  char *result;
467 
468  /*
469  * Normalize the password with SASLprep. If that doesn't work, because
470  * the password isn't valid UTF-8 or contains prohibited characters, just
471  * proceed with the original password. (See comments at top of file.)
472  */
473  rc = pg_saslprep(password, &prep_password);
474  if (rc == SASLPREP_SUCCESS)
475  password = (const char *) prep_password;
476 
477  /* Generate random salt */
479  ereport(ERROR,
480  (errcode(ERRCODE_INTERNAL_ERROR),
481  errmsg("could not generate random salt")));
482 
483  result = scram_build_secret(saltbuf, SCRAM_DEFAULT_SALT_LEN,
485 
486  if (prep_password)
487  pfree(prep_password);
488 
489  return result;
490 }
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

◆ read_any_attr()

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

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

815 {
816  char *begin = *input;
817  char *end;
818  char attr = *begin;
819 
820  if (attr == '\0')
821  ereport(ERROR,
822  (errcode(ERRCODE_PROTOCOL_VIOLATION),
823  errmsg("malformed SCRAM message"),
824  errdetail("Attribute expected, but found end of string.")));
825 
826  /*------
827  * attr-val = ALPHA "=" value
828  * ;; Generic syntax of any attribute sent
829  * ;; by server or client
830  *------
831  */
832  if (!((attr >= 'A' && attr <= 'Z') ||
833  (attr >= 'a' && attr <= 'z')))
834  ereport(ERROR,
835  (errcode(ERRCODE_PROTOCOL_VIOLATION),
836  errmsg("malformed SCRAM message"),
837  errdetail("Attribute expected, but found invalid character \"%s\".",
838  sanitize_char(attr))));
839  if (attr_p)
840  *attr_p = attr;
841  begin++;
842 
843  if (*begin != '=')
844  ereport(ERROR,
845  (errcode(ERRCODE_PROTOCOL_VIOLATION),
846  errmsg("malformed SCRAM message"),
847  errdetail("Expected character \"=\" for attribute \"%c\".", attr)));
848  begin++;
849 
850  end = begin;
851  while (*end && *end != ',')
852  end++;
853 
854  if (*end)
855  {
856  *end = '\0';
857  *input = end + 1;
858  }
859  else
860  *input = end;
861 
862  return begin;
863 }
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:766
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 702 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().

703 {
704  char *begin = *input;
705  char *end;
706 
707  if (*begin != attr)
708  ereport(ERROR,
709  (errcode(ERRCODE_PROTOCOL_VIOLATION),
710  errmsg("malformed SCRAM message"),
711  errdetail("Expected attribute \"%c\" but found \"%s\".",
712  attr, sanitize_char(*begin))));
713  begin++;
714 
715  if (*begin != '=')
716  ereport(ERROR,
717  (errcode(ERRCODE_PROTOCOL_VIOLATION),
718  errmsg("malformed SCRAM message"),
719  errdetail("Expected character \"=\" for attribute \"%c\".", attr)));
720  begin++;
721 
722  end = begin;
723  while (*end && *end != ',')
724  end++;
725 
726  if (*end)
727  {
728  *end = '\0';
729  *input = end + 1;
730  }
731  else
732  *input = end;
733 
734  return begin;
735 }
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:766
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 1223 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 scram_exchange().

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

◆ read_client_first_message()

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

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

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

◆ sanitize_char()

static char * sanitize_char ( char  c)
static

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

References buf, and snprintf.

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

767 {
768  static char buf[5];
769 
770  if (c >= 0x21 && c <= 0x7E)
771  snprintf(buf, sizeof(buf), "'%c'", c);
772  else
773  snprintf(buf, sizeof(buf), "0x%02x", (unsigned char) c);
774  return buf;
775 }
char * c
static char * buf
Definition: pg_test_fsync.c:68
#define snprintf
Definition: port.h:217

◆ sanitize_str()

static char * sanitize_str ( const char *  s)
static

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

References buf, and i.

Referenced by read_client_first_message().

787 {
788  static char buf[30 + 1];
789  int i;
790 
791  for (i = 0; i < sizeof(buf) - 1; i++)
792  {
793  char c = s[i];
794 
795  if (c == '\0')
796  break;
797 
798  if (c >= 0x21 && c <= 0x7E)
799  buf[i] = c;
800  else
801  buf[i] = '?';
802  }
803  buf[i] = '\0';
804  return buf;
805 }
char * c
static char * buf
Definition: pg_test_fsync.c:68
int i

◆ scram_exchange()

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

Definition at line 337 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, PG_SASL_EXCHANGE_CONTINUE, PG_SASL_EXCHANGE_FAILURE, PG_SASL_EXCHANGE_SUCCESS, pstrdup(), read_client_final_message(), read_client_first_message(), SCRAM_AUTH_FINISHED, SCRAM_AUTH_INIT, SCRAM_AUTH_SALT_SENT, scram_state::state, verify_client_proof(), and verify_final_nonce().

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

◆ scram_get_mechanisms()

static void scram_get_mechanisms ( Port port,
StringInfo  buf 
)
static

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

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

195 {
196  /*
197  * Advertise the mechanisms in decreasing order of importance. So the
198  * channel-binding variants go first, if they are supported. Channel
199  * binding is only supported with SSL, and only if the SSL implementation
200  * has a function to get the certificate's hash.
201  */
202 #ifdef HAVE_BE_TLS_GET_CERTIFICATE_HASH
203  if (port->ssl_in_use)
204  {
206  appendStringInfoChar(buf, '\0');
207  }
208 #endif
210  appendStringInfoChar(buf, '\0');
211 }
#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

◆ scram_init()

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

Definition at line 229 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.

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

◆ scram_mock_salt()

static char * scram_mock_salt ( const char *  username)
static

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

1428 {
1429  pg_cryptohash_ctx *ctx;
1430  static uint8 sha_digest[PG_SHA256_DIGEST_LENGTH];
1431  char *mock_auth_nonce = GetMockAuthenticationNonce();
1432 
1433  /*
1434  * Generate salt using a SHA256 hash of the username and the cluster's
1435  * mock authentication nonce. (This works as long as the salt length is
1436  * not larger than the SHA256 digest length. If the salt is smaller, the
1437  * caller will just ignore the extra data.)
1438  */
1440  "salt length greater than SHA256 digest length");
1441 
1443  if (pg_cryptohash_init(ctx) < 0 ||
1444  pg_cryptohash_update(ctx, (uint8 *) username, strlen(username)) < 0 ||
1445  pg_cryptohash_update(ctx, (uint8 *) mock_auth_nonce, MOCK_AUTH_NONCE_LEN) < 0 ||
1446  pg_cryptohash_final(ctx, sha_digest, sizeof(sha_digest)) < 0)
1447  {
1448  pg_cryptohash_free(ctx);
1449  return NULL;
1450  }
1451  pg_cryptohash_free(ctx);
1452 
1453  return (char *) sha_digest;
1454 }
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:23
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:282
#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:5008
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 498 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().

500 {
501  char *encoded_salt;
502  char *salt;
503  int saltlen;
504  int iterations;
505  uint8 salted_password[SCRAM_KEY_LEN];
506  uint8 stored_key[SCRAM_KEY_LEN];
507  uint8 server_key[SCRAM_KEY_LEN];
508  uint8 computed_key[SCRAM_KEY_LEN];
509  char *prep_password;
510  pg_saslprep_rc rc;
511 
512  if (!parse_scram_secret(secret, &iterations, &encoded_salt,
513  stored_key, server_key))
514  {
515  /*
516  * The password looked like a SCRAM secret, but could not be parsed.
517  */
518  ereport(LOG,
519  (errmsg("invalid SCRAM secret for user \"%s\"", username)));
520  return false;
521  }
522 
523  saltlen = pg_b64_dec_len(strlen(encoded_salt));
524  salt = palloc(saltlen);
525  saltlen = pg_b64_decode(encoded_salt, strlen(encoded_salt), salt,
526  saltlen);
527  if (saltlen < 0)
528  {
529  ereport(LOG,
530  (errmsg("invalid SCRAM secret for user \"%s\"", username)));
531  return false;
532  }
533 
534  /* Normalize the password */
535  rc = pg_saslprep(password, &prep_password);
536  if (rc == SASLPREP_SUCCESS)
537  password = prep_password;
538 
539  /* Compute Server Key based on the user-supplied plaintext password */
540  if (scram_SaltedPassword(password, salt, saltlen, iterations,
541  salted_password) < 0 ||
542  scram_ServerKey(salted_password, computed_key) < 0)
543  {
544  elog(ERROR, "could not compute server key");
545  }
546 
547  if (prep_password)
548  pfree(prep_password);
549 
550  /*
551  * Compare the secret's Server Key with the one computed from the
552  * user-supplied password.
553  */
554  return memcmp(computed_key, server_key, SCRAM_KEY_LEN) == 0;
555 }
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:282
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:570
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 1108 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 scram_exchange().

1109 {
1110  uint8 ClientSignature[SCRAM_KEY_LEN];
1111  uint8 ClientKey[SCRAM_KEY_LEN];
1112  uint8 client_StoredKey[SCRAM_KEY_LEN];
1114  int i;
1115 
1116  /*
1117  * Calculate ClientSignature. Note that we don't log directly a failure
1118  * here even when processing the calculations as this could involve a mock
1119  * authentication.
1120  */
1121  if (pg_hmac_init(ctx, state->StoredKey, SCRAM_KEY_LEN) < 0 ||
1122  pg_hmac_update(ctx,
1123  (uint8 *) state->client_first_message_bare,
1124  strlen(state->client_first_message_bare)) < 0 ||
1125  pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
1126  pg_hmac_update(ctx,
1127  (uint8 *) state->server_first_message,
1128  strlen(state->server_first_message)) < 0 ||
1129  pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
1130  pg_hmac_update(ctx,
1132  strlen(state->client_final_message_without_proof)) < 0 ||
1133  pg_hmac_final(ctx, ClientSignature, sizeof(ClientSignature)) < 0)
1134  {
1135  elog(ERROR, "could not calculate client signature");
1136  }
1137 
1138  pg_hmac_free(ctx);
1139 
1140  /* Extract the ClientKey that the client calculated from the proof */
1141  for (i = 0; i < SCRAM_KEY_LEN; i++)
1142  ClientKey[i] = state->ClientProof[i] ^ ClientSignature[i];
1143 
1144  /* Hash it one more time, and compare with StoredKey */
1145  if (scram_H(ClientKey, SCRAM_KEY_LEN, client_StoredKey) < 0)
1146  elog(ERROR, "could not hash stored key");
1147 
1148  if (memcmp(client_StoredKey, state->StoredKey, SCRAM_KEY_LEN) != 0)
1149  return false;
1150 
1151  return true;
1152 }
uint8 StoredKey[SCRAM_KEY_LEN]
Definition: auth-scram.c:145
unsigned char uint8
Definition: c.h:439
char ClientProof[SCRAM_KEY_LEN]
Definition: auth-scram.c:157
pg_hmac_ctx * pg_hmac_create(pg_cryptohash_type type)
Definition: hmac.c:69
char * client_final_message_without_proof
Definition: auth-scram.c:155
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:160
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:260
#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:150

◆ verify_final_nonce()

static bool verify_final_nonce ( scram_state state)
static

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

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

Referenced by scram_exchange().

1087 {
1088  int client_nonce_len = strlen(state->client_nonce);
1089  int server_nonce_len = strlen(state->server_nonce);
1090  int final_nonce_len = strlen(state->client_final_nonce);
1091 
1092  if (final_nonce_len != client_nonce_len + server_nonce_len)
1093  return false;
1094  if (memcmp(state->client_final_nonce, state->client_nonce, client_nonce_len) != 0)
1095  return false;
1096  if (memcmp(state->client_final_nonce + client_nonce_len, state->server_nonce, server_nonce_len) != 0)
1097  return false;
1098 
1099  return true;
1100 }
char * client_nonce
Definition: auth-scram.c:152
char * client_final_nonce
Definition: auth-scram.c:156
char * server_nonce
Definition: auth-scram.c:161

Variable Documentation

◆ pg_be_scram_mech

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

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

Referenced by CheckPWChallengeAuth().