1e71b7053SJung-uk Kim /*
2ad991e4cSEd Maste * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
374664626SKris Kennaway *
4b077aed3SPierre Pronchery * Licensed under the Apache License 2.0 (the "License"). You may not use
5e71b7053SJung-uk Kim * this file except in compliance with the License. You can obtain a copy
6e71b7053SJung-uk Kim * in the file LICENSE in the source distribution or at
7e71b7053SJung-uk Kim * https://www.openssl.org/source/license.html
874664626SKris Kennaway */
974664626SKris Kennaway
10b077aed3SPierre Pronchery /*
11b077aed3SPierre Pronchery * DH low level APIs are deprecated for public use, but still ok for
12b077aed3SPierre Pronchery * internal use.
13b077aed3SPierre Pronchery */
14b077aed3SPierre Pronchery #include "internal/deprecated.h"
15b077aed3SPierre Pronchery
1674664626SKris Kennaway #include <stdio.h>
17e71b7053SJung-uk Kim #include "internal/cryptlib.h"
1817f01e99SJung-uk Kim #include "dh_local.h"
1917f01e99SJung-uk Kim #include "crypto/bn.h"
20b077aed3SPierre Pronchery #include "crypto/dh.h"
21b077aed3SPierre Pronchery #include "crypto/security_bits.h"
22b077aed3SPierre Pronchery
23b077aed3SPierre Pronchery #ifdef FIPS_MODULE
24b077aed3SPierre Pronchery # define MIN_STRENGTH 112
25b077aed3SPierre Pronchery #else
26b077aed3SPierre Pronchery # define MIN_STRENGTH 80
27b077aed3SPierre Pronchery #endif
2874664626SKris Kennaway
29f579bf8eSKris Kennaway static int generate_key(DH *dh);
305c87c606SMark Murray static int dh_bn_mod_exp(const DH *dh, BIGNUM *r,
315c87c606SMark Murray const BIGNUM *a, const BIGNUM *p,
326f9291ceSJung-uk Kim const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
33f579bf8eSKris Kennaway static int dh_init(DH *dh);
34f579bf8eSKris Kennaway static int dh_finish(DH *dh);
35f579bf8eSKris Kennaway
36b077aed3SPierre Pronchery /*
37b077aed3SPierre Pronchery * See SP800-56Ar3 Section 5.7.1.1
38b077aed3SPierre Pronchery * Finite Field Cryptography Diffie-Hellman (FFC DH) Primitive
39b077aed3SPierre Pronchery */
ossl_dh_compute_key(unsigned char * key,const BIGNUM * pub_key,DH * dh)40b077aed3SPierre Pronchery int ossl_dh_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh)
4174664626SKris Kennaway {
42b077aed3SPierre Pronchery BN_CTX *ctx = NULL;
43b077aed3SPierre Pronchery BN_MONT_CTX *mont = NULL;
44b077aed3SPierre Pronchery BIGNUM *z = NULL, *pminus1;
45b077aed3SPierre Pronchery int ret = -1;
46b077aed3SPierre Pronchery
47b077aed3SPierre Pronchery if (BN_num_bits(dh->params.p) > OPENSSL_DH_MAX_MODULUS_BITS) {
48b077aed3SPierre Pronchery ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE);
49b077aed3SPierre Pronchery goto err;
50b077aed3SPierre Pronchery }
51b077aed3SPierre Pronchery
52e0c4386eSCy Schubert if (dh->params.q != NULL
53e0c4386eSCy Schubert && BN_num_bits(dh->params.q) > OPENSSL_DH_MAX_MODULUS_BITS) {
54e0c4386eSCy Schubert ERR_raise(ERR_LIB_DH, DH_R_Q_TOO_LARGE);
55e0c4386eSCy Schubert goto err;
56e0c4386eSCy Schubert }
57e0c4386eSCy Schubert
58b077aed3SPierre Pronchery if (BN_num_bits(dh->params.p) < DH_MIN_MODULUS_BITS) {
59b077aed3SPierre Pronchery ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_SMALL);
60b077aed3SPierre Pronchery return 0;
61b077aed3SPierre Pronchery }
62b077aed3SPierre Pronchery
63b077aed3SPierre Pronchery ctx = BN_CTX_new_ex(dh->libctx);
64b077aed3SPierre Pronchery if (ctx == NULL)
65b077aed3SPierre Pronchery goto err;
66b077aed3SPierre Pronchery BN_CTX_start(ctx);
67b077aed3SPierre Pronchery pminus1 = BN_CTX_get(ctx);
68b077aed3SPierre Pronchery z = BN_CTX_get(ctx);
69b077aed3SPierre Pronchery if (z == NULL)
70b077aed3SPierre Pronchery goto err;
71b077aed3SPierre Pronchery
72b077aed3SPierre Pronchery if (dh->priv_key == NULL) {
73b077aed3SPierre Pronchery ERR_raise(ERR_LIB_DH, DH_R_NO_PRIVATE_VALUE);
74b077aed3SPierre Pronchery goto err;
75b077aed3SPierre Pronchery }
76b077aed3SPierre Pronchery
77b077aed3SPierre Pronchery if (dh->flags & DH_FLAG_CACHE_MONT_P) {
78b077aed3SPierre Pronchery mont = BN_MONT_CTX_set_locked(&dh->method_mont_p,
79b077aed3SPierre Pronchery dh->lock, dh->params.p, ctx);
80b077aed3SPierre Pronchery BN_set_flags(dh->priv_key, BN_FLG_CONSTTIME);
81b077aed3SPierre Pronchery if (!mont)
82b077aed3SPierre Pronchery goto err;
83b077aed3SPierre Pronchery }
84b077aed3SPierre Pronchery
85b077aed3SPierre Pronchery /* (Step 1) Z = pub_key^priv_key mod p */
86b077aed3SPierre Pronchery if (!dh->meth->bn_mod_exp(dh, z, pub_key, dh->priv_key, dh->params.p, ctx,
87b077aed3SPierre Pronchery mont)) {
88b077aed3SPierre Pronchery ERR_raise(ERR_LIB_DH, ERR_R_BN_LIB);
89b077aed3SPierre Pronchery goto err;
90b077aed3SPierre Pronchery }
91b077aed3SPierre Pronchery
92b077aed3SPierre Pronchery /* (Step 2) Error if z <= 1 or z = p - 1 */
93b077aed3SPierre Pronchery if (BN_copy(pminus1, dh->params.p) == NULL
94b077aed3SPierre Pronchery || !BN_sub_word(pminus1, 1)
95b077aed3SPierre Pronchery || BN_cmp(z, BN_value_one()) <= 0
96b077aed3SPierre Pronchery || BN_cmp(z, pminus1) == 0) {
97b077aed3SPierre Pronchery ERR_raise(ERR_LIB_DH, DH_R_INVALID_SECRET);
98b077aed3SPierre Pronchery goto err;
99b077aed3SPierre Pronchery }
100b077aed3SPierre Pronchery
101b077aed3SPierre Pronchery /* return the padded key, i.e. same number of bytes as the modulus */
102b077aed3SPierre Pronchery ret = BN_bn2binpad(z, key, BN_num_bytes(dh->params.p));
103b077aed3SPierre Pronchery err:
104b077aed3SPierre Pronchery BN_clear(z); /* (Step 2) destroy intermediate values */
105b077aed3SPierre Pronchery BN_CTX_end(ctx);
106b077aed3SPierre Pronchery BN_CTX_free(ctx);
107b077aed3SPierre Pronchery return ret;
108f579bf8eSKris Kennaway }
109f579bf8eSKris Kennaway
11088e852c0SJung-uk Kim /*-
11188e852c0SJung-uk Kim * NB: This function is inherently not constant time due to the
11288e852c0SJung-uk Kim * RFC 5246 (8.1.2) padding style that strips leading zero bytes.
11388e852c0SJung-uk Kim */
DH_compute_key(unsigned char * key,const BIGNUM * pub_key,DH * dh)1145c87c606SMark Murray int DH_compute_key(unsigned char *key, const BIGNUM *pub_key, DH *dh)
115f579bf8eSKris Kennaway {
11688e852c0SJung-uk Kim int ret = 0, i;
11788e852c0SJung-uk Kim volatile size_t npad = 0, mask = 1;
11888e852c0SJung-uk Kim
11988e852c0SJung-uk Kim /* compute the key; ret is constant unless compute_key is external */
120b077aed3SPierre Pronchery #ifdef FIPS_MODULE
121b077aed3SPierre Pronchery ret = ossl_dh_compute_key(key, pub_key, dh);
122b077aed3SPierre Pronchery #else
123b077aed3SPierre Pronchery ret = dh->meth->compute_key(key, pub_key, dh);
124b077aed3SPierre Pronchery #endif
125b077aed3SPierre Pronchery if (ret <= 0)
12688e852c0SJung-uk Kim return ret;
12788e852c0SJung-uk Kim
12888e852c0SJung-uk Kim /* count leading zero bytes, yet still touch all bytes */
12988e852c0SJung-uk Kim for (i = 0; i < ret; i++) {
13088e852c0SJung-uk Kim mask &= !key[i];
13188e852c0SJung-uk Kim npad += mask;
13288e852c0SJung-uk Kim }
13388e852c0SJung-uk Kim
13488e852c0SJung-uk Kim /* unpad key */
13588e852c0SJung-uk Kim ret -= npad;
13688e852c0SJung-uk Kim /* key-dependent memory access, potentially leaking npad / ret */
13788e852c0SJung-uk Kim memmove(key, key + npad, ret);
13888e852c0SJung-uk Kim /* key-dependent memory access, potentially leaking npad / ret */
13988e852c0SJung-uk Kim memset(key + ret, 0, npad);
14088e852c0SJung-uk Kim
14188e852c0SJung-uk Kim return ret;
142f579bf8eSKris Kennaway }
143f579bf8eSKris Kennaway
DH_compute_key_padded(unsigned char * key,const BIGNUM * pub_key,DH * dh)1447bded2dbSJung-uk Kim int DH_compute_key_padded(unsigned char *key, const BIGNUM *pub_key, DH *dh)
1457bded2dbSJung-uk Kim {
1467bded2dbSJung-uk Kim int rv, pad;
14788e852c0SJung-uk Kim
14888e852c0SJung-uk Kim /* rv is constant unless compute_key is external */
149b077aed3SPierre Pronchery #ifdef FIPS_MODULE
150b077aed3SPierre Pronchery rv = ossl_dh_compute_key(key, pub_key, dh);
151b077aed3SPierre Pronchery #else
1527bded2dbSJung-uk Kim rv = dh->meth->compute_key(key, pub_key, dh);
153b077aed3SPierre Pronchery #endif
1547bded2dbSJung-uk Kim if (rv <= 0)
1557bded2dbSJung-uk Kim return rv;
156b077aed3SPierre Pronchery pad = BN_num_bytes(dh->params.p) - rv;
15788e852c0SJung-uk Kim /* pad is constant (zero) unless compute_key is external */
1587bded2dbSJung-uk Kim if (pad > 0) {
1597bded2dbSJung-uk Kim memmove(key + pad, key, rv);
1607bded2dbSJung-uk Kim memset(key, 0, pad);
1617bded2dbSJung-uk Kim }
1627bded2dbSJung-uk Kim return rv + pad;
1637bded2dbSJung-uk Kim }
1647bded2dbSJung-uk Kim
165f579bf8eSKris Kennaway static DH_METHOD dh_ossl = {
166f579bf8eSKris Kennaway "OpenSSL DH Method",
167f579bf8eSKris Kennaway generate_key,
168b077aed3SPierre Pronchery ossl_dh_compute_key,
169f579bf8eSKris Kennaway dh_bn_mod_exp,
170f579bf8eSKris Kennaway dh_init,
171f579bf8eSKris Kennaway dh_finish,
172e71b7053SJung-uk Kim DH_FLAG_FIPS_METHOD,
1733b4e3dcbSSimon L. B. Nielsen NULL,
174f579bf8eSKris Kennaway NULL
175f579bf8eSKris Kennaway };
176f579bf8eSKris Kennaway
177e71b7053SJung-uk Kim static const DH_METHOD *default_DH_method = &dh_ossl;
178e71b7053SJung-uk Kim
DH_OpenSSL(void)1795c87c606SMark Murray const DH_METHOD *DH_OpenSSL(void)
180f579bf8eSKris Kennaway {
181f579bf8eSKris Kennaway return &dh_ossl;
182f579bf8eSKris Kennaway }
183f579bf8eSKris Kennaway
DH_get_default_method(void)184e71b7053SJung-uk Kim const DH_METHOD *DH_get_default_method(void)
185e71b7053SJung-uk Kim {
186e71b7053SJung-uk Kim return default_DH_method;
187e71b7053SJung-uk Kim }
188e71b7053SJung-uk Kim
dh_bn_mod_exp(const DH * dh,BIGNUM * r,const BIGNUM * a,const BIGNUM * p,const BIGNUM * m,BN_CTX * ctx,BN_MONT_CTX * m_ctx)1895c87c606SMark Murray static int dh_bn_mod_exp(const DH *dh, BIGNUM *r,
1905c87c606SMark Murray const BIGNUM *a, const BIGNUM *p,
1916f9291ceSJung-uk Kim const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx)
192f579bf8eSKris Kennaway {
193f579bf8eSKris Kennaway return BN_mod_exp_mont(r, a, p, m, ctx, m_ctx);
194f579bf8eSKris Kennaway }
195f579bf8eSKris Kennaway
dh_init(DH * dh)196f579bf8eSKris Kennaway static int dh_init(DH *dh)
197f579bf8eSKris Kennaway {
198f579bf8eSKris Kennaway dh->flags |= DH_FLAG_CACHE_MONT_P;
199b077aed3SPierre Pronchery dh->dirty_cnt++;
200e71b7053SJung-uk Kim return 1;
201f579bf8eSKris Kennaway }
202f579bf8eSKris Kennaway
dh_finish(DH * dh)203f579bf8eSKris Kennaway static int dh_finish(DH *dh)
204f579bf8eSKris Kennaway {
2053b4e3dcbSSimon L. B. Nielsen BN_MONT_CTX_free(dh->method_mont_p);
206e71b7053SJung-uk Kim return 1;
207f579bf8eSKris Kennaway }
208b077aed3SPierre Pronchery
209b077aed3SPierre Pronchery #ifndef FIPS_MODULE
DH_set_default_method(const DH_METHOD * meth)210b077aed3SPierre Pronchery void DH_set_default_method(const DH_METHOD *meth)
211b077aed3SPierre Pronchery {
212b077aed3SPierre Pronchery default_DH_method = meth;
213b077aed3SPierre Pronchery }
214b077aed3SPierre Pronchery #endif /* FIPS_MODULE */
215b077aed3SPierre Pronchery
DH_generate_key(DH * dh)216b077aed3SPierre Pronchery int DH_generate_key(DH *dh)
217b077aed3SPierre Pronchery {
218b077aed3SPierre Pronchery #ifdef FIPS_MODULE
219b077aed3SPierre Pronchery return generate_key(dh);
220b077aed3SPierre Pronchery #else
221b077aed3SPierre Pronchery return dh->meth->generate_key(dh);
222b077aed3SPierre Pronchery #endif
223b077aed3SPierre Pronchery }
224b077aed3SPierre Pronchery
ossl_dh_generate_public_key(BN_CTX * ctx,const DH * dh,const BIGNUM * priv_key,BIGNUM * pub_key)225b077aed3SPierre Pronchery int ossl_dh_generate_public_key(BN_CTX *ctx, const DH *dh,
226b077aed3SPierre Pronchery const BIGNUM *priv_key, BIGNUM *pub_key)
227b077aed3SPierre Pronchery {
228b077aed3SPierre Pronchery int ret = 0;
229b077aed3SPierre Pronchery BIGNUM *prk = BN_new();
230b077aed3SPierre Pronchery BN_MONT_CTX *mont = NULL;
231b077aed3SPierre Pronchery
232b077aed3SPierre Pronchery if (prk == NULL)
233b077aed3SPierre Pronchery return 0;
234b077aed3SPierre Pronchery
235b077aed3SPierre Pronchery if (dh->flags & DH_FLAG_CACHE_MONT_P) {
236b077aed3SPierre Pronchery /*
237b077aed3SPierre Pronchery * We take the input DH as const, but we lie, because in some cases we
238b077aed3SPierre Pronchery * want to get a hold of its Montgomery context.
239b077aed3SPierre Pronchery *
240b077aed3SPierre Pronchery * We cast to remove the const qualifier in this case, it should be
241b077aed3SPierre Pronchery * fine...
242b077aed3SPierre Pronchery */
243b077aed3SPierre Pronchery BN_MONT_CTX **pmont = (BN_MONT_CTX **)&dh->method_mont_p;
244b077aed3SPierre Pronchery
245b077aed3SPierre Pronchery mont = BN_MONT_CTX_set_locked(pmont, dh->lock, dh->params.p, ctx);
246b077aed3SPierre Pronchery if (mont == NULL)
247b077aed3SPierre Pronchery goto err;
248b077aed3SPierre Pronchery }
249b077aed3SPierre Pronchery BN_with_flags(prk, priv_key, BN_FLG_CONSTTIME);
250b077aed3SPierre Pronchery
251b077aed3SPierre Pronchery /* pub_key = g^priv_key mod p */
252b077aed3SPierre Pronchery if (!dh->meth->bn_mod_exp(dh, pub_key, dh->params.g, prk, dh->params.p,
253b077aed3SPierre Pronchery ctx, mont))
254b077aed3SPierre Pronchery goto err;
255b077aed3SPierre Pronchery ret = 1;
256b077aed3SPierre Pronchery err:
257b077aed3SPierre Pronchery BN_clear_free(prk);
258b077aed3SPierre Pronchery return ret;
259b077aed3SPierre Pronchery }
260b077aed3SPierre Pronchery
generate_key(DH * dh)261b077aed3SPierre Pronchery static int generate_key(DH *dh)
262b077aed3SPierre Pronchery {
263b077aed3SPierre Pronchery int ok = 0;
264b077aed3SPierre Pronchery int generate_new_key = 0;
265b077aed3SPierre Pronchery #ifndef FIPS_MODULE
266b077aed3SPierre Pronchery unsigned l;
267b077aed3SPierre Pronchery #endif
268b077aed3SPierre Pronchery BN_CTX *ctx = NULL;
269b077aed3SPierre Pronchery BIGNUM *pub_key = NULL, *priv_key = NULL;
270b077aed3SPierre Pronchery
271b077aed3SPierre Pronchery if (BN_num_bits(dh->params.p) > OPENSSL_DH_MAX_MODULUS_BITS) {
272b077aed3SPierre Pronchery ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE);
273b077aed3SPierre Pronchery return 0;
274b077aed3SPierre Pronchery }
275b077aed3SPierre Pronchery
276e0c4386eSCy Schubert if (dh->params.q != NULL
277e0c4386eSCy Schubert && BN_num_bits(dh->params.q) > OPENSSL_DH_MAX_MODULUS_BITS) {
278e0c4386eSCy Schubert ERR_raise(ERR_LIB_DH, DH_R_Q_TOO_LARGE);
279e0c4386eSCy Schubert return 0;
280e0c4386eSCy Schubert }
281e0c4386eSCy Schubert
282b077aed3SPierre Pronchery if (BN_num_bits(dh->params.p) < DH_MIN_MODULUS_BITS) {
283b077aed3SPierre Pronchery ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_SMALL);
284b077aed3SPierre Pronchery return 0;
285b077aed3SPierre Pronchery }
286b077aed3SPierre Pronchery
287b077aed3SPierre Pronchery ctx = BN_CTX_new_ex(dh->libctx);
288b077aed3SPierre Pronchery if (ctx == NULL)
289b077aed3SPierre Pronchery goto err;
290b077aed3SPierre Pronchery
291b077aed3SPierre Pronchery if (dh->priv_key == NULL) {
292b077aed3SPierre Pronchery priv_key = BN_secure_new();
293b077aed3SPierre Pronchery if (priv_key == NULL)
294b077aed3SPierre Pronchery goto err;
295b077aed3SPierre Pronchery generate_new_key = 1;
296b077aed3SPierre Pronchery } else {
297b077aed3SPierre Pronchery priv_key = dh->priv_key;
298b077aed3SPierre Pronchery }
299b077aed3SPierre Pronchery
300b077aed3SPierre Pronchery if (dh->pub_key == NULL) {
301b077aed3SPierre Pronchery pub_key = BN_new();
302b077aed3SPierre Pronchery if (pub_key == NULL)
303b077aed3SPierre Pronchery goto err;
304b077aed3SPierre Pronchery } else {
305b077aed3SPierre Pronchery pub_key = dh->pub_key;
306b077aed3SPierre Pronchery }
307b077aed3SPierre Pronchery if (generate_new_key) {
308b077aed3SPierre Pronchery /* Is it an approved safe prime ?*/
309b077aed3SPierre Pronchery if (DH_get_nid(dh) != NID_undef) {
310b077aed3SPierre Pronchery int max_strength =
311b077aed3SPierre Pronchery ossl_ifc_ffc_compute_security_bits(BN_num_bits(dh->params.p));
312b077aed3SPierre Pronchery
313b077aed3SPierre Pronchery if (dh->params.q == NULL
314b077aed3SPierre Pronchery || dh->length > BN_num_bits(dh->params.q))
315b077aed3SPierre Pronchery goto err;
316b077aed3SPierre Pronchery /* dh->length = maximum bit length of generated private key */
317b077aed3SPierre Pronchery if (!ossl_ffc_generate_private_key(ctx, &dh->params, dh->length,
318b077aed3SPierre Pronchery max_strength, priv_key))
319b077aed3SPierre Pronchery goto err;
320b077aed3SPierre Pronchery } else {
321b077aed3SPierre Pronchery #ifdef FIPS_MODULE
322b077aed3SPierre Pronchery if (dh->params.q == NULL)
323b077aed3SPierre Pronchery goto err;
324b077aed3SPierre Pronchery #else
325b077aed3SPierre Pronchery if (dh->params.q == NULL) {
326b077aed3SPierre Pronchery /* secret exponent length, must satisfy 2^(l-1) <= p */
327b077aed3SPierre Pronchery if (dh->length != 0
328b077aed3SPierre Pronchery && dh->length >= BN_num_bits(dh->params.p))
329b077aed3SPierre Pronchery goto err;
330b077aed3SPierre Pronchery l = dh->length ? dh->length : BN_num_bits(dh->params.p) - 1;
331b077aed3SPierre Pronchery if (!BN_priv_rand_ex(priv_key, l, BN_RAND_TOP_ONE,
332b077aed3SPierre Pronchery BN_RAND_BOTTOM_ANY, 0, ctx))
333b077aed3SPierre Pronchery goto err;
334b077aed3SPierre Pronchery /*
335b077aed3SPierre Pronchery * We handle just one known case where g is a quadratic non-residue:
336b077aed3SPierre Pronchery * for g = 2: p % 8 == 3
337b077aed3SPierre Pronchery */
338b077aed3SPierre Pronchery if (BN_is_word(dh->params.g, DH_GENERATOR_2)
339b077aed3SPierre Pronchery && !BN_is_bit_set(dh->params.p, 2)) {
340b077aed3SPierre Pronchery /* clear bit 0, since it won't be a secret anyway */
341b077aed3SPierre Pronchery if (!BN_clear_bit(priv_key, 0))
342b077aed3SPierre Pronchery goto err;
343b077aed3SPierre Pronchery }
344b077aed3SPierre Pronchery } else
345b077aed3SPierre Pronchery #endif
346b077aed3SPierre Pronchery {
347b077aed3SPierre Pronchery /* Do a partial check for invalid p, q, g */
348b077aed3SPierre Pronchery if (!ossl_ffc_params_simple_validate(dh->libctx, &dh->params,
349b077aed3SPierre Pronchery FFC_PARAM_TYPE_DH, NULL))
350b077aed3SPierre Pronchery goto err;
351b077aed3SPierre Pronchery /*
352b077aed3SPierre Pronchery * For FFC FIPS 186-4 keygen
353b077aed3SPierre Pronchery * security strength s = 112,
354b077aed3SPierre Pronchery * Max Private key size N = len(q)
355b077aed3SPierre Pronchery */
356b077aed3SPierre Pronchery if (!ossl_ffc_generate_private_key(ctx, &dh->params,
357b077aed3SPierre Pronchery BN_num_bits(dh->params.q),
358b077aed3SPierre Pronchery MIN_STRENGTH,
359b077aed3SPierre Pronchery priv_key))
360b077aed3SPierre Pronchery goto err;
361b077aed3SPierre Pronchery }
362b077aed3SPierre Pronchery }
363b077aed3SPierre Pronchery }
364b077aed3SPierre Pronchery
365b077aed3SPierre Pronchery if (!ossl_dh_generate_public_key(ctx, dh, priv_key, pub_key))
366b077aed3SPierre Pronchery goto err;
367b077aed3SPierre Pronchery
368b077aed3SPierre Pronchery dh->pub_key = pub_key;
369b077aed3SPierre Pronchery dh->priv_key = priv_key;
370b077aed3SPierre Pronchery dh->dirty_cnt++;
371b077aed3SPierre Pronchery ok = 1;
372b077aed3SPierre Pronchery err:
373b077aed3SPierre Pronchery if (ok != 1)
374b077aed3SPierre Pronchery ERR_raise(ERR_LIB_DH, ERR_R_BN_LIB);
375b077aed3SPierre Pronchery
376b077aed3SPierre Pronchery if (pub_key != dh->pub_key)
377b077aed3SPierre Pronchery BN_free(pub_key);
378b077aed3SPierre Pronchery if (priv_key != dh->priv_key)
379b077aed3SPierre Pronchery BN_free(priv_key);
380b077aed3SPierre Pronchery BN_CTX_free(ctx);
381b077aed3SPierre Pronchery return ok;
382b077aed3SPierre Pronchery }
383b077aed3SPierre Pronchery
ossl_dh_buf2key(DH * dh,const unsigned char * buf,size_t len)384b077aed3SPierre Pronchery int ossl_dh_buf2key(DH *dh, const unsigned char *buf, size_t len)
385b077aed3SPierre Pronchery {
386b077aed3SPierre Pronchery int err_reason = DH_R_BN_ERROR;
387b077aed3SPierre Pronchery BIGNUM *pubkey = NULL;
388b077aed3SPierre Pronchery const BIGNUM *p;
389b077aed3SPierre Pronchery int ret;
390b077aed3SPierre Pronchery
391b077aed3SPierre Pronchery if ((pubkey = BN_bin2bn(buf, len, NULL)) == NULL)
392b077aed3SPierre Pronchery goto err;
393b077aed3SPierre Pronchery DH_get0_pqg(dh, &p, NULL, NULL);
394b077aed3SPierre Pronchery if (p == NULL || BN_num_bytes(p) == 0) {
395b077aed3SPierre Pronchery err_reason = DH_R_NO_PARAMETERS_SET;
396b077aed3SPierre Pronchery goto err;
397b077aed3SPierre Pronchery }
398b077aed3SPierre Pronchery /* Prevent small subgroup attacks per RFC 8446 Section 4.2.8.1 */
399b077aed3SPierre Pronchery if (!ossl_dh_check_pub_key_partial(dh, pubkey, &ret)) {
400b077aed3SPierre Pronchery err_reason = DH_R_INVALID_PUBKEY;
401b077aed3SPierre Pronchery goto err;
402b077aed3SPierre Pronchery }
403b077aed3SPierre Pronchery if (DH_set0_key(dh, pubkey, NULL) != 1)
404b077aed3SPierre Pronchery goto err;
405b077aed3SPierre Pronchery return 1;
406b077aed3SPierre Pronchery err:
407b077aed3SPierre Pronchery ERR_raise(ERR_LIB_DH, err_reason);
408b077aed3SPierre Pronchery BN_free(pubkey);
409b077aed3SPierre Pronchery return 0;
410b077aed3SPierre Pronchery }
411b077aed3SPierre Pronchery
ossl_dh_key2buf(const DH * dh,unsigned char ** pbuf_out,size_t size,int alloc)412b077aed3SPierre Pronchery size_t ossl_dh_key2buf(const DH *dh, unsigned char **pbuf_out, size_t size,
413b077aed3SPierre Pronchery int alloc)
414b077aed3SPierre Pronchery {
415b077aed3SPierre Pronchery const BIGNUM *pubkey;
416b077aed3SPierre Pronchery unsigned char *pbuf = NULL;
417b077aed3SPierre Pronchery const BIGNUM *p;
418b077aed3SPierre Pronchery int p_size;
419b077aed3SPierre Pronchery
420b077aed3SPierre Pronchery DH_get0_pqg(dh, &p, NULL, NULL);
421b077aed3SPierre Pronchery DH_get0_key(dh, &pubkey, NULL);
422b077aed3SPierre Pronchery if (p == NULL || pubkey == NULL
423b077aed3SPierre Pronchery || (p_size = BN_num_bytes(p)) == 0
424b077aed3SPierre Pronchery || BN_num_bytes(pubkey) == 0) {
425b077aed3SPierre Pronchery ERR_raise(ERR_LIB_DH, DH_R_INVALID_PUBKEY);
426b077aed3SPierre Pronchery return 0;
427b077aed3SPierre Pronchery }
428b077aed3SPierre Pronchery if (pbuf_out != NULL && (alloc || *pbuf_out != NULL)) {
429b077aed3SPierre Pronchery if (!alloc) {
430b077aed3SPierre Pronchery if (size >= (size_t)p_size)
431b077aed3SPierre Pronchery pbuf = *pbuf_out;
432b077aed3SPierre Pronchery } else {
433b077aed3SPierre Pronchery pbuf = OPENSSL_malloc(p_size);
434b077aed3SPierre Pronchery }
435b077aed3SPierre Pronchery
436b077aed3SPierre Pronchery if (pbuf == NULL) {
437b077aed3SPierre Pronchery ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE);
438b077aed3SPierre Pronchery return 0;
439b077aed3SPierre Pronchery }
440b077aed3SPierre Pronchery /*
441b077aed3SPierre Pronchery * As per Section 4.2.8.1 of RFC 8446 left pad public
442b077aed3SPierre Pronchery * key with zeros to the size of p
443b077aed3SPierre Pronchery */
444b077aed3SPierre Pronchery if (BN_bn2binpad(pubkey, pbuf, p_size) < 0) {
445b077aed3SPierre Pronchery if (alloc)
446b077aed3SPierre Pronchery OPENSSL_free(pbuf);
447b077aed3SPierre Pronchery ERR_raise(ERR_LIB_DH, DH_R_BN_ERROR);
448b077aed3SPierre Pronchery return 0;
449b077aed3SPierre Pronchery }
450b077aed3SPierre Pronchery *pbuf_out = pbuf;
451b077aed3SPierre Pronchery }
452b077aed3SPierre Pronchery return p_size;
453b077aed3SPierre Pronchery }
454