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