]> git.ipfire.org Git - thirdparty/openssl.git/blame - providers/implementations/kem/ecx_kem.c
Copyright year updates
[thirdparty/openssl.git] / providers / implementations / kem / ecx_kem.c
CommitLineData
78c44b05 1/*
da1c088f 2 * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved.
78c44b05 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 * 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.
14 */
15
16#include "internal/deprecated.h"
17
18#include <string.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"
33#include "prov/ecx.h"
34#include "crypto/ecx.h"
ad062480
SF
35#include <openssl/hpke.h>
36#include "internal/hpke_util.h"
78c44b05 37#include "eckem.h"
38
39#define MAX_ECX_KEYLEN X448_KEYLEN
40
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
44
ad062480
SF
45/* ASCII: "KEM", in hex for EBCDIC compatibility */
46static const char LABEL_KEM[] = "\x4b\x45\x4d";
47
78c44b05 48typedef struct {
49 ECX_KEY *recipient_key;
50 ECX_KEY *sender_authkey;
51 OSSL_LIB_CTX *libctx;
52 char *propq;
53 unsigned int mode;
54 unsigned int op;
78c44b05 55 unsigned char *ikm;
56 size_t ikmlen;
57 const char *kdfname;
ad062480 58 const OSSL_HPKE_KEM_INFO *info;
78c44b05 59} PROV_ECX_CTX;
60
61static OSSL_FUNC_kem_newctx_fn ecxkem_newctx;
62static OSSL_FUNC_kem_encapsulate_init_fn ecxkem_encapsulate_init;
63static OSSL_FUNC_kem_encapsulate_fn ecxkem_encapsulate;
64static OSSL_FUNC_kem_decapsulate_init_fn ecxkem_decapsulate_init;
65static OSSL_FUNC_kem_decapsulate_fn ecxkem_decapsulate;
66static OSSL_FUNC_kem_freectx_fn ecxkem_freectx;
67static OSSL_FUNC_kem_set_ctx_params_fn ecxkem_set_ctx_params;
68static OSSL_FUNC_kem_auth_encapsulate_init_fn ecxkem_auth_encapsulate_init;
69static OSSL_FUNC_kem_auth_decapsulate_init_fn ecxkem_auth_decapsulate_init;
70
71/*
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.
75 */
ad062480 76static const OSSL_HPKE_KEM_INFO *get_kem_info(ECX_KEY *ecx)
78c44b05 77{
ad062480
SF
78 const char *name = NULL;
79
80 if (ecx->type == ECX_KEY_TYPE_X25519)
81 name = SN_X25519;
82 else
83 name = SN_X448;
84 return ossl_HPKE_KEM_INFO_find_curve(name);
78c44b05 85}
86
87/*
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.
90 */
91static int recipient_key_set(PROV_ECX_CTX *ctx, ECX_KEY *ecx)
92{
93 ossl_ecx_key_free(ctx->recipient_key);
94 ctx->recipient_key = NULL;
95 if (ecx != NULL) {
ad062480
SF
96 ctx->info = get_kem_info(ecx);
97 if (ctx->info == NULL)
98 return -2;
78c44b05 99 ctx->kdfname = "HKDF";
100 if (!ossl_ecx_key_up_ref(ecx))
101 return 0;
102 ctx->recipient_key = ecx;
103 }
104 return 1;
105}
106
107/*
108 * Set the senders auth key, and free any existing auth key.
109 * ecx can be NULL.
110 */
111static int sender_authkey_set(PROV_ECX_CTX *ctx, ECX_KEY *ecx)
112{
113 ossl_ecx_key_free(ctx->sender_authkey);
114 ctx->sender_authkey = NULL;
115
116 if (ecx != NULL) {
117 if (!ossl_ecx_key_up_ref(ecx))
118 return 0;
119 ctx->sender_authkey = ecx;
120 }
121 return 1;
122}
123
124/*
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.
128 */
129static ECX_KEY *ecxkey_pubfromdata(PROV_ECX_CTX *ctx,
130 const unsigned char *pubbuf, size_t pubbuflen)
131{
132 ECX_KEY *ecx = NULL;
133 OSSL_PARAM params[2], *p = params;
134
135 *p++ = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY,
136 (char *)pubbuf, pubbuflen);
137 *p = OSSL_PARAM_construct_end();
138
139 ecx = ossl_ecx_key_new(ctx->libctx, ctx->recipient_key->type, 1, ctx->propq);
140 if (ecx == NULL)
141 return NULL;
142 if (ossl_ecx_key_fromdata(ecx, params, 0) <= 0) {
143 ossl_ecx_key_free(ecx);
144 ecx = NULL;
145 }
146 return ecx;
147}
148
149static unsigned char *ecx_pubkey(ECX_KEY *ecx)
150{
151 if (ecx == NULL || !ecx->haspubkey) {
152 ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY);
153 return 0;
154 }
155 return ecx->pubkey;
156}
157
158static void *ecxkem_newctx(void *provctx)
159{
160 PROV_ECX_CTX *ctx = OPENSSL_zalloc(sizeof(PROV_ECX_CTX));
161
162 if (ctx == NULL)
163 return NULL;
164 ctx->libctx = PROV_LIBCTX_OF(provctx);
165
166 return ctx;
167}
168
169static void ecxkem_freectx(void *vectx)
170{
171 PROV_ECX_CTX *ctx = (PROV_ECX_CTX *)vectx;
172
173 OPENSSL_clear_free(ctx->ikm, ctx->ikmlen);
174 recipient_key_set(ctx, NULL);
175 sender_authkey_set(ctx, NULL);
176 OPENSSL_free(ctx);
177}
178
179static int ecx_match_params(const ECX_KEY *key1, const ECX_KEY *key2)
180{
181 return (key1->type == key2->type && key1->keylen == key2->keylen);
182}
183
184static int ecx_key_check(const ECX_KEY *ecx, int requires_privatekey)
185{
186 if (ecx->privkey == NULL)
187 return (requires_privatekey == 0);
188 return 1;
189}
190
191static int ecxkem_init(void *vecxctx, int operation, void *vecx, void *vauth,
192 ossl_unused const OSSL_PARAM params[])
193{
194 int rv;
195 PROV_ECX_CTX *ctx = (PROV_ECX_CTX *)vecxctx;
196 ECX_KEY *ecx = vecx;
197 ECX_KEY *auth = vauth;
198
199 if (!ossl_prov_is_running())
200 return 0;
201
202 if (!ecx_key_check(ecx, operation == EVP_PKEY_OP_DECAPSULATE))
203 return 0;
204 rv = recipient_key_set(ctx, ecx);
205 if (rv <= 0)
206 return rv;
207
208 if (auth != NULL) {
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))
212 return 0;
213 }
214
215 ctx->op = operation;
216 return ecxkem_set_ctx_params(vecxctx, params);
217}
218
219static int ecxkem_encapsulate_init(void *vecxctx, void *vecx,
220 const OSSL_PARAM params[])
221{
222 return ecxkem_init(vecxctx, EVP_PKEY_OP_ENCAPSULATE, vecx, NULL, params);
223}
224
225static int ecxkem_decapsulate_init(void *vecxctx, void *vecx,
226 const OSSL_PARAM params[])
227{
228 return ecxkem_init(vecxctx, EVP_PKEY_OP_DECAPSULATE, vecx, NULL, params);
229}
230
231static int ecxkem_auth_encapsulate_init(void *vctx, void *vecx, void *vauthpriv,
232 const OSSL_PARAM params[])
233{
234 return ecxkem_init(vctx, EVP_PKEY_OP_ENCAPSULATE, vecx, vauthpriv, params);
235}
236
237static int ecxkem_auth_decapsulate_init(void *vctx, void *vecx, void *vauthpub,
238 const OSSL_PARAM params[])
239{
240 return ecxkem_init(vctx, EVP_PKEY_OP_DECAPSULATE, vecx, vauthpub, params);
241}
242
243static int ecxkem_set_ctx_params(void *vctx, const OSSL_PARAM params[])
244{
245 PROV_ECX_CTX *ctx = (PROV_ECX_CTX *)vctx;
246 const OSSL_PARAM *p;
247 int mode;
248
249 if (ctx == NULL)
250 return 0;
251 if (params == NULL)
252 return 1;
253
254 p = OSSL_PARAM_locate_const(params, OSSL_KEM_PARAM_IKME);
255 if (p != NULL) {
256 void *tmp = NULL;
257 size_t tmplen = 0;
258
259 if (p->data != NULL && p->data_size != 0) {
260 if (!OSSL_PARAM_get_octet_string(p, &tmp, 0, &tmplen))
261 return 0;
262 }
263 OPENSSL_clear_free(ctx->ikm, ctx->ikmlen);
264 ctx->ikm = tmp;
265 ctx->ikmlen = tmplen;
266 }
267 p = OSSL_PARAM_locate_const(params, OSSL_KEM_PARAM_OPERATION);
268 if (p != NULL) {
269 if (p->data_type != OSSL_PARAM_UTF8_STRING)
270 return 0;
271 mode = ossl_eckem_modename2id(p->data);
272 if (mode == KEM_MODE_UNDEFINED)
273 return 0;
274 ctx->mode = mode;
275 }
276 return 1;
277}
278
279static 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),
282 OSSL_PARAM_END
283};
284
285static const OSSL_PARAM *ecxkem_settable_ctx_params(ossl_unused void *vctx,
286 ossl_unused void *provctx)
287{
288 return known_settable_ecxkem_ctx_params;
289}
290
291/*
292 * See Section 4.1 DH-Based KEM (DHKEM) ExtractAndExpand
293 */
294static int dhkem_extract_and_expand(EVP_KDF_CTX *kctx,
295 unsigned char *okm, size_t okmlen,
296 uint16_t kemid,
297 const unsigned char *dhkm, size_t dhkmlen,
298 const unsigned char *kemctx,
299 size_t kemctxlen)
300{
ad062480 301 uint8_t suiteid[2];
78c44b05 302 uint8_t prk[EVP_MAX_MD_SIZE];
303 size_t prklen = okmlen; /* Nh */
304 int ret;
305
306 if (prklen > sizeof(prk))
307 return 0;
308
ad062480
SF
309 suiteid[0] = (kemid >> 8) &0xff;
310 suiteid[1] = kemid & 0xff;
78c44b05 311
312 ret = ossl_hpke_labeled_extract(kctx, prk, prklen,
ad062480 313 NULL, 0, LABEL_KEM, suiteid, sizeof(suiteid),
78c44b05 314 OSSL_DHKEM_LABEL_EAE_PRK, dhkm, dhkmlen)
315 && ossl_hpke_labeled_expand(kctx, okm, okmlen, prk, prklen,
ad062480 316 LABEL_KEM, suiteid, sizeof(suiteid),
78c44b05 317 OSSL_DHKEM_LABEL_SHARED_SECRET,
318 kemctx, kemctxlen);
319 OPENSSL_cleanse(prk, prklen);
320 return ret;
321}
322
323/*
324 * See Section 7.1.3 DeriveKeyPair.
325 *
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).
328 *
329 * Params:
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
335 * Returns:
336 * 1 if successful or 0 otherwise.
337 */
338int ossl_ecx_dhkem_derive_private(ECX_KEY *ecx, unsigned char *privout,
339 const unsigned char *ikm, size_t ikmlen)
340{
341 int ret = 0;
342 EVP_KDF_CTX *kdfctx = NULL;
343 unsigned char prk[EVP_MAX_MD_SIZE];
ad062480
SF
344 uint8_t suiteid[2];
345 const OSSL_HPKE_KEM_INFO *info = get_kem_info(ecx);
78c44b05 346
347 /* ikmlen should have a length of at least Nsk */
ad062480 348 if (ikmlen < info->Nsk) {
78c44b05 349 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_INPUT_LENGTH,
350 "ikm length is :%zu, should be at least %zu",
ad062480 351 ikmlen, info->Nsk);
78c44b05 352 goto err;
353 }
354
ad062480 355 kdfctx = ossl_kdf_ctx_create("HKDF", info->mdname, ecx->libctx, ecx->propq);
78c44b05 356 if (kdfctx == NULL)
357 return 0;
358
ad062480
SF
359 suiteid[0] = info->kem_id / 256;
360 suiteid[1] = info->kem_id % 256;
78c44b05 361
ad062480
SF
362 if (!ossl_hpke_labeled_extract(kdfctx, prk, info->Nsecret,
363 NULL, 0, LABEL_KEM, suiteid, sizeof(suiteid),
78c44b05 364 OSSL_DHKEM_LABEL_DKP_PRK, ikm, ikmlen))
365 goto err;
366
ad062480
SF
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))
78c44b05 370 goto err;
371 ret = 1;
372err:
373 OPENSSL_cleanse(prk, sizeof(prk));
374 EVP_KDF_CTX_free(kdfctx);
375 return ret;
376}
377
378/*
379 * Do a keygen operation without having to use EVP_PKEY.
380 * Params:
381 * ctx Context object
382 * ikm The seed material - if this is NULL, then a random seed is used.
383 * Returns:
384 * The generated ECX key, or NULL on failure.
385 */
386static ECX_KEY *derivekey(PROV_ECX_CTX *ctx,
387 const unsigned char *ikm, size_t ikmlen)
388{
389 int ok = 0;
390 ECX_KEY *key;
391 unsigned char *privkey;
392 unsigned char *seed = (unsigned char *)ikm;
393 size_t seedlen = ikmlen;
394 unsigned char tmpbuf[OSSL_HPKE_MAX_PRIVATE];
ad062480 395 const OSSL_HPKE_KEM_INFO *info = ctx->info;
78c44b05 396
397 key = ossl_ecx_key_new(ctx->libctx, ctx->recipient_key->type, 0, ctx->propq);
398 if (key == NULL)
399 return NULL;
400 privkey = ossl_ecx_key_allocate_privkey(key);
401 if (privkey == NULL)
402 goto err;
403
404 /* Generate a random seed if there is no input ikm */
405 if (seed == NULL || seedlen == 0) {
ad062480 406 if (info->Nsk > sizeof(tmpbuf))
78c44b05 407 goto err;
ad062480 408 if (RAND_priv_bytes_ex(ctx->libctx, tmpbuf, info->Nsk, 0) <= 0)
78c44b05 409 goto err;
410 seed = tmpbuf;
ad062480 411 seedlen = info->Nsk;
78c44b05 412 }
413 if (!ossl_ecx_dhkem_derive_private(key, privkey, seed, seedlen))
414 goto err;
415 if (!ossl_ecx_public_from_private(key))
416 goto err;
417 key->haspubkey = 1;
418 ok = 1;
419err:
420 if (!ok) {
421 ossl_ecx_key_free(key);
422 key = NULL;
423 }
424 if (seed != ikm)
425 OPENSSL_cleanse(seed, seedlen);
426 return key;
427}
428
429/*
430 * Do an ecxdh key exchange.
431 * dhkm = DH(sender, peer)
432 *
433 * NOTE: Instead of using EVP_PKEY_derive() API's, we use ECX_KEY operations
434 * to avoid messy conversions back to EVP_PKEY.
435 *
436 * Returns the size of the secret if successful, or 0 otherwise,
437 */
438static int generate_ecxdhkm(const ECX_KEY *sender, const ECX_KEY *peer,
439 unsigned char *out, size_t maxout,
440 unsigned int secretsz)
441{
442 size_t len = 0;
443
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);
447}
448
449/*
450 * Derive a secret using ECXDH (code is shared by the encap and decap)
451 *
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);
455 *
456 * Params:
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.
462 * It can be NULL.
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.
467 * Notes:
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).
470 */
471static 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)
476{
477 int ret = 0;
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;
ad062480 483 const OSSL_HPKE_KEM_INFO *info = ctx->info;
78c44b05 484 int auth = ctx->sender_authkey != NULL;
ad062480 485 size_t encodedkeylen = info->Npk;
78c44b05 486
487 if (!generate_ecxdhkm(privkey1, peerkey1, dhkm, sizeof(dhkm), encodedkeylen))
488 goto err;
489 dhkmlen = encodedkeylen;
490
491 /* Concat the optional second ECXDH (used for Auth) */
492 if (auth) {
493 if (!generate_ecxdhkm(privkey2, peerkey2,
494 dhkm + dhkmlen, sizeof(dhkm) - dhkmlen,
495 encodedkeylen))
496 goto err;
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)
500 goto err;
501 dhkmlen += encodedkeylen;
502 }
503 kemctxlen = encodedkeylen + dhkmlen;
504 if (kemctxlen > sizeof(kemctx))
505 goto err;
506
507 /* kemctx is the concat of both sides encoded public key */
508 memcpy(kemctx, sender_pub, encodedkeylen);
509 memcpy(kemctx + encodedkeylen, recipient_pub, encodedkeylen);
510 if (auth)
511 memcpy(kemctx + 2 * encodedkeylen, sender_authpub, encodedkeylen);
ad062480 512 kdfctx = ossl_kdf_ctx_create(ctx->kdfname, info->mdname,
78c44b05 513 ctx->libctx, ctx->propq);
514 if (kdfctx == NULL)
515 goto err;
ad062480
SF
516 if (!dhkem_extract_and_expand(kdfctx, secret, info->Nsecret,
517 info->kem_id, dhkm, dhkmlen,
78c44b05 518 kemctx, kemctxlen))
519 goto err;
520 ret = 1;
521err:
522 OPENSSL_cleanse(dhkm, dhkmlen);
523 EVP_KDF_CTX_free(kdfctx);
524 return ret;
525}
526
527/*
528 * Do a DHKEM encapsulate operation.
529 *
530 * See Section 4.1 Encap() and AuthEncap()
531 *
532 * Params:
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
542 * secret length.
543 * Returns: 1 on success or 0 otherwise.
544 */
545static int dhkem_encap(PROV_ECX_CTX *ctx,
546 unsigned char *enc, size_t *enclen,
547 unsigned char *secret, size_t *secretlen)
548{
549 int ret = 0;
550 ECX_KEY *sender_ephemkey = NULL;
551 unsigned char *sender_ephempub, *recipient_pub;
ad062480 552 const OSSL_HPKE_KEM_INFO *info = ctx->info;
78c44b05 553
554 if (enc == NULL) {
555 if (enclen == NULL && secretlen == NULL)
556 return 0;
557 if (enclen != NULL)
ad062480 558 *enclen = info->Nenc;
78c44b05 559 if (secretlen != NULL)
ad062480 560 *secretlen = info->Nsecret;
78c44b05 561 return 1;
562 }
563
ad062480 564 if (*secretlen < info->Nsecret) {
78c44b05 565 ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*secretlen too small");
566 return 0;
567 }
ad062480 568 if (*enclen < info->Nenc) {
78c44b05 569 ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*enclen too small");
570 return 0;
571 }
572
573 /* Create an ephemeral key */
574 sender_ephemkey = derivekey(ctx, ctx->ikm, ctx->ikmlen);
575
576 sender_ephempub = ecx_pubkey(sender_ephemkey);
577 recipient_pub = ecx_pubkey(ctx->recipient_key);
578 if (sender_ephempub == NULL || recipient_pub == NULL)
579 goto err;
580
581 if (!derive_secret(ctx, secret,
582 sender_ephemkey, ctx->recipient_key,
583 ctx->sender_authkey, ctx->recipient_key,
584 sender_ephempub, recipient_pub))
585 goto err;
586
587 /* Return the public part of the ephemeral key */
ad062480
SF
588 memcpy(enc, sender_ephempub, info->Nenc);
589 *enclen = info->Nenc;
590 *secretlen = info->Nsecret;
78c44b05 591 ret = 1;
592err:
593 ossl_ecx_key_free(sender_ephemkey);
594 return ret;
595}
596
597/*
598 * Do a DHKEM decapsulate operation.
599 * See Section 4.1 Decap() and Auth Decap()
600 *
601 * Params:
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
607 * secret length.
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.
612 */
613static int dhkem_decap(PROV_ECX_CTX *ctx,
614 unsigned char *secret, size_t *secretlen,
615 const unsigned char *enc, size_t enclen)
616{
617 int ret = 0;
618 ECX_KEY *recipient_privkey = ctx->recipient_key;
619 ECX_KEY *sender_ephempubkey = NULL;
ad062480 620 const OSSL_HPKE_KEM_INFO *info = ctx->info;
78c44b05 621 unsigned char *recipient_pub;
622
623 if (secret == NULL) {
ad062480 624 *secretlen = info->Nsecret;
78c44b05 625 return 1;
626 }
ad062480 627 if (*secretlen < info->Nsecret) {
78c44b05 628 ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*secretlen too small");
629 return 0;
630 }
ad062480 631 if (enclen != info->Nenc) {
78c44b05 632 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, "Invalid enc public key");
633 return 0;
634 }
635
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)
639 goto err;
640
641 recipient_pub = ecx_pubkey(recipient_privkey);
642 if (recipient_pub == NULL)
643 goto err;
644
645 if (!derive_secret(ctx, secret,
646 ctx->recipient_key, sender_ephempubkey,
647 ctx->recipient_key, ctx->sender_authkey,
648 enc, recipient_pub))
649 goto err;
650
ad062480 651 *secretlen = info->Nsecret;
78c44b05 652 ret = 1;
653err:
654 ossl_ecx_key_free(sender_ephempubkey);
655 return ret;
656}
657
658static int ecxkem_encapsulate(void *vctx, unsigned char *out, size_t *outlen,
659 unsigned char *secret, size_t *secretlen)
660{
661 PROV_ECX_CTX *ctx = (PROV_ECX_CTX *)vctx;
662
663 switch (ctx->mode) {
664 case KEM_MODE_DHKEM:
665 return dhkem_encap(ctx, out, outlen, secret, secretlen);
666 default:
667 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE);
668 return -2;
669 }
670}
671
672static int ecxkem_decapsulate(void *vctx, unsigned char *out, size_t *outlen,
673 const unsigned char *in, size_t inlen)
674{
675 PROV_ECX_CTX *ctx = (PROV_ECX_CTX *)vctx;
676
677 switch (ctx->mode) {
678 case KEM_MODE_DHKEM:
679 return dhkem_decap(vctx, out, outlen, in, inlen);
680 default:
681 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE);
682 return -2;
683 }
684}
685
686const 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 },
1e6bd31e 703 OSSL_DISPATCH_END
78c44b05 704};