From f124acb1af235ecd30249f903573175c1ea624a2 Mon Sep 17 00:00:00 2001
From: Weili Qian <qianweili@huawei.com>
Date: Thu, 19 Dec 2024 15:57:57 +0800
Subject: [PATCH 04/10] uadk_provider: support ec keymgmt hardware acceleration

Support ECDH key generation.

Signed-off-by: Weili Qian <qianweili@huawei.com>
Signed-off-by: JiangShui Yang <yangjiangshui@h-partners.com>
---
 src/Makefile.am          |   3 +-
 src/uadk_prov.h          |   2 +
 src/uadk_prov_ec_kmgmt.c | 746 +++++++++++++++++++++++++++++++++++++++
 src/uadk_prov_init.c     |   2 +
 src/uadk_prov_pkey.c     |  26 +-
 src/uadk_prov_pkey.h     |   9 +
 6 files changed, 785 insertions(+), 3 deletions(-)
 create mode 100644 src/uadk_prov_ec_kmgmt.c

diff --git a/src/Makefile.am b/src/Makefile.am
index 921305b..b2e2c06 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -65,7 +65,8 @@ uadk_provider_la_SOURCES=uadk_prov_init.c uadk_async.c uadk_utils.c \
 			 uadk_prov_rsa.c uadk_prov_dh.c \
 			 uadk_prov_bio.c uadk_prov_der_writer.c uadk_prov_packet.c \
 			 uadk_prov_pkey.c uadk_prov_sm2.c \
-			 uadk_prov_ffc.c uadk_prov_aead.c
+			 uadk_prov_ffc.c uadk_prov_aead.c \
+			 uadk_prov_ec_kmgmt.c
 
 uadk_provider_la_LDFLAGS=-module -version-number $(VERSION)
 uadk_provider_la_LIBADD=$(WD_LIBS) -lpthread
diff --git a/src/uadk_prov.h b/src/uadk_prov.h
index e85aff8..9c310b7 100644
--- a/src/uadk_prov.h
+++ b/src/uadk_prov.h
@@ -179,6 +179,8 @@ extern const OSSL_DISPATCH uadk_sm2_keymgmt_functions[FUNC_MAX_NUM];
 extern const OSSL_DISPATCH uadk_sm2_signature_functions[FUNC_MAX_NUM];
 extern const OSSL_DISPATCH uadk_sm2_asym_cipher_functions[FUNC_MAX_NUM];
 
+extern const OSSL_DISPATCH uadk_ec_keymgmt_functions[FUNC_MAX_NUM];
+
 void uadk_prov_destroy_digest(void);
 void uadk_prov_destroy_cipher(void);
 void uadk_prov_destroy_aead(void);
diff --git a/src/uadk_prov_ec_kmgmt.c b/src/uadk_prov_ec_kmgmt.c
new file mode 100644
index 0000000..86182bd
--- /dev/null
+++ b/src/uadk_prov_ec_kmgmt.c
@@ -0,0 +1,746 @@
+// SPDX-License-Identifier: Apache-2.0
+/*
+ * Copyright 2024 Huawei Technologies Co.,Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <openssl/bn.h>
+#include <uadk/wd_ecc.h>
+#include "uadk_async.h"
+#include "uadk_prov.h"
+#include "uadk_prov_pkey.h"
+
+#define UADK_PROV_ECC_PADDING		7
+#define UADK_PROV_RAND_MAX_CNT		1000
+#define UADK_EC_DEFAULT_FLAGS		0
+#define UADK_EC_FLAGS_ERROR		(-1)
+
+static const OSSL_ITEM check_group_type_nameid_map[] = {
+	{0, OSSL_PKEY_EC_GROUP_CHECK_DEFAULT},
+	{EC_FLAG_CHECK_NAMED_GROUP, OSSL_PKEY_EC_GROUP_CHECK_NAMED},
+	{EC_FLAG_CHECK_NAMED_GROUP_NIST, OSSL_PKEY_EC_GROUP_CHECK_NAMED_NIST},
+};
+
+UADK_PKEY_KEYMGMT_DESCR(ec, EC);
+
+static int ec_param_check(struct ec_gen_ctx *gctx, EC_KEY *ec)
+{
+	const EC_GROUP *group;
+	int type, ret;
+
+	ret = uadk_prov_ecc_genctx_check(gctx, ec);
+	if (!ret) {
+		fprintf(stderr, "failed to check genctx!\n");
+		return ret;
+	}
+
+	group = EC_KEY_get0_group(ec);
+	/* Field GF(2m) is not supported by uadk */
+	type = EC_METHOD_get_field_type(EC_GROUP_method_of(group));
+	if (type != NID_X9_62_prime_field) {
+		fprintf(stderr, "invalid: uadk unsupport Field GF(2m)!\n");
+		return UADK_P_FAIL;
+	}
+
+	return uadk_prov_ecc_bit_check(group);
+}
+
+static int ec_set_public_key(EC_KEY *ec, struct wd_ecc_out *ec_out)
+{
+	int key_size_std, key_size_x, key_size_y;
+	struct wd_ecc_point *pubkey = NULL;
+	int ret = UADK_P_FAIL;
+	const EC_GROUP *group;
+	int x_shift, y_shift;
+	unsigned char *buff;
+	EC_POINT *point;
+	int buff_size;
+
+	wd_ecxdh_get_out_params(ec_out, &pubkey);
+	if (!pubkey) {
+		fprintf(stderr, "failed to get pubkey!\n");
+		return ret;
+	}
+
+	group = EC_KEY_get0_group(ec);
+	point = EC_POINT_new(group);
+	if (!point) {
+		fprintf(stderr, "failed to new ec point!\n");
+		return ret;
+	}
+
+	key_size_std = (unsigned int)(EC_GROUP_get_degree(group) +
+			UADK_PROV_ECC_PADDING) >> TRANS_BITS_BYTES_SHIFT;
+	key_size_x = pubkey->x.dsize;
+	key_size_y = pubkey->y.dsize;
+	if (key_size_x > key_size_std || key_size_y > key_size_std) {
+		fprintf(stderr, "invalid: key size is error!\n");
+		goto free_point;
+	}
+
+	/*
+	 * The public key is composed as: tag + point_x + point_y
+	 * tag - 1 byte
+	 * point_x - [key_size_std] bytes
+	 * point_y - [key_size_std] bytes
+	 */
+	buff_size = ECC_POINT_SIZE(key_size_std) + 1;
+	x_shift = key_size_std - key_size_x + 1;
+	y_shift = buff_size - key_size_y;
+	buff = (unsigned char *)OPENSSL_zalloc(buff_size);
+	if (!buff) {
+		fprintf(stderr, "failed to alloc buf, buff_size = %d!\n",
+			buff_size);
+		goto free_point;
+	}
+
+	buff[0] = UADK_OCTET_STRING;
+	memcpy(buff + x_shift, pubkey->x.data, key_size_x);
+	memcpy(buff + y_shift, pubkey->y.data, key_size_y);
+
+	ret = EC_POINT_oct2point(group, point, buff, buff_size, NULL);
+	if (!ret) {
+		fprintf(stderr, "failed to do EC_POINT_oct2point!\n");
+		goto free_buf;
+	}
+
+	ret = EC_KEY_set_public_key(ec, point);
+	if (!ret)
+		fprintf(stderr, "failed to do EC_KEY_set_public_key!\n");
+
+free_buf:
+	OPENSSL_free(buff);
+free_point:
+	EC_POINT_free(point);
+
+	return ret;
+}
+
+static handle_t ec_alloc_sess(EC_KEY *ec, struct wd_ecc_out **ec_out)
+{
+	handle_t sess;
+	int ret;
+
+	ret = uadk_prov_keymgmt_get_support_state(KEYMGMT_EC);
+	if (!ret) {
+		fprintf(stderr, "failed to get hardware ecdh keygen support!\n");
+		return ret;
+	}
+
+	ret = uadk_prov_ecc_init("ecdh");
+	if (!ret) {
+		fprintf(stderr, "failed to init ecdh!\n");
+		return ret;
+	}
+
+	sess = uadk_prov_ecc_alloc_sess(ec, "ecdh");
+	if (!sess) {
+		fprintf(stderr, "failed to alloc ec sess!\n");
+		return ret;
+	}
+
+	*ec_out = wd_ecxdh_new_out(sess);
+	if (!(*ec_out)) {
+		fprintf(stderr, "failed to new sign out\n");
+		wd_ecc_free_sess(sess);
+		return UADK_P_FAIL;
+	}
+
+	return sess;
+}
+
+static void ec_free_sess(handle_t sess, struct wd_ecc_out *ec_out)
+{
+	wd_ecc_del_out(sess, ec_out);
+	wd_ecc_free_sess(sess);
+}
+
+static int ec_set_private_key(EC_KEY *ec, BIGNUM *priv_key)
+{
+	BIGNUM *priv_k = priv_key;
+	int ret = UADK_P_FAIL;
+	const EC_GROUP *group;
+	const BIGNUM *order;
+	int cnt = 0;
+
+	if (priv_k)
+		goto set_key;
+
+	priv_k = BN_new();
+	if (!priv_k) {
+		fprintf(stderr, "failed to BN_new priv_k!\n");
+		return UADK_P_FAIL;
+	}
+
+	group = EC_KEY_get0_group(ec);
+	order = EC_GROUP_get0_order(group);
+
+	do {
+		cnt++;
+		if (cnt > UADK_PROV_RAND_MAX_CNT) {
+			fprintf(stderr, "failed to get appropriate prikey, timeout\n");
+			goto free_priv_k;
+		}
+
+		if (!BN_priv_rand_range(priv_k, order)) {
+			fprintf(stderr, "failed to get rand data!\n");
+			goto free_priv_k;
+		}
+	} while (BN_is_zero(priv_k) || BN_is_one(priv_k));
+
+set_key:
+	ret = EC_KEY_set_private_key(ec, priv_k);
+	if (!ret)
+		fprintf(stderr, "failed to set private key!\n");
+
+free_priv_k:
+	if (!priv_key)
+		BN_clear_free(priv_k);
+	return ret;
+}
+
+static int ec_update_private_key(EC_KEY *ec, handle_t sess, BIGNUM *priv_key)
+{
+	int ret;
+
+	ret = ec_set_private_key(ec, priv_key);
+	if (!ret)
+		return ret;
+
+	return uadk_prov_ecc_set_private_key(sess, ec);
+}
+
+static int ec_hw_keygen(EC_KEY *ec, BIGNUM *priv_key)
+{
+	struct wd_ecc_out *ec_out = NULL;
+	struct wd_ecc_req req = {0};
+	handle_t sess;
+	int ret;
+
+	sess = ec_alloc_sess(ec, &ec_out);
+	if (!sess) {
+		fprintf(stderr, "failed to alloc sess!\n");
+		return UADK_P_FAIL;
+	}
+
+	ret = ec_update_private_key(ec, sess, priv_key);
+	if (!ret) {
+		fprintf(stderr, "failed to update private key!\n");
+		goto free_sess;
+	}
+
+	uadk_prov_ecc_fill_req(&req, WD_ECXDH_GEN_KEY, NULL, ec_out);
+	ret = uadk_prov_ecc_crypto(sess, &req, (void *)sess);
+	if (!ret) {
+		fprintf(stderr, "failed to generate key!\n");
+		goto free_sess;
+	}
+
+	ret = ec_set_public_key(ec, ec_out);
+
+free_sess:
+	ec_free_sess(sess, ec_out);
+	return ret;
+}
+
+static int ec_set_cofactor_mode(EC_KEY *ec, int mode)
+{
+	const EC_GROUP *group = EC_KEY_get0_group(ec);
+	const BIGNUM *cofactor;
+	/*
+	 * mode can be only 0 for disable, or 1 for enable here.
+	 *
+	 * This is in contrast with the same parameter on an ECDH EVP_PKEY_CTX that
+	 * also supports mode == -1 with the meaning of "reset to the default for
+	 * the associated key".
+	 */
+	if (mode < COFACTOR_MODE_DISABLED || mode > COFACTOR_MODE_ENABLED)
+		return UADK_P_FAIL;
+
+	cofactor = EC_GROUP_get0_cofactor(group);
+	if (!cofactor)
+		return UADK_P_FAIL;
+
+	/* ECDH cofactor mode has no effect if cofactor is 1 */
+	if (BN_is_one(cofactor))
+		return UADK_P_SUCCESS;
+
+	if (mode == COFACTOR_MODE_ENABLED)
+		EC_KEY_set_flags(ec, EC_FLAG_COFACTOR_ECDH);
+	else
+		EC_KEY_clear_flags(ec, EC_FLAG_COFACTOR_ECDH);
+
+	return UADK_P_SUCCESS;
+}
+
+static int ec_check_group_type_name2id(const char *name)
+{
+	size_t size = OSSL_NELEM(check_group_type_nameid_map);
+	size_t i;
+
+	/* Return the default value if there is no name */
+	if (!name)
+		return UADK_EC_DEFAULT_FLAGS;
+
+	for (i = 0; i < size; i++) {
+		if (!OPENSSL_strcasecmp(name, check_group_type_nameid_map[i].ptr))
+			return check_group_type_nameid_map[i].id;
+	}
+
+	return UADK_EC_FLAGS_ERROR;
+}
+
+static int ec_set_check_group_type(EC_KEY *ec, const char *name)
+{
+	int flags;
+
+	flags = ec_check_group_type_name2id(name);
+	if (flags == UADK_EC_FLAGS_ERROR)
+		return UADK_P_FAIL;
+
+	EC_KEY_clear_flags(ec, EC_FLAG_CHECK_NAMED_GROUP_MASK);
+	EC_KEY_set_flags(ec, flags);
+
+	return UADK_P_SUCCESS;
+}
+
+static void *uadk_keymgmt_ec_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg)
+{
+	struct ec_gen_ctx *gctx = genctx;
+	EC_KEY *ec;
+	int ret;
+
+	if (!gctx) {
+		fprintf(stderr, "invalid: gctx is NULL to ec gen!\n");
+		return NULL;
+	}
+
+	ec = EC_KEY_new_ex(gctx->libctx, NULL);
+	if (!ec) {
+		fprintf(stderr, "failed to new ec key!\n");
+		return NULL;
+	}
+
+	ret = ec_param_check(genctx, ec);
+	if (!ret) {
+		fprintf(stderr, "failed to check genctx!\n");
+		goto free_ec_key;
+	}
+
+	/* Whether you want it or not, you get a keypair, not just one half */
+	if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) {
+		ret = ec_hw_keygen(ec, gctx->priv_key);
+		if (!ret) {
+			fprintf(stderr, "failed to gen public key!\n");
+			goto free_ec_key;
+		}
+	}
+
+	if (gctx->ecdh_mode != COFACTOR_MODE_USE_KEY) {
+		ret = ec_set_cofactor_mode(ec, gctx->ecdh_mode);
+		if (!ret)
+			goto free_ec_key;
+	}
+
+	if (gctx->group_check) {
+		ret = ec_set_check_group_type(ec, gctx->group_check);
+		if (!ret)
+			goto free_ec_key;
+	}
+
+	return ec;
+
+free_ec_key:
+	EC_KEY_free(ec);
+	return NULL;
+}
+
+static void uadk_keymgmt_ec_gen_cleanup(void *genctx)
+{
+	struct ec_gen_ctx *gctx = genctx;
+
+	if (!gctx)
+		return;
+
+	EC_GROUP_free(gctx->gen_group);
+	BN_free(gctx->p);
+	BN_free(gctx->a);
+	BN_free(gctx->b);
+	BN_free(gctx->order);
+	BN_free(gctx->cofactor);
+	BN_clear_free(gctx->priv_key);
+	OPENSSL_free(gctx->group_name);
+	OPENSSL_free(gctx->field_type);
+	OPENSSL_free(gctx->pt_format);
+	OPENSSL_free(gctx->encoding);
+	OPENSSL_free(gctx->seed);
+	OPENSSL_free(gctx->gen);
+	OPENSSL_free(gctx);
+}
+
+static void *uadk_keymgmt_ec_gen_init(void *provctx, int selection,
+				      const OSSL_PARAM params[])
+{
+	struct ec_gen_ctx *gctx;
+	int ret;
+
+	if (!provctx)
+		return NULL;
+
+	if (!(selection & OSSL_KEYMGMT_SELECT_ALL))
+		return NULL;
+
+	gctx = OPENSSL_zalloc(sizeof(*gctx));
+	if (!gctx)
+		return NULL;
+
+	gctx->libctx = prov_libctx_of(provctx);
+	gctx->selection = selection;
+
+	ret = uadk_keymgmt_ec_gen_set_params(gctx, params);
+	if (!ret) {
+		OPENSSL_free(gctx);
+		return NULL;
+	}
+
+	return gctx;
+}
+
+static int uadk_keymgmt_ec_gen_set_template(void *genctx, void *templ)
+{
+	struct ec_gen_ctx *gctx = genctx;
+	const EC_GROUP *src_group;
+	EC_GROUP *dst_group;
+	EC_KEY *ec = templ;
+
+	if (!gctx || !ec) {
+		fprintf(stderr, "invalid: genctx or templ is NULL!\n");
+		return UADK_P_FAIL;
+	}
+
+	src_group = EC_KEY_get0_group(ec);
+	if (!src_group) {
+		fprintf(stderr, "failed to get source group!\n");
+		return UADK_P_FAIL;
+	}
+
+	dst_group = EC_GROUP_dup(src_group);
+	if (!dst_group) {
+		fprintf(stderr, "failed to copy group!\n");
+		return UADK_P_FAIL;
+	}
+
+	EC_GROUP_free(gctx->gen_group);
+	gctx->gen_group = dst_group;
+
+	return UADK_P_SUCCESS;
+}
+
+static int ec_set_int_param(const char *key, int *val, const OSSL_PARAM params[])
+{
+	const OSSL_PARAM *p;
+
+	p = OSSL_PARAM_locate_const(params, key);
+	if (!p)
+		return UADK_P_SUCCESS;
+
+	return OSSL_PARAM_get_int(p, val);
+}
+
+static int ec_set_utf8_param(const char *key, char **val, const OSSL_PARAM params[])
+{
+	const OSSL_PARAM *p;
+
+	p = OSSL_PARAM_locate_const(params, key);
+	if (!p)
+		return UADK_P_SUCCESS;
+
+	if (p->data_type != OSSL_PARAM_UTF8_STRING)
+		return UADK_P_FAIL;
+
+	OPENSSL_free(*val);
+	*val = OPENSSL_strdup(p->data);
+	if (!(*val))
+		return UADK_P_FAIL;
+
+	return UADK_P_SUCCESS;
+}
+
+static int ec_set_bn_param(const char *key, BIGNUM **val, const OSSL_PARAM params[])
+{
+	const OSSL_PARAM *p;
+
+	p = OSSL_PARAM_locate_const(params, key);
+	if (!p)
+		return UADK_P_SUCCESS;
+
+	if (!(*val))
+		*val = BN_new();
+
+	if (!(*val))
+		return UADK_P_FAIL;
+
+	return OSSL_PARAM_get_BN(p, val);
+}
+
+static int ec_set_octet_param(const char *key, unsigned char **val,
+			      size_t *val_len, const OSSL_PARAM params[])
+{
+	const OSSL_PARAM *p;
+
+	p = OSSL_PARAM_locate_const(params, key);
+	if (!p)
+		return UADK_P_SUCCESS;
+
+	if (p->data_type != OSSL_PARAM_OCTET_STRING)
+		return UADK_P_FAIL;
+
+	OPENSSL_free(*val);
+	*val = OPENSSL_memdup(p->data, p->data_size);
+	if (!(*val))
+		return UADK_P_FAIL;
+
+	*val_len = p->data_size;
+
+	return UADK_P_SUCCESS;
+}
+
+static int uadk_keymgmt_ec_gen_set_params(void *genctx, const OSSL_PARAM params[])
+{
+	struct ec_gen_ctx *gctx = genctx;
+	int ret;
+
+	if (!gctx) {
+		fprintf(stderr, "invalid: gctx is NULL to set params!\n");
+		return UADK_P_FAIL;
+	}
+
+	ret = ec_set_int_param(OSSL_PKEY_PARAM_USE_COFACTOR_ECDH, &gctx->ecdh_mode, params);
+	if (!ret)
+		return ret;
+
+	ret = ec_set_utf8_param(OSSL_PKEY_PARAM_GROUP_NAME, &gctx->group_name, params);
+	if (!ret)
+		return ret;
+
+	ret = ec_set_utf8_param(OSSL_PKEY_PARAM_EC_FIELD_TYPE, &gctx->field_type, params);
+	if (!ret)
+		return ret;
+
+	ret = ec_set_utf8_param(OSSL_PKEY_PARAM_EC_ENCODING, &gctx->encoding, params);
+	if (!ret)
+		return ret;
+
+	ret = ec_set_utf8_param(OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT,
+				&gctx->pt_format, params);
+	if (!ret)
+		return ret;
+
+	ret = ec_set_utf8_param(OSSL_PKEY_PARAM_EC_GROUP_CHECK_TYPE,
+				&gctx->group_check, params);
+	if (!ret)
+		return ret;
+
+	ret = ec_set_bn_param(OSSL_PKEY_PARAM_EC_P, &gctx->p, params);
+	if (!ret)
+		return ret;
+
+	ret = ec_set_bn_param(OSSL_PKEY_PARAM_EC_A, &gctx->a, params);
+	if (!ret)
+		return ret;
+
+	ret = ec_set_bn_param(OSSL_PKEY_PARAM_EC_B, &gctx->b, params);
+	if (!ret)
+		return ret;
+
+	ret = ec_set_bn_param(OSSL_PKEY_PARAM_EC_ORDER, &gctx->order, params);
+	if (!ret)
+		return ret;
+
+	ret = ec_set_bn_param(OSSL_PKEY_PARAM_PRIV_KEY, &gctx->priv_key, params);
+	if (!ret)
+		return ret;
+
+	ret = ec_set_bn_param(OSSL_PKEY_PARAM_EC_COFACTOR, &gctx->cofactor, params);
+	if (!ret)
+		return ret;
+
+	ret = ec_set_octet_param(OSSL_PKEY_PARAM_EC_SEED, &gctx->seed,
+				 &gctx->seed_len, params);
+	if (!ret)
+		return ret;
+
+	return ec_set_octet_param(OSSL_PKEY_PARAM_EC_GENERATOR,
+				  &gctx->gen, &gctx->gen_len, params);
+}
+
+static const OSSL_PARAM *uadk_keymgmt_ec_gen_settable_params(ossl_unused void *genctx,
+							     ossl_unused void *provctx)
+{
+	static OSSL_PARAM settable[] = {
+		OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0),
+		OSSL_PARAM_int(OSSL_PKEY_PARAM_USE_COFACTOR_ECDH, NULL),
+		OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_ENCODING, NULL, 0),
+		OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT,
+				       NULL, 0),
+		OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_FIELD_TYPE, NULL, 0),
+		OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_P, NULL, 0),
+		OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_A, NULL, 0),
+		OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_B, NULL, 0),
+		OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_EC_GENERATOR, NULL, 0),
+		OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_ORDER, NULL, 0),
+		OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_COFACTOR, NULL, 0),
+		OSSL_PARAM_BN(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0),
+		OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_EC_SEED, NULL, 0),
+		OSSL_PARAM_END
+	};
+
+	return settable;
+}
+
+static void *uadk_keymgmt_ec_new(void *provctx)
+{
+	if (!get_default_ec_keymgmt().new_fun)
+		return NULL;
+
+	return get_default_ec_keymgmt().new_fun(provctx);
+}
+
+static void uadk_keymgmt_ec_free(void *keydata)
+{
+	if (!get_default_ec_keymgmt().free)
+		return;
+
+	return get_default_ec_keymgmt().free(keydata);
+}
+
+static int uadk_keymgmt_ec_get_params(void *key, OSSL_PARAM params[])
+{
+	if (!get_default_ec_keymgmt().get_params)
+		return UADK_P_FAIL;
+
+	return get_default_ec_keymgmt().get_params(key, params);
+}
+
+static const OSSL_PARAM *uadk_keymgmt_ec_gettable_params(void *provctx)
+{
+	if (!get_default_ec_keymgmt().gettable_params)
+		return NULL;
+
+	return get_default_ec_keymgmt().gettable_params(provctx);
+}
+
+static int uadk_keymgmt_ec_set_params(void *key, const OSSL_PARAM params[])
+{
+	if (!get_default_ec_keymgmt().set_params)
+		return UADK_P_FAIL;
+
+	return get_default_ec_keymgmt().set_params(key, params);
+}
+
+static const OSSL_PARAM *uadk_keymgmt_ec_settable_params(void *provctx)
+{
+	if (!get_default_ec_keymgmt().settable_params)
+		return NULL;
+
+	return get_default_ec_keymgmt().settable_params(provctx);
+}
+
+static void *uadk_keymgmt_ec_load(const void *reference, size_t reference_sz)
+{
+	if (!get_default_ec_keymgmt().load)
+		return NULL;
+
+	return get_default_ec_keymgmt().load(reference, reference_sz);
+}
+
+static int uadk_keymgmt_ec_has(const void *keydata, int selection)
+{
+	if (!get_default_ec_keymgmt().has)
+		return UADK_P_FAIL;
+
+	return get_default_ec_keymgmt().has(keydata, selection);
+}
+
+static int uadk_keymgmt_ec_validate(const void *keydata,
+				    int selection, int checktype)
+{
+	if (!get_default_ec_keymgmt().validate)
+		return UADK_P_FAIL;
+
+	return get_default_ec_keymgmt().validate(keydata, selection, checktype);
+}
+
+static int uadk_keymgmt_ec_match(const void *keydata1,
+				 const void *keydata2, int selection)
+{
+	if (!get_default_ec_keymgmt().match)
+		return UADK_P_FAIL;
+
+	return get_default_ec_keymgmt().match(keydata1, keydata2, selection);
+}
+
+static int uadk_keymgmt_ec_import(void *keydata, int selection,
+				  const OSSL_PARAM params[])
+{
+	if (!get_default_ec_keymgmt().import)
+		return UADK_P_FAIL;
+
+	return get_default_ec_keymgmt().import(keydata, selection, params);
+}
+
+static const OSSL_PARAM *uadk_keymgmt_ec_import_types(int selection)
+{
+	if (!get_default_ec_keymgmt().import_types)
+		return NULL;
+
+	return get_default_ec_keymgmt().import_types(selection);
+}
+
+static int uadk_keymgmt_ec_export(void *keydata, int selection,
+				  OSSL_CALLBACK *param_cb, void *cbarg)
+{
+	if (!get_default_ec_keymgmt().export_fun)
+		return UADK_P_FAIL;
+
+	return get_default_ec_keymgmt().export_fun(keydata, selection, param_cb, cbarg);
+}
+
+static const OSSL_PARAM *uadk_keymgmt_ec_export_types(int selection)
+{
+	if (!get_default_ec_keymgmt().export_types)
+		return NULL;
+
+	return get_default_ec_keymgmt().export_types(selection);
+}
+
+static void *uadk_keymgmt_ec_dup(const void *keydata_from, int selection)
+{
+	if (!get_default_ec_keymgmt().dup)
+		return NULL;
+
+	return get_default_ec_keymgmt().dup(keydata_from, selection);
+}
+
+static const char *uadk_keymgmt_ec_query_operation_name(int operation_id)
+{
+	if (!get_default_ec_keymgmt().query_operation_name)
+		return NULL;
+
+	return get_default_ec_keymgmt().query_operation_name(operation_id);
+}
diff --git a/src/uadk_prov_init.c b/src/uadk_prov_init.c
index 55202ae..b5d3df5 100644
--- a/src/uadk_prov_init.c
+++ b/src/uadk_prov_init.c
@@ -174,6 +174,8 @@ static const OSSL_ALGORITHM uadk_prov_keymgmt[] = {
 	{ "DH", UADK_DEFAULT_PROPERTIES, uadk_dh_keymgmt_functions },
 	{ "SM2", UADK_DEFAULT_PROPERTIES,
 	  uadk_sm2_keymgmt_functions, "uadk SM2 Keymgmt implementation." },
+	{ "EC", UADK_DEFAULT_PROPERTIES,
+	  uadk_ec_keymgmt_functions, "uadk EC Keymgmt implementation."},
 	{ NULL, NULL, NULL }
 };
 
diff --git a/src/uadk_prov_pkey.c b/src/uadk_prov_pkey.c
index 6e0612e..170c30b 100644
--- a/src/uadk_prov_pkey.c
+++ b/src/uadk_prov_pkey.c
@@ -628,7 +628,7 @@ int uadk_prov_ecc_genctx_check(struct ec_gen_ctx *gctx, EC_KEY *ec)
 	return UADK_P_SUCCESS;
 }
 
-static bool uadk_prov_support_algorithm(const char *alg)
+bool uadk_prov_support_algorithm(const char *alg)
 {
 	struct uacce_dev_list *list = wd_get_accel_list(alg);
 
@@ -642,7 +642,7 @@ static bool uadk_prov_support_algorithm(const char *alg)
 
 void uadk_prov_keymgmt_alg(void)
 {
-	static const char * const keymgmt_alg[] = {"sm2"};
+	static const char * const keymgmt_alg[] = {"sm2", "ecdh"};
 	__u32 i, size;
 	bool sp;
 
@@ -811,3 +811,25 @@ void uadk_prov_ecc_uninit(void)
 	}
 	pthread_mutex_unlock(&ecc_mutex);
 }
+
+int uadk_prov_ecc_bit_check(const EC_GROUP *group)
+{
+	int bits = EC_GROUP_order_bits(group);
+
+	switch (bits) {
+	case ECC128BITS:
+	case ECC192BITS:
+	case ECC224BITS:
+	case ECC256BITS:
+	case ECC320BITS:
+	case ECC384BITS:
+	case ECC521BITS:
+		return UADK_P_SUCCESS;
+	default:
+		break;
+	}
+
+	fprintf(stderr, "invalid: unsupport key bits %d!\n", bits);
+
+	return UADK_P_FAIL;
+}
diff --git a/src/uadk_prov_pkey.h b/src/uadk_prov_pkey.h
index c9ddba1..1d4911c 100644
--- a/src/uadk_prov_pkey.h
+++ b/src/uadk_prov_pkey.h
@@ -68,6 +68,7 @@
 
 enum {
 	KEYMGMT_SM2 = 0x0,
+	KEYMGMT_EC = 0x1,
 	KEYMGMT_MAX = 0x6
 };
 
@@ -76,6 +77,12 @@ enum {
 	SIGNATURE_MAX = 0x3
 };
 
+enum {
+	COFACTOR_MODE_USE_KEY = -1,
+	COFACTOR_MODE_DISABLED = 0,
+	COFACTOR_MODE_ENABLED = 1,
+};
+
 struct curve_param {
 	/* Prime */
 	BIGNUM *p;
@@ -102,6 +109,7 @@ struct ec_gen_ctx {
 	int selection;
 	int ecdh_mode;
 	EC_GROUP *gen_group;
+	BIGNUM *priv_key;
 };
 
 typedef struct {
@@ -443,5 +451,6 @@ void uadk_prov_signature_alg(void);
 void uadk_prov_asym_cipher_alg(void);
 int uadk_prov_asym_cipher_get_support_state(int alg_tag);
 int uadk_prov_ecc_init(const char *alg_name);
+int uadk_prov_ecc_bit_check(const EC_GROUP *group);
 
 #endif
-- 
2.25.1

