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 
83 static bool read_server_first_message(fe_scram_state *state, char *input);
84 static bool read_server_final_message(fe_scram_state *state, char *input);
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. */
252  if (!read_server_first_message(state, input))
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 */
266  if (!read_server_final_message(state, input))
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  break;
286 
287  default:
288  /* shouldn't happen */
289  libpq_append_conn_error(conn, "invalid SCRAM exchange state");
290  goto error;
291  }
292  return;
293 
294 error:
295  *done = true;
296  *success = false;
297 }
298 
299 /*
300  * Read value for an attribute part of a SCRAM message.
301  *
302  * The buffer at **input is destructively modified, and *input is
303  * advanced over the "attr=value" string and any following comma.
304  *
305  * On failure, append an error message to *errorMessage and return NULL.
306  */
307 static char *
308 read_attr_value(char **input, char attr, PQExpBuffer errorMessage)
309 {
310  char *begin = *input;
311  char *end;
312 
313  if (*begin != attr)
314  {
315  libpq_append_error(errorMessage,
316  "malformed SCRAM message (attribute \"%c\" expected)",
317  attr);
318  return NULL;
319  }
320  begin++;
321 
322  if (*begin != '=')
323  {
324  libpq_append_error(errorMessage,
325  "malformed SCRAM message (expected character \"=\" for attribute \"%c\")",
326  attr);
327  return NULL;
328  }
329  begin++;
330 
331  end = begin;
332  while (*end && *end != ',')
333  end++;
334 
335  if (*end)
336  {
337  *end = '\0';
338  *input = end + 1;
339  }
340  else
341  *input = end;
342 
343  return begin;
344 }
345 
346 /*
347  * Build the first exchange message sent by the client.
348  */
349 static char *
351 {
352  PGconn *conn = state->conn;
353  char raw_nonce[SCRAM_RAW_NONCE_LEN + 1];
354  char *result;
355  int channel_info_len;
356  int encoded_len;
358 
359  /*
360  * Generate a "raw" nonce. This is converted to ASCII-printable form by
361  * base64-encoding it.
362  */
363  if (!pg_strong_random(raw_nonce, SCRAM_RAW_NONCE_LEN))
364  {
365  libpq_append_conn_error(conn, "could not generate nonce");
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  {
374  libpq_append_conn_error(conn, "out of memory");
375  return NULL;
376  }
377  encoded_len = pg_b64_encode(raw_nonce, SCRAM_RAW_NONCE_LEN,
378  state->client_nonce, encoded_len);
379  if (encoded_len < 0)
380  {
381  libpq_append_conn_error(conn, "could not encode nonce");
382  return NULL;
383  }
384  state->client_nonce[encoded_len] = '\0';
385 
386  /*
387  * Generate message. The username is left empty as the backend uses the
388  * value provided by the startup packet. Also, as this username is not
389  * prepared with SASLprep, the message parsing would fail if it includes
390  * '=' or ',' characters.
391  */
392 
394 
395  /*
396  * First build the gs2-header with channel binding information.
397  */
398  if (strcmp(state->sasl_mechanism, SCRAM_SHA_256_PLUS_NAME) == 0)
399  {
401  appendPQExpBufferStr(&buf, "p=tls-server-end-point");
402  }
403 #ifdef HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH
404  else if (conn->channel_binding[0] != 'd' && /* disable */
405  conn->ssl_in_use)
406  {
407  /*
408  * Client supports channel binding, but thinks the server does not.
409  */
410  appendPQExpBufferChar(&buf, 'y');
411  }
412 #endif
413  else
414  {
415  /*
416  * Client does not support channel binding, or has disabled it.
417  */
418  appendPQExpBufferChar(&buf, 'n');
419  }
420 
422  goto oom_error;
423 
424  channel_info_len = buf.len;
425 
426  appendPQExpBuffer(&buf, ",,n=,r=%s", state->client_nonce);
428  goto oom_error;
429 
430  /*
431  * The first message content needs to be saved without channel binding
432  * information.
433  */
434  state->client_first_message_bare = strdup(buf.data + channel_info_len + 2);
435  if (!state->client_first_message_bare)
436  goto oom_error;
437 
438  result = strdup(buf.data);
439  if (result == NULL)
440  goto oom_error;
441 
443  return result;
444 
445 oom_error:
447  libpq_append_conn_error(conn, "out of memory");
448  return NULL;
449 }
450 
451 /*
452  * Build the final exchange message sent from the client.
453  */
454 static char *
456 {
458  PGconn *conn = state->conn;
459  uint8 client_proof[SCRAM_MAX_KEY_LEN];
460  char *result;
461  int encoded_len;
462  const char *errstr = NULL;
463 
465 
466  /*
467  * Construct client-final-message-without-proof. We need to remember it
468  * for verifying the server proof in the final step of authentication.
469  *
470  * The channel binding flag handling (p/y/n) must be consistent with
471  * build_client_first_message(), because the server will check that it's
472  * the same flag both times.
473  */
474  if (strcmp(state->sasl_mechanism, SCRAM_SHA_256_PLUS_NAME) == 0)
475  {
476 #ifdef HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH
477  char *cbind_data = NULL;
478  size_t cbind_data_len = 0;
479  size_t cbind_header_len;
480  char *cbind_input;
481  size_t cbind_input_len;
482  int encoded_cbind_len;
483 
484  /* Fetch hash data of server's SSL certificate */
485  cbind_data =
486  pgtls_get_peer_certificate_hash(state->conn,
487  &cbind_data_len);
488  if (cbind_data == NULL)
489  {
490  /* error message is already set on error */
492  return NULL;
493  }
494 
495  appendPQExpBufferStr(&buf, "c=");
496 
497  /* p=type,, */
498  cbind_header_len = strlen("p=tls-server-end-point,,");
499  cbind_input_len = cbind_header_len + cbind_data_len;
500  cbind_input = malloc(cbind_input_len);
501  if (!cbind_input)
502  {
503  free(cbind_data);
504  goto oom_error;
505  }
506  memcpy(cbind_input, "p=tls-server-end-point,,", cbind_header_len);
507  memcpy(cbind_input + cbind_header_len, cbind_data, cbind_data_len);
508 
509  encoded_cbind_len = pg_b64_enc_len(cbind_input_len);
510  if (!enlargePQExpBuffer(&buf, encoded_cbind_len))
511  {
512  free(cbind_data);
513  free(cbind_input);
514  goto oom_error;
515  }
516  encoded_cbind_len = pg_b64_encode(cbind_input, cbind_input_len,
517  buf.data + buf.len,
518  encoded_cbind_len);
519  if (encoded_cbind_len < 0)
520  {
521  free(cbind_data);
522  free(cbind_input);
525  "could not encode cbind data for channel binding\n");
526  return NULL;
527  }
528  buf.len += encoded_cbind_len;
529  buf.data[buf.len] = '\0';
530 
531  free(cbind_data);
532  free(cbind_input);
533 #else
534  /*
535  * Chose channel binding, but the SSL library doesn't support it.
536  * Shouldn't happen.
537  */
540  "channel binding not supported by this build\n");
541  return NULL;
542 #endif /* HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH */
543  }
544 #ifdef HAVE_PGTLS_GET_PEER_CERTIFICATE_HASH
545  else if (conn->channel_binding[0] != 'd' && /* disable */
546  conn->ssl_in_use)
547  appendPQExpBufferStr(&buf, "c=eSws"); /* base64 of "y,," */
548 #endif
549  else
550  appendPQExpBufferStr(&buf, "c=biws"); /* base64 of "n,," */
551 
553  goto oom_error;
554 
555  appendPQExpBuffer(&buf, ",r=%s", state->nonce);
557  goto oom_error;
558 
559  state->client_final_message_without_proof = strdup(buf.data);
560  if (state->client_final_message_without_proof == NULL)
561  goto oom_error;
562 
563  /* Append proof to it, to form client-final-message. */
565  state->client_final_message_without_proof,
566  client_proof, &errstr))
567  {
569  libpq_append_conn_error(conn, "could not calculate client proof: %s", errstr);
570  return NULL;
571  }
572 
573  appendPQExpBufferStr(&buf, ",p=");
574  encoded_len = pg_b64_enc_len(state->key_length);
575  if (!enlargePQExpBuffer(&buf, encoded_len))
576  goto oom_error;
577  encoded_len = pg_b64_encode((char *) client_proof,
578  state->key_length,
579  buf.data + buf.len,
580  encoded_len);
581  if (encoded_len < 0)
582  {
584  libpq_append_conn_error(conn, "could not encode client proof");
585  return NULL;
586  }
587  buf.len += encoded_len;
588  buf.data[buf.len] = '\0';
589 
590  result = strdup(buf.data);
591  if (result == NULL)
592  goto oom_error;
593 
595  return result;
596 
597 oom_error:
599  libpq_append_conn_error(conn, "out of memory");
600  return NULL;
601 }
602 
603 /*
604  * Read the first exchange message coming from the server.
605  */
606 static bool
608 {
609  PGconn *conn = state->conn;
610  char *iterations_str;
611  char *endptr;
612  char *encoded_salt;
613  char *nonce;
614  int decoded_salt_len;
615 
616  state->server_first_message = strdup(input);
617  if (state->server_first_message == NULL)
618  {
619  libpq_append_conn_error(conn, "out of memory");
620  return false;
621  }
622 
623  /* parse the message */
624  nonce = read_attr_value(&input, 'r',
625  &conn->errorMessage);
626  if (nonce == NULL)
627  {
628  /* read_attr_value() has appended an error string */
629  return false;
630  }
631 
632  /* Verify immediately that the server used our part of the nonce */
633  if (strlen(nonce) < strlen(state->client_nonce) ||
634  memcmp(nonce, state->client_nonce, strlen(state->client_nonce)) != 0)
635  {
636  libpq_append_conn_error(conn, "invalid SCRAM response (nonce mismatch)");
637  return false;
638  }
639 
640  state->nonce = strdup(nonce);
641  if (state->nonce == NULL)
642  {
643  libpq_append_conn_error(conn, "out of memory");
644  return false;
645  }
646 
647  encoded_salt = read_attr_value(&input, 's', &conn->errorMessage);
648  if (encoded_salt == NULL)
649  {
650  /* read_attr_value() has appended an error string */
651  return false;
652  }
653  decoded_salt_len = pg_b64_dec_len(strlen(encoded_salt));
654  state->salt = malloc(decoded_salt_len);
655  if (state->salt == NULL)
656  {
657  libpq_append_conn_error(conn, "out of memory");
658  return false;
659  }
660  state->saltlen = pg_b64_decode(encoded_salt,
661  strlen(encoded_salt),
662  state->salt,
663  decoded_salt_len);
664  if (state->saltlen < 0)
665  {
666  libpq_append_conn_error(conn, "malformed SCRAM message (invalid salt)");
667  return false;
668  }
669 
670  iterations_str = read_attr_value(&input, 'i', &conn->errorMessage);
671  if (iterations_str == NULL)
672  {
673  /* read_attr_value() has appended an error string */
674  return false;
675  }
676  state->iterations = strtol(iterations_str, &endptr, 10);
677  if (*endptr != '\0' || state->iterations < 1)
678  {
679  libpq_append_conn_error(conn, "malformed SCRAM message (invalid iteration count)");
680  return false;
681  }
682 
683  if (*input != '\0')
684  libpq_append_conn_error(conn, "malformed SCRAM message (garbage at end of server-first-message)");
685 
686  return true;
687 }
688 
689 /*
690  * Read the final exchange message coming from the server.
691  */
692 static bool
694 {
695  PGconn *conn = state->conn;
696  char *encoded_server_signature;
697  char *decoded_server_signature;
698  int server_signature_len;
699 
700  state->server_final_message = strdup(input);
701  if (!state->server_final_message)
702  {
703  libpq_append_conn_error(conn, "out of memory");
704  return false;
705  }
706 
707  /* Check for error result. */
708  if (*input == 'e')
709  {
710  char *errmsg = read_attr_value(&input, 'e',
711  &conn->errorMessage);
712 
713  if (errmsg == NULL)
714  {
715  /* read_attr_value() has appended an error message */
716  return false;
717  }
718  libpq_append_conn_error(conn, "error received from server in SCRAM exchange: %s",
719  errmsg);
720  return false;
721  }
722 
723  /* Parse the message. */
724  encoded_server_signature = read_attr_value(&input, 'v',
725  &conn->errorMessage);
726  if (encoded_server_signature == NULL)
727  {
728  /* read_attr_value() has appended an error message */
729  return false;
730  }
731 
732  if (*input != '\0')
733  libpq_append_conn_error(conn, "malformed SCRAM message (garbage at end of server-final-message)");
734 
735  server_signature_len = pg_b64_dec_len(strlen(encoded_server_signature));
736  decoded_server_signature = malloc(server_signature_len);
737  if (!decoded_server_signature)
738  {
739  libpq_append_conn_error(conn, "out of memory");
740  return false;
741  }
742 
743  server_signature_len = pg_b64_decode(encoded_server_signature,
744  strlen(encoded_server_signature),
745  decoded_server_signature,
746  server_signature_len);
747  if (server_signature_len != state->key_length)
748  {
749  free(decoded_server_signature);
750  libpq_append_conn_error(conn, "malformed SCRAM message (invalid server signature)");
751  return false;
752  }
753  memcpy(state->ServerSignature, decoded_server_signature,
754  state->key_length);
755  free(decoded_server_signature);
756 
757  return true;
758 }
759 
760 /*
761  * Calculate the client proof, part of the final exchange message sent
762  * by the client. Returns true on success, false on failure with *errstr
763  * pointing to a message about the error details.
764  */
765 static bool
767  const char *client_final_message_without_proof,
768  uint8 *result, const char **errstr)
769 {
770  uint8 StoredKey[SCRAM_MAX_KEY_LEN];
771  uint8 ClientKey[SCRAM_MAX_KEY_LEN];
772  uint8 ClientSignature[SCRAM_MAX_KEY_LEN];
773  int i;
774  pg_hmac_ctx *ctx;
775 
776  ctx = pg_hmac_create(state->hash_type);
777  if (ctx == NULL)
778  {
779  *errstr = pg_hmac_error(NULL); /* returns OOM */
780  return false;
781  }
782 
783  /*
784  * Calculate SaltedPassword, and store it in 'state' so that we can reuse
785  * it later in verify_server_signature.
786  */
787  if (scram_SaltedPassword(state->password, state->hash_type,
788  state->key_length, state->salt, state->saltlen,
789  state->iterations, state->SaltedPassword,
790  errstr) < 0 ||
791  scram_ClientKey(state->SaltedPassword, state->hash_type,
792  state->key_length, ClientKey, errstr) < 0 ||
793  scram_H(ClientKey, state->hash_type, state->key_length,
794  StoredKey, errstr) < 0)
795  {
796  /* errstr is already filled here */
797  pg_hmac_free(ctx);
798  return false;
799  }
800 
801  if (pg_hmac_init(ctx, StoredKey, state->key_length) < 0 ||
802  pg_hmac_update(ctx,
803  (uint8 *) state->client_first_message_bare,
804  strlen(state->client_first_message_bare)) < 0 ||
805  pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
806  pg_hmac_update(ctx,
807  (uint8 *) state->server_first_message,
808  strlen(state->server_first_message)) < 0 ||
809  pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
810  pg_hmac_update(ctx,
811  (uint8 *) client_final_message_without_proof,
812  strlen(client_final_message_without_proof)) < 0 ||
813  pg_hmac_final(ctx, ClientSignature, state->key_length) < 0)
814  {
815  *errstr = pg_hmac_error(ctx);
816  pg_hmac_free(ctx);
817  return false;
818  }
819 
820  for (i = 0; i < state->key_length; i++)
821  result[i] = ClientKey[i] ^ ClientSignature[i];
822 
823  pg_hmac_free(ctx);
824  return true;
825 }
826 
827 /*
828  * Validate the server signature, received as part of the final exchange
829  * message received from the server. *match tracks if the server signature
830  * matched or not. Returns true if the server signature got verified, and
831  * false for a processing error with *errstr pointing to a message about the
832  * error details.
833  */
834 static bool
836  const char **errstr)
837 {
838  uint8 expected_ServerSignature[SCRAM_MAX_KEY_LEN];
839  uint8 ServerKey[SCRAM_MAX_KEY_LEN];
840  pg_hmac_ctx *ctx;
841 
842  ctx = pg_hmac_create(state->hash_type);
843  if (ctx == NULL)
844  {
845  *errstr = pg_hmac_error(NULL); /* returns OOM */
846  return false;
847  }
848 
849  if (scram_ServerKey(state->SaltedPassword, state->hash_type,
850  state->key_length, ServerKey, errstr) < 0)
851  {
852  /* errstr is filled already */
853  pg_hmac_free(ctx);
854  return false;
855  }
856 
857  /* calculate ServerSignature */
858  if (pg_hmac_init(ctx, ServerKey, state->key_length) < 0 ||
859  pg_hmac_update(ctx,
860  (uint8 *) state->client_first_message_bare,
861  strlen(state->client_first_message_bare)) < 0 ||
862  pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
863  pg_hmac_update(ctx,
864  (uint8 *) state->server_first_message,
865  strlen(state->server_first_message)) < 0 ||
866  pg_hmac_update(ctx, (uint8 *) ",", 1) < 0 ||
867  pg_hmac_update(ctx,
868  (uint8 *) state->client_final_message_without_proof,
869  strlen(state->client_final_message_without_proof)) < 0 ||
870  pg_hmac_final(ctx, expected_ServerSignature,
871  state->key_length) < 0)
872  {
873  *errstr = pg_hmac_error(ctx);
874  pg_hmac_free(ctx);
875  return false;
876  }
877 
878  pg_hmac_free(ctx);
879 
880  /* signature processed, so now check after it */
881  if (memcmp(expected_ServerSignature, state->ServerSignature,
882  state->key_length) != 0)
883  *match = false;
884  else
885  *match = true;
886 
887  return true;
888 }
889 
890 /*
891  * Build a new SCRAM secret.
892  *
893  * On error, returns NULL and sets *errstr to point to a message about the
894  * error details.
895  */
896 char *
897 pg_fe_scram_build_secret(const char *password, const char **errstr)
898 {
899  char *prep_password;
900  pg_saslprep_rc rc;
901  char saltbuf[SCRAM_DEFAULT_SALT_LEN];
902  char *result;
903 
904  /*
905  * Normalize the password with SASLprep. If that doesn't work, because
906  * the password isn't valid UTF-8 or contains prohibited characters, just
907  * proceed with the original password. (See comments at the top of
908  * auth-scram.c.)
909  */
910  rc = pg_saslprep(password, &prep_password);
911  if (rc == SASLPREP_OOM)
912  {
913  *errstr = libpq_gettext("out of memory");
914  return NULL;
915  }
916  if (rc == SASLPREP_SUCCESS)
917  password = (const char *) prep_password;
918 
919  /* Generate a random salt */
921  {
922  *errstr = libpq_gettext("could not generate random salt");
923  free(prep_password);
924  return NULL;
925  }
926 
930  errstr);
931 
932  free(prep_password);
933 
934  return result;
935 }
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:488
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)
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: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)
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
#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:170
int i
Definition: isn.c:73
#define libpq_gettext(x)
Definition: libpq-int.h:882
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: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:161
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:35
int scram_ClientKey(const uint8 *salted_password, pg_cryptohash_type hash_type, int key_length, uint8 *result, const char **errstr)
Definition: scram-common.c:131
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:199
int scram_H(const uint8 *input, pg_cryptohash_type hash_type, int key_length, uint8 *result, const char **errstr)
Definition: scram-common.c:101
#define SCRAM_DEFAULT_ITERATIONS
Definition: scram-common.h:50
#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:374
PQExpBufferData errorMessage
Definition: libpq-int.h:588
bool ssl_in_use
Definition: libpq-int.h:520
Definition: regguts.h:318