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