scram/client.c

Go to the documentation of this file.
00001 /* client.c --- SASL SCRAM client side functions.
00002  * Copyright (C) 2009  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. */
00031 #include <stdlib.h>
00032 
00033 /* Get memcpy, strlen, strchr. */
00034 #include <string.h>
00035 
00036 /* Get bool. */
00037 #include <stdbool.h>
00038 
00039 #include "tokens.h"
00040 #include "parser.h"
00041 #include "printer.h"
00042 #include "gc.h"
00043 #include "memxor.h"
00044 
00045 #define CNONCE_ENTROPY_BYTES 18
00046 
00047 struct scram_client_state
00048 {
00049   int step;
00050   char *cfmb; /* client first message bare */
00051   char *serversignature;
00052   char *authmessage;
00053   struct scram_client_first cf;
00054   struct scram_server_first sf;
00055   struct scram_client_final cl;
00056   struct scram_server_final sl;
00057 };
00058 
00059 int
00060 _gsasl_scram_sha1_client_start (Gsasl_session * sctx, void **mech_data)
00061 {
00062   struct scram_client_state *state;
00063   char buf[CNONCE_ENTROPY_BYTES];
00064   int rc;
00065 
00066   state = (struct scram_client_state *) calloc (sizeof (*state), 1);
00067   if (state == NULL)
00068     return GSASL_MALLOC_ERROR;
00069 
00070   rc = gsasl_nonce (buf, CNONCE_ENTROPY_BYTES);
00071   if (rc != GSASL_OK)
00072     {
00073       free (state);
00074       return rc;
00075     }
00076 
00077   rc = gsasl_base64_to (buf, CNONCE_ENTROPY_BYTES,
00078                         &state->cf.client_nonce, NULL);
00079   if (rc != GSASL_OK)
00080     {
00081       free (state);
00082       return rc;
00083     }
00084 
00085   *mech_data = state;
00086 
00087   return GSASL_OK;
00088 }
00089 
00090 static char
00091 hexdigit_to_char (char hexdigit)
00092 {
00093   if (hexdigit >= '0' && hexdigit <= '9')
00094     return hexdigit - '0';
00095   if (hexdigit >= 'a' && hexdigit <= 'f')
00096     return hexdigit - 'a' + 10;
00097   return 0;
00098 }
00099 
00100 static char
00101 hex_to_char (char u, char l)
00102 {
00103   return (char) (((unsigned char) hexdigit_to_char (u)) * 16
00104                  + hexdigit_to_char (l));
00105 }
00106 
00107 static void
00108 sha1_hex_to_byte (char *saltedpassword, const char *p)
00109 {
00110   while (*p)
00111     {
00112       *saltedpassword = hex_to_char (p[0], p[1]);
00113       p += 2;
00114       saltedpassword++;
00115     }
00116 }
00117 
00118 static bool
00119 hex_p (const char *hexstr)
00120 {
00121   static const char hexalpha[] = "0123456789abcdef";
00122 
00123   for (; *hexstr; hexstr++)
00124     if (strchr (hexalpha, *hexstr) == NULL)
00125       return false;
00126 
00127   return true;
00128 }
00129 
00130 int
00131 _gsasl_scram_sha1_client_step (Gsasl_session * sctx,
00132                                void *mech_data,
00133                                const char *input, size_t input_len,
00134                                char **output, size_t * output_len)
00135 {
00136   struct scram_client_state *state = mech_data;
00137   int res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
00138   int rc;
00139 
00140   *output = NULL;
00141   *output_len = 0;
00142 
00143   switch (state->step)
00144     {
00145     case 0:
00146       {
00147         const char *p;
00148 
00149         /* We don't support channel bindings. */
00150         state->cf.cbflag = 'n';
00151 
00152         p = gsasl_property_get (sctx, GSASL_AUTHID);
00153         if (!p)
00154           return GSASL_NO_AUTHID;
00155 
00156         /* FIXME check that final document uses query strings. */
00157         rc = gsasl_saslprep (p, GSASL_ALLOW_UNASSIGNED,
00158                              &state->cf.username, NULL);
00159         if (rc != GSASL_OK)
00160           return rc;
00161 
00162         p = gsasl_property_get (sctx, GSASL_AUTHZID);
00163         if (p)
00164           state->cf.authzid = strdup (p);
00165 
00166         rc = scram_print_client_first (&state->cf, output);
00167         if (rc == -2)
00168           return GSASL_MALLOC_ERROR;
00169         else if (rc != 0)
00170           return GSASL_AUTHENTICATION_ERROR;
00171 
00172         *output_len = strlen (*output);
00173 
00174         /* Save "cbind" and "bare" for next step. */
00175         p = strchr (*output, ',');
00176         if (!p)
00177             return GSASL_AUTHENTICATION_ERROR;
00178         p++;
00179         p = strchr (p, ',');
00180         if (!p)
00181             return GSASL_AUTHENTICATION_ERROR;
00182         p++;
00183         rc = gsasl_base64_to (*output, p - *output, &state->cl.cbind, NULL);
00184         if (rc != 0)
00185           return rc;
00186 
00187         state->cfmb = strdup (p);
00188         if (!state->cfmb)
00189           return GSASL_MALLOC_ERROR;
00190 
00191         /* We are done. */
00192         state->step++;
00193         return GSASL_NEEDS_MORE;
00194         break;
00195       }
00196 
00197     case 1:
00198       {
00199         if (scram_parse_server_first (input, input_len, &state->sf) < 0)
00200           return GSASL_MECHANISM_PARSE_ERROR;
00201 
00202         if (strlen (state->sf.nonce) < strlen (state->cf.client_nonce) ||
00203             memcmp (state->cf.client_nonce, state->sf.nonce,
00204                     strlen (state->cf.client_nonce)) != 0)
00205           return GSASL_AUTHENTICATION_ERROR;
00206 
00207         state->cl.nonce = strdup (state->sf.nonce);
00208         if (!state->cl.nonce)
00209           return GSASL_MALLOC_ERROR;
00210 
00211         /* Save salt/iter as properties, so that client callback can
00212            access them. */
00213         {
00214           char *str = NULL;
00215           int n;
00216           n = asprintf (&str, "%d", state->sf.iter);
00217           if (n < 0 || str == NULL)
00218             return GSASL_MALLOC_ERROR;
00219           gsasl_property_set (sctx, GSASL_SCRAM_ITER, str);
00220           free (str);
00221         }
00222 
00223         gsasl_property_set (sctx, GSASL_SCRAM_SALT, state->sf.salt);
00224 
00225         /* Generate ClientProof. */
00226         {
00227           char saltedpassword[20];
00228           char *clientkey;
00229           char *storedkey;
00230           char *clientsignature;
00231           char clientproof[20];
00232           const char *p;
00233 
00234           /* Get SaltedPassword. */
00235           p = gsasl_property_get (sctx, GSASL_SCRAM_SALTED_PASSWORD);
00236           if (p && strlen (p) == 40 && hex_p (p))
00237             sha1_hex_to_byte (saltedpassword, p);
00238           else if ((p = gsasl_property_get (sctx, GSASL_PASSWORD)) != NULL)
00239             {
00240               Gc_rc err;
00241               char *salt;
00242               size_t saltlen;
00243               char *preppasswd;
00244 
00245               rc = gsasl_saslprep (p, 0, &preppasswd, NULL);
00246               if (rc != GSASL_OK)
00247                 return rc;
00248 
00249               rc = gsasl_base64_from (state->sf.salt, strlen (state->sf.salt),
00250                                       &salt, &saltlen);
00251               if (rc != 0)
00252                 {
00253                   gsasl_free (preppasswd);
00254                   return rc;
00255                 }
00256 
00257               /* SaltedPassword := Hi(password, salt) */
00258               err = gc_pbkdf2_sha1 (preppasswd, strlen (preppasswd),
00259                                     salt, saltlen,
00260                                     state->sf.iter, saltedpassword, 20);
00261               gsasl_free (preppasswd);
00262               gsasl_free (salt);
00263               if (err != GC_OK)
00264                 return GSASL_MALLOC_ERROR;
00265             }
00266           else
00267             return GSASL_NO_PASSWORD;
00268 
00269           /* Get client-final-message-without-proof. */
00270           {
00271             char *cfmwp;
00272             int n;
00273 
00274             state->cl.proof = strdup ("p");
00275             rc = scram_print_client_final (&state->cl, &cfmwp);
00276             if (rc != 0)
00277               return GSASL_MALLOC_ERROR;
00278             free (state->cl.proof);
00279 
00280             /* Compute AuthMessage */
00281             n = asprintf (&state->authmessage, "%s,%.*s,%.*s",
00282                           state->cfmb,
00283                           input_len, input,
00284                           strlen (cfmwp) - 4,
00285                           cfmwp);
00286             free (cfmwp);
00287             if (n <= 0 || !state->authmessage)
00288               return GSASL_MALLOC_ERROR;
00289           }
00290 
00291           /* ClientKey := HMAC(SaltedPassword, "Client Key") */
00292 #define CLIENT_KEY "Client Key"
00293           rc = gsasl_hmac_sha1 (saltedpassword, 20,
00294                                 CLIENT_KEY, strlen (CLIENT_KEY),
00295                                 &clientkey);
00296           if (rc != 0)
00297             return rc;
00298 
00299           /* StoredKey := H(ClientKey) */
00300           rc = gsasl_sha1 (clientkey, 20, &storedkey);
00301           if (rc != 0)
00302             {
00303               free (clientkey);
00304               return rc;
00305             }
00306 
00307           /* ClientSignature := HMAC(StoredKey, AuthMessage) */
00308           rc = gsasl_hmac_sha1 (storedkey, 20,
00309                                 state->authmessage,
00310                                 strlen (state->authmessage),
00311                                 &clientsignature);
00312           free (storedkey);
00313           if (rc != 0)
00314             {
00315               free (clientkey);
00316               return rc;
00317             }
00318 
00319           /* ClientProof := ClientKey XOR ClientSignature */
00320           memcpy (clientproof, clientkey, 20);
00321           memxor (clientproof, clientsignature, 20);
00322 
00323           free (clientkey);
00324           free (clientsignature);
00325 
00326           rc = gsasl_base64_to (clientproof, 20, &state->cl.proof, NULL);
00327           if (rc != 0)
00328             return rc;
00329 
00330           /* Generate ServerSignature, for comparison in next step. */
00331           {
00332             char *serverkey;
00333             char *serversignature;
00334 
00335             /* ServerKey := HMAC(SaltedPassword, "Server Key") */
00336 #define SERVER_KEY "Server Key"
00337             rc = gsasl_hmac_sha1 (saltedpassword, 20,
00338                                   SERVER_KEY, strlen (SERVER_KEY),
00339                                   &serverkey);
00340             if (rc != 0)
00341               return rc;
00342 
00343             /* ServerSignature := HMAC(ServerKey, AuthMessage) */
00344             rc = gsasl_hmac_sha1 (serverkey, 20,
00345                                   state->authmessage,
00346                                   strlen (state->authmessage),
00347                                   &serversignature);
00348             gsasl_free (serverkey);
00349             if (rc != 0)
00350               return rc;
00351 
00352             rc = gsasl_base64_to (serversignature, 20,
00353                                   &state->serversignature, NULL);
00354             gsasl_free (serversignature);
00355             if (rc != 0)
00356               return rc;
00357           }
00358         }
00359 
00360         rc = scram_print_client_final (&state->cl, output);
00361         if (rc != 0)
00362           return GSASL_MALLOC_ERROR;
00363 
00364         *output_len = strlen (*output);
00365 
00366         state->step++;
00367         return GSASL_NEEDS_MORE;
00368         break;
00369       }
00370 
00371     case 2:
00372       {
00373         if (scram_parse_server_final (input, input_len, &state->sl) < 0)
00374           return GSASL_MECHANISM_PARSE_ERROR;
00375 
00376         if (strcmp (state->sl.verifier, state->serversignature) != 0)
00377           return GSASL_AUTHENTICATION_ERROR;
00378 
00379         state->step++;
00380         return GSASL_OK;
00381         break;
00382       }
00383 
00384     default:
00385       break;
00386     }
00387 
00388   return res;
00389 }
00390 
00391 void
00392 _gsasl_scram_sha1_client_finish (Gsasl_session * sctx, void *mech_data)
00393 {
00394   struct scram_client_state *state = mech_data;
00395 
00396   if (!state)
00397     return;
00398 
00399   free (state->cfmb);
00400   free (state->serversignature);
00401   free (state->authmessage);
00402   scram_free_client_first (&state->cf);
00403   scram_free_server_first (&state->sf);
00404   scram_free_client_final (&state->cl);
00405   scram_free_server_final (&state->sl);
00406 
00407   free (state);
00408 }