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 password verifier, 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 | * verifier 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-2019, 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_verifier(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 | 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 | if (port->ssl_in_use) |
191 | { |
192 | appendStringInfoString(buf, SCRAM_SHA_256_PLUS_NAME); |
193 | appendStringInfoChar(buf, '\0'); |
194 | } |
195 | #endif |
196 | appendStringInfoString(buf, SCRAM_SHA_256_NAME); |
197 | appendStringInfoChar(buf, '\0'); |
198 | } |
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 verifier data. |
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 password verifier, 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 | pg_be_scram_init(Port *port, |
219 | const char *selected_mech, |
220 | const char *shadow_pass) |
221 | { |
222 | scram_state *state; |
223 | bool got_verifier; |
224 | |
225 | state = (scram_state *) palloc0(sizeof(scram_state)); |
226 | state->port = port; |
227 | 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 | if (strcmp(selected_mech, SCRAM_SHA_256_PLUS_NAME) == 0 && port->ssl_in_use) |
240 | state->channel_binding_in_use = true; |
241 | else |
242 | #endif |
243 | if (strcmp(selected_mech, SCRAM_SHA_256_NAME) == 0) |
244 | state->channel_binding_in_use = false; |
245 | else |
246 | ereport(ERROR, |
247 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
248 | errmsg("client selected an invalid SASL authentication mechanism" ))); |
249 | |
250 | /* |
251 | * Parse the stored password verifier. |
252 | */ |
253 | if (shadow_pass) |
254 | { |
255 | int password_type = get_password_type(shadow_pass); |
256 | |
257 | if (password_type == PASSWORD_TYPE_SCRAM_SHA_256) |
258 | { |
259 | if (parse_scram_verifier(shadow_pass, &state->iterations, &state->salt, |
260 | state->StoredKey, state->ServerKey)) |
261 | got_verifier = true; |
262 | else |
263 | { |
264 | /* |
265 | * The password looked like a SCRAM verifier, but could not be |
266 | * parsed. |
267 | */ |
268 | ereport(LOG, |
269 | (errmsg("invalid SCRAM verifier for user \"%s\"" , |
270 | state->port->user_name))); |
271 | got_verifier = false; |
272 | } |
273 | } |
274 | else |
275 | { |
276 | /* |
277 | * The user doesn't have SCRAM verifier. (You cannot do SCRAM |
278 | * authentication with an MD5 hash.) |
279 | */ |
280 | state->logdetail = psprintf(_("User \"%s\" does not have a valid SCRAM verifier." ), |
281 | state->port->user_name); |
282 | got_verifier = 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 | got_verifier = false; |
293 | } |
294 | |
295 | /* |
296 | * If the user did not have a valid SCRAM verifier, we still go through |
297 | * the 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 | if (!got_verifier) |
302 | { |
303 | mock_scram_verifier(state->port->user_name, &state->iterations, |
304 | &state->salt, state->StoredKey, state->ServerKey); |
305 | state->doomed = true; |
306 | } |
307 | |
308 | 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 | pg_be_scram_exchange(void *opaq, const char *input, int inputlen, |
329 | char **output, int *outputlen, char **logdetail) |
330 | { |
331 | scram_state *state = (scram_state *) opaq; |
332 | int result; |
333 | |
334 | *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 | if (input == NULL) |
343 | { |
344 | Assert(state->state == SCRAM_AUTH_INIT); |
345 | |
346 | *output = pstrdup("" ); |
347 | *outputlen = 0; |
348 | 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 | if (inputlen == 0) |
356 | ereport(ERROR, |
357 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
358 | errmsg("malformed SCRAM message" ), |
359 | errdetail("The message is empty." ))); |
360 | if (inputlen != strlen(input)) |
361 | ereport(ERROR, |
362 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
363 | errmsg("malformed SCRAM message" ), |
364 | errdetail("Message length does not match input length." ))); |
365 | |
366 | switch (state->state) |
367 | { |
368 | 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 | read_client_first_message(state, input); |
376 | |
377 | /* prepare message to send challenge */ |
378 | *output = build_server_first_message(state); |
379 | |
380 | state->state = SCRAM_AUTH_SALT_SENT; |
381 | result = SASL_EXCHANGE_CONTINUE; |
382 | break; |
383 | |
384 | 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 | read_client_final_message(state, input); |
392 | |
393 | if (!verify_final_nonce(state)) |
394 | 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 | if (!verify_client_proof(state) || state->doomed) |
418 | { |
419 | result = SASL_EXCHANGE_FAILURE; |
420 | break; |
421 | } |
422 | |
423 | /* Build final message for client */ |
424 | *output = build_server_final_message(state); |
425 | |
426 | /* Success! */ |
427 | result = SASL_EXCHANGE_SUCCESS; |
428 | state->state = SCRAM_AUTH_FINISHED; |
429 | break; |
430 | |
431 | default: |
432 | elog(ERROR, "invalid SCRAM exchange state" ); |
433 | result = SASL_EXCHANGE_FAILURE; |
434 | } |
435 | |
436 | if (result == SASL_EXCHANGE_FAILURE && state->logdetail && logdetail) |
437 | *logdetail = state->logdetail; |
438 | |
439 | if (*output) |
440 | *outputlen = strlen(*output); |
441 | |
442 | return result; |
443 | } |
444 | |
445 | /* |
446 | * Construct a verifier string for SCRAM, stored in pg_authid.rolpassword. |
447 | * |
448 | * The result is palloc'd, so caller is responsible for freeing it. |
449 | */ |
450 | char * |
451 | pg_be_scram_build_verifier(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 | rc = pg_saslprep(password, &prep_password); |
464 | if (rc == SASLPREP_SUCCESS) |
465 | password = (const char *) prep_password; |
466 | |
467 | /* Generate random salt */ |
468 | if (!pg_strong_random(saltbuf, SCRAM_DEFAULT_SALT_LEN)) |
469 | ereport(ERROR, |
470 | (errcode(ERRCODE_INTERNAL_ERROR), |
471 | errmsg("could not generate random salt" ))); |
472 | |
473 | result = scram_build_verifier(saltbuf, SCRAM_DEFAULT_SALT_LEN, |
474 | SCRAM_DEFAULT_ITERATIONS, password); |
475 | |
476 | if (prep_password) |
477 | pfree(prep_password); |
478 | |
479 | return result; |
480 | } |
481 | |
482 | /* |
483 | * Verify a plaintext password against a SCRAM verifier. This is used when |
484 | * performing plaintext password authentication for a user that has a SCRAM |
485 | * verifier stored in pg_authid. |
486 | */ |
487 | bool |
488 | scram_verify_plain_password(const char *username, const char *password, |
489 | const char *verifier) |
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 | if (!parse_scram_verifier(verifier, &iterations, &encoded_salt, |
503 | stored_key, server_key)) |
504 | { |
505 | /* |
506 | * The password looked like a SCRAM verifier, but could not be parsed. |
507 | */ |
508 | ereport(LOG, |
509 | (errmsg("invalid SCRAM verifier for user \"%s\"" , username))); |
510 | return false; |
511 | } |
512 | |
513 | salt = palloc(pg_b64_dec_len(strlen(encoded_salt))); |
514 | saltlen = pg_b64_decode(encoded_salt, strlen(encoded_salt), salt); |
515 | if (saltlen == -1) |
516 | { |
517 | ereport(LOG, |
518 | (errmsg("invalid SCRAM verifier for user \"%s\"" , username))); |
519 | return false; |
520 | } |
521 | |
522 | /* Normalize the password */ |
523 | rc = pg_saslprep(password, &prep_password); |
524 | if (rc == SASLPREP_SUCCESS) |
525 | password = prep_password; |
526 | |
527 | /* Compute Server Key based on the user-supplied plaintext password */ |
528 | scram_SaltedPassword(password, salt, saltlen, iterations, salted_password); |
529 | scram_ServerKey(salted_password, computed_key); |
530 | |
531 | if (prep_password) |
532 | pfree(prep_password); |
533 | |
534 | /* |
535 | * Compare the verifier's Server Key with the one computed from the |
536 | * user-supplied password. |
537 | */ |
538 | return memcmp(computed_key, server_key, SCRAM_KEY_LEN) == 0; |
539 | } |
540 | |
541 | |
542 | /* |
543 | * Parse and validate format of given SCRAM verifier. |
544 | * |
545 | * On success, the iteration count, salt, stored key, and server key are |
546 | * extracted from the verifier, and returned to the caller. For 'stored_key' |
547 | * and 'server_key', the caller must pass pre-allocated buffers of size |
548 | * SCRAM_KEY_LEN. Salt is returned as a base64-encoded, null-terminated |
549 | * string. The buffer for the salt is palloc'd by this function. |
550 | * |
551 | * Returns true if the SCRAM verifier has been parsed, and false otherwise. |
552 | */ |
553 | bool |
554 | parse_scram_verifier(const char *verifier, int *iterations, char **salt, |
555 | uint8 *stored_key, uint8 *server_key) |
556 | { |
557 | char *v; |
558 | char *p; |
559 | char *scheme_str; |
560 | char *salt_str; |
561 | char *iterations_str; |
562 | char *storedkey_str; |
563 | char *serverkey_str; |
564 | int decoded_len; |
565 | char *decoded_salt_buf; |
566 | char *decoded_stored_buf; |
567 | char *decoded_server_buf; |
568 | |
569 | /* |
570 | * The verifier is of form: |
571 | * |
572 | * SCRAM-SHA-256$<iterations>:<salt>$<storedkey>:<serverkey> |
573 | */ |
574 | v = pstrdup(verifier); |
575 | if ((scheme_str = strtok(v, "$" )) == NULL) |
576 | goto invalid_verifier; |
577 | if ((iterations_str = strtok(NULL, ":" )) == NULL) |
578 | goto invalid_verifier; |
579 | if ((salt_str = strtok(NULL, "$" )) == NULL) |
580 | goto invalid_verifier; |
581 | if ((storedkey_str = strtok(NULL, ":" )) == NULL) |
582 | goto invalid_verifier; |
583 | if ((serverkey_str = strtok(NULL, "" )) == NULL) |
584 | goto invalid_verifier; |
585 | |
586 | /* Parse the fields */ |
587 | if (strcmp(scheme_str, "SCRAM-SHA-256" ) != 0) |
588 | goto invalid_verifier; |
589 | |
590 | errno = 0; |
591 | *iterations = strtol(iterations_str, &p, 10); |
592 | if (*p || errno != 0) |
593 | goto invalid_verifier; |
594 | |
595 | /* |
596 | * Verify that the salt is in Base64-encoded format, by decoding it, |
597 | * although we return the encoded version to the caller. |
598 | */ |
599 | decoded_salt_buf = palloc(pg_b64_dec_len(strlen(salt_str))); |
600 | decoded_len = pg_b64_decode(salt_str, strlen(salt_str), |
601 | decoded_salt_buf); |
602 | if (decoded_len < 0) |
603 | goto invalid_verifier; |
604 | *salt = pstrdup(salt_str); |
605 | |
606 | /* |
607 | * Decode StoredKey and ServerKey. |
608 | */ |
609 | decoded_stored_buf = palloc(pg_b64_dec_len(strlen(storedkey_str))); |
610 | decoded_len = pg_b64_decode(storedkey_str, strlen(storedkey_str), |
611 | decoded_stored_buf); |
612 | if (decoded_len != SCRAM_KEY_LEN) |
613 | goto invalid_verifier; |
614 | memcpy(stored_key, decoded_stored_buf, SCRAM_KEY_LEN); |
615 | |
616 | decoded_server_buf = palloc(pg_b64_dec_len(strlen(serverkey_str))); |
617 | decoded_len = pg_b64_decode(serverkey_str, strlen(serverkey_str), |
618 | decoded_server_buf); |
619 | if (decoded_len != SCRAM_KEY_LEN) |
620 | goto invalid_verifier; |
621 | memcpy(server_key, decoded_server_buf, SCRAM_KEY_LEN); |
622 | |
623 | return true; |
624 | |
625 | invalid_verifier: |
626 | *salt = NULL; |
627 | return false; |
628 | } |
629 | |
630 | /* |
631 | * Generate plausible SCRAM verifier parameters for mock authentication. |
632 | * |
633 | * In a normal authentication, these are extracted from the verifier |
634 | * stored in the server. This function generates values that look |
635 | * realistic, for when there is no stored verifier. |
636 | * |
637 | * Like in parse_scram_verifier(), for 'stored_key' and 'server_key', the |
638 | * caller must pass pre-allocated buffers of size SCRAM_KEY_LEN, and |
639 | * the buffer for the salt is palloc'd by this function. |
640 | */ |
641 | static void |
642 | mock_scram_verifier(const char *username, int *iterations, char **salt, |
643 | uint8 *stored_key, uint8 *server_key) |
644 | { |
645 | char *raw_salt; |
646 | char *encoded_salt; |
647 | int encoded_len; |
648 | |
649 | /* Generate deterministic salt */ |
650 | raw_salt = scram_mock_salt(username); |
651 | |
652 | encoded_salt = (char *) palloc(pg_b64_enc_len(SCRAM_DEFAULT_SALT_LEN) + 1); |
653 | encoded_len = pg_b64_encode(raw_salt, SCRAM_DEFAULT_SALT_LEN, encoded_salt); |
654 | encoded_salt[encoded_len] = '\0'; |
655 | |
656 | *salt = encoded_salt; |
657 | *iterations = SCRAM_DEFAULT_ITERATIONS; |
658 | |
659 | /* StoredKey and ServerKey are not used in a doomed authentication */ |
660 | memset(stored_key, 0, SCRAM_KEY_LEN); |
661 | memset(server_key, 0, SCRAM_KEY_LEN); |
662 | } |
663 | |
664 | /* |
665 | * Read the value in a given SCRAM exchange message for given attribute. |
666 | */ |
667 | static char * |
668 | read_attr_value(char **input, char attr) |
669 | { |
670 | char *begin = *input; |
671 | char *end; |
672 | |
673 | if (*begin != attr) |
674 | ereport(ERROR, |
675 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
676 | errmsg("malformed SCRAM message" ), |
677 | errdetail("Expected attribute \"%c\" but found \"%s\"." , |
678 | attr, sanitize_char(*begin)))); |
679 | begin++; |
680 | |
681 | if (*begin != '=') |
682 | ereport(ERROR, |
683 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
684 | errmsg("malformed SCRAM message" ), |
685 | errdetail("Expected character \"=\" for attribute \"%c\"." , attr))); |
686 | begin++; |
687 | |
688 | end = begin; |
689 | while (*end && *end != ',') |
690 | end++; |
691 | |
692 | if (*end) |
693 | { |
694 | *end = '\0'; |
695 | *input = end + 1; |
696 | } |
697 | else |
698 | *input = end; |
699 | |
700 | return begin; |
701 | } |
702 | |
703 | static bool |
704 | is_scram_printable(char *p) |
705 | { |
706 | /*------ |
707 | * Printable characters, as defined by SCRAM spec: (RFC 5802) |
708 | * |
709 | * printable = %x21-2B / %x2D-7E |
710 | * ;; Printable ASCII except ",". |
711 | * ;; Note that any "printable" is also |
712 | * ;; a valid "value". |
713 | *------ |
714 | */ |
715 | for (; *p; p++) |
716 | { |
717 | if (*p < 0x21 || *p > 0x7E || *p == 0x2C /* comma */ ) |
718 | return false; |
719 | } |
720 | return true; |
721 | } |
722 | |
723 | /* |
724 | * Convert an arbitrary byte to printable form. For error messages. |
725 | * |
726 | * If it's a printable ASCII character, print it as a single character. |
727 | * otherwise, print it in hex. |
728 | * |
729 | * The returned pointer points to a static buffer. |
730 | */ |
731 | static char * |
732 | sanitize_char(char c) |
733 | { |
734 | static char buf[5]; |
735 | |
736 | if (c >= 0x21 && c <= 0x7E) |
737 | snprintf(buf, sizeof(buf), "'%c'" , c); |
738 | else |
739 | snprintf(buf, sizeof(buf), "0x%02x" , (unsigned char) c); |
740 | return buf; |
741 | } |
742 | |
743 | /* |
744 | * Convert an arbitrary string to printable form, for error messages. |
745 | * |
746 | * Anything that's not a printable ASCII character is replaced with |
747 | * '?', and the string is truncated at 30 characters. |
748 | * |
749 | * The returned pointer points to a static buffer. |
750 | */ |
751 | static char * |
752 | sanitize_str(const char *s) |
753 | { |
754 | static char buf[30 + 1]; |
755 | int i; |
756 | |
757 | for (i = 0; i < sizeof(buf) - 1; i++) |
758 | { |
759 | char c = s[i]; |
760 | |
761 | if (c == '\0') |
762 | break; |
763 | |
764 | if (c >= 0x21 && c <= 0x7E) |
765 | buf[i] = c; |
766 | else |
767 | buf[i] = '?'; |
768 | } |
769 | buf[i] = '\0'; |
770 | return buf; |
771 | } |
772 | |
773 | /* |
774 | * Read the next attribute and value in a SCRAM exchange message. |
775 | * |
776 | * Returns NULL if there is attribute. |
777 | */ |
778 | static char * |
779 | read_any_attr(char **input, char *attr_p) |
780 | { |
781 | char *begin = *input; |
782 | char *end; |
783 | char attr = *begin; |
784 | |
785 | /*------ |
786 | * attr-val = ALPHA "=" value |
787 | * ;; Generic syntax of any attribute sent |
788 | * ;; by server or client |
789 | *------ |
790 | */ |
791 | if (!((attr >= 'A' && attr <= 'Z') || |
792 | (attr >= 'a' && attr <= 'z'))) |
793 | ereport(ERROR, |
794 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
795 | errmsg("malformed SCRAM message" ), |
796 | errdetail("Attribute expected, but found invalid character \"%s\"." , |
797 | sanitize_char(attr)))); |
798 | if (attr_p) |
799 | *attr_p = attr; |
800 | begin++; |
801 | |
802 | if (*begin != '=') |
803 | ereport(ERROR, |
804 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
805 | errmsg("malformed SCRAM message" ), |
806 | errdetail("Expected character \"=\" for attribute \"%c\"." , attr))); |
807 | begin++; |
808 | |
809 | end = begin; |
810 | while (*end && *end != ',') |
811 | end++; |
812 | |
813 | if (*end) |
814 | { |
815 | *end = '\0'; |
816 | *input = end + 1; |
817 | } |
818 | else |
819 | *input = end; |
820 | |
821 | return begin; |
822 | } |
823 | |
824 | /* |
825 | * Read and parse the first message from client in the context of a SCRAM |
826 | * authentication exchange message. |
827 | * |
828 | * At this stage, any errors will be reported directly with ereport(ERROR). |
829 | */ |
830 | static void |
831 | read_client_first_message(scram_state *state, const char *input) |
832 | { |
833 | char *p = pstrdup(input); |
834 | char *channel_binding_type; |
835 | |
836 | |
837 | /*------ |
838 | * The syntax for the client-first-message is: (RFC 5802) |
839 | * |
840 | * saslname = 1*(value-safe-char / "=2C" / "=3D") |
841 | * ;; Conforms to <value>. |
842 | * |
843 | * authzid = "a=" saslname |
844 | * ;; Protocol specific. |
845 | * |
846 | * cb-name = 1*(ALPHA / DIGIT / "." / "-") |
847 | * ;; See RFC 5056, Section 7. |
848 | * ;; E.g., "tls-server-end-point" or |
849 | * ;; "tls-unique". |
850 | * |
851 | * gs2-cbind-flag = ("p=" cb-name) / "n" / "y" |
852 | * ;; "n" -> client doesn't support channel binding. |
853 | * ;; "y" -> client does support channel binding |
854 | * ;; but thinks the server does not. |
855 | * ;; "p" -> client requires channel binding. |
856 | * ;; The selected channel binding follows "p=". |
857 | * |
858 | * gs2-header = gs2-cbind-flag "," [ authzid ] "," |
859 | * ;; GS2 header for SCRAM |
860 | * ;; (the actual GS2 header includes an optional |
861 | * ;; flag to indicate that the GSS mechanism is not |
862 | * ;; "standard", but since SCRAM is "standard", we |
863 | * ;; don't include that flag). |
864 | * |
865 | * username = "n=" saslname |
866 | * ;; Usernames are prepared using SASLprep. |
867 | * |
868 | * reserved-mext = "m=" 1*(value-char) |
869 | * ;; Reserved for signaling mandatory extensions. |
870 | * ;; The exact syntax will be defined in |
871 | * ;; the future. |
872 | * |
873 | * nonce = "r=" c-nonce [s-nonce] |
874 | * ;; Second part provided by server. |
875 | * |
876 | * c-nonce = printable |
877 | * |
878 | * client-first-message-bare = |
879 | * [reserved-mext ","] |
880 | * username "," nonce ["," extensions] |
881 | * |
882 | * client-first-message = |
883 | * gs2-header client-first-message-bare |
884 | * |
885 | * For example: |
886 | * n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL |
887 | * |
888 | * The "n,," in the beginning means that the client doesn't support |
889 | * channel binding, and no authzid is given. "n=user" is the username. |
890 | * However, in PostgreSQL the username is sent in the startup packet, and |
891 | * the username in the SCRAM exchange is ignored. libpq always sends it |
892 | * as an empty string. The last part, "r=fyko+d2lbbFgONRv9qkxdawL" is |
893 | * the client nonce. |
894 | *------ |
895 | */ |
896 | |
897 | /* |
898 | * Read gs2-cbind-flag. (For details see also RFC 5802 Section 6 "Channel |
899 | * Binding".) |
900 | */ |
901 | state->cbind_flag = *p; |
902 | switch (*p) |
903 | { |
904 | case 'n': |
905 | |
906 | /* |
907 | * The client does not support channel binding or has simply |
908 | * decided to not use it. In that case just let it go. |
909 | */ |
910 | if (state->channel_binding_in_use) |
911 | ereport(ERROR, |
912 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
913 | errmsg("malformed SCRAM message" ), |
914 | errdetail("The client selected SCRAM-SHA-256-PLUS, but the SCRAM message does not include channel binding data." ))); |
915 | |
916 | p++; |
917 | if (*p != ',') |
918 | ereport(ERROR, |
919 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
920 | errmsg("malformed SCRAM message" ), |
921 | errdetail("Comma expected, but found character \"%s\"." , |
922 | sanitize_char(*p)))); |
923 | p++; |
924 | break; |
925 | case 'y': |
926 | |
927 | /* |
928 | * The client supports channel binding and thinks that the server |
929 | * does not. In this case, the server must fail authentication if |
930 | * it supports channel binding. |
931 | */ |
932 | if (state->channel_binding_in_use) |
933 | ereport(ERROR, |
934 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
935 | errmsg("malformed SCRAM message" ), |
936 | errdetail("The client selected SCRAM-SHA-256-PLUS, but the SCRAM message does not include channel binding data." ))); |
937 | |
938 | #ifdef HAVE_BE_TLS_GET_CERTIFICATE_HASH |
939 | if (state->port->ssl_in_use) |
940 | ereport(ERROR, |
941 | (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), |
942 | errmsg("SCRAM channel binding negotiation error" ), |
943 | errdetail("The client supports SCRAM channel binding but thinks the server does not. " |
944 | "However, this server does support channel binding." ))); |
945 | #endif |
946 | p++; |
947 | if (*p != ',') |
948 | ereport(ERROR, |
949 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
950 | errmsg("malformed SCRAM message" ), |
951 | errdetail("Comma expected, but found character \"%s\"." , |
952 | sanitize_char(*p)))); |
953 | p++; |
954 | break; |
955 | case 'p': |
956 | |
957 | /* |
958 | * The client requires channel binding. Channel binding type |
959 | * follows, e.g., "p=tls-server-end-point". |
960 | */ |
961 | if (!state->channel_binding_in_use) |
962 | ereport(ERROR, |
963 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
964 | errmsg("malformed SCRAM message" ), |
965 | errdetail("The client selected SCRAM-SHA-256 without channel binding, but the SCRAM message includes channel binding data." ))); |
966 | |
967 | channel_binding_type = read_attr_value(&p, 'p'); |
968 | |
969 | /* |
970 | * The only channel binding type we support is |
971 | * tls-server-end-point. |
972 | */ |
973 | if (strcmp(channel_binding_type, "tls-server-end-point" ) != 0) |
974 | ereport(ERROR, |
975 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
976 | (errmsg("unsupported SCRAM channel-binding type \"%s\"" , |
977 | sanitize_str(channel_binding_type))))); |
978 | break; |
979 | default: |
980 | ereport(ERROR, |
981 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
982 | errmsg("malformed SCRAM message" ), |
983 | errdetail("Unexpected channel-binding flag \"%s\"." , |
984 | sanitize_char(*p)))); |
985 | } |
986 | |
987 | /* |
988 | * Forbid optional authzid (authorization identity). We don't support it. |
989 | */ |
990 | if (*p == 'a') |
991 | ereport(ERROR, |
992 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
993 | errmsg("client uses authorization identity, but it is not supported" ))); |
994 | if (*p != ',') |
995 | ereport(ERROR, |
996 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
997 | errmsg("malformed SCRAM message" ), |
998 | errdetail("Unexpected attribute \"%s\" in client-first-message." , |
999 | sanitize_char(*p)))); |
1000 | p++; |
1001 | |
1002 | state->client_first_message_bare = pstrdup(p); |
1003 | |
1004 | /* |
1005 | * Any mandatory extensions would go here. We don't support any. |
1006 | * |
1007 | * RFC 5802 specifies error code "e=extensions-not-supported" for this, |
1008 | * but it can only be sent in the server-final message. We prefer to fail |
1009 | * immediately (which the RFC also allows). |
1010 | */ |
1011 | if (*p == 'm') |
1012 | ereport(ERROR, |
1013 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
1014 | errmsg("client requires an unsupported SCRAM extension" ))); |
1015 | |
1016 | /* |
1017 | * Read username. Note: this is ignored. We use the username from the |
1018 | * startup message instead, still it is kept around if provided as it |
1019 | * proves to be useful for debugging purposes. |
1020 | */ |
1021 | state->client_username = read_attr_value(&p, 'n'); |
1022 | |
1023 | /* read nonce and check that it is made of only printable characters */ |
1024 | state->client_nonce = read_attr_value(&p, 'r'); |
1025 | if (!is_scram_printable(state->client_nonce)) |
1026 | ereport(ERROR, |
1027 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
1028 | errmsg("non-printable characters in SCRAM nonce" ))); |
1029 | |
1030 | /* |
1031 | * There can be any number of optional extensions after this. We don't |
1032 | * support any extensions, so ignore them. |
1033 | */ |
1034 | while (*p != '\0') |
1035 | read_any_attr(&p, NULL); |
1036 | |
1037 | /* success! */ |
1038 | } |
1039 | |
1040 | /* |
1041 | * Verify the final nonce contained in the last message received from |
1042 | * client in an exchange. |
1043 | */ |
1044 | static bool |
1045 | verify_final_nonce(scram_state *state) |
1046 | { |
1047 | int client_nonce_len = strlen(state->client_nonce); |
1048 | int server_nonce_len = strlen(state->server_nonce); |
1049 | int final_nonce_len = strlen(state->client_final_nonce); |
1050 | |
1051 | if (final_nonce_len != client_nonce_len + server_nonce_len) |
1052 | return false; |
1053 | if (memcmp(state->client_final_nonce, state->client_nonce, client_nonce_len) != 0) |
1054 | return false; |
1055 | if (memcmp(state->client_final_nonce + client_nonce_len, state->server_nonce, server_nonce_len) != 0) |
1056 | return false; |
1057 | |
1058 | return true; |
1059 | } |
1060 | |
1061 | /* |
1062 | * Verify the client proof contained in the last message received from |
1063 | * client in an exchange. |
1064 | */ |
1065 | static bool |
1066 | verify_client_proof(scram_state *state) |
1067 | { |
1068 | uint8 ClientSignature[SCRAM_KEY_LEN]; |
1069 | uint8 ClientKey[SCRAM_KEY_LEN]; |
1070 | uint8 client_StoredKey[SCRAM_KEY_LEN]; |
1071 | scram_HMAC_ctx ctx; |
1072 | int i; |
1073 | |
1074 | /* calculate ClientSignature */ |
1075 | scram_HMAC_init(&ctx, state->StoredKey, SCRAM_KEY_LEN); |
1076 | scram_HMAC_update(&ctx, |
1077 | state->client_first_message_bare, |
1078 | strlen(state->client_first_message_bare)); |
1079 | scram_HMAC_update(&ctx, "," , 1); |
1080 | scram_HMAC_update(&ctx, |
1081 | state->server_first_message, |
1082 | strlen(state->server_first_message)); |
1083 | scram_HMAC_update(&ctx, "," , 1); |
1084 | scram_HMAC_update(&ctx, |
1085 | state->client_final_message_without_proof, |
1086 | strlen(state->client_final_message_without_proof)); |
1087 | scram_HMAC_final(ClientSignature, &ctx); |
1088 | |
1089 | /* Extract the ClientKey that the client calculated from the proof */ |
1090 | for (i = 0; i < SCRAM_KEY_LEN; i++) |
1091 | ClientKey[i] = state->ClientProof[i] ^ ClientSignature[i]; |
1092 | |
1093 | /* Hash it one more time, and compare with StoredKey */ |
1094 | scram_H(ClientKey, SCRAM_KEY_LEN, client_StoredKey); |
1095 | |
1096 | if (memcmp(client_StoredKey, state->StoredKey, SCRAM_KEY_LEN) != 0) |
1097 | return false; |
1098 | |
1099 | return true; |
1100 | } |
1101 | |
1102 | /* |
1103 | * Build the first server-side message sent to the client in a SCRAM |
1104 | * communication exchange. |
1105 | */ |
1106 | static char * |
1107 | build_server_first_message(scram_state *state) |
1108 | { |
1109 | /*------ |
1110 | * The syntax for the server-first-message is: (RFC 5802) |
1111 | * |
1112 | * server-first-message = |
1113 | * [reserved-mext ","] nonce "," salt "," |
1114 | * iteration-count ["," extensions] |
1115 | * |
1116 | * nonce = "r=" c-nonce [s-nonce] |
1117 | * ;; Second part provided by server. |
1118 | * |
1119 | * c-nonce = printable |
1120 | * |
1121 | * s-nonce = printable |
1122 | * |
1123 | * salt = "s=" base64 |
1124 | * |
1125 | * iteration-count = "i=" posit-number |
1126 | * ;; A positive number. |
1127 | * |
1128 | * Example: |
1129 | * |
1130 | * r=fyko+d2lbbFgONRv9qkxdawL3rfcNHYJY1ZVvWVs7j,s=QSXCR+Q6sek8bf92,i=4096 |
1131 | *------ |
1132 | */ |
1133 | |
1134 | /* |
1135 | * Per the spec, the nonce may consist of any printable ASCII characters. |
1136 | * For convenience, however, we don't use the whole range available, |
1137 | * rather, we generate some random bytes, and base64 encode them. |
1138 | */ |
1139 | char raw_nonce[SCRAM_RAW_NONCE_LEN]; |
1140 | int encoded_len; |
1141 | |
1142 | if (!pg_strong_random(raw_nonce, SCRAM_RAW_NONCE_LEN)) |
1143 | ereport(ERROR, |
1144 | (errcode(ERRCODE_INTERNAL_ERROR), |
1145 | errmsg("could not generate random nonce" ))); |
1146 | |
1147 | state->server_nonce = palloc(pg_b64_enc_len(SCRAM_RAW_NONCE_LEN) + 1); |
1148 | encoded_len = pg_b64_encode(raw_nonce, SCRAM_RAW_NONCE_LEN, state->server_nonce); |
1149 | state->server_nonce[encoded_len] = '\0'; |
1150 | |
1151 | state->server_first_message = |
1152 | psprintf("r=%s%s,s=%s,i=%u" , |
1153 | state->client_nonce, state->server_nonce, |
1154 | state->salt, state->iterations); |
1155 | |
1156 | return pstrdup(state->server_first_message); |
1157 | } |
1158 | |
1159 | |
1160 | /* |
1161 | * Read and parse the final message received from client. |
1162 | */ |
1163 | static void |
1164 | read_client_final_message(scram_state *state, const char *input) |
1165 | { |
1166 | char attr; |
1167 | char *channel_binding; |
1168 | char *value; |
1169 | char *begin, |
1170 | *proof; |
1171 | char *p; |
1172 | char *client_proof; |
1173 | |
1174 | begin = p = pstrdup(input); |
1175 | |
1176 | /*------ |
1177 | * The syntax for the server-first-message is: (RFC 5802) |
1178 | * |
1179 | * gs2-header = gs2-cbind-flag "," [ authzid ] "," |
1180 | * ;; GS2 header for SCRAM |
1181 | * ;; (the actual GS2 header includes an optional |
1182 | * ;; flag to indicate that the GSS mechanism is not |
1183 | * ;; "standard", but since SCRAM is "standard", we |
1184 | * ;; don't include that flag). |
1185 | * |
1186 | * cbind-input = gs2-header [ cbind-data ] |
1187 | * ;; cbind-data MUST be present for |
1188 | * ;; gs2-cbind-flag of "p" and MUST be absent |
1189 | * ;; for "y" or "n". |
1190 | * |
1191 | * channel-binding = "c=" base64 |
1192 | * ;; base64 encoding of cbind-input. |
1193 | * |
1194 | * proof = "p=" base64 |
1195 | * |
1196 | * client-final-message-without-proof = |
1197 | * channel-binding "," nonce ["," |
1198 | * extensions] |
1199 | * |
1200 | * client-final-message = |
1201 | * client-final-message-without-proof "," proof |
1202 | *------ |
1203 | */ |
1204 | |
1205 | /* |
1206 | * Read channel binding. This repeats the channel-binding flags and is |
1207 | * then followed by the actual binding data depending on the type. |
1208 | */ |
1209 | channel_binding = read_attr_value(&p, 'c'); |
1210 | if (state->channel_binding_in_use) |
1211 | { |
1212 | #ifdef HAVE_BE_TLS_GET_CERTIFICATE_HASH |
1213 | const char *cbind_data = NULL; |
1214 | size_t cbind_data_len = 0; |
1215 | size_t cbind_header_len; |
1216 | char *cbind_input; |
1217 | size_t cbind_input_len; |
1218 | char *b64_message; |
1219 | int b64_message_len; |
1220 | |
1221 | Assert(state->cbind_flag == 'p'); |
1222 | |
1223 | /* Fetch hash data of server's SSL certificate */ |
1224 | cbind_data = be_tls_get_certificate_hash(state->port, |
1225 | &cbind_data_len); |
1226 | |
1227 | /* should not happen */ |
1228 | if (cbind_data == NULL || cbind_data_len == 0) |
1229 | elog(ERROR, "could not get server certificate hash" ); |
1230 | |
1231 | cbind_header_len = strlen("p=tls-server-end-point,," ); /* p=type,, */ |
1232 | cbind_input_len = cbind_header_len + cbind_data_len; |
1233 | cbind_input = palloc(cbind_input_len); |
1234 | snprintf(cbind_input, cbind_input_len, "p=tls-server-end-point,," ); |
1235 | memcpy(cbind_input + cbind_header_len, cbind_data, cbind_data_len); |
1236 | |
1237 | b64_message = palloc(pg_b64_enc_len(cbind_input_len) + 1); |
1238 | b64_message_len = pg_b64_encode(cbind_input, cbind_input_len, |
1239 | b64_message); |
1240 | b64_message[b64_message_len] = '\0'; |
1241 | |
1242 | /* |
1243 | * Compare the value sent by the client with the value expected by the |
1244 | * server. |
1245 | */ |
1246 | if (strcmp(channel_binding, b64_message) != 0) |
1247 | ereport(ERROR, |
1248 | (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), |
1249 | (errmsg("SCRAM channel binding check failed" )))); |
1250 | #else |
1251 | /* shouldn't happen, because we checked this earlier already */ |
1252 | elog(ERROR, "channel binding not supported by this build" ); |
1253 | #endif |
1254 | } |
1255 | else |
1256 | { |
1257 | /* |
1258 | * If we are not using channel binding, the binding data is expected |
1259 | * to always be "biws", which is "n,," base64-encoded, or "eSws", |
1260 | * which is "y,,". We also have to check whether the flag is the same |
1261 | * one that the client originally sent. |
1262 | */ |
1263 | if (!(strcmp(channel_binding, "biws" ) == 0 && state->cbind_flag == 'n') && |
1264 | !(strcmp(channel_binding, "eSws" ) == 0 && state->cbind_flag == 'y')) |
1265 | ereport(ERROR, |
1266 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
1267 | (errmsg("unexpected SCRAM channel-binding attribute in client-final-message" )))); |
1268 | } |
1269 | |
1270 | state->client_final_nonce = read_attr_value(&p, 'r'); |
1271 | |
1272 | /* ignore optional extensions */ |
1273 | do |
1274 | { |
1275 | proof = p - 1; |
1276 | value = read_any_attr(&p, &attr); |
1277 | } while (attr != 'p'); |
1278 | |
1279 | client_proof = palloc(pg_b64_dec_len(strlen(value))); |
1280 | if (pg_b64_decode(value, strlen(value), client_proof) != SCRAM_KEY_LEN) |
1281 | ereport(ERROR, |
1282 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
1283 | errmsg("malformed SCRAM message" ), |
1284 | errdetail("Malformed proof in client-final-message." ))); |
1285 | memcpy(state->ClientProof, client_proof, SCRAM_KEY_LEN); |
1286 | pfree(client_proof); |
1287 | |
1288 | if (*p != '\0') |
1289 | ereport(ERROR, |
1290 | (errcode(ERRCODE_PROTOCOL_VIOLATION), |
1291 | errmsg("malformed SCRAM message" ), |
1292 | errdetail("Garbage found at the end of client-final-message." ))); |
1293 | |
1294 | state->client_final_message_without_proof = palloc(proof - begin + 1); |
1295 | memcpy(state->client_final_message_without_proof, input, proof - begin); |
1296 | state->client_final_message_without_proof[proof - begin] = '\0'; |
1297 | } |
1298 | |
1299 | /* |
1300 | * Build the final server-side message of an exchange. |
1301 | */ |
1302 | static char * |
1303 | build_server_final_message(scram_state *state) |
1304 | { |
1305 | uint8 ServerSignature[SCRAM_KEY_LEN]; |
1306 | char *server_signature_base64; |
1307 | int siglen; |
1308 | scram_HMAC_ctx ctx; |
1309 | |
1310 | /* calculate ServerSignature */ |
1311 | scram_HMAC_init(&ctx, state->ServerKey, SCRAM_KEY_LEN); |
1312 | scram_HMAC_update(&ctx, |
1313 | state->client_first_message_bare, |
1314 | strlen(state->client_first_message_bare)); |
1315 | scram_HMAC_update(&ctx, "," , 1); |
1316 | scram_HMAC_update(&ctx, |
1317 | state->server_first_message, |
1318 | strlen(state->server_first_message)); |
1319 | scram_HMAC_update(&ctx, "," , 1); |
1320 | scram_HMAC_update(&ctx, |
1321 | state->client_final_message_without_proof, |
1322 | strlen(state->client_final_message_without_proof)); |
1323 | scram_HMAC_final(ServerSignature, &ctx); |
1324 | |
1325 | server_signature_base64 = palloc(pg_b64_enc_len(SCRAM_KEY_LEN) + 1); |
1326 | siglen = pg_b64_encode((const char *) ServerSignature, |
1327 | SCRAM_KEY_LEN, server_signature_base64); |
1328 | server_signature_base64[siglen] = '\0'; |
1329 | |
1330 | /*------ |
1331 | * The syntax for the server-final-message is: (RFC 5802) |
1332 | * |
1333 | * verifier = "v=" base64 |
1334 | * ;; base-64 encoded ServerSignature. |
1335 | * |
1336 | * server-final-message = (server-error / verifier) |
1337 | * ["," extensions] |
1338 | * |
1339 | *------ |
1340 | */ |
1341 | return psprintf("v=%s" , server_signature_base64); |
1342 | } |
1343 | |
1344 | |
1345 | /* |
1346 | * Deterministically generate salt for mock authentication, using a SHA256 |
1347 | * hash based on the username and a cluster-level secret key. Returns a |
1348 | * pointer to a static buffer of size SCRAM_DEFAULT_SALT_LEN. |
1349 | */ |
1350 | static char * |
1351 | scram_mock_salt(const char *username) |
1352 | { |
1353 | pg_sha256_ctx ctx; |
1354 | static uint8 sha_digest[PG_SHA256_DIGEST_LENGTH]; |
1355 | char *mock_auth_nonce = GetMockAuthenticationNonce(); |
1356 | |
1357 | /* |
1358 | * Generate salt using a SHA256 hash of the username and the cluster's |
1359 | * mock authentication nonce. (This works as long as the salt length is |
1360 | * not larger the SHA256 digest length. If the salt is smaller, the caller |
1361 | * will just ignore the extra data.) |
1362 | */ |
1363 | StaticAssertStmt(PG_SHA256_DIGEST_LENGTH >= SCRAM_DEFAULT_SALT_LEN, |
1364 | "salt length greater than SHA256 digest length" ); |
1365 | |
1366 | pg_sha256_init(&ctx); |
1367 | pg_sha256_update(&ctx, (uint8 *) username, strlen(username)); |
1368 | pg_sha256_update(&ctx, (uint8 *) mock_auth_nonce, MOCK_AUTH_NONCE_LEN); |
1369 | pg_sha256_final(&ctx, sha_digest); |
1370 | |
1371 | return (char *) sha_digest; |
1372 | } |
1373 | |