1 /*-------------------------------------------------------------------------
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
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"
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
= {
40 * Status of exchange messages used for SCRAM authentication via the
49 } fe_scram_state_enum
;
53 fe_scram_state_enum state
;
55 /* These are supplied by the user */
60 /* State data depending on the hash type */
61 pg_cryptohash_type hash_type
;
64 /* We construct these */
65 uint8 SaltedPassword
[SCRAM_MAX_KEY_LEN
];
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
;
77 /* These come from the server-final message */
78 char *server_final_message
;
79 char ServerSignature
[SCRAM_MAX_KEY_LEN
];
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
,
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.
96 scram_init(PGconn
*conn
,
98 const char *sasl_mechanism
)
100 fe_scram_state
*state
;
104 Assert(sasl_mechanism
!= NULL
);
106 state
= (fe_scram_state
*) malloc(sizeof(fe_scram_state
));
109 memset(state
, 0, sizeof(fe_scram_state
));
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
)
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
);
132 if (rc
!= SASLPREP_SUCCESS
)
134 prep_password
= strdup(password
);
137 free(state
->sasl_mechanism
);
142 state
->password
= prep_password
;
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
157 scram_channel_bound(void *opaq
)
159 fe_scram_state
*state
= (fe_scram_state
*) opaq
;
161 /* no SCRAM exchange done */
165 /* SCRAM exchange not completed */
166 if (state
->state
!= FE_SCRAM_FINISHED
)
169 /* channel binding mechanism not used */
170 if (strcmp(state
->sasl_mechanism
, SCRAM_SHA_256_PLUS_NAME
) != 0)
178 * Free SCRAM exchange status
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
);
198 /* final message from server */
199 free(state
->server_final_message
);
205 * Exchange a SCRAM message with backend.
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
;
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
)
226 libpq_append_conn_error(conn
, "malformed SCRAM message (empty message)");
229 if (inputlen
!= strlen(input
))
231 libpq_append_conn_error(conn
, "malformed SCRAM message (length mismatch)");
236 switch (state
->state
)
239 /* Begin the SCRAM handshake, by sending client nonce */
240 *output
= build_client_first_message(state
);
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
))
253 *output
= build_client_final_message(state
);
257 *outputlen
= strlen(*output
);
258 state
->state
= FE_SCRAM_PROOF_SENT
;
259 return SASL_CONTINUE
;
261 case FE_SCRAM_PROOF_SENT
:
265 /* Receive server signature */
266 if (!read_server_final_message(state
, input
))
270 * Verify server signature, to make sure we're talking to the
273 if (!verify_server_signature(state
, &match
, &errstr
))
275 libpq_append_conn_error(conn
, "could not verify server signature: %s", errstr
);
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
;
289 /* shouldn't happen */
290 libpq_append_conn_error(conn
, "invalid SCRAM exchange state");
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.
306 read_attr_value(char **input
, char attr
, PQExpBuffer errorMessage
)
308 char *begin
= *input
;
313 libpq_append_error(errorMessage
,
314 "malformed SCRAM message (attribute \"%c\" expected)",
322 libpq_append_error(errorMessage
,
323 "malformed SCRAM message (expected character \"=\" for attribute \"%c\")",
330 while (*end
&& *end
!= ',')
345 * Build the first exchange message sent by the client.
348 build_client_first_message(fe_scram_state
*state
)
350 PGconn
*conn
= state
->conn
;
351 char raw_nonce
[SCRAM_RAW_NONCE_LEN
+ 1];
353 int channel_info_len
;
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");
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");
375 encoded_len
= pg_b64_encode(raw_nonce
, SCRAM_RAW_NONCE_LEN
,
376 state
->client_nonce
, encoded_len
);
379 libpq_append_conn_error(conn
, "could not encode nonce");
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");
402 else if (conn
->channel_binding
[0] != 'd' && /* disable */
406 * Client supports channel binding, but thinks the server does not.
408 appendPQExpBufferChar(&buf
, 'y');
414 * Client does not support channel binding, or has disabled it.
416 appendPQExpBufferChar(&buf
, 'n');
419 if (PQExpBufferDataBroken(buf
))
422 channel_info_len
= buf
.len
;
424 appendPQExpBuffer(&buf
, ",,n=,r=%s", state
->client_nonce
);
425 if (PQExpBufferDataBroken(buf
))
429 * The first message content needs to be saved without channel binding
432 state
->client_first_message_bare
= strdup(buf
.data
+ channel_info_len
+ 2);
433 if (!state
->client_first_message_bare
)
436 result
= strdup(buf
.data
);
440 termPQExpBuffer(&buf
);
444 termPQExpBuffer(&buf
);
445 libpq_append_conn_error(conn
, "out of memory");
450 * Build the final exchange message sent from the client.
453 build_client_final_message(fe_scram_state
*state
)
456 PGconn
*conn
= state
->conn
;
457 uint8 client_proof
[SCRAM_MAX_KEY_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)
475 char *cbind_data
= NULL
;
476 size_t cbind_data_len
= 0;
477 size_t cbind_header_len
;
479 size_t cbind_input_len
;
480 int encoded_cbind_len
;
482 /* Fetch hash data of server's SSL certificate */
484 pgtls_get_peer_certificate_hash(state
->conn
,
486 if (cbind_data
== NULL
)
488 /* error message is already set on error */
489 termPQExpBuffer(&buf
);
493 appendPQExpBufferStr(&buf
, "c=");
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
);
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
))
514 encoded_cbind_len
= pg_b64_encode(cbind_input
, cbind_input_len
,
517 if (encoded_cbind_len
< 0)
521 termPQExpBuffer(&buf
);
522 appendPQExpBufferStr(&conn
->errorMessage
,
523 "could not encode cbind data for channel binding\n");
526 buf
.len
+= encoded_cbind_len
;
527 buf
.data
[buf
.len
] = '\0';
533 * Chose channel binding, but the SSL library doesn't support it.
536 termPQExpBuffer(&buf
);
537 appendPQExpBufferStr(&conn
->errorMessage
,
538 "channel binding not supported by this build\n");
543 else if (conn
->channel_binding
[0] != 'd' && /* disable */
545 appendPQExpBufferStr(&buf
, "c=eSws"); /* base64 of "y,," */
548 appendPQExpBufferStr(&buf
, "c=biws"); /* base64 of "n,," */
550 if (PQExpBufferDataBroken(buf
))
553 appendPQExpBuffer(&buf
, ",r=%s", state
->nonce
);
554 if (PQExpBufferDataBroken(buf
))
557 state
->client_final_message_without_proof
= strdup(buf
.data
);
558 if (state
->client_final_message_without_proof
== NULL
)
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
);
571 appendPQExpBufferStr(&buf
, ",p=");
572 encoded_len
= pg_b64_enc_len(state
->key_length
);
573 if (!enlargePQExpBuffer(&buf
, encoded_len
))
575 encoded_len
= pg_b64_encode((char *) client_proof
,
581 termPQExpBuffer(&buf
);
582 libpq_append_conn_error(conn
, "could not encode client proof");
585 buf
.len
+= encoded_len
;
586 buf
.data
[buf
.len
] = '\0';
588 result
= strdup(buf
.data
);
592 termPQExpBuffer(&buf
);
596 termPQExpBuffer(&buf
);
597 libpq_append_conn_error(conn
, "out of memory");
602 * Read the first exchange message coming from the server.
605 read_server_first_message(fe_scram_state
*state
, char *input
)
607 PGconn
*conn
= state
->conn
;
608 char *iterations_str
;
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");
621 /* parse the message */
622 nonce
= read_attr_value(&input
, 'r',
623 &conn
->errorMessage
);
626 /* read_attr_value() has appended an error string */
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)");
638 state
->nonce
= strdup(nonce
);
639 if (state
->nonce
== NULL
)
641 libpq_append_conn_error(conn
, "out of memory");
645 encoded_salt
= read_attr_value(&input
, 's', &conn
->errorMessage
);
646 if (encoded_salt
== NULL
)
648 /* read_attr_value() has appended an error string */
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");
658 state
->saltlen
= pg_b64_decode(encoded_salt
,
659 strlen(encoded_salt
),
662 if (state
->saltlen
< 0)
664 libpq_append_conn_error(conn
, "malformed SCRAM message (invalid salt)");
668 iterations_str
= read_attr_value(&input
, 'i', &conn
->errorMessage
);
669 if (iterations_str
== NULL
)
671 /* read_attr_value() has appended an error string */
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)");
682 libpq_append_conn_error(conn
, "malformed SCRAM message (garbage at end of server-first-message)");
688 * Read the final exchange message coming from the server.
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");
705 /* Check for error result. */
708 char *errmsg
= read_attr_value(&input
, 'e',
709 &conn
->errorMessage
);
713 /* read_attr_value() has appended an error message */
716 libpq_append_conn_error(conn
, "error received from server in SCRAM exchange: %s",
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 */
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");
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)");
751 memcpy(state
->ServerSignature
, decoded_server_signature
,
753 free(decoded_server_signature
);
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.
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
];
774 ctx
= pg_hmac_create(state
->hash_type
);
777 *errstr
= pg_hmac_error(NULL
); /* returns OOM */
781 if (state
->conn
->scram_client_key_binary
)
783 memcpy(ClientKey
, state
->conn
->scram_client_key_binary
, SCRAM_MAX_KEY_LEN
);
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
,
795 scram_ClientKey(state
->SaltedPassword
, state
->hash_type
,
796 state
->key_length
, ClientKey
, errstr
) < 0)
798 /* errstr is already filled here */
804 if (scram_H(ClientKey
, state
->hash_type
, state
->key_length
, StoredKey
, errstr
) < 0)
810 if (pg_hmac_init(ctx
, StoredKey
, state
->key_length
) < 0 ||
812 (uint8
*) state
->client_first_message_bare
,
813 strlen(state
->client_first_message_bare
)) < 0 ||
814 pg_hmac_update(ctx
, (uint8
*) ",", 1) < 0 ||
816 (uint8
*) state
->server_first_message
,
817 strlen(state
->server_first_message
)) < 0 ||
818 pg_hmac_update(ctx
, (uint8
*) ",", 1) < 0 ||
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
);
829 for (i
= 0; i
< state
->key_length
; i
++)
830 result
[i
] = ClientKey
[i
] ^ ClientSignature
[i
];
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
844 verify_server_signature(fe_scram_state
*state
, bool *match
,
847 uint8 expected_ServerSignature
[SCRAM_MAX_KEY_LEN
];
848 uint8 ServerKey
[SCRAM_MAX_KEY_LEN
];
851 ctx
= pg_hmac_create(state
->hash_type
);
854 *errstr
= pg_hmac_error(NULL
); /* returns OOM */
858 if (state
->conn
->scram_server_key_binary
)
860 memcpy(ServerKey
, state
->conn
->scram_server_key_binary
, SCRAM_MAX_KEY_LEN
);
864 if (scram_ServerKey(state
->SaltedPassword
, state
->hash_type
,
865 state
->key_length
, ServerKey
, errstr
) < 0)
867 /* errstr is filled already */
873 /* calculate ServerSignature */
874 if (pg_hmac_init(ctx
, ServerKey
, state
->key_length
) < 0 ||
876 (uint8
*) state
->client_first_message_bare
,
877 strlen(state
->client_first_message_bare
)) < 0 ||
878 pg_hmac_update(ctx
, (uint8
*) ",", 1) < 0 ||
880 (uint8
*) state
->server_first_message
,
881 strlen(state
->server_first_message
)) < 0 ||
882 pg_hmac_update(ctx
, (uint8
*) ",", 1) < 0 ||
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
);
896 /* signature processed, so now check after it */
897 if (memcmp(expected_ServerSignature
, state
->ServerSignature
,
898 state
->key_length
) != 0)
907 * Build a new SCRAM secret.
909 * On error, returns NULL and sets *errstr to point to a message about the
913 pg_fe_scram_build_secret(const char *password
, int iterations
, const char **errstr
)
917 char saltbuf
[SCRAM_DEFAULT_SALT_LEN
];
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
926 rc
= pg_saslprep(password
, &prep_password
);
927 if (rc
== SASLPREP_OOM
)
929 *errstr
= libpq_gettext("out of memory");
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");
943 result
= scram_build_secret(PG_SHA256
, SCRAM_SHA_256_KEY_LEN
, saltbuf
,
944 SCRAM_DEFAULT_SALT_LEN
,
945 iterations
, password
,