PostgreSQL Source Code  git master
fe-auth-scram.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * fe-auth-scram.c
4  * The front-end (client) implementation of SCRAM authentication.
5  *
6  * Portions Copyright (c) 1996-2021, 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/hmac.h"
19 #include "common/saslprep.h"
20 #include "common/scram-common.h"
21 #include "fe-auth.h"
22 
23 
24 /* The exported SCRAM callback mechanism. */
25 static void *scram_init(PGconn *conn, const char *password,
26  const char *sasl_mechanism);
27 static void scram_exchange(void *opaq, char *input, int inputlen,
28  char **output, int *outputlen,
29  bool *done, bool *success);
30 static bool scram_channel_bound(void *opaq);
31 static void scram_free(void *opaq);
32 
34  scram_init,
38 };
39 
40 /*
41  * Status of exchange messages used for SCRAM authentication via the
42  * SASL protocol.
43  */
44 typedef enum
45 {
51 
52 typedef struct
53 {
55 
56  /* These are supplied by the user */
58  char *password;
60 
61  /* We construct these */
62  uint8 SaltedPassword[SCRAM_KEY_LEN];
63  char *client_nonce;
66 
67  /* These come from the server-first message */
69  char *salt;
70  int saltlen;
72  char *nonce;
73 
74  /* These come from the server-final message */
76  char ServerSignature[SCRAM_KEY_LEN];
78 
79 static bool read_server_first_message(fe_scram_state *state, char *input);
80 static bool read_server_final_message(fe_scram_state *state, char *input);
83 static bool verify_server_signature(fe_scram_state *state, bool *match);
85  const char *client_final_message_without_proof,
86  uint8 *result);
87 
88 /*
89  * Initialize SCRAM exchange status.
90  */
91 static void *
93  const char *password,
94  const char *sasl_mechanism)
95 {
97  char *prep_password;
98  pg_saslprep_rc rc;
99 
100  Assert(sasl_mechanism != NULL);
101 
102  state = (fe_scram_state *) malloc(sizeof(fe_scram_state));
103  if (!state)
104  return NULL;
105  memset(state, 0, sizeof(fe_scram_state));
106  state->conn = conn;
107  state->state = FE_SCRAM_INIT;
108  state->sasl_mechanism = strdup(sasl_mechanism);
109 
110  if (!state->sasl_mechanism)
111  {
112  free(state);
113  return NULL;
114  }
115 
116  /* Normalize the password with SASLprep, if possible */
117  rc = pg_saslprep(password, &prep_password);
118  if (rc == SASLPREP_OOM)
119  {
120  free(state->sasl_mechanism);
121  free(state);
122  return NULL;
123  }
124  if (rc != SASLPREP_SUCCESS)
125  {
126  prep_password = strdup(password);
127  if (!prep_password)
128  {
129  free(state->sasl_mechanism);
130  free(state);
131  return NULL;
132  }
133  }
134  state->password = prep_password;
135 
136  return state;
137 }
138 
139 /*
140  * Return true if channel binding was employed and the SCRAM exchange
141  * completed. This should be used after a successful exchange to determine
142  * whether the server authenticated itself to the client.
143  *
144  * Note that the caller must also ensure that the exchange was actually
145  * successful.
146  */
147 static bool
149 {
150  fe_scram_state *state = (fe_scram_state *) opaq;
151 
152  /* no SCRAM exchange done */
153  if (state == NULL)
154  return false;
155 
156  /* SCRAM exchange not completed */
157  if (state->state != FE_SCRAM_FINISHED)
158  return false;
159 
160  /* channel binding mechanism not used */
161  if (strcmp(state->sasl_mechanism, SCRAM_SHA_256_PLUS_NAME) != 0)
162  return false;
163 
164  /* all clear! */
165  return true;
166 }
167 
168 /*
169  * Free SCRAM exchange status
170  */
171 static void
172 scram_free(void *opaq)
173 {
174  fe_scram_state *state = (fe_scram_state *) opaq;
175 
176  if (state->password)
177  free(state->password);
178  if (state->sasl_mechanism)
179  free(state->sasl_mechanism);
180 
181  /* client messages */
182  if (state->client_nonce)
183  free(state->client_nonce);
184  if (state->client_first_message_bare)
188 
189  /* first message from server */
190  if (state->server_first_message)
191  free(state->server_first_message);
192  if (state->salt)
193  free(state->salt);
194  if (state->nonce)
195  free(state->nonce);
196 
197  /* final message from server */
198  if (state->server_final_message)
199  free(state->server_final_message);
200 
201  free(state);
202 }
203 
204 /*
205  * Exchange a SCRAM message with backend.
206  */
207 static void
208 scram_exchange(void *opaq, char *input, int inputlen,
209  char **output, int *outputlen,
210  bool *done, bool *success)
211 {
212  fe_scram_state *state = (fe_scram_state *) opaq;
213  PGconn *conn = state->conn;
214 
215  *done = false;
216  *success = false;
217  *output = NULL;
218  *outputlen = 0;
219 
220  /*
221  * Check that the input length agrees with the string length of the input.
222  * We can ignore inputlen after this.
223  */
224  if (state->state != FE_SCRAM_INIT)
225  {
226  if (inputlen == 0)
227  {
229  libpq_gettext("malformed SCRAM message (empty message)\n"));
230  goto error;
231  }
232  if (inputlen != strlen(input))
233  {
235  libpq_gettext("malformed SCRAM message (length mismatch)\n"));
236  goto error;
237  }
238  }
239 
240  switch (state->state)
241  {
242  case FE_SCRAM_INIT:
243  /* Begin the SCRAM handshake, by sending client nonce */
244  *output = build_client_first_message(state);
245  if (*output == NULL)
246  goto error;
247 
248  *outputlen = strlen(*output);
249  *done = false;
250  state->state = FE_SCRAM_NONCE_SENT;
251  break;
252 
253  case FE_SCRAM_NONCE_SENT:
254  /* Receive salt and server nonce, send response. */
255  if (!read_server_first_message(state, input))
256  goto error;
257 
258  *output = build_client_final_message(state);
259  if (*output == NULL)
260  goto error;
261 
262  *outputlen = strlen(*output);
263  *done = false;
264  state->state = FE_SCRAM_PROOF_SENT;
265  break;
266 
267  case FE_SCRAM_PROOF_SENT:
268  /* Receive server signature */
269  if (!read_server_final_message(state, input))
270  goto error;
271 
272  /*
273  * Verify server signature, to make sure we're talking to the
274  * genuine server.
275  */
276  if (!verify_server_signature(state, success))
277  {
279  libpq_gettext("could not verify server signature\n"));
280  goto error;
281  }
282 
283  if (!*success)
284  {
286  libpq_gettext("incorrect server signature\n"));
287  }
288  *done = true;
289  state->state = FE_SCRAM_FINISHED;
290  break;
291 
292  default:
293  /* shouldn't happen */
295  libpq_gettext("invalid SCRAM exchange state\n"));
296  goto error;
297  }
298  return;
299 
300 error:
301  *done = true;
302  *success = false;
303 }
304 
305 /*
306  * Read value for an attribute part of a SCRAM message.
307  *
308  * The buffer at **input is destructively modified, and *input is
309  * advanced over the "attr=value" string and any following comma.
310  *
311  * On failure, append an error message to *errorMessage and return NULL.
312  */
313 static char *
314 read_attr_value(char **input, char attr, PQExpBuffer errorMessage)
315 {
316  char *begin = *input;
317  char *end;
318 
319  if (*begin != attr)
320  {
321  appendPQExpBuffer(errorMessage,
322  libpq_gettext("malformed SCRAM message (attribute \"%c\" expected)\n"),
323  attr);
324  return NULL;
325  }
326  begin++;
327 
328  if (*begin != '=')
329  {
330  appendPQExpBuffer(errorMessage,
331  libpq_gettext("malformed SCRAM message (expected character \"=\" for attribute \"%c\")\n"),
332  attr);
333  return NULL;
334  }
335  begin++;
336 
337  end = begin;
338  while (*end && *end != ',')
339  end++;
340 
341  if (*end)
342  {
343  *end = '\0';
344  *input = end + 1;
345  }
346  else
347  *input = end;
348 
349  return begin;
350 }
351 
352 /*
353  * Build the first exchange message sent by the client.
354  */
355 static char *
357 {
358  PGconn *conn = state->conn;
359  char raw_nonce[SCRAM_RAW_NONCE_LEN + 1];
360  char *result;
361  int channel_info_len;
362  int encoded_len;
364 
365  /*
366  * Generate a "raw" nonce. This is converted to ASCII-printable form by
367  * base64-encoding it.
368  */
369  if (!pg_strong_random(raw_nonce, SCRAM_RAW_NONCE_LEN))
370  {
372  libpq_gettext("could not generate nonce\n"));
373  return NULL;
374  }
375 
376  encoded_len = pg_b64_enc_len(SCRAM_RAW_NONCE_LEN);
377  /* don't forget the zero-terminator */
378  state->client_nonce = malloc(encoded_len + 1);
379  if (state->client_nonce == NULL)
380  {
382  libpq_gettext("out of memory\n"));
383  return NULL;
384  }
385  encoded_len = pg_b64_encode(raw_nonce, SCRAM_RAW_NONCE_LEN,
386  state->client_nonce, encoded_len);
387  if (encoded_len < 0)
388  {
390  libpq_gettext("could not encode nonce\n"));
391  return NULL;
392  }
393  state->client_nonce[encoded_len] = '\0';
394 
395  /*
396  * Generate message. The username is left empty as the backend uses the
397  * value provided by the startup packet. Also, as this username is not
398  * prepared with SASLprep, the message parsing would fail if it includes
399  * '=' or ',' characters.
400  */
401 
402  initPQExpBuffer(&buf);
403 
404  /*
405  * First build the gs2-header with channel binding information.
406  */
407  if (strcmp(state->sasl_mechanism, SCRAM_SHA_256_PLUS_NAME) == 0)
408  {
409  Assert(conn->ssl_in_use);
410  appendPQExpBufferStr(&buf, "p=tls-server-end-point");
411  }
412 #ifdef HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH
413  else if (conn->channel_binding[0] != 'd' && /* disable */
414  conn->ssl_in_use)
415  {
416  /*
417  * Client supports channel binding, but thinks the server does not.
418  */
419  appendPQExpBufferChar(&buf, 'y');
420  }
421 #endif
422  else
423  {
424  /*
425  * Client does not support channel binding, or has disabled it.
426  */
427  appendPQExpBufferChar(&buf, 'n');
428  }
429 
430  if (PQExpBufferDataBroken(buf))
431  goto oom_error;
432 
433  channel_info_len = buf.len;
434 
435  appendPQExpBuffer(&buf, ",,n=,r=%s", state->client_nonce);
436  if (PQExpBufferDataBroken(buf))
437  goto oom_error;
438 
439  /*
440  * The first message content needs to be saved without channel binding
441  * information.
442  */
443  state->client_first_message_bare = strdup(buf.data + channel_info_len + 2);
444  if (!state->client_first_message_bare)
445  goto oom_error;
446 
447  result = strdup(buf.data);
448  if (result == NULL)
449  goto oom_error;
450 
451  termPQExpBuffer(&buf);
452  return result;
453 
454 oom_error:
455  termPQExpBuffer(&buf);
457  libpq_gettext("out of memory\n"));
458  return NULL;
459 }
460 
461 /*
462  * Build the final exchange message sent from the client.
463  */
464 static char *
466 {
468  PGconn *conn = state->conn;
469  uint8 client_proof[SCRAM_KEY_LEN];
470  char *result;
471  int encoded_len;
472 
473  initPQExpBuffer(&buf);
474 
475  /*
476  * Construct client-final-message-without-proof. We need to remember it
477  * for verifying the server proof in the final step of authentication.
478  *
479  * The channel binding flag handling (p/y/n) must be consistent with
480  * build_client_first_message(), because the server will check that it's
481  * the same flag both times.
482  */
483  if (strcmp(state->sasl_mechanism, SCRAM_SHA_256_PLUS_NAME) == 0)
484  {
485 #ifdef HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH
486  char *cbind_data = NULL;
487  size_t cbind_data_len = 0;
488  size_t cbind_header_len;
489  char *cbind_input;
490  size_t cbind_input_len;
491  int encoded_cbind_len;
492 
493  /* Fetch hash data of server's SSL certificate */
494  cbind_data =
495  pgtls_get_peer_certificate_hash(state->conn,
496  &cbind_data_len);
497  if (cbind_data == NULL)
498  {
499  /* error message is already set on error */
500  termPQExpBuffer(&buf);
501  return NULL;
502  }
503 
504  appendPQExpBufferStr(&buf, "c=");
505 
506  /* p=type,, */
507  cbind_header_len = strlen("p=tls-server-end-point,,");
508  cbind_input_len = cbind_header_len + cbind_data_len;
509  cbind_input = malloc(cbind_input_len);
510  if (!cbind_input)
511  {
512  free(cbind_data);
513  goto oom_error;
514  }
515  memcpy(cbind_input, "p=tls-server-end-point,,", cbind_header_len);
516  memcpy(cbind_input + cbind_header_len, cbind_data, cbind_data_len);
517 
518  encoded_cbind_len = pg_b64_enc_len(cbind_input_len);
519  if (!enlargePQExpBuffer(&buf, encoded_cbind_len))
520  {
521  free(cbind_data);
522  free(cbind_input);
523  goto oom_error;
524  }
525  encoded_cbind_len = pg_b64_encode(cbind_input, cbind_input_len,
526  buf.data + buf.len,
527  encoded_cbind_len);
528  if (encoded_cbind_len < 0)
529  {
530  free(cbind_data);
531  free(cbind_input);
532  termPQExpBuffer(&buf);
534  "could not encode cbind data for channel binding\n");
535  return NULL;
536  }
537  buf.len += encoded_cbind_len;
538  buf.data[buf.len] = '\0';
539 
540  free(cbind_data);
541  free(cbind_input);
542 #else
543  /*
544  * Chose channel binding, but the SSL library doesn't support it.
545  * Shouldn't happen.
546  */
547  termPQExpBuffer(&buf);
549  "channel binding not supported by this build\n");
550  return NULL;
551 #endif /* HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH */
552  }
553 #ifdef HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH
554  else if (conn->channel_binding[0] != 'd' && /* disable */
555  conn->ssl_in_use)
556  appendPQExpBufferStr(&buf, "c=eSws"); /* base64 of "y,," */
557 #endif
558  else
559  appendPQExpBufferStr(&buf, "c=biws"); /* base64 of "n,," */
560 
561  if (PQExpBufferDataBroken(buf))
562  goto oom_error;
563 
564  appendPQExpBuffer(&buf, ",r=%s", state->nonce);
565  if (PQExpBufferDataBroken(buf))
566  goto oom_error;
567 
568  state->client_final_message_without_proof = strdup(buf.data);
569  if (state->client_final_message_without_proof == NULL)
570  goto oom_error;
571 
572  /* Append proof to it, to form client-final-message. */
573  if (!calculate_client_proof(state,
575  client_proof))
576  {
577  termPQExpBuffer(&buf);
579  libpq_gettext("could not calculate client proof\n"));
580  return NULL;
581  }
582 
583  appendPQExpBufferStr(&buf, ",p=");
584  encoded_len = pg_b64_enc_len(SCRAM_KEY_LEN);
585  if (!enlargePQExpBuffer(&buf, encoded_len))
586  goto oom_error;
587  encoded_len = pg_b64_encode((char *) client_proof,
589  buf.data + buf.len,
590  encoded_len);
591  if (encoded_len < 0)
592  {
593  termPQExpBuffer(&buf);
595  libpq_gettext("could not encode client proof\n"));
596  return NULL;
597  }
598  buf.len += encoded_len;
599  buf.data[buf.len] = '\0';
600 
601  result = strdup(buf.data);
602  if (result == NULL)
603  goto oom_error;
604 
605  termPQExpBuffer(&buf);
606  return result;
607 
608 oom_error:
609  termPQExpBuffer(&buf);
611  libpq_gettext("out of memory\n"));
612  return NULL;
613 }
614 
615 /*
616  * Read the first exchange message coming from the server.
617  */
618 static bool
620 {
621  PGconn *conn = state->conn;
622  char *iterations_str;
623  char *endptr;
624  char *encoded_salt;
625  char *nonce;
626  int decoded_salt_len;
627 
628  state->server_first_message = strdup(input);
629  if (state->server_first_message == NULL)
630  {
632  libpq_gettext("out of memory\n"));
633  return false;
634  }
635 
636  /* parse the message */
637  nonce = read_attr_value(&input, 'r',
638  &conn->errorMessage);
639  if (nonce == NULL)
640  {
641  /* read_attr_value() has appended an error string */
642  return false;
643  }
644 
645  /* Verify immediately that the server used our part of the nonce */
646  if (strlen(nonce) < strlen(state->client_nonce) ||
647  memcmp(nonce, state->client_nonce, strlen(state->client_nonce)) != 0)
648  {
650  libpq_gettext("invalid SCRAM response (nonce mismatch)\n"));
651  return false;
652  }
653 
654  state->nonce = strdup(nonce);
655  if (state->nonce == NULL)
656  {
658  libpq_gettext("out of memory\n"));
659  return false;
660  }
661 
662  encoded_salt = read_attr_value(&input, 's', &conn->errorMessage);
663  if (encoded_salt == NULL)
664  {
665  /* read_attr_value() has appended an error string */
666  return false;
667  }
668  decoded_salt_len = pg_b64_dec_len(strlen(encoded_salt));
669  state->salt = malloc(decoded_salt_len);
670  if (state->salt == NULL)
671  {
673  libpq_gettext("out of memory\n"));
674  return false;
675  }
676  state->saltlen = pg_b64_decode(encoded_salt,
677  strlen(encoded_salt),
678  state->salt,
679  decoded_salt_len);
680  if (state->saltlen < 0)
681  {
683  libpq_gettext("malformed SCRAM message (invalid salt)\n"));
684  return false;
685  }
686 
687  iterations_str = read_attr_value(&input, 'i', &conn->errorMessage);
688  if (iterations_str == NULL)
689  {
690  /* read_attr_value() has appended an error string */
691  return false;
692  }
693  state->iterations = strtol(iterations_str, &endptr, 10);
694  if (*endptr != '\0' || state->iterations < 1)
695  {
697  libpq_gettext("malformed SCRAM message (invalid iteration count)\n"));
698  return false;
699  }
700 
701  if (*input != '\0')
703  libpq_gettext("malformed SCRAM message (garbage at end of server-first-message)\n"));
704 
705  return true;
706 }
707 
708 /*
709  * Read the final exchange message coming from the server.
710  */
711 static bool
713 {
714  PGconn *conn = state->conn;
715  char *encoded_server_signature;
716  char *decoded_server_signature;
717  int server_signature_len;
718 
719  state->server_final_message = strdup(input);
720  if (!state->server_final_message)
721  {
723  libpq_gettext("out of memory\n"));
724  return false;
725  }
726 
727  /* Check for error result. */
728  if (*input == 'e')
729  {
730  char *errmsg = read_attr_value(&input, 'e',
731  &conn->errorMessage);
732 
733  if (errmsg == NULL)
734  {
735  /* read_attr_value() has appended an error message */
736  return false;
737  }
739  libpq_gettext("error received from server in SCRAM exchange: %s\n"),
740  errmsg);
741  return false;
742  }
743 
744  /* Parse the message. */
745  encoded_server_signature = read_attr_value(&input, 'v',
746  &conn->errorMessage);
747  if (encoded_server_signature == NULL)
748  {
749  /* read_attr_value() has appended an error message */
750  return false;
751  }
752 
753  if (*input != '\0')
755  libpq_gettext("malformed SCRAM message (garbage at end of server-final-message)\n"));
756 
757  server_signature_len = pg_b64_dec_len(strlen(encoded_server_signature));
758  decoded_server_signature = malloc(server_signature_len);
759  if (!decoded_server_signature)
760  {
762  libpq_gettext("out of memory\n"));
763  return false;
764  }
765 
766  server_signature_len = pg_b64_decode(encoded_server_signature,
767  strlen(encoded_server_signature),
768  decoded_server_signature,
769  server_signature_len);
770  if (server_signature_len != SCRAM_KEY_LEN)
771  {
772  free(decoded_server_signature);
774  libpq_gettext("malformed SCRAM message (invalid server signature)\n"));
775  return false;
776  }
777  memcpy(state->ServerSignature, decoded_server_signature, SCRAM_KEY_LEN);
778  free(decoded_server_signature);
779 
780  return true;
781 }
782 
783 /*
784  * Calculate the client proof, part of the final exchange message sent
785  * by the client. Returns true on success, false on failure.
786  */
787 static bool
789  const char *client_final_message_without_proof,
790  uint8 *result)
791 {
792  uint8 StoredKey[SCRAM_KEY_LEN];
793  uint8 ClientKey[SCRAM_KEY_LEN];
794  uint8 ClientSignature[SCRAM_KEY_LEN];
795  int i;
796  pg_hmac_ctx *ctx;
797 
798  ctx = pg_hmac_create(PG_SHA256);
799  if (ctx == NULL)
800  return false;
801 
802  /*
803  * Calculate SaltedPassword, and store it in 'state' so that we can reuse
804  * it later in verify_server_signature.
805  */
806  if (scram_SaltedPassword(state->password, state->salt, state->saltlen,
807  state->iterations, state->SaltedPassword) < 0 ||
808  scram_ClientKey(state->SaltedPassword, ClientKey) < 0 ||
809  scram_H(ClientKey, SCRAM_KEY_LEN, StoredKey) < 0 ||
810  pg_hmac_init(ctx, StoredKey, SCRAM_KEY_LEN) < 0 ||
811  pg_hmac_update(ctx,
812  (uint8 *) state->client_first_message_bare,
813  strlen(state->client_first_message_bare)) < 0 ||
814  pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
815  pg_hmac_update(ctx,
816  (uint8 *) state->server_first_message,
817  strlen(state->server_first_message)) < 0 ||
818  pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
819  pg_hmac_update(ctx,
820  (uint8 *) client_final_message_without_proof,
821  strlen(client_final_message_without_proof)) < 0 ||
822  pg_hmac_final(ctx, ClientSignature, sizeof(ClientSignature)) < 0)
823  {
824  pg_hmac_free(ctx);
825  return false;
826  }
827 
828  for (i = 0; i < SCRAM_KEY_LEN; i++)
829  result[i] = ClientKey[i] ^ ClientSignature[i];
830 
831  pg_hmac_free(ctx);
832  return true;
833 }
834 
835 /*
836  * Validate the server signature, received as part of the final exchange
837  * message received from the server. *match tracks if the server signature
838  * matched or not. Returns true if the server signature got verified, and
839  * false for a processing error.
840  */
841 static bool
843 {
844  uint8 expected_ServerSignature[SCRAM_KEY_LEN];
845  uint8 ServerKey[SCRAM_KEY_LEN];
846  pg_hmac_ctx *ctx;
847 
848  ctx = pg_hmac_create(PG_SHA256);
849  if (ctx == NULL)
850  return false;
851 
852  if (scram_ServerKey(state->SaltedPassword, ServerKey) < 0 ||
853  /* calculate ServerSignature */
854  pg_hmac_init(ctx, ServerKey, SCRAM_KEY_LEN) < 0 ||
855  pg_hmac_update(ctx,
856  (uint8 *) state->client_first_message_bare,
857  strlen(state->client_first_message_bare)) < 0 ||
858  pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
859  pg_hmac_update(ctx,
860  (uint8 *) state->server_first_message,
861  strlen(state->server_first_message)) < 0 ||
862  pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
863  pg_hmac_update(ctx,
865  strlen(state->client_final_message_without_proof)) < 0 ||
866  pg_hmac_final(ctx, expected_ServerSignature,
867  sizeof(expected_ServerSignature)) < 0)
868  {
869  pg_hmac_free(ctx);
870  return false;
871  }
872 
873  pg_hmac_free(ctx);
874 
875  /* signature processed, so now check after it */
876  if (memcmp(expected_ServerSignature, state->ServerSignature, SCRAM_KEY_LEN) != 0)
877  *match = false;
878  else
879  *match = true;
880 
881  return true;
882 }
883 
884 /*
885  * Build a new SCRAM secret.
886  */
887 char *
889 {
890  char *prep_password;
891  pg_saslprep_rc rc;
892  char saltbuf[SCRAM_DEFAULT_SALT_LEN];
893  char *result;
894 
895  /*
896  * Normalize the password with SASLprep. If that doesn't work, because
897  * the password isn't valid UTF-8 or contains prohibited characters, just
898  * proceed with the original password. (See comments at top of file.)
899  */
900  rc = pg_saslprep(password, &prep_password);
901  if (rc == SASLPREP_OOM)
902  return NULL;
903  if (rc == SASLPREP_SUCCESS)
904  password = (const char *) prep_password;
905 
906  /* Generate a random salt */
908  {
909  if (prep_password)
910  free(prep_password);
911  return NULL;
912  }
913 
914  result = scram_build_secret(saltbuf, SCRAM_DEFAULT_SALT_LEN,
915  SCRAM_DEFAULT_ITERATIONS, password);
916 
917  if (prep_password)
918  free(prep_password);
919 
920  return result;
921 }
char * client_nonce
Definition: fe-auth-scram.c:63
fe_scram_state_enum
Definition: fe-auth-scram.c:44
static void error(void)
Definition: sql-dyntest.c:147
int pg_b64_encode(const char *src, int len, char *dst, int dstlen)
Definition: base64.c:49
static void output(uint64 loop_count)
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
static bool verify_server_signature(fe_scram_state *state, bool *match)
char ServerSignature[SCRAM_KEY_LEN]
Definition: fe-auth-scram.c:76
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
static void * scram_init(PGconn *conn, const char *password, const char *sasl_mechanism)
Definition: fe-auth-scram.c:92
unsigned char uint8
Definition: c.h:439
char * scram_build_secret(const char *salt, int saltlen, int iterations, const char *password)
Definition: scram-common.c:169
pg_saslprep_rc pg_saslprep(const char *input, char **output)
Definition: saslprep.c:1044
uint8 SaltedPassword[SCRAM_KEY_LEN]
Definition: fe-auth-scram.c:62
pg_hmac_ctx * pg_hmac_create(pg_cryptohash_type type)
Definition: hmac.c:69
static char * build_client_final_message(fe_scram_state *state)
int scram_ServerKey(const uint8 *salted_password, uint8 *result)
Definition: scram-common.c:140
int pg_b64_dec_len(int srclen)
Definition: base64.c:239
int scram_H(const uint8 *input, int len, uint8 *result)
Definition: scram-common.c:93
#define malloc(a)
Definition: header.h:50
int scram_ClientKey(const uint8 *salted_password, uint8 *result)
Definition: scram-common.c:117
pg_saslprep_rc
Definition: saslprep.h:20
PGconn * conn
Definition: streamutil.c:54
int pg_hmac_update(pg_hmac_ctx *ctx, const uint8 *data, size_t len)
Definition: hmac.c:205
static bool read_server_final_message(fe_scram_state *state, char *input)
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
char * pg_fe_scram_build_secret(const char *password)
bool ssl_in_use
Definition: libpq-int.h:508
static char * buf
Definition: pg_test_fsync.c:68
#define SCRAM_SHA_256_PLUS_NAME
Definition: scram-common.h:21
char * channel_binding
Definition: libpq-int.h:371
static char * password
Definition: streamutil.c:53
static bool scram_channel_bound(void *opaq)
int pg_b64_decode(const char *src, int len, char *dst, int dstlen)
Definition: base64.c:116
const pg_fe_sasl_mech pg_scram_mech
Definition: fe-auth-scram.c:33
#define SCRAM_DEFAULT_SALT_LEN
Definition: scram-common.h:41
int pg_hmac_init(pg_hmac_ctx *ctx, const uint8 *key, size_t len)
Definition: hmac.c:128
void pg_hmac_free(pg_hmac_ctx *ctx)
Definition: hmac.c:255
char * server_first_message
Definition: fe-auth-scram.c:68
char * client_final_message_without_proof
Definition: fe-auth-scram.c:65
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:380
PQExpBufferData errorMessage
Definition: libpq-int.h:571
#define SCRAM_RAW_NONCE_LEN
Definition: scram-common.h:34
#define free(a)
Definition: header.h:65
#define PQExpBufferDataBroken(buf)
Definition: pqexpbuffer.h:67
bool pg_strong_random(void *buf, size_t len)
static void scram_exchange(void *opaq, char *input, int inputlen, char **output, int *outputlen, bool *done, bool *success)
#define Assert(condition)
Definition: c.h:804
Definition: regguts.h:317
static bool read_server_first_message(fe_scram_state *state, char *input)
char * client_first_message_bare
Definition: fe-auth-scram.c:64
#define SCRAM_DEFAULT_ITERATIONS
Definition: scram-common.h:47
static bool calculate_client_proof(fe_scram_state *state, const char *client_final_message_without_proof, uint8 *result)
int scram_SaltedPassword(const char *password, const char *salt, int saltlen, int iterations, uint8 *result)
Definition: scram-common.c:34
int pg_b64_enc_len(int srclen)
Definition: base64.c:224
static char * build_client_first_message(fe_scram_state *state)
char * sasl_mechanism
Definition: fe-auth-scram.c:59
int errmsg(const char *fmt,...)
Definition: elog.c:909
int i
char * server_final_message
Definition: fe-auth-scram.c:75
static void scram_free(void *opaq)
static bool success
Definition: initdb.c:165
#define SCRAM_KEY_LEN
Definition: scram-common.h:24
static char * read_attr_value(char **input, char attr, PQExpBuffer errorMessage)
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92
#define libpq_gettext(x)
Definition: libpq-int.h:841
fe_scram_state_enum state
Definition: fe-auth-scram.c:54
int pg_hmac_final(pg_hmac_ctx *ctx, uint8 *dest, size_t len)
Definition: hmac.c:222
int enlargePQExpBuffer(PQExpBuffer str, size_t needed)
Definition: pqexpbuffer.c:174