Packaging: clean spec file
[platform/upstream/libgsasl.git] / scram / server.c
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 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   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
120 end:
121   free (state->sf.salt);
122   free (state->snonce);
123   free (state);
124   return rc;
125 }
126
127 int
128 _gsasl_scram_sha1_server_start (Gsasl_session * sctx, void **mech_data)
129 {
130   return scram_start (sctx, mech_data, 0);
131 }
132
133 int
134 _gsasl_scram_sha1_plus_server_start (Gsasl_session * sctx, void **mech_data)
135 {
136   return scram_start (sctx, mech_data, 1);
137 }
138
139 int
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
456 void
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 }