1238384Sjkim/* crypto/srp/srp_vfy.c */ 2296341Sdelphij/* 3296341Sdelphij * Written by Christophe Renou (christophe.renou@edelweb.fr) with the 4296341Sdelphij * precious help of Peter Sylvester (peter.sylvester@edelweb.fr) for the 5296341Sdelphij * EdelKey project and contributed to the OpenSSL project 2004. 6238384Sjkim */ 7238384Sjkim/* ==================================================================== 8238384Sjkim * Copyright (c) 2004 The OpenSSL Project. All rights reserved. 9238384Sjkim * 10238384Sjkim * Redistribution and use in source and binary forms, with or without 11238384Sjkim * modification, are permitted provided that the following conditions 12238384Sjkim * are met: 13238384Sjkim * 14238384Sjkim * 1. Redistributions of source code must retain the above copyright 15296341Sdelphij * notice, this list of conditions and the following disclaimer. 16238384Sjkim * 17238384Sjkim * 2. Redistributions in binary form must reproduce the above copyright 18238384Sjkim * notice, this list of conditions and the following disclaimer in 19238384Sjkim * the documentation and/or other materials provided with the 20238384Sjkim * distribution. 21238384Sjkim * 22238384Sjkim * 3. All advertising materials mentioning features or use of this 23238384Sjkim * software must display the following acknowledgment: 24238384Sjkim * "This product includes software developed by the OpenSSL Project 25238384Sjkim * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 26238384Sjkim * 27238384Sjkim * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 28238384Sjkim * endorse or promote products derived from this software without 29238384Sjkim * prior written permission. For written permission, please contact 30238384Sjkim * licensing@OpenSSL.org. 31238384Sjkim * 32238384Sjkim * 5. Products derived from this software may not be called "OpenSSL" 33238384Sjkim * nor may "OpenSSL" appear in their names without prior written 34238384Sjkim * permission of the OpenSSL Project. 35238384Sjkim * 36238384Sjkim * 6. Redistributions of any form whatsoever must retain the following 37238384Sjkim * acknowledgment: 38238384Sjkim * "This product includes software developed by the OpenSSL Project 39238384Sjkim * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 40238384Sjkim * 41238384Sjkim * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 42238384Sjkim * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43238384Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 44238384Sjkim * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 45238384Sjkim * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 46238384Sjkim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 47238384Sjkim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 48238384Sjkim * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 49238384Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 50238384Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 51238384Sjkim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 52238384Sjkim * OF THE POSSIBILITY OF SUCH DAMAGE. 53238384Sjkim * ==================================================================== 54238384Sjkim * 55238384Sjkim * This product includes cryptographic software written by Eric Young 56238384Sjkim * (eay@cryptsoft.com). This product includes software written by Tim 57238384Sjkim * Hudson (tjh@cryptsoft.com). 58238384Sjkim * 59238384Sjkim */ 60238384Sjkim#ifndef OPENSSL_NO_SRP 61296341Sdelphij# include "cryptlib.h" 62296341Sdelphij# include "srp_lcl.h" 63296341Sdelphij# include <openssl/srp.h> 64296341Sdelphij# include <openssl/evp.h> 65296341Sdelphij# include <openssl/buffer.h> 66296341Sdelphij# include <openssl/rand.h> 67296341Sdelphij# include <openssl/txt_db.h> 68238384Sjkim 69296341Sdelphij# define SRP_RANDOM_SALT_LEN 20 70296341Sdelphij# define MAX_LEN 2500 71238384Sjkim 72238384Sjkimstatic char b64table[] = 73296341Sdelphij "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./"; 74238384Sjkim 75296341Sdelphij/* 76296341Sdelphij * the following two conversion routines have been inspired by code from 77296341Sdelphij * Stanford 78296341Sdelphij */ 79238384Sjkim 80238384Sjkim/* 81238384Sjkim * Convert a base64 string into raw byte array representation. 82238384Sjkim */ 83238384Sjkimstatic int t_fromb64(unsigned char *a, const char *src) 84296341Sdelphij{ 85296341Sdelphij char *loc; 86296341Sdelphij int i, j; 87296341Sdelphij int size; 88238384Sjkim 89296341Sdelphij while (*src && (*src == ' ' || *src == '\t' || *src == '\n')) 90296341Sdelphij ++src; 91296341Sdelphij size = strlen(src); 92296341Sdelphij i = 0; 93296341Sdelphij while (i < size) { 94296341Sdelphij loc = strchr(b64table, src[i]); 95296341Sdelphij if (loc == (char *)0) 96296341Sdelphij break; 97296341Sdelphij else 98296341Sdelphij a[i] = loc - b64table; 99296341Sdelphij ++i; 100296341Sdelphij } 101296341Sdelphij /* if nothing valid to process we have a zero length response */ 102296341Sdelphij if (i == 0) 103296341Sdelphij return 0; 104296341Sdelphij size = i; 105296341Sdelphij i = size - 1; 106296341Sdelphij j = size; 107296341Sdelphij while (1) { 108296341Sdelphij a[j] = a[i]; 109296341Sdelphij if (--i < 0) 110296341Sdelphij break; 111296341Sdelphij a[j] |= (a[i] & 3) << 6; 112296341Sdelphij --j; 113296341Sdelphij a[j] = (unsigned char)((a[i] & 0x3c) >> 2); 114296341Sdelphij if (--i < 0) 115296341Sdelphij break; 116296341Sdelphij a[j] |= (a[i] & 0xf) << 4; 117296341Sdelphij --j; 118296341Sdelphij a[j] = (unsigned char)((a[i] & 0x30) >> 4); 119296341Sdelphij if (--i < 0) 120296341Sdelphij break; 121296341Sdelphij a[j] |= (a[i] << 2); 122238384Sjkim 123296341Sdelphij a[--j] = 0; 124296341Sdelphij if (--i < 0) 125296341Sdelphij break; 126296341Sdelphij } 127296341Sdelphij while (a[j] == 0 && j <= size) 128296341Sdelphij ++j; 129296341Sdelphij i = 0; 130296341Sdelphij while (j <= size) 131296341Sdelphij a[i++] = a[j++]; 132296341Sdelphij return i; 133296341Sdelphij} 134238384Sjkim 135238384Sjkim/* 136238384Sjkim * Convert a raw byte string into a null-terminated base64 ASCII string. 137238384Sjkim */ 138238384Sjkimstatic char *t_tob64(char *dst, const unsigned char *src, int size) 139296341Sdelphij{ 140296341Sdelphij int c, pos = size % 3; 141296341Sdelphij unsigned char b0 = 0, b1 = 0, b2 = 0, notleading = 0; 142296341Sdelphij char *olddst = dst; 143238384Sjkim 144296341Sdelphij switch (pos) { 145296341Sdelphij case 1: 146296341Sdelphij b2 = src[0]; 147296341Sdelphij break; 148296341Sdelphij case 2: 149296341Sdelphij b1 = src[0]; 150296341Sdelphij b2 = src[1]; 151296341Sdelphij break; 152296341Sdelphij } 153238384Sjkim 154296341Sdelphij while (1) { 155296341Sdelphij c = (b0 & 0xfc) >> 2; 156296341Sdelphij if (notleading || c != 0) { 157296341Sdelphij *dst++ = b64table[c]; 158296341Sdelphij notleading = 1; 159296341Sdelphij } 160296341Sdelphij c = ((b0 & 3) << 4) | ((b1 & 0xf0) >> 4); 161296341Sdelphij if (notleading || c != 0) { 162296341Sdelphij *dst++ = b64table[c]; 163296341Sdelphij notleading = 1; 164296341Sdelphij } 165296341Sdelphij c = ((b1 & 0xf) << 2) | ((b2 & 0xc0) >> 6); 166296341Sdelphij if (notleading || c != 0) { 167296341Sdelphij *dst++ = b64table[c]; 168296341Sdelphij notleading = 1; 169296341Sdelphij } 170296341Sdelphij c = b2 & 0x3f; 171296341Sdelphij if (notleading || c != 0) { 172296341Sdelphij *dst++ = b64table[c]; 173296341Sdelphij notleading = 1; 174296341Sdelphij } 175296341Sdelphij if (pos >= size) 176296341Sdelphij break; 177296341Sdelphij else { 178296341Sdelphij b0 = src[pos++]; 179296341Sdelphij b1 = src[pos++]; 180296341Sdelphij b2 = src[pos++]; 181296341Sdelphij } 182296341Sdelphij } 183238384Sjkim 184296341Sdelphij *dst++ = '\0'; 185296341Sdelphij return olddst; 186296341Sdelphij} 187238384Sjkim 188296341Sdelphijvoid SRP_user_pwd_free(SRP_user_pwd *user_pwd) 189296341Sdelphij{ 190296341Sdelphij if (user_pwd == NULL) 191296341Sdelphij return; 192296341Sdelphij BN_free(user_pwd->s); 193296341Sdelphij BN_clear_free(user_pwd->v); 194296341Sdelphij OPENSSL_free(user_pwd->id); 195296341Sdelphij OPENSSL_free(user_pwd->info); 196296341Sdelphij OPENSSL_free(user_pwd); 197296341Sdelphij} 198238384Sjkim 199238384Sjkimstatic SRP_user_pwd *SRP_user_pwd_new() 200296341Sdelphij{ 201296341Sdelphij SRP_user_pwd *ret = OPENSSL_malloc(sizeof(SRP_user_pwd)); 202296341Sdelphij if (ret == NULL) 203296341Sdelphij return NULL; 204296341Sdelphij ret->N = NULL; 205296341Sdelphij ret->g = NULL; 206296341Sdelphij ret->s = NULL; 207296341Sdelphij ret->v = NULL; 208296341Sdelphij ret->id = NULL; 209296341Sdelphij ret->info = NULL; 210296341Sdelphij return ret; 211296341Sdelphij} 212238384Sjkim 213238384Sjkimstatic void SRP_user_pwd_set_gN(SRP_user_pwd *vinfo, const BIGNUM *g, 214296341Sdelphij const BIGNUM *N) 215296341Sdelphij{ 216296341Sdelphij vinfo->N = N; 217296341Sdelphij vinfo->g = g; 218296341Sdelphij} 219238384Sjkim 220238384Sjkimstatic int SRP_user_pwd_set_ids(SRP_user_pwd *vinfo, const char *id, 221296341Sdelphij const char *info) 222296341Sdelphij{ 223296341Sdelphij if (id != NULL && NULL == (vinfo->id = BUF_strdup(id))) 224296341Sdelphij return 0; 225296341Sdelphij return (info == NULL || NULL != (vinfo->info = BUF_strdup(info))); 226296341Sdelphij} 227238384Sjkim 228238384Sjkimstatic int SRP_user_pwd_set_sv(SRP_user_pwd *vinfo, const char *s, 229296341Sdelphij const char *v) 230296341Sdelphij{ 231296341Sdelphij unsigned char tmp[MAX_LEN]; 232296341Sdelphij int len; 233238384Sjkim 234296341Sdelphij if (strlen(s) > MAX_LEN || strlen(v) > MAX_LEN) 235296341Sdelphij return 0; 236296341Sdelphij len = t_fromb64(tmp, v); 237296341Sdelphij if (NULL == (vinfo->v = BN_bin2bn(tmp, len, NULL))) 238296341Sdelphij return 0; 239296341Sdelphij len = t_fromb64(tmp, s); 240296341Sdelphij return ((vinfo->s = BN_bin2bn(tmp, len, NULL)) != NULL); 241296341Sdelphij} 242238384Sjkim 243238384Sjkimstatic int SRP_user_pwd_set_sv_BN(SRP_user_pwd *vinfo, BIGNUM *s, BIGNUM *v) 244296341Sdelphij{ 245296341Sdelphij vinfo->v = v; 246296341Sdelphij vinfo->s = s; 247296341Sdelphij return (vinfo->s != NULL && vinfo->v != NULL); 248296341Sdelphij} 249238384Sjkim 250296341Sdelphijstatic SRP_user_pwd *srp_user_pwd_dup(SRP_user_pwd *src) 251296341Sdelphij{ 252296341Sdelphij SRP_user_pwd *ret; 253296341Sdelphij 254296341Sdelphij if (src == NULL) 255296341Sdelphij return NULL; 256296341Sdelphij if ((ret = SRP_user_pwd_new()) == NULL) 257296341Sdelphij return NULL; 258296341Sdelphij 259296341Sdelphij SRP_user_pwd_set_gN(ret, src->g, src->N); 260296341Sdelphij if (!SRP_user_pwd_set_ids(ret, src->id, src->info) 261296341Sdelphij || !SRP_user_pwd_set_sv_BN(ret, BN_dup(src->s), BN_dup(src->v))) { 262296341Sdelphij SRP_user_pwd_free(ret); 263296341Sdelphij return NULL; 264296341Sdelphij } 265296341Sdelphij return ret; 266296341Sdelphij} 267296341Sdelphij 268238384SjkimSRP_VBASE *SRP_VBASE_new(char *seed_key) 269296341Sdelphij{ 270296341Sdelphij SRP_VBASE *vb = (SRP_VBASE *)OPENSSL_malloc(sizeof(SRP_VBASE)); 271238384Sjkim 272296341Sdelphij if (vb == NULL) 273296341Sdelphij return NULL; 274296341Sdelphij if (!(vb->users_pwd = sk_SRP_user_pwd_new_null()) || 275296341Sdelphij !(vb->gN_cache = sk_SRP_gN_cache_new_null())) { 276296341Sdelphij OPENSSL_free(vb); 277296341Sdelphij return NULL; 278296341Sdelphij } 279296341Sdelphij vb->default_g = NULL; 280296341Sdelphij vb->default_N = NULL; 281296341Sdelphij vb->seed_key = NULL; 282296341Sdelphij if ((seed_key != NULL) && (vb->seed_key = BUF_strdup(seed_key)) == NULL) { 283296341Sdelphij sk_SRP_user_pwd_free(vb->users_pwd); 284296341Sdelphij sk_SRP_gN_cache_free(vb->gN_cache); 285296341Sdelphij OPENSSL_free(vb); 286296341Sdelphij return NULL; 287296341Sdelphij } 288296341Sdelphij return vb; 289296341Sdelphij} 290238384Sjkim 291238384Sjkimint SRP_VBASE_free(SRP_VBASE *vb) 292296341Sdelphij{ 293296341Sdelphij sk_SRP_user_pwd_pop_free(vb->users_pwd, SRP_user_pwd_free); 294296341Sdelphij sk_SRP_gN_cache_free(vb->gN_cache); 295296341Sdelphij OPENSSL_free(vb->seed_key); 296296341Sdelphij OPENSSL_free(vb); 297296341Sdelphij return 0; 298296341Sdelphij} 299238384Sjkim 300238384Sjkimstatic SRP_gN_cache *SRP_gN_new_init(const char *ch) 301296341Sdelphij{ 302296341Sdelphij unsigned char tmp[MAX_LEN]; 303296341Sdelphij int len; 304238384Sjkim 305296341Sdelphij SRP_gN_cache *newgN = 306296341Sdelphij (SRP_gN_cache *)OPENSSL_malloc(sizeof(SRP_gN_cache)); 307296341Sdelphij if (newgN == NULL) 308296341Sdelphij return NULL; 309238384Sjkim 310296341Sdelphij if ((newgN->b64_bn = BUF_strdup(ch)) == NULL) 311296341Sdelphij goto err; 312238384Sjkim 313296341Sdelphij len = t_fromb64(tmp, ch); 314296341Sdelphij if ((newgN->bn = BN_bin2bn(tmp, len, NULL))) 315296341Sdelphij return newgN; 316238384Sjkim 317296341Sdelphij OPENSSL_free(newgN->b64_bn); 318296341Sdelphij err: 319296341Sdelphij OPENSSL_free(newgN); 320296341Sdelphij return NULL; 321296341Sdelphij} 322238384Sjkim 323238384Sjkimstatic void SRP_gN_free(SRP_gN_cache *gN_cache) 324296341Sdelphij{ 325296341Sdelphij if (gN_cache == NULL) 326296341Sdelphij return; 327296341Sdelphij OPENSSL_free(gN_cache->b64_bn); 328296341Sdelphij BN_free(gN_cache->bn); 329296341Sdelphij OPENSSL_free(gN_cache); 330296341Sdelphij} 331238384Sjkim 332238384Sjkimstatic SRP_gN *SRP_get_gN_by_id(const char *id, STACK_OF(SRP_gN) *gN_tab) 333296341Sdelphij{ 334296341Sdelphij int i; 335238384Sjkim 336296341Sdelphij SRP_gN *gN; 337296341Sdelphij if (gN_tab != NULL) 338296341Sdelphij for (i = 0; i < sk_SRP_gN_num(gN_tab); i++) { 339296341Sdelphij gN = sk_SRP_gN_value(gN_tab, i); 340296341Sdelphij if (gN && (id == NULL || strcmp(gN->id, id) == 0)) 341296341Sdelphij return gN; 342296341Sdelphij } 343238384Sjkim 344296341Sdelphij return SRP_get_default_gN(id); 345296341Sdelphij} 346296341Sdelphij 347238384Sjkimstatic BIGNUM *SRP_gN_place_bn(STACK_OF(SRP_gN_cache) *gN_cache, char *ch) 348296341Sdelphij{ 349296341Sdelphij int i; 350296341Sdelphij if (gN_cache == NULL) 351296341Sdelphij return NULL; 352238384Sjkim 353296341Sdelphij /* search if we have already one... */ 354296341Sdelphij for (i = 0; i < sk_SRP_gN_cache_num(gN_cache); i++) { 355296341Sdelphij SRP_gN_cache *cache = sk_SRP_gN_cache_value(gN_cache, i); 356296341Sdelphij if (strcmp(cache->b64_bn, ch) == 0) 357296341Sdelphij return cache->bn; 358296341Sdelphij } 359296341Sdelphij { /* it is the first time that we find it */ 360296341Sdelphij SRP_gN_cache *newgN = SRP_gN_new_init(ch); 361296341Sdelphij if (newgN) { 362296341Sdelphij if (sk_SRP_gN_cache_insert(gN_cache, newgN, 0) > 0) 363296341Sdelphij return newgN->bn; 364296341Sdelphij SRP_gN_free(newgN); 365296341Sdelphij } 366296341Sdelphij } 367296341Sdelphij return NULL; 368296341Sdelphij} 369238384Sjkim 370296341Sdelphij/* 371296341Sdelphij * this function parses verifier file. Format is: 372238384Sjkim * string(index):base64(N):base64(g):0 373238384Sjkim * string(username):base64(v):base64(salt):int(index) 374238384Sjkim */ 375238384Sjkim 376238384Sjkimint SRP_VBASE_init(SRP_VBASE *vb, char *verifier_file) 377296341Sdelphij{ 378296341Sdelphij int error_code; 379296341Sdelphij STACK_OF(SRP_gN) *SRP_gN_tab = sk_SRP_gN_new_null(); 380296341Sdelphij char *last_index = NULL; 381296341Sdelphij int i; 382296341Sdelphij char **pp; 383238384Sjkim 384296341Sdelphij SRP_gN *gN = NULL; 385296341Sdelphij SRP_user_pwd *user_pwd = NULL; 386238384Sjkim 387296341Sdelphij TXT_DB *tmpdb = NULL; 388296341Sdelphij BIO *in = BIO_new(BIO_s_file()); 389238384Sjkim 390296341Sdelphij error_code = SRP_ERR_OPEN_FILE; 391238384Sjkim 392296341Sdelphij if (in == NULL || BIO_read_filename(in, verifier_file) <= 0) 393296341Sdelphij goto err; 394238384Sjkim 395296341Sdelphij error_code = SRP_ERR_VBASE_INCOMPLETE_FILE; 396238384Sjkim 397296341Sdelphij if ((tmpdb = TXT_DB_read(in, DB_NUMBER)) == NULL) 398296341Sdelphij goto err; 399238384Sjkim 400296341Sdelphij error_code = SRP_ERR_MEMORY; 401238384Sjkim 402296341Sdelphij if (vb->seed_key) { 403296341Sdelphij last_index = SRP_get_default_gN(NULL)->id; 404296341Sdelphij } 405296341Sdelphij for (i = 0; i < sk_OPENSSL_PSTRING_num(tmpdb->data); i++) { 406296341Sdelphij pp = sk_OPENSSL_PSTRING_value(tmpdb->data, i); 407296341Sdelphij if (pp[DB_srptype][0] == DB_SRP_INDEX) { 408296341Sdelphij /* 409296341Sdelphij * we add this couple in the internal Stack 410296341Sdelphij */ 411238384Sjkim 412296341Sdelphij if ((gN = (SRP_gN *) OPENSSL_malloc(sizeof(SRP_gN))) == NULL) 413296341Sdelphij goto err; 414238384Sjkim 415296341Sdelphij if (!(gN->id = BUF_strdup(pp[DB_srpid])) 416296341Sdelphij || !(gN->N = 417296341Sdelphij SRP_gN_place_bn(vb->gN_cache, pp[DB_srpverifier])) 418296341Sdelphij || !(gN->g = SRP_gN_place_bn(vb->gN_cache, pp[DB_srpsalt])) 419296341Sdelphij || sk_SRP_gN_insert(SRP_gN_tab, gN, 0) == 0) 420296341Sdelphij goto err; 421238384Sjkim 422296341Sdelphij gN = NULL; 423238384Sjkim 424296341Sdelphij if (vb->seed_key != NULL) { 425296341Sdelphij last_index = pp[DB_srpid]; 426296341Sdelphij } 427296341Sdelphij } else if (pp[DB_srptype][0] == DB_SRP_VALID) { 428296341Sdelphij /* it is a user .... */ 429296341Sdelphij SRP_gN *lgN; 430296341Sdelphij if ((lgN = SRP_get_gN_by_id(pp[DB_srpgN], SRP_gN_tab)) != NULL) { 431296341Sdelphij error_code = SRP_ERR_MEMORY; 432296341Sdelphij if ((user_pwd = SRP_user_pwd_new()) == NULL) 433296341Sdelphij goto err; 434238384Sjkim 435296341Sdelphij SRP_user_pwd_set_gN(user_pwd, lgN->g, lgN->N); 436296341Sdelphij if (!SRP_user_pwd_set_ids 437296341Sdelphij (user_pwd, pp[DB_srpid], pp[DB_srpinfo])) 438296341Sdelphij goto err; 439238384Sjkim 440296341Sdelphij error_code = SRP_ERR_VBASE_BN_LIB; 441296341Sdelphij if (!SRP_user_pwd_set_sv 442296341Sdelphij (user_pwd, pp[DB_srpsalt], pp[DB_srpverifier])) 443296341Sdelphij goto err; 444238384Sjkim 445296341Sdelphij if (sk_SRP_user_pwd_insert(vb->users_pwd, user_pwd, 0) == 0) 446296341Sdelphij goto err; 447296341Sdelphij user_pwd = NULL; /* abandon responsability */ 448296341Sdelphij } 449296341Sdelphij } 450296341Sdelphij } 451238384Sjkim 452296341Sdelphij if (last_index != NULL) { 453296341Sdelphij /* this means that we want to simulate a default user */ 454296341Sdelphij 455296341Sdelphij if (((gN = SRP_get_gN_by_id(last_index, SRP_gN_tab)) == NULL)) { 456296341Sdelphij error_code = SRP_ERR_VBASE_BN_LIB; 457296341Sdelphij goto err; 458296341Sdelphij } 459296341Sdelphij vb->default_g = gN->g; 460296341Sdelphij vb->default_N = gN->N; 461296341Sdelphij gN = NULL; 462296341Sdelphij } 463296341Sdelphij error_code = SRP_NO_ERROR; 464296341Sdelphij 465238384Sjkim err: 466296341Sdelphij /* 467296341Sdelphij * there may be still some leaks to fix, if this fails, the application 468296341Sdelphij * terminates most likely 469296341Sdelphij */ 470238384Sjkim 471296341Sdelphij if (gN != NULL) { 472296341Sdelphij OPENSSL_free(gN->id); 473296341Sdelphij OPENSSL_free(gN); 474296341Sdelphij } 475238384Sjkim 476296341Sdelphij SRP_user_pwd_free(user_pwd); 477238384Sjkim 478296341Sdelphij if (tmpdb) 479296341Sdelphij TXT_DB_free(tmpdb); 480296341Sdelphij if (in) 481296341Sdelphij BIO_free_all(in); 482238384Sjkim 483296341Sdelphij sk_SRP_gN_free(SRP_gN_tab); 484238384Sjkim 485296341Sdelphij return error_code; 486238384Sjkim 487296341Sdelphij} 488238384Sjkim 489296341Sdelphijstatic SRP_user_pwd *find_user(SRP_VBASE *vb, char *username) 490296341Sdelphij{ 491296341Sdelphij int i; 492296341Sdelphij SRP_user_pwd *user; 493238384Sjkim 494296341Sdelphij if (vb == NULL) 495296341Sdelphij return NULL; 496296341Sdelphij 497296341Sdelphij for (i = 0; i < sk_SRP_user_pwd_num(vb->users_pwd); i++) { 498296341Sdelphij user = sk_SRP_user_pwd_value(vb->users_pwd, i); 499296341Sdelphij if (strcmp(user->id, username) == 0) 500296341Sdelphij return user; 501296341Sdelphij } 502296341Sdelphij 503296341Sdelphij return NULL; 504296341Sdelphij} 505296341Sdelphij 506296341Sdelphij/* 507296341Sdelphij * This method ignores the configured seed and fails for an unknown user. 508296341Sdelphij * Ownership of the returned pointer is not released to the caller. 509296341Sdelphij * In other words, caller must not free the result. 510296341Sdelphij */ 511238384SjkimSRP_user_pwd *SRP_VBASE_get_by_user(SRP_VBASE *vb, char *username) 512296341Sdelphij{ 513296341Sdelphij return find_user(vb, username); 514296341Sdelphij} 515238384Sjkim 516296341Sdelphij/* 517296341Sdelphij * Ownership of the returned pointer is released to the caller. 518296341Sdelphij * In other words, caller must free the result once done. 519296341Sdelphij */ 520296341SdelphijSRP_user_pwd *SRP_VBASE_get1_by_user(SRP_VBASE *vb, char *username) 521296341Sdelphij{ 522296341Sdelphij SRP_user_pwd *user; 523296341Sdelphij unsigned char digv[SHA_DIGEST_LENGTH]; 524296341Sdelphij unsigned char digs[SHA_DIGEST_LENGTH]; 525296341Sdelphij EVP_MD_CTX ctxt; 526238384Sjkim 527296341Sdelphij if (vb == NULL) 528296341Sdelphij return NULL; 529296341Sdelphij 530296341Sdelphij if ((user = find_user(vb, username)) != NULL) 531296341Sdelphij return srp_user_pwd_dup(user); 532296341Sdelphij 533296341Sdelphij if ((vb->seed_key == NULL) || 534296341Sdelphij (vb->default_g == NULL) || (vb->default_N == NULL)) 535296341Sdelphij return NULL; 536296341Sdelphij 537238384Sjkim/* if the user is unknown we set parameters as well if we have a seed_key */ 538238384Sjkim 539296341Sdelphij if ((user = SRP_user_pwd_new()) == NULL) 540296341Sdelphij return NULL; 541238384Sjkim 542296341Sdelphij SRP_user_pwd_set_gN(user, vb->default_g, vb->default_N); 543238384Sjkim 544296341Sdelphij if (!SRP_user_pwd_set_ids(user, username, NULL)) 545296341Sdelphij goto err; 546238384Sjkim 547296341Sdelphij if (RAND_pseudo_bytes(digv, SHA_DIGEST_LENGTH) < 0) 548296341Sdelphij goto err; 549296341Sdelphij EVP_MD_CTX_init(&ctxt); 550296341Sdelphij EVP_DigestInit_ex(&ctxt, EVP_sha1(), NULL); 551296341Sdelphij EVP_DigestUpdate(&ctxt, vb->seed_key, strlen(vb->seed_key)); 552296341Sdelphij EVP_DigestUpdate(&ctxt, username, strlen(username)); 553296341Sdelphij EVP_DigestFinal_ex(&ctxt, digs, NULL); 554296341Sdelphij EVP_MD_CTX_cleanup(&ctxt); 555296341Sdelphij if (SRP_user_pwd_set_sv_BN 556296341Sdelphij (user, BN_bin2bn(digs, SHA_DIGEST_LENGTH, NULL), 557296341Sdelphij BN_bin2bn(digv, SHA_DIGEST_LENGTH, NULL))) 558296341Sdelphij return user; 559238384Sjkim 560296341Sdelphij err:SRP_user_pwd_free(user); 561296341Sdelphij return NULL; 562296341Sdelphij} 563296341Sdelphij 564238384Sjkim/* 565296341Sdelphij * create a verifier (*salt,*verifier,g and N are in base64) 566296341Sdelphij */ 567238384Sjkimchar *SRP_create_verifier(const char *user, const char *pass, char **salt, 568296341Sdelphij char **verifier, const char *N, const char *g) 569296341Sdelphij{ 570296341Sdelphij int len; 571296341Sdelphij char *result = NULL; 572296341Sdelphij char *vf; 573296341Sdelphij BIGNUM *N_bn = NULL, *g_bn = NULL, *s = NULL, *v = NULL; 574296341Sdelphij unsigned char tmp[MAX_LEN]; 575296341Sdelphij unsigned char tmp2[MAX_LEN]; 576296341Sdelphij char *defgNid = NULL; 577238384Sjkim 578296341Sdelphij if ((user == NULL) || 579296341Sdelphij (pass == NULL) || (salt == NULL) || (verifier == NULL)) 580296341Sdelphij goto err; 581238384Sjkim 582296341Sdelphij if (N) { 583296341Sdelphij if (!(len = t_fromb64(tmp, N))) 584296341Sdelphij goto err; 585296341Sdelphij N_bn = BN_bin2bn(tmp, len, NULL); 586296341Sdelphij if (!(len = t_fromb64(tmp, g))) 587296341Sdelphij goto err; 588296341Sdelphij g_bn = BN_bin2bn(tmp, len, NULL); 589296341Sdelphij defgNid = "*"; 590296341Sdelphij } else { 591296341Sdelphij SRP_gN *gN = SRP_get_gN_by_id(g, NULL); 592296341Sdelphij if (gN == NULL) 593296341Sdelphij goto err; 594296341Sdelphij N_bn = gN->N; 595296341Sdelphij g_bn = gN->g; 596296341Sdelphij defgNid = gN->id; 597296341Sdelphij } 598238384Sjkim 599296341Sdelphij if (*salt == NULL) { 600296341Sdelphij if (RAND_pseudo_bytes(tmp2, SRP_RANDOM_SALT_LEN) < 0) 601296341Sdelphij goto err; 602238384Sjkim 603296341Sdelphij s = BN_bin2bn(tmp2, SRP_RANDOM_SALT_LEN, NULL); 604296341Sdelphij } else { 605296341Sdelphij if (!(len = t_fromb64(tmp2, *salt))) 606296341Sdelphij goto err; 607296341Sdelphij s = BN_bin2bn(tmp2, len, NULL); 608296341Sdelphij } 609238384Sjkim 610296341Sdelphij if (!SRP_create_verifier_BN(user, pass, &s, &v, N_bn, g_bn)) 611296341Sdelphij goto err; 612238384Sjkim 613296341Sdelphij BN_bn2bin(v, tmp); 614296341Sdelphij if (((vf = OPENSSL_malloc(BN_num_bytes(v) * 2)) == NULL)) 615296341Sdelphij goto err; 616296341Sdelphij t_tob64(vf, tmp, BN_num_bytes(v)); 617238384Sjkim 618296341Sdelphij *verifier = vf; 619296341Sdelphij if (*salt == NULL) { 620296341Sdelphij char *tmp_salt; 621238384Sjkim 622296341Sdelphij if ((tmp_salt = OPENSSL_malloc(SRP_RANDOM_SALT_LEN * 2)) == NULL) { 623296341Sdelphij OPENSSL_free(vf); 624296341Sdelphij goto err; 625296341Sdelphij } 626296341Sdelphij t_tob64(tmp_salt, tmp2, SRP_RANDOM_SALT_LEN); 627296341Sdelphij *salt = tmp_salt; 628296341Sdelphij } 629246772Sjkim 630296341Sdelphij result = defgNid; 631238384Sjkim 632296341Sdelphij err: 633296341Sdelphij if (N) { 634296341Sdelphij BN_free(N_bn); 635296341Sdelphij BN_free(g_bn); 636296341Sdelphij } 637296341Sdelphij return result; 638296341Sdelphij} 639238384Sjkim 640238384Sjkim/* 641296341Sdelphij * create a verifier (*salt,*verifier,g and N are BIGNUMs) 642296341Sdelphij */ 643296341Sdelphijint SRP_create_verifier_BN(const char *user, const char *pass, BIGNUM **salt, 644296341Sdelphij BIGNUM **verifier, BIGNUM *N, BIGNUM *g) 645296341Sdelphij{ 646296341Sdelphij int result = 0; 647296341Sdelphij BIGNUM *x = NULL; 648296341Sdelphij BN_CTX *bn_ctx = BN_CTX_new(); 649296341Sdelphij unsigned char tmp2[MAX_LEN]; 650238384Sjkim 651296341Sdelphij if ((user == NULL) || 652296341Sdelphij (pass == NULL) || 653296341Sdelphij (salt == NULL) || 654296341Sdelphij (verifier == NULL) || (N == NULL) || (g == NULL) || (bn_ctx == NULL)) 655296341Sdelphij goto err; 656238384Sjkim 657296341Sdelphij srp_bn_print(N); 658296341Sdelphij srp_bn_print(g); 659238384Sjkim 660296341Sdelphij if (*salt == NULL) { 661296341Sdelphij if (RAND_pseudo_bytes(tmp2, SRP_RANDOM_SALT_LEN) < 0) 662296341Sdelphij goto err; 663238384Sjkim 664296341Sdelphij *salt = BN_bin2bn(tmp2, SRP_RANDOM_SALT_LEN, NULL); 665296341Sdelphij } 666238384Sjkim 667296341Sdelphij x = SRP_Calc_x(*salt, user, pass); 668238384Sjkim 669296341Sdelphij *verifier = BN_new(); 670296341Sdelphij if (*verifier == NULL) 671296341Sdelphij goto err; 672238384Sjkim 673296341Sdelphij if (!BN_mod_exp(*verifier, g, x, N, bn_ctx)) { 674296341Sdelphij BN_clear_free(*verifier); 675296341Sdelphij goto err; 676296341Sdelphij } 677238384Sjkim 678296341Sdelphij srp_bn_print(*verifier); 679238384Sjkim 680296341Sdelphij result = 1; 681238384Sjkim 682296341Sdelphij err: 683238384Sjkim 684296341Sdelphij BN_clear_free(x); 685296341Sdelphij BN_CTX_free(bn_ctx); 686296341Sdelphij return result; 687296341Sdelphij} 688238384Sjkim 689238384Sjkim#endif 690