/src/openssl/crypto/srp/srp_vfy.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2004-2023 The OpenSSL Project Authors. All Rights Reserved. |
3 | | * Copyright (c) 2004, EdelKey Project. All Rights Reserved. |
4 | | * |
5 | | * Licensed under the Apache License 2.0 (the "License"). You may not use |
6 | | * this file except in compliance with the License. You can obtain a copy |
7 | | * in the file LICENSE in the source distribution or at |
8 | | * https://www.openssl.org/source/license.html |
9 | | * |
10 | | * Originally written by Christophe Renou and Peter Sylvester, |
11 | | * for the EdelKey project. |
12 | | */ |
13 | | |
14 | | /* All the SRP APIs in this file are deprecated */ |
15 | | #define OPENSSL_SUPPRESS_DEPRECATED |
16 | | |
17 | | #ifndef OPENSSL_NO_SRP |
18 | | # include "internal/cryptlib.h" |
19 | | # include "crypto/evp.h" |
20 | | # include <openssl/sha.h> |
21 | | # include <openssl/srp.h> |
22 | | # include <openssl/evp.h> |
23 | | # include <openssl/buffer.h> |
24 | | # include <openssl/rand.h> |
25 | | # include <openssl/txt_db.h> |
26 | | # include <openssl/err.h> |
27 | | |
28 | 0 | # define SRP_RANDOM_SALT_LEN 20 |
29 | | # define MAX_LEN 2500 |
30 | | |
31 | | /* |
32 | | * Note that SRP uses its own variant of base 64 encoding. A different base64 |
33 | | * alphabet is used and no padding '=' characters are added. Instead we pad to |
34 | | * the front with 0 bytes and subsequently strip off leading encoded padding. |
35 | | * This variant is used for compatibility with other SRP implementations - |
36 | | * notably libsrp, but also others. It is also required for backwards |
37 | | * compatibility in order to load verifier files from other OpenSSL versions. |
38 | | */ |
39 | | |
40 | | /* |
41 | | * Convert a base64 string into raw byte array representation. |
42 | | * Returns the length of the decoded data, or -1 on error. |
43 | | */ |
44 | | static int t_fromb64(unsigned char *a, size_t alen, const char *src) |
45 | 0 | { |
46 | 0 | EVP_ENCODE_CTX *ctx; |
47 | 0 | int outl = 0, outl2 = 0; |
48 | 0 | size_t size, padsize; |
49 | 0 | const unsigned char *pad = (const unsigned char *)"00"; |
50 | |
|
51 | 0 | while (*src == ' ' || *src == '\t' || *src == '\n') |
52 | 0 | ++src; |
53 | 0 | size = strlen(src); |
54 | 0 | padsize = 4 - (size & 3); |
55 | 0 | padsize &= 3; |
56 | | |
57 | | /* Four bytes in src become three bytes output. */ |
58 | 0 | if (size > INT_MAX || ((size + padsize) / 4) * 3 > alen) |
59 | 0 | return -1; |
60 | | |
61 | 0 | ctx = EVP_ENCODE_CTX_new(); |
62 | 0 | if (ctx == NULL) |
63 | 0 | return -1; |
64 | | |
65 | | /* |
66 | | * This should never occur because 1 byte of data always requires 2 bytes of |
67 | | * encoding, i.e. |
68 | | * 0 bytes unencoded = 0 bytes encoded |
69 | | * 1 byte unencoded = 2 bytes encoded |
70 | | * 2 bytes unencoded = 3 bytes encoded |
71 | | * 3 bytes unencoded = 4 bytes encoded |
72 | | * 4 bytes unencoded = 6 bytes encoded |
73 | | * etc |
74 | | */ |
75 | 0 | if (padsize == 3) { |
76 | 0 | outl = -1; |
77 | 0 | goto err; |
78 | 0 | } |
79 | | |
80 | | /* Valid padsize values are now 0, 1 or 2 */ |
81 | | |
82 | 0 | EVP_DecodeInit(ctx); |
83 | 0 | evp_encode_ctx_set_flags(ctx, EVP_ENCODE_CTX_USE_SRP_ALPHABET); |
84 | | |
85 | | /* Add any encoded padding that is required */ |
86 | 0 | if (padsize != 0 |
87 | 0 | && EVP_DecodeUpdate(ctx, a, &outl, pad, padsize) < 0) { |
88 | 0 | outl = -1; |
89 | 0 | goto err; |
90 | 0 | } |
91 | 0 | if (EVP_DecodeUpdate(ctx, a, &outl2, (const unsigned char *)src, size) < 0) { |
92 | 0 | outl = -1; |
93 | 0 | goto err; |
94 | 0 | } |
95 | 0 | outl += outl2; |
96 | 0 | EVP_DecodeFinal(ctx, a + outl, &outl2); |
97 | 0 | outl += outl2; |
98 | | |
99 | | /* Strip off the leading padding */ |
100 | 0 | if (padsize != 0) { |
101 | 0 | if ((int)padsize >= outl) { |
102 | 0 | outl = -1; |
103 | 0 | goto err; |
104 | 0 | } |
105 | | |
106 | | /* |
107 | | * If we added 1 byte of padding prior to encoding then we have 2 bytes |
108 | | * of "real" data which gets spread across 4 encoded bytes like this: |
109 | | * (6 bits pad)(2 bits pad | 4 bits data)(6 bits data)(6 bits data) |
110 | | * So 1 byte of pre-encoding padding results in 1 full byte of encoded |
111 | | * padding. |
112 | | * If we added 2 bytes of padding prior to encoding this gets encoded |
113 | | * as: |
114 | | * (6 bits pad)(6 bits pad)(4 bits pad | 2 bits data)(6 bits data) |
115 | | * So 2 bytes of pre-encoding padding results in 2 full bytes of encoded |
116 | | * padding, i.e. we have to strip the same number of bytes of padding |
117 | | * from the encoded data as we added to the pre-encoded data. |
118 | | */ |
119 | 0 | memmove(a, a + padsize, outl - padsize); |
120 | 0 | outl -= padsize; |
121 | 0 | } |
122 | | |
123 | 0 | err: |
124 | 0 | EVP_ENCODE_CTX_free(ctx); |
125 | |
|
126 | 0 | return outl; |
127 | 0 | } |
128 | | |
129 | | /* |
130 | | * Convert a raw byte string into a null-terminated base64 ASCII string. |
131 | | * Returns 1 on success or 0 on error. |
132 | | */ |
133 | | static int t_tob64(char *dst, const unsigned char *src, int size) |
134 | 0 | { |
135 | 0 | EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new(); |
136 | 0 | int outl = 0, outl2 = 0; |
137 | 0 | unsigned char pad[2] = {0, 0}; |
138 | 0 | size_t leadz = 0; |
139 | |
|
140 | 0 | if (ctx == NULL) |
141 | 0 | return 0; |
142 | | |
143 | 0 | EVP_EncodeInit(ctx); |
144 | 0 | evp_encode_ctx_set_flags(ctx, EVP_ENCODE_CTX_NO_NEWLINES |
145 | 0 | | EVP_ENCODE_CTX_USE_SRP_ALPHABET); |
146 | | |
147 | | /* |
148 | | * We pad at the front with zero bytes until the length is a multiple of 3 |
149 | | * so that EVP_EncodeUpdate/EVP_EncodeFinal does not add any of its own "=" |
150 | | * padding |
151 | | */ |
152 | 0 | leadz = 3 - (size % 3); |
153 | 0 | if (leadz != 3 |
154 | 0 | && !EVP_EncodeUpdate(ctx, (unsigned char *)dst, &outl, pad, |
155 | 0 | leadz)) { |
156 | 0 | EVP_ENCODE_CTX_free(ctx); |
157 | 0 | return 0; |
158 | 0 | } |
159 | | |
160 | 0 | if (!EVP_EncodeUpdate(ctx, (unsigned char *)dst + outl, &outl2, src, |
161 | 0 | size)) { |
162 | 0 | EVP_ENCODE_CTX_free(ctx); |
163 | 0 | return 0; |
164 | 0 | } |
165 | 0 | outl += outl2; |
166 | 0 | EVP_EncodeFinal(ctx, (unsigned char *)dst + outl, &outl2); |
167 | 0 | outl += outl2; |
168 | | |
169 | | /* Strip the encoded padding at the front */ |
170 | 0 | if (leadz != 3) { |
171 | 0 | memmove(dst, dst + leadz, outl - leadz); |
172 | 0 | dst[outl - leadz] = '\0'; |
173 | 0 | } |
174 | |
|
175 | 0 | EVP_ENCODE_CTX_free(ctx); |
176 | 0 | return 1; |
177 | 0 | } |
178 | | |
179 | | void SRP_user_pwd_free(SRP_user_pwd *user_pwd) |
180 | 0 | { |
181 | 0 | if (user_pwd == NULL) |
182 | 0 | return; |
183 | 0 | BN_free(user_pwd->s); |
184 | 0 | BN_clear_free(user_pwd->v); |
185 | 0 | OPENSSL_free(user_pwd->id); |
186 | 0 | OPENSSL_free(user_pwd->info); |
187 | 0 | OPENSSL_free(user_pwd); |
188 | 0 | } |
189 | | |
190 | | SRP_user_pwd *SRP_user_pwd_new(void) |
191 | 0 | { |
192 | 0 | SRP_user_pwd *ret; |
193 | |
|
194 | 0 | if ((ret = OPENSSL_malloc(sizeof(*ret))) == NULL) |
195 | 0 | return NULL; |
196 | 0 | ret->N = NULL; |
197 | 0 | ret->g = NULL; |
198 | 0 | ret->s = NULL; |
199 | 0 | ret->v = NULL; |
200 | 0 | ret->id = NULL; |
201 | 0 | ret->info = NULL; |
202 | 0 | return ret; |
203 | 0 | } |
204 | | |
205 | | void SRP_user_pwd_set_gN(SRP_user_pwd *vinfo, const BIGNUM *g, |
206 | | const BIGNUM *N) |
207 | 0 | { |
208 | 0 | vinfo->N = N; |
209 | 0 | vinfo->g = g; |
210 | 0 | } |
211 | | |
212 | | int SRP_user_pwd_set1_ids(SRP_user_pwd *vinfo, const char *id, |
213 | | const char *info) |
214 | 0 | { |
215 | 0 | OPENSSL_free(vinfo->id); |
216 | 0 | OPENSSL_free(vinfo->info); |
217 | 0 | vinfo->id = NULL; |
218 | 0 | vinfo->info = NULL; |
219 | 0 | if (id != NULL && NULL == (vinfo->id = OPENSSL_strdup(id))) |
220 | 0 | return 0; |
221 | 0 | return (info == NULL || NULL != (vinfo->info = OPENSSL_strdup(info))); |
222 | 0 | } |
223 | | |
224 | | static int SRP_user_pwd_set_sv(SRP_user_pwd *vinfo, const char *s, |
225 | | const char *v) |
226 | 0 | { |
227 | 0 | unsigned char tmp[MAX_LEN]; |
228 | 0 | int len; |
229 | |
|
230 | 0 | vinfo->v = NULL; |
231 | 0 | vinfo->s = NULL; |
232 | |
|
233 | 0 | len = t_fromb64(tmp, sizeof(tmp), v); |
234 | 0 | if (len < 0) |
235 | 0 | return 0; |
236 | 0 | if (NULL == (vinfo->v = BN_bin2bn(tmp, len, NULL))) |
237 | 0 | return 0; |
238 | 0 | len = t_fromb64(tmp, sizeof(tmp), s); |
239 | 0 | if (len < 0) |
240 | 0 | goto err; |
241 | 0 | vinfo->s = BN_bin2bn(tmp, len, NULL); |
242 | 0 | if (vinfo->s == NULL) |
243 | 0 | goto err; |
244 | 0 | return 1; |
245 | 0 | err: |
246 | 0 | BN_free(vinfo->v); |
247 | 0 | vinfo->v = NULL; |
248 | 0 | return 0; |
249 | 0 | } |
250 | | |
251 | | int SRP_user_pwd_set0_sv(SRP_user_pwd *vinfo, BIGNUM *s, BIGNUM *v) |
252 | 0 | { |
253 | 0 | BN_free(vinfo->s); |
254 | 0 | BN_clear_free(vinfo->v); |
255 | 0 | vinfo->v = v; |
256 | 0 | vinfo->s = s; |
257 | 0 | return (vinfo->s != NULL && vinfo->v != NULL); |
258 | 0 | } |
259 | | |
260 | | static SRP_user_pwd *srp_user_pwd_dup(SRP_user_pwd *src) |
261 | 0 | { |
262 | 0 | SRP_user_pwd *ret; |
263 | |
|
264 | 0 | if (src == NULL) |
265 | 0 | return NULL; |
266 | 0 | if ((ret = SRP_user_pwd_new()) == NULL) |
267 | 0 | return NULL; |
268 | | |
269 | 0 | SRP_user_pwd_set_gN(ret, src->g, src->N); |
270 | 0 | if (!SRP_user_pwd_set1_ids(ret, src->id, src->info) |
271 | 0 | || !SRP_user_pwd_set0_sv(ret, BN_dup(src->s), BN_dup(src->v))) { |
272 | 0 | SRP_user_pwd_free(ret); |
273 | 0 | return NULL; |
274 | 0 | } |
275 | 0 | return ret; |
276 | 0 | } |
277 | | |
278 | | SRP_VBASE *SRP_VBASE_new(char *seed_key) |
279 | 0 | { |
280 | 0 | SRP_VBASE *vb = OPENSSL_malloc(sizeof(*vb)); |
281 | |
|
282 | 0 | if (vb == NULL) |
283 | 0 | return NULL; |
284 | 0 | if ((vb->users_pwd = sk_SRP_user_pwd_new_null()) == NULL |
285 | 0 | || (vb->gN_cache = sk_SRP_gN_cache_new_null()) == NULL) { |
286 | 0 | sk_SRP_user_pwd_free(vb->users_pwd); |
287 | 0 | OPENSSL_free(vb); |
288 | 0 | return NULL; |
289 | 0 | } |
290 | 0 | vb->default_g = NULL; |
291 | 0 | vb->default_N = NULL; |
292 | 0 | vb->seed_key = NULL; |
293 | 0 | if ((seed_key != NULL) && (vb->seed_key = OPENSSL_strdup(seed_key)) == NULL) { |
294 | 0 | sk_SRP_user_pwd_free(vb->users_pwd); |
295 | 0 | sk_SRP_gN_cache_free(vb->gN_cache); |
296 | 0 | OPENSSL_free(vb); |
297 | 0 | return NULL; |
298 | 0 | } |
299 | 0 | return vb; |
300 | 0 | } |
301 | | |
302 | | void SRP_VBASE_free(SRP_VBASE *vb) |
303 | 0 | { |
304 | 0 | if (!vb) |
305 | 0 | return; |
306 | 0 | sk_SRP_user_pwd_pop_free(vb->users_pwd, SRP_user_pwd_free); |
307 | 0 | sk_SRP_gN_cache_free(vb->gN_cache); |
308 | 0 | OPENSSL_free(vb->seed_key); |
309 | 0 | OPENSSL_free(vb); |
310 | 0 | } |
311 | | |
312 | | static SRP_gN_cache *SRP_gN_new_init(const char *ch) |
313 | 0 | { |
314 | 0 | unsigned char tmp[MAX_LEN]; |
315 | 0 | int len; |
316 | 0 | SRP_gN_cache *newgN = OPENSSL_malloc(sizeof(*newgN)); |
317 | |
|
318 | 0 | if (newgN == NULL) |
319 | 0 | return NULL; |
320 | | |
321 | 0 | len = t_fromb64(tmp, sizeof(tmp), ch); |
322 | 0 | if (len < 0) |
323 | 0 | goto err; |
324 | | |
325 | 0 | if ((newgN->b64_bn = OPENSSL_strdup(ch)) == NULL) |
326 | 0 | goto err; |
327 | | |
328 | 0 | if ((newgN->bn = BN_bin2bn(tmp, len, NULL))) |
329 | 0 | return newgN; |
330 | | |
331 | 0 | OPENSSL_free(newgN->b64_bn); |
332 | 0 | err: |
333 | 0 | OPENSSL_free(newgN); |
334 | 0 | return NULL; |
335 | 0 | } |
336 | | |
337 | | static void SRP_gN_free(SRP_gN_cache *gN_cache) |
338 | 0 | { |
339 | 0 | if (gN_cache == NULL) |
340 | 0 | return; |
341 | 0 | OPENSSL_free(gN_cache->b64_bn); |
342 | 0 | BN_free(gN_cache->bn); |
343 | 0 | OPENSSL_free(gN_cache); |
344 | 0 | } |
345 | | |
346 | | static SRP_gN *SRP_get_gN_by_id(const char *id, STACK_OF(SRP_gN) *gN_tab) |
347 | 0 | { |
348 | 0 | int i; |
349 | |
|
350 | 0 | SRP_gN *gN; |
351 | 0 | if (gN_tab != NULL) { |
352 | 0 | for (i = 0; i < sk_SRP_gN_num(gN_tab); i++) { |
353 | 0 | gN = sk_SRP_gN_value(gN_tab, i); |
354 | 0 | if (gN && (id == NULL || strcmp(gN->id, id) == 0)) |
355 | 0 | return gN; |
356 | 0 | } |
357 | 0 | } |
358 | | |
359 | 0 | return SRP_get_default_gN(id); |
360 | 0 | } |
361 | | |
362 | | static BIGNUM *SRP_gN_place_bn(STACK_OF(SRP_gN_cache) *gN_cache, char *ch) |
363 | 0 | { |
364 | 0 | int i; |
365 | 0 | if (gN_cache == NULL) |
366 | 0 | return NULL; |
367 | | |
368 | | /* search if we have already one... */ |
369 | 0 | for (i = 0; i < sk_SRP_gN_cache_num(gN_cache); i++) { |
370 | 0 | SRP_gN_cache *cache = sk_SRP_gN_cache_value(gN_cache, i); |
371 | 0 | if (strcmp(cache->b64_bn, ch) == 0) |
372 | 0 | return cache->bn; |
373 | 0 | } |
374 | 0 | { /* it is the first time that we find it */ |
375 | 0 | SRP_gN_cache *newgN = SRP_gN_new_init(ch); |
376 | 0 | if (newgN) { |
377 | 0 | if (sk_SRP_gN_cache_insert(gN_cache, newgN, 0) > 0) |
378 | 0 | return newgN->bn; |
379 | 0 | SRP_gN_free(newgN); |
380 | 0 | } |
381 | 0 | } |
382 | 0 | return NULL; |
383 | 0 | } |
384 | | |
385 | | /* |
386 | | * This function parses the verifier file generated by the srp app. |
387 | | * The format for each entry is: |
388 | | * V base64(verifier) base64(salt) username gNid userinfo(optional) |
389 | | * or |
390 | | * I base64(N) base64(g) |
391 | | * Note that base64 is the SRP variant of base64 encoding described |
392 | | * in t_fromb64(). |
393 | | */ |
394 | | |
395 | | int SRP_VBASE_init(SRP_VBASE *vb, char *verifier_file) |
396 | 0 | { |
397 | 0 | int error_code = SRP_ERR_MEMORY; |
398 | 0 | STACK_OF(SRP_gN) *SRP_gN_tab = sk_SRP_gN_new_null(); |
399 | 0 | char *last_index = NULL; |
400 | 0 | int i; |
401 | 0 | char **pp; |
402 | |
|
403 | 0 | SRP_gN *gN = NULL; |
404 | 0 | SRP_user_pwd *user_pwd = NULL; |
405 | |
|
406 | 0 | TXT_DB *tmpdb = NULL; |
407 | 0 | BIO *in = BIO_new(BIO_s_file()); |
408 | |
|
409 | 0 | if (SRP_gN_tab == NULL) |
410 | 0 | goto err; |
411 | | |
412 | 0 | error_code = SRP_ERR_OPEN_FILE; |
413 | |
|
414 | 0 | if (verifier_file == NULL) { |
415 | 0 | ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER); |
416 | 0 | goto err; |
417 | 0 | } |
418 | | |
419 | 0 | if (in == NULL || BIO_read_filename(in, verifier_file) <= 0) |
420 | 0 | goto err; |
421 | | |
422 | 0 | error_code = SRP_ERR_VBASE_INCOMPLETE_FILE; |
423 | |
|
424 | 0 | if ((tmpdb = TXT_DB_read(in, DB_NUMBER)) == NULL) |
425 | 0 | goto err; |
426 | | |
427 | 0 | error_code = SRP_ERR_MEMORY; |
428 | |
|
429 | 0 | if (vb->seed_key) { |
430 | 0 | last_index = SRP_get_default_gN(NULL)->id; |
431 | 0 | } |
432 | 0 | for (i = 0; i < sk_OPENSSL_PSTRING_num(tmpdb->data); i++) { |
433 | 0 | pp = sk_OPENSSL_PSTRING_value(tmpdb->data, i); |
434 | 0 | if (pp[DB_srptype][0] == DB_SRP_INDEX) { |
435 | | /* |
436 | | * we add this couple in the internal Stack |
437 | | */ |
438 | |
|
439 | 0 | if ((gN = OPENSSL_malloc(sizeof(*gN))) == NULL) |
440 | 0 | goto err; |
441 | | |
442 | 0 | if ((gN->id = OPENSSL_strdup(pp[DB_srpid])) == NULL |
443 | 0 | || (gN->N = SRP_gN_place_bn(vb->gN_cache, pp[DB_srpverifier])) |
444 | 0 | == NULL |
445 | 0 | || (gN->g = SRP_gN_place_bn(vb->gN_cache, pp[DB_srpsalt])) |
446 | 0 | == NULL |
447 | 0 | || sk_SRP_gN_insert(SRP_gN_tab, gN, 0) == 0) |
448 | 0 | goto err; |
449 | | |
450 | 0 | gN = NULL; |
451 | |
|
452 | 0 | if (vb->seed_key != NULL) { |
453 | 0 | last_index = pp[DB_srpid]; |
454 | 0 | } |
455 | 0 | } else if (pp[DB_srptype][0] == DB_SRP_VALID) { |
456 | | /* it is a user .... */ |
457 | 0 | const SRP_gN *lgN; |
458 | |
|
459 | 0 | if ((lgN = SRP_get_gN_by_id(pp[DB_srpgN], SRP_gN_tab)) != NULL) { |
460 | 0 | error_code = SRP_ERR_MEMORY; |
461 | 0 | if ((user_pwd = SRP_user_pwd_new()) == NULL) |
462 | 0 | goto err; |
463 | | |
464 | 0 | SRP_user_pwd_set_gN(user_pwd, lgN->g, lgN->N); |
465 | 0 | if (!SRP_user_pwd_set1_ids |
466 | 0 | (user_pwd, pp[DB_srpid], pp[DB_srpinfo])) |
467 | 0 | goto err; |
468 | | |
469 | 0 | error_code = SRP_ERR_VBASE_BN_LIB; |
470 | 0 | if (!SRP_user_pwd_set_sv |
471 | 0 | (user_pwd, pp[DB_srpsalt], pp[DB_srpverifier])) |
472 | 0 | goto err; |
473 | | |
474 | 0 | if (sk_SRP_user_pwd_insert(vb->users_pwd, user_pwd, 0) == 0) |
475 | 0 | goto err; |
476 | 0 | user_pwd = NULL; /* abandon responsibility */ |
477 | 0 | } |
478 | 0 | } |
479 | 0 | } |
480 | | |
481 | 0 | if (last_index != NULL) { |
482 | | /* this means that we want to simulate a default user */ |
483 | |
|
484 | 0 | if (((gN = SRP_get_gN_by_id(last_index, SRP_gN_tab)) == NULL)) { |
485 | 0 | error_code = SRP_ERR_VBASE_BN_LIB; |
486 | 0 | goto err; |
487 | 0 | } |
488 | 0 | vb->default_g = gN->g; |
489 | 0 | vb->default_N = gN->N; |
490 | 0 | gN = NULL; |
491 | 0 | } |
492 | 0 | error_code = SRP_NO_ERROR; |
493 | |
|
494 | 0 | err: |
495 | | /* |
496 | | * there may be still some leaks to fix, if this fails, the application |
497 | | * terminates most likely |
498 | | */ |
499 | |
|
500 | 0 | if (gN != NULL) { |
501 | 0 | OPENSSL_free(gN->id); |
502 | 0 | OPENSSL_free(gN); |
503 | 0 | } |
504 | |
|
505 | 0 | SRP_user_pwd_free(user_pwd); |
506 | |
|
507 | 0 | TXT_DB_free(tmpdb); |
508 | 0 | BIO_free_all(in); |
509 | |
|
510 | 0 | sk_SRP_gN_free(SRP_gN_tab); |
511 | |
|
512 | 0 | return error_code; |
513 | |
|
514 | 0 | } |
515 | | |
516 | | static SRP_user_pwd *find_user(SRP_VBASE *vb, char *username) |
517 | 0 | { |
518 | 0 | int i; |
519 | 0 | SRP_user_pwd *user; |
520 | |
|
521 | 0 | if (vb == NULL) |
522 | 0 | return NULL; |
523 | | |
524 | 0 | for (i = 0; i < sk_SRP_user_pwd_num(vb->users_pwd); i++) { |
525 | 0 | user = sk_SRP_user_pwd_value(vb->users_pwd, i); |
526 | 0 | if (strcmp(user->id, username) == 0) |
527 | 0 | return user; |
528 | 0 | } |
529 | | |
530 | 0 | return NULL; |
531 | 0 | } |
532 | | |
533 | | int SRP_VBASE_add0_user(SRP_VBASE *vb, SRP_user_pwd *user_pwd) |
534 | 0 | { |
535 | 0 | if (sk_SRP_user_pwd_push(vb->users_pwd, user_pwd) <= 0) |
536 | 0 | return 0; |
537 | 0 | return 1; |
538 | 0 | } |
539 | | |
540 | | # ifndef OPENSSL_NO_DEPRECATED_1_1_0 |
541 | | /* |
542 | | * DEPRECATED: use SRP_VBASE_get1_by_user instead. |
543 | | * This method ignores the configured seed and fails for an unknown user. |
544 | | * Ownership of the returned pointer is not released to the caller. |
545 | | * In other words, caller must not free the result. |
546 | | */ |
547 | | SRP_user_pwd *SRP_VBASE_get_by_user(SRP_VBASE *vb, char *username) |
548 | 0 | { |
549 | 0 | return find_user(vb, username); |
550 | 0 | } |
551 | | # endif |
552 | | |
553 | | /* |
554 | | * Ownership of the returned pointer is released to the caller. |
555 | | * In other words, caller must free the result once done. |
556 | | */ |
557 | | SRP_user_pwd *SRP_VBASE_get1_by_user(SRP_VBASE *vb, char *username) |
558 | 0 | { |
559 | 0 | SRP_user_pwd *user; |
560 | 0 | unsigned char digv[SHA_DIGEST_LENGTH]; |
561 | 0 | unsigned char digs[SHA_DIGEST_LENGTH]; |
562 | 0 | EVP_MD_CTX *ctxt = NULL; |
563 | 0 | EVP_MD *md = NULL; |
564 | |
|
565 | 0 | if (vb == NULL) |
566 | 0 | return NULL; |
567 | | |
568 | 0 | if ((user = find_user(vb, username)) != NULL) |
569 | 0 | return srp_user_pwd_dup(user); |
570 | | |
571 | 0 | if ((vb->seed_key == NULL) || |
572 | 0 | (vb->default_g == NULL) || (vb->default_N == NULL)) |
573 | 0 | return NULL; |
574 | | |
575 | | /* if the user is unknown we set parameters as well if we have a seed_key */ |
576 | | |
577 | 0 | if ((user = SRP_user_pwd_new()) == NULL) |
578 | 0 | return NULL; |
579 | | |
580 | 0 | SRP_user_pwd_set_gN(user, vb->default_g, vb->default_N); |
581 | |
|
582 | 0 | if (!SRP_user_pwd_set1_ids(user, username, NULL)) |
583 | 0 | goto err; |
584 | | |
585 | 0 | if (RAND_priv_bytes(digv, SHA_DIGEST_LENGTH) <= 0) |
586 | 0 | goto err; |
587 | 0 | md = EVP_MD_fetch(NULL, SN_sha1, NULL); |
588 | 0 | if (md == NULL) |
589 | 0 | goto err; |
590 | 0 | ctxt = EVP_MD_CTX_new(); |
591 | 0 | if (ctxt == NULL |
592 | 0 | || !EVP_DigestInit_ex(ctxt, md, NULL) |
593 | 0 | || !EVP_DigestUpdate(ctxt, vb->seed_key, strlen(vb->seed_key)) |
594 | 0 | || !EVP_DigestUpdate(ctxt, username, strlen(username)) |
595 | 0 | || !EVP_DigestFinal_ex(ctxt, digs, NULL)) |
596 | 0 | goto err; |
597 | 0 | EVP_MD_CTX_free(ctxt); |
598 | 0 | ctxt = NULL; |
599 | 0 | EVP_MD_free(md); |
600 | 0 | md = NULL; |
601 | 0 | if (SRP_user_pwd_set0_sv(user, |
602 | 0 | BN_bin2bn(digs, SHA_DIGEST_LENGTH, NULL), |
603 | 0 | BN_bin2bn(digv, SHA_DIGEST_LENGTH, NULL))) |
604 | 0 | return user; |
605 | | |
606 | 0 | err: |
607 | 0 | EVP_MD_free(md); |
608 | 0 | EVP_MD_CTX_free(ctxt); |
609 | 0 | SRP_user_pwd_free(user); |
610 | 0 | return NULL; |
611 | 0 | } |
612 | | |
613 | | /* |
614 | | * create a verifier (*salt,*verifier,g and N are in base64) |
615 | | */ |
616 | | char *SRP_create_verifier_ex(const char *user, const char *pass, char **salt, |
617 | | char **verifier, const char *N, const char *g, |
618 | | OSSL_LIB_CTX *libctx, const char *propq) |
619 | 0 | { |
620 | 0 | int len; |
621 | 0 | char *result = NULL, *vf = NULL; |
622 | 0 | const BIGNUM *N_bn = NULL, *g_bn = NULL; |
623 | 0 | BIGNUM *N_bn_alloc = NULL, *g_bn_alloc = NULL, *s = NULL, *v = NULL; |
624 | 0 | unsigned char tmp[MAX_LEN]; |
625 | 0 | unsigned char tmp2[MAX_LEN]; |
626 | 0 | char *defgNid = NULL; |
627 | 0 | int vfsize = 0; |
628 | |
|
629 | 0 | if ((user == NULL) || |
630 | 0 | (pass == NULL) || (salt == NULL) || (verifier == NULL)) |
631 | 0 | goto err; |
632 | | |
633 | 0 | if (N) { |
634 | 0 | if ((len = t_fromb64(tmp, sizeof(tmp), N)) <= 0) |
635 | 0 | goto err; |
636 | 0 | N_bn_alloc = BN_bin2bn(tmp, len, NULL); |
637 | 0 | if (N_bn_alloc == NULL) |
638 | 0 | goto err; |
639 | 0 | N_bn = N_bn_alloc; |
640 | 0 | if ((len = t_fromb64(tmp, sizeof(tmp), g)) <= 0) |
641 | 0 | goto err; |
642 | 0 | g_bn_alloc = BN_bin2bn(tmp, len, NULL); |
643 | 0 | if (g_bn_alloc == NULL) |
644 | 0 | goto err; |
645 | 0 | g_bn = g_bn_alloc; |
646 | 0 | defgNid = "*"; |
647 | 0 | } else { |
648 | 0 | SRP_gN *gN = SRP_get_default_gN(g); |
649 | 0 | if (gN == NULL) |
650 | 0 | goto err; |
651 | 0 | N_bn = gN->N; |
652 | 0 | g_bn = gN->g; |
653 | 0 | defgNid = gN->id; |
654 | 0 | } |
655 | | |
656 | 0 | if (*salt == NULL) { |
657 | 0 | if (RAND_bytes_ex(libctx, tmp2, SRP_RANDOM_SALT_LEN, 0) <= 0) |
658 | 0 | goto err; |
659 | | |
660 | 0 | s = BN_bin2bn(tmp2, SRP_RANDOM_SALT_LEN, NULL); |
661 | 0 | } else { |
662 | 0 | if ((len = t_fromb64(tmp2, sizeof(tmp2), *salt)) <= 0) |
663 | 0 | goto err; |
664 | 0 | s = BN_bin2bn(tmp2, len, NULL); |
665 | 0 | } |
666 | 0 | if (s == NULL) |
667 | 0 | goto err; |
668 | | |
669 | 0 | if (!SRP_create_verifier_BN_ex(user, pass, &s, &v, N_bn, g_bn, libctx, |
670 | 0 | propq)) |
671 | 0 | goto err; |
672 | | |
673 | 0 | if (BN_bn2bin(v, tmp) < 0) |
674 | 0 | goto err; |
675 | 0 | vfsize = BN_num_bytes(v) * 2; |
676 | 0 | if (((vf = OPENSSL_malloc(vfsize)) == NULL)) |
677 | 0 | goto err; |
678 | 0 | if (!t_tob64(vf, tmp, BN_num_bytes(v))) |
679 | 0 | goto err; |
680 | | |
681 | 0 | if (*salt == NULL) { |
682 | 0 | char *tmp_salt; |
683 | |
|
684 | 0 | if ((tmp_salt = OPENSSL_malloc(SRP_RANDOM_SALT_LEN * 2)) == NULL) { |
685 | 0 | goto err; |
686 | 0 | } |
687 | 0 | if (!t_tob64(tmp_salt, tmp2, SRP_RANDOM_SALT_LEN)) { |
688 | 0 | OPENSSL_free(tmp_salt); |
689 | 0 | goto err; |
690 | 0 | } |
691 | 0 | *salt = tmp_salt; |
692 | 0 | } |
693 | | |
694 | 0 | *verifier = vf; |
695 | 0 | vf = NULL; |
696 | 0 | result = defgNid; |
697 | |
|
698 | 0 | err: |
699 | 0 | BN_free(N_bn_alloc); |
700 | 0 | BN_free(g_bn_alloc); |
701 | 0 | OPENSSL_clear_free(vf, vfsize); |
702 | 0 | BN_clear_free(s); |
703 | 0 | BN_clear_free(v); |
704 | 0 | return result; |
705 | 0 | } |
706 | | |
707 | | char *SRP_create_verifier(const char *user, const char *pass, char **salt, |
708 | | char **verifier, const char *N, const char *g) |
709 | 0 | { |
710 | 0 | return SRP_create_verifier_ex(user, pass, salt, verifier, N, g, NULL, NULL); |
711 | 0 | } |
712 | | |
713 | | /* |
714 | | * create a verifier (*salt,*verifier,g and N are BIGNUMs). If *salt != NULL |
715 | | * then the provided salt will be used. On successful exit *verifier will point |
716 | | * to a newly allocated BIGNUM containing the verifier and (if a salt was not |
717 | | * provided) *salt will be populated with a newly allocated BIGNUM containing a |
718 | | * random salt. |
719 | | * The caller is responsible for freeing the allocated *salt and *verifier |
720 | | * BIGNUMS. |
721 | | */ |
722 | | int SRP_create_verifier_BN_ex(const char *user, const char *pass, BIGNUM **salt, |
723 | | BIGNUM **verifier, const BIGNUM *N, |
724 | | const BIGNUM *g, OSSL_LIB_CTX *libctx, |
725 | | const char *propq) |
726 | 0 | { |
727 | 0 | int result = 0; |
728 | 0 | BIGNUM *x = NULL; |
729 | 0 | BN_CTX *bn_ctx = BN_CTX_new_ex(libctx); |
730 | 0 | unsigned char tmp2[MAX_LEN]; |
731 | 0 | BIGNUM *salttmp = NULL, *verif; |
732 | |
|
733 | 0 | if ((user == NULL) || |
734 | 0 | (pass == NULL) || |
735 | 0 | (salt == NULL) || |
736 | 0 | (verifier == NULL) || (N == NULL) || (g == NULL) || (bn_ctx == NULL)) |
737 | 0 | goto err; |
738 | | |
739 | 0 | if (*salt == NULL) { |
740 | 0 | if (RAND_bytes_ex(libctx, tmp2, SRP_RANDOM_SALT_LEN, 0) <= 0) |
741 | 0 | goto err; |
742 | | |
743 | 0 | salttmp = BN_bin2bn(tmp2, SRP_RANDOM_SALT_LEN, NULL); |
744 | 0 | if (salttmp == NULL) |
745 | 0 | goto err; |
746 | 0 | } else { |
747 | 0 | salttmp = *salt; |
748 | 0 | } |
749 | | |
750 | 0 | x = SRP_Calc_x_ex(salttmp, user, pass, libctx, propq); |
751 | 0 | if (x == NULL) |
752 | 0 | goto err; |
753 | | |
754 | 0 | verif = BN_new(); |
755 | 0 | if (verif == NULL) |
756 | 0 | goto err; |
757 | | |
758 | 0 | if (!BN_mod_exp(verif, g, x, N, bn_ctx)) { |
759 | 0 | BN_clear_free(verif); |
760 | 0 | goto err; |
761 | 0 | } |
762 | | |
763 | 0 | result = 1; |
764 | 0 | *salt = salttmp; |
765 | 0 | *verifier = verif; |
766 | |
|
767 | 0 | err: |
768 | 0 | if (salt != NULL && *salt != salttmp) |
769 | 0 | BN_clear_free(salttmp); |
770 | 0 | BN_clear_free(x); |
771 | 0 | BN_CTX_free(bn_ctx); |
772 | 0 | return result; |
773 | 0 | } |
774 | | |
775 | | int SRP_create_verifier_BN(const char *user, const char *pass, BIGNUM **salt, |
776 | | BIGNUM **verifier, const BIGNUM *N, |
777 | | const BIGNUM *g) |
778 | 0 | { |
779 | 0 | return SRP_create_verifier_BN_ex(user, pass, salt, verifier, N, g, NULL, |
780 | 0 | NULL); |
781 | 0 | } |
782 | | #endif |