gsasl  1.8.0
scram/server.c
Go to the documentation of this file.
00001 /* server.c --- SASL CRAM-MD5 server side functions.
00002  * Copyright (C) 2009-2012 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 plus;
00054   int step;
00055   char *cbind;
00056   char *gs2header;              /* copy of client first gs2-header */
00057   char *cfmb_str;               /* copy of client first message bare */
00058   char *sf_str;                 /* copy of server first message */
00059   char *snonce;
00060   char *clientproof;
00061   char *storedkey;
00062   char *serverkey;
00063   char *authmessage;
00064   char *cbtlsunique;
00065   size_t cbtlsuniquelen;
00066   struct scram_client_first cf;
00067   struct scram_server_first sf;
00068   struct scram_client_final cl;
00069   struct scram_server_final sl;
00070 };
00071 
00072 static int
00073 scram_start (Gsasl_session * sctx, void **mech_data, int plus)
00074 {
00075   struct scram_server_state *state;
00076   char buf[MAX (SNONCE_ENTROPY_BYTES, DEFAULT_SALT_BYTES)];
00077   const char *p;
00078   int rc;
00079 
00080   state = (struct scram_server_state *) calloc (sizeof (*state), 1);
00081   if (state == NULL)
00082     return GSASL_MALLOC_ERROR;
00083 
00084   state->plus = plus;
00085 
00086   rc = gsasl_nonce (buf, SNONCE_ENTROPY_BYTES);
00087   if (rc != GSASL_OK)
00088     goto end;
00089 
00090   rc = gsasl_base64_to (buf, SNONCE_ENTROPY_BYTES, &state->snonce, NULL);
00091   if (rc != GSASL_OK)
00092     goto end;
00093 
00094   rc = gsasl_nonce (buf, DEFAULT_SALT_BYTES);
00095   if (rc != GSASL_OK)
00096     goto end;
00097 
00098   rc = gsasl_base64_to (buf, DEFAULT_SALT_BYTES, &state->sf.salt, NULL);
00099   if (rc != GSASL_OK)
00100     goto end;
00101 
00102   p = gsasl_property_get (sctx, GSASL_CB_TLS_UNIQUE);
00103   if (plus && !p)
00104     {
00105       rc = GSASL_NO_CB_TLS_UNIQUE;
00106       goto end;
00107     }
00108   if (p)
00109     {
00110       rc = gsasl_base64_from (p, strlen (p), &state->cbtlsunique,
00111                               &state->cbtlsuniquelen);
00112       if (rc != GSASL_OK)
00113         goto end;
00114     }
00115 
00116   *mech_data = state;
00117 
00118   return GSASL_OK;
00119 
00120 end:
00121   free (state->sf.salt);
00122   free (state->snonce);
00123   free (state);
00124   return rc;
00125 }
00126 
00127 int
00128 _gsasl_scram_sha1_server_start (Gsasl_session * sctx, void **mech_data)
00129 {
00130   return scram_start (sctx, mech_data, 0);
00131 }
00132 
00133 int
00134 _gsasl_scram_sha1_plus_server_start (Gsasl_session * sctx, void **mech_data)
00135 {
00136   return scram_start (sctx, mech_data, 1);
00137 }
00138 
00139 int
00140 _gsasl_scram_sha1_server_step (Gsasl_session * sctx,
00141                                void *mech_data,
00142                                const char *input,
00143                                size_t input_len,
00144                                char **output, size_t * output_len)
00145 {
00146   struct scram_server_state *state = mech_data;
00147   int res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
00148   int rc;
00149 
00150   *output = NULL;
00151   *output_len = 0;
00152 
00153   switch (state->step)
00154     {
00155     case 0:
00156       {
00157         if (input_len == 0)
00158           return GSASL_NEEDS_MORE;
00159 
00160         if (scram_parse_client_first (input, input_len, &state->cf) < 0)
00161           return GSASL_MECHANISM_PARSE_ERROR;
00162 
00163         /* In PLUS server mode, we require use of channel bindings. */
00164         if (state->plus && state->cf.cbflag != 'p')
00165           return GSASL_AUTHENTICATION_ERROR;
00166 
00167         /* In non-PLUS mode, but where have channel bindings data (and
00168            thus advertised PLUS) we reject a client 'y' cbflag. */
00169         if (!state->plus
00170             && state->cbtlsuniquelen > 0 && state->cf.cbflag == 'y')
00171           return GSASL_AUTHENTICATION_ERROR;
00172 
00173         /* Check that username doesn't fail SASLprep. */
00174         {
00175           char *tmp;
00176           rc = gsasl_saslprep (state->cf.username, GSASL_ALLOW_UNASSIGNED,
00177                                &tmp, NULL);
00178           if (rc != GSASL_OK || *tmp == '\0')
00179             return GSASL_AUTHENTICATION_ERROR;
00180           gsasl_free (tmp);
00181         }
00182 
00183         {
00184           const char *p;
00185 
00186           /* Save "gs2-header" and "message-bare" for next step. */
00187           p = memchr (input, ',', input_len);
00188           if (!p)
00189             return GSASL_AUTHENTICATION_ERROR;
00190           p++;
00191           p = memchr (p, ',', input_len - (p - input));
00192           if (!p)
00193             return GSASL_AUTHENTICATION_ERROR;
00194           p++;
00195 
00196           state->gs2header = malloc (p - input + 1);
00197           if (!state->gs2header)
00198             return GSASL_MALLOC_ERROR;
00199           memcpy (state->gs2header, input, p - input);
00200           state->gs2header[p - input] = '\0';
00201 
00202           state->cfmb_str = malloc (input_len - (p - input) + 1);
00203           if (!state->cfmb_str)
00204             return GSASL_MALLOC_ERROR;
00205           memcpy (state->cfmb_str, p, input_len - (p - input));
00206           state->cfmb_str[input_len - (p - input)] = '\0';
00207         }
00208 
00209         /* Create new nonce. */
00210         {
00211           size_t cnlen = strlen (state->cf.client_nonce);
00212 
00213           state->sf.nonce = malloc (cnlen + SNONCE_ENTROPY_BYTES + 1);
00214           if (!state->sf.nonce)
00215             return GSASL_MALLOC_ERROR;
00216 
00217           memcpy (state->sf.nonce, state->cf.client_nonce, cnlen);
00218           memcpy (state->sf.nonce + cnlen, state->snonce,
00219                   SNONCE_ENTROPY_BYTES);
00220           state->sf.nonce[cnlen + SNONCE_ENTROPY_BYTES] = '\0';
00221         }
00222 
00223         gsasl_property_set (sctx, GSASL_AUTHID, state->cf.username);
00224         gsasl_property_set (sctx, GSASL_AUTHZID, state->cf.authzid);
00225 
00226         {
00227           const char *p = gsasl_property_get (sctx, GSASL_SCRAM_ITER);
00228           if (p)
00229             state->sf.iter = strtoul (p, NULL, 10);
00230           if (!p || state->sf.iter == 0 || state->sf.iter == ULONG_MAX)
00231             state->sf.iter = 4096;
00232         }
00233 
00234         {
00235           const char *p = gsasl_property_get (sctx, GSASL_SCRAM_SALT);
00236           if (p)
00237             {
00238               free (state->sf.salt);
00239               state->sf.salt = strdup (p);
00240             }
00241         }
00242 
00243         rc = scram_print_server_first (&state->sf, &state->sf_str);
00244         if (rc != 0)
00245           return GSASL_MALLOC_ERROR;
00246 
00247         *output = strdup (state->sf_str);
00248         if (!*output)
00249           return GSASL_MALLOC_ERROR;
00250         *output_len = strlen (*output);
00251 
00252         state->step++;
00253         return GSASL_NEEDS_MORE;
00254         break;
00255       }
00256 
00257     case 1:
00258       {
00259         if (scram_parse_client_final (input, input_len, &state->cl) < 0)
00260           return GSASL_MECHANISM_PARSE_ERROR;
00261 
00262         if (strcmp (state->cl.nonce, state->sf.nonce) != 0)
00263           return GSASL_AUTHENTICATION_ERROR;
00264 
00265         /* Base64 decode the c= field and check that it matches
00266            client-first.  Also check channel binding data. */
00267         {
00268           size_t len;
00269 
00270           rc = gsasl_base64_from (state->cl.cbind, strlen (state->cl.cbind),
00271                                   &state->cbind, &len);
00272           if (rc != 0)
00273             return rc;
00274 
00275           if (state->cf.cbflag == 'p')
00276             {
00277               if (len < strlen (state->gs2header))
00278                 return GSASL_AUTHENTICATION_ERROR;
00279 
00280               if (memcmp (state->cbind, state->gs2header,
00281                           strlen (state->gs2header)) != 0)
00282                 return GSASL_AUTHENTICATION_ERROR;
00283 
00284               if (len - strlen (state->gs2header) != state->cbtlsuniquelen)
00285                 return GSASL_AUTHENTICATION_ERROR;
00286 
00287               if (memcmp (state->cbind + strlen (state->gs2header),
00288                           state->cbtlsunique, state->cbtlsuniquelen) != 0)
00289                 return GSASL_AUTHENTICATION_ERROR;
00290             }
00291           else
00292             {
00293               if (len != strlen (state->gs2header))
00294                 return GSASL_AUTHENTICATION_ERROR;
00295 
00296               if (memcmp (state->cbind, state->gs2header, len) != 0)
00297                 return GSASL_AUTHENTICATION_ERROR;
00298             }
00299         }
00300 
00301         /* Base64 decode client proof and check that length matches
00302            SHA-1 size. */
00303         {
00304           size_t len;
00305 
00306           rc = gsasl_base64_from (state->cl.proof, strlen (state->cl.proof),
00307                                   &state->clientproof, &len);
00308           if (rc != 0)
00309             return rc;
00310           if (len != 20)
00311             return GSASL_MECHANISM_PARSE_ERROR;
00312         }
00313 
00314         {
00315           const char *p;
00316 
00317           /* Get StoredKey and ServerKey */
00318           if ((p = gsasl_property_get (sctx, GSASL_PASSWORD)))
00319             {
00320               Gc_rc err;
00321               char *salt;
00322               size_t saltlen;
00323               char saltedpassword[20];
00324               char *clientkey;
00325               char *preppasswd;
00326 
00327               rc = gsasl_saslprep (p, 0, &preppasswd, NULL);
00328               if (rc != GSASL_OK)
00329                 return rc;
00330 
00331               rc = gsasl_base64_from (state->sf.salt, strlen (state->sf.salt),
00332                                       &salt, &saltlen);
00333               if (rc != 0)
00334                 {
00335                   gsasl_free (preppasswd);
00336                   return rc;
00337                 }
00338 
00339               /* SaltedPassword := Hi(password, salt) */
00340               err = gc_pbkdf2_sha1 (preppasswd, strlen (preppasswd),
00341                                     salt, saltlen,
00342                                     state->sf.iter, saltedpassword, 20);
00343               gsasl_free (preppasswd);
00344               gsasl_free (salt);
00345               if (err != GC_OK)
00346                 return GSASL_MALLOC_ERROR;
00347 
00348               /* ClientKey := HMAC(SaltedPassword, "Client Key") */
00349 #define CLIENT_KEY "Client Key"
00350               rc = gsasl_hmac_sha1 (saltedpassword, 20,
00351                                     CLIENT_KEY, strlen (CLIENT_KEY),
00352                                     &clientkey);
00353               if (rc != 0)
00354                 return rc;
00355 
00356               /* StoredKey := H(ClientKey) */
00357               rc = gsasl_sha1 (clientkey, 20, &state->storedkey);
00358               free (clientkey);
00359               if (rc != 0)
00360                 return rc;
00361 
00362               /* ServerKey := HMAC(SaltedPassword, "Server Key") */
00363 #define SERVER_KEY "Server Key"
00364               rc = gsasl_hmac_sha1 (saltedpassword, 20,
00365                                     SERVER_KEY, strlen (SERVER_KEY),
00366                                     &state->serverkey);
00367               if (rc != 0)
00368                 return rc;
00369             }
00370           else
00371             return GSASL_NO_PASSWORD;
00372 
00373           /* Compute AuthMessage */
00374           {
00375             size_t len;
00376             int n;
00377 
00378             /* Get client-final-message-without-proof. */
00379             p = memmem (input, input_len, ",p=", 3);
00380             if (!p)
00381               return GSASL_MECHANISM_PARSE_ERROR;
00382             len = p - input;
00383 
00384             n = asprintf (&state->authmessage, "%s,%.*s,%.*s",
00385                           state->cfmb_str,
00386                           (int) strlen (state->sf_str), state->sf_str,
00387                           (int) len, input);
00388             if (n <= 0 || !state->authmessage)
00389               return GSASL_MALLOC_ERROR;
00390           }
00391 
00392           /* Check client proof. */
00393           {
00394             char *clientsignature;
00395             char *maybe_storedkey;
00396 
00397             /* ClientSignature := HMAC(StoredKey, AuthMessage) */
00398             rc = gsasl_hmac_sha1 (state->storedkey, 20,
00399                                   state->authmessage,
00400                                   strlen (state->authmessage),
00401                                   &clientsignature);
00402             if (rc != 0)
00403               return rc;
00404 
00405             /* ClientKey := ClientProof XOR ClientSignature */
00406             memxor (clientsignature, state->clientproof, 20);
00407 
00408             rc = gsasl_sha1 (clientsignature, 20, &maybe_storedkey);
00409             free (clientsignature);
00410             if (rc != 0)
00411               return rc;
00412 
00413             rc = memcmp (state->storedkey, maybe_storedkey, 20);
00414             free (maybe_storedkey);
00415             if (rc != 0)
00416               return GSASL_AUTHENTICATION_ERROR;
00417           }
00418 
00419           /* Generate server verifier. */
00420           {
00421             char *serversignature;
00422 
00423             /* ServerSignature := HMAC(ServerKey, AuthMessage) */
00424             rc = gsasl_hmac_sha1 (state->serverkey, 20,
00425                                   state->authmessage,
00426                                   strlen (state->authmessage),
00427                                   &serversignature);
00428             if (rc != 0)
00429               return rc;
00430 
00431             rc = gsasl_base64_to (serversignature, 20,
00432                                   &state->sl.verifier, NULL);
00433             free (serversignature);
00434             if (rc != 0)
00435               return rc;
00436           }
00437         }
00438 
00439         rc = scram_print_server_final (&state->sl, output);
00440         if (rc != 0)
00441           return GSASL_MALLOC_ERROR;
00442         *output_len = strlen (*output);
00443 
00444         state->step++;
00445         return GSASL_OK;
00446         break;
00447       }
00448 
00449     default:
00450       break;
00451     }
00452 
00453   return res;
00454 }
00455 
00456 void
00457 _gsasl_scram_sha1_server_finish (Gsasl_session * sctx, void *mech_data)
00458 {
00459   struct scram_server_state *state = mech_data;
00460 
00461   if (!state)
00462     return;
00463 
00464   free (state->cbind);
00465   free (state->gs2header);
00466   free (state->cfmb_str);
00467   free (state->sf_str);
00468   free (state->snonce);
00469   free (state->clientproof);
00470   free (state->storedkey);
00471   free (state->serverkey);
00472   free (state->authmessage);
00473   free (state->cbtlsunique);
00474   scram_free_client_first (&state->cf);
00475   scram_free_server_first (&state->sf);
00476   scram_free_client_final (&state->cl);
00477   scram_free_server_final (&state->sl);
00478 
00479   free (state);
00480 }