|
gsasl
1.8.0
|
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 }
1.7.6.1