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