From c6aab5dadf83fad2716b1687366d040303b1301c Mon Sep 17 00:00:00 2001 From: Zhangfei Gao Date: Fri, 9 Jun 2023 09:04:30 +0000 Subject: [PATCH 6/7] uadk: support openssl 3.0 Openssl3.0 provoder will be built when libcrypto >= 3.0 First step to support digest Test with openssl speed -provider xx/uadk_provider.so -provider default -evp md5 openssl speed -provider xx/uadk_provider.so -provider default -evp sm3 openssl speed -provider xx/uadk_provider.so -provider default -evp sha1 openssl speed -provider xx/uadk_provider.so -provider default -evp sha2-224 openssl speed -provider xx/uadk_provider.so -provider default -evp sha2-256 openssl speed -provider xx/uadk_provider.so -provider default -evp sha2-384 openssl speed -provider xx/uadk_provider.so -provider default -evp sha2-512 Signed-off-by: Zhangfei Gao --- src/Makefile.am | 11 + src/uadk_prov.h | 30 ++ src/uadk_prov_digest.c | 699 +++++++++++++++++++++++++++++++++++++++++ src/uadk_prov_init.c | 110 +++++++ 4 files changed, 850 insertions(+) create mode 100644 src/uadk_prov.h create mode 100644 src/uadk_prov_digest.c create mode 100644 src/uadk_prov_init.c diff --git a/src/Makefile.am b/src/Makefile.am index 65afe1d..bfaeb78 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,6 +5,10 @@ if HAVE_CRYPTO lib_LTLIBRARIES=uadk_engine.la endif #HAVE_CRYPTO +if HAVE_CRYPTO3 +lib_LTLIBRARIES=uadk_provider.la +endif #HAVE_CRYPTO3 + uadk_engine_la_SOURCES=uadk_utils.c uadk_engine_init.c uadk_cipher.c \ uadk_digest.c uadk_async.c uadk_rsa.c uadk_sm2.c \ uadk_pkey.c uadk_dh.c uadk_ec.c uadk_ecx.c @@ -45,3 +49,10 @@ uadk_engine_la_SOURCES+=v1/alg/ciphers/sec_ciphers.c \ v1/async/async_poll.c \ v1/async/async_task_queue.c endif #WD_KAE + +uadk_provider_la_SOURCES=uadk_prov_init.c uadk_prov_digest.c uadk_async.c uadk_utils.c + +uadk_provider_la_LDFLAGS=-module -version-number $(VERSION) +uadk_provider_la_LIBADD=$(WD_LIBS) -lpthread +uadk_provider_la_CFLAGS=$(WD_CFLAGS) $(libcrypto_CFLAGS) +uadk_provider_la_CFLAGS+=-DCRYPTO3 diff --git a/src/uadk_prov.h b/src/uadk_prov.h new file mode 100644 index 0000000..c63c3fe --- /dev/null +++ b/src/uadk_prov.h @@ -0,0 +1,30 @@ +/* + * 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. + * + */ +#ifndef UADK_PROV_H +#define UADK_PROV_H + +extern const OSSL_DISPATCH uadk_md5_functions[]; +extern const OSSL_DISPATCH uadk_sm3_functions[]; +extern const OSSL_DISPATCH uadk_sha1_functions[]; +extern const OSSL_DISPATCH uadk_sha224_functions[]; +extern const OSSL_DISPATCH uadk_sha256_functions[]; +extern const OSSL_DISPATCH uadk_sha384_functions[]; +extern const OSSL_DISPATCH uadk_sha512_functions[]; + +void uadk_prov_destroy_digest(void); +#endif diff --git a/src/uadk_prov_digest.c b/src/uadk_prov_digest.c new file mode 100644 index 0000000..fd05753 --- /dev/null +++ b/src/uadk_prov_digest.c @@ -0,0 +1,699 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "uadk.h" +#include "uadk_async.h" +#include "uadk_utils.h" + +#define UADK_DO_SOFT (-0xE0) +#define CTX_SYNC 0 +#define CTX_ASYNC 1 +#define CTX_NUM 2 +#define DIGEST_DOING 1 +#define DIGEST_END 0 + +/* The max BD data length is 16M-512B */ +#define BUF_LEN 0xFFFE00 + +#define SM3_DIGEST_LENGTH 32 +#define SM3_CBLOCK 64 +#define SM3_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT (512) +#define MD5_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT (8 * 1024) +#define SHA_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT (512) +#define MAX_DIGEST_LENGTH 64 +#define DIGEST_BLOCK_SIZE (512 * 1024) +#define ALG_NAME_SIZE 128 + +enum sec_digest_state { + SEC_DIGEST_INIT, + SEC_DIGEST_FIRST_UPDATING, + SEC_DIGEST_DOING, + SEC_DIGEST_FINAL +}; + +struct digest_threshold_table { + int nid; + int threshold; +}; + +struct digest_prov { + int pid; +}; + +static struct digest_prov prov; +static pthread_mutex_t digest_mutex = PTHREAD_MUTEX_INITIALIZER; + +struct evp_md_ctx_st { + const EVP_MD *digest; + /* Functional reference if 'digest' is ENGINE-provided */ + ENGINE *engine; + unsigned long flags; + void *md_data; + /* Public key context for sign/verify */ + EVP_PKEY_CTX *pctx; + /* Update function: usually copied from EVP_MD */ + int (*update)(EVP_MD_CTX *ctx, const void *data, size_t count); +}; + +struct digest_priv_ctx { + handle_t sess; + struct wd_digest_sess_setup setup; + struct wd_digest_req req; + unsigned char *data; + unsigned char out[MAX_DIGEST_LENGTH]; + EVP_MD_CTX *soft_ctx; + EVP_MD *soft_md; + size_t last_update_bufflen; + uint32_t e_nid; + uint32_t state; + uint32_t switch_threshold; + int switch_flag; + size_t md_size; + size_t blk_size; + char alg_name[ALG_NAME_SIZE]; +}; + +struct digest_info { + int nid; + enum wd_digest_mode mode; + enum wd_digest_type alg; + __u32 out_len; +}; + +static struct digest_threshold_table digest_pkt_threshold_table[] = { + { NID_sm3, SM3_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT }, + { NID_md5, MD5_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT }, + { NID_sha1, SHA_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT }, + { NID_sha224, SHA_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT }, + { NID_sha256, SHA_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT }, + { NID_sha384, SHA_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT }, + { NID_sha512, SHA_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT }, +}; + +static struct digest_info digest_info_table[] = { + {NID_md5, WD_DIGEST_NORMAL, WD_DIGEST_MD5, 16}, + {NID_sm3, WD_DIGEST_NORMAL, WD_DIGEST_SM3, 32}, + {NID_sha1, WD_DIGEST_NORMAL, WD_DIGEST_SHA1, 20}, + {NID_sha224, WD_DIGEST_NORMAL, WD_DIGEST_SHA224, 28}, + {NID_sha256, WD_DIGEST_NORMAL, WD_DIGEST_SHA256, 32}, + {NID_sha384, WD_DIGEST_NORMAL, WD_DIGEST_SHA384, 48}, + {NID_sha512, WD_DIGEST_NORMAL, WD_DIGEST_SHA512, 64}, +}; + +static int uadk_e_digests_soft_md(struct digest_priv_ctx *priv) +{ + if (priv->soft_md) + return 1; + + switch (priv->e_nid) { + case NID_sm3: + priv->soft_md = EVP_MD_fetch(NULL, OSSL_DIGEST_NAME_SM3, "provider=default"); + break; + case NID_md5: + priv->soft_md = EVP_MD_fetch(NULL, OSSL_DIGEST_NAME_MD5, "provider=default"); + break; + case NID_sha1: + priv->soft_md = EVP_MD_fetch(NULL, OSSL_DIGEST_NAME_SHA1, "provider=default"); + break; + case NID_sha224: + priv->soft_md = EVP_MD_fetch(NULL, OSSL_DIGEST_NAME_SHA3_224, "provider=default"); + break; + case NID_sha256: + priv->soft_md = EVP_MD_fetch(NULL, OSSL_DIGEST_NAME_SHA3_256, "provider=default"); + break; + case NID_sha384: + priv->soft_md = EVP_MD_fetch(NULL, OSSL_DIGEST_NAME_SHA3_384, "provider=default"); + break; + case NID_sha512: + priv->soft_md = EVP_MD_fetch(NULL, OSSL_DIGEST_NAME_SHA3_512, "provider=default"); + break; + default: + break; + } + + if (unlikely(priv->soft_md == NULL)) + return 0; + + return 1; +} + +static uint32_t sec_digest_get_sw_threshold(int n_id) +{ + int threshold_table_size = ARRAY_SIZE(digest_pkt_threshold_table); + int i = 0; + + do { + if (digest_pkt_threshold_table[i].nid == n_id) + return digest_pkt_threshold_table[i].threshold; + } while (++i < threshold_table_size); + + fprintf(stderr, "nid %d not found in digest threshold table", n_id); + return 0; +} + +static int digest_soft_init(struct digest_priv_ctx *priv) +{ + return EVP_DigestInit(priv->soft_ctx, priv->soft_md); +} + +static int digest_soft_update(EVP_MD_CTX *ctx, const void *data, size_t len) +{ + return EVP_DigestUpdate(ctx, data, len); +} + +static int digest_soft_final(struct digest_priv_ctx *priv, unsigned char *digest) +{ + unsigned int digest_length = EVP_MD_get_size(priv->soft_md); + + return EVP_DigestFinal(priv->soft_ctx, digest, &digest_length); +} + +static void digest_soft_cleanup(struct digest_priv_ctx *priv) +{ + EVP_MD_CTX *ctx = priv->soft_ctx; + + if (ctx != NULL) { + if (ctx->md_data) { + OPENSSL_free(ctx->md_data); + ctx->md_data = NULL; + } + EVP_MD_CTX_free(ctx); + ctx = NULL; + } + + if (priv->soft_md) { + EVP_MD_free(priv->soft_md); + priv->soft_md = NULL; + } +} + +static int uadk_e_digest_soft_work(struct digest_priv_ctx *priv, int len, + unsigned char *digest) +{ + digest_soft_init(priv); + + if (len != 0) + digest_soft_update(priv->soft_ctx, priv->data, len); + + digest_soft_final(priv, digest); + digest_soft_cleanup(priv); + + return 1; +} + +static int uadk_e_digest_env_poll(void *ctx) +{ + __u64 rx_cnt = 0; + __u32 recv = 0; + /* Poll one packet currently */ + int expt = 1; + int ret; + + do { + ret = wd_digest_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 int uadk_digest_init(struct digest_priv_ctx *priv) +{ + int digest_counts = ARRAY_SIZE(digest_info_table); + struct sched_params params = {0}; + int nid = priv->e_nid; + int ret, i; + + pthread_mutex_lock(&digest_mutex); + if (prov.pid != getpid()) { + ret = wd_digest_init2(priv->alg_name, 0, 0); + if (unlikely(ret)) { + priv->switch_flag = UADK_DO_SOFT; + goto soft_init; + } + prov.pid = getpid(); + async_register_poll_fn(ASYNC_TASK_DIGEST, uadk_e_digest_env_poll); + } + pthread_mutex_unlock(&digest_mutex); + + for (i = 0; i < digest_counts; i++) { + if (nid == digest_info_table[i].nid) { + priv->setup.alg = digest_info_table[i].alg; + priv->setup.mode = digest_info_table[i].mode; + priv->req.out_buf_bytes = MAX_DIGEST_LENGTH; + priv->req.out_bytes = digest_info_table[i].out_len; + break; + } + } + + if (unlikely(i == digest_counts)) { + fprintf(stderr, "failed to setup the private ctx.\n"); + return 0; + } + + /* Use the default numa parameters */ + params.numa_id = -1; + priv->setup.sched_param = ¶ms; + priv->sess = wd_digest_alloc_sess(&priv->setup); + if (unlikely(!priv->sess)) + return 0; + + priv->data = malloc(DIGEST_BLOCK_SIZE); + if (unlikely(!priv->data)) { + wd_digest_free_sess(priv->sess); + return 0; + } + + if (uadk_e_digests_soft_md(priv)) + priv->switch_threshold = sec_digest_get_sw_threshold(nid); + + return 1; + +soft_init: + pthread_mutex_unlock(&digest_mutex); + fprintf(stderr, "uadk failed to initialize digest.\n"); + return digest_soft_init(priv); +} + +static void digest_update_out_length(struct digest_priv_ctx *priv) +{ + /* Sha224 and Sha384 need full length mac buffer as doing long hash */ + if (priv->e_nid == NID_sha224) + priv->req.out_bytes = WD_DIGEST_SHA224_FULL_LEN; + + if (priv->e_nid == NID_sha384) + priv->req.out_bytes = WD_DIGEST_SHA384_FULL_LEN; +} + +static int digest_update_inner(struct digest_priv_ctx *priv, const void *data, size_t data_len) +{ + const unsigned char *tmpdata = (const unsigned char *)data; + size_t left_len = data_len; + int copy_to_bufflen; + int ret; + + digest_update_out_length(priv); + + priv->req.has_next = DIGEST_DOING; + + while (priv->last_update_bufflen + left_len > DIGEST_BLOCK_SIZE) { + copy_to_bufflen = DIGEST_BLOCK_SIZE - priv->last_update_bufflen; + uadk_memcpy(priv->data + priv->last_update_bufflen, tmpdata, + copy_to_bufflen); + + priv->last_update_bufflen = DIGEST_BLOCK_SIZE; + priv->req.in_bytes = DIGEST_BLOCK_SIZE; + priv->req.in = priv->data; + priv->req.out = priv->out; + left_len -= copy_to_bufflen; + tmpdata += copy_to_bufflen; + if (priv->state == SEC_DIGEST_INIT) + priv->state = SEC_DIGEST_FIRST_UPDATING; + else if (priv->state == SEC_DIGEST_FIRST_UPDATING) + priv->state = SEC_DIGEST_DOING; + + ret = wd_do_digest_sync(priv->sess, &priv->req); + if (ret) { + fprintf(stderr, "do sec digest sync failed, switch to soft digest.\n"); + goto do_soft_digest; + } + + priv->last_update_bufflen = 0; + if (left_len <= DIGEST_BLOCK_SIZE) { + priv->last_update_bufflen = left_len; + uadk_memcpy(priv->data, tmpdata, priv->last_update_bufflen); + break; + } + } + + return 1; + +do_soft_digest: + if (priv->state == SEC_DIGEST_FIRST_UPDATING + && priv->data + && priv->last_update_bufflen != 0) { + priv->switch_flag = UADK_DO_SOFT; + digest_soft_init(priv); + ret = digest_soft_update(priv->soft_ctx, + priv->data, priv->last_update_bufflen); + if (ret != 1) + return ret; + + return digest_soft_update(priv->soft_ctx, + tmpdata, left_len); + } + + fprintf(stderr, "do soft digest failed during updating!\n"); + return 0; +} + +static int uadk_digest_update(struct digest_priv_ctx *priv, const void *data, size_t data_len) +{ + if (unlikely(priv->switch_flag == UADK_DO_SOFT)) + goto soft_update; + + if (priv->last_update_bufflen + data_len <= DIGEST_BLOCK_SIZE) { + uadk_memcpy(priv->data + priv->last_update_bufflen, data, data_len); + priv->last_update_bufflen += data_len; + return 1; + } + + return digest_update_inner(priv, data, data_len); + +soft_update: + return digest_soft_update(priv->soft_ctx, data, data_len); +} + +static void async_cb(struct wd_digest_req *req, void *data) +{ + struct uadk_e_cb_info *cb_param; + struct async_op *op; + + if (!req) + return; + + cb_param = req->cb_param; + if (!cb_param) + return; + 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); + } +} + +static int do_digest_sync(struct digest_priv_ctx *priv) +{ + int ret; + + if (priv->req.in_bytes <= priv->switch_threshold && + priv->state == SEC_DIGEST_INIT) + return 0; + + ret = wd_do_digest_sync(priv->sess, &priv->req); + if (ret) { + fprintf(stderr, "do sec digest sync failed, switch to soft digest.\n"); + return 0; + } + return 1; +} + +static int do_digest_async(struct digest_priv_ctx *priv, struct async_op *op) +{ + struct uadk_e_cb_info cb_param; + int idx, ret; + + if (unlikely(priv->switch_flag == UADK_DO_SOFT)) { + fprintf(stderr, "async cipher init failed.\n"); + return 0; + } + + cb_param.op = op; + cb_param.priv = priv; + priv->req.cb = (void *)async_cb; + priv->req.cb_param = &cb_param; + + ret = async_get_free_task(&idx); + if (!ret) + return 0; + + op->idx = idx; + + do { + ret = wd_do_digest_async(priv->sess, &priv->req); + if (ret < 0 && ret != -EBUSY) { + fprintf(stderr, "do sec digest async failed.\n"); + async_free_poll_task(op->idx, 0); + return 0; + } + } while (ret == -EBUSY); + + ret = async_pause_job(priv, op, ASYNC_TASK_DIGEST, idx); + if (!ret) + return 0; + return 1; +} + +static int uadk_digest_final(struct digest_priv_ctx *priv, unsigned char *digest) +{ + struct async_op op; + int ret; + + priv->req.has_next = DIGEST_END; + priv->req.in = priv->data; + priv->req.out = priv->out; + priv->req.in_bytes = priv->last_update_bufflen; + + if (priv->e_nid == NID_sha224) + priv->req.out_bytes = WD_DIGEST_SHA224_LEN; + + if (priv->e_nid == NID_sha384) + priv->req.out_bytes = WD_DIGEST_SHA384_LEN; + + ret = async_setup_async_event_notification(&op); + if (unlikely(!ret)) { + fprintf(stderr, "failed to setup async event notification.\n"); + return 0; + } + + if (op.job == NULL) { + /* Synchronous, only the synchronous mode supports soft computing */ + if (unlikely(priv->switch_flag == UADK_DO_SOFT)) { + ret = digest_soft_final(priv, digest); + digest_soft_cleanup(priv); + goto clear; + } + + ret = do_digest_sync(priv); + if (!ret) + goto sync_err; + } else { + ret = do_digest_async(priv, &op); + if (!ret) + goto clear; + } + memcpy(digest, priv->req.out, priv->req.out_bytes); + + return 1; + +sync_err: + if (priv->state == SEC_DIGEST_INIT) { + ret = uadk_e_digest_soft_work(priv, priv->req.in_bytes, digest); + } else { + ret = 0; + fprintf(stderr, "do sec digest stream mode failed.\n"); + } +clear: + async_clear_async_event_notification(); + return ret; +} + +static int uadk_digest_cleanup(struct digest_priv_ctx *priv) +{ + if (priv->sess) { + wd_digest_free_sess(priv->sess); + priv->sess = 0; + } + + if (priv->data) + OPENSSL_free(priv->data); + + return 1; +} + +/* some params related code is copied from OpenSSL v3.0 prov/digestcommon.h */ +static const OSSL_PARAM uadk_digest_default_known_gettable_params[] = { + OSSL_PARAM_size_t(OSSL_DIGEST_PARAM_BLOCK_SIZE, NULL), + OSSL_PARAM_size_t(OSSL_DIGEST_PARAM_SIZE, NULL), + OSSL_PARAM_int(OSSL_DIGEST_PARAM_XOF, NULL), + OSSL_PARAM_int(OSSL_DIGEST_PARAM_ALGID_ABSENT, NULL), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *uadk_prov_gettable_params(void *provctx) +{ + return uadk_digest_default_known_gettable_params; +} + +static int uadk_digest_default_get_params(OSSL_PARAM params[], size_t blksz, + size_t paramsz) +{ + OSSL_PARAM *p = NULL; + + p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_BLOCK_SIZE); + if (p != NULL && !OSSL_PARAM_set_size_t(p, blksz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_SIZE); + if (p != NULL && !OSSL_PARAM_set_size_t(p, paramsz)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_XOF); + if (p != NULL + && !OSSL_PARAM_set_int(p, 0)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_ALGID_ABSENT); + if (p != NULL + && !OSSL_PARAM_set_int(p, 0)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return 0; + } + + return 1; +} + +static void uadk_prov_freectx(void *dctx) +{ + struct digest_priv_ctx *priv = (struct digest_priv_ctx *)dctx; + + uadk_digest_cleanup(priv); + OPENSSL_clear_free(priv, sizeof(*priv)); +} + +static void *uadk_prov_dupctx(void *dctx) +{ + struct digest_priv_ctx *in; + struct digest_priv_ctx *ret; + + in = (struct digest_priv_ctx *)dctx; + ret = OPENSSL_zalloc(sizeof(struct digest_priv_ctx *)); + + if (ret != NULL) + *ret = *in; + return ret; +} + +static int uadk_prov_init(void *dctx, const OSSL_PARAM params[]) +{ + struct digest_priv_ctx *priv = + (struct digest_priv_ctx *) dctx; + + return uadk_digest_init(priv); +} + +static int uadk_prov_update(void *dctx, const unsigned char *in, size_t inl) +{ + return uadk_digest_update((struct digest_priv_ctx *)dctx, in, inl); +} + +/* + * Note: + * The I parameter contains a pointer to the provider side context. + * The digest should be written to I<*out> and the length of the digest to I<*outl>. + * The digest should not exceed I bytes. + */ +static int uadk_prov_final(void *dctx, unsigned char *out, + size_t *outl, size_t outsz) +{ + struct digest_priv_ctx *priv = + (struct digest_priv_ctx *) dctx; + int ret; + + if (outsz > 0) { + ret = uadk_digest_final(priv, out); + if (!ret) + return ret; + } + + if (unlikely(outl != NULL)) + *outl = priv->md_size; + + return 1; +} + +void uadk_prov_destroy_digest(void) +{ + pthread_mutex_lock(&digest_mutex); + if (prov.pid == getpid()) { + wd_digest_uninit2(); + prov.pid = 0; + } + pthread_mutex_unlock(&digest_mutex); +} + +static OSSL_FUNC_digest_freectx_fn uadk_prov_freectx; +static OSSL_FUNC_digest_dupctx_fn uadk_prov_dupctx; +static OSSL_FUNC_digest_init_fn uadk_prov_init; +static OSSL_FUNC_digest_update_fn uadk_prov_update; +static OSSL_FUNC_digest_final_fn uadk_prov_final; +static OSSL_FUNC_digest_gettable_params_fn + uadk_prov_gettable_params; + +#define UADK_PROVIDER_IMPLEMENTATION(name, nid, mdsize, blksize) \ +static OSSL_FUNC_digest_newctx_fn uadk_##name##_newctx; \ +static void *uadk_##name##_newctx(void *provctx) \ +{ \ + struct digest_priv_ctx *ctx = OPENSSL_zalloc(sizeof(*ctx)); \ + \ + if (ctx == NULL) \ + return NULL; \ + ctx->blk_size = blksize; \ + ctx->md_size = mdsize; \ + ctx->e_nid = nid; \ + ctx->soft_ctx = EVP_MD_CTX_new(); \ + if (ctx->soft_ctx == NULL) \ + fprintf(stderr, "EVP_MD_CTX_new failed.\n"); \ + strncpy(ctx->alg_name, #name, ALG_NAME_SIZE - 1); \ + return ctx; \ +} \ +static OSSL_FUNC_digest_get_params_fn uadk_##name##_get_params; \ +static int uadk_##name##_get_params(OSSL_PARAM params[]) \ +{ \ + return uadk_digest_default_get_params(params, blksize, mdsize); \ +} \ +const OSSL_DISPATCH uadk_##name##_functions[] = { \ + { OSSL_FUNC_DIGEST_NEWCTX, (void (*)(void))uadk_##name##_newctx }, \ + { OSSL_FUNC_DIGEST_FREECTX, (void (*)(void))uadk_prov_freectx }, \ + { OSSL_FUNC_DIGEST_DUPCTX, (void (*)(void))uadk_prov_dupctx }, \ + { OSSL_FUNC_DIGEST_INIT, (void (*)(void))uadk_prov_init }, \ + { OSSL_FUNC_DIGEST_UPDATE, (void (*)(void))uadk_prov_update }, \ + { OSSL_FUNC_DIGEST_FINAL, (void (*)(void))uadk_prov_final }, \ + { OSSL_FUNC_DIGEST_GET_PARAMS, \ + (void (*)(void))uadk_##name##_get_params }, \ + { OSSL_FUNC_DIGEST_GETTABLE_PARAMS, \ + (void (*)(void))uadk_prov_gettable_params }, \ + { 0, NULL } \ +} + +UADK_PROVIDER_IMPLEMENTATION(md5, NID_md5, MD5_DIGEST_LENGTH, MD5_CBLOCK); +UADK_PROVIDER_IMPLEMENTATION(sm3, NID_sm3, SM3_DIGEST_LENGTH, SM3_CBLOCK); +UADK_PROVIDER_IMPLEMENTATION(sha1, NID_sha1, 20, 64); +UADK_PROVIDER_IMPLEMENTATION(sha224, NID_sha224, 28, 64); +UADK_PROVIDER_IMPLEMENTATION(sha256, NID_sha256, 32, 64); +UADK_PROVIDER_IMPLEMENTATION(sha384, NID_sha384, 48, 128); +UADK_PROVIDER_IMPLEMENTATION(sha512, NID_sha512, 64, 128); diff --git a/src/uadk_prov_init.c b/src/uadk_prov_init.c new file mode 100644 index 0000000..e363584 --- /dev/null +++ b/src/uadk_prov_init.c @@ -0,0 +1,110 @@ +/* + * 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 +#include + +#include +#include +#include + +#include "uadk_async.h" +#include "uadk_prov.h" + +struct p_uadk_ctx { + const OSSL_CORE_HANDLE *handle; + OSSL_LIB_CTX *libctx; +}; + +const char *engine_uadk_id = "uadk_provider"; +static const char UADK_DEFAULT_PROPERTIES[] = "provider=uadk"; + +const OSSL_ALGORITHM uadk_prov_digests[] = { + { OSSL_DIGEST_NAME_MD5, UADK_DEFAULT_PROPERTIES, + uadk_md5_functions, "uadk_provider md5" }, + { OSSL_DIGEST_NAME_SM3, UADK_DEFAULT_PROPERTIES, + uadk_sm3_functions, "uadk_provider sm3" }, + { OSSL_DIGEST_NAME_SHA1, UADK_DEFAULT_PROPERTIES, + uadk_sha1_functions, "uadk_provider sha1" }, + { OSSL_DIGEST_NAME_SHA2_224, UADK_DEFAULT_PROPERTIES, + uadk_sha224_functions, "uadk_provider sha2-224" }, + { OSSL_DIGEST_NAME_SHA2_256, UADK_DEFAULT_PROPERTIES, + uadk_sha256_functions, "uadk_provider sha2-256" }, + { OSSL_DIGEST_NAME_SHA2_384, UADK_DEFAULT_PROPERTIES, + uadk_sha384_functions, "uadk_provider sha2-384" }, + { OSSL_DIGEST_NAME_SHA2_512, UADK_DEFAULT_PROPERTIES, + uadk_sha512_functions, "uadk_provider sha2-512" }, + { NULL, NULL, NULL } +}; + +static const OSSL_ALGORITHM *p_prov_query(void *provctx, int operation_id, + int *no_cache) +{ + *no_cache = 0; + + switch (operation_id) { + case OSSL_OP_DIGEST: + return uadk_prov_digests; + } + return NULL; +} + +static void p_teardown(void *provctx) +{ + struct p_uadk_ctx *ctx = (struct p_uadk_ctx *)provctx; + + uadk_prov_destroy_digest(); + OPENSSL_free(ctx); +} + +static const OSSL_DISPATCH p_test_table[] = { + { OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))p_prov_query }, + { OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))p_teardown }, + { 0, NULL } +}; + +static void provider_init_child_at_fork_handler(void) +{ + int ret; + + ret = async_module_init(); + if (!ret) + fprintf(stderr, "async_module_init fail!\n"); +} + +int OSSL_provider_init(const OSSL_CORE_HANDLE *handle, + const OSSL_DISPATCH *oin, + const OSSL_DISPATCH **out, + void **provctx) +{ + struct p_uadk_ctx *ctx; + int ret; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (ctx == NULL) + return 0; + + ret = async_module_init(); + if (!ret) + fprintf(stderr, "async_module_init fail!\n"); + pthread_atfork(NULL, NULL, provider_init_child_at_fork_handler); + + *provctx = (void *)ctx; + *out = p_test_table; + return 1; +} -- 2.25.1