PostgreSQL Source Code git master
fe-auth-scram.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * fe-auth-scram.c
4 * The front-end (client) implementation of SCRAM authentication.
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 * IDENTIFICATION
10 * src/interfaces/libpq/fe-auth-scram.c
11 *
12 *-------------------------------------------------------------------------
13 */
14
15#include "postgres_fe.h"
16
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"
22
23
24/* The exported SCRAM callback mechanism. */
25static void *scram_init(PGconn *conn, const char *password,
26 const char *sasl_mechanism);
27static SASLStatus scram_exchange(void *opaq, char *input, int inputlen,
28 char **output, int *outputlen);
29static bool scram_channel_bound(void *opaq);
30static void scram_free(void *opaq);
31
37};
38
39/*
40 * Status of exchange messages used for SCRAM authentication via the
41 * SASL protocol.
42 */
43typedef enum
44{
50
51typedef struct
52{
54
55 /* These are supplied by the user */
57 char *password;
59
60 /* State data depending on the hash type */
63
64 /* We construct these */
65 uint8 SaltedPassword[SCRAM_MAX_KEY_LEN];
69
70 /* These come from the server-first message */
72 char *salt;
75 char *nonce;
76
77 /* These come from the server-final message */
79 char ServerSignature[SCRAM_MAX_KEY_LEN];
81
86static bool verify_server_signature(fe_scram_state *state, bool *match,
87 const char **errstr);
89 const char *client_final_message_without_proof,
90 uint8 *result, const char **errstr);
91
92/*
93 * Initialize SCRAM exchange status.
94 */
95static void *
97 const char *password,
98 const char *sasl_mechanism)
99{
101 char *prep_password;
103
104 Assert(sasl_mechanism != NULL);
105
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;
114
115 state->sasl_mechanism = strdup(sasl_mechanism);
116 if (!state->sasl_mechanism)
117 {
118 free(state);
119 return NULL;
120 }
121
122 if (password)
123 {
124 /* Normalize the password with SASLprep, if possible */
125 rc = pg_saslprep(password, &prep_password);
126 if (rc == SASLPREP_OOM)
127 {
128 free(state->sasl_mechanism);
129 free(state);
130 return NULL;
131 }
132 if (rc != SASLPREP_SUCCESS)
133 {
134 prep_password = strdup(password);
135 if (!prep_password)
136 {
137 free(state->sasl_mechanism);
138 free(state);
139 return NULL;
140 }
141 }
142 state->password = prep_password;
143 }
144
145 return state;
146}
147
148/*
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.
152 *
153 * Note that the caller must also ensure that the exchange was actually
154 * successful.
155 */
156static bool
158{
160
161 /* no SCRAM exchange done */
162 if (state == NULL)
163 return false;
164
165 /* SCRAM exchange not completed */
166 if (state->state != FE_SCRAM_FINISHED)
167 return false;
168
169 /* channel binding mechanism not used */
170 if (strcmp(state->sasl_mechanism, SCRAM_SHA_256_PLUS_NAME) != 0)
171 return false;
172
173 /* all clear! */
174 return true;
175}
176
177/*
178 * Free SCRAM exchange status
179 */
180static void
181scram_free(void *opaq)
182{
184
185 free(state->password);
186 free(state->sasl_mechanism);
187
188 /* client messages */
189 free(state->client_nonce);
190 free(state->client_first_message_bare);
191 free(state->client_final_message_without_proof);
192
193 /* first message from server */
194 free(state->server_first_message);
195 free(state->salt);
196 free(state->nonce);
197
198 /* final message from server */
199 free(state->server_final_message);
200
201 free(state);
202}
203
204/*
205 * Exchange a SCRAM message with backend.
206 */
207static SASLStatus
208scram_exchange(void *opaq, char *input, int inputlen,
209 char **output, int *outputlen)
210{
212 PGconn *conn = state->conn;
213 const char *errstr = NULL;
214
215 *output = NULL;
216 *outputlen = 0;
217
218 /*
219 * Check that the input length agrees with the string length of the input.
220 * We can ignore inputlen after this.
221 */
222 if (state->state != FE_SCRAM_INIT)
223 {
224 if (inputlen == 0)
225 {
226 libpq_append_conn_error(conn, "malformed SCRAM message (empty message)");
227 return SASL_FAILED;
228 }
229 if (inputlen != strlen(input))
230 {
231 libpq_append_conn_error(conn, "malformed SCRAM message (length mismatch)");
232 return SASL_FAILED;
233 }
234 }
235
236 switch (state->state)
237 {
238 case FE_SCRAM_INIT:
239 /* Begin the SCRAM handshake, by sending client nonce */
241 if (*output == NULL)
242 return SASL_FAILED;
243
244 *outputlen = strlen(*output);
245 state->state = FE_SCRAM_NONCE_SENT;
246 return SASL_CONTINUE;
247
249 /* Receive salt and server nonce, send response. */
251 return SASL_FAILED;
252
254 if (*output == NULL)
255 return SASL_FAILED;
256
257 *outputlen = strlen(*output);
258 state->state = FE_SCRAM_PROOF_SENT;
259 return SASL_CONTINUE;
260
262 {
263 bool match;
264
265 /* Receive server signature */
267 return SASL_FAILED;
268
269 /*
270 * Verify server signature, to make sure we're talking to the
271 * genuine server.
272 */
273 if (!verify_server_signature(state, &match, &errstr))
274 {
275 libpq_append_conn_error(conn, "could not verify server signature: %s", errstr);
276 return SASL_FAILED;
277 }
278
279 if (!match)
280 {
281 libpq_append_conn_error(conn, "incorrect server signature");
282 }
283 state->state = FE_SCRAM_FINISHED;
284 state->conn->client_finished_auth = true;
285 return match ? SASL_COMPLETE : SASL_FAILED;
286 }
287
288 default:
289 /* shouldn't happen */
290 libpq_append_conn_error(conn, "invalid SCRAM exchange state");
291 break;
292 }
293
294 return SASL_FAILED;
295}
296
297/*
298 * Read value for an attribute part of a SCRAM message.
299 *
300 * The buffer at **input is destructively modified, and *input is
301 * advanced over the "attr=value" string and any following comma.
302 *
303 * On failure, append an error message to *errorMessage and return NULL.
304 */
305static char *
306read_attr_value(char **input, char attr, PQExpBuffer errorMessage)
307{
308 char *begin = *input;
309 char *end;
310
311 if (*begin != attr)
312 {
313 libpq_append_error(errorMessage,
314 "malformed SCRAM message (attribute \"%c\" expected)",
315 attr);
316 return NULL;
317 }
318 begin++;
319
320 if (*begin != '=')
321 {
322 libpq_append_error(errorMessage,
323 "malformed SCRAM message (expected character \"=\" for attribute \"%c\")",
324 attr);
325 return NULL;
326 }
327 begin++;
328
329 end = begin;
330 while (*end && *end != ',')
331 end++;
332
333 if (*end)
334 {
335 *end = '\0';
336 *input = end + 1;
337 }
338 else
339 *input = end;
340
341 return begin;
342}
343
344/*
345 * Build the first exchange message sent by the client.
346 */
347static char *
349{
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;
356
357 /*
358 * Generate a "raw" nonce. This is converted to ASCII-printable form by
359 * base64-encoding it.
360 */
361 if (!pg_strong_random(raw_nonce, SCRAM_RAW_NONCE_LEN))
362 {
363 libpq_append_conn_error(conn, "could not generate nonce");
364 return NULL;
365 }
366
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)
371 {
372 libpq_append_conn_error(conn, "out of memory");
373 return NULL;
374 }
375 encoded_len = pg_b64_encode(raw_nonce, SCRAM_RAW_NONCE_LEN,
376 state->client_nonce, encoded_len);
377 if (encoded_len < 0)
378 {
379 libpq_append_conn_error(conn, "could not encode nonce");
380 return NULL;
381 }
382 state->client_nonce[encoded_len] = '\0';
383
384 /*
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.
389 */
390
392
393 /*
394 * First build the gs2-header with channel binding information.
395 */
396 if (strcmp(state->sasl_mechanism, SCRAM_SHA_256_PLUS_NAME) == 0)
397 {
399 appendPQExpBufferStr(&buf, "p=tls-server-end-point");
400 }
401#ifdef USE_SSL
402 else if (conn->channel_binding[0] != 'd' && /* disable */
404 {
405 /*
406 * Client supports channel binding, but thinks the server does not.
407 */
409 }
410#endif
411 else
412 {
413 /*
414 * Client does not support channel binding, or has disabled it.
415 */
417 }
418
420 goto oom_error;
421
422 channel_info_len = buf.len;
423
424 appendPQExpBuffer(&buf, ",,n=,r=%s", state->client_nonce);
426 goto oom_error;
427
428 /*
429 * The first message content needs to be saved without channel binding
430 * information.
431 */
432 state->client_first_message_bare = strdup(buf.data + channel_info_len + 2);
433 if (!state->client_first_message_bare)
434 goto oom_error;
435
436 result = strdup(buf.data);
437 if (result == NULL)
438 goto oom_error;
439
441 return result;
442
443oom_error:
445 libpq_append_conn_error(conn, "out of memory");
446 return NULL;
447}
448
449/*
450 * Build the final exchange message sent from the client.
451 */
452static char *
454{
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;
461
463
464 /*
465 * Construct client-final-message-without-proof. We need to remember it
466 * for verifying the server proof in the final step of authentication.
467 *
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.
471 */
472 if (strcmp(state->sasl_mechanism, SCRAM_SHA_256_PLUS_NAME) == 0)
473 {
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;
481
482 /* Fetch hash data of server's SSL certificate */
483 cbind_data =
485 &cbind_data_len);
486 if (cbind_data == NULL)
487 {
488 /* error message is already set on error */
490 return NULL;
491 }
492
494
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)
500 {
501 free(cbind_data);
502 goto oom_error;
503 }
504 memcpy(cbind_input, "p=tls-server-end-point,,", cbind_header_len);
505 memcpy(cbind_input + cbind_header_len, cbind_data, cbind_data_len);
506
507 encoded_cbind_len = pg_b64_enc_len(cbind_input_len);
508 if (!enlargePQExpBuffer(&buf, encoded_cbind_len))
509 {
510 free(cbind_data);
511 free(cbind_input);
512 goto oom_error;
513 }
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)
518 {
519 free(cbind_data);
520 free(cbind_input);
523 "could not encode cbind data for channel binding\n");
524 return NULL;
525 }
526 buf.len += encoded_cbind_len;
527 buf.data[buf.len] = '\0';
528
529 free(cbind_data);
530 free(cbind_input);
531#else
532 /*
533 * Chose channel binding, but the SSL library doesn't support it.
534 * Shouldn't happen.
535 */
538 "channel binding not supported by this build\n");
539 return NULL;
540#endif /* USE_SSL */
541 }
542#ifdef USE_SSL
543 else if (conn->channel_binding[0] != 'd' && /* disable */
545 appendPQExpBufferStr(&buf, "c=eSws"); /* base64 of "y,," */
546#endif
547 else
548 appendPQExpBufferStr(&buf, "c=biws"); /* base64 of "n,," */
549
551 goto oom_error;
552
553 appendPQExpBuffer(&buf, ",r=%s", state->nonce);
555 goto oom_error;
556
557 state->client_final_message_without_proof = strdup(buf.data);
558 if (state->client_final_message_without_proof == NULL)
559 goto oom_error;
560
561 /* Append proof to it, to form client-final-message. */
563 state->client_final_message_without_proof,
564 client_proof, &errstr))
565 {
567 libpq_append_conn_error(conn, "could not calculate client proof: %s", errstr);
568 return NULL;
569 }
570
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)
580 {
582 libpq_append_conn_error(conn, "could not encode client proof");
583 return NULL;
584 }
585 buf.len += encoded_len;
586 buf.data[buf.len] = '\0';
587
588 result = strdup(buf.data);
589 if (result == NULL)
590 goto oom_error;
591
593 return result;
594
595oom_error:
597 libpq_append_conn_error(conn, "out of memory");
598 return NULL;
599}
600
601/*
602 * Read the first exchange message coming from the server.
603 */
604static bool
606{
607 PGconn *conn = state->conn;
608 char *iterations_str;
609 char *endptr;
610 char *encoded_salt;
611 char *nonce;
612 int decoded_salt_len;
613
614 state->server_first_message = strdup(input);
615 if (state->server_first_message == NULL)
616 {
617 libpq_append_conn_error(conn, "out of memory");
618 return false;
619 }
620
621 /* parse the message */
622 nonce = read_attr_value(&input, 'r',
624 if (nonce == NULL)
625 {
626 /* read_attr_value() has appended an error string */
627 return false;
628 }
629
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)
633 {
634 libpq_append_conn_error(conn, "invalid SCRAM response (nonce mismatch)");
635 return false;
636 }
637
638 state->nonce = strdup(nonce);
639 if (state->nonce == NULL)
640 {
641 libpq_append_conn_error(conn, "out of memory");
642 return false;
643 }
644
645 encoded_salt = read_attr_value(&input, 's', &conn->errorMessage);
646 if (encoded_salt == NULL)
647 {
648 /* read_attr_value() has appended an error string */
649 return false;
650 }
651 decoded_salt_len = pg_b64_dec_len(strlen(encoded_salt));
652 state->salt = malloc(decoded_salt_len);
653 if (state->salt == NULL)
654 {
655 libpq_append_conn_error(conn, "out of memory");
656 return false;
657 }
658 state->saltlen = pg_b64_decode(encoded_salt,
659 strlen(encoded_salt),
660 state->salt,
661 decoded_salt_len);
662 if (state->saltlen < 0)
663 {
664 libpq_append_conn_error(conn, "malformed SCRAM message (invalid salt)");
665 return false;
666 }
667
668 iterations_str = read_attr_value(&input, 'i', &conn->errorMessage);
669 if (iterations_str == NULL)
670 {
671 /* read_attr_value() has appended an error string */
672 return false;
673 }
674 state->iterations = strtol(iterations_str, &endptr, 10);
675 if (*endptr != '\0' || state->iterations < 1)
676 {
677 libpq_append_conn_error(conn, "malformed SCRAM message (invalid iteration count)");
678 return false;
679 }
680
681 if (*input != '\0')
682 libpq_append_conn_error(conn, "malformed SCRAM message (garbage at end of server-first-message)");
683
684 return true;
685}
686
687/*
688 * Read the final exchange message coming from the server.
689 */
690static bool
692{
693 PGconn *conn = state->conn;
694 char *encoded_server_signature;
695 char *decoded_server_signature;
696 int server_signature_len;
697
698 state->server_final_message = strdup(input);
699 if (!state->server_final_message)
700 {
701 libpq_append_conn_error(conn, "out of memory");
702 return false;
703 }
704
705 /* Check for error result. */
706 if (*input == 'e')
707 {
708 char *errmsg = read_attr_value(&input, 'e',
710
711 if (errmsg == NULL)
712 {
713 /* read_attr_value() has appended an error message */
714 return false;
715 }
716 libpq_append_conn_error(conn, "error received from server in SCRAM exchange: %s",
717 errmsg);
718 return false;
719 }
720
721 /* Parse the message. */
722 encoded_server_signature = read_attr_value(&input, 'v',
724 if (encoded_server_signature == NULL)
725 {
726 /* read_attr_value() has appended an error message */
727 return false;
728 }
729
730 if (*input != '\0')
731 libpq_append_conn_error(conn, "malformed SCRAM message (garbage at end of server-final-message)");
732
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)
736 {
737 libpq_append_conn_error(conn, "out of memory");
738 return false;
739 }
740
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)
746 {
747 free(decoded_server_signature);
748 libpq_append_conn_error(conn, "malformed SCRAM message (invalid server signature)");
749 return false;
750 }
751 memcpy(state->ServerSignature, decoded_server_signature,
752 state->key_length);
753 free(decoded_server_signature);
754
755 return true;
756}
757
758/*
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.
762 */
763static bool
765 const char *client_final_message_without_proof,
766 uint8 *result, const char **errstr)
767{
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;
773
774 ctx = pg_hmac_create(state->hash_type);
775 if (ctx == NULL)
776 {
777 *errstr = pg_hmac_error(NULL); /* returns OOM */
778 return false;
779 }
780
781 if (state->conn->scram_client_key_binary)
782 {
783 memcpy(ClientKey, state->conn->scram_client_key_binary, SCRAM_MAX_KEY_LEN);
784 }
785 else
786 {
787 /*
788 * Calculate SaltedPassword, and store it in 'state' so that we can
789 * reuse it later in verify_server_signature.
790 */
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)
797 {
798 /* errstr is already filled here */
799 pg_hmac_free(ctx);
800 return false;
801 }
802 }
803
804 if (scram_H(ClientKey, state->hash_type, state->key_length, StoredKey, errstr) < 0)
805 {
806 pg_hmac_free(ctx);
807 return false;
808 }
809
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)
823 {
824 *errstr = pg_hmac_error(ctx);
825 pg_hmac_free(ctx);
826 return false;
827 }
828
829 for (i = 0; i < state->key_length; i++)
830 result[i] = ClientKey[i] ^ ClientSignature[i];
831
832 pg_hmac_free(ctx);
833 return true;
834}
835
836/*
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.
842 */
843static bool
845 const char **errstr)
846{
847 uint8 expected_ServerSignature[SCRAM_MAX_KEY_LEN];
848 uint8 ServerKey[SCRAM_MAX_KEY_LEN];
849 pg_hmac_ctx *ctx;
850
851 ctx = pg_hmac_create(state->hash_type);
852 if (ctx == NULL)
853 {
854 *errstr = pg_hmac_error(NULL); /* returns OOM */
855 return false;
856 }
857
858 if (state->conn->scram_server_key_binary)
859 {
860 memcpy(ServerKey, state->conn->scram_server_key_binary, SCRAM_MAX_KEY_LEN);
861 }
862 else
863 {
864 if (scram_ServerKey(state->SaltedPassword, state->hash_type,
865 state->key_length, ServerKey, errstr) < 0)
866 {
867 /* errstr is filled already */
868 pg_hmac_free(ctx);
869 return false;
870 }
871 }
872
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)
888 {
889 *errstr = pg_hmac_error(ctx);
890 pg_hmac_free(ctx);
891 return false;
892 }
893
894 pg_hmac_free(ctx);
895
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;
902
903 return true;
904}
905
906/*
907 * Build a new SCRAM secret.
908 *
909 * On error, returns NULL and sets *errstr to point to a message about the
910 * error details.
911 */
912char *
913pg_fe_scram_build_secret(const char *password, int iterations, const char **errstr)
914{
915 char *prep_password;
917 char saltbuf[SCRAM_DEFAULT_SALT_LEN];
918 char *result;
919
920 /*
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.)
925 */
926 rc = pg_saslprep(password, &prep_password);
927 if (rc == SASLPREP_OOM)
928 {
929 *errstr = libpq_gettext("out of memory");
930 return NULL;
931 }
932 if (rc == SASLPREP_SUCCESS)
933 password = (const char *) prep_password;
934
935 /* Generate a random salt */
937 {
938 *errstr = libpq_gettext("could not generate random salt");
939 free(prep_password);
940 return NULL;
941 }
942
946 errstr);
947
948 free(prep_password);
949
950 return result;
951}
int pg_b64_decode(const char *src, int len, char *dst, int dstlen)
Definition: base64.c:116
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
int pg_b64_dec_len(int srclen)
Definition: base64.c:239
uint8_t uint8
Definition: c.h:483
#define Assert(condition)
Definition: c.h:812
pg_cryptohash_type
Definition: cryptohash.h:20
@ PG_SHA256
Definition: cryptohash.h:24
int errmsg(const char *fmt,...)
Definition: elog.c:1070
SASLStatus
Definition: fe-auth-sasl.h:29
@ SASL_CONTINUE
Definition: fe-auth-sasl.h:32
@ SASL_COMPLETE
Definition: fe-auth-sasl.h:30
@ SASL_FAILED
Definition: fe-auth-sasl.h:31
static char * build_client_first_message(fe_scram_state *state)
const pg_fe_sasl_mech pg_scram_mech
Definition: fe-auth-scram.c:32
static bool verify_server_signature(fe_scram_state *state, bool *match, const char **errstr)
fe_scram_state_enum
Definition: fe-auth-scram.c:44
@ FE_SCRAM_PROOF_SENT
Definition: fe-auth-scram.c:47
@ FE_SCRAM_NONCE_SENT
Definition: fe-auth-scram.c:46
@ FE_SCRAM_FINISHED
Definition: fe-auth-scram.c:48
@ FE_SCRAM_INIT
Definition: fe-auth-scram.c:45
static void * scram_init(PGconn *conn, const char *password, const char *sasl_mechanism)
Definition: fe-auth-scram.c:96
static char * read_attr_value(char **input, char attr, PQExpBuffer errorMessage)
static void scram_free(void *opaq)
static bool read_server_first_message(fe_scram_state *state, char *input)
static bool scram_channel_bound(void *opaq)
char * pg_fe_scram_build_secret(const char *password, int iterations, const char **errstr)
static SASLStatus scram_exchange(void *opaq, char *input, int inputlen, char **output, int *outputlen)
static bool calculate_client_proof(fe_scram_state *state, const char *client_final_message_without_proof, uint8 *result, const char **errstr)
static char * build_client_final_message(fe_scram_state *state)
static bool read_server_final_message(fe_scram_state *state, char *input)
void libpq_append_error(PQExpBuffer errorMessage, const char *fmt,...)
Definition: fe-misc.c:1343
void libpq_append_conn_error(PGconn *conn, const char *fmt,...)
Definition: fe-misc.c:1372
char * pgtls_get_peer_certificate_hash(PGconn *conn, size_t *len)
#define free(a)
Definition: header.h:65
#define malloc(a)
Definition: header.h:50
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
FILE * input
FILE * output
int i
Definition: isn.c:72
#define libpq_gettext(x)
Definition: libpq-int.h:913
static char * buf
Definition: pg_test_fsync.c:72
bool pg_strong_random(void *buf, size_t len)
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:90
int enlargePQExpBuffer(PQExpBuffer str, size_t needed)
Definition: pqexpbuffer.c:172
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:265
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:378
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:367
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:129
#define PQExpBufferDataBroken(buf)
Definition: pqexpbuffer.h:67
pg_saslprep_rc pg_saslprep(const char *input, char **output)
Definition: saslprep.c:1047
pg_saslprep_rc
Definition: saslprep.h:21
@ SASLPREP_OOM
Definition: saslprep.h:23
@ 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
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
int scram_ClientKey(const uint8 *salted_password, pg_cryptohash_type hash_type, int key_length, uint8 *result, const char **errstr)
Definition: scram-common.c:142
int scram_H(const uint8 *input, pg_cryptohash_type hash_type, int key_length, uint8 *result, const char **errstr)
Definition: scram-common.c:112
#define SCRAM_SHA_256_PLUS_NAME
Definition: scram-common.h:21
#define SCRAM_RAW_NONCE_LEN
Definition: scram-common.h:37
#define SCRAM_DEFAULT_SALT_LEN
Definition: scram-common.h:44
#define SCRAM_MAX_KEY_LEN
Definition: scram-common.h:30
#define SCRAM_SHA_256_KEY_LEN
Definition: scram-common.h:24
static char * password
Definition: streamutil.c:52
PGconn * conn
Definition: streamutil.c:53
char * client_final_message_without_proof
Definition: fe-auth-scram.c:68
fe_scram_state_enum state
Definition: fe-auth-scram.c:53
char * client_first_message_bare
Definition: fe-auth-scram.c:67
char * server_final_message
Definition: fe-auth-scram.c:78
char * server_first_message
Definition: fe-auth-scram.c:71
char * sasl_mechanism
Definition: fe-auth-scram.c:58
pg_cryptohash_type hash_type
Definition: fe-auth-scram.c:61
char * client_nonce
Definition: fe-auth-scram.c:66
char * channel_binding
Definition: libpq-int.h:401
PQExpBufferData errorMessage
Definition: libpq-int.h:650
bool ssl_in_use
Definition: libpq-int.h:587
Definition: regguts.h:323
int iterations
Definition: thread-thread.c:39