srp_vfy.c revision 306195
1/* crypto/srp/srp_vfy.c */
2/*
3 * Written by Christophe Renou (christophe.renou@edelweb.fr) with the
4 * precious help of Peter Sylvester (peter.sylvester@edelweb.fr) for the
5 * EdelKey project and contributed to the OpenSSL project 2004.
6 */
7/* ====================================================================
8 * Copyright (c) 2004 The OpenSSL Project.  All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 *
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in
19 *    the documentation and/or other materials provided with the
20 *    distribution.
21 *
22 * 3. All advertising materials mentioning features or use of this
23 *    software must display the following acknowledgment:
24 *    "This product includes software developed by the OpenSSL Project
25 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
26 *
27 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
28 *    endorse or promote products derived from this software without
29 *    prior written permission. For written permission, please contact
30 *    licensing@OpenSSL.org.
31 *
32 * 5. Products derived from this software may not be called "OpenSSL"
33 *    nor may "OpenSSL" appear in their names without prior written
34 *    permission of the OpenSSL Project.
35 *
36 * 6. Redistributions of any form whatsoever must retain the following
37 *    acknowledgment:
38 *    "This product includes software developed by the OpenSSL Project
39 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
40 *
41 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
42 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
44 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
45 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
47 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
48 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
50 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
51 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
52 * OF THE POSSIBILITY OF SUCH DAMAGE.
53 * ====================================================================
54 *
55 * This product includes cryptographic software written by Eric Young
56 * (eay@cryptsoft.com).  This product includes software written by Tim
57 * Hudson (tjh@cryptsoft.com).
58 *
59 */
60#ifndef OPENSSL_NO_SRP
61# include "cryptlib.h"
62# include "srp_lcl.h"
63# include <openssl/srp.h>
64# include <openssl/evp.h>
65# include <openssl/buffer.h>
66# include <openssl/rand.h>
67# include <openssl/txt_db.h>
68
69# define SRP_RANDOM_SALT_LEN 20
70# define MAX_LEN 2500
71
72static char b64table[] =
73    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./";
74
75/*
76 * the following two conversion routines have been inspired by code from
77 * Stanford
78 */
79
80/*
81 * Convert a base64 string into raw byte array representation.
82 */
83static int t_fromb64(unsigned char *a, size_t alen, const char *src)
84{
85    char *loc;
86    int i, j;
87    int size;
88
89    while (*src && (*src == ' ' || *src == '\t' || *src == '\n'))
90        ++src;
91    size = strlen(src);
92    if (alen > INT_MAX || size > (int)alen)
93        return -1;
94
95    i = 0;
96    while (i < size) {
97        loc = strchr(b64table, src[i]);
98        if (loc == (char *)0)
99            break;
100        else
101            a[i] = loc - b64table;
102        ++i;
103    }
104    /* if nothing valid to process we have a zero length response */
105    if (i == 0)
106        return 0;
107    size = i;
108    i = size - 1;
109    j = size;
110    while (1) {
111        a[j] = a[i];
112        if (--i < 0)
113            break;
114        a[j] |= (a[i] & 3) << 6;
115        --j;
116        a[j] = (unsigned char)((a[i] & 0x3c) >> 2);
117        if (--i < 0)
118            break;
119        a[j] |= (a[i] & 0xf) << 4;
120        --j;
121        a[j] = (unsigned char)((a[i] & 0x30) >> 4);
122        if (--i < 0)
123            break;
124        a[j] |= (a[i] << 2);
125
126        a[--j] = 0;
127        if (--i < 0)
128            break;
129    }
130    while (a[j] == 0 && j <= size)
131        ++j;
132    i = 0;
133    while (j <= size)
134        a[i++] = a[j++];
135    return i;
136}
137
138/*
139 * Convert a raw byte string into a null-terminated base64 ASCII string.
140 */
141static char *t_tob64(char *dst, const unsigned char *src, int size)
142{
143    int c, pos = size % 3;
144    unsigned char b0 = 0, b1 = 0, b2 = 0, notleading = 0;
145    char *olddst = dst;
146
147    switch (pos) {
148    case 1:
149        b2 = src[0];
150        break;
151    case 2:
152        b1 = src[0];
153        b2 = src[1];
154        break;
155    }
156
157    while (1) {
158        c = (b0 & 0xfc) >> 2;
159        if (notleading || c != 0) {
160            *dst++ = b64table[c];
161            notleading = 1;
162        }
163        c = ((b0 & 3) << 4) | ((b1 & 0xf0) >> 4);
164        if (notleading || c != 0) {
165            *dst++ = b64table[c];
166            notleading = 1;
167        }
168        c = ((b1 & 0xf) << 2) | ((b2 & 0xc0) >> 6);
169        if (notleading || c != 0) {
170            *dst++ = b64table[c];
171            notleading = 1;
172        }
173        c = b2 & 0x3f;
174        if (notleading || c != 0) {
175            *dst++ = b64table[c];
176            notleading = 1;
177        }
178        if (pos >= size)
179            break;
180        else {
181            b0 = src[pos++];
182            b1 = src[pos++];
183            b2 = src[pos++];
184        }
185    }
186
187    *dst++ = '\0';
188    return olddst;
189}
190
191void SRP_user_pwd_free(SRP_user_pwd *user_pwd)
192{
193    if (user_pwd == NULL)
194        return;
195    BN_free(user_pwd->s);
196    BN_clear_free(user_pwd->v);
197    OPENSSL_free(user_pwd->id);
198    OPENSSL_free(user_pwd->info);
199    OPENSSL_free(user_pwd);
200}
201
202static SRP_user_pwd *SRP_user_pwd_new()
203{
204    SRP_user_pwd *ret = OPENSSL_malloc(sizeof(SRP_user_pwd));
205    if (ret == NULL)
206        return NULL;
207    ret->N = NULL;
208    ret->g = NULL;
209    ret->s = NULL;
210    ret->v = NULL;
211    ret->id = NULL;
212    ret->info = NULL;
213    return ret;
214}
215
216static void SRP_user_pwd_set_gN(SRP_user_pwd *vinfo, const BIGNUM *g,
217                                const BIGNUM *N)
218{
219    vinfo->N = N;
220    vinfo->g = g;
221}
222
223static int SRP_user_pwd_set_ids(SRP_user_pwd *vinfo, const char *id,
224                                const char *info)
225{
226    if (id != NULL && NULL == (vinfo->id = BUF_strdup(id)))
227        return 0;
228    return (info == NULL || NULL != (vinfo->info = BUF_strdup(info)));
229}
230
231static int SRP_user_pwd_set_sv(SRP_user_pwd *vinfo, const char *s,
232                               const char *v)
233{
234    unsigned char tmp[MAX_LEN];
235    int len;
236
237    vinfo->v = NULL;
238    vinfo->s = NULL;
239
240    len = t_fromb64(tmp, sizeof(tmp), v);
241    if (len < 0)
242        return 0;
243    if (NULL == (vinfo->v = BN_bin2bn(tmp, len, NULL)))
244        return 0;
245    len = t_fromb64(tmp, sizeof(tmp), s);
246    if (len < 0)
247        goto err;
248    vinfo->s = BN_bin2bn(tmp, len, NULL);
249    if (vinfo->s == NULL)
250        goto err;
251    return 1;
252 err:
253    BN_free(vinfo->v);
254    vinfo->v = NULL;
255    return 0;
256}
257
258static int SRP_user_pwd_set_sv_BN(SRP_user_pwd *vinfo, BIGNUM *s, BIGNUM *v)
259{
260    vinfo->v = v;
261    vinfo->s = s;
262    return (vinfo->s != NULL && vinfo->v != NULL);
263}
264
265static SRP_user_pwd *srp_user_pwd_dup(SRP_user_pwd *src)
266{
267    SRP_user_pwd *ret;
268
269    if (src == NULL)
270        return NULL;
271    if ((ret = SRP_user_pwd_new()) == NULL)
272        return NULL;
273
274    SRP_user_pwd_set_gN(ret, src->g, src->N);
275    if (!SRP_user_pwd_set_ids(ret, src->id, src->info)
276        || !SRP_user_pwd_set_sv_BN(ret, BN_dup(src->s), BN_dup(src->v))) {
277            SRP_user_pwd_free(ret);
278            return NULL;
279    }
280    return ret;
281}
282
283SRP_VBASE *SRP_VBASE_new(char *seed_key)
284{
285    SRP_VBASE *vb = (SRP_VBASE *)OPENSSL_malloc(sizeof(SRP_VBASE));
286
287    if (vb == NULL)
288        return NULL;
289    if (!(vb->users_pwd = sk_SRP_user_pwd_new_null()) ||
290        !(vb->gN_cache = sk_SRP_gN_cache_new_null())) {
291        OPENSSL_free(vb);
292        return NULL;
293    }
294    vb->default_g = NULL;
295    vb->default_N = NULL;
296    vb->seed_key = NULL;
297    if ((seed_key != NULL) && (vb->seed_key = BUF_strdup(seed_key)) == NULL) {
298        sk_SRP_user_pwd_free(vb->users_pwd);
299        sk_SRP_gN_cache_free(vb->gN_cache);
300        OPENSSL_free(vb);
301        return NULL;
302    }
303    return vb;
304}
305
306int SRP_VBASE_free(SRP_VBASE *vb)
307{
308    sk_SRP_user_pwd_pop_free(vb->users_pwd, SRP_user_pwd_free);
309    sk_SRP_gN_cache_free(vb->gN_cache);
310    OPENSSL_free(vb->seed_key);
311    OPENSSL_free(vb);
312    return 0;
313}
314
315static SRP_gN_cache *SRP_gN_new_init(const char *ch)
316{
317    unsigned char tmp[MAX_LEN];
318    int len;
319
320    SRP_gN_cache *newgN =
321        (SRP_gN_cache *)OPENSSL_malloc(sizeof(SRP_gN_cache));
322    if (newgN == NULL)
323        return NULL;
324
325    len = t_fromb64(tmp, sizeof(tmp), ch);
326    if (len < 0)
327        goto err;
328
329    if ((newgN->b64_bn = BUF_strdup(ch)) == NULL)
330        goto err;
331
332    if ((newgN->bn = BN_bin2bn(tmp, len, NULL)))
333        return newgN;
334
335    OPENSSL_free(newgN->b64_bn);
336 err:
337    OPENSSL_free(newgN);
338    return NULL;
339}
340
341static void SRP_gN_free(SRP_gN_cache *gN_cache)
342{
343    if (gN_cache == NULL)
344        return;
345    OPENSSL_free(gN_cache->b64_bn);
346    BN_free(gN_cache->bn);
347    OPENSSL_free(gN_cache);
348}
349
350static SRP_gN *SRP_get_gN_by_id(const char *id, STACK_OF(SRP_gN) *gN_tab)
351{
352    int i;
353
354    SRP_gN *gN;
355    if (gN_tab != NULL)
356        for (i = 0; i < sk_SRP_gN_num(gN_tab); i++) {
357            gN = sk_SRP_gN_value(gN_tab, i);
358            if (gN && (id == NULL || strcmp(gN->id, id) == 0))
359                return gN;
360        }
361
362    return SRP_get_default_gN(id);
363}
364
365static BIGNUM *SRP_gN_place_bn(STACK_OF(SRP_gN_cache) *gN_cache, char *ch)
366{
367    int i;
368    if (gN_cache == NULL)
369        return NULL;
370
371    /* search if we have already one... */
372    for (i = 0; i < sk_SRP_gN_cache_num(gN_cache); i++) {
373        SRP_gN_cache *cache = sk_SRP_gN_cache_value(gN_cache, i);
374        if (strcmp(cache->b64_bn, ch) == 0)
375            return cache->bn;
376    }
377    {                           /* it is the first time that we find it */
378        SRP_gN_cache *newgN = SRP_gN_new_init(ch);
379        if (newgN) {
380            if (sk_SRP_gN_cache_insert(gN_cache, newgN, 0) > 0)
381                return newgN->bn;
382            SRP_gN_free(newgN);
383        }
384    }
385    return NULL;
386}
387
388/*
389 * this function parses verifier file. Format is:
390 * string(index):base64(N):base64(g):0
391 * string(username):base64(v):base64(salt):int(index)
392 */
393
394int SRP_VBASE_init(SRP_VBASE *vb, char *verifier_file)
395{
396    int error_code;
397    STACK_OF(SRP_gN) *SRP_gN_tab = sk_SRP_gN_new_null();
398    char *last_index = NULL;
399    int i;
400    char **pp;
401
402    SRP_gN *gN = NULL;
403    SRP_user_pwd *user_pwd = NULL;
404
405    TXT_DB *tmpdb = NULL;
406    BIO *in = BIO_new(BIO_s_file());
407
408    error_code = SRP_ERR_OPEN_FILE;
409
410    if (in == NULL || BIO_read_filename(in, verifier_file) <= 0)
411        goto err;
412
413    error_code = SRP_ERR_VBASE_INCOMPLETE_FILE;
414
415    if ((tmpdb = TXT_DB_read(in, DB_NUMBER)) == NULL)
416        goto err;
417
418    error_code = SRP_ERR_MEMORY;
419
420    if (vb->seed_key) {
421        last_index = SRP_get_default_gN(NULL)->id;
422    }
423    for (i = 0; i < sk_OPENSSL_PSTRING_num(tmpdb->data); i++) {
424        pp = sk_OPENSSL_PSTRING_value(tmpdb->data, i);
425        if (pp[DB_srptype][0] == DB_SRP_INDEX) {
426            /*
427             * we add this couple in the internal Stack
428             */
429
430            if ((gN = (SRP_gN *) OPENSSL_malloc(sizeof(SRP_gN))) == NULL)
431                goto err;
432
433            if (!(gN->id = BUF_strdup(pp[DB_srpid]))
434                || !(gN->N =
435                     SRP_gN_place_bn(vb->gN_cache, pp[DB_srpverifier]))
436                || !(gN->g = SRP_gN_place_bn(vb->gN_cache, pp[DB_srpsalt]))
437                || sk_SRP_gN_insert(SRP_gN_tab, gN, 0) == 0)
438                goto err;
439
440            gN = NULL;
441
442            if (vb->seed_key != NULL) {
443                last_index = pp[DB_srpid];
444            }
445        } else if (pp[DB_srptype][0] == DB_SRP_VALID) {
446            /* it is a user .... */
447            SRP_gN *lgN;
448            if ((lgN = SRP_get_gN_by_id(pp[DB_srpgN], SRP_gN_tab)) != NULL) {
449                error_code = SRP_ERR_MEMORY;
450                if ((user_pwd = SRP_user_pwd_new()) == NULL)
451                    goto err;
452
453                SRP_user_pwd_set_gN(user_pwd, lgN->g, lgN->N);
454                if (!SRP_user_pwd_set_ids
455                    (user_pwd, pp[DB_srpid], pp[DB_srpinfo]))
456                    goto err;
457
458                error_code = SRP_ERR_VBASE_BN_LIB;
459                if (!SRP_user_pwd_set_sv
460                    (user_pwd, pp[DB_srpsalt], pp[DB_srpverifier]))
461                    goto err;
462
463                if (sk_SRP_user_pwd_insert(vb->users_pwd, user_pwd, 0) == 0)
464                    goto err;
465                user_pwd = NULL; /* abandon responsability */
466            }
467        }
468    }
469
470    if (last_index != NULL) {
471        /* this means that we want to simulate a default user */
472
473        if (((gN = SRP_get_gN_by_id(last_index, SRP_gN_tab)) == NULL)) {
474            error_code = SRP_ERR_VBASE_BN_LIB;
475            goto err;
476        }
477        vb->default_g = gN->g;
478        vb->default_N = gN->N;
479        gN = NULL;
480    }
481    error_code = SRP_NO_ERROR;
482
483 err:
484    /*
485     * there may be still some leaks to fix, if this fails, the application
486     * terminates most likely
487     */
488
489    if (gN != NULL) {
490        OPENSSL_free(gN->id);
491        OPENSSL_free(gN);
492    }
493
494    SRP_user_pwd_free(user_pwd);
495
496    if (tmpdb)
497        TXT_DB_free(tmpdb);
498    if (in)
499        BIO_free_all(in);
500
501    sk_SRP_gN_free(SRP_gN_tab);
502
503    return error_code;
504
505}
506
507static SRP_user_pwd *find_user(SRP_VBASE *vb, char *username)
508{
509    int i;
510    SRP_user_pwd *user;
511
512    if (vb == NULL)
513        return NULL;
514
515    for (i = 0; i < sk_SRP_user_pwd_num(vb->users_pwd); i++) {
516        user = sk_SRP_user_pwd_value(vb->users_pwd, i);
517        if (strcmp(user->id, username) == 0)
518            return user;
519    }
520
521    return NULL;
522}
523
524/*
525 * This method ignores the configured seed and fails for an unknown user.
526 * Ownership of the returned pointer is not released to the caller.
527 * In other words, caller must not free the result.
528 */
529SRP_user_pwd *SRP_VBASE_get_by_user(SRP_VBASE *vb, char *username)
530{
531    return find_user(vb, username);
532}
533
534/*
535 * Ownership of the returned pointer is released to the caller.
536 * In other words, caller must free the result once done.
537 */
538SRP_user_pwd *SRP_VBASE_get1_by_user(SRP_VBASE *vb, char *username)
539{
540    SRP_user_pwd *user;
541    unsigned char digv[SHA_DIGEST_LENGTH];
542    unsigned char digs[SHA_DIGEST_LENGTH];
543    EVP_MD_CTX ctxt;
544
545    if (vb == NULL)
546        return NULL;
547
548    if ((user = find_user(vb, username)) != NULL)
549        return srp_user_pwd_dup(user);
550
551    if ((vb->seed_key == NULL) ||
552        (vb->default_g == NULL) || (vb->default_N == NULL))
553        return NULL;
554
555/* if the user is unknown we set parameters as well if we have a seed_key */
556
557    if ((user = SRP_user_pwd_new()) == NULL)
558        return NULL;
559
560    SRP_user_pwd_set_gN(user, vb->default_g, vb->default_N);
561
562    if (!SRP_user_pwd_set_ids(user, username, NULL))
563        goto err;
564
565    if (RAND_bytes(digv, SHA_DIGEST_LENGTH) <= 0)
566        goto err;
567    EVP_MD_CTX_init(&ctxt);
568    EVP_DigestInit_ex(&ctxt, EVP_sha1(), NULL);
569    EVP_DigestUpdate(&ctxt, vb->seed_key, strlen(vb->seed_key));
570    EVP_DigestUpdate(&ctxt, username, strlen(username));
571    EVP_DigestFinal_ex(&ctxt, digs, NULL);
572    EVP_MD_CTX_cleanup(&ctxt);
573    if (SRP_user_pwd_set_sv_BN
574        (user, BN_bin2bn(digs, SHA_DIGEST_LENGTH, NULL),
575         BN_bin2bn(digv, SHA_DIGEST_LENGTH, NULL)))
576        return user;
577
578 err:SRP_user_pwd_free(user);
579    return NULL;
580}
581
582/*
583 * create a verifier (*salt,*verifier,g and N are in base64)
584 */
585char *SRP_create_verifier(const char *user, const char *pass, char **salt,
586                          char **verifier, const char *N, const char *g)
587{
588    int len;
589    char *result = NULL, *vf = NULL;
590    BIGNUM *N_bn = NULL, *g_bn = NULL, *s = NULL, *v = NULL;
591    unsigned char tmp[MAX_LEN];
592    unsigned char tmp2[MAX_LEN];
593    char *defgNid = NULL;
594    int vfsize = 0;
595
596    if ((user == NULL) ||
597        (pass == NULL) || (salt == NULL) || (verifier == NULL))
598        goto err;
599
600    if (N) {
601        if (!(len = t_fromb64(tmp, sizeof(tmp), N)))
602            goto err;
603        N_bn = BN_bin2bn(tmp, len, NULL);
604        if (!(len = t_fromb64(tmp, sizeof(tmp), g)))
605            goto err;
606        g_bn = BN_bin2bn(tmp, len, NULL);
607        defgNid = "*";
608    } else {
609        SRP_gN *gN = SRP_get_gN_by_id(g, NULL);
610        if (gN == NULL)
611            goto err;
612        N_bn = gN->N;
613        g_bn = gN->g;
614        defgNid = gN->id;
615    }
616
617    if (*salt == NULL) {
618        if (RAND_bytes(tmp2, SRP_RANDOM_SALT_LEN) <= 0)
619            goto err;
620
621        s = BN_bin2bn(tmp2, SRP_RANDOM_SALT_LEN, NULL);
622    } else {
623        if (!(len = t_fromb64(tmp2, sizeof(tmp2), *salt)))
624            goto err;
625        s = BN_bin2bn(tmp2, len, NULL);
626    }
627
628    if (!SRP_create_verifier_BN(user, pass, &s, &v, N_bn, g_bn))
629        goto err;
630
631    BN_bn2bin(v, tmp);
632    vfsize = BN_num_bytes(v) * 2;
633    if (((vf = OPENSSL_malloc(vfsize)) == NULL))
634        goto err;
635    t_tob64(vf, tmp, BN_num_bytes(v));
636
637    if (*salt == NULL) {
638        char *tmp_salt;
639
640        if ((tmp_salt = OPENSSL_malloc(SRP_RANDOM_SALT_LEN * 2)) == NULL) {
641            goto err;
642        }
643        t_tob64(tmp_salt, tmp2, SRP_RANDOM_SALT_LEN);
644        *salt = tmp_salt;
645    }
646
647    *verifier = vf;
648    vf = NULL;
649    result = defgNid;
650
651 err:
652    if (N) {
653        BN_free(N_bn);
654        BN_free(g_bn);
655    }
656    if (vf != NULL)
657        OPENSSL_cleanse(vf, vfsize);
658    OPENSSL_free(vf);
659    BN_clear_free(s);
660    BN_clear_free(v);
661    return result;
662}
663
664/*
665 * create a verifier (*salt,*verifier,g and N are BIGNUMs). If *salt != NULL
666 * then the provided salt will be used. On successful exit *verifier will point
667 * to a newly allocated BIGNUM containing the verifier and (if a salt was not
668 * provided) *salt will be populated with a newly allocated BIGNUM containing a
669 * random salt.
670 * The caller is responsible for freeing the allocated *salt and *verifier
671 * BIGNUMS.
672 */
673int SRP_create_verifier_BN(const char *user, const char *pass, BIGNUM **salt,
674                           BIGNUM **verifier, BIGNUM *N, BIGNUM *g)
675{
676    int result = 0;
677    BIGNUM *x = NULL;
678    BN_CTX *bn_ctx = BN_CTX_new();
679    unsigned char tmp2[MAX_LEN];
680    BIGNUM *salttmp = NULL;
681
682    if ((user == NULL) ||
683        (pass == NULL) ||
684        (salt == NULL) ||
685        (verifier == NULL) || (N == NULL) || (g == NULL) || (bn_ctx == NULL))
686        goto err;
687
688    srp_bn_print(N);
689    srp_bn_print(g);
690
691    if (*salt == NULL) {
692        if (RAND_bytes(tmp2, SRP_RANDOM_SALT_LEN) <= 0)
693            goto err;
694
695        salttmp = BN_bin2bn(tmp2, SRP_RANDOM_SALT_LEN, NULL);
696    } else {
697        salttmp = *salt;
698    }
699
700    x = SRP_Calc_x(salttmp, user, pass);
701
702    *verifier = BN_new();
703    if (*verifier == NULL)
704        goto err;
705
706    if (!BN_mod_exp(*verifier, g, x, N, bn_ctx)) {
707        BN_clear_free(*verifier);
708        goto err;
709    }
710
711    srp_bn_print(*verifier);
712
713    result = 1;
714    *salt = salttmp;
715
716 err:
717    if (*salt != salttmp)
718        BN_clear_free(salttmp);
719    BN_clear_free(x);
720    BN_CTX_free(bn_ctx);
721    return result;
722}
723
724#endif
725