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