From 1bd3dba1cf677fc7a23be78b4aad8979348c9871 Mon Sep 17 00:00:00 2001
From: Zhiqi Song <songzhiqi1@huawei.com>
Date: Thu, 19 Dec 2024 15:58:05 +0800
Subject: [PATCH 06/10] uadk_provider: support x448 alg

Test:
openssl genpkey -provider uadk_provider -algorithm X448 \
        -out a_prikey_x448.pem
openssl pkey -in a_prikey_x448.pem -text
openssl pkey -in a_prikey_x448.pem -pubout -out a_pubkey_x448.pub
openssl genpkey  -provider uadk_provider -algorithm x448 \
        -out b_prikey_x448.pem
openssl pkey -in b_prikey_x448.pem -text
openssl pkey -in b_prikey_x448.pem -pubout -out b_pubkey_x448.pub
openssl pkeyutl -derive -out ab_x448.key -inkey a_prikey_x448.pem \
        -peerkey b_pubkey_x448.pub -provider uadk_provider
openssl pkeyutl -derive -out ba_x448.key -inkey b_prikey_x448.pem \
        -peerkey a_pubkey_x448.pub -provider uadk_provider

cmp ab_x448.key ba_x448.key
xxd ab_x448.key
xxd ba_x448.key

Signed-off-by: Zhiqi Song <songzhiqi1@huawei.com>
Signed-off-by: JiangShui Yang <yangjiangshui@h-partners.com>
---
 src/Makefile.am           |    3 +-
 src/uadk_prov.h           |    3 +
 src/uadk_prov_ec_kmgmt.c  |    2 +-
 src/uadk_prov_ecdh_exch.c |    9 +-
 src/uadk_prov_ecx.c       | 1192 +++++++++++++++++++++++++++++++++++++
 src/uadk_prov_init.c      |    4 +
 src/uadk_prov_pkey.c      |   51 +-
 src/uadk_prov_pkey.h      |   12 +-
 8 files changed, 1256 insertions(+), 20 deletions(-)
 create mode 100644 src/uadk_prov_ecx.c

diff --git a/src/Makefile.am b/src/Makefile.am
index 5a1abe7..a165d3a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -66,7 +66,8 @@ uadk_provider_la_SOURCES=uadk_prov_init.c uadk_async.c uadk_utils.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_ec_kmgmt.c uadk_prov_ecdh_exch.c
+			 uadk_prov_ec_kmgmt.c uadk_prov_ecdh_exch.c \
+			 uadk_prov_ecx.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 7975884..84a3f01 100644
--- a/src/uadk_prov.h
+++ b/src/uadk_prov.h
@@ -182,6 +182,9 @@ extern const OSSL_DISPATCH uadk_sm2_asym_cipher_functions[FUNC_MAX_NUM];
 extern const OSSL_DISPATCH uadk_ec_keymgmt_functions[FUNC_MAX_NUM];
 extern const OSSL_DISPATCH uadk_ecdh_keyexch_functions[FUNC_MAX_NUM];
 
+extern const OSSL_DISPATCH uadk_x448_keymgmt_functions[FUNC_MAX_NUM];
+extern const OSSL_DISPATCH uadk_x448_keyexch_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
index 86182bd..355d601 100644
--- a/src/uadk_prov_ec_kmgmt.c
+++ b/src/uadk_prov_ec_kmgmt.c
@@ -136,7 +136,7 @@ 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);
+	ret = uadk_prov_keymgmt_get_support_state(KEYMGMT_ECDH);
 	if (!ret) {
 		fprintf(stderr, "failed to get hardware ecdh keygen support!\n");
 		return ret;
diff --git a/src/uadk_prov_ecdh_exch.c b/src/uadk_prov_ecdh_exch.c
index f549d25..9ac8e58 100644
--- a/src/uadk_prov_ecdh_exch.c
+++ b/src/uadk_prov_ecdh_exch.c
@@ -72,12 +72,6 @@ struct ecdh_sess_ctx {
 };
 
 UADK_PKEY_KEYEXCH_DESCR(ecdh, ECDH);
-static bool g_keyexch_ecdh_support;
-
-void uadk_prov_keyexch_alg(void)
-{
-	g_keyexch_ecdh_support = uadk_prov_support_algorithm("ecdh");
-}
 
 static size_t ecdh_get_ec_size(const EC_GROUP *group)
 {
@@ -169,7 +163,8 @@ static handle_t ecdh_alloc_sess(EC_KEY *privk)
 {
 	int ret;
 
-	if (!g_keyexch_ecdh_support) {
+	ret = uadk_prov_keyexch_get_support_state(KEYEXCH_ECDH);
+	if (!ret) {
 		fprintf(stderr, "invalid: hardware not support ecdh!\n");
 		return UADK_P_FAIL;
 	}
diff --git a/src/uadk_prov_ecx.c b/src/uadk_prov_ecx.c
new file mode 100644
index 0000000..302dc48
--- /dev/null
+++ b/src/uadk_prov_ecx.c
@@ -0,0 +1,1192 @@
+// 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/core_names.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/params.h>
+#include <openssl/param_build.h>
+#include <openssl/proverr.h>
+#include <openssl/rand.h>
+#include <openssl/trace.h>
+#include <uadk/wd_ecc.h>
+#include <uadk/wd_sched.h>
+#include "uadk_async.h"
+#include "uadk_prov.h"
+#include "uadk_prov_pkey.h"
+
+#define X448_KEYLEN		56
+#define X448_KEYBITS		448
+#define ECX_MAX_KEYLEN		57
+#define X448_SECURITY_BITS	224
+
+#define ECX_POSSIBLE_SELECTIONS (OSSL_KEYMGMT_SELECT_KEYPAIR)
+
+#define UADK_CRYPTO_UP_REF(val, ret, lock) CRYPTO_atomic_add(val, 1, ret, lock)
+
+static inline int UADK_CRYPTO_DOWN_REF(int *val, int *ret,
+				  ossl_unused void *lock)
+{
+	*ret = __atomic_fetch_sub(val, 1, __ATOMIC_RELAXED) - 1;
+	if (*ret == 0)
+		__atomic_thread_fence(__ATOMIC_ACQUIRE);
+	return 1;
+}
+
+UADK_PKEY_KEYMGMT_DESCR(x448, X448);
+UADK_PKEY_KEYEXCH_DESCR(x448, X448);
+
+typedef enum {
+	ECX_KEY_TYPE_X25519 = 0x0,
+	ECX_KEY_TYPE_X448 = 0x1,
+} ECX_KEY_TYPE;
+
+typedef struct {
+	OSSL_LIB_CTX *libctx;
+	char *propq;
+	unsigned int haspubkey:1;
+	unsigned char pubkey[ECX_MAX_KEYLEN];
+	unsigned char *privkey;
+	size_t keylen;
+	ECX_KEY_TYPE type;
+	int references;
+	void *lock;
+} ECX_KEY;
+
+typedef struct {
+	OSSL_LIB_CTX *libctx;
+	char *propq;
+	ECX_KEY_TYPE type;
+	int selection;
+	size_t keylen;
+	/* uadk sesssion */
+	handle_t sess;
+} PROV_ECX_KEYMGMT_CTX;
+
+typedef struct {
+	size_t keylen;
+	ECX_KEY *key;
+	ECX_KEY *peerkey;
+	OSSL_LIB_CTX *libctx;
+	char *propq;
+	/* uadk sesssion */
+	handle_t sess;
+} PROV_ECX_KEYEXCH_CTX;
+
+static const OSSL_PARAM ecx_key_types[] = {
+	OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0),
+	OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0),
+	OSSL_PARAM_END
+};
+
+struct x448_res {
+	int pid;
+} g_x448_prov;
+
+static void *uadk_keymgmt_x448_new(void *provctx)
+{
+	if (get_default_x448_keymgmt().new_fun == NULL)
+		return NULL;
+
+	return get_default_x448_keymgmt().new_fun(provctx);
+}
+
+void uadk_keymgmt_x448_free(void *keydata)
+{
+	if (get_default_x448_keymgmt().free == NULL)
+		return;
+
+	get_default_x448_keymgmt().free(keydata);
+}
+
+static int uadk_keymgmt_x448_has(const void *keydata, int selection)
+{
+	if (get_default_x448_keymgmt().has == NULL)
+		return UADK_P_FAIL;
+
+	return get_default_x448_keymgmt().has(keydata, selection);
+}
+
+static int uadk_keymgmt_x448_match(const void *keydata1, const void *keydata2, int selection)
+{
+	if (get_default_x448_keymgmt().match == NULL)
+		return UADK_P_FAIL;
+
+	return get_default_x448_keymgmt().match(keydata1, keydata2, selection);
+}
+
+static int uadk_keymgmt_x448_import(void *keydata, int selection, const OSSL_PARAM params[])
+{
+	if (get_default_x448_keymgmt().import == NULL)
+		return UADK_P_FAIL;
+
+	return get_default_x448_keymgmt().import(keydata, selection, params);
+}
+
+static int uadk_keymgmt_x448_export(void *keydata, int selection,
+				    OSSL_CALLBACK *cb, void *cb_params)
+{
+	if (get_default_x448_keymgmt().export_fun == NULL)
+		return UADK_P_FAIL;
+
+	return get_default_x448_keymgmt().export_fun(keydata, selection, cb, cb_params);
+}
+
+static const OSSL_PARAM *uadk_keymgmt_x448_import_types(int selection)
+{
+	if (get_default_x448_keymgmt().import_types == NULL)
+		return NULL;
+
+	return get_default_x448_keymgmt().import_types(selection);
+}
+
+static const OSSL_PARAM *uadk_keymgmt_x448_export_types(int selection)
+{
+	if (get_default_x448_keymgmt().export_types == NULL)
+		return NULL;
+
+	return get_default_x448_keymgmt().export_types(selection);
+}
+
+void *uadk_keymgmt_x448_load(const void *reference, size_t reference_sz)
+{
+	if (get_default_x448_keymgmt().load == NULL)
+		return NULL;
+
+	return get_default_x448_keymgmt().load(reference, reference_sz);
+}
+
+static void *uadk_keymgmt_x448_dup(const void *keydata_from, int selection)
+{
+	if (get_default_x448_keymgmt().dup == NULL)
+		return NULL;
+
+	return get_default_x448_keymgmt().dup(keydata_from, selection);
+}
+
+static int uadk_keymgmt_x448_validate(const void *keydata, int selection, int checktype)
+{
+	if (get_default_x448_keymgmt().validate == NULL)
+		return UADK_P_FAIL;
+
+	return get_default_x448_keymgmt().validate(keydata, selection, checktype);
+}
+
+static const OSSL_PARAM *uadk_keymgmt_x448_gettable_params(void *provctx)
+{
+	if (get_default_x448_keymgmt().gettable_params == NULL)
+		return NULL;
+
+	return get_default_x448_keymgmt().gettable_params(provctx);
+}
+
+static int uadk_keymgmt_x448_set_params(void *key, const OSSL_PARAM params[])
+{
+	if (get_default_x448_keymgmt().set_params == NULL)
+		return UADK_P_FAIL;
+
+	return get_default_x448_keymgmt().set_params(key, params);
+}
+
+static const OSSL_PARAM *uadk_keymgmt_x448_settable_params(void *provctx)
+{
+	if (get_default_x448_keymgmt().settable_params == NULL)
+		return NULL;
+
+	return get_default_x448_keymgmt().settable_params(provctx);
+}
+
+static int uadk_keymgmt_x448_gen_set_params(void *genctx,
+					  const OSSL_PARAM params[])
+{
+	if (get_default_x448_keymgmt().gen_set_params == NULL)
+		return UADK_P_FAIL;
+
+	return get_default_x448_keymgmt().gen_set_params(genctx, params);
+}
+
+static const OSSL_PARAM *uadk_keymgmt_x448_gen_settable_params(ossl_unused void *genctx,
+						ossl_unused void *provctx)
+{
+	if (get_default_x448_keymgmt().gen_settable_params == NULL)
+		return NULL;
+
+	return get_default_x448_keymgmt().gen_settable_params(genctx, provctx);
+}
+
+static int uadk_keymgmt_x448_gen_set_template(void *genctx, void *templ)
+{
+	if (get_default_x448_keymgmt().gen_set_template == NULL)
+		return UADK_P_FAIL;
+
+	return get_default_x448_keymgmt().gen_set_template(genctx, templ);
+}
+
+static const char *uadk_keymgmt_x448_query_operation_name(int operation_id)
+{
+	if (get_default_x448_keymgmt().query_operation_name == NULL)
+		return NULL;
+
+	return get_default_x448_keymgmt().query_operation_name(operation_id);
+}
+
+static int ossl_param_build_set_octet_string(OSSL_PARAM_BLD *bld, OSSL_PARAM *p, const char *key,
+					     const unsigned char *data, size_t data_len)
+{
+	if (bld != NULL)
+		return OSSL_PARAM_BLD_push_octet_string(bld, key, data, data_len);
+
+	p = OSSL_PARAM_locate(p, key);
+	if (p != NULL)
+		return OSSL_PARAM_set_octet_string(p, data, data_len);
+
+	return UADK_P_SUCCESS;
+}
+
+static int ossl_param_build_set_bn_pad(OSSL_PARAM_BLD *bld, OSSL_PARAM *p,
+				       const char *key, const BIGNUM *bn, size_t sz)
+{
+	if (bld != NULL)
+		return OSSL_PARAM_BLD_push_BN_pad(bld, key, bn, sz);
+
+	p = OSSL_PARAM_locate(p, key);
+	if (p != NULL) {
+		if (sz > p->data_size)
+			return UADK_P_FAIL;
+		p->data_size = sz;
+		return OSSL_PARAM_set_BN(p, bn);
+	}
+
+	return UADK_P_SUCCESS;
+}
+
+static int uadk_prov_key_to_params(ECX_KEY *key, OSSL_PARAM_BLD *tmpl,
+				   OSSL_PARAM params[], int include_private)
+{
+	if (!ossl_param_build_set_octet_string(tmpl, params,
+					       OSSL_PKEY_PARAM_PUB_KEY,
+					       key->pubkey, key->keylen))
+		return UADK_P_FAIL;
+
+	if (include_private && key->privkey != NULL
+	    && !ossl_param_build_set_octet_string(tmpl, params,
+						  OSSL_PKEY_PARAM_PRIV_KEY,
+						  key->privkey, key->keylen))
+		return UADK_P_FAIL;
+
+	return UADK_P_SUCCESS;
+}
+
+static int uadk_prov_ecx_get_params(void *key, OSSL_PARAM params[],
+				    int bits, int secbits, int size)
+{
+	ECX_KEY *ecx = key;
+	OSSL_PARAM *p;
+
+	if (ecx == NULL)
+		return UADK_P_FAIL;
+
+	p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS);
+	if (p && !OSSL_PARAM_set_int(p, bits))
+		return UADK_P_FAIL;
+
+	p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS);
+	if (p && !OSSL_PARAM_set_int(p, secbits))
+		return UADK_P_FAIL;
+
+	p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE);
+	if (p && !OSSL_PARAM_set_int(p, size))
+		return UADK_P_FAIL;
+
+	p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY);
+	if (p && (ecx->type == ECX_KEY_TYPE_X25519 || ecx->type == ECX_KEY_TYPE_X448)) {
+		if (!OSSL_PARAM_set_octet_string(p, ecx->pubkey, ecx->keylen))
+			return UADK_P_FAIL;
+	}
+
+	return uadk_prov_key_to_params(ecx, NULL, params, 1);
+}
+
+static int uadk_keymgmt_x448_get_params(void *key, OSSL_PARAM params[])
+{
+	return uadk_prov_ecx_get_params(key, params, X448_KEYBITS, X448_SECURITY_BITS,
+					X448_KEYLEN);
+}
+
+static int ossl_ecx_gen_set_params(void *genctx, const OSSL_PARAM params[])
+{
+	PROV_ECX_KEYMGMT_CTX *gctx = (PROV_ECX_KEYMGMT_CTX *)genctx;
+	const char *groupname = NULL;
+	const OSSL_PARAM *p;
+
+	p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_GROUP_NAME);
+	if (p != NULL) {
+		/*
+		 * We optionally allow setting a group name - but each algorithm only
+		 * support one such name, so all we do is verify that it is the one we
+		 * expected.
+		 */
+		switch (gctx->type) {
+		case ECX_KEY_TYPE_X25519:
+			groupname = "x25519";
+			break;
+		case ECX_KEY_TYPE_X448:
+			groupname = "x448";
+			break;
+		default:
+			/* We only support this for key exchange at the moment */
+			break;
+		}
+		if (p->data_type != OSSL_PARAM_UTF8_STRING || groupname == NULL ||
+		    OPENSSL_strcasecmp(p->data, groupname) != 0) {
+			fprintf(stderr, "invalid ecx params\n");
+			return UADK_P_FAIL;
+		}
+	}
+	p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PROPERTIES);
+	if (p != NULL) {
+		if (p->data_type != OSSL_PARAM_UTF8_STRING)
+			return UADK_P_FAIL;
+
+		OPENSSL_free(gctx->propq);
+		gctx->propq = OPENSSL_strdup(p->data);
+		if (gctx->propq == NULL)
+			return UADK_P_FAIL;
+	}
+
+	return UADK_P_SUCCESS;
+}
+
+static handle_t uadk_prov_x448_alloc_sess(void)
+{
+	struct wd_ecc_sess_setup setup = {0};
+	struct sched_params params = {0};
+
+	setup.alg = "x448";
+	setup.key_bits = X448_KEYBITS;
+	params.numa_id = -1;
+	setup.sched_param = &params;
+
+	return wd_ecc_alloc_sess(&setup);
+}
+
+static void uadk_prov_x448_free_sess(handle_t sess)
+{
+	if (sess)
+		wd_ecc_free_sess(sess);
+}
+
+static void *ossl_ecx_gen_init(void *provctx, int selection, const OSSL_PARAM params[],
+				    ECX_KEY_TYPE type)
+{
+	OSSL_LIB_CTX *libctx = prov_libctx_of(provctx);
+	PROV_ECX_KEYMGMT_CTX *gctx = NULL;
+	int ret;
+
+	gctx = OPENSSL_zalloc(sizeof(PROV_ECX_KEYMGMT_CTX));
+	if (gctx == NULL) {
+		fprintf(stderr, "failed to alloc ecx gctx\n");
+		return NULL;
+	}
+
+	gctx->libctx = libctx;
+	gctx->type = type;
+	gctx->selection = selection;
+
+	ret = ossl_ecx_gen_set_params(gctx, params);
+	if (ret == UADK_P_FAIL) {
+		fprintf(stderr, "failed to set ecx params\n");
+		OPENSSL_free(gctx);
+		gctx = NULL;
+	}
+
+	return gctx;
+}
+
+static void uadk_keymgmt_x448_gen_cleanup(void *genctx)
+{
+	/* genctx will be freed in cleanup function */
+	if (get_default_x448_keymgmt().gen_cleanup == NULL)
+		return;
+
+	get_default_x448_keymgmt().gen_cleanup(genctx);
+}
+
+static void *uadk_keymgmt_x448_gen_init(void *provctx, int selection,
+					const OSSL_PARAM params[])
+{
+	PROV_ECX_KEYMGMT_CTX *gctx = NULL;
+	int ret;
+
+	if (provctx == NULL) {
+		fprintf(stderr, "invalid: provctx is NULL\n");
+		return NULL;
+	}
+
+	return ossl_ecx_gen_init(provctx, selection, params, ECX_KEY_TYPE_X448);
+}
+
+ECX_KEY *uadk_prov_ecx_key_new(OSSL_LIB_CTX *libctx, ECX_KEY_TYPE type, int haspubkey,
+			       const char *propq)
+{
+	ECX_KEY *ecx_key = OPENSSL_zalloc(sizeof(ECX_KEY));
+
+	if (ecx_key == NULL) {
+		fprintf(stderr, "failed to alloc ecx key");
+		return NULL;
+	}
+
+	ecx_key->libctx = libctx;
+	ecx_key->haspubkey = haspubkey;
+
+	switch (type) {
+	case ECX_KEY_TYPE_X448:
+		ecx_key->keylen = X448_KEYLEN;
+		ecx_key->type = type;
+		ecx_key->references = 1;
+		break;
+	default:
+		fprintf(stderr, "invalid: unsupported ecx type\n");
+		goto free_ecx_key;
+	}
+
+	if (propq) {
+		ecx_key->propq = OPENSSL_strdup(propq);
+		if (ecx_key->propq == NULL)
+			goto free_ecx_key;
+	}
+
+	ecx_key->lock = CRYPTO_THREAD_lock_new();
+	if (ecx_key->lock == NULL)
+		goto err;
+
+	return ecx_key;
+
+err:
+	if (propq)
+		OPENSSL_free(ecx_key->propq);
+free_ecx_key:
+	OPENSSL_free(ecx_key);
+	return NULL;
+}
+
+static void uadk_prov_ecx_key_free(ECX_KEY *ecx_key)
+{
+	int i = 0;
+
+	if (ecx_key == NULL)
+		return;
+
+	UADK_CRYPTO_DOWN_REF(&ecx_key->references, &i, ecx_key->lock);
+	if (i > 0)
+		return;
+
+	if (ecx_key->propq)
+		OPENSSL_free(ecx_key->propq);
+
+	if (ecx_key->privkey)
+		OPENSSL_secure_free(ecx_key->privkey);
+
+	if (ecx_key->lock)
+		CRYPTO_THREAD_lock_free(ecx_key->lock);
+
+	OPENSSL_free(ecx_key);
+}
+
+static ECX_KEY *uadk_prov_ecx_create_prikey(PROV_ECX_KEYMGMT_CTX *gctx)
+{
+	unsigned char *prikey = NULL;
+	ECX_KEY *ecx_key = NULL;
+	int ret;
+
+	ecx_key = uadk_prov_ecx_key_new(gctx->libctx, gctx->type, 0, gctx->propq);
+	if (ecx_key == NULL) {
+		fprintf(stderr, "failed to new ecx_key\n");
+		return UADK_P_FAIL;
+	}
+	gctx->keylen = X448_KEYLEN;
+
+	/* If we're doing parameter generation then we just return a blank key */
+	if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0)
+		return ecx_key;
+
+	prikey = OPENSSL_secure_malloc(ecx_key->keylen);
+	if (prikey == NULL) {
+		fprintf(stderr, "failed to alloc prikey\n");
+		goto free_ecx_key;
+	}
+
+	ret = RAND_priv_bytes(prikey, ecx_key->keylen);
+	if (ret <= 0) {
+		fprintf(stderr, "failed to set rand bytes to prikey\n");
+		goto free_pri;
+	}
+	ecx_key->privkey = prikey;
+
+	return ecx_key;
+
+free_pri:
+	OPENSSL_secure_free(prikey);
+free_ecx_key:
+	uadk_prov_ecx_key_free(ecx_key);
+
+	return NULL;
+}
+
+static void uadk_prov_ecx_free_prikey(ECX_KEY *ecx_key)
+{
+	if (ecx_key == NULL)
+		return;
+
+	if (ecx_key->privkey) {
+		OPENSSL_secure_free(ecx_key->privkey);
+		ecx_key->privkey = NULL;
+	}
+
+	uadk_prov_ecx_key_free(ecx_key);
+}
+
+static int uadk_prov_ecx_keygen_init_iot(handle_t sess, struct wd_ecc_req *req)
+{
+	struct wd_ecc_out *ecx_out;
+
+	ecx_out = wd_ecxdh_new_out(sess);
+	if (ecx_out == NULL) {
+		fprintf(stderr, "failed to new sign out\n");
+		return UADK_P_FAIL;
+	}
+
+	uadk_prov_ecc_fill_req(req, WD_ECXDH_GEN_KEY, NULL, ecx_out);
+
+	return UADK_P_SUCCESS;
+}
+
+static void uadk_prov_ecx_keygen_uninit_iot(handle_t sess, struct wd_ecc_req *req)
+{
+	wd_ecc_del_out(sess, req->dst);
+}
+
+static int uadk_prov_reverse_bytes(unsigned char *to_buf, __u32 size)
+{
+	unsigned char *tmp_buf = NULL;
+	unsigned char tmp;
+
+	if (size == 0) {
+		fprintf(stderr, "invalid size, size = %u\n", size);
+		return UADK_P_FAIL;
+	}
+
+	if (to_buf == NULL) {
+		fprintf(stderr, "to_buf is NULL\n");
+		return UADK_P_FAIL;
+	}
+
+	tmp_buf = to_buf + size - 1;
+	while (to_buf < tmp_buf) {
+		tmp = *tmp_buf;
+		*tmp_buf-- = *to_buf;
+		*to_buf++ = tmp;
+	}
+
+	return UADK_P_SUCCESS;
+}
+
+static int uadk_prov_reverse_bytes_ex(unsigned char *src_buf, unsigned char *dst_buf, __u32 size)
+{
+	__u32 i;
+
+	if (size == 0) {
+		fprintf(stderr, "invalid size, size = %u\n", size);
+		return UADK_P_FAIL;
+	}
+
+	if (src_buf == NULL) {
+		fprintf(stderr, "src_buf is NULL\n");
+		return UADK_P_FAIL;
+	}
+
+	if (dst_buf == NULL) {
+		fprintf(stderr, "dst_buf is NULL\n");
+		return UADK_P_FAIL;
+	}
+
+	for (i = 0; i < size; i++)
+		dst_buf[i] = src_buf[size - i - 1];
+
+	return UADK_P_SUCCESS;
+}
+
+static int uadk_prov_ecx_set_pkey(PROV_ECX_KEYMGMT_CTX *gctx, struct wd_ecc_req *req,
+				  ECX_KEY *ecx_key)
+{
+	struct wd_ecc_point *pubkey = NULL;
+	int ret;
+
+	wd_ecxdh_get_out_params(req->dst, &pubkey);
+	if (pubkey == NULL) {
+		fprintf(stderr, "failed to get pubkey\n");
+		return UADK_P_FAIL;
+	}
+
+	if (pubkey->x.dsize >= ECX_MAX_KEYLEN) {
+		fprintf(stderr, "invalid: pubkey->x.dsize = %u\n",
+			pubkey->x.dsize);
+		return UADK_P_FAIL;
+	}
+
+	/* Trans public key from big-endian to little-endian */
+	ret = uadk_prov_reverse_bytes_ex((unsigned char *)pubkey->x.data,
+					 ecx_key->pubkey, pubkey->x.dsize);
+	if (ret == UADK_P_FAIL) {
+		fprintf(stderr, "failed to transform pubkey\n");
+		return ret;
+	}
+	/* Trans private key from big-endian to little-endian */
+	ret = uadk_prov_reverse_bytes(ecx_key->privkey, gctx->keylen);
+	if (ret == UADK_P_FAIL) {
+		fprintf(stderr, "failed to transform prikey\n");
+		return ret;
+	}
+	/*
+	 * This is a pretreatment of X448 described in RFC 7748.
+	 * In order to decode the random bytes as an integer scaler, there
+	 * are some special data processing. And use little-endian mode for
+	 * decoding.
+	 */
+	if (gctx->type == ECX_KEY_TYPE_X448) {
+		/* Set the two LSB of the first byte to 0 */
+		ecx_key->privkey[0] &= 0xFC;
+
+		/* Set the MSB of the last byte to 1 */
+		ecx_key->privkey[X448_KEYLEN - 1] |= 0x80;
+	} else {
+		fprintf(stderr, "invalid: unsupported ecx type\n");
+		return UADK_P_FAIL;
+	}
+
+	return ret;
+}
+
+static int uadk_prov_ecx_keygen_set_prikey(PROV_ECX_KEYMGMT_CTX *gctx, ECX_KEY *ecx_key)
+{
+	struct wd_ecc_key *ecc_key = NULL;
+	struct wd_dtb prikey = {0};
+	handle_t sess = gctx->sess;
+	int ret;
+
+	prikey.data = (char *)ecx_key->privkey;
+	prikey.dsize = ecx_key->keylen;
+
+	ecc_key = wd_ecc_get_key(sess);
+	ret = wd_ecc_set_prikey(ecc_key, &prikey);
+	if (ret) {
+		fprintf(stderr, "failed to set ecc prikey, ret = %d\n", ret);
+		return UADK_P_FAIL;
+	}
+
+	return UADK_P_SUCCESS;
+}
+
+static void *uadk_prov_ecx_keygen(PROV_ECX_KEYMGMT_CTX *gctx)
+{
+	struct wd_ecc_req req = {0};
+	ECX_KEY *ecx_key = NULL;
+	int ret;
+
+	ecx_key = uadk_prov_ecx_create_prikey(gctx);
+	if (ecx_key == NULL)
+		return NULL;
+
+	ret = uadk_prov_ecx_keygen_init_iot(gctx->sess, &req);
+	if (ret == UADK_P_FAIL)
+		goto free_prikey;
+
+	ret = uadk_prov_ecx_keygen_set_prikey(gctx, ecx_key);
+	if (ret == UADK_P_FAIL)
+		goto uninit_iot;
+
+	ret = uadk_prov_ecc_crypto(gctx->sess, &req, (void *)gctx->sess);
+	if (ret == UADK_P_FAIL)
+		goto uninit_iot;
+
+	ret = uadk_prov_ecx_set_pkey(gctx, &req, ecx_key);
+	if (ret == UADK_P_FAIL)
+		goto uninit_iot;
+
+	ecx_key->haspubkey = 1;
+
+	uadk_prov_ecx_keygen_uninit_iot(gctx->sess, &req);
+
+	return ecx_key;
+
+uninit_iot:
+	uadk_prov_ecx_keygen_uninit_iot(gctx->sess, &req);
+free_prikey:
+	uadk_prov_ecx_free_prikey(ecx_key);
+
+	return NULL;
+}
+
+static void *uadk_keymgmt_x448_gen(void *genctx, OSSL_CALLBACK *cb, void *cb_params)
+{
+	PROV_ECX_KEYMGMT_CTX *gctx = (PROV_ECX_KEYMGMT_CTX *)genctx;
+	ECX_KEY *ecx_key = NULL;
+	int ret;
+
+	if (gctx == NULL) {
+		fprintf(stderr, "invalid: ecx keygen ctx is NULL\n");
+		return NULL;
+	}
+
+	if (gctx->type != ECX_KEY_TYPE_X448) {
+		fprintf(stderr, "invalid: unsupported ecx type\n");
+		return NULL;
+	}
+
+	ret = uadk_prov_keymgmt_get_support_state(KEYMGMT_X448);
+	if (ret == UADK_P_FAIL) {
+		fprintf(stderr, "failed to get hardware x448 keygen support\n");
+		return NULL;
+	}
+
+	ret = uadk_prov_ecc_init("x448");
+	if (ret != UADK_P_SUCCESS) {
+		fprintf(stderr, "failed to init x448\n");
+		return NULL;
+	}
+
+	gctx->sess = uadk_prov_x448_alloc_sess();
+	if (gctx->sess == (handle_t)0) {
+		fprintf(stderr, "failed to alloc x448 sess\n");
+		return NULL;
+	}
+
+	ecx_key = uadk_prov_ecx_keygen(gctx);
+	if (ecx_key == NULL)
+		fprintf(stderr, "failed to generate x448 key\n");
+
+	uadk_prov_x448_free_sess(gctx->sess);
+
+	return ecx_key;
+}
+
+static UADK_PKEY_KEYEXCH get_default_x448_keyexch(void)
+{
+	static UADK_PKEY_KEYEXCH s_keyexch;
+	static int initilazed;
+
+	if (!initilazed) {
+		UADK_PKEY_KEYEXCH *keyexch =
+			(UADK_PKEY_KEYEXCH *)EVP_KEYEXCH_fetch(NULL, "X448", "provider=default");
+		if (keyexch) {
+			s_keyexch = *keyexch;
+			EVP_KEYEXCH_free((EVP_KEYEXCH *)keyexch);
+			initilazed = 1;
+		} else {
+			fprintf(stderr, "failed to EVP_KEYEXCH_fetch default X448 provider\n");
+		}
+	}
+	return s_keyexch;
+}
+
+static void *uadk_keyexch_x448_newctx(void *provctx)
+{
+	PROV_ECX_KEYEXCH_CTX *ecxctx = NULL;
+	int ret;
+
+	ecxctx = OPENSSL_zalloc(sizeof(PROV_ECX_KEYEXCH_CTX));
+	if (ecxctx == NULL) {
+		ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+		return NULL;
+	}
+
+	ecxctx->keylen = X448_KEYLEN;
+
+	return ecxctx;
+}
+
+static void uadk_keyexch_x448_freectx(void *vecxctx)
+{
+	PROV_ECX_KEYEXCH_CTX *ecxctx = (PROV_ECX_KEYEXCH_CTX *)vecxctx;
+
+	if (ecxctx == NULL)
+		return;
+
+	OPENSSL_free(ecxctx);
+	ecxctx = NULL;
+}
+
+static int uadk_keyexch_x448_set_ctx_params(void *ecxctx, const OSSL_PARAM params[])
+{
+	if (get_default_x448_keyexch().set_ctx_params == NULL)
+		return UADK_P_FAIL;
+
+	return get_default_x448_keyexch().set_ctx_params(ecxctx, params);
+}
+
+static const OSSL_PARAM *uadk_keyexch_x448_settable_ctx_params(ossl_unused void *ecxctx,
+						ossl_unused void *provctx)
+{
+	if (get_default_x448_keyexch().settable_ctx_params == NULL)
+		return NULL;
+
+	return get_default_x448_keyexch().settable_ctx_params(ecxctx, provctx);
+}
+
+static const OSSL_PARAM *uadk_keyexch_x448_gettable_ctx_params(ossl_unused void *ecxctx,
+						ossl_unused void *provctx)
+{
+	if (get_default_x448_keyexch().gettable_ctx_params == NULL)
+		return NULL;
+
+	return get_default_x448_keyexch().gettable_ctx_params(ecxctx, provctx);
+}
+
+static int uadk_keyexch_x448_get_ctx_params(void *ecxctx, OSSL_PARAM params[])
+{
+	if (get_default_x448_keyexch().get_ctx_params == NULL)
+		return UADK_P_FAIL;
+
+	return get_default_x448_keyexch().get_ctx_params(ecxctx, params);
+}
+
+static int uadk_keyexch_x448_init(void *vecxctx, void *vkey,
+				  ossl_unused const OSSL_PARAM params[])
+{
+	PROV_ECX_KEYEXCH_CTX *ecxctx = (PROV_ECX_KEYEXCH_CTX *)vecxctx;
+	ECX_KEY *key = vkey;
+	int ret;
+
+	if (ecxctx == NULL) {
+		fprintf(stderr, "invalid: ecxctx is NULL\n");
+		return UADK_P_FAIL;
+	}
+
+	if (key == NULL) {
+		fprintf(stderr, "invalid: key is NULL\n");
+		return UADK_P_FAIL;
+	}
+
+	if (key->keylen != ecxctx->keylen) {
+		fprintf(stderr, "invalid: key->keylen(%zu) != ecxctx->keylen(%zu)\n",
+			key->keylen, ecxctx->keylen);
+		return UADK_P_FAIL;
+	}
+
+	uadk_prov_ecx_key_free(ecxctx->key);
+	ecxctx->key = key;
+
+	return UADK_P_SUCCESS;
+}
+
+int ossl_ecx_key_up_ref(ECX_KEY *key)
+{
+	int i = 0;
+
+	if (UADK_CRYPTO_UP_REF(&key->references, &i, key->lock) <= 0)
+		return UADK_P_FAIL;
+
+	return ((i > 1) ? UADK_P_SUCCESS : UADK_P_FAIL);
+}
+
+static int uadk_keyexch_x448_set_peer(void *vecxctx, void *vkey)
+{
+	PROV_ECX_KEYEXCH_CTX *ecxctx = (PROV_ECX_KEYEXCH_CTX *)vecxctx;
+	ECX_KEY *key = vkey;
+
+	if (ecxctx == NULL) {
+		fprintf(stderr, "invalid: ecxctx is NULL\n");
+		return UADK_P_FAIL;
+	}
+
+	if (key == NULL) {
+		fprintf(stderr, "invalid: key is NULL\n");
+		return UADK_P_FAIL;
+	}
+
+	if (key->keylen != ecxctx->keylen || !ossl_ecx_key_up_ref(key)) {
+		fprintf(stderr, "invalid: key->keylen(%zu) != ecxctx->keylen(%zu)\n",
+			key->keylen, ecxctx->keylen);
+		return UADK_P_FAIL;
+	}
+
+	uadk_prov_ecx_key_free(ecxctx->peerkey);
+	ecxctx->peerkey = key;
+
+	return UADK_P_SUCCESS;
+}
+
+static int uadk_prov_ecx_compkey_init_iot(PROV_ECX_KEYEXCH_CTX *ecxctx, struct wd_ecc_req *req)
+{
+	char buffer_y[ECX_MAX_KEYLEN] = {0};
+	handle_t sess = ecxctx->sess;
+	struct wd_ecc_point in_pubkey;
+	struct wd_ecc_out *ecx_out;
+	struct wd_ecc_in *ecx_in;
+	int ret;
+
+	/* Trans public key from little-endian to big-endian */
+	ret = uadk_prov_reverse_bytes(ecxctx->peerkey->pubkey, ecxctx->keylen);
+	if (ret == UADK_P_FAIL) {
+		fprintf(stderr, "failed to trans public key\n");
+		return UADK_P_FAIL;
+	}
+
+	in_pubkey.x.data = (char *)ecxctx->peerkey->pubkey;
+	in_pubkey.x.dsize = ecxctx->keylen;
+	in_pubkey.y.data = buffer_y;
+	in_pubkey.y.dsize = 1;
+
+	ecx_in = wd_ecxdh_new_in(sess, &in_pubkey);
+	if (ecx_in == NULL) {
+		fprintf(stderr, "failed to new ecxdh in\n");
+		return UADK_P_FAIL;
+	}
+
+	ecx_out = wd_ecxdh_new_out(sess);
+	if (ecx_out == NULL) {
+		fprintf(stderr, "failed to new ecxdh out\n");
+		ret = UADK_P_FAIL;
+		goto del_in;
+	}
+
+	uadk_prov_ecc_fill_req(req, WD_ECXDH_COMPUTE_KEY, ecx_in, ecx_out);
+
+	/* Trans public key from big-endian to little-endian */
+	ret = uadk_prov_reverse_bytes(ecxctx->peerkey->pubkey, ecxctx->keylen);
+	if (ret == UADK_P_FAIL) {
+		fprintf(stderr, "failed to trans public key\n");
+		goto del_out;
+	}
+
+	return ret;
+
+del_out:
+	wd_ecc_del_out(sess, ecx_out);
+del_in:
+	wd_ecc_del_in(sess, ecx_in);
+
+	return ret;
+}
+
+static void uadk_prov_ecx_compkey_uninit_iot(PROV_ECX_KEYEXCH_CTX *ecxctx, struct wd_ecc_req *req)
+{
+	wd_ecc_del_in(ecxctx->sess, req->src);
+	wd_ecc_del_out(ecxctx->sess, req->dst);
+}
+
+static int uadk_prov_ecx_derive_set_prikey(PROV_ECX_KEYEXCH_CTX *ecxctx)
+{
+	handle_t sess = ecxctx->sess;
+	struct wd_ecc_key *ecc_key;
+	struct wd_dtb prikey;
+	int ret;
+
+	/* Trans private key from little-endian to big-endian */
+	ret = uadk_prov_reverse_bytes(ecxctx->key->privkey, ecxctx->keylen);
+	if (!ret) {
+		fprintf(stderr, "failed to trans private key\n");
+		return UADK_P_FAIL;
+	}
+
+	prikey.data = (char *)ecxctx->key->privkey;
+	prikey.dsize = ecxctx->keylen;
+	ecc_key = wd_ecc_get_key(sess);
+	ret = wd_ecc_set_prikey(ecc_key, &prikey);
+	if (ret) {
+		fprintf(stderr, "failed to set ecc prikey, ret = %d\n", ret);
+		return UADK_P_FAIL;
+	}
+
+	/* Trans private key from big-endian to little-endian */
+	ret = uadk_prov_reverse_bytes(ecxctx->key->privkey, ecxctx->keylen);
+	if (ret == UADK_P_FAIL) {
+		fprintf(stderr, "failed to trans private key\n");
+		return UADK_P_FAIL;
+	}
+
+	return UADK_P_SUCCESS;
+}
+
+static void uadk_prov_x448_pad_out_key(unsigned char *dst_key, unsigned char *src_key,
+			     size_t len)
+{
+	unsigned char x448_pad_key[X448_KEYLEN] = {0};
+
+	if (len != X448_KEYLEN) {
+		memcpy(x448_pad_key, src_key, len);
+		memcpy(dst_key, x448_pad_key, X448_KEYLEN);
+	} else {
+		memcpy(dst_key, src_key, X448_KEYLEN);
+	}
+}
+
+static void uadk_prov_ecx_pad_out_key(unsigned char *dst_key, unsigned char *src_key,
+				      size_t len, int type)
+{
+	if (type == ECX_KEY_TYPE_X448) {
+		uadk_prov_x448_pad_out_key(dst_key, src_key, len);
+		return;
+	}
+}
+
+static int uadk_prov_ecx_derive(PROV_ECX_KEYEXCH_CTX *ecxctx, unsigned char *key, size_t *keylen)
+{
+	struct wd_ecc_point *s_key = NULL;
+	ECX_KEY *peer_ecx_key = NULL;
+	struct wd_ecc_req req = {0};
+	ECX_KEY *ecx_key = NULL;
+	int ret;
+
+	if (ecxctx == NULL) {
+		fprintf(stderr, "invalid: ctx is NULL\n");
+		return UADK_P_FAIL;
+	}
+
+	peer_ecx_key = ecxctx->peerkey;
+	ecx_key = ecxctx->key;
+	if (peer_ecx_key == NULL || ecx_key == NULL) {
+		fprintf(stderr, "invalid: peer_ecx_key or ecx_key is NULL\n");
+		return UADK_P_FAIL;
+	}
+
+	if (key == NULL || *keylen == 0) {
+		*keylen = (size_t)ecxctx->keylen;
+		return UADK_P_SUCCESS;
+	}
+
+	ret = uadk_prov_ecx_compkey_init_iot(ecxctx, &req);
+	if (ret == UADK_P_FAIL)
+		return UADK_P_FAIL;
+
+	ret = uadk_prov_ecx_derive_set_prikey(ecxctx);
+	if (ret == UADK_P_FAIL)
+		goto uninit_iot;
+
+	ret = uadk_prov_ecc_crypto(ecxctx->sess, &req, (void *)ecxctx);
+	if (ret == UADK_P_FAIL)
+		goto uninit_iot;
+
+	wd_ecxdh_get_out_params(req.dst, &s_key);
+	if (!s_key)
+		goto uninit_iot;
+
+	ret = uadk_prov_reverse_bytes((unsigned char *)s_key->x.data, s_key->x.dsize);
+	if (ret == UADK_P_FAIL)
+		goto uninit_iot;
+
+	uadk_prov_ecx_pad_out_key(key, (unsigned char *)s_key->x.data,
+				  s_key->x.dsize, ecx_key->type);
+
+uninit_iot:
+	uadk_prov_ecx_compkey_uninit_iot(ecxctx, &req);
+
+	return ret;
+}
+
+static int uadk_keyexch_x448_derive(void *vecxctx, unsigned char *secret, size_t *secretlen,
+				    size_t outlen)
+{
+	PROV_ECX_KEYEXCH_CTX *ecxctx = (PROV_ECX_KEYEXCH_CTX *)vecxctx;
+	int ret;
+
+	if (ecxctx == NULL) {
+		fprintf(stderr, "invalid: ecxctx is NULL in derive op\n");
+		return UADK_P_FAIL;
+	}
+
+	if (ecxctx->key == NULL || ecxctx->key->privkey == NULL ||
+	    ecxctx->peerkey == NULL) {
+		ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
+		return UADK_P_FAIL;
+	}
+
+	if (ecxctx->keylen != X448_KEYLEN) {
+		ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH);
+		return UADK_P_FAIL;
+	}
+
+	if (secret == NULL) {
+		*secretlen = ecxctx->keylen;
+		return UADK_P_SUCCESS;
+	}
+
+	if (outlen < ecxctx->keylen) {
+		ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
+		return UADK_P_FAIL;
+	}
+
+	ret = uadk_prov_keyexch_get_support_state(KEYEXCH_X448);
+	if (ret == UADK_P_FAIL) {
+		fprintf(stderr, "failed to get hardware x448 keyexch support\n");
+		return UADK_P_FAIL;
+	}
+
+	ret = uadk_prov_ecc_init("x448");
+	if (ret != UADK_P_SUCCESS) {
+		fprintf(stderr, "failed to init x448\n");
+		return UADK_P_FAIL;
+	}
+
+	ecxctx->sess = uadk_prov_x448_alloc_sess();
+	if (ecxctx->sess == (handle_t)0) {
+		fprintf(stderr, "failed to alloc sess\n");
+		return UADK_P_FAIL;
+	}
+
+	ret = uadk_prov_ecx_derive(ecxctx, secret, &ecxctx->keylen);
+	if (ret == UADK_P_FAIL)
+		fprintf(stderr, "failed to do x448 derive\n");
+
+	*secretlen = ecxctx->keylen;
+
+	uadk_prov_x448_free_sess(ecxctx->sess);
+
+	return ret;
+}
+
+static void *uadk_keyexch_x448_dupctx(void *vecxctx)
+{
+	PROV_ECX_KEYEXCH_CTX *srcctx = (PROV_ECX_KEYEXCH_CTX *)vecxctx;
+	PROV_ECX_KEYEXCH_CTX *dstctx;
+
+	if (srcctx == NULL)
+		return NULL;
+
+	dstctx = OPENSSL_zalloc(sizeof(PROV_ECX_KEYEXCH_CTX));
+	if (dstctx == NULL) {
+		ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+		return NULL;
+	}
+
+	*dstctx = *srcctx;
+	if (dstctx->key != NULL && !ossl_ecx_key_up_ref(dstctx->key)) {
+		ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
+		OPENSSL_free(dstctx);
+		return NULL;
+	}
+
+	if (dstctx->peerkey != NULL && !ossl_ecx_key_up_ref(dstctx->peerkey)) {
+		ERR_raise(ERR_LIB_PROV, ERR_R_INTERNAL_ERROR);
+		uadk_prov_ecx_key_free(dstctx->key);
+		OPENSSL_free(dstctx);
+		return NULL;
+	}
+
+	return dstctx;
+}
diff --git a/src/uadk_prov_init.c b/src/uadk_prov_init.c
index 42e1272..9a2baeb 100644
--- a/src/uadk_prov_init.c
+++ b/src/uadk_prov_init.c
@@ -176,6 +176,8 @@ static const OSSL_ALGORITHM uadk_prov_keymgmt[] = {
 	  uadk_sm2_keymgmt_functions, "uadk SM2 Keymgmt implementation." },
 	{ "EC", UADK_DEFAULT_PROPERTIES,
 	  uadk_ec_keymgmt_functions, "uadk EC Keymgmt implementation."},
+	{ "X448", UADK_DEFAULT_PROPERTIES,
+	  uadk_x448_keymgmt_functions, "uadk X448 Keymgmt implementation."},
 	{ NULL, NULL, NULL }
 };
 
@@ -192,6 +194,8 @@ static const OSSL_ALGORITHM uadk_prov_keyexch[] = {
 	  uadk_dh_keyexch_functions, "UADK DH keyexch implementation"},
 	{ "ECDH", UADK_DEFAULT_PROPERTIES,
 	  uadk_ecdh_keyexch_functions, "uadk_provider ecdh_keyexch" },
+	{ "X448", UADK_DEFAULT_PROPERTIES,
+	  uadk_x448_keyexch_functions, "uadk X448 keyexch implementation."},
 	{ NULL, NULL, NULL }
 };
 
diff --git a/src/uadk_prov_pkey.c b/src/uadk_prov_pkey.c
index a861551..0615b61 100644
--- a/src/uadk_prov_pkey.c
+++ b/src/uadk_prov_pkey.c
@@ -29,6 +29,7 @@
 #define PROV_SUPPORT		1
 #define SIGNATURE_TYPE		3
 #define ASYM_CIPHER_TYPE	3
+#define KEYEXCH_TYPE		4
 #define SECURITY_CHECK_DISABLE	0
 #define UADK_PROV_MIN_BITS	112
 #define UADK_PROV_SECURITY_BITS	80
@@ -36,6 +37,7 @@
 static int p_keymgmt_support_state[KEYMGMT_TYPE];
 static int p_signature_support_state[SIGNATURE_TYPE];
 static int p_asym_cipher_support_state[ASYM_CIPHER_TYPE];
+static int p_keyexch_support_state[KEYEXCH_TYPE];
 
 struct ecc_prov {
 	int pid;
@@ -85,6 +87,16 @@ static void uadk_prov_asym_cipher_set_support_state(int alg_tag, int value)
 	p_asym_cipher_support_state[alg_tag] = value;
 }
 
+int uadk_prov_keyexch_get_support_state(int alg_tag)
+{
+	return p_keyexch_support_state[alg_tag];
+}
+
+static void uadk_prov_keyexch_set_support_state(int alg_tag, int value)
+{
+	p_keyexch_support_state[alg_tag] = value;
+}
+
 static int uadk_prov_ecc_get_hw_keybits(int key_bits)
 {
 	if (key_bits > ECC384BITS)
@@ -358,7 +370,7 @@ int uadk_prov_ecc_crypto(handle_t sess, struct wd_ecc_req *req, void *usr)
 {
 	struct uadk_e_cb_info cb_param;
 	struct async_op op;
-	int idx, ret;
+	int idx, ret, cnt;
 
 	ret = async_setup_async_event_notification(&op);
 	if (ret == 0) {
@@ -385,11 +397,17 @@ int uadk_prov_ecc_crypto(handle_t sess, struct wd_ecc_req *req, void *usr)
 		goto err;
 
 	op.idx = idx;
+	cnt = 0;
 	do {
 		ret = wd_do_ecc_async(sess, req);
 		if (ret < 0 && ret != -EBUSY) {
-			async_free_poll_task(op.idx, 0);
-			goto err;
+			fprintf(stderr, "failed to do ecc async\n");
+			goto free_poll_task;
+		}
+
+		if (unlikely(++cnt > PROV_SEND_MAX_CNT)) {
+			fprintf(stderr, "do ecc async operation timeout\n");
+			goto free_poll_task;
 		}
 	} while (ret == -EBUSY);
 
@@ -398,10 +416,12 @@ int uadk_prov_ecc_crypto(handle_t sess, struct wd_ecc_req *req, void *usr)
 		goto err;
 
 	if (req->status)
-		return UADK_P_FAIL;
+		goto err;
 
 	return UADK_P_SUCCESS;
 
+free_poll_task:
+	async_free_poll_task(op.idx, 0);
 err:
 	(void)async_clear_async_event_notification();
 	return UADK_P_FAIL;
@@ -631,7 +651,7 @@ int uadk_prov_ecc_genctx_check(struct ec_gen_ctx *gctx, EC_KEY *ec)
 	return UADK_P_SUCCESS;
 }
 
-bool uadk_prov_support_algorithm(const char *alg)
+static bool uadk_prov_support_algorithm(const char *alg)
 {
 	struct uacce_dev_list *list = wd_get_accel_list(alg);
 
@@ -645,7 +665,7 @@ bool uadk_prov_support_algorithm(const char *alg)
 
 void uadk_prov_keymgmt_alg(void)
 {
-	static const char * const keymgmt_alg[] = {"sm2", "ecdh"};
+	static const char * const keymgmt_alg[] = {"sm2", "x448", "ecdh"};
 	__u32 i, size;
 	bool sp;
 
@@ -664,7 +684,7 @@ void uadk_prov_signature_alg(void)
 	__u32 i, size;
 	bool sp;
 
-	/* Enumerate keymgmt algs to check whether it is supported and set tags */
+	/* Enumerate signature algs to check whether it is supported and set tags */
 	size = ARRAY_SIZE(signature_alg);
 	for (i = 0; i < size; i++) {
 		sp = uadk_prov_support_algorithm(*(signature_alg + i));
@@ -769,7 +789,7 @@ void uadk_prov_asym_cipher_alg(void)
 	__u32 i, size;
 	bool sp;
 
-	/* Enumerate keymgmt algs to check whether it is supported and set tags */
+	/* Enumerate asym_cipher algs to check whether it is supported and set tags */
 	size = ARRAY_SIZE(asym_cipher_alg);
 	for (i = 0; i < size; i++) {
 		sp = uadk_prov_support_algorithm(*(asym_cipher_alg + i));
@@ -815,6 +835,21 @@ void uadk_prov_ecc_uninit(void)
 	pthread_mutex_unlock(&ecc_mutex);
 }
 
+void uadk_prov_keyexch_alg(void)
+{
+	static const char * const keyexch_alg[] = {"x448", "ecdh"};
+	__u32 i, size;
+	bool sp;
+
+	/* Enumerate keyexch algs to check whether it is supported and set tags */
+	size = ARRAY_SIZE(keyexch_alg);
+	for (i = 0; i < size; i++) {
+		sp = uadk_prov_support_algorithm(*(keyexch_alg + i));
+		if (sp)
+			uadk_prov_keyexch_set_support_state(i, PROV_SUPPORT);
+	}
+}
+
 int uadk_prov_ecc_bit_check(const EC_GROUP *group)
 {
 	int bits = EC_GROUP_order_bits(group);
diff --git a/src/uadk_prov_pkey.h b/src/uadk_prov_pkey.h
index fbec388..e79fc52 100644
--- a/src/uadk_prov_pkey.h
+++ b/src/uadk_prov_pkey.h
@@ -68,7 +68,8 @@
 
 enum {
 	KEYMGMT_SM2 = 0x0,
-	KEYMGMT_EC = 0x1,
+	KEYMGMT_X448 = 0x1,
+	KEYMGMT_ECDH = 0x2,
 	KEYMGMT_MAX = 0x6
 };
 
@@ -83,6 +84,11 @@ enum {
 	COFACTOR_MODE_ENABLED = 1,
 };
 
+enum {
+	KEYEXCH_X448 = 0x0,
+	KEYEXCH_ECDH = 0x1,
+};
+
 struct curve_param {
 	/* Prime */
 	BIGNUM *p;
@@ -451,11 +457,11 @@ 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);
+void uadk_prov_keyexch_alg(void);
+int uadk_prov_keyexch_get_support_state(int alg_tag);
 int uadk_prov_ecc_bit_check(const EC_GROUP *group);
-bool uadk_prov_support_algorithm(const char *alg);
 int uadk_prov_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *p,
 				     BIGNUM *x, BIGNUM *y, BN_CTX *ctx);
-void uadk_prov_keyexch_alg(void);
 int uadk_prov_securitycheck_enabled(OSSL_LIB_CTX *ctx);
 int uadk_prov_ecc_check_key(OSSL_LIB_CTX *ctx, const EC_KEY *ec, int protect);
 
-- 
2.25.1

