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