uadk_engine/0005-uadk_provider-support-ecdh-keyexch-hardware-accelera.patch
Eingesch de8288e8f7 uadk_engine: adding the uadk_provider library
(cherry picked from commit 66c935685ac0a2f1c37fd09e88d24f793a8c24ba)
2024-12-20 15:58:28 +08:00

1083 lines
28 KiB
Diff

From 8b0bd5f9f9cfd2e2435df8bc8b2aac9379b6b2c9 Mon Sep 17 00:00:00 2001
From: Weili Qian <qianweili@huawei.com>
Date: Thu, 19 Dec 2024 15:58:01 +0800
Subject: [PATCH 05/10] uadk_provider: support ecdh keyexch hardware
acceleration
Support ECDH key exchange.
Test:
openssl speed -provider uadk_provider ecdhp192
openssl speed -provider uadk_provider ecdhp224
openssl speed -provider uadk_provider ecdhp256
openssl speed -provider uadk_provider ecdhp384
openssl speed -provider uadk_provider ecdhp521
Signed-off-by: Weili Qian <qianweili@huawei.com>
Signed-off-by: JiangShui Yang <yangjiangshui@h-partners.com>
---
src/Makefile.am | 2 +-
src/uadk_prov.h | 1 +
src/uadk_prov_ecdh_exch.c | 889 ++++++++++++++++++++++++++++++++++++++
src/uadk_prov_init.c | 9 +-
src/uadk_prov_pkey.c | 68 +++
src/uadk_prov_pkey.h | 6 +
6 files changed, 971 insertions(+), 4 deletions(-)
create mode 100644 src/uadk_prov_ecdh_exch.c
diff --git a/src/Makefile.am b/src/Makefile.am
index b2e2c06..5a1abe7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -66,7 +66,7 @@ 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_ec_kmgmt.c uadk_prov_ecdh_exch.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 9c310b7..7975884 100644
--- a/src/uadk_prov.h
+++ b/src/uadk_prov.h
@@ -180,6 +180,7 @@ 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];
+extern const OSSL_DISPATCH uadk_ecdh_keyexch_functions[FUNC_MAX_NUM];
void uadk_prov_destroy_digest(void);
void uadk_prov_destroy_cipher(void);
diff --git a/src/uadk_prov_ecdh_exch.c b/src/uadk_prov_ecdh_exch.c
new file mode 100644
index 0000000..f549d25
--- /dev/null
+++ b/src/uadk_prov_ecdh_exch.c
@@ -0,0 +1,889 @@
+// 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 <openssl/kdf.h>
+#include <uadk/wd_ecc.h>
+#include "uadk_async.h"
+#include "uadk_prov.h"
+#include "uadk_prov_der_writer.h"
+#include "uadk_prov_pkey.h"
+
+#define UADK_PROV_MAX_PARAM_LEN 80
+
+enum kdf_type {
+ PROV_ECDH_KDF_NONE = 0,
+ PROV_ECDH_KDF_X9_63
+};
+
+/*
+ * What's passed as an actual key is defined by the KEYMGMT interface.
+ * We happen to know that our KEYMGMT simply passes EC_KEY structures, so
+ * we use that here too.
+ */
+struct ecdh_ctx {
+ OSSL_LIB_CTX *libctx;
+
+ EC_KEY *k;
+ EC_KEY *peerk;
+
+ /*
+ * ECDH cofactor mode:
+ *
+ * . 0 disabled
+ * . 1 enabled
+ * . -1 use cofactor mode set for k
+ */
+ int cofactor_mode;
+ /* KDF (if any) to use for ECDH */
+ enum kdf_type kdf_type;
+ /* Message digest to use for key derivation */
+ EVP_MD *kdf_md;
+ /* User key material */
+ unsigned char *kdf_ukm;
+ size_t kdf_ukmlen;
+ /* KDF output length */
+ size_t kdf_outlen;
+};
+
+struct ecdh_sess_ctx {
+ EC_KEY *privk;
+ const EC_POINT *pub_key;
+ const BIGNUM *cofactor;
+ const EC_GROUP *group;
+};
+
+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)
+{
+ size_t degree;
+
+ degree = EC_GROUP_get_degree(group);
+
+ return BITS_TO_BYTES(degree);
+}
+
+static int ecdh_param_check(struct ecdh_ctx *pecdhctx, struct ecdh_sess_ctx *sess_ctx)
+{
+ const EC_GROUP *group;
+ int type;
+
+ if (!pecdhctx->k || !pecdhctx->peerk) {
+ fprintf(stderr, "invalid: k or peerk is NULL.\n");
+ return UADK_P_FAIL;
+ }
+
+ sess_ctx->pub_key = EC_KEY_get0_public_key(pecdhctx->peerk);
+ if (!sess_ctx->pub_key) {
+ fprintf(stderr, "invalid: public key is NULL.\n");
+ return UADK_P_FAIL;
+ }
+
+ group = EC_KEY_get0_group(pecdhctx->k);
+ if (!group) {
+ fprintf(stderr, "invalid: group is 0.\n");
+ return UADK_P_FAIL;
+ }
+
+ sess_ctx->cofactor = EC_GROUP_get0_cofactor(group);
+ if (!sess_ctx->cofactor) {
+ fprintf(stderr, "invalid: cofactor is NULL!\n");
+ return UADK_P_FAIL;
+ }
+
+ /* 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;
+ }
+
+ sess_ctx->group = group;
+
+ return uadk_prov_ecc_bit_check(group);
+}
+
+static int ecdh_set_privk(struct ecdh_ctx *pecdhctx,
+ struct ecdh_sess_ctx *sess_ctx)
+{
+ int key_cofactor_mode;
+
+ /*
+ * The ctx->cofactor_mode flag has precedence over the
+ * cofactor_mode flag set on ctx->k.
+ *
+ * - if ctx->cofactor_mode == -1, use ctx->k directly
+ * - if ctx->cofactor_mode == key_cofactor_mode, use ctx->k directly
+ * - if ctx->cofactor_mode != key_cofactor_mode:
+ * - if ctx->k->cofactor == 1, the cofactor_mode flag is irrelevant, use
+ * ctx->k directly
+ * - if ctx->k->cofactor != 1, use a duplicate of ctx->k with the flag
+ * set to ctx->cofactor_mode
+ */
+ key_cofactor_mode = (EC_KEY_get_flags(pecdhctx->k) & EC_FLAG_COFACTOR_ECDH) ?
+ COFACTOR_MODE_ENABLED : COFACTOR_MODE_DISABLED;
+ if (pecdhctx->cofactor_mode != COFACTOR_MODE_USE_KEY &&
+ pecdhctx->cofactor_mode != key_cofactor_mode &&
+ !BN_is_one(sess_ctx->cofactor)) {
+ sess_ctx->privk = EC_KEY_dup(pecdhctx->k);
+ if (!sess_ctx->privk)
+ return UADK_P_FAIL;
+
+ if (pecdhctx->cofactor_mode == COFACTOR_MODE_ENABLED)
+ EC_KEY_set_flags(sess_ctx->privk, EC_FLAG_COFACTOR_ECDH);
+ else
+ EC_KEY_clear_flags(sess_ctx->privk, EC_FLAG_COFACTOR_ECDH);
+ } else {
+ sess_ctx->privk = pecdhctx->k;
+ }
+
+ return UADK_P_SUCCESS;
+}
+
+static handle_t ecdh_alloc_sess(EC_KEY *privk)
+{
+ int ret;
+
+ if (!g_keyexch_ecdh_support) {
+ fprintf(stderr, "invalid: hardware not support ecdh!\n");
+ return UADK_P_FAIL;
+ }
+
+ ret = uadk_prov_ecc_init("ecdh");
+ if (!ret) {
+ fprintf(stderr, "failed to init ecdh to compute key!\n");
+ return UADK_P_FAIL;
+ }
+
+ return uadk_prov_ecc_alloc_sess(privk, "ecdh");
+}
+
+static void ecdh_free_sess(handle_t sess)
+{
+ wd_ecc_free_sess(sess);
+}
+
+static int ecdh_init_req(struct ecdh_sess_ctx *sess_ctx,
+ struct wd_ecc_req *req, handle_t sess)
+{
+ char buf_x[UADK_ECC_MAX_KEY_BYTES];
+ char buf_y[UADK_ECC_MAX_KEY_BYTES];
+ struct wd_ecc_point in_pkey;
+ struct wd_ecc_out *ecdh_out;
+ struct wd_ecc_in *ecdh_in;
+ BIGNUM *pkey_x, *pkey_y;
+ int ret = UADK_P_FAIL;
+ BN_CTX *ctx;
+
+ ctx = BN_CTX_new();
+ if (!ctx)
+ return -ENOMEM;
+
+ BN_CTX_start(ctx);
+ pkey_x = BN_CTX_get(ctx);
+ if (!pkey_x)
+ goto free_ctx;
+
+ pkey_y = BN_CTX_get(ctx);
+ if (!pkey_y)
+ goto free_ctx;
+
+ uadk_prov_get_affine_coordinates(sess_ctx->group, sess_ctx->pub_key, pkey_x, pkey_y, ctx);
+ in_pkey.x.data = buf_x;
+ in_pkey.y.data = buf_y;
+ in_pkey.x.dsize = BN_bn2bin(pkey_x, (unsigned char *)in_pkey.x.data);
+ in_pkey.y.dsize = BN_bn2bin(pkey_y, (unsigned char *)in_pkey.y.data);
+
+ /* Set public key */
+ ecdh_in = wd_ecxdh_new_in(sess, &in_pkey);
+ if (!ecdh_in) {
+ fprintf(stderr, "failed to new ecxdh in\n");
+ goto free_ctx;
+ }
+
+ ecdh_out = wd_ecxdh_new_out(sess);
+ if (!ecdh_out) {
+ fprintf(stderr, "failed to new ecxdh out\n");
+ wd_ecc_del_in(sess, ecdh_in);
+ goto free_ctx;
+ }
+
+ uadk_prov_ecc_fill_req(req, WD_ECXDH_COMPUTE_KEY, ecdh_in, ecdh_out);
+
+ ret = UADK_P_SUCCESS;
+
+free_ctx:
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+
+ return ret;
+}
+
+static void ecdh_uninit_req(struct wd_ecc_req *req, handle_t sess)
+{
+ wd_ecc_del_in(sess, req->src);
+ wd_ecc_del_out(sess, req->dst);
+}
+
+static int ecdh_get_shared_key(unsigned char *secret,
+ size_t size, size_t *psecretlen,
+ struct wd_ecc_req *req)
+{
+ struct wd_ecc_point *shared_key = NULL;
+
+ wd_ecxdh_get_out_params(req->dst, &shared_key);
+ if (!shared_key) {
+ fprintf(stderr, "failed to get ecdh shared key\n");
+ return UADK_P_FAIL;
+ }
+
+ size = size < shared_key->x.dsize ? size : shared_key->x.dsize;
+ *psecretlen = size;
+
+ memcpy(secret, (unsigned char *)shared_key->x.data, size);
+
+ return UADK_P_SUCCESS;
+}
+
+static int ecdh_compute_key(struct ecdh_sess_ctx *sess_ctx,
+ unsigned char *secret,
+ size_t *psecretlen, size_t size)
+{
+ struct wd_ecc_req req = {0};
+ handle_t sess;
+ int ret;
+
+ sess = ecdh_alloc_sess(sess_ctx->privk);
+ if (!sess) {
+ fprintf(stderr, "failed to alloc sess to compute key!\n");
+ return UADK_P_FAIL;
+ }
+
+ ret = uadk_prov_ecc_set_private_key(sess, sess_ctx->privk);
+ if (!ret) {
+ fprintf(stderr, "failed to set private key!\n");
+ goto free_sess;
+ }
+
+ ret = ecdh_init_req(sess_ctx, &req, sess);
+ if (!ret) {
+ fprintf(stderr, "failed to init req!\n");
+ goto free_sess;
+ }
+
+ ret = uadk_prov_ecc_crypto(sess, &req, (void *)sess);
+ if (!ret) {
+ fprintf(stderr, "failed to calculate shared key!\n");
+ goto uninit_req;
+ }
+
+ ret = ecdh_get_shared_key(secret, size, psecretlen, &req);
+
+uninit_req:
+ ecdh_uninit_req(&req, sess);
+free_sess:
+ ecdh_free_sess(sess);
+ return ret;
+}
+
+static int ecdh_plain_derive(struct ecdh_ctx *pecdhctx,
+ unsigned char *secret,
+ size_t *psecretlen, size_t outlen)
+{
+ struct ecdh_sess_ctx sess_ctx = {0};
+ size_t size, ec_size;
+ int ret;
+
+ ret = ecdh_param_check(pecdhctx, &sess_ctx);
+ if (!ret)
+ return ret;
+
+ ec_size = ecdh_get_ec_size(sess_ctx.group);
+ if (!secret) {
+ *psecretlen = ec_size;
+ return UADK_P_SUCCESS;
+ }
+
+ ret = ecdh_set_privk(pecdhctx, &sess_ctx);
+ if (!ret) {
+ fprintf(stderr, "failed to set private key!\n");
+ return ret;
+ }
+
+ size = outlen < ec_size ? outlen : ec_size;
+ ret = ecdh_compute_key(&sess_ctx, secret, psecretlen, size);
+ if (sess_ctx.privk != pecdhctx->k)
+ EC_KEY_free(sess_ctx.privk);
+
+ return ret;
+}
+
+/* Key derivation function from X9.63/SECG */
+static int ecdh_kdf_X9_63(unsigned char *out, struct ecdh_ctx *pecdhctx,
+ unsigned char *stmp, size_t stmplen)
+{
+ EVP_KDF *kdf = EVP_KDF_fetch(pecdhctx->libctx, OSSL_KDF_NAME_X963KDF, NULL);
+ const char *mdname = EVP_MD_get0_name(pecdhctx->kdf_md);
+ OSSL_PARAM params[4], *p = params;
+ int ret = UADK_P_FAIL;
+ EVP_KDF_CTX *kctx;
+
+ if (!kdf) {
+ fprintf(stderr, "failed to fetch kdf!\n");
+ return ret;
+ }
+
+ kctx = EVP_KDF_CTX_new(kdf);
+ if (!kctx) {
+ fprintf(stderr, "failed to new kctx!\n");
+ goto free_kdf;
+ }
+
+ *p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, (char *)mdname, 0);
+ *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, (void *)stmp, stmplen);
+ *p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO,
+ (void *)pecdhctx->kdf_ukm, pecdhctx->kdf_ukmlen);
+ *p = OSSL_PARAM_construct_end();
+
+ ret = EVP_KDF_derive(kctx, out, pecdhctx->kdf_outlen, params);
+ ret = ret <= 0 ? UADK_P_FAIL : UADK_P_SUCCESS;
+
+ EVP_KDF_CTX_free(kctx);
+
+free_kdf:
+ EVP_KDF_free(kdf);
+
+ return ret;
+}
+
+static int ecdh_X9_63_kdf_derive(struct ecdh_ctx *pecdhctx, unsigned char *secret,
+ size_t *psecretlen, size_t outlen)
+{
+ unsigned char *stmp;
+ size_t stmplen = 0;
+ int ret;
+
+ if (!secret) {
+ *psecretlen = pecdhctx->kdf_outlen;
+ return UADK_P_SUCCESS;
+ }
+
+ if (outlen < pecdhctx->kdf_outlen) {
+ fprintf(stderr, "invalid: outlen %lu is less than kdf_outlen %lu!\n",
+ outlen, pecdhctx->kdf_outlen);
+ return UADK_P_FAIL;
+ }
+
+ ret = ecdh_plain_derive(pecdhctx, NULL, &stmplen, 0);
+ if (!ret)
+ return ret;
+
+ stmp = OPENSSL_secure_malloc(stmplen);
+ if (!stmp) {
+ fprintf(stderr, "failed to alloc stmp!\n");
+ return UADK_P_FAIL;
+ }
+
+ ret = ecdh_plain_derive(pecdhctx, stmp, &stmplen, stmplen);
+ if (!ret)
+ goto free_stmp;
+
+ ret = ecdh_kdf_X9_63(secret, pecdhctx, stmp, stmplen);
+ if (!ret)
+ goto free_stmp;
+
+ *psecretlen = pecdhctx->kdf_outlen;
+
+ free_stmp:
+ OPENSSL_secure_clear_free(stmp, stmplen);
+ return ret;
+}
+
+static int uadk_keyexch_ecdh_derive(void *vpecdhctx, unsigned char *secret,
+ size_t *psecretlen, size_t outlen)
+{
+ struct ecdh_ctx *pecdhctx = vpecdhctx;
+
+ if (!pecdhctx) {
+ fprintf(stderr, "invalid: vpecdhctx is NULL to derive!\n");
+ return UADK_P_FAIL;
+ }
+
+ switch (pecdhctx->kdf_type) {
+ case PROV_ECDH_KDF_NONE:
+ return ecdh_plain_derive(pecdhctx, secret, psecretlen, outlen);
+ case PROV_ECDH_KDF_X9_63:
+ return ecdh_X9_63_kdf_derive(pecdhctx, secret, psecretlen, outlen);
+ default:
+ break;
+ }
+
+ return UADK_P_FAIL;
+}
+
+static void *uadk_keyexch_ecdh_newctx(void *provctx)
+{
+ struct ecdh_ctx *pectx;
+
+ pectx = OPENSSL_zalloc(sizeof(*pectx));
+ if (!pectx)
+ return NULL;
+
+ pectx->libctx = prov_libctx_of(provctx);
+ pectx->cofactor_mode = COFACTOR_MODE_USE_KEY;
+ pectx->kdf_type = PROV_ECDH_KDF_NONE;
+
+ return pectx;
+}
+
+static void uadk_keyexch_ecdh_freectx(void *vpecdhctx)
+{
+ struct ecdh_ctx *pecdhctx = vpecdhctx;
+
+ if (!pecdhctx)
+ return;
+
+ EC_KEY_free(pecdhctx->k);
+ EC_KEY_free(pecdhctx->peerk);
+ EVP_MD_free(pecdhctx->kdf_md);
+ OPENSSL_clear_free(pecdhctx->kdf_ukm, pecdhctx->kdf_ukmlen);
+ OPENSSL_free(pecdhctx);
+}
+
+static int uadk_keyexch_ecdh_init(void *vpecdhctx, void *vecdh, const OSSL_PARAM params[])
+{
+ struct ecdh_ctx *pecdhctx = vpecdhctx;
+ int ret;
+
+ if (!pecdhctx || !vecdh) {
+ fprintf(stderr, "invalid: pecdhctx or vecdh is to init!\n");
+ return UADK_P_FAIL;
+ }
+
+ if (!EC_KEY_up_ref(vecdh))
+ return UADK_P_FAIL;
+
+ EC_KEY_free(pecdhctx->k);
+ pecdhctx->k = vecdh;
+ pecdhctx->cofactor_mode = COFACTOR_MODE_USE_KEY;
+ pecdhctx->kdf_type = PROV_ECDH_KDF_NONE;
+
+ ret = uadk_keyexch_ecdh_set_ctx_params(pecdhctx, params);
+ if (!ret) {
+ fprintf(stderr, "failed to set_ctx_params!\n");
+ return ret;
+ }
+
+ return uadk_prov_ecc_check_key(pecdhctx->libctx, vecdh, 1);
+}
+
+static int ecdh_match_params(const EC_KEY *privk, const EC_KEY *pubk)
+{
+ const EC_GROUP *group_privk = EC_KEY_get0_group(privk);
+ const EC_GROUP *group_pubk = EC_KEY_get0_group(pubk);
+ int ret = UADK_P_SUCCESS;
+ BN_CTX *ctx;
+
+ ctx = BN_CTX_new_ex(privk->libctx);
+ if (!ctx) {
+ fprintf(stderr, "failed to new ctx!\n");
+ return UADK_P_FAIL;
+ }
+
+ if (group_privk && group_pubk) {
+ if (EC_GROUP_cmp(group_privk, group_pubk, ctx)) {
+ fprintf(stderr, "invalid: privk is not match pubk!\n");
+ ret = UADK_P_FAIL;
+ }
+ }
+
+ BN_CTX_free(ctx);
+
+ return ret;
+}
+
+static int uadk_keyexch_ecdh_set_peer(void *vpecdhctx, void *vecdh)
+{
+ struct ecdh_ctx *pecdhctx = vpecdhctx;
+ int ret;
+
+ if (!pecdhctx || !vecdh) {
+ fprintf(stderr, "invalid: vpecdhctx or vecdh is NULL to set_peer!\n");
+ return UADK_P_FAIL;
+ }
+
+ ret = ecdh_match_params(pecdhctx->k, vecdh);
+ if (!ret)
+ return ret;
+
+ ret = uadk_prov_ecc_check_key(pecdhctx->libctx, vecdh, 1);
+ if (!ret)
+ return ret;
+
+ if (!EC_KEY_up_ref(vecdh))
+ return UADK_P_FAIL;
+
+ EC_KEY_free(pecdhctx->peerk);
+ pecdhctx->peerk = vecdh;
+
+ return UADK_P_SUCCESS;
+}
+
+static void *uadk_keyexch_ecdh_dupctx(void *vpecdhctx)
+{
+ struct ecdh_ctx *srcctx = vpecdhctx;
+ struct ecdh_ctx *dstctx;
+
+ if (!srcctx) {
+ fprintf(stderr, "invalid: source ecdh ctx is NULL!\n");
+ return NULL;
+ }
+
+ dstctx = OPENSSL_zalloc(sizeof(*srcctx));
+ if (!dstctx) {
+ fprintf(stderr, "failed to alloc dst ctx!\n");
+ return NULL;
+ }
+
+ memcpy(dstctx, srcctx, sizeof(*dstctx));
+
+ dstctx->k = NULL;
+ dstctx->peerk = NULL;
+ dstctx->kdf_md = NULL;
+ dstctx->kdf_ukm = NULL;
+
+ /* up-ref all ref-counted objects referenced in dstctx */
+ if (srcctx->k && !EC_KEY_up_ref(srcctx->k))
+ goto err;
+ else
+ dstctx->k = srcctx->k;
+
+ if (srcctx->peerk && !EC_KEY_up_ref(srcctx->peerk))
+ goto err;
+ else
+ dstctx->peerk = srcctx->peerk;
+
+ if (srcctx->kdf_md && !EVP_MD_up_ref(srcctx->kdf_md))
+ goto err;
+ else
+ dstctx->kdf_md = srcctx->kdf_md;
+
+ /* Duplicate UKM data if present */
+ if (srcctx->kdf_ukm && srcctx->kdf_ukmlen > 0) {
+ dstctx->kdf_ukm = OPENSSL_memdup(srcctx->kdf_ukm,
+ srcctx->kdf_ukmlen);
+ if (!dstctx->kdf_ukm)
+ goto err;
+ }
+
+ return dstctx;
+
+err:
+ uadk_keyexch_ecdh_freectx(dstctx);
+ return NULL;
+}
+
+static int ecdh_set_cofactor_mode(struct ecdh_ctx *pectx, const OSSL_PARAM params[])
+{
+ const OSSL_PARAM *p;
+ int mode, ret;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE);
+ if (!p)
+ return UADK_P_SUCCESS;
+
+ ret = OSSL_PARAM_get_int(p, &mode);
+ if (!ret)
+ return UADK_P_FAIL;
+
+ if (mode < COFACTOR_MODE_USE_KEY || mode > COFACTOR_MODE_ENABLED)
+ return UADK_P_FAIL;
+
+ pectx->cofactor_mode = mode;
+
+ return UADK_P_SUCCESS;
+}
+
+static int ecdh_get_cofactor_mode(struct ecdh_ctx *pectx, OSSL_PARAM params[])
+{
+ int mode = pectx->cofactor_mode;
+ OSSL_PARAM *p;
+
+ p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE);
+ if (!p)
+ return UADK_P_SUCCESS;
+
+ if (mode == COFACTOR_MODE_USE_KEY)
+ /* Check what is the default for pecdhctx->k */
+ mode = EC_KEY_get_flags(pectx->k) & EC_FLAG_COFACTOR_ECDH ?
+ COFACTOR_MODE_ENABLED : COFACTOR_MODE_DISABLED;
+
+ return OSSL_PARAM_set_int(p, mode);
+}
+
+static int ecdh_set_kdf_type(struct ecdh_ctx *pectx, const OSSL_PARAM params[])
+{
+ char name[UADK_PROV_MAX_PARAM_LEN] = {'\0'};
+ const OSSL_PARAM *p;
+ char *str = name;
+ int ret;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_TYPE);
+ if (!p)
+ return UADK_P_SUCCESS;
+
+ ret = OSSL_PARAM_get_utf8_string(p, &str, sizeof(name));
+ if (!ret)
+ return UADK_P_FAIL;
+
+ if (name[0] == '\0')
+ pectx->kdf_type = PROV_ECDH_KDF_NONE;
+ else if (!strcmp(name, OSSL_KDF_NAME_X963KDF))
+ pectx->kdf_type = PROV_ECDH_KDF_X9_63;
+ else
+ return UADK_P_FAIL;
+
+ return UADK_P_SUCCESS;
+}
+
+static int ecdh_get_kdf_type(struct ecdh_ctx *pectx, OSSL_PARAM params[])
+{
+ const char *kdf_type;
+ OSSL_PARAM *p;
+
+ p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_TYPE);
+ if (!p)
+ return UADK_P_SUCCESS;
+
+ switch (pectx->kdf_type) {
+ case PROV_ECDH_KDF_NONE:
+ kdf_type = "";
+ break;
+ case PROV_ECDH_KDF_X9_63:
+ kdf_type = OSSL_KDF_NAME_X963KDF;
+ break;
+ default:
+ return UADK_P_FAIL;
+ }
+
+ return OSSL_PARAM_set_utf8_string(p, kdf_type);
+}
+
+static int ecdh_set_kdf_digest(struct ecdh_ctx *pectx, const OSSL_PARAM params[])
+{
+ char mdprops[UADK_PROV_MAX_PARAM_LEN] = {'\0'};
+ char name[UADK_PROV_MAX_PARAM_LEN] = {'\0'};
+ const OSSL_PARAM *p;
+ char *str = name;
+ int ret;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST);
+ if (!p)
+ return UADK_P_SUCCESS;
+
+ ret = OSSL_PARAM_get_utf8_string(p, &str, sizeof(name));
+ if (!ret)
+ return UADK_P_FAIL;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS);
+ if (p) {
+ str = mdprops;
+ ret = OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops));
+ if (!ret)
+ return UADK_P_FAIL;
+ }
+
+ EVP_MD_free(pectx->kdf_md);
+ pectx->kdf_md = EVP_MD_fetch(pectx->libctx, name, mdprops);
+ if (!pectx->kdf_md)
+ return UADK_P_FAIL;
+
+ return UADK_P_SUCCESS;
+}
+
+static int ecdh_get_kdf_digest(struct ecdh_ctx *pectx, OSSL_PARAM params[])
+{
+ OSSL_PARAM *p;
+
+ p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST);
+ if (!p)
+ return UADK_P_SUCCESS;
+
+ if (!pectx->kdf_md)
+ return OSSL_PARAM_set_utf8_string(p, "");
+
+ return OSSL_PARAM_set_utf8_string(p, EVP_MD_get0_name(pectx->kdf_md));
+}
+
+static int ecdh_set_kdf_outlen(struct ecdh_ctx *pectx, const OSSL_PARAM params[])
+{
+ const OSSL_PARAM *p;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN);
+ if (!p)
+ return UADK_P_SUCCESS;
+
+ return OSSL_PARAM_get_size_t(p, &pectx->kdf_outlen);
+}
+
+static int ecdh_get_kdf_outlen(struct ecdh_ctx *pectx, OSSL_PARAM params[])
+{
+ OSSL_PARAM *p;
+
+ p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN);
+ if (!p)
+ return UADK_P_SUCCESS;
+
+ return OSSL_PARAM_set_size_t(p, pectx->kdf_outlen);
+}
+
+static int ecdh_set_kdf_ukm(struct ecdh_ctx *pectx, const OSSL_PARAM params[])
+{
+ const OSSL_PARAM *p;
+ void *tmp_ukm = NULL;
+ size_t tmp_ukmlen;
+ int ret;
+
+ p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_UKM);
+ if (!p)
+ return UADK_P_SUCCESS;
+
+ ret = OSSL_PARAM_get_octet_string(p, &tmp_ukm, 0, &tmp_ukmlen);
+ if (!ret)
+ return ret;
+
+ OPENSSL_free(pectx->kdf_ukm);
+ pectx->kdf_ukm = tmp_ukm;
+ pectx->kdf_ukmlen = tmp_ukmlen;
+
+ return UADK_P_SUCCESS;
+}
+
+static int ecdh_get_kdf_ukm(struct ecdh_ctx *pectx, OSSL_PARAM params[])
+{
+ OSSL_PARAM *p;
+
+ p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_UKM);
+ if (!p)
+ return UADK_P_SUCCESS;
+
+ return OSSL_PARAM_set_octet_ptr(p, pectx->kdf_ukm, pectx->kdf_ukmlen);
+}
+
+static int uadk_keyexch_ecdh_set_ctx_params(void *vpecdhctx, const OSSL_PARAM params[])
+{
+ struct ecdh_ctx *pectx = (struct ecdh_ctx *)vpecdhctx;
+ int ret;
+
+ if (!pectx) {
+ fprintf(stderr, "invalid: pectx is NULL to set_ctx_params!\n");
+ return UADK_P_FAIL;
+ }
+
+ if (!params)
+ return UADK_P_SUCCESS;
+
+ ret = ecdh_set_cofactor_mode(pectx, params);
+ if (!ret)
+ return ret;
+
+ ret = ecdh_set_kdf_type(pectx, params);
+ if (!ret)
+ return ret;
+
+ ret = ecdh_set_kdf_digest(pectx, params);
+ if (!ret)
+ return ret;
+
+ ret = ecdh_set_kdf_outlen(pectx, params);
+ if (!ret)
+ return ret;
+
+ return ecdh_set_kdf_ukm(pectx, params);
+}
+
+static int uadk_keyexch_ecdh_get_ctx_params(void *vpecdhctx, OSSL_PARAM params[])
+{
+ struct ecdh_ctx *pectx = vpecdhctx;
+ int ret;
+
+ if (!pectx) {
+ fprintf(stderr, "invalid: pectx is NULL to get_ctx_params!\n");
+ return UADK_P_FAIL;
+ }
+
+ ret = ecdh_get_cofactor_mode(pectx, params);
+ if (!ret)
+ return ret;
+
+ ret = ecdh_get_kdf_type(pectx, params);
+ if (!ret)
+ return ret;
+
+ ret = ecdh_get_kdf_digest(pectx, params);
+ if (!ret)
+ return ret;
+
+ ret = ecdh_get_kdf_outlen(pectx, params);
+ if (!ret)
+ return ret;
+
+ return ecdh_get_kdf_ukm(pectx, params);
+}
+
+static const OSSL_PARAM *uadk_keyexch_ecdh_settable_ctx_params(ossl_unused void *vpecdhctx,
+ ossl_unused void *provctx)
+{
+ static const OSSL_PARAM known_settable_ctx_params[] = {
+ OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE, NULL),
+ OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS, NULL, 0),
+ OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL),
+ OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM, NULL, 0),
+ OSSL_PARAM_END
+ };
+
+ return known_settable_ctx_params;
+}
+
+static const OSSL_PARAM *uadk_keyexch_ecdh_gettable_ctx_params(ossl_unused void *vpecdhctx,
+ ossl_unused void *provctx)
+{
+ static const OSSL_PARAM known_gettable_ctx_params[] = {
+ OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE, NULL),
+ OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0),
+ OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0),
+ OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL),
+ OSSL_PARAM_DEFN(OSSL_EXCHANGE_PARAM_KDF_UKM, OSSL_PARAM_OCTET_PTR,
+ NULL, 0),
+ OSSL_PARAM_END
+ };
+
+ return known_gettable_ctx_params;
+}
diff --git a/src/uadk_prov_init.c b/src/uadk_prov_init.c
index b5d3df5..42e1272 100644
--- a/src/uadk_prov_init.c
+++ b/src/uadk_prov_init.c
@@ -190,6 +190,8 @@ static const OSSL_ALGORITHM uadk_prov_asym_cipher[] = {
static const OSSL_ALGORITHM uadk_prov_keyexch[] = {
{ "DH", UADK_DEFAULT_PROPERTIES,
uadk_dh_keyexch_functions, "UADK DH keyexch implementation"},
+ { "ECDH", UADK_DEFAULT_PROPERTIES,
+ uadk_ecdh_keyexch_functions, "uadk_provider ecdh_keyexch" },
{ NULL, NULL, NULL }
};
@@ -218,15 +220,16 @@ static const OSSL_ALGORITHM *uadk_query(void *provctx, int operation_id,
return uadk_prov_ciphers_v3;
return uadk_prov_ciphers_v2;
case OSSL_OP_SIGNATURE:
- (void)uadk_prov_signature_alg();
+ uadk_prov_signature_alg();
return uadk_prov_signature;
case OSSL_OP_KEYMGMT:
- (void)uadk_prov_keymgmt_alg();
+ uadk_prov_keymgmt_alg();
return uadk_prov_keymgmt;
case OSSL_OP_ASYM_CIPHER:
- (void)uadk_prov_asym_cipher_alg();
+ uadk_prov_asym_cipher_alg();
return uadk_prov_asym_cipher;
case OSSL_OP_KEYEXCH:
+ uadk_prov_keyexch_alg();
return uadk_prov_keyexch;
case OSSL_OP_STORE:
return prov->query_operation(provctx, operation_id, no_cache);
diff --git a/src/uadk_prov_pkey.c b/src/uadk_prov_pkey.c
index 170c30b..a861551 100644
--- a/src/uadk_prov_pkey.c
+++ b/src/uadk_prov_pkey.c
@@ -29,6 +29,9 @@
#define PROV_SUPPORT 1
#define SIGNATURE_TYPE 3
#define ASYM_CIPHER_TYPE 3
+#define SECURITY_CHECK_DISABLE 0
+#define UADK_PROV_MIN_BITS 112
+#define UADK_PROV_SECURITY_BITS 80
static int p_keymgmt_support_state[KEYMGMT_TYPE];
static int p_signature_support_state[SIGNATURE_TYPE];
@@ -833,3 +836,68 @@ int uadk_prov_ecc_bit_check(const EC_GROUP *group)
return UADK_P_FAIL;
}
+
+/* Currently, disable the security checks in the default provider and uadk provider */
+int uadk_prov_securitycheck_enabled(OSSL_LIB_CTX *ctx)
+{
+ return SECURITY_CHECK_DISABLE;
+}
+
+#ifdef OPENSSL_NO_FIPS_SECURITYCHECKS
+int uadk_prov_ecc_check_key(OSSL_LIB_CTX *ctx, const EC_KEY *ec, int protect)
+{
+ return UADK_P_SUCCESS;
+}
+#else
+int uadk_prov_ecc_check_key(OSSL_LIB_CTX *ctx, const EC_KEY *ec, int protect)
+{
+ const EC_GROUP *group = EC_KEY_get0_group(ec);
+ const char *curve_name;
+ int nid, strength;
+
+ if (!uadk_prov_securitycheck_enabled(ctx))
+ return UADK_P_SUCCESS;
+
+ if (!group) {
+ fprintf(stderr, "invalid: group is NULL!\n");
+ return UADK_P_FAIL;
+ }
+
+ nid = EC_GROUP_get_curve_name(group);
+ if (nid == NID_undef) {
+ fprintf(stderr, "invalid: explicit curves are not allowed in fips mode!\n");
+ return UADK_P_FAIL;
+ }
+
+ curve_name = EC_curve_nid2nist(nid);
+ if (!curve_name) {
+ fprintf(stderr, "invalid: Curve %s is not approved in FIPS mode!\n",
+ curve_name);
+ return UADK_P_FAIL;
+ }
+
+ /*
+ * For EC the security strength is the (order_bits / 2)
+ * e.g. P-224 is 112 bits.
+ */
+ strength = (unsigned int)EC_GROUP_order_bits(group) >> 1;
+ /* The min security strength allowed for legacy verification is 80 bits */
+ if (strength < UADK_PROV_SECURITY_BITS) {
+ fprintf(stderr, "invalid: Curve %s strength %d is not approved in FIPS mode!\n",
+ curve_name, strength);
+ return UADK_P_FAIL;
+ }
+
+ /*
+ * For signing or key agreement only allow curves with at least 112 bits of
+ * security strength
+ */
+ if (protect && strength < UADK_PROV_MIN_BITS) {
+ fprintf(stderr, "invalid: Curve %s strength %d cannot be used for signing\n",
+ curve_name, strength);
+ return UADK_P_FAIL;
+ }
+
+ return UADK_P_SUCCESS;
+}
+#endif /* OPENSSL_NO_FIPS_SECURITYCHECKS */
diff --git a/src/uadk_prov_pkey.h b/src/uadk_prov_pkey.h
index 1d4911c..fbec388 100644
--- a/src/uadk_prov_pkey.h
+++ b/src/uadk_prov_pkey.h
@@ -452,5 +452,11 @@ 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);
+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);
#endif
--
2.25.1