
From: Chenghai Huang <huangchenghai2@huawei.com> Add the HMAC mode for the following digest algorithm: md5 sm3 sha1 sha224 sha256 sha384 sha512 sha512_224 sha512_256 Signed-off-by: Chenghai Huang <huangchenghai2@huawei.com> Signed-off-by: JiangShui Yang <yangjiangshui@h-partners.com> --- src/Makefile.am | 3 +- src/uadk_async.h | 1 + src/uadk_prov.h | 7 + src/uadk_prov_digest.c | 6 +- src/uadk_prov_hmac.c | 834 +++++++++++++++++++++++++++++++++++++++++ src/uadk_prov_init.c | 9 + 6 files changed, 856 insertions(+), 4 deletions(-) create mode 100644 src/uadk_prov_hmac.c diff --git a/src/Makefile.am b/src/Makefile.am index c1863e1..b262319 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -67,7 +67,8 @@ uadk_provider_la_SOURCES=uadk_prov_init.c uadk_async.c uadk_utils.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_ecx.c uadk_prov_ecdsa.c + uadk_prov_ecx.c uadk_prov_ecdsa.c \ + uadk_prov_hmac.c uadk_provider_la_LDFLAGS=-module -version-number $(VERSION) uadk_provider_la_LIBADD=$(WD_LIBS) -lpthread diff --git a/src/uadk_async.h b/src/uadk_async.h index dcb94d3..8de3c3c 100644 --- a/src/uadk_async.h +++ b/src/uadk_async.h @@ -44,6 +44,7 @@ typedef int (*async_recv_t)(void *ctx); enum task_type { ASYNC_TASK_CIPHER = 0x1, ASYNC_TASK_DIGEST, + ASYNC_TASK_HMAC, ASYNC_TASK_AEAD, ASYNC_TASK_RSA, ASYNC_TASK_DH, diff --git a/src/uadk_prov.h b/src/uadk_prov.h index b6c236a..ac83ee5 100644 --- a/src/uadk_prov.h +++ b/src/uadk_prov.h @@ -31,10 +31,15 @@ #define POLL_ERROR (-1) /* Copy openssl/providers/implementations/include/prov/names.h */ +#define PROV_NAMES_MD5 "MD5:SSL3-MD5:1.2.840.113549.2.5" +#define PROV_NAMES_SM3 "SM3:1.2.156.10197.1.401" +#define PROV_NAMES_SHA1 "SHA1:SHA-1:SSL3-SHA1:1.3.14.3.2.26" #define PROV_NAMES_SHA2_224 "SHA2-224:SHA-224:SHA224:2.16.840.1.101.3.4.2.4" #define PROV_NAMES_SHA2_256 "SHA2-256:SHA-256:SHA256:2.16.840.1.101.3.4.2.1" #define PROV_NAMES_SHA2_384 "SHA2-384:SHA-384:SHA384:2.16.840.1.101.3.4.2.2" #define PROV_NAMES_SHA2_512 "SHA2-512:SHA-512:SHA512:2.16.840.1.101.3.4.2.3" +#define PROV_NAMES_SHA2_512_224 "SHA2-512/224:SHA-512/224:SHA512-224:2.16.840.1.101.3.4.2.5" +#define PROV_NAMES_SHA2_512_256 "SHA2-512/256:SHA-512/256:SHA512-256:2.16.840.1.101.3.4.2.6" typedef int CRYPTO_REF_COUNT; @@ -137,6 +142,7 @@ extern const OSSL_DISPATCH uadk_sha384_functions[FUNC_MAX_NUM]; extern const OSSL_DISPATCH uadk_sha512_functions[FUNC_MAX_NUM]; extern const OSSL_DISPATCH uadk_sha512_224_functions[FUNC_MAX_NUM]; extern const OSSL_DISPATCH uadk_sha512_256_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH uadk_hmac_functions[FUNC_MAX_NUM]; extern const OSSL_DISPATCH uadk_aes_128_cbc_functions[FUNC_MAX_NUM]; extern const OSSL_DISPATCH uadk_aes_192_cbc_functions[FUNC_MAX_NUM]; @@ -192,6 +198,7 @@ extern const OSSL_DISPATCH uadk_x25519_keyexch_functions[FUNC_MAX_NUM]; extern const OSSL_DISPATCH uadk_ecdsa_signature_functions[FUNC_MAX_NUM]; void uadk_prov_destroy_digest(void); +void uadk_prov_destroy_hmac(void); void uadk_prov_destroy_cipher(void); void uadk_prov_destroy_aead(void); void uadk_prov_destroy_rsa(void); diff --git a/src/uadk_prov_digest.c b/src/uadk_prov_digest.c index d6af557..562e786 100644 --- a/src/uadk_prov_digest.c +++ b/src/uadk_prov_digest.c @@ -309,8 +309,8 @@ static int uadk_prov_digest_dev_init(struct digest_priv_ctx *priv) ctx_set_num.async_ctx_num = UADK_DIGEST_DEF_CTXS; ret = wd_digest_init2_(priv->alg_name, TASK_MIX, SCHED_POLICY_RR, &cparams); - if (unlikely(ret)) { - fprintf(stderr, "uadk failed to initialize digest.\n"); + if (unlikely(ret && ret != -WD_EEXIST)) { + fprintf(stderr, "uadk failed to initialize digest dev, ret = %d\n", ret); goto free_nodemask; } ret = UADK_DIGEST_SUCCESS; @@ -568,7 +568,7 @@ static int uadk_do_digest_async(struct digest_priv_ctx *priv, struct async_op *o } while (ret == -EBUSY); ret = async_pause_job(priv, op, ASYNC_TASK_DIGEST); - if (!ret) + if (!ret || priv->req.state) return UADK_DIGEST_FAIL; return UADK_DIGEST_SUCCESS; diff --git a/src/uadk_prov_hmac.c b/src/uadk_prov_hmac.c new file mode 100644 index 0000000..3c70c5d --- /dev/null +++ b/src/uadk_prov_hmac.c @@ -0,0 +1,834 @@ +// 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 <openssl/evp.h> +#include <openssl/core_names.h> +#include <openssl/proverr.h> +#include <uadk/wd_digest.h> +#include <uadk/wd_sched.h> +#include "uadk.h" +#include "uadk_async.h" +#include "uadk_prov.h" +#include "uadk_utils.h" + +#define UADK_HMAC_SUCCESS 1 +#define UADK_HMAC_FAIL 0 + +/* The max BD data length is 16M-512B */ +#define BUF_LEN 0xFFFE00 + +#define MAX_DIGEST_LENGTH 64 +#define MAX_KEY_LEN 144 +#define HMAC_BLOCK_SIZE (512 * 1024) +#define ALG_NAME_SIZE 128 + +#define KEY_4BYTE_ALIGN(keylen) ((keylen + 3) & ~3) + +#define UADK_DIGEST_DEF_CTXS 1 +#define UADK_DIGEST_OP_NUM 1 + +enum sec_digest_state { + SEC_DIGEST_INIT, + SEC_DIGEST_FIRST_UPDATING, + SEC_DIGEST_DOING, + SEC_DIGEST_FINAL +}; + +struct hmac_prov { + int pid; +}; + +static struct hmac_prov hprov; +static pthread_mutex_t hmac_mutex = PTHREAD_MUTEX_INITIALIZER; + +struct hmac_priv_ctx { + __u32 alg_id; + __u32 state; + size_t out_len; + size_t blk_size; + size_t keylen; + size_t last_update_bufflen; + size_t total_data_len; + OSSL_LIB_CTX *libctx; + handle_t sess; + struct wd_digest_sess_setup setup; + struct wd_digest_req req; + unsigned char *data; + unsigned char key[MAX_KEY_LEN]; + unsigned char out[MAX_DIGEST_LENGTH]; + char alg_name[ALG_NAME_SIZE]; + bool is_stream_copy; +}; + +struct hmac_info { + enum wd_digest_type alg; + __u32 alg_id; + size_t out_len; + size_t blk_size; + const char ossl_alg_name[ALG_NAME_SIZE]; +}; + +static struct hmac_info hmac_info_table[] = { + {WD_DIGEST_MD5, NID_md5, 16, 64, PROV_NAMES_MD5}, + {WD_DIGEST_SM3, NID_sm3, 32, 64, PROV_NAMES_SM3}, + {WD_DIGEST_SHA1, NID_sha1, 20, 64, PROV_NAMES_SHA1}, + {WD_DIGEST_SHA224, NID_sha224, 28, 64, PROV_NAMES_SHA2_224}, + {WD_DIGEST_SHA256, NID_sha256, 32, 64, PROV_NAMES_SHA2_256}, + {WD_DIGEST_SHA384, NID_sha384, 48, 64, PROV_NAMES_SHA2_384}, + {WD_DIGEST_SHA512, NID_sha512, 64, 128, PROV_NAMES_SHA2_512}, + {WD_DIGEST_SHA512_224, NID_sha512_224, 28, 128, PROV_NAMES_SHA2_512_224}, + {WD_DIGEST_SHA512_256, NID_sha512_256, 32, 128, PROV_NAMES_SHA2_512_256} +}; + +static OSSL_FUNC_mac_newctx_fn uadk_prov_hmac_newctx; +static OSSL_FUNC_mac_dupctx_fn uadk_prov_hmac_dupctx; +static OSSL_FUNC_mac_freectx_fn uadk_prov_hmac_freectx; +static OSSL_FUNC_mac_init_fn uadk_prov_hmac_init; +static OSSL_FUNC_mac_update_fn uadk_prov_hmac_update; +static OSSL_FUNC_mac_final_fn uadk_prov_hmac_final; +static OSSL_FUNC_mac_gettable_ctx_params_fn + uadk_prov_hmac_gettable_ctx_params; +static OSSL_FUNC_mac_get_ctx_params_fn uadk_prov_hmac_get_ctx_params; +static OSSL_FUNC_mac_settable_ctx_params_fn + uadk_prov_hmac_settable_ctx_params; +static OSSL_FUNC_mac_set_ctx_params_fn uadk_prov_hmac_set_ctx_params; + +static int uadk_hmac_poll(void *ctx) +{ + __u64 rx_cnt = 0; + __u32 recv = 0; + /* Poll one packet currently */ + __u32 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 void uadk_fill_mac_buffer_len(struct hmac_priv_ctx *priv, bool is_end) +{ + /* Sha224 and Sha384 and Sha512-XXX need full length mac buffer as doing long hash */ + switch (priv->alg_id) { + case NID_sha224: + priv->req.out_bytes = is_end ? WD_DIGEST_SHA224_LEN : WD_DIGEST_SHA224_FULL_LEN; + break; + case NID_sha384: + priv->req.out_bytes = is_end ? WD_DIGEST_SHA384_LEN : WD_DIGEST_SHA384_FULL_LEN; + break; + case NID_sha512_224: + priv->req.out_bytes = is_end ? + WD_DIGEST_SHA512_224_LEN : WD_DIGEST_SHA512_224_FULL_LEN; + break; + case NID_sha512_256: + priv->req.out_bytes = is_end ? + WD_DIGEST_SHA512_256_LEN : WD_DIGEST_SHA512_256_FULL_LEN; + break; + default: + break; + } +} + +static void uadk_digest_set_msg_state(struct hmac_priv_ctx *priv, bool is_end) +{ + if (priv->is_stream_copy) { + priv->req.has_next = is_end ? WD_DIGEST_STREAM_END : WD_DIGEST_STREAM_DOING; + priv->is_stream_copy = false; + } else { + priv->req.has_next = is_end ? WD_DIGEST_END : WD_DIGEST_DOING; + } +} + +static int uadk_get_hmac_info(struct hmac_priv_ctx *priv) +{ + int digest_counts = ARRAY_SIZE(hmac_info_table); + int i; + + for (i = 0; i < digest_counts; i++) { + if (strstr(hmac_info_table[i].ossl_alg_name, priv->alg_name)) { + priv->alg_id = hmac_info_table[i].alg_id; + priv->out_len = hmac_info_table[i].out_len; + priv->blk_size = hmac_info_table[i].blk_size; + priv->setup.alg = hmac_info_table[i].alg; + priv->setup.mode = WD_DIGEST_HMAC; + priv->req.out_buf_bytes = MAX_DIGEST_LENGTH; + priv->req.out_bytes = hmac_info_table[i].out_len; + + return UADK_HMAC_SUCCESS; + } + } + + fprintf(stderr, "failed to setup the private ctx, algname = %s.\n", priv->alg_name); + return UADK_HMAC_FAIL; +} + +static const char *get_uadk_alg_name(__u32 alg_id) +{ + switch (alg_id) { + case NID_md5: + return "md5"; + case NID_sm3: + return "sm3"; + case NID_sha1: + return "sha1"; + case NID_sha224: + return "sha224"; + case NID_sha256: + return "sha256"; + case NID_sha384: + return "sha384"; + case NID_sha512: + return "sha512"; + case NID_sha512_224: + return "sha512-224"; + case NID_sha512_256: + return "sha512-256"; + default: + break; + } + + fprintf(stderr, "failed to find alg, nid = %u.\n", alg_id); + return NULL; +} + +static void uadk_hmac_mutex_infork(void) +{ + /* Release the replication lock of the child process */ + pthread_mutex_unlock(&hmac_mutex); +} + +static int uadk_prov_hmac_dev_init(struct hmac_priv_ctx *priv) +{ + struct wd_ctx_params cparams = {0}; + struct wd_ctx_nums ctx_set_num; + int ret = UADK_HMAC_SUCCESS; + const char *alg_name; + + pthread_atfork(NULL, NULL, uadk_hmac_mutex_infork); + pthread_mutex_lock(&hmac_mutex); + if (hprov.pid == getpid()) + goto mutex_unlock; + + alg_name = get_uadk_alg_name(priv->alg_id); + if (!alg_name) { + ret = UADK_HMAC_FAIL; + goto mutex_unlock; + } + + cparams.op_type_num = UADK_DIGEST_OP_NUM; + cparams.ctx_set_num = &ctx_set_num; + cparams.bmp = numa_allocate_nodemask(); + if (!cparams.bmp) { + ret = UADK_HMAC_FAIL; + fprintf(stderr, "failed to create nodemask!\n"); + goto mutex_unlock; + } + + numa_bitmask_setall(cparams.bmp); + + ctx_set_num.sync_ctx_num = UADK_DIGEST_DEF_CTXS; + ctx_set_num.async_ctx_num = UADK_DIGEST_DEF_CTXS; + + ret = wd_digest_init2_((char *)alg_name, TASK_MIX, SCHED_POLICY_RR, &cparams); + if (unlikely(ret && ret != -WD_EEXIST)) { + fprintf(stderr, "uadk failed to initialize hmac, ret = %d\n", ret); + goto free_nodemask; + } + ret = UADK_HMAC_SUCCESS; + + hprov.pid = getpid(); + async_register_poll_fn(ASYNC_TASK_HMAC, uadk_hmac_poll); + +free_nodemask: + numa_free_nodemask(cparams.bmp); +mutex_unlock: + pthread_mutex_unlock(&hmac_mutex); + return ret; +} + +static int uadk_prov_compute_key_hash(struct hmac_priv_ctx *priv, + const unsigned char *key, size_t keylen) +{ + int ret = UADK_HMAC_FAIL; + EVP_MD_CTX *ctx = NULL; + EVP_MD *key_md = NULL; + __u32 outlen = 0; + + key_md = EVP_MD_fetch(priv->libctx, priv->alg_name, NULL); + if (!key_md) + return UADK_HMAC_FAIL; + + ctx = EVP_MD_CTX_new(); + if (!ctx) + goto free_md; + + if (!EVP_DigestInit_ex2(ctx, key_md, NULL) + || !EVP_DigestUpdate(ctx, key, keylen) + || !EVP_DigestFinal_ex(ctx, priv->key, &outlen)) + goto free_ctx; + + priv->keylen = outlen; + ret = UADK_HMAC_SUCCESS; + +free_ctx: + EVP_MD_CTX_free(ctx); +free_md: + EVP_MD_free(key_md); + + return ret; +} + +static int uadk_hmac_ctx_init(struct hmac_priv_ctx *priv) +{ + struct sched_params params = {0}; + int ret; + + ret = uadk_prov_hmac_dev_init(priv); + if (unlikely(ret <= 0)) + return UADK_HMAC_FAIL; + + /* Use the default numa parameters */ + params.numa_id = -1; + priv->setup.sched_param = ¶ms; + + if (!priv->sess) { + priv->sess = wd_digest_alloc_sess(&priv->setup); + if (unlikely(!priv->sess)) { + fprintf(stderr, "uadk failed to alloc hmac sess.\n"); + return UADK_HMAC_FAIL; + } + + ret = wd_digest_set_key(priv->sess, priv->key, priv->keylen); + if (ret) { + fprintf(stderr, "uadk failed to set hmac key!\n"); + goto free_sess; + } + } + + return UADK_HMAC_SUCCESS; + +free_sess: + wd_digest_free_sess(priv->sess); + priv->sess = 0; + return UADK_HMAC_FAIL; +} + +static void uadk_hmac_async_cb(struct wd_digest_req *req, void *data) +{ + struct uadk_e_cb_info *hmac_cb_param; + struct wd_digest_req *req_origin; + struct async_op *op; + + if (!req || !req->cb_param) + return; + + hmac_cb_param = req->cb_param; + req_origin = hmac_cb_param->priv; + req_origin->state = req->state; + op = hmac_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 uadk_do_hmac_sync(struct hmac_priv_ctx *priv) +{ + int ret; + + ret = wd_do_digest_sync(priv->sess, &priv->req); + if (ret) { + fprintf(stderr, "do sec hmac sync failed.\n"); + return UADK_HMAC_FAIL; + } + + return UADK_HMAC_SUCCESS; +} + +static int uadk_do_hmac_async(struct hmac_priv_ctx *priv, struct async_op *op) +{ + struct uadk_e_cb_info cb_param; + int idx, ret; + int cnt = 0; + + cb_param.op = op; + cb_param.priv = &priv->req; + priv->req.cb = (void *)uadk_hmac_async_cb; + priv->req.cb_param = &cb_param; + priv->req.state = POLL_ERROR; + + ret = async_get_free_task(&idx); + if (!ret) + return UADK_HMAC_FAIL; + + 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"); + goto free_poll_task; + } + + if (unlikely(++cnt > ENGINE_SEND_MAX_CNT)) { + fprintf(stderr, "do digest async operation timeout.\n"); + goto free_poll_task; + } + } while (ret == -EBUSY); + + ret = async_pause_job(priv, op, ASYNC_TASK_HMAC); + if (!ret || priv->req.state) + return UADK_HMAC_FAIL; + + return UADK_HMAC_SUCCESS; + +free_poll_task: + async_free_poll_task(op->idx, 0); + return UADK_HMAC_FAIL; +} + +static int uadk_hmac_update_inner(struct hmac_priv_ctx *priv, const void *data, size_t data_len) +{ + unsigned char *input_data = (unsigned char *)data; + size_t remain_len = data_len; + size_t processing_len; + int ret; + + ret = uadk_hmac_ctx_init(priv); + if (ret != UADK_HMAC_SUCCESS) + return UADK_HMAC_FAIL; + + uadk_digest_set_msg_state(priv, false); + uadk_fill_mac_buffer_len(priv, false); + + do { + /* + * If there is data in the buffer, it will be filled and processed. Otherwise, it + * will be processed according to the UADK package len(16M-512Byte). Finally the + * remaining data less than the size of the buffer will be stored in the buffer. + */ + if (priv->last_update_bufflen != 0) { + processing_len = HMAC_BLOCK_SIZE - priv->last_update_bufflen; + uadk_memcpy(priv->data + priv->last_update_bufflen, input_data, + processing_len); + + priv->req.in_bytes = HMAC_BLOCK_SIZE; + priv->req.in = priv->data; + priv->last_update_bufflen = 0; + } else { + if (remain_len > BUF_LEN) + processing_len = BUF_LEN; + else + processing_len = remain_len - (remain_len % HMAC_BLOCK_SIZE); + + priv->req.in_bytes = processing_len; + priv->req.in = input_data; + } + + 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; + + priv->req.out = priv->out; + + ret = uadk_do_hmac_sync(priv); + if (!ret) { + fprintf(stderr, "do sec digest update failed.\n"); + return UADK_HMAC_FAIL; + } + + remain_len -= processing_len; + input_data += processing_len; + } while (remain_len > HMAC_BLOCK_SIZE); + + priv->last_update_bufflen = remain_len; + uadk_memcpy(priv->data, input_data, priv->last_update_bufflen); + + return UADK_HMAC_SUCCESS; +} + +static int uadk_hmac_update(struct hmac_priv_ctx *priv, const void *data, size_t data_len) +{ + if (!priv->data) { + fprintf(stderr, "failed to do digest update, data in CTX is NULL.\n"); + return UADK_HMAC_FAIL; + } + + priv->total_data_len += data_len; + + if (priv->last_update_bufflen + data_len <= HMAC_BLOCK_SIZE) { + uadk_memcpy(priv->data + priv->last_update_bufflen, data, data_len); + priv->last_update_bufflen += data_len; + return UADK_HMAC_SUCCESS; + } + + return uadk_hmac_update_inner(priv, data, data_len); +} + +static int uadk_hmac_final(struct hmac_priv_ctx *priv, unsigned char *digest) +{ + struct async_op op; + int ret; + + if (!priv->data) { + fprintf(stderr, "failed to do digest final, data in CTX is NULL.\n"); + return UADK_HMAC_FAIL; + } + + ret = uadk_hmac_ctx_init(priv); + if (!ret) + return UADK_HMAC_FAIL; + + priv->req.in = priv->data; + priv->req.out = priv->state == SEC_DIGEST_INIT ? digest : priv->out; + priv->req.in_bytes = priv->last_update_bufflen; + + uadk_digest_set_msg_state(priv, true); + uadk_fill_mac_buffer_len(priv, true); + + ret = async_setup_async_event_notification(&op); + if (unlikely(!ret)) { + fprintf(stderr, "failed to setup async event notification.\n"); + return UADK_HMAC_FAIL; + } + + if (!op.job) + ret = uadk_do_hmac_sync(priv); + else + ret = uadk_do_hmac_async(priv, &op); + + if (!ret) + goto clear; + + if (priv->state != SEC_DIGEST_INIT) + memcpy(digest, priv->req.out, priv->req.out_bytes); + + return UADK_HMAC_SUCCESS; + +clear: + async_clear_async_event_notification(); + return ret; +} + +static void *uadk_prov_hmac_dupctx(void *hctx) +{ + struct hmac_priv_ctx *dst_ctx, *src_ctx; + + if (!hctx) + return NULL; + + src_ctx = (struct hmac_priv_ctx *)hctx; + dst_ctx = OPENSSL_memdup(src_ctx, sizeof(struct hmac_priv_ctx)); + if (!dst_ctx) + return NULL; + + /* + * When a copy is performed during digest execution, + * the status in the sess needs to be synchronized. + */ + if (dst_ctx->sess && dst_ctx->state != SEC_DIGEST_INIT) { + dst_ctx->is_stream_copy = true; + /* + * Length that the hardware has processed should be equal to + * total input data length minus software cache data length. + */ + dst_ctx->req.long_data_len = dst_ctx->total_data_len - + dst_ctx->last_update_bufflen; + } + + dst_ctx->sess = 0; + dst_ctx->data = OPENSSL_memdup(src_ctx->data, HMAC_BLOCK_SIZE); + if (!dst_ctx->data) + goto free_ctx; + + return dst_ctx; + +free_data: + OPENSSL_clear_free(dst_ctx->data, HMAC_BLOCK_SIZE); +free_ctx: + OPENSSL_clear_free(dst_ctx, sizeof(*dst_ctx)); + return NULL; +} + +static void uadk_hmac_cleanup(struct hmac_priv_ctx *priv) +{ + if (priv->sess) + wd_digest_free_sess(priv->sess); + + if (priv->data) + OPENSSL_clear_free(priv->data, HMAC_BLOCK_SIZE); +} + +static void uadk_prov_hmac_freectx(void *hctx) +{ + struct hmac_priv_ctx *priv = (struct hmac_priv_ctx *)hctx; + + if (!hctx) { + fprintf(stderr, "the CTX to be free is NULL.\n"); + return; + } + + uadk_hmac_cleanup(priv); + OPENSSL_clear_free(priv, sizeof(*priv)); +} + +static int uadk_prov_hmac_setkey(struct hmac_priv_ctx *priv, + const unsigned char *key, size_t keylen) +{ + size_t padding; + + if (priv->key) + memset(priv->key, 0, MAX_KEY_LEN); + + if (keylen > priv->blk_size) + return uadk_prov_compute_key_hash(priv, key, keylen); + + padding = KEY_4BYTE_ALIGN(keylen); + memcpy(priv->key, key, keylen); + priv->keylen = padding; + + return UADK_HMAC_SUCCESS; +} + +static int uadk_prov_hmac_init(void *hctx, const unsigned char *key, + size_t keylen, const OSSL_PARAM params[]) +{ + struct hmac_priv_ctx *priv = (struct hmac_priv_ctx *)hctx; + int ret; + + if (!hctx) { + fprintf(stderr, "CTX is NULL.\n"); + return UADK_HMAC_FAIL; + } + + ret = uadk_prov_hmac_set_ctx_params(hctx, params); + if (unlikely(!ret)) + return UADK_HMAC_FAIL; + + ret = uadk_get_hmac_info(priv); + if (unlikely(!ret)) + return UADK_HMAC_FAIL; + + if (key) { + ret = uadk_prov_hmac_setkey(priv, key, keylen); + if (!ret) + return UADK_HMAC_FAIL; + } + + ret = uadk_prov_hmac_dev_init(priv); + if (unlikely(ret <= 0)) + return UADK_HMAC_FAIL; + + return UADK_HMAC_SUCCESS; +} + +static int uadk_prov_hmac_update(void *hctx, const unsigned char *data, size_t datalen) +{ + if (!hctx || !data) { + fprintf(stderr, "CTX or input data is NULL.\n"); + return UADK_HMAC_FAIL; + } + + return uadk_hmac_update((struct hmac_priv_ctx *)hctx, data, datalen); +} + +/* + * Note: + * The I<hctx> 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<outsz> bytes. + */ +static int uadk_prov_hmac_final(void *hctx, unsigned char *out, size_t *outl, + size_t outsize) +{ + struct hmac_priv_ctx *priv = (struct hmac_priv_ctx *)hctx; + int ret; + + if (!hctx) { + fprintf(stderr, "hmac CTX or output data is NULL.\n"); + return UADK_HMAC_FAIL; + } + + if (out && outsize > 0) { + ret = uadk_hmac_final(priv, out); + if (!ret) + return ret; + } + + if (outl) + *outl = priv->out_len; + + return UADK_HMAC_SUCCESS; +} + +void uadk_prov_destroy_hmac(void) +{ + pthread_mutex_lock(&hmac_mutex); + if (hprov.pid == getpid()) { + wd_digest_uninit2(); + hprov.pid = 0; + } + pthread_mutex_unlock(&hmac_mutex); +} + +static const OSSL_PARAM uadk_prov_hmac_known_gettable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_MAC_PARAM_SIZE, NULL), + OSSL_PARAM_size_t(OSSL_MAC_PARAM_BLOCK_SIZE, NULL), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *uadk_prov_hmac_gettable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + return uadk_prov_hmac_known_gettable_ctx_params; +} + +static int uadk_prov_hmac_get_ctx_params(void *hctx, OSSL_PARAM params[]) +{ + struct hmac_priv_ctx *priv = (struct hmac_priv_ctx *)hctx; + OSSL_PARAM *p = NULL; + + if (!hctx) + return UADK_HMAC_FAIL; + + p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_SIZE); + if (p && !OSSL_PARAM_set_size_t(p, priv->out_len)) + return UADK_HMAC_FAIL; + + p = OSSL_PARAM_locate(params, OSSL_MAC_PARAM_BLOCK_SIZE); + if (p && !OSSL_PARAM_set_size_t(p, priv->blk_size)) + return UADK_HMAC_FAIL; + + return UADK_HMAC_SUCCESS; +} + +static const OSSL_PARAM uadk_prov_settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_MAC_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_octet_string(OSSL_MAC_PARAM_KEY, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *uadk_prov_hmac_settable_ctx_params(ossl_unused void *ctx, + ossl_unused void *provctx) +{ + return uadk_prov_settable_ctx_params; +} + +static void uadk_hmac_name_uppercase(char *str) +{ + size_t length = strlen(str); + + for (size_t i = 0; i < length; i++) + str[i] = toupper(str[i]); +} + +/* + * ALL parameters should be set before init(). + */ +static int uadk_prov_hmac_set_ctx_params(void *hctx, const OSSL_PARAM params[]) +{ + struct hmac_priv_ctx *priv = (struct hmac_priv_ctx *)hctx; + const OSSL_PARAM *p; + int ret; + + if (!params || !params->key) + return UADK_HMAC_SUCCESS; + + if (!hctx) + return UADK_HMAC_FAIL; + + p = OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_DIGEST); + if (p) { + if (p->data_type != OSSL_PARAM_UTF8_STRING || + strlen((char *)p->data) > ALG_NAME_SIZE - 1) + return UADK_HMAC_FAIL; + + /* + * For subsequent character string matching, no end flag is added, + * and the length will be within the value of ALG_NAME_SIZE. + */ + ret = snprintf(priv->alg_name, ALG_NAME_SIZE, "%s", p->data); + if (ret < 0) { + fprintf(stderr, "Invalid alg name %s.\n", p->data); + return UADK_HMAC_FAIL; + } + + uadk_hmac_name_uppercase(priv->alg_name); + } + + p = OSSL_PARAM_locate_const(params, OSSL_MAC_PARAM_KEY); + if (p) { + if (p->data_type != OSSL_PARAM_OCTET_STRING) + return UADK_HMAC_FAIL; + + if (!uadk_prov_hmac_setkey(priv, p->data, p->data_size)) + return UADK_HMAC_FAIL; + } + + return UADK_HMAC_SUCCESS; +} + +static void *uadk_prov_hmac_newctx(void *hctx) +{ + struct hmac_priv_ctx *ctx; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (!ctx) + return NULL; + + ctx->libctx = prov_libctx_of(hctx); + + ctx->data = OPENSSL_zalloc(HMAC_BLOCK_SIZE); + if (!ctx->data) { + OPENSSL_free(ctx); + return NULL; + } + + return ctx; +} + +const OSSL_DISPATCH uadk_hmac_functions[] = { + { OSSL_FUNC_MAC_NEWCTX, (void (*)(void))uadk_prov_hmac_newctx }, + { OSSL_FUNC_MAC_DUPCTX, (void (*)(void))uadk_prov_hmac_dupctx }, + { OSSL_FUNC_MAC_FREECTX, (void (*)(void))uadk_prov_hmac_freectx }, + { OSSL_FUNC_MAC_INIT, (void (*)(void))uadk_prov_hmac_init }, + { OSSL_FUNC_MAC_UPDATE, (void (*)(void))uadk_prov_hmac_update }, + { OSSL_FUNC_MAC_FINAL, (void (*)(void))uadk_prov_hmac_final }, + { OSSL_FUNC_MAC_GETTABLE_CTX_PARAMS, + (void (*)(void))uadk_prov_hmac_gettable_ctx_params }, + { OSSL_FUNC_MAC_GET_CTX_PARAMS, + (void (*)(void))uadk_prov_hmac_get_ctx_params }, + { OSSL_FUNC_MAC_SETTABLE_CTX_PARAMS, + (void (*)(void))uadk_prov_hmac_settable_ctx_params }, + { OSSL_FUNC_MAC_SET_CTX_PARAMS, + (void (*)(void))uadk_prov_hmac_set_ctx_params }, + { 0, NULL } +}; diff --git a/src/uadk_prov_init.c b/src/uadk_prov_init.c index b5588f2..c29500b 100644 --- a/src/uadk_prov_init.c +++ b/src/uadk_prov_init.c @@ -69,6 +69,12 @@ const OSSL_ALGORITHM uadk_prov_digests[] = { { NULL, NULL, NULL } }; +const OSSL_ALGORITHM uadk_prov_hmac[] = { + { "HMAC", UADK_DEFAULT_PROPERTIES, + uadk_hmac_functions, "uadk_provider hmac" }, + { NULL, NULL, NULL } +}; + const OSSL_ALGORITHM uadk_prov_ciphers_v2[] = { { "AES-128-CBC", UADK_DEFAULT_PROPERTIES, uadk_aes_128_cbc_functions, "uadk_provider aes-128-cbc" }, @@ -268,6 +274,8 @@ static const OSSL_ALGORITHM *uadk_query(void *provctx, int operation_id, if (!ver && uadk_get_sw_offload_state()) break; return uadk_prov_digests; + case OSSL_OP_MAC: + return uadk_prov_hmac; case OSSL_OP_CIPHER: ver = uadk_prov_cipher_version(); if (!ver && uadk_get_sw_offload_state()) @@ -324,6 +332,7 @@ static void uadk_teardown(void *provctx) } uadk_prov_destroy_digest(); + uadk_prov_destroy_hmac(); uadk_prov_destroy_cipher(); uadk_prov_destroy_aead(); uadk_prov_destroy_rsa(); -- 2.33.0