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