PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
auth-scram.c File Reference
#include "postgres.h"
#include <unistd.h>
#include "access/xlog.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/crypt.h"
#include "libpq/sasl.h"
#include "libpq/scram.h"
#include "miscadmin.h"
Include dependency graph for auth-scram.c:

Go to the source code of this file.

Data Structures

struct  scram_state
 

Enumerations

enum  scram_state_enum { SCRAM_AUTH_INIT , SCRAM_AUTH_SALT_SENT , SCRAM_AUTH_FINISHED }
 

Functions

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

Variables

const pg_be_sasl_mech pg_be_scram_mech
 
int scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS
 

Enumeration Type Documentation

◆ scram_state_enum

Enumerator
SCRAM_AUTH_INIT 
SCRAM_AUTH_SALT_SENT 
SCRAM_AUTH_FINISHED 

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

127{
scram_state_enum
Definition: auth-scram.c:127
@ SCRAM_AUTH_SALT_SENT
Definition: auth-scram.c:129
@ SCRAM_AUTH_FINISHED
Definition: auth-scram.c:130
@ SCRAM_AUTH_INIT
Definition: auth-scram.c:128

Function Documentation

◆ build_server_final_message()

static char * build_server_final_message ( scram_state state)
static

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

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

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

Referenced by scram_exchange().

◆ build_server_first_message()

static char * build_server_first_message ( scram_state state)
static

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

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

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

Referenced by scram_exchange().

◆ is_scram_printable()

static bool is_scram_printable ( char *  p)
static

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

780{
781 /*------
782 * Printable characters, as defined by SCRAM spec: (RFC 5802)
783 *
784 * printable = %x21-2B / %x2D-7E
785 * ;; Printable ASCII except ",".
786 * ;; Note that any "printable" is also
787 * ;; a valid "value".
788 *------
789 */
790 for (; *p; p++)
791 {
792 if (*p < 0x21 || *p > 0x7E || *p == 0x2C /* comma */ )
793 return false;
794 }
795 return true;
796}

Referenced by read_client_first_message().

◆ mock_scram_secret()

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

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

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

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

Referenced by scram_init().

◆ parse_scram_secret()

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

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

603{
604 char *v;
605 char *p;
606 char *scheme_str;
607 char *salt_str;
608 char *iterations_str;
609 char *storedkey_str;
610 char *serverkey_str;
611 int decoded_len;
612 char *decoded_salt_buf;
613 char *decoded_stored_buf;
614 char *decoded_server_buf;
615
616 /*
617 * The secret is of form:
618 *
619 * SCRAM-SHA-256$<iterations>:<salt>$<storedkey>:<serverkey>
620 */
621 v = pstrdup(secret);
622 scheme_str = strsep(&v, "$");
623 if (v == NULL)
624 goto invalid_secret;
625 iterations_str = strsep(&v, ":");
626 if (v == NULL)
627 goto invalid_secret;
628 salt_str = strsep(&v, "$");
629 if (v == NULL)
630 goto invalid_secret;
631 storedkey_str = strsep(&v, ":");
632 if (v == NULL)
633 goto invalid_secret;
634 serverkey_str = v;
635
636 /* Parse the fields */
637 if (strcmp(scheme_str, "SCRAM-SHA-256") != 0)
638 goto invalid_secret;
639 *hash_type = PG_SHA256;
640 *key_length = SCRAM_SHA_256_KEY_LEN;
641
642 errno = 0;
643 *iterations = strtol(iterations_str, &p, 10);
644 if (*p || errno != 0)
645 goto invalid_secret;
646
647 /*
648 * Verify that the salt is in Base64-encoded format, by decoding it,
649 * although we return the encoded version to the caller.
650 */
651 decoded_len = pg_b64_dec_len(strlen(salt_str));
652 decoded_salt_buf = palloc(decoded_len);
653 decoded_len = pg_b64_decode(salt_str, strlen(salt_str),
654 decoded_salt_buf, decoded_len);
655 if (decoded_len < 0)
656 goto invalid_secret;
657 *salt = pstrdup(salt_str);
658
659 /*
660 * Decode StoredKey and ServerKey.
661 */
662 decoded_len = pg_b64_dec_len(strlen(storedkey_str));
663 decoded_stored_buf = palloc(decoded_len);
664 decoded_len = pg_b64_decode(storedkey_str, strlen(storedkey_str),
665 decoded_stored_buf, decoded_len);
666 if (decoded_len != *key_length)
667 goto invalid_secret;
668 memcpy(stored_key, decoded_stored_buf, *key_length);
669
670 decoded_len = pg_b64_dec_len(strlen(serverkey_str));
671 decoded_server_buf = palloc(decoded_len);
672 decoded_len = pg_b64_decode(serverkey_str, strlen(serverkey_str),
673 decoded_server_buf, decoded_len);
674 if (decoded_len != *key_length)
675 goto invalid_secret;
676 memcpy(server_key, decoded_server_buf, *key_length);
677
678 return true;
679
680invalid_secret:
681 *salt = NULL;
682 return false;
683}
int pg_b64_decode(const char *src, int len, char *dst, int dstlen)
Definition: base64.c:116
int pg_b64_dec_len(int srclen)
Definition: base64.c:239
char * strsep(char **stringp, const char *delim)
Definition: strsep.c:49

References iterations, palloc(), pg_b64_dec_len(), pg_b64_decode(), PG_SHA256, pstrdup(), SCRAM_SHA_256_KEY_LEN, and strsep().

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

◆ pg_be_scram_build_secret()

char * pg_be_scram_build_secret ( const char *  password)

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

484{
485 char *prep_password;
487 char saltbuf[SCRAM_DEFAULT_SALT_LEN];
488 char *result;
489 const char *errstr = NULL;
490
491 /*
492 * Normalize the password with SASLprep. If that doesn't work, because
493 * the password isn't valid UTF-8 or contains prohibited characters, just
494 * proceed with the original password. (See comments at top of file.)
495 */
496 rc = pg_saslprep(password, &prep_password);
497 if (rc == SASLPREP_SUCCESS)
498 password = (const char *) prep_password;
499
500 /* Generate random salt */
503 (errcode(ERRCODE_INTERNAL_ERROR),
504 errmsg("could not generate random salt")));
505
507 saltbuf, SCRAM_DEFAULT_SALT_LEN,
509 &errstr);
510
511 if (prep_password)
512 pfree(prep_password);
513
514 return result;
515}
int scram_sha_256_iterations
Definition: auth-scram.c:196
void pfree(void *pointer)
Definition: mcxt.c:1521
pg_saslprep_rc pg_saslprep(const char *input, char **output)
Definition: saslprep.c:1047
pg_saslprep_rc
Definition: saslprep.h:21
@ SASLPREP_SUCCESS
Definition: saslprep.h:22
char * scram_build_secret(pg_cryptohash_type hash_type, int key_length, const char *salt, int saltlen, int iterations, const char *password, const char **errstr)
Definition: scram-common.c:209
static char * password
Definition: streamutil.c:52

References ereport, errcode(), errmsg(), ERROR, password, pfree(), pg_saslprep(), PG_SHA256, pg_strong_random(), SASLPREP_SUCCESS, scram_build_secret(), SCRAM_DEFAULT_SALT_LEN, scram_sha_256_iterations, and SCRAM_SHA_256_KEY_LEN.

Referenced by encrypt_password().

◆ read_any_attr()

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

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

856{
857 char *begin = *input;
858 char *end;
859 char attr = *begin;
860
861 if (attr == '\0')
863 (errcode(ERRCODE_PROTOCOL_VIOLATION),
864 errmsg("malformed SCRAM message"),
865 errdetail("Attribute expected, but found end of string.")));
866
867 /*------
868 * attr-val = ALPHA "=" value
869 * ;; Generic syntax of any attribute sent
870 * ;; by server or client
871 *------
872 */
873 if (!((attr >= 'A' && attr <= 'Z') ||
874 (attr >= 'a' && attr <= 'z')))
876 (errcode(ERRCODE_PROTOCOL_VIOLATION),
877 errmsg("malformed SCRAM message"),
878 errdetail("Attribute expected, but found invalid character \"%s\".",
879 sanitize_char(attr))));
880 if (attr_p)
881 *attr_p = attr;
882 begin++;
883
884 if (*begin != '=')
886 (errcode(ERRCODE_PROTOCOL_VIOLATION),
887 errmsg("malformed SCRAM message"),
888 errdetail("Expected character \"=\" for attribute \"%c\".", attr)));
889 begin++;
890
891 end = begin;
892 while (*end && *end != ',')
893 end++;
894
895 if (*end)
896 {
897 *end = '\0';
898 *input = end + 1;
899 }
900 else
901 *input = end;
902
903 return begin;
904}
static char * sanitize_char(char c)
Definition: auth-scram.c:807
int errdetail(const char *fmt,...)
Definition: elog.c:1203
FILE * input

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

Referenced by read_client_final_message(), and read_client_first_message().

◆ read_attr_value()

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

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

744{
745 char *begin = *input;
746 char *end;
747
748 if (*begin != attr)
750 (errcode(ERRCODE_PROTOCOL_VIOLATION),
751 errmsg("malformed SCRAM message"),
752 errdetail("Expected attribute \"%c\" but found \"%s\".",
753 attr, sanitize_char(*begin))));
754 begin++;
755
756 if (*begin != '=')
758 (errcode(ERRCODE_PROTOCOL_VIOLATION),
759 errmsg("malformed SCRAM message"),
760 errdetail("Expected character \"=\" for attribute \"%c\".", attr)));
761 begin++;
762
763 end = begin;
764 while (*end && *end != ',')
765 end++;
766
767 if (*end)
768 {
769 *end = '\0';
770 *input = end + 1;
771 }
772 else
773 *input = end;
774
775 return begin;
776}

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

Referenced by read_client_final_message(), and read_client_first_message().

◆ read_client_final_message()

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

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

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

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

Referenced by scram_exchange().

◆ read_client_first_message()

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

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

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

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

Referenced by scram_exchange().

◆ sanitize_char()

static char * sanitize_char ( char  c)
static

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

808{
809 static char buf[5];
810
811 if (c >= 0x21 && c <= 0x7E)
812 snprintf(buf, sizeof(buf), "'%c'", c);
813 else
814 snprintf(buf, sizeof(buf), "0x%02x", (unsigned char) c);
815 return buf;
816}
static char * buf
Definition: pg_test_fsync.c:72
char * c

References buf, and snprintf.

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

◆ sanitize_str()

static char * sanitize_str ( const char *  s)
static

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

828{
829 static char buf[30 + 1];
830 int i;
831
832 for (i = 0; i < sizeof(buf) - 1; i++)
833 {
834 char c = s[i];
835
836 if (c == '\0')
837 break;
838
839 if (c >= 0x21 && c <= 0x7E)
840 buf[i] = c;
841 else
842 buf[i] = '?';
843 }
844 buf[i] = '\0';
845 return buf;
846}
int i
Definition: isn.c:72

References buf, and i.

Referenced by read_client_first_message().

◆ scram_exchange()

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

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

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

References Assert, build_server_final_message(), build_server_first_message(), elog, ereport, errcode(), errdetail(), errmsg(), ERROR, Port::has_scram_keys, input, MyProcPort, output, PG_SASL_EXCHANGE_CONTINUE, PG_SASL_EXCHANGE_FAILURE, PG_SASL_EXCHANGE_SUCCESS, pstrdup(), read_client_final_message(), read_client_first_message(), SCRAM_AUTH_FINISHED, SCRAM_AUTH_INIT, SCRAM_AUTH_SALT_SENT, Port::scram_ClientKey, Port::scram_ServerKey, verify_client_proof(), and verify_final_nonce().

◆ scram_get_mechanisms()

static void scram_get_mechanisms ( Port port,
StringInfo  buf 
)
static

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

207{
208 /*
209 * Advertise the mechanisms in decreasing order of importance. So the
210 * channel-binding variants go first, if they are supported. Channel
211 * binding is only supported with SSL.
212 */
213#ifdef USE_SSL
214 if (port->ssl_in_use)
215 {
218 }
219#endif
222}
static int port
Definition: pg_regress.c:115
#define SCRAM_SHA_256_PLUS_NAME
Definition: scram-common.h:21
#define SCRAM_SHA_256_NAME
Definition: scram-common.h:20
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:230
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:242

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

◆ scram_init()

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

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

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

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

◆ scram_mock_salt()

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

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

1473{
1474 pg_cryptohash_ctx *ctx;
1475 static uint8 sha_digest[SCRAM_MAX_KEY_LEN];
1476 char *mock_auth_nonce = GetMockAuthenticationNonce();
1477
1478 /*
1479 * Generate salt using a SHA256 hash of the username and the cluster's
1480 * mock authentication nonce. (This works as long as the salt length is
1481 * not larger than the SHA256 digest length. If the salt is smaller, the
1482 * caller will just ignore the extra data.)
1483 */
1485 "salt length greater than SHA256 digest length");
1486
1487 /*
1488 * This may be worth refreshing if support for more hash methods is\
1489 * added.
1490 */
1491 Assert(hash_type == PG_SHA256);
1492
1493 ctx = pg_cryptohash_create(hash_type);
1494 if (pg_cryptohash_init(ctx) < 0 ||
1495 pg_cryptohash_update(ctx, (uint8 *) username, strlen(username)) < 0 ||
1496 pg_cryptohash_update(ctx, (uint8 *) mock_auth_nonce, MOCK_AUTH_NONCE_LEN) < 0 ||
1497 pg_cryptohash_final(ctx, sha_digest, key_length) < 0)
1498 {
1499 pg_cryptohash_free(ctx);
1500 return NULL;
1501 }
1502 pg_cryptohash_free(ctx);
1503
1504 return (char *) sha_digest;
1505}
#define StaticAssertDecl(condition, errmessage)
Definition: c.h:893
int pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len)
Definition: cryptohash.c:136
pg_cryptohash_ctx * pg_cryptohash_create(pg_cryptohash_type type)
Definition: cryptohash.c:74
int pg_cryptohash_init(pg_cryptohash_ctx *ctx)
Definition: cryptohash.c:100
void pg_cryptohash_free(pg_cryptohash_ctx *ctx)
Definition: cryptohash.c:238
int pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest, size_t len)
Definition: cryptohash.c:172
#define MOCK_AUTH_NONCE_LEN
Definition: pg_control.h:28
#define PG_SHA256_DIGEST_LENGTH
Definition: sha2.h:23
char * GetMockAuthenticationNonce(void)
Definition: xlog.c:4578

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

Referenced by mock_scram_secret().

◆ scram_verify_plain_password()

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

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

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

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

Referenced by plain_crypt_verify().

◆ verify_client_proof()

static bool verify_client_proof ( scram_state state)
static

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

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

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

Referenced by scram_exchange().

◆ verify_final_nonce()

static bool verify_final_nonce ( scram_state state)
static

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

1128{
1129 int client_nonce_len = strlen(state->client_nonce);
1130 int server_nonce_len = strlen(state->server_nonce);
1131 int final_nonce_len = strlen(state->client_final_nonce);
1132
1133 if (final_nonce_len != client_nonce_len + server_nonce_len)
1134 return false;
1135 if (memcmp(state->client_final_nonce, state->client_nonce, client_nonce_len) != 0)
1136 return false;
1137 if (memcmp(state->client_final_nonce + client_nonce_len, state->server_nonce, server_nonce_len) != 0)
1138 return false;
1139
1140 return true;
1141}

Referenced by scram_exchange().

Variable Documentation

◆ pg_be_scram_mech

const pg_be_sasl_mech pg_be_scram_mech
Initial value:
= {
}
static void * scram_init(Port *port, const char *selected_mech, const char *shadow_pass)
Definition: auth-scram.c:240
static int scram_exchange(void *opaq, const char *input, int inputlen, char **output, int *outputlen, const char **logdetail)
Definition: auth-scram.c:352
static void scram_get_mechanisms(Port *port, StringInfo buf)
Definition: auth-scram.c:206
#define PG_MAX_SASL_MESSAGE_LENGTH
Definition: sasl.h:35

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

Referenced by CheckPWChallengeAuth().

◆ scram_sha_256_iterations

int scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS

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

Referenced by pg_be_scram_build_secret().