2 * PgBouncer - Lightweight connection pooler for PostgreSQL.
4 * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 #include "common/base64.h"
26 #include "common/saslprep.h"
27 #include "common/scram-common.h"
30 static bool calculate_client_proof(ScramState *scram_state,
35 const char *client_final_message_without_proof,
40 * free SCRAM state info after auth is done
42 void free_scram_state(ScramState *scram_state)
44 free(scram_state->client_nonce);
45 free(scram_state->client_first_message_bare);
46 free(scram_state->client_final_message_without_proof);
47 free(scram_state->server_nonce);
48 free(scram_state->server_first_message);
49 free(scram_state->SaltedPassword);
50 free(scram_state->salt);
51 memset(scram_state, 0, sizeof(*scram_state));
54 static bool is_scram_printable(char *p)
57 * Printable characters, as defined by SCRAM spec: (RFC 5802)
59 * printable = %x21-2B / %x2D-7E
60 * ;; Printable ASCII except ",".
61 * ;; Note that any "printable" is also
66 if (*p < 0x21 || *p > 0x7E || *p == 0x2C /* comma */ )
72 static char *sanitize_char(char c)
76 if (c >= 0x21 && c <= 0x7E)
77 snprintf(buf, sizeof(buf), "'%c'", c);
79 snprintf(buf, sizeof(buf), "0x%02x", (unsigned char) c);
84 * Read value for an attribute part of a SCRAM message.
86 static char *read_attr_value(PgSocket *sk, char **input, char attr)
93 slog_error(sk, "malformed SCRAM message (attribute \"%c\" expected)",
101 slog_error(sk, "malformed SCRAM message (expected \"=\" after attribute \"%c\")",
108 while (*end && *end != ',')
123 * Read the next attribute and value in a SCRAM exchange message.
125 * Returns NULL if there is no attribute.
128 read_any_attr(PgSocket *sk, char **input, char *attr_p)
130 char *begin = *input;
134 if (!((attr >= 'A' && attr <= 'Z') ||
135 (attr >= 'a' && attr <= 'z')))
137 slog_error(sk, "malformed SCRAM message (attribute expected, but found invalid character \"%s\")",
138 sanitize_char(attr));
147 slog_error(sk, "malformed SCRAM message (expected character \"=\" after attribute \"%c\")",
154 while (*end && *end != ',')
169 * Parse and validate format of given SCRAM verifier.
171 * Returns true if the SCRAM verifier has been parsed, and false otherwise.
173 static bool parse_scram_verifier(const char *verifier, int *iterations, char **salt,
174 uint8_t *stored_key, uint8_t *server_key)
180 char *iterations_str;
184 char *decoded_salt_buf;
185 char *decoded_stored_buf = NULL;
186 char *decoded_server_buf = NULL;
189 * The verifier is of form:
191 * SCRAM-SHA-256$<iterations>:<salt>$<storedkey>:<serverkey>
193 v = strdup(verifier);
195 goto invalid_verifier;
196 if ((scheme_str = strtok(v, "$")) == NULL)
197 goto invalid_verifier;
198 if ((iterations_str = strtok(NULL, ":")) == NULL)
199 goto invalid_verifier;
200 if ((salt_str = strtok(NULL, "$")) == NULL)
201 goto invalid_verifier;
202 if ((storedkey_str = strtok(NULL, ":")) == NULL)
203 goto invalid_verifier;
204 if ((serverkey_str = strtok(NULL, "")) == NULL)
205 goto invalid_verifier;
207 /* Parse the fields */
208 if (strcmp(scheme_str, "SCRAM-SHA-256") != 0)
209 goto invalid_verifier;
212 *iterations = strtol(iterations_str, &p, 10);
213 if (*p || errno != 0)
214 goto invalid_verifier;
217 * Verify that the salt is in Base64-encoded format, by decoding it,
218 * although we return the encoded version to the caller.
220 decoded_salt_buf = malloc(pg_b64_dec_len(strlen(salt_str)));
221 if (!decoded_salt_buf)
222 goto invalid_verifier;
223 decoded_len = pg_b64_decode(salt_str, strlen(salt_str), decoded_salt_buf);
224 free(decoded_salt_buf);
226 goto invalid_verifier;
227 *salt = strdup(salt_str);
230 * Decode StoredKey and ServerKey.
232 decoded_stored_buf = malloc(pg_b64_dec_len(strlen(storedkey_str)));
233 if (!decoded_stored_buf)
234 goto invalid_verifier;
235 decoded_len = pg_b64_decode(storedkey_str, strlen(storedkey_str), decoded_stored_buf);
236 if (decoded_len != SCRAM_KEY_LEN)
237 goto invalid_verifier;
238 memcpy(stored_key, decoded_stored_buf, SCRAM_KEY_LEN);
240 decoded_server_buf = malloc(pg_b64_dec_len(strlen(serverkey_str)));
241 decoded_len = pg_b64_decode(serverkey_str, strlen(serverkey_str),
243 if (decoded_len != SCRAM_KEY_LEN)
244 goto invalid_verifier;
245 memcpy(server_key, decoded_server_buf, SCRAM_KEY_LEN);
247 free(decoded_stored_buf);
248 free(decoded_server_buf);
253 free(decoded_stored_buf);
254 free(decoded_server_buf);
260 #define MD5_PASSWD_CHARSET "0123456789abcdef"
263 * What kind of a password verifier is 'shadow_pass'?
266 get_password_type(const char *shadow_pass)
268 char *encoded_salt = NULL;
270 uint8_t stored_key[SCRAM_KEY_LEN];
271 uint8_t server_key[SCRAM_KEY_LEN];
273 if (strncmp(shadow_pass, "md5", 3) == 0 &&
274 strlen(shadow_pass) == MD5_PASSWD_LEN &&
275 strspn(shadow_pass + 3, MD5_PASSWD_CHARSET) == MD5_PASSWD_LEN - 3)
276 return PASSWORD_TYPE_MD5;
277 if (parse_scram_verifier(shadow_pass, &iterations, &encoded_salt,
278 stored_key, server_key)) {
280 return PASSWORD_TYPE_SCRAM_SHA_256;
283 return PASSWORD_TYPE_PLAINTEXT;
287 * Functions for communicating as a client with the server
290 char *build_client_first_message(ScramState *scram_state)
292 uint8_t raw_nonce[SCRAM_RAW_NONCE_LEN + 1];
297 get_random_bytes(raw_nonce, SCRAM_RAW_NONCE_LEN);
299 scram_state->client_nonce = malloc(pg_b64_enc_len(SCRAM_RAW_NONCE_LEN) + 1);
300 if (scram_state->client_nonce == NULL)
302 encoded_len = pg_b64_encode((char *) raw_nonce, SCRAM_RAW_NONCE_LEN, scram_state->client_nonce);
303 scram_state->client_nonce[encoded_len] = '\0';
305 len = 8 + strlen(scram_state->client_nonce) + 1;
306 result = malloc(len);
309 snprintf(result, len, "n,,n=,r=%s", scram_state->client_nonce);
311 scram_state->client_first_message_bare = strdup(result + 3);
312 if (scram_state->client_first_message_bare == NULL)
319 free(scram_state->client_nonce);
320 free(scram_state->client_first_message_bare);
324 char *build_client_final_message(ScramState *scram_state,
326 const char *server_nonce,
333 uint8_t client_proof[SCRAM_KEY_LEN];
335 len = snprintf(buf, sizeof(buf), "c=biws,r=%s", server_nonce);
337 scram_state->client_final_message_without_proof = strdup(buf);
338 if (scram_state->client_final_message_without_proof == NULL)
341 if (!calculate_client_proof(scram_state, passwd,
342 salt, saltlen, iterations, buf,
346 len = strlcat(buf, ",p=", sizeof(buf));
347 len += pg_b64_encode((char *) client_proof,
357 bool read_server_first_message(PgSocket *server, char *input,
358 char **server_nonce_p, char **salt_p, int *saltlen_p, int *iterations_p)
364 char *iterations_str;
368 server->scram_state.server_first_message = strdup(input);
369 if (server->scram_state.server_first_message == NULL)
372 server_nonce = read_attr_value(server, &input, 'r');
373 if (server_nonce == NULL)
376 if (strlen(server_nonce) < strlen(server->scram_state.client_nonce) ||
377 memcmp(server_nonce, server->scram_state.client_nonce, strlen(server->scram_state.client_nonce)) != 0)
379 slog_error(server, "invalid SCRAM response (nonce mismatch)");
383 encoded_salt = read_attr_value(server, &input, 's');
384 if (encoded_salt == NULL)
386 salt = malloc(pg_b64_dec_len(strlen(encoded_salt)));
389 saltlen = pg_b64_decode(encoded_salt,
390 strlen(encoded_salt),
394 slog_error(server, "malformed SCRAM message (invalid salt)");
398 iterations_str = read_attr_value(server, &input, 'i');
399 if (iterations_str == NULL)
402 iterations = strtol(iterations_str, &endptr, 10);
403 if (*endptr != '\0' || iterations < 1)
405 slog_error(server, "malformed SCRAM message (invalid iteration count)");
411 slog_error(server, "malformed SCRAM message (garbage at end of server-first-message)");
415 *server_nonce_p = server_nonce;
417 *saltlen_p = saltlen;
418 *iterations_p = iterations;
425 bool read_server_final_message(PgSocket *server, char *input, char *ServerSignature)
427 char *encoded_server_signature;
428 char *decoded_server_signature = NULL;
429 int server_signature_len;
433 char *errmsg = read_attr_value(server, &input, 'e');
434 slog_error(server, "error received from server in SCRAM exchange: %s",
439 encoded_server_signature = read_attr_value(server, &input, 'v');
440 if (encoded_server_signature == NULL)
444 slog_error(server, "malformed SCRAM message (garbage at end of server-final-message)");
446 server_signature_len = pg_b64_dec_len(strlen(encoded_server_signature));
447 decoded_server_signature = malloc(server_signature_len);
448 if (!decoded_server_signature)
451 server_signature_len = pg_b64_decode(encoded_server_signature,
452 strlen(encoded_server_signature),
453 decoded_server_signature);
454 if (server_signature_len != SCRAM_KEY_LEN)
456 slog_error(server, "malformed SCRAM message (malformed server signature)");
459 memcpy(ServerSignature, decoded_server_signature, SCRAM_KEY_LEN);
461 free(decoded_server_signature);
464 free(decoded_server_signature);
468 static bool calculate_client_proof(ScramState *scram_state,
473 const char *client_final_message_without_proof,
477 char *prep_password = NULL;
478 uint8_t StoredKey[SCRAM_KEY_LEN];
479 uint8_t ClientKey[SCRAM_KEY_LEN];
480 uint8_t ClientSignature[SCRAM_KEY_LEN];
483 rc = pg_saslprep(passwd, &prep_password);
484 if (rc == SASLPREP_OOM)
486 if (rc != SASLPREP_SUCCESS)
488 prep_password = strdup(passwd);
493 scram_state->SaltedPassword = malloc(SCRAM_KEY_LEN);
494 if (scram_state->SaltedPassword == NULL)
496 scram_SaltedPassword(prep_password,
500 scram_state->SaltedPassword);
502 scram_ClientKey(scram_state->SaltedPassword, ClientKey);
503 scram_H(ClientKey, SCRAM_KEY_LEN, StoredKey);
505 scram_HMAC_init(&ctx, StoredKey, SCRAM_KEY_LEN);
506 scram_HMAC_update(&ctx,
507 scram_state->client_first_message_bare,
508 strlen(scram_state->client_first_message_bare));
509 scram_HMAC_update(&ctx, ",", 1);
510 scram_HMAC_update(&ctx,
511 scram_state->server_first_message,
512 strlen(scram_state->server_first_message));
513 scram_HMAC_update(&ctx, ",", 1);
514 scram_HMAC_update(&ctx,
515 client_final_message_without_proof,
516 strlen(client_final_message_without_proof));
517 scram_HMAC_final(ClientSignature, &ctx);
519 for (int i = 0; i < SCRAM_KEY_LEN; i++)
520 result[i] = ClientKey[i] ^ ClientSignature[i];
529 bool verify_server_signature(ScramState *scram_state, const char *ServerSignature)
531 uint8_t expected_ServerSignature[SCRAM_KEY_LEN];
532 uint8_t ServerKey[SCRAM_KEY_LEN];
535 scram_ServerKey(scram_state->SaltedPassword, ServerKey);
537 scram_HMAC_init(&ctx, ServerKey, SCRAM_KEY_LEN);
538 scram_HMAC_update(&ctx,
539 scram_state->client_first_message_bare,
540 strlen(scram_state->client_first_message_bare));
541 scram_HMAC_update(&ctx, ",", 1);
542 scram_HMAC_update(&ctx,
543 scram_state->server_first_message,
544 strlen(scram_state->server_first_message));
545 scram_HMAC_update(&ctx, ",", 1);
546 scram_HMAC_update(&ctx,
547 scram_state->client_final_message_without_proof,
548 strlen(scram_state->client_final_message_without_proof));
549 scram_HMAC_final(expected_ServerSignature, &ctx);
551 if (memcmp(expected_ServerSignature, ServerSignature, SCRAM_KEY_LEN) != 0)
559 * Functions for communicating as a server to the client
562 bool read_client_first_message(PgSocket *client, char *input,
563 char **client_first_message_bare_p,
564 char **client_nonce_p)
566 char *client_first_message_bare = NULL;
567 char *client_nonce = NULL;
571 /* Client does not support channel binding */
575 /* Client supports channel binding, but we're not doing it today */
579 /* Client requires channel binding. We don't support it. */
580 slog_error(client, "client requires SCRAM channel binding, but it is not supported");
583 slog_error(client, "malformed SCRAM message (unexpected channel-binding flag \"%s\")",
584 sanitize_char(*input));
589 slog_error(client, "malformed SCRAM message (comma expected, but found character \"%s\")",
590 sanitize_char(*input));
596 slog_error(client, "client uses authorization identity, but it is not supported");
600 slog_error(client, "malformed SCRAM message (unexpected attribute \"%s\" in client-first-message)",
601 sanitize_char(*input));
606 client_first_message_bare = strdup(input);
607 if (client_first_message_bare == NULL)
611 slog_error(client, "client requires an unsupported SCRAM extension");
615 /* read and ignore user name */
616 read_attr_value(client, &input, 'n');
618 client_nonce = read_attr_value(client, &input, 'r');
619 if (client_nonce == NULL)
621 if (!is_scram_printable(client_nonce)) {
622 slog_error(client, "non-printable characters in SCRAM nonce");
625 client_nonce = strdup(client_nonce);
626 if (client_nonce == NULL)
630 * There can be any number of optional extensions after this. We don't
631 * support any extensions, so ignore them.
633 while (*input != '\0')
634 read_any_attr(client, &input, NULL);
636 *client_first_message_bare_p = client_first_message_bare;
637 *client_nonce_p = client_nonce;
640 free(client_first_message_bare);
644 bool read_client_final_message(PgSocket *client, const uint8_t *raw_input, char *input,
645 const char **client_final_nonce_p,
648 const char *input_start = input;
650 char *channel_binding;
651 char *client_final_nonce;
658 * Read channel-binding. We don't support channel binding, so
659 * it's expected to always be "biws", which is "n,,",
662 channel_binding = read_attr_value(client, &input, 'c');
663 if (channel_binding == NULL)
665 if (strcmp(channel_binding, "biws") != 0) {
666 slog_error(client, "unexpected SCRAM channel-binding attribute in client-final-message");
670 client_final_nonce = read_attr_value(client, &input, 'r');
672 /* ignore optional extensions */
675 proof_start = input - 1;
676 encoded_proof = read_any_attr(client, &input, &attr);
677 } while (attr != 'p');
679 if (!encoded_proof) {
680 slog_error(client, "could not read proof");
684 proof = malloc(pg_b64_dec_len(strlen(encoded_proof)));
686 slog_error(client, "could not decode proof");
689 prooflen = pg_b64_decode(encoded_proof,
690 strlen(encoded_proof),
694 if (*input != '\0') {
695 slog_error(client, "malformed SCRAM message (garbage at the end of client-final-message)");
699 client->scram_state.client_final_message_without_proof = malloc(proof_start - input_start + 1);
700 if (!client->scram_state.client_final_message_without_proof)
702 memcpy(client->scram_state.client_final_message_without_proof, raw_input, proof_start - input_start);
703 client->scram_state.client_final_message_without_proof[proof_start - input_start] = '\0';
705 *client_final_nonce_p = client_final_nonce;
714 * For doing SCRAM with a password stored in plain text, build a SCRAM
717 static bool build_adhoc_scram_secret(const char *plain_password, ScramState *scram_state)
719 const char *password;
722 char saltbuf[SCRAM_DEFAULT_SALT_LEN];
724 uint8_t salted_password[SCRAM_KEY_LEN];
726 rc = pg_saslprep(plain_password, &prep_password);
727 if (rc == SASLPREP_OOM)
729 else if (rc == SASLPREP_SUCCESS)
730 password = prep_password;
732 password = plain_password;
734 get_random_bytes((uint8_t *) saltbuf, sizeof(saltbuf));
736 scram_state->iterations = SCRAM_DEFAULT_ITERATIONS;
738 scram_state->salt = malloc(pg_b64_enc_len(sizeof(saltbuf)) + 1);
739 if (!scram_state->salt)
741 encoded_len = pg_b64_encode(saltbuf, sizeof(saltbuf), scram_state->salt);
742 scram_state->salt[encoded_len] = '\0';
744 /* Calculate StoredKey and ServerKey */
745 scram_SaltedPassword(password, saltbuf, sizeof(saltbuf),
746 scram_state->iterations,
748 scram_ClientKey(salted_password, scram_state->StoredKey);
749 scram_H(scram_state->StoredKey, SCRAM_KEY_LEN, scram_state->StoredKey);
750 scram_ServerKey(salted_password, scram_state->ServerKey);
761 char *build_server_first_message(ScramState *scram_state, const char *stored_secret)
763 uint8_t raw_nonce[SCRAM_RAW_NONCE_LEN + 1];
768 switch (get_password_type(stored_secret)) {
769 case PASSWORD_TYPE_SCRAM_SHA_256:
770 if (!parse_scram_verifier(stored_secret,
771 &scram_state->iterations,
773 scram_state->StoredKey,
774 scram_state->ServerKey))
777 case PASSWORD_TYPE_PLAINTEXT:
778 if (!build_adhoc_scram_secret(stored_secret, scram_state))
782 /* shouldn't get here */
786 get_random_bytes(raw_nonce, SCRAM_RAW_NONCE_LEN);
787 scram_state->server_nonce = malloc(pg_b64_enc_len(SCRAM_RAW_NONCE_LEN) + 1);
788 if (scram_state->server_nonce == NULL)
790 encoded_len = pg_b64_encode((char *) raw_nonce, SCRAM_RAW_NONCE_LEN, scram_state->server_nonce);
791 scram_state->server_nonce[encoded_len] = '\0';
794 + strlen(scram_state->client_nonce)
795 + strlen(scram_state->server_nonce)
797 + strlen(scram_state->salt)
799 result = malloc(len);
802 snprintf(result, len,
804 scram_state->client_nonce,
805 scram_state->server_nonce,
807 scram_state->iterations);
809 scram_state->server_first_message = result;
813 free(scram_state->server_nonce);
814 free(scram_state->server_first_message);
819 compute_server_signature(ScramState *state)
821 uint8_t ServerSignature[SCRAM_KEY_LEN];
822 char *server_signature_base64;
826 /* calculate ServerSignature */
827 scram_HMAC_init(&ctx, state->ServerKey, SCRAM_KEY_LEN);
828 scram_HMAC_update(&ctx,
829 state->client_first_message_bare,
830 strlen(state->client_first_message_bare));
831 scram_HMAC_update(&ctx, ",", 1);
832 scram_HMAC_update(&ctx,
833 state->server_first_message,
834 strlen(state->server_first_message));
835 scram_HMAC_update(&ctx, ",", 1);
836 scram_HMAC_update(&ctx,
837 state->client_final_message_without_proof,
838 strlen(state->client_final_message_without_proof));
839 scram_HMAC_final(ServerSignature, &ctx);
841 server_signature_base64 = malloc(pg_b64_enc_len(SCRAM_KEY_LEN) + 1);
842 if (!server_signature_base64)
844 siglen = pg_b64_encode((const char *) ServerSignature,
845 SCRAM_KEY_LEN, server_signature_base64);
846 server_signature_base64[siglen] = '\0';
848 return server_signature_base64;
851 char *build_server_final_message(ScramState *scram_state)
853 char *server_signature = NULL;
857 server_signature = compute_server_signature(scram_state);
858 if (!server_signature)
861 len = 2 + strlen(server_signature) + 1;
862 result = malloc(len);
865 snprintf(result, len, "v=%s", server_signature);
867 free(server_signature);
870 free(server_signature);
874 bool verify_final_nonce(const ScramState *scram_state, const char *client_final_nonce)
876 size_t client_nonce_len = strlen(scram_state->client_nonce);
877 size_t server_nonce_len = strlen(scram_state->server_nonce);
878 size_t final_nonce_len = strlen(client_final_nonce);
880 if (final_nonce_len != client_nonce_len + server_nonce_len)
882 if (memcmp(client_final_nonce, scram_state->client_nonce, client_nonce_len) != 0)
884 if (memcmp(client_final_nonce + client_nonce_len, scram_state->server_nonce, server_nonce_len) != 0)
890 bool verify_client_proof(ScramState *state, const char *ClientProof)
892 uint8_t ClientSignature[SCRAM_KEY_LEN];
893 uint8_t ClientKey[SCRAM_KEY_LEN];
894 uint8_t client_StoredKey[SCRAM_KEY_LEN];
898 /* calculate ClientSignature */
899 scram_HMAC_init(&ctx, state->StoredKey, SCRAM_KEY_LEN);
900 scram_HMAC_update(&ctx,
901 state->client_first_message_bare,
902 strlen(state->client_first_message_bare));
903 scram_HMAC_update(&ctx, ",", 1);
904 scram_HMAC_update(&ctx,
905 state->server_first_message,
906 strlen(state->server_first_message));
907 scram_HMAC_update(&ctx, ",", 1);
908 scram_HMAC_update(&ctx,
909 state->client_final_message_without_proof,
910 strlen(state->client_final_message_without_proof));
911 scram_HMAC_final(ClientSignature, &ctx);
913 /* Extract the ClientKey that the client calculated from the proof */
914 for (i = 0; i < SCRAM_KEY_LEN; i++)
915 ClientKey[i] = ClientProof[i] ^ ClientSignature[i];
917 /* Hash it one more time, and compare with StoredKey */
918 scram_H(ClientKey, SCRAM_KEY_LEN, client_StoredKey);
920 if (memcmp(client_StoredKey, state->StoredKey, SCRAM_KEY_LEN) != 0)
927 * Verify a plaintext password against a SCRAM verifier. This is used when
928 * performing plaintext password authentication for a user that has a SCRAM
929 * verifier stored in pg_authid.
932 scram_verify_plain_password(PgSocket *client,
933 const char *username, const char *password,
934 const char *verifier)
936 char *encoded_salt = NULL;
940 uint8_t salted_password[SCRAM_KEY_LEN];
941 uint8_t stored_key[SCRAM_KEY_LEN];
942 uint8_t server_key[SCRAM_KEY_LEN];
943 uint8_t computed_key[SCRAM_KEY_LEN];
944 char *prep_password = NULL;
948 if (!parse_scram_verifier(verifier, &iterations, &encoded_salt,
949 stored_key, server_key))
951 /* The password looked like a SCRAM verifier, but could not be parsed. */
952 slog_warning(client, "invalid SCRAM verifier for user \"%s\"", username);
956 salt = malloc(pg_b64_dec_len(strlen(encoded_salt)));
959 saltlen = pg_b64_decode(encoded_salt, strlen(encoded_salt), salt);
962 slog_warning(client, "invalid SCRAM verifier for user \"%s\"", username);
966 /* Normalize the password */
967 rc = pg_saslprep(password, &prep_password);
968 if (rc == SASLPREP_SUCCESS)
969 password = prep_password;
971 /* Compute Server Key based on the user-supplied plaintext password */
972 scram_SaltedPassword(password, salt, saltlen, iterations, salted_password);
973 scram_ServerKey(salted_password, computed_key);
976 * Compare the verifier's Server Key with the one computed from the
977 * user-supplied password.
979 result = memcmp(computed_key, server_key, SCRAM_KEY_LEN) == 0;