1 /* 2 * Copyright 2019-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 * DH 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/core_dispatch.h> 19 #include <openssl/core_names.h> 20 #include <openssl/dh.h> 21 #include <openssl/err.h> 22 #include <openssl/proverr.h> 23 #include <openssl/params.h> 24 #include "prov/providercommon.h" 25 #include "prov/implementations.h" 26 #include "prov/provider_ctx.h" 27 #include "prov/securitycheck.h" 28 #include "crypto/dh.h" 29 30 static OSSL_FUNC_keyexch_newctx_fn dh_newctx; 31 static OSSL_FUNC_keyexch_init_fn dh_init; 32 static OSSL_FUNC_keyexch_set_peer_fn dh_set_peer; 33 static OSSL_FUNC_keyexch_derive_fn dh_derive; 34 static OSSL_FUNC_keyexch_freectx_fn dh_freectx; 35 static OSSL_FUNC_keyexch_dupctx_fn dh_dupctx; 36 static OSSL_FUNC_keyexch_set_ctx_params_fn dh_set_ctx_params; 37 static OSSL_FUNC_keyexch_settable_ctx_params_fn dh_settable_ctx_params; 38 static OSSL_FUNC_keyexch_get_ctx_params_fn dh_get_ctx_params; 39 static OSSL_FUNC_keyexch_gettable_ctx_params_fn dh_gettable_ctx_params; 40 41 /* 42 * This type is only really used to handle some legacy related functionality. 43 * If you need to use other KDF's (such as SSKDF) just use PROV_DH_KDF_NONE 44 * here and then create and run a KDF after the key is derived. 45 * Note that X942 has 2 variants of key derivation: 46 * (1) DH_KDF_X9_42_ASN1 - which contains an ANS1 encoded object that has 47 * the counter embedded in it. 48 * (2) DH_KDF_X941_CONCAT - which is the same as ECDH_X963_KDF (which can be 49 * done by creating a "X963KDF". 50 */ 51 enum kdf_type { 52 PROV_DH_KDF_NONE = 0, 53 PROV_DH_KDF_X9_42_ASN1 54 }; 55 56 /* 57 * What's passed as an actual key is defined by the KEYMGMT interface. 58 * We happen to know that our KEYMGMT simply passes DH structures, so 59 * we use that here too. 60 */ 61 62 typedef struct { 63 OSSL_LIB_CTX *libctx; 64 DH *dh; 65 DH *dhpeer; 66 unsigned int pad : 1; 67 68 /* DH KDF */ 69 /* KDF (if any) to use for DH */ 70 enum kdf_type kdf_type; 71 /* Message digest to use for key derivation */ 72 EVP_MD *kdf_md; 73 /* User key material */ 74 unsigned char *kdf_ukm; 75 size_t kdf_ukmlen; 76 /* KDF output length */ 77 size_t kdf_outlen; 78 char *kdf_cekalg; 79 OSSL_FIPS_IND_DECLARE 80 } PROV_DH_CTX; 81 82 static void *dh_newctx(void *provctx) 83 { 84 PROV_DH_CTX *pdhctx; 85 86 if (!ossl_prov_is_running()) 87 return NULL; 88 89 pdhctx = OPENSSL_zalloc(sizeof(PROV_DH_CTX)); 90 if (pdhctx == NULL) 91 return NULL; 92 OSSL_FIPS_IND_INIT(pdhctx) 93 pdhctx->libctx = PROV_LIBCTX_OF(provctx); 94 pdhctx->kdf_type = PROV_DH_KDF_NONE; 95 return pdhctx; 96 } 97 98 #ifdef FIPS_MODULE 99 static int dh_check_key(PROV_DH_CTX *ctx) 100 { 101 int key_approved = ossl_dh_check_key(ctx->dh); 102 103 if (!key_approved) { 104 if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE0, 105 ctx->libctx, "DH Init", "DH Key", 106 ossl_fips_config_securitycheck_enabled)) { 107 ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); 108 return 0; 109 } 110 } 111 return 1; 112 } 113 114 static int digest_check(PROV_DH_CTX *ctx, const EVP_MD *md) 115 { 116 return ossl_fips_ind_digest_exch_check(OSSL_FIPS_IND_GET(ctx), 117 OSSL_FIPS_IND_SETTABLE1, ctx->libctx, 118 md, "DH Set Ctx"); 119 } 120 #endif 121 122 static int dh_init(void *vpdhctx, void *vdh, const OSSL_PARAM params[]) 123 { 124 PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; 125 126 if (!ossl_prov_is_running() 127 || pdhctx == NULL 128 || vdh == NULL 129 || !DH_up_ref(vdh)) 130 return 0; 131 DH_free(pdhctx->dh); 132 pdhctx->dh = vdh; 133 pdhctx->kdf_type = PROV_DH_KDF_NONE; 134 135 OSSL_FIPS_IND_SET_APPROVED(pdhctx) 136 if (!dh_set_ctx_params(pdhctx, params)) 137 return 0; 138 #ifdef FIPS_MODULE 139 if (!dh_check_key(pdhctx)) 140 return 0; 141 #endif 142 return 1; 143 } 144 145 /* The 2 parties must share the same domain parameters */ 146 static int dh_match_params(DH *priv, DH *peer) 147 { 148 int ret; 149 FFC_PARAMS *dhparams_priv = ossl_dh_get0_params(priv); 150 FFC_PARAMS *dhparams_peer = ossl_dh_get0_params(peer); 151 152 ret = dhparams_priv != NULL 153 && dhparams_peer != NULL 154 && ossl_ffc_params_cmp(dhparams_priv, dhparams_peer, 1); 155 if (!ret) 156 ERR_raise(ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS); 157 return ret; 158 } 159 160 static int dh_set_peer(void *vpdhctx, void *vdh) 161 { 162 PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; 163 164 if (!ossl_prov_is_running() 165 || pdhctx == NULL 166 || vdh == NULL 167 || !dh_match_params(vdh, pdhctx->dh) 168 || !DH_up_ref(vdh)) 169 return 0; 170 DH_free(pdhctx->dhpeer); 171 pdhctx->dhpeer = vdh; 172 return 1; 173 } 174 175 static int dh_plain_derive(void *vpdhctx, 176 unsigned char *secret, size_t *secretlen, 177 size_t outlen, unsigned int pad) 178 { 179 PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; 180 int ret; 181 size_t dhsize; 182 const BIGNUM *pub_key = NULL; 183 184 if (pdhctx->dh == NULL || pdhctx->dhpeer == NULL) { 185 ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); 186 return 0; 187 } 188 189 dhsize = (size_t)DH_size(pdhctx->dh); 190 if (secret == NULL) { 191 *secretlen = dhsize; 192 return 1; 193 } 194 if (outlen < dhsize) { 195 ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); 196 return 0; 197 } 198 199 DH_get0_key(pdhctx->dhpeer, &pub_key, NULL); 200 if (pad) 201 ret = DH_compute_key_padded(secret, pub_key, pdhctx->dh); 202 else 203 ret = DH_compute_key(secret, pub_key, pdhctx->dh); 204 if (ret <= 0) 205 return 0; 206 207 *secretlen = ret; 208 return 1; 209 } 210 211 static int dh_X9_42_kdf_derive(void *vpdhctx, unsigned char *secret, 212 size_t *secretlen, size_t outlen) 213 { 214 PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; 215 unsigned char *stmp = NULL; 216 size_t stmplen; 217 int ret = 0; 218 219 if (secret == NULL) { 220 *secretlen = pdhctx->kdf_outlen; 221 return 1; 222 } 223 224 if (pdhctx->kdf_outlen > outlen) { 225 ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); 226 return 0; 227 } 228 if (!dh_plain_derive(pdhctx, NULL, &stmplen, 0, 1)) 229 return 0; 230 if ((stmp = OPENSSL_secure_malloc(stmplen)) == NULL) 231 return 0; 232 if (!dh_plain_derive(pdhctx, stmp, &stmplen, stmplen, 1)) 233 goto err; 234 235 /* Do KDF stuff */ 236 if (pdhctx->kdf_type == PROV_DH_KDF_X9_42_ASN1) { 237 if (!ossl_dh_kdf_X9_42_asn1(secret, pdhctx->kdf_outlen, 238 stmp, stmplen, 239 pdhctx->kdf_cekalg, 240 pdhctx->kdf_ukm, 241 pdhctx->kdf_ukmlen, 242 pdhctx->kdf_md, 243 pdhctx->libctx, NULL)) 244 goto err; 245 } 246 *secretlen = pdhctx->kdf_outlen; 247 ret = 1; 248 err: 249 OPENSSL_secure_clear_free(stmp, stmplen); 250 return ret; 251 } 252 253 static int dh_derive(void *vpdhctx, unsigned char *secret, 254 size_t *psecretlen, size_t outlen) 255 { 256 PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; 257 258 if (!ossl_prov_is_running()) 259 return 0; 260 261 switch (pdhctx->kdf_type) { 262 case PROV_DH_KDF_NONE: 263 return dh_plain_derive(pdhctx, secret, psecretlen, outlen, 264 pdhctx->pad); 265 case PROV_DH_KDF_X9_42_ASN1: 266 return dh_X9_42_kdf_derive(pdhctx, secret, psecretlen, outlen); 267 default: 268 break; 269 } 270 return 0; 271 } 272 273 static void dh_freectx(void *vpdhctx) 274 { 275 PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; 276 277 OPENSSL_free(pdhctx->kdf_cekalg); 278 DH_free(pdhctx->dh); 279 DH_free(pdhctx->dhpeer); 280 EVP_MD_free(pdhctx->kdf_md); 281 OPENSSL_clear_free(pdhctx->kdf_ukm, pdhctx->kdf_ukmlen); 282 283 OPENSSL_free(pdhctx); 284 } 285 286 static void *dh_dupctx(void *vpdhctx) 287 { 288 PROV_DH_CTX *srcctx = (PROV_DH_CTX *)vpdhctx; 289 PROV_DH_CTX *dstctx; 290 291 if (!ossl_prov_is_running()) 292 return NULL; 293 294 dstctx = OPENSSL_zalloc(sizeof(*srcctx)); 295 if (dstctx == NULL) 296 return NULL; 297 298 *dstctx = *srcctx; 299 dstctx->dh = NULL; 300 dstctx->dhpeer = NULL; 301 dstctx->kdf_md = NULL; 302 dstctx->kdf_ukm = NULL; 303 dstctx->kdf_cekalg = NULL; 304 305 if (srcctx->dh != NULL && !DH_up_ref(srcctx->dh)) 306 goto err; 307 else 308 dstctx->dh = srcctx->dh; 309 310 if (srcctx->dhpeer != NULL && !DH_up_ref(srcctx->dhpeer)) 311 goto err; 312 else 313 dstctx->dhpeer = srcctx->dhpeer; 314 315 if (srcctx->kdf_md != NULL && !EVP_MD_up_ref(srcctx->kdf_md)) 316 goto err; 317 else 318 dstctx->kdf_md = srcctx->kdf_md; 319 320 /* Duplicate UKM data if present */ 321 if (srcctx->kdf_ukm != NULL && srcctx->kdf_ukmlen > 0) { 322 dstctx->kdf_ukm = OPENSSL_memdup(srcctx->kdf_ukm, 323 srcctx->kdf_ukmlen); 324 if (dstctx->kdf_ukm == NULL) 325 goto err; 326 } 327 328 if (srcctx->kdf_cekalg != NULL) { 329 dstctx->kdf_cekalg = OPENSSL_strdup(srcctx->kdf_cekalg); 330 if (dstctx->kdf_cekalg == NULL) 331 goto err; 332 } 333 334 return dstctx; 335 err: 336 dh_freectx(dstctx); 337 return NULL; 338 } 339 340 static int dh_set_ctx_params(void *vpdhctx, const OSSL_PARAM params[]) 341 { 342 PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; 343 const OSSL_PARAM *p; 344 unsigned int pad; 345 char name[80] = { '\0' }; /* should be big enough */ 346 char *str = NULL; 347 348 if (pdhctx == NULL) 349 return 0; 350 if (ossl_param_is_empty(params)) 351 return 1; 352 353 if (!OSSL_FIPS_IND_SET_CTX_PARAM(pdhctx, OSSL_FIPS_IND_SETTABLE0, params, 354 OSSL_EXCHANGE_PARAM_FIPS_KEY_CHECK)) 355 return 0; 356 if (!OSSL_FIPS_IND_SET_CTX_PARAM(pdhctx, OSSL_FIPS_IND_SETTABLE1, params, 357 OSSL_EXCHANGE_PARAM_FIPS_DIGEST_CHECK)) 358 return 0; 359 360 p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_TYPE); 361 if (p != NULL) { 362 str = name; 363 if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name))) 364 return 0; 365 366 if (name[0] == '\0') 367 pdhctx->kdf_type = PROV_DH_KDF_NONE; 368 else if (strcmp(name, OSSL_KDF_NAME_X942KDF_ASN1) == 0) 369 pdhctx->kdf_type = PROV_DH_KDF_X9_42_ASN1; 370 else 371 return 0; 372 } 373 p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST); 374 if (p != NULL) { 375 char mdprops[80] = { '\0' }; /* should be big enough */ 376 377 str = name; 378 if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name))) 379 return 0; 380 381 str = mdprops; 382 p = OSSL_PARAM_locate_const(params, 383 OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS); 384 385 if (p != NULL) { 386 if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops))) 387 return 0; 388 } 389 390 EVP_MD_free(pdhctx->kdf_md); 391 pdhctx->kdf_md = EVP_MD_fetch(pdhctx->libctx, name, mdprops); 392 if (pdhctx->kdf_md == NULL) 393 return 0; 394 /* XOF digests are not allowed */ 395 if (EVP_MD_xof(pdhctx->kdf_md)) { 396 ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED); 397 return 0; 398 } 399 #ifdef FIPS_MODULE 400 if (!digest_check(pdhctx, pdhctx->kdf_md)) { 401 EVP_MD_free(pdhctx->kdf_md); 402 pdhctx->kdf_md = NULL; 403 return 0; 404 } 405 #endif 406 } 407 408 p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN); 409 if (p != NULL) { 410 size_t outlen; 411 412 if (!OSSL_PARAM_get_size_t(p, &outlen)) 413 return 0; 414 pdhctx->kdf_outlen = outlen; 415 } 416 417 p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_UKM); 418 if (p != NULL) { 419 void *tmp_ukm = NULL; 420 size_t tmp_ukmlen; 421 422 OPENSSL_free(pdhctx->kdf_ukm); 423 pdhctx->kdf_ukm = NULL; 424 pdhctx->kdf_ukmlen = 0; 425 /* ukm is an optional field so it can be NULL */ 426 if (p->data != NULL && p->data_size != 0) { 427 if (!OSSL_PARAM_get_octet_string(p, &tmp_ukm, 0, &tmp_ukmlen)) 428 return 0; 429 pdhctx->kdf_ukm = tmp_ukm; 430 pdhctx->kdf_ukmlen = tmp_ukmlen; 431 } 432 } 433 434 p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_PAD); 435 if (p != NULL) { 436 if (!OSSL_PARAM_get_uint(p, &pad)) 437 return 0; 438 pdhctx->pad = pad ? 1 : 0; 439 } 440 441 p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_CEK_ALG); 442 if (p != NULL) { 443 str = name; 444 445 OPENSSL_free(pdhctx->kdf_cekalg); 446 pdhctx->kdf_cekalg = NULL; 447 if (p->data != NULL && p->data_size != 0) { 448 if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name))) 449 return 0; 450 pdhctx->kdf_cekalg = OPENSSL_strdup(name); 451 if (pdhctx->kdf_cekalg == NULL) 452 return 0; 453 } 454 } 455 return 1; 456 } 457 458 static const OSSL_PARAM known_settable_ctx_params[] = { 459 OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_PAD, NULL), 460 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0), 461 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0), 462 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS, NULL, 0), 463 OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL), 464 OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM, NULL, 0), 465 OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG, NULL, 0), 466 OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_EXCHANGE_PARAM_FIPS_KEY_CHECK) 467 OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_EXCHANGE_PARAM_FIPS_DIGEST_CHECK) 468 OSSL_PARAM_END 469 }; 470 471 static const OSSL_PARAM *dh_settable_ctx_params(ossl_unused void *vpdhctx, 472 ossl_unused void *provctx) 473 { 474 return known_settable_ctx_params; 475 } 476 477 static const OSSL_PARAM known_gettable_ctx_params[] = { 478 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0), 479 OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0), 480 OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL), 481 OSSL_PARAM_DEFN(OSSL_EXCHANGE_PARAM_KDF_UKM, OSSL_PARAM_OCTET_PTR, 482 NULL, 0), 483 OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG, NULL, 0), 484 OSSL_FIPS_IND_GETTABLE_CTX_PARAM() 485 OSSL_PARAM_END 486 }; 487 488 static const OSSL_PARAM *dh_gettable_ctx_params(ossl_unused void *vpdhctx, 489 ossl_unused void *provctx) 490 { 491 return known_gettable_ctx_params; 492 } 493 494 static int dh_get_ctx_params(void *vpdhctx, OSSL_PARAM params[]) 495 { 496 PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx; 497 OSSL_PARAM *p; 498 499 if (pdhctx == NULL) 500 return 0; 501 502 p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_TYPE); 503 if (p != NULL) { 504 const char *kdf_type = NULL; 505 506 switch (pdhctx->kdf_type) { 507 case PROV_DH_KDF_NONE: 508 kdf_type = ""; 509 break; 510 case PROV_DH_KDF_X9_42_ASN1: 511 kdf_type = OSSL_KDF_NAME_X942KDF_ASN1; 512 break; 513 default: 514 return 0; 515 } 516 517 if (!OSSL_PARAM_set_utf8_string(p, kdf_type)) 518 return 0; 519 } 520 521 p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST); 522 if (p != NULL 523 && !OSSL_PARAM_set_utf8_string(p, pdhctx->kdf_md == NULL 524 ? "" 525 : EVP_MD_get0_name(pdhctx->kdf_md))) { 526 return 0; 527 } 528 529 p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN); 530 if (p != NULL && !OSSL_PARAM_set_size_t(p, pdhctx->kdf_outlen)) 531 return 0; 532 533 p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_UKM); 534 if (p != NULL 535 && !OSSL_PARAM_set_octet_ptr(p, pdhctx->kdf_ukm, pdhctx->kdf_ukmlen)) 536 return 0; 537 538 p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_CEK_ALG); 539 if (p != NULL 540 && !OSSL_PARAM_set_utf8_string(p, pdhctx->kdf_cekalg == NULL 541 ? "" : pdhctx->kdf_cekalg)) 542 return 0; 543 if (!OSSL_FIPS_IND_GET_CTX_PARAM(pdhctx, params)) 544 return 0; 545 return 1; 546 } 547 548 const OSSL_DISPATCH ossl_dh_keyexch_functions[] = { 549 { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))dh_newctx }, 550 { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))dh_init }, 551 { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))dh_derive }, 552 { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))dh_set_peer }, 553 { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))dh_freectx }, 554 { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))dh_dupctx }, 555 { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))dh_set_ctx_params }, 556 { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS, 557 (void (*)(void))dh_settable_ctx_params }, 558 { OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS, (void (*)(void))dh_get_ctx_params }, 559 { OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS, 560 (void (*)(void))dh_gettable_ctx_params }, 561 OSSL_DISPATCH_END 562 }; 563