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