1 /* server.c --- SASL CRAM-MD5 server side functions.
2 * Copyright (C) 2009-2012 Simon Josefsson
4 * This file is part of GNU SASL Library.
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.
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.
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.
27 /* Get specification. */
30 /* Get malloc, free, strtoul. */
36 /* Get memcpy, strdup, strlen. */
48 #define DEFAULT_SALT_BYTES 12
49 #define SNONCE_ENTROPY_BYTES 18
51 struct scram_server_state
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 */
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;
73 scram_start (Gsasl_session * sctx, void **mech_data, int plus)
75 struct scram_server_state *state;
76 char buf[MAX (SNONCE_ENTROPY_BYTES, DEFAULT_SALT_BYTES)];
80 state = (struct scram_server_state *) calloc (sizeof (*state), 1);
82 return GSASL_MALLOC_ERROR;
86 rc = gsasl_nonce (buf, SNONCE_ENTROPY_BYTES);
90 rc = gsasl_base64_to (buf, SNONCE_ENTROPY_BYTES, &state->snonce, NULL);
94 rc = gsasl_nonce (buf, DEFAULT_SALT_BYTES);
98 rc = gsasl_base64_to (buf, DEFAULT_SALT_BYTES, &state->sf.salt, NULL);
102 p = gsasl_property_get (sctx, GSASL_CB_TLS_UNIQUE);
105 rc = GSASL_NO_CB_TLS_UNIQUE;
110 rc = gsasl_base64_from (p, strlen (p), &state->cbtlsunique,
111 &state->cbtlsuniquelen);
121 free (state->sf.salt);
122 free (state->snonce);
128 _gsasl_scram_sha1_server_start (Gsasl_session * sctx, void **mech_data)
130 return scram_start (sctx, mech_data, 0);
134 _gsasl_scram_sha1_plus_server_start (Gsasl_session * sctx, void **mech_data)
136 return scram_start (sctx, mech_data, 1);
140 _gsasl_scram_sha1_server_step (Gsasl_session * sctx,
144 char **output, size_t * output_len)
146 struct scram_server_state *state = mech_data;
147 int res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
158 return GSASL_NEEDS_MORE;
160 if (scram_parse_client_first (input, input_len, &state->cf) < 0)
161 return GSASL_MECHANISM_PARSE_ERROR;
163 /* In PLUS server mode, we require use of channel bindings. */
164 if (state->plus && state->cf.cbflag != 'p')
165 return GSASL_AUTHENTICATION_ERROR;
167 /* In non-PLUS mode, but where have channel bindings data (and
168 thus advertised PLUS) we reject a client 'y' cbflag. */
170 && state->cbtlsuniquelen > 0 && state->cf.cbflag == 'y')
171 return GSASL_AUTHENTICATION_ERROR;
173 /* Check that username doesn't fail SASLprep. */
176 rc = gsasl_saslprep (state->cf.username, GSASL_ALLOW_UNASSIGNED,
178 if (rc != GSASL_OK || *tmp == '\0')
179 return GSASL_AUTHENTICATION_ERROR;
186 /* Save "gs2-header" and "message-bare" for next step. */
187 p = memchr (input, ',', input_len);
189 return GSASL_AUTHENTICATION_ERROR;
191 p = memchr (p, ',', input_len - (p - input));
193 return GSASL_AUTHENTICATION_ERROR;
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';
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';
209 /* Create new nonce. */
211 size_t cnlen = strlen (state->cf.client_nonce);
213 state->sf.nonce = malloc (cnlen + SNONCE_ENTROPY_BYTES + 1);
214 if (!state->sf.nonce)
215 return GSASL_MALLOC_ERROR;
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';
223 gsasl_property_set (sctx, GSASL_AUTHID, state->cf.username);
224 gsasl_property_set (sctx, GSASL_AUTHZID, state->cf.authzid);
227 const char *p = gsasl_property_get (sctx, GSASL_SCRAM_ITER);
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;
235 const char *p = gsasl_property_get (sctx, GSASL_SCRAM_SALT);
238 free (state->sf.salt);
239 state->sf.salt = strdup (p);
243 rc = scram_print_server_first (&state->sf, &state->sf_str);
245 return GSASL_MALLOC_ERROR;
247 *output = strdup (state->sf_str);
249 return GSASL_MALLOC_ERROR;
250 *output_len = strlen (*output);
253 return GSASL_NEEDS_MORE;
259 if (scram_parse_client_final (input, input_len, &state->cl) < 0)
260 return GSASL_MECHANISM_PARSE_ERROR;
262 if (strcmp (state->cl.nonce, state->sf.nonce) != 0)
263 return GSASL_AUTHENTICATION_ERROR;
265 /* Base64 decode the c= field and check that it matches
266 client-first. Also check channel binding data. */
270 rc = gsasl_base64_from (state->cl.cbind, strlen (state->cl.cbind),
271 &state->cbind, &len);
275 if (state->cf.cbflag == 'p')
277 if (len < strlen (state->gs2header))
278 return GSASL_AUTHENTICATION_ERROR;
280 if (memcmp (state->cbind, state->gs2header,
281 strlen (state->gs2header)) != 0)
282 return GSASL_AUTHENTICATION_ERROR;
284 if (len - strlen (state->gs2header) != state->cbtlsuniquelen)
285 return GSASL_AUTHENTICATION_ERROR;
287 if (memcmp (state->cbind + strlen (state->gs2header),
288 state->cbtlsunique, state->cbtlsuniquelen) != 0)
289 return GSASL_AUTHENTICATION_ERROR;
293 if (len != strlen (state->gs2header))
294 return GSASL_AUTHENTICATION_ERROR;
296 if (memcmp (state->cbind, state->gs2header, len) != 0)
297 return GSASL_AUTHENTICATION_ERROR;
301 /* Base64 decode client proof and check that length matches
306 rc = gsasl_base64_from (state->cl.proof, strlen (state->cl.proof),
307 &state->clientproof, &len);
311 return GSASL_MECHANISM_PARSE_ERROR;
317 /* Get StoredKey and ServerKey */
318 if ((p = gsasl_property_get (sctx, GSASL_PASSWORD)))
323 char saltedpassword[20];
327 rc = gsasl_saslprep (p, 0, &preppasswd, NULL);
331 rc = gsasl_base64_from (state->sf.salt, strlen (state->sf.salt),
335 gsasl_free (preppasswd);
339 /* SaltedPassword := Hi(password, salt) */
340 err = gc_pbkdf2_sha1 (preppasswd, strlen (preppasswd),
342 state->sf.iter, saltedpassword, 20);
343 gsasl_free (preppasswd);
346 return GSASL_MALLOC_ERROR;
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),
356 /* StoredKey := H(ClientKey) */
357 rc = gsasl_sha1 (clientkey, 20, &state->storedkey);
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),
371 return GSASL_NO_PASSWORD;
373 /* Compute AuthMessage */
378 /* Get client-final-message-without-proof. */
379 p = memmem (input, input_len, ",p=", 3);
381 return GSASL_MECHANISM_PARSE_ERROR;
384 n = asprintf (&state->authmessage, "%s,%.*s,%.*s",
386 (int) strlen (state->sf_str), state->sf_str,
388 if (n <= 0 || !state->authmessage)
389 return GSASL_MALLOC_ERROR;
392 /* Check client proof. */
394 char *clientsignature;
395 char *maybe_storedkey;
397 /* ClientSignature := HMAC(StoredKey, AuthMessage) */
398 rc = gsasl_hmac_sha1 (state->storedkey, 20,
400 strlen (state->authmessage),
405 /* ClientKey := ClientProof XOR ClientSignature */
406 memxor (clientsignature, state->clientproof, 20);
408 rc = gsasl_sha1 (clientsignature, 20, &maybe_storedkey);
409 free (clientsignature);
413 rc = memcmp (state->storedkey, maybe_storedkey, 20);
414 free (maybe_storedkey);
416 return GSASL_AUTHENTICATION_ERROR;
419 /* Generate server verifier. */
421 char *serversignature;
423 /* ServerSignature := HMAC(ServerKey, AuthMessage) */
424 rc = gsasl_hmac_sha1 (state->serverkey, 20,
426 strlen (state->authmessage),
431 rc = gsasl_base64_to (serversignature, 20,
432 &state->sl.verifier, NULL);
433 free (serversignature);
439 rc = scram_print_server_final (&state->sl, output);
441 return GSASL_MALLOC_ERROR;
442 *output_len = strlen (*output);
457 _gsasl_scram_sha1_server_finish (Gsasl_session * sctx, void *mech_data)
459 struct scram_server_state *state = mech_data;
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);