*** BLURB HERE ***
Chenghai Huang (1): uadk_provider: add aead alg for uadk_provider in openssl3.0
Weili Qian (4): uadk_provider: move functions to uadk_prov_pkey.c uadk_provider: add query_operation_name callback for keymgmt uadk_provider: support ec keymgmt hardware acceleration uadk_provider: support ecdh keyexch hardware acceleration
Zhiqi Song (1): uadk_provider: support x448 alg
src/Makefile.am | 4 +- src/uadk_prov.h | 12 +- src/uadk_prov_aead.c | 1030 ++++++++++++++++++++++++++++++++ src/uadk_prov_dh.c | 8 + src/uadk_prov_ec_kmgmt.c | 746 +++++++++++++++++++++++ src/uadk_prov_ecdh_exch.c | 884 +++++++++++++++++++++++++++ src/uadk_prov_ecx.c | 1192 +++++++++++++++++++++++++++++++++++++ src/uadk_prov_init.c | 24 +- src/uadk_prov_pkey.c | 183 +++++- src/uadk_prov_pkey.h | 26 +- src/uadk_prov_rsa.c | 8 + src/uadk_prov_sm2.c | 71 +-- 12 files changed, 4121 insertions(+), 67 deletions(-) create mode 100644 src/uadk_prov_aead.c create mode 100644 src/uadk_prov_ec_kmgmt.c create mode 100644 src/uadk_prov_ecdh_exch.c create mode 100644 src/uadk_prov_ecx.c
From: Chenghai Huang huangchenghai2@huawei.com
The following 3 AES algorithms are added: AES-128-GCM AES-192-GCM AES-256-GCM
Signed-off-by: Chenghai Huang huangchenghai2@huawei.com --- src/Makefile.am | 2 +- src/uadk_prov.h | 4 + src/uadk_prov_aead.c | 1030 ++++++++++++++++++++++++++++++++++++++++++ src/uadk_prov_init.c | 7 + 4 files changed, 1042 insertions(+), 1 deletion(-) create mode 100644 src/uadk_prov_aead.c
diff --git a/src/Makefile.am b/src/Makefile.am index 54c00e7..921305b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -65,7 +65,7 @@ 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_ffc.c uadk_prov_aead.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 8756fc6..ac82245 100644 --- a/src/uadk_prov.h +++ b/src/uadk_prov.h @@ -162,6 +162,9 @@ extern const OSSL_DISPATCH uadk_sm4_ecb_functions[FUNC_MAX_NUM]; extern const OSSL_DISPATCH uadk_sm4_ofb128_functions[FUNC_MAX_NUM]; extern const OSSL_DISPATCH uadk_sm4_cfb128_functions[FUNC_MAX_NUM]; extern const OSSL_DISPATCH uadk_sm4_ctr_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH uadk_aes_128_gcm_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH uadk_aes_192_gcm_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH uadk_aes_256_gcm_functions[FUNC_MAX_NUM]; extern const OSSL_DISPATCH uadk_des_ede3_cbc_functions[]; extern const OSSL_DISPATCH uadk_des_ede3_ecb_functions[];
@@ -178,6 +181,7 @@ extern const OSSL_DISPATCH uadk_sm2_asym_cipher_functions[FUNC_MAX_NUM];
void uadk_prov_destroy_digest(void); void uadk_prov_destroy_cipher(void); +void uadk_prov_destroy_aead(void); void uadk_prov_destroy_rsa(void); void uadk_prov_destroy_dh(void); void uadk_prov_sm2_uninit(void); diff --git a/src/uadk_prov_aead.c b/src/uadk_prov_aead.c new file mode 100644 index 0000000..1f86da3 --- /dev/null +++ b/src/uadk_prov_aead.c @@ -0,0 +1,1030 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + * Copyright 2023-2024 Huawei Technologies Co.,Ltd. All rights reserved. + * Copyright 2023-2024 Linaro ltd. + * + * 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 <stdio.h> +#include <stdbool.h> +#include <string.h> +#include <dlfcn.h> +#include <numa.h> +#include <openssl/core_names.h> +#include <openssl/proverr.h> +#include <uadk/wd_aead.h> +#include <uadk/wd_sched.h> +#include "uadk.h" +#include "uadk_async.h" +#include "uadk_prov.h" + +#define MAX_IV_LEN 16 +#define MAX_KEY_LEN 64 +#define MAX_AAD_LEN 0xFFFF +#define ALG_NAME_SIZE 128 +#define AES_GCM_TAG_LEN 16 +/* The max data length is 16M-512B */ +#define AEAD_BLOCK_SIZE 0xFFFE00 + +#define UADK_OSSL_FAIL 0 +#define UADK_AEAD_SUCCESS 1 +#define UADK_AEAD_FAIL (-1) + +#define UNINITIALISED_SIZET ((size_t)-1) +#define IV_STATE_UNINITIALISED 0 +#define IV_STATE_SET 1 +#define KEY_STATE_SET 1 + +/* Internal flags that can be queried */ +#define PROV_CIPHER_FLAG_AEAD 0x0001 +#define PROV_CIPHER_FLAG_CUSTOM_IV 0x0002 +#define AEAD_FLAGS (PROV_CIPHER_FLAG_AEAD | PROV_CIPHER_FLAG_CUSTOM_IV) + +#define UADK_AEAD_DEF_CTXS 2 +#define UADK_AEAD_OP_NUM 1 + +struct aead_prov { + int pid; +}; +static struct aead_prov aprov; +static pthread_mutex_t aead_mutex = PTHREAD_MUTEX_INITIALIZER; + +enum uadk_aead_mode { + UNINIT_MODE, + ASYNC_MODE, + SYNC_MODE +}; + +enum aead_tag_status { + INIT_TAG, + READ_TAG, /* The MAC has been read. */ + SET_TAG /* The MAC has been set to req. */ +}; + +struct aead_priv_ctx { + int nid; + char alg_name[ALG_NAME_SIZE]; + size_t keylen; + size_t ivlen; + size_t taglen; + + unsigned int enc : 1; + unsigned int key_set : 1; /* Whether key is copied to priv key buffers */ + unsigned int iv_set : 1; /* Whether iv is copied to priv iv buffers */ + enum aead_tag_status tag_set; /* Whether mac is copied to priv mac buffers */ + + unsigned char iv[MAX_IV_LEN]; + unsigned char key[MAX_KEY_LEN]; + unsigned char buf[AES_GCM_TAG_LEN]; /* mac buffers */ + unsigned char *data; /* store input and output when block mode */ + + struct wd_aead_sess_setup setup; + struct wd_aead_req req; + enum uadk_aead_mode mode; + handle_t sess; +}; + +struct aead_info { + int nid; + enum wd_cipher_alg alg; + enum wd_cipher_mode mode; +}; + +static struct aead_info aead_info_table[] = { + { NID_aes_128_gcm, WD_CIPHER_AES, WD_CIPHER_GCM }, + { NID_aes_192_gcm, WD_CIPHER_AES, WD_CIPHER_GCM }, + { NID_aes_256_gcm, WD_CIPHER_AES, WD_CIPHER_GCM } +}; + +static int uadk_aead_poll(void *ctx) +{ + __u64 rx_cnt = 0; + __u32 recv = 0; + /* Poll one packet currently */ + int expt = 1; + int ret; + + do { + ret = wd_aead_poll(expt, &recv); + if (ret < 0 || recv >= expt) + return ret; + rx_cnt++; + } while (rx_cnt < ENGINE_RECV_MAX_CNT); + + fprintf(stderr, "failed to poll msg: timeout!\n"); + + return -ETIMEDOUT; +} + +static void uadk_aead_mutex_infork(void) +{ + /* Release the replication lock of the child process */ + pthread_mutex_unlock(&aead_mutex); +} + +static int uadk_prov_aead_dev_init(struct aead_priv_ctx *priv) +{ + struct wd_ctx_nums ctx_set_num; + struct wd_ctx_params cparams = {0}; + int ret = UADK_AEAD_SUCCESS; + + pthread_atfork(NULL, NULL, uadk_aead_mutex_infork); + pthread_mutex_lock(&aead_mutex); + if (aprov.pid == getpid()) + goto mutex_unlock; + + cparams.op_type_num = UADK_AEAD_OP_NUM; + cparams.ctx_set_num = &ctx_set_num; + cparams.bmp = numa_allocate_nodemask(); + if (!cparams.bmp) { + ret = UADK_AEAD_FAIL; + fprintf(stderr, "failed to create nodemask!\n"); + goto mutex_unlock; + } + + numa_bitmask_setall(cparams.bmp); + + ctx_set_num.sync_ctx_num = UADK_AEAD_DEF_CTXS; + ctx_set_num.async_ctx_num = UADK_AEAD_DEF_CTXS; + + ret = wd_aead_init2_(priv->alg_name, TASK_MIX, SCHED_POLICY_RR, &cparams); + if (unlikely(ret)) { + ret = UADK_AEAD_FAIL; + fprintf(stderr, "failed to init aead!\n"); + goto free_nodemask; + } + + aprov.pid = getpid(); + async_register_poll_fn(ASYNC_TASK_AEAD, uadk_aead_poll); + +free_nodemask: + numa_free_nodemask(cparams.bmp); +mutex_unlock: + pthread_mutex_unlock(&aead_mutex); + return ret; +} + +static int uadk_prov_aead_ctx_init(struct aead_priv_ctx *priv) +{ + struct wd_aead_sess_setup setup = {0}; + struct sched_params params = {0}; + int ret; + + if (!priv->key_set || !priv->iv_set) { + fprintf(stderr, "key or iv is not set yet!\n"); + return UADK_AEAD_FAIL; + } + + priv->req.iv_bytes = priv->ivlen; + priv->req.iv = priv->iv; + priv->req.out_bytes = 0; + priv->req.mac = priv->buf; + priv->req.mac_bytes = priv->taglen; + + ret = uadk_prov_aead_dev_init(priv); + if (unlikely(ret < 0)) + return UADK_AEAD_FAIL; + + /* dec and enc use the same op */ + params.type = 0; + /* Use the default numa parameters */ + params.numa_id = -1; + memcpy(setup, priv->setup, sizeof(struct wd_aead_sess_setup)); + setup.sched_param = ¶ms; + + if (!priv->sess) { + priv->sess = wd_aead_alloc_sess(&setup); + if (!priv->sess) { + fprintf(stderr, "uadk failed to alloc session!\n"); + return UADK_AEAD_FAIL; + } + + ret = wd_aead_set_authsize(priv->sess, priv->taglen); + if (ret) { + fprintf(stderr, "uadk failed to set authsize!\n"); + goto free_sess; + } + + ret = wd_aead_set_ckey(priv->sess, priv->key, priv->keylen); + if (ret) { + fprintf(stderr, "uadk failed to set key!\n"); + goto free_sess; + } + } + + return UADK_AEAD_SUCCESS; + +free_sess: + wd_aead_free_sess(priv->sess); + priv->sess = 0; + return UADK_AEAD_FAIL; +} + +static void *uadk_prov_aead_cb(struct wd_aead_req *req, void *data) +{ + struct uadk_e_cb_info *cb_param; + struct wd_aead_req *req_origin; + struct async_op *op; + + if (!req) + return NULL; + + cb_param = req->cb_param; + if (!cb_param) + return NULL; + + req_origin = cb_param->priv; + req_origin->state = req->state; + + op = cb_param->op; + if (op && op->job && !op->done) { + op->done = 1; + async_free_poll_task(op->idx, 1); + async_wake_job(op->job); + } + + return NULL; +} + +static int do_aes_gcm_prepare(struct aead_priv_ctx *priv) +{ + if (priv->mode == UNINIT_MODE) { + if (ASYNC_get_current_job()) + priv->mode = ASYNC_MODE; + else + priv->mode = SYNC_MODE; + } + + if (!priv->enc && priv->tag_set == READ_TAG) { + if (likely(priv->taglen == AES_GCM_TAG_LEN)) { + memcpy(priv->req.mac, priv->buf, AES_GCM_TAG_LEN); + priv->tag_set = SET_TAG; + } else { + fprintf(stderr, "invalid: aead gcm mac length only support 16B.\n"); + return UADK_AEAD_FAIL; + } + } + + return UADK_AEAD_SUCCESS; +} + +static void uadk_do_aead_async_prepare(struct aead_priv_ctx *priv, unsigned char *out, + const unsigned char *in, size_t inlen) +{ + priv->req.in_bytes = inlen; + /* AAD data is input or output together with plaintext or ciphertext. */ + if (priv->req.assoc_bytes) { + memcpy(priv->data + priv->req.assoc_bytes, in, inlen); + priv->req.src = priv->data; + priv->req.dst = priv->data + AEAD_BLOCK_SIZE; + } else { + priv->req.src = (unsigned char *)in; + priv->req.dst = out; + } +} + +static int uadk_do_aead_sync_inner(struct aead_priv_ctx *priv, unsigned char *out, + const unsigned char *in, size_t inlen, enum wd_aead_msg_state state) +{ + int ret; + + if ((state == AEAD_MSG_BLOCK || state == AEAD_MSG_END) + && !priv->enc && priv->tag_set != SET_TAG) { + fprintf(stderr, "The tag for synchronous decryption is not set.\n"); + return UADK_AEAD_FAIL; + } + + priv->req.msg_state = state; + priv->req.src = (unsigned char *)in; + priv->req.dst = out; + priv->req.in_bytes = inlen; + priv->req.state = 0; + ret = wd_do_aead_sync(priv->sess, &priv->req); + if (unlikely(ret < 0 || priv->req.state)) { + fprintf(stderr, "do aead task failed, msg state: %u, ret: %d, state: %u!\n", + state, ret, priv->req.state); + return UADK_AEAD_FAIL; + } + + return inlen; +} + +static int uadk_do_aead_sync(struct aead_priv_ctx *priv, unsigned char *out, + const unsigned char *in, size_t inlen) +{ + size_t nbytes, tail, processing_len, max_mid_len; + const unsigned char *in_block = in; + unsigned char *out_block = out; + int ret; + + /* Due to a hardware limitation, zero-length aad using block mode. */ + if (!priv->req.assoc_bytes) + return uadk_do_aead_sync_inner(priv, out, in, inlen, AEAD_MSG_BLOCK); + + tail = inlen % AES_BLOCK_SIZE; + nbytes = inlen - tail; + max_mid_len = AEAD_BLOCK_SIZE - priv->req.assoc_bytes; + + /* If the data length is not 16-byte aligned, it is split according to the protocol. */ + while (nbytes > 0) { + processing_len = nbytes > max_mid_len ? max_mid_len : nbytes; + processing_len -= (processing_len % AES_BLOCK_SIZE); + + ret = uadk_do_aead_sync_inner(priv, out_block, in_block, + processing_len, AEAD_MSG_MIDDLE); + if (ret < 0) + return UADK_AEAD_FAIL; + nbytes -= processing_len; + in_block = in_block + processing_len; + out_block = out_block + processing_len; + } + + if (tail) { + ret = uadk_do_aead_sync_inner(priv, out_block, in_block, tail, AEAD_MSG_END); + if (ret < 0) + return UADK_AEAD_FAIL; + } + + return inlen; +} + +static int uadk_do_aead_async(struct aead_priv_ctx *priv, struct async_op *op, + unsigned char *out, const unsigned char *in, size_t inlen) +{ + struct uadk_e_cb_info *cb_param; + int cnt = 0; + int ret; + + if (!priv->enc && priv->tag_set != SET_TAG) { + fprintf(stderr, "The tag for asynchronous decryption is not set.\n"); + return UADK_AEAD_FAIL; + } + + if (unlikely(priv->req.assoc_bytes + inlen > AEAD_BLOCK_SIZE)) { + fprintf(stderr, "aead input data length is too long!\n"); + return UADK_AEAD_FAIL; + } + + uadk_do_aead_async_prepare(priv, out, in, inlen); + + cb_param = malloc(sizeof(struct uadk_e_cb_info)); + if (unlikely(!cb_param)) { + fprintf(stderr, "failed to alloc cb_param.\n"); + return UADK_AEAD_FAIL; + } + + cb_param->op = op; + cb_param->priv = &priv->req; + priv->req.cb = uadk_prov_aead_cb; + priv->req.cb_param = cb_param; + priv->req.msg_state = AEAD_MSG_BLOCK; + priv->req.state = UADK_AEAD_FAIL; + + ret = async_get_free_task(&op->idx); + if (unlikely(!ret)) + goto free_cb_param; + + do { + ret = wd_do_aead_async(priv->sess, &priv->req); + if (unlikely(ret < 0)) { + if (unlikely(ret != -EBUSY)) + fprintf(stderr, "do aead async operation failed ret = %d.\n", ret); + else if (unlikely(cnt++ > ENGINE_SEND_MAX_CNT)) + fprintf(stderr, "do aead async operation timeout.\n"); + else + continue; + + async_free_poll_task(op->idx, 0); + ret = UADK_AEAD_FAIL; + goto free_cb_param; + } + } while (ret == -EBUSY); + + ret = async_pause_job(priv, op, ASYNC_TASK_AEAD); + if (unlikely(!ret || priv->req.state)) { + fprintf(stderr, "do aead async job failed, ret: %d, state: %u!\n", + ret, priv->req.state); + ret = UADK_AEAD_FAIL; + goto free_cb_param; + } + + if (priv->req.assoc_bytes) + memcpy(out, priv->req.dst + priv->req.assoc_bytes, inlen); + +free_cb_param: + free(cb_param); + return ret; +} + +static int uadk_prov_do_aes_gcm_first(struct aead_priv_ctx *priv, unsigned char *out, + const unsigned char *in, size_t inlen) +{ + int ret; + + if (inlen > MAX_AAD_LEN) { + fprintf(stderr, "the aad len is out of range, aad len = %lu.\n", inlen); + return UADK_AEAD_FAIL; + } + + priv->req.assoc_bytes = inlen; + + /* Asynchronous jobs use the block mode. */ + if (priv->mode == ASYNC_MODE || !priv->req.assoc_bytes) { + memcpy(priv->data, in, inlen); + return UADK_AEAD_SUCCESS; + } + + ret = uadk_do_aead_sync_inner(priv, out, in, inlen, AEAD_MSG_FIRST); + if (unlikely(ret < 0)) + return UADK_AEAD_FAIL; + + return UADK_AEAD_SUCCESS; +} + +static int uadk_prov_do_aes_gcm_update(struct aead_priv_ctx *priv, unsigned char *out, + const unsigned char *in, size_t inlen) +{ + struct async_op *op; + int ret; + + if (priv->mode == ASYNC_MODE) { + op = malloc(sizeof(struct async_op)); + if (unlikely(!op)) + return UADK_AEAD_FAIL; + + ret = async_setup_async_event_notification(op); + if (unlikely(!ret)) { + fprintf(stderr, "failed to setup async event notification.\n"); + goto free_op; + } + + ret = uadk_do_aead_async(priv, op, out, in, inlen); + if (unlikely(ret < 0)) { + fprintf(stderr, "uadk_do_aead_async failed ret = %d.\n", ret); + goto free_notification; + } + + free(op); + return inlen; + } + + return uadk_do_aead_sync(priv, out, in, inlen); + +free_notification: + (void)async_clear_async_event_notification(); +free_op: + free(op); + return UADK_AEAD_FAIL; +} + +static int uadk_prov_do_aes_gcm_final(struct aead_priv_ctx *priv, unsigned char *out, + const unsigned char *in, size_t inlen) +{ + int ret; + + if (priv->mode == ASYNC_MODE || !priv->req.assoc_bytes || + priv->req.msg_state == AEAD_MSG_END) + goto out; + + ret = uadk_do_aead_sync_inner(priv, out, in, inlen, AEAD_MSG_END); + if (unlikely(ret < 0)) + return UADK_AEAD_FAIL; + +out: + if (priv->enc) + memcpy(priv->buf, priv->req.mac, priv->taglen); + else + priv->tag_set = INIT_TAG; + + priv->mode = UNINIT_MODE; + return UADK_AEAD_SUCCESS; +} + +static int uadk_prov_do_aes_gcm(struct aead_priv_ctx *priv, unsigned char *out, + size_t *outl, size_t outsize, + const unsigned char *in, size_t inlen) +{ + int ret; + + ret = uadk_prov_aead_ctx_init(priv); + if (ret != UADK_AEAD_SUCCESS) + return UADK_AEAD_FAIL; + + ret = do_aes_gcm_prepare(priv); + if (unlikely(ret < 0)) + return UADK_AEAD_FAIL; + + if (in) { + if (!out) + return uadk_prov_do_aes_gcm_first(priv, out, in, inlen); + + return uadk_prov_do_aes_gcm_update(priv, out, in, inlen); + } + + return uadk_prov_do_aes_gcm_final(priv, out, NULL, 0); +} + +void uadk_prov_destroy_aead(void) +{ + pthread_mutex_lock(&aead_mutex); + if (aprov.pid == getpid()) { + wd_aead_uninit2(); + aprov.pid = 0; + } + pthread_mutex_unlock(&aead_mutex); +} + +static OSSL_FUNC_cipher_encrypt_init_fn uadk_prov_aead_einit; +static OSSL_FUNC_cipher_decrypt_init_fn uadk_prov_aead_dinit; +static OSSL_FUNC_cipher_freectx_fn uadk_prov_aead_freectx; +static OSSL_FUNC_cipher_dupctx_fn uadk_prov_aead_dupctx; +static OSSL_FUNC_cipher_get_ctx_params_fn uadk_prov_aead_get_ctx_params; +static OSSL_FUNC_cipher_gettable_ctx_params_fn uadk_prov_aead_gettable_ctx_params; +static OSSL_FUNC_cipher_set_ctx_params_fn uadk_prov_aead_set_ctx_params; +static OSSL_FUNC_cipher_settable_ctx_params_fn uadk_prov_aead_settable_ctx_params; + +static int uadk_prov_aead_cipher(void *vctx, unsigned char *out, size_t *outl, + size_t outsize, const unsigned char *in, + size_t inl) +{ + struct aead_priv_ctx *priv = (struct aead_priv_ctx *)vctx; + int ret; + + if (!vctx || !out || !outl) + return UADK_OSSL_FAIL; + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return UADK_OSSL_FAIL; + } + + ret = uadk_prov_do_aes_gcm(priv, out, outl, outsize, in, inl); + if (ret < 0) + return UADK_OSSL_FAIL; + + *outl = inl; + return UADK_AEAD_SUCCESS; +} + +static int uadk_prov_aead_stream_update(void *vctx, unsigned char *out, + size_t *outl, size_t outsize, + const unsigned char *in, size_t inl) +{ + struct aead_priv_ctx *priv = (struct aead_priv_ctx *)vctx; + int ret; + + if (!vctx) + return UADK_OSSL_FAIL; + + if (outsize < inl) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return UADK_OSSL_FAIL; + } + + ret = uadk_prov_do_aes_gcm(priv, out, outl, outsize, in, inl); + if (ret < 0) { + fprintf(stderr, "stream data update failed.\n"); + return UADK_OSSL_FAIL; + } + + *outl = inl; + return UADK_AEAD_SUCCESS; +} + +static int uadk_prov_aead_stream_final(void *vctx, unsigned char *out, + size_t *outl, size_t outsize) +{ + struct aead_priv_ctx *priv = (struct aead_priv_ctx *)vctx; + int ret; + + if (!vctx || !out || !outl) + return UADK_OSSL_FAIL; + + ret = uadk_prov_do_aes_gcm(priv, out, outl, outsize, NULL, 0); + if (ret < 0) { + fprintf(stderr, "stream data final failed, ret = %d\n", ret); + return UADK_OSSL_FAIL; + } + + *outl = 0; + return UADK_AEAD_SUCCESS; +} + +static int uadk_get_aead_info(struct aead_priv_ctx *priv) +{ + int aead_counts = ARRAY_SIZE(aead_info_table); + int i; + + for (i = 0; i < aead_counts; i++) { + if (priv->nid == aead_info_table[i].nid) { + priv->setup.calg = aead_info_table[i].alg; + priv->setup.cmode = aead_info_table[i].mode; + break; + } + } + + if (unlikely(i == aead_counts)) { + fprintf(stderr, "failed to setup the private ctx.\n"); + return UADK_AEAD_FAIL; + } + + return UADK_AEAD_SUCCESS; +} + +static int uadk_prov_aead_init(struct aead_priv_ctx *priv, + const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen) +{ + int ret; + + if (ivlen > MAX_IV_LEN || keylen > MAX_KEY_LEN) { + fprintf(stderr, "invalid keylen or ivlen.\n"); + return UADK_OSSL_FAIL; + } + + if (iv) { + memcpy(priv->iv, iv, ivlen); + priv->iv_set = IV_STATE_SET; + } + + ret = uadk_get_aead_info(priv); + if (unlikely(ret < 0)) + return UADK_OSSL_FAIL; + + if (key) { + memcpy(priv->key, key, keylen); + priv->key_set = KEY_STATE_SET; + } + + ret = uadk_prov_aead_dev_init(priv); + if (unlikely(ret < 0)) + return UADK_OSSL_FAIL; + + return UADK_AEAD_SUCCESS; +} + +static int uadk_prov_aead_einit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + struct aead_priv_ctx *priv = (struct aead_priv_ctx *)vctx; + + if (!vctx) + return UADK_OSSL_FAIL; + + priv->req.op_type = WD_CIPHER_ENCRYPTION_DIGEST; + priv->enc = 1; + + return uadk_prov_aead_init(priv, key, keylen, iv, ivlen); +} + +static int uadk_prov_aead_dinit(void *vctx, const unsigned char *key, size_t keylen, + const unsigned char *iv, size_t ivlen, + const OSSL_PARAM params[]) +{ + struct aead_priv_ctx *priv = (struct aead_priv_ctx *)vctx; + + if (!vctx) + return UADK_OSSL_FAIL; + + priv->req.op_type = WD_CIPHER_DECRYPTION_DIGEST; + priv->enc = 0; + + return uadk_prov_aead_init(priv, key, keylen, iv, ivlen); +} + +static const OSSL_PARAM uadk_prov_settable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN, NULL), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0), + OSSL_PARAM_END +}; + +const OSSL_PARAM *uadk_prov_aead_settable_ctx_params(ossl_unused void *cctx, + ossl_unused void *provctx) +{ + return uadk_prov_settable_ctx_params; +} + +static int uadk_prov_aead_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + struct aead_priv_ctx *priv = (struct aead_priv_ctx *)vctx; + const OSSL_PARAM *p; + size_t sz = 0; + void *vp; + + if (!vctx) + return UADK_OSSL_FAIL; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_TAG); + if (p) { + vp = priv->buf; + if (!OSSL_PARAM_get_octet_string(p, &vp, EVP_GCM_TLS_TAG_LEN, &sz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return UADK_OSSL_FAIL; + } + + if (sz == 0 || priv->enc) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAG); + return UADK_OSSL_FAIL; + } + priv->tag_set = READ_TAG; + priv->taglen = sz; + } + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p) { + size_t keylen; + + if (!OSSL_PARAM_get_size_t(p, &keylen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return UADK_OSSL_FAIL; + } + if (priv->keylen != keylen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return UADK_OSSL_FAIL; + } + } + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_AEAD_IVLEN); + if (p) { + if (!OSSL_PARAM_get_size_t(p, &sz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); + return UADK_OSSL_FAIL; + } + if (sz == 0 || sz > priv->ivlen) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return UADK_OSSL_FAIL; + } + priv->ivlen = sz; + } + + return UADK_AEAD_SUCCESS; +} + +static const OSSL_PARAM uadk_prov_aead_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_AEAD_TAGLEN, NULL), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_IV, NULL, 0), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_UPDATED_IV, NULL, 0), + OSSL_PARAM_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *uadk_prov_aead_gettable_ctx_params(ossl_unused void *cctx, + ossl_unused void *provctx) +{ + return uadk_prov_aead_ctx_params; +} + +static int uadk_prov_aead_get_ctx_params(void *vctx, OSSL_PARAM params[]) +{ + struct aead_priv_ctx *priv = (struct aead_priv_ctx *)vctx; + OSSL_PARAM *p; + + if (!vctx || !params) + return UADK_OSSL_FAIL; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN); + if (p && !OSSL_PARAM_set_size_t(p, priv->ivlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return UADK_OSSL_FAIL; + } + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p && !OSSL_PARAM_set_size_t(p, priv->keylen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return UADK_OSSL_FAIL; + } + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAGLEN); + if (p) { + size_t taglen = (priv->taglen != UNINITIALISED_SIZET) ? + priv->taglen : AES_GCM_TAG_LEN; + + if (!OSSL_PARAM_set_size_t(p, taglen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return UADK_OSSL_FAIL; + } + } + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IV); + if (p) { + if (priv->iv_set == IV_STATE_UNINITIALISED) + return UADK_OSSL_FAIL; + if (priv->ivlen > p->data_size) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return UADK_OSSL_FAIL; + } + if (!OSSL_PARAM_set_octet_string(p, priv->iv, priv->ivlen) + && !OSSL_PARAM_set_octet_ptr(p, &priv->iv, priv->ivlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return UADK_OSSL_FAIL; + } + } + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_UPDATED_IV); + if (p) { + if (priv->iv_set == IV_STATE_UNINITIALISED) + return UADK_OSSL_FAIL; + if (priv->ivlen > p->data_size) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return UADK_OSSL_FAIL; + } + if (!OSSL_PARAM_set_octet_string(p, priv->iv, priv->ivlen) + && !OSSL_PARAM_set_octet_ptr(p, &priv->iv, priv->ivlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return UADK_OSSL_FAIL; + } + } + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAG); + if (p) { + size_t sz = p->data_size; + + if (sz == 0 || sz > EVP_GCM_TLS_TAG_LEN || !priv->enc + || priv->taglen == UNINITIALISED_SIZET) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_TAG); + return UADK_OSSL_FAIL; + } + + if (!OSSL_PARAM_set_octet_string(p, priv->buf, sz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return UADK_OSSL_FAIL; + } + } + return UADK_AEAD_SUCCESS; +} + +static const OSSL_PARAM aead_known_gettable_params[] = { + OSSL_PARAM_uint(OSSL_CIPHER_PARAM_MODE, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_KEYLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_IVLEN, NULL), + OSSL_PARAM_size_t(OSSL_CIPHER_PARAM_BLOCK_SIZE, NULL), + OSSL_PARAM_int(OSSL_CIPHER_PARAM_AEAD, NULL), + OSSL_PARAM_int(OSSL_CIPHER_PARAM_CUSTOM_IV, NULL), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *uadk_prov_aead_gettable_params(ossl_unused void *provctx) +{ + return aead_known_gettable_params; +} + +static int uadk_cipher_aead_get_params(OSSL_PARAM params[], unsigned int md, + uint64_t flags, size_t kbits, + size_t blkbits, size_t ivbits) +{ + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_MODE); + if (p && !OSSL_PARAM_set_uint(p, md)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return UADK_OSSL_FAIL; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD); + if (p && !OSSL_PARAM_set_int(p, (flags & PROV_CIPHER_FLAG_AEAD) != 0)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return UADK_OSSL_FAIL; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_CUSTOM_IV); + if (p && !OSSL_PARAM_set_int(p, (flags & PROV_CIPHER_FLAG_CUSTOM_IV) != 0)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return UADK_OSSL_FAIL; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p && !OSSL_PARAM_set_size_t(p, kbits)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return UADK_OSSL_FAIL; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_BLOCK_SIZE); + if (p && !OSSL_PARAM_set_size_t(p, blkbits)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return UADK_OSSL_FAIL; + } + p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IVLEN); + if (p && !OSSL_PARAM_set_size_t(p, ivbits)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return UADK_OSSL_FAIL; + } + + return UADK_AEAD_SUCCESS; +} + +static void *uadk_prov_aead_dupctx(void *ctx) +{ + struct aead_priv_ctx *priv, *ret; + + priv = (struct aead_priv_ctx *)ctx; + if (!priv) + return NULL; + + ret = OPENSSL_memdup(priv, sizeof(*priv)); + if (!ret) + return NULL; + + ret->sess = 0; + ret->data = OPENSSL_memdup(priv->data, AEAD_BLOCK_SIZE << 1); + if (!ret->data) { + OPENSSL_clear_free(ret, sizeof(*ret)); + return NULL; + } + + return ret; +} + +static void uadk_prov_aead_freectx(void *ctx) +{ + struct aead_priv_ctx *priv = (struct aead_priv_ctx *)ctx; + + if (!ctx) + return; + + if (priv->sess) { + wd_aead_free_sess(priv->sess); + priv->sess = 0; + } + + if (priv->data) { + OPENSSL_clear_free(priv->data, AEAD_BLOCK_SIZE << 1); + priv->data = NULL; + } + OPENSSL_clear_free(priv, sizeof(*priv)); +} + +#define UADK_AEAD_DESCR(nm, tag_len, key_len, iv_len, blk_size, \ + flags, e_nid, algnm, mode) \ +static OSSL_FUNC_cipher_newctx_fn uadk_##nm##_newctx; \ +static void *uadk_##nm##_newctx(void *provctx) \ +{ \ + struct aead_priv_ctx *ctx = OPENSSL_zalloc(sizeof(*ctx)); \ + if (!ctx) \ + return NULL; \ + \ + ctx->data = OPENSSL_zalloc(AEAD_BLOCK_SIZE << 1); \ + if (!ctx->data) { \ + OPENSSL_clear_free(ctx, sizeof(*ctx)); \ + return NULL; \ + } \ + \ + ctx->keylen = key_len; \ + ctx->ivlen = iv_len; \ + ctx->nid = e_nid; \ + ctx->taglen = tag_len; \ + strncpy(ctx->alg_name, #algnm, ALG_NAME_SIZE - 1); \ + \ + return ctx; \ +} \ +static OSSL_FUNC_cipher_get_params_fn uadk_##nm##_get_params; \ +static int uadk_##nm##_get_params(OSSL_PARAM params[]) \ +{ \ + return uadk_cipher_aead_get_params(params, mode, flags, \ + key_len, blk_size, iv_len); \ +} \ +const OSSL_DISPATCH uadk_##nm##_functions[] = { \ + { OSSL_FUNC_CIPHER_NEWCTX, (void (*)(void))uadk_##nm##_newctx }, \ + { OSSL_FUNC_CIPHER_FREECTX, (void (*)(void))uadk_prov_aead_freectx }, \ + { OSSL_FUNC_CIPHER_DUPCTX, (void (*)(void))uadk_prov_aead_dupctx }, \ + { OSSL_FUNC_CIPHER_ENCRYPT_INIT, \ + (void (*)(void))uadk_prov_aead_einit }, \ + { OSSL_FUNC_CIPHER_DECRYPT_INIT, \ + (void (*)(void))uadk_prov_aead_dinit }, \ + { OSSL_FUNC_CIPHER_UPDATE, \ + (void (*)(void))uadk_prov_aead_stream_update }, \ + { OSSL_FUNC_CIPHER_FINAL, \ + (void (*)(void))uadk_prov_aead_stream_final }, \ + { OSSL_FUNC_CIPHER_CIPHER, (void (*)(void))uadk_prov_aead_cipher }, \ + { OSSL_FUNC_CIPHER_GET_PARAMS, \ + (void (*)(void))uadk_##nm##_get_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_PARAMS, \ + (void (*)(void))uadk_prov_aead_gettable_params }, \ + { OSSL_FUNC_CIPHER_GET_CTX_PARAMS, \ + (void (*)(void))uadk_prov_aead_get_ctx_params }, \ + { OSSL_FUNC_CIPHER_GETTABLE_CTX_PARAMS, \ + (void (*)(void))uadk_prov_aead_gettable_ctx_params }, \ + { OSSL_FUNC_CIPHER_SET_CTX_PARAMS, \ + (void (*)(void))uadk_prov_aead_set_ctx_params }, \ + { OSSL_FUNC_CIPHER_SETTABLE_CTX_PARAMS, \ + (void (*)(void))uadk_prov_aead_settable_ctx_params }, \ + { 0, NULL } \ +} + +UADK_AEAD_DESCR(aes_128_gcm, AES_GCM_TAG_LEN, 16, 12, 8, AEAD_FLAGS, NID_aes_128_gcm, gcm(aes), + EVP_CIPH_GCM_MODE); +UADK_AEAD_DESCR(aes_192_gcm, AES_GCM_TAG_LEN, 24, 12, 8, AEAD_FLAGS, NID_aes_192_gcm, gcm(aes), + EVP_CIPH_GCM_MODE); +UADK_AEAD_DESCR(aes_256_gcm, AES_GCM_TAG_LEN, 32, 12, 8, AEAD_FLAGS, NID_aes_256_gcm, gcm(aes), + EVP_CIPH_GCM_MODE); diff --git a/src/uadk_prov_init.c b/src/uadk_prov_init.c index 972f953..772ddbb 100644 --- a/src/uadk_prov_init.c +++ b/src/uadk_prov_init.c @@ -137,6 +137,12 @@ const OSSL_ALGORITHM uadk_prov_ciphers_v3[] = { uadk_aes_192_cfb128_functions, "uadk_provider aes-192-cfb" }, { "AES-256-CFB", UADK_DEFAULT_PROPERTIES, uadk_aes_256_cfb128_functions, "uadk_provider aes-256-cfb" }, + { "AES-128-GCM", UADK_DEFAULT_PROPERTIES, + uadk_aes_128_gcm_functions, "uadk_provider aes-128-gcm" }, + { "AES-192-GCM", UADK_DEFAULT_PROPERTIES, + uadk_aes_192_gcm_functions, "uadk_provider aes-192-gcm" }, + { "AES-256-GCM", UADK_DEFAULT_PROPERTIES, + uadk_aes_256_gcm_functions, "uadk_provider aes-256-gcm" }, { "SM4-CBC", UADK_DEFAULT_PROPERTIES, uadk_sm4_cbc_functions, "uadk_provider sm4-cbc" }, { "SM4-ECB", UADK_DEFAULT_PROPERTIES, @@ -232,6 +238,7 @@ static void uadk_teardown(void *provctx)
uadk_prov_destroy_digest(); uadk_prov_destroy_cipher(); + uadk_prov_destroy_aead(); uadk_prov_destroy_rsa(); uadk_prov_sm2_uninit(); uadk_prov_dh_uninit();
From: Weili Qian qianweili@huawei.com
The ecc algorithm initialization and resource release processes are the same. Therefore, the functions uadk_prov_sm2_init() and uadk_prov_sm2_uninit() functions are moved from uadk_prov_sm2.c to uadk_prov_pkey.c and change the functions name.
Signed-off-by: Weili Qian qianweili@huawei.com --- src/uadk_prov.h | 2 +- src/uadk_prov_init.c | 2 +- src/uadk_prov_pkey.c | 44 ++++++++++++++++++++++++++++++++ src/uadk_prov_pkey.h | 2 +- src/uadk_prov_sm2.c | 61 ++++++-------------------------------------- 5 files changed, 55 insertions(+), 56 deletions(-)
diff --git a/src/uadk_prov.h b/src/uadk_prov.h index ac82245..e85aff8 100644 --- a/src/uadk_prov.h +++ b/src/uadk_prov.h @@ -184,7 +184,7 @@ void uadk_prov_destroy_cipher(void); void uadk_prov_destroy_aead(void); void uadk_prov_destroy_rsa(void); void uadk_prov_destroy_dh(void); -void uadk_prov_sm2_uninit(void); +void uadk_prov_ecc_uninit(void); void uadk_prov_dh_uninit(void); int uadk_prov_cipher_version(void);
diff --git a/src/uadk_prov_init.c b/src/uadk_prov_init.c index 772ddbb..55202ae 100644 --- a/src/uadk_prov_init.c +++ b/src/uadk_prov_init.c @@ -240,7 +240,7 @@ static void uadk_teardown(void *provctx) uadk_prov_destroy_cipher(); uadk_prov_destroy_aead(); uadk_prov_destroy_rsa(); - uadk_prov_sm2_uninit(); + uadk_prov_ecc_uninit(); uadk_prov_dh_uninit(); OPENSSL_free(ctx); OSSL_PROVIDER_unload(prov); diff --git a/src/uadk_prov_pkey.c b/src/uadk_prov_pkey.c index d1f7afe..6e0612e 100644 --- a/src/uadk_prov_pkey.c +++ b/src/uadk_prov_pkey.c @@ -34,6 +34,13 @@ 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];
+struct ecc_prov { + int pid; +}; + +static struct ecc_prov g_ecc_prov; +static pthread_mutex_t ecc_mutex = PTHREAD_MUTEX_INITIALIZER; + /* Mapping between a flag and a name */ static const OSSL_ITEM encoding_nameid_map[] = { { OPENSSL_EC_EXPLICIT_CURVE, OSSL_PKEY_EC_ENCODING_EXPLICIT }, @@ -767,3 +774,40 @@ void uadk_prov_asym_cipher_alg(void) uadk_prov_asym_cipher_set_support_state(i, PROV_SUPPORT); } } + +static void uadk_prov_ecc_mutex_infork(void) +{ + /* Release the replication lock of the child process */ + pthread_mutex_unlock(&ecc_mutex); +} + +int uadk_prov_ecc_init(const char *alg_name) +{ + int ret; + + pthread_atfork(NULL, NULL, uadk_prov_ecc_mutex_infork); + pthread_mutex_lock(&ecc_mutex); + if (g_ecc_prov.pid != getpid()) { + ret = wd_ecc_init2((char *)alg_name, SCHED_POLICY_RR, TASK_HW); + if (unlikely(ret)) { + pthread_mutex_unlock(&ecc_mutex); + return UADK_P_FAIL; + } + g_ecc_prov.pid = getpid(); + async_register_poll_fn(ASYNC_TASK_ECC, uadk_prov_ecc_poll); + } + pthread_mutex_unlock(&ecc_mutex); + + return UADK_P_SUCCESS; +} + +/* Uninit only when the process exits, will not uninit when thread exits. */ +void uadk_prov_ecc_uninit(void) +{ + pthread_mutex_lock(&ecc_mutex); + if (g_ecc_prov.pid == getpid()) { + wd_ecc_uninit2(); + g_ecc_prov.pid = 0; + } + pthread_mutex_unlock(&ecc_mutex); +} diff --git a/src/uadk_prov_pkey.h b/src/uadk_prov_pkey.h index 0e27fcb..3eb9667 100644 --- a/src/uadk_prov_pkey.h +++ b/src/uadk_prov_pkey.h @@ -41,7 +41,6 @@ #define UADK_ECC_MAX_KEY_BITS 521 #define UADK_ECC_MAX_KEY_BYTES 66 #define UADK_ECC_CV_PARAM_NUM 6 -#define UADK_P_INTI_SUCCESS 0 #define UADK_P_SUCCESS 1 #define UADK_P_FAIL 0 #define UADK_P_INVALID (-1) @@ -440,5 +439,6 @@ int uadk_prov_ecc_set_public_key(handle_t sess, const EC_KEY *eckey); 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);
#endif diff --git a/src/uadk_prov_sm2.c b/src/uadk_prov_sm2.c index b6d5d01..e27cccb 100644 --- a/src/uadk_prov_sm2.c +++ b/src/uadk_prov_sm2.c @@ -36,8 +36,6 @@ UADK_PKEY_KEYMGMT_DESCR(sm2, SM2); UADK_PKEY_SIGNATURE_DESCR(sm2, SM2); UADK_PKEY_ASYM_CIPHER_DESCR(sm2, SM2);
-static pthread_mutex_t sm2_mutex = PTHREAD_MUTEX_INITIALIZER; - static const OSSL_PARAM sm2_asym_cipher_known_settable_ctx_params[] = { OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_DIGEST, NULL, 0), OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_PROPERTIES, NULL, 0), @@ -64,12 +62,6 @@ static const OSSL_PARAM sm2_sig_known_gettable_ctx_params[] = { OSSL_PARAM_END };
-struct sm2_prov { - int pid; -}; - -static struct sm2_prov g_sm2_prov; - enum { CTX_INIT_FAIL = -1, CTX_UNINIT, @@ -457,43 +449,6 @@ static const OSSL_PARAM *uadk_keymgmt_sm2_gen_settable_params(ossl_unused void * return get_default_sm2_keymgmt().gen_settable_params(genctx, provctx); }
-static void uadk_prov_sm2_mutex_infork(void) -{ - /* Release the replication lock of the child process */ - pthread_mutex_unlock(&sm2_mutex); -} - -int uadk_prov_sm2_init(void) -{ - int ret; - - pthread_atfork(NULL, NULL, uadk_prov_sm2_mutex_infork); - pthread_mutex_lock(&sm2_mutex); - if (g_sm2_prov.pid != getpid()) { - ret = wd_ecc_init2("sm2", SCHED_POLICY_RR, TASK_HW); - if (unlikely(ret)) { - pthread_mutex_unlock(&sm2_mutex); - return ret; - } - g_sm2_prov.pid = getpid(); - async_register_poll_fn(ASYNC_TASK_ECC, uadk_prov_ecc_poll); - } - pthread_mutex_unlock(&sm2_mutex); - - return UADK_P_INTI_SUCCESS; -} - -/* Uninit only when the process exits, will not uninit when thread exits. */ -void uadk_prov_sm2_uninit(void) -{ - pthread_mutex_lock(&sm2_mutex); - if (g_sm2_prov.pid == getpid()) { - wd_ecc_uninit2(); - g_sm2_prov.pid = 0; - } - pthread_mutex_unlock(&sm2_mutex); -} - static int uadk_prov_sm2_keygen_init_iot(handle_t sess, struct wd_ecc_req *req) { struct wd_ecc_out *ecc_out = wd_sm2_new_kg_out(sess); @@ -671,8 +626,8 @@ static void *uadk_keymgmt_sm2_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cba }
/* SM2 hardware init */ - ret = uadk_prov_sm2_init(); - if (ret) { + ret = uadk_prov_ecc_init("sm2"); + if (ret == UADK_P_FAIL) { fprintf(stderr, "failed to init sm2\n"); goto free_ec_key; } @@ -1001,10 +956,10 @@ static int uadk_signature_sm2_sign_init(void *vpsm2ctx, void *ec, }
/* Init with UADK */ - ret = uadk_prov_sm2_init(); - if (ret) { + ret = uadk_prov_ecc_init("sm2"); + if (ret == UADK_P_FAIL) { fprintf(stderr, "failed to init sm2\n"); - return UADK_P_FAIL; + return ret; }
psm2ctx->sm2_pctx->init_status = CTX_INIT_SUCC; @@ -2408,10 +2363,10 @@ static int uadk_asym_cipher_sm2_encrypt_init(void *vpsm2ctx, void *vkey, }
/* Init with UADK */ - ret = uadk_prov_sm2_init(); - if (ret) { + ret = uadk_prov_ecc_init("sm2"); + if (ret == UADK_P_FAIL) { fprintf(stderr, "failed to init sm2\n"); - return UADK_P_FAIL; + return ret; }
smctx->init_status = CTX_INIT_SUCC;
From: Weili Qian qianweili@huawei.com
The key generation process may query the name of the algorithm supported by operation_id. If callback is not implemented, task will fail.
Signed-off-by: Weili Qian qianweili@huawei.com --- src/uadk_prov_dh.c | 8 ++++++++ src/uadk_prov_pkey.h | 3 +++ src/uadk_prov_rsa.c | 8 ++++++++ src/uadk_prov_sm2.c | 10 ++++++++++ 4 files changed, 29 insertions(+)
diff --git a/src/uadk_prov_dh.c b/src/uadk_prov_dh.c index e5c956c..8d2c6f6 100644 --- a/src/uadk_prov_dh.c +++ b/src/uadk_prov_dh.c @@ -190,6 +190,14 @@ typedef struct { char *kdf_cekalg; } PROV_DH_KEYEXCH_CTX;
+static const char *uadk_keymgmt_dh_query_operation_name(int operation_id) +{ + if (get_default_dh_keymgmt().query_operation_name == NULL) + return NULL; + + return get_default_dh_keymgmt().query_operation_name(operation_id); +} + static void *uadk_keymgmt_dh_new(void *provctx) { if (get_default_dh_keymgmt().new_fun == NULL) diff --git a/src/uadk_prov_pkey.h b/src/uadk_prov_pkey.h index 3eb9667..c9ddba1 100644 --- a/src/uadk_prov_pkey.h +++ b/src/uadk_prov_pkey.h @@ -168,6 +168,7 @@ static OSSL_FUNC_keymgmt_import_types_fn uadk_keymgmt_##nm##_import_types; \ static OSSL_FUNC_keymgmt_export_fn uadk_keymgmt_##nm##_export; \ static OSSL_FUNC_keymgmt_export_types_fn uadk_keymgmt_##nm##_export_types; \ static OSSL_FUNC_keymgmt_dup_fn uadk_keymgmt_##nm##_dup; \ +static OSSL_FUNC_keymgmt_query_operation_name_fn uadk_keymgmt_##nm##_query_operation_name; \ static UADK_PKEY_KEYMGMT get_default_##nm##_keymgmt(void) \ { \ static UADK_PKEY_KEYMGMT s_keymgmt; \ @@ -215,6 +216,8 @@ const OSSL_DISPATCH uadk_##nm##_keymgmt_functions[] = { \ { OSSL_FUNC_KEYMGMT_EXPORT, (void (*)(void))uadk_keymgmt_##nm##_export }, \ { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))uadk_keymgmt_##nm##_export_types }, \ { OSSL_FUNC_KEYMGMT_DUP, (void (*)(void))uadk_keymgmt_##nm##_dup }, \ + { OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME, \ + (void (*)(void))uadk_keymgmt_##nm##_query_operation_name }, \ { 0, NULL } \ } \
diff --git a/src/uadk_prov_rsa.c b/src/uadk_prov_rsa.c index 9872b27..d1ec153 100644 --- a/src/uadk_prov_rsa.c +++ b/src/uadk_prov_rsa.c @@ -2476,6 +2476,14 @@ static const OSSL_PARAM *uadk_asym_cipher_rsa_settable_ctx_params(void *vprsactx return get_default_rsa_asym_cipher().settable_ctx_params(vprsactx, provctx); }
+static const char *uadk_keymgmt_rsa_query_operation_name(int operation_id) +{ + if (!get_default_rsa_keymgmt().query_operation_name) + return NULL; + + return get_default_rsa_keymgmt().query_operation_name(operation_id); +} + static void *uadk_keymgmt_rsa_new(void *provctx) { if (!get_default_rsa_keymgmt().new_fun) diff --git a/src/uadk_prov_sm2.c b/src/uadk_prov_sm2.c index e27cccb..df753bd 100644 --- a/src/uadk_prov_sm2.c +++ b/src/uadk_prov_sm2.c @@ -191,6 +191,16 @@ ASN1_SEQUENCE(SM2_Ciphertext) = {
IMPLEMENT_ASN1_FUNCTIONS(SM2_Ciphertext)
+static const char *uadk_keymgmt_sm2_query_operation_name(int operation_id) +{ + if (!get_default_sm2_keymgmt().query_operation_name) { + fprintf(stderr, "failed to get keymgmt query_operation_name function\n"); + return NULL; + } + + return get_default_sm2_keymgmt().query_operation_name(operation_id); +} + /** * Create an uadk provider side sm2 key object. *
From: Weili Qian qianweili@huawei.com
Support ECDH key generation.
Signed-off-by: Weili Qian qianweili@huawei.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
From: Weili Qian qianweili@huawei.com
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 --- 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
From: Zhiqi Song songzhiqi1@huawei.com
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 --- 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 = ¶ms; + + 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);