xref: /openssl/crypto/srp/srp_lib.c (revision fc27fca8)
1 /*
2  * Copyright 2004-2021 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 <openssl/sha.h>
20 # include <openssl/srp.h>
21 # include <openssl/evp.h>
22 # include "crypto/bn_srp.h"
23 
24 /* calculate = SHA1(PAD(x) || PAD(y)) */
25 
srp_Calc_xy(const BIGNUM * x,const BIGNUM * y,const BIGNUM * N,OSSL_LIB_CTX * libctx,const char * propq)26 static BIGNUM *srp_Calc_xy(const BIGNUM *x, const BIGNUM *y, const BIGNUM *N,
27                            OSSL_LIB_CTX *libctx, const char *propq)
28 {
29     unsigned char digest[SHA_DIGEST_LENGTH];
30     unsigned char *tmp = NULL;
31     int numN = BN_num_bytes(N);
32     BIGNUM *res = NULL;
33     EVP_MD *sha1 = EVP_MD_fetch(libctx, "SHA1", propq);
34 
35     if (sha1 == NULL)
36         return NULL;
37 
38     if (x != N && BN_ucmp(x, N) >= 0)
39         goto err;
40     if (y != N && BN_ucmp(y, N) >= 0)
41         goto err;
42     if ((tmp = OPENSSL_malloc(numN * 2)) == NULL)
43         goto err;
44     if (BN_bn2binpad(x, tmp, numN) < 0
45         || BN_bn2binpad(y, tmp + numN, numN) < 0
46         || !EVP_Digest(tmp, numN * 2, digest, NULL, sha1, NULL))
47         goto err;
48     res = BN_bin2bn(digest, sizeof(digest), NULL);
49  err:
50     EVP_MD_free(sha1);
51     OPENSSL_free(tmp);
52     return res;
53 }
54 
srp_Calc_k(const BIGNUM * N,const BIGNUM * g,OSSL_LIB_CTX * libctx,const char * propq)55 static BIGNUM *srp_Calc_k(const BIGNUM *N, const BIGNUM *g,
56                           OSSL_LIB_CTX *libctx,
57                           const char *propq)
58 {
59     /* k = SHA1(N | PAD(g)) -- tls-srp RFC 5054 */
60     return srp_Calc_xy(N, g, N, libctx, propq);
61 }
62 
SRP_Calc_u_ex(const BIGNUM * A,const BIGNUM * B,const BIGNUM * N,OSSL_LIB_CTX * libctx,const char * propq)63 BIGNUM *SRP_Calc_u_ex(const BIGNUM *A, const BIGNUM *B, const BIGNUM *N,
64                       OSSL_LIB_CTX *libctx, const char *propq)
65 {
66     /* u = SHA1(PAD(A) || PAD(B) ) -- tls-srp RFC 5054 */
67     return srp_Calc_xy(A, B, N, libctx, propq);
68 }
69 
SRP_Calc_u(const BIGNUM * A,const BIGNUM * B,const BIGNUM * N)70 BIGNUM *SRP_Calc_u(const BIGNUM *A, const BIGNUM *B, const BIGNUM *N)
71 {
72     /* u = SHA1(PAD(A) || PAD(B) ) -- tls-srp RFC 5054 */
73     return srp_Calc_xy(A, B, N, NULL, NULL);
74 }
75 
SRP_Calc_server_key(const BIGNUM * A,const BIGNUM * v,const BIGNUM * u,const BIGNUM * b,const BIGNUM * N)76 BIGNUM *SRP_Calc_server_key(const BIGNUM *A, const BIGNUM *v, const BIGNUM *u,
77                             const BIGNUM *b, const BIGNUM *N)
78 {
79     BIGNUM *tmp = NULL, *S = NULL;
80     BN_CTX *bn_ctx;
81 
82     if (u == NULL || A == NULL || v == NULL || b == NULL || N == NULL)
83         return NULL;
84 
85     if ((bn_ctx = BN_CTX_new()) == NULL || (tmp = BN_new()) == NULL)
86         goto err;
87 
88     /* S = (A*v**u) ** b */
89 
90     if (!BN_mod_exp(tmp, v, u, N, bn_ctx))
91         goto err;
92     if (!BN_mod_mul(tmp, A, tmp, N, bn_ctx))
93         goto err;
94 
95     S = BN_new();
96     if (S != NULL && !BN_mod_exp(S, tmp, b, N, bn_ctx)) {
97         BN_free(S);
98         S = NULL;
99     }
100  err:
101     BN_CTX_free(bn_ctx);
102     BN_clear_free(tmp);
103     return S;
104 }
105 
SRP_Calc_B_ex(const BIGNUM * b,const BIGNUM * N,const BIGNUM * g,const BIGNUM * v,OSSL_LIB_CTX * libctx,const char * propq)106 BIGNUM *SRP_Calc_B_ex(const BIGNUM *b, const BIGNUM *N, const BIGNUM *g,
107                       const BIGNUM *v, OSSL_LIB_CTX *libctx, const char *propq)
108 {
109     BIGNUM *kv = NULL, *gb = NULL;
110     BIGNUM *B = NULL, *k = NULL;
111     BN_CTX *bn_ctx;
112 
113     if (b == NULL || N == NULL || g == NULL || v == NULL ||
114         (bn_ctx = BN_CTX_new_ex(libctx)) == NULL)
115         return NULL;
116 
117     if ((kv = BN_new()) == NULL ||
118         (gb = BN_new()) == NULL || (B = BN_new()) == NULL)
119         goto err;
120 
121     /* B = g**b + k*v */
122 
123     if (!BN_mod_exp(gb, g, b, N, bn_ctx)
124         || (k = srp_Calc_k(N, g, libctx, propq)) == NULL
125         || !BN_mod_mul(kv, v, k, N, bn_ctx)
126         || !BN_mod_add(B, gb, kv, N, bn_ctx)) {
127         BN_free(B);
128         B = NULL;
129     }
130  err:
131     BN_CTX_free(bn_ctx);
132     BN_clear_free(kv);
133     BN_clear_free(gb);
134     BN_free(k);
135     return B;
136 }
137 
SRP_Calc_B(const BIGNUM * b,const BIGNUM * N,const BIGNUM * g,const BIGNUM * v)138 BIGNUM *SRP_Calc_B(const BIGNUM *b, const BIGNUM *N, const BIGNUM *g,
139                    const BIGNUM *v)
140 {
141     return SRP_Calc_B_ex(b, N, g, v, NULL, NULL);
142 }
143 
SRP_Calc_x_ex(const BIGNUM * s,const char * user,const char * pass,OSSL_LIB_CTX * libctx,const char * propq)144 BIGNUM *SRP_Calc_x_ex(const BIGNUM *s, const char *user, const char *pass,
145                       OSSL_LIB_CTX *libctx, const char *propq)
146 {
147     unsigned char dig[SHA_DIGEST_LENGTH];
148     EVP_MD_CTX *ctxt;
149     unsigned char *cs = NULL;
150     BIGNUM *res = NULL;
151     EVP_MD *sha1 = NULL;
152 
153     if ((s == NULL) || (user == NULL) || (pass == NULL))
154         return NULL;
155 
156     ctxt = EVP_MD_CTX_new();
157     if (ctxt == NULL)
158         return NULL;
159     if ((cs = OPENSSL_malloc(BN_num_bytes(s))) == NULL)
160         goto err;
161 
162     sha1 = EVP_MD_fetch(libctx, "SHA1", propq);
163     if (sha1 == NULL)
164         goto err;
165 
166     if (!EVP_DigestInit_ex(ctxt, sha1, NULL)
167         || !EVP_DigestUpdate(ctxt, user, strlen(user))
168         || !EVP_DigestUpdate(ctxt, ":", 1)
169         || !EVP_DigestUpdate(ctxt, pass, strlen(pass))
170         || !EVP_DigestFinal_ex(ctxt, dig, NULL)
171         || !EVP_DigestInit_ex(ctxt, sha1, NULL))
172         goto err;
173     if (BN_bn2bin(s, cs) < 0)
174         goto err;
175     if (!EVP_DigestUpdate(ctxt, cs, BN_num_bytes(s)))
176         goto err;
177 
178     if (!EVP_DigestUpdate(ctxt, dig, sizeof(dig))
179         || !EVP_DigestFinal_ex(ctxt, dig, NULL))
180         goto err;
181 
182     res = BN_bin2bn(dig, sizeof(dig), NULL);
183 
184  err:
185     EVP_MD_free(sha1);
186     OPENSSL_free(cs);
187     EVP_MD_CTX_free(ctxt);
188     return res;
189 }
190 
SRP_Calc_x(const BIGNUM * s,const char * user,const char * pass)191 BIGNUM *SRP_Calc_x(const BIGNUM *s, const char *user, const char *pass)
192 {
193     return SRP_Calc_x_ex(s, user, pass, NULL, NULL);
194 }
195 
SRP_Calc_A(const BIGNUM * a,const BIGNUM * N,const BIGNUM * g)196 BIGNUM *SRP_Calc_A(const BIGNUM *a, const BIGNUM *N, const BIGNUM *g)
197 {
198     BN_CTX *bn_ctx;
199     BIGNUM *A = NULL;
200 
201     if (a == NULL || N == NULL || g == NULL || (bn_ctx = BN_CTX_new()) == NULL)
202         return NULL;
203 
204     if ((A = BN_new()) != NULL && !BN_mod_exp(A, g, a, N, bn_ctx)) {
205         BN_free(A);
206         A = NULL;
207     }
208     BN_CTX_free(bn_ctx);
209     return A;
210 }
211 
SRP_Calc_client_key_ex(const BIGNUM * N,const BIGNUM * B,const BIGNUM * g,const BIGNUM * x,const BIGNUM * a,const BIGNUM * u,OSSL_LIB_CTX * libctx,const char * propq)212 BIGNUM *SRP_Calc_client_key_ex(const BIGNUM *N, const BIGNUM *B, const BIGNUM *g,
213                             const BIGNUM *x, const BIGNUM *a, const BIGNUM *u,
214                             OSSL_LIB_CTX *libctx, const char *propq)
215 {
216     BIGNUM *tmp = NULL, *tmp2 = NULL, *tmp3 = NULL, *k = NULL, *K = NULL;
217     BIGNUM *xtmp = NULL;
218     BN_CTX *bn_ctx;
219 
220     if (u == NULL || B == NULL || N == NULL || g == NULL || x == NULL
221         || a == NULL || (bn_ctx = BN_CTX_new_ex(libctx)) == NULL)
222         return NULL;
223 
224     if ((tmp = BN_new()) == NULL ||
225         (tmp2 = BN_new()) == NULL ||
226         (tmp3 = BN_new()) == NULL ||
227         (xtmp = BN_new()) == NULL)
228         goto err;
229 
230     BN_with_flags(xtmp, x, BN_FLG_CONSTTIME);
231     BN_set_flags(tmp, BN_FLG_CONSTTIME);
232     if (!BN_mod_exp(tmp, g, xtmp, N, bn_ctx))
233         goto err;
234     if ((k = srp_Calc_k(N, g, libctx, propq)) == NULL)
235         goto err;
236     if (!BN_mod_mul(tmp2, tmp, k, N, bn_ctx))
237         goto err;
238     if (!BN_mod_sub(tmp, B, tmp2, N, bn_ctx))
239         goto err;
240     if (!BN_mul(tmp3, u, xtmp, bn_ctx))
241         goto err;
242     if (!BN_add(tmp2, a, tmp3))
243         goto err;
244     K = BN_new();
245     if (K != NULL && !BN_mod_exp(K, tmp, tmp2, N, bn_ctx)) {
246         BN_free(K);
247         K = NULL;
248     }
249 
250  err:
251     BN_CTX_free(bn_ctx);
252     BN_free(xtmp);
253     BN_clear_free(tmp);
254     BN_clear_free(tmp2);
255     BN_clear_free(tmp3);
256     BN_free(k);
257     return K;
258 }
259 
SRP_Calc_client_key(const BIGNUM * N,const BIGNUM * B,const BIGNUM * g,const BIGNUM * x,const BIGNUM * a,const BIGNUM * u)260 BIGNUM *SRP_Calc_client_key(const BIGNUM *N, const BIGNUM *B, const BIGNUM *g,
261                             const BIGNUM *x, const BIGNUM *a, const BIGNUM *u)
262 {
263     return SRP_Calc_client_key_ex(N, B, g, x, a, u, NULL, NULL);
264 }
265 
SRP_Verify_B_mod_N(const BIGNUM * B,const BIGNUM * N)266 int SRP_Verify_B_mod_N(const BIGNUM *B, const BIGNUM *N)
267 {
268     BIGNUM *r;
269     BN_CTX *bn_ctx;
270     int ret = 0;
271 
272     if (B == NULL || N == NULL || (bn_ctx = BN_CTX_new()) == NULL)
273         return 0;
274 
275     if ((r = BN_new()) == NULL)
276         goto err;
277     /* Checks if B % N == 0 */
278     if (!BN_nnmod(r, B, N, bn_ctx))
279         goto err;
280     ret = !BN_is_zero(r);
281  err:
282     BN_CTX_free(bn_ctx);
283     BN_free(r);
284     return ret;
285 }
286 
SRP_Verify_A_mod_N(const BIGNUM * A,const BIGNUM * N)287 int SRP_Verify_A_mod_N(const BIGNUM *A, const BIGNUM *N)
288 {
289     /* Checks if A % N == 0 */
290     return SRP_Verify_B_mod_N(A, N);
291 }
292 
293 static SRP_gN knowngN[] = {
294     {"8192", &ossl_bn_generator_19, &ossl_bn_group_8192},
295     {"6144", &ossl_bn_generator_5, &ossl_bn_group_6144},
296     {"4096", &ossl_bn_generator_5, &ossl_bn_group_4096},
297     {"3072", &ossl_bn_generator_5, &ossl_bn_group_3072},
298     {"2048", &ossl_bn_generator_2, &ossl_bn_group_2048},
299     {"1536", &ossl_bn_generator_2, &ossl_bn_group_1536},
300     {"1024", &ossl_bn_generator_2, &ossl_bn_group_1024},
301 };
302 
303 # define KNOWN_GN_NUMBER sizeof(knowngN) / sizeof(SRP_gN)
304 
305 /*
306  * Check if G and N are known parameters. The values have been generated
307  * from the IETF RFC 5054
308  */
SRP_check_known_gN_param(const BIGNUM * g,const BIGNUM * N)309 char *SRP_check_known_gN_param(const BIGNUM *g, const BIGNUM *N)
310 {
311     size_t i;
312     if ((g == NULL) || (N == NULL))
313         return NULL;
314 
315     for (i = 0; i < KNOWN_GN_NUMBER; i++) {
316         if (BN_cmp(knowngN[i].g, g) == 0 && BN_cmp(knowngN[i].N, N) == 0)
317             return knowngN[i].id;
318     }
319     return NULL;
320 }
321 
SRP_get_default_gN(const char * id)322 SRP_gN *SRP_get_default_gN(const char *id)
323 {
324     size_t i;
325 
326     if (id == NULL)
327         return knowngN;
328     for (i = 0; i < KNOWN_GN_NUMBER; i++) {
329         if (strcmp(knowngN[i].id, id) == 0)
330             return knowngN + i;
331     }
332     return NULL;
333 }
334 #endif
335