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