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