Path: blob/main/crypto/openssl/providers/implementations/exchange/dh_exch.c
48383 views
/*1* Copyright 2019-2024 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89/*10* DH low level APIs are deprecated for public use, but still ok for11* internal use.12*/13#include "internal/deprecated.h"1415#include <string.h>16#include <openssl/crypto.h>17#include <openssl/core_dispatch.h>18#include <openssl/core_names.h>19#include <openssl/dh.h>20#include <openssl/err.h>21#include <openssl/proverr.h>22#include <openssl/params.h>23#include "prov/providercommon.h"24#include "prov/implementations.h"25#include "prov/provider_ctx.h"26#include "prov/securitycheck.h"27#include "crypto/dh.h"2829static OSSL_FUNC_keyexch_newctx_fn dh_newctx;30static OSSL_FUNC_keyexch_init_fn dh_init;31static OSSL_FUNC_keyexch_set_peer_fn dh_set_peer;32static OSSL_FUNC_keyexch_derive_fn dh_derive;33static OSSL_FUNC_keyexch_freectx_fn dh_freectx;34static OSSL_FUNC_keyexch_dupctx_fn dh_dupctx;35static OSSL_FUNC_keyexch_set_ctx_params_fn dh_set_ctx_params;36static OSSL_FUNC_keyexch_settable_ctx_params_fn dh_settable_ctx_params;37static OSSL_FUNC_keyexch_get_ctx_params_fn dh_get_ctx_params;38static OSSL_FUNC_keyexch_gettable_ctx_params_fn dh_gettable_ctx_params;3940/*41* This type is only really used to handle some legacy related functionality.42* If you need to use other KDF's (such as SSKDF) just use PROV_DH_KDF_NONE43* here and then create and run a KDF after the key is derived.44* Note that X942 has 2 variants of key derivation:45* (1) DH_KDF_X9_42_ASN1 - which contains an ANS1 encoded object that has46* the counter embedded in it.47* (2) DH_KDF_X941_CONCAT - which is the same as ECDH_X963_KDF (which can be48* done by creating a "X963KDF".49*/50enum kdf_type {51PROV_DH_KDF_NONE = 0,52PROV_DH_KDF_X9_42_ASN153};5455/*56* What's passed as an actual key is defined by the KEYMGMT interface.57* We happen to know that our KEYMGMT simply passes DH structures, so58* we use that here too.59*/6061typedef struct {62OSSL_LIB_CTX *libctx;63DH *dh;64DH *dhpeer;65unsigned int pad : 1;6667/* DH KDF */68/* KDF (if any) to use for DH */69enum kdf_type kdf_type;70/* Message digest to use for key derivation */71EVP_MD *kdf_md;72/* User key material */73unsigned char *kdf_ukm;74size_t kdf_ukmlen;75/* KDF output length */76size_t kdf_outlen;77char *kdf_cekalg;78OSSL_FIPS_IND_DECLARE79} PROV_DH_CTX;8081static void *dh_newctx(void *provctx)82{83PROV_DH_CTX *pdhctx;8485if (!ossl_prov_is_running())86return NULL;8788pdhctx = OPENSSL_zalloc(sizeof(PROV_DH_CTX));89if (pdhctx == NULL)90return NULL;91OSSL_FIPS_IND_INIT(pdhctx)92pdhctx->libctx = PROV_LIBCTX_OF(provctx);93pdhctx->kdf_type = PROV_DH_KDF_NONE;94return pdhctx;95}9697#ifdef FIPS_MODULE98static int dh_check_key(PROV_DH_CTX *ctx)99{100int key_approved = ossl_dh_check_key(ctx->dh);101102if (!key_approved) {103if (!OSSL_FIPS_IND_ON_UNAPPROVED(ctx, OSSL_FIPS_IND_SETTABLE0,104ctx->libctx, "DH Init", "DH Key",105ossl_fips_config_securitycheck_enabled)) {106ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);107return 0;108}109}110return 1;111}112113static int digest_check(PROV_DH_CTX *ctx, const EVP_MD *md)114{115return ossl_fips_ind_digest_exch_check(OSSL_FIPS_IND_GET(ctx),116OSSL_FIPS_IND_SETTABLE1, ctx->libctx,117md, "DH Set Ctx");118}119#endif120121static int dh_init(void *vpdhctx, void *vdh, const OSSL_PARAM params[])122{123PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;124125if (!ossl_prov_is_running()126|| pdhctx == NULL127|| vdh == NULL128|| !DH_up_ref(vdh))129return 0;130DH_free(pdhctx->dh);131pdhctx->dh = vdh;132pdhctx->kdf_type = PROV_DH_KDF_NONE;133134OSSL_FIPS_IND_SET_APPROVED(pdhctx)135if (!dh_set_ctx_params(pdhctx, params))136return 0;137#ifdef FIPS_MODULE138if (!dh_check_key(pdhctx))139return 0;140#endif141return 1;142}143144/* The 2 parties must share the same domain parameters */145static int dh_match_params(DH *priv, DH *peer)146{147int ret;148FFC_PARAMS *dhparams_priv = ossl_dh_get0_params(priv);149FFC_PARAMS *dhparams_peer = ossl_dh_get0_params(peer);150151ret = dhparams_priv != NULL152&& dhparams_peer != NULL153&& ossl_ffc_params_cmp(dhparams_priv, dhparams_peer, 1);154if (!ret)155ERR_raise(ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS);156return ret;157}158159static int dh_set_peer(void *vpdhctx, void *vdh)160{161PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;162163if (!ossl_prov_is_running()164|| pdhctx == NULL165|| vdh == NULL166|| !dh_match_params(vdh, pdhctx->dh)167|| !DH_up_ref(vdh))168return 0;169DH_free(pdhctx->dhpeer);170pdhctx->dhpeer = vdh;171return 1;172}173174static int dh_plain_derive(void *vpdhctx,175unsigned char *secret, size_t *secretlen,176size_t outlen, unsigned int pad)177{178PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;179int ret;180size_t dhsize;181const BIGNUM *pub_key = NULL;182183if (pdhctx->dh == NULL || pdhctx->dhpeer == NULL) {184ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);185return 0;186}187188dhsize = (size_t)DH_size(pdhctx->dh);189if (secret == NULL) {190*secretlen = dhsize;191return 1;192}193if (outlen < dhsize) {194ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);195return 0;196}197198DH_get0_key(pdhctx->dhpeer, &pub_key, NULL);199if (pad)200ret = DH_compute_key_padded(secret, pub_key, pdhctx->dh);201else202ret = DH_compute_key(secret, pub_key, pdhctx->dh);203if (ret <= 0)204return 0;205206*secretlen = ret;207return 1;208}209210static int dh_X9_42_kdf_derive(void *vpdhctx, unsigned char *secret,211size_t *secretlen, size_t outlen)212{213PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;214unsigned char *stmp = NULL;215size_t stmplen;216int ret = 0;217218if (secret == NULL) {219*secretlen = pdhctx->kdf_outlen;220return 1;221}222223if (pdhctx->kdf_outlen > outlen) {224ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);225return 0;226}227if (!dh_plain_derive(pdhctx, NULL, &stmplen, 0, 1))228return 0;229if ((stmp = OPENSSL_secure_malloc(stmplen)) == NULL)230return 0;231if (!dh_plain_derive(pdhctx, stmp, &stmplen, stmplen, 1))232goto err;233234/* Do KDF stuff */235if (pdhctx->kdf_type == PROV_DH_KDF_X9_42_ASN1) {236if (!ossl_dh_kdf_X9_42_asn1(secret, pdhctx->kdf_outlen,237stmp, stmplen,238pdhctx->kdf_cekalg,239pdhctx->kdf_ukm,240pdhctx->kdf_ukmlen,241pdhctx->kdf_md,242pdhctx->libctx, NULL))243goto err;244}245*secretlen = pdhctx->kdf_outlen;246ret = 1;247err:248OPENSSL_secure_clear_free(stmp, stmplen);249return ret;250}251252static int dh_derive(void *vpdhctx, unsigned char *secret,253size_t *psecretlen, size_t outlen)254{255PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;256257if (!ossl_prov_is_running())258return 0;259260switch (pdhctx->kdf_type) {261case PROV_DH_KDF_NONE:262return dh_plain_derive(pdhctx, secret, psecretlen, outlen,263pdhctx->pad);264case PROV_DH_KDF_X9_42_ASN1:265return dh_X9_42_kdf_derive(pdhctx, secret, psecretlen, outlen);266default:267break;268}269return 0;270}271272static void dh_freectx(void *vpdhctx)273{274PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;275276OPENSSL_free(pdhctx->kdf_cekalg);277DH_free(pdhctx->dh);278DH_free(pdhctx->dhpeer);279EVP_MD_free(pdhctx->kdf_md);280OPENSSL_clear_free(pdhctx->kdf_ukm, pdhctx->kdf_ukmlen);281282OPENSSL_free(pdhctx);283}284285static void *dh_dupctx(void *vpdhctx)286{287PROV_DH_CTX *srcctx = (PROV_DH_CTX *)vpdhctx;288PROV_DH_CTX *dstctx;289290if (!ossl_prov_is_running())291return NULL;292293dstctx = OPENSSL_zalloc(sizeof(*srcctx));294if (dstctx == NULL)295return NULL;296297*dstctx = *srcctx;298dstctx->dh = NULL;299dstctx->dhpeer = NULL;300dstctx->kdf_md = NULL;301dstctx->kdf_ukm = NULL;302dstctx->kdf_cekalg = NULL;303304if (srcctx->dh != NULL && !DH_up_ref(srcctx->dh))305goto err;306else307dstctx->dh = srcctx->dh;308309if (srcctx->dhpeer != NULL && !DH_up_ref(srcctx->dhpeer))310goto err;311else312dstctx->dhpeer = srcctx->dhpeer;313314if (srcctx->kdf_md != NULL && !EVP_MD_up_ref(srcctx->kdf_md))315goto err;316else317dstctx->kdf_md = srcctx->kdf_md;318319/* Duplicate UKM data if present */320if (srcctx->kdf_ukm != NULL && srcctx->kdf_ukmlen > 0) {321dstctx->kdf_ukm = OPENSSL_memdup(srcctx->kdf_ukm,322srcctx->kdf_ukmlen);323if (dstctx->kdf_ukm == NULL)324goto err;325}326327if (srcctx->kdf_cekalg != NULL) {328dstctx->kdf_cekalg = OPENSSL_strdup(srcctx->kdf_cekalg);329if (dstctx->kdf_cekalg == NULL)330goto err;331}332333return dstctx;334err:335dh_freectx(dstctx);336return NULL;337}338339static int dh_set_ctx_params(void *vpdhctx, const OSSL_PARAM params[])340{341PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;342const OSSL_PARAM *p;343unsigned int pad;344char name[80] = { '\0' }; /* should be big enough */345char *str = NULL;346347if (pdhctx == NULL)348return 0;349if (ossl_param_is_empty(params))350return 1;351352if (!OSSL_FIPS_IND_SET_CTX_PARAM(pdhctx, OSSL_FIPS_IND_SETTABLE0, params,353OSSL_EXCHANGE_PARAM_FIPS_KEY_CHECK))354return 0;355if (!OSSL_FIPS_IND_SET_CTX_PARAM(pdhctx, OSSL_FIPS_IND_SETTABLE1, params,356OSSL_EXCHANGE_PARAM_FIPS_DIGEST_CHECK))357return 0;358359p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_TYPE);360if (p != NULL) {361str = name;362if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name)))363return 0;364365if (name[0] == '\0')366pdhctx->kdf_type = PROV_DH_KDF_NONE;367else if (strcmp(name, OSSL_KDF_NAME_X942KDF_ASN1) == 0)368pdhctx->kdf_type = PROV_DH_KDF_X9_42_ASN1;369else370return 0;371}372p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST);373if (p != NULL) {374char mdprops[80] = { '\0' }; /* should be big enough */375376str = name;377if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name)))378return 0;379380str = mdprops;381p = OSSL_PARAM_locate_const(params,382OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS);383384if (p != NULL) {385if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops)))386return 0;387}388389EVP_MD_free(pdhctx->kdf_md);390pdhctx->kdf_md = EVP_MD_fetch(pdhctx->libctx, name, mdprops);391if (pdhctx->kdf_md == NULL)392return 0;393/* XOF digests are not allowed */394if (EVP_MD_xof(pdhctx->kdf_md)) {395ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED);396return 0;397}398#ifdef FIPS_MODULE399if (!digest_check(pdhctx, pdhctx->kdf_md)) {400EVP_MD_free(pdhctx->kdf_md);401pdhctx->kdf_md = NULL;402return 0;403}404#endif405}406407p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN);408if (p != NULL) {409size_t outlen;410411if (!OSSL_PARAM_get_size_t(p, &outlen))412return 0;413pdhctx->kdf_outlen = outlen;414}415416p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_UKM);417if (p != NULL) {418void *tmp_ukm = NULL;419size_t tmp_ukmlen;420421OPENSSL_free(pdhctx->kdf_ukm);422pdhctx->kdf_ukm = NULL;423pdhctx->kdf_ukmlen = 0;424/* ukm is an optional field so it can be NULL */425if (p->data != NULL && p->data_size != 0) {426if (!OSSL_PARAM_get_octet_string(p, &tmp_ukm, 0, &tmp_ukmlen))427return 0;428pdhctx->kdf_ukm = tmp_ukm;429pdhctx->kdf_ukmlen = tmp_ukmlen;430}431}432433p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_PAD);434if (p != NULL) {435if (!OSSL_PARAM_get_uint(p, &pad))436return 0;437pdhctx->pad = pad ? 1 : 0;438}439440p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_CEK_ALG);441if (p != NULL) {442str = name;443444OPENSSL_free(pdhctx->kdf_cekalg);445pdhctx->kdf_cekalg = NULL;446if (p->data != NULL && p->data_size != 0) {447if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name)))448return 0;449pdhctx->kdf_cekalg = OPENSSL_strdup(name);450if (pdhctx->kdf_cekalg == NULL)451return 0;452}453}454return 1;455}456457static const OSSL_PARAM known_settable_ctx_params[] = {458OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_PAD, NULL),459OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0),460OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0),461OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS, NULL, 0),462OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL),463OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM, NULL, 0),464OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG, NULL, 0),465OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_EXCHANGE_PARAM_FIPS_KEY_CHECK)466OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_EXCHANGE_PARAM_FIPS_DIGEST_CHECK)467OSSL_PARAM_END468};469470static const OSSL_PARAM *dh_settable_ctx_params(ossl_unused void *vpdhctx,471ossl_unused void *provctx)472{473return known_settable_ctx_params;474}475476static const OSSL_PARAM known_gettable_ctx_params[] = {477OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0),478OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0),479OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL),480OSSL_PARAM_DEFN(OSSL_EXCHANGE_PARAM_KDF_UKM, OSSL_PARAM_OCTET_PTR,481NULL, 0),482OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_CEK_ALG, NULL, 0),483OSSL_FIPS_IND_GETTABLE_CTX_PARAM()484OSSL_PARAM_END485};486487static const OSSL_PARAM *dh_gettable_ctx_params(ossl_unused void *vpdhctx,488ossl_unused void *provctx)489{490return known_gettable_ctx_params;491}492493static int dh_get_ctx_params(void *vpdhctx, OSSL_PARAM params[])494{495PROV_DH_CTX *pdhctx = (PROV_DH_CTX *)vpdhctx;496OSSL_PARAM *p;497498if (pdhctx == NULL)499return 0;500501p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_TYPE);502if (p != NULL) {503const char *kdf_type = NULL;504505switch (pdhctx->kdf_type) {506case PROV_DH_KDF_NONE:507kdf_type = "";508break;509case PROV_DH_KDF_X9_42_ASN1:510kdf_type = OSSL_KDF_NAME_X942KDF_ASN1;511break;512default:513return 0;514}515516if (!OSSL_PARAM_set_utf8_string(p, kdf_type))517return 0;518}519520p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST);521if (p != NULL522&& !OSSL_PARAM_set_utf8_string(p, pdhctx->kdf_md == NULL523? ""524: EVP_MD_get0_name(pdhctx->kdf_md))) {525return 0;526}527528p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN);529if (p != NULL && !OSSL_PARAM_set_size_t(p, pdhctx->kdf_outlen))530return 0;531532p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_UKM);533if (p != NULL534&& !OSSL_PARAM_set_octet_ptr(p, pdhctx->kdf_ukm, pdhctx->kdf_ukmlen))535return 0;536537p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_CEK_ALG);538if (p != NULL539&& !OSSL_PARAM_set_utf8_string(p, pdhctx->kdf_cekalg == NULL540? "" : pdhctx->kdf_cekalg))541return 0;542if (!OSSL_FIPS_IND_GET_CTX_PARAM(pdhctx, params))543return 0;544return 1;545}546547const OSSL_DISPATCH ossl_dh_keyexch_functions[] = {548{ OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))dh_newctx },549{ OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))dh_init },550{ OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))dh_derive },551{ OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))dh_set_peer },552{ OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))dh_freectx },553{ OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))dh_dupctx },554{ OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))dh_set_ctx_params },555{ OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS,556(void (*)(void))dh_settable_ctx_params },557{ OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS, (void (*)(void))dh_get_ctx_params },558{ OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS,559(void (*)(void))dh_gettable_ctx_params },560OSSL_DISPATCH_END561};562563564