Branch data Line data Source code
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 : :
51 : : struct 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 : :
72 : : static int
73 : 55 : scram_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 : 55 : state = (struct scram_server_state *) calloc (sizeof (*state), 1);
81 [ - + ]: 55 : if (state == NULL)
82 : 0 : return GSASL_MALLOC_ERROR;
83 : :
84 : 55 : state->plus = plus;
85 : :
86 : 55 : rc = gsasl_nonce (buf, SNONCE_ENTROPY_BYTES);
87 [ - + ]: 55 : if (rc != GSASL_OK)
88 : 0 : goto end;
89 : :
90 : 55 : rc = gsasl_base64_to (buf, SNONCE_ENTROPY_BYTES, &state->snonce, NULL);
91 [ - + ]: 55 : if (rc != GSASL_OK)
92 : 0 : goto end;
93 : :
94 : 55 : rc = gsasl_nonce (buf, DEFAULT_SALT_BYTES);
95 [ - + ]: 55 : if (rc != GSASL_OK)
96 : 0 : goto end;
97 : :
98 : 55 : rc = gsasl_base64_to (buf, DEFAULT_SALT_BYTES, &state->sf.salt, NULL);
99 [ - + ]: 55 : if (rc != GSASL_OK)
100 : 0 : goto end;
101 : :
102 : 55 : p = gsasl_property_get (sctx, GSASL_CB_TLS_UNIQUE);
103 [ + + ][ + + ]: 55 : if (plus && !p)
104 : : {
105 : 3 : rc = GSASL_NO_CB_TLS_UNIQUE;
106 : 3 : goto end;
107 : : }
108 [ + + ]: 52 : if (p)
109 : : {
110 : 22 : rc = gsasl_base64_from (p, strlen (p), &state->cbtlsunique,
111 : : &state->cbtlsuniquelen);
112 [ - + ]: 22 : if (rc != GSASL_OK)
113 : 0 : goto end;
114 : : }
115 : :
116 : 52 : *mech_data = state;
117 : :
118 : 52 : return GSASL_OK;
119 : :
120 : : end:
121 : 3 : free (state->sf.salt);
122 : 3 : free (state->snonce);
123 : 3 : free (state);
124 : 55 : return rc;
125 : : }
126 : :
127 : : int
128 : 30 : _gsasl_scram_sha1_server_start (Gsasl_session * sctx, void **mech_data)
129 : : {
130 : 30 : return scram_start (sctx, mech_data, 0);
131 : : }
132 : :
133 : : int
134 : 25 : _gsasl_scram_sha1_plus_server_start (Gsasl_session * sctx, void **mech_data)
135 : : {
136 : 25 : return scram_start (sctx, mech_data, 1);
137 : : }
138 : :
139 : : int
140 : 115 : _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 : 115 : struct scram_server_state *state = mech_data;
147 : 115 : int res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
148 : : int rc;
149 : :
150 : 115 : *output = NULL;
151 : 115 : *output_len = 0;
152 : :
153 [ + + - ]: 115 : switch (state->step)
154 : : {
155 : : case 0:
156 : : {
157 [ + + ]: 71 : if (input_len == 0)
158 : 23 : return GSASL_NEEDS_MORE;
159 : :
160 [ + + ]: 48 : if (scram_parse_client_first (input, input_len, &state->cf) < 0)
161 : 4 : return GSASL_MECHANISM_PARSE_ERROR;
162 : :
163 : : /* In PLUS server mode, we require use of channel bindings. */
164 [ + + ][ - + ]: 44 : if (state->plus && state->cf.cbflag != 'p')
165 : 0 : 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 [ + + ]: 44 : if (!state->plus
170 [ - + ][ # # ]: 22 : && state->cbtlsuniquelen > 0 && state->cf.cbflag == 'y')
171 : 0 : return GSASL_AUTHENTICATION_ERROR;
172 : :
173 : : /* Check that username doesn't fail SASLprep. */
174 : : {
175 : : char *tmp;
176 : 44 : rc = gsasl_saslprep (state->cf.username, GSASL_ALLOW_UNASSIGNED,
177 : : &tmp, NULL);
178 [ + - ][ - + ]: 44 : if (rc != GSASL_OK || *tmp == '\0')
179 : 0 : return GSASL_AUTHENTICATION_ERROR;
180 : 44 : gsasl_free (tmp);
181 : : }
182 : :
183 : : {
184 : : const char *p;
185 : :
186 : : /* Save "gs2-header" and "message-bare" for next step. */
187 : 44 : p = memchr (input, ',', input_len);
188 [ - + ]: 44 : if (!p)
189 : 0 : return GSASL_AUTHENTICATION_ERROR;
190 : 44 : p++;
191 : 44 : p = memchr (p, ',', input_len - (p - input));
192 [ - + ]: 44 : if (!p)
193 : 0 : return GSASL_AUTHENTICATION_ERROR;
194 : 44 : p++;
195 : :
196 : 44 : state->gs2header = malloc (p - input + 1);
197 [ - + ]: 44 : if (!state->gs2header)
198 : 0 : return GSASL_MALLOC_ERROR;
199 : 44 : memcpy (state->gs2header, input, p - input);
200 : 44 : state->gs2header[p - input] = '\0';
201 : :
202 : 44 : state->cfmb_str = malloc (input_len - (p - input) + 1);
203 [ - + ]: 44 : if (!state->cfmb_str)
204 : 0 : return GSASL_MALLOC_ERROR;
205 : 44 : memcpy (state->cfmb_str, p, input_len - (p - input));
206 : 44 : state->cfmb_str[input_len - (p - input)] = '\0';
207 : : }
208 : :
209 : : /* Create new nonce. */
210 : : {
211 : 44 : size_t cnlen = strlen (state->cf.client_nonce);
212 : :
213 : 44 : state->sf.nonce = malloc (cnlen + SNONCE_ENTROPY_BYTES + 1);
214 [ - + ]: 44 : if (!state->sf.nonce)
215 : 0 : return GSASL_MALLOC_ERROR;
216 : :
217 : 44 : memcpy (state->sf.nonce, state->cf.client_nonce, cnlen);
218 : 44 : memcpy (state->sf.nonce + cnlen, state->snonce,
219 : : SNONCE_ENTROPY_BYTES);
220 : 44 : state->sf.nonce[cnlen + SNONCE_ENTROPY_BYTES] = '\0';
221 : : }
222 : :
223 : 44 : gsasl_property_set (sctx, GSASL_AUTHID, state->cf.username);
224 : 44 : gsasl_property_set (sctx, GSASL_AUTHZID, state->cf.authzid);
225 : :
226 : : {
227 : 44 : const char *p = gsasl_property_get (sctx, GSASL_SCRAM_ITER);
228 [ + + ]: 44 : if (p)
229 : 20 : state->sf.iter = strtoul (p, NULL, 10);
230 [ + + ][ + - ]: 44 : if (!p || state->sf.iter == 0 || state->sf.iter == ULONG_MAX)
[ - + ]
231 : 24 : state->sf.iter = 4096;
232 : : }
233 : :
234 : : {
235 : 44 : const char *p = gsasl_property_get (sctx, GSASL_SCRAM_SALT);
236 [ + + ]: 44 : if (p)
237 : : {
238 : 20 : free (state->sf.salt);
239 : 20 : state->sf.salt = strdup (p);
240 : : }
241 : : }
242 : :
243 : 44 : rc = scram_print_server_first (&state->sf, &state->sf_str);
244 [ - + ]: 44 : if (rc != 0)
245 : 0 : return GSASL_MALLOC_ERROR;
246 : :
247 : 44 : *output = strdup (state->sf_str);
248 [ - + ]: 44 : if (!*output)
249 : 0 : return GSASL_MALLOC_ERROR;
250 : 44 : *output_len = strlen (*output);
251 : :
252 : 44 : state->step++;
253 : 44 : return GSASL_NEEDS_MORE;
254 : : break;
255 : : }
256 : :
257 : : case 1:
258 : : {
259 [ - + ]: 44 : if (scram_parse_client_final (input, input_len, &state->cl) < 0)
260 : 0 : return GSASL_MECHANISM_PARSE_ERROR;
261 : :
262 [ - + ]: 44 : if (strcmp (state->cl.nonce, state->sf.nonce) != 0)
263 : 0 : 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 : 44 : rc = gsasl_base64_from (state->cl.cbind, strlen (state->cl.cbind),
271 : : &state->cbind, &len);
272 [ - + ]: 44 : if (rc != 0)
273 : 0 : return rc;
274 : :
275 [ + + ]: 44 : if (state->cf.cbflag == 'p')
276 : : {
277 [ - + ]: 22 : if (len < strlen (state->gs2header))
278 : 0 : return GSASL_AUTHENTICATION_ERROR;
279 : :
280 [ - + ]: 22 : if (memcmp (state->cbind, state->gs2header,
281 : 22 : strlen (state->gs2header)) != 0)
282 : 0 : return GSASL_AUTHENTICATION_ERROR;
283 : :
284 [ + + ]: 22 : if (len - strlen (state->gs2header) != state->cbtlsuniquelen)
285 : 2 : return GSASL_AUTHENTICATION_ERROR;
286 : :
287 [ + + ]: 20 : if (memcmp (state->cbind + strlen (state->gs2header),
288 : 20 : state->cbtlsunique, state->cbtlsuniquelen) != 0)
289 : 1 : return GSASL_AUTHENTICATION_ERROR;
290 : : }
291 : : else
292 : : {
293 [ - + ]: 22 : if (len != strlen (state->gs2header))
294 : 0 : return GSASL_AUTHENTICATION_ERROR;
295 : :
296 [ + + ]: 22 : if (memcmp (state->cbind, state->gs2header, len) != 0)
297 : 1 : 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 : 40 : rc = gsasl_base64_from (state->cl.proof, strlen (state->cl.proof),
307 : : &state->clientproof, &len);
308 [ - + ]: 40 : if (rc != 0)
309 : 0 : return rc;
310 [ - + ]: 40 : if (len != 20)
311 : 0 : return GSASL_MECHANISM_PARSE_ERROR;
312 : : }
313 : :
314 : : {
315 : : const char *p;
316 : :
317 : : /* Get StoredKey and ServerKey */
318 [ + - ]: 40 : 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 : 40 : rc = gsasl_saslprep (p, 0, &preppasswd, NULL);
328 [ - + ]: 40 : if (rc != GSASL_OK)
329 : 0 : return rc;
330 : :
331 : 40 : rc = gsasl_base64_from (state->sf.salt, strlen (state->sf.salt),
332 : : &salt, &saltlen);
333 [ - + ]: 40 : if (rc != 0)
334 : : {
335 : 0 : gsasl_free (preppasswd);
336 : 0 : return rc;
337 : : }
338 : :
339 : : /* SaltedPassword := Hi(password, salt) */
340 : 40 : err = gc_pbkdf2_sha1 (preppasswd, strlen (preppasswd),
341 : : salt, saltlen,
342 : 40 : state->sf.iter, saltedpassword, 20);
343 : 40 : gsasl_free (preppasswd);
344 : 40 : gsasl_free (salt);
345 [ - + ]: 40 : if (err != GC_OK)
346 : 0 : return GSASL_MALLOC_ERROR;
347 : :
348 : : /* ClientKey := HMAC(SaltedPassword, "Client Key") */
349 : : #define CLIENT_KEY "Client Key"
350 : 40 : rc = gsasl_hmac_sha1 (saltedpassword, 20,
351 : : CLIENT_KEY, strlen (CLIENT_KEY),
352 : : &clientkey);
353 [ - + ]: 40 : if (rc != 0)
354 : 0 : return rc;
355 : :
356 : : /* StoredKey := H(ClientKey) */
357 : 40 : rc = gsasl_sha1 (clientkey, 20, &state->storedkey);
358 : 40 : free (clientkey);
359 [ - + ]: 40 : if (rc != 0)
360 : 0 : return rc;
361 : :
362 : : /* ServerKey := HMAC(SaltedPassword, "Server Key") */
363 : : #define SERVER_KEY "Server Key"
364 : 40 : rc = gsasl_hmac_sha1 (saltedpassword, 20,
365 : : SERVER_KEY, strlen (SERVER_KEY),
366 : : &state->serverkey);
367 [ - + ]: 40 : if (rc != 0)
368 : 0 : return rc;
369 : : }
370 : : else
371 : 0 : 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 : 40 : p = memmem (input, input_len, ",p=", 3);
380 [ - + ]: 40 : if (!p)
381 : 0 : return GSASL_MECHANISM_PARSE_ERROR;
382 : 40 : len = p - input;
383 : :
384 : 40 : n = asprintf (&state->authmessage, "%s,%.*s,%.*s",
385 : : state->cfmb_str,
386 : 40 : (int) strlen (state->sf_str), state->sf_str,
387 : : (int) len, input);
388 [ + - ][ - + ]: 40 : if (n <= 0 || !state->authmessage)
389 : 0 : 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 : 40 : rc = gsasl_hmac_sha1 (state->storedkey, 20,
399 : 40 : state->authmessage,
400 : 40 : strlen (state->authmessage),
401 : : &clientsignature);
402 [ - + ]: 40 : if (rc != 0)
403 : 0 : return rc;
404 : :
405 : : /* ClientKey := ClientProof XOR ClientSignature */
406 : 40 : memxor (clientsignature, state->clientproof, 20);
407 : :
408 : 40 : rc = gsasl_sha1 (clientsignature, 20, &maybe_storedkey);
409 : 40 : free (clientsignature);
410 [ - + ]: 40 : if (rc != 0)
411 : 0 : return rc;
412 : :
413 : 40 : rc = memcmp (state->storedkey, maybe_storedkey, 20);
414 : 40 : free (maybe_storedkey);
415 [ + + ]: 40 : if (rc != 0)
416 : 5 : return GSASL_AUTHENTICATION_ERROR;
417 : : }
418 : :
419 : : /* Generate server verifier. */
420 : : {
421 : : char *serversignature;
422 : :
423 : : /* ServerSignature := HMAC(ServerKey, AuthMessage) */
424 : 35 : rc = gsasl_hmac_sha1 (state->serverkey, 20,
425 : 35 : state->authmessage,
426 : 35 : strlen (state->authmessage),
427 : : &serversignature);
428 [ - + ]: 35 : if (rc != 0)
429 : 0 : return rc;
430 : :
431 : 35 : rc = gsasl_base64_to (serversignature, 20,
432 : : &state->sl.verifier, NULL);
433 : 35 : free (serversignature);
434 [ - + ]: 35 : if (rc != 0)
435 : 0 : return rc;
436 : : }
437 : : }
438 : :
439 : 35 : rc = scram_print_server_final (&state->sl, output);
440 [ - + ]: 35 : if (rc != 0)
441 : 0 : return GSASL_MALLOC_ERROR;
442 : 35 : *output_len = strlen (*output);
443 : :
444 : 35 : state->step++;
445 : 35 : return GSASL_OK;
446 : : break;
447 : : }
448 : :
449 : : default:
450 : 0 : break;
451 : : }
452 : :
453 : 115 : return res;
454 : : }
455 : :
456 : : void
457 : 55 : _gsasl_scram_sha1_server_finish (Gsasl_session * sctx, void *mech_data)
458 : : {
459 : 55 : struct scram_server_state *state = mech_data;
460 : :
461 [ + + ]: 55 : if (!state)
462 : 55 : return;
463 : :
464 : 52 : free (state->cbind);
465 : 52 : free (state->gs2header);
466 : 52 : free (state->cfmb_str);
467 : 52 : free (state->sf_str);
468 : 52 : free (state->snonce);
469 : 52 : free (state->clientproof);
470 : 52 : free (state->storedkey);
471 : 52 : free (state->serverkey);
472 : 52 : free (state->authmessage);
473 : 52 : free (state->cbtlsunique);
474 : 52 : scram_free_client_first (&state->cf);
475 : 52 : scram_free_server_first (&state->sf);
476 : 52 : scram_free_client_final (&state->cl);
477 : 52 : scram_free_server_final (&state->sl);
478 : :
479 : 52 : free (state);
480 : : }
|