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