1 /* 2 * Copyright 2020-2021 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 } PROV_ECDH_CTX; 81 82 static 83 void *ecdh_newctx(void *provctx) 84 { 85 PROV_ECDH_CTX *pectx; 86 87 if (!ossl_prov_is_running()) 88 return NULL; 89 90 pectx = OPENSSL_zalloc(sizeof(*pectx)); 91 if (pectx == NULL) 92 return NULL; 93 94 pectx->libctx = PROV_LIBCTX_OF(provctx); 95 pectx->cofactor_mode = -1; 96 pectx->kdf_type = PROV_ECDH_KDF_NONE; 97 98 return (void *)pectx; 99 } 100 101 static 102 int ecdh_init(void *vpecdhctx, void *vecdh, const OSSL_PARAM params[]) 103 { 104 PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx; 105 106 if (!ossl_prov_is_running() 107 || pecdhctx == NULL 108 || vecdh == NULL 109 || !EC_KEY_up_ref(vecdh)) 110 return 0; 111 EC_KEY_free(pecdhctx->k); 112 pecdhctx->k = vecdh; 113 pecdhctx->cofactor_mode = -1; 114 pecdhctx->kdf_type = PROV_ECDH_KDF_NONE; 115 return ecdh_set_ctx_params(pecdhctx, params) 116 && ossl_ec_check_key(pecdhctx->libctx, vecdh, 1); 117 } 118 119 static 120 int ecdh_match_params(const EC_KEY *priv, const EC_KEY *peer) 121 { 122 int ret; 123 BN_CTX *ctx = NULL; 124 const EC_GROUP *group_priv = EC_KEY_get0_group(priv); 125 const EC_GROUP *group_peer = EC_KEY_get0_group(peer); 126 127 ctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(priv)); 128 if (ctx == NULL) { 129 ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); 130 return 0; 131 } 132 ret = group_priv != NULL 133 && group_peer != NULL 134 && EC_GROUP_cmp(group_priv, group_peer, ctx) == 0; 135 if (!ret) 136 ERR_raise(ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS); 137 BN_CTX_free(ctx); 138 return ret; 139 } 140 141 static 142 int ecdh_set_peer(void *vpecdhctx, void *vecdh) 143 { 144 PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx; 145 146 if (!ossl_prov_is_running() 147 || pecdhctx == NULL 148 || vecdh == NULL 149 || !ecdh_match_params(pecdhctx->k, vecdh) 150 || !ossl_ec_check_key(pecdhctx->libctx, vecdh, 1) 151 || !EC_KEY_up_ref(vecdh)) 152 return 0; 153 154 EC_KEY_free(pecdhctx->peerk); 155 pecdhctx->peerk = vecdh; 156 return 1; 157 } 158 159 static 160 void ecdh_freectx(void *vpecdhctx) 161 { 162 PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx; 163 164 EC_KEY_free(pecdhctx->k); 165 EC_KEY_free(pecdhctx->peerk); 166 167 EVP_MD_free(pecdhctx->kdf_md); 168 OPENSSL_clear_free(pecdhctx->kdf_ukm, pecdhctx->kdf_ukmlen); 169 170 OPENSSL_free(pecdhctx); 171 } 172 173 static 174 void *ecdh_dupctx(void *vpecdhctx) 175 { 176 PROV_ECDH_CTX *srcctx = (PROV_ECDH_CTX *)vpecdhctx; 177 PROV_ECDH_CTX *dstctx; 178 179 if (!ossl_prov_is_running()) 180 return NULL; 181 182 dstctx = OPENSSL_zalloc(sizeof(*srcctx)); 183 if (dstctx == NULL) 184 return NULL; 185 186 *dstctx = *srcctx; 187 188 /* clear all pointers */ 189 190 dstctx->k= NULL; 191 dstctx->peerk = NULL; 192 dstctx->kdf_md = NULL; 193 dstctx->kdf_ukm = NULL; 194 195 /* up-ref all ref-counted objects referenced in dstctx */ 196 197 if (srcctx->k != NULL && !EC_KEY_up_ref(srcctx->k)) 198 goto err; 199 else 200 dstctx->k = srcctx->k; 201 202 if (srcctx->peerk != NULL && !EC_KEY_up_ref(srcctx->peerk)) 203 goto err; 204 else 205 dstctx->peerk = srcctx->peerk; 206 207 if (srcctx->kdf_md != NULL && !EVP_MD_up_ref(srcctx->kdf_md)) 208 goto err; 209 else 210 dstctx->kdf_md = srcctx->kdf_md; 211 212 /* Duplicate UKM data if present */ 213 if (srcctx->kdf_ukm != NULL && srcctx->kdf_ukmlen > 0) { 214 dstctx->kdf_ukm = OPENSSL_memdup(srcctx->kdf_ukm, 215 srcctx->kdf_ukmlen); 216 if (dstctx->kdf_ukm == NULL) 217 goto err; 218 } 219 220 return dstctx; 221 222 err: 223 ecdh_freectx(dstctx); 224 return NULL; 225 } 226 227 static 228 int ecdh_set_ctx_params(void *vpecdhctx, const OSSL_PARAM params[]) 229 { 230 char name[80] = { '\0' }; /* should be big enough */ 231 char *str = NULL; 232 PROV_ECDH_CTX *pectx = (PROV_ECDH_CTX *)vpecdhctx; 233 const OSSL_PARAM *p; 234 235 if (pectx == NULL) 236 return 0; 237 if (params == NULL) 238 return 1; 239 240 p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE); 241 if (p != NULL) { 242 int mode; 243 244 if (!OSSL_PARAM_get_int(p, &mode)) 245 return 0; 246 247 if (mode < -1 || mode > 1) 248 return 0; 249 250 pectx->cofactor_mode = mode; 251 } 252 253 p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_TYPE); 254 if (p != NULL) { 255 str = name; 256 if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name))) 257 return 0; 258 259 if (name[0] == '\0') 260 pectx->kdf_type = PROV_ECDH_KDF_NONE; 261 else if (strcmp(name, OSSL_KDF_NAME_X963KDF) == 0) 262 pectx->kdf_type = PROV_ECDH_KDF_X9_63; 263 else 264 return 0; 265 } 266 267 p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST); 268 if (p != NULL) { 269 char mdprops[80] = { '\0' }; /* should be big enough */ 270 271 str = name; 272 if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name))) 273 return 0; 274 275 str = mdprops; 276 p = OSSL_PARAM_locate_const(params, 277 OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS); 278 279 if (p != NULL) { 280 if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops))) 281 return 0; 282 } 283 284 EVP_MD_free(pectx->kdf_md); 285 pectx->kdf_md = EVP_MD_fetch(pectx->libctx, name, mdprops); 286 if (!ossl_digest_is_allowed(pectx->libctx, pectx->kdf_md)) { 287 EVP_MD_free(pectx->kdf_md); 288 pectx->kdf_md = NULL; 289 } 290 if (pectx->kdf_md == NULL) 291 return 0; 292 } 293 294 p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN); 295 if (p != NULL) { 296 size_t outlen; 297 298 if (!OSSL_PARAM_get_size_t(p, &outlen)) 299 return 0; 300 pectx->kdf_outlen = outlen; 301 } 302 303 p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_UKM); 304 if (p != NULL) { 305 void *tmp_ukm = NULL; 306 size_t tmp_ukmlen; 307 308 if (!OSSL_PARAM_get_octet_string(p, &tmp_ukm, 0, &tmp_ukmlen)) 309 return 0; 310 OPENSSL_free(pectx->kdf_ukm); 311 pectx->kdf_ukm = tmp_ukm; 312 pectx->kdf_ukmlen = tmp_ukmlen; 313 } 314 315 return 1; 316 } 317 318 static const OSSL_PARAM known_settable_ctx_params[] = { 319 OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE, NULL), 320 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0), 321 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0), 322 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS, NULL, 0), 323 OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL), 324 OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM, NULL, 0), 325 OSSL_PARAM_END 326 }; 327 328 static 329 const OSSL_PARAM *ecdh_settable_ctx_params(ossl_unused void *vpecdhctx, 330 ossl_unused void *provctx) 331 { 332 return known_settable_ctx_params; 333 } 334 335 static 336 int ecdh_get_ctx_params(void *vpecdhctx, OSSL_PARAM params[]) 337 { 338 PROV_ECDH_CTX *pectx = (PROV_ECDH_CTX *)vpecdhctx; 339 OSSL_PARAM *p; 340 341 if (pectx == NULL) 342 return 0; 343 344 p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE); 345 if (p != NULL) { 346 int mode = pectx->cofactor_mode; 347 348 if (mode == -1) { 349 /* check what is the default for pecdhctx->k */ 350 mode = EC_KEY_get_flags(pectx->k) & EC_FLAG_COFACTOR_ECDH ? 1 : 0; 351 } 352 353 if (!OSSL_PARAM_set_int(p, mode)) 354 return 0; 355 } 356 357 p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_TYPE); 358 if (p != NULL) { 359 const char *kdf_type = NULL; 360 361 switch (pectx->kdf_type) { 362 case PROV_ECDH_KDF_NONE: 363 kdf_type = ""; 364 break; 365 case PROV_ECDH_KDF_X9_63: 366 kdf_type = OSSL_KDF_NAME_X963KDF; 367 break; 368 default: 369 return 0; 370 } 371 372 if (!OSSL_PARAM_set_utf8_string(p, kdf_type)) 373 return 0; 374 } 375 376 p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST); 377 if (p != NULL 378 && !OSSL_PARAM_set_utf8_string(p, pectx->kdf_md == NULL 379 ? "" 380 : EVP_MD_get0_name(pectx->kdf_md))){ 381 return 0; 382 } 383 384 p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN); 385 if (p != NULL && !OSSL_PARAM_set_size_t(p, pectx->kdf_outlen)) 386 return 0; 387 388 p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_UKM); 389 if (p != NULL && 390 !OSSL_PARAM_set_octet_ptr(p, pectx->kdf_ukm, pectx->kdf_ukmlen)) 391 return 0; 392 393 return 1; 394 } 395 396 static const OSSL_PARAM known_gettable_ctx_params[] = { 397 OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE, NULL), 398 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0), 399 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0), 400 OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL), 401 OSSL_PARAM_DEFN(OSSL_EXCHANGE_PARAM_KDF_UKM, OSSL_PARAM_OCTET_PTR, 402 NULL, 0), 403 OSSL_PARAM_END 404 }; 405 406 static 407 const OSSL_PARAM *ecdh_gettable_ctx_params(ossl_unused void *vpecdhctx, 408 ossl_unused void *provctx) 409 { 410 return known_gettable_ctx_params; 411 } 412 413 static ossl_inline 414 size_t ecdh_size(const EC_KEY *k) 415 { 416 size_t degree = 0; 417 const EC_GROUP *group; 418 419 if (k == NULL 420 || (group = EC_KEY_get0_group(k)) == NULL) 421 return 0; 422 423 degree = EC_GROUP_get_degree(group); 424 425 return (degree + 7) / 8; 426 } 427 428 static ossl_inline 429 int ecdh_plain_derive(void *vpecdhctx, unsigned char *secret, 430 size_t *psecretlen, size_t outlen) 431 { 432 PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx; 433 int retlen, ret = 0; 434 size_t ecdhsize, size; 435 const EC_POINT *ppubkey = NULL; 436 EC_KEY *privk = NULL; 437 const EC_GROUP *group; 438 const BIGNUM *cofactor; 439 int key_cofactor_mode; 440 441 if (pecdhctx->k == NULL || pecdhctx->peerk == NULL) { 442 ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); 443 return 0; 444 } 445 446 ecdhsize = ecdh_size(pecdhctx->k); 447 if (secret == NULL) { 448 *psecretlen = ecdhsize; 449 return 1; 450 } 451 452 if ((group = EC_KEY_get0_group(pecdhctx->k)) == NULL 453 || (cofactor = EC_GROUP_get0_cofactor(group)) == NULL ) 454 return 0; 455 456 /* 457 * NB: unlike PKCS#3 DH, if outlen is less than maximum size this is not 458 * an error, the result is truncated. 459 */ 460 size = outlen < ecdhsize ? outlen : ecdhsize; 461 462 /* 463 * The ctx->cofactor_mode flag has precedence over the 464 * cofactor_mode flag set on ctx->k. 465 * 466 * - if ctx->cofactor_mode == -1, use ctx->k directly 467 * - if ctx->cofactor_mode == key_cofactor_mode, use ctx->k directly 468 * - if ctx->cofactor_mode != key_cofactor_mode: 469 * - if ctx->k->cofactor == 1, the cofactor_mode flag is irrelevant, use 470 * ctx->k directly 471 * - if ctx->k->cofactor != 1, use a duplicate of ctx->k with the flag 472 * set to ctx->cofactor_mode 473 */ 474 key_cofactor_mode = 475 (EC_KEY_get_flags(pecdhctx->k) & EC_FLAG_COFACTOR_ECDH) ? 1 : 0; 476 if (pecdhctx->cofactor_mode != -1 477 && pecdhctx->cofactor_mode != key_cofactor_mode 478 && !BN_is_one(cofactor)) { 479 if ((privk = EC_KEY_dup(pecdhctx->k)) == NULL) 480 return 0; 481 482 if (pecdhctx->cofactor_mode == 1) 483 EC_KEY_set_flags(privk, EC_FLAG_COFACTOR_ECDH); 484 else 485 EC_KEY_clear_flags(privk, EC_FLAG_COFACTOR_ECDH); 486 } else { 487 privk = pecdhctx->k; 488 } 489 490 ppubkey = EC_KEY_get0_public_key(pecdhctx->peerk); 491 492 retlen = ECDH_compute_key(secret, size, ppubkey, privk, NULL); 493 494 if (retlen <= 0) 495 goto end; 496 497 *psecretlen = retlen; 498 ret = 1; 499 500 end: 501 if (privk != pecdhctx->k) 502 EC_KEY_free(privk); 503 return ret; 504 } 505 506 static ossl_inline 507 int ecdh_X9_63_kdf_derive(void *vpecdhctx, unsigned char *secret, 508 size_t *psecretlen, size_t outlen) 509 { 510 PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx; 511 unsigned char *stmp = NULL; 512 size_t stmplen; 513 int ret = 0; 514 515 if (secret == NULL) { 516 *psecretlen = pecdhctx->kdf_outlen; 517 return 1; 518 } 519 520 if (pecdhctx->kdf_outlen > outlen) { 521 ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); 522 return 0; 523 } 524 if (!ecdh_plain_derive(vpecdhctx, NULL, &stmplen, 0)) 525 return 0; 526 if ((stmp = OPENSSL_secure_malloc(stmplen)) == NULL) { 527 ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); 528 return 0; 529 } 530 if (!ecdh_plain_derive(vpecdhctx, stmp, &stmplen, stmplen)) 531 goto err; 532 533 /* Do KDF stuff */ 534 if (!ossl_ecdh_kdf_X9_63(secret, pecdhctx->kdf_outlen, 535 stmp, stmplen, 536 pecdhctx->kdf_ukm, 537 pecdhctx->kdf_ukmlen, 538 pecdhctx->kdf_md, 539 pecdhctx->libctx, NULL)) 540 goto err; 541 *psecretlen = pecdhctx->kdf_outlen; 542 ret = 1; 543 544 err: 545 OPENSSL_secure_clear_free(stmp, stmplen); 546 return ret; 547 } 548 549 static 550 int ecdh_derive(void *vpecdhctx, unsigned char *secret, 551 size_t *psecretlen, size_t outlen) 552 { 553 PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx; 554 555 switch (pecdhctx->kdf_type) { 556 case PROV_ECDH_KDF_NONE: 557 return ecdh_plain_derive(vpecdhctx, secret, psecretlen, outlen); 558 case PROV_ECDH_KDF_X9_63: 559 return ecdh_X9_63_kdf_derive(vpecdhctx, secret, psecretlen, outlen); 560 default: 561 break; 562 } 563 return 0; 564 } 565 566 const OSSL_DISPATCH ossl_ecdh_keyexch_functions[] = { 567 { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))ecdh_newctx }, 568 { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))ecdh_init }, 569 { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))ecdh_derive }, 570 { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))ecdh_set_peer }, 571 { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))ecdh_freectx }, 572 { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))ecdh_dupctx }, 573 { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))ecdh_set_ctx_params }, 574 { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS, 575 (void (*)(void))ecdh_settable_ctx_params }, 576 { OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS, (void (*)(void))ecdh_get_ctx_params }, 577 { OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS, 578 (void (*)(void))ecdh_gettable_ctx_params }, 579 { 0, NULL } 580 }; 581