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 * EC keys (i.e. P-256, P-384 and P-521) 13 * References to Sections in the comments below refer to RFC 9180. 14 */ 15 16 #include "internal/deprecated.h" 17 18 #include <openssl/crypto.h> 19 #include <openssl/evp.h> 20 #include <openssl/core_dispatch.h> 21 #include <openssl/core_names.h> 22 #include <openssl/ec.h> 23 #include <openssl/params.h> 24 #include <openssl/err.h> 25 #include <openssl/proverr.h> 26 #include <openssl/kdf.h> 27 #include <openssl/rand.h> 28 #include "prov/provider_ctx.h" 29 #include "prov/implementations.h" 30 #include "prov/securitycheck.h" 31 #include "prov/providercommon.h" 32 33 #include <openssl/hpke.h> 34 #include "internal/hpke_util.h" 35 #include "crypto/ec.h" 36 #include "prov/ecx.h" 37 #include "eckem.h" 38 39 typedef struct { 40 EC_KEY *recipient_key; 41 EC_KEY *sender_authkey; 42 OSSL_LIB_CTX *libctx; 43 char *propq; 44 unsigned int mode; 45 unsigned int op; 46 unsigned char *ikm; 47 size_t ikmlen; 48 const char *kdfname; 49 const OSSL_HPKE_KEM_INFO *info; 50 } PROV_EC_CTX; 51 52 static OSSL_FUNC_kem_newctx_fn eckem_newctx; 53 static OSSL_FUNC_kem_encapsulate_init_fn eckem_encapsulate_init; 54 static OSSL_FUNC_kem_auth_encapsulate_init_fn eckem_auth_encapsulate_init; 55 static OSSL_FUNC_kem_encapsulate_fn eckem_encapsulate; 56 static OSSL_FUNC_kem_decapsulate_init_fn eckem_decapsulate_init; 57 static OSSL_FUNC_kem_auth_decapsulate_init_fn eckem_auth_decapsulate_init; 58 static OSSL_FUNC_kem_decapsulate_fn eckem_decapsulate; 59 static OSSL_FUNC_kem_freectx_fn eckem_freectx; 60 static OSSL_FUNC_kem_set_ctx_params_fn eckem_set_ctx_params; 61 static OSSL_FUNC_kem_settable_ctx_params_fn eckem_settable_ctx_params; 62 63 /* ASCII: "KEM", in hex for EBCDIC compatibility */ 64 static const char LABEL_KEM[] = "\x4b\x45\x4d"; 65 66 static int eckey_check(const EC_KEY *ec, int requires_privatekey) 67 { 68 int rv = 0; 69 BN_CTX *bnctx = NULL; 70 BIGNUM *rem = NULL; 71 const BIGNUM *priv = EC_KEY_get0_private_key(ec); 72 const EC_POINT *pub = EC_KEY_get0_public_key(ec); 73 74 /* Keys always require a public component */ 75 if (pub == NULL) { 76 ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY); 77 return 0; 78 } 79 if (priv == NULL) { 80 return (requires_privatekey == 0); 81 } else { 82 /* If there is a private key, check that is non zero (mod order) */ 83 const EC_GROUP *group = EC_KEY_get0_group(ec); 84 const BIGNUM *order = EC_GROUP_get0_order(group); 85 86 bnctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(ec)); 87 rem = BN_new(); 88 89 if (order != NULL && rem != NULL && bnctx != NULL) { 90 rv = BN_mod(rem, priv, order, bnctx) 91 && !BN_is_zero(rem); 92 } 93 } 94 BN_free(rem); 95 BN_CTX_free(bnctx); 96 return rv; 97 } 98 99 /* Returns NULL if the curve is not supported */ 100 static const char *ec_curvename_get0(const EC_KEY *ec) 101 { 102 const EC_GROUP *group = EC_KEY_get0_group(ec); 103 104 return EC_curve_nid2nist(EC_GROUP_get_curve_name(group)); 105 } 106 107 /* 108 * Set the recipient key, and free any existing key. 109 * ec can be NULL. 110 * The ec key may have only a private or public component 111 * (but it must have a group). 112 */ 113 static int recipient_key_set(PROV_EC_CTX *ctx, EC_KEY *ec) 114 { 115 EC_KEY_free(ctx->recipient_key); 116 ctx->recipient_key = NULL; 117 118 if (ec != NULL) { 119 const char *curve = ec_curvename_get0(ec); 120 121 if (curve == NULL) 122 return -2; 123 ctx->info = ossl_HPKE_KEM_INFO_find_curve(curve); 124 if (ctx->info == NULL) 125 return -2; 126 if (!EC_KEY_up_ref(ec)) 127 return 0; 128 ctx->recipient_key = ec; 129 ctx->kdfname = "HKDF"; 130 } 131 return 1; 132 } 133 134 /* 135 * Set the senders auth key, and free any existing auth key. 136 * ec can be NULL. 137 */ 138 static int sender_authkey_set(PROV_EC_CTX *ctx, EC_KEY *ec) 139 { 140 EC_KEY_free(ctx->sender_authkey); 141 ctx->sender_authkey = NULL; 142 143 if (ec != NULL) { 144 if (!EC_KEY_up_ref(ec)) 145 return 0; 146 ctx->sender_authkey = ec; 147 } 148 return 1; 149 } 150 151 /* 152 * Serializes a encoded public key buffer into a EC public key. 153 * Params: 154 * in Contains the group. 155 * pubbuf The encoded public key buffer 156 * Returns: The created public EC key, or NULL if there is an error. 157 */ 158 static EC_KEY *eckey_frompub(EC_KEY *in, 159 const unsigned char *pubbuf, size_t pubbuflen) 160 { 161 EC_KEY *key; 162 163 key = EC_KEY_new_ex(ossl_ec_key_get_libctx(in), ossl_ec_key_get0_propq(in)); 164 if (key == NULL) 165 goto err; 166 if (!EC_KEY_set_group(key, EC_KEY_get0_group(in))) 167 goto err; 168 if (!EC_KEY_oct2key(key, pubbuf, pubbuflen, NULL)) 169 goto err; 170 return key; 171 err: 172 EC_KEY_free(key); 173 return NULL; 174 } 175 176 /* 177 * Deserialises a EC public key into a encoded byte array. 178 * Returns: 1 if successful or 0 otherwise. 179 */ 180 static int ecpubkey_todata(const EC_KEY *ec, unsigned char *out, size_t *outlen, 181 size_t maxoutlen) 182 { 183 const EC_POINT *pub; 184 const EC_GROUP *group; 185 186 group = EC_KEY_get0_group(ec); 187 pub = EC_KEY_get0_public_key(ec); 188 *outlen = EC_POINT_point2oct(group, pub, POINT_CONVERSION_UNCOMPRESSED, 189 out, maxoutlen, NULL); 190 return *outlen != 0; 191 } 192 193 static void *eckem_newctx(void *provctx) 194 { 195 PROV_EC_CTX *ctx = OPENSSL_zalloc(sizeof(PROV_EC_CTX)); 196 197 if (ctx == NULL) 198 return NULL; 199 ctx->libctx = PROV_LIBCTX_OF(provctx); 200 ctx->mode = KEM_MODE_DHKEM; 201 202 return ctx; 203 } 204 205 static void eckem_freectx(void *vectx) 206 { 207 PROV_EC_CTX *ctx = (PROV_EC_CTX *)vectx; 208 209 OPENSSL_clear_free(ctx->ikm, ctx->ikmlen); 210 recipient_key_set(ctx, NULL); 211 sender_authkey_set(ctx, NULL); 212 OPENSSL_free(ctx); 213 } 214 215 static int ossl_ec_match_params(const EC_KEY *key1, const EC_KEY *key2) 216 { 217 int ret; 218 BN_CTX *ctx = NULL; 219 const EC_GROUP *group1 = EC_KEY_get0_group(key1); 220 const EC_GROUP *group2 = EC_KEY_get0_group(key2); 221 222 ctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(key1)); 223 if (ctx == NULL) 224 return 0; 225 226 ret = group1 != NULL 227 && group2 != NULL 228 && EC_GROUP_cmp(group1, group2, ctx) == 0; 229 if (!ret) 230 ERR_raise(ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS); 231 BN_CTX_free(ctx); 232 return ret; 233 } 234 235 static int eckem_init(void *vctx, int operation, void *vec, void *vauth, 236 const OSSL_PARAM params[]) 237 { 238 int rv; 239 PROV_EC_CTX *ctx = (PROV_EC_CTX *)vctx; 240 EC_KEY *ec = vec; 241 EC_KEY *auth = vauth; 242 243 if (!ossl_prov_is_running()) 244 return 0; 245 246 if (!eckey_check(ec, operation == EVP_PKEY_OP_DECAPSULATE)) 247 return 0; 248 rv = recipient_key_set(ctx, ec); 249 if (rv <= 0) 250 return rv; 251 252 if (auth != NULL) { 253 if (!ossl_ec_match_params(ec, auth) 254 || !eckey_check(auth, operation == EVP_PKEY_OP_ENCAPSULATE) 255 || !sender_authkey_set(ctx, auth)) 256 return 0; 257 } 258 259 ctx->op = operation; 260 return eckem_set_ctx_params(vctx, params); 261 } 262 263 static int eckem_encapsulate_init(void *vctx, void *vec, 264 const OSSL_PARAM params[]) 265 { 266 return eckem_init(vctx, EVP_PKEY_OP_ENCAPSULATE, vec, NULL, params); 267 } 268 269 static int eckem_decapsulate_init(void *vctx, void *vec, 270 const OSSL_PARAM params[]) 271 { 272 return eckem_init(vctx, EVP_PKEY_OP_DECAPSULATE, vec, NULL, params); 273 } 274 275 static int eckem_auth_encapsulate_init(void *vctx, void *vecx, void *vauthpriv, 276 const OSSL_PARAM params[]) 277 { 278 return eckem_init(vctx, EVP_PKEY_OP_ENCAPSULATE, vecx, vauthpriv, params); 279 } 280 281 static int eckem_auth_decapsulate_init(void *vctx, void *vecx, void *vauthpub, 282 const OSSL_PARAM params[]) 283 { 284 return eckem_init(vctx, EVP_PKEY_OP_DECAPSULATE, vecx, vauthpub, params); 285 } 286 287 static int eckem_set_ctx_params(void *vctx, const OSSL_PARAM params[]) 288 { 289 PROV_EC_CTX *ctx = (PROV_EC_CTX *)vctx; 290 const OSSL_PARAM *p; 291 int mode; 292 293 if (ossl_param_is_empty(params)) 294 return 1; 295 296 p = OSSL_PARAM_locate_const(params, OSSL_KEM_PARAM_IKME); 297 if (p != NULL) { 298 void *tmp = NULL; 299 size_t tmplen = 0; 300 301 if (p->data != NULL && p->data_size != 0) { 302 if (!OSSL_PARAM_get_octet_string(p, &tmp, 0, &tmplen)) 303 return 0; 304 } 305 OPENSSL_clear_free(ctx->ikm, ctx->ikmlen); 306 /* Set the ephemeral seed */ 307 ctx->ikm = tmp; 308 ctx->ikmlen = tmplen; 309 } 310 311 p = OSSL_PARAM_locate_const(params, OSSL_KEM_PARAM_OPERATION); 312 if (p != NULL) { 313 if (p->data_type != OSSL_PARAM_UTF8_STRING) 314 return 0; 315 mode = ossl_eckem_modename2id(p->data); 316 if (mode == KEM_MODE_UNDEFINED) 317 return 0; 318 ctx->mode = mode; 319 } 320 return 1; 321 } 322 323 static const OSSL_PARAM known_settable_eckem_ctx_params[] = { 324 OSSL_PARAM_utf8_string(OSSL_KEM_PARAM_OPERATION, NULL, 0), 325 OSSL_PARAM_octet_string(OSSL_KEM_PARAM_IKME, NULL, 0), 326 OSSL_PARAM_END 327 }; 328 329 static const OSSL_PARAM *eckem_settable_ctx_params(ossl_unused void *vctx, 330 ossl_unused void *provctx) 331 { 332 return known_settable_eckem_ctx_params; 333 } 334 335 /* 336 * See Section 4.1 DH-Based KEM (DHKEM) ExtractAndExpand 337 */ 338 static int dhkem_extract_and_expand(EVP_KDF_CTX *kctx, 339 unsigned char *okm, size_t okmlen, 340 uint16_t kemid, 341 const unsigned char *dhkm, size_t dhkmlen, 342 const unsigned char *kemctx, 343 size_t kemctxlen) 344 { 345 uint8_t suiteid[2]; 346 uint8_t prk[EVP_MAX_MD_SIZE]; 347 size_t prklen = okmlen; 348 int ret; 349 350 if (prklen > sizeof(prk)) 351 return 0; 352 353 suiteid[0] = (kemid >> 8) & 0xff; 354 suiteid[1] = kemid & 0xff; 355 356 ret = ossl_hpke_labeled_extract(kctx, prk, prklen, 357 NULL, 0, LABEL_KEM, suiteid, sizeof(suiteid), 358 OSSL_DHKEM_LABEL_EAE_PRK, dhkm, dhkmlen) 359 && ossl_hpke_labeled_expand(kctx, okm, okmlen, prk, prklen, 360 LABEL_KEM, suiteid, sizeof(suiteid), 361 OSSL_DHKEM_LABEL_SHARED_SECRET, 362 kemctx, kemctxlen); 363 OPENSSL_cleanse(prk, prklen); 364 return ret; 365 } 366 367 /* 368 * See Section 7.1.3 DeriveKeyPair. 369 * 370 * This function is used by ec keygen. 371 * (For this reason it does not use any of the state stored in PROV_EC_CTX). 372 * 373 * Params: 374 * ec An initialized ec key. 375 * priv The buffer to store the generated private key into (it is assumed 376 * this is of length alg->encodedprivlen). 377 * ikm buffer containing the input key material (seed). This must be set. 378 * ikmlen size of the ikm buffer in bytes 379 * Returns: 380 * 1 if successful or 0 otherwise. 381 */ 382 int ossl_ec_dhkem_derive_private(EC_KEY *ec, BIGNUM *priv, 383 const unsigned char *ikm, size_t ikmlen) 384 { 385 int ret = 0; 386 EVP_KDF_CTX *kdfctx = NULL; 387 uint8_t suiteid[2]; 388 unsigned char prk[OSSL_HPKE_MAX_SECRET]; 389 unsigned char privbuf[OSSL_HPKE_MAX_PRIVATE]; 390 const BIGNUM *order; 391 unsigned char counter = 0; 392 const char *curve = ec_curvename_get0(ec); 393 const OSSL_HPKE_KEM_INFO *info; 394 395 if (curve == NULL) 396 return -2; 397 398 info = ossl_HPKE_KEM_INFO_find_curve(curve); 399 if (info == NULL) 400 return -2; 401 402 kdfctx = ossl_kdf_ctx_create("HKDF", info->mdname, 403 ossl_ec_key_get_libctx(ec), 404 ossl_ec_key_get0_propq(ec)); 405 if (kdfctx == NULL) 406 return 0; 407 408 /* ikmlen should have a length of at least Nsk */ 409 if (ikmlen < info->Nsk) { 410 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_INPUT_LENGTH, 411 "ikm length is :%zu, should be at least %zu", 412 ikmlen, info->Nsk); 413 goto err; 414 } 415 416 suiteid[0] = info->kem_id / 256; 417 suiteid[1] = info->kem_id % 256; 418 419 if (!ossl_hpke_labeled_extract(kdfctx, prk, info->Nsecret, 420 NULL, 0, LABEL_KEM, suiteid, sizeof(suiteid), 421 OSSL_DHKEM_LABEL_DKP_PRK, ikm, ikmlen)) 422 goto err; 423 424 order = EC_GROUP_get0_order(EC_KEY_get0_group(ec)); 425 do { 426 if (!ossl_hpke_labeled_expand(kdfctx, privbuf, info->Nsk, 427 prk, info->Nsecret, 428 LABEL_KEM, suiteid, sizeof(suiteid), 429 OSSL_DHKEM_LABEL_CANDIDATE, 430 &counter, 1)) 431 goto err; 432 privbuf[0] &= info->bitmask; 433 if (BN_bin2bn(privbuf, info->Nsk, priv) == NULL) 434 goto err; 435 if (counter == 0xFF) { 436 ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GENERATE_KEY); 437 goto err; 438 } 439 counter++; 440 } while (BN_is_zero(priv) || BN_cmp(priv, order) >= 0); 441 ret = 1; 442 err: 443 OPENSSL_cleanse(prk, sizeof(prk)); 444 OPENSSL_cleanse(privbuf, sizeof(privbuf)); 445 EVP_KDF_CTX_free(kdfctx); 446 return ret; 447 } 448 449 /* 450 * Do a keygen operation without having to use EVP_PKEY. 451 * Params: 452 * ctx Context object 453 * ikm The seed material - if this is NULL, then a random seed is used. 454 * Returns: 455 * The generated EC key, or NULL on failure. 456 */ 457 static EC_KEY *derivekey(PROV_EC_CTX *ctx, 458 const unsigned char *ikm, size_t ikmlen) 459 { 460 int ret = 0; 461 EC_KEY *key; 462 unsigned char *seed = (unsigned char *)ikm; 463 size_t seedlen = ikmlen; 464 unsigned char tmpbuf[OSSL_HPKE_MAX_PRIVATE]; 465 466 key = EC_KEY_new_ex(ctx->libctx, ctx->propq); 467 if (key == NULL) 468 goto err; 469 if (!EC_KEY_set_group(key, EC_KEY_get0_group(ctx->recipient_key))) 470 goto err; 471 472 /* Generate a random seed if there is no input ikm */ 473 if (seed == NULL || seedlen == 0) { 474 seedlen = ctx->info->Nsk; 475 if (seedlen > sizeof(tmpbuf)) 476 goto err; 477 if (RAND_priv_bytes_ex(ctx->libctx, tmpbuf, seedlen, 0) <= 0) 478 goto err; 479 seed = tmpbuf; 480 } 481 ret = ossl_ec_generate_key_dhkem(key, seed, seedlen); 482 err: 483 if (seed != ikm) 484 OPENSSL_cleanse(seed, seedlen); 485 if (ret <= 0) { 486 EC_KEY_free(key); 487 key = NULL; 488 } 489 return key; 490 } 491 492 /* 493 * Before doing a key exchange the public key of the peer needs to be checked 494 * Note that the group check is not done here as we have already checked 495 * that it only uses one of the approved curve names when the key was set. 496 * 497 * Returns 1 if the public key is valid, or 0 if it fails. 498 */ 499 static int check_publickey(const EC_KEY *pub) 500 { 501 int ret = 0; 502 BN_CTX *bnctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(pub)); 503 504 if (bnctx == NULL) 505 return 0; 506 ret = ossl_ec_key_public_check(pub, bnctx); 507 BN_CTX_free(bnctx); 508 509 return ret; 510 } 511 512 /* 513 * Do an ecdh key exchange. 514 * dhkm = DH(sender, peer) 515 * 516 * NOTE: Instead of using EVP_PKEY_derive() API's, we use EC_KEY operations 517 * to avoid messy conversions back to EVP_PKEY. 518 * 519 * Returns the size of the secret if successful, or 0 otherwise, 520 */ 521 static int generate_ecdhkm(const EC_KEY *sender, const EC_KEY *peer, 522 unsigned char *out, size_t maxout, 523 unsigned int secretsz) 524 { 525 const EC_GROUP *group = EC_KEY_get0_group(sender); 526 size_t secretlen = (EC_GROUP_get_degree(group) + 7) / 8; 527 528 if (secretlen != secretsz || secretlen > maxout) { 529 ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "secretsz invalid"); 530 return 0; 531 } 532 533 if (!check_publickey(peer)) 534 return 0; 535 return ECDH_compute_key(out, secretlen, EC_KEY_get0_public_key(peer), 536 sender, NULL) > 0; 537 } 538 539 /* 540 * Derive a secret using ECDH (code is shared by the encap and decap) 541 * 542 * dhkm = Concat(ecdh(privkey1, peerkey1), ecdh(privkey2, peerkey2) 543 * kemctx = Concat(sender_pub, recipient_pub, ctx->sender_authkey) 544 * secret = dhkem_extract_and_expand(kemid, dhkm, kemctx); 545 * 546 * Params: 547 * ctx Object that contains algorithm state and constants. 548 * secret The returned secret (with a length ctx->alg->secretlen bytes). 549 * privkey1 A private key used for ECDH key derivation. 550 * peerkey1 A public key used for ECDH key derivation with privkey1 551 * privkey2 A optional private key used for a second ECDH key derivation. 552 * It can be NULL. 553 * peerkey2 A optional public key used for a second ECDH key derivation 554 * with privkey2,. It can be NULL. 555 * sender_pub The senders public key in encoded form. 556 * recipient_pub The recipients public key in encoded form. 557 * Notes: 558 * The second ecdh() is only used for the HPKE auth modes when both privkey2 559 * and peerkey2 are non NULL (i.e. ctx->sender_authkey is not NULL). 560 */ 561 static int derive_secret(PROV_EC_CTX *ctx, unsigned char *secret, 562 const EC_KEY *privkey1, const EC_KEY *peerkey1, 563 const EC_KEY *privkey2, const EC_KEY *peerkey2, 564 const unsigned char *sender_pub, 565 const unsigned char *recipient_pub) 566 { 567 int ret = 0; 568 EVP_KDF_CTX *kdfctx = NULL; 569 unsigned char sender_authpub[OSSL_HPKE_MAX_PUBLIC]; 570 unsigned char dhkm[OSSL_HPKE_MAX_PRIVATE * 2]; 571 unsigned char kemctx[OSSL_HPKE_MAX_PUBLIC * 3]; 572 size_t sender_authpublen; 573 size_t kemctxlen = 0, dhkmlen = 0; 574 const OSSL_HPKE_KEM_INFO *info = ctx->info; 575 size_t encodedpublen = info->Npk; 576 size_t encodedprivlen = info->Nsk; 577 int auth = ctx->sender_authkey != NULL; 578 579 if (!generate_ecdhkm(privkey1, peerkey1, dhkm, sizeof(dhkm), encodedprivlen)) 580 goto err; 581 dhkmlen = encodedprivlen; 582 kemctxlen = 2 * encodedpublen; 583 584 /* Concat the optional second ECDH (used for Auth) */ 585 if (auth) { 586 /* Get the public key of the auth sender in encoded form */ 587 if (!ecpubkey_todata(ctx->sender_authkey, sender_authpub, 588 &sender_authpublen, sizeof(sender_authpub))) 589 goto err; 590 if (sender_authpublen != encodedpublen) { 591 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, 592 "Invalid sender auth public key"); 593 goto err; 594 } 595 if (!generate_ecdhkm(privkey2, peerkey2, 596 dhkm + dhkmlen, sizeof(dhkm) - dhkmlen, 597 encodedprivlen)) 598 goto err; 599 dhkmlen += encodedprivlen; 600 kemctxlen += encodedpublen; 601 } 602 if (kemctxlen > sizeof(kemctx)) 603 goto err; 604 605 /* kemctx is the concat of both sides encoded public key */ 606 memcpy(kemctx, sender_pub, info->Npk); 607 memcpy(kemctx + info->Npk, recipient_pub, info->Npk); 608 if (auth) 609 memcpy(kemctx + 2 * encodedpublen, sender_authpub, encodedpublen); 610 kdfctx = ossl_kdf_ctx_create(ctx->kdfname, info->mdname, 611 ctx->libctx, ctx->propq); 612 if (kdfctx == NULL) 613 goto err; 614 if (!dhkem_extract_and_expand(kdfctx, secret, info->Nsecret, 615 info->kem_id, dhkm, dhkmlen, 616 kemctx, kemctxlen)) 617 goto err; 618 ret = 1; 619 err: 620 OPENSSL_cleanse(dhkm, dhkmlen); 621 EVP_KDF_CTX_free(kdfctx); 622 return ret; 623 } 624 625 /* 626 * Do a DHKEM encapsulate operation. 627 * 628 * See Section 4.1 Encap() and AuthEncap() 629 * 630 * Params: 631 * ctx A context object holding the recipients public key and the 632 * optional senders auth private key. 633 * enc A buffer to return the senders ephemeral public key. 634 * Setting this to NULL allows the enclen and secretlen to return 635 * values, without calculating the secret. 636 * enclen Passes in the max size of the enc buffer and returns the 637 * encoded public key length. 638 * secret A buffer to return the calculated shared secret. 639 * secretlen Passes in the max size of the secret buffer and returns the 640 * secret length. 641 * Returns: 1 on success or 0 otherwise. 642 */ 643 static int dhkem_encap(PROV_EC_CTX *ctx, 644 unsigned char *enc, size_t *enclen, 645 unsigned char *secret, size_t *secretlen) 646 { 647 int ret = 0; 648 EC_KEY *sender_ephemkey = NULL; 649 unsigned char sender_pub[OSSL_HPKE_MAX_PUBLIC]; 650 unsigned char recipient_pub[OSSL_HPKE_MAX_PUBLIC]; 651 size_t sender_publen, recipient_publen; 652 const OSSL_HPKE_KEM_INFO *info = ctx->info; 653 654 if (enc == NULL) { 655 if (enclen == NULL && secretlen == NULL) 656 return 0; 657 if (enclen != NULL) 658 *enclen = info->Nenc; 659 if (secretlen != NULL) 660 *secretlen = info->Nsecret; 661 return 1; 662 } 663 664 if (*secretlen < info->Nsecret) { 665 ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*secretlen too small"); 666 return 0; 667 } 668 if (*enclen < info->Nenc) { 669 ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*enclen too small"); 670 return 0; 671 } 672 673 /* Create an ephemeral key */ 674 sender_ephemkey = derivekey(ctx, ctx->ikm, ctx->ikmlen); 675 if (sender_ephemkey == NULL) 676 goto err; 677 if (!ecpubkey_todata(sender_ephemkey, sender_pub, &sender_publen, 678 sizeof(sender_pub)) 679 || !ecpubkey_todata(ctx->recipient_key, recipient_pub, 680 &recipient_publen, sizeof(recipient_pub))) 681 goto err; 682 683 if (sender_publen != info->Npk 684 || recipient_publen != sender_publen) { 685 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, "Invalid public key"); 686 goto err; 687 } 688 689 if (!derive_secret(ctx, secret, 690 sender_ephemkey, ctx->recipient_key, 691 ctx->sender_authkey, ctx->recipient_key, 692 sender_pub, recipient_pub)) 693 goto err; 694 695 /* Return the senders ephemeral public key in encoded form */ 696 memcpy(enc, sender_pub, sender_publen); 697 *enclen = sender_publen; 698 *secretlen = info->Nsecret; 699 ret = 1; 700 err: 701 EC_KEY_free(sender_ephemkey); 702 return ret; 703 } 704 705 /* 706 * Do a DHKEM decapsulate operation. 707 * See Section 4.1 Decap() and Auth Decap() 708 * 709 * Params: 710 * ctx A context object holding the recipients private key and the 711 * optional senders auth public key. 712 * secret A buffer to return the calculated shared secret. Setting this to 713 * NULL can be used to return the secretlen. 714 * secretlen Passes in the max size of the secret buffer and returns the 715 * secret length. 716 * enc A buffer containing the senders ephemeral public key that was returned 717 * from dhkem_encap(). 718 * enclen The length in bytes of enc. 719 * Returns: 1 If the shared secret is returned or 0 on error. 720 */ 721 static int dhkem_decap(PROV_EC_CTX *ctx, 722 unsigned char *secret, size_t *secretlen, 723 const unsigned char *enc, size_t enclen) 724 { 725 int ret = 0; 726 EC_KEY *sender_ephempubkey = NULL; 727 const OSSL_HPKE_KEM_INFO *info = ctx->info; 728 unsigned char recipient_pub[OSSL_HPKE_MAX_PUBLIC]; 729 size_t recipient_publen; 730 size_t encodedpublen = info->Npk; 731 732 if (secret == NULL) { 733 *secretlen = info->Nsecret; 734 return 1; 735 } 736 737 if (*secretlen < info->Nsecret) { 738 ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_LENGTH, "*secretlen too small"); 739 return 0; 740 } 741 if (enclen != encodedpublen) { 742 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, "Invalid enc public key"); 743 return 0; 744 } 745 746 sender_ephempubkey = eckey_frompub(ctx->recipient_key, enc, enclen); 747 if (sender_ephempubkey == NULL) 748 goto err; 749 if (!ecpubkey_todata(ctx->recipient_key, recipient_pub, &recipient_publen, 750 sizeof(recipient_pub))) 751 goto err; 752 if (recipient_publen != encodedpublen) { 753 ERR_raise_data(ERR_LIB_PROV, PROV_R_INVALID_KEY, "Invalid recipient public key"); 754 goto err; 755 } 756 757 if (!derive_secret(ctx, secret, 758 ctx->recipient_key, sender_ephempubkey, 759 ctx->recipient_key, ctx->sender_authkey, 760 enc, recipient_pub)) 761 goto err; 762 *secretlen = info->Nsecret; 763 ret = 1; 764 err: 765 EC_KEY_free(sender_ephempubkey); 766 return ret; 767 } 768 769 static int eckem_encapsulate(void *vctx, unsigned char *out, size_t *outlen, 770 unsigned char *secret, size_t *secretlen) 771 { 772 PROV_EC_CTX *ctx = (PROV_EC_CTX *)vctx; 773 774 switch (ctx->mode) { 775 case KEM_MODE_DHKEM: 776 return dhkem_encap(ctx, out, outlen, secret, secretlen); 777 default: 778 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); 779 return -2; 780 } 781 } 782 783 static int eckem_decapsulate(void *vctx, unsigned char *out, size_t *outlen, 784 const unsigned char *in, size_t inlen) 785 { 786 PROV_EC_CTX *ctx = (PROV_EC_CTX *)vctx; 787 788 switch (ctx->mode) { 789 case KEM_MODE_DHKEM: 790 return dhkem_decap(ctx, out, outlen, in, inlen); 791 default: 792 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); 793 return -2; 794 } 795 } 796 797 const OSSL_DISPATCH ossl_ec_asym_kem_functions[] = { 798 { OSSL_FUNC_KEM_NEWCTX, (void (*)(void))eckem_newctx }, 799 { OSSL_FUNC_KEM_ENCAPSULATE_INIT, 800 (void (*)(void))eckem_encapsulate_init }, 801 { OSSL_FUNC_KEM_ENCAPSULATE, (void (*)(void))eckem_encapsulate }, 802 { OSSL_FUNC_KEM_DECAPSULATE_INIT, 803 (void (*)(void))eckem_decapsulate_init }, 804 { OSSL_FUNC_KEM_DECAPSULATE, (void (*)(void))eckem_decapsulate }, 805 { OSSL_FUNC_KEM_FREECTX, (void (*)(void))eckem_freectx }, 806 { OSSL_FUNC_KEM_SET_CTX_PARAMS, 807 (void (*)(void))eckem_set_ctx_params }, 808 { OSSL_FUNC_KEM_SETTABLE_CTX_PARAMS, 809 (void (*)(void))eckem_settable_ctx_params }, 810 { OSSL_FUNC_KEM_AUTH_ENCAPSULATE_INIT, 811 (void (*)(void))eckem_auth_encapsulate_init }, 812 { OSSL_FUNC_KEM_AUTH_DECAPSULATE_INIT, 813 (void (*)(void))eckem_auth_decapsulate_init }, 814 OSSL_DISPATCH_END 815 }; 816