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