Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * auth-scram.c
4 : * Server-side implementation of the SASL SCRAM-SHA-256 mechanism.
5 : *
6 : * See the following RFCs for more details:
7 : * - RFC 5802: https://tools.ietf.org/html/rfc5802
8 : * - RFC 5803: https://tools.ietf.org/html/rfc5803
9 : * - RFC 7677: https://tools.ietf.org/html/rfc7677
10 : *
11 : * Here are some differences:
12 : *
13 : * - Username from the authentication exchange is not used. The client
14 : * should send an empty string as the username.
15 : *
16 : * - If the password isn't valid UTF-8, or contains characters prohibited
17 : * by the SASLprep profile, we skip the SASLprep pre-processing and use
18 : * the raw bytes in calculating the hash.
19 : *
20 : * - If channel binding is used, the channel binding type is always
21 : * "tls-server-end-point". The spec says the default is "tls-unique"
22 : * (RFC 5802, section 6.1. Default Channel Binding), but there are some
23 : * problems with that. Firstly, not all SSL libraries provide an API to
24 : * get the TLS Finished message, required to use "tls-unique". Secondly,
25 : * "tls-unique" is not specified for TLS v1.3, and as of this writing,
26 : * it's not clear if there will be a replacement. We could support both
27 : * "tls-server-end-point" and "tls-unique", but for our use case,
28 : * "tls-unique" doesn't really have any advantages. The main advantage
29 : * of "tls-unique" would be that it works even if the server doesn't
30 : * have a certificate, but PostgreSQL requires a server certificate
31 : * whenever SSL is used, anyway.
32 : *
33 : *
34 : * The password stored in pg_authid consists of the iteration count, salt,
35 : * StoredKey and ServerKey.
36 : *
37 : * SASLprep usage
38 : * --------------
39 : *
40 : * One notable difference to the SCRAM specification is that while the
41 : * specification dictates that the password is in UTF-8, and prohibits
42 : * certain characters, we are more lenient. If the password isn't a valid
43 : * UTF-8 string, or contains prohibited characters, the raw bytes are used
44 : * to calculate the hash instead, without SASLprep processing. This is
45 : * because PostgreSQL supports other encodings too, and the encoding being
46 : * used during authentication is undefined (client_encoding isn't set until
47 : * after authentication). In effect, we try to interpret the password as
48 : * UTF-8 and apply SASLprep processing, but if it looks invalid, we assume
49 : * that it's in some other encoding.
50 : *
51 : * In the worst case, we misinterpret a password that's in a different
52 : * encoding as being Unicode, because it happens to consists entirely of
53 : * valid UTF-8 bytes, and we apply Unicode normalization to it. As long
54 : * as we do that consistently, that will not lead to failed logins.
55 : * Fortunately, the UTF-8 byte sequences that are ignored by SASLprep
56 : * don't correspond to any commonly used characters in any of the other
57 : * supported encodings, so it should not lead to any significant loss in
58 : * entropy, even if the normalization is incorrectly applied to a
59 : * non-UTF-8 password.
60 : *
61 : * Error handling
62 : * --------------
63 : *
64 : * Don't reveal user information to an unauthenticated client. We don't
65 : * want an attacker to be able to probe whether a particular username is
66 : * valid. In SCRAM, the server has to read the salt and iteration count
67 : * from the user's stored secret, and send it to the client. To avoid
68 : * revealing whether a user exists, when the client tries to authenticate
69 : * with a username that doesn't exist, or doesn't have a valid SCRAM
70 : * secret in pg_authid, we create a fake salt and iteration count
71 : * on-the-fly, and proceed with the authentication with that. In the end,
72 : * we'll reject the attempt, as if an incorrect password was given. When
73 : * we are performing a "mock" authentication, the 'doomed' flag in
74 : * scram_state is set.
75 : *
76 : * In the error messages, avoid printing strings from the client, unless
77 : * you check that they are pure ASCII. We don't want an unauthenticated
78 : * attacker to be able to spam the logs with characters that are not valid
79 : * to the encoding being used, whatever that is. We cannot avoid that in
80 : * general, after logging in, but let's do what we can here.
81 : *
82 : *
83 : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
84 : * Portions Copyright (c) 1994, Regents of the University of California
85 : *
86 : * src/backend/libpq/auth-scram.c
87 : *
88 : *-------------------------------------------------------------------------
89 : */
90 : #include "postgres.h"
91 :
92 : #include <unistd.h>
93 :
94 : #include "access/xlog.h"
95 : #include "catalog/pg_control.h"
96 : #include "common/base64.h"
97 : #include "common/hmac.h"
98 : #include "common/saslprep.h"
99 : #include "common/scram-common.h"
100 : #include "common/sha2.h"
101 : #include "libpq/crypt.h"
102 : #include "libpq/sasl.h"
103 : #include "libpq/scram.h"
104 :
105 : static void scram_get_mechanisms(Port *port, StringInfo buf);
106 : static void *scram_init(Port *port, const char *selected_mech,
107 : const char *shadow_pass);
108 : static int scram_exchange(void *opaq, const char *input, int inputlen,
109 : char **output, int *outputlen,
110 : const char **logdetail);
111 :
112 : /* Mechanism declaration */
113 : const pg_be_sasl_mech pg_be_scram_mech = {
114 : scram_get_mechanisms,
115 : scram_init,
116 : scram_exchange
117 : };
118 :
119 : /*
120 : * Status data for a SCRAM authentication exchange. This should be kept
121 : * internal to this file.
122 : */
123 : typedef enum
124 : {
125 : SCRAM_AUTH_INIT,
126 : SCRAM_AUTH_SALT_SENT,
127 : SCRAM_AUTH_FINISHED,
128 : } scram_state_enum;
129 :
130 : typedef struct
131 : {
132 : scram_state_enum state;
133 :
134 : const char *username; /* username from startup packet */
135 :
136 : Port *port;
137 : bool channel_binding_in_use;
138 :
139 : /* State data depending on the hash type */
140 : pg_cryptohash_type hash_type;
141 : int key_length;
142 :
143 : int iterations;
144 : char *salt; /* base64-encoded */
145 : uint8 StoredKey[SCRAM_MAX_KEY_LEN];
146 : uint8 ServerKey[SCRAM_MAX_KEY_LEN];
147 :
148 : /* Fields of the first message from client */
149 : char cbind_flag;
150 : char *client_first_message_bare;
151 : char *client_username;
152 : char *client_nonce;
153 :
154 : /* Fields from the last message from client */
155 : char *client_final_message_without_proof;
156 : char *client_final_nonce;
157 : char ClientProof[SCRAM_MAX_KEY_LEN];
158 :
159 : /* Fields generated in the server */
160 : char *server_first_message;
161 : char *server_nonce;
162 :
163 : /*
164 : * If something goes wrong during the authentication, or we are performing
165 : * a "mock" authentication (see comments at top of file), the 'doomed'
166 : * flag is set. A reason for the failure, for the server log, is put in
167 : * 'logdetail'.
168 : */
169 : bool doomed;
170 : char *logdetail;
171 : } scram_state;
172 :
173 : static void read_client_first_message(scram_state *state, const char *input);
174 : static void read_client_final_message(scram_state *state, const char *input);
175 : static char *build_server_first_message(scram_state *state);
176 : static char *build_server_final_message(scram_state *state);
177 : static bool verify_client_proof(scram_state *state);
178 : static bool verify_final_nonce(scram_state *state);
179 : static void mock_scram_secret(const char *username, pg_cryptohash_type *hash_type,
180 : int *iterations, int *key_length, char **salt,
181 : uint8 *stored_key, uint8 *server_key);
182 : static bool is_scram_printable(char *p);
183 : static char *sanitize_char(char c);
184 : static char *sanitize_str(const char *s);
185 : static char *scram_mock_salt(const char *username,
186 : pg_cryptohash_type hash_type,
187 : int key_length);
188 :
189 : /*
190 : * The number of iterations to use when generating new secrets.
191 : */
192 : int scram_sha_256_iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
193 :
194 : /*
195 : * Get a list of SASL mechanisms that this module supports.
196 : *
197 : * For the convenience of building the FE/BE packet that lists the
198 : * mechanisms, the names are appended to the given StringInfo buffer,
199 : * separated by '\0' bytes.
200 : */
201 : static void
202 98 : scram_get_mechanisms(Port *port, StringInfo buf)
203 : {
204 : /*
205 : * Advertise the mechanisms in decreasing order of importance. So the
206 : * channel-binding variants go first, if they are supported. Channel
207 : * binding is only supported with SSL.
208 : */
209 : #ifdef USE_SSL
210 98 : if (port->ssl_in_use)
211 : {
212 12 : appendStringInfoString(buf, SCRAM_SHA_256_PLUS_NAME);
213 12 : appendStringInfoChar(buf, '\0');
214 : }
215 : #endif
216 98 : appendStringInfoString(buf, SCRAM_SHA_256_NAME);
217 98 : appendStringInfoChar(buf, '\0');
218 98 : }
219 :
220 : /*
221 : * Initialize a new SCRAM authentication exchange status tracker. This
222 : * needs to be called before doing any exchange. It will be filled later
223 : * after the beginning of the exchange with authentication information.
224 : *
225 : * 'selected_mech' identifies the SASL mechanism that the client selected.
226 : * It should be one of the mechanisms that we support, as returned by
227 : * scram_get_mechanisms().
228 : *
229 : * 'shadow_pass' is the role's stored secret, from pg_authid.rolpassword.
230 : * The username was provided by the client in the startup message, and is
231 : * available in port->user_name. If 'shadow_pass' is NULL, we still perform
232 : * an authentication exchange, but it will fail, as if an incorrect password
233 : * was given.
234 : */
235 : static void *
236 76 : scram_init(Port *port, const char *selected_mech, const char *shadow_pass)
237 : {
238 : scram_state *state;
239 : bool got_secret;
240 :
241 76 : state = (scram_state *) palloc0(sizeof(scram_state));
242 76 : state->port = port;
243 76 : state->state = SCRAM_AUTH_INIT;
244 :
245 : /*
246 : * Parse the selected mechanism.
247 : *
248 : * Note that if we don't support channel binding, or if we're not using
249 : * SSL at all, we would not have advertised the PLUS variant in the first
250 : * place. If the client nevertheless tries to select it, it's a protocol
251 : * violation like selecting any other SASL mechanism we don't support.
252 : */
253 : #ifdef USE_SSL
254 76 : if (strcmp(selected_mech, SCRAM_SHA_256_PLUS_NAME) == 0 && port->ssl_in_use)
255 8 : state->channel_binding_in_use = true;
256 : else
257 : #endif
258 68 : if (strcmp(selected_mech, SCRAM_SHA_256_NAME) == 0)
259 68 : state->channel_binding_in_use = false;
260 : else
261 0 : ereport(ERROR,
262 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
263 : errmsg("client selected an invalid SASL authentication mechanism")));
264 :
265 : /*
266 : * Parse the stored secret.
267 : */
268 76 : if (shadow_pass)
269 : {
270 76 : int password_type = get_password_type(shadow_pass);
271 :
272 76 : if (password_type == PASSWORD_TYPE_SCRAM_SHA_256)
273 : {
274 74 : if (parse_scram_secret(shadow_pass, &state->iterations,
275 : &state->hash_type, &state->key_length,
276 : &state->salt,
277 74 : state->StoredKey,
278 74 : state->ServerKey))
279 74 : got_secret = true;
280 : else
281 : {
282 : /*
283 : * The password looked like a SCRAM secret, but could not be
284 : * parsed.
285 : */
286 0 : ereport(LOG,
287 : (errmsg("invalid SCRAM secret for user \"%s\"",
288 : state->port->user_name)));
289 0 : got_secret = false;
290 : }
291 : }
292 : else
293 : {
294 : /*
295 : * The user doesn't have SCRAM secret. (You cannot do SCRAM
296 : * authentication with an MD5 hash.)
297 : */
298 4 : state->logdetail = psprintf(_("User \"%s\" does not have a valid SCRAM secret."),
299 2 : state->port->user_name);
300 2 : got_secret = false;
301 : }
302 : }
303 : else
304 : {
305 : /*
306 : * The caller requested us to perform a dummy authentication. This is
307 : * considered normal, since the caller requested it, so don't set log
308 : * detail.
309 : */
310 0 : got_secret = false;
311 : }
312 :
313 : /*
314 : * If the user did not have a valid SCRAM secret, we still go through the
315 : * motions with a mock one, and fail as if the client supplied an
316 : * incorrect password. This is to avoid revealing information to an
317 : * attacker.
318 : */
319 76 : if (!got_secret)
320 : {
321 2 : mock_scram_secret(state->port->user_name, &state->hash_type,
322 : &state->iterations, &state->key_length,
323 : &state->salt,
324 2 : state->StoredKey, state->ServerKey);
325 2 : state->doomed = true;
326 : }
327 :
328 76 : return state;
329 : }
330 :
331 : /*
332 : * Continue a SCRAM authentication exchange.
333 : *
334 : * 'input' is the SCRAM payload sent by the client. On the first call,
335 : * 'input' contains the "Initial Client Response" that the client sent as
336 : * part of the SASLInitialResponse message, or NULL if no Initial Client
337 : * Response was given. (The SASL specification distinguishes between an
338 : * empty response and non-existing one.) On subsequent calls, 'input'
339 : * cannot be NULL. For convenience in this function, the caller must
340 : * ensure that there is a null terminator at input[inputlen].
341 : *
342 : * The next message to send to client is saved in 'output', for a length
343 : * of 'outputlen'. In the case of an error, optionally store a palloc'd
344 : * string at *logdetail that will be sent to the postmaster log (but not
345 : * the client).
346 : */
347 : static int
348 152 : scram_exchange(void *opaq, const char *input, int inputlen,
349 : char **output, int *outputlen, const char **logdetail)
350 : {
351 152 : scram_state *state = (scram_state *) opaq;
352 : int result;
353 :
354 152 : *output = NULL;
355 :
356 : /*
357 : * If the client didn't include an "Initial Client Response" in the
358 : * SASLInitialResponse message, send an empty challenge, to which the
359 : * client will respond with the same data that usually comes in the
360 : * Initial Client Response.
361 : */
362 152 : if (input == NULL)
363 : {
364 : Assert(state->state == SCRAM_AUTH_INIT);
365 :
366 0 : *output = pstrdup("");
367 0 : *outputlen = 0;
368 0 : return PG_SASL_EXCHANGE_CONTINUE;
369 : }
370 :
371 : /*
372 : * Check that the input length agrees with the string length of the input.
373 : * We can ignore inputlen after this.
374 : */
375 152 : if (inputlen == 0)
376 0 : ereport(ERROR,
377 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
378 : errmsg("malformed SCRAM message"),
379 : errdetail("The message is empty.")));
380 152 : if (inputlen != strlen(input))
381 0 : ereport(ERROR,
382 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
383 : errmsg("malformed SCRAM message"),
384 : errdetail("Message length does not match input length.")));
385 :
386 152 : switch (state->state)
387 : {
388 76 : case SCRAM_AUTH_INIT:
389 :
390 : /*
391 : * Initialization phase. Receive the first message from client
392 : * and be sure that it parsed correctly. Then send the challenge
393 : * to the client.
394 : */
395 76 : read_client_first_message(state, input);
396 :
397 : /* prepare message to send challenge */
398 76 : *output = build_server_first_message(state);
399 :
400 76 : state->state = SCRAM_AUTH_SALT_SENT;
401 76 : result = PG_SASL_EXCHANGE_CONTINUE;
402 76 : break;
403 :
404 76 : case SCRAM_AUTH_SALT_SENT:
405 :
406 : /*
407 : * Final phase for the server. Receive the response to the
408 : * challenge previously sent, verify, and let the client know that
409 : * everything went well (or not).
410 : */
411 76 : read_client_final_message(state, input);
412 :
413 76 : if (!verify_final_nonce(state))
414 0 : ereport(ERROR,
415 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
416 : errmsg("invalid SCRAM response"),
417 : errdetail("Nonce does not match.")));
418 :
419 : /*
420 : * Now check the final nonce and the client proof.
421 : *
422 : * If we performed a "mock" authentication that we knew would fail
423 : * from the get go, this is where we fail.
424 : *
425 : * The SCRAM specification includes an error code,
426 : * "invalid-proof", for authentication failure, but it also allows
427 : * erroring out in an application-specific way. We choose to do
428 : * the latter, so that the error message for invalid password is
429 : * the same for all authentication methods. The caller will call
430 : * ereport(), when we return PG_SASL_EXCHANGE_FAILURE with no
431 : * output.
432 : *
433 : * NB: the order of these checks is intentional. We calculate the
434 : * client proof even in a mock authentication, even though it's
435 : * bound to fail, to thwart timing attacks to determine if a role
436 : * with the given name exists or not.
437 : */
438 76 : if (!verify_client_proof(state) || state->doomed)
439 : {
440 10 : result = PG_SASL_EXCHANGE_FAILURE;
441 10 : break;
442 : }
443 :
444 : /* Build final message for client */
445 66 : *output = build_server_final_message(state);
446 :
447 : /* Success! */
448 66 : result = PG_SASL_EXCHANGE_SUCCESS;
449 66 : state->state = SCRAM_AUTH_FINISHED;
450 66 : break;
451 :
452 0 : default:
453 0 : elog(ERROR, "invalid SCRAM exchange state");
454 : result = PG_SASL_EXCHANGE_FAILURE;
455 : }
456 :
457 152 : if (result == PG_SASL_EXCHANGE_FAILURE && state->logdetail && logdetail)
458 2 : *logdetail = state->logdetail;
459 :
460 152 : if (*output)
461 142 : *outputlen = strlen(*output);
462 :
463 152 : return result;
464 : }
465 :
466 : /*
467 : * Construct a SCRAM secret, for storing in pg_authid.rolpassword.
468 : *
469 : * The result is palloc'd, so caller is responsible for freeing it.
470 : */
471 : char *
472 96 : pg_be_scram_build_secret(const char *password)
473 : {
474 : char *prep_password;
475 : pg_saslprep_rc rc;
476 : char saltbuf[SCRAM_DEFAULT_SALT_LEN];
477 : char *result;
478 96 : const char *errstr = NULL;
479 :
480 : /*
481 : * Normalize the password with SASLprep. If that doesn't work, because
482 : * the password isn't valid UTF-8 or contains prohibited characters, just
483 : * proceed with the original password. (See comments at top of file.)
484 : */
485 96 : rc = pg_saslprep(password, &prep_password);
486 96 : if (rc == SASLPREP_SUCCESS)
487 94 : password = (const char *) prep_password;
488 :
489 : /* Generate random salt */
490 96 : if (!pg_strong_random(saltbuf, SCRAM_DEFAULT_SALT_LEN))
491 0 : ereport(ERROR,
492 : (errcode(ERRCODE_INTERNAL_ERROR),
493 : errmsg("could not generate random salt")));
494 :
495 96 : result = scram_build_secret(PG_SHA256, SCRAM_SHA_256_KEY_LEN,
496 : saltbuf, SCRAM_DEFAULT_SALT_LEN,
497 : scram_sha_256_iterations, password,
498 : &errstr);
499 :
500 96 : if (prep_password)
501 94 : pfree(prep_password);
502 :
503 96 : return result;
504 : }
505 :
506 : /*
507 : * Verify a plaintext password against a SCRAM secret. This is used when
508 : * performing plaintext password authentication for a user that has a SCRAM
509 : * secret stored in pg_authid.
510 : */
511 : bool
512 38 : scram_verify_plain_password(const char *username, const char *password,
513 : const char *secret)
514 : {
515 : char *encoded_salt;
516 : char *salt;
517 : int saltlen;
518 : int iterations;
519 38 : int key_length = 0;
520 : pg_cryptohash_type hash_type;
521 : uint8 salted_password[SCRAM_MAX_KEY_LEN];
522 : uint8 stored_key[SCRAM_MAX_KEY_LEN];
523 : uint8 server_key[SCRAM_MAX_KEY_LEN];
524 : uint8 computed_key[SCRAM_MAX_KEY_LEN];
525 : char *prep_password;
526 : pg_saslprep_rc rc;
527 38 : const char *errstr = NULL;
528 :
529 38 : if (!parse_scram_secret(secret, &iterations, &hash_type, &key_length,
530 : &encoded_salt, stored_key, server_key))
531 : {
532 : /*
533 : * The password looked like a SCRAM secret, but could not be parsed.
534 : */
535 0 : ereport(LOG,
536 : (errmsg("invalid SCRAM secret for user \"%s\"", username)));
537 0 : return false;
538 : }
539 :
540 38 : saltlen = pg_b64_dec_len(strlen(encoded_salt));
541 38 : salt = palloc(saltlen);
542 38 : saltlen = pg_b64_decode(encoded_salt, strlen(encoded_salt), salt,
543 : saltlen);
544 38 : if (saltlen < 0)
545 : {
546 0 : ereport(LOG,
547 : (errmsg("invalid SCRAM secret for user \"%s\"", username)));
548 0 : return false;
549 : }
550 :
551 : /* Normalize the password */
552 38 : rc = pg_saslprep(password, &prep_password);
553 38 : if (rc == SASLPREP_SUCCESS)
554 38 : password = prep_password;
555 :
556 : /* Compute Server Key based on the user-supplied plaintext password */
557 38 : if (scram_SaltedPassword(password, hash_type, key_length,
558 : salt, saltlen, iterations,
559 38 : salted_password, &errstr) < 0 ||
560 38 : scram_ServerKey(salted_password, hash_type, key_length,
561 : computed_key, &errstr) < 0)
562 : {
563 0 : elog(ERROR, "could not compute server key: %s", errstr);
564 : }
565 :
566 38 : if (prep_password)
567 38 : pfree(prep_password);
568 :
569 : /*
570 : * Compare the secret's Server Key with the one computed from the
571 : * user-supplied password.
572 : */
573 38 : return memcmp(computed_key, server_key, key_length) == 0;
574 : }
575 :
576 :
577 : /*
578 : * Parse and validate format of given SCRAM secret.
579 : *
580 : * On success, the iteration count, salt, stored key, and server key are
581 : * extracted from the secret, and returned to the caller. For 'stored_key'
582 : * and 'server_key', the caller must pass pre-allocated buffers of size
583 : * SCRAM_MAX_KEY_LEN. Salt is returned as a base64-encoded, null-terminated
584 : * string. The buffer for the salt is palloc'd by this function.
585 : *
586 : * Returns true if the SCRAM secret has been parsed, and false otherwise.
587 : */
588 : bool
589 578 : parse_scram_secret(const char *secret, int *iterations,
590 : pg_cryptohash_type *hash_type, int *key_length,
591 : char **salt, uint8 *stored_key, uint8 *server_key)
592 : {
593 : char *v;
594 : char *p;
595 : char *scheme_str;
596 : char *salt_str;
597 : char *iterations_str;
598 : char *storedkey_str;
599 : char *serverkey_str;
600 : int decoded_len;
601 : char *decoded_salt_buf;
602 : char *decoded_stored_buf;
603 : char *decoded_server_buf;
604 :
605 : /*
606 : * The secret is of form:
607 : *
608 : * SCRAM-SHA-256$<iterations>:<salt>$<storedkey>:<serverkey>
609 : */
610 578 : v = pstrdup(secret);
611 578 : if ((scheme_str = strsep(&v, "$")) == NULL)
612 0 : goto invalid_secret;
613 578 : if ((iterations_str = strsep(&v, ":")) == NULL)
614 208 : goto invalid_secret;
615 370 : if ((salt_str = strsep(&v, "$")) == NULL)
616 12 : goto invalid_secret;
617 358 : if ((storedkey_str = strsep(&v, ":")) == NULL)
618 0 : goto invalid_secret;
619 358 : serverkey_str = v;
620 :
621 : /* Parse the fields */
622 358 : if (strcmp(scheme_str, "SCRAM-SHA-256") != 0)
623 0 : goto invalid_secret;
624 358 : *hash_type = PG_SHA256;
625 358 : *key_length = SCRAM_SHA_256_KEY_LEN;
626 :
627 358 : errno = 0;
628 358 : *iterations = strtol(iterations_str, &p, 10);
629 358 : if (*p || errno != 0)
630 0 : goto invalid_secret;
631 :
632 : /*
633 : * Verify that the salt is in Base64-encoded format, by decoding it,
634 : * although we return the encoded version to the caller.
635 : */
636 358 : decoded_len = pg_b64_dec_len(strlen(salt_str));
637 358 : decoded_salt_buf = palloc(decoded_len);
638 358 : decoded_len = pg_b64_decode(salt_str, strlen(salt_str),
639 : decoded_salt_buf, decoded_len);
640 358 : if (decoded_len < 0)
641 0 : goto invalid_secret;
642 358 : *salt = pstrdup(salt_str);
643 :
644 : /*
645 : * Decode StoredKey and ServerKey.
646 : */
647 358 : decoded_len = pg_b64_dec_len(strlen(storedkey_str));
648 358 : decoded_stored_buf = palloc(decoded_len);
649 358 : decoded_len = pg_b64_decode(storedkey_str, strlen(storedkey_str),
650 : decoded_stored_buf, decoded_len);
651 358 : if (decoded_len != *key_length)
652 12 : goto invalid_secret;
653 346 : memcpy(stored_key, decoded_stored_buf, *key_length);
654 :
655 346 : decoded_len = pg_b64_dec_len(strlen(serverkey_str));
656 346 : decoded_server_buf = palloc(decoded_len);
657 346 : decoded_len = pg_b64_decode(serverkey_str, strlen(serverkey_str),
658 : decoded_server_buf, decoded_len);
659 346 : if (decoded_len != *key_length)
660 12 : goto invalid_secret;
661 334 : memcpy(server_key, decoded_server_buf, *key_length);
662 :
663 334 : return true;
664 :
665 244 : invalid_secret:
666 244 : *salt = NULL;
667 244 : return false;
668 : }
669 :
670 : /*
671 : * Generate plausible SCRAM secret parameters for mock authentication.
672 : *
673 : * In a normal authentication, these are extracted from the secret
674 : * stored in the server. This function generates values that look
675 : * realistic, for when there is no stored secret, using SCRAM-SHA-256.
676 : *
677 : * Like in parse_scram_secret(), for 'stored_key' and 'server_key', the
678 : * caller must pass pre-allocated buffers of size SCRAM_MAX_KEY_LEN, and
679 : * the buffer for the salt is palloc'd by this function.
680 : */
681 : static void
682 2 : mock_scram_secret(const char *username, pg_cryptohash_type *hash_type,
683 : int *iterations, int *key_length, char **salt,
684 : uint8 *stored_key, uint8 *server_key)
685 : {
686 : char *raw_salt;
687 : char *encoded_salt;
688 : int encoded_len;
689 :
690 : /* Enforce the use of SHA-256, which would be realistic enough */
691 2 : *hash_type = PG_SHA256;
692 2 : *key_length = SCRAM_SHA_256_KEY_LEN;
693 :
694 : /*
695 : * Generate deterministic salt.
696 : *
697 : * Note that we cannot reveal any information to an attacker here so the
698 : * error messages need to remain generic. This should never fail anyway
699 : * as the salt generated for mock authentication uses the cluster's nonce
700 : * value.
701 : */
702 2 : raw_salt = scram_mock_salt(username, *hash_type, *key_length);
703 2 : if (raw_salt == NULL)
704 0 : elog(ERROR, "could not encode salt");
705 :
706 2 : encoded_len = pg_b64_enc_len(SCRAM_DEFAULT_SALT_LEN);
707 : /* don't forget the zero-terminator */
708 2 : encoded_salt = (char *) palloc(encoded_len + 1);
709 2 : encoded_len = pg_b64_encode(raw_salt, SCRAM_DEFAULT_SALT_LEN, encoded_salt,
710 : encoded_len);
711 :
712 2 : if (encoded_len < 0)
713 0 : elog(ERROR, "could not encode salt");
714 2 : encoded_salt[encoded_len] = '\0';
715 :
716 2 : *salt = encoded_salt;
717 2 : *iterations = SCRAM_SHA_256_DEFAULT_ITERATIONS;
718 :
719 : /* StoredKey and ServerKey are not used in a doomed authentication */
720 2 : memset(stored_key, 0, SCRAM_MAX_KEY_LEN);
721 2 : memset(server_key, 0, SCRAM_MAX_KEY_LEN);
722 2 : }
723 :
724 : /*
725 : * Read the value in a given SCRAM exchange message for given attribute.
726 : */
727 : static char *
728 312 : read_attr_value(char **input, char attr)
729 : {
730 312 : char *begin = *input;
731 : char *end;
732 :
733 312 : if (*begin != attr)
734 0 : ereport(ERROR,
735 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
736 : errmsg("malformed SCRAM message"),
737 : errdetail("Expected attribute \"%c\" but found \"%s\".",
738 : attr, sanitize_char(*begin))));
739 312 : begin++;
740 :
741 312 : if (*begin != '=')
742 0 : ereport(ERROR,
743 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
744 : errmsg("malformed SCRAM message"),
745 : errdetail("Expected character \"=\" for attribute \"%c\".", attr)));
746 312 : begin++;
747 :
748 312 : end = begin;
749 6824 : while (*end && *end != ',')
750 6512 : end++;
751 :
752 312 : if (*end)
753 : {
754 236 : *end = '\0';
755 236 : *input = end + 1;
756 : }
757 : else
758 76 : *input = end;
759 :
760 312 : return begin;
761 : }
762 :
763 : static bool
764 76 : is_scram_printable(char *p)
765 : {
766 : /*------
767 : * Printable characters, as defined by SCRAM spec: (RFC 5802)
768 : *
769 : * printable = %x21-2B / %x2D-7E
770 : * ;; Printable ASCII except ",".
771 : * ;; Note that any "printable" is also
772 : * ;; a valid "value".
773 : *------
774 : */
775 1900 : for (; *p; p++)
776 : {
777 1824 : if (*p < 0x21 || *p > 0x7E || *p == 0x2C /* comma */ )
778 0 : return false;
779 : }
780 76 : return true;
781 : }
782 :
783 : /*
784 : * Convert an arbitrary byte to printable form. For error messages.
785 : *
786 : * If it's a printable ASCII character, print it as a single character.
787 : * otherwise, print it in hex.
788 : *
789 : * The returned pointer points to a static buffer.
790 : */
791 : static char *
792 0 : sanitize_char(char c)
793 : {
794 : static char buf[5];
795 :
796 0 : if (c >= 0x21 && c <= 0x7E)
797 0 : snprintf(buf, sizeof(buf), "'%c'", c);
798 : else
799 0 : snprintf(buf, sizeof(buf), "0x%02x", (unsigned char) c);
800 0 : return buf;
801 : }
802 :
803 : /*
804 : * Convert an arbitrary string to printable form, for error messages.
805 : *
806 : * Anything that's not a printable ASCII character is replaced with
807 : * '?', and the string is truncated at 30 characters.
808 : *
809 : * The returned pointer points to a static buffer.
810 : */
811 : static char *
812 0 : sanitize_str(const char *s)
813 : {
814 : static char buf[30 + 1];
815 : int i;
816 :
817 0 : for (i = 0; i < sizeof(buf) - 1; i++)
818 : {
819 0 : char c = s[i];
820 :
821 0 : if (c == '\0')
822 0 : break;
823 :
824 0 : if (c >= 0x21 && c <= 0x7E)
825 0 : buf[i] = c;
826 : else
827 0 : buf[i] = '?';
828 : }
829 0 : buf[i] = '\0';
830 0 : return buf;
831 : }
832 :
833 : /*
834 : * Read the next attribute and value in a SCRAM exchange message.
835 : *
836 : * The attribute character is set in *attr_p, the attribute value is the
837 : * return value.
838 : */
839 : static char *
840 76 : read_any_attr(char **input, char *attr_p)
841 : {
842 76 : char *begin = *input;
843 : char *end;
844 76 : char attr = *begin;
845 :
846 76 : if (attr == '\0')
847 0 : ereport(ERROR,
848 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
849 : errmsg("malformed SCRAM message"),
850 : errdetail("Attribute expected, but found end of string.")));
851 :
852 : /*------
853 : * attr-val = ALPHA "=" value
854 : * ;; Generic syntax of any attribute sent
855 : * ;; by server or client
856 : *------
857 : */
858 76 : if (!((attr >= 'A' && attr <= 'Z') ||
859 76 : (attr >= 'a' && attr <= 'z')))
860 0 : ereport(ERROR,
861 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
862 : errmsg("malformed SCRAM message"),
863 : errdetail("Attribute expected, but found invalid character \"%s\".",
864 : sanitize_char(attr))));
865 76 : if (attr_p)
866 76 : *attr_p = attr;
867 76 : begin++;
868 :
869 76 : if (*begin != '=')
870 0 : ereport(ERROR,
871 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
872 : errmsg("malformed SCRAM message"),
873 : errdetail("Expected character \"=\" for attribute \"%c\".", attr)));
874 76 : begin++;
875 :
876 76 : end = begin;
877 3420 : while (*end && *end != ',')
878 3344 : end++;
879 :
880 76 : if (*end)
881 : {
882 0 : *end = '\0';
883 0 : *input = end + 1;
884 : }
885 : else
886 76 : *input = end;
887 :
888 76 : return begin;
889 : }
890 :
891 : /*
892 : * Read and parse the first message from client in the context of a SCRAM
893 : * authentication exchange message.
894 : *
895 : * At this stage, any errors will be reported directly with ereport(ERROR).
896 : */
897 : static void
898 76 : read_client_first_message(scram_state *state, const char *input)
899 : {
900 76 : char *p = pstrdup(input);
901 : char *channel_binding_type;
902 :
903 :
904 : /*------
905 : * The syntax for the client-first-message is: (RFC 5802)
906 : *
907 : * saslname = 1*(value-safe-char / "=2C" / "=3D")
908 : * ;; Conforms to <value>.
909 : *
910 : * authzid = "a=" saslname
911 : * ;; Protocol specific.
912 : *
913 : * cb-name = 1*(ALPHA / DIGIT / "." / "-")
914 : * ;; See RFC 5056, Section 7.
915 : * ;; E.g., "tls-server-end-point" or
916 : * ;; "tls-unique".
917 : *
918 : * gs2-cbind-flag = ("p=" cb-name) / "n" / "y"
919 : * ;; "n" -> client doesn't support channel binding.
920 : * ;; "y" -> client does support channel binding
921 : * ;; but thinks the server does not.
922 : * ;; "p" -> client requires channel binding.
923 : * ;; The selected channel binding follows "p=".
924 : *
925 : * gs2-header = gs2-cbind-flag "," [ authzid ] ","
926 : * ;; GS2 header for SCRAM
927 : * ;; (the actual GS2 header includes an optional
928 : * ;; flag to indicate that the GSS mechanism is not
929 : * ;; "standard", but since SCRAM is "standard", we
930 : * ;; don't include that flag).
931 : *
932 : * username = "n=" saslname
933 : * ;; Usernames are prepared using SASLprep.
934 : *
935 : * reserved-mext = "m=" 1*(value-char)
936 : * ;; Reserved for signaling mandatory extensions.
937 : * ;; The exact syntax will be defined in
938 : * ;; the future.
939 : *
940 : * nonce = "r=" c-nonce [s-nonce]
941 : * ;; Second part provided by server.
942 : *
943 : * c-nonce = printable
944 : *
945 : * client-first-message-bare =
946 : * [reserved-mext ","]
947 : * username "," nonce ["," extensions]
948 : *
949 : * client-first-message =
950 : * gs2-header client-first-message-bare
951 : *
952 : * For example:
953 : * n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL
954 : *
955 : * The "n,," in the beginning means that the client doesn't support
956 : * channel binding, and no authzid is given. "n=user" is the username.
957 : * However, in PostgreSQL the username is sent in the startup packet, and
958 : * the username in the SCRAM exchange is ignored. libpq always sends it
959 : * as an empty string. The last part, "r=fyko+d2lbbFgONRv9qkxdawL" is
960 : * the client nonce.
961 : *------
962 : */
963 :
964 : /*
965 : * Read gs2-cbind-flag. (For details see also RFC 5802 Section 6 "Channel
966 : * Binding".)
967 : */
968 76 : state->cbind_flag = *p;
969 76 : switch (*p)
970 : {
971 68 : case 'n':
972 :
973 : /*
974 : * The client does not support channel binding or has simply
975 : * decided to not use it. In that case just let it go.
976 : */
977 68 : if (state->channel_binding_in_use)
978 0 : ereport(ERROR,
979 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
980 : errmsg("malformed SCRAM message"),
981 : errdetail("The client selected SCRAM-SHA-256-PLUS, but the SCRAM message does not include channel binding data.")));
982 :
983 68 : p++;
984 68 : if (*p != ',')
985 0 : ereport(ERROR,
986 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
987 : errmsg("malformed SCRAM message"),
988 : errdetail("Comma expected, but found character \"%s\".",
989 : sanitize_char(*p))));
990 68 : p++;
991 68 : break;
992 0 : case 'y':
993 :
994 : /*
995 : * The client supports channel binding and thinks that the server
996 : * does not. In this case, the server must fail authentication if
997 : * it supports channel binding.
998 : */
999 0 : if (state->channel_binding_in_use)
1000 0 : ereport(ERROR,
1001 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
1002 : errmsg("malformed SCRAM message"),
1003 : errdetail("The client selected SCRAM-SHA-256-PLUS, but the SCRAM message does not include channel binding data.")));
1004 :
1005 : #ifdef USE_SSL
1006 0 : if (state->port->ssl_in_use)
1007 0 : ereport(ERROR,
1008 : (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
1009 : errmsg("SCRAM channel binding negotiation error"),
1010 : errdetail("The client supports SCRAM channel binding but thinks the server does not. "
1011 : "However, this server does support channel binding.")));
1012 : #endif
1013 0 : p++;
1014 0 : if (*p != ',')
1015 0 : ereport(ERROR,
1016 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
1017 : errmsg("malformed SCRAM message"),
1018 : errdetail("Comma expected, but found character \"%s\".",
1019 : sanitize_char(*p))));
1020 0 : p++;
1021 0 : break;
1022 8 : case 'p':
1023 :
1024 : /*
1025 : * The client requires channel binding. Channel binding type
1026 : * follows, e.g., "p=tls-server-end-point".
1027 : */
1028 8 : if (!state->channel_binding_in_use)
1029 0 : ereport(ERROR,
1030 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
1031 : errmsg("malformed SCRAM message"),
1032 : errdetail("The client selected SCRAM-SHA-256 without channel binding, but the SCRAM message includes channel binding data.")));
1033 :
1034 8 : channel_binding_type = read_attr_value(&p, 'p');
1035 :
1036 : /*
1037 : * The only channel binding type we support is
1038 : * tls-server-end-point.
1039 : */
1040 8 : if (strcmp(channel_binding_type, "tls-server-end-point") != 0)
1041 0 : ereport(ERROR,
1042 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
1043 : errmsg("unsupported SCRAM channel-binding type \"%s\"",
1044 : sanitize_str(channel_binding_type))));
1045 8 : break;
1046 0 : default:
1047 0 : ereport(ERROR,
1048 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
1049 : errmsg("malformed SCRAM message"),
1050 : errdetail("Unexpected channel-binding flag \"%s\".",
1051 : sanitize_char(*p))));
1052 : }
1053 :
1054 : /*
1055 : * Forbid optional authzid (authorization identity). We don't support it.
1056 : */
1057 76 : if (*p == 'a')
1058 0 : ereport(ERROR,
1059 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1060 : errmsg("client uses authorization identity, but it is not supported")));
1061 76 : if (*p != ',')
1062 0 : ereport(ERROR,
1063 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
1064 : errmsg("malformed SCRAM message"),
1065 : errdetail("Unexpected attribute \"%s\" in client-first-message.",
1066 : sanitize_char(*p))));
1067 76 : p++;
1068 :
1069 76 : state->client_first_message_bare = pstrdup(p);
1070 :
1071 : /*
1072 : * Any mandatory extensions would go here. We don't support any.
1073 : *
1074 : * RFC 5802 specifies error code "e=extensions-not-supported" for this,
1075 : * but it can only be sent in the server-final message. We prefer to fail
1076 : * immediately (which the RFC also allows).
1077 : */
1078 76 : if (*p == 'm')
1079 0 : ereport(ERROR,
1080 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1081 : errmsg("client requires an unsupported SCRAM extension")));
1082 :
1083 : /*
1084 : * Read username. Note: this is ignored. We use the username from the
1085 : * startup message instead, still it is kept around if provided as it
1086 : * proves to be useful for debugging purposes.
1087 : */
1088 76 : state->client_username = read_attr_value(&p, 'n');
1089 :
1090 : /* read nonce and check that it is made of only printable characters */
1091 76 : state->client_nonce = read_attr_value(&p, 'r');
1092 76 : if (!is_scram_printable(state->client_nonce))
1093 0 : ereport(ERROR,
1094 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
1095 : errmsg("non-printable characters in SCRAM nonce")));
1096 :
1097 : /*
1098 : * There can be any number of optional extensions after this. We don't
1099 : * support any extensions, so ignore them.
1100 : */
1101 76 : while (*p != '\0')
1102 0 : read_any_attr(&p, NULL);
1103 :
1104 : /* success! */
1105 76 : }
1106 :
1107 : /*
1108 : * Verify the final nonce contained in the last message received from
1109 : * client in an exchange.
1110 : */
1111 : static bool
1112 76 : verify_final_nonce(scram_state *state)
1113 : {
1114 76 : int client_nonce_len = strlen(state->client_nonce);
1115 76 : int server_nonce_len = strlen(state->server_nonce);
1116 76 : int final_nonce_len = strlen(state->client_final_nonce);
1117 :
1118 76 : if (final_nonce_len != client_nonce_len + server_nonce_len)
1119 0 : return false;
1120 76 : if (memcmp(state->client_final_nonce, state->client_nonce, client_nonce_len) != 0)
1121 0 : return false;
1122 76 : if (memcmp(state->client_final_nonce + client_nonce_len, state->server_nonce, server_nonce_len) != 0)
1123 0 : return false;
1124 :
1125 76 : return true;
1126 : }
1127 :
1128 : /*
1129 : * Verify the client proof contained in the last message received from
1130 : * client in an exchange. Returns true if the verification is a success,
1131 : * or false for a failure.
1132 : */
1133 : static bool
1134 76 : verify_client_proof(scram_state *state)
1135 : {
1136 : uint8 ClientSignature[SCRAM_MAX_KEY_LEN];
1137 : uint8 ClientKey[SCRAM_MAX_KEY_LEN];
1138 : uint8 client_StoredKey[SCRAM_MAX_KEY_LEN];
1139 76 : pg_hmac_ctx *ctx = pg_hmac_create(state->hash_type);
1140 : int i;
1141 76 : const char *errstr = NULL;
1142 :
1143 : /*
1144 : * Calculate ClientSignature. Note that we don't log directly a failure
1145 : * here even when processing the calculations as this could involve a mock
1146 : * authentication.
1147 : */
1148 152 : if (pg_hmac_init(ctx, state->StoredKey, state->key_length) < 0 ||
1149 76 : pg_hmac_update(ctx,
1150 76 : (uint8 *) state->client_first_message_bare,
1151 152 : strlen(state->client_first_message_bare)) < 0 ||
1152 152 : pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
1153 76 : pg_hmac_update(ctx,
1154 76 : (uint8 *) state->server_first_message,
1155 152 : strlen(state->server_first_message)) < 0 ||
1156 152 : pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
1157 76 : pg_hmac_update(ctx,
1158 76 : (uint8 *) state->client_final_message_without_proof,
1159 152 : strlen(state->client_final_message_without_proof)) < 0 ||
1160 76 : pg_hmac_final(ctx, ClientSignature, state->key_length) < 0)
1161 : {
1162 0 : elog(ERROR, "could not calculate client signature: %s",
1163 : pg_hmac_error(ctx));
1164 : }
1165 :
1166 76 : pg_hmac_free(ctx);
1167 :
1168 : /* Extract the ClientKey that the client calculated from the proof */
1169 2508 : for (i = 0; i < state->key_length; i++)
1170 2432 : ClientKey[i] = state->ClientProof[i] ^ ClientSignature[i];
1171 :
1172 : /* Hash it one more time, and compare with StoredKey */
1173 76 : if (scram_H(ClientKey, state->hash_type, state->key_length,
1174 : client_StoredKey, &errstr) < 0)
1175 0 : elog(ERROR, "could not hash stored key: %s", errstr);
1176 :
1177 76 : if (memcmp(client_StoredKey, state->StoredKey, state->key_length) != 0)
1178 10 : return false;
1179 :
1180 66 : return true;
1181 : }
1182 :
1183 : /*
1184 : * Build the first server-side message sent to the client in a SCRAM
1185 : * communication exchange.
1186 : */
1187 : static char *
1188 76 : build_server_first_message(scram_state *state)
1189 : {
1190 : /*------
1191 : * The syntax for the server-first-message is: (RFC 5802)
1192 : *
1193 : * server-first-message =
1194 : * [reserved-mext ","] nonce "," salt ","
1195 : * iteration-count ["," extensions]
1196 : *
1197 : * nonce = "r=" c-nonce [s-nonce]
1198 : * ;; Second part provided by server.
1199 : *
1200 : * c-nonce = printable
1201 : *
1202 : * s-nonce = printable
1203 : *
1204 : * salt = "s=" base64
1205 : *
1206 : * iteration-count = "i=" posit-number
1207 : * ;; A positive number.
1208 : *
1209 : * Example:
1210 : *
1211 : * r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096
1212 : *------
1213 : */
1214 :
1215 : /*
1216 : * Per the spec, the nonce may consist of any printable ASCII characters.
1217 : * For convenience, however, we don't use the whole range available,
1218 : * rather, we generate some random bytes, and base64 encode them.
1219 : */
1220 : char raw_nonce[SCRAM_RAW_NONCE_LEN];
1221 : int encoded_len;
1222 :
1223 76 : if (!pg_strong_random(raw_nonce, SCRAM_RAW_NONCE_LEN))
1224 0 : ereport(ERROR,
1225 : (errcode(ERRCODE_INTERNAL_ERROR),
1226 : errmsg("could not generate random nonce")));
1227 :
1228 76 : encoded_len = pg_b64_enc_len(SCRAM_RAW_NONCE_LEN);
1229 : /* don't forget the zero-terminator */
1230 76 : state->server_nonce = palloc(encoded_len + 1);
1231 76 : encoded_len = pg_b64_encode(raw_nonce, SCRAM_RAW_NONCE_LEN,
1232 : state->server_nonce, encoded_len);
1233 76 : if (encoded_len < 0)
1234 0 : ereport(ERROR,
1235 : (errcode(ERRCODE_INTERNAL_ERROR),
1236 : errmsg("could not encode random nonce")));
1237 76 : state->server_nonce[encoded_len] = '\0';
1238 :
1239 76 : state->server_first_message =
1240 76 : psprintf("r=%s%s,s=%s,i=%d",
1241 : state->client_nonce, state->server_nonce,
1242 : state->salt, state->iterations);
1243 :
1244 76 : return pstrdup(state->server_first_message);
1245 : }
1246 :
1247 :
1248 : /*
1249 : * Read and parse the final message received from client.
1250 : */
1251 : static void
1252 76 : read_client_final_message(scram_state *state, const char *input)
1253 : {
1254 : char attr;
1255 : char *channel_binding;
1256 : char *value;
1257 : char *begin,
1258 : *proof;
1259 : char *p;
1260 : char *client_proof;
1261 : int client_proof_len;
1262 :
1263 76 : begin = p = pstrdup(input);
1264 :
1265 : /*------
1266 : * The syntax for the server-first-message is: (RFC 5802)
1267 : *
1268 : * gs2-header = gs2-cbind-flag "," [ authzid ] ","
1269 : * ;; GS2 header for SCRAM
1270 : * ;; (the actual GS2 header includes an optional
1271 : * ;; flag to indicate that the GSS mechanism is not
1272 : * ;; "standard", but since SCRAM is "standard", we
1273 : * ;; don't include that flag).
1274 : *
1275 : * cbind-input = gs2-header [ cbind-data ]
1276 : * ;; cbind-data MUST be present for
1277 : * ;; gs2-cbind-flag of "p" and MUST be absent
1278 : * ;; for "y" or "n".
1279 : *
1280 : * channel-binding = "c=" base64
1281 : * ;; base64 encoding of cbind-input.
1282 : *
1283 : * proof = "p=" base64
1284 : *
1285 : * client-final-message-without-proof =
1286 : * channel-binding "," nonce [","
1287 : * extensions]
1288 : *
1289 : * client-final-message =
1290 : * client-final-message-without-proof "," proof
1291 : *------
1292 : */
1293 :
1294 : /*
1295 : * Read channel binding. This repeats the channel-binding flags and is
1296 : * then followed by the actual binding data depending on the type.
1297 : */
1298 76 : channel_binding = read_attr_value(&p, 'c');
1299 76 : if (state->channel_binding_in_use)
1300 : {
1301 : #ifdef USE_SSL
1302 8 : const char *cbind_data = NULL;
1303 8 : size_t cbind_data_len = 0;
1304 : size_t cbind_header_len;
1305 : char *cbind_input;
1306 : size_t cbind_input_len;
1307 : char *b64_message;
1308 : int b64_message_len;
1309 :
1310 : Assert(state->cbind_flag == 'p');
1311 :
1312 : /* Fetch hash data of server's SSL certificate */
1313 8 : cbind_data = be_tls_get_certificate_hash(state->port,
1314 : &cbind_data_len);
1315 :
1316 : /* should not happen */
1317 8 : if (cbind_data == NULL || cbind_data_len == 0)
1318 0 : elog(ERROR, "could not get server certificate hash");
1319 :
1320 8 : cbind_header_len = strlen("p=tls-server-end-point,,"); /* p=type,, */
1321 8 : cbind_input_len = cbind_header_len + cbind_data_len;
1322 8 : cbind_input = palloc(cbind_input_len);
1323 8 : snprintf(cbind_input, cbind_input_len, "p=tls-server-end-point,,");
1324 8 : memcpy(cbind_input + cbind_header_len, cbind_data, cbind_data_len);
1325 :
1326 8 : b64_message_len = pg_b64_enc_len(cbind_input_len);
1327 : /* don't forget the zero-terminator */
1328 8 : b64_message = palloc(b64_message_len + 1);
1329 8 : b64_message_len = pg_b64_encode(cbind_input, cbind_input_len,
1330 : b64_message, b64_message_len);
1331 8 : if (b64_message_len < 0)
1332 0 : elog(ERROR, "could not encode channel binding data");
1333 8 : b64_message[b64_message_len] = '\0';
1334 :
1335 : /*
1336 : * Compare the value sent by the client with the value expected by the
1337 : * server.
1338 : */
1339 8 : if (strcmp(channel_binding, b64_message) != 0)
1340 0 : ereport(ERROR,
1341 : (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
1342 : errmsg("SCRAM channel binding check failed")));
1343 : #else
1344 : /* shouldn't happen, because we checked this earlier already */
1345 : elog(ERROR, "channel binding not supported by this build");
1346 : #endif
1347 : }
1348 : else
1349 : {
1350 : /*
1351 : * If we are not using channel binding, the binding data is expected
1352 : * to always be "biws", which is "n,," base64-encoded, or "eSws",
1353 : * which is "y,,". We also have to check whether the flag is the same
1354 : * one that the client originally sent.
1355 : */
1356 68 : if (!(strcmp(channel_binding, "biws") == 0 && state->cbind_flag == 'n') &&
1357 0 : !(strcmp(channel_binding, "eSws") == 0 && state->cbind_flag == 'y'))
1358 0 : ereport(ERROR,
1359 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
1360 : errmsg("unexpected SCRAM channel-binding attribute in client-final-message")));
1361 : }
1362 :
1363 76 : state->client_final_nonce = read_attr_value(&p, 'r');
1364 :
1365 : /* ignore optional extensions, read until we find "p" attribute */
1366 : do
1367 : {
1368 76 : proof = p - 1;
1369 76 : value = read_any_attr(&p, &attr);
1370 76 : } while (attr != 'p');
1371 :
1372 76 : client_proof_len = pg_b64_dec_len(strlen(value));
1373 76 : client_proof = palloc(client_proof_len);
1374 76 : if (pg_b64_decode(value, strlen(value), client_proof,
1375 76 : client_proof_len) != state->key_length)
1376 0 : ereport(ERROR,
1377 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
1378 : errmsg("malformed SCRAM message"),
1379 : errdetail("Malformed proof in client-final-message.")));
1380 76 : memcpy(state->ClientProof, client_proof, state->key_length);
1381 76 : pfree(client_proof);
1382 :
1383 76 : if (*p != '\0')
1384 0 : ereport(ERROR,
1385 : (errcode(ERRCODE_PROTOCOL_VIOLATION),
1386 : errmsg("malformed SCRAM message"),
1387 : errdetail("Garbage found at the end of client-final-message.")));
1388 :
1389 76 : state->client_final_message_without_proof = palloc(proof - begin + 1);
1390 76 : memcpy(state->client_final_message_without_proof, input, proof - begin);
1391 76 : state->client_final_message_without_proof[proof - begin] = '\0';
1392 76 : }
1393 :
1394 : /*
1395 : * Build the final server-side message of an exchange.
1396 : */
1397 : static char *
1398 66 : build_server_final_message(scram_state *state)
1399 : {
1400 : uint8 ServerSignature[SCRAM_MAX_KEY_LEN];
1401 : char *server_signature_base64;
1402 : int siglen;
1403 66 : pg_hmac_ctx *ctx = pg_hmac_create(state->hash_type);
1404 :
1405 : /* calculate ServerSignature */
1406 132 : if (pg_hmac_init(ctx, state->ServerKey, state->key_length) < 0 ||
1407 66 : pg_hmac_update(ctx,
1408 66 : (uint8 *) state->client_first_message_bare,
1409 132 : strlen(state->client_first_message_bare)) < 0 ||
1410 132 : pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
1411 66 : pg_hmac_update(ctx,
1412 66 : (uint8 *) state->server_first_message,
1413 132 : strlen(state->server_first_message)) < 0 ||
1414 132 : pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
1415 66 : pg_hmac_update(ctx,
1416 66 : (uint8 *) state->client_final_message_without_proof,
1417 132 : strlen(state->client_final_message_without_proof)) < 0 ||
1418 66 : pg_hmac_final(ctx, ServerSignature, state->key_length) < 0)
1419 : {
1420 0 : elog(ERROR, "could not calculate server signature: %s",
1421 : pg_hmac_error(ctx));
1422 : }
1423 :
1424 66 : pg_hmac_free(ctx);
1425 :
1426 66 : siglen = pg_b64_enc_len(state->key_length);
1427 : /* don't forget the zero-terminator */
1428 66 : server_signature_base64 = palloc(siglen + 1);
1429 66 : siglen = pg_b64_encode((const char *) ServerSignature,
1430 : state->key_length, server_signature_base64,
1431 : siglen);
1432 66 : if (siglen < 0)
1433 0 : elog(ERROR, "could not encode server signature");
1434 66 : server_signature_base64[siglen] = '\0';
1435 :
1436 : /*------
1437 : * The syntax for the server-final-message is: (RFC 5802)
1438 : *
1439 : * verifier = "v=" base64
1440 : * ;; base-64 encoded ServerSignature.
1441 : *
1442 : * server-final-message = (server-error / verifier)
1443 : * ["," extensions]
1444 : *
1445 : *------
1446 : */
1447 66 : return psprintf("v=%s", server_signature_base64);
1448 : }
1449 :
1450 :
1451 : /*
1452 : * Deterministically generate salt for mock authentication, using a SHA256
1453 : * hash based on the username and a cluster-level secret key. Returns a
1454 : * pointer to a static buffer of size SCRAM_DEFAULT_SALT_LEN, or NULL.
1455 : */
1456 : static char *
1457 2 : scram_mock_salt(const char *username, pg_cryptohash_type hash_type,
1458 : int key_length)
1459 : {
1460 : pg_cryptohash_ctx *ctx;
1461 : static uint8 sha_digest[SCRAM_MAX_KEY_LEN];
1462 2 : char *mock_auth_nonce = GetMockAuthenticationNonce();
1463 :
1464 : /*
1465 : * Generate salt using a SHA256 hash of the username and the cluster's
1466 : * mock authentication nonce. (This works as long as the salt length is
1467 : * not larger than the SHA256 digest length. If the salt is smaller, the
1468 : * caller will just ignore the extra data.)
1469 : */
1470 : StaticAssertDecl(PG_SHA256_DIGEST_LENGTH >= SCRAM_DEFAULT_SALT_LEN,
1471 : "salt length greater than SHA256 digest length");
1472 :
1473 : /*
1474 : * This may be worth refreshing if support for more hash methods is\
1475 : * added.
1476 : */
1477 : Assert(hash_type == PG_SHA256);
1478 :
1479 2 : ctx = pg_cryptohash_create(hash_type);
1480 4 : if (pg_cryptohash_init(ctx) < 0 ||
1481 4 : pg_cryptohash_update(ctx, (uint8 *) username, strlen(username)) < 0 ||
1482 4 : pg_cryptohash_update(ctx, (uint8 *) mock_auth_nonce, MOCK_AUTH_NONCE_LEN) < 0 ||
1483 2 : pg_cryptohash_final(ctx, sha_digest, key_length) < 0)
1484 : {
1485 0 : pg_cryptohash_free(ctx);
1486 0 : return NULL;
1487 : }
1488 2 : pg_cryptohash_free(ctx);
1489 :
1490 2 : return (char *) sha_digest;
1491 : }
|