]>
Commit | Line | Data |
---|---|---|
0f113f3e | 1 | /* |
aa6bb135 | 2 | * Copyright 2011-2016 The OpenSSL Project Authors. All Rights Reserved. |
edc032b5 | 3 | * |
aa6bb135 RS |
4 | * Licensed under the OpenSSL license (the "License"). You may not use |
5 | * this file except in compliance with the License. You can obtain a copy | |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
edc032b5 | 8 | */ |
aa6bb135 | 9 | |
edc032b5 | 10 | #ifndef OPENSSL_NO_SRP |
b39fc560 | 11 | # include "internal/cryptlib.h" |
dfb56425 | 12 | # include <openssl/sha.h> |
0f113f3e MC |
13 | # include <openssl/srp.h> |
14 | # include <openssl/evp.h> | |
15 | # include <openssl/buffer.h> | |
16 | # include <openssl/rand.h> | |
17 | # include <openssl/txt_db.h> | |
edc032b5 | 18 | |
0f113f3e MC |
19 | # define SRP_RANDOM_SALT_LEN 20 |
20 | # define MAX_LEN 2500 | |
edc032b5 BL |
21 | |
22 | static char b64table[] = | |
0f113f3e | 23 | "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./"; |
edc032b5 | 24 | |
0f113f3e MC |
25 | /* |
26 | * the following two conversion routines have been inspired by code from | |
27 | * Stanford | |
28 | */ | |
edc032b5 BL |
29 | |
30 | /* | |
31 | * Convert a base64 string into raw byte array representation. | |
32 | */ | |
33 | static int t_fromb64(unsigned char *a, const char *src) | |
0f113f3e MC |
34 | { |
35 | char *loc; | |
36 | int i, j; | |
37 | int size; | |
38 | ||
39 | while (*src && (*src == ' ' || *src == '\t' || *src == '\n')) | |
40 | ++src; | |
41 | size = strlen(src); | |
42 | i = 0; | |
43 | while (i < size) { | |
44 | loc = strchr(b64table, src[i]); | |
45 | if (loc == (char *)0) | |
46 | break; | |
47 | else | |
48 | a[i] = loc - b64table; | |
49 | ++i; | |
50 | } | |
51 | /* if nothing valid to process we have a zero length response */ | |
52 | if (i == 0) | |
53 | return 0; | |
54 | size = i; | |
55 | i = size - 1; | |
56 | j = size; | |
57 | while (1) { | |
58 | a[j] = a[i]; | |
59 | if (--i < 0) | |
60 | break; | |
61 | a[j] |= (a[i] & 3) << 6; | |
62 | --j; | |
63 | a[j] = (unsigned char)((a[i] & 0x3c) >> 2); | |
64 | if (--i < 0) | |
65 | break; | |
66 | a[j] |= (a[i] & 0xf) << 4; | |
67 | --j; | |
68 | a[j] = (unsigned char)((a[i] & 0x30) >> 4); | |
69 | if (--i < 0) | |
70 | break; | |
71 | a[j] |= (a[i] << 2); | |
72 | ||
73 | a[--j] = 0; | |
74 | if (--i < 0) | |
75 | break; | |
76 | } | |
77 | while (a[j] == 0 && j <= size) | |
78 | ++j; | |
79 | i = 0; | |
80 | while (j <= size) | |
81 | a[i++] = a[j++]; | |
82 | return i; | |
83 | } | |
edc032b5 BL |
84 | |
85 | /* | |
86 | * Convert a raw byte string into a null-terminated base64 ASCII string. | |
87 | */ | |
88 | static char *t_tob64(char *dst, const unsigned char *src, int size) | |
0f113f3e MC |
89 | { |
90 | int c, pos = size % 3; | |
91 | unsigned char b0 = 0, b1 = 0, b2 = 0, notleading = 0; | |
92 | char *olddst = dst; | |
93 | ||
94 | switch (pos) { | |
95 | case 1: | |
96 | b2 = src[0]; | |
97 | break; | |
98 | case 2: | |
99 | b1 = src[0]; | |
100 | b2 = src[1]; | |
101 | break; | |
102 | } | |
103 | ||
104 | while (1) { | |
105 | c = (b0 & 0xfc) >> 2; | |
106 | if (notleading || c != 0) { | |
107 | *dst++ = b64table[c]; | |
108 | notleading = 1; | |
109 | } | |
110 | c = ((b0 & 3) << 4) | ((b1 & 0xf0) >> 4); | |
111 | if (notleading || c != 0) { | |
112 | *dst++ = b64table[c]; | |
113 | notleading = 1; | |
114 | } | |
115 | c = ((b1 & 0xf) << 2) | ((b2 & 0xc0) >> 6); | |
116 | if (notleading || c != 0) { | |
117 | *dst++ = b64table[c]; | |
118 | notleading = 1; | |
119 | } | |
120 | c = b2 & 0x3f; | |
121 | if (notleading || c != 0) { | |
122 | *dst++ = b64table[c]; | |
123 | notleading = 1; | |
124 | } | |
125 | if (pos >= size) | |
126 | break; | |
127 | else { | |
128 | b0 = src[pos++]; | |
129 | b1 = src[pos++]; | |
130 | b2 = src[pos++]; | |
131 | } | |
132 | } | |
133 | ||
134 | *dst++ = '\0'; | |
135 | return olddst; | |
136 | } | |
edc032b5 | 137 | |
380f18ed | 138 | void SRP_user_pwd_free(SRP_user_pwd *user_pwd) |
0f113f3e MC |
139 | { |
140 | if (user_pwd == NULL) | |
141 | return; | |
142 | BN_free(user_pwd->s); | |
143 | BN_clear_free(user_pwd->v); | |
144 | OPENSSL_free(user_pwd->id); | |
145 | OPENSSL_free(user_pwd->info); | |
146 | OPENSSL_free(user_pwd); | |
147 | } | |
edc032b5 | 148 | |
71fa4513 | 149 | static SRP_user_pwd *SRP_user_pwd_new(void) |
0f113f3e | 150 | { |
b4faea50 | 151 | SRP_user_pwd *ret = OPENSSL_malloc(sizeof(*ret)); |
0f113f3e MC |
152 | if (ret == NULL) |
153 | return NULL; | |
154 | ret->N = NULL; | |
155 | ret->g = NULL; | |
156 | ret->s = NULL; | |
157 | ret->v = NULL; | |
158 | ret->id = NULL; | |
159 | ret->info = NULL; | |
160 | return ret; | |
161 | } | |
edc032b5 BL |
162 | |
163 | static void SRP_user_pwd_set_gN(SRP_user_pwd *vinfo, const BIGNUM *g, | |
0f113f3e MC |
164 | const BIGNUM *N) |
165 | { | |
166 | vinfo->N = N; | |
167 | vinfo->g = g; | |
168 | } | |
edc032b5 BL |
169 | |
170 | static int SRP_user_pwd_set_ids(SRP_user_pwd *vinfo, const char *id, | |
0f113f3e MC |
171 | const char *info) |
172 | { | |
7644a9ae | 173 | if (id != NULL && NULL == (vinfo->id = OPENSSL_strdup(id))) |
0f113f3e | 174 | return 0; |
7644a9ae | 175 | return (info == NULL || NULL != (vinfo->info = OPENSSL_strdup(info))); |
0f113f3e | 176 | } |
edc032b5 BL |
177 | |
178 | static int SRP_user_pwd_set_sv(SRP_user_pwd *vinfo, const char *s, | |
0f113f3e MC |
179 | const char *v) |
180 | { | |
181 | unsigned char tmp[MAX_LEN]; | |
182 | int len; | |
183 | ||
184 | if (strlen(s) > MAX_LEN || strlen(v) > MAX_LEN) | |
185 | return 0; | |
186 | len = t_fromb64(tmp, v); | |
187 | if (NULL == (vinfo->v = BN_bin2bn(tmp, len, NULL))) | |
188 | return 0; | |
189 | len = t_fromb64(tmp, s); | |
190 | return ((vinfo->s = BN_bin2bn(tmp, len, NULL)) != NULL); | |
191 | } | |
edc032b5 | 192 | |
71fa4513 | 193 | static int SRP_user_pwd_set_sv_BN(SRP_user_pwd *vinfo, BIGNUM *s, BIGNUM *v) |
0f113f3e MC |
194 | { |
195 | vinfo->v = v; | |
196 | vinfo->s = s; | |
197 | return (vinfo->s != NULL && vinfo->v != NULL); | |
198 | } | |
edc032b5 | 199 | |
380f18ed EK |
200 | static SRP_user_pwd *srp_user_pwd_dup(SRP_user_pwd *src) |
201 | { | |
202 | SRP_user_pwd *ret; | |
203 | ||
204 | if (src == NULL) | |
205 | return NULL; | |
206 | if ((ret = SRP_user_pwd_new()) == NULL) | |
207 | return NULL; | |
208 | ||
209 | SRP_user_pwd_set_gN(ret, src->g, src->N); | |
210 | if (!SRP_user_pwd_set_ids(ret, src->id, src->info) | |
211 | || !SRP_user_pwd_set_sv_BN(ret, BN_dup(src->s), BN_dup(src->v))) { | |
212 | SRP_user_pwd_free(ret); | |
213 | return NULL; | |
214 | } | |
215 | return ret; | |
216 | } | |
217 | ||
edc032b5 | 218 | SRP_VBASE *SRP_VBASE_new(char *seed_key) |
0f113f3e | 219 | { |
b4faea50 | 220 | SRP_VBASE *vb = OPENSSL_malloc(sizeof(*vb)); |
0f113f3e MC |
221 | |
222 | if (vb == NULL) | |
223 | return NULL; | |
75ebbd9a RS |
224 | if ((vb->users_pwd = sk_SRP_user_pwd_new_null()) == NULL |
225 | || (vb->gN_cache = sk_SRP_gN_cache_new_null()) == NULL) { | |
0f113f3e MC |
226 | OPENSSL_free(vb); |
227 | return NULL; | |
228 | } | |
229 | vb->default_g = NULL; | |
230 | vb->default_N = NULL; | |
231 | vb->seed_key = NULL; | |
7644a9ae | 232 | if ((seed_key != NULL) && (vb->seed_key = OPENSSL_strdup(seed_key)) == NULL) { |
0f113f3e MC |
233 | sk_SRP_user_pwd_free(vb->users_pwd); |
234 | sk_SRP_gN_cache_free(vb->gN_cache); | |
235 | OPENSSL_free(vb); | |
236 | return NULL; | |
237 | } | |
238 | return vb; | |
239 | } | |
edc032b5 | 240 | |
895cba19 | 241 | void SRP_VBASE_free(SRP_VBASE *vb) |
0f113f3e | 242 | { |
895cba19 RS |
243 | if (!vb) |
244 | return; | |
0f113f3e MC |
245 | sk_SRP_user_pwd_pop_free(vb->users_pwd, SRP_user_pwd_free); |
246 | sk_SRP_gN_cache_free(vb->gN_cache); | |
247 | OPENSSL_free(vb->seed_key); | |
248 | OPENSSL_free(vb); | |
0f113f3e | 249 | } |
edc032b5 BL |
250 | |
251 | static SRP_gN_cache *SRP_gN_new_init(const char *ch) | |
0f113f3e MC |
252 | { |
253 | unsigned char tmp[MAX_LEN]; | |
254 | int len; | |
b4faea50 | 255 | SRP_gN_cache *newgN = OPENSSL_malloc(sizeof(*newgN)); |
edc032b5 | 256 | |
0f113f3e MC |
257 | if (newgN == NULL) |
258 | return NULL; | |
edc032b5 | 259 | |
7644a9ae | 260 | if ((newgN->b64_bn = OPENSSL_strdup(ch)) == NULL) |
0f113f3e | 261 | goto err; |
edc032b5 | 262 | |
0f113f3e MC |
263 | len = t_fromb64(tmp, ch); |
264 | if ((newgN->bn = BN_bin2bn(tmp, len, NULL))) | |
265 | return newgN; | |
edc032b5 | 266 | |
0f113f3e MC |
267 | OPENSSL_free(newgN->b64_bn); |
268 | err: | |
269 | OPENSSL_free(newgN); | |
270 | return NULL; | |
271 | } | |
edc032b5 BL |
272 | |
273 | static void SRP_gN_free(SRP_gN_cache *gN_cache) | |
0f113f3e MC |
274 | { |
275 | if (gN_cache == NULL) | |
276 | return; | |
277 | OPENSSL_free(gN_cache->b64_bn); | |
278 | BN_free(gN_cache->bn); | |
279 | OPENSSL_free(gN_cache); | |
280 | } | |
edc032b5 BL |
281 | |
282 | static SRP_gN *SRP_get_gN_by_id(const char *id, STACK_OF(SRP_gN) *gN_tab) | |
0f113f3e MC |
283 | { |
284 | int i; | |
285 | ||
286 | SRP_gN *gN; | |
287 | if (gN_tab != NULL) | |
288 | for (i = 0; i < sk_SRP_gN_num(gN_tab); i++) { | |
289 | gN = sk_SRP_gN_value(gN_tab, i); | |
290 | if (gN && (id == NULL || strcmp(gN->id, id) == 0)) | |
291 | return gN; | |
292 | } | |
293 | ||
294 | return SRP_get_default_gN(id); | |
295 | } | |
edc032b5 BL |
296 | |
297 | static BIGNUM *SRP_gN_place_bn(STACK_OF(SRP_gN_cache) *gN_cache, char *ch) | |
0f113f3e MC |
298 | { |
299 | int i; | |
300 | if (gN_cache == NULL) | |
301 | return NULL; | |
302 | ||
303 | /* search if we have already one... */ | |
304 | for (i = 0; i < sk_SRP_gN_cache_num(gN_cache); i++) { | |
305 | SRP_gN_cache *cache = sk_SRP_gN_cache_value(gN_cache, i); | |
306 | if (strcmp(cache->b64_bn, ch) == 0) | |
307 | return cache->bn; | |
308 | } | |
309 | { /* it is the first time that we find it */ | |
310 | SRP_gN_cache *newgN = SRP_gN_new_init(ch); | |
311 | if (newgN) { | |
312 | if (sk_SRP_gN_cache_insert(gN_cache, newgN, 0) > 0) | |
313 | return newgN->bn; | |
314 | SRP_gN_free(newgN); | |
315 | } | |
316 | } | |
317 | return NULL; | |
318 | } | |
319 | ||
320 | /* | |
321 | * this function parses verifier file. Format is: | |
edc032b5 BL |
322 | * string(index):base64(N):base64(g):0 |
323 | * string(username):base64(v):base64(salt):int(index) | |
324 | */ | |
325 | ||
edc032b5 | 326 | int SRP_VBASE_init(SRP_VBASE *vb, char *verifier_file) |
0f113f3e MC |
327 | { |
328 | int error_code; | |
329 | STACK_OF(SRP_gN) *SRP_gN_tab = sk_SRP_gN_new_null(); | |
330 | char *last_index = NULL; | |
331 | int i; | |
332 | char **pp; | |
333 | ||
334 | SRP_gN *gN = NULL; | |
335 | SRP_user_pwd *user_pwd = NULL; | |
336 | ||
337 | TXT_DB *tmpdb = NULL; | |
338 | BIO *in = BIO_new(BIO_s_file()); | |
339 | ||
340 | error_code = SRP_ERR_OPEN_FILE; | |
341 | ||
342 | if (in == NULL || BIO_read_filename(in, verifier_file) <= 0) | |
343 | goto err; | |
344 | ||
345 | error_code = SRP_ERR_VBASE_INCOMPLETE_FILE; | |
346 | ||
347 | if ((tmpdb = TXT_DB_read(in, DB_NUMBER)) == NULL) | |
348 | goto err; | |
349 | ||
350 | error_code = SRP_ERR_MEMORY; | |
351 | ||
352 | if (vb->seed_key) { | |
353 | last_index = SRP_get_default_gN(NULL)->id; | |
354 | } | |
355 | for (i = 0; i < sk_OPENSSL_PSTRING_num(tmpdb->data); i++) { | |
356 | pp = sk_OPENSSL_PSTRING_value(tmpdb->data, i); | |
357 | if (pp[DB_srptype][0] == DB_SRP_INDEX) { | |
358 | /* | |
359 | * we add this couple in the internal Stack | |
360 | */ | |
361 | ||
b4faea50 | 362 | if ((gN = OPENSSL_malloc(sizeof(*gN))) == NULL) |
0f113f3e MC |
363 | goto err; |
364 | ||
7644a9ae | 365 | if ((gN->id = OPENSSL_strdup(pp[DB_srpid])) == NULL |
75ebbd9a RS |
366 | || (gN->N = SRP_gN_place_bn(vb->gN_cache, pp[DB_srpverifier])) |
367 | == NULL | |
368 | || (gN->g = SRP_gN_place_bn(vb->gN_cache, pp[DB_srpsalt])) | |
369 | == NULL | |
0f113f3e MC |
370 | || sk_SRP_gN_insert(SRP_gN_tab, gN, 0) == 0) |
371 | goto err; | |
372 | ||
373 | gN = NULL; | |
374 | ||
375 | if (vb->seed_key != NULL) { | |
376 | last_index = pp[DB_srpid]; | |
377 | } | |
378 | } else if (pp[DB_srptype][0] == DB_SRP_VALID) { | |
379 | /* it is a user .... */ | |
380 | const SRP_gN *lgN; | |
381 | ||
382 | if ((lgN = SRP_get_gN_by_id(pp[DB_srpgN], SRP_gN_tab)) != NULL) { | |
383 | error_code = SRP_ERR_MEMORY; | |
384 | if ((user_pwd = SRP_user_pwd_new()) == NULL) | |
385 | goto err; | |
386 | ||
387 | SRP_user_pwd_set_gN(user_pwd, lgN->g, lgN->N); | |
388 | if (!SRP_user_pwd_set_ids | |
389 | (user_pwd, pp[DB_srpid], pp[DB_srpinfo])) | |
390 | goto err; | |
391 | ||
392 | error_code = SRP_ERR_VBASE_BN_LIB; | |
393 | if (!SRP_user_pwd_set_sv | |
394 | (user_pwd, pp[DB_srpsalt], pp[DB_srpverifier])) | |
395 | goto err; | |
396 | ||
397 | if (sk_SRP_user_pwd_insert(vb->users_pwd, user_pwd, 0) == 0) | |
398 | goto err; | |
8483a003 | 399 | user_pwd = NULL; /* abandon responsibility */ |
0f113f3e MC |
400 | } |
401 | } | |
402 | } | |
403 | ||
404 | if (last_index != NULL) { | |
405 | /* this means that we want to simulate a default user */ | |
406 | ||
407 | if (((gN = SRP_get_gN_by_id(last_index, SRP_gN_tab)) == NULL)) { | |
408 | error_code = SRP_ERR_VBASE_BN_LIB; | |
409 | goto err; | |
410 | } | |
411 | vb->default_g = gN->g; | |
412 | vb->default_N = gN->N; | |
413 | gN = NULL; | |
414 | } | |
415 | error_code = SRP_NO_ERROR; | |
edc032b5 BL |
416 | |
417 | err: | |
0f113f3e MC |
418 | /* |
419 | * there may be still some leaks to fix, if this fails, the application | |
420 | * terminates most likely | |
421 | */ | |
edc032b5 | 422 | |
0f113f3e MC |
423 | if (gN != NULL) { |
424 | OPENSSL_free(gN->id); | |
425 | OPENSSL_free(gN); | |
426 | } | |
edc032b5 | 427 | |
0f113f3e | 428 | SRP_user_pwd_free(user_pwd); |
edc032b5 | 429 | |
895cba19 | 430 | TXT_DB_free(tmpdb); |
ca3a82c3 | 431 | BIO_free_all(in); |
edc032b5 | 432 | |
0f113f3e | 433 | sk_SRP_gN_free(SRP_gN_tab); |
edc032b5 | 434 | |
0f113f3e | 435 | return error_code; |
edc032b5 | 436 | |
0f113f3e | 437 | } |
edc032b5 | 438 | |
380f18ed | 439 | static SRP_user_pwd *find_user(SRP_VBASE *vb, char *username) |
0f113f3e MC |
440 | { |
441 | int i; | |
442 | SRP_user_pwd *user; | |
0f113f3e MC |
443 | |
444 | if (vb == NULL) | |
445 | return NULL; | |
380f18ed | 446 | |
0f113f3e MC |
447 | for (i = 0; i < sk_SRP_user_pwd_num(vb->users_pwd); i++) { |
448 | user = sk_SRP_user_pwd_value(vb->users_pwd, i); | |
449 | if (strcmp(user->id, username) == 0) | |
450 | return user; | |
451 | } | |
380f18ed EK |
452 | |
453 | return NULL; | |
454 | } | |
455 | ||
1e45206f | 456 | #if OPENSSL_API_COMPAT < 0x10100000L |
380f18ed EK |
457 | /* |
458 | * DEPRECATED: use SRP_VBASE_get1_by_user instead. | |
459 | * This method ignores the configured seed and fails for an unknown user. | |
460 | * Ownership of the returned pointer is not released to the caller. | |
461 | * In other words, caller must not free the result. | |
462 | */ | |
463 | SRP_user_pwd *SRP_VBASE_get_by_user(SRP_VBASE *vb, char *username) | |
464 | { | |
465 | return find_user(vb, username); | |
466 | } | |
1e45206f | 467 | #endif |
380f18ed EK |
468 | |
469 | /* | |
470 | * Ownership of the returned pointer is released to the caller. | |
471 | * In other words, caller must free the result once done. | |
472 | */ | |
473 | SRP_user_pwd *SRP_VBASE_get1_by_user(SRP_VBASE *vb, char *username) | |
474 | { | |
475 | SRP_user_pwd *user; | |
476 | unsigned char digv[SHA_DIGEST_LENGTH]; | |
477 | unsigned char digs[SHA_DIGEST_LENGTH]; | |
478 | EVP_MD_CTX *ctxt = NULL; | |
479 | ||
480 | if (vb == NULL) | |
481 | return NULL; | |
482 | ||
483 | if ((user = find_user(vb, username)) != NULL) | |
484 | return srp_user_pwd_dup(user); | |
485 | ||
0f113f3e MC |
486 | if ((vb->seed_key == NULL) || |
487 | (vb->default_g == NULL) || (vb->default_N == NULL)) | |
488 | return NULL; | |
edc032b5 BL |
489 | |
490 | /* if the user is unknown we set parameters as well if we have a seed_key */ | |
491 | ||
0f113f3e MC |
492 | if ((user = SRP_user_pwd_new()) == NULL) |
493 | return NULL; | |
494 | ||
495 | SRP_user_pwd_set_gN(user, vb->default_g, vb->default_N); | |
edc032b5 | 496 | |
0f113f3e MC |
497 | if (!SRP_user_pwd_set_ids(user, username, NULL)) |
498 | goto err; | |
499 | ||
266483d2 MC |
500 | if (RAND_bytes(digv, SHA_DIGEST_LENGTH) <= 0) |
501 | goto err; | |
bfb0641f | 502 | ctxt = EVP_MD_CTX_new(); |
6e59a892 RL |
503 | EVP_DigestInit_ex(ctxt, EVP_sha1(), NULL); |
504 | EVP_DigestUpdate(ctxt, vb->seed_key, strlen(vb->seed_key)); | |
505 | EVP_DigestUpdate(ctxt, username, strlen(username)); | |
506 | EVP_DigestFinal_ex(ctxt, digs, NULL); | |
bfb0641f | 507 | EVP_MD_CTX_free(ctxt); |
6e59a892 RL |
508 | ctxt = NULL; |
509 | if (SRP_user_pwd_set_sv_BN(user, | |
510 | BN_bin2bn(digs, SHA_DIGEST_LENGTH, NULL), | |
511 | BN_bin2bn(digv, SHA_DIGEST_LENGTH, NULL))) | |
0f113f3e MC |
512 | return user; |
513 | ||
895cba19 | 514 | err: |
bfb0641f | 515 | EVP_MD_CTX_free(ctxt); |
895cba19 | 516 | SRP_user_pwd_free(user); |
0f113f3e MC |
517 | return NULL; |
518 | } | |
edc032b5 BL |
519 | |
520 | /* | |
0f113f3e MC |
521 | * create a verifier (*salt,*verifier,g and N are in base64) |
522 | */ | |
edc032b5 | 523 | char *SRP_create_verifier(const char *user, const char *pass, char **salt, |
0f113f3e MC |
524 | char **verifier, const char *N, const char *g) |
525 | { | |
526 | int len; | |
bf95cde2 | 527 | char *result = NULL, *vf = NULL; |
0f113f3e MC |
528 | BIGNUM *N_bn = NULL, *g_bn = NULL, *s = NULL, *v = NULL; |
529 | unsigned char tmp[MAX_LEN]; | |
530 | unsigned char tmp2[MAX_LEN]; | |
531 | char *defgNid = NULL; | |
bf95cde2 | 532 | int vfsize = 0; |
0f113f3e MC |
533 | |
534 | if ((user == NULL) || | |
535 | (pass == NULL) || (salt == NULL) || (verifier == NULL)) | |
536 | goto err; | |
537 | ||
538 | if (N) { | |
75ebbd9a | 539 | if ((len = t_fromb64(tmp, N)) == 0) |
0f113f3e MC |
540 | goto err; |
541 | N_bn = BN_bin2bn(tmp, len, NULL); | |
75ebbd9a | 542 | if ((len = t_fromb64(tmp, g)) == 0) |
0f113f3e MC |
543 | goto err; |
544 | g_bn = BN_bin2bn(tmp, len, NULL); | |
545 | defgNid = "*"; | |
546 | } else { | |
547 | SRP_gN *gN = SRP_get_gN_by_id(g, NULL); | |
548 | if (gN == NULL) | |
549 | goto err; | |
550 | N_bn = gN->N; | |
551 | g_bn = gN->g; | |
552 | defgNid = gN->id; | |
553 | } | |
554 | ||
555 | if (*salt == NULL) { | |
266483d2 MC |
556 | if (RAND_bytes(tmp2, SRP_RANDOM_SALT_LEN) <= 0) |
557 | goto err; | |
0f113f3e MC |
558 | |
559 | s = BN_bin2bn(tmp2, SRP_RANDOM_SALT_LEN, NULL); | |
560 | } else { | |
75ebbd9a | 561 | if ((len = t_fromb64(tmp2, *salt)) == 0) |
0f113f3e MC |
562 | goto err; |
563 | s = BN_bin2bn(tmp2, len, NULL); | |
564 | } | |
565 | ||
566 | if (!SRP_create_verifier_BN(user, pass, &s, &v, N_bn, g_bn)) | |
567 | goto err; | |
568 | ||
569 | BN_bn2bin(v, tmp); | |
bf95cde2 MC |
570 | vfsize = BN_num_bytes(v) * 2; |
571 | if (((vf = OPENSSL_malloc(vfsize)) == NULL)) | |
0f113f3e MC |
572 | goto err; |
573 | t_tob64(vf, tmp, BN_num_bytes(v)); | |
574 | ||
0f113f3e MC |
575 | if (*salt == NULL) { |
576 | char *tmp_salt; | |
577 | ||
578 | if ((tmp_salt = OPENSSL_malloc(SRP_RANDOM_SALT_LEN * 2)) == NULL) { | |
0f113f3e MC |
579 | goto err; |
580 | } | |
581 | t_tob64(tmp_salt, tmp2, SRP_RANDOM_SALT_LEN); | |
582 | *salt = tmp_salt; | |
583 | } | |
584 | ||
bf95cde2 MC |
585 | *verifier = vf; |
586 | vf = NULL; | |
0f113f3e MC |
587 | result = defgNid; |
588 | ||
589 | err: | |
590 | if (N) { | |
591 | BN_free(N_bn); | |
592 | BN_free(g_bn); | |
593 | } | |
bf95cde2 MC |
594 | OPENSSL_clear_free(vf, vfsize); |
595 | BN_clear_free(s); | |
596 | BN_clear_free(v); | |
0f113f3e MC |
597 | return result; |
598 | } | |
edc032b5 BL |
599 | |
600 | /* | |
bf95cde2 MC |
601 | * create a verifier (*salt,*verifier,g and N are BIGNUMs). If *salt != NULL |
602 | * then the provided salt will be used. On successful exit *verifier will point | |
603 | * to a newly allocated BIGNUM containing the verifier and (if a salt was not | |
604 | * provided) *salt will be populated with a newly allocated BIGNUM containing a | |
605 | * random salt. | |
606 | * The caller is responsible for freeing the allocated *salt and *verifier | |
607 | * BIGNUMS. | |
0f113f3e | 608 | */ |
8892ce77 | 609 | int SRP_create_verifier_BN(const char *user, const char *pass, BIGNUM **salt, |
0f113f3e MC |
610 | BIGNUM **verifier, const BIGNUM *N, |
611 | const BIGNUM *g) | |
612 | { | |
613 | int result = 0; | |
614 | BIGNUM *x = NULL; | |
615 | BN_CTX *bn_ctx = BN_CTX_new(); | |
616 | unsigned char tmp2[MAX_LEN]; | |
bf95cde2 | 617 | BIGNUM *salttmp = NULL; |
edc032b5 | 618 | |
0f113f3e MC |
619 | if ((user == NULL) || |
620 | (pass == NULL) || | |
621 | (salt == NULL) || | |
622 | (verifier == NULL) || (N == NULL) || (g == NULL) || (bn_ctx == NULL)) | |
623 | goto err; | |
edc032b5 | 624 | |
0f113f3e | 625 | if (*salt == NULL) { |
266483d2 MC |
626 | if (RAND_bytes(tmp2, SRP_RANDOM_SALT_LEN) <= 0) |
627 | goto err; | |
edc032b5 | 628 | |
bf95cde2 MC |
629 | salttmp = BN_bin2bn(tmp2, SRP_RANDOM_SALT_LEN, NULL); |
630 | } else { | |
631 | salttmp = *salt; | |
0f113f3e | 632 | } |
edc032b5 | 633 | |
bf95cde2 | 634 | x = SRP_Calc_x(salttmp, user, pass); |
edc032b5 | 635 | |
0f113f3e MC |
636 | *verifier = BN_new(); |
637 | if (*verifier == NULL) | |
638 | goto err; | |
edc032b5 | 639 | |
0f113f3e MC |
640 | if (!BN_mod_exp(*verifier, g, x, N, bn_ctx)) { |
641 | BN_clear_free(*verifier); | |
642 | goto err; | |
643 | } | |
edc032b5 | 644 | |
0f113f3e | 645 | result = 1; |
bf95cde2 | 646 | *salt = salttmp; |
edc032b5 | 647 | |
0f113f3e | 648 | err: |
3bbd1d63 | 649 | if (salt != NULL && *salt != salttmp) |
bf95cde2 | 650 | BN_clear_free(salttmp); |
0f113f3e MC |
651 | BN_clear_free(x); |
652 | BN_CTX_free(bn_ctx); | |
653 | return result; | |
654 | } | |
edc032b5 BL |
655 | |
656 | #endif |