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