1/* server.c --- SASL CRAM-MD5 server side functions.
2 * Copyright (C) 2009-2012 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
48#define DEFAULT_SALT_BYTES 12
49#define SNONCE_ENTROPY_BYTES 18
50
51struct scram_server_state
52{
53 int plus;
54 int step;
55 char *cbind;
56 char *gs2header; /* copy of client first gs2-header */
57 char *cfmb_str; /* copy of client first message bare */
58 char *sf_str; /* copy of server first message */
59 char *snonce;
60 char *clientproof;
61 char *storedkey;
62 char *serverkey;
63 char *authmessage;
64 char *cbtlsunique;
65 size_t cbtlsuniquelen;
66 struct scram_client_first cf;
67 struct scram_server_first sf;
68 struct scram_client_final cl;
69 struct scram_server_final sl;
70};
71
72static int
73scram_start (Gsasl_session * sctx, void **mech_data, int plus)
74{
75 struct scram_server_state *state;
76 char buf[MAX (SNONCE_ENTROPY_BYTES, DEFAULT_SALT_BYTES)];
77 const char *p;
78 int rc;
79
80 state = (struct scram_server_state *) calloc (sizeof (*state), 1);
81 if (state == NULL)
82 return GSASL_MALLOC_ERROR;
83
84 state->plus = plus;
85
86 rc = gsasl_nonce (buf, SNONCE_ENTROPY_BYTES);
87 if (rc != GSASL_OK)
88 goto end;
89
90 rc = gsasl_base64_to (buf, SNONCE_ENTROPY_BYTES, &state->snonce, NULL);
91 if (rc != GSASL_OK)
92 goto end;
93
94 rc = gsasl_nonce (buf, DEFAULT_SALT_BYTES);
95 if (rc != GSASL_OK)
96 goto end;
97
98 rc = gsasl_base64_to (buf, DEFAULT_SALT_BYTES, &state->sf.salt, NULL);
99 if (rc != GSASL_OK)
100 goto end;
101
102 p = gsasl_property_get (sctx, GSASL_CB_TLS_UNIQUE);
103 if (plus && !p)
104 {
105 rc = GSASL_NO_CB_TLS_UNIQUE;
106 goto end;
107 }
108 if (p)
109 {
110 rc = gsasl_base64_from (p, strlen (p), &state->cbtlsunique,
111 &state->cbtlsuniquelen);
112 if (rc != GSASL_OK)
113 goto end;
114 }
115
116 *mech_data = state;
117
118 return GSASL_OK;
119
120end:
121 free (state->sf.salt);
122 free (state->snonce);
123 free (state);
124 return rc;
125}
126
127int
128_gsasl_scram_sha1_server_start (Gsasl_session * sctx, void **mech_data)
129{
130 return scram_start (sctx, mech_data, 0);
131}
132
133int
134_gsasl_scram_sha1_plus_server_start (Gsasl_session * sctx, void **mech_data)
135{
136 return scram_start (sctx, mech_data, 1);
137}
138
139int
140_gsasl_scram_sha1_server_step (Gsasl_session * sctx,
141 void *mech_data,
142 const char *input,
143 size_t input_len,
144 char **output, size_t * output_len)
145{
146 struct scram_server_state *state = mech_data;
147 int res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
148 int rc;
149
150 *output = NULL;
151 *output_len = 0;
152
153 switch (state->step)
154 {
155 case 0:
156 {
157 if (input_len == 0)
158 return GSASL_NEEDS_MORE;
159
160 if (scram_parse_client_first (input, input_len, &state->cf) < 0)
161 return GSASL_MECHANISM_PARSE_ERROR;
162
163 /* In PLUS server mode, we require use of channel bindings. */
164 if (state->plus && state->cf.cbflag != 'p')
165 return GSASL_AUTHENTICATION_ERROR;
166
167 /* In non-PLUS mode, but where have channel bindings data (and
168 thus advertised PLUS) we reject a client 'y' cbflag. */
169 if (!state->plus
170 && state->cbtlsuniquelen > 0 && state->cf.cbflag == 'y')
171 return GSASL_AUTHENTICATION_ERROR;
172
173 /* Check that username doesn't fail SASLprep. */
174 {
175 char *tmp;
176 rc = gsasl_saslprep (state->cf.username, GSASL_ALLOW_UNASSIGNED,
177 &tmp, NULL);
178 if (rc != GSASL_OK || *tmp == '\0')
179 return GSASL_AUTHENTICATION_ERROR;
180 gsasl_free (tmp);
181 }
182
183 {
184 const char *p;
185
186 /* Save "gs2-header" and "message-bare" for next step. */
187 p = memchr (input, ',', input_len);
188 if (!p)
189 return GSASL_AUTHENTICATION_ERROR;
190 p++;
191 p = memchr (p, ',', input_len - (p - input));
192 if (!p)
193 return GSASL_AUTHENTICATION_ERROR;
194 p++;
195
196 state->gs2header = malloc (p - input + 1);
197 if (!state->gs2header)
198 return GSASL_MALLOC_ERROR;
199 memcpy (state->gs2header, input, p - input);
200 state->gs2header[p - input] = '\0';
201
202 state->cfmb_str = malloc (input_len - (p - input) + 1);
203 if (!state->cfmb_str)
204 return GSASL_MALLOC_ERROR;
205 memcpy (state->cfmb_str, p, input_len - (p - input));
206 state->cfmb_str[input_len - (p - input)] = '\0';
207 }
208
209 /* Create new nonce. */
210 {
211 size_t cnlen = strlen (state->cf.client_nonce);
212
213 state->sf.nonce = malloc (cnlen + SNONCE_ENTROPY_BYTES + 1);
214 if (!state->sf.nonce)
215 return GSASL_MALLOC_ERROR;
216
217 memcpy (state->sf.nonce, state->cf.client_nonce, cnlen);
218 memcpy (state->sf.nonce + cnlen, state->snonce,
219 SNONCE_ENTROPY_BYTES);
220 state->sf.nonce[cnlen + SNONCE_ENTROPY_BYTES] = '\0';
221 }
222
223 gsasl_property_set (sctx, GSASL_AUTHID, state->cf.username);
224 gsasl_property_set (sctx, GSASL_AUTHZID, state->cf.authzid);
225
226 {
227 const char *p = gsasl_property_get (sctx, GSASL_SCRAM_ITER);
228 if (p)
229 state->sf.iter = strtoul (p, NULL, 10);
230 if (!p || state->sf.iter == 0 || state->sf.iter == ULONG_MAX)
231 state->sf.iter = 4096;
232 }
233
234 {
235 const char *p = gsasl_property_get (sctx, GSASL_SCRAM_SALT);
236 if (p)
237 {
238 free (state->sf.salt);
239 state->sf.salt = strdup (p);
240 }
241 }
242
243 rc = scram_print_server_first (&state->sf, &state->sf_str);
244 if (rc != 0)
245 return GSASL_MALLOC_ERROR;
246
247 *output = strdup (state->sf_str);
248 if (!*output)
249 return GSASL_MALLOC_ERROR;
250 *output_len = strlen (*output);
251
252 state->step++;
253 return GSASL_NEEDS_MORE;
254 break;
255 }
256
257 case 1:
258 {
259 if (scram_parse_client_final (input, input_len, &state->cl) < 0)
260 return GSASL_MECHANISM_PARSE_ERROR;
261
262 if (strcmp (state->cl.nonce, state->sf.nonce) != 0)
263 return GSASL_AUTHENTICATION_ERROR;
264
265 /* Base64 decode the c= field and check that it matches
266 client-first. Also check channel binding data. */
267 {
268 size_t len;
269
270 rc = gsasl_base64_from (state->cl.cbind, strlen (state->cl.cbind),
271 &state->cbind, &len);
272 if (rc != 0)
273 return rc;
274
275 if (state->cf.cbflag == 'p')
276 {
277 if (len < strlen (state->gs2header))
278 return GSASL_AUTHENTICATION_ERROR;
279
280 if (memcmp (state->cbind, state->gs2header,
281 strlen (state->gs2header)) != 0)
282 return GSASL_AUTHENTICATION_ERROR;
283
284 if (len - strlen (state->gs2header) != state->cbtlsuniquelen)
285 return GSASL_AUTHENTICATION_ERROR;
286
287 if (memcmp (state->cbind + strlen (state->gs2header),
288 state->cbtlsunique, state->cbtlsuniquelen) != 0)
289 return GSASL_AUTHENTICATION_ERROR;
290 }
291 else
292 {
293 if (len != strlen (state->gs2header))
294 return GSASL_AUTHENTICATION_ERROR;
295
296 if (memcmp (state->cbind, state->gs2header, len) != 0)
297 return GSASL_AUTHENTICATION_ERROR;
298 }
299 }
300
301 /* Base64 decode client proof and check that length matches
302 SHA-1 size. */
303 {
304 size_t len;
305
306 rc = gsasl_base64_from (state->cl.proof, strlen (state->cl.proof),
307 &state->clientproof, &len);
308 if (rc != 0)
309 return rc;
310 if (len != 20)
311 return GSASL_MECHANISM_PARSE_ERROR;
312 }
313
314 {
315 const char *p;
316
317 /* Get StoredKey and ServerKey */
318 if ((p = gsasl_property_get (sctx, GSASL_PASSWORD)))
319 {
320 Gc_rc err;
321 char *salt;
322 size_t saltlen;
323 char saltedpassword[20];
324 char *clientkey;
325 char *preppasswd;
326
327 rc = gsasl_saslprep (p, 0, &preppasswd, NULL);
328 if (rc != GSASL_OK)
329 return rc;
330
331 rc = gsasl_base64_from (state->sf.salt, strlen (state->sf.salt),
332 &salt, &saltlen);
333 if (rc != 0)
334 {
335 gsasl_free (preppasswd);
336 return rc;
337 }
338
339 /* SaltedPassword := Hi(password, salt) */
340 err = gc_pbkdf2_sha1 (preppasswd, strlen (preppasswd),
341 salt, saltlen,
342 state->sf.iter, saltedpassword, 20);
343 gsasl_free (preppasswd);
344 gsasl_free (salt);
345 if (err != GC_OK)
346 return GSASL_MALLOC_ERROR;
347
348 /* ClientKey := HMAC(SaltedPassword, "Client Key") */
349#define CLIENT_KEY "Client Key"
350 rc = gsasl_hmac_sha1 (saltedpassword, 20,
351 CLIENT_KEY, strlen (CLIENT_KEY),
352 &clientkey);
353 if (rc != 0)
354 return rc;
355
356 /* StoredKey := H(ClientKey) */
357 rc = gsasl_sha1 (clientkey, 20, &state->storedkey);
358 free (clientkey);
359 if (rc != 0)
360 return rc;
361
362 /* ServerKey := HMAC(SaltedPassword, "Server Key") */
363#define SERVER_KEY "Server Key"
364 rc = gsasl_hmac_sha1 (saltedpassword, 20,
365 SERVER_KEY, strlen (SERVER_KEY),
366 &state->serverkey);
367 if (rc != 0)
368 return rc;
369 }
370 else
371 return GSASL_NO_PASSWORD;
372
373 /* Compute AuthMessage */
374 {
375 size_t len;
376 int n;
377
378 /* Get client-final-message-without-proof. */
379 p = memmem (input, input_len, ",p=", 3);
380 if (!p)
381 return GSASL_MECHANISM_PARSE_ERROR;
382 len = p - input;
383
384 n = asprintf (&state->authmessage, "%s,%.*s,%.*s",
385 state->cfmb_str,
386 (int) strlen (state->sf_str), state->sf_str,
387 (int) len, input);
388 if (n <= 0 || !state->authmessage)
389 return GSASL_MALLOC_ERROR;
390 }
391
392 /* Check client proof. */
393 {
394 char *clientsignature;
395 char *maybe_storedkey;
396
397 /* ClientSignature := HMAC(StoredKey, AuthMessage) */
398 rc = gsasl_hmac_sha1 (state->storedkey, 20,
399 state->authmessage,
400 strlen (state->authmessage),
401 &clientsignature);
402 if (rc != 0)
403 return rc;
404
405 /* ClientKey := ClientProof XOR ClientSignature */
406 memxor (clientsignature, state->clientproof, 20);
407
408 rc = gsasl_sha1 (clientsignature, 20, &maybe_storedkey);
409 free (clientsignature);
410 if (rc != 0)
411 return rc;
412
413 rc = memcmp (state->storedkey, maybe_storedkey, 20);
414 free (maybe_storedkey);
415 if (rc != 0)
416 return GSASL_AUTHENTICATION_ERROR;
417 }
418
419 /* Generate server verifier. */
420 {
421 char *serversignature;
422
423 /* ServerSignature := HMAC(ServerKey, AuthMessage) */
424 rc = gsasl_hmac_sha1 (state->serverkey, 20,
425 state->authmessage,
426 strlen (state->authmessage),
427 &serversignature);
428 if (rc != 0)
429 return rc;
430
431 rc = gsasl_base64_to (serversignature, 20,
432 &state->sl.verifier, NULL);
433 free (serversignature);
434 if (rc != 0)
435 return rc;
436 }
437 }
438
439 rc = scram_print_server_final (&state->sl, output);
440 if (rc != 0)
441 return GSASL_MALLOC_ERROR;
442 *output_len = strlen (*output);
443
444 state->step++;
445 return GSASL_OK;
446 break;
447 }
448
449 default:
450 break;
451 }
452
453 return res;
454}
455
456void
457_gsasl_scram_sha1_server_finish (Gsasl_session * sctx, void *mech_data)
458{
459 struct scram_server_state *state = mech_data;
460
461 if (!state)
462 return;
463
464 free (state->cbind);
465 free (state->gs2header);
466 free (state->cfmb_str);
467 free (state->sf_str);
468 free (state->snonce);
469 free (state->clientproof);
470 free (state->storedkey);
471 free (state->serverkey);
472 free (state->authmessage);
473 free (state->cbtlsunique);
474 scram_free_client_first (&state->cf);
475 scram_free_server_first (&state->sf);
476 scram_free_client_final (&state->cl);
477 scram_free_server_final (&state->sl);
478
479 free (state);
480}
481