Move routines to manipulate WAL into PostgreSQL::Test::Cluster
[pgsql.git] / src / interfaces / libpq / fe-auth-scram.c
blob557e9c568b66990897af39ddf2833d4c144360aa
1 /*-------------------------------------------------------------------------
3 * fe-auth-scram.c
4 * The front-end (client) implementation of SCRAM authentication.
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
9 * IDENTIFICATION
10 * src/interfaces/libpq/fe-auth-scram.c
12 *-------------------------------------------------------------------------
15 #include "postgres_fe.h"
17 #include "common/base64.h"
18 #include "common/hmac.h"
19 #include "common/saslprep.h"
20 #include "common/scram-common.h"
21 #include "fe-auth.h"
24 /* The exported SCRAM callback mechanism. */
25 static void *scram_init(PGconn *conn, const char *password,
26 const char *sasl_mechanism);
27 static SASLStatus scram_exchange(void *opaq, char *input, int inputlen,
28 char **output, int *outputlen);
29 static bool scram_channel_bound(void *opaq);
30 static void scram_free(void *opaq);
32 const pg_fe_sasl_mech pg_scram_mech = {
33 scram_init,
34 scram_exchange,
35 scram_channel_bound,
36 scram_free
40 * Status of exchange messages used for SCRAM authentication via the
41 * SASL protocol.
43 typedef enum
45 FE_SCRAM_INIT,
46 FE_SCRAM_NONCE_SENT,
47 FE_SCRAM_PROOF_SENT,
48 FE_SCRAM_FINISHED,
49 } fe_scram_state_enum;
51 typedef struct
53 fe_scram_state_enum state;
55 /* These are supplied by the user */
56 PGconn *conn;
57 char *password;
58 char *sasl_mechanism;
60 /* State data depending on the hash type */
61 pg_cryptohash_type hash_type;
62 int key_length;
64 /* We construct these */
65 uint8 SaltedPassword[SCRAM_MAX_KEY_LEN];
66 char *client_nonce;
67 char *client_first_message_bare;
68 char *client_final_message_without_proof;
70 /* These come from the server-first message */
71 char *server_first_message;
72 char *salt;
73 int saltlen;
74 int iterations;
75 char *nonce;
77 /* These come from the server-final message */
78 char *server_final_message;
79 char ServerSignature[SCRAM_MAX_KEY_LEN];
80 } fe_scram_state;
82 static bool read_server_first_message(fe_scram_state *state, char *input);
83 static bool read_server_final_message(fe_scram_state *state, char *input);
84 static char *build_client_first_message(fe_scram_state *state);
85 static char *build_client_final_message(fe_scram_state *state);
86 static bool verify_server_signature(fe_scram_state *state, bool *match,
87 const char **errstr);
88 static bool calculate_client_proof(fe_scram_state *state,
89 const char *client_final_message_without_proof,
90 uint8 *result, const char **errstr);
93 * Initialize SCRAM exchange status.
95 static void *
96 scram_init(PGconn *conn,
97 const char *password,
98 const char *sasl_mechanism)
100 fe_scram_state *state;
101 char *prep_password;
102 pg_saslprep_rc rc;
104 Assert(sasl_mechanism != NULL);
106 state = (fe_scram_state *) malloc(sizeof(fe_scram_state));
107 if (!state)
108 return NULL;
109 memset(state, 0, sizeof(fe_scram_state));
110 state->conn = conn;
111 state->state = FE_SCRAM_INIT;
112 state->key_length = SCRAM_SHA_256_KEY_LEN;
113 state->hash_type = PG_SHA256;
115 state->sasl_mechanism = strdup(sasl_mechanism);
116 if (!state->sasl_mechanism)
118 free(state);
119 return NULL;
122 if (password)
124 /* Normalize the password with SASLprep, if possible */
125 rc = pg_saslprep(password, &prep_password);
126 if (rc == SASLPREP_OOM)
128 free(state->sasl_mechanism);
129 free(state);
130 return NULL;
132 if (rc != SASLPREP_SUCCESS)
134 prep_password = strdup(password);
135 if (!prep_password)
137 free(state->sasl_mechanism);
138 free(state);
139 return NULL;
142 state->password = prep_password;
145 return state;
149 * Return true if channel binding was employed and the SCRAM exchange
150 * completed. This should be used after a successful exchange to determine
151 * whether the server authenticated itself to the client.
153 * Note that the caller must also ensure that the exchange was actually
154 * successful.
156 static bool
157 scram_channel_bound(void *opaq)
159 fe_scram_state *state = (fe_scram_state *) opaq;
161 /* no SCRAM exchange done */
162 if (state == NULL)
163 return false;
165 /* SCRAM exchange not completed */
166 if (state->state != FE_SCRAM_FINISHED)
167 return false;
169 /* channel binding mechanism not used */
170 if (strcmp(state->sasl_mechanism, SCRAM_SHA_256_PLUS_NAME) != 0)
171 return false;
173 /* all clear! */
174 return true;
178 * Free SCRAM exchange status
180 static void
181 scram_free(void *opaq)
183 fe_scram_state *state = (fe_scram_state *) opaq;
185 free(state->password);
186 free(state->sasl_mechanism);
188 /* client messages */
189 free(state->client_nonce);
190 free(state->client_first_message_bare);
191 free(state->client_final_message_without_proof);
193 /* first message from server */
194 free(state->server_first_message);
195 free(state->salt);
196 free(state->nonce);
198 /* final message from server */
199 free(state->server_final_message);
201 free(state);
205 * Exchange a SCRAM message with backend.
207 static SASLStatus
208 scram_exchange(void *opaq, char *input, int inputlen,
209 char **output, int *outputlen)
211 fe_scram_state *state = (fe_scram_state *) opaq;
212 PGconn *conn = state->conn;
213 const char *errstr = NULL;
215 *output = NULL;
216 *outputlen = 0;
219 * Check that the input length agrees with the string length of the input.
220 * We can ignore inputlen after this.
222 if (state->state != FE_SCRAM_INIT)
224 if (inputlen == 0)
226 libpq_append_conn_error(conn, "malformed SCRAM message (empty message)");
227 return SASL_FAILED;
229 if (inputlen != strlen(input))
231 libpq_append_conn_error(conn, "malformed SCRAM message (length mismatch)");
232 return SASL_FAILED;
236 switch (state->state)
238 case FE_SCRAM_INIT:
239 /* Begin the SCRAM handshake, by sending client nonce */
240 *output = build_client_first_message(state);
241 if (*output == NULL)
242 return SASL_FAILED;
244 *outputlen = strlen(*output);
245 state->state = FE_SCRAM_NONCE_SENT;
246 return SASL_CONTINUE;
248 case FE_SCRAM_NONCE_SENT:
249 /* Receive salt and server nonce, send response. */
250 if (!read_server_first_message(state, input))
251 return SASL_FAILED;
253 *output = build_client_final_message(state);
254 if (*output == NULL)
255 return SASL_FAILED;
257 *outputlen = strlen(*output);
258 state->state = FE_SCRAM_PROOF_SENT;
259 return SASL_CONTINUE;
261 case FE_SCRAM_PROOF_SENT:
263 bool match;
265 /* Receive server signature */
266 if (!read_server_final_message(state, input))
267 return SASL_FAILED;
270 * Verify server signature, to make sure we're talking to the
271 * genuine server.
273 if (!verify_server_signature(state, &match, &errstr))
275 libpq_append_conn_error(conn, "could not verify server signature: %s", errstr);
276 return SASL_FAILED;
279 if (!match)
281 libpq_append_conn_error(conn, "incorrect server signature");
283 state->state = FE_SCRAM_FINISHED;
284 state->conn->client_finished_auth = true;
285 return match ? SASL_COMPLETE : SASL_FAILED;
288 default:
289 /* shouldn't happen */
290 libpq_append_conn_error(conn, "invalid SCRAM exchange state");
291 break;
294 return SASL_FAILED;
298 * Read value for an attribute part of a SCRAM message.
300 * The buffer at **input is destructively modified, and *input is
301 * advanced over the "attr=value" string and any following comma.
303 * On failure, append an error message to *errorMessage and return NULL.
305 static char *
306 read_attr_value(char **input, char attr, PQExpBuffer errorMessage)
308 char *begin = *input;
309 char *end;
311 if (*begin != attr)
313 libpq_append_error(errorMessage,
314 "malformed SCRAM message (attribute \"%c\" expected)",
315 attr);
316 return NULL;
318 begin++;
320 if (*begin != '=')
322 libpq_append_error(errorMessage,
323 "malformed SCRAM message (expected character \"=\" for attribute \"%c\")",
324 attr);
325 return NULL;
327 begin++;
329 end = begin;
330 while (*end && *end != ',')
331 end++;
333 if (*end)
335 *end = '\0';
336 *input = end + 1;
338 else
339 *input = end;
341 return begin;
345 * Build the first exchange message sent by the client.
347 static char *
348 build_client_first_message(fe_scram_state *state)
350 PGconn *conn = state->conn;
351 char raw_nonce[SCRAM_RAW_NONCE_LEN + 1];
352 char *result;
353 int channel_info_len;
354 int encoded_len;
355 PQExpBufferData buf;
358 * Generate a "raw" nonce. This is converted to ASCII-printable form by
359 * base64-encoding it.
361 if (!pg_strong_random(raw_nonce, SCRAM_RAW_NONCE_LEN))
363 libpq_append_conn_error(conn, "could not generate nonce");
364 return NULL;
367 encoded_len = pg_b64_enc_len(SCRAM_RAW_NONCE_LEN);
368 /* don't forget the zero-terminator */
369 state->client_nonce = malloc(encoded_len + 1);
370 if (state->client_nonce == NULL)
372 libpq_append_conn_error(conn, "out of memory");
373 return NULL;
375 encoded_len = pg_b64_encode(raw_nonce, SCRAM_RAW_NONCE_LEN,
376 state->client_nonce, encoded_len);
377 if (encoded_len < 0)
379 libpq_append_conn_error(conn, "could not encode nonce");
380 return NULL;
382 state->client_nonce[encoded_len] = '\0';
385 * Generate message. The username is left empty as the backend uses the
386 * value provided by the startup packet. Also, as this username is not
387 * prepared with SASLprep, the message parsing would fail if it includes
388 * '=' or ',' characters.
391 initPQExpBuffer(&buf);
394 * First build the gs2-header with channel binding information.
396 if (strcmp(state->sasl_mechanism, SCRAM_SHA_256_PLUS_NAME) == 0)
398 Assert(conn->ssl_in_use);
399 appendPQExpBufferStr(&buf, "p=tls-server-end-point");
401 #ifdef USE_SSL
402 else if (conn->channel_binding[0] != 'd' && /* disable */
403 conn->ssl_in_use)
406 * Client supports channel binding, but thinks the server does not.
408 appendPQExpBufferChar(&buf, 'y');
410 #endif
411 else
414 * Client does not support channel binding, or has disabled it.
416 appendPQExpBufferChar(&buf, 'n');
419 if (PQExpBufferDataBroken(buf))
420 goto oom_error;
422 channel_info_len = buf.len;
424 appendPQExpBuffer(&buf, ",,n=,r=%s", state->client_nonce);
425 if (PQExpBufferDataBroken(buf))
426 goto oom_error;
429 * The first message content needs to be saved without channel binding
430 * information.
432 state->client_first_message_bare = strdup(buf.data + channel_info_len + 2);
433 if (!state->client_first_message_bare)
434 goto oom_error;
436 result = strdup(buf.data);
437 if (result == NULL)
438 goto oom_error;
440 termPQExpBuffer(&buf);
441 return result;
443 oom_error:
444 termPQExpBuffer(&buf);
445 libpq_append_conn_error(conn, "out of memory");
446 return NULL;
450 * Build the final exchange message sent from the client.
452 static char *
453 build_client_final_message(fe_scram_state *state)
455 PQExpBufferData buf;
456 PGconn *conn = state->conn;
457 uint8 client_proof[SCRAM_MAX_KEY_LEN];
458 char *result;
459 int encoded_len;
460 const char *errstr = NULL;
462 initPQExpBuffer(&buf);
465 * Construct client-final-message-without-proof. We need to remember it
466 * for verifying the server proof in the final step of authentication.
468 * The channel binding flag handling (p/y/n) must be consistent with
469 * build_client_first_message(), because the server will check that it's
470 * the same flag both times.
472 if (strcmp(state->sasl_mechanism, SCRAM_SHA_256_PLUS_NAME) == 0)
474 #ifdef USE_SSL
475 char *cbind_data = NULL;
476 size_t cbind_data_len = 0;
477 size_t cbind_header_len;
478 char *cbind_input;
479 size_t cbind_input_len;
480 int encoded_cbind_len;
482 /* Fetch hash data of server's SSL certificate */
483 cbind_data =
484 pgtls_get_peer_certificate_hash(state->conn,
485 &cbind_data_len);
486 if (cbind_data == NULL)
488 /* error message is already set on error */
489 termPQExpBuffer(&buf);
490 return NULL;
493 appendPQExpBufferStr(&buf, "c=");
495 /* p=type,, */
496 cbind_header_len = strlen("p=tls-server-end-point,,");
497 cbind_input_len = cbind_header_len + cbind_data_len;
498 cbind_input = malloc(cbind_input_len);
499 if (!cbind_input)
501 free(cbind_data);
502 goto oom_error;
504 memcpy(cbind_input, "p=tls-server-end-point,,", cbind_header_len);
505 memcpy(cbind_input + cbind_header_len, cbind_data, cbind_data_len);
507 encoded_cbind_len = pg_b64_enc_len(cbind_input_len);
508 if (!enlargePQExpBuffer(&buf, encoded_cbind_len))
510 free(cbind_data);
511 free(cbind_input);
512 goto oom_error;
514 encoded_cbind_len = pg_b64_encode(cbind_input, cbind_input_len,
515 buf.data + buf.len,
516 encoded_cbind_len);
517 if (encoded_cbind_len < 0)
519 free(cbind_data);
520 free(cbind_input);
521 termPQExpBuffer(&buf);
522 appendPQExpBufferStr(&conn->errorMessage,
523 "could not encode cbind data for channel binding\n");
524 return NULL;
526 buf.len += encoded_cbind_len;
527 buf.data[buf.len] = '\0';
529 free(cbind_data);
530 free(cbind_input);
531 #else
533 * Chose channel binding, but the SSL library doesn't support it.
534 * Shouldn't happen.
536 termPQExpBuffer(&buf);
537 appendPQExpBufferStr(&conn->errorMessage,
538 "channel binding not supported by this build\n");
539 return NULL;
540 #endif /* USE_SSL */
542 #ifdef USE_SSL
543 else if (conn->channel_binding[0] != 'd' && /* disable */
544 conn->ssl_in_use)
545 appendPQExpBufferStr(&buf, "c=eSws"); /* base64 of "y,," */
546 #endif
547 else
548 appendPQExpBufferStr(&buf, "c=biws"); /* base64 of "n,," */
550 if (PQExpBufferDataBroken(buf))
551 goto oom_error;
553 appendPQExpBuffer(&buf, ",r=%s", state->nonce);
554 if (PQExpBufferDataBroken(buf))
555 goto oom_error;
557 state->client_final_message_without_proof = strdup(buf.data);
558 if (state->client_final_message_without_proof == NULL)
559 goto oom_error;
561 /* Append proof to it, to form client-final-message. */
562 if (!calculate_client_proof(state,
563 state->client_final_message_without_proof,
564 client_proof, &errstr))
566 termPQExpBuffer(&buf);
567 libpq_append_conn_error(conn, "could not calculate client proof: %s", errstr);
568 return NULL;
571 appendPQExpBufferStr(&buf, ",p=");
572 encoded_len = pg_b64_enc_len(state->key_length);
573 if (!enlargePQExpBuffer(&buf, encoded_len))
574 goto oom_error;
575 encoded_len = pg_b64_encode((char *) client_proof,
576 state->key_length,
577 buf.data + buf.len,
578 encoded_len);
579 if (encoded_len < 0)
581 termPQExpBuffer(&buf);
582 libpq_append_conn_error(conn, "could not encode client proof");
583 return NULL;
585 buf.len += encoded_len;
586 buf.data[buf.len] = '\0';
588 result = strdup(buf.data);
589 if (result == NULL)
590 goto oom_error;
592 termPQExpBuffer(&buf);
593 return result;
595 oom_error:
596 termPQExpBuffer(&buf);
597 libpq_append_conn_error(conn, "out of memory");
598 return NULL;
602 * Read the first exchange message coming from the server.
604 static bool
605 read_server_first_message(fe_scram_state *state, char *input)
607 PGconn *conn = state->conn;
608 char *iterations_str;
609 char *endptr;
610 char *encoded_salt;
611 char *nonce;
612 int decoded_salt_len;
614 state->server_first_message = strdup(input);
615 if (state->server_first_message == NULL)
617 libpq_append_conn_error(conn, "out of memory");
618 return false;
621 /* parse the message */
622 nonce = read_attr_value(&input, 'r',
623 &conn->errorMessage);
624 if (nonce == NULL)
626 /* read_attr_value() has appended an error string */
627 return false;
630 /* Verify immediately that the server used our part of the nonce */
631 if (strlen(nonce) < strlen(state->client_nonce) ||
632 memcmp(nonce, state->client_nonce, strlen(state->client_nonce)) != 0)
634 libpq_append_conn_error(conn, "invalid SCRAM response (nonce mismatch)");
635 return false;
638 state->nonce = strdup(nonce);
639 if (state->nonce == NULL)
641 libpq_append_conn_error(conn, "out of memory");
642 return false;
645 encoded_salt = read_attr_value(&input, 's', &conn->errorMessage);
646 if (encoded_salt == NULL)
648 /* read_attr_value() has appended an error string */
649 return false;
651 decoded_salt_len = pg_b64_dec_len(strlen(encoded_salt));
652 state->salt = malloc(decoded_salt_len);
653 if (state->salt == NULL)
655 libpq_append_conn_error(conn, "out of memory");
656 return false;
658 state->saltlen = pg_b64_decode(encoded_salt,
659 strlen(encoded_salt),
660 state->salt,
661 decoded_salt_len);
662 if (state->saltlen < 0)
664 libpq_append_conn_error(conn, "malformed SCRAM message (invalid salt)");
665 return false;
668 iterations_str = read_attr_value(&input, 'i', &conn->errorMessage);
669 if (iterations_str == NULL)
671 /* read_attr_value() has appended an error string */
672 return false;
674 state->iterations = strtol(iterations_str, &endptr, 10);
675 if (*endptr != '\0' || state->iterations < 1)
677 libpq_append_conn_error(conn, "malformed SCRAM message (invalid iteration count)");
678 return false;
681 if (*input != '\0')
682 libpq_append_conn_error(conn, "malformed SCRAM message (garbage at end of server-first-message)");
684 return true;
688 * Read the final exchange message coming from the server.
690 static bool
691 read_server_final_message(fe_scram_state *state, char *input)
693 PGconn *conn = state->conn;
694 char *encoded_server_signature;
695 char *decoded_server_signature;
696 int server_signature_len;
698 state->server_final_message = strdup(input);
699 if (!state->server_final_message)
701 libpq_append_conn_error(conn, "out of memory");
702 return false;
705 /* Check for error result. */
706 if (*input == 'e')
708 char *errmsg = read_attr_value(&input, 'e',
709 &conn->errorMessage);
711 if (errmsg == NULL)
713 /* read_attr_value() has appended an error message */
714 return false;
716 libpq_append_conn_error(conn, "error received from server in SCRAM exchange: %s",
717 errmsg);
718 return false;
721 /* Parse the message. */
722 encoded_server_signature = read_attr_value(&input, 'v',
723 &conn->errorMessage);
724 if (encoded_server_signature == NULL)
726 /* read_attr_value() has appended an error message */
727 return false;
730 if (*input != '\0')
731 libpq_append_conn_error(conn, "malformed SCRAM message (garbage at end of server-final-message)");
733 server_signature_len = pg_b64_dec_len(strlen(encoded_server_signature));
734 decoded_server_signature = malloc(server_signature_len);
735 if (!decoded_server_signature)
737 libpq_append_conn_error(conn, "out of memory");
738 return false;
741 server_signature_len = pg_b64_decode(encoded_server_signature,
742 strlen(encoded_server_signature),
743 decoded_server_signature,
744 server_signature_len);
745 if (server_signature_len != state->key_length)
747 free(decoded_server_signature);
748 libpq_append_conn_error(conn, "malformed SCRAM message (invalid server signature)");
749 return false;
751 memcpy(state->ServerSignature, decoded_server_signature,
752 state->key_length);
753 free(decoded_server_signature);
755 return true;
759 * Calculate the client proof, part of the final exchange message sent
760 * by the client. Returns true on success, false on failure with *errstr
761 * pointing to a message about the error details.
763 static bool
764 calculate_client_proof(fe_scram_state *state,
765 const char *client_final_message_without_proof,
766 uint8 *result, const char **errstr)
768 uint8 StoredKey[SCRAM_MAX_KEY_LEN];
769 uint8 ClientKey[SCRAM_MAX_KEY_LEN];
770 uint8 ClientSignature[SCRAM_MAX_KEY_LEN];
771 int i;
772 pg_hmac_ctx *ctx;
774 ctx = pg_hmac_create(state->hash_type);
775 if (ctx == NULL)
777 *errstr = pg_hmac_error(NULL); /* returns OOM */
778 return false;
781 if (state->conn->scram_client_key_binary)
783 memcpy(ClientKey, state->conn->scram_client_key_binary, SCRAM_MAX_KEY_LEN);
785 else
788 * Calculate SaltedPassword, and store it in 'state' so that we can
789 * reuse it later in verify_server_signature.
791 if (scram_SaltedPassword(state->password, state->hash_type,
792 state->key_length, state->salt, state->saltlen,
793 state->iterations, state->SaltedPassword,
794 errstr) < 0 ||
795 scram_ClientKey(state->SaltedPassword, state->hash_type,
796 state->key_length, ClientKey, errstr) < 0)
798 /* errstr is already filled here */
799 pg_hmac_free(ctx);
800 return false;
804 if (scram_H(ClientKey, state->hash_type, state->key_length, StoredKey, errstr) < 0)
806 pg_hmac_free(ctx);
807 return false;
810 if (pg_hmac_init(ctx, StoredKey, state->key_length) < 0 ||
811 pg_hmac_update(ctx,
812 (uint8 *) state->client_first_message_bare,
813 strlen(state->client_first_message_bare)) < 0 ||
814 pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
815 pg_hmac_update(ctx,
816 (uint8 *) state->server_first_message,
817 strlen(state->server_first_message)) < 0 ||
818 pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
819 pg_hmac_update(ctx,
820 (uint8 *) client_final_message_without_proof,
821 strlen(client_final_message_without_proof)) < 0 ||
822 pg_hmac_final(ctx, ClientSignature, state->key_length) < 0)
824 *errstr = pg_hmac_error(ctx);
825 pg_hmac_free(ctx);
826 return false;
829 for (i = 0; i < state->key_length; i++)
830 result[i] = ClientKey[i] ^ ClientSignature[i];
832 pg_hmac_free(ctx);
833 return true;
837 * Validate the server signature, received as part of the final exchange
838 * message received from the server. *match tracks if the server signature
839 * matched or not. Returns true if the server signature got verified, and
840 * false for a processing error with *errstr pointing to a message about the
841 * error details.
843 static bool
844 verify_server_signature(fe_scram_state *state, bool *match,
845 const char **errstr)
847 uint8 expected_ServerSignature[SCRAM_MAX_KEY_LEN];
848 uint8 ServerKey[SCRAM_MAX_KEY_LEN];
849 pg_hmac_ctx *ctx;
851 ctx = pg_hmac_create(state->hash_type);
852 if (ctx == NULL)
854 *errstr = pg_hmac_error(NULL); /* returns OOM */
855 return false;
858 if (state->conn->scram_server_key_binary)
860 memcpy(ServerKey, state->conn->scram_server_key_binary, SCRAM_MAX_KEY_LEN);
862 else
864 if (scram_ServerKey(state->SaltedPassword, state->hash_type,
865 state->key_length, ServerKey, errstr) < 0)
867 /* errstr is filled already */
868 pg_hmac_free(ctx);
869 return false;
873 /* calculate ServerSignature */
874 if (pg_hmac_init(ctx, ServerKey, state->key_length) < 0 ||
875 pg_hmac_update(ctx,
876 (uint8 *) state->client_first_message_bare,
877 strlen(state->client_first_message_bare)) < 0 ||
878 pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
879 pg_hmac_update(ctx,
880 (uint8 *) state->server_first_message,
881 strlen(state->server_first_message)) < 0 ||
882 pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
883 pg_hmac_update(ctx,
884 (uint8 *) state->client_final_message_without_proof,
885 strlen(state->client_final_message_without_proof)) < 0 ||
886 pg_hmac_final(ctx, expected_ServerSignature,
887 state->key_length) < 0)
889 *errstr = pg_hmac_error(ctx);
890 pg_hmac_free(ctx);
891 return false;
894 pg_hmac_free(ctx);
896 /* signature processed, so now check after it */
897 if (memcmp(expected_ServerSignature, state->ServerSignature,
898 state->key_length) != 0)
899 *match = false;
900 else
901 *match = true;
903 return true;
907 * Build a new SCRAM secret.
909 * On error, returns NULL and sets *errstr to point to a message about the
910 * error details.
912 char *
913 pg_fe_scram_build_secret(const char *password, int iterations, const char **errstr)
915 char *prep_password;
916 pg_saslprep_rc rc;
917 char saltbuf[SCRAM_DEFAULT_SALT_LEN];
918 char *result;
921 * Normalize the password with SASLprep. If that doesn't work, because
922 * the password isn't valid UTF-8 or contains prohibited characters, just
923 * proceed with the original password. (See comments at the top of
924 * auth-scram.c.)
926 rc = pg_saslprep(password, &prep_password);
927 if (rc == SASLPREP_OOM)
929 *errstr = libpq_gettext("out of memory");
930 return NULL;
932 if (rc == SASLPREP_SUCCESS)
933 password = (const char *) prep_password;
935 /* Generate a random salt */
936 if (!pg_strong_random(saltbuf, SCRAM_DEFAULT_SALT_LEN))
938 *errstr = libpq_gettext("could not generate random salt");
939 free(prep_password);
940 return NULL;
943 result = scram_build_secret(PG_SHA256, SCRAM_SHA_256_KEY_LEN, saltbuf,
944 SCRAM_DEFAULT_SALT_LEN,
945 iterations, password,
946 errstr);
948 free(prep_password);
950 return result;