160662d10Schristos /*
2*1dcdf01fSchristos  * Copyright 2004-2021 The OpenSSL Project Authors. All Rights Reserved.
3*1dcdf01fSchristos  * Copyright (c) 2004, EdelKey Project. All Rights Reserved.
4*1dcdf01fSchristos  *
5*1dcdf01fSchristos  * Licensed under the OpenSSL license (the "License").  You may not use
6*1dcdf01fSchristos  * this file except in compliance with the License.  You can obtain a copy
7*1dcdf01fSchristos  * in the file LICENSE in the source distribution or at
8*1dcdf01fSchristos  * https://www.openssl.org/source/license.html
9*1dcdf01fSchristos  *
10*1dcdf01fSchristos  * Originally written by Christophe Renou and Peter Sylvester,
11*1dcdf01fSchristos  * for the EdelKey project.
1260662d10Schristos  */
13*1dcdf01fSchristos 
1460662d10Schristos #ifndef OPENSSL_NO_SRP
15*1dcdf01fSchristos # include "internal/cryptlib.h"
16*1dcdf01fSchristos # include "crypto/evp.h"
17*1dcdf01fSchristos # include <openssl/sha.h>
1860662d10Schristos # include <openssl/srp.h>
1960662d10Schristos # include <openssl/evp.h>
2060662d10Schristos # include <openssl/buffer.h>
2160662d10Schristos # include <openssl/rand.h>
2260662d10Schristos # include <openssl/txt_db.h>
23*1dcdf01fSchristos # include <openssl/err.h>
2460662d10Schristos 
2560662d10Schristos # define SRP_RANDOM_SALT_LEN 20
2660662d10Schristos # define MAX_LEN 2500
2760662d10Schristos 
2860662d10Schristos /*
29*1dcdf01fSchristos  * Note that SRP uses its own variant of base 64 encoding. A different base64
30*1dcdf01fSchristos  * alphabet is used and no padding '=' characters are added. Instead we pad to
31*1dcdf01fSchristos  * the front with 0 bytes and subsequently strip off leading encoded padding.
32*1dcdf01fSchristos  * This variant is used for compatibility with other SRP implementations -
33*1dcdf01fSchristos  * notably libsrp, but also others. It is also required for backwards
34*1dcdf01fSchristos  * compatibility in order to load verifier files from other OpenSSL versions.
3560662d10Schristos  */
3660662d10Schristos 
3760662d10Schristos /*
3860662d10Schristos  * Convert a base64 string into raw byte array representation.
39*1dcdf01fSchristos  * Returns the length of the decoded data, or -1 on error.
4060662d10Schristos  */
t_fromb64(unsigned char * a,size_t alen,const char * src)4160662d10Schristos static int t_fromb64(unsigned char *a, size_t alen, const char *src)
4260662d10Schristos {
43*1dcdf01fSchristos     EVP_ENCODE_CTX *ctx;
44*1dcdf01fSchristos     int outl = 0, outl2 = 0;
45*1dcdf01fSchristos     size_t size, padsize;
46*1dcdf01fSchristos     const unsigned char *pad = (const unsigned char *)"00";
4760662d10Schristos 
48*1dcdf01fSchristos     while (*src == ' ' || *src == '\t' || *src == '\n')
4960662d10Schristos         ++src;
5060662d10Schristos     size = strlen(src);
51*1dcdf01fSchristos     padsize = 4 - (size & 3);
52*1dcdf01fSchristos     padsize &= 3;
53*1dcdf01fSchristos 
54*1dcdf01fSchristos     /* Four bytes in src become three bytes output. */
55*1dcdf01fSchristos     if (size > INT_MAX || ((size + padsize) / 4) * 3 > alen)
5660662d10Schristos         return -1;
5760662d10Schristos 
58*1dcdf01fSchristos     ctx = EVP_ENCODE_CTX_new();
59*1dcdf01fSchristos     if (ctx == NULL)
60*1dcdf01fSchristos         return -1;
6160662d10Schristos 
62*1dcdf01fSchristos     /*
63*1dcdf01fSchristos      * This should never occur because 1 byte of data always requires 2 bytes of
64*1dcdf01fSchristos      * encoding, i.e.
65*1dcdf01fSchristos      *  0 bytes unencoded = 0 bytes encoded
66*1dcdf01fSchristos      *  1 byte unencoded  = 2 bytes encoded
67*1dcdf01fSchristos      *  2 bytes unencoded = 3 bytes encoded
68*1dcdf01fSchristos      *  3 bytes unencoded = 4 bytes encoded
69*1dcdf01fSchristos      *  4 bytes unencoded = 6 bytes encoded
70*1dcdf01fSchristos      *  etc
71*1dcdf01fSchristos      */
72*1dcdf01fSchristos     if (padsize == 3) {
73*1dcdf01fSchristos         outl = -1;
74*1dcdf01fSchristos         goto err;
7560662d10Schristos     }
76*1dcdf01fSchristos 
77*1dcdf01fSchristos     /* Valid padsize values are now 0, 1 or 2 */
78*1dcdf01fSchristos 
79*1dcdf01fSchristos     EVP_DecodeInit(ctx);
80*1dcdf01fSchristos     evp_encode_ctx_set_flags(ctx, EVP_ENCODE_CTX_USE_SRP_ALPHABET);
81*1dcdf01fSchristos 
82*1dcdf01fSchristos     /* Add any encoded padding that is required */
83*1dcdf01fSchristos     if (padsize != 0
84*1dcdf01fSchristos             && EVP_DecodeUpdate(ctx, a, &outl, pad, padsize) < 0) {
85*1dcdf01fSchristos         outl = -1;
86*1dcdf01fSchristos         goto err;
87*1dcdf01fSchristos     }
88*1dcdf01fSchristos     if (EVP_DecodeUpdate(ctx, a, &outl2, (const unsigned char *)src, size) < 0) {
89*1dcdf01fSchristos         outl = -1;
90*1dcdf01fSchristos         goto err;
91*1dcdf01fSchristos     }
92*1dcdf01fSchristos     outl += outl2;
93*1dcdf01fSchristos     EVP_DecodeFinal(ctx, a + outl, &outl2);
94*1dcdf01fSchristos     outl += outl2;
95*1dcdf01fSchristos 
96*1dcdf01fSchristos     /* Strip off the leading padding */
97*1dcdf01fSchristos     if (padsize != 0) {
98*1dcdf01fSchristos         if ((int)padsize >= outl) {
99*1dcdf01fSchristos             outl = -1;
100*1dcdf01fSchristos             goto err;
101*1dcdf01fSchristos         }
102*1dcdf01fSchristos 
103*1dcdf01fSchristos         /*
104*1dcdf01fSchristos          * If we added 1 byte of padding prior to encoding then we have 2 bytes
105*1dcdf01fSchristos          * of "real" data which gets spread across 4 encoded bytes like this:
106*1dcdf01fSchristos          *   (6 bits pad)(2 bits pad | 4 bits data)(6 bits data)(6 bits data)
107*1dcdf01fSchristos          * So 1 byte of pre-encoding padding results in 1 full byte of encoded
108*1dcdf01fSchristos          * padding.
109*1dcdf01fSchristos          * If we added 2 bytes of padding prior to encoding this gets encoded
110*1dcdf01fSchristos          * as:
111*1dcdf01fSchristos          *   (6 bits pad)(6 bits pad)(4 bits pad | 2 bits data)(6 bits data)
112*1dcdf01fSchristos          * So 2 bytes of pre-encoding padding results in 2 full bytes of encoded
113*1dcdf01fSchristos          * padding, i.e. we have to strip the same number of bytes of padding
114*1dcdf01fSchristos          * from the encoded data as we added to the pre-encoded data.
115*1dcdf01fSchristos          */
116*1dcdf01fSchristos         memmove(a, a + padsize, outl - padsize);
117*1dcdf01fSchristos         outl -= padsize;
118*1dcdf01fSchristos     }
119*1dcdf01fSchristos 
120*1dcdf01fSchristos  err:
121*1dcdf01fSchristos     EVP_ENCODE_CTX_free(ctx);
122*1dcdf01fSchristos 
123*1dcdf01fSchristos     return outl;
12460662d10Schristos }
12560662d10Schristos 
12660662d10Schristos /*
12760662d10Schristos  * Convert a raw byte string into a null-terminated base64 ASCII string.
128*1dcdf01fSchristos  * Returns 1 on success or 0 on error.
12960662d10Schristos  */
t_tob64(char * dst,const unsigned char * src,int size)130*1dcdf01fSchristos static int t_tob64(char *dst, const unsigned char *src, int size)
13160662d10Schristos {
132*1dcdf01fSchristos     EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new();
133*1dcdf01fSchristos     int outl = 0, outl2 = 0;
134*1dcdf01fSchristos     unsigned char pad[2] = {0, 0};
135*1dcdf01fSchristos     size_t leadz = 0;
13660662d10Schristos 
137*1dcdf01fSchristos     if (ctx == NULL)
138*1dcdf01fSchristos         return 0;
139*1dcdf01fSchristos 
140*1dcdf01fSchristos     EVP_EncodeInit(ctx);
141*1dcdf01fSchristos     evp_encode_ctx_set_flags(ctx, EVP_ENCODE_CTX_NO_NEWLINES
142*1dcdf01fSchristos                                   | EVP_ENCODE_CTX_USE_SRP_ALPHABET);
143*1dcdf01fSchristos 
144*1dcdf01fSchristos     /*
145*1dcdf01fSchristos      * We pad at the front with zero bytes until the length is a multiple of 3
146*1dcdf01fSchristos      * so that EVP_EncodeUpdate/EVP_EncodeFinal does not add any of its own "="
147*1dcdf01fSchristos      * padding
148*1dcdf01fSchristos      */
149*1dcdf01fSchristos     leadz = 3 - (size % 3);
150*1dcdf01fSchristos     if (leadz != 3
151*1dcdf01fSchristos             && !EVP_EncodeUpdate(ctx, (unsigned char *)dst, &outl, pad,
152*1dcdf01fSchristos                                  leadz)) {
153*1dcdf01fSchristos         EVP_ENCODE_CTX_free(ctx);
154*1dcdf01fSchristos         return 0;
15560662d10Schristos     }
15660662d10Schristos 
157*1dcdf01fSchristos     if (!EVP_EncodeUpdate(ctx, (unsigned char *)dst + outl, &outl2, src,
158*1dcdf01fSchristos                           size)) {
159*1dcdf01fSchristos         EVP_ENCODE_CTX_free(ctx);
160*1dcdf01fSchristos         return 0;
16160662d10Schristos     }
162*1dcdf01fSchristos     outl += outl2;
163*1dcdf01fSchristos     EVP_EncodeFinal(ctx, (unsigned char *)dst + outl, &outl2);
164*1dcdf01fSchristos     outl += outl2;
165*1dcdf01fSchristos 
166*1dcdf01fSchristos     /* Strip the encoded padding at the front */
167*1dcdf01fSchristos     if (leadz != 3) {
168*1dcdf01fSchristos         memmove(dst, dst + leadz, outl - leadz);
169*1dcdf01fSchristos         dst[outl - leadz] = '\0';
17060662d10Schristos     }
17160662d10Schristos 
172*1dcdf01fSchristos     EVP_ENCODE_CTX_free(ctx);
173*1dcdf01fSchristos     return 1;
17460662d10Schristos }
17560662d10Schristos 
SRP_user_pwd_free(SRP_user_pwd * user_pwd)17660662d10Schristos void SRP_user_pwd_free(SRP_user_pwd *user_pwd)
17760662d10Schristos {
17860662d10Schristos     if (user_pwd == NULL)
17960662d10Schristos         return;
18060662d10Schristos     BN_free(user_pwd->s);
18160662d10Schristos     BN_clear_free(user_pwd->v);
18260662d10Schristos     OPENSSL_free(user_pwd->id);
18360662d10Schristos     OPENSSL_free(user_pwd->info);
18460662d10Schristos     OPENSSL_free(user_pwd);
18560662d10Schristos }
18660662d10Schristos 
SRP_user_pwd_new(void)187*1dcdf01fSchristos static SRP_user_pwd *SRP_user_pwd_new(void)
18860662d10Schristos {
189*1dcdf01fSchristos     SRP_user_pwd *ret;
190*1dcdf01fSchristos 
191*1dcdf01fSchristos     if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL) {
192*1dcdf01fSchristos         /* SRPerr(SRP_F_SRP_USER_PWD_NEW, ERR_R_MALLOC_FAILURE); */ /*ckerr_ignore*/
19360662d10Schristos         return NULL;
194*1dcdf01fSchristos     }
19560662d10Schristos     ret->N = NULL;
19660662d10Schristos     ret->g = NULL;
19760662d10Schristos     ret->s = NULL;
19860662d10Schristos     ret->v = NULL;
19960662d10Schristos     ret->id = NULL;
20060662d10Schristos     ret->info = NULL;
20160662d10Schristos     return ret;
20260662d10Schristos }
20360662d10Schristos 
SRP_user_pwd_set_gN(SRP_user_pwd * vinfo,const BIGNUM * g,const BIGNUM * N)20460662d10Schristos static void SRP_user_pwd_set_gN(SRP_user_pwd *vinfo, const BIGNUM *g,
20560662d10Schristos                                 const BIGNUM *N)
20660662d10Schristos {
20760662d10Schristos     vinfo->N = N;
20860662d10Schristos     vinfo->g = g;
20960662d10Schristos }
21060662d10Schristos 
SRP_user_pwd_set_ids(SRP_user_pwd * vinfo,const char * id,const char * info)21160662d10Schristos static int SRP_user_pwd_set_ids(SRP_user_pwd *vinfo, const char *id,
21260662d10Schristos                                 const char *info)
21360662d10Schristos {
214*1dcdf01fSchristos     if (id != NULL && NULL == (vinfo->id = OPENSSL_strdup(id)))
21560662d10Schristos         return 0;
216*1dcdf01fSchristos     return (info == NULL || NULL != (vinfo->info = OPENSSL_strdup(info)));
21760662d10Schristos }
21860662d10Schristos 
SRP_user_pwd_set_sv(SRP_user_pwd * vinfo,const char * s,const char * v)21960662d10Schristos static int SRP_user_pwd_set_sv(SRP_user_pwd *vinfo, const char *s,
22060662d10Schristos                                const char *v)
22160662d10Schristos {
22260662d10Schristos     unsigned char tmp[MAX_LEN];
22360662d10Schristos     int len;
22460662d10Schristos 
22560662d10Schristos     vinfo->v = NULL;
22660662d10Schristos     vinfo->s = NULL;
22760662d10Schristos 
22860662d10Schristos     len = t_fromb64(tmp, sizeof(tmp), v);
22960662d10Schristos     if (len < 0)
23060662d10Schristos         return 0;
23160662d10Schristos     if (NULL == (vinfo->v = BN_bin2bn(tmp, len, NULL)))
23260662d10Schristos         return 0;
23360662d10Schristos     len = t_fromb64(tmp, sizeof(tmp), s);
23460662d10Schristos     if (len < 0)
23560662d10Schristos         goto err;
23660662d10Schristos     vinfo->s = BN_bin2bn(tmp, len, NULL);
23760662d10Schristos     if (vinfo->s == NULL)
23860662d10Schristos         goto err;
23960662d10Schristos     return 1;
24060662d10Schristos  err:
24160662d10Schristos     BN_free(vinfo->v);
24260662d10Schristos     vinfo->v = NULL;
24360662d10Schristos     return 0;
24460662d10Schristos }
24560662d10Schristos 
SRP_user_pwd_set_sv_BN(SRP_user_pwd * vinfo,BIGNUM * s,BIGNUM * v)24660662d10Schristos static int SRP_user_pwd_set_sv_BN(SRP_user_pwd *vinfo, BIGNUM *s, BIGNUM *v)
24760662d10Schristos {
24860662d10Schristos     vinfo->v = v;
24960662d10Schristos     vinfo->s = s;
25060662d10Schristos     return (vinfo->s != NULL && vinfo->v != NULL);
25160662d10Schristos }
25260662d10Schristos 
srp_user_pwd_dup(SRP_user_pwd * src)25360662d10Schristos static SRP_user_pwd *srp_user_pwd_dup(SRP_user_pwd *src)
25460662d10Schristos {
25560662d10Schristos     SRP_user_pwd *ret;
25660662d10Schristos 
25760662d10Schristos     if (src == NULL)
25860662d10Schristos         return NULL;
25960662d10Schristos     if ((ret = SRP_user_pwd_new()) == NULL)
26060662d10Schristos         return NULL;
26160662d10Schristos 
26260662d10Schristos     SRP_user_pwd_set_gN(ret, src->g, src->N);
26360662d10Schristos     if (!SRP_user_pwd_set_ids(ret, src->id, src->info)
26460662d10Schristos         || !SRP_user_pwd_set_sv_BN(ret, BN_dup(src->s), BN_dup(src->v))) {
26560662d10Schristos             SRP_user_pwd_free(ret);
26660662d10Schristos             return NULL;
26760662d10Schristos     }
26860662d10Schristos     return ret;
26960662d10Schristos }
27060662d10Schristos 
SRP_VBASE_new(char * seed_key)27160662d10Schristos SRP_VBASE *SRP_VBASE_new(char *seed_key)
27260662d10Schristos {
273*1dcdf01fSchristos     SRP_VBASE *vb = OPENSSL_malloc(sizeof(*vb));
27460662d10Schristos 
27560662d10Schristos     if (vb == NULL)
27660662d10Schristos         return NULL;
277*1dcdf01fSchristos     if ((vb->users_pwd = sk_SRP_user_pwd_new_null()) == NULL
278*1dcdf01fSchristos         || (vb->gN_cache = sk_SRP_gN_cache_new_null()) == NULL) {
27960662d10Schristos         OPENSSL_free(vb);
28060662d10Schristos         return NULL;
28160662d10Schristos     }
28260662d10Schristos     vb->default_g = NULL;
28360662d10Schristos     vb->default_N = NULL;
28460662d10Schristos     vb->seed_key = NULL;
285*1dcdf01fSchristos     if ((seed_key != NULL) && (vb->seed_key = OPENSSL_strdup(seed_key)) == NULL) {
28660662d10Schristos         sk_SRP_user_pwd_free(vb->users_pwd);
28760662d10Schristos         sk_SRP_gN_cache_free(vb->gN_cache);
28860662d10Schristos         OPENSSL_free(vb);
28960662d10Schristos         return NULL;
29060662d10Schristos     }
29160662d10Schristos     return vb;
29260662d10Schristos }
29360662d10Schristos 
SRP_VBASE_free(SRP_VBASE * vb)294*1dcdf01fSchristos void SRP_VBASE_free(SRP_VBASE *vb)
29560662d10Schristos {
296*1dcdf01fSchristos     if (!vb)
297*1dcdf01fSchristos         return;
29860662d10Schristos     sk_SRP_user_pwd_pop_free(vb->users_pwd, SRP_user_pwd_free);
29960662d10Schristos     sk_SRP_gN_cache_free(vb->gN_cache);
30060662d10Schristos     OPENSSL_free(vb->seed_key);
30160662d10Schristos     OPENSSL_free(vb);
30260662d10Schristos }
30360662d10Schristos 
SRP_gN_new_init(const char * ch)30460662d10Schristos static SRP_gN_cache *SRP_gN_new_init(const char *ch)
30560662d10Schristos {
30660662d10Schristos     unsigned char tmp[MAX_LEN];
30760662d10Schristos     int len;
308*1dcdf01fSchristos     SRP_gN_cache *newgN = OPENSSL_malloc(sizeof(*newgN));
30960662d10Schristos 
31060662d10Schristos     if (newgN == NULL)
31160662d10Schristos         return NULL;
31260662d10Schristos 
31360662d10Schristos     len = t_fromb64(tmp, sizeof(tmp), ch);
31460662d10Schristos     if (len < 0)
31560662d10Schristos         goto err;
31660662d10Schristos 
317*1dcdf01fSchristos     if ((newgN->b64_bn = OPENSSL_strdup(ch)) == NULL)
31860662d10Schristos         goto err;
31960662d10Schristos 
32060662d10Schristos     if ((newgN->bn = BN_bin2bn(tmp, len, NULL)))
32160662d10Schristos         return newgN;
32260662d10Schristos 
32360662d10Schristos     OPENSSL_free(newgN->b64_bn);
32460662d10Schristos  err:
32560662d10Schristos     OPENSSL_free(newgN);
32660662d10Schristos     return NULL;
32760662d10Schristos }
32860662d10Schristos 
SRP_gN_free(SRP_gN_cache * gN_cache)32960662d10Schristos static void SRP_gN_free(SRP_gN_cache *gN_cache)
33060662d10Schristos {
33160662d10Schristos     if (gN_cache == NULL)
33260662d10Schristos         return;
33360662d10Schristos     OPENSSL_free(gN_cache->b64_bn);
33460662d10Schristos     BN_free(gN_cache->bn);
33560662d10Schristos     OPENSSL_free(gN_cache);
33660662d10Schristos }
33760662d10Schristos 
SRP_get_gN_by_id(const char * id,STACK_OF (SRP_gN)* gN_tab)33860662d10Schristos static SRP_gN *SRP_get_gN_by_id(const char *id, STACK_OF(SRP_gN) *gN_tab)
33960662d10Schristos {
34060662d10Schristos     int i;
34160662d10Schristos 
34260662d10Schristos     SRP_gN *gN;
34360662d10Schristos     if (gN_tab != NULL)
34460662d10Schristos         for (i = 0; i < sk_SRP_gN_num(gN_tab); i++) {
34560662d10Schristos             gN = sk_SRP_gN_value(gN_tab, i);
34660662d10Schristos             if (gN && (id == NULL || strcmp(gN->id, id) == 0))
34760662d10Schristos                 return gN;
34860662d10Schristos         }
34960662d10Schristos 
35060662d10Schristos     return SRP_get_default_gN(id);
35160662d10Schristos }
35260662d10Schristos 
SRP_gN_place_bn(STACK_OF (SRP_gN_cache)* gN_cache,char * ch)35360662d10Schristos static BIGNUM *SRP_gN_place_bn(STACK_OF(SRP_gN_cache) *gN_cache, char *ch)
35460662d10Schristos {
35560662d10Schristos     int i;
35660662d10Schristos     if (gN_cache == NULL)
35760662d10Schristos         return NULL;
35860662d10Schristos 
35960662d10Schristos     /* search if we have already one... */
36060662d10Schristos     for (i = 0; i < sk_SRP_gN_cache_num(gN_cache); i++) {
36160662d10Schristos         SRP_gN_cache *cache = sk_SRP_gN_cache_value(gN_cache, i);
36260662d10Schristos         if (strcmp(cache->b64_bn, ch) == 0)
36360662d10Schristos             return cache->bn;
36460662d10Schristos     }
36560662d10Schristos     {                           /* it is the first time that we find it */
36660662d10Schristos         SRP_gN_cache *newgN = SRP_gN_new_init(ch);
36760662d10Schristos         if (newgN) {
36860662d10Schristos             if (sk_SRP_gN_cache_insert(gN_cache, newgN, 0) > 0)
36960662d10Schristos                 return newgN->bn;
37060662d10Schristos             SRP_gN_free(newgN);
37160662d10Schristos         }
37260662d10Schristos     }
37360662d10Schristos     return NULL;
37460662d10Schristos }
37560662d10Schristos 
37660662d10Schristos /*
37760662d10Schristos  * this function parses verifier file. Format is:
37860662d10Schristos  * string(index):base64(N):base64(g):0
37960662d10Schristos  * string(username):base64(v):base64(salt):int(index)
38060662d10Schristos  */
38160662d10Schristos 
SRP_VBASE_init(SRP_VBASE * vb,char * verifier_file)38260662d10Schristos int SRP_VBASE_init(SRP_VBASE *vb, char *verifier_file)
38360662d10Schristos {
38460662d10Schristos     int error_code;
38560662d10Schristos     STACK_OF(SRP_gN) *SRP_gN_tab = sk_SRP_gN_new_null();
38660662d10Schristos     char *last_index = NULL;
38760662d10Schristos     int i;
38860662d10Schristos     char **pp;
38960662d10Schristos 
39060662d10Schristos     SRP_gN *gN = NULL;
39160662d10Schristos     SRP_user_pwd *user_pwd = NULL;
39260662d10Schristos 
39360662d10Schristos     TXT_DB *tmpdb = NULL;
39460662d10Schristos     BIO *in = BIO_new(BIO_s_file());
39560662d10Schristos 
39660662d10Schristos     error_code = SRP_ERR_OPEN_FILE;
39760662d10Schristos 
39860662d10Schristos     if (in == NULL || BIO_read_filename(in, verifier_file) <= 0)
39960662d10Schristos         goto err;
40060662d10Schristos 
40160662d10Schristos     error_code = SRP_ERR_VBASE_INCOMPLETE_FILE;
40260662d10Schristos 
40360662d10Schristos     if ((tmpdb = TXT_DB_read(in, DB_NUMBER)) == NULL)
40460662d10Schristos         goto err;
40560662d10Schristos 
40660662d10Schristos     error_code = SRP_ERR_MEMORY;
40760662d10Schristos 
40860662d10Schristos     if (vb->seed_key) {
40960662d10Schristos         last_index = SRP_get_default_gN(NULL)->id;
41060662d10Schristos     }
41160662d10Schristos     for (i = 0; i < sk_OPENSSL_PSTRING_num(tmpdb->data); i++) {
41260662d10Schristos         pp = sk_OPENSSL_PSTRING_value(tmpdb->data, i);
41360662d10Schristos         if (pp[DB_srptype][0] == DB_SRP_INDEX) {
41460662d10Schristos             /*
41560662d10Schristos              * we add this couple in the internal Stack
41660662d10Schristos              */
41760662d10Schristos 
418*1dcdf01fSchristos             if ((gN = OPENSSL_malloc(sizeof(*gN))) == NULL)
41960662d10Schristos                 goto err;
42060662d10Schristos 
421*1dcdf01fSchristos             if ((gN->id = OPENSSL_strdup(pp[DB_srpid])) == NULL
422*1dcdf01fSchristos                 || (gN->N = SRP_gN_place_bn(vb->gN_cache, pp[DB_srpverifier]))
423*1dcdf01fSchristos                         == NULL
424*1dcdf01fSchristos                 || (gN->g = SRP_gN_place_bn(vb->gN_cache, pp[DB_srpsalt]))
425*1dcdf01fSchristos                         == NULL
42660662d10Schristos                 || sk_SRP_gN_insert(SRP_gN_tab, gN, 0) == 0)
42760662d10Schristos                 goto err;
42860662d10Schristos 
42960662d10Schristos             gN = NULL;
43060662d10Schristos 
43160662d10Schristos             if (vb->seed_key != NULL) {
43260662d10Schristos                 last_index = pp[DB_srpid];
43360662d10Schristos             }
43460662d10Schristos         } else if (pp[DB_srptype][0] == DB_SRP_VALID) {
43560662d10Schristos             /* it is a user .... */
436*1dcdf01fSchristos             const SRP_gN *lgN;
437*1dcdf01fSchristos 
43860662d10Schristos             if ((lgN = SRP_get_gN_by_id(pp[DB_srpgN], SRP_gN_tab)) != NULL) {
43960662d10Schristos                 error_code = SRP_ERR_MEMORY;
44060662d10Schristos                 if ((user_pwd = SRP_user_pwd_new()) == NULL)
44160662d10Schristos                     goto err;
44260662d10Schristos 
44360662d10Schristos                 SRP_user_pwd_set_gN(user_pwd, lgN->g, lgN->N);
44460662d10Schristos                 if (!SRP_user_pwd_set_ids
44560662d10Schristos                     (user_pwd, pp[DB_srpid], pp[DB_srpinfo]))
44660662d10Schristos                     goto err;
44760662d10Schristos 
44860662d10Schristos                 error_code = SRP_ERR_VBASE_BN_LIB;
44960662d10Schristos                 if (!SRP_user_pwd_set_sv
45060662d10Schristos                     (user_pwd, pp[DB_srpsalt], pp[DB_srpverifier]))
45160662d10Schristos                     goto err;
45260662d10Schristos 
45360662d10Schristos                 if (sk_SRP_user_pwd_insert(vb->users_pwd, user_pwd, 0) == 0)
45460662d10Schristos                     goto err;
455*1dcdf01fSchristos                 user_pwd = NULL; /* abandon responsibility */
45660662d10Schristos             }
45760662d10Schristos         }
45860662d10Schristos     }
45960662d10Schristos 
46060662d10Schristos     if (last_index != NULL) {
46160662d10Schristos         /* this means that we want to simulate a default user */
46260662d10Schristos 
46360662d10Schristos         if (((gN = SRP_get_gN_by_id(last_index, SRP_gN_tab)) == NULL)) {
46460662d10Schristos             error_code = SRP_ERR_VBASE_BN_LIB;
46560662d10Schristos             goto err;
46660662d10Schristos         }
46760662d10Schristos         vb->default_g = gN->g;
46860662d10Schristos         vb->default_N = gN->N;
46960662d10Schristos         gN = NULL;
47060662d10Schristos     }
47160662d10Schristos     error_code = SRP_NO_ERROR;
47260662d10Schristos 
47360662d10Schristos  err:
47460662d10Schristos     /*
47560662d10Schristos      * there may be still some leaks to fix, if this fails, the application
47660662d10Schristos      * terminates most likely
47760662d10Schristos      */
47860662d10Schristos 
47960662d10Schristos     if (gN != NULL) {
48060662d10Schristos         OPENSSL_free(gN->id);
48160662d10Schristos         OPENSSL_free(gN);
48260662d10Schristos     }
48360662d10Schristos 
48460662d10Schristos     SRP_user_pwd_free(user_pwd);
48560662d10Schristos 
48660662d10Schristos     TXT_DB_free(tmpdb);
48760662d10Schristos     BIO_free_all(in);
48860662d10Schristos 
48960662d10Schristos     sk_SRP_gN_free(SRP_gN_tab);
49060662d10Schristos 
49160662d10Schristos     return error_code;
49260662d10Schristos 
49360662d10Schristos }
49460662d10Schristos 
find_user(SRP_VBASE * vb,char * username)49560662d10Schristos static SRP_user_pwd *find_user(SRP_VBASE *vb, char *username)
49660662d10Schristos {
49760662d10Schristos     int i;
49860662d10Schristos     SRP_user_pwd *user;
49960662d10Schristos 
50060662d10Schristos     if (vb == NULL)
50160662d10Schristos         return NULL;
50260662d10Schristos 
50360662d10Schristos     for (i = 0; i < sk_SRP_user_pwd_num(vb->users_pwd); i++) {
50460662d10Schristos         user = sk_SRP_user_pwd_value(vb->users_pwd, i);
50560662d10Schristos         if (strcmp(user->id, username) == 0)
50660662d10Schristos             return user;
50760662d10Schristos     }
50860662d10Schristos 
50960662d10Schristos     return NULL;
51060662d10Schristos }
51160662d10Schristos 
512*1dcdf01fSchristos # if OPENSSL_API_COMPAT < 0x10100000L
51360662d10Schristos /*
514*1dcdf01fSchristos  * DEPRECATED: use SRP_VBASE_get1_by_user instead.
51560662d10Schristos  * This method ignores the configured seed and fails for an unknown user.
51660662d10Schristos  * Ownership of the returned pointer is not released to the caller.
51760662d10Schristos  * In other words, caller must not free the result.
51860662d10Schristos  */
SRP_VBASE_get_by_user(SRP_VBASE * vb,char * username)51960662d10Schristos SRP_user_pwd *SRP_VBASE_get_by_user(SRP_VBASE *vb, char *username)
52060662d10Schristos {
52160662d10Schristos     return find_user(vb, username);
52260662d10Schristos }
523*1dcdf01fSchristos # endif
52460662d10Schristos 
52560662d10Schristos /*
52660662d10Schristos  * Ownership of the returned pointer is released to the caller.
52760662d10Schristos  * In other words, caller must free the result once done.
52860662d10Schristos  */
SRP_VBASE_get1_by_user(SRP_VBASE * vb,char * username)52960662d10Schristos SRP_user_pwd *SRP_VBASE_get1_by_user(SRP_VBASE *vb, char *username)
53060662d10Schristos {
53160662d10Schristos     SRP_user_pwd *user;
53260662d10Schristos     unsigned char digv[SHA_DIGEST_LENGTH];
53360662d10Schristos     unsigned char digs[SHA_DIGEST_LENGTH];
534*1dcdf01fSchristos     EVP_MD_CTX *ctxt = NULL;
53560662d10Schristos 
53660662d10Schristos     if (vb == NULL)
53760662d10Schristos         return NULL;
53860662d10Schristos 
53960662d10Schristos     if ((user = find_user(vb, username)) != NULL)
54060662d10Schristos         return srp_user_pwd_dup(user);
54160662d10Schristos 
54260662d10Schristos     if ((vb->seed_key == NULL) ||
54360662d10Schristos         (vb->default_g == NULL) || (vb->default_N == NULL))
54460662d10Schristos         return NULL;
54560662d10Schristos 
54660662d10Schristos /* if the user is unknown we set parameters as well if we have a seed_key */
54760662d10Schristos 
54860662d10Schristos     if ((user = SRP_user_pwd_new()) == NULL)
54960662d10Schristos         return NULL;
55060662d10Schristos 
55160662d10Schristos     SRP_user_pwd_set_gN(user, vb->default_g, vb->default_N);
55260662d10Schristos 
55360662d10Schristos     if (!SRP_user_pwd_set_ids(user, username, NULL))
55460662d10Schristos         goto err;
55560662d10Schristos 
556*1dcdf01fSchristos     if (RAND_priv_bytes(digv, SHA_DIGEST_LENGTH) <= 0)
55760662d10Schristos         goto err;
558*1dcdf01fSchristos     ctxt = EVP_MD_CTX_new();
559*1dcdf01fSchristos     if (ctxt == NULL
560*1dcdf01fSchristos         || !EVP_DigestInit_ex(ctxt, EVP_sha1(), NULL)
561*1dcdf01fSchristos         || !EVP_DigestUpdate(ctxt, vb->seed_key, strlen(vb->seed_key))
562*1dcdf01fSchristos         || !EVP_DigestUpdate(ctxt, username, strlen(username))
563*1dcdf01fSchristos         || !EVP_DigestFinal_ex(ctxt, digs, NULL))
564*1dcdf01fSchristos         goto err;
565*1dcdf01fSchristos     EVP_MD_CTX_free(ctxt);
566*1dcdf01fSchristos     ctxt = NULL;
567*1dcdf01fSchristos     if (SRP_user_pwd_set_sv_BN(user,
568*1dcdf01fSchristos                                BN_bin2bn(digs, SHA_DIGEST_LENGTH, NULL),
56960662d10Schristos                                BN_bin2bn(digv, SHA_DIGEST_LENGTH, NULL)))
57060662d10Schristos         return user;
57160662d10Schristos 
572*1dcdf01fSchristos  err:
573*1dcdf01fSchristos     EVP_MD_CTX_free(ctxt);
574*1dcdf01fSchristos     SRP_user_pwd_free(user);
57560662d10Schristos     return NULL;
57660662d10Schristos }
57760662d10Schristos 
57860662d10Schristos /*
57960662d10Schristos  * create a verifier (*salt,*verifier,g and N are in base64)
58060662d10Schristos  */
SRP_create_verifier(const char * user,const char * pass,char ** salt,char ** verifier,const char * N,const char * g)58160662d10Schristos char *SRP_create_verifier(const char *user, const char *pass, char **salt,
58260662d10Schristos                           char **verifier, const char *N, const char *g)
58360662d10Schristos {
58460662d10Schristos     int len;
58560662d10Schristos     char *result = NULL, *vf = NULL;
586*1dcdf01fSchristos     const BIGNUM *N_bn = NULL, *g_bn = NULL;
587*1dcdf01fSchristos     BIGNUM *N_bn_alloc = NULL, *g_bn_alloc = NULL, *s = NULL, *v = NULL;
58860662d10Schristos     unsigned char tmp[MAX_LEN];
58960662d10Schristos     unsigned char tmp2[MAX_LEN];
59060662d10Schristos     char *defgNid = NULL;
59160662d10Schristos     int vfsize = 0;
59260662d10Schristos 
59360662d10Schristos     if ((user == NULL) ||
59460662d10Schristos         (pass == NULL) || (salt == NULL) || (verifier == NULL))
59560662d10Schristos         goto err;
59660662d10Schristos 
59760662d10Schristos     if (N) {
598*1dcdf01fSchristos         if ((len = t_fromb64(tmp, sizeof(tmp), N)) <= 0)
59960662d10Schristos             goto err;
600*1dcdf01fSchristos         N_bn_alloc = BN_bin2bn(tmp, len, NULL);
601*1dcdf01fSchristos         if (N_bn_alloc == NULL)
60260662d10Schristos             goto err;
603*1dcdf01fSchristos         N_bn = N_bn_alloc;
604*1dcdf01fSchristos         if ((len = t_fromb64(tmp, sizeof(tmp) ,g)) <= 0)
605*1dcdf01fSchristos             goto err;
606*1dcdf01fSchristos         g_bn_alloc = BN_bin2bn(tmp, len, NULL);
607*1dcdf01fSchristos         if (g_bn_alloc == NULL)
608*1dcdf01fSchristos             goto err;
609*1dcdf01fSchristos         g_bn = g_bn_alloc;
61060662d10Schristos         defgNid = "*";
61160662d10Schristos     } else {
61260662d10Schristos         SRP_gN *gN = SRP_get_gN_by_id(g, NULL);
61360662d10Schristos         if (gN == NULL)
61460662d10Schristos             goto err;
61560662d10Schristos         N_bn = gN->N;
61660662d10Schristos         g_bn = gN->g;
61760662d10Schristos         defgNid = gN->id;
61860662d10Schristos     }
61960662d10Schristos 
62060662d10Schristos     if (*salt == NULL) {
62160662d10Schristos         if (RAND_bytes(tmp2, SRP_RANDOM_SALT_LEN) <= 0)
62260662d10Schristos             goto err;
62360662d10Schristos 
62460662d10Schristos         s = BN_bin2bn(tmp2, SRP_RANDOM_SALT_LEN, NULL);
62560662d10Schristos     } else {
626*1dcdf01fSchristos         if ((len = t_fromb64(tmp2, sizeof(tmp2), *salt)) <= 0)
62760662d10Schristos             goto err;
62860662d10Schristos         s = BN_bin2bn(tmp2, len, NULL);
62960662d10Schristos     }
630*1dcdf01fSchristos     if (s == NULL)
631*1dcdf01fSchristos         goto err;
63260662d10Schristos 
63360662d10Schristos     if (!SRP_create_verifier_BN(user, pass, &s, &v, N_bn, g_bn))
63460662d10Schristos         goto err;
63560662d10Schristos 
636*1dcdf01fSchristos     if (BN_bn2bin(v, tmp) < 0)
637*1dcdf01fSchristos         goto err;
63860662d10Schristos     vfsize = BN_num_bytes(v) * 2;
63960662d10Schristos     if (((vf = OPENSSL_malloc(vfsize)) == NULL))
64060662d10Schristos         goto err;
641*1dcdf01fSchristos     if (!t_tob64(vf, tmp, BN_num_bytes(v)))
642*1dcdf01fSchristos         goto err;
64360662d10Schristos 
64460662d10Schristos     if (*salt == NULL) {
64560662d10Schristos         char *tmp_salt;
64660662d10Schristos 
64760662d10Schristos         if ((tmp_salt = OPENSSL_malloc(SRP_RANDOM_SALT_LEN * 2)) == NULL) {
64860662d10Schristos             goto err;
64960662d10Schristos         }
650*1dcdf01fSchristos         if (!t_tob64(tmp_salt, tmp2, SRP_RANDOM_SALT_LEN)) {
651*1dcdf01fSchristos             OPENSSL_free(tmp_salt);
652*1dcdf01fSchristos             goto err;
653*1dcdf01fSchristos         }
65460662d10Schristos         *salt = tmp_salt;
65560662d10Schristos     }
65660662d10Schristos 
65760662d10Schristos     *verifier = vf;
65860662d10Schristos     vf = NULL;
65960662d10Schristos     result = defgNid;
66060662d10Schristos 
66160662d10Schristos  err:
662*1dcdf01fSchristos     BN_free(N_bn_alloc);
663*1dcdf01fSchristos     BN_free(g_bn_alloc);
664*1dcdf01fSchristos     OPENSSL_clear_free(vf, vfsize);
66560662d10Schristos     BN_clear_free(s);
66660662d10Schristos     BN_clear_free(v);
66760662d10Schristos     return result;
66860662d10Schristos }
66960662d10Schristos 
67060662d10Schristos /*
67160662d10Schristos  * create a verifier (*salt,*verifier,g and N are BIGNUMs). If *salt != NULL
67260662d10Schristos  * then the provided salt will be used. On successful exit *verifier will point
67360662d10Schristos  * to a newly allocated BIGNUM containing the verifier and (if a salt was not
67460662d10Schristos  * provided) *salt will be populated with a newly allocated BIGNUM containing a
67560662d10Schristos  * random salt.
67660662d10Schristos  * The caller is responsible for freeing the allocated *salt and *verifier
67760662d10Schristos  * BIGNUMS.
67860662d10Schristos  */
SRP_create_verifier_BN(const char * user,const char * pass,BIGNUM ** salt,BIGNUM ** verifier,const BIGNUM * N,const BIGNUM * g)67960662d10Schristos int SRP_create_verifier_BN(const char *user, const char *pass, BIGNUM **salt,
680*1dcdf01fSchristos                            BIGNUM **verifier, const BIGNUM *N,
681*1dcdf01fSchristos                            const BIGNUM *g)
68260662d10Schristos {
68360662d10Schristos     int result = 0;
68460662d10Schristos     BIGNUM *x = NULL;
68560662d10Schristos     BN_CTX *bn_ctx = BN_CTX_new();
68660662d10Schristos     unsigned char tmp2[MAX_LEN];
687*1dcdf01fSchristos     BIGNUM *salttmp = NULL, *verif;
68860662d10Schristos 
68960662d10Schristos     if ((user == NULL) ||
69060662d10Schristos         (pass == NULL) ||
69160662d10Schristos         (salt == NULL) ||
69260662d10Schristos         (verifier == NULL) || (N == NULL) || (g == NULL) || (bn_ctx == NULL))
69360662d10Schristos         goto err;
69460662d10Schristos 
69560662d10Schristos     if (*salt == NULL) {
69660662d10Schristos         if (RAND_bytes(tmp2, SRP_RANDOM_SALT_LEN) <= 0)
69760662d10Schristos             goto err;
69860662d10Schristos 
69960662d10Schristos         salttmp = BN_bin2bn(tmp2, SRP_RANDOM_SALT_LEN, NULL);
700*1dcdf01fSchristos         if (salttmp == NULL)
701*1dcdf01fSchristos             goto err;
70260662d10Schristos     } else {
70360662d10Schristos         salttmp = *salt;
70460662d10Schristos     }
70560662d10Schristos 
70660662d10Schristos     x = SRP_Calc_x(salttmp, user, pass);
707*1dcdf01fSchristos     if (x == NULL)
70860662d10Schristos         goto err;
70960662d10Schristos 
710*1dcdf01fSchristos     verif = BN_new();
711*1dcdf01fSchristos     if (verif == NULL)
712*1dcdf01fSchristos         goto err;
713*1dcdf01fSchristos 
714*1dcdf01fSchristos     if (!BN_mod_exp(verif, g, x, N, bn_ctx)) {
715*1dcdf01fSchristos         BN_clear_free(verif);
71660662d10Schristos         goto err;
71760662d10Schristos     }
71860662d10Schristos 
71960662d10Schristos     result = 1;
72060662d10Schristos     *salt = salttmp;
721*1dcdf01fSchristos     *verifier = verif;
72260662d10Schristos 
72360662d10Schristos  err:
724*1dcdf01fSchristos     if (salt != NULL && *salt != salttmp)
72560662d10Schristos         BN_clear_free(salttmp);
72660662d10Schristos     BN_clear_free(x);
72760662d10Schristos     BN_CTX_free(bn_ctx);
72860662d10Schristos     return result;
72960662d10Schristos }
73060662d10Schristos 
73160662d10Schristos #endif
732