1/*-------------------------------------------------------------------------
2 *
3 * fe-auth-scram.c
4 * The front-end (client) implementation of SCRAM authentication.
5 *
6 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 * IDENTIFICATION
10 * src/interfaces/libpq/fe-auth-scram.c
11 *
12 *-------------------------------------------------------------------------
13 */
14
15#include "postgres_fe.h"
16
17#include "common/base64.h"
18#include "common/saslprep.h"
19#include "common/scram-common.h"
20#include "fe-auth.h"
21
22
23/*
24 * Status of exchange messages used for SCRAM authentication via the
25 * SASL protocol.
26 */
27typedef enum
28{
29 FE_SCRAM_INIT,
30 FE_SCRAM_NONCE_SENT,
31 FE_SCRAM_PROOF_SENT,
32 FE_SCRAM_FINISHED
33} fe_scram_state_enum;
34
35typedef struct
36{
37 fe_scram_state_enum state;
38
39 /* These are supplied by the user */
40 PGconn *conn;
41 char *password;
42 char *sasl_mechanism;
43
44 /* We construct these */
45 uint8 SaltedPassword[SCRAM_KEY_LEN];
46 char *client_nonce;
47 char *client_first_message_bare;
48 char *client_final_message_without_proof;
49
50 /* These come from the server-first message */
51 char *server_first_message;
52 char *salt;
53 int saltlen;
54 int iterations;
55 char *nonce;
56
57 /* These come from the server-final message */
58 char *server_final_message;
59 char ServerSignature[SCRAM_KEY_LEN];
60} fe_scram_state;
61
62static bool read_server_first_message(fe_scram_state *state, char *input);
63static bool read_server_final_message(fe_scram_state *state, char *input);
64static char *build_client_first_message(fe_scram_state *state);
65static char *build_client_final_message(fe_scram_state *state);
66static bool verify_server_signature(fe_scram_state *state);
67static void calculate_client_proof(fe_scram_state *state,
68 const char *client_final_message_without_proof,
69 uint8 *result);
70
71/*
72 * Initialize SCRAM exchange status.
73 */
74void *
75pg_fe_scram_init(PGconn *conn,
76 const char *password,
77 const char *sasl_mechanism)
78{
79 fe_scram_state *state;
80 char *prep_password;
81 pg_saslprep_rc rc;
82
83 Assert(sasl_mechanism != NULL);
84
85 state = (fe_scram_state *) malloc(sizeof(fe_scram_state));
86 if (!state)
87 return NULL;
88 memset(state, 0, sizeof(fe_scram_state));
89 state->conn = conn;
90 state->state = FE_SCRAM_INIT;
91 state->sasl_mechanism = strdup(sasl_mechanism);
92
93 if (!state->sasl_mechanism)
94 {
95 free(state);
96 return NULL;
97 }
98
99 /* Normalize the password with SASLprep, if possible */
100 rc = pg_saslprep(password, &prep_password);
101 if (rc == SASLPREP_OOM)
102 {
103 free(state->sasl_mechanism);
104 free(state);
105 return NULL;
106 }
107 if (rc != SASLPREP_SUCCESS)
108 {
109 prep_password = strdup(password);
110 if (!prep_password)
111 {
112 free(state->sasl_mechanism);
113 free(state);
114 return NULL;
115 }
116 }
117 state->password = prep_password;
118
119 return state;
120}
121
122/*
123 * Free SCRAM exchange status
124 */
125void
126pg_fe_scram_free(void *opaq)
127{
128 fe_scram_state *state = (fe_scram_state *) opaq;
129
130 if (state->password)
131 free(state->password);
132 if (state->sasl_mechanism)
133 free(state->sasl_mechanism);
134
135 /* client messages */
136 if (state->client_nonce)
137 free(state->client_nonce);
138 if (state->client_first_message_bare)
139 free(state->client_first_message_bare);
140 if (state->client_final_message_without_proof)
141 free(state->client_final_message_without_proof);
142
143 /* first message from server */
144 if (state->server_first_message)
145 free(state->server_first_message);
146 if (state->salt)
147 free(state->salt);
148 if (state->nonce)
149 free(state->nonce);
150
151 /* final message from server */
152 if (state->server_final_message)
153 free(state->server_final_message);
154
155 free(state);
156}
157
158/*
159 * Exchange a SCRAM message with backend.
160 */
161void
162pg_fe_scram_exchange(void *opaq, char *input, int inputlen,
163 char **output, int *outputlen,
164 bool *done, bool *success)
165{
166 fe_scram_state *state = (fe_scram_state *) opaq;
167 PGconn *conn = state->conn;
168
169 *done = false;
170 *success = false;
171 *output = NULL;
172 *outputlen = 0;
173
174 /*
175 * Check that the input length agrees with the string length of the input.
176 * We can ignore inputlen after this.
177 */
178 if (state->state != FE_SCRAM_INIT)
179 {
180 if (inputlen == 0)
181 {
182 printfPQExpBuffer(&conn->errorMessage,
183 libpq_gettext("malformed SCRAM message (empty message)\n"));
184 goto error;
185 }
186 if (inputlen != strlen(input))
187 {
188 printfPQExpBuffer(&conn->errorMessage,
189 libpq_gettext("malformed SCRAM message (length mismatch)\n"));
190 goto error;
191 }
192 }
193
194 switch (state->state)
195 {
196 case FE_SCRAM_INIT:
197 /* Begin the SCRAM handshake, by sending client nonce */
198 *output = build_client_first_message(state);
199 if (*output == NULL)
200 goto error;
201
202 *outputlen = strlen(*output);
203 *done = false;
204 state->state = FE_SCRAM_NONCE_SENT;
205 break;
206
207 case FE_SCRAM_NONCE_SENT:
208 /* Receive salt and server nonce, send response. */
209 if (!read_server_first_message(state, input))
210 goto error;
211
212 *output = build_client_final_message(state);
213 if (*output == NULL)
214 goto error;
215
216 *outputlen = strlen(*output);
217 *done = false;
218 state->state = FE_SCRAM_PROOF_SENT;
219 break;
220
221 case FE_SCRAM_PROOF_SENT:
222 /* Receive server signature */
223 if (!read_server_final_message(state, input))
224 goto error;
225
226 /*
227 * Verify server signature, to make sure we're talking to the
228 * genuine server. XXX: A fake server could simply not require
229 * authentication, though. There is currently no option in libpq
230 * to reject a connection, if SCRAM authentication did not happen.
231 */
232 if (verify_server_signature(state))
233 *success = true;
234 else
235 {
236 *success = false;
237 printfPQExpBuffer(&conn->errorMessage,
238 libpq_gettext("incorrect server signature\n"));
239 }
240 *done = true;
241 state->state = FE_SCRAM_FINISHED;
242 break;
243
244 default:
245 /* shouldn't happen */
246 printfPQExpBuffer(&conn->errorMessage,
247 libpq_gettext("invalid SCRAM exchange state\n"));
248 goto error;
249 }
250 return;
251
252error:
253 *done = true;
254 *success = false;
255 return;
256}
257
258/*
259 * Read value for an attribute part of a SCRAM message.
260 */
261static char *
262read_attr_value(char **input, char attr, PQExpBuffer errorMessage)
263{
264 char *begin = *input;
265 char *end;
266
267 if (*begin != attr)
268 {
269 printfPQExpBuffer(errorMessage,
270 libpq_gettext("malformed SCRAM message (attribute \"%c\" expected)\n"),
271 attr);
272 return NULL;
273 }
274 begin++;
275
276 if (*begin != '=')
277 {
278 printfPQExpBuffer(errorMessage,
279 libpq_gettext("malformed SCRAM message (expected character \"=\" for attribute \"%c\")\n"),
280 attr);
281 return NULL;
282 }
283 begin++;
284
285 end = begin;
286 while (*end && *end != ',')
287 end++;
288
289 if (*end)
290 {
291 *end = '\0';
292 *input = end + 1;
293 }
294 else
295 *input = end;
296
297 return begin;
298}
299
300/*
301 * Build the first exchange message sent by the client.
302 */
303static char *
304build_client_first_message(fe_scram_state *state)
305{
306 PGconn *conn = state->conn;
307 char raw_nonce[SCRAM_RAW_NONCE_LEN + 1];
308 char *result;
309 int channel_info_len;
310 int encoded_len;
311 PQExpBufferData buf;
312
313 /*
314 * Generate a "raw" nonce. This is converted to ASCII-printable form by
315 * base64-encoding it.
316 */
317 if (!pg_strong_random(raw_nonce, SCRAM_RAW_NONCE_LEN))
318 {
319 printfPQExpBuffer(&conn->errorMessage,
320 libpq_gettext("could not generate nonce\n"));
321 return NULL;
322 }
323
324 state->client_nonce = malloc(pg_b64_enc_len(SCRAM_RAW_NONCE_LEN) + 1);
325 if (state->client_nonce == NULL)
326 {
327 printfPQExpBuffer(&conn->errorMessage,
328 libpq_gettext("out of memory\n"));
329 return NULL;
330 }
331 encoded_len = pg_b64_encode(raw_nonce, SCRAM_RAW_NONCE_LEN, state->client_nonce);
332 state->client_nonce[encoded_len] = '\0';
333
334 /*
335 * Generate message. The username is left empty as the backend uses the
336 * value provided by the startup packet. Also, as this username is not
337 * prepared with SASLprep, the message parsing would fail if it includes
338 * '=' or ',' characters.
339 */
340
341 initPQExpBuffer(&buf);
342
343 /*
344 * First build the gs2-header with channel binding information.
345 */
346 if (strcmp(state->sasl_mechanism, SCRAM_SHA_256_PLUS_NAME) == 0)
347 {
348 Assert(conn->ssl_in_use);
349 appendPQExpBuffer(&buf, "p=tls-server-end-point");
350 }
351#ifdef HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH
352 else if (conn->ssl_in_use)
353 {
354 /*
355 * Client supports channel binding, but thinks the server does not.
356 */
357 appendPQExpBuffer(&buf, "y");
358 }
359#endif
360 else
361 {
362 /*
363 * Client does not support channel binding.
364 */
365 appendPQExpBuffer(&buf, "n");
366 }
367
368 if (PQExpBufferDataBroken(buf))
369 goto oom_error;
370
371 channel_info_len = buf.len;
372
373 appendPQExpBuffer(&buf, ",,n=,r=%s", state->client_nonce);
374 if (PQExpBufferDataBroken(buf))
375 goto oom_error;
376
377 /*
378 * The first message content needs to be saved without channel binding
379 * information.
380 */
381 state->client_first_message_bare = strdup(buf.data + channel_info_len + 2);
382 if (!state->client_first_message_bare)
383 goto oom_error;
384
385 result = strdup(buf.data);
386 if (result == NULL)
387 goto oom_error;
388
389 termPQExpBuffer(&buf);
390 return result;
391
392oom_error:
393 termPQExpBuffer(&buf);
394 printfPQExpBuffer(&conn->errorMessage,
395 libpq_gettext("out of memory\n"));
396 return NULL;
397}
398
399/*
400 * Build the final exchange message sent from the client.
401 */
402static char *
403build_client_final_message(fe_scram_state *state)
404{
405 PQExpBufferData buf;
406 PGconn *conn = state->conn;
407 uint8 client_proof[SCRAM_KEY_LEN];
408 char *result;
409
410 initPQExpBuffer(&buf);
411
412 /*
413 * Construct client-final-message-without-proof. We need to remember it
414 * for verifying the server proof in the final step of authentication.
415 *
416 * The channel binding flag handling (p/y/n) must be consistent with
417 * build_client_first_message(), because the server will check that it's
418 * the same flag both times.
419 */
420 if (strcmp(state->sasl_mechanism, SCRAM_SHA_256_PLUS_NAME) == 0)
421 {
422#ifdef HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH
423 char *cbind_data = NULL;
424 size_t cbind_data_len = 0;
425 size_t cbind_header_len;
426 char *cbind_input;
427 size_t cbind_input_len;
428
429 /* Fetch hash data of server's SSL certificate */
430 cbind_data =
431 pgtls_get_peer_certificate_hash(state->conn,
432 &cbind_data_len);
433 if (cbind_data == NULL)
434 {
435 /* error message is already set on error */
436 termPQExpBuffer(&buf);
437 return NULL;
438 }
439
440 appendPQExpBuffer(&buf, "c=");
441
442 /* p=type,, */
443 cbind_header_len = strlen("p=tls-server-end-point,,");
444 cbind_input_len = cbind_header_len + cbind_data_len;
445 cbind_input = malloc(cbind_input_len);
446 if (!cbind_input)
447 {
448 free(cbind_data);
449 goto oom_error;
450 }
451 memcpy(cbind_input, "p=tls-server-end-point,,", cbind_header_len);
452 memcpy(cbind_input + cbind_header_len, cbind_data, cbind_data_len);
453
454 if (!enlargePQExpBuffer(&buf, pg_b64_enc_len(cbind_input_len)))
455 {
456 free(cbind_data);
457 free(cbind_input);
458 goto oom_error;
459 }
460 buf.len += pg_b64_encode(cbind_input, cbind_input_len, buf.data + buf.len);
461 buf.data[buf.len] = '\0';
462
463 free(cbind_data);
464 free(cbind_input);
465#else
466 /*
467 * Chose channel binding, but the SSL library doesn't support it.
468 * Shouldn't happen.
469 */
470 termPQExpBuffer(&buf);
471 printfPQExpBuffer(&conn->errorMessage,
472 "channel binding not supported by this build\n");
473 return NULL;
474#endif /* HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH */
475 }
476#ifdef HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH
477 else if (conn->ssl_in_use)
478 appendPQExpBuffer(&buf, "c=eSws"); /* base64 of "y,," */
479#endif
480 else
481 appendPQExpBuffer(&buf, "c=biws"); /* base64 of "n,," */
482
483 if (PQExpBufferDataBroken(buf))
484 goto oom_error;
485
486 appendPQExpBuffer(&buf, ",r=%s", state->nonce);
487 if (PQExpBufferDataBroken(buf))
488 goto oom_error;
489
490 state->client_final_message_without_proof = strdup(buf.data);
491 if (state->client_final_message_without_proof == NULL)
492 goto oom_error;
493
494 /* Append proof to it, to form client-final-message. */
495 calculate_client_proof(state,
496 state->client_final_message_without_proof,
497 client_proof);
498
499 appendPQExpBuffer(&buf, ",p=");
500 if (!enlargePQExpBuffer(&buf, pg_b64_enc_len(SCRAM_KEY_LEN)))
501 goto oom_error;
502 buf.len += pg_b64_encode((char *) client_proof,
503 SCRAM_KEY_LEN,
504 buf.data + buf.len);
505 buf.data[buf.len] = '\0';
506
507 result = strdup(buf.data);
508 if (result == NULL)
509 goto oom_error;
510
511 termPQExpBuffer(&buf);
512 return result;
513
514oom_error:
515 termPQExpBuffer(&buf);
516 printfPQExpBuffer(&conn->errorMessage,
517 libpq_gettext("out of memory\n"));
518 return NULL;
519}
520
521/*
522 * Read the first exchange message coming from the server.
523 */
524static bool
525read_server_first_message(fe_scram_state *state, char *input)
526{
527 PGconn *conn = state->conn;
528 char *iterations_str;
529 char *endptr;
530 char *encoded_salt;
531 char *nonce;
532
533 state->server_first_message = strdup(input);
534 if (state->server_first_message == NULL)
535 {
536 printfPQExpBuffer(&conn->errorMessage,
537 libpq_gettext("out of memory\n"));
538 return false;
539 }
540
541 /* parse the message */
542 nonce = read_attr_value(&input, 'r',
543 &conn->errorMessage);
544 if (nonce == NULL)
545 {
546 /* read_attr_value() has generated an error string */
547 return false;
548 }
549
550 /* Verify immediately that the server used our part of the nonce */
551 if (strlen(nonce) < strlen(state->client_nonce) ||
552 memcmp(nonce, state->client_nonce, strlen(state->client_nonce)) != 0)
553 {
554 printfPQExpBuffer(&conn->errorMessage,
555 libpq_gettext("invalid SCRAM response (nonce mismatch)\n"));
556 return false;
557 }
558
559 state->nonce = strdup(nonce);
560 if (state->nonce == NULL)
561 {
562 printfPQExpBuffer(&conn->errorMessage,
563 libpq_gettext("out of memory\n"));
564 return false;
565 }
566
567 encoded_salt = read_attr_value(&input, 's', &conn->errorMessage);
568 if (encoded_salt == NULL)
569 {
570 /* read_attr_value() has generated an error string */
571 return false;
572 }
573 state->salt = malloc(pg_b64_dec_len(strlen(encoded_salt)));
574 if (state->salt == NULL)
575 {
576 printfPQExpBuffer(&conn->errorMessage,
577 libpq_gettext("out of memory\n"));
578 return false;
579 }
580 state->saltlen = pg_b64_decode(encoded_salt,
581 strlen(encoded_salt),
582 state->salt);
583 if (state->saltlen < 0)
584 {
585 printfPQExpBuffer(&conn->errorMessage,
586 libpq_gettext("malformed SCRAM message (invalid salt)\n"));
587 return false;
588 }
589
590 iterations_str = read_attr_value(&input, 'i', &conn->errorMessage);
591 if (iterations_str == NULL)
592 {
593 /* read_attr_value() has generated an error string */
594 return false;
595 }
596 state->iterations = strtol(iterations_str, &endptr, 10);
597 if (*endptr != '\0' || state->iterations < 1)
598 {
599 printfPQExpBuffer(&conn->errorMessage,
600 libpq_gettext("malformed SCRAM message (invalid iteration count)\n"));
601 return false;
602 }
603
604 if (*input != '\0')
605 printfPQExpBuffer(&conn->errorMessage,
606 libpq_gettext("malformed SCRAM message (garbage at end of server-first-message)\n"));
607
608 return true;
609}
610
611/*
612 * Read the final exchange message coming from the server.
613 */
614static bool
615read_server_final_message(fe_scram_state *state, char *input)
616{
617 PGconn *conn = state->conn;
618 char *encoded_server_signature;
619 char *decoded_server_signature;
620 int server_signature_len;
621
622 state->server_final_message = strdup(input);
623 if (!state->server_final_message)
624 {
625 printfPQExpBuffer(&conn->errorMessage,
626 libpq_gettext("out of memory\n"));
627 return false;
628 }
629
630 /* Check for error result. */
631 if (*input == 'e')
632 {
633 char *errmsg = read_attr_value(&input, 'e',
634 &conn->errorMessage);
635
636 printfPQExpBuffer(&conn->errorMessage,
637 libpq_gettext("error received from server in SCRAM exchange: %s\n"),
638 errmsg);
639 return false;
640 }
641
642 /* Parse the message. */
643 encoded_server_signature = read_attr_value(&input, 'v',
644 &conn->errorMessage);
645 if (encoded_server_signature == NULL)
646 {
647 /* read_attr_value() has generated an error message */
648 return false;
649 }
650
651 if (*input != '\0')
652 printfPQExpBuffer(&conn->errorMessage,
653 libpq_gettext("malformed SCRAM message (garbage at end of server-final-message)\n"));
654
655 server_signature_len = pg_b64_dec_len(strlen(encoded_server_signature));
656 decoded_server_signature = malloc(server_signature_len);
657 if (!decoded_server_signature)
658 {
659 printfPQExpBuffer(&conn->errorMessage,
660 libpq_gettext("out of memory\n"));
661 return false;
662 }
663
664 server_signature_len = pg_b64_decode(encoded_server_signature,
665 strlen(encoded_server_signature),
666 decoded_server_signature);
667 if (server_signature_len != SCRAM_KEY_LEN)
668 {
669 free(decoded_server_signature);
670 printfPQExpBuffer(&conn->errorMessage,
671 libpq_gettext("malformed SCRAM message (invalid server signature)\n"));
672 return false;
673 }
674 memcpy(state->ServerSignature, decoded_server_signature, SCRAM_KEY_LEN);
675 free(decoded_server_signature);
676
677 return true;
678}
679
680/*
681 * Calculate the client proof, part of the final exchange message sent
682 * by the client.
683 */
684static void
685calculate_client_proof(fe_scram_state *state,
686 const char *client_final_message_without_proof,
687 uint8 *result)
688{
689 uint8 StoredKey[SCRAM_KEY_LEN];
690 uint8 ClientKey[SCRAM_KEY_LEN];
691 uint8 ClientSignature[SCRAM_KEY_LEN];
692 int i;
693 scram_HMAC_ctx ctx;
694
695 /*
696 * Calculate SaltedPassword, and store it in 'state' so that we can reuse
697 * it later in verify_server_signature.
698 */
699 scram_SaltedPassword(state->password, state->salt, state->saltlen,
700 state->iterations, state->SaltedPassword);
701
702 scram_ClientKey(state->SaltedPassword, ClientKey);
703 scram_H(ClientKey, SCRAM_KEY_LEN, StoredKey);
704
705 scram_HMAC_init(&ctx, StoredKey, SCRAM_KEY_LEN);
706 scram_HMAC_update(&ctx,
707 state->client_first_message_bare,
708 strlen(state->client_first_message_bare));
709 scram_HMAC_update(&ctx, ",", 1);
710 scram_HMAC_update(&ctx,
711 state->server_first_message,
712 strlen(state->server_first_message));
713 scram_HMAC_update(&ctx, ",", 1);
714 scram_HMAC_update(&ctx,
715 client_final_message_without_proof,
716 strlen(client_final_message_without_proof));
717 scram_HMAC_final(ClientSignature, &ctx);
718
719 for (i = 0; i < SCRAM_KEY_LEN; i++)
720 result[i] = ClientKey[i] ^ ClientSignature[i];
721}
722
723/*
724 * Validate the server signature, received as part of the final exchange
725 * message received from the server.
726 */
727static bool
728verify_server_signature(fe_scram_state *state)
729{
730 uint8 expected_ServerSignature[SCRAM_KEY_LEN];
731 uint8 ServerKey[SCRAM_KEY_LEN];
732 scram_HMAC_ctx ctx;
733
734 scram_ServerKey(state->SaltedPassword, ServerKey);
735
736 /* calculate ServerSignature */
737 scram_HMAC_init(&ctx, ServerKey, SCRAM_KEY_LEN);
738 scram_HMAC_update(&ctx,
739 state->client_first_message_bare,
740 strlen(state->client_first_message_bare));
741 scram_HMAC_update(&ctx, ",", 1);
742 scram_HMAC_update(&ctx,
743 state->server_first_message,
744 strlen(state->server_first_message));
745 scram_HMAC_update(&ctx, ",", 1);
746 scram_HMAC_update(&ctx,
747 state->client_final_message_without_proof,
748 strlen(state->client_final_message_without_proof));
749 scram_HMAC_final(expected_ServerSignature, &ctx);
750
751 if (memcmp(expected_ServerSignature, state->ServerSignature, SCRAM_KEY_LEN) != 0)
752 return false;
753
754 return true;
755}
756
757/*
758 * Build a new SCRAM verifier.
759 */
760char *
761pg_fe_scram_build_verifier(const char *password)
762{
763 char *prep_password;
764 pg_saslprep_rc rc;
765 char saltbuf[SCRAM_DEFAULT_SALT_LEN];
766 char *result;
767
768 /*
769 * Normalize the password with SASLprep. If that doesn't work, because
770 * the password isn't valid UTF-8 or contains prohibited characters, just
771 * proceed with the original password. (See comments at top of file.)
772 */
773 rc = pg_saslprep(password, &prep_password);
774 if (rc == SASLPREP_OOM)
775 return NULL;
776 if (rc == SASLPREP_SUCCESS)
777 password = (const char *) prep_password;
778
779 /* Generate a random salt */
780 if (!pg_strong_random(saltbuf, SCRAM_DEFAULT_SALT_LEN))
781 {
782 if (prep_password)
783 free(prep_password);
784 return NULL;
785 }
786
787 result = scram_build_verifier(saltbuf, SCRAM_DEFAULT_SALT_LEN,
788 SCRAM_DEFAULT_ITERATIONS, password);
789
790 if (prep_password)
791 free(prep_password);
792
793 return result;
794}
795