xref: /freebsd/crypto/openssl/crypto/dh/dh_key.c (revision e0c4386e)
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