srp_vfy.c revision 284285
1/* crypto/srp/srp_vfy.c */ 2/* 3 * Written by Christophe Renou (christophe.renou@edelweb.fr) with the 4 * precious help of Peter Sylvester (peter.sylvester@edelweb.fr) for the 5 * EdelKey project and contributed to the OpenSSL project 2004. 6 */ 7/* ==================================================================== 8 * Copyright (c) 2004 The OpenSSL Project. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in 19 * the documentation and/or other materials provided with the 20 * distribution. 21 * 22 * 3. All advertising materials mentioning features or use of this 23 * software must display the following acknowledgment: 24 * "This product includes software developed by the OpenSSL Project 25 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 26 * 27 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 28 * endorse or promote products derived from this software without 29 * prior written permission. For written permission, please contact 30 * licensing@OpenSSL.org. 31 * 32 * 5. Products derived from this software may not be called "OpenSSL" 33 * nor may "OpenSSL" appear in their names without prior written 34 * permission of the OpenSSL Project. 35 * 36 * 6. Redistributions of any form whatsoever must retain the following 37 * acknowledgment: 38 * "This product includes software developed by the OpenSSL Project 39 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 42 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 44 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 45 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 46 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 47 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 48 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 50 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 51 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 52 * OF THE POSSIBILITY OF SUCH DAMAGE. 53 * ==================================================================== 54 * 55 * This product includes cryptographic software written by Eric Young 56 * (eay@cryptsoft.com). This product includes software written by Tim 57 * Hudson (tjh@cryptsoft.com). 58 * 59 */ 60#ifndef OPENSSL_NO_SRP 61# include "cryptlib.h" 62# include "srp_lcl.h" 63# include <openssl/srp.h> 64# include <openssl/evp.h> 65# include <openssl/buffer.h> 66# include <openssl/rand.h> 67# include <openssl/txt_db.h> 68 69# define SRP_RANDOM_SALT_LEN 20 70# define MAX_LEN 2500 71 72static char b64table[] = 73 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./"; 74 75/* 76 * the following two conversion routines have been inspired by code from 77 * Stanford 78 */ 79 80/* 81 * Convert a base64 string into raw byte array representation. 82 */ 83static int t_fromb64(unsigned char *a, const char *src) 84{ 85 char *loc; 86 int i, j; 87 int size; 88 89 while (*src && (*src == ' ' || *src == '\t' || *src == '\n')) 90 ++src; 91 size = strlen(src); 92 i = 0; 93 while (i < size) { 94 loc = strchr(b64table, src[i]); 95 if (loc == (char *)0) 96 break; 97 else 98 a[i] = loc - b64table; 99 ++i; 100 } 101 /* if nothing valid to process we have a zero length response */ 102 if (i == 0) 103 return 0; 104 size = i; 105 i = size - 1; 106 j = size; 107 while (1) { 108 a[j] = a[i]; 109 if (--i < 0) 110 break; 111 a[j] |= (a[i] & 3) << 6; 112 --j; 113 a[j] = (unsigned char)((a[i] & 0x3c) >> 2); 114 if (--i < 0) 115 break; 116 a[j] |= (a[i] & 0xf) << 4; 117 --j; 118 a[j] = (unsigned char)((a[i] & 0x30) >> 4); 119 if (--i < 0) 120 break; 121 a[j] |= (a[i] << 2); 122 123 a[--j] = 0; 124 if (--i < 0) 125 break; 126 } 127 while (a[j] == 0 && j <= size) 128 ++j; 129 i = 0; 130 while (j <= size) 131 a[i++] = a[j++]; 132 return i; 133} 134 135/* 136 * Convert a raw byte string into a null-terminated base64 ASCII string. 137 */ 138static char *t_tob64(char *dst, const unsigned char *src, int size) 139{ 140 int c, pos = size % 3; 141 unsigned char b0 = 0, b1 = 0, b2 = 0, notleading = 0; 142 char *olddst = dst; 143 144 switch (pos) { 145 case 1: 146 b2 = src[0]; 147 break; 148 case 2: 149 b1 = src[0]; 150 b2 = src[1]; 151 break; 152 } 153 154 while (1) { 155 c = (b0 & 0xfc) >> 2; 156 if (notleading || c != 0) { 157 *dst++ = b64table[c]; 158 notleading = 1; 159 } 160 c = ((b0 & 3) << 4) | ((b1 & 0xf0) >> 4); 161 if (notleading || c != 0) { 162 *dst++ = b64table[c]; 163 notleading = 1; 164 } 165 c = ((b1 & 0xf) << 2) | ((b2 & 0xc0) >> 6); 166 if (notleading || c != 0) { 167 *dst++ = b64table[c]; 168 notleading = 1; 169 } 170 c = b2 & 0x3f; 171 if (notleading || c != 0) { 172 *dst++ = b64table[c]; 173 notleading = 1; 174 } 175 if (pos >= size) 176 break; 177 else { 178 b0 = src[pos++]; 179 b1 = src[pos++]; 180 b2 = src[pos++]; 181 } 182 } 183 184 *dst++ = '\0'; 185 return olddst; 186} 187 188static void SRP_user_pwd_free(SRP_user_pwd *user_pwd) 189{ 190 if (user_pwd == NULL) 191 return; 192 BN_free(user_pwd->s); 193 BN_clear_free(user_pwd->v); 194 OPENSSL_free(user_pwd->id); 195 OPENSSL_free(user_pwd->info); 196 OPENSSL_free(user_pwd); 197} 198 199static SRP_user_pwd *SRP_user_pwd_new() 200{ 201 SRP_user_pwd *ret = OPENSSL_malloc(sizeof(SRP_user_pwd)); 202 if (ret == NULL) 203 return NULL; 204 ret->N = NULL; 205 ret->g = NULL; 206 ret->s = NULL; 207 ret->v = NULL; 208 ret->id = NULL; 209 ret->info = NULL; 210 return ret; 211} 212 213static void SRP_user_pwd_set_gN(SRP_user_pwd *vinfo, const BIGNUM *g, 214 const BIGNUM *N) 215{ 216 vinfo->N = N; 217 vinfo->g = g; 218} 219 220static int SRP_user_pwd_set_ids(SRP_user_pwd *vinfo, const char *id, 221 const char *info) 222{ 223 if (id != NULL && NULL == (vinfo->id = BUF_strdup(id))) 224 return 0; 225 return (info == NULL || NULL != (vinfo->info = BUF_strdup(info))); 226} 227 228static int SRP_user_pwd_set_sv(SRP_user_pwd *vinfo, const char *s, 229 const char *v) 230{ 231 unsigned char tmp[MAX_LEN]; 232 int len; 233 234 if (strlen(s) > MAX_LEN || strlen(v) > MAX_LEN) 235 return 0; 236 len = t_fromb64(tmp, v); 237 if (NULL == (vinfo->v = BN_bin2bn(tmp, len, NULL))) 238 return 0; 239 len = t_fromb64(tmp, s); 240 return ((vinfo->s = BN_bin2bn(tmp, len, NULL)) != NULL); 241} 242 243static int SRP_user_pwd_set_sv_BN(SRP_user_pwd *vinfo, BIGNUM *s, BIGNUM *v) 244{ 245 vinfo->v = v; 246 vinfo->s = s; 247 return (vinfo->s != NULL && vinfo->v != NULL); 248} 249 250SRP_VBASE *SRP_VBASE_new(char *seed_key) 251{ 252 SRP_VBASE *vb = (SRP_VBASE *)OPENSSL_malloc(sizeof(SRP_VBASE)); 253 254 if (vb == NULL) 255 return NULL; 256 if (!(vb->users_pwd = sk_SRP_user_pwd_new_null()) || 257 !(vb->gN_cache = sk_SRP_gN_cache_new_null())) { 258 OPENSSL_free(vb); 259 return NULL; 260 } 261 vb->default_g = NULL; 262 vb->default_N = NULL; 263 vb->seed_key = NULL; 264 if ((seed_key != NULL) && (vb->seed_key = BUF_strdup(seed_key)) == NULL) { 265 sk_SRP_user_pwd_free(vb->users_pwd); 266 sk_SRP_gN_cache_free(vb->gN_cache); 267 OPENSSL_free(vb); 268 return NULL; 269 } 270 return vb; 271} 272 273int SRP_VBASE_free(SRP_VBASE *vb) 274{ 275 sk_SRP_user_pwd_pop_free(vb->users_pwd, SRP_user_pwd_free); 276 sk_SRP_gN_cache_free(vb->gN_cache); 277 OPENSSL_free(vb->seed_key); 278 OPENSSL_free(vb); 279 return 0; 280} 281 282static SRP_gN_cache *SRP_gN_new_init(const char *ch) 283{ 284 unsigned char tmp[MAX_LEN]; 285 int len; 286 287 SRP_gN_cache *newgN = 288 (SRP_gN_cache *)OPENSSL_malloc(sizeof(SRP_gN_cache)); 289 if (newgN == NULL) 290 return NULL; 291 292 if ((newgN->b64_bn = BUF_strdup(ch)) == NULL) 293 goto err; 294 295 len = t_fromb64(tmp, ch); 296 if ((newgN->bn = BN_bin2bn(tmp, len, NULL))) 297 return newgN; 298 299 OPENSSL_free(newgN->b64_bn); 300 err: 301 OPENSSL_free(newgN); 302 return NULL; 303} 304 305static void SRP_gN_free(SRP_gN_cache *gN_cache) 306{ 307 if (gN_cache == NULL) 308 return; 309 OPENSSL_free(gN_cache->b64_bn); 310 BN_free(gN_cache->bn); 311 OPENSSL_free(gN_cache); 312} 313 314static SRP_gN *SRP_get_gN_by_id(const char *id, STACK_OF(SRP_gN) *gN_tab) 315{ 316 int i; 317 318 SRP_gN *gN; 319 if (gN_tab != NULL) 320 for (i = 0; i < sk_SRP_gN_num(gN_tab); i++) { 321 gN = sk_SRP_gN_value(gN_tab, i); 322 if (gN && (id == NULL || strcmp(gN->id, id) == 0)) 323 return gN; 324 } 325 326 return SRP_get_default_gN(id); 327} 328 329static BIGNUM *SRP_gN_place_bn(STACK_OF(SRP_gN_cache) *gN_cache, char *ch) 330{ 331 int i; 332 if (gN_cache == NULL) 333 return NULL; 334 335 /* search if we have already one... */ 336 for (i = 0; i < sk_SRP_gN_cache_num(gN_cache); i++) { 337 SRP_gN_cache *cache = sk_SRP_gN_cache_value(gN_cache, i); 338 if (strcmp(cache->b64_bn, ch) == 0) 339 return cache->bn; 340 } 341 { /* it is the first time that we find it */ 342 SRP_gN_cache *newgN = SRP_gN_new_init(ch); 343 if (newgN) { 344 if (sk_SRP_gN_cache_insert(gN_cache, newgN, 0) > 0) 345 return newgN->bn; 346 SRP_gN_free(newgN); 347 } 348 } 349 return NULL; 350} 351 352/* 353 * this function parses verifier file. Format is: 354 * string(index):base64(N):base64(g):0 355 * string(username):base64(v):base64(salt):int(index) 356 */ 357 358int SRP_VBASE_init(SRP_VBASE *vb, char *verifier_file) 359{ 360 int error_code; 361 STACK_OF(SRP_gN) *SRP_gN_tab = sk_SRP_gN_new_null(); 362 char *last_index = NULL; 363 int i; 364 char **pp; 365 366 SRP_gN *gN = NULL; 367 SRP_user_pwd *user_pwd = NULL; 368 369 TXT_DB *tmpdb = NULL; 370 BIO *in = BIO_new(BIO_s_file()); 371 372 error_code = SRP_ERR_OPEN_FILE; 373 374 if (in == NULL || BIO_read_filename(in, verifier_file) <= 0) 375 goto err; 376 377 error_code = SRP_ERR_VBASE_INCOMPLETE_FILE; 378 379 if ((tmpdb = TXT_DB_read(in, DB_NUMBER)) == NULL) 380 goto err; 381 382 error_code = SRP_ERR_MEMORY; 383 384 if (vb->seed_key) { 385 last_index = SRP_get_default_gN(NULL)->id; 386 } 387 for (i = 0; i < sk_OPENSSL_PSTRING_num(tmpdb->data); i++) { 388 pp = sk_OPENSSL_PSTRING_value(tmpdb->data, i); 389 if (pp[DB_srptype][0] == DB_SRP_INDEX) { 390 /* 391 * we add this couple in the internal Stack 392 */ 393 394 if ((gN = (SRP_gN *) OPENSSL_malloc(sizeof(SRP_gN))) == NULL) 395 goto err; 396 397 if (!(gN->id = BUF_strdup(pp[DB_srpid])) 398 || !(gN->N = 399 SRP_gN_place_bn(vb->gN_cache, pp[DB_srpverifier])) 400 || !(gN->g = SRP_gN_place_bn(vb->gN_cache, pp[DB_srpsalt])) 401 || sk_SRP_gN_insert(SRP_gN_tab, gN, 0) == 0) 402 goto err; 403 404 gN = NULL; 405 406 if (vb->seed_key != NULL) { 407 last_index = pp[DB_srpid]; 408 } 409 } else if (pp[DB_srptype][0] == DB_SRP_VALID) { 410 /* it is a user .... */ 411 SRP_gN *lgN; 412 if ((lgN = SRP_get_gN_by_id(pp[DB_srpgN], SRP_gN_tab)) != NULL) { 413 error_code = SRP_ERR_MEMORY; 414 if ((user_pwd = SRP_user_pwd_new()) == NULL) 415 goto err; 416 417 SRP_user_pwd_set_gN(user_pwd, lgN->g, lgN->N); 418 if (!SRP_user_pwd_set_ids 419 (user_pwd, pp[DB_srpid], pp[DB_srpinfo])) 420 goto err; 421 422 error_code = SRP_ERR_VBASE_BN_LIB; 423 if (!SRP_user_pwd_set_sv 424 (user_pwd, pp[DB_srpsalt], pp[DB_srpverifier])) 425 goto err; 426 427 if (sk_SRP_user_pwd_insert(vb->users_pwd, user_pwd, 0) == 0) 428 goto err; 429 user_pwd = NULL; /* abandon responsability */ 430 } 431 } 432 } 433 434 if (last_index != NULL) { 435 /* this means that we want to simulate a default user */ 436 437 if (((gN = SRP_get_gN_by_id(last_index, SRP_gN_tab)) == NULL)) { 438 error_code = SRP_ERR_VBASE_BN_LIB; 439 goto err; 440 } 441 vb->default_g = gN->g; 442 vb->default_N = gN->N; 443 gN = NULL; 444 } 445 error_code = SRP_NO_ERROR; 446 447 err: 448 /* 449 * there may be still some leaks to fix, if this fails, the application 450 * terminates most likely 451 */ 452 453 if (gN != NULL) { 454 OPENSSL_free(gN->id); 455 OPENSSL_free(gN); 456 } 457 458 SRP_user_pwd_free(user_pwd); 459 460 if (tmpdb) 461 TXT_DB_free(tmpdb); 462 if (in) 463 BIO_free_all(in); 464 465 sk_SRP_gN_free(SRP_gN_tab); 466 467 return error_code; 468 469} 470 471SRP_user_pwd *SRP_VBASE_get_by_user(SRP_VBASE *vb, char *username) 472{ 473 int i; 474 SRP_user_pwd *user; 475 unsigned char digv[SHA_DIGEST_LENGTH]; 476 unsigned char digs[SHA_DIGEST_LENGTH]; 477 EVP_MD_CTX ctxt; 478 479 if (vb == NULL) 480 return NULL; 481 for (i = 0; i < sk_SRP_user_pwd_num(vb->users_pwd); i++) { 482 user = sk_SRP_user_pwd_value(vb->users_pwd, i); 483 if (strcmp(user->id, username) == 0) 484 return user; 485 } 486 if ((vb->seed_key == NULL) || 487 (vb->default_g == NULL) || (vb->default_N == NULL)) 488 return NULL; 489 490/* if the user is unknown we set parameters as well if we have a seed_key */ 491 492 if ((user = SRP_user_pwd_new()) == NULL) 493 return NULL; 494 495 SRP_user_pwd_set_gN(user, vb->default_g, vb->default_N); 496 497 if (!SRP_user_pwd_set_ids(user, username, NULL)) 498 goto err; 499 500 if (RAND_pseudo_bytes(digv, SHA_DIGEST_LENGTH) < 0) 501 goto err; 502 EVP_MD_CTX_init(&ctxt); 503 EVP_DigestInit_ex(&ctxt, EVP_sha1(), NULL); 504 EVP_DigestUpdate(&ctxt, vb->seed_key, strlen(vb->seed_key)); 505 EVP_DigestUpdate(&ctxt, username, strlen(username)); 506 EVP_DigestFinal_ex(&ctxt, digs, NULL); 507 EVP_MD_CTX_cleanup(&ctxt); 508 if (SRP_user_pwd_set_sv_BN 509 (user, BN_bin2bn(digs, SHA_DIGEST_LENGTH, NULL), 510 BN_bin2bn(digv, SHA_DIGEST_LENGTH, NULL))) 511 return user; 512 513 err:SRP_user_pwd_free(user); 514 return NULL; 515} 516 517/* 518 * create a verifier (*salt,*verifier,g and N are in base64) 519 */ 520char *SRP_create_verifier(const char *user, const char *pass, char **salt, 521 char **verifier, const char *N, const char *g) 522{ 523 int len; 524 char *result = NULL; 525 char *vf; 526 BIGNUM *N_bn = NULL, *g_bn = NULL, *s = NULL, *v = NULL; 527 unsigned char tmp[MAX_LEN]; 528 unsigned char tmp2[MAX_LEN]; 529 char *defgNid = NULL; 530 531 if ((user == NULL) || 532 (pass == NULL) || (salt == NULL) || (verifier == NULL)) 533 goto err; 534 535 if (N) { 536 if (!(len = t_fromb64(tmp, N))) 537 goto err; 538 N_bn = BN_bin2bn(tmp, len, NULL); 539 if (!(len = t_fromb64(tmp, g))) 540 goto err; 541 g_bn = BN_bin2bn(tmp, len, NULL); 542 defgNid = "*"; 543 } else { 544 SRP_gN *gN = SRP_get_gN_by_id(g, NULL); 545 if (gN == NULL) 546 goto err; 547 N_bn = gN->N; 548 g_bn = gN->g; 549 defgNid = gN->id; 550 } 551 552 if (*salt == NULL) { 553 if (RAND_pseudo_bytes(tmp2, SRP_RANDOM_SALT_LEN) < 0) 554 goto err; 555 556 s = BN_bin2bn(tmp2, SRP_RANDOM_SALT_LEN, NULL); 557 } else { 558 if (!(len = t_fromb64(tmp2, *salt))) 559 goto err; 560 s = BN_bin2bn(tmp2, len, NULL); 561 } 562 563 if (!SRP_create_verifier_BN(user, pass, &s, &v, N_bn, g_bn)) 564 goto err; 565 566 BN_bn2bin(v, tmp); 567 if (((vf = OPENSSL_malloc(BN_num_bytes(v) * 2)) == NULL)) 568 goto err; 569 t_tob64(vf, tmp, BN_num_bytes(v)); 570 571 *verifier = vf; 572 if (*salt == NULL) { 573 char *tmp_salt; 574 575 if ((tmp_salt = OPENSSL_malloc(SRP_RANDOM_SALT_LEN * 2)) == NULL) { 576 OPENSSL_free(vf); 577 goto err; 578 } 579 t_tob64(tmp_salt, tmp2, SRP_RANDOM_SALT_LEN); 580 *salt = tmp_salt; 581 } 582 583 result = defgNid; 584 585 err: 586 if (N) { 587 BN_free(N_bn); 588 BN_free(g_bn); 589 } 590 return result; 591} 592 593/* 594 * create a verifier (*salt,*verifier,g and N are BIGNUMs) 595 */ 596int SRP_create_verifier_BN(const char *user, const char *pass, BIGNUM **salt, 597 BIGNUM **verifier, BIGNUM *N, BIGNUM *g) 598{ 599 int result = 0; 600 BIGNUM *x = NULL; 601 BN_CTX *bn_ctx = BN_CTX_new(); 602 unsigned char tmp2[MAX_LEN]; 603 604 if ((user == NULL) || 605 (pass == NULL) || 606 (salt == NULL) || 607 (verifier == NULL) || (N == NULL) || (g == NULL) || (bn_ctx == NULL)) 608 goto err; 609 610 srp_bn_print(N); 611 srp_bn_print(g); 612 613 if (*salt == NULL) { 614 if (RAND_pseudo_bytes(tmp2, SRP_RANDOM_SALT_LEN) < 0) 615 goto err; 616 617 *salt = BN_bin2bn(tmp2, SRP_RANDOM_SALT_LEN, NULL); 618 } 619 620 x = SRP_Calc_x(*salt, user, pass); 621 622 *verifier = BN_new(); 623 if (*verifier == NULL) 624 goto err; 625 626 if (!BN_mod_exp(*verifier, g, x, N, bn_ctx)) { 627 BN_clear_free(*verifier); 628 goto err; 629 } 630 631 srp_bn_print(*verifier); 632 633 result = 1; 634 635 err: 636 637 BN_clear_free(x); 638 BN_CTX_free(bn_ctx); 639 return result; 640} 641 642#endif 643