111 const char **logdetail);
182 int *
iterations,
int *key_length,
char **salt,
212 if (
port->ssl_in_use)
257 state->channel_binding_in_use =
true;
261 state->channel_binding_in_use =
false;
265 errmsg(
"client selected an invalid SASL authentication mechanism")));
289 (
errmsg(
"invalid SCRAM secret for user \"%s\"",
290 state->port->user_name)));
300 state->logdetail =
psprintf(
_(
"User \"%s\" does not have a valid SCRAM secret."),
301 state->port->user_name);
327 state->doomed =
true;
380 errmsg(
"malformed SCRAM message"),
385 errmsg(
"malformed SCRAM message"),
386 errdetail(
"Message length does not match input length.")));
388 switch (
state->state)
418 errmsg(
"invalid SCRAM response"),
455 elog(
ERROR,
"invalid SCRAM exchange state");
460 *logdetail =
state->logdetail;
502 errmsg(
"could not generate random salt")));
642 if (*p ||
errno != 0)
696 int *
iterations,
int *key_length,
char **salt,
743 char *begin = *
input;
749 errmsg(
"malformed SCRAM message"),
750 errdetail(
"Expected attribute \"%c\" but found \"%s\".",
757 errmsg(
"malformed SCRAM message"),
758 errdetail(
"Expected character \"=\" for attribute \"%c\".", attr)));
762 while (*end && *end !=
',')
809 if (
c >= 0x21 &&
c <= 0x7E)
827 static char buf[30 + 1];
830 for (
i = 0;
i <
sizeof(
buf) - 1;
i++)
837 if (
c >= 0x21 &&
c <= 0x7E)
855 char *begin = *
input;
862 errmsg(
"malformed SCRAM message"),
863 errdetail(
"Attribute expected, but found end of string.")));
871 if (!((attr >=
'A' && attr <=
'Z') ||
872 (attr >=
'a' && attr <=
'z')))
875 errmsg(
"malformed SCRAM message"),
876 errdetail(
"Attribute expected, but found invalid character \"%s\".",
885 errmsg(
"malformed SCRAM message"),
886 errdetail(
"Expected character \"=\" for attribute \"%c\".", attr)));
890 while (*end && *end !=
',')
981 state->cbind_flag = *p;
990 if (
state->channel_binding_in_use)
993 errmsg(
"malformed SCRAM message"),
994 errdetail(
"The client selected SCRAM-SHA-256-PLUS, but the SCRAM message does not include channel binding data.")));
1000 errmsg(
"malformed SCRAM message"),
1001 errdetail(
"Comma expected, but found character \"%s\".",
1012 if (
state->channel_binding_in_use)
1015 errmsg(
"malformed SCRAM message"),
1016 errdetail(
"The client selected SCRAM-SHA-256-PLUS, but the SCRAM message does not include channel binding data.")));
1019 if (
state->port->ssl_in_use)
1022 errmsg(
"SCRAM channel binding negotiation error"),
1023 errdetail(
"The client supports SCRAM channel binding but thinks the server does not. "
1024 "However, this server does support channel binding.")));
1030 errmsg(
"malformed SCRAM message"),
1031 errdetail(
"Comma expected, but found character \"%s\".",
1041 if (!
state->channel_binding_in_use)
1044 errmsg(
"malformed SCRAM message"),
1045 errdetail(
"The client selected SCRAM-SHA-256 without channel binding, but the SCRAM message includes channel binding data.")));
1056 errmsg(
"unsupported SCRAM channel-binding type \"%s\"",
1062 errmsg(
"malformed SCRAM message"),
1063 errdetail(
"Unexpected channel-binding flag \"%s\".",
1073 errmsg(
"client uses authorization identity, but it is not supported")));
1077 errmsg(
"malformed SCRAM message"),
1078 errdetail(
"Unexpected attribute \"%s\" in client-first-message.",
1094 errmsg(
"client requires an unsupported SCRAM extension")));
1108 errmsg(
"non-printable characters in SCRAM nonce")));
1170 (
uint8 *)
state->client_final_message_without_proof,
1171 strlen(
state->client_final_message_without_proof)) < 0 ||
1174 elog(
ERROR,
"could not calculate client signature: %s",
1181 for (
i = 0;
i <
state->key_length;
i++)
1238 errmsg(
"could not generate random nonce")));
1248 errmsg(
"could not encode random nonce")));
1251 state->server_first_message =
1267 char *channel_binding;
1311 if (
state->channel_binding_in_use)
1330 elog(
ERROR,
"could not get server certificate hash");
1344 elog(
ERROR,
"could not encode channel binding data");
1354 errmsg(
"SCRAM channel binding check failed")));
1357 elog(
ERROR,
"channel binding not supported by this build");
1368 if (!(
strcmp(channel_binding,
"biws") == 0 &&
state->cbind_flag ==
'n') &&
1369 !(
strcmp(channel_binding,
"eSws") == 0 &&
state->cbind_flag ==
'y'))
1372 errmsg(
"unexpected SCRAM channel-binding attribute in client-final-message")));
1382 }
while (attr !=
'p');
1390 errmsg(
"malformed SCRAM message"),
1391 errdetail(
"Malformed proof in client-final-message.")));
1398 errmsg(
"malformed SCRAM message"),
1399 errdetail(
"Garbage found at the end of client-final-message.")));
1403 state->client_final_message_without_proof[
proof - begin] =
'\0';
1428 (
uint8 *)
state->client_final_message_without_proof,
1429 strlen(
state->client_final_message_without_proof)) < 0 ||
1432 elog(
ERROR,
"could not calculate server signature: %s",
1445 elog(
ERROR,
"could not encode server signature");
1483 "salt length greater than SHA256 digest length");
static void * scram_init(Port *port, const char *selected_mech, const char *shadow_pass)
static char * build_server_first_message(scram_state *state)
const pg_be_sasl_mech pg_be_scram_mech
static void read_client_first_message(scram_state *state, const char *input)
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 bool verify_client_proof(scram_state *state)
static bool verify_final_nonce(scram_state *state)
static char * sanitize_str(const char *s)
char * pg_be_scram_build_secret(const char *password)
static int scram_exchange(void *opaq, const char *input, int inputlen, char **output, int *outputlen, const char **logdetail)
static bool is_scram_printable(char *p)
static char * sanitize_char(char c)
bool scram_verify_plain_password(const char *username, const char *password, const char *secret)
static char * read_attr_value(char **input, char attr)
static void read_client_final_message(scram_state *state, const char *input)
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 char * read_any_attr(char **input, char *attr_p)
static char * build_server_final_message(scram_state *state)
static void scram_get_mechanisms(Port *port, StringInfo buf)
int scram_sha_256_iterations
static uint8 * scram_mock_salt(const char *username, pg_cryptohash_type hash_type, int key_length)
int pg_b64_enc_len(int srclen)
int pg_b64_encode(const uint8 *src, int len, char *dst, int dstlen)
int pg_b64_dec_len(int srclen)
int pg_b64_decode(const char *src, int len, uint8 *dst, int dstlen)
char * be_tls_get_certificate_hash(Port *port, size_t *len)
#define Assert(condition)
#define StaticAssertDecl(condition, errmessage)
PasswordType get_password_type(const char *shadow_pass)
@ PASSWORD_TYPE_SCRAM_SHA_256
int pg_cryptohash_update(pg_cryptohash_ctx *ctx, const uint8 *data, size_t len)
pg_cryptohash_ctx * pg_cryptohash_create(pg_cryptohash_type type)
int pg_cryptohash_init(pg_cryptohash_ctx *ctx)
void pg_cryptohash_free(pg_cryptohash_ctx *ctx)
int pg_cryptohash_final(pg_cryptohash_ctx *ctx, uint8 *dest, size_t len)
int errdetail(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
#define palloc0_object(type)
pg_hmac_ctx * pg_hmac_create(pg_cryptohash_type type)
void pg_hmac_free(pg_hmac_ctx *ctx)
const char * pg_hmac_error(pg_hmac_ctx *ctx)
int pg_hmac_update(pg_hmac_ctx *ctx, const uint8 *data, size_t len)
int pg_hmac_init(pg_hmac_ctx *ctx, const uint8 *key, size_t len)
int pg_hmac_final(pg_hmac_ctx *ctx, uint8 *dest, size_t len)
char * pstrdup(const char *in)
void pfree(void *pointer)
#define MOCK_AUTH_NONCE_LEN
static char buf[DEFAULT_XLOG_SEG_SIZE]
char * strsep(char **stringp, const char *delim)
bool pg_strong_random(void *buf, size_t len)
char * psprintf(const char *fmt,...)
#define PG_MAX_SASL_MESSAGE_LENGTH
#define PG_SASL_EXCHANGE_FAILURE
#define PG_SASL_EXCHANGE_CONTINUE
#define PG_SASL_EXCHANGE_SUCCESS
pg_saslprep_rc pg_saslprep(const char *input, char **output)
int scram_ServerKey(const uint8 *salted_password, pg_cryptohash_type hash_type, int key_length, uint8 *result, const char **errstr)
int scram_SaltedPassword(const char *password, pg_cryptohash_type hash_type, int key_length, const uint8 *salt, int saltlen, int iterations, uint8 *result, const char **errstr)
char * scram_build_secret(pg_cryptohash_type hash_type, int key_length, const uint8 *salt, int saltlen, int iterations, const char *password, const char **errstr)
int scram_H(const uint8 *input, pg_cryptohash_type hash_type, int key_length, uint8 *result, const char **errstr)
#define SCRAM_SHA_256_PLUS_NAME
#define SCRAM_SHA_256_NAME
#define SCRAM_RAW_NONCE_LEN
#define SCRAM_DEFAULT_SALT_LEN
#define SCRAM_MAX_KEY_LEN
#define SCRAM_SHA_256_KEY_LEN
#define SCRAM_SHA_256_DEFAULT_ITERATIONS
#define PG_SHA256_DIGEST_LENGTH
void appendStringInfoString(StringInfo str, const char *s)
void appendStringInfoChar(StringInfo str, char ch)
uint8 scram_ServerKey[SCRAM_MAX_KEY_LEN]
uint8 scram_ClientKey[SCRAM_MAX_KEY_LEN]
char * client_final_nonce
char * client_first_message_bare
char * client_final_message_without_proof
char * server_first_message
bool channel_binding_in_use
pg_cryptohash_type hash_type
char * GetMockAuthenticationNonce(void)