gsasl  1.10.0
About: GNU SASL is an implementation of the Simple Authentication and Security Layer (SASL). Development version.
  Fossies Dox: gsasl-1.10.0.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

client.c
Go to the documentation of this file.
1 /* client.c --- SASL SCRAM client side functions.
2  * Copyright (C) 2009-2021 Simon Josefsson
3  *
4  * This file is part of GNU SASL Library.
5  *
6  * GNU SASL Library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public License
8  * as published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * GNU SASL Library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with GNU SASL Library; if not, write to the Free
18  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 /* Get specification. */
28 #include "scram.h"
29 
30 /* Get malloc, free. */
31 #include <stdlib.h>
32 
33 /* Get memcpy, strlen, strchr. */
34 #include <string.h>
35 
36 /* Get bool. */
37 #include <stdbool.h>
38 
39 #include "tokens.h"
40 #include "parser.h"
41 #include "printer.h"
42 #include "gc.h"
43 #include "memxor.h"
44 #include "tools.h"
45 #include "mechtools.h"
46 
47 #define CNONCE_ENTROPY_BYTES 18
48 
50 {
51  bool plus;
53  int step;
54  char *cfmb; /* client first message bare */
56  char *authmessage;
57  char *cbtlsunique;
59  struct scram_client_first cf;
60  struct scram_server_first sf;
61  struct scram_client_final cl;
62  struct scram_server_final sl;
63 };
64 
65 static int
66 scram_start (Gsasl_session * sctx _GL_UNUSED,
67  void **mech_data, bool plus, Gsasl_hash hash)
68 {
69  struct scram_client_state *state;
71  int rc;
72 
73  state = (struct scram_client_state *) calloc (sizeof (*state), 1);
74  if (state == NULL)
75  return GSASL_MALLOC_ERROR;
76 
77  state->plus = plus;
78  state->hash = hash;
79 
81  if (rc != GSASL_OK)
82  {
83  free (state);
84  return rc;
85  }
86 
88  &state->cf.client_nonce, NULL);
89  if (rc != GSASL_OK)
90  {
91  free (state);
92  return rc;
93  }
94 
95  *mech_data = state;
96 
97  return GSASL_OK;
98 }
99 
100 #ifdef USE_SCRAM_SHA1
101 int
102 _gsasl_scram_sha1_client_start (Gsasl_session * sctx, void **mech_data)
103 {
104  return scram_start (sctx, mech_data, false, GSASL_HASH_SHA1);
105 }
106 
107 int
108 _gsasl_scram_sha1_plus_client_start (Gsasl_session * sctx, void **mech_data)
109 {
110  return scram_start (sctx, mech_data, true, GSASL_HASH_SHA1);
111 }
112 #endif
113 
114 #ifdef USE_SCRAM_SHA256
115 int
116 _gsasl_scram_sha256_client_start (Gsasl_session * sctx, void **mech_data)
117 {
118  return scram_start (sctx, mech_data, false, GSASL_HASH_SHA256);
119 }
120 
121 int
122 _gsasl_scram_sha256_plus_client_start (Gsasl_session * sctx, void **mech_data)
123 {
124  return scram_start (sctx, mech_data, true, GSASL_HASH_SHA256);
125 }
126 #endif
127 
128 int
130  void *mech_data,
131  const char *input, size_t input_len,
132  char **output, size_t *output_len)
133 {
134  struct scram_client_state *state = mech_data;
136  int rc;
137 
138  *output = NULL;
139  *output_len = 0;
140 
141  switch (state->step)
142  {
143  case 0:
144  {
145  const char *p;
146 
148  if (state->plus && !p)
149  return GSASL_NO_CB_TLS_UNIQUE;
150  if (p)
151  {
152  rc = gsasl_base64_from (p, strlen (p), &state->cbtlsunique,
153  &state->cbtlsuniquelen);
154  if (rc != GSASL_OK)
155  return rc;
156  }
157 
158  if (state->plus)
159  {
160  state->cf.cbflag = 'p';
161  state->cf.cbname = strdup ("tls-unique");
162  }
163  else
164  {
165  if (state->cbtlsuniquelen > 0)
166  state->cf.cbflag = 'y';
167  else
168  state->cf.cbflag = 'n';
169  }
170 
172  if (!p)
173  return GSASL_NO_AUTHID;
174 
176  &state->cf.username, NULL);
177  if (rc != GSASL_OK)
178  return rc;
179 
181  if (p)
182  state->cf.authzid = strdup (p);
183 
184  rc = scram_print_client_first (&state->cf, output);
185  if (rc == -2)
186  return GSASL_MALLOC_ERROR;
187  else if (rc != 0)
189 
190  *output_len = strlen (*output);
191 
192  /* Point p to client-first-message-bare. */
193  p = strchr (*output, ',');
194  if (!p)
196  p++;
197  p = strchr (p, ',');
198  if (!p)
200  p++;
201 
202  /* Save "client-first-message-bare" for the next step. */
203  state->cfmb = strdup (p);
204  if (!state->cfmb)
205  return GSASL_MALLOC_ERROR;
206 
207  /* Prepare B64("cbind-input") for the next step. */
208  if (state->cf.cbflag == 'p')
209  {
210  size_t len = (p - *output) + state->cbtlsuniquelen;
211  char *cbind_input = malloc (len);
212  if (cbind_input == NULL)
213  return GSASL_MALLOC_ERROR;
214  memcpy (cbind_input, *output, p - *output);
215  memcpy (cbind_input + (p - *output), state->cbtlsunique,
216  state->cbtlsuniquelen);
217  rc = gsasl_base64_to (cbind_input, len, &state->cl.cbind, NULL);
218  free (cbind_input);
219  }
220  else
221  rc = gsasl_base64_to (*output, p - *output, &state->cl.cbind, NULL);
222  if (rc != 0)
223  return rc;
224 
225  /* We are done. */
226  state->step++;
227  return GSASL_NEEDS_MORE;
228  break;
229  }
230 
231  case 1:
232  {
233  if (scram_parse_server_first (input, input_len, &state->sf) < 0)
235 
236  if (strlen (state->sf.nonce) < strlen (state->cf.client_nonce) ||
237  memcmp (state->cf.client_nonce, state->sf.nonce,
238  strlen (state->cf.client_nonce)) != 0)
240 
241  state->cl.nonce = strdup (state->sf.nonce);
242  if (!state->cl.nonce)
243  return GSASL_MALLOC_ERROR;
244 
245  /* Save salt/iter as properties, so that client callback can
246  access them. */
247  {
248  char *str = NULL;
249  int n;
250  n = asprintf (&str, "%zu", state->sf.iter);
251  if (n < 0 || str == NULL)
252  return GSASL_MALLOC_ERROR;
254  free (str);
255  }
256 
257  gsasl_property_set (sctx, GSASL_SCRAM_SALT, state->sf.salt);
258 
259  /* Generate ClientProof. */
260  {
261  char saltedpassword[GSASL_HASH_MAX_SIZE];
262  char clientkey[GSASL_HASH_MAX_SIZE];
263  char serverkey[GSASL_HASH_MAX_SIZE];
264  char storedkey[GSASL_HASH_MAX_SIZE];
265  const char *p;
266 
267  /* Get SaltedPassword. */
268 
270  && (strlen (p) == 2 * gsasl_hash_length (state->hash))
271  && _gsasl_hex_p (p))
272  {
273  _gsasl_hex_decode (p, saltedpassword);
274 
276  saltedpassword,
277  clientkey,
278  serverkey,
279  storedkey);
280  if (rc != 0)
281  return rc;
282  }
283  else if ((p = gsasl_property_get (sctx, GSASL_PASSWORD)) != NULL)
284  {
285  char *salt;
286  size_t saltlen;
287 
288  rc = gsasl_base64_from (state->sf.salt, strlen (state->sf.salt),
289  &salt, &saltlen);
290  if (rc != 0)
291  return rc;
292 
294  p,
295  state->sf.iter,
296  salt, saltlen,
297  saltedpassword,
298  clientkey,
299  serverkey, storedkey);
300  if (rc != 0)
301  return rc;
302 
303  set_saltedpassword (sctx, state->hash, saltedpassword);
304 
305  gsasl_free (salt);
306  }
307  else
308  return GSASL_NO_PASSWORD;
309 
310  /* Get client-final-message-without-proof. */
311  {
312  char *cfmwp;
313  int n;
314 
315  state->cl.proof = strdup ("p");
316  rc = scram_print_client_final (&state->cl, &cfmwp);
317  if (rc != 0)
318  return GSASL_MALLOC_ERROR;
319  free (state->cl.proof);
320 
321  /* Compute AuthMessage */
322  n = asprintf (&state->authmessage, "%s,%.*s,%.*s",
323  state->cfmb,
324  (int) input_len, input,
325  (int) (strlen (cfmwp) - 4), cfmwp);
326  free (cfmwp);
327  if (n <= 0 || !state->authmessage)
328  return GSASL_MALLOC_ERROR;
329  }
330 
331  {
332  char clientsignature[GSASL_HASH_MAX_SIZE];
333  char clientproof[GSASL_HASH_MAX_SIZE];
334 
335  /* ClientSignature := HMAC(StoredKey, AuthMessage) */
336  rc = _gsasl_hmac (state->hash,
337  storedkey,
338  gsasl_hash_length (state->hash),
339  state->authmessage,
340  strlen (state->authmessage), clientsignature);
341  if (rc != 0)
342  return rc;
343 
344  /* ClientProof := ClientKey XOR ClientSignature */
345  memcpy (clientproof, clientkey, gsasl_hash_length (state->hash));
346  memxor (clientproof, clientsignature,
347  gsasl_hash_length (state->hash));
348 
349  rc =
350  gsasl_base64_to (clientproof, gsasl_hash_length (state->hash),
351  &state->cl.proof, NULL);
352  if (rc != 0)
353  return rc;
354  }
355 
356  /* Generate ServerSignature, for comparison in next step. */
357  {
359 
360  /* ServerSignature := HMAC(ServerKey, AuthMessage) */
361  rc = _gsasl_hmac (state->hash,
362  serverkey, gsasl_hash_length (state->hash),
363  state->authmessage,
364  strlen (state->authmessage), serversignature);
365  if (rc != 0)
366  return rc;
367 
369  gsasl_hash_length (state->hash),
370  &state->serversignature, NULL);
371  if (rc != 0)
372  return rc;
373  }
374  }
375 
376  rc = scram_print_client_final (&state->cl, output);
377  if (rc != 0)
378  return GSASL_MALLOC_ERROR;
379 
380  *output_len = strlen (*output);
381 
382  state->step++;
383  return GSASL_NEEDS_MORE;
384  break;
385  }
386 
387  case 2:
388  {
389  if (scram_parse_server_final (input, input_len, &state->sl) < 0)
391 
392  if (strcmp (state->sl.verifier, state->serversignature) != 0)
394 
395  state->step++;
396  return GSASL_OK;
397  break;
398  }
399 
400  default:
401  break;
402  }
403 
404  return res;
405 }
406 
407 void
408 _gsasl_scram_client_finish (Gsasl_session * sctx _GL_UNUSED, void *mech_data)
409 {
410  struct scram_client_state *state = mech_data;
411 
412  if (!state)
413  return;
414 
415  free (state->cfmb);
416  free (state->serversignature);
417  free (state->authmessage);
418  free (state->cbtlsunique);
419  scram_free_client_first (&state->cf);
420  scram_free_server_first (&state->sf);
421  scram_free_client_final (&state->cl);
422  scram_free_server_final (&state->sl);
423 
424  free (state);
425 }
size_t gsasl_hash_length(Gsasl_hash hash)
Definition: crypto.c:72
int gsasl_scram_secrets_from_salted_password(Gsasl_hash hash, const char *salted_password, char *client_key, char *server_key, char *stored_key)
Definition: crypto.c:103
int gsasl_nonce(char *data, size_t datalen)
Definition: crypto.c:38
int gsasl_scram_secrets_from_password(Gsasl_hash hash, const char *password, unsigned int iteration_count, const char *salt, size_t saltlen, char *salted_password, char *client_key, char *server_key, char *stored_key)
Definition: crypto.c:155
int asprintf(char **resultp, const char *format,...)
Definition: asprintf.c:30
#define NULL
Definition: stddef.in.h:72
const char * gsasl_property_get(Gsasl_session *sctx, Gsasl_property prop)
Definition: property.c:263
@ GSASL_ALLOW_UNASSIGNED
Definition: gsasl.h:272
void gsasl_property_set(Gsasl_session *sctx, Gsasl_property prop, const char *data)
Definition: property.c:158
int gsasl_saslprep(const char *in, Gsasl_saslprep_flags flags, char **out, int *stringpreprc)
Gsasl_hash
Definition: gsasl.h:471
@ GSASL_HASH_SHA1
Definition: gsasl.h:473
@ GSASL_HASH_SHA256
Definition: gsasl.h:474
@ GSASL_OK
Definition: gsasl.h:171
@ GSASL_AUTHENTICATION_ERROR
Definition: gsasl.h:180
@ GSASL_NEEDS_MORE
Definition: gsasl.h:172
@ GSASL_MALLOC_ERROR
Definition: gsasl.h:175
@ GSASL_NO_PASSWORD
Definition: gsasl.h:188
@ GSASL_MECHANISM_CALLED_TOO_MANY_TIMES
Definition: gsasl.h:174
@ GSASL_NO_AUTHID
Definition: gsasl.h:186
@ GSASL_MECHANISM_PARSE_ERROR
Definition: gsasl.h:179
@ GSASL_NO_CB_TLS_UNIQUE
Definition: gsasl.h:193
@ GSASL_HASH_MAX_SIZE
Definition: gsasl.h:482
@ GSASL_AUTHZID
Definition: gsasl.h:336
@ GSASL_SCRAM_SALT
Definition: gsasl.h:350
@ GSASL_CB_TLS_UNIQUE
Definition: gsasl.h:354
@ GSASL_SCRAM_SALTED_PASSWORD
Definition: gsasl.h:351
@ GSASL_PASSWORD
Definition: gsasl.h:337
@ GSASL_SCRAM_ITER
Definition: gsasl.h:349
@ GSASL_AUTHID
Definition: gsasl.h:335
int rc
Definition: error.c:42
int res
Definition: mbrtowc-impl.h:45
const char * p
Definition: mbrtowc-impl.h:42
char buf[4]
Definition: mbrtowc-impl.h:39
void _gsasl_hex_decode(const char *hexstr, char *bin)
Definition: mechtools.c:262
int _gsasl_hmac(Gsasl_hash hash, const char *key, size_t keylen, const char *in, size_t inlen, char *outhash)
Definition: mechtools.c:335
signed char _gsasl_hex_p(const char *hexstr)
Definition: mechtools.c:274
void * memxor(void *dest, const void *src, size_t n)
Definition: memxor.c:25
static int scram_start(Gsasl_session *sctx _GL_UNUSED, void **mech_data, signed char plus, Gsasl_hash hash)
Definition: client.c:66
#define CNONCE_ENTROPY_BYTES
Definition: client.c:47
int _gsasl_scram_client_step(Gsasl_session *sctx, void *mech_data, const char *input, size_t input_len, char **output, size_t *output_len)
Definition: client.c:129
void _gsasl_scram_client_finish(Gsasl_session *sctx _GL_UNUSED, void *mech_data)
Definition: client.c:408
int scram_parse_server_final(const char *str, size_t len, struct scram_server_final *sl)
Definition: parser.c:457
int scram_parse_server_first(const char *str, size_t len, struct scram_server_first *sf)
Definition: parser.c:220
int scram_print_client_first(struct scram_client_first *cf, char **out)
Definition: printer.c:79
int scram_print_client_final(struct scram_client_final *cl, char **out)
Definition: printer.c:144
int gsasl_base64_from(const char *in, size_t inlen, char **out, size_t *outlen)
Definition: base64.c:74
int gsasl_base64_to(const char *in, size_t inlen, char **out, size_t *outlen)
Definition: base64.c:44
void gsasl_free(void *ptr)
Definition: free.c:41
char * strdup(const char *s)
Definition: strdup.c:39
char * proof
Definition: tokens.h:49
char * nonce
Definition: tokens.h:48
char * cbind
Definition: tokens.h:47
char * cbname
Definition: tokens.h:32
char * username
Definition: tokens.h:34
char * client_nonce
Definition: tokens.h:35
char * authzid
Definition: tokens.h:33
struct scram_client_first cf
Definition: client.c:59
struct scram_server_final sl
Definition: client.c:62
struct scram_client_final cl
Definition: client.c:61
size_t cbtlsuniquelen
Definition: client.c:58
Gsasl_hash hash
Definition: client.c:52
struct scram_server_first sf
Definition: client.c:60
char * authmessage
Definition: client.c:56
char * serversignature
Definition: client.c:55
signed char plus
Definition: client.c:51
char * cbtlsunique
Definition: client.c:57
char * verifier
Definition: tokens.h:54
char * nonce
Definition: tokens.h:40
void scram_free_server_first(struct scram_server_first *sf)
Definition: tokens.c:44
void scram_free_client_first(struct scram_client_first *cf)
Definition: tokens.c:33
void scram_free_server_final(struct scram_server_final *sl)
Definition: tokens.c:63
void scram_free_client_final(struct scram_client_final *cl)
Definition: tokens.c:53
void set_saltedpassword(Gsasl_session *sctx, Gsasl_hash hash, const char *hashbuf)
Definition: tools.c:31