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  return;
283 }
284 
285 /*
286  * Read value for an attribute part of a SCRAM message.
287  */
288 static char *
289 read_attr_value(char **input, char attr, PQExpBuffer errorMessage)
290 {
291  char *begin = *input;
292  char *end;
293 
294  if (*begin != attr)
295  {
296  printfPQExpBuffer(errorMessage,
297  libpq_gettext("malformed SCRAM message (attribute \"%c\" expected)\n"),
298  attr);
299  return NULL;
300  }
301  begin++;
302 
303  if (*begin != '=')
304  {
305  printfPQExpBuffer(errorMessage,
306  libpq_gettext("malformed SCRAM message (expected character \"=\" for attribute \"%c\")\n"),
307  attr);
308  return NULL;
309  }
310  begin++;
311 
312  end = begin;
313  while (*end && *end != ',')
314  end++;
315 
316  if (*end)
317  {
318  *end = '\0';
319  *input = end + 1;
320  }
321  else
322  *input = end;
323 
324  return begin;
325 }
326 
327 /*
328  * Build the first exchange message sent by the client.
329  */
330 static char *
332 {
333  PGconn *conn = state->conn;
334  char raw_nonce[SCRAM_RAW_NONCE_LEN + 1];
335  char *result;
336  int channel_info_len;
337  int encoded_len;
339 
340  /*
341  * Generate a "raw" nonce. This is converted to ASCII-printable form by
342  * base64-encoding it.
343  */
344  if (!pg_strong_random(raw_nonce, SCRAM_RAW_NONCE_LEN))
345  {
347  libpq_gettext("could not generate nonce\n"));
348  return NULL;
349  }
350 
351  encoded_len = pg_b64_enc_len(SCRAM_RAW_NONCE_LEN);
352  /* don't forget the zero-terminator */
353  state->client_nonce = malloc(encoded_len + 1);
354  if (state->client_nonce == NULL)
355  {
357  libpq_gettext("out of memory\n"));
358  return NULL;
359  }
360  encoded_len = pg_b64_encode(raw_nonce, SCRAM_RAW_NONCE_LEN,
361  state->client_nonce, encoded_len);
362  if (encoded_len < 0)
363  {
365  libpq_gettext("could not encode nonce\n"));
366  return NULL;
367  }
368  state->client_nonce[encoded_len] = '\0';
369 
370  /*
371  * Generate message. The username is left empty as the backend uses the
372  * value provided by the startup packet. Also, as this username is not
373  * prepared with SASLprep, the message parsing would fail if it includes
374  * '=' or ',' characters.
375  */
376 
377  initPQExpBuffer(&buf);
378 
379  /*
380  * First build the gs2-header with channel binding information.
381  */
382  if (strcmp(state->sasl_mechanism, SCRAM_SHA_256_PLUS_NAME) == 0)
383  {
384  Assert(conn->ssl_in_use);
385  appendPQExpBufferStr(&buf, "p=tls-server-end-point");
386  }
387 #ifdef HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH
388  else if (conn->channel_binding[0] != 'd' && /* disable */
389  conn->ssl_in_use)
390  {
391  /*
392  * Client supports channel binding, but thinks the server does not.
393  */
394  appendPQExpBufferChar(&buf, 'y');
395  }
396 #endif
397  else
398  {
399  /*
400  * Client does not support channel binding, or has disabled it.
401  */
402  appendPQExpBufferChar(&buf, 'n');
403  }
404 
405  if (PQExpBufferDataBroken(buf))
406  goto oom_error;
407 
408  channel_info_len = buf.len;
409 
410  appendPQExpBuffer(&buf, ",,n=,r=%s", state->client_nonce);
411  if (PQExpBufferDataBroken(buf))
412  goto oom_error;
413 
414  /*
415  * The first message content needs to be saved without channel binding
416  * information.
417  */
418  state->client_first_message_bare = strdup(buf.data + channel_info_len + 2);
419  if (!state->client_first_message_bare)
420  goto oom_error;
421 
422  result = strdup(buf.data);
423  if (result == NULL)
424  goto oom_error;
425 
426  termPQExpBuffer(&buf);
427  return result;
428 
429 oom_error:
430  termPQExpBuffer(&buf);
432  libpq_gettext("out of memory\n"));
433  return NULL;
434 }
435 
436 /*
437  * Build the final exchange message sent from the client.
438  */
439 static char *
441 {
443  PGconn *conn = state->conn;
444  uint8 client_proof[SCRAM_KEY_LEN];
445  char *result;
446  int encoded_len;
447 
448  initPQExpBuffer(&buf);
449 
450  /*
451  * Construct client-final-message-without-proof. We need to remember it
452  * for verifying the server proof in the final step of authentication.
453  *
454  * The channel binding flag handling (p/y/n) must be consistent with
455  * build_client_first_message(), because the server will check that it's
456  * the same flag both times.
457  */
458  if (strcmp(state->sasl_mechanism, SCRAM_SHA_256_PLUS_NAME) == 0)
459  {
460 #ifdef HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH
461  char *cbind_data = NULL;
462  size_t cbind_data_len = 0;
463  size_t cbind_header_len;
464  char *cbind_input;
465  size_t cbind_input_len;
466  int encoded_cbind_len;
467 
468  /* Fetch hash data of server's SSL certificate */
469  cbind_data =
470  pgtls_get_peer_certificate_hash(state->conn,
471  &cbind_data_len);
472  if (cbind_data == NULL)
473  {
474  /* error message is already set on error */
475  termPQExpBuffer(&buf);
476  return NULL;
477  }
478 
479  appendPQExpBufferStr(&buf, "c=");
480 
481  /* p=type,, */
482  cbind_header_len = strlen("p=tls-server-end-point,,");
483  cbind_input_len = cbind_header_len + cbind_data_len;
484  cbind_input = malloc(cbind_input_len);
485  if (!cbind_input)
486  {
487  free(cbind_data);
488  goto oom_error;
489  }
490  memcpy(cbind_input, "p=tls-server-end-point,,", cbind_header_len);
491  memcpy(cbind_input + cbind_header_len, cbind_data, cbind_data_len);
492 
493  encoded_cbind_len = pg_b64_enc_len(cbind_input_len);
494  if (!enlargePQExpBuffer(&buf, encoded_cbind_len))
495  {
496  free(cbind_data);
497  free(cbind_input);
498  goto oom_error;
499  }
500  encoded_cbind_len = pg_b64_encode(cbind_input, cbind_input_len,
501  buf.data + buf.len,
502  encoded_cbind_len);
503  if (encoded_cbind_len < 0)
504  {
505  free(cbind_data);
506  free(cbind_input);
507  termPQExpBuffer(&buf);
509  "could not encode cbind data for channel binding\n");
510  return NULL;
511  }
512  buf.len += encoded_cbind_len;
513  buf.data[buf.len] = '\0';
514 
515  free(cbind_data);
516  free(cbind_input);
517 #else
518  /*
519  * Chose channel binding, but the SSL library doesn't support it.
520  * Shouldn't happen.
521  */
522  termPQExpBuffer(&buf);
524  "channel binding not supported by this build\n");
525  return NULL;
526 #endif /* HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH */
527  }
528 #ifdef HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH
529  else if (conn->channel_binding[0] != 'd' && /* disable */
530  conn->ssl_in_use)
531  appendPQExpBufferStr(&buf, "c=eSws"); /* base64 of "y,," */
532 #endif
533  else
534  appendPQExpBufferStr(&buf, "c=biws"); /* base64 of "n,," */
535 
536  if (PQExpBufferDataBroken(buf))
537  goto oom_error;
538 
539  appendPQExpBuffer(&buf, ",r=%s", state->nonce);
540  if (PQExpBufferDataBroken(buf))
541  goto oom_error;
542 
543  state->client_final_message_without_proof = strdup(buf.data);
544  if (state->client_final_message_without_proof == NULL)
545  goto oom_error;
546 
547  /* Append proof to it, to form client-final-message. */
550  client_proof);
551 
552  appendPQExpBufferStr(&buf, ",p=");
553  encoded_len = pg_b64_enc_len(SCRAM_KEY_LEN);
554  if (!enlargePQExpBuffer(&buf, encoded_len))
555  goto oom_error;
556  encoded_len = pg_b64_encode((char *) client_proof,
558  buf.data + buf.len,
559  encoded_len);
560  if (encoded_len < 0)
561  {
562  termPQExpBuffer(&buf);
564  libpq_gettext("could not encode client proof\n"));
565  return NULL;
566  }
567  buf.len += encoded_len;
568  buf.data[buf.len] = '\0';
569 
570  result = strdup(buf.data);
571  if (result == NULL)
572  goto oom_error;
573 
574  termPQExpBuffer(&buf);
575  return result;
576 
577 oom_error:
578  termPQExpBuffer(&buf);
580  libpq_gettext("out of memory\n"));
581  return NULL;
582 }
583 
584 /*
585  * Read the first exchange message coming from the server.
586  */
587 static bool
589 {
590  PGconn *conn = state->conn;
591  char *iterations_str;
592  char *endptr;
593  char *encoded_salt;
594  char *nonce;
595  int decoded_salt_len;
596 
597  state->server_first_message = strdup(input);
598  if (state->server_first_message == NULL)
599  {
601  libpq_gettext("out of memory\n"));
602  return false;
603  }
604 
605  /* parse the message */
606  nonce = read_attr_value(&input, 'r',
607  &conn->errorMessage);
608  if (nonce == NULL)
609  {
610  /* read_attr_value() has generated an error string */
611  return false;
612  }
613 
614  /* Verify immediately that the server used our part of the nonce */
615  if (strlen(nonce) < strlen(state->client_nonce) ||
616  memcmp(nonce, state->client_nonce, strlen(state->client_nonce)) != 0)
617  {
619  libpq_gettext("invalid SCRAM response (nonce mismatch)\n"));
620  return false;
621  }
622 
623  state->nonce = strdup(nonce);
624  if (state->nonce == NULL)
625  {
627  libpq_gettext("out of memory\n"));
628  return false;
629  }
630 
631  encoded_salt = read_attr_value(&input, 's', &conn->errorMessage);
632  if (encoded_salt == NULL)
633  {
634  /* read_attr_value() has generated an error string */
635  return false;
636  }
637  decoded_salt_len = pg_b64_dec_len(strlen(encoded_salt));
638  state->salt = malloc(decoded_salt_len);
639  if (state->salt == NULL)
640  {
642  libpq_gettext("out of memory\n"));
643  return false;
644  }
645  state->saltlen = pg_b64_decode(encoded_salt,
646  strlen(encoded_salt),
647  state->salt,
648  decoded_salt_len);
649  if (state->saltlen < 0)
650  {
652  libpq_gettext("malformed SCRAM message (invalid salt)\n"));
653  return false;
654  }
655 
656  iterations_str = read_attr_value(&input, 'i', &conn->errorMessage);
657  if (iterations_str == NULL)
658  {
659  /* read_attr_value() has generated an error string */
660  return false;
661  }
662  state->iterations = strtol(iterations_str, &endptr, 10);
663  if (*endptr != '\0' || state->iterations < 1)
664  {
666  libpq_gettext("malformed SCRAM message (invalid iteration count)\n"));
667  return false;
668  }
669 
670  if (*input != '\0')
672  libpq_gettext("malformed SCRAM message (garbage at end of server-first-message)\n"));
673 
674  return true;
675 }
676 
677 /*
678  * Read the final exchange message coming from the server.
679  */
680 static bool
682 {
683  PGconn *conn = state->conn;
684  char *encoded_server_signature;
685  char *decoded_server_signature;
686  int server_signature_len;
687 
688  state->server_final_message = strdup(input);
689  if (!state->server_final_message)
690  {
692  libpq_gettext("out of memory\n"));
693  return false;
694  }
695 
696  /* Check for error result. */
697  if (*input == 'e')
698  {
699  char *errmsg = read_attr_value(&input, 'e',
700  &conn->errorMessage);
701 
703  libpq_gettext("error received from server in SCRAM exchange: %s\n"),
704  errmsg);
705  return false;
706  }
707 
708  /* Parse the message. */
709  encoded_server_signature = read_attr_value(&input, 'v',
710  &conn->errorMessage);
711  if (encoded_server_signature == NULL)
712  {
713  /* read_attr_value() has generated an error message */
714  return false;
715  }
716 
717  if (*input != '\0')
719  libpq_gettext("malformed SCRAM message (garbage at end of server-final-message)\n"));
720 
721  server_signature_len = pg_b64_dec_len(strlen(encoded_server_signature));
722  decoded_server_signature = malloc(server_signature_len);
723  if (!decoded_server_signature)
724  {
726  libpq_gettext("out of memory\n"));
727  return false;
728  }
729 
730  server_signature_len = pg_b64_decode(encoded_server_signature,
731  strlen(encoded_server_signature),
732  decoded_server_signature,
733  server_signature_len);
734  if (server_signature_len != SCRAM_KEY_LEN)
735  {
736  free(decoded_server_signature);
738  libpq_gettext("malformed SCRAM message (invalid server signature)\n"));
739  return false;
740  }
741  memcpy(state->ServerSignature, decoded_server_signature, SCRAM_KEY_LEN);
742  free(decoded_server_signature);
743 
744  return true;
745 }
746 
747 /*
748  * Calculate the client proof, part of the final exchange message sent
749  * by the client.
750  */
751 static void
753  const char *client_final_message_without_proof,
754  uint8 *result)
755 {
756  uint8 StoredKey[SCRAM_KEY_LEN];
757  uint8 ClientKey[SCRAM_KEY_LEN];
758  uint8 ClientSignature[SCRAM_KEY_LEN];
759  int i;
760  scram_HMAC_ctx ctx;
761 
762  /*
763  * Calculate SaltedPassword, and store it in 'state' so that we can reuse
764  * it later in verify_server_signature.
765  */
766  scram_SaltedPassword(state->password, state->salt, state->saltlen,
767  state->iterations, state->SaltedPassword);
768 
769  scram_ClientKey(state->SaltedPassword, ClientKey);
770  scram_H(ClientKey, SCRAM_KEY_LEN, StoredKey);
771 
772  scram_HMAC_init(&ctx, StoredKey, SCRAM_KEY_LEN);
773  scram_HMAC_update(&ctx,
775  strlen(state->client_first_message_bare));
776  scram_HMAC_update(&ctx, ",", 1);
777  scram_HMAC_update(&ctx,
778  state->server_first_message,
779  strlen(state->server_first_message));
780  scram_HMAC_update(&ctx, ",", 1);
781  scram_HMAC_update(&ctx,
782  client_final_message_without_proof,
783  strlen(client_final_message_without_proof));
784  scram_HMAC_final(ClientSignature, &ctx);
785 
786  for (i = 0; i < SCRAM_KEY_LEN; i++)
787  result[i] = ClientKey[i] ^ ClientSignature[i];
788 }
789 
790 /*
791  * Validate the server signature, received as part of the final exchange
792  * message received from the server.
793  */
794 static bool
796 {
797  uint8 expected_ServerSignature[SCRAM_KEY_LEN];
798  uint8 ServerKey[SCRAM_KEY_LEN];
799  scram_HMAC_ctx ctx;
800 
801  scram_ServerKey(state->SaltedPassword, ServerKey);
802 
803  /* calculate ServerSignature */
804  scram_HMAC_init(&ctx, ServerKey, SCRAM_KEY_LEN);
805  scram_HMAC_update(&ctx,
807  strlen(state->client_first_message_bare));
808  scram_HMAC_update(&ctx, ",", 1);
809  scram_HMAC_update(&ctx,
810  state->server_first_message,
811  strlen(state->server_first_message));
812  scram_HMAC_update(&ctx, ",", 1);
813  scram_HMAC_update(&ctx,
815  strlen(state->client_final_message_without_proof));
816  scram_HMAC_final(expected_ServerSignature, &ctx);
817 
818  if (memcmp(expected_ServerSignature, state->ServerSignature, SCRAM_KEY_LEN) != 0)
819  return false;
820 
821  return true;
822 }
823 
824 /*
825  * Build a new SCRAM secret.
826  */
827 char *
829 {
830  char *prep_password;
831  pg_saslprep_rc rc;
832  char saltbuf[SCRAM_DEFAULT_SALT_LEN];
833  char *result;
834 
835  /*
836  * Normalize the password with SASLprep. If that doesn't work, because
837  * the password isn't valid UTF-8 or contains prohibited characters, just
838  * proceed with the original password. (See comments at top of file.)
839  */
840  rc = pg_saslprep(password, &prep_password);
841  if (rc == SASLPREP_OOM)
842  return NULL;
843  if (rc == SASLPREP_SUCCESS)
844  password = (const char *) prep_password;
845 
846  /* Generate a random salt */
848  {
849  if (prep_password)
850  free(prep_password);
851  return NULL;
852  }
853 
854  result = scram_build_secret(saltbuf, SCRAM_DEFAULT_SALT_LEN,
855  SCRAM_DEFAULT_ITERATIONS, password);
856 
857  if (prep_password)
858  free(prep_password);
859 
860  return result;
861 }
void scram_H(const uint8 *input, int len, uint8 *result)
Definition: scram-common.c:147
static char password[100]
Definition: streamutil.c:55
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:356
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:56
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:68
#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:732
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:784
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:790
fe_scram_state_enum state
Definition: fe-auth-scram.c:37
int enlargePQExpBuffer(PQExpBuffer str, size_t needed)
Definition: pqexpbuffer.c:174