1 /* 2 * Copyright 2022-2025 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 * 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" 35 #include <openssl/hpke.h> 36 #include "internal/hpke_util.h" 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 45 /* ASCII: "KEM", in hex for EBCDIC compatibility */ 46 static const char LABEL_KEM[] = "\x4b\x45\x4d"; 47 48 typedef 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; 55 unsigned char *ikm; 56 size_t ikmlen; 57 const char *kdfname; 58 const OSSL_HPKE_KEM_INFO *info; 59 } PROV_ECX_CTX; 60 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; 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 */ 76 static const OSSL_HPKE_KEM_INFO *get_kem_info(ECX_KEY *ecx) 77 { 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); 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 */ 91 static 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) { 96 ctx->info = get_kem_info(ecx); 97 if (ctx->info == NULL) 98 return -2; 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 */ 111 static 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 */ 129 static 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 149 static 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 158 static 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 ctx->mode = KEM_MODE_DHKEM; 166 167 return ctx; 168 } 169 170 static void ecxkem_freectx(void *vectx) 171 { 172 PROV_ECX_CTX *ctx = (PROV_ECX_CTX *)vectx; 173 174 OPENSSL_clear_free(ctx->ikm, ctx->ikmlen); 175 recipient_key_set(ctx, NULL); 176 sender_authkey_set(ctx, NULL); 177 OPENSSL_free(ctx); 178 } 179 180 static int ecx_match_params(const ECX_KEY *key1, const ECX_KEY *key2) 181 { 182 return (key1->type == key2->type && key1->keylen == key2->keylen); 183 } 184 185 static int ecx_key_check(const ECX_KEY *ecx, int requires_privatekey) 186 { 187 if (ecx->privkey == NULL) 188 return (requires_privatekey == 0); 189 return 1; 190 } 191 192 static int ecxkem_init(void *vecxctx, int operation, void *vecx, void *vauth, 193 ossl_unused const OSSL_PARAM params[]) 194 { 195 int rv; 196 PROV_ECX_CTX *ctx = (PROV_ECX_CTX *)vecxctx; 197 ECX_KEY *ecx = vecx; 198 ECX_KEY *auth = vauth; 199 200 if (!ossl_prov_is_running()) 201 return 0; 202 203 if (!ecx_key_check(ecx, operation == EVP_PKEY_OP_DECAPSULATE)) 204 return 0; 205 rv = recipient_key_set(ctx, ecx); 206 if (rv <= 0) 207 return rv; 208 209 if (auth != NULL) { 210 if (!ecx_match_params(auth, ctx->recipient_key) 211 || !ecx_key_check(auth, operation == EVP_PKEY_OP_ENCAPSULATE) 212 || !sender_authkey_set(ctx, auth)) 213 return 0; 214 } 215 216 ctx->op = operation; 217 return ecxkem_set_ctx_params(vecxctx, params); 218 } 219 220 static int ecxkem_encapsulate_init(void *vecxctx, void *vecx, 221 const OSSL_PARAM params[]) 222 { 223 return ecxkem_init(vecxctx, EVP_PKEY_OP_ENCAPSULATE, vecx, NULL, params); 224 } 225 226 static int ecxkem_decapsulate_init(void *vecxctx, void *vecx, 227 const OSSL_PARAM params[]) 228 { 229 return ecxkem_init(vecxctx, EVP_PKEY_OP_DECAPSULATE, vecx, NULL, params); 230 } 231 232 static int ecxkem_auth_encapsulate_init(void *vctx, void *vecx, void *vauthpriv, 233 const OSSL_PARAM params[]) 234 { 235 return ecxkem_init(vctx, EVP_PKEY_OP_ENCAPSULATE, vecx, vauthpriv, params); 236 } 237 238 static int ecxkem_auth_decapsulate_init(void *vctx, void *vecx, void *vauthpub, 239 const OSSL_PARAM params[]) 240 { 241 return ecxkem_init(vctx, EVP_PKEY_OP_DECAPSULATE, vecx, vauthpub, params); 242 } 243 244 static int ecxkem_set_ctx_params(void *vctx, const OSSL_PARAM params[]) 245 { 246 PROV_ECX_CTX *ctx = (PROV_ECX_CTX *)vctx; 247 const OSSL_PARAM *p; 248 int mode; 249 250 if (ctx == NULL) 251 return 0; 252 if (ossl_param_is_empty(params)) 253 return 1; 254 255 p = OSSL_PARAM_locate_const(params, OSSL_KEM_PARAM_IKME); 256 if (p != NULL) { 257 void *tmp = NULL; 258 size_t tmplen = 0; 259 260 if (p->data != NULL && p->data_size != 0) { 261 if (!OSSL_PARAM_get_octet_string(p, &tmp, 0, &tmplen)) 262 return 0; 263 } 264 OPENSSL_clear_free(ctx->ikm, ctx->ikmlen); 265 ctx->ikm = tmp; 266 ctx->ikmlen = tmplen; 267 } 268 p = OSSL_PARAM_locate_const(params, OSSL_KEM_PARAM_OPERATION); 269 if (p != NULL) { 270 if (p->data_type != OSSL_PARAM_UTF8_STRING) 271 return 0; 272 mode = ossl_eckem_modename2id(p->data); 273 if (mode == KEM_MODE_UNDEFINED) 274 return 0; 275 ctx->mode = mode; 276 } 277 return 1; 278 } 279 280 static const OSSL_PARAM known_settable_ecxkem_ctx_params[] = { 281 OSSL_PARAM_utf8_string(OSSL_KEM_PARAM_OPERATION, NULL, 0), 282 OSSL_PARAM_octet_string(OSSL_KEM_PARAM_IKME, NULL, 0), 283 OSSL_PARAM_END 284 }; 285 286 static const OSSL_PARAM *ecxkem_settable_ctx_params(ossl_unused void *vctx, 287 ossl_unused void *provctx) 288 { 289 return known_settable_ecxkem_ctx_params; 290 } 291 292 /* 293 * See Section 4.1 DH-Based KEM (DHKEM) ExtractAndExpand 294 */ 295 static int dhkem_extract_and_expand(EVP_KDF_CTX *kctx, 296 unsigned char *okm, size_t okmlen, 297 uint16_t kemid, 298 const unsigned char *dhkm, size_t dhkmlen, 299 const unsigned char *kemctx, 300 size_t kemctxlen) 301 { 302 uint8_t suiteid[2]; 303 uint8_t prk[EVP_MAX_MD_SIZE]; 304 size_t prklen = okmlen; /* Nh */ 305 int ret; 306 307 if (prklen > sizeof(prk)) 308 return 0; 309 310 suiteid[0] = (kemid >> 8) &0xff; 311 suiteid[1] = kemid & 0xff; 312 313 ret = ossl_hpke_labeled_extract(kctx, prk, prklen, 314 NULL, 0, LABEL_KEM, suiteid, sizeof(suiteid), 315 OSSL_DHKEM_LABEL_EAE_PRK, dhkm, dhkmlen) 316 && ossl_hpke_labeled_expand(kctx, okm, okmlen, prk, prklen, 317 LABEL_KEM, suiteid, sizeof(suiteid), 318 OSSL_DHKEM_LABEL_SHARED_SECRET, 319 kemctx, kemctxlen); 320 OPENSSL_cleanse(prk, prklen); 321 return ret; 322 } 323 324 /* 325 * See Section 7.1.3 DeriveKeyPair. 326 * 327 * This function is used by ecx keygen. 328 * (For this reason it does not use any of the state stored in PROV_ECX_CTX). 329 * 330 * Params: 331 * ecx An initialized ecx key. 332 * privout The buffer to store the generated private key into (it is assumed 333 * this is of length ecx->keylen). 334 * ikm buffer containing the input key material (seed). This must be non NULL. 335 * ikmlen size of the ikm buffer in bytes 336 * Returns: 337 * 1 if successful or 0 otherwise. 338 */ 339 int ossl_ecx_dhkem_derive_private(ECX_KEY *ecx, unsigned char *privout, 340 const unsigned char *ikm, size_t ikmlen) 341 { 342 int ret = 0; 343 EVP_KDF_CTX *kdfctx = NULL; 344 unsigned char prk[EVP_MAX_MD_SIZE]; 345 uint8_t suiteid[2]; 346 const OSSL_HPKE_KEM_INFO *info = get_kem_info(ecx); 347 348 /* ikmlen should have a length of at least Nsk */ 349 if (ikmlen < info->Nsk) { 350 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_INPUT_LENGTH, 351 "ikm length is :%zu, should be at least %zu", 352 ikmlen, info->Nsk); 353 goto err; 354 } 355 356 kdfctx = ossl_kdf_ctx_create("HKDF", info->mdname, ecx->libctx, ecx->propq); 357 if (kdfctx == NULL) 358 return 0; 359 360 suiteid[0] = info->kem_id / 256; 361 suiteid[1] = info->kem_id % 256; 362 363 if (!ossl_hpke_labeled_extract(kdfctx, prk, info->Nsecret, 364 NULL, 0, LABEL_KEM, suiteid, sizeof(suiteid), 365 OSSL_DHKEM_LABEL_DKP_PRK, ikm, ikmlen)) 366 goto err; 367 368 if (!ossl_hpke_labeled_expand(kdfctx, privout, info->Nsk, prk, info->Nsecret, 369 LABEL_KEM, suiteid, sizeof(suiteid), 370 OSSL_DHKEM_LABEL_SK, NULL, 0)) 371 goto err; 372 ret = 1; 373 err: 374 OPENSSL_cleanse(prk, sizeof(prk)); 375 EVP_KDF_CTX_free(kdfctx); 376 return ret; 377 } 378 379 /* 380 * Do a keygen operation without having to use EVP_PKEY. 381 * Params: 382 * ctx Context object 383 * ikm The seed material - if this is NULL, then a random seed is used. 384 * Returns: 385 * The generated ECX key, or NULL on failure. 386 */ 387 static ECX_KEY *derivekey(PROV_ECX_CTX *ctx, 388 const unsigned char *ikm, size_t ikmlen) 389 { 390 int ok = 0; 391 ECX_KEY *key; 392 unsigned char *privkey; 393 unsigned char *seed = (unsigned char *)ikm; 394 size_t seedlen = ikmlen; 395 unsigned char tmpbuf[OSSL_HPKE_MAX_PRIVATE]; 396 const OSSL_HPKE_KEM_INFO *info = ctx->info; 397 398 key = ossl_ecx_key_new(ctx->libctx, ctx->recipient_key->type, 0, ctx->propq); 399 if (key == NULL) 400 return NULL; 401 privkey = ossl_ecx_key_allocate_privkey(key); 402 if (privkey == NULL) 403 goto err; 404 405 /* Generate a random seed if there is no input ikm */ 406 if (seed == NULL || seedlen == 0) { 407 if (info->Nsk > sizeof(tmpbuf)) 408 goto err; 409 if (RAND_priv_bytes_ex(ctx->libctx, tmpbuf, info->Nsk, 0) <= 0) 410 goto err; 411 seed = tmpbuf; 412 seedlen = info->Nsk; 413 } 414 if (!ossl_ecx_dhkem_derive_private(key, privkey, seed, seedlen)) 415 goto err; 416 if (!ossl_ecx_public_from_private(key)) 417 goto err; 418 key->haspubkey = 1; 419 ok = 1; 420 err: 421 if (!ok) { 422 ossl_ecx_key_free(key); 423 key = NULL; 424 } 425 if (seed != ikm) 426 OPENSSL_cleanse(seed, seedlen); 427 return key; 428 } 429 430 /* 431 * Do an ecxdh key exchange. 432 * dhkm = DH(sender, peer) 433 * 434 * NOTE: Instead of using EVP_PKEY_derive() API's, we use ECX_KEY operations 435 * to avoid messy conversions back to EVP_PKEY. 436 * 437 * Returns the size of the secret if successful, or 0 otherwise, 438 */ 439 static int generate_ecxdhkm(const ECX_KEY *sender, const ECX_KEY *peer, 440 unsigned char *out, size_t maxout, 441 unsigned int secretsz) 442 { 443 size_t len = 0; 444 445 /* NOTE: ossl_ecx_compute_key checks for shared secret being all zeros */ 446 return ossl_ecx_compute_key((ECX_KEY *)peer, (ECX_KEY *)sender, 447 sender->keylen, out, &len, maxout); 448 } 449 450 /* 451 * Derive a secret using ECXDH (code is shared by the encap and decap) 452 * 453 * dhkm = Concat(ecxdh(privkey1, peerkey1), ecdh(privkey2, peerkey2) 454 * kemctx = Concat(sender_pub, recipient_pub, ctx->sender_authkey) 455 * secret = dhkem_extract_and_expand(kemid, dhkm, kemctx); 456 * 457 * Params: 458 * ctx Object that contains algorithm state and constants. 459 * secret The returned secret (with a length ctx->alg->secretlen bytes). 460 * privkey1 A private key used for ECXDH key derivation. 461 * peerkey1 A public key used for ECXDH key derivation with privkey1 462 * privkey2 A optional private key used for a second ECXDH key derivation. 463 * It can be NULL. 464 * peerkey2 A optional public key used for a second ECXDH key derivation 465 * with privkey2,. It can be NULL. 466 * sender_pub The senders public key in encoded form. 467 * recipient_pub The recipients public key in encoded form. 468 * Notes: 469 * The second ecdh() is only used for the HPKE auth modes when both privkey2 470 * and peerkey2 are non NULL (i.e. ctx->sender_authkey is not NULL). 471 */ 472 static int derive_secret(PROV_ECX_CTX *ctx, unsigned char *secret, 473 const ECX_KEY *privkey1, const ECX_KEY *peerkey1, 474 const ECX_KEY *privkey2, const ECX_KEY *peerkey2, 475 const unsigned char *sender_pub, 476 const unsigned char *recipient_pub) 477 { 478 int ret = 0; 479 EVP_KDF_CTX *kdfctx = NULL; 480 unsigned char *sender_authpub = NULL; 481 unsigned char dhkm[MAX_ECX_KEYLEN * 2]; 482 unsigned char kemctx[MAX_ECX_KEYLEN * 3]; 483 size_t kemctxlen = 0, dhkmlen = 0; 484 const OSSL_HPKE_KEM_INFO *info = ctx->info; 485 int auth = ctx->sender_authkey != NULL; 486 size_t encodedkeylen = info->Npk; 487 488 if (!generate_ecxdhkm(privkey1, peerkey1, dhkm, sizeof(dhkm), encodedkeylen)) 489 goto err; 490 dhkmlen = encodedkeylen; 491 492 /* Concat the optional second ECXDH (used for Auth) */ 493 if (auth) { 494 if (!generate_ecxdhkm(privkey2, peerkey2, 495 dhkm + dhkmlen, sizeof(dhkm) - dhkmlen, 496 encodedkeylen)) 497 goto err; 498 /* Get the public key of the auth sender in encoded form */ 499 sender_authpub = ecx_pubkey(ctx->sender_authkey); 500 if (sender_authpub == NULL) 501 goto err; 502 dhkmlen += encodedkeylen; 503 } 504 kemctxlen = encodedkeylen + dhkmlen; 505 if (kemctxlen > sizeof(kemctx)) 506 goto err; 507 508 /* kemctx is the concat of both sides encoded public key */ 509 memcpy(kemctx, sender_pub, encodedkeylen); 510 memcpy(kemctx + encodedkeylen, recipient_pub, encodedkeylen); 511 if (auth) 512 memcpy(kemctx + 2 * encodedkeylen, sender_authpub, encodedkeylen); 513 kdfctx = ossl_kdf_ctx_create(ctx->kdfname, info->mdname, 514 ctx->libctx, ctx->propq); 515 if (kdfctx == NULL) 516 goto err; 517 if (!dhkem_extract_and_expand(kdfctx, secret, info->Nsecret, 518 info->kem_id, dhkm, dhkmlen, 519 kemctx, kemctxlen)) 520 goto err; 521 ret = 1; 522 err: 523 OPENSSL_cleanse(dhkm, dhkmlen); 524 EVP_KDF_CTX_free(kdfctx); 525 return ret; 526 } 527 528 /* 529 * Do a DHKEM encapsulate operation. 530 * 531 * See Section 4.1 Encap() and AuthEncap() 532 * 533 * Params: 534 * ctx A context object holding the recipients public key and the 535 * optional senders auth private key. 536 * enc A buffer to return the senders ephemeral public key. 537 * Setting this to NULL allows the enclen and secretlen to return 538 * values, without calculating the secret. 539 * enclen Passes in the max size of the enc buffer and returns the 540 * encoded public key length. 541 * secret A buffer to return the calculated shared secret. 542 * secretlen Passes in the max size of the secret buffer and returns the 543 * secret length. 544 * Returns: 1 on success or 0 otherwise. 545 */ 546 static int dhkem_encap(PROV_ECX_CTX *ctx, 547 unsigned char *enc, size_t *enclen, 548 unsigned char *secret, size_t *secretlen) 549 { 550 int ret = 0; 551 ECX_KEY *sender_ephemkey = NULL; 552 unsigned char *sender_ephempub, *recipient_pub; 553 const OSSL_HPKE_KEM_INFO *info = ctx->info; 554 555 if (enc == NULL) { 556 if (enclen == NULL && secretlen == NULL) 557 return 0; 558 if (enclen != NULL) 559 *enclen = info->Nenc; 560 if (secretlen != NULL) 561 *secretlen = info->Nsecret; 562 return 1; 563 } 564 565 if (*secretlen < info->Nsecret) { 566 ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*secretlen too small"); 567 return 0; 568 } 569 if (*enclen < info->Nenc) { 570 ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*enclen too small"); 571 return 0; 572 } 573 574 /* Create an ephemeral key */ 575 sender_ephemkey = derivekey(ctx, ctx->ikm, ctx->ikmlen); 576 577 sender_ephempub = ecx_pubkey(sender_ephemkey); 578 recipient_pub = ecx_pubkey(ctx->recipient_key); 579 if (sender_ephempub == NULL || recipient_pub == NULL) 580 goto err; 581 582 if (!derive_secret(ctx, secret, 583 sender_ephemkey, ctx->recipient_key, 584 ctx->sender_authkey, ctx->recipient_key, 585 sender_ephempub, recipient_pub)) 586 goto err; 587 588 /* Return the public part of the ephemeral key */ 589 memcpy(enc, sender_ephempub, info->Nenc); 590 *enclen = info->Nenc; 591 *secretlen = info->Nsecret; 592 ret = 1; 593 err: 594 ossl_ecx_key_free(sender_ephemkey); 595 return ret; 596 } 597 598 /* 599 * Do a DHKEM decapsulate operation. 600 * See Section 4.1 Decap() and Auth Decap() 601 * 602 * Params: 603 * ctx A context object holding the recipients private key and the 604 * optional senders auth public key. 605 * secret A buffer to return the calculated shared secret. Setting this to 606 * NULL can be used to return the secretlen. 607 * secretlen Passes in the max size of the secret buffer and returns the 608 * secret length. 609 * enc A buffer containing the senders ephemeral public key that was returned 610 * from dhkem_encap(). 611 * enclen The length in bytes of enc. 612 * Returns: 1 If the shared secret is returned or 0 on error. 613 */ 614 static int dhkem_decap(PROV_ECX_CTX *ctx, 615 unsigned char *secret, size_t *secretlen, 616 const unsigned char *enc, size_t enclen) 617 { 618 int ret = 0; 619 ECX_KEY *recipient_privkey = ctx->recipient_key; 620 ECX_KEY *sender_ephempubkey = NULL; 621 const OSSL_HPKE_KEM_INFO *info = ctx->info; 622 unsigned char *recipient_pub; 623 624 if (secret == NULL) { 625 *secretlen = info->Nsecret; 626 return 1; 627 } 628 if (*secretlen < info->Nsecret) { 629 ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*secretlen too small"); 630 return 0; 631 } 632 if (enclen != info->Nenc) { 633 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, "Invalid enc public key"); 634 return 0; 635 } 636 637 /* Get the public part of the ephemeral key created by encap */ 638 sender_ephempubkey = ecxkey_pubfromdata(ctx, enc, enclen); 639 if (sender_ephempubkey == NULL) 640 goto err; 641 642 recipient_pub = ecx_pubkey(recipient_privkey); 643 if (recipient_pub == NULL) 644 goto err; 645 646 if (!derive_secret(ctx, secret, 647 ctx->recipient_key, sender_ephempubkey, 648 ctx->recipient_key, ctx->sender_authkey, 649 enc, recipient_pub)) 650 goto err; 651 652 *secretlen = info->Nsecret; 653 ret = 1; 654 err: 655 ossl_ecx_key_free(sender_ephempubkey); 656 return ret; 657 } 658 659 static int ecxkem_encapsulate(void *vctx, unsigned char *out, size_t *outlen, 660 unsigned char *secret, size_t *secretlen) 661 { 662 PROV_ECX_CTX *ctx = (PROV_ECX_CTX *)vctx; 663 664 switch (ctx->mode) { 665 case KEM_MODE_DHKEM: 666 return dhkem_encap(ctx, out, outlen, secret, secretlen); 667 default: 668 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); 669 return -2; 670 } 671 } 672 673 static int ecxkem_decapsulate(void *vctx, unsigned char *out, size_t *outlen, 674 const unsigned char *in, size_t inlen) 675 { 676 PROV_ECX_CTX *ctx = (PROV_ECX_CTX *)vctx; 677 678 switch (ctx->mode) { 679 case KEM_MODE_DHKEM: 680 return dhkem_decap(vctx, out, outlen, in, inlen); 681 default: 682 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); 683 return -2; 684 } 685 } 686 687 const OSSL_DISPATCH ossl_ecx_asym_kem_functions[] = { 688 { OSSL_FUNC_KEM_NEWCTX, (void (*)(void))ecxkem_newctx }, 689 { OSSL_FUNC_KEM_ENCAPSULATE_INIT, 690 (void (*)(void))ecxkem_encapsulate_init }, 691 { OSSL_FUNC_KEM_ENCAPSULATE, (void (*)(void))ecxkem_encapsulate }, 692 { OSSL_FUNC_KEM_DECAPSULATE_INIT, 693 (void (*)(void))ecxkem_decapsulate_init }, 694 { OSSL_FUNC_KEM_DECAPSULATE, (void (*)(void))ecxkem_decapsulate }, 695 { OSSL_FUNC_KEM_FREECTX, (void (*)(void))ecxkem_freectx }, 696 { OSSL_FUNC_KEM_SET_CTX_PARAMS, 697 (void (*)(void))ecxkem_set_ctx_params }, 698 { OSSL_FUNC_KEM_SETTABLE_CTX_PARAMS, 699 (void (*)(void))ecxkem_settable_ctx_params }, 700 { OSSL_FUNC_KEM_AUTH_ENCAPSULATE_INIT, 701 (void (*)(void))ecxkem_auth_encapsulate_init }, 702 { OSSL_FUNC_KEM_AUTH_DECAPSULATE_INIT, 703 (void (*)(void))ecxkem_auth_decapsulate_init }, 704 OSSL_DISPATCH_END 705 }; 706