2 * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved.
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
11 * The following implementation is part of RFC 9180 related to DHKEM using
12 * ECX keys (i.e. X25519 and X448)
13 * References to Sections in the comments below refer to RFC 9180.
16 #include "internal/deprecated.h"
19 #include <openssl/crypto.h>
20 #include <openssl/evp.h>
21 #include <openssl/core_dispatch.h>
22 #include <openssl/core_names.h>
23 #include <openssl/params.h>
24 #include <openssl/kdf.h>
25 #include <openssl/err.h>
26 #include <openssl/sha.h>
27 #include <openssl/rand.h>
28 #include <openssl/proverr.h>
29 #include "prov/provider_ctx.h"
30 #include "prov/implementations.h"
31 #include "prov/securitycheck.h"
32 #include "prov/providercommon.h"
34 #include "crypto/ecx.h"
35 #include <openssl/hpke.h>
36 #include "internal/hpke_util.h"
39 #define MAX_ECX_KEYLEN X448_KEYLEN
41 /* KEM identifiers from Section 7.1 "Table 2 KEM IDs" */
42 #define KEMID_X25519_HKDF_SHA256 0x20
43 #define KEMID_X448_HKDF_SHA512 0x21
45 /* ASCII: "KEM", in hex for EBCDIC compatibility */
46 static const char LABEL_KEM
[] = "\x4b\x45\x4d";
49 ECX_KEY
*recipient_key
;
50 ECX_KEY
*sender_authkey
;
58 const OSSL_HPKE_KEM_INFO
*info
;
61 static OSSL_FUNC_kem_newctx_fn ecxkem_newctx
;
62 static OSSL_FUNC_kem_encapsulate_init_fn ecxkem_encapsulate_init
;
63 static OSSL_FUNC_kem_encapsulate_fn ecxkem_encapsulate
;
64 static OSSL_FUNC_kem_decapsulate_init_fn ecxkem_decapsulate_init
;
65 static OSSL_FUNC_kem_decapsulate_fn ecxkem_decapsulate
;
66 static OSSL_FUNC_kem_freectx_fn ecxkem_freectx
;
67 static OSSL_FUNC_kem_set_ctx_params_fn ecxkem_set_ctx_params
;
68 static OSSL_FUNC_kem_auth_encapsulate_init_fn ecxkem_auth_encapsulate_init
;
69 static OSSL_FUNC_kem_auth_decapsulate_init_fn ecxkem_auth_decapsulate_init
;
72 * Set KEM values as specified in Section 7.1 "Table 2 KEM IDs"
73 * There is only one set of values for X25519 and X448.
74 * Additional values could be set via set_params if required.
76 static const OSSL_HPKE_KEM_INFO
*get_kem_info(ECX_KEY
*ecx
)
78 const char *name
= NULL
;
80 if (ecx
->type
== ECX_KEY_TYPE_X25519
)
84 return ossl_HPKE_KEM_INFO_find_curve(name
);
88 * Set the recipient key, and free any existing key.
89 * ecx can be NULL. The ecx key may have only a private or public component.
91 static int recipient_key_set(PROV_ECX_CTX
*ctx
, ECX_KEY
*ecx
)
93 ossl_ecx_key_free(ctx
->recipient_key
);
94 ctx
->recipient_key
= NULL
;
96 ctx
->info
= get_kem_info(ecx
);
97 if (ctx
->info
== NULL
)
99 ctx
->kdfname
= "HKDF";
100 if (!ossl_ecx_key_up_ref(ecx
))
102 ctx
->recipient_key
= ecx
;
108 * Set the senders auth key, and free any existing auth key.
111 static int sender_authkey_set(PROV_ECX_CTX
*ctx
, ECX_KEY
*ecx
)
113 ossl_ecx_key_free(ctx
->sender_authkey
);
114 ctx
->sender_authkey
= NULL
;
117 if (!ossl_ecx_key_up_ref(ecx
))
119 ctx
->sender_authkey
= ecx
;
125 * Serialize a public key from byte array's for the encoded public keys.
126 * ctx is used to access the key type.
127 * Returns: The created ECX_KEY or NULL on error.
129 static ECX_KEY
*ecxkey_pubfromdata(PROV_ECX_CTX
*ctx
,
130 const unsigned char *pubbuf
, size_t pubbuflen
)
133 OSSL_PARAM params
[2], *p
= params
;
135 *p
++ = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY
,
136 (char *)pubbuf
, pubbuflen
);
137 *p
= OSSL_PARAM_construct_end();
139 ecx
= ossl_ecx_key_new(ctx
->libctx
, ctx
->recipient_key
->type
, 1, ctx
->propq
);
142 if (ossl_ecx_key_fromdata(ecx
, params
, 0) <= 0) {
143 ossl_ecx_key_free(ecx
);
149 static unsigned char *ecx_pubkey(ECX_KEY
*ecx
)
151 if (ecx
== NULL
|| !ecx
->haspubkey
) {
152 ERR_raise(ERR_LIB_PROV
, PROV_R_NOT_A_PUBLIC_KEY
);
158 static void *ecxkem_newctx(void *provctx
)
160 PROV_ECX_CTX
*ctx
= OPENSSL_zalloc(sizeof(PROV_ECX_CTX
));
164 ctx
->libctx
= PROV_LIBCTX_OF(provctx
);
169 static void ecxkem_freectx(void *vectx
)
171 PROV_ECX_CTX
*ctx
= (PROV_ECX_CTX
*)vectx
;
173 OPENSSL_clear_free(ctx
->ikm
, ctx
->ikmlen
);
174 recipient_key_set(ctx
, NULL
);
175 sender_authkey_set(ctx
, NULL
);
179 static int ecx_match_params(const ECX_KEY
*key1
, const ECX_KEY
*key2
)
181 return (key1
->type
== key2
->type
&& key1
->keylen
== key2
->keylen
);
184 static int ecx_key_check(const ECX_KEY
*ecx
, int requires_privatekey
)
186 if (ecx
->privkey
== NULL
)
187 return (requires_privatekey
== 0);
191 static int ecxkem_init(void *vecxctx
, int operation
, void *vecx
, void *vauth
,
192 ossl_unused
const OSSL_PARAM params
[])
195 PROV_ECX_CTX
*ctx
= (PROV_ECX_CTX
*)vecxctx
;
197 ECX_KEY
*auth
= vauth
;
199 if (!ossl_prov_is_running())
202 if (!ecx_key_check(ecx
, operation
== EVP_PKEY_OP_DECAPSULATE
))
204 rv
= recipient_key_set(ctx
, ecx
);
209 if (!ecx_match_params(auth
, ctx
->recipient_key
)
210 || !ecx_key_check(auth
, operation
== EVP_PKEY_OP_ENCAPSULATE
)
211 || !sender_authkey_set(ctx
, auth
))
216 return ecxkem_set_ctx_params(vecxctx
, params
);
219 static int ecxkem_encapsulate_init(void *vecxctx
, void *vecx
,
220 const OSSL_PARAM params
[])
222 return ecxkem_init(vecxctx
, EVP_PKEY_OP_ENCAPSULATE
, vecx
, NULL
, params
);
225 static int ecxkem_decapsulate_init(void *vecxctx
, void *vecx
,
226 const OSSL_PARAM params
[])
228 return ecxkem_init(vecxctx
, EVP_PKEY_OP_DECAPSULATE
, vecx
, NULL
, params
);
231 static int ecxkem_auth_encapsulate_init(void *vctx
, void *vecx
, void *vauthpriv
,
232 const OSSL_PARAM params
[])
234 return ecxkem_init(vctx
, EVP_PKEY_OP_ENCAPSULATE
, vecx
, vauthpriv
, params
);
237 static int ecxkem_auth_decapsulate_init(void *vctx
, void *vecx
, void *vauthpub
,
238 const OSSL_PARAM params
[])
240 return ecxkem_init(vctx
, EVP_PKEY_OP_DECAPSULATE
, vecx
, vauthpub
, params
);
243 static int ecxkem_set_ctx_params(void *vctx
, const OSSL_PARAM params
[])
245 PROV_ECX_CTX
*ctx
= (PROV_ECX_CTX
*)vctx
;
254 p
= OSSL_PARAM_locate_const(params
, OSSL_KEM_PARAM_IKME
);
259 if (p
->data
!= NULL
&& p
->data_size
!= 0) {
260 if (!OSSL_PARAM_get_octet_string(p
, &tmp
, 0, &tmplen
))
263 OPENSSL_clear_free(ctx
->ikm
, ctx
->ikmlen
);
265 ctx
->ikmlen
= tmplen
;
267 p
= OSSL_PARAM_locate_const(params
, OSSL_KEM_PARAM_OPERATION
);
269 if (p
->data_type
!= OSSL_PARAM_UTF8_STRING
)
271 mode
= ossl_eckem_modename2id(p
->data
);
272 if (mode
== KEM_MODE_UNDEFINED
)
279 static const OSSL_PARAM known_settable_ecxkem_ctx_params
[] = {
280 OSSL_PARAM_utf8_string(OSSL_KEM_PARAM_OPERATION
, NULL
, 0),
281 OSSL_PARAM_octet_string(OSSL_KEM_PARAM_IKME
, NULL
, 0),
285 static const OSSL_PARAM
*ecxkem_settable_ctx_params(ossl_unused
void *vctx
,
286 ossl_unused
void *provctx
)
288 return known_settable_ecxkem_ctx_params
;
292 * See Section 4.1 DH-Based KEM (DHKEM) ExtractAndExpand
294 static int dhkem_extract_and_expand(EVP_KDF_CTX
*kctx
,
295 unsigned char *okm
, size_t okmlen
,
297 const unsigned char *dhkm
, size_t dhkmlen
,
298 const unsigned char *kemctx
,
302 uint8_t prk
[EVP_MAX_MD_SIZE
];
303 size_t prklen
= okmlen
; /* Nh */
306 if (prklen
> sizeof(prk
))
309 suiteid
[0] = (kemid
>> 8) &0xff;
310 suiteid
[1] = kemid
& 0xff;
312 ret
= ossl_hpke_labeled_extract(kctx
, prk
, prklen
,
313 NULL
, 0, LABEL_KEM
, suiteid
, sizeof(suiteid
),
314 OSSL_DHKEM_LABEL_EAE_PRK
, dhkm
, dhkmlen
)
315 && ossl_hpke_labeled_expand(kctx
, okm
, okmlen
, prk
, prklen
,
316 LABEL_KEM
, suiteid
, sizeof(suiteid
),
317 OSSL_DHKEM_LABEL_SHARED_SECRET
,
319 OPENSSL_cleanse(prk
, prklen
);
324 * See Section 7.1.3 DeriveKeyPair.
326 * This function is used by ecx keygen.
327 * (For this reason it does not use any of the state stored in PROV_ECX_CTX).
330 * ecx An initialized ecx key.
331 * privout The buffer to store the generated private key into (it is assumed
332 * this is of length ecx->keylen).
333 * ikm buffer containing the input key material (seed). This must be non NULL.
334 * ikmlen size of the ikm buffer in bytes
336 * 1 if successful or 0 otherwise.
338 int ossl_ecx_dhkem_derive_private(ECX_KEY
*ecx
, unsigned char *privout
,
339 const unsigned char *ikm
, size_t ikmlen
)
342 EVP_KDF_CTX
*kdfctx
= NULL
;
343 unsigned char prk
[EVP_MAX_MD_SIZE
];
345 const OSSL_HPKE_KEM_INFO
*info
= get_kem_info(ecx
);
347 /* ikmlen should have a length of at least Nsk */
348 if (ikmlen
< info
->Nsk
) {
349 ERR_raise_data(ERR_LIB_PROV
, PROV_R_INVALID_INPUT_LENGTH
,
350 "ikm length is :%zu, should be at least %zu",
355 kdfctx
= ossl_kdf_ctx_create("HKDF", info
->mdname
, ecx
->libctx
, ecx
->propq
);
359 suiteid
[0] = info
->kem_id
/ 256;
360 suiteid
[1] = info
->kem_id
% 256;
362 if (!ossl_hpke_labeled_extract(kdfctx
, prk
, info
->Nsecret
,
363 NULL
, 0, LABEL_KEM
, suiteid
, sizeof(suiteid
),
364 OSSL_DHKEM_LABEL_DKP_PRK
, ikm
, ikmlen
))
367 if (!ossl_hpke_labeled_expand(kdfctx
, privout
, info
->Nsk
, prk
, info
->Nsecret
,
368 LABEL_KEM
, suiteid
, sizeof(suiteid
),
369 OSSL_DHKEM_LABEL_SK
, NULL
, 0))
373 OPENSSL_cleanse(prk
, sizeof(prk
));
374 EVP_KDF_CTX_free(kdfctx
);
379 * Do a keygen operation without having to use EVP_PKEY.
382 * ikm The seed material - if this is NULL, then a random seed is used.
384 * The generated ECX key, or NULL on failure.
386 static ECX_KEY
*derivekey(PROV_ECX_CTX
*ctx
,
387 const unsigned char *ikm
, size_t ikmlen
)
391 unsigned char *privkey
;
392 unsigned char *seed
= (unsigned char *)ikm
;
393 size_t seedlen
= ikmlen
;
394 unsigned char tmpbuf
[OSSL_HPKE_MAX_PRIVATE
];
395 const OSSL_HPKE_KEM_INFO
*info
= ctx
->info
;
397 key
= ossl_ecx_key_new(ctx
->libctx
, ctx
->recipient_key
->type
, 0, ctx
->propq
);
400 privkey
= ossl_ecx_key_allocate_privkey(key
);
404 /* Generate a random seed if there is no input ikm */
405 if (seed
== NULL
|| seedlen
== 0) {
406 if (info
->Nsk
> sizeof(tmpbuf
))
408 if (RAND_priv_bytes_ex(ctx
->libctx
, tmpbuf
, info
->Nsk
, 0) <= 0)
413 if (!ossl_ecx_dhkem_derive_private(key
, privkey
, seed
, seedlen
))
415 if (!ossl_ecx_public_from_private(key
))
421 ossl_ecx_key_free(key
);
425 OPENSSL_cleanse(seed
, seedlen
);
430 * Do an ecxdh key exchange.
431 * dhkm = DH(sender, peer)
433 * NOTE: Instead of using EVP_PKEY_derive() API's, we use ECX_KEY operations
434 * to avoid messy conversions back to EVP_PKEY.
436 * Returns the size of the secret if successful, or 0 otherwise,
438 static int generate_ecxdhkm(const ECX_KEY
*sender
, const ECX_KEY
*peer
,
439 unsigned char *out
, size_t maxout
,
440 unsigned int secretsz
)
444 /* NOTE: ossl_ecx_compute_key checks for shared secret being all zeros */
445 return ossl_ecx_compute_key((ECX_KEY
*)peer
, (ECX_KEY
*)sender
,
446 sender
->keylen
, out
, &len
, maxout
);
450 * Derive a secret using ECXDH (code is shared by the encap and decap)
452 * dhkm = Concat(ecxdh(privkey1, peerkey1), ecdh(privkey2, peerkey2)
453 * kemctx = Concat(sender_pub, recipient_pub, ctx->sender_authkey)
454 * secret = dhkem_extract_and_expand(kemid, dhkm, kemctx);
457 * ctx Object that contains algorithm state and constants.
458 * secret The returned secret (with a length ctx->alg->secretlen bytes).
459 * privkey1 A private key used for ECXDH key derivation.
460 * peerkey1 A public key used for ECXDH key derivation with privkey1
461 * privkey2 A optional private key used for a second ECXDH key derivation.
463 * peerkey2 A optional public key used for a second ECXDH key derivation
464 * with privkey2,. It can be NULL.
465 * sender_pub The senders public key in encoded form.
466 * recipient_pub The recipients public key in encoded form.
468 * The second ecdh() is only used for the HPKE auth modes when both privkey2
469 * and peerkey2 are non NULL (i.e. ctx->sender_authkey is not NULL).
471 static int derive_secret(PROV_ECX_CTX
*ctx
, unsigned char *secret
,
472 const ECX_KEY
*privkey1
, const ECX_KEY
*peerkey1
,
473 const ECX_KEY
*privkey2
, const ECX_KEY
*peerkey2
,
474 const unsigned char *sender_pub
,
475 const unsigned char *recipient_pub
)
478 EVP_KDF_CTX
*kdfctx
= NULL
;
479 unsigned char *sender_authpub
= NULL
;
480 unsigned char dhkm
[MAX_ECX_KEYLEN
* 2];
481 unsigned char kemctx
[MAX_ECX_KEYLEN
* 3];
482 size_t kemctxlen
= 0, dhkmlen
= 0;
483 const OSSL_HPKE_KEM_INFO
*info
= ctx
->info
;
484 int auth
= ctx
->sender_authkey
!= NULL
;
485 size_t encodedkeylen
= info
->Npk
;
487 if (!generate_ecxdhkm(privkey1
, peerkey1
, dhkm
, sizeof(dhkm
), encodedkeylen
))
489 dhkmlen
= encodedkeylen
;
491 /* Concat the optional second ECXDH (used for Auth) */
493 if (!generate_ecxdhkm(privkey2
, peerkey2
,
494 dhkm
+ dhkmlen
, sizeof(dhkm
) - dhkmlen
,
497 /* Get the public key of the auth sender in encoded form */
498 sender_authpub
= ecx_pubkey(ctx
->sender_authkey
);
499 if (sender_authpub
== NULL
)
501 dhkmlen
+= encodedkeylen
;
503 kemctxlen
= encodedkeylen
+ dhkmlen
;
504 if (kemctxlen
> sizeof(kemctx
))
507 /* kemctx is the concat of both sides encoded public key */
508 memcpy(kemctx
, sender_pub
, encodedkeylen
);
509 memcpy(kemctx
+ encodedkeylen
, recipient_pub
, encodedkeylen
);
511 memcpy(kemctx
+ 2 * encodedkeylen
, sender_authpub
, encodedkeylen
);
512 kdfctx
= ossl_kdf_ctx_create(ctx
->kdfname
, info
->mdname
,
513 ctx
->libctx
, ctx
->propq
);
516 if (!dhkem_extract_and_expand(kdfctx
, secret
, info
->Nsecret
,
517 info
->kem_id
, dhkm
, dhkmlen
,
522 OPENSSL_cleanse(dhkm
, dhkmlen
);
523 EVP_KDF_CTX_free(kdfctx
);
528 * Do a DHKEM encapsulate operation.
530 * See Section 4.1 Encap() and AuthEncap()
533 * ctx A context object holding the recipients public key and the
534 * optional senders auth private key.
535 * enc A buffer to return the senders ephemeral public key.
536 * Setting this to NULL allows the enclen and secretlen to return
537 * values, without calculating the secret.
538 * enclen Passes in the max size of the enc buffer and returns the
539 * encoded public key length.
540 * secret A buffer to return the calculated shared secret.
541 * secretlen Passes in the max size of the secret buffer and returns the
543 * Returns: 1 on success or 0 otherwise.
545 static int dhkem_encap(PROV_ECX_CTX
*ctx
,
546 unsigned char *enc
, size_t *enclen
,
547 unsigned char *secret
, size_t *secretlen
)
550 ECX_KEY
*sender_ephemkey
= NULL
;
551 unsigned char *sender_ephempub
, *recipient_pub
;
552 const OSSL_HPKE_KEM_INFO
*info
= ctx
->info
;
555 if (enclen
== NULL
&& secretlen
== NULL
)
558 *enclen
= info
->Nenc
;
559 if (secretlen
!= NULL
)
560 *secretlen
= info
->Nsecret
;
564 if (*secretlen
< info
->Nsecret
) {
565 ERR_raise_data(ERR_LIB_PROV
, PROV_R_BAD_LENGTH
, "*secretlen too small");
568 if (*enclen
< info
->Nenc
) {
569 ERR_raise_data(ERR_LIB_PROV
, PROV_R_BAD_LENGTH
, "*enclen too small");
573 /* Create an ephemeral key */
574 sender_ephemkey
= derivekey(ctx
, ctx
->ikm
, ctx
->ikmlen
);
576 sender_ephempub
= ecx_pubkey(sender_ephemkey
);
577 recipient_pub
= ecx_pubkey(ctx
->recipient_key
);
578 if (sender_ephempub
== NULL
|| recipient_pub
== NULL
)
581 if (!derive_secret(ctx
, secret
,
582 sender_ephemkey
, ctx
->recipient_key
,
583 ctx
->sender_authkey
, ctx
->recipient_key
,
584 sender_ephempub
, recipient_pub
))
587 /* Return the public part of the ephemeral key */
588 memcpy(enc
, sender_ephempub
, info
->Nenc
);
589 *enclen
= info
->Nenc
;
590 *secretlen
= info
->Nsecret
;
593 ossl_ecx_key_free(sender_ephemkey
);
598 * Do a DHKEM decapsulate operation.
599 * See Section 4.1 Decap() and Auth Decap()
602 * ctx A context object holding the recipients private key and the
603 * optional senders auth public key.
604 * secret A buffer to return the calculated shared secret. Setting this to
605 * NULL can be used to return the secretlen.
606 * secretlen Passes in the max size of the secret buffer and returns the
608 * enc A buffer containing the senders ephemeral public key that was returned
609 * from dhkem_encap().
610 * enclen The length in bytes of enc.
611 * Returns: 1 If the shared secret is returned or 0 on error.
613 static int dhkem_decap(PROV_ECX_CTX
*ctx
,
614 unsigned char *secret
, size_t *secretlen
,
615 const unsigned char *enc
, size_t enclen
)
618 ECX_KEY
*recipient_privkey
= ctx
->recipient_key
;
619 ECX_KEY
*sender_ephempubkey
= NULL
;
620 const OSSL_HPKE_KEM_INFO
*info
= ctx
->info
;
621 unsigned char *recipient_pub
;
623 if (secret
== NULL
) {
624 *secretlen
= info
->Nsecret
;
627 if (*secretlen
< info
->Nsecret
) {
628 ERR_raise_data(ERR_LIB_PROV
, PROV_R_BAD_LENGTH
, "*secretlen too small");
631 if (enclen
!= info
->Nenc
) {
632 ERR_raise_data(ERR_LIB_PROV
, PROV_R_INVALID_KEY
, "Invalid enc public key");
636 /* Get the public part of the ephemeral key created by encap */
637 sender_ephempubkey
= ecxkey_pubfromdata(ctx
, enc
, enclen
);
638 if (sender_ephempubkey
== NULL
)
641 recipient_pub
= ecx_pubkey(recipient_privkey
);
642 if (recipient_pub
== NULL
)
645 if (!derive_secret(ctx
, secret
,
646 ctx
->recipient_key
, sender_ephempubkey
,
647 ctx
->recipient_key
, ctx
->sender_authkey
,
651 *secretlen
= info
->Nsecret
;
654 ossl_ecx_key_free(sender_ephempubkey
);
658 static int ecxkem_encapsulate(void *vctx
, unsigned char *out
, size_t *outlen
,
659 unsigned char *secret
, size_t *secretlen
)
661 PROV_ECX_CTX
*ctx
= (PROV_ECX_CTX
*)vctx
;
665 return dhkem_encap(ctx
, out
, outlen
, secret
, secretlen
);
667 ERR_raise(ERR_LIB_PROV
, PROV_R_INVALID_MODE
);
672 static int ecxkem_decapsulate(void *vctx
, unsigned char *out
, size_t *outlen
,
673 const unsigned char *in
, size_t inlen
)
675 PROV_ECX_CTX
*ctx
= (PROV_ECX_CTX
*)vctx
;
679 return dhkem_decap(vctx
, out
, outlen
, in
, inlen
);
681 ERR_raise(ERR_LIB_PROV
, PROV_R_INVALID_MODE
);
686 const OSSL_DISPATCH ossl_ecx_asym_kem_functions
[] = {
687 { OSSL_FUNC_KEM_NEWCTX
, (void (*)(void))ecxkem_newctx
},
688 { OSSL_FUNC_KEM_ENCAPSULATE_INIT
,
689 (void (*)(void))ecxkem_encapsulate_init
},
690 { OSSL_FUNC_KEM_ENCAPSULATE
, (void (*)(void))ecxkem_encapsulate
},
691 { OSSL_FUNC_KEM_DECAPSULATE_INIT
,
692 (void (*)(void))ecxkem_decapsulate_init
},
693 { OSSL_FUNC_KEM_DECAPSULATE
, (void (*)(void))ecxkem_decapsulate
},
694 { OSSL_FUNC_KEM_FREECTX
, (void (*)(void))ecxkem_freectx
},
695 { OSSL_FUNC_KEM_SET_CTX_PARAMS
,
696 (void (*)(void))ecxkem_set_ctx_params
},
697 { OSSL_FUNC_KEM_SETTABLE_CTX_PARAMS
,
698 (void (*)(void))ecxkem_settable_ctx_params
},
699 { OSSL_FUNC_KEM_AUTH_ENCAPSULATE_INIT
,
700 (void (*)(void))ecxkem_auth_encapsulate_init
},
701 { OSSL_FUNC_KEM_AUTH_DECAPSULATE_INIT
,
702 (void (*)(void))ecxkem_auth_decapsulate_init
},