]>
Commit | Line | Data |
---|---|---|
aa6bb135 | 1 | /* |
f11f86f6 | 2 | * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved. |
d02b48c6 | 3 | * |
e38873f5 | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
aa6bb135 RS |
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 | |
d02b48c6 RE |
8 | */ |
9 | ||
ada66e78 P |
10 | /* |
11 | * DH low level APIs are deprecated for public use, but still ok for | |
12 | * internal use. | |
13 | */ | |
14 | #include "internal/deprecated.h" | |
15 | ||
d02b48c6 | 16 | #include <stdio.h> |
b39fc560 | 17 | #include "internal/cryptlib.h" |
706457b7 | 18 | #include "dh_local.h" |
25f2138b | 19 | #include "crypto/bn.h" |
62f49b90 | 20 | #include "crypto/dh.h" |
738ee181 | 21 | #include "crypto/security_bits.h" |
d02b48c6 | 22 | |
f844f9eb | 23 | #ifdef FIPS_MODULE |
b03ec3b5 SL |
24 | # define MIN_STRENGTH 112 |
25 | #else | |
26 | # define MIN_STRENGTH 80 | |
27 | #endif | |
28 | ||
13066cee | 29 | static int generate_key(DH *dh); |
f971ccb2 | 30 | static int dh_bn_mod_exp(const DH *dh, BIGNUM *r, |
0f113f3e MC |
31 | const BIGNUM *a, const BIGNUM *p, |
32 | const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); | |
13066cee DSH |
33 | static int dh_init(DH *dh); |
34 | static int dh_finish(DH *dh); | |
35 | ||
8083fd3a | 36 | static int compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh) |
0f113f3e | 37 | { |
62f49b90 SL |
38 | BN_CTX *ctx = NULL; |
39 | BN_MONT_CTX *mont = NULL; | |
40 | BIGNUM *tmp; | |
41 | int ret = -1; | |
f844f9eb | 42 | #ifndef FIPS_MODULE |
62f49b90 SL |
43 | int check_result; |
44 | #endif | |
45 | ||
dc8de3e6 | 46 | if (BN_num_bits(dh->params.p) > OPENSSL_DH_MAX_MODULUS_BITS) { |
9311d0c4 | 47 | ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE); |
62f49b90 SL |
48 | goto err; |
49 | } | |
50 | ||
dc8de3e6 | 51 | if (BN_num_bits(dh->params.p) < DH_MIN_MODULUS_BITS) { |
9311d0c4 | 52 | ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_SMALL); |
62f49b90 SL |
53 | return 0; |
54 | } | |
55 | ||
8083fd3a | 56 | ctx = BN_CTX_new_ex(dh->libctx); |
62f49b90 SL |
57 | if (ctx == NULL) |
58 | goto err; | |
59 | BN_CTX_start(ctx); | |
60 | tmp = BN_CTX_get(ctx); | |
61 | if (tmp == NULL) | |
62 | goto err; | |
63 | ||
64 | if (dh->priv_key == NULL) { | |
9311d0c4 | 65 | ERR_raise(ERR_LIB_DH, DH_R_NO_PRIVATE_VALUE); |
62f49b90 SL |
66 | goto err; |
67 | } | |
68 | ||
69 | if (dh->flags & DH_FLAG_CACHE_MONT_P) { | |
70 | mont = BN_MONT_CTX_set_locked(&dh->method_mont_p, | |
dc8de3e6 | 71 | dh->lock, dh->params.p, ctx); |
62f49b90 SL |
72 | BN_set_flags(dh->priv_key, BN_FLG_CONSTTIME); |
73 | if (!mont) | |
74 | goto err; | |
75 | } | |
76 | /* TODO(3.0) : Solve in a PR related to Key validation for DH */ | |
f844f9eb | 77 | #ifndef FIPS_MODULE |
62f49b90 | 78 | if (!DH_check_pub_key(dh, pub_key, &check_result) || check_result) { |
9311d0c4 | 79 | ERR_raise(ERR_LIB_DH, DH_R_INVALID_PUBKEY); |
62f49b90 SL |
80 | goto err; |
81 | } | |
82 | #endif | |
dc8de3e6 | 83 | if (!dh->meth->bn_mod_exp(dh, tmp, pub_key, dh->priv_key, dh->params.p, ctx, |
62f49b90 | 84 | mont)) { |
9311d0c4 | 85 | ERR_raise(ERR_LIB_DH, ERR_R_BN_LIB); |
62f49b90 SL |
86 | goto err; |
87 | } | |
88 | ||
89 | ret = BN_bn2bin(tmp, key); | |
90 | err: | |
91 | BN_CTX_end(ctx); | |
92 | BN_CTX_free(ctx); | |
93 | return ret; | |
0f113f3e | 94 | } |
13066cee | 95 | |
8083fd3a | 96 | int DH_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh) |
0f113f3e | 97 | { |
f844f9eb | 98 | #ifdef FIPS_MODULE |
8083fd3a SL |
99 | return compute_key(key, pub_key, dh); |
100 | #else | |
101 | return dh->meth->compute_key(key, pub_key, dh); | |
102 | #endif | |
0f113f3e | 103 | } |
13066cee | 104 | |
8083fd3a | 105 | int DH_compute_key_padded(unsigned char *key, const BIGNUM *pub_key, DH *dh) |
0f113f3e MC |
106 | { |
107 | int rv, pad; | |
62f49b90 | 108 | |
f844f9eb | 109 | #ifdef FIPS_MODULE |
8083fd3a | 110 | rv = compute_key(key, pub_key, dh); |
62f49b90 | 111 | #else |
0f113f3e | 112 | rv = dh->meth->compute_key(key, pub_key, dh); |
62f49b90 | 113 | #endif |
0f113f3e MC |
114 | if (rv <= 0) |
115 | return rv; | |
dc8de3e6 | 116 | pad = BN_num_bytes(dh->params.p) - rv; |
0f113f3e MC |
117 | if (pad > 0) { |
118 | memmove(key + pad, key, rv); | |
119 | memset(key, 0, pad); | |
120 | } | |
121 | return rv + pad; | |
122 | } | |
bc91494e | 123 | |
13066cee | 124 | static DH_METHOD dh_ossl = { |
0f113f3e MC |
125 | "OpenSSL DH Method", |
126 | generate_key, | |
127 | compute_key, | |
128 | dh_bn_mod_exp, | |
129 | dh_init, | |
130 | dh_finish, | |
131 | DH_FLAG_FIPS_METHOD, | |
132 | NULL, | |
133 | NULL | |
13066cee DSH |
134 | }; |
135 | ||
076fc555 RS |
136 | static const DH_METHOD *default_DH_method = &dh_ossl; |
137 | ||
f971ccb2 | 138 | const DH_METHOD *DH_OpenSSL(void) |
13066cee | 139 | { |
0f113f3e | 140 | return &dh_ossl; |
13066cee DSH |
141 | } |
142 | ||
62f49b90 SL |
143 | const DH_METHOD *DH_get_default_method(void) |
144 | { | |
145 | return default_DH_method; | |
146 | } | |
147 | ||
148 | static int dh_bn_mod_exp(const DH *dh, BIGNUM *r, | |
149 | const BIGNUM *a, const BIGNUM *p, | |
150 | const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx) | |
151 | { | |
152 | return BN_mod_exp_mont(r, a, p, m, ctx, m_ctx); | |
153 | } | |
154 | ||
155 | static int dh_init(DH *dh) | |
156 | { | |
157 | dh->flags |= DH_FLAG_CACHE_MONT_P; | |
5357c106 | 158 | ossl_ffc_params_init(&dh->params); |
f11f86f6 | 159 | dh->dirty_cnt++; |
62f49b90 SL |
160 | return 1; |
161 | } | |
162 | ||
163 | static int dh_finish(DH *dh) | |
164 | { | |
165 | BN_MONT_CTX_free(dh->method_mont_p); | |
166 | return 1; | |
167 | } | |
168 | ||
f844f9eb | 169 | #ifndef FIPS_MODULE |
076fc555 RS |
170 | void DH_set_default_method(const DH_METHOD *meth) |
171 | { | |
172 | default_DH_method = meth; | |
173 | } | |
f844f9eb | 174 | #endif /* FIPS_MODULE */ |
076fc555 | 175 | |
62f49b90 | 176 | int DH_generate_key(DH *dh) |
076fc555 | 177 | { |
f844f9eb | 178 | #ifdef FIPS_MODULE |
8083fd3a SL |
179 | return generate_key(dh); |
180 | #else | |
62f49b90 | 181 | return dh->meth->generate_key(dh); |
8083fd3a | 182 | #endif |
076fc555 RS |
183 | } |
184 | ||
d1fb6b48 | 185 | int dh_generate_public_key(BN_CTX *ctx, const DH *dh, const BIGNUM *priv_key, |
8083fd3a SL |
186 | BIGNUM *pub_key) |
187 | { | |
188 | int ret = 0; | |
189 | BIGNUM *prk = BN_new(); | |
190 | BN_MONT_CTX *mont = NULL; | |
191 | ||
192 | if (prk == NULL) | |
193 | return 0; | |
194 | ||
195 | if (dh->flags & DH_FLAG_CACHE_MONT_P) { | |
d1fb6b48 NT |
196 | /* |
197 | * We take the input DH as const, but we lie, because in some cases we | |
198 | * want to get a hold of its Montgomery context. | |
199 | * | |
200 | * We cast to remove the const qualifier in this case, it should be | |
201 | * fine... | |
202 | */ | |
203 | BN_MONT_CTX **pmont = (BN_MONT_CTX **)&dh->method_mont_p; | |
204 | ||
205 | mont = BN_MONT_CTX_set_locked(pmont, dh->lock, dh->params.p, ctx); | |
8083fd3a SL |
206 | if (mont == NULL) |
207 | goto err; | |
208 | } | |
209 | BN_with_flags(prk, priv_key, BN_FLG_CONSTTIME); | |
210 | ||
211 | /* pub_key = g^priv_key mod p */ | |
212 | if (!dh->meth->bn_mod_exp(dh, pub_key, dh->params.g, prk, dh->params.p, | |
213 | ctx, mont)) | |
214 | goto err; | |
215 | ret = 1; | |
216 | err: | |
217 | BN_clear_free(prk); | |
218 | return ret; | |
219 | } | |
220 | ||
221 | static int generate_key(DH *dh) | |
0f113f3e MC |
222 | { |
223 | int ok = 0; | |
224 | int generate_new_key = 0; | |
f844f9eb | 225 | #ifndef FIPS_MODULE |
0f113f3e | 226 | unsigned l; |
f11f86f6 | 227 | #endif |
91f7361f | 228 | BN_CTX *ctx = NULL; |
0f113f3e | 229 | BIGNUM *pub_key = NULL, *priv_key = NULL; |
d02b48c6 | 230 | |
dc8de3e6 | 231 | if (BN_num_bits(dh->params.p) > OPENSSL_DH_MAX_MODULUS_BITS) { |
9311d0c4 | 232 | ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE); |
91f7361f GV |
233 | return 0; |
234 | } | |
235 | ||
dc8de3e6 | 236 | if (BN_num_bits(dh->params.p) < DH_MIN_MODULUS_BITS) { |
9311d0c4 | 237 | ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_SMALL); |
6de1fe90 BE |
238 | return 0; |
239 | } | |
240 | ||
8083fd3a | 241 | ctx = BN_CTX_new_ex(dh->libctx); |
0f113f3e MC |
242 | if (ctx == NULL) |
243 | goto err; | |
d02b48c6 | 244 | |
0f113f3e | 245 | if (dh->priv_key == NULL) { |
74924dcb | 246 | priv_key = BN_secure_new(); |
0f113f3e MC |
247 | if (priv_key == NULL) |
248 | goto err; | |
249 | generate_new_key = 1; | |
8083fd3a | 250 | } else { |
0f113f3e | 251 | priv_key = dh->priv_key; |
8083fd3a | 252 | } |
d02b48c6 | 253 | |
0f113f3e MC |
254 | if (dh->pub_key == NULL) { |
255 | pub_key = BN_new(); | |
256 | if (pub_key == NULL) | |
257 | goto err; | |
8083fd3a | 258 | } else { |
0f113f3e | 259 | pub_key = dh->pub_key; |
0f113f3e | 260 | } |
0f113f3e | 261 | if (generate_new_key) { |
f11f86f6 SL |
262 | /* Is it an approved safe prime ?*/ |
263 | if (DH_get_nid(dh) != NID_undef) { | |
738ee181 SL |
264 | int max_strength = |
265 | ifc_ffc_compute_security_bits(BN_num_bits(dh->params.p)); | |
266 | ||
55f02cb6 | 267 | if (dh->params.q == NULL |
f11f86f6 SL |
268 | || dh->length > BN_num_bits(dh->params.q)) |
269 | goto err; | |
738ee181 | 270 | /* dh->length = maximum bit length of generated private key */ |
5357c106 P |
271 | if (!ossl_ffc_generate_private_key(ctx, &dh->params, dh->length, |
272 | max_strength, priv_key)) | |
f11f86f6 SL |
273 | goto err; |
274 | } else { | |
f844f9eb | 275 | #ifdef FIPS_MODULE |
f11f86f6 SL |
276 | if (dh->params.q == NULL) |
277 | goto err; | |
278 | #else | |
279 | if (dh->params.q == NULL) { | |
28e1d588 RL |
280 | /* secret exponent length, must satisfy 2^(l-1) <= p */ |
281 | if (dh->length != 0 | |
282 | && dh->length >= BN_num_bits(dh->params.p)) | |
283 | goto err; | |
f11f86f6 SL |
284 | l = dh->length ? dh->length : BN_num_bits(dh->params.p) - 1; |
285 | if (!BN_priv_rand_ex(priv_key, l, BN_RAND_TOP_ONE, | |
286 | BN_RAND_BOTTOM_ANY, ctx)) | |
287 | goto err; | |
288 | /* | |
289 | * We handle just one known case where g is a quadratic non-residue: | |
290 | * for g = 2: p % 8 == 3 | |
291 | */ | |
292 | if (BN_is_word(dh->params.g, DH_GENERATOR_2) | |
293 | && !BN_is_bit_set(dh->params.p, 2)) { | |
294 | /* clear bit 0, since it won't be a secret anyway */ | |
295 | if (!BN_clear_bit(priv_key, 0)) | |
296 | goto err; | |
297 | } | |
298 | } else | |
299 | #endif | |
300 | { | |
63794b04 | 301 | /* Do a partial check for invalid p, q, g */ |
5357c106 P |
302 | if (!ossl_ffc_params_simple_validate(dh->libctx, &dh->params, |
303 | FFC_PARAM_TYPE_DH)) | |
63794b04 | 304 | goto err; |
f11f86f6 SL |
305 | /* |
306 | * For FFC FIPS 186-4 keygen | |
307 | * security strength s = 112, | |
308 | * Max Private key size N = len(q) | |
309 | */ | |
5357c106 P |
310 | if (!ossl_ffc_generate_private_key(ctx, &dh->params, |
311 | BN_num_bits(dh->params.q), | |
312 | MIN_STRENGTH, | |
313 | priv_key)) | |
a38c878c BE |
314 | goto err; |
315 | } | |
0f113f3e MC |
316 | } |
317 | } | |
dfeab068 | 318 | |
8083fd3a SL |
319 | if (!dh_generate_public_key(ctx, dh, priv_key, pub_key)) |
320 | goto err; | |
46a64376 | 321 | |
0f113f3e MC |
322 | dh->pub_key = pub_key; |
323 | dh->priv_key = priv_key; | |
8b84b075 | 324 | dh->dirty_cnt++; |
0f113f3e MC |
325 | ok = 1; |
326 | err: | |
327 | if (ok != 1) | |
9311d0c4 | 328 | ERR_raise(ERR_LIB_DH, ERR_R_BN_LIB); |
d02b48c6 | 329 | |
23a1d5e9 | 330 | if (pub_key != dh->pub_key) |
0f113f3e | 331 | BN_free(pub_key); |
23a1d5e9 | 332 | if (priv_key != dh->priv_key) |
0f113f3e MC |
333 | BN_free(priv_key); |
334 | BN_CTX_free(ctx); | |
26a7d938 | 335 | return ok; |
0f113f3e | 336 | } |
d02b48c6 | 337 | |
9aaecbfc | 338 | int dh_buf2key(DH *dh, const unsigned char *buf, size_t len) |
339 | { | |
340 | int err_reason = DH_R_BN_ERROR; | |
341 | BIGNUM *pubkey = NULL; | |
342 | const BIGNUM *p; | |
343 | size_t p_size; | |
344 | ||
345 | if ((pubkey = BN_bin2bn(buf, len, NULL)) == NULL) | |
346 | goto err; | |
347 | DH_get0_pqg(dh, &p, NULL, NULL); | |
348 | if (p == NULL || (p_size = BN_num_bytes(p)) == 0) { | |
349 | err_reason = DH_R_NO_PARAMETERS_SET; | |
350 | goto err; | |
351 | } | |
352 | /* | |
353 | * As per Section 4.2.8.1 of RFC 8446 fail if DHE's | |
354 | * public key is of size not equal to size of p | |
355 | */ | |
356 | if (BN_is_zero(pubkey) || p_size != len) { | |
357 | err_reason = DH_R_INVALID_PUBKEY; | |
358 | goto err; | |
359 | } | |
360 | if (DH_set0_key(dh, pubkey, NULL) != 1) | |
361 | goto err; | |
362 | return 1; | |
363 | err: | |
9311d0c4 | 364 | ERR_raise(ERR_LIB_DH, err_reason); |
9aaecbfc | 365 | BN_free(pubkey); |
366 | return 0; | |
367 | } | |
368 | ||
6a9bd929 | 369 | size_t dh_key2buf(const DH *dh, unsigned char **pbuf_out, size_t size, int alloc) |
9aaecbfc | 370 | { |
371 | const BIGNUM *pubkey; | |
6a9bd929 | 372 | unsigned char *pbuf = NULL; |
9aaecbfc | 373 | const BIGNUM *p; |
374 | int p_size; | |
375 | ||
376 | DH_get0_pqg(dh, &p, NULL, NULL); | |
377 | DH_get0_key(dh, &pubkey, NULL); | |
378 | if (p == NULL || pubkey == NULL | |
379 | || (p_size = BN_num_bytes(p)) == 0 | |
380 | || BN_num_bytes(pubkey) == 0) { | |
9311d0c4 | 381 | ERR_raise(ERR_LIB_DH, DH_R_INVALID_PUBKEY); |
9aaecbfc | 382 | return 0; |
383 | } | |
6a9bd929 MC |
384 | if (pbuf_out != NULL && (alloc || *pbuf_out != NULL)) { |
385 | if (!alloc) { | |
386 | if (size >= (size_t)p_size) | |
387 | pbuf = *pbuf_out; | |
388 | } else { | |
389 | pbuf = OPENSSL_malloc(p_size); | |
390 | } | |
391 | ||
392 | if (pbuf == NULL) { | |
9311d0c4 | 393 | ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE); |
6a9bd929 MC |
394 | return 0; |
395 | } | |
396 | /* | |
397 | * As per Section 4.2.8.1 of RFC 8446 left pad public | |
398 | * key with zeros to the size of p | |
399 | */ | |
400 | if (BN_bn2binpad(pubkey, pbuf, p_size) < 0) { | |
401 | if (alloc) | |
402 | OPENSSL_free(pbuf); | |
9311d0c4 | 403 | ERR_raise(ERR_LIB_DH, DH_R_BN_ERROR); |
6a9bd929 MC |
404 | return 0; |
405 | } | |
406 | *pbuf_out = pbuf; | |
9aaecbfc | 407 | } |
9aaecbfc | 408 | return p_size; |
409 | } |