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)  

server.c
Go to the documentation of this file.
1 /* server.c --- SASL CRAM-MD5 server 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, strtoul. */
31 #include <stdlib.h>
32 
33 /* Get ULONG_MAX. */
34 #include <limits.h>
35 
36 /* Get memcpy, strdup, strlen. */
37 #include <string.h>
38 
39 /* Get MAX. */
40 #include "minmax.h"
41 
42 #include "tokens.h"
43 #include "parser.h"
44 #include "printer.h"
45 #include "gc.h"
46 #include "memxor.h"
47 #include "tools.h"
48 #include "mechtools.h"
49 
50 #define DEFAULT_SALT_BYTES 12
51 #define SNONCE_ENTROPY_BYTES 18
52 
54 {
55  bool plus;
57  int step;
58  char *cbind;
59  char *gs2header; /* copy of client first gs2-header */
60  char *cfmb_str; /* copy of client first message bare */
61  char *sf_str; /* copy of server first message */
62  char *snonce;
63  char *clientproof;
66  char *authmessage;
67  char *cbtlsunique;
69  struct scram_client_first cf;
70  struct scram_server_first sf;
71  struct scram_client_final cl;
72  struct scram_server_final sl;
73 };
74 
75 static int
76 scram_start (Gsasl_session * sctx _GL_UNUSED, void **mech_data,
77  bool plus, Gsasl_hash hash)
78 {
79  struct scram_server_state *state;
81  int rc;
82 
83  state = (struct scram_server_state *) calloc (sizeof (*state), 1);
84  if (state == NULL)
85  return GSASL_MALLOC_ERROR;
86 
87  state->plus = plus;
88  state->hash = hash;
89 
91  if (rc != GSASL_OK)
92  goto end;
93 
95  if (rc != GSASL_OK)
96  goto end;
97 
99  if (rc != GSASL_OK)
100  goto end;
101 
103  if (rc != GSASL_OK)
104  goto end;
105 
106  *mech_data = state;
107 
108  return GSASL_OK;
109 
110 end:
111  free (state->sf.salt);
112  free (state->snonce);
113  free (state);
114  return rc;
115 }
116 
117 #ifdef USE_SCRAM_SHA1
118 int
119 _gsasl_scram_sha1_server_start (Gsasl_session * sctx, void **mech_data)
120 {
121  return scram_start (sctx, mech_data, false, GSASL_HASH_SHA1);
122 }
123 
124 int
125 _gsasl_scram_sha1_plus_server_start (Gsasl_session * sctx, void **mech_data)
126 {
127  return scram_start (sctx, mech_data, true, GSASL_HASH_SHA1);
128 }
129 #endif
130 
131 #ifdef USE_SCRAM_SHA256
132 int
133 _gsasl_scram_sha256_server_start (Gsasl_session * sctx, void **mech_data)
134 {
135  return scram_start (sctx, mech_data, false, GSASL_HASH_SHA256);
136 }
137 
138 int
139 _gsasl_scram_sha256_plus_server_start (Gsasl_session * sctx, void **mech_data)
140 {
141  return scram_start (sctx, mech_data, true, GSASL_HASH_SHA256);
142 }
143 #endif
144 
145 static int
147  const char *b64, char *buf)
148 {
149  char *bin;
150  size_t binlen;
151  int rc;
152 
153  rc = gsasl_base64_from (b64, strlen (b64), &bin, &binlen);
154  if (rc != GSASL_OK)
155  return rc;
156 
157  if (binlen != gsasl_hash_length (state->hash))
158  {
159  free (bin);
161  }
162 
163  memcpy (buf, bin, binlen);
164 
165  free (bin);
166 
167  return GSASL_OK;
168 }
169 
170 int
172  void *mech_data,
173  const char *input,
174  size_t input_len, char **output, size_t *output_len)
175 {
176  struct scram_server_state *state = mech_data;
178  int rc;
179 
180  *output = NULL;
181  *output_len = 0;
182 
183  switch (state->step)
184  {
185  case 0:
186  {
187  if (input_len == 0)
188  return GSASL_NEEDS_MORE;
189 
190  {
191  const char *p;
192 
194  if (state->plus && !p)
195  return GSASL_NO_CB_TLS_UNIQUE;
196  if (p)
197  {
198  rc = gsasl_base64_from (p, strlen (p), &state->cbtlsunique,
199  &state->cbtlsuniquelen);
200  if (rc != GSASL_OK)
201  return rc;
202  }
203  }
204 
205  if (scram_parse_client_first (input, input_len, &state->cf) < 0)
207 
208  /* In PLUS server mode, we require use of channel bindings. */
209  if (state->plus && state->cf.cbflag != 'p')
211 
212  /* In non-PLUS mode, but where have channel bindings data (and
213  thus advertised PLUS) we reject a client 'y' cbflag. */
214  if (!state->plus
215  && state->cbtlsuniquelen > 0 && state->cf.cbflag == 'y')
217 
218  /* Check that username doesn't fail SASLprep. */
219  {
220  char *tmp;
222  &tmp, NULL);
223  if (rc != GSASL_OK || *tmp == '\0')
225  gsasl_free (tmp);
226  }
227 
228  {
229  const char *p;
230 
231  /* Save "gs2-header" and "message-bare" for next step. */
232  p = memchr (input, ',', input_len);
233  if (!p)
235  p++;
236  p = memchr (p, ',', input_len - (p - input));
237  if (!p)
239  p++;
240 
241  state->gs2header = malloc (p - input + 1);
242  if (!state->gs2header)
243  return GSASL_MALLOC_ERROR;
244  memcpy (state->gs2header, input, p - input);
245  state->gs2header[p - input] = '\0';
246 
247  state->cfmb_str = malloc (input_len - (p - input) + 1);
248  if (!state->cfmb_str)
249  return GSASL_MALLOC_ERROR;
250  memcpy (state->cfmb_str, p, input_len - (p - input));
251  state->cfmb_str[input_len - (p - input)] = '\0';
252  }
253 
254  /* Create new nonce. */
255  {
256  size_t cnlen = strlen (state->cf.client_nonce);
257  size_t snlen = strlen (state->snonce);
258 
259  state->sf.nonce = malloc (cnlen + snlen + 1);
260  if (!state->sf.nonce)
261  return GSASL_MALLOC_ERROR;
262 
263  memcpy (state->sf.nonce, state->cf.client_nonce, cnlen);
264  memcpy (state->sf.nonce + cnlen, state->snonce, snlen);
265  state->sf.nonce[cnlen + snlen] = '\0';
266  }
267 
268  gsasl_property_set (sctx, GSASL_AUTHID, state->cf.username);
269  gsasl_property_set (sctx, GSASL_AUTHZID, state->cf.authzid);
270 
271  {
272  const char *p = gsasl_property_get (sctx, GSASL_SCRAM_ITER);
273 
274  if (p)
275  state->sf.iter = strtoul (p, NULL, 10);
276  if (!p || state->sf.iter == 0 || state->sf.iter == ULONG_MAX)
277  state->sf.iter = 4096;
278 
279  /* Save salt/iter as properties, so that client callback can
280  access them. */
281  {
282  char *str = NULL;
283  int n;
284  n = asprintf (&str, "%zu", state->sf.iter);
285  if (n < 0 || str == NULL)
286  return GSASL_MALLOC_ERROR;
288  free (str);
289  }
290  }
291 
292  {
293  const char *p = gsasl_property_get (sctx, GSASL_SCRAM_SALT);
294  if (p)
295  {
296  free (state->sf.salt);
297  state->sf.salt = strdup (p);
298  }
299  else
300  gsasl_property_set (sctx, GSASL_SCRAM_SALT, state->sf.salt);
301  }
302 
303  rc = scram_print_server_first (&state->sf, &state->sf_str);
304  if (rc != 0)
305  return GSASL_MALLOC_ERROR;
306 
307  *output = strdup (state->sf_str);
308  if (!*output)
309  return GSASL_MALLOC_ERROR;
310  *output_len = strlen (*output);
311 
312  state->step++;
313  return GSASL_NEEDS_MORE;
314  break;
315  }
316 
317  case 1:
318  {
319  if (scram_parse_client_final (input, input_len, &state->cl) < 0)
321 
322  if (strcmp (state->cl.nonce, state->sf.nonce) != 0)
324 
325  /* Base64 decode the c= field and check that it matches
326  client-first. Also check channel binding data. */
327  {
328  size_t len;
329 
330  rc = gsasl_base64_from (state->cl.cbind, strlen (state->cl.cbind),
331  &state->cbind, &len);
332  if (rc != 0)
333  return rc;
334 
335  if (state->cf.cbflag == 'p')
336  {
337  if (len < strlen (state->gs2header))
339 
340  if (memcmp (state->cbind, state->gs2header,
341  strlen (state->gs2header)) != 0)
343 
344  if (len - strlen (state->gs2header) != state->cbtlsuniquelen)
346 
347  if (memcmp (state->cbind + strlen (state->gs2header),
348  state->cbtlsunique, state->cbtlsuniquelen) != 0)
350  }
351  else
352  {
353  if (len != strlen (state->gs2header))
355 
356  if (memcmp (state->cbind, state->gs2header, len) != 0)
358  }
359  }
360 
361  /* Base64 decode client proof and check that length matches
362  hash size. */
363  {
364  size_t len;
365 
366  rc = gsasl_base64_from (state->cl.proof, strlen (state->cl.proof),
367  &state->clientproof, &len);
368  if (rc != 0)
369  return rc;
370  if (gsasl_hash_length (state->hash) != len)
372  }
373  {
374  const char *p, *q;
375 
376  /* Get StoredKey and ServerKey */
378  && (q = gsasl_property_get (sctx, GSASL_SCRAM_STOREDKEY)))
379  {
380  rc = extract_serverkey (state, p, state->serverkey);
381  if (rc != GSASL_OK)
382  return rc;
383  rc = extract_serverkey (state, q, state->storedkey);
384  if (rc != GSASL_OK)
385  return rc;
386  }
387  else if ((p = gsasl_property_get (sctx, GSASL_PASSWORD)))
388  {
389  char *salt;
390  size_t saltlen;
391  char saltedpassword[GSASL_HASH_MAX_SIZE];
392  char clientkey[GSASL_HASH_MAX_SIZE];
393  char *b64str;
394 
395  rc = gsasl_base64_from (state->sf.salt, strlen (state->sf.salt),
396  &salt, &saltlen);
397  if (rc != GSASL_OK)
398  return rc;
399 
401  p,
402  state->sf.iter,
403  salt, saltlen,
404  saltedpassword,
405  clientkey,
406  state->serverkey,
407  state->storedkey);
408  if (rc != GSASL_OK)
409  return rc;
410 
411  set_saltedpassword (sctx, state->hash, saltedpassword);
412 
413  rc = gsasl_base64_to (state->serverkey,
414  gsasl_hash_length (state->hash),
415  &b64str, NULL);
416  if (rc != 0)
417  return rc;
419  free (b64str);
420 
421 
422  rc = gsasl_base64_to (state->storedkey,
423  gsasl_hash_length (state->hash),
424  &b64str, NULL);
425  if (rc != 0)
426  return rc;
428  free (b64str);
429 
430  gsasl_free (salt);
431  }
432  else
433  return GSASL_NO_PASSWORD;
434 
435  /* Compute AuthMessage */
436  {
437  size_t len;
438  int n;
439 
440  /* Get client-final-message-without-proof. */
441  p = memmem (input, input_len, ",p=", 3);
442  if (!p)
444  len = p - input;
445 
446  n = asprintf (&state->authmessage, "%s,%.*s,%.*s",
447  state->cfmb_str,
448  (int) strlen (state->sf_str), state->sf_str,
449  (int) len, input);
450  if (n <= 0 || !state->authmessage)
451  return GSASL_MALLOC_ERROR;
452  }
453 
454  /* Check client proof. */
455  {
456  char clientsignature[GSASL_HASH_MAX_SIZE];
457  char maybe_storedkey[GSASL_HASH_MAX_SIZE];
458 
459  /* ClientSignature := HMAC(StoredKey, AuthMessage) */
460  rc = _gsasl_hmac (state->hash,
461  state->storedkey,
462  gsasl_hash_length (state->hash),
463  state->authmessage, strlen (state->authmessage),
464  clientsignature);
465  if (rc != 0)
466  return rc;
467 
468  /* ClientKey := ClientProof XOR ClientSignature */
469  memxor (clientsignature, state->clientproof,
470  gsasl_hash_length (state->hash));
471 
472  rc = _gsasl_hash (state->hash, clientsignature,
473  gsasl_hash_length (state->hash),
474  maybe_storedkey);
475  if (rc != 0)
476  return rc;
477 
478  rc = memcmp (state->storedkey, maybe_storedkey,
479  gsasl_hash_length (state->hash));
480  if (rc != 0)
482  }
483 
484  /* Generate server verifier. */
485  {
486  char serversignature[GSASL_HASH_MAX_SIZE];
487 
488  /* ServerSignature := HMAC(ServerKey, AuthMessage) */
489  rc = _gsasl_hmac (state->hash, state->serverkey,
490  gsasl_hash_length (state->hash),
491  state->authmessage,
492  strlen (state->authmessage), serversignature);
493  if (rc != 0)
494  return rc;
495 
496  rc = gsasl_base64_to (serversignature,
497  gsasl_hash_length (state->hash),
498  &state->sl.verifier, NULL);
499  if (rc != 0)
500  return rc;
501  }
502  }
503 
504  rc = scram_print_server_final (&state->sl, output);
505  if (rc != 0)
506  return GSASL_MALLOC_ERROR;
507  *output_len = strlen (*output);
508 
509  state->step++;
510  return GSASL_OK;
511  break;
512  }
513 
514  default:
515  break;
516  }
517 
518  return res;
519 }
520 
521 void
522 _gsasl_scram_server_finish (Gsasl_session * sctx _GL_UNUSED, void *mech_data)
523 {
524  struct scram_server_state *state = mech_data;
525 
526  if (!state)
527  return;
528 
529  free (state->cbind);
530  free (state->gs2header);
531  free (state->cfmb_str);
532  free (state->sf_str);
533  free (state->snonce);
534  free (state->clientproof);
535  free (state->authmessage);
536  free (state->cbtlsunique);
537  scram_free_client_first (&state->cf);
538  scram_free_server_first (&state->sf);
539  scram_free_client_final (&state->cl);
540  scram_free_server_final (&state->sl);
541 
542  free (state);
543 }
size_t gsasl_hash_length(Gsasl_hash hash)
Definition: crypto.c:72
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
static const signed char b64[0x100]
Definition: base64.c:252
void * memchr(void const *s, int c_in, size_t n)
Definition: memchr.c:59
#define MAX(a, b)
Definition: minmax.h:52
#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_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_SCRAM_STOREDKEY
Definition: gsasl.h:353
@ GSASL_AUTHZID
Definition: gsasl.h:336
@ GSASL_SCRAM_SALT
Definition: gsasl.h:350
@ GSASL_CB_TLS_UNIQUE
Definition: gsasl.h:354
@ GSASL_PASSWORD
Definition: gsasl.h:337
@ GSASL_SCRAM_ITER
Definition: gsasl.h:349
@ GSASL_AUTHID
Definition: gsasl.h:335
@ GSASL_SCRAM_SERVERKEY
Definition: gsasl.h:352
static gss_OID_desc tmp
Definition: gss-extra.c:38
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
int _gsasl_hmac(Gsasl_hash hash, const char *key, size_t keylen, const char *in, size_t inlen, char *outhash)
Definition: mechtools.c:335
int _gsasl_hash(Gsasl_hash hash, const char *in, size_t inlen, char *outhash)
Definition: mechtools.c:302
void * memmem(const void *haystack_start, size_t haystack_len, const void *needle_start, size_t needle_len)
Definition: memmem.c:35
void * memxor(void *dest, const void *src, size_t n)
Definition: memxor.c:25
int scram_parse_client_final(const char *str, size_t len, struct scram_client_final *cl)
Definition: parser.c:329
int scram_parse_client_first(const char *str, size_t len, struct scram_client_first *cf)
Definition: parser.c:78
int scram_print_server_final(struct scram_server_final *sl, char **out)
Definition: printer.c:164
int scram_print_server_first(struct scram_server_first *sf, char **out)
Definition: printer.c:123
void _gsasl_scram_server_finish(Gsasl_session *sctx _GL_UNUSED, void *mech_data)
Definition: server.c:522
static int scram_start(Gsasl_session *sctx _GL_UNUSED, void **mech_data, signed char plus, Gsasl_hash hash)
Definition: server.c:76
#define DEFAULT_SALT_BYTES
Definition: server.c:50
static int extract_serverkey(struct scram_server_state *state, const char *b64, char *buf)
Definition: server.c:146
#define SNONCE_ENTROPY_BYTES
Definition: server.c:51
int _gsasl_scram_server_step(Gsasl_session *sctx, void *mech_data, const char *input, size_t input_len, char **output, size_t *output_len)
Definition: server.c:171
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 * username
Definition: tokens.h:34
char * client_nonce
Definition: tokens.h:35
char * authzid
Definition: tokens.h:33
char * verifier
Definition: tokens.h:54
char * nonce
Definition: tokens.h:40
char * gs2header
Definition: server.c:59
char * cfmb_str
Definition: server.c:60
char serverkey[GSASL_HASH_MAX_SIZE]
Definition: server.c:65
Gsasl_hash hash
Definition: server.c:56
size_t cbtlsuniquelen
Definition: server.c:68
char storedkey[GSASL_HASH_MAX_SIZE]
Definition: server.c:64
struct scram_server_final sl
Definition: server.c:72
char * cbind
Definition: server.c:58
char * snonce
Definition: server.c:62
struct scram_server_first sf
Definition: server.c:70
char * cbtlsunique
Definition: server.c:67
struct scram_client_first cf
Definition: server.c:69
char * authmessage
Definition: server.c:66
char * sf_str
Definition: server.c:61
signed char plus
Definition: server.c:55
char * clientproof
Definition: server.c:63
struct scram_client_final cl
Definition: server.c:71
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