xref: /freebsd/crypto/openssl/providers/implementations/exchange/dh_exch.c (revision e7be843b4a162e68651d3911f0357ed464915629)
1b077aed3SPierre Pronchery /*
2*e7be843bSPierre Pronchery  * Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved.
3b077aed3SPierre Pronchery  *
4b077aed3SPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5b077aed3SPierre Pronchery  * this file except in compliance with the License.  You can obtain a copy
6b077aed3SPierre Pronchery  * in the file LICENSE in the source distribution or at
7b077aed3SPierre Pronchery  * https://www.openssl.org/source/license.html
8b077aed3SPierre Pronchery  */
9b077aed3SPierre Pronchery 
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 
16b077aed3SPierre Pronchery #include <string.h>
17b077aed3SPierre Pronchery #include <openssl/crypto.h>
18b077aed3SPierre Pronchery #include <openssl/core_dispatch.h>
19b077aed3SPierre Pronchery #include <openssl/core_names.h>
20b077aed3SPierre Pronchery #include <openssl/dh.h>
21b077aed3SPierre Pronchery #include <openssl/err.h>
22b077aed3SPierre Pronchery #include <openssl/proverr.h>
23b077aed3SPierre Pronchery #include <openssl/params.h>
24b077aed3SPierre Pronchery #include "prov/providercommon.h"
25b077aed3SPierre Pronchery #include "prov/implementations.h"
26b077aed3SPierre Pronchery #include "prov/provider_ctx.h"
27b077aed3SPierre Pronchery #include "prov/securitycheck.h"
28b077aed3SPierre Pronchery #include "crypto/dh.h"
29b077aed3SPierre Pronchery 
30b077aed3SPierre Pronchery static OSSL_FUNC_keyexch_newctx_fn dh_newctx;
31b077aed3SPierre Pronchery static OSSL_FUNC_keyexch_init_fn dh_init;
32b077aed3SPierre Pronchery static OSSL_FUNC_keyexch_set_peer_fn dh_set_peer;
33b077aed3SPierre Pronchery static OSSL_FUNC_keyexch_derive_fn dh_derive;
34b077aed3SPierre Pronchery static OSSL_FUNC_keyexch_freectx_fn dh_freectx;
35b077aed3SPierre Pronchery static OSSL_FUNC_keyexch_dupctx_fn dh_dupctx;
36b077aed3SPierre Pronchery static OSSL_FUNC_keyexch_set_ctx_params_fn dh_set_ctx_params;
37b077aed3SPierre Pronchery static OSSL_FUNC_keyexch_settable_ctx_params_fn dh_settable_ctx_params;
38b077aed3SPierre Pronchery static OSSL_FUNC_keyexch_get_ctx_params_fn dh_get_ctx_params;
39b077aed3SPierre Pronchery static OSSL_FUNC_keyexch_gettable_ctx_params_fn dh_gettable_ctx_params;
40b077aed3SPierre Pronchery 
41b077aed3SPierre Pronchery /*
42b077aed3SPierre Pronchery  * This type is only really used to handle some legacy related functionality.
43b077aed3SPierre Pronchery  * If you need to use other KDF's (such as SSKDF) just use PROV_DH_KDF_NONE
44b077aed3SPierre Pronchery  * here and then create and run a KDF after the key is derived.
45b077aed3SPierre Pronchery  * Note that X942 has 2 variants of key derivation:
46b077aed3SPierre Pronchery  *   (1) DH_KDF_X9_42_ASN1 - which contains an ANS1 encoded object that has
47b077aed3SPierre Pronchery  *   the counter embedded in it.
48b077aed3SPierre Pronchery  *   (2) DH_KDF_X941_CONCAT - which is the same as ECDH_X963_KDF (which can be
49b077aed3SPierre Pronchery  *       done by creating a "X963KDF".
50b077aed3SPierre Pronchery  */
51b077aed3SPierre Pronchery enum kdf_type {
52b077aed3SPierre Pronchery     PROV_DH_KDF_NONE = 0,
53b077aed3SPierre Pronchery     PROV_DH_KDF_X9_42_ASN1
54b077aed3SPierre Pronchery };
55b077aed3SPierre Pronchery 
56b077aed3SPierre Pronchery /*
57b077aed3SPierre Pronchery  * What's passed as an actual key is defined by the KEYMGMT interface.
58b077aed3SPierre Pronchery  * We happen to know that our KEYMGMT simply passes DH structures, so
59b077aed3SPierre Pronchery  * we use that here too.
60b077aed3SPierre Pronchery  */
61b077aed3SPierre Pronchery 
62b077aed3SPierre Pronchery typedef struct {
63b077aed3SPierre Pronchery     OSSL_LIB_CTX *libctx;
64b077aed3SPierre Pronchery     DH *dh;
65b077aed3SPierre Pronchery     DH *dhpeer;
66b077aed3SPierre Pronchery     unsigned int pad : 1;
67b077aed3SPierre Pronchery 
68b077aed3SPierre Pronchery     /* DH KDF */
69b077aed3SPierre Pronchery     /* KDF (if any) to use for DH */
70b077aed3SPierre Pronchery     enum kdf_type kdf_type;
71b077aed3SPierre Pronchery     /* Message digest to use for key derivation */
72b077aed3SPierre Pronchery     EVP_MD *kdf_md;
73b077aed3SPierre Pronchery     /* User key material */
74b077aed3SPierre Pronchery     unsigned char *kdf_ukm;
75b077aed3SPierre Pronchery     size_t kdf_ukmlen;
76b077aed3SPierre Pronchery     /* KDF output length */
77b077aed3SPierre Pronchery     size_t kdf_outlen;
78b077aed3SPierre Pronchery     char *kdf_cekalg;
79*e7be843bSPierre Pronchery     OSSL_FIPS_IND_DECLARE
80b077aed3SPierre Pronchery } PROV_DH_CTX;
81b077aed3SPierre Pronchery 
dh_newctx(void * provctx)82b077aed3SPierre Pronchery static void *dh_newctx(void *provctx)
83b077aed3SPierre Pronchery {
84b077aed3SPierre Pronchery     PROV_DH_CTX *pdhctx;
85b077aed3SPierre Pronchery 
86b077aed3SPierre Pronchery     if (!ossl_prov_is_running())
87b077aed3SPierre Pronchery         return NULL;
88b077aed3SPierre Pronchery 
89b077aed3SPierre Pronchery     pdhctx = OPENSSL_zalloc(sizeof(PROV_DH_CTX));
90b077aed3SPierre Pronchery     if (pdhctx == NULL)
91b077aed3SPierre Pronchery         return NULL;
92*e7be843bSPierre Pronchery     OSSL_FIPS_IND_INIT(pdhctx)
93b077aed3SPierre Pronchery     pdhctx->libctx = PROV_LIBCTX_OF(provctx);
94b077aed3SPierre Pronchery     pdhctx->kdf_type = PROV_DH_KDF_NONE;
95b077aed3SPierre Pronchery     return pdhctx;
96b077aed3SPierre Pronchery }
97b077aed3SPierre Pronchery 
98*e7be843bSPierre Pronchery #ifdef FIPS_MODULE
dh_check_key(PROV_DH_CTX * ctx)99*e7be843bSPierre Pronchery static int dh_check_key(PROV_DH_CTX *ctx)
100*e7be843bSPierre Pronchery {
101*e7be843bSPierre Pronchery     int key_approved = ossl_dh_check_key(ctx->dh);
102*e7be843bSPierre Pronchery 
103*e7be843bSPierre Pronchery     if (!key_approved) {
104*e7be843bSPierre Pronchery         if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE0,
105*e7be843bSPierre Pronchery                                          ctx->libctx, "DH Init", "DH Key",
106*e7be843bSPierre Pronchery                                          ossl_fips_config_securitycheck_enabled)) {
107*e7be843bSPierre Pronchery             ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
108*e7be843bSPierre Pronchery             return 0;
109*e7be843bSPierre Pronchery         }
110*e7be843bSPierre Pronchery     }
111*e7be843bSPierre Pronchery     return 1;
112*e7be843bSPierre Pronchery }
113*e7be843bSPierre Pronchery 
digest_check(PROV_DH_CTX * ctx,const EVP_MD * md)114*e7be843bSPierre Pronchery static int digest_check(PROV_DH_CTX *ctx, const EVP_MD *md)
115*e7be843bSPierre Pronchery {
116*e7be843bSPierre Pronchery     return ossl_fips_ind_digest_exch_check(OSSL_FIPS_IND_GET(ctx),
117*e7be843bSPierre Pronchery                                            OSSL_FIPS_IND_SETTABLE1, ctx->libctx,
118*e7be843bSPierre Pronchery                                            md, "DH Set Ctx");
119*e7be843bSPierre Pronchery }
120*e7be843bSPierre Pronchery #endif
121*e7be843bSPierre Pronchery 
dh_init(void * vpdhctx,void * vdh,const OSSL_PARAM params[])122b077aed3SPierre Pronchery static int dh_init(void *vpdhctx, void *vdh, const OSSL_PARAM params[])
123b077aed3SPierre Pronchery {
124b077aed3SPierre Pronchery     PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
125b077aed3SPierre Pronchery 
126b077aed3SPierre Pronchery     if (!ossl_prov_is_running()
127b077aed3SPierre Pronchery             || pdhctx == NULL
128b077aed3SPierre Pronchery             || vdh == NULL
129b077aed3SPierre Pronchery             || !DH_up_ref(vdh))
130b077aed3SPierre Pronchery         return 0;
131b077aed3SPierre Pronchery     DH_free(pdhctx->dh);
132b077aed3SPierre Pronchery     pdhctx->dh = vdh;
133b077aed3SPierre Pronchery     pdhctx->kdf_type = PROV_DH_KDF_NONE;
134*e7be843bSPierre Pronchery 
135*e7be843bSPierre Pronchery     OSSL_FIPS_IND_SET_APPROVED(pdhctx)
136*e7be843bSPierre Pronchery     if (!dh_set_ctx_params(pdhctx, params))
137*e7be843bSPierre Pronchery         return 0;
138*e7be843bSPierre Pronchery #ifdef FIPS_MODULE
139*e7be843bSPierre Pronchery     if (!dh_check_key(pdhctx))
140*e7be843bSPierre Pronchery         return 0;
141*e7be843bSPierre Pronchery #endif
142*e7be843bSPierre Pronchery     return 1;
143b077aed3SPierre Pronchery }
144b077aed3SPierre Pronchery 
145b077aed3SPierre Pronchery /* The 2 parties must share the same domain parameters */
dh_match_params(DH * priv,DH * peer)146b077aed3SPierre Pronchery static int dh_match_params(DH *priv, DH *peer)
147b077aed3SPierre Pronchery {
148b077aed3SPierre Pronchery     int ret;
149b077aed3SPierre Pronchery     FFC_PARAMS *dhparams_priv = ossl_dh_get0_params(priv);
150b077aed3SPierre Pronchery     FFC_PARAMS *dhparams_peer = ossl_dh_get0_params(peer);
151b077aed3SPierre Pronchery 
152b077aed3SPierre Pronchery     ret = dhparams_priv != NULL
153b077aed3SPierre Pronchery           && dhparams_peer != NULL
154b077aed3SPierre Pronchery           && ossl_ffc_params_cmp(dhparams_priv, dhparams_peer, 1);
155b077aed3SPierre Pronchery     if (!ret)
156b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS);
157b077aed3SPierre Pronchery     return ret;
158b077aed3SPierre Pronchery }
159b077aed3SPierre Pronchery 
dh_set_peer(void * vpdhctx,void * vdh)160b077aed3SPierre Pronchery static int dh_set_peer(void *vpdhctx, void *vdh)
161b077aed3SPierre Pronchery {
162b077aed3SPierre Pronchery     PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
163b077aed3SPierre Pronchery 
164b077aed3SPierre Pronchery     if (!ossl_prov_is_running()
165b077aed3SPierre Pronchery             || pdhctx == NULL
166b077aed3SPierre Pronchery             || vdh == NULL
167b077aed3SPierre Pronchery             || !dh_match_params(vdh, pdhctx->dh)
168b077aed3SPierre Pronchery             || !DH_up_ref(vdh))
169b077aed3SPierre Pronchery         return 0;
170b077aed3SPierre Pronchery     DH_free(pdhctx->dhpeer);
171b077aed3SPierre Pronchery     pdhctx->dhpeer = vdh;
172b077aed3SPierre Pronchery     return 1;
173b077aed3SPierre Pronchery }
174b077aed3SPierre Pronchery 
dh_plain_derive(void * vpdhctx,unsigned char * secret,size_t * secretlen,size_t outlen,unsigned int pad)175b077aed3SPierre Pronchery static int dh_plain_derive(void *vpdhctx,
176b077aed3SPierre Pronchery                            unsigned char *secret, size_t *secretlen,
177b077aed3SPierre Pronchery                            size_t outlen, unsigned int pad)
178b077aed3SPierre Pronchery {
179b077aed3SPierre Pronchery     PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
180b077aed3SPierre Pronchery     int ret;
181b077aed3SPierre Pronchery     size_t dhsize;
182b077aed3SPierre Pronchery     const BIGNUM *pub_key = NULL;
183b077aed3SPierre Pronchery 
184b077aed3SPierre Pronchery     if (pdhctx->dh == NULL || pdhctx->dhpeer == NULL) {
185b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
186b077aed3SPierre Pronchery         return 0;
187b077aed3SPierre Pronchery     }
188b077aed3SPierre Pronchery 
189b077aed3SPierre Pronchery     dhsize = (size_t)DH_size(pdhctx->dh);
190b077aed3SPierre Pronchery     if (secret == NULL) {
191b077aed3SPierre Pronchery         *secretlen = dhsize;
192b077aed3SPierre Pronchery         return 1;
193b077aed3SPierre Pronchery     }
194b077aed3SPierre Pronchery     if (outlen < dhsize) {
195b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
196b077aed3SPierre Pronchery         return 0;
197b077aed3SPierre Pronchery     }
198b077aed3SPierre Pronchery 
199b077aed3SPierre Pronchery     DH_get0_key(pdhctx->dhpeer, &pub_key, NULL);
200b077aed3SPierre Pronchery     if (pad)
201b077aed3SPierre Pronchery         ret = DH_compute_key_padded(secret, pub_key, pdhctx->dh);
202b077aed3SPierre Pronchery     else
203b077aed3SPierre Pronchery         ret = DH_compute_key(secret, pub_key, pdhctx->dh);
204b077aed3SPierre Pronchery     if (ret <= 0)
205b077aed3SPierre Pronchery         return 0;
206b077aed3SPierre Pronchery 
207b077aed3SPierre Pronchery     *secretlen = ret;
208b077aed3SPierre Pronchery     return 1;
209b077aed3SPierre Pronchery }
210b077aed3SPierre Pronchery 
dh_X9_42_kdf_derive(void * vpdhctx,unsigned char * secret,size_t * secretlen,size_t outlen)211b077aed3SPierre Pronchery static int dh_X9_42_kdf_derive(void *vpdhctx, unsigned char *secret,
212b077aed3SPierre Pronchery                                size_t *secretlen, size_t outlen)
213b077aed3SPierre Pronchery {
214b077aed3SPierre Pronchery     PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
215b077aed3SPierre Pronchery     unsigned char *stmp = NULL;
216b077aed3SPierre Pronchery     size_t stmplen;
217b077aed3SPierre Pronchery     int ret = 0;
218b077aed3SPierre Pronchery 
219b077aed3SPierre Pronchery     if (secret == NULL) {
220b077aed3SPierre Pronchery         *secretlen = pdhctx->kdf_outlen;
221b077aed3SPierre Pronchery         return 1;
222b077aed3SPierre Pronchery     }
223b077aed3SPierre Pronchery 
224b077aed3SPierre Pronchery     if (pdhctx->kdf_outlen > outlen) {
225b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
226b077aed3SPierre Pronchery         return 0;
227b077aed3SPierre Pronchery     }
228b077aed3SPierre Pronchery     if (!dh_plain_derive(pdhctx, NULL, &stmplen, 0, 1))
229b077aed3SPierre Pronchery         return 0;
230*e7be843bSPierre Pronchery     if ((stmp = OPENSSL_secure_malloc(stmplen)) == NULL)
231b077aed3SPierre Pronchery         return 0;
232b077aed3SPierre Pronchery     if (!dh_plain_derive(pdhctx, stmp, &stmplen, stmplen, 1))
233b077aed3SPierre Pronchery         goto err;
234b077aed3SPierre Pronchery 
235b077aed3SPierre Pronchery     /* Do KDF stuff */
236b077aed3SPierre Pronchery     if (pdhctx->kdf_type == PROV_DH_KDF_X9_42_ASN1) {
237b077aed3SPierre Pronchery         if (!ossl_dh_kdf_X9_42_asn1(secret, pdhctx->kdf_outlen,
238b077aed3SPierre Pronchery                                     stmp, stmplen,
239b077aed3SPierre Pronchery                                     pdhctx->kdf_cekalg,
240b077aed3SPierre Pronchery                                     pdhctx->kdf_ukm,
241b077aed3SPierre Pronchery                                     pdhctx->kdf_ukmlen,
242b077aed3SPierre Pronchery                                     pdhctx->kdf_md,
243b077aed3SPierre Pronchery                                     pdhctx->libctx, NULL))
244b077aed3SPierre Pronchery             goto err;
245b077aed3SPierre Pronchery     }
246b077aed3SPierre Pronchery     *secretlen = pdhctx->kdf_outlen;
247b077aed3SPierre Pronchery     ret = 1;
248b077aed3SPierre Pronchery err:
249b077aed3SPierre Pronchery     OPENSSL_secure_clear_free(stmp, stmplen);
250b077aed3SPierre Pronchery     return ret;
251b077aed3SPierre Pronchery }
252b077aed3SPierre Pronchery 
dh_derive(void * vpdhctx,unsigned char * secret,size_t * psecretlen,size_t outlen)253b077aed3SPierre Pronchery static int dh_derive(void *vpdhctx, unsigned char *secret,
254b077aed3SPierre Pronchery                      size_t *psecretlen, size_t outlen)
255b077aed3SPierre Pronchery {
256b077aed3SPierre Pronchery     PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
257b077aed3SPierre Pronchery 
258b077aed3SPierre Pronchery     if (!ossl_prov_is_running())
259b077aed3SPierre Pronchery         return 0;
260b077aed3SPierre Pronchery 
261b077aed3SPierre Pronchery     switch (pdhctx->kdf_type) {
262b077aed3SPierre Pronchery         case PROV_DH_KDF_NONE:
263b077aed3SPierre Pronchery             return dh_plain_derive(pdhctx, secret, psecretlen, outlen,
264b077aed3SPierre Pronchery                                    pdhctx->pad);
265b077aed3SPierre Pronchery         case PROV_DH_KDF_X9_42_ASN1:
266b077aed3SPierre Pronchery             return dh_X9_42_kdf_derive(pdhctx, secret, psecretlen, outlen);
267b077aed3SPierre Pronchery         default:
268b077aed3SPierre Pronchery             break;
269b077aed3SPierre Pronchery     }
270b077aed3SPierre Pronchery     return 0;
271b077aed3SPierre Pronchery }
272b077aed3SPierre Pronchery 
dh_freectx(void * vpdhctx)273b077aed3SPierre Pronchery static void dh_freectx(void *vpdhctx)
274b077aed3SPierre Pronchery {
275b077aed3SPierre Pronchery     PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
276b077aed3SPierre Pronchery 
277b077aed3SPierre Pronchery     OPENSSL_free(pdhctx->kdf_cekalg);
278b077aed3SPierre Pronchery     DH_free(pdhctx->dh);
279b077aed3SPierre Pronchery     DH_free(pdhctx->dhpeer);
280b077aed3SPierre Pronchery     EVP_MD_free(pdhctx->kdf_md);
281b077aed3SPierre Pronchery     OPENSSL_clear_free(pdhctx->kdf_ukm, pdhctx->kdf_ukmlen);
282b077aed3SPierre Pronchery 
283b077aed3SPierre Pronchery     OPENSSL_free(pdhctx);
284b077aed3SPierre Pronchery }
285b077aed3SPierre Pronchery 
dh_dupctx(void * vpdhctx)286b077aed3SPierre Pronchery static void *dh_dupctx(void *vpdhctx)
287b077aed3SPierre Pronchery {
288b077aed3SPierre Pronchery     PROV_DH_CTX *srcctx = (PROV_DH_CTX *)vpdhctx;
289b077aed3SPierre Pronchery     PROV_DH_CTX *dstctx;
290b077aed3SPierre Pronchery 
291b077aed3SPierre Pronchery     if (!ossl_prov_is_running())
292b077aed3SPierre Pronchery         return NULL;
293b077aed3SPierre Pronchery 
294b077aed3SPierre Pronchery     dstctx = OPENSSL_zalloc(sizeof(*srcctx));
295b077aed3SPierre Pronchery     if (dstctx == NULL)
296b077aed3SPierre Pronchery         return NULL;
297b077aed3SPierre Pronchery 
298b077aed3SPierre Pronchery     *dstctx = *srcctx;
299b077aed3SPierre Pronchery     dstctx->dh = NULL;
300b077aed3SPierre Pronchery     dstctx->dhpeer = NULL;
301b077aed3SPierre Pronchery     dstctx->kdf_md = NULL;
302b077aed3SPierre Pronchery     dstctx->kdf_ukm = NULL;
303b077aed3SPierre Pronchery     dstctx->kdf_cekalg = NULL;
304b077aed3SPierre Pronchery 
305b077aed3SPierre Pronchery     if (srcctx->dh != NULL && !DH_up_ref(srcctx->dh))
306b077aed3SPierre Pronchery         goto err;
307b077aed3SPierre Pronchery     else
308b077aed3SPierre Pronchery         dstctx->dh = srcctx->dh;
309b077aed3SPierre Pronchery 
310b077aed3SPierre Pronchery     if (srcctx->dhpeer != NULL && !DH_up_ref(srcctx->dhpeer))
311b077aed3SPierre Pronchery         goto err;
312b077aed3SPierre Pronchery     else
313b077aed3SPierre Pronchery         dstctx->dhpeer = srcctx->dhpeer;
314b077aed3SPierre Pronchery 
315b077aed3SPierre Pronchery     if (srcctx->kdf_md != NULL && !EVP_MD_up_ref(srcctx->kdf_md))
316b077aed3SPierre Pronchery         goto err;
317b077aed3SPierre Pronchery     else
318b077aed3SPierre Pronchery         dstctx->kdf_md = srcctx->kdf_md;
319b077aed3SPierre Pronchery 
320b077aed3SPierre Pronchery     /* Duplicate UKM data if present */
321b077aed3SPierre Pronchery     if (srcctx->kdf_ukm != NULL && srcctx->kdf_ukmlen > 0) {
322b077aed3SPierre Pronchery         dstctx->kdf_ukm = OPENSSL_memdup(srcctx->kdf_ukm,
323b077aed3SPierre Pronchery                                          srcctx->kdf_ukmlen);
324b077aed3SPierre Pronchery         if (dstctx->kdf_ukm == NULL)
325b077aed3SPierre Pronchery             goto err;
326b077aed3SPierre Pronchery     }
327b077aed3SPierre Pronchery 
328b077aed3SPierre Pronchery     if (srcctx->kdf_cekalg != NULL) {
329b077aed3SPierre Pronchery         dstctx->kdf_cekalg = OPENSSL_strdup(srcctx->kdf_cekalg);
330b077aed3SPierre Pronchery         if (dstctx->kdf_cekalg == NULL)
331b077aed3SPierre Pronchery             goto err;
332b077aed3SPierre Pronchery     }
333b077aed3SPierre Pronchery 
334b077aed3SPierre Pronchery     return dstctx;
335b077aed3SPierre Pronchery err:
336b077aed3SPierre Pronchery     dh_freectx(dstctx);
337b077aed3SPierre Pronchery     return NULL;
338b077aed3SPierre Pronchery }
339b077aed3SPierre Pronchery 
dh_set_ctx_params(void * vpdhctx,const OSSL_PARAM params[])340b077aed3SPierre Pronchery static int dh_set_ctx_params(void *vpdhctx, const OSSL_PARAM params[])
341b077aed3SPierre Pronchery {
342b077aed3SPierre Pronchery     PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
343b077aed3SPierre Pronchery     const OSSL_PARAM *p;
344b077aed3SPierre Pronchery     unsigned int pad;
345b077aed3SPierre Pronchery     char name[80] = { '\0' }; /* should be big enough */
346b077aed3SPierre Pronchery     char *str = NULL;
347b077aed3SPierre Pronchery 
348b077aed3SPierre Pronchery     if (pdhctx == NULL)
349b077aed3SPierre Pronchery         return 0;
350*e7be843bSPierre Pronchery     if (ossl_param_is_empty(params))
351b077aed3SPierre Pronchery         return 1;
352b077aed3SPierre Pronchery 
353*e7be843bSPierre Pronchery     if (!OSSL_FIPS_IND_SET_CTX_PARAM(pdhctx, OSSL_FIPS_IND_SETTABLE0, params,
354*e7be843bSPierre Pronchery                                      OSSL_EXCHANGE_PARAM_FIPS_KEY_CHECK))
355*e7be843bSPierre Pronchery         return  0;
356*e7be843bSPierre Pronchery     if (!OSSL_FIPS_IND_SET_CTX_PARAM(pdhctx, OSSL_FIPS_IND_SETTABLE1, params,
357*e7be843bSPierre Pronchery                                      OSSL_EXCHANGE_PARAM_FIPS_DIGEST_CHECK))
358*e7be843bSPierre Pronchery         return  0;
359*e7be843bSPierre Pronchery 
360b077aed3SPierre Pronchery     p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_TYPE);
361b077aed3SPierre Pronchery     if (p != NULL) {
362b077aed3SPierre Pronchery         str = name;
363b077aed3SPierre Pronchery         if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name)))
364b077aed3SPierre Pronchery             return 0;
365b077aed3SPierre Pronchery 
366b077aed3SPierre Pronchery         if (name[0] == '\0')
367b077aed3SPierre Pronchery             pdhctx->kdf_type = PROV_DH_KDF_NONE;
368b077aed3SPierre Pronchery         else if (strcmp(name, OSSL_KDF_NAME_X942KDF_ASN1) == 0)
369b077aed3SPierre Pronchery             pdhctx->kdf_type = PROV_DH_KDF_X9_42_ASN1;
370b077aed3SPierre Pronchery         else
371b077aed3SPierre Pronchery             return 0;
372b077aed3SPierre Pronchery     }
373b077aed3SPierre Pronchery     p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST);
374b077aed3SPierre Pronchery     if (p != NULL) {
375b077aed3SPierre Pronchery         char mdprops[80] = { '\0' }; /* should be big enough */
376b077aed3SPierre Pronchery 
377b077aed3SPierre Pronchery         str = name;
378b077aed3SPierre Pronchery         if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name)))
379b077aed3SPierre Pronchery             return 0;
380b077aed3SPierre Pronchery 
381b077aed3SPierre Pronchery         str = mdprops;
382b077aed3SPierre Pronchery         p = OSSL_PARAM_locate_const(params,
383b077aed3SPierre Pronchery                                     OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS);
384b077aed3SPierre Pronchery 
385b077aed3SPierre Pronchery         if (p != NULL) {
386b077aed3SPierre Pronchery             if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops)))
387b077aed3SPierre Pronchery                 return 0;
388b077aed3SPierre Pronchery         }
389b077aed3SPierre Pronchery 
390b077aed3SPierre Pronchery         EVP_MD_free(pdhctx->kdf_md);
391b077aed3SPierre Pronchery         pdhctx->kdf_md = EVP_MD_fetch(pdhctx->libctx, name, mdprops);
392b077aed3SPierre Pronchery         if (pdhctx->kdf_md == NULL)
393b077aed3SPierre Pronchery             return 0;
394*e7be843bSPierre Pronchery         /* XOF digests are not allowed */
395*e7be843bSPierre Pronchery         if (EVP_MD_xof(pdhctx->kdf_md)) {
396*e7be843bSPierre Pronchery             ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED);
397*e7be843bSPierre Pronchery             return 0;
398*e7be843bSPierre Pronchery         }
399*e7be843bSPierre Pronchery #ifdef FIPS_MODULE
400*e7be843bSPierre Pronchery         if (!digest_check(pdhctx, pdhctx->kdf_md)) {
401*e7be843bSPierre Pronchery             EVP_MD_free(pdhctx->kdf_md);
402*e7be843bSPierre Pronchery             pdhctx->kdf_md = NULL;
403*e7be843bSPierre Pronchery             return 0;
404*e7be843bSPierre Pronchery         }
405*e7be843bSPierre Pronchery #endif
406b077aed3SPierre Pronchery     }
407b077aed3SPierre Pronchery 
408b077aed3SPierre Pronchery     p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN);
409b077aed3SPierre Pronchery     if (p != NULL) {
410b077aed3SPierre Pronchery         size_t outlen;
411b077aed3SPierre Pronchery 
412b077aed3SPierre Pronchery         if (!OSSL_PARAM_get_size_t(p, &outlen))
413b077aed3SPierre Pronchery             return 0;
414b077aed3SPierre Pronchery         pdhctx->kdf_outlen = outlen;
415b077aed3SPierre Pronchery     }
416b077aed3SPierre Pronchery 
417b077aed3SPierre Pronchery     p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_UKM);
418b077aed3SPierre Pronchery     if (p != NULL) {
419b077aed3SPierre Pronchery         void *tmp_ukm = NULL;
420b077aed3SPierre Pronchery         size_t tmp_ukmlen;
421b077aed3SPierre Pronchery 
422b077aed3SPierre Pronchery         OPENSSL_free(pdhctx->kdf_ukm);
423b077aed3SPierre Pronchery         pdhctx->kdf_ukm = NULL;
424b077aed3SPierre Pronchery         pdhctx->kdf_ukmlen = 0;
425b077aed3SPierre Pronchery         /* ukm is an optional field so it can be NULL */
426b077aed3SPierre Pronchery         if (p->data != NULL && p->data_size != 0) {
427b077aed3SPierre Pronchery             if (!OSSL_PARAM_get_octet_string(p, &tmp_ukm, 0, &tmp_ukmlen))
428b077aed3SPierre Pronchery                 return 0;
429b077aed3SPierre Pronchery             pdhctx->kdf_ukm = tmp_ukm;
430b077aed3SPierre Pronchery             pdhctx->kdf_ukmlen = tmp_ukmlen;
431b077aed3SPierre Pronchery         }
432b077aed3SPierre Pronchery     }
433b077aed3SPierre Pronchery 
434b077aed3SPierre Pronchery     p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_PAD);
435b077aed3SPierre Pronchery     if (p != NULL) {
436b077aed3SPierre Pronchery         if (!OSSL_PARAM_get_uint(p, &pad))
437b077aed3SPierre Pronchery             return 0;
438b077aed3SPierre Pronchery         pdhctx->pad = pad ? 1 : 0;
439b077aed3SPierre Pronchery     }
440b077aed3SPierre Pronchery 
441b077aed3SPierre Pronchery     p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_CEK_ALG);
442b077aed3SPierre Pronchery     if (p != NULL) {
443b077aed3SPierre Pronchery         str = name;
444b077aed3SPierre Pronchery 
445b077aed3SPierre Pronchery         OPENSSL_free(pdhctx->kdf_cekalg);
446b077aed3SPierre Pronchery         pdhctx->kdf_cekalg = NULL;
447b077aed3SPierre Pronchery         if (p->data != NULL && p->data_size != 0) {
448b077aed3SPierre Pronchery             if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name)))
449b077aed3SPierre Pronchery                 return 0;
450b077aed3SPierre Pronchery             pdhctx->kdf_cekalg = OPENSSL_strdup(name);
451b077aed3SPierre Pronchery             if (pdhctx->kdf_cekalg == NULL)
452b077aed3SPierre Pronchery                 return 0;
453b077aed3SPierre Pronchery         }
454b077aed3SPierre Pronchery     }
455b077aed3SPierre Pronchery     return 1;
456b077aed3SPierre Pronchery }
457b077aed3SPierre Pronchery 
458b077aed3SPierre Pronchery static const OSSL_PARAM known_settable_ctx_params[] = {
459b077aed3SPierre Pronchery     OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_PAD, NULL),
460b077aed3SPierre Pronchery     OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0),
461b077aed3SPierre Pronchery     OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0),
462b077aed3SPierre Pronchery     OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS, NULL, 0),
463b077aed3SPierre Pronchery     OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL),
464b077aed3SPierre Pronchery     OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM, NULL, 0),
465b077aed3SPierre Pronchery     OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG, NULL, 0),
466*e7be843bSPierre Pronchery     OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_EXCHANGE_PARAM_FIPS_KEY_CHECK)
467*e7be843bSPierre Pronchery     OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_EXCHANGE_PARAM_FIPS_DIGEST_CHECK)
468b077aed3SPierre Pronchery     OSSL_PARAM_END
469b077aed3SPierre Pronchery };
470b077aed3SPierre Pronchery 
dh_settable_ctx_params(ossl_unused void * vpdhctx,ossl_unused void * provctx)471b077aed3SPierre Pronchery static const OSSL_PARAM *dh_settable_ctx_params(ossl_unused void *vpdhctx,
472b077aed3SPierre Pronchery                                                 ossl_unused void *provctx)
473b077aed3SPierre Pronchery {
474b077aed3SPierre Pronchery     return known_settable_ctx_params;
475b077aed3SPierre Pronchery }
476b077aed3SPierre Pronchery 
477b077aed3SPierre Pronchery static const OSSL_PARAM known_gettable_ctx_params[] = {
478b077aed3SPierre Pronchery     OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0),
479b077aed3SPierre Pronchery     OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0),
480b077aed3SPierre Pronchery     OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL),
481b077aed3SPierre Pronchery     OSSL_PARAM_DEFN(OSSL_EXCHANGE_PARAM_KDF_UKM, OSSL_PARAM_OCTET_PTR,
482b077aed3SPierre Pronchery                     NULL, 0),
483b077aed3SPierre Pronchery     OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG, NULL, 0),
484*e7be843bSPierre Pronchery     OSSL_FIPS_IND_GETTABLE_CTX_PARAM()
485b077aed3SPierre Pronchery     OSSL_PARAM_END
486b077aed3SPierre Pronchery };
487b077aed3SPierre Pronchery 
dh_gettable_ctx_params(ossl_unused void * vpdhctx,ossl_unused void * provctx)488b077aed3SPierre Pronchery static const OSSL_PARAM *dh_gettable_ctx_params(ossl_unused void *vpdhctx,
489b077aed3SPierre Pronchery                                                 ossl_unused void *provctx)
490b077aed3SPierre Pronchery {
491b077aed3SPierre Pronchery     return known_gettable_ctx_params;
492b077aed3SPierre Pronchery }
493b077aed3SPierre Pronchery 
dh_get_ctx_params(void * vpdhctx,OSSL_PARAM params[])494b077aed3SPierre Pronchery static int dh_get_ctx_params(void *vpdhctx, OSSL_PARAM params[])
495b077aed3SPierre Pronchery {
496b077aed3SPierre Pronchery     PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;
497b077aed3SPierre Pronchery     OSSL_PARAM *p;
498b077aed3SPierre Pronchery 
499b077aed3SPierre Pronchery     if (pdhctx == NULL)
500b077aed3SPierre Pronchery         return 0;
501b077aed3SPierre Pronchery 
502b077aed3SPierre Pronchery     p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_TYPE);
503b077aed3SPierre Pronchery     if (p != NULL) {
504b077aed3SPierre Pronchery         const char *kdf_type = NULL;
505b077aed3SPierre Pronchery 
506b077aed3SPierre Pronchery         switch (pdhctx->kdf_type) {
507b077aed3SPierre Pronchery             case PROV_DH_KDF_NONE:
508b077aed3SPierre Pronchery                 kdf_type = "";
509b077aed3SPierre Pronchery                 break;
510b077aed3SPierre Pronchery             case PROV_DH_KDF_X9_42_ASN1:
511b077aed3SPierre Pronchery                 kdf_type = OSSL_KDF_NAME_X942KDF_ASN1;
512b077aed3SPierre Pronchery                 break;
513b077aed3SPierre Pronchery             default:
514b077aed3SPierre Pronchery                 return 0;
515b077aed3SPierre Pronchery         }
516b077aed3SPierre Pronchery 
517b077aed3SPierre Pronchery         if (!OSSL_PARAM_set_utf8_string(p, kdf_type))
518b077aed3SPierre Pronchery             return 0;
519b077aed3SPierre Pronchery     }
520b077aed3SPierre Pronchery 
521b077aed3SPierre Pronchery     p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST);
522b077aed3SPierre Pronchery     if (p != NULL
523b077aed3SPierre Pronchery             && !OSSL_PARAM_set_utf8_string(p, pdhctx->kdf_md == NULL
524b077aed3SPierre Pronchery                                            ? ""
525b077aed3SPierre Pronchery                                            : EVP_MD_get0_name(pdhctx->kdf_md))) {
526b077aed3SPierre Pronchery         return 0;
527b077aed3SPierre Pronchery     }
528b077aed3SPierre Pronchery 
529b077aed3SPierre Pronchery     p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN);
530b077aed3SPierre Pronchery     if (p != NULL && !OSSL_PARAM_set_size_t(p, pdhctx->kdf_outlen))
531b077aed3SPierre Pronchery         return 0;
532b077aed3SPierre Pronchery 
533b077aed3SPierre Pronchery     p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_UKM);
534b077aed3SPierre Pronchery     if (p != NULL
535b077aed3SPierre Pronchery         && !OSSL_PARAM_set_octet_ptr(p, pdhctx->kdf_ukm, pdhctx->kdf_ukmlen))
536b077aed3SPierre Pronchery         return 0;
537b077aed3SPierre Pronchery 
538b077aed3SPierre Pronchery     p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_CEK_ALG);
539b077aed3SPierre Pronchery     if (p != NULL
540b077aed3SPierre Pronchery             && !OSSL_PARAM_set_utf8_string(p, pdhctx->kdf_cekalg == NULL
541b077aed3SPierre Pronchery                                            ? "" :  pdhctx->kdf_cekalg))
542b077aed3SPierre Pronchery         return 0;
543*e7be843bSPierre Pronchery     if (!OSSL_FIPS_IND_GET_CTX_PARAM(pdhctx, params))
544*e7be843bSPierre Pronchery         return 0;
545b077aed3SPierre Pronchery     return 1;
546b077aed3SPierre Pronchery }
547b077aed3SPierre Pronchery 
548b077aed3SPierre Pronchery const OSSL_DISPATCH ossl_dh_keyexch_functions[] = {
549b077aed3SPierre Pronchery     { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))dh_newctx },
550b077aed3SPierre Pronchery     { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))dh_init },
551b077aed3SPierre Pronchery     { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))dh_derive },
552b077aed3SPierre Pronchery     { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))dh_set_peer },
553b077aed3SPierre Pronchery     { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))dh_freectx },
554b077aed3SPierre Pronchery     { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))dh_dupctx },
555b077aed3SPierre Pronchery     { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))dh_set_ctx_params },
556b077aed3SPierre Pronchery     { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS,
557b077aed3SPierre Pronchery       (void (*)(void))dh_settable_ctx_params },
558b077aed3SPierre Pronchery     { OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS, (void (*)(void))dh_get_ctx_params },
559b077aed3SPierre Pronchery     { OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS,
560b077aed3SPierre Pronchery       (void (*)(void))dh_gettable_ctx_params },
561*e7be843bSPierre Pronchery     OSSL_DISPATCH_END
562b077aed3SPierre Pronchery };
563