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