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