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