00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 # include "config.h"
00025 #endif
00026
00027
00028 #include "scram.h"
00029
00030
00031 #include <stdlib.h>
00032
00033
00034 #include <string.h>
00035
00036
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;
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
00150 state->cf.cbflag = 'n';
00151
00152 p = gsasl_property_get (sctx, GSASL_AUTHID);
00153 if (!p)
00154 return GSASL_NO_AUTHID;
00155
00156
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
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
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
00212
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
00226 {
00227 char saltedpassword[20];
00228 char *clientkey;
00229 char *storedkey;
00230 char *clientsignature;
00231 char clientproof[20];
00232 const char *p;
00233
00234
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
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
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
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
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
00300 rc = gsasl_sha1 (clientkey, 20, &storedkey);
00301 if (rc != 0)
00302 {
00303 free (clientkey);
00304 return rc;
00305 }
00306
00307
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
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
00331 {
00332 char *serverkey;
00333 char *serversignature;
00334
00335
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
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 }