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 188void 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 250static SRP_user_pwd *srp_user_pwd_dup(SRP_user_pwd *src) 251{ 252 SRP_user_pwd *ret; 253 254 if (src == NULL) 255 return NULL; 256 if ((ret = SRP_user_pwd_new()) == NULL) 257 return NULL; 258 259 SRP_user_pwd_set_gN(ret, src->g, src->N); 260 if (!SRP_user_pwd_set_ids(ret, src->id, src->info) 261 || !SRP_user_pwd_set_sv_BN(ret, BN_dup(src->s), BN_dup(src->v))) { 262 SRP_user_pwd_free(ret); 263 return NULL; 264 } 265 return ret; 266} 267 268SRP_VBASE *SRP_VBASE_new(char *seed_key) 269{ 270 SRP_VBASE *vb = (SRP_VBASE *)OPENSSL_malloc(sizeof(SRP_VBASE)); 271 272 if (vb == NULL) 273 return NULL; 274 if (!(vb->users_pwd = sk_SRP_user_pwd_new_null()) || 275 !(vb->gN_cache = sk_SRP_gN_cache_new_null())) { 276 OPENSSL_free(vb); 277 return NULL; 278 } 279 vb->default_g = NULL; 280 vb->default_N = NULL; 281 vb->seed_key = NULL; 282 if ((seed_key != NULL) && (vb->seed_key = BUF_strdup(seed_key)) == NULL) { 283 sk_SRP_user_pwd_free(vb->users_pwd); 284 sk_SRP_gN_cache_free(vb->gN_cache); 285 OPENSSL_free(vb); 286 return NULL; 287 } 288 return vb; 289} 290 291int SRP_VBASE_free(SRP_VBASE *vb) 292{ 293 sk_SRP_user_pwd_pop_free(vb->users_pwd, SRP_user_pwd_free); 294 sk_SRP_gN_cache_free(vb->gN_cache); 295 OPENSSL_free(vb->seed_key); 296 OPENSSL_free(vb); 297 return 0; 298} 299 300static SRP_gN_cache *SRP_gN_new_init(const char *ch) 301{ 302 unsigned char tmp[MAX_LEN]; 303 int len; 304 305 SRP_gN_cache *newgN = 306 (SRP_gN_cache *)OPENSSL_malloc(sizeof(SRP_gN_cache)); 307 if (newgN == NULL) 308 return NULL; 309 310 if ((newgN->b64_bn = BUF_strdup(ch)) == NULL) 311 goto err; 312 313 len = t_fromb64(tmp, ch); 314 if ((newgN->bn = BN_bin2bn(tmp, len, NULL))) 315 return newgN; 316 317 OPENSSL_free(newgN->b64_bn); 318 err: 319 OPENSSL_free(newgN); 320 return NULL; 321} 322 323static void SRP_gN_free(SRP_gN_cache *gN_cache) 324{ 325 if (gN_cache == NULL) 326 return; 327 OPENSSL_free(gN_cache->b64_bn); 328 BN_free(gN_cache->bn); 329 OPENSSL_free(gN_cache); 330} 331 332static SRP_gN *SRP_get_gN_by_id(const char *id, STACK_OF(SRP_gN) *gN_tab) 333{ 334 int i; 335 336 SRP_gN *gN; 337 if (gN_tab != NULL) 338 for (i = 0; i < sk_SRP_gN_num(gN_tab); i++) { 339 gN = sk_SRP_gN_value(gN_tab, i); 340 if (gN && (id == NULL || strcmp(gN->id, id) == 0)) 341 return gN; 342 } 343 344 return SRP_get_default_gN(id); 345} 346 347static BIGNUM *SRP_gN_place_bn(STACK_OF(SRP_gN_cache) *gN_cache, char *ch) 348{ 349 int i; 350 if (gN_cache == NULL) 351 return NULL; 352 353 /* search if we have already one... */ 354 for (i = 0; i < sk_SRP_gN_cache_num(gN_cache); i++) { 355 SRP_gN_cache *cache = sk_SRP_gN_cache_value(gN_cache, i); 356 if (strcmp(cache->b64_bn, ch) == 0) 357 return cache->bn; 358 } 359 { /* it is the first time that we find it */ 360 SRP_gN_cache *newgN = SRP_gN_new_init(ch); 361 if (newgN) { 362 if (sk_SRP_gN_cache_insert(gN_cache, newgN, 0) > 0) 363 return newgN->bn; 364 SRP_gN_free(newgN); 365 } 366 } 367 return NULL; 368} 369 370/* 371 * this function parses verifier file. Format is: 372 * string(index):base64(N):base64(g):0 373 * string(username):base64(v):base64(salt):int(index) 374 */ 375 376int SRP_VBASE_init(SRP_VBASE *vb, char *verifier_file) 377{ 378 int error_code; 379 STACK_OF(SRP_gN) *SRP_gN_tab = sk_SRP_gN_new_null(); 380 char *last_index = NULL; 381 int i; 382 char **pp; 383 384 SRP_gN *gN = NULL; 385 SRP_user_pwd *user_pwd = NULL; 386 387 TXT_DB *tmpdb = NULL; 388 BIO *in = BIO_new(BIO_s_file()); 389 390 error_code = SRP_ERR_OPEN_FILE; 391 392 if (in == NULL || BIO_read_filename(in, verifier_file) <= 0) 393 goto err; 394 395 error_code = SRP_ERR_VBASE_INCOMPLETE_FILE; 396 397 if ((tmpdb = TXT_DB_read(in, DB_NUMBER)) == NULL) 398 goto err; 399 400 error_code = SRP_ERR_MEMORY; 401 402 if (vb->seed_key) { 403 last_index = SRP_get_default_gN(NULL)->id; 404 } 405 for (i = 0; i < sk_OPENSSL_PSTRING_num(tmpdb->data); i++) { 406 pp = sk_OPENSSL_PSTRING_value(tmpdb->data, i); 407 if (pp[DB_srptype][0] == DB_SRP_INDEX) { 408 /* 409 * we add this couple in the internal Stack 410 */ 411 412 if ((gN = (SRP_gN *) OPENSSL_malloc(sizeof(SRP_gN))) == NULL) 413 goto err; 414 415 if (!(gN->id = BUF_strdup(pp[DB_srpid])) 416 || !(gN->N = 417 SRP_gN_place_bn(vb->gN_cache, pp[DB_srpverifier])) 418 || !(gN->g = SRP_gN_place_bn(vb->gN_cache, pp[DB_srpsalt])) 419 || sk_SRP_gN_insert(SRP_gN_tab, gN, 0) == 0) 420 goto err; 421 422 gN = NULL; 423 424 if (vb->seed_key != NULL) { 425 last_index = pp[DB_srpid]; 426 } 427 } else if (pp[DB_srptype][0] == DB_SRP_VALID) { 428 /* it is a user .... */ 429 SRP_gN *lgN; 430 if ((lgN = SRP_get_gN_by_id(pp[DB_srpgN], SRP_gN_tab)) != NULL) { 431 error_code = SRP_ERR_MEMORY; 432 if ((user_pwd = SRP_user_pwd_new()) == NULL) 433 goto err; 434 435 SRP_user_pwd_set_gN(user_pwd, lgN->g, lgN->N); 436 if (!SRP_user_pwd_set_ids 437 (user_pwd, pp[DB_srpid], pp[DB_srpinfo])) 438 goto err; 439 440 error_code = SRP_ERR_VBASE_BN_LIB; 441 if (!SRP_user_pwd_set_sv 442 (user_pwd, pp[DB_srpsalt], pp[DB_srpverifier])) 443 goto err; 444 445 if (sk_SRP_user_pwd_insert(vb->users_pwd, user_pwd, 0) == 0) 446 goto err; 447 user_pwd = NULL; /* abandon responsability */ 448 } 449 } 450 } 451 452 if (last_index != NULL) { 453 /* this means that we want to simulate a default user */ 454 455 if (((gN = SRP_get_gN_by_id(last_index, SRP_gN_tab)) == NULL)) { 456 error_code = SRP_ERR_VBASE_BN_LIB; 457 goto err; 458 } 459 vb->default_g = gN->g; 460 vb->default_N = gN->N; 461 gN = NULL; 462 } 463 error_code = SRP_NO_ERROR; 464 465 err: 466 /* 467 * there may be still some leaks to fix, if this fails, the application 468 * terminates most likely 469 */ 470 471 if (gN != NULL) { 472 OPENSSL_free(gN->id); 473 OPENSSL_free(gN); 474 } 475 476 SRP_user_pwd_free(user_pwd); 477 478 if (tmpdb) 479 TXT_DB_free(tmpdb); 480 if (in) 481 BIO_free_all(in); 482 483 sk_SRP_gN_free(SRP_gN_tab); 484 485 return error_code; 486 487} 488 489static SRP_user_pwd *find_user(SRP_VBASE *vb, char *username) 490{ 491 int i; 492 SRP_user_pwd *user; 493 494 if (vb == NULL) 495 return NULL; 496 497 for (i = 0; i < sk_SRP_user_pwd_num(vb->users_pwd); i++) { 498 user = sk_SRP_user_pwd_value(vb->users_pwd, i); 499 if (strcmp(user->id, username) == 0) 500 return user; 501 } 502 503 return NULL; 504} 505 506/* 507 * This method ignores the configured seed and fails for an unknown user. 508 * Ownership of the returned pointer is not released to the caller. 509 * In other words, caller must not free the result. 510 */ 511SRP_user_pwd *SRP_VBASE_get_by_user(SRP_VBASE *vb, char *username) 512{ 513 return find_user(vb, username); 514} 515 516/* 517 * Ownership of the returned pointer is released to the caller. 518 * In other words, caller must free the result once done. 519 */ 520SRP_user_pwd *SRP_VBASE_get1_by_user(SRP_VBASE *vb, char *username) 521{ 522 SRP_user_pwd *user; 523 unsigned char digv[SHA_DIGEST_LENGTH]; 524 unsigned char digs[SHA_DIGEST_LENGTH]; 525 EVP_MD_CTX ctxt; 526 527 if (vb == NULL) 528 return NULL; 529 530 if ((user = find_user(vb, username)) != NULL) 531 return srp_user_pwd_dup(user); 532 533 if ((vb->seed_key == NULL) || 534 (vb->default_g == NULL) || (vb->default_N == NULL)) 535 return NULL; 536 537/* if the user is unknown we set parameters as well if we have a seed_key */ 538 539 if ((user = SRP_user_pwd_new()) == NULL) 540 return NULL; 541 542 SRP_user_pwd_set_gN(user, vb->default_g, vb->default_N); 543 544 if (!SRP_user_pwd_set_ids(user, username, NULL)) 545 goto err; 546 547 if (RAND_pseudo_bytes(digv, SHA_DIGEST_LENGTH) < 0) 548 goto err; 549 EVP_MD_CTX_init(&ctxt); 550 EVP_DigestInit_ex(&ctxt, EVP_sha1(), NULL); 551 EVP_DigestUpdate(&ctxt, vb->seed_key, strlen(vb->seed_key)); 552 EVP_DigestUpdate(&ctxt, username, strlen(username)); 553 EVP_DigestFinal_ex(&ctxt, digs, NULL); 554 EVP_MD_CTX_cleanup(&ctxt); 555 if (SRP_user_pwd_set_sv_BN 556 (user, BN_bin2bn(digs, SHA_DIGEST_LENGTH, NULL), 557 BN_bin2bn(digv, SHA_DIGEST_LENGTH, NULL))) 558 return user; 559 560 err:SRP_user_pwd_free(user); 561 return NULL; 562} 563 564/* 565 * create a verifier (*salt,*verifier,g and N are in base64) 566 */ 567char *SRP_create_verifier(const char *user, const char *pass, char **salt, 568 char **verifier, const char *N, const char *g) 569{ 570 int len; 571 char *result = NULL; 572 char *vf; 573 BIGNUM *N_bn = NULL, *g_bn = NULL, *s = NULL, *v = NULL; 574 unsigned char tmp[MAX_LEN]; 575 unsigned char tmp2[MAX_LEN]; 576 char *defgNid = NULL; 577 578 if ((user == NULL) || 579 (pass == NULL) || (salt == NULL) || (verifier == NULL)) 580 goto err; 581 582 if (N) { 583 if (!(len = t_fromb64(tmp, N))) 584 goto err; 585 N_bn = BN_bin2bn(tmp, len, NULL); 586 if (!(len = t_fromb64(tmp, g))) 587 goto err; 588 g_bn = BN_bin2bn(tmp, len, NULL); 589 defgNid = "*"; 590 } else { 591 SRP_gN *gN = SRP_get_gN_by_id(g, NULL); 592 if (gN == NULL) 593 goto err; 594 N_bn = gN->N; 595 g_bn = gN->g; 596 defgNid = gN->id; 597 } 598 599 if (*salt == NULL) { 600 if (RAND_pseudo_bytes(tmp2, SRP_RANDOM_SALT_LEN) < 0) 601 goto err; 602 603 s = BN_bin2bn(tmp2, SRP_RANDOM_SALT_LEN, NULL); 604 } else { 605 if (!(len = t_fromb64(tmp2, *salt))) 606 goto err; 607 s = BN_bin2bn(tmp2, len, NULL); 608 } 609 610 if (!SRP_create_verifier_BN(user, pass, &s, &v, N_bn, g_bn)) 611 goto err; 612 613 BN_bn2bin(v, tmp); 614 if (((vf = OPENSSL_malloc(BN_num_bytes(v) * 2)) == NULL)) 615 goto err; 616 t_tob64(vf, tmp, BN_num_bytes(v)); 617 618 *verifier = vf; 619 if (*salt == NULL) { 620 char *tmp_salt; 621 622 if ((tmp_salt = OPENSSL_malloc(SRP_RANDOM_SALT_LEN * 2)) == NULL) { 623 OPENSSL_free(vf); 624 goto err; 625 } 626 t_tob64(tmp_salt, tmp2, SRP_RANDOM_SALT_LEN); 627 *salt = tmp_salt; 628 } 629 630 result = defgNid; 631 632 err: 633 if (N) { 634 BN_free(N_bn); 635 BN_free(g_bn); 636 } 637 return result; 638} 639 640/* 641 * create a verifier (*salt,*verifier,g and N are BIGNUMs) 642 */ 643int SRP_create_verifier_BN(const char *user, const char *pass, BIGNUM **salt, 644 BIGNUM **verifier, BIGNUM *N, BIGNUM *g) 645{ 646 int result = 0; 647 BIGNUM *x = NULL; 648 BN_CTX *bn_ctx = BN_CTX_new(); 649 unsigned char tmp2[MAX_LEN]; 650 651 if ((user == NULL) || 652 (pass == NULL) || 653 (salt == NULL) || 654 (verifier == NULL) || (N == NULL) || (g == NULL) || (bn_ctx == NULL)) 655 goto err; 656 657 srp_bn_print(N); 658 srp_bn_print(g); 659 660 if (*salt == NULL) { 661 if (RAND_pseudo_bytes(tmp2, SRP_RANDOM_SALT_LEN) < 0) 662 goto err; 663 664 *salt = BN_bin2bn(tmp2, SRP_RANDOM_SALT_LEN, NULL); 665 } 666 667 x = SRP_Calc_x(*salt, user, pass); 668 669 *verifier = BN_new(); 670 if (*verifier == NULL) 671 goto err; 672 673 if (!BN_mod_exp(*verifier, g, x, N, bn_ctx)) { 674 BN_clear_free(*verifier); 675 goto err; 676 } 677 678 srp_bn_print(*verifier); 679 680 result = 1; 681 682 err: 683 684 BN_clear_free(x); 685 BN_CTX_free(bn_ctx); 686 return result; 687} 688 689#endif 690