1 /* 2 * Copyright 2020-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 * ECDH 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/evp.h> 19 #include <openssl/core_dispatch.h> 20 #include <openssl/core_names.h> 21 #include <openssl/ec.h> 22 #include <openssl/params.h> 23 #include <openssl/err.h> 24 #include <openssl/proverr.h> 25 #include "prov/provider_ctx.h" 26 #include "prov/providercommon.h" 27 #include "prov/implementations.h" 28 #include "prov/securitycheck.h" 29 #include "crypto/ec.h" /* ossl_ecdh_kdf_X9_63() */ 30 31 static OSSL_FUNC_keyexch_newctx_fn ecdh_newctx; 32 static OSSL_FUNC_keyexch_init_fn ecdh_init; 33 static OSSL_FUNC_keyexch_set_peer_fn ecdh_set_peer; 34 static OSSL_FUNC_keyexch_derive_fn ecdh_derive; 35 static OSSL_FUNC_keyexch_freectx_fn ecdh_freectx; 36 static OSSL_FUNC_keyexch_dupctx_fn ecdh_dupctx; 37 static OSSL_FUNC_keyexch_set_ctx_params_fn ecdh_set_ctx_params; 38 static OSSL_FUNC_keyexch_settable_ctx_params_fn ecdh_settable_ctx_params; 39 static OSSL_FUNC_keyexch_get_ctx_params_fn ecdh_get_ctx_params; 40 static OSSL_FUNC_keyexch_gettable_ctx_params_fn ecdh_gettable_ctx_params; 41 42 enum kdf_type { 43 PROV_ECDH_KDF_NONE = 0, 44 PROV_ECDH_KDF_X9_63 45 }; 46 47 /* 48 * What's passed as an actual key is defined by the KEYMGMT interface. 49 * We happen to know that our KEYMGMT simply passes EC_KEY structures, so 50 * we use that here too. 51 */ 52 53 typedef struct { 54 OSSL_LIB_CTX *libctx; 55 56 EC_KEY *k; 57 EC_KEY *peerk; 58 59 /* 60 * ECDH cofactor mode: 61 * 62 * . 0 disabled 63 * . 1 enabled 64 * . -1 use cofactor mode set for k 65 */ 66 int cofactor_mode; 67 68 /************ 69 * ECDH KDF * 70 ************/ 71 /* KDF (if any) to use for ECDH */ 72 enum kdf_type kdf_type; 73 /* Message digest to use for key derivation */ 74 EVP_MD *kdf_md; 75 /* User key material */ 76 unsigned char *kdf_ukm; 77 size_t kdf_ukmlen; 78 /* KDF output length */ 79 size_t kdf_outlen; 80 OSSL_FIPS_IND_DECLARE 81 } PROV_ECDH_CTX; 82 83 static 84 void *ecdh_newctx(void *provctx) 85 { 86 PROV_ECDH_CTX *pectx; 87 88 if (!ossl_prov_is_running()) 89 return NULL; 90 91 pectx = OPENSSL_zalloc(sizeof(*pectx)); 92 if (pectx == NULL) 93 return NULL; 94 95 pectx->libctx = PROV_LIBCTX_OF(provctx); 96 pectx->cofactor_mode = -1; 97 pectx->kdf_type = PROV_ECDH_KDF_NONE; 98 OSSL_FIPS_IND_INIT(pectx) 99 100 return (void *)pectx; 101 } 102 103 static 104 int ecdh_init(void *vpecdhctx, void *vecdh, const OSSL_PARAM params[]) 105 { 106 PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx; 107 108 if (!ossl_prov_is_running() 109 || pecdhctx == NULL 110 || vecdh == NULL 111 || (EC_KEY_get0_group(vecdh) == NULL) 112 || !EC_KEY_up_ref(vecdh)) 113 return 0; 114 EC_KEY_free(pecdhctx->k); 115 pecdhctx->k = vecdh; 116 pecdhctx->cofactor_mode = -1; 117 pecdhctx->kdf_type = PROV_ECDH_KDF_NONE; 118 119 OSSL_FIPS_IND_SET_APPROVED(pecdhctx) 120 if (!ecdh_set_ctx_params(pecdhctx, params)) 121 return 0; 122 #ifdef FIPS_MODULE 123 if (!ossl_fips_ind_ec_key_check(OSSL_FIPS_IND_GET(pecdhctx), 124 OSSL_FIPS_IND_SETTABLE0, pecdhctx->libctx, 125 EC_KEY_get0_group(vecdh), "ECDH Init", 1)) 126 return 0; 127 #endif 128 return 1; 129 } 130 131 static 132 int ecdh_match_params(const EC_KEY *priv, const EC_KEY *peer) 133 { 134 int ret; 135 BN_CTX *ctx = NULL; 136 const EC_GROUP *group_priv = EC_KEY_get0_group(priv); 137 const EC_GROUP *group_peer = EC_KEY_get0_group(peer); 138 139 ctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(priv)); 140 if (ctx == NULL) { 141 ERR_raise(ERR_LIB_PROV, ERR_R_BN_LIB); 142 return 0; 143 } 144 ret = group_priv != NULL 145 && group_peer != NULL 146 && EC_GROUP_cmp(group_priv, group_peer, ctx) == 0; 147 if (!ret) 148 ERR_raise(ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS); 149 BN_CTX_free(ctx); 150 return ret; 151 } 152 153 static 154 int ecdh_set_peer(void *vpecdhctx, void *vecdh) 155 { 156 PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx; 157 158 if (!ossl_prov_is_running() 159 || pecdhctx == NULL 160 || vecdh == NULL 161 || !ecdh_match_params(pecdhctx->k, vecdh)) 162 return 0; 163 #ifdef FIPS_MODULE 164 if (!ossl_fips_ind_ec_key_check(OSSL_FIPS_IND_GET(pecdhctx), 165 OSSL_FIPS_IND_SETTABLE0, pecdhctx->libctx, 166 EC_KEY_get0_group(vecdh), "ECDH Set Peer", 167 1)) 168 return 0; 169 #endif 170 if (!EC_KEY_up_ref(vecdh)) 171 return 0; 172 173 EC_KEY_free(pecdhctx->peerk); 174 pecdhctx->peerk = vecdh; 175 return 1; 176 } 177 178 static 179 void ecdh_freectx(void *vpecdhctx) 180 { 181 PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx; 182 183 EC_KEY_free(pecdhctx->k); 184 EC_KEY_free(pecdhctx->peerk); 185 186 EVP_MD_free(pecdhctx->kdf_md); 187 OPENSSL_clear_free(pecdhctx->kdf_ukm, pecdhctx->kdf_ukmlen); 188 189 OPENSSL_free(pecdhctx); 190 } 191 192 static 193 void *ecdh_dupctx(void *vpecdhctx) 194 { 195 PROV_ECDH_CTX *srcctx = (PROV_ECDH_CTX *)vpecdhctx; 196 PROV_ECDH_CTX *dstctx; 197 198 if (!ossl_prov_is_running()) 199 return NULL; 200 201 dstctx = OPENSSL_zalloc(sizeof(*srcctx)); 202 if (dstctx == NULL) 203 return NULL; 204 205 *dstctx = *srcctx; 206 207 /* clear all pointers */ 208 209 dstctx->k= NULL; 210 dstctx->peerk = NULL; 211 dstctx->kdf_md = NULL; 212 dstctx->kdf_ukm = NULL; 213 214 /* up-ref all ref-counted objects referenced in dstctx */ 215 216 if (srcctx->k != NULL && !EC_KEY_up_ref(srcctx->k)) 217 goto err; 218 else 219 dstctx->k = srcctx->k; 220 221 if (srcctx->peerk != NULL && !EC_KEY_up_ref(srcctx->peerk)) 222 goto err; 223 else 224 dstctx->peerk = srcctx->peerk; 225 226 if (srcctx->kdf_md != NULL && !EVP_MD_up_ref(srcctx->kdf_md)) 227 goto err; 228 else 229 dstctx->kdf_md = srcctx->kdf_md; 230 231 /* Duplicate UKM data if present */ 232 if (srcctx->kdf_ukm != NULL && srcctx->kdf_ukmlen > 0) { 233 dstctx->kdf_ukm = OPENSSL_memdup(srcctx->kdf_ukm, 234 srcctx->kdf_ukmlen); 235 if (dstctx->kdf_ukm == NULL) 236 goto err; 237 } 238 239 return dstctx; 240 241 err: 242 ecdh_freectx(dstctx); 243 return NULL; 244 } 245 246 static 247 int ecdh_set_ctx_params(void *vpecdhctx, const OSSL_PARAM params[]) 248 { 249 char name[80] = { '\0' }; /* should be big enough */ 250 char *str = NULL; 251 PROV_ECDH_CTX *pectx = (PROV_ECDH_CTX *)vpecdhctx; 252 const OSSL_PARAM *p; 253 254 if (pectx == NULL) 255 return 0; 256 if (ossl_param_is_empty(params)) 257 return 1; 258 259 if (!OSSL_FIPS_IND_SET_CTX_PARAM(pectx, OSSL_FIPS_IND_SETTABLE0, params, 260 OSSL_EXCHANGE_PARAM_FIPS_KEY_CHECK)) 261 return 0; 262 if (!OSSL_FIPS_IND_SET_CTX_PARAM(pectx, OSSL_FIPS_IND_SETTABLE1, params, 263 OSSL_EXCHANGE_PARAM_FIPS_DIGEST_CHECK)) 264 return 0; 265 if (!OSSL_FIPS_IND_SET_CTX_PARAM(pectx, OSSL_FIPS_IND_SETTABLE2, params, 266 OSSL_EXCHANGE_PARAM_FIPS_ECDH_COFACTOR_CHECK)) 267 return 0; 268 269 p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE); 270 if (p != NULL) { 271 int mode; 272 273 if (!OSSL_PARAM_get_int(p, &mode)) 274 return 0; 275 276 if (mode < -1 || mode > 1) 277 return 0; 278 279 pectx->cofactor_mode = mode; 280 } 281 282 p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_TYPE); 283 if (p != NULL) { 284 str = name; 285 if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name))) 286 return 0; 287 288 if (name[0] == '\0') 289 pectx->kdf_type = PROV_ECDH_KDF_NONE; 290 else if (strcmp(name, OSSL_KDF_NAME_X963KDF) == 0) 291 pectx->kdf_type = PROV_ECDH_KDF_X9_63; 292 else 293 return 0; 294 } 295 296 p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST); 297 if (p != NULL) { 298 char mdprops[80] = { '\0' }; /* should be big enough */ 299 300 str = name; 301 if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name))) 302 return 0; 303 304 str = mdprops; 305 p = OSSL_PARAM_locate_const(params, 306 OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS); 307 308 if (p != NULL) { 309 if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops))) 310 return 0; 311 } 312 313 EVP_MD_free(pectx->kdf_md); 314 pectx->kdf_md = EVP_MD_fetch(pectx->libctx, name, mdprops); 315 if (pectx->kdf_md == NULL) 316 return 0; 317 /* XOF digests are not allowed */ 318 if (EVP_MD_xof(pectx->kdf_md)) { 319 ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED); 320 return 0; 321 } 322 #ifdef FIPS_MODULE 323 if (!ossl_fips_ind_digest_exch_check(OSSL_FIPS_IND_GET(pectx), 324 OSSL_FIPS_IND_SETTABLE1, pectx->libctx, 325 pectx->kdf_md, "ECDH Set Ctx")) { 326 EVP_MD_free(pectx->kdf_md); 327 pectx->kdf_md = NULL; 328 return 0; 329 } 330 #endif 331 } 332 333 p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN); 334 if (p != NULL) { 335 size_t outlen; 336 337 if (!OSSL_PARAM_get_size_t(p, &outlen)) 338 return 0; 339 pectx->kdf_outlen = outlen; 340 } 341 342 p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_UKM); 343 if (p != NULL) { 344 void *tmp_ukm = NULL; 345 size_t tmp_ukmlen; 346 347 if (!OSSL_PARAM_get_octet_string(p, &tmp_ukm, 0, &tmp_ukmlen)) 348 return 0; 349 OPENSSL_free(pectx->kdf_ukm); 350 pectx->kdf_ukm = tmp_ukm; 351 pectx->kdf_ukmlen = tmp_ukmlen; 352 } 353 354 return 1; 355 } 356 357 static const OSSL_PARAM known_settable_ctx_params[] = { 358 OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE, NULL), 359 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0), 360 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0), 361 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS, NULL, 0), 362 OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL), 363 OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM, NULL, 0), 364 OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_EXCHANGE_PARAM_FIPS_KEY_CHECK) 365 OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_EXCHANGE_PARAM_FIPS_DIGEST_CHECK) 366 OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_EXCHANGE_PARAM_FIPS_ECDH_COFACTOR_CHECK) 367 OSSL_PARAM_END 368 }; 369 370 static 371 const OSSL_PARAM *ecdh_settable_ctx_params(ossl_unused void *vpecdhctx, 372 ossl_unused void *provctx) 373 { 374 return known_settable_ctx_params; 375 } 376 377 static 378 int ecdh_get_ctx_params(void *vpecdhctx, OSSL_PARAM params[]) 379 { 380 PROV_ECDH_CTX *pectx = (PROV_ECDH_CTX *)vpecdhctx; 381 OSSL_PARAM *p; 382 383 if (pectx == NULL) 384 return 0; 385 386 p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE); 387 if (p != NULL) { 388 int mode = pectx->cofactor_mode; 389 390 if (mode == -1) { 391 /* check what is the default for pecdhctx->k */ 392 mode = EC_KEY_get_flags(pectx->k) & EC_FLAG_COFACTOR_ECDH ? 1 : 0; 393 } 394 395 if (!OSSL_PARAM_set_int(p, mode)) 396 return 0; 397 } 398 399 p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_TYPE); 400 if (p != NULL) { 401 const char *kdf_type = NULL; 402 403 switch (pectx->kdf_type) { 404 case PROV_ECDH_KDF_NONE: 405 kdf_type = ""; 406 break; 407 case PROV_ECDH_KDF_X9_63: 408 kdf_type = OSSL_KDF_NAME_X963KDF; 409 break; 410 default: 411 return 0; 412 } 413 414 if (!OSSL_PARAM_set_utf8_string(p, kdf_type)) 415 return 0; 416 } 417 418 p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST); 419 if (p != NULL 420 && !OSSL_PARAM_set_utf8_string(p, pectx->kdf_md == NULL 421 ? "" 422 : EVP_MD_get0_name(pectx->kdf_md))) { 423 return 0; 424 } 425 426 p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN); 427 if (p != NULL && !OSSL_PARAM_set_size_t(p, pectx->kdf_outlen)) 428 return 0; 429 430 p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_UKM); 431 if (p != NULL && 432 !OSSL_PARAM_set_octet_ptr(p, pectx->kdf_ukm, pectx->kdf_ukmlen)) 433 return 0; 434 if (!OSSL_FIPS_IND_GET_CTX_PARAM(pectx, params)) 435 return 0; 436 return 1; 437 } 438 439 static const OSSL_PARAM known_gettable_ctx_params[] = { 440 OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE, NULL), 441 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0), 442 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0), 443 OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL), 444 OSSL_PARAM_DEFN(OSSL_EXCHANGE_PARAM_KDF_UKM, OSSL_PARAM_OCTET_PTR, 445 NULL, 0), 446 OSSL_FIPS_IND_GETTABLE_CTX_PARAM() 447 OSSL_PARAM_END 448 }; 449 450 static 451 const OSSL_PARAM *ecdh_gettable_ctx_params(ossl_unused void *vpecdhctx, 452 ossl_unused void *provctx) 453 { 454 return known_gettable_ctx_params; 455 } 456 457 static ossl_inline 458 size_t ecdh_size(const EC_KEY *k) 459 { 460 size_t degree = 0; 461 const EC_GROUP *group; 462 463 if (k == NULL 464 || (group = EC_KEY_get0_group(k)) == NULL) 465 return 0; 466 467 degree = EC_GROUP_get_degree(group); 468 469 return (degree + 7) / 8; 470 } 471 472 static ossl_inline 473 int ecdh_plain_derive(void *vpecdhctx, unsigned char *secret, 474 size_t *psecretlen, size_t outlen) 475 { 476 PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx; 477 int retlen, ret = 0; 478 size_t ecdhsize, size; 479 const EC_POINT *ppubkey = NULL; 480 EC_KEY *privk = NULL; 481 const EC_GROUP *group; 482 const BIGNUM *cofactor; 483 int key_cofactor_mode; 484 int has_cofactor; 485 #ifdef FIPS_MODULE 486 int cofactor_approved = 0; 487 #endif 488 489 if (pecdhctx->k == NULL || pecdhctx->peerk == NULL) { 490 ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); 491 return 0; 492 } 493 494 ecdhsize = ecdh_size(pecdhctx->k); 495 if (secret == NULL) { 496 *psecretlen = ecdhsize; 497 return 1; 498 } 499 500 if ((group = EC_KEY_get0_group(pecdhctx->k)) == NULL 501 || (cofactor = EC_GROUP_get0_cofactor(group)) == NULL) 502 return 0; 503 504 has_cofactor = !BN_is_one(cofactor); 505 506 /* 507 * NB: unlike PKCS#3 DH, if outlen is less than maximum size this is not 508 * an error, the result is truncated. 509 */ 510 size = outlen < ecdhsize ? outlen : ecdhsize; 511 512 /* 513 * The ctx->cofactor_mode flag has precedence over the 514 * cofactor_mode flag set on ctx->k. 515 * 516 * - if ctx->cofactor_mode == -1, use ctx->k directly 517 * - if ctx->cofactor_mode == key_cofactor_mode, use ctx->k directly 518 * - if ctx->cofactor_mode != key_cofactor_mode: 519 * - if ctx->k->cofactor == 1, the cofactor_mode flag is irrelevant, use 520 * ctx->k directly 521 * - if ctx->k->cofactor != 1, use a duplicate of ctx->k with the flag 522 * set to ctx->cofactor_mode 523 */ 524 key_cofactor_mode = 525 (EC_KEY_get_flags(pecdhctx->k) & EC_FLAG_COFACTOR_ECDH) ? 1 : 0; 526 if (pecdhctx->cofactor_mode != -1 527 && pecdhctx->cofactor_mode != key_cofactor_mode 528 && has_cofactor) { 529 if ((privk = EC_KEY_dup(pecdhctx->k)) == NULL) 530 return 0; 531 532 if (pecdhctx->cofactor_mode == 1) { 533 EC_KEY_set_flags(privk, EC_FLAG_COFACTOR_ECDH); 534 #ifdef FIPS_MODULE 535 cofactor_approved = 1; 536 #endif 537 } else { 538 EC_KEY_clear_flags(privk, EC_FLAG_COFACTOR_ECDH); 539 } 540 } else { 541 privk = pecdhctx->k; 542 #ifdef FIPS_MODULE 543 cofactor_approved = key_cofactor_mode; 544 #endif 545 } 546 547 #ifdef FIPS_MODULE 548 /* 549 * SP800-56A r3 Section 5.7.1.2 requires ECC Cofactor DH to be used. 550 * This applies to the 'B' and 'K' curves that have cofactors that are not 1. 551 */ 552 if (has_cofactor && !cofactor_approved) { 553 if (!OSSL_FIPS_IND_ON_UNAPPROVED(pecdhctx, OSSL_FIPS_IND_SETTABLE2, 554 pecdhctx->libctx, "ECDH", "Cofactor", 555 ossl_fips_config_ecdh_cofactor_check)) { 556 ERR_raise(ERR_LIB_PROV, PROV_R_COFACTOR_REQUIRED); 557 goto end; 558 } 559 } 560 #endif 561 562 ppubkey = EC_KEY_get0_public_key(pecdhctx->peerk); 563 564 retlen = ECDH_compute_key(secret, size, ppubkey, privk, NULL); 565 566 if (retlen <= 0) 567 goto end; 568 569 *psecretlen = retlen; 570 ret = 1; 571 572 end: 573 if (privk != pecdhctx->k) 574 EC_KEY_free(privk); 575 return ret; 576 } 577 578 static ossl_inline 579 int ecdh_X9_63_kdf_derive(void *vpecdhctx, unsigned char *secret, 580 size_t *psecretlen, size_t outlen) 581 { 582 PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx; 583 unsigned char *stmp = NULL; 584 size_t stmplen; 585 int ret = 0; 586 587 if (secret == NULL) { 588 *psecretlen = pecdhctx->kdf_outlen; 589 return 1; 590 } 591 592 if (pecdhctx->kdf_outlen > outlen) { 593 ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); 594 return 0; 595 } 596 if (!ecdh_plain_derive(vpecdhctx, NULL, &stmplen, 0)) 597 return 0; 598 if ((stmp = OPENSSL_secure_malloc(stmplen)) == NULL) 599 return 0; 600 if (!ecdh_plain_derive(vpecdhctx, stmp, &stmplen, stmplen)) 601 goto err; 602 603 /* Do KDF stuff */ 604 if (!ossl_ecdh_kdf_X9_63(secret, pecdhctx->kdf_outlen, 605 stmp, stmplen, 606 pecdhctx->kdf_ukm, 607 pecdhctx->kdf_ukmlen, 608 pecdhctx->kdf_md, 609 pecdhctx->libctx, NULL)) 610 goto err; 611 *psecretlen = pecdhctx->kdf_outlen; 612 ret = 1; 613 614 err: 615 OPENSSL_secure_clear_free(stmp, stmplen); 616 return ret; 617 } 618 619 static 620 int ecdh_derive(void *vpecdhctx, unsigned char *secret, 621 size_t *psecretlen, size_t outlen) 622 { 623 PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx; 624 625 switch (pecdhctx->kdf_type) { 626 case PROV_ECDH_KDF_NONE: 627 return ecdh_plain_derive(vpecdhctx, secret, psecretlen, outlen); 628 case PROV_ECDH_KDF_X9_63: 629 return ecdh_X9_63_kdf_derive(vpecdhctx, secret, psecretlen, outlen); 630 default: 631 break; 632 } 633 return 0; 634 } 635 636 const OSSL_DISPATCH ossl_ecdh_keyexch_functions[] = { 637 { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))ecdh_newctx }, 638 { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))ecdh_init }, 639 { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))ecdh_derive }, 640 { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))ecdh_set_peer }, 641 { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))ecdh_freectx }, 642 { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))ecdh_dupctx }, 643 { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))ecdh_set_ctx_params }, 644 { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS, 645 (void (*)(void))ecdh_settable_ctx_params }, 646 { OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS, (void (*)(void))ecdh_get_ctx_params }, 647 { OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS, 648 (void (*)(void))ecdh_gettable_ctx_params }, 649 OSSL_DISPATCH_END 650 }; 651