1238384Sjkim/* crypto/srp/srp_vfy.c */ 2238384Sjkim/* Written by Christophe Renou (christophe.renou@edelweb.fr) with 3238384Sjkim * the precious help of Peter Sylvester (peter.sylvester@edelweb.fr) 4238384Sjkim * for the EdelKey project and contributed to the OpenSSL project 2004. 5238384Sjkim */ 6238384Sjkim/* ==================================================================== 7238384Sjkim * Copyright (c) 2004 The OpenSSL Project. All rights reserved. 8238384Sjkim * 9238384Sjkim * Redistribution and use in source and binary forms, with or without 10238384Sjkim * modification, are permitted provided that the following conditions 11238384Sjkim * are met: 12238384Sjkim * 13238384Sjkim * 1. Redistributions of source code must retain the above copyright 14238384Sjkim * notice, this list of conditions and the following disclaimer. 15238384Sjkim * 16238384Sjkim * 2. Redistributions in binary form must reproduce the above copyright 17238384Sjkim * notice, this list of conditions and the following disclaimer in 18238384Sjkim * the documentation and/or other materials provided with the 19238384Sjkim * distribution. 20238384Sjkim * 21238384Sjkim * 3. All advertising materials mentioning features or use of this 22238384Sjkim * software must display the following acknowledgment: 23238384Sjkim * "This product includes software developed by the OpenSSL Project 24238384Sjkim * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 25238384Sjkim * 26238384Sjkim * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 27238384Sjkim * endorse or promote products derived from this software without 28238384Sjkim * prior written permission. For written permission, please contact 29238384Sjkim * licensing@OpenSSL.org. 30238384Sjkim * 31238384Sjkim * 5. Products derived from this software may not be called "OpenSSL" 32238384Sjkim * nor may "OpenSSL" appear in their names without prior written 33238384Sjkim * permission of the OpenSSL Project. 34238384Sjkim * 35238384Sjkim * 6. Redistributions of any form whatsoever must retain the following 36238384Sjkim * acknowledgment: 37238384Sjkim * "This product includes software developed by the OpenSSL Project 38238384Sjkim * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 39238384Sjkim * 40238384Sjkim * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 41238384Sjkim * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42238384Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 43238384Sjkim * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 44238384Sjkim * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45238384Sjkim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 46238384Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 47238384Sjkim * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48238384Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 49238384Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 50238384Sjkim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 51238384Sjkim * OF THE POSSIBILITY OF SUCH DAMAGE. 52238384Sjkim * ==================================================================== 53238384Sjkim * 54238384Sjkim * This product includes cryptographic software written by Eric Young 55238384Sjkim * (eay@cryptsoft.com). This product includes software written by Tim 56238384Sjkim * Hudson (tjh@cryptsoft.com). 57238384Sjkim * 58238384Sjkim */ 59238384Sjkim#ifndef OPENSSL_NO_SRP 60238384Sjkim#include "cryptlib.h" 61238384Sjkim#include "srp_lcl.h" 62238384Sjkim#include <openssl/srp.h> 63238384Sjkim#include <openssl/evp.h> 64238384Sjkim#include <openssl/buffer.h> 65238384Sjkim#include <openssl/rand.h> 66238384Sjkim#include <openssl/txt_db.h> 67238384Sjkim 68238384Sjkim#define SRP_RANDOM_SALT_LEN 20 69238384Sjkim#define MAX_LEN 2500 70238384Sjkim 71238384Sjkimstatic char b64table[] = 72238384Sjkim "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./"; 73238384Sjkim 74238384Sjkim/* the following two conversion routines have been inspired by code from Stanford */ 75238384Sjkim 76238384Sjkim/* 77238384Sjkim * Convert a base64 string into raw byte array representation. 78238384Sjkim */ 79238384Sjkimstatic int t_fromb64(unsigned char *a, const char *src) 80238384Sjkim { 81238384Sjkim char *loc; 82238384Sjkim int i, j; 83238384Sjkim int size; 84238384Sjkim 85238384Sjkim while(*src && (*src == ' ' || *src == '\t' || *src == '\n')) 86238384Sjkim ++src; 87238384Sjkim size = strlen(src); 88238384Sjkim i = 0; 89238384Sjkim while(i < size) 90238384Sjkim { 91238384Sjkim loc = strchr(b64table, src[i]); 92238384Sjkim if(loc == (char *) 0) break; 93238384Sjkim else a[i] = loc - b64table; 94238384Sjkim ++i; 95238384Sjkim } 96279264Sdelphij /* if nothing valid to process we have a zero length response */ 97279264Sdelphij if (i == 0) 98279264Sdelphij return 0; 99238384Sjkim size = i; 100238384Sjkim i = size - 1; 101238384Sjkim j = size; 102238384Sjkim while(1) 103238384Sjkim { 104238384Sjkim a[j] = a[i]; 105238384Sjkim if(--i < 0) break; 106238384Sjkim a[j] |= (a[i] & 3) << 6; 107238384Sjkim --j; 108238384Sjkim a[j] = (unsigned char) ((a[i] & 0x3c) >> 2); 109238384Sjkim if(--i < 0) break; 110238384Sjkim a[j] |= (a[i] & 0xf) << 4; 111238384Sjkim --j; 112238384Sjkim a[j] = (unsigned char) ((a[i] & 0x30) >> 4); 113238384Sjkim if(--i < 0) break; 114238384Sjkim a[j] |= (a[i] << 2); 115238384Sjkim 116238384Sjkim a[--j] = 0; 117238384Sjkim if(--i < 0) break; 118238384Sjkim } 119238384Sjkim while(a[j] == 0 && j <= size) ++j; 120238384Sjkim i = 0; 121238384Sjkim while (j <= size) a[i++] = a[j++]; 122238384Sjkim return i; 123238384Sjkim } 124238384Sjkim 125238384Sjkim 126238384Sjkim/* 127238384Sjkim * Convert a raw byte string into a null-terminated base64 ASCII string. 128238384Sjkim */ 129238384Sjkimstatic char *t_tob64(char *dst, const unsigned char *src, int size) 130238384Sjkim { 131238384Sjkim int c, pos = size % 3; 132238384Sjkim unsigned char b0 = 0, b1 = 0, b2 = 0, notleading = 0; 133238384Sjkim char *olddst = dst; 134238384Sjkim 135238384Sjkim switch(pos) 136238384Sjkim { 137238384Sjkim case 1: 138238384Sjkim b2 = src[0]; 139238384Sjkim break; 140238384Sjkim case 2: 141238384Sjkim b1 = src[0]; 142238384Sjkim b2 = src[1]; 143238384Sjkim break; 144238384Sjkim } 145238384Sjkim 146238384Sjkim while(1) 147238384Sjkim { 148238384Sjkim c = (b0 & 0xfc) >> 2; 149238384Sjkim if(notleading || c != 0) 150238384Sjkim { 151238384Sjkim *dst++ = b64table[c]; 152238384Sjkim notleading = 1; 153238384Sjkim } 154238384Sjkim c = ((b0 & 3) << 4) | ((b1 & 0xf0) >> 4); 155238384Sjkim if(notleading || c != 0) 156238384Sjkim { 157238384Sjkim *dst++ = b64table[c]; 158238384Sjkim notleading = 1; 159238384Sjkim } 160238384Sjkim c = ((b1 & 0xf) << 2) | ((b2 & 0xc0) >> 6); 161238384Sjkim if(notleading || c != 0) 162238384Sjkim { 163238384Sjkim *dst++ = b64table[c]; 164238384Sjkim notleading = 1; 165238384Sjkim } 166238384Sjkim c = b2 & 0x3f; 167238384Sjkim if(notleading || c != 0) 168238384Sjkim { 169238384Sjkim *dst++ = b64table[c]; 170238384Sjkim notleading = 1; 171238384Sjkim } 172238384Sjkim if(pos >= size) break; 173238384Sjkim else 174238384Sjkim { 175238384Sjkim b0 = src[pos++]; 176238384Sjkim b1 = src[pos++]; 177238384Sjkim b2 = src[pos++]; 178238384Sjkim } 179238384Sjkim } 180238384Sjkim 181238384Sjkim *dst++ = '\0'; 182238384Sjkim return olddst; 183238384Sjkim } 184238384Sjkim 185238384Sjkimstatic void SRP_user_pwd_free(SRP_user_pwd *user_pwd) 186238384Sjkim { 187238384Sjkim if (user_pwd == NULL) 188238384Sjkim return; 189238384Sjkim BN_free(user_pwd->s); 190238384Sjkim BN_clear_free(user_pwd->v); 191238384Sjkim OPENSSL_free(user_pwd->id); 192238384Sjkim OPENSSL_free(user_pwd->info); 193238384Sjkim OPENSSL_free(user_pwd); 194238384Sjkim } 195238384Sjkim 196238384Sjkimstatic SRP_user_pwd *SRP_user_pwd_new() 197238384Sjkim { 198238384Sjkim SRP_user_pwd *ret = OPENSSL_malloc(sizeof(SRP_user_pwd)); 199238384Sjkim if (ret == NULL) 200238384Sjkim return NULL; 201238384Sjkim ret->N = NULL; 202238384Sjkim ret->g = NULL; 203238384Sjkim ret->s = NULL; 204238384Sjkim ret->v = NULL; 205238384Sjkim ret->id = NULL ; 206238384Sjkim ret->info = NULL; 207238384Sjkim return ret; 208238384Sjkim } 209238384Sjkim 210238384Sjkimstatic void SRP_user_pwd_set_gN(SRP_user_pwd *vinfo, const BIGNUM *g, 211238384Sjkim const BIGNUM *N) 212238384Sjkim { 213238384Sjkim vinfo->N = N; 214238384Sjkim vinfo->g = g; 215238384Sjkim } 216238384Sjkim 217238384Sjkimstatic int SRP_user_pwd_set_ids(SRP_user_pwd *vinfo, const char *id, 218238384Sjkim const char *info) 219238384Sjkim { 220238384Sjkim if (id != NULL && NULL == (vinfo->id = BUF_strdup(id))) 221238384Sjkim return 0; 222238384Sjkim return (info == NULL || NULL != (vinfo->info = BUF_strdup(info))) ; 223238384Sjkim } 224238384Sjkim 225238384Sjkimstatic int SRP_user_pwd_set_sv(SRP_user_pwd *vinfo, const char *s, 226238384Sjkim const char *v) 227238384Sjkim { 228238384Sjkim unsigned char tmp[MAX_LEN]; 229238384Sjkim int len; 230238384Sjkim 231238384Sjkim if (strlen(s) > MAX_LEN || strlen(v) > MAX_LEN) 232238384Sjkim return 0; 233238384Sjkim len = t_fromb64(tmp, v); 234238384Sjkim if (NULL == (vinfo->v = BN_bin2bn(tmp, len, NULL)) ) 235238384Sjkim return 0; 236238384Sjkim len = t_fromb64(tmp, s); 237238384Sjkim return ((vinfo->s = BN_bin2bn(tmp, len, NULL)) != NULL) ; 238238384Sjkim } 239238384Sjkim 240238384Sjkimstatic int SRP_user_pwd_set_sv_BN(SRP_user_pwd *vinfo, BIGNUM *s, BIGNUM *v) 241238384Sjkim { 242238384Sjkim vinfo->v = v; 243238384Sjkim vinfo->s = s; 244238384Sjkim return (vinfo->s != NULL && vinfo->v != NULL) ; 245238384Sjkim } 246238384Sjkim 247238384SjkimSRP_VBASE *SRP_VBASE_new(char *seed_key) 248238384Sjkim { 249238384Sjkim SRP_VBASE *vb = (SRP_VBASE *) OPENSSL_malloc(sizeof(SRP_VBASE)); 250238384Sjkim 251238384Sjkim if (vb == NULL) 252238384Sjkim return NULL; 253238384Sjkim if (!(vb->users_pwd = sk_SRP_user_pwd_new_null()) || 254238384Sjkim !(vb->gN_cache = sk_SRP_gN_cache_new_null())) 255238384Sjkim { 256238384Sjkim OPENSSL_free(vb); 257238384Sjkim return NULL; 258238384Sjkim } 259238384Sjkim vb->default_g = NULL; 260238384Sjkim vb->default_N = NULL; 261238384Sjkim vb->seed_key = NULL; 262238384Sjkim if ((seed_key != NULL) && 263238384Sjkim (vb->seed_key = BUF_strdup(seed_key)) == NULL) 264238384Sjkim { 265238384Sjkim sk_SRP_user_pwd_free(vb->users_pwd); 266238384Sjkim sk_SRP_gN_cache_free(vb->gN_cache); 267238384Sjkim OPENSSL_free(vb); 268238384Sjkim return NULL; 269238384Sjkim } 270238384Sjkim return vb; 271238384Sjkim } 272238384Sjkim 273238384Sjkim 274238384Sjkimint SRP_VBASE_free(SRP_VBASE *vb) 275238384Sjkim { 276238384Sjkim sk_SRP_user_pwd_pop_free(vb->users_pwd,SRP_user_pwd_free); 277238384Sjkim sk_SRP_gN_cache_free(vb->gN_cache); 278238384Sjkim OPENSSL_free(vb->seed_key); 279238384Sjkim OPENSSL_free(vb); 280238384Sjkim return 0; 281238384Sjkim } 282238384Sjkim 283238384Sjkim 284238384Sjkimstatic SRP_gN_cache *SRP_gN_new_init(const char *ch) 285238384Sjkim { 286238384Sjkim unsigned char tmp[MAX_LEN]; 287238384Sjkim int len; 288238384Sjkim 289238384Sjkim SRP_gN_cache *newgN = (SRP_gN_cache *)OPENSSL_malloc(sizeof(SRP_gN_cache)); 290238384Sjkim if (newgN == NULL) 291238384Sjkim return NULL; 292238384Sjkim 293238384Sjkim if ((newgN->b64_bn = BUF_strdup(ch)) == NULL) 294238384Sjkim goto err; 295238384Sjkim 296238384Sjkim len = t_fromb64(tmp, ch); 297238384Sjkim if ((newgN->bn = BN_bin2bn(tmp, len, NULL))) 298238384Sjkim return newgN; 299238384Sjkim 300238384Sjkim OPENSSL_free(newgN->b64_bn); 301238384Sjkimerr: 302238384Sjkim OPENSSL_free(newgN); 303238384Sjkim return NULL; 304238384Sjkim } 305238384Sjkim 306238384Sjkim 307238384Sjkimstatic void SRP_gN_free(SRP_gN_cache *gN_cache) 308238384Sjkim { 309238384Sjkim if (gN_cache == NULL) 310238384Sjkim return; 311238384Sjkim OPENSSL_free(gN_cache->b64_bn); 312238384Sjkim BN_free(gN_cache->bn); 313238384Sjkim OPENSSL_free(gN_cache); 314238384Sjkim } 315238384Sjkim 316238384Sjkimstatic SRP_gN *SRP_get_gN_by_id(const char *id, STACK_OF(SRP_gN) *gN_tab) 317238384Sjkim { 318238384Sjkim int i; 319238384Sjkim 320238384Sjkim SRP_gN *gN; 321238384Sjkim if (gN_tab != NULL) 322238384Sjkim for(i = 0; i < sk_SRP_gN_num(gN_tab); i++) 323238384Sjkim { 324238384Sjkim gN = sk_SRP_gN_value(gN_tab, i); 325238384Sjkim if (gN && (id == NULL || strcmp(gN->id,id)==0)) 326238384Sjkim return gN; 327238384Sjkim } 328238384Sjkim 329238384Sjkim return SRP_get_default_gN(id); 330238384Sjkim } 331238384Sjkim 332238384Sjkimstatic BIGNUM *SRP_gN_place_bn(STACK_OF(SRP_gN_cache) *gN_cache, char *ch) 333238384Sjkim { 334238384Sjkim int i; 335238384Sjkim if (gN_cache == NULL) 336238384Sjkim return NULL; 337238384Sjkim 338238384Sjkim /* search if we have already one... */ 339238384Sjkim for(i = 0; i < sk_SRP_gN_cache_num(gN_cache); i++) 340238384Sjkim { 341238384Sjkim SRP_gN_cache *cache = sk_SRP_gN_cache_value(gN_cache, i); 342238384Sjkim if (strcmp(cache->b64_bn,ch)==0) 343238384Sjkim return cache->bn; 344238384Sjkim } 345238384Sjkim { /* it is the first time that we find it */ 346238384Sjkim SRP_gN_cache *newgN = SRP_gN_new_init(ch); 347238384Sjkim if (newgN) 348238384Sjkim { 349238384Sjkim if (sk_SRP_gN_cache_insert(gN_cache,newgN,0)>0) 350238384Sjkim return newgN->bn; 351238384Sjkim SRP_gN_free(newgN); 352238384Sjkim } 353238384Sjkim } 354238384Sjkim return NULL; 355238384Sjkim } 356238384Sjkim 357238384Sjkim/* this function parses verifier file. Format is: 358238384Sjkim * string(index):base64(N):base64(g):0 359238384Sjkim * string(username):base64(v):base64(salt):int(index) 360238384Sjkim */ 361238384Sjkim 362238384Sjkim 363238384Sjkimint SRP_VBASE_init(SRP_VBASE *vb, char *verifier_file) 364238384Sjkim { 365238384Sjkim int error_code ; 366238384Sjkim STACK_OF(SRP_gN) *SRP_gN_tab = sk_SRP_gN_new_null(); 367238384Sjkim char *last_index = NULL; 368238384Sjkim int i; 369238384Sjkim char **pp; 370238384Sjkim 371238384Sjkim SRP_gN *gN = NULL; 372238384Sjkim SRP_user_pwd *user_pwd = NULL ; 373238384Sjkim 374238384Sjkim TXT_DB *tmpdb = NULL; 375238384Sjkim BIO *in = BIO_new(BIO_s_file()); 376238384Sjkim 377238384Sjkim error_code = SRP_ERR_OPEN_FILE; 378238384Sjkim 379238384Sjkim if (in == NULL || BIO_read_filename(in,verifier_file) <= 0) 380238384Sjkim goto err; 381238384Sjkim 382238384Sjkim error_code = SRP_ERR_VBASE_INCOMPLETE_FILE; 383238384Sjkim 384238384Sjkim if ((tmpdb =TXT_DB_read(in,DB_NUMBER)) == NULL) 385238384Sjkim goto err; 386238384Sjkim 387238384Sjkim error_code = SRP_ERR_MEMORY; 388238384Sjkim 389238384Sjkim 390238384Sjkim if (vb->seed_key) 391238384Sjkim { 392238384Sjkim last_index = SRP_get_default_gN(NULL)->id; 393238384Sjkim } 394238384Sjkim for (i = 0; i < sk_OPENSSL_PSTRING_num(tmpdb->data); i++) 395238384Sjkim { 396246772Sjkim pp = sk_OPENSSL_PSTRING_value(tmpdb->data,i); 397238384Sjkim if (pp[DB_srptype][0] == DB_SRP_INDEX) 398238384Sjkim { 399238384Sjkim /*we add this couple in the internal Stack */ 400238384Sjkim 401238384Sjkim if ((gN = (SRP_gN *)OPENSSL_malloc(sizeof(SRP_gN))) == NULL) 402238384Sjkim goto err; 403238384Sjkim 404238384Sjkim if (!(gN->id = BUF_strdup(pp[DB_srpid])) 405238384Sjkim || !(gN->N = SRP_gN_place_bn(vb->gN_cache,pp[DB_srpverifier])) 406238384Sjkim || !(gN->g = SRP_gN_place_bn(vb->gN_cache,pp[DB_srpsalt])) 407238384Sjkim || sk_SRP_gN_insert(SRP_gN_tab,gN,0) == 0) 408238384Sjkim goto err; 409238384Sjkim 410238384Sjkim gN = NULL; 411238384Sjkim 412238384Sjkim if (vb->seed_key != NULL) 413238384Sjkim { 414238384Sjkim last_index = pp[DB_srpid]; 415238384Sjkim } 416238384Sjkim } 417238384Sjkim else if (pp[DB_srptype][0] == DB_SRP_VALID) 418238384Sjkim { 419238384Sjkim /* it is a user .... */ 420238384Sjkim SRP_gN *lgN; 421238384Sjkim if ((lgN = SRP_get_gN_by_id(pp[DB_srpgN],SRP_gN_tab))!=NULL) 422238384Sjkim { 423238384Sjkim error_code = SRP_ERR_MEMORY; 424238384Sjkim if ((user_pwd = SRP_user_pwd_new()) == NULL) 425238384Sjkim goto err; 426238384Sjkim 427238384Sjkim SRP_user_pwd_set_gN(user_pwd,lgN->g,lgN->N); 428238384Sjkim if (!SRP_user_pwd_set_ids(user_pwd, pp[DB_srpid],pp[DB_srpinfo])) 429238384Sjkim goto err; 430238384Sjkim 431238384Sjkim error_code = SRP_ERR_VBASE_BN_LIB; 432238384Sjkim if (!SRP_user_pwd_set_sv(user_pwd, pp[DB_srpsalt],pp[DB_srpverifier])) 433238384Sjkim goto err; 434238384Sjkim 435238384Sjkim if (sk_SRP_user_pwd_insert(vb->users_pwd, user_pwd, 0) == 0) 436238384Sjkim goto err; 437238384Sjkim user_pwd = NULL; /* abandon responsability */ 438238384Sjkim } 439238384Sjkim } 440238384Sjkim } 441238384Sjkim 442238384Sjkim if (last_index != NULL) 443238384Sjkim { 444238384Sjkim /* this means that we want to simulate a default user */ 445238384Sjkim 446238384Sjkim if (((gN = SRP_get_gN_by_id(last_index,SRP_gN_tab))==NULL)) 447238384Sjkim { 448238384Sjkim error_code = SRP_ERR_VBASE_BN_LIB; 449238384Sjkim goto err; 450238384Sjkim } 451238384Sjkim vb->default_g = gN->g ; 452238384Sjkim vb->default_N = gN->N ; 453238384Sjkim gN = NULL ; 454238384Sjkim } 455238384Sjkim error_code = SRP_NO_ERROR; 456238384Sjkim 457238384Sjkim err: 458238384Sjkim /* there may be still some leaks to fix, if this fails, the application terminates most likely */ 459238384Sjkim 460238384Sjkim if (gN != NULL) 461238384Sjkim { 462238384Sjkim OPENSSL_free(gN->id); 463238384Sjkim OPENSSL_free(gN); 464238384Sjkim } 465238384Sjkim 466238384Sjkim SRP_user_pwd_free(user_pwd); 467238384Sjkim 468238384Sjkim if (tmpdb) TXT_DB_free(tmpdb); 469238384Sjkim if (in) BIO_free_all(in); 470238384Sjkim 471238384Sjkim sk_SRP_gN_free(SRP_gN_tab); 472238384Sjkim 473238384Sjkim return error_code; 474238384Sjkim 475238384Sjkim } 476238384Sjkim 477238384Sjkim 478238384SjkimSRP_user_pwd *SRP_VBASE_get_by_user(SRP_VBASE *vb, char *username) 479238384Sjkim { 480238384Sjkim int i; 481238384Sjkim SRP_user_pwd *user; 482238384Sjkim unsigned char digv[SHA_DIGEST_LENGTH]; 483238384Sjkim unsigned char digs[SHA_DIGEST_LENGTH]; 484238384Sjkim EVP_MD_CTX ctxt; 485238384Sjkim 486238384Sjkim if (vb == NULL) 487238384Sjkim return NULL; 488238384Sjkim for(i = 0; i < sk_SRP_user_pwd_num(vb->users_pwd); i++) 489238384Sjkim { 490238384Sjkim user = sk_SRP_user_pwd_value(vb->users_pwd, i); 491238384Sjkim if (strcmp(user->id,username)==0) 492238384Sjkim return user; 493238384Sjkim } 494238384Sjkim if ((vb->seed_key == NULL) || 495238384Sjkim (vb->default_g == NULL) || 496238384Sjkim (vb->default_N == NULL)) 497238384Sjkim return NULL; 498238384Sjkim 499238384Sjkim/* if the user is unknown we set parameters as well if we have a seed_key */ 500238384Sjkim 501238384Sjkim if ((user = SRP_user_pwd_new()) == NULL) 502238384Sjkim return NULL; 503238384Sjkim 504238384Sjkim SRP_user_pwd_set_gN(user,vb->default_g,vb->default_N); 505238384Sjkim 506238384Sjkim if (!SRP_user_pwd_set_ids(user,username,NULL)) 507238384Sjkim goto err; 508238384Sjkim 509238384Sjkim RAND_pseudo_bytes(digv, SHA_DIGEST_LENGTH); 510238384Sjkim EVP_MD_CTX_init(&ctxt); 511238384Sjkim EVP_DigestInit_ex(&ctxt, EVP_sha1(), NULL); 512238384Sjkim EVP_DigestUpdate(&ctxt, vb->seed_key, strlen(vb->seed_key)); 513238384Sjkim EVP_DigestUpdate(&ctxt, username, strlen(username)); 514238384Sjkim EVP_DigestFinal_ex(&ctxt, digs, NULL); 515238384Sjkim EVP_MD_CTX_cleanup(&ctxt); 516238384Sjkim if (SRP_user_pwd_set_sv_BN(user, BN_bin2bn(digs,SHA_DIGEST_LENGTH,NULL), BN_bin2bn(digv,SHA_DIGEST_LENGTH, NULL))) 517238384Sjkim return user; 518238384Sjkim 519238384Sjkimerr: SRP_user_pwd_free(user); 520238384Sjkim return NULL; 521238384Sjkim } 522238384Sjkim 523238384Sjkim 524238384Sjkim/* 525238384Sjkim create a verifier (*salt,*verifier,g and N are in base64) 526238384Sjkim*/ 527238384Sjkimchar *SRP_create_verifier(const char *user, const char *pass, char **salt, 528238384Sjkim char **verifier, const char *N, const char *g) 529238384Sjkim { 530238384Sjkim int len; 531238384Sjkim char * result=NULL; 532238384Sjkim char *vf; 533238384Sjkim BIGNUM *N_bn = NULL, *g_bn = NULL, *s = NULL, *v = NULL; 534238384Sjkim unsigned char tmp[MAX_LEN]; 535238384Sjkim unsigned char tmp2[MAX_LEN]; 536238384Sjkim char * defgNid = NULL; 537238384Sjkim 538238384Sjkim if ((user == NULL)|| 539238384Sjkim (pass == NULL)|| 540238384Sjkim (salt == NULL)|| 541238384Sjkim (verifier == NULL)) 542238384Sjkim goto err; 543238384Sjkim 544238384Sjkim if (N) 545238384Sjkim { 546238384Sjkim if (!(len = t_fromb64(tmp, N))) goto err; 547238384Sjkim N_bn = BN_bin2bn(tmp, len, NULL); 548238384Sjkim if (!(len = t_fromb64(tmp, g))) goto err; 549238384Sjkim g_bn = BN_bin2bn(tmp, len, NULL); 550238384Sjkim defgNid = "*"; 551238384Sjkim } 552238384Sjkim else 553238384Sjkim { 554238384Sjkim SRP_gN * gN = SRP_get_gN_by_id(g, NULL) ; 555238384Sjkim if (gN == NULL) 556238384Sjkim goto err; 557238384Sjkim N_bn = gN->N; 558238384Sjkim g_bn = gN->g; 559238384Sjkim defgNid = gN->id; 560238384Sjkim } 561238384Sjkim 562238384Sjkim if (*salt == NULL) 563238384Sjkim { 564238384Sjkim RAND_pseudo_bytes(tmp2, SRP_RANDOM_SALT_LEN); 565238384Sjkim 566238384Sjkim s = BN_bin2bn(tmp2, SRP_RANDOM_SALT_LEN, NULL); 567238384Sjkim } 568238384Sjkim else 569238384Sjkim { 570238384Sjkim if (!(len = t_fromb64(tmp2, *salt))) 571238384Sjkim goto err; 572238384Sjkim s = BN_bin2bn(tmp2, len, NULL); 573238384Sjkim } 574238384Sjkim 575238384Sjkim 576238384Sjkim if(!SRP_create_verifier_BN(user, pass, &s, &v, N_bn, g_bn)) goto err; 577238384Sjkim 578238384Sjkim BN_bn2bin(v,tmp); 579238384Sjkim if (((vf = OPENSSL_malloc(BN_num_bytes(v)*2)) == NULL)) 580238384Sjkim goto err; 581238384Sjkim t_tob64(vf, tmp, BN_num_bytes(v)); 582238384Sjkim 583238384Sjkim *verifier = vf; 584238384Sjkim if (*salt == NULL) 585238384Sjkim { 586238384Sjkim char *tmp_salt; 587246772Sjkim 588246772Sjkim if ((tmp_salt = OPENSSL_malloc(SRP_RANDOM_SALT_LEN * 2)) == NULL) 589238384Sjkim { 590238384Sjkim OPENSSL_free(vf); 591238384Sjkim goto err; 592238384Sjkim } 593238384Sjkim t_tob64(tmp_salt, tmp2, SRP_RANDOM_SALT_LEN); 594238384Sjkim *salt = tmp_salt; 595238384Sjkim } 596238384Sjkim 597238384Sjkim result=defgNid; 598238384Sjkim 599238384Sjkimerr: 600238384Sjkim if(N) 601238384Sjkim { 602238384Sjkim BN_free(N_bn); 603238384Sjkim BN_free(g_bn); 604238384Sjkim } 605238384Sjkim return result; 606238384Sjkim } 607238384Sjkim 608238384Sjkim/* 609238384Sjkim create a verifier (*salt,*verifier,g and N are BIGNUMs) 610238384Sjkim*/ 611238384Sjkimint SRP_create_verifier_BN(const char *user, const char *pass, BIGNUM **salt, BIGNUM **verifier, BIGNUM *N, BIGNUM *g) 612238384Sjkim { 613238384Sjkim int result=0; 614238384Sjkim BIGNUM *x = NULL; 615238384Sjkim BN_CTX *bn_ctx = BN_CTX_new(); 616238384Sjkim unsigned char tmp2[MAX_LEN]; 617238384Sjkim 618238384Sjkim if ((user == NULL)|| 619238384Sjkim (pass == NULL)|| 620238384Sjkim (salt == NULL)|| 621238384Sjkim (verifier == NULL)|| 622238384Sjkim (N == NULL)|| 623238384Sjkim (g == NULL)|| 624238384Sjkim (bn_ctx == NULL)) 625238384Sjkim goto err; 626238384Sjkim 627238384Sjkim srp_bn_print(N); 628238384Sjkim srp_bn_print(g); 629238384Sjkim 630238384Sjkim if (*salt == NULL) 631238384Sjkim { 632238384Sjkim RAND_pseudo_bytes(tmp2, SRP_RANDOM_SALT_LEN); 633238384Sjkim 634238384Sjkim *salt = BN_bin2bn(tmp2,SRP_RANDOM_SALT_LEN,NULL); 635238384Sjkim } 636238384Sjkim 637238384Sjkim x = SRP_Calc_x(*salt,user,pass); 638238384Sjkim 639238384Sjkim *verifier = BN_new(); 640238384Sjkim if(*verifier == NULL) goto err; 641238384Sjkim 642238384Sjkim if (!BN_mod_exp(*verifier,g,x,N,bn_ctx)) 643238384Sjkim { 644238384Sjkim BN_clear_free(*verifier); 645238384Sjkim goto err; 646238384Sjkim } 647238384Sjkim 648238384Sjkim srp_bn_print(*verifier); 649238384Sjkim 650238384Sjkim result=1; 651238384Sjkim 652238384Sjkimerr: 653238384Sjkim 654238384Sjkim BN_clear_free(x); 655238384Sjkim BN_CTX_free(bn_ctx); 656238384Sjkim return result; 657238384Sjkim } 658238384Sjkim 659238384Sjkim 660238384Sjkim 661238384Sjkim#endif 662