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