scram/server.c

Go to the documentation of this file.
00001 /* server.c --- SASL CRAM-MD5 server side functions.
00002  * Copyright (C) 2009, 2010  Simon Josefsson
00003  *
00004  * This file is part of GNU SASL Library.
00005  *
00006  * GNU SASL Library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public License
00008  * as published by the Free Software Foundation; either version 2.1 of
00009  * the License, or (at your option) any later version.
00010  *
00011  * GNU SASL Library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with GNU SASL Library; if not, write to the Free
00018  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 # include "config.h"
00025 #endif
00026 
00027 /* Get specification. */
00028 #include "scram.h"
00029 
00030 /* Get malloc, free, strtoul. */
00031 #include <stdlib.h>
00032 
00033 /* Get ULONG_MAX. */
00034 #include <limits.h>
00035 
00036 /* Get memcpy, strdup, strlen. */
00037 #include <string.h>
00038 
00039 /* Get MAX. */
00040 #include "minmax.h"
00041 
00042 #include "tokens.h"
00043 #include "parser.h"
00044 #include "printer.h"
00045 #include "gc.h"
00046 #include "memxor.h"
00047 
00048 #define DEFAULT_SALT_BYTES 12
00049 #define SNONCE_ENTROPY_BYTES 18
00050 
00051 struct scram_server_state
00052 {
00053   int step;
00054   char *gs2header; /* copy of client first gs2-header */
00055   char *cfmb_str; /* copy of client first message bare */
00056   char *sf_str; /* copy of server first message */
00057   char *snonce;
00058   char *clientproof;
00059   char *storedkey;
00060   char *serverkey;
00061   char *authmessage;
00062   struct scram_client_first cf;
00063   struct scram_server_first sf;
00064   struct scram_client_final cl;
00065   struct scram_server_final sl;
00066 };
00067 
00068 int
00069 _gsasl_scram_sha1_server_start (Gsasl_session * sctx, void **mech_data)
00070 {
00071   struct scram_server_state *state;
00072   char buf[MAX (SNONCE_ENTROPY_BYTES, DEFAULT_SALT_BYTES)];
00073   int rc;
00074 
00075   state = (struct scram_server_state *) calloc (sizeof (*state), 1);
00076   if (state == NULL)
00077     return GSASL_MALLOC_ERROR;
00078 
00079   rc = gsasl_nonce (buf, SNONCE_ENTROPY_BYTES);
00080   if (rc != GSASL_OK)
00081     goto end;
00082 
00083   rc = gsasl_base64_to (buf, SNONCE_ENTROPY_BYTES,
00084                         &state->snonce, NULL);
00085   if (rc != GSASL_OK)
00086     goto end;
00087 
00088   rc = gsasl_nonce (buf, DEFAULT_SALT_BYTES);
00089   if (rc != GSASL_OK)
00090     goto end;
00091 
00092   rc = gsasl_base64_to (buf, DEFAULT_SALT_BYTES,
00093                         &state->sf.salt, NULL);
00094   if (rc != GSASL_OK)
00095     goto end;
00096 
00097   *mech_data = state;
00098 
00099   return GSASL_OK;
00100 
00101  end:
00102   free (state->sf.salt);
00103   free (state->snonce);
00104   free (state);
00105   return rc;
00106 }
00107 
00108 int
00109 _gsasl_scram_sha1_server_step (Gsasl_session * sctx,
00110                                void *mech_data,
00111                                const char *input,
00112                                size_t input_len,
00113                                char **output, size_t * output_len)
00114 {
00115   struct scram_server_state *state = mech_data;
00116   int res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
00117   int rc;
00118 
00119   *output = NULL;
00120   *output_len = 0;
00121 
00122   switch (state->step)
00123     {
00124     case 0:
00125       {
00126         if (input_len == 0)
00127           return GSASL_NEEDS_MORE;
00128 
00129         if (scram_parse_client_first (input, input_len, &state->cf) < 0)
00130           return GSASL_MECHANISM_PARSE_ERROR;
00131 
00132         /* We don't support channel bindings. */
00133         if (state->cf.cbflag != 'n' && state->cf.cbflag != 'y')
00134           return GSASL_AUTHENTICATION_ERROR;
00135 
00136         /* Check that username doesn't fail SASLprep. */
00137         {
00138           char *tmp;
00139           rc = gsasl_saslprep (state->cf.username, GSASL_ALLOW_UNASSIGNED,
00140                                &tmp, NULL);
00141           if (rc != GSASL_OK || *tmp == '\0')
00142             return GSASL_AUTHENTICATION_ERROR;
00143           gsasl_free (tmp);
00144         }
00145 
00146         {
00147           const char *p;
00148 
00149           /* Save "gs2-header" and "message-bare" for next step. */
00150           p = memchr (input, ',', input_len);
00151           if (!p)
00152             return GSASL_AUTHENTICATION_ERROR;
00153           p++;
00154           p = memchr (p, ',', input_len - (p - input));
00155           if (!p)
00156             return GSASL_AUTHENTICATION_ERROR;
00157           p++;
00158 
00159           state->gs2header = malloc (p - input + 1);
00160           if (!state->gs2header)
00161             return GSASL_MALLOC_ERROR;
00162           memcpy (state->gs2header, input, p - input);
00163           state->gs2header[p - input] = '\0';
00164 
00165           state->cfmb_str = malloc (input_len - (p - input) + 1);
00166           if (!state->cfmb_str)
00167             return GSASL_MALLOC_ERROR;
00168           memcpy (state->cfmb_str, p, input_len - (p - input));
00169           state->cfmb_str[input_len - (p - input)] = '\0';
00170         }
00171 
00172         /* Create new nonce. */
00173         {
00174           size_t cnlen = strlen (state->cf.client_nonce);
00175 
00176           state->sf.nonce = malloc (cnlen + SNONCE_ENTROPY_BYTES + 1);
00177           if (!state->sf.nonce)
00178             return GSASL_MALLOC_ERROR;
00179 
00180           memcpy (state->sf.nonce, state->cf.client_nonce, cnlen);
00181           memcpy (state->sf.nonce + cnlen, state->snonce,
00182                   SNONCE_ENTROPY_BYTES);
00183           state->sf.nonce[cnlen + SNONCE_ENTROPY_BYTES] = '\0';
00184         }
00185 
00186         gsasl_property_set (sctx, GSASL_AUTHID, state->cf.username);
00187         gsasl_property_set (sctx, GSASL_AUTHZID, state->cf.authzid);
00188 
00189         {
00190           const char *p = gsasl_property_get (sctx, GSASL_SCRAM_ITER);
00191           if (p)
00192             state->sf.iter = strtoul (p, NULL, 10);
00193           if (!p || state->sf.iter == 0 || state->sf.iter == ULONG_MAX)
00194             state->sf.iter = 4096;
00195         }
00196 
00197         {
00198           const char *p = gsasl_property_get (sctx, GSASL_SCRAM_SALT);
00199           if (p)
00200             {
00201               free (state->sf.salt);
00202               state->sf.salt = strdup (p);
00203             }
00204         }
00205 
00206         rc = scram_print_server_first (&state->sf, &state->sf_str);
00207         if (rc != 0)
00208           return GSASL_MALLOC_ERROR;
00209 
00210         *output = strdup (state->sf_str);
00211         if (!*output)
00212           return GSASL_MALLOC_ERROR;
00213         *output_len = strlen (*output);
00214 
00215         state->step++;
00216         return GSASL_NEEDS_MORE;
00217         break;
00218       }
00219 
00220     case 1:
00221       {
00222         if (scram_parse_client_final (input, input_len, &state->cl) < 0)
00223           return GSASL_MECHANISM_PARSE_ERROR;
00224 
00225         if (strcmp (state->cl.nonce, state->sf.nonce) != 0)
00226           return GSASL_AUTHENTICATION_ERROR;
00227 
00228         /* Base64 decode the c= field and check that it matches
00229            client-first. */
00230         {
00231           size_t len;
00232           char *cbind;
00233 
00234           rc = gsasl_base64_from (state->cl.cbind, strlen (state->cl.cbind),
00235                                   &cbind, &len);
00236           if (rc != 0)
00237             return rc;
00238 
00239           if (len != strlen (state->gs2header))
00240             return GSASL_AUTHENTICATION_ERROR;
00241 
00242           if (memcmp (cbind, state->gs2header, len) != 0)
00243             return GSASL_AUTHENTICATION_ERROR;
00244         }
00245 
00246         /* Base64 decode client proof and check that length matches
00247            SHA-1 size. */
00248         {
00249           size_t len;
00250 
00251           rc = gsasl_base64_from (state->cl.proof, strlen (state->cl.proof),
00252                                   &state->clientproof, &len);
00253           if (rc != 0)
00254             return rc;
00255           if (len != 20)
00256             return GSASL_MECHANISM_PARSE_ERROR;
00257         }
00258 
00259         {
00260           const char *p;
00261 
00262           /* Get StoredKey and ServerKey */
00263           if ((p = gsasl_property_get (sctx, GSASL_PASSWORD)))
00264             {
00265               Gc_rc err;
00266               char *salt;
00267               size_t saltlen;
00268               char saltedpassword[20];
00269               char *clientkey;
00270               char *preppasswd;
00271 
00272               rc = gsasl_saslprep (p, 0, &preppasswd, NULL);
00273               if (rc != GSASL_OK)
00274                 return rc;
00275 
00276               rc = gsasl_base64_from (state->sf.salt, strlen (state->sf.salt),
00277                                       &salt, &saltlen);
00278               if (rc != 0)
00279                 {
00280                   gsasl_free (preppasswd);
00281                   return rc;
00282                 }
00283 
00284               /* SaltedPassword := Hi(password, salt) */
00285               err = gc_pbkdf2_sha1 (preppasswd, strlen (preppasswd),
00286                                     salt, saltlen,
00287                                     state->sf.iter, saltedpassword, 20);
00288               gsasl_free (preppasswd);
00289               gsasl_free (salt);
00290               if (err != GC_OK)
00291                 return GSASL_MALLOC_ERROR;
00292 
00293               /* ClientKey := HMAC(SaltedPassword, "Client Key") */
00294 #define CLIENT_KEY "Client Key"
00295               rc = gsasl_hmac_sha1 (saltedpassword, 20,
00296                                     CLIENT_KEY, strlen (CLIENT_KEY),
00297                                     &clientkey);
00298               if (rc != 0)
00299                 return rc;
00300 
00301               /* StoredKey := H(ClientKey) */
00302               rc = gsasl_sha1 (clientkey, 20, &state->storedkey);
00303               free (clientkey);
00304               if (rc != 0)
00305                 return rc;
00306 
00307               /* ServerKey := HMAC(SaltedPassword, "Server Key") */
00308 #define SERVER_KEY "Server Key"
00309               rc = gsasl_hmac_sha1 (saltedpassword, 20,
00310                                     SERVER_KEY, strlen (SERVER_KEY),
00311                                     &state->serverkey);
00312               if (rc != 0)
00313                 return rc;
00314             }
00315           else
00316             return GSASL_NO_PASSWORD;
00317 
00318           /* Compute AuthMessage */
00319           {
00320             size_t len;
00321             int n;
00322 
00323             /* Get client-final-message-without-proof. */
00324             p = memmem (input, input_len, ",p=", 3);
00325             if (!p)
00326               return GSASL_MECHANISM_PARSE_ERROR;
00327             len = p - input;
00328 
00329             n = asprintf (&state->authmessage, "%s,%.*s,%.*s",
00330                           state->cfmb_str,
00331                           strlen (state->sf_str), state->sf_str,
00332                           len, input);
00333             if (n <= 0 || !state->authmessage)
00334               return GSASL_MALLOC_ERROR;
00335           }
00336 
00337           /* Check client proof. */
00338           {
00339             char *clientsignature;
00340             char *maybe_storedkey;
00341 
00342             /* ClientSignature := HMAC(StoredKey, AuthMessage) */
00343             rc = gsasl_hmac_sha1 (state->storedkey, 20,
00344                                   state->authmessage,
00345                                   strlen (state->authmessage),
00346                                   &clientsignature);
00347             if (rc != 0)
00348               return rc;
00349 
00350             /* ClientKey := ClientProof XOR ClientSignature */
00351             memxor (clientsignature, state->clientproof, 20);
00352 
00353             rc = gsasl_sha1 (clientsignature, 20, &maybe_storedkey);
00354             free (clientsignature);
00355             if (rc != 0)
00356               return rc;
00357 
00358             rc = memcmp (state->storedkey, maybe_storedkey, 20);
00359             free (maybe_storedkey);
00360             if (rc != 0)
00361               return GSASL_AUTHENTICATION_ERROR;
00362           }
00363 
00364           /* Generate server verifier. */
00365           {
00366             char *serversignature;
00367 
00368             /* ServerSignature := HMAC(ServerKey, AuthMessage) */
00369             rc = gsasl_hmac_sha1 (state->serverkey, 20,
00370                                   state->authmessage,
00371                                   strlen (state->authmessage),
00372                                   &serversignature);
00373             if (rc != 0)
00374               return rc;
00375 
00376             rc = gsasl_base64_to (serversignature, 20,
00377                                   &state->sl.verifier, NULL);
00378             free (serversignature);
00379             if (rc != 0)
00380               return rc;
00381           }
00382         }
00383 
00384         rc = scram_print_server_final (&state->sl, output);
00385         if (rc != 0)
00386           return GSASL_MALLOC_ERROR;
00387         *output_len = strlen (*output);
00388 
00389         state->step++;
00390         return GSASL_OK;
00391         break;
00392       }
00393 
00394     default:
00395       break;
00396     }
00397 
00398   return res;
00399 }
00400 
00401 void
00402 _gsasl_scram_sha1_server_finish (Gsasl_session * sctx, void *mech_data)
00403 {
00404   struct scram_server_state *state = mech_data;
00405 
00406   if (!state)
00407     return;
00408 
00409   free (state->cfmb_str);
00410   free (state->sf_str);
00411   free (state->snonce);
00412   free (state->clientproof);
00413   free (state->storedkey);
00414   free (state->serverkey);
00415   free (state->authmessage);
00416   scram_free_client_first (&state->cf);
00417   scram_free_server_first (&state->sf);
00418   scram_free_client_final (&state->cl);
00419   scram_free_server_final (&state->sl);
00420 
00421   free (state);
00422 }