From: JiangShui Yang yangjiangshui@h-partners.com
Chenghai Huang (9): uadk_provider: define the err and success return name uadk_provider: add digest single block function for provider uadk_provider: add input pointer check uadk_provider: code cleanup for provider digest uadk_provider: extract Digest info table check function uadk_provider: optimized provider update performance uadk_provider: add sha512_XXX algorithm name processing uadk_provider: fix the uadk_provider digest ctx copy function uadk_engine: optimized engine update process
Zhiqi Song (3): uadk_provider: fixup bio problem in provider uadk_provider: add der encode and packet for SM2 uadk_provider: support sm2 hardware acceleration
src/Makefile.am | 5 +- src/uadk_digest.c | 44 +- src/uadk_prov.h | 54 +- src/uadk_prov_bio.c | 265 +++ src/uadk_prov_bio.h | 34 + src/uadk_prov_der_writer.c | 236 +++ src/uadk_prov_der_writer.h | 129 ++ src/uadk_prov_digest.c | 352 ++-- src/uadk_prov_init.c | 84 +- src/uadk_prov_packet.c | 514 ++++++ src/uadk_prov_packet.h | 959 +++++++++++ src/uadk_prov_pkey.c | 770 +++++++++ src/uadk_prov_pkey.h | 429 +++++ src/uadk_prov_sm2.c | 3146 ++++++++++++++++++++++++++++++++++++ 14 files changed, 6864 insertions(+), 157 deletions(-) create mode 100644 src/uadk_prov_bio.c create mode 100644 src/uadk_prov_bio.h create mode 100644 src/uadk_prov_der_writer.c create mode 100644 src/uadk_prov_der_writer.h create mode 100644 src/uadk_prov_packet.c create mode 100644 src/uadk_prov_packet.h create mode 100644 src/uadk_prov_pkey.c create mode 100644 src/uadk_prov_pkey.h create mode 100644 src/uadk_prov_sm2.c
From: Chenghai Huang huangchenghai2@huawei.com
The return values 0 and 1 are hard to understand. Therefore, the return values for success and failure are named.
Signed-off-by: Chenghai Huang huangchenghai2@huawei.com Signed-off-by: JiangShui Yang yangjiangshui@h-partners.com --- src/uadk_prov_digest.c | 80 ++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 39 deletions(-)
diff --git a/src/uadk_prov_digest.c b/src/uadk_prov_digest.c index 378bcbc..081488e 100644 --- a/src/uadk_prov_digest.c +++ b/src/uadk_prov_digest.c @@ -36,19 +36,21 @@ #define CTX_SYNC 0 #define CTX_ASYNC 1 #define CTX_NUM 2 -#define DIGEST_DOING 1 -#define DIGEST_END 0 +#define DIGEST_DOING 1 +#define DIGEST_END 0 +#define UADK_DIGEST_SUCCESS 1 +#define UADK_DIGEST_FAIL 0
/* The max BD data length is 16M-512B */ -#define BUF_LEN 0xFFFE00 +#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 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 DIGEST_BLOCK_SIZE (512 * 1024) #define ALG_NAME_SIZE 128
enum sec_digest_state { @@ -123,7 +125,7 @@ static struct digest_info digest_info_table[] = { static int uadk_digests_soft_md(struct digest_priv_ctx *priv) { if (priv->soft_md) - return 1; + return UADK_DIGEST_SUCCESS;
switch (priv->e_nid) { case NID_sm3: @@ -152,9 +154,9 @@ static int uadk_digests_soft_md(struct digest_priv_ctx *priv) }
if (unlikely(priv->soft_md == NULL)) - return 0; + return UADK_DIGEST_FAIL;
- return 1; + return UADK_DIGEST_SUCCESS; }
static int uadk_digest_soft_init(struct digest_priv_ctx *priv) @@ -162,7 +164,7 @@ static int uadk_digest_soft_init(struct digest_priv_ctx *priv) if (priv->soft_md) return EVP_DigestInit_ex(priv->soft_ctx, priv->soft_md, NULL);
- return 0; + return UADK_DIGEST_FAIL; }
static int uadk_digest_soft_update(struct digest_priv_ctx *priv, @@ -171,7 +173,7 @@ static int uadk_digest_soft_update(struct digest_priv_ctx *priv, if (priv->soft_md) return EVP_DigestUpdate(priv->soft_ctx, data, len);
- return 0; + return UADK_DIGEST_FAIL; }
static int uadk_digest_soft_final(struct digest_priv_ctx *priv, unsigned char *digest) @@ -182,7 +184,7 @@ static int uadk_digest_soft_final(struct digest_priv_ctx *priv, unsigned char *d return EVP_DigestFinal_ex(priv->soft_ctx, digest, &digest_length); }
- return 0; + return UADK_DIGEST_FAIL; }
static void digest_soft_cleanup(struct digest_priv_ctx *priv) @@ -208,7 +210,7 @@ static int uadk_digest_soft_work(struct digest_priv_ctx *priv, int len, unsigned char *digest) { if (!priv->soft_md) - return 0; + return UADK_DIGEST_FAIL;
uadk_digest_soft_init(priv);
@@ -218,7 +220,7 @@ static int uadk_digest_soft_work(struct digest_priv_ctx *priv, int len, uadk_digest_soft_final(priv, digest); digest_soft_cleanup(priv);
- return 1; + return UADK_DIGEST_SUCCESS; }
static int uadk_digest_env_poll(void *ctx) @@ -273,7 +275,7 @@ static int uadk_digest_init(struct digest_priv_ctx *priv)
if (unlikely(i == digest_counts)) { fprintf(stderr, "failed to setup the private ctx.\n"); - return 0; + return UADK_DIGEST_FAIL; }
/* Use the default numa parameters */ @@ -281,18 +283,18 @@ static int uadk_digest_init(struct digest_priv_ctx *priv) priv->setup.sched_param = ¶ms; priv->sess = wd_digest_alloc_sess(&priv->setup); if (unlikely(!priv->sess)) - return 0; + return UADK_DIGEST_FAIL;
priv->data = malloc(DIGEST_BLOCK_SIZE); if (unlikely(!priv->data)) { wd_digest_free_sess(priv->sess); - return 0; + return UADK_DIGEST_FAIL; }
if (enable_sw_offload) uadk_digests_soft_md(priv);
- return 1; + return UADK_DIGEST_SUCCESS;
soft_init: pthread_mutex_unlock(&digest_mutex); @@ -346,7 +348,7 @@ static int uadk_digest_update_inner(struct digest_priv_ctx *priv, const void *da } }
- return 1; + return UADK_DIGEST_SUCCESS;
do_soft_digest: if (priv->state == SEC_DIGEST_FIRST_UPDATING @@ -362,7 +364,7 @@ do_soft_digest: }
fprintf(stderr, "do soft digest failed during updating!\n"); - return 0; + return UADK_DIGEST_FAIL; }
static int uadk_digest_update(struct digest_priv_ctx *priv, const void *data, size_t data_len) @@ -373,7 +375,7 @@ static int uadk_digest_update(struct digest_priv_ctx *priv, const void *data, si 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 UADK_DIGEST_SUCCESS; }
return uadk_digest_update_inner(priv, data, data_len); @@ -408,14 +410,14 @@ static int uadk_do_digest_sync(struct digest_priv_ctx *priv) if (priv->soft_md && priv->req.in_bytes <= priv->switch_threshold && priv->state == SEC_DIGEST_INIT) - return 0; + return UADK_DIGEST_FAIL;
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 UADK_DIGEST_FAIL; } - return 1; + return UADK_DIGEST_SUCCESS; }
static int uadk_do_digest_async(struct digest_priv_ctx *priv, struct async_op *op) @@ -425,7 +427,7 @@ static int uadk_do_digest_async(struct digest_priv_ctx *priv, struct async_op *o
if (unlikely(priv->switch_flag == UADK_DO_SOFT)) { fprintf(stderr, "async cipher init failed.\n"); - return 0; + return UADK_DIGEST_FAIL; }
cb_param.op = op; @@ -435,7 +437,7 @@ static int uadk_do_digest_async(struct digest_priv_ctx *priv, struct async_op *o
ret = async_get_free_task(&idx); if (!ret) - return 0; + return UADK_DIGEST_FAIL;
op->idx = idx;
@@ -444,14 +446,14 @@ static int uadk_do_digest_async(struct digest_priv_ctx *priv, struct async_op *o if (ret < 0 && ret != -EBUSY) { fprintf(stderr, "do sec digest async failed.\n"); async_free_poll_task(op->idx, 0); - return 0; + return UADK_DIGEST_FAIL; } } while (ret == -EBUSY);
ret = async_pause_job(priv, op, ASYNC_TASK_DIGEST); if (!ret) - return 0; - return 1; + return UADK_DIGEST_FAIL; + return UADK_DIGEST_SUCCESS; }
static int uadk_digest_final(struct digest_priv_ctx *priv, unsigned char *digest) @@ -473,7 +475,7 @@ static int uadk_digest_final(struct digest_priv_ctx *priv, unsigned char *digest ret = async_setup_async_event_notification(&op); if (unlikely(!ret)) { fprintf(stderr, "failed to setup async event notification.\n"); - return 0; + return UADK_DIGEST_FAIL; }
if (op.job == NULL) { @@ -494,7 +496,7 @@ static int uadk_digest_final(struct digest_priv_ctx *priv, unsigned char *digest } memcpy(digest, priv->req.out, priv->req.out_bytes);
- return 1; + return UADK_DIGEST_SUCCESS;
sync_err: if (priv->state == SEC_DIGEST_INIT) { @@ -518,7 +520,7 @@ static int uadk_digest_cleanup(struct digest_priv_ctx *priv) if (priv->data) OPENSSL_free(priv->data);
- return 1; + return UADK_DIGEST_SUCCESS; }
/* some params related code is copied from OpenSSL v3.0 prov/digestcommon.h */ @@ -543,27 +545,27 @@ static int uadk_digest_default_get_params(OSSL_PARAM params[], size_t blksz, 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; + return UADK_DIGEST_FAIL; } 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; + return UADK_DIGEST_FAIL; } 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; + return UADK_DIGEST_FAIL; } 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 UADK_DIGEST_FAIL; }
- return 1; + return UADK_DIGEST_SUCCESS; }
static void uadk_prov_freectx(void *dctx) @@ -622,7 +624,7 @@ static int uadk_prov_final(void *dctx, unsigned char *out, if (unlikely(outl != NULL)) *outl = priv->md_size;
- return 1; + return UADK_DIGEST_SUCCESS; }
void uadk_prov_destroy_digest(void)
From: Chenghai Huang huangchenghai2@huawei.com
The digest algorithm of a single block is added. Only one block size file can be processed.
Signed-off-by: Chenghai Huang huangchenghai2@huawei.com Signed-off-by: JiangShui Yang yangjiangshui@h-partners.com --- src/uadk_prov_digest.c | 68 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+)
diff --git a/src/uadk_prov_digest.c b/src/uadk_prov_digest.c index 081488e..c75b444 100644 --- a/src/uadk_prov_digest.c +++ b/src/uadk_prov_digest.c @@ -510,6 +510,49 @@ clear: return ret; }
+static int uadk_digest_digest(struct digest_priv_ctx *priv, const void *data, size_t data_len, + 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 = data_len; + uadk_memcpy(priv->data, data, data_len); + + 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 UADK_DIGEST_FAIL; + } + + if (op.job == NULL) { + ret = uadk_do_digest_sync(priv); + if (!ret) + goto uadk_do_digest_err; + } else { + ret = uadk_do_digest_async(priv, &op); + if (!ret) + goto uadk_do_digest_err; + } + memcpy(digest, priv->req.out, priv->req.out_bytes); + + return UADK_DIGEST_SUCCESS; + +uadk_do_digest_err: + fprintf(stderr, "do sec single block digest failed.\n"); + async_clear_async_event_notification(); + return ret; +} + static int uadk_digest_cleanup(struct digest_priv_ctx *priv) { if (priv->sess) { @@ -627,6 +670,29 @@ static int uadk_prov_final(void *dctx, unsigned char *out, return UADK_DIGEST_SUCCESS; }
+static int uadk_prov_digest(void *dctx, const unsigned char *in, size_t inl, + unsigned char *out, size_t *outl, size_t outsz) +{ + struct digest_priv_ctx *priv = (struct digest_priv_ctx *)dctx; + int ret; + + if (!dctx || !in || !out) { + fprintf(stderr, "CTX or input or output data is NULL.\n"); + return UADK_DIGEST_FAIL; + } + + if (outsz > 0) { + ret = uadk_digest_digest(priv, in, inl, out); + if (!ret) + return ret; + } + + if (unlikely(outl != NULL)) + *outl = priv->md_size; + + return UADK_DIGEST_SUCCESS; +} + void uadk_prov_destroy_digest(void) { pthread_mutex_lock(&digest_mutex); @@ -642,6 +708,7 @@ 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_digest_fn uadk_prov_digest; static OSSL_FUNC_digest_gettable_params_fn uadk_prov_gettable_params;
@@ -674,6 +741,7 @@ const OSSL_DISPATCH uadk_##name##_functions[] = { \ { 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_DIGEST, (void (*)(void))uadk_prov_digest }, \ { OSSL_FUNC_DIGEST_GET_PARAMS, \ (void (*)(void))uadk_##name##_get_params }, \ { OSSL_FUNC_DIGEST_GETTABLE_PARAMS, \
From: Chenghai Huang huangchenghai2@huawei.com
The input pointer of the external interface is insecure. Null pointer verification is added.
Signed-off-by: Chenghai Huang huangchenghai2@huawei.com Signed-off-by: JiangShui Yang yangjiangshui@h-partners.com --- src/uadk_prov_digest.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/src/uadk_prov_digest.c b/src/uadk_prov_digest.c index c75b444..e7cc19e 100644 --- a/src/uadk_prov_digest.c +++ b/src/uadk_prov_digest.c @@ -615,6 +615,11 @@ static void uadk_prov_freectx(void *dctx) { struct digest_priv_ctx *priv = (struct digest_priv_ctx *)dctx;
+ if (!dctx) { + fprintf(stderr, "the CTX to be free is NULL.\n"); + return; + } + uadk_digest_cleanup(priv); OPENSSL_clear_free(priv, sizeof(*priv)); } @@ -623,6 +628,8 @@ static void *uadk_prov_dupctx(void *dctx) { struct digest_priv_ctx *in; struct digest_priv_ctx *ret; + if (!dctx) + return NULL;
in = (struct digest_priv_ctx *)dctx; ret = OPENSSL_zalloc(sizeof(struct digest_priv_ctx *)); @@ -634,14 +641,23 @@ static void *uadk_prov_dupctx(void *dctx)
static int uadk_prov_init(void *dctx, const OSSL_PARAM params[]) { - struct digest_priv_ctx *priv = - (struct digest_priv_ctx *) dctx; + struct digest_priv_ctx *priv = (struct digest_priv_ctx *)dctx; + + if (!dctx) { + fprintf(stderr, "CTX is NULL.\n"); + return UADK_DIGEST_FAIL; + }
return uadk_digest_init(priv); }
static int uadk_prov_update(void *dctx, const unsigned char *in, size_t inl) { + if (!dctx || !in) { + fprintf(stderr, "CTX or input data is NULL.\n"); + return UADK_DIGEST_FAIL; + } + return uadk_digest_update((struct digest_priv_ctx *)dctx, in, inl); }
@@ -654,10 +670,14 @@ static int uadk_prov_update(void *dctx, const unsigned char *in, size_t inl) 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; + struct digest_priv_ctx *priv = (struct digest_priv_ctx *)dctx; int ret;
+ if (!dctx || !out) { + fprintf(stderr, "CTX or output data is NULL.\n"); + return UADK_DIGEST_FAIL; + } + if (outsz > 0) { ret = uadk_digest_final(priv, out); if (!ret)
From: Chenghai Huang huangchenghai2@huawei.com
The function name and error printf is modified to differentiate error information of different functions.
Signed-off-by: Chenghai Huang huangchenghai2@huawei.com Signed-off-by: JiangShui Yang yangjiangshui@h-partners.com --- src/uadk_prov_digest.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-)
diff --git a/src/uadk_prov_digest.c b/src/uadk_prov_digest.c index e7cc19e..1974e3a 100644 --- a/src/uadk_prov_digest.c +++ b/src/uadk_prov_digest.c @@ -64,7 +64,7 @@ struct digest_prov { int pid; };
-static struct digest_prov prov; +static struct digest_prov dprov; static pthread_mutex_t digest_mutex = PTHREAD_MUTEX_INITIALIZER;
struct evp_md_ctx_st { @@ -223,12 +223,12 @@ static int uadk_digest_soft_work(struct digest_priv_ctx *priv, int len, return UADK_DIGEST_SUCCESS; }
-static int uadk_digest_env_poll(void *ctx) +static int uadk_digest_poll(void *ctx) { __u64 rx_cnt = 0; __u32 recv = 0; /* Poll one packet currently */ - int expt = 1; + __u32 expt = 1; int ret;
do { @@ -251,14 +251,14 @@ static int uadk_digest_init(struct digest_priv_ctx *priv) int ret, i;
pthread_mutex_lock(&digest_mutex); - if (prov.pid != getpid()) { + if (dprov.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_digest_env_poll); + dprov.pid = getpid(); + async_register_poll_fn(ASYNC_TASK_DIGEST, uadk_digest_poll); } pthread_mutex_unlock(&digest_mutex);
@@ -282,12 +282,15 @@ static int uadk_digest_init(struct digest_priv_ctx *priv) params.numa_id = -1; priv->setup.sched_param = ¶ms; priv->sess = wd_digest_alloc_sess(&priv->setup); - if (unlikely(!priv->sess)) + if (unlikely(!priv->sess)) { + fprintf(stderr, "uadk failed to alloc sess.\n"); return UADK_DIGEST_FAIL; + }
- priv->data = malloc(DIGEST_BLOCK_SIZE); + priv->data = OPENSSL_malloc(DIGEST_BLOCK_SIZE); if (unlikely(!priv->data)) { wd_digest_free_sess(priv->sess); + fprintf(stderr, "uadk failed to apply mem for data storage.\n"); return UADK_DIGEST_FAIL; }
@@ -336,7 +339,7 @@ static int uadk_digest_update_inner(struct digest_priv_ctx *priv, const void *da
ret = wd_do_digest_sync(priv->sess, &priv->req); if (ret) { - fprintf(stderr, "do sec digest sync failed, switch to soft digest.\n"); + fprintf(stderr, "do sec digest update failed, switch to soft digest.\n"); goto do_soft_digest; }
@@ -503,7 +506,7 @@ sync_err: ret = uadk_digest_soft_work(priv, priv->req.in_bytes, digest); } else { ret = 0; - fprintf(stderr, "do sec digest stream mode failed.\n"); + fprintf(stderr, "do sec digest final failed.\n"); } clear: async_clear_async_event_notification(); @@ -553,7 +556,7 @@ uadk_do_digest_err: return ret; }
-static int uadk_digest_cleanup(struct digest_priv_ctx *priv) +static void uadk_digest_cleanup(struct digest_priv_ctx *priv) { if (priv->sess) { wd_digest_free_sess(priv->sess); @@ -562,8 +565,6 @@ static int uadk_digest_cleanup(struct digest_priv_ctx *priv)
if (priv->data) OPENSSL_free(priv->data); - - return UADK_DIGEST_SUCCESS; }
/* some params related code is copied from OpenSSL v3.0 prov/digestcommon.h */ @@ -716,9 +717,9 @@ static int uadk_prov_digest(void *dctx, const unsigned char *in, size_t inl, void uadk_prov_destroy_digest(void) { pthread_mutex_lock(&digest_mutex); - if (prov.pid == getpid()) { + if (dprov.pid == getpid()) { wd_digest_uninit2(); - prov.pid = 0; + dprov.pid = 0; } pthread_mutex_unlock(&digest_mutex); }
From: Chenghai Huang huangchenghai2@huawei.com
Get info about the algorithm can be extracted as a separate function, improving code readability.
Signed-off-by: Chenghai Huang huangchenghai2@huawei.com Signed-off-by: JiangShui Yang yangjiangshui@h-partners.com --- src/uadk_prov_digest.c | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-)
diff --git a/src/uadk_prov_digest.c b/src/uadk_prov_digest.c index 1974e3a..9e23877 100644 --- a/src/uadk_prov_digest.c +++ b/src/uadk_prov_digest.c @@ -243,24 +243,11 @@ static int uadk_digest_poll(void *ctx) return -ETIMEDOUT; }
-static int uadk_digest_init(struct digest_priv_ctx *priv) +static int uadk_get_digest_info(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 (dprov.pid != getpid()) { - ret = wd_digest_init2(priv->alg_name, 0, 0); - if (unlikely(ret)) { - priv->switch_flag = UADK_DO_SOFT; - goto soft_init; - } - dprov.pid = getpid(); - async_register_poll_fn(ASYNC_TASK_DIGEST, uadk_digest_poll); - } - pthread_mutex_unlock(&digest_mutex); + int i;
for (i = 0; i < digest_counts; i++) { if (nid == digest_info_table[i].nid) { @@ -278,6 +265,30 @@ static int uadk_digest_init(struct digest_priv_ctx *priv) return UADK_DIGEST_FAIL; }
+ return UADK_DIGEST_SUCCESS; +} + +static int uadk_digest_init(struct digest_priv_ctx *priv) +{ + struct sched_params params = {0}; + int ret; + + pthread_mutex_lock(&digest_mutex); + if (dprov.pid != getpid()) { + ret = wd_digest_init2(priv->alg_name, 0, 0); + if (unlikely(ret)) { + priv->switch_flag = UADK_DO_SOFT; + goto soft_init; + } + dprov.pid = getpid(); + async_register_poll_fn(ASYNC_TASK_DIGEST, uadk_digest_poll); + } + pthread_mutex_unlock(&digest_mutex); + + ret = uadk_get_digest_info(priv); + if (unlikely(!ret)) + return ret; + /* Use the default numa parameters */ params.numa_id = -1; priv->setup.sched_param = ¶ms;
From: Chenghai Huang huangchenghai2@huawei.com
In the update operation, the first packet needs to combine the previous unprocessed data into a 512 KB packet for calculation.
Other data is calculated based on the maximum packet length 16M-512B of the UADK
In this way, computing resources required for copying can be omitted, a single hardware computing data volume can be increased, and a quantity of times of data sending and receiving can be reduced, so that hardware acceleration performance can be better exerted.
Signed-off-by: Chenghai Huang huangchenghai2@huawei.com Signed-off-by: JiangShui Yang yangjiangshui@h-partners.com --- src/uadk_prov_digest.c | 92 +++++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 41 deletions(-)
diff --git a/src/uadk_prov_digest.c b/src/uadk_prov_digest.c index 9e23877..3d8e1e9 100644 --- a/src/uadk_prov_digest.c +++ b/src/uadk_prov_digest.c @@ -32,17 +32,17 @@ #include "uadk_prov.h" #include "uadk_utils.h"
-#define UADK_DO_SOFT (-0xE0) -#define CTX_SYNC 0 -#define CTX_ASYNC 1 -#define CTX_NUM 2 +#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 #define UADK_DIGEST_SUCCESS 1 #define UADK_DIGEST_FAIL 0
/* The max BD data length is 16M-512B */ -#define BUF_LEN 0xFFFE00 +#define BUF_LEN 0xFFFE00
#define SM3_DIGEST_LENGTH 32 #define SM3_CBLOCK 64 @@ -316,51 +316,69 @@ soft_init: return uadk_digest_soft_init(priv); }
+static void uadk_fill_mac_buffer_len(struct digest_priv_ctx *priv) +{ + /* Sha224 and Sha384 need full length mac buffer as doing long hash */ + switch (priv->e_nid) { + case NID_sha224: + priv->req.out_bytes = (priv->req.has_next == DIGEST_DOING) ? + WD_DIGEST_SHA224_FULL_LEN : WD_DIGEST_SHA224_LEN; + break; + case NID_sha384: + priv->req.out_bytes = (priv->req.has_next == DIGEST_DOING) ? + WD_DIGEST_SHA384_FULL_LEN : WD_DIGEST_SHA384_LEN; + break; + default: + break; + } +} + static int uadk_digest_update_inner(struct digest_priv_ctx *priv, const void *data, size_t data_len) { - const unsigned char *tmpdata = (const unsigned char *)data; + unsigned char *tmpdata = (unsigned char *)data; size_t left_len = data_len; - int copy_to_bufflen; + size_t processing_len; int ret;
- /* 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; - priv->req.has_next = DIGEST_DOING; + uadk_fill_mac_buffer_len(priv);
- 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); + do { + if (left_len == data_len) { + processing_len = DIGEST_BLOCK_SIZE - priv->last_update_bufflen; + uadk_memcpy(priv->data + priv->last_update_bufflen, tmpdata, + processing_len); + + priv->req.in_bytes = DIGEST_BLOCK_SIZE; + priv->req.in = priv->data; + } else { + if (left_len > BUF_LEN) + processing_len = BUF_LEN; + else + processing_len = left_len - (left_len % DIGEST_BLOCK_SIZE); + + priv->req.in_bytes = processing_len; + priv->req.in = tmpdata; + }
- 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;
+ priv->req.out = priv->out; + left_len -= processing_len; + tmpdata += processing_len; + ret = wd_do_digest_sync(priv->sess, &priv->req); if (ret) { fprintf(stderr, "do sec digest update failed, switch to soft digest.\n"); goto do_soft_digest; } + } while (left_len > DIGEST_BLOCK_SIZE);
- 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; - } - } + priv->last_update_bufflen = left_len; + uadk_memcpy(priv->data, tmpdata, priv->last_update_bufflen);
return UADK_DIGEST_SUCCESS;
@@ -480,11 +498,7 @@ static int uadk_digest_final(struct digest_priv_ctx *priv, unsigned char *digest 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; + uadk_fill_mac_buffer_len(priv);
ret = async_setup_async_event_notification(&op); if (unlikely(!ret)) { @@ -536,11 +550,7 @@ static int uadk_digest_digest(struct digest_priv_ctx *priv, const void *data, si priv->req.in_bytes = data_len; uadk_memcpy(priv->data, data, data_len);
- 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; + uadk_fill_mac_buffer_len(priv);
ret = async_setup_async_event_notification(&op); if (unlikely(!ret)) {
From: Chenghai Huang huangchenghai2@huawei.com
The UADK can identify only the sha512-XXX algorithm name and needs to perform additional processing.
Signed-off-by: Chenghai Huang huangchenghai2@huawei.com Signed-off-by: JiangShui Yang yangjiangshui@h-partners.com --- src/uadk_prov.h | 19 ++++++++++++------- src/uadk_prov_digest.c | 21 +++++++++++++++++++-- src/uadk_prov_init.c | 4 ++++ 3 files changed, 35 insertions(+), 9 deletions(-)
diff --git a/src/uadk_prov.h b/src/uadk_prov.h index 8d1b712..e5ac61f 100644 --- a/src/uadk_prov.h +++ b/src/uadk_prov.h @@ -18,6 +18,8 @@ #ifndef UADK_PROV_H #define UADK_PROV_H
+#define FUNC_MAX_NUM 32 + /* Copy openssl/providers/implementations/include/prov/names.h */ #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" @@ -98,13 +100,16 @@ static inline OSSL_LIB_CTX *prov_libctx_of(struct uadk_prov_ctx *ctx) return ctx->libctx; }
-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[]; +extern const OSSL_DISPATCH uadk_md5_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH uadk_sm3_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH uadk_sha1_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH uadk_sha224_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH uadk_sha256_functions[FUNC_MAX_NUM]; +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_aes_128_cbc_functions[]; extern const OSSL_DISPATCH uadk_aes_192_cbc_functions[]; diff --git a/src/uadk_prov_digest.c b/src/uadk_prov_digest.c index 3d8e1e9..2266224 100644 --- a/src/uadk_prov_digest.c +++ b/src/uadk_prov_digest.c @@ -120,6 +120,10 @@ static struct digest_info digest_info_table[] = { 48, SHA_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, {NID_sha512, WD_DIGEST_NORMAL, WD_DIGEST_SHA512, 64, SHA_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_sha512_224, WD_DIGEST_NORMAL, WD_DIGEST_SHA512_224, + 28, SHA_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, + {NID_sha512_256, WD_DIGEST_NORMAL, WD_DIGEST_SHA512_256, + 32, SHA_SMALL_PACKET_OFFLOAD_THRESHOLD_DEFAULT}, };
static int uadk_digests_soft_md(struct digest_priv_ctx *priv) @@ -328,6 +332,14 @@ static void uadk_fill_mac_buffer_len(struct digest_priv_ctx *priv) priv->req.out_bytes = (priv->req.has_next == DIGEST_DOING) ? WD_DIGEST_SHA384_FULL_LEN : WD_DIGEST_SHA384_LEN; break; + case NID_sha512_224: + priv->req.out_bytes = (priv->req.has_next == DIGEST_DOING) ? + WD_DIGEST_SHA512_224_FULL_LEN : WD_DIGEST_SHA512_224_LEN; + break; + case NID_sha512_256: + priv->req.out_bytes = (priv->req.has_next == DIGEST_DOING) ? + WD_DIGEST_SHA512_256_FULL_LEN : WD_DIGEST_SHA512_256_LEN; + break; default: break; } @@ -759,8 +771,8 @@ 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) \ + char *ptr; \ + if (!ctx) \ return NULL; \ ctx->blk_size = blksize; \ ctx->md_size = mdsize; \ @@ -769,6 +781,9 @@ static void *uadk_##name##_newctx(void *provctx) \ if (ctx->soft_ctx == NULL) \ fprintf(stderr, "EVP_MD_CTX_new failed.\n"); \ strncpy(ctx->alg_name, #name, ALG_NAME_SIZE - 1); \ + ptr = strchr(ctx->alg_name, '_'); \ + if (ptr != NULL) \ + *ptr = '-'; \ return ctx; \ } \ static OSSL_FUNC_digest_get_params_fn uadk_##name##_get_params; \ @@ -798,3 +813,5 @@ 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); +UADK_PROVIDER_IMPLEMENTATION(sha512_224, NID_sha512_224, 28, 128); +UADK_PROVIDER_IMPLEMENTATION(sha512_256, NID_sha512_256, 32, 128); diff --git a/src/uadk_prov_init.c b/src/uadk_prov_init.c index 83bde5e..4a81620 100644 --- a/src/uadk_prov_init.c +++ b/src/uadk_prov_init.c @@ -57,6 +57,10 @@ const OSSL_ALGORITHM uadk_prov_digests[] = { uadk_sha384_functions, "uadk_provider sha2-384" }, { PROV_NAMES_SHA2_512, UADK_DEFAULT_PROPERTIES, uadk_sha512_functions, "uadk_provider sha2-512" }, + { "SHA2-512/224:SHA-512/224:SHA512-224", UADK_DEFAULT_PROPERTIES, + uadk_sha512_224_functions, "uadk_provider sha2-512-224" }, + { "SHA2-512/256:SHA-512/256:SHA512-256", UADK_DEFAULT_PROPERTIES, + uadk_sha512_256_functions, "uadk_provider sha2-512-256" }, { NULL, NULL, NULL } };
From: Chenghai Huang huangchenghai2@huawei.com
In the ctx copy function, the copy method of directly assigning a value through the pointer has a bug. In addition, the input parameter needs to be verified. Fix them.
Signed-off-by: Chenghai Huang huangchenghai2@huawei.com Signed-off-by: JiangShui Yang yangjiangshui@h-partners.com --- src/uadk_prov_digest.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/src/uadk_prov_digest.c b/src/uadk_prov_digest.c index 2266224..8cadbcf 100644 --- a/src/uadk_prov_digest.c +++ b/src/uadk_prov_digest.c @@ -660,16 +660,15 @@ static void uadk_prov_freectx(void *dctx)
static void *uadk_prov_dupctx(void *dctx) { - struct digest_priv_ctx *in; - struct digest_priv_ctx *ret; + struct digest_priv_ctx *in, *ret; + if (!dctx) return NULL;
in = (struct digest_priv_ctx *)dctx; - ret = OPENSSL_zalloc(sizeof(struct digest_priv_ctx *)); - - if (ret != NULL) - *ret = *in; + ret = OPENSSL_zalloc(sizeof(struct digest_priv_ctx)); + if (ret) + memcpy(ret, in, sizeof(struct digest_priv_ctx)); return ret; }
From: Chenghai Huang huangchenghai2@huawei.com
In the update operation, the first packet needs to combine the previous unprocessed data into a 512 KB packet for calculation.
Other data is calculated based on the maximum packet length (16M-512B) of the UADK
In this way, a computing resource required for copying may be omitted, and a data volume of once hardware computation may be increased, thereby reducing a quantity of times of sending and receiving data, and better exerting hardware acceleration performance.
Signed-off-by: Chenghai Huang huangchenghai2@huawei.com Signed-off-by: JiangShui Yang yangjiangshui@h-partners.com --- src/uadk_digest.c | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-)
diff --git a/src/uadk_digest.c b/src/uadk_digest.c index 7e6e3c3..dfce8a9 100644 --- a/src/uadk_digest.c +++ b/src/uadk_digest.c @@ -673,8 +673,7 @@ static int digest_update_inner(EVP_MD_CTX *ctx, const void *data, size_t data_le (struct digest_priv_ctx *)EVP_MD_CTX_md_data(ctx); const unsigned char *tmpdata = (const unsigned char *)data; size_t left_len = data_len; - int copy_to_bufflen; - int ret; + int ret, processing_len;
if (unlikely(!priv)) { fprintf(stderr, "priv get from digest ctx is NULL.\n"); @@ -684,36 +683,43 @@ static int digest_update_inner(EVP_MD_CTX *ctx, const void *data, size_t data_le digest_update_out_length(ctx); digest_set_msg_state(priv, false);
- 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); + do { + if (left_len == data_len) { + processing_len = DIGEST_BLOCK_SIZE - priv->last_update_bufflen; + uadk_memcpy(priv->data + priv->last_update_bufflen, tmpdata, + processing_len); + + priv->last_update_bufflen = DIGEST_BLOCK_SIZE; + priv->req.in_bytes = DIGEST_BLOCK_SIZE; + priv->req.in = priv->data; + } else { + if (left_len > BUF_LEN) + processing_len = BUF_LEN; + else + processing_len = left_len - (left_len % DIGEST_BLOCK_SIZE);
- 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; + priv->req.in_bytes = processing_len; + priv->req.in = tmpdata; + }
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; + left_len -= processing_len; + tmpdata += processing_len; + 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; } + } while (left_len > DIGEST_BLOCK_SIZE);
- 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; - } - } + priv->last_update_bufflen = left_len; + uadk_memcpy(priv->data, tmpdata, priv->last_update_bufflen);
return 1; do_soft_digest:
Add core bio method for uadk_provider to correctly deal with file IO, otherwise the fseek() will be suspended.
Error log: [...] in lseek64 () from /usr/lib64/libc.so.6 [...] in _IO_file_seekoff () from /usr/lib64/libc.so.6 [...] in fseek () from /usr/lib64/libc.so.6 [...] in file_ctrl () from /usr/lib64/libcrypto.so.3 [...] in BIO_ctrl () from /usr/lib64/libcrypto.so.3 [...] in decoder_process () from /usr/lib64/libcrypto.so.3 [...] in OSSL_DECODER_from_bio () from /usr/lib64/libcrypto.so.3 [...] in file_load () from /usr/lib64/libcrypto.so.3 [...] in OSSL_STORE_load () from /usr/lib64/libcrypto.so.3 [...] in load_key_certs_crls_suppress () [...] in load_key_certs_crls () [...] in load_key () [...] in dgst_main () [...] in do_cmd () [...] in main ()
Signed-off-by: Zhiqi Song songzhiqi1@huawei.com Signed-off-by: JiangShui Yang yangjiangshui@h-partners.com --- src/Makefile.am | 3 +- src/uadk_prov.h | 20 +++- src/uadk_prov_bio.c | 265 +++++++++++++++++++++++++++++++++++++++++++ src/uadk_prov_bio.h | 34 ++++++ src/uadk_prov_init.c | 69 +++++++++-- 5 files changed, 376 insertions(+), 15 deletions(-) create mode 100644 src/uadk_prov_bio.c create mode 100644 src/uadk_prov_bio.h
diff --git a/src/Makefile.am b/src/Makefile.am index 5911edb..fe57b9d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -62,7 +62,8 @@ endif #WD_KAE
uadk_provider_la_SOURCES=uadk_prov_init.c uadk_async.c uadk_utils.c \ uadk_prov_digest.c uadk_prov_cipher.c \ - uadk_prov_rsa.c uadk_prov_dh.c + uadk_prov_rsa.c uadk_prov_dh.c \ + uadk_prov_bio.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 e5ac61f..508f113 100644 --- a/src/uadk_prov.h +++ b/src/uadk_prov.h @@ -88,10 +88,26 @@ struct ossl_provider_st { const OSSL_DISPATCH *dispatch; };
-struct uadk_prov_ctx { +typedef struct bio_method_st { + int type; + char *name; + int (*bwrite)(BIO *bio, const char *data, size_t datal, size_t *written); + int (*bwrite_old)(BIO *bio, const char *data, int datal); + int (*bread)(BIO *bio, char *data, size_t datal, size_t *read); + int (*bread_old)(BIO *bio, char *data, int datal); + int (*bputs)(BIO *bio, const char *buf); + int (*bgets)(BIO *bio, char *buf, int size); + long (*ctrl)(BIO *bio, int cmd, long larg, void *parg); + int (*create)(BIO *bio); + int (*destroy)(BIO *bio); + long (*callback_ctrl)(BIO *bio, int cmd, BIO_info_cb *fp); +} UADK_BIO_METHOD; + +typedef struct uadk_prov_ctx { const OSSL_CORE_HANDLE *handle; OSSL_LIB_CTX *libctx; -}; + UADK_BIO_METHOD *corebiometh; +} UADK_PROV_CTX;
static inline OSSL_LIB_CTX *prov_libctx_of(struct uadk_prov_ctx *ctx) { diff --git a/src/uadk_prov_bio.c b/src/uadk_prov_bio.c new file mode 100644 index 0000000..09383aa --- /dev/null +++ b/src/uadk_prov_bio.c @@ -0,0 +1,265 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ +#include <assert.h> +#include <openssl/core_dispatch.h> +#include <openssl/bio.h> +#include "uadk_prov_bio.h" + +/* Functions provided by bio */ +static OSSL_FUNC_BIO_new_file_fn *c_bio_new_file; +static OSSL_FUNC_BIO_new_membuf_fn *c_bio_new_membuf; +static OSSL_FUNC_BIO_read_ex_fn *c_bio_read_ex; +static OSSL_FUNC_BIO_write_ex_fn *c_bio_write_ex; +static OSSL_FUNC_BIO_gets_fn *c_bio_gets; +static OSSL_FUNC_BIO_puts_fn *c_bio_puts; +static OSSL_FUNC_BIO_ctrl_fn *c_bio_ctrl; +static OSSL_FUNC_BIO_up_ref_fn *c_bio_up_ref; +static OSSL_FUNC_BIO_free_fn *c_bio_free; +static OSSL_FUNC_BIO_vprintf_fn *c_bio_vprintf; + +int ossl_prov_bio_from_dispatch(const OSSL_DISPATCH *fns) +{ + for (fns; fns->function_id != 0; fns++) { + switch (fns->function_id) { + case OSSL_FUNC_BIO_NEW_FILE: + if (c_bio_new_file == NULL) + c_bio_new_file = OSSL_FUNC_BIO_new_file(fns); + break; + case OSSL_FUNC_BIO_NEW_MEMBUF: + if (c_bio_new_membuf == NULL) + c_bio_new_membuf = OSSL_FUNC_BIO_new_membuf(fns); + break; + case OSSL_FUNC_BIO_READ_EX: + if (c_bio_read_ex == NULL) + c_bio_read_ex = OSSL_FUNC_BIO_read_ex(fns); + break; + case OSSL_FUNC_BIO_WRITE_EX: + if (c_bio_write_ex == NULL) + c_bio_write_ex = OSSL_FUNC_BIO_write_ex(fns); + break; + case OSSL_FUNC_BIO_GETS: + if (c_bio_gets == NULL) + c_bio_gets = OSSL_FUNC_BIO_gets(fns); + break; + case OSSL_FUNC_BIO_PUTS: + if (c_bio_puts == NULL) + c_bio_puts = OSSL_FUNC_BIO_puts(fns); + break; + case OSSL_FUNC_BIO_CTRL: + if (c_bio_ctrl == NULL) + c_bio_ctrl = OSSL_FUNC_BIO_ctrl(fns); + break; + case OSSL_FUNC_BIO_UP_REF: + if (c_bio_up_ref == NULL) + c_bio_up_ref = OSSL_FUNC_BIO_up_ref(fns); + break; + case OSSL_FUNC_BIO_FREE: + if (c_bio_free == NULL) + c_bio_free = OSSL_FUNC_BIO_free(fns); + break; + case OSSL_FUNC_BIO_VPRINTF: + if (c_bio_vprintf == NULL) + c_bio_vprintf = OSSL_FUNC_BIO_vprintf(fns); + break; + } + } + + return 1; +} + +OSSL_CORE_BIO *ossl_prov_bio_new_file(const char *filename, const char *mode) +{ + if (c_bio_new_file == NULL) + return NULL; + + return c_bio_new_file(filename, mode); +} + +OSSL_CORE_BIO *ossl_prov_bio_new_membuf(const char *filename, int len) +{ + if (c_bio_new_membuf == NULL) + return NULL; + + return c_bio_new_membuf(filename, len); +} + +int ossl_prov_bio_read_ex(OSSL_CORE_BIO *bio, void *data, size_t data_len, + size_t *bytes_read) +{ + if (c_bio_read_ex == NULL) + return 0; + + return c_bio_read_ex(bio, data, data_len, bytes_read); +} + +int ossl_prov_bio_write_ex(OSSL_CORE_BIO *bio, const void *data, size_t data_len, + size_t *written) +{ + if (c_bio_write_ex == NULL) + return 0; + + return c_bio_write_ex(bio, data, data_len, written); +} + +int ossl_prov_bio_gets(OSSL_CORE_BIO *bio, char *buf, int size) +{ + if (c_bio_gets == NULL) + return -1; + + return c_bio_gets(bio, buf, size); +} + +int ossl_prov_bio_puts(OSSL_CORE_BIO *bio, const char *str) +{ + if (c_bio_puts == NULL) + return -1; + + return c_bio_puts(bio, str); +} + +int ossl_prov_bio_ctrl(OSSL_CORE_BIO *bio, int cmd, long num, void *ptr) +{ + if (c_bio_ctrl == NULL) + return -1; + + return c_bio_ctrl(bio, cmd, num, ptr); +} + +int ossl_prov_bio_up_ref(OSSL_CORE_BIO *bio) +{ + if (c_bio_up_ref == NULL) + return 0; + + return c_bio_up_ref(bio); +} + +int ossl_prov_bio_free(OSSL_CORE_BIO *bio) +{ + if (c_bio_free == NULL) + return 0; + + return c_bio_free(bio); +} + +int ossl_prov_bio_vprintf(OSSL_CORE_BIO *bio, const char *format, va_list ap) +{ + if (c_bio_vprintf == NULL) + return -1; + + return c_bio_vprintf(bio, format, ap); +} + +int ossl_prov_bio_printf(OSSL_CORE_BIO *bio, const char *format, ...) +{ + va_list ap; + int ret; + + va_start(ap, format); + ret = ossl_prov_bio_vprintf(bio, format, ap); + va_end(ap); + + return ret; +} + +#ifndef FIPS_MODULE +/* No direct BIO support in the FIPS module */ + +static int bio_core_read_ex(BIO *bio, char *data, size_t data_len, + size_t *bytes_read) +{ + return ossl_prov_bio_read_ex(BIO_get_data(bio), data, data_len, bytes_read); +} + +static int bio_core_write_ex(BIO *bio, const char *data, size_t data_len, + size_t *written) +{ + return ossl_prov_bio_write_ex(BIO_get_data(bio), data, data_len, written); +} + +static long bio_core_ctrl(BIO *bio, int cmd, long num, void *ptr) +{ + return ossl_prov_bio_ctrl(BIO_get_data(bio), cmd, num, ptr); +} + +static int bio_core_gets(BIO *bio, char *buf, int size) +{ + return ossl_prov_bio_gets(BIO_get_data(bio), buf, size); +} + +static int bio_core_puts(BIO *bio, const char *str) +{ + return ossl_prov_bio_puts(BIO_get_data(bio), str); +} + +static int bio_core_new(BIO *bio) +{ + BIO_set_init(bio, 1); + + return 1; +} + +BIO_METHOD *ossl_prov_ctx_get0_core_bio_method(UADK_PROV_CTX *ctx) +{ + if (ctx == NULL) + return NULL; + + return ctx->corebiometh; +} + +static int bio_core_free(BIO *bio) +{ + BIO_set_init(bio, 0); + ossl_prov_bio_free(BIO_get_data(bio)); + + return 1; +} + +BIO_METHOD *ossl_bio_prov_init_bio_method(void) +{ + BIO_METHOD *corebiometh = NULL; + + corebiometh = BIO_meth_new(BIO_TYPE_CORE_TO_PROV, "BIO to Core filter"); + if (corebiometh == NULL + || !BIO_meth_set_write_ex(corebiometh, bio_core_write_ex) + || !BIO_meth_set_read_ex(corebiometh, bio_core_read_ex) + || !BIO_meth_set_puts(corebiometh, bio_core_puts) + || !BIO_meth_set_gets(corebiometh, bio_core_gets) + || !BIO_meth_set_ctrl(corebiometh, bio_core_ctrl) + || !BIO_meth_set_create(corebiometh, bio_core_new) + || !BIO_meth_set_destroy(corebiometh, bio_core_free)) { + BIO_meth_free(corebiometh); + return NULL; + } + + return corebiometh; +} + +BIO *ossl_bio_new_from_core_bio(UADK_PROV_CTX *provctx, OSSL_CORE_BIO *corebio) +{ + BIO_METHOD *corebiometh = ossl_prov_ctx_get0_core_bio_method(provctx); + BIO *outbio; + + if (corebiometh == NULL) + return NULL; + + outbio = BIO_new(corebiometh); + if (outbio == NULL) + return NULL; + + if (!ossl_prov_bio_up_ref(corebio)) { + BIO_free(outbio); + return NULL; + } + + BIO_set_data(outbio, corebio); + + return outbio; +} +#endif diff --git a/src/uadk_prov_bio.h b/src/uadk_prov_bio.h new file mode 100644 index 0000000..2b0d044 --- /dev/null +++ b/src/uadk_prov_bio.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdarg.h> +#include <openssl/bio.h> +#include <openssl/core.h> +#include "uadk_prov.h" + +int ossl_prov_bio_from_dispatch(const OSSL_DISPATCH *fns); + +OSSL_CORE_BIO *ossl_prov_bio_new_file(const char *filename, const char *mode); +OSSL_CORE_BIO *ossl_prov_bio_new_membuf(const char *filename, int len); +int ossl_prov_bio_read_ex(OSSL_CORE_BIO *bio, void *data, size_t data_len, + size_t *bytes_read); +int ossl_prov_bio_write_ex(OSSL_CORE_BIO *bio, const void *data, size_t data_len, + size_t *written); +int ossl_prov_bio_gets(OSSL_CORE_BIO *bio, char *buf, int size); +int ossl_prov_bio_puts(OSSL_CORE_BIO *bio, const char *str); +int ossl_prov_bio_ctrl(OSSL_CORE_BIO *bio, int cmd, long num, void *ptr); +int ossl_prov_bio_up_ref(OSSL_CORE_BIO *bio); +int ossl_prov_bio_free(OSSL_CORE_BIO *bio); +int ossl_prov_bio_vprintf(OSSL_CORE_BIO *bio, const char *format, va_list ap); +int ossl_prov_bio_printf(OSSL_CORE_BIO *bio, const char *format, ...); + +BIO_METHOD *ossl_bio_prov_init_bio_method(void); +BIO *ossl_bio_new_from_core_bio(UADK_PROV_CTX *provctx, OSSL_CORE_BIO *corebio); +BIO_METHOD *ossl_prov_ctx_get0_core_bio_method(UADK_PROV_CTX *ctx); diff --git a/src/uadk_prov_init.c b/src/uadk_prov_init.c index 4a81620..f521160 100644 --- a/src/uadk_prov_init.c +++ b/src/uadk_prov_init.c @@ -19,6 +19,7 @@ #include <stdio.h> #include <string.h>
+#include <openssl/bio.h> #include <openssl/core_dispatch.h> #include <openssl/core_names.h> #include <openssl/crypto.h> @@ -27,10 +28,16 @@
#include "uadk_async.h" #include "uadk_prov.h" +#include "uadk_prov_bio.h"
static const char UADK_DEFAULT_PROPERTIES[] = "provider=uadk_provider"; static OSSL_PROVIDER *prov;
+/* Functions provided by the core */ +static OSSL_FUNC_core_gettable_params_fn *c_gettable_params; +static OSSL_FUNC_core_get_params_fn *c_get_params; +static OSSL_FUNC_core_get_libctx_fn *c_get_libctx; + /* Functions provided by the core */ static OSSL_FUNC_core_get_params_fn *c_get_params; static OSSL_FUNC_core_get_libctx_fn *c_get_libctx; @@ -199,38 +206,75 @@ static void provider_init_child_at_fork_handler(void) 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) +static int uadk_prov_ctx_set_core_bio_method(struct uadk_prov_ctx *ctx) { - struct uadk_prov_ctx *ctx; - int ret; + UADK_BIO_METHOD *core_bio;
- for (; oin->function_id != 0; oin++) { - switch (oin->function_id) { + core_bio = ossl_bio_prov_init_bio_method(); + if (core_bio == NULL) { + fprintf(stderr, "failed to set bio from dispatch\n"); + return 0; + } + + ctx->corebiometh = core_bio; + + return 1; +} + +static void ossl_prov_core_from_dispatch(const OSSL_DISPATCH *fns) +{ + for (fns; fns->function_id != 0; fns++) { + switch (fns->function_id) { + case OSSL_FUNC_CORE_GETTABLE_PARAMS: + c_gettable_params = OSSL_FUNC_core_gettable_params(fns); + break; case OSSL_FUNC_CORE_GET_PARAMS: - c_get_params = OSSL_FUNC_core_get_params(oin); + c_get_params = OSSL_FUNC_core_get_params(fns); break; case OSSL_FUNC_CORE_GET_LIBCTX: - c_get_libctx = OSSL_FUNC_core_get_libctx(oin); + c_get_libctx = OSSL_FUNC_core_get_libctx(fns); break; default: - /* Just ignore anything we don't understand */ + /* Just ignore anything we don't understand */ break; } } +} + +int OSSL_provider_init(const OSSL_CORE_HANDLE *handle, + const OSSL_DISPATCH *oin, + const OSSL_DISPATCH **out, + void **provctx) +{ + struct uadk_prov_ctx *ctx; + int ret; + + if (oin == NULL) { + fprintf(stderr, "failed to get dispatch in\n"); + return 0; + } + + (void)ossl_prov_bio_from_dispatch(oin); + ossl_prov_core_from_dispatch(oin);
/* get parameters from uadk_provider.cnf */ if (!uadk_get_params_from_core(handle)) return 0;
ctx = OPENSSL_zalloc(sizeof(*ctx)); - if (ctx == NULL) + if (ctx == NULL) { + fprintf(stderr, "failed to alloc ctx\n"); return 0; + }
+ /* Set handle from core to get core functions */ ctx->handle = handle; ctx->libctx = (OSSL_LIB_CTX *)c_get_libctx(handle); + + ret = uadk_prov_ctx_set_core_bio_method(ctx); + if (!ret) + return 0; + ret = async_module_init(); if (!ret) fprintf(stderr, "async_module_init fail!\n"); @@ -238,5 +282,6 @@ int OSSL_provider_init(const OSSL_CORE_HANDLE *handle,
*provctx = (void *)ctx; *out = uadk_dispatch_table; + return 1; }
As SM2 needs DER encode/decode API of OpenSSL, but the OpenSSL3.x does not place these APIs in externel header files currently. Therefore, we put the related APIs in independent files of uadk_provider.
Signed-off-by: Zhiqi Song songzhiqi1@huawei.com Signed-off-by: JiangShui Yang yangjiangshui@h-partners.com --- src/Makefile.am | 2 +- src/uadk_prov_der_writer.c | 236 +++++++++ src/uadk_prov_der_writer.h | 129 +++++ src/uadk_prov_packet.c | 514 ++++++++++++++++++++ src/uadk_prov_packet.h | 959 +++++++++++++++++++++++++++++++++++++ 5 files changed, 1839 insertions(+), 1 deletion(-) create mode 100644 src/uadk_prov_der_writer.c create mode 100644 src/uadk_prov_der_writer.h create mode 100644 src/uadk_prov_packet.c create mode 100644 src/uadk_prov_packet.h
diff --git a/src/Makefile.am b/src/Makefile.am index fe57b9d..b911ab5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -63,7 +63,7 @@ endif #WD_KAE uadk_provider_la_SOURCES=uadk_prov_init.c uadk_async.c uadk_utils.c \ uadk_prov_digest.c uadk_prov_cipher.c \ uadk_prov_rsa.c uadk_prov_dh.c \ - uadk_prov_bio.c + uadk_prov_bio.c uadk_prov_der_writer.c uadk_prov_packet.c \
uadk_provider_la_LDFLAGS=-module -version-number $(VERSION) uadk_provider_la_LIBADD=$(WD_LIBS) -lpthread diff --git a/src/uadk_prov_der_writer.c b/src/uadk_prov_der_writer.c new file mode 100644 index 0000000..3876d49 --- /dev/null +++ b/src/uadk_prov_der_writer.c @@ -0,0 +1,236 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdlib.h> +#include <string.h> +#include "uadk_prov_der_writer.h" + +#define DER_OID_SZ_sm2_with_SM3 10 +#define PACKET_LEN_TAG 30 + +unsigned char ossl_der_oid_sm2_with_SM3[DER_OID_SZ_sm2_with_SM3] = { + 6, 8, 0x2A, 0x81, 0x1C, 0xCF, 0x55, 0x01, 0x83, 0x75 +}; + +static int int_start_context(WPACKET *pkt, int tag) +{ + if (tag < 0) + return 1; + if (!ossl_assert(tag <= PACKET_LEN_TAG)) + return 0; + + return WPACKET_start_sub_packet(pkt); +} + +static int int_end_context(WPACKET *pkt, int tag) +{ + /* + * If someone set the flag WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH on this + * sub-packet and this sub-packet has nothing written to it, the DER length + * will not be written, and the total written size will be unchanged before + * and after WPACKET_close(). We use size1 and size2 to determine if + * anything was written, and only write our tag if it has. + * + */ + size_t size1, size2; + + if (tag < 0) + return 1; + if (!ossl_assert(tag <= PACKET_LEN_TAG)) + return 0; + + /* Context specific are normally (?) constructed */ + tag |= DER_F_CONSTRUCTED | DER_C_CONTEXT; + + return WPACKET_get_total_written(pkt, &size1) + && WPACKET_close(pkt) + && WPACKET_get_total_written(pkt, &size2) + && (size1 == size2 || WPACKET_put_bytes_u8(pkt, tag)); +} + +int ossl_DER_w_precompiled(WPACKET *pkt, int tag, + const unsigned char *precompiled, + size_t precompiled_n) +{ + return int_start_context(pkt, tag) + && WPACKET_memcpy(pkt, precompiled, precompiled_n) + && int_end_context(pkt, tag); +} + +int ossl_DER_w_boolean(WPACKET *pkt, int tag, int b) +{ + return int_start_context(pkt, tag) + && WPACKET_start_sub_packet(pkt) + && (!b || WPACKET_put_bytes_u8(pkt, 0xFF)) + && !WPACKET_close(pkt) + && !WPACKET_put_bytes_u8(pkt, DER_P_BOOLEAN) + && int_end_context(pkt, tag); +} + +int ossl_DER_w_octet_string(WPACKET *pkt, int tag, + const unsigned char *data, size_t data_n) +{ + return int_start_context(pkt, tag) + && WPACKET_start_sub_packet(pkt) + && WPACKET_memcpy(pkt, data, data_n) + && WPACKET_close(pkt) + && WPACKET_put_bytes_u8(pkt, DER_P_OCTET_STRING) + && int_end_context(pkt, tag); +} + +int ossl_DER_w_octet_string_uint32(WPACKET *pkt, int tag, uint32_t value) +{ + unsigned char tmp[4] = { 0, 0, 0, 0 }; + unsigned char *pbuf = tmp + (sizeof(tmp) - 1); + + while (value > 0) { + *pbuf-- = (value & 0xFF); + value >>= LOW_BIT_SIZE; + } + + return ossl_DER_w_octet_string(pkt, tag, tmp, sizeof(tmp)); +} + +static int int_der_w_integer(WPACKET *pkt, int tag, + int (*put_bytes)(WPACKET *pkt, const void *v, + unsigned int *top_byte), + const void *v) +{ + unsigned int top_byte = 0; + + return int_start_context(pkt, tag) + && WPACKET_start_sub_packet(pkt) + && put_bytes(pkt, v, &top_byte) + && ((top_byte & 0x80) == 0 || WPACKET_put_bytes_u8(pkt, 0)) + && WPACKET_close(pkt) + && WPACKET_put_bytes_u8(pkt, DER_P_INTEGER) + && int_end_context(pkt, tag); +} + +static int int_put_bytes_uint32(WPACKET *pkt, const void *v, + unsigned int *top_byte) +{ + const uint32_t *value = v; + uint32_t tmp = *value; + size_t n = 0; + + while (tmp != 0) { + n++; + *top_byte = (tmp & 0xFF); + tmp >>= LOW_BIT_SIZE; + } + + if (n == 0) + n = 1; + + return WPACKET_put_bytes__(pkt, *value, n); +} + +/* For integers, we only support unsigned values for now */ +int ossl_DER_w_uint32(WPACKET *pkt, int tag, uint32_t v) +{ + return int_der_w_integer(pkt, tag, int_put_bytes_uint32, &v); +} + +BN_ULONG *bn_get_words(const BIGNUM *a) +{ + return a->d; +} + +static int int_put_bytes_bn(WPACKET *pkt, const void *v, + unsigned int *top_byte) +{ + unsigned char *p = NULL; + size_t n = BN_num_bytes(v); + + /* The BIGNUM limbs are in LE order */ + *top_byte = + ((bn_get_words(v)[(n - 1) / BN_BYTES]) + >> (BYTES_TO_BITS_OFFSET * ((n - 1) % BN_BYTES))) + & 0xFF; + + if (!WPACKET_allocate_bytes(pkt, n, &p)) + return 0; + + if (p != NULL) + BN_bn2bin(v, p); + + return 1; +} + +int ossl_DER_w_bn(WPACKET *pkt, int tag, const BIGNUM *v) +{ + if (v == NULL || BN_is_negative(v)) + return 0; + + if (BN_is_zero(v)) + return ossl_DER_w_uint32(pkt, tag, 0); + + return int_der_w_integer(pkt, tag, int_put_bytes_bn, v); +} + +int ossl_DER_w_null(WPACKET *pkt, int tag) +{ + return int_start_context(pkt, tag) + && WPACKET_start_sub_packet(pkt) + && WPACKET_close(pkt) + && WPACKET_put_bytes_u8(pkt, DER_P_NULL) + && int_end_context(pkt, tag); +} + +/* Constructed things need a start and an end */ +int ossl_DER_w_begin_sequence(WPACKET *pkt, int tag) +{ + return int_start_context(pkt, tag) + && WPACKET_start_sub_packet(pkt); +} + +int ossl_DER_w_end_sequence(WPACKET *pkt, int tag) +{ + /* + * If someone set the flag WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH on this + * sub-packet and this sub-packet has nothing written to it, the DER length + * will not be written, and the total written size will be unchanged before + * and after WPACKET_close(). We use size1 and size2 to determine if + * anything was written, and only write our tag if it has. + * Because we know that int_end_context() needs to do the same check, + * we reproduce this flag if the written length was unchanged, or we will + * have an erroneous context tag. + */ + size_t size1, size2; + + return WPACKET_get_total_written(pkt, &size1) + && WPACKET_close(pkt) + && WPACKET_get_total_written(pkt, &size2) + && (size1 == size2 + ? WPACKET_set_flags(pkt, WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) + : WPACKET_put_bytes_u8(pkt, DER_F_CONSTRUCTED | DER_P_SEQUENCE)) + && int_end_context(pkt, tag); +} + +int ossl_DER_w_algorithmIdentifier_SM2_with_MD(WPACKET *pkt, int cont, + EC_KEY *ec, int mdnid) +{ + const unsigned char *precompiled = NULL; + size_t precompiled_sz = 0; + + switch (mdnid) { + case NID_sm3: + precompiled = ossl_der_oid_sm2_with_SM3; + precompiled_sz = sizeof(ossl_der_oid_sm2_with_SM3); + break; + default: + return 0; + } + + return ossl_DER_w_begin_sequence(pkt, cont) /* No parameters (yet?) */ + && ossl_DER_w_precompiled(pkt, -1, precompiled, precompiled_sz) + && ossl_DER_w_end_sequence(pkt, cont); +} diff --git a/src/uadk_prov_der_writer.h b/src/uadk_prov_der_writer.h new file mode 100644 index 0000000..39308e0 --- /dev/null +++ b/src/uadk_prov_der_writer.h @@ -0,0 +1,129 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ +#ifndef UADK_PROV_DER_WRITER_H +#define UADK_PROV_DER_WRITER_H +#include <openssl/bn.h> +#include <openssl/ec.h> +#include <openssl/obj_mac.h> +#include <openssl/types.h> +#include "uadk_prov_packet.h" +#include "uadk_utils.h" + +/* + * NOTE: X.690 numbers the identifier octet bits 1 to 8. + * We use the same numbering in comments here. + */ + +/* Well known primitive tags */ + +/* + * DER UNIVERSAL tags, occupying bits 1-5 in the DER identifier byte + * These are only valid for the UNIVERSAL class. With the other classes, + * these bits have a different meaning. + */ +#define DER_P_EOC 0 /* BER End Of Contents tag */ +#define DER_P_BOOLEAN 1 +#define DER_P_INTEGER 2 +#define DER_P_BIT_STRING 3 +#define DER_P_OCTET_STRING 4 +#define DER_P_NULL 5 +#define DER_P_OBJECT 6 +#define DER_P_OBJECT_DESCRIPTOR 7 +#define DER_P_EXTERNAL 8 +#define DER_P_REAL 9 +#define DER_P_ENUMERATED 10 +#define DER_P_UTF8STRING 12 +#define DER_P_SEQUENCE 16 +#define DER_P_SET 17 +#define DER_P_NUMERICSTRING 18 +#define DER_P_PRINTABLESTRING 19 +#define DER_P_T61STRING 20 +#define DER_P_VIDEOTEXSTRING 21 +#define DER_P_IA5STRING 22 +#define DER_P_UTCTIME 23 +#define DER_P_GENERALIZEDTIME 24 +#define DER_P_GRAPHICSTRING 25 +#define DER_P_ISO64STRING 26 +#define DER_P_GENERALSTRING 27 +#define DER_P_UNIVERSALSTRING 28 +#define DER_P_BMPSTRING 30 + +/* DER Flags, occupying bit 6 in the DER identifier byte */ +#define DER_F_PRIMITIVE 0x00 +#define DER_F_CONSTRUCTED 0x20 + +/* DER classes tags, occupying bits 7-8 in the DER identifier byte */ +#define DER_C_UNIVERSAL 0x00 +#define DER_C_APPLICATION 0x40 +#define DER_C_CONTEXT 0x80 +#define DER_C_PRIVATE 0xC0 + +/* + * Run-time constructors. + * + * They all construct DER backwards, so care should be taken to use them + * that way. + */ + +/* This can be used for all items that don't have a context */ +#define DER_NO_CONTEXT -1 + +struct bignum_st { + BN_ULONG *d; /* Pointer to an array of 'BN_BITS2' bit chunks. */ + int top; /* Index of last used d +1. */ + /* The next are internal book keeping for bn_expand. */ + int dmax; /* Size of the d array. */ + int neg; /* one if the number is negative */ + int flags; +}; + +struct ec_key_st { + const EC_KEY_METHOD *meth; + ENGINE *engine; + int version; + EC_GROUP *group; + EC_POINT *pub_key; + BIGNUM *priv_key; + unsigned int enc_flag; + point_conversion_form_t conv_form; + int references; + int flags; +#ifndef FIPS_MODULE + CRYPTO_EX_DATA ex_data; +#endif + void *lock; + OSSL_LIB_CTX *libctx; + char *propq; + + /* Provider data */ + size_t dirty_cnt; /* If any key material changes, increment this */ +}; + +int ossl_DER_w_precompiled(WPACKET *pkt, int tag, + const unsigned char *precompiled, + size_t precompiled_n); + +int ossl_DER_w_boolean(WPACKET *pkt, int tag, int b); +int ossl_DER_w_uint32(WPACKET *pkt, int tag, uint32_t v); +int ossl_DER_w_bn(WPACKET *pkt, int tag, const BIGNUM *v); +int ossl_DER_w_null(WPACKET *pkt, int tag); +int ossl_DER_w_octet_string(WPACKET *pkt, int tag, + const unsigned char *data, size_t data_n); +int ossl_DER_w_octet_string_uint32(WPACKET *pkt, int tag, uint32_t value); + +/* + * All constructors for constructed elements have a begin and a end function + */ +int ossl_DER_w_begin_sequence(WPACKET *pkt, int tag); +int ossl_DER_w_end_sequence(WPACKET *pkt, int tag); + +int ossl_DER_w_algorithmIdentifier_SM2_with_MD(WPACKET *pkt, int cont, + EC_KEY *ec, int mdnid); +#endif diff --git a/src/uadk_prov_packet.c b/src/uadk_prov_packet.c new file mode 100644 index 0000000..3c84de8 --- /dev/null +++ b/src/uadk_prov_packet.c @@ -0,0 +1,514 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ +#include <openssl/err.h> +#include "uadk_prov_packet.h" + +#define DEFAULT_BUF_SIZE 256 +#define REF_SIZE_LIMIT 2 + +#define GETBUF(p) (((p)->staticbuf != NULL) \ + ? (p)->staticbuf \ + : ((p)->buf != NULL \ + ? (unsigned char *)(p)->buf->data \ + : NULL)) + +int WPACKET_allocate_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes) +{ + if (!WPACKET_reserve_bytes(pkt, len, allocbytes)) + return 0; + + pkt->written += len; + pkt->curr += len; + return 1; +} + +int WPACKET_sub_allocate_bytes__(WPACKET *pkt, size_t len, + unsigned char **allocbytes, size_t lenbytes) +{ + if (!WPACKET_start_sub_packet_len__(pkt, lenbytes) + || !WPACKET_allocate_bytes(pkt, len, allocbytes) + || !WPACKET_close(pkt)) + return 0; + + return 1; +} + +int WPACKET_reserve_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes) +{ + size_t newlen; + size_t reflen; + + /* Internal API, so should not fail */ + if (!ossl_assert(pkt->subs != NULL && len != 0)) + return 0; + + if (pkt->maxsize - pkt->written < len) + return 0; + + if (pkt->buf != NULL && (pkt->buf->length - pkt->written < len)) { + reflen = (len > pkt->buf->length) ? len : pkt->buf->length; + if (reflen > SIZE_MAX / REF_SIZE_LIMIT) { + newlen = SIZE_MAX; + } else { + newlen = reflen * REF_SIZE_LIMIT; + if (newlen < DEFAULT_BUF_SIZE) + newlen = DEFAULT_BUF_SIZE; + } + + if (BUF_MEM_grow(pkt->buf, newlen) == 0) + return 0; + } + + if (allocbytes != NULL) { + *allocbytes = WPACKET_get_curr(pkt); + if (pkt->endfirst && *allocbytes != NULL) + *allocbytes -= len; + } + + return 1; +} + +int WPACKET_sub_reserve_bytes__(WPACKET *pkt, size_t len, + unsigned char **allocbytes, size_t lenbytes) +{ + if (pkt->endfirst && lenbytes > 0) + return 0; + + if (!WPACKET_reserve_bytes(pkt, lenbytes + len, allocbytes)) + return 0; + + if (*allocbytes != NULL) + *allocbytes += lenbytes; + + return 1; +} + +static size_t maxmaxsize(size_t lenbytes) +{ + if (lenbytes >= sizeof(size_t) || lenbytes == 0) + return SIZE_MAX; + + return ((size_t)1 << (lenbytes * BYTES_TO_BITS_OFFSET)) - 1 + lenbytes; +} + +static int wpacket_intern_init_len(WPACKET *pkt, size_t lenbytes) +{ + unsigned char *lenchars; + + pkt->curr = 0; + pkt->written = 0; + + pkt->subs = OPENSSL_zalloc(sizeof(*pkt->subs)); + if (pkt->subs == NULL) { + ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (lenbytes == 0) + return 1; + + pkt->subs->pwritten = lenbytes; + pkt->subs->lenbytes = lenbytes; + + if (!WPACKET_allocate_bytes(pkt, lenbytes, &lenchars)) { + OPENSSL_free(pkt->subs); + pkt->subs = NULL; + return 0; + } + pkt->subs->packet_len = 0; + + return 1; +} + +int WPACKET_init_static_len(WPACKET *pkt, unsigned char *buf, size_t len, + size_t lenbytes) +{ + size_t max = maxmaxsize(lenbytes); + + /* Internal API, so should not fail */ + if (!ossl_assert(buf != NULL && len > 0)) + return 0; + + pkt->staticbuf = buf; + pkt->buf = NULL; + pkt->maxsize = (max < len) ? max : len; + pkt->endfirst = 0; + + return wpacket_intern_init_len(pkt, lenbytes); +} + +int WPACKET_init_der(WPACKET *pkt, unsigned char *buf, size_t len) +{ + /* Internal API, so should not fail */ + if (!ossl_assert(buf != NULL && len > 0)) + return 0; + + pkt->staticbuf = buf; + pkt->buf = NULL; + pkt->maxsize = len; + pkt->endfirst = 1; + + return wpacket_intern_init_len(pkt, 0); +} + +int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes) +{ + /* Internal API, so should not fail */ + if (!ossl_assert(buf != NULL)) + return 0; + + pkt->staticbuf = NULL; + pkt->buf = buf; + pkt->maxsize = maxmaxsize(lenbytes); + pkt->endfirst = 0; + + return wpacket_intern_init_len(pkt, lenbytes); +} + +int WPACKET_init(WPACKET *pkt, BUF_MEM *buf) +{ + return WPACKET_init_len(pkt, buf, 0); +} + +int WPACKET_init_null(WPACKET *pkt, size_t lenbytes) +{ + pkt->staticbuf = NULL; + pkt->buf = NULL; + pkt->maxsize = maxmaxsize(lenbytes); + pkt->endfirst = 0; + + return wpacket_intern_init_len(pkt, 0); +} + +int WPACKET_init_null_der(WPACKET *pkt) +{ + pkt->staticbuf = NULL; + pkt->buf = NULL; + pkt->maxsize = SIZE_MAX; + pkt->endfirst = 1; + + return wpacket_intern_init_len(pkt, 0); +} + +int WPACKET_set_flags(WPACKET *pkt, unsigned int flags) +{ + /* Internal API, so should not fail */ + if (!ossl_assert(pkt->subs != NULL)) + return 0; + + pkt->subs->flags = flags; + + return 1; +} + +/* Store the |value| of length |len| at location |data| */ +static int put_value(unsigned char *data, uint64_t value, size_t len) +{ + if (data == NULL) + return 1; + + for (data += len - 1; len > 0; len--) { + *data = (unsigned char)(value & 0xff); + data--; + value >>= LOW_BIT_SIZE; + } + + /* Check whether we could fit the value in the assigned number of bytes */ + if (value > 0) + return 0; + + return 1; +} + +/* + * Internal helper function used by WPACKET_close(), WPACKET_finish() and + * WPACKET_fill_lengths() to close a sub-packet and write out its length if + * necessary. If |doclose| is 0 then it goes through the motions of closing + * (i.e. it fills in all the lengths), but doesn't actually close anything. + */ +static int wpacket_intern_close(WPACKET *pkt, WPACKET_SUB *sub, int doclose) +{ + size_t packlen = pkt->written - sub->pwritten; + + if (packlen == 0 + && (sub->flags & WPACKET_FLAGS_NON_ZERO_LENGTH) != 0) + return 0; + + if (packlen == 0 + && sub->flags & WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) { + /* We can't handle this case. Return an error */ + if (!doclose) + return 0; + + /* Deallocate any bytes allocated for the length of the WPACKET */ + if ((pkt->curr - sub->lenbytes) == sub->packet_len) { + pkt->written -= sub->lenbytes; + pkt->curr -= sub->lenbytes; + } + + /* Don't write out the packet length */ + sub->packet_len = 0; + sub->lenbytes = 0; + } + + /* Write out the WPACKET length if needed */ + if (sub->lenbytes > 0) { + unsigned char *buf = GETBUF(pkt); + + if (buf != NULL + && !put_value(&buf[sub->packet_len], packlen, + sub->lenbytes)) + return 0; + } else if (pkt->endfirst && sub->parent != NULL + && (packlen != 0 || (sub->flags + & WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) == 0)) { + size_t tmplen = packlen; + size_t numlenbytes = 1; + + while ((tmplen = tmplen >> LOW_BIT_SIZE) > 0) + numlenbytes++; + if (!WPACKET_put_bytes__(pkt, packlen, numlenbytes)) + return 0; + if (packlen > 0x7f) { + numlenbytes |= 0x80; + if (!WPACKET_put_bytes_u8(pkt, numlenbytes)) + return 0; + } + } + + if (doclose) { + pkt->subs = sub->parent; + OPENSSL_free(sub); + } + + return 1; +} + +int WPACKET_fill_lengths(WPACKET *pkt) +{ + WPACKET_SUB *sub; + + if (!ossl_assert(pkt->subs != NULL)) + return 0; + + for (sub = pkt->subs; sub != NULL; sub = sub->parent) { + if (!wpacket_intern_close(pkt, sub, 0)) + return 0; + } + + return 1; +} + +int WPACKET_close(WPACKET *pkt) +{ + /* + * Internal API, so should not fail - but we do negative testing of this + * so no assert (otherwise the tests fail) + */ + if (pkt->subs == NULL || pkt->subs->parent == NULL) + return 0; + + return wpacket_intern_close(pkt, pkt->subs, 1); +} + +int WPACKET_finish(WPACKET *pkt) +{ + int ret; + + /* + * Internal API, so should not fail - but we do negative testing of this + * so no assert (otherwise the tests fail) + */ + if (pkt->subs == NULL || pkt->subs->parent != NULL) + return 0; + + ret = wpacket_intern_close(pkt, pkt->subs, 1); + if (ret) { + OPENSSL_free(pkt->subs); + pkt->subs = NULL; + } + + return ret; +} + +int WPACKET_start_sub_packet_len__(WPACKET *pkt, size_t lenbytes) +{ + WPACKET_SUB *sub; + unsigned char *lenchars; + + /* Internal API, so should not fail */ + if (!ossl_assert(pkt->subs != NULL)) + return 0; + + /* We don't support lenbytes greater than 0 when doing endfirst writing */ + if (lenbytes > 0 && pkt->endfirst) + return 0; + + sub = OPENSSL_zalloc(sizeof(*sub)); + if (sub == NULL) { + ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE); + return 0; + } + + sub->parent = pkt->subs; + pkt->subs = sub; + sub->pwritten = pkt->written + lenbytes; + sub->lenbytes = lenbytes; + + if (lenbytes == 0) { + sub->packet_len = 0; + return 1; + } + + sub->packet_len = pkt->written; + + if (!WPACKET_allocate_bytes(pkt, lenbytes, &lenchars)) + return 0; + + return 1; +} + +int WPACKET_start_sub_packet(WPACKET *pkt) +{ + return WPACKET_start_sub_packet_len__(pkt, 0); +} + +int WPACKET_put_bytes__(WPACKET *pkt, uint64_t val, size_t size) +{ + unsigned char *data; + + /* Internal API, so should not fail */ + if (!ossl_assert(size <= sizeof(uint64_t)) + || !WPACKET_allocate_bytes(pkt, size, &data) + || !put_value(data, val, size)) + return 0; + + return 1; +} + +int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize) +{ + WPACKET_SUB *sub; + size_t lenbytes; + + /* Internal API, so should not fail */ + if (!ossl_assert(pkt->subs != NULL)) + return 0; + + /* Find the WPACKET_SUB for the top level */ + for (sub = pkt->subs; sub->parent != NULL; sub = sub->parent) + continue; + + lenbytes = sub->lenbytes; + if (lenbytes == 0) + lenbytes = sizeof(pkt->maxsize); + + if (maxmaxsize(lenbytes) < maxsize || maxsize < pkt->written) + return 0; + + pkt->maxsize = maxsize; + + return 1; +} + +int WPACKET_memset(WPACKET *pkt, int ch, size_t len) +{ + unsigned char *dest; + + if (len == 0) + return 1; + + if (!WPACKET_allocate_bytes(pkt, len, &dest)) + return 0; + + if (dest != NULL) + memset(dest, ch, len); + + return 1; +} + +int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len) +{ + unsigned char *dest; + + if (len == 0) + return 1; + + if (!WPACKET_allocate_bytes(pkt, len, &dest)) + return 0; + + if (dest != NULL) + memcpy(dest, src, len); + + return 1; +} + +int WPACKET_sub_memcpy__(WPACKET *pkt, const void *src, size_t len, + size_t lenbytes) +{ + if (!WPACKET_start_sub_packet_len__(pkt, lenbytes) + || !WPACKET_memcpy(pkt, src, len) + || !WPACKET_close(pkt)) + return 0; + + return 1; +} + +int WPACKET_get_total_written(WPACKET *pkt, size_t *written) +{ + /* Internal API, so should not fail */ + if (!ossl_assert(written != NULL)) + return 0; + + *written = pkt->written; + + return 1; +} + +int WPACKET_get_length(WPACKET *pkt, size_t *len) +{ + /* Internal API, so should not fail */ + if (!ossl_assert(pkt->subs != NULL && len != NULL)) + return 0; + + *len = pkt->written - pkt->subs->pwritten; + + return 1; +} + +unsigned char *WPACKET_get_curr(WPACKET *pkt) +{ + unsigned char *buf = GETBUF(pkt); + + if (buf == NULL) + return NULL; + + if (pkt->endfirst) + return buf + pkt->maxsize - pkt->curr; + + return buf + pkt->curr; +} + +int WPACKET_is_null_buf(WPACKET *pkt) +{ + return pkt->buf == NULL && pkt->staticbuf == NULL; +} + +void WPACKET_cleanup(WPACKET *pkt) +{ + WPACKET_SUB *sub, *parent; + + for (sub = pkt->subs; sub != NULL; sub = parent) { + parent = sub->parent; + OPENSSL_free(sub); + } + + pkt->subs = NULL; +} diff --git a/src/uadk_prov_packet.h b/src/uadk_prov_packet.h new file mode 100644 index 0000000..aabd042 --- /dev/null +++ b/src/uadk_prov_packet.h @@ -0,0 +1,959 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef UADK_PROV_PACKET_H +#define UADK_PROV_PACKET_H + +#include <string.h> +#include <openssl/bn.h> +#include <openssl/buffer.h> +#include <openssl/crypto.h> +#include <openssl/e_os2.h> + +#ifdef NDEBUG +#define ossl_assert(x) ((x) != 0) +#else +__owur static ossl_inline int ossl_assert_int(int expr, const char *exprstr, + const char *file, int line) +{ + if (!expr) + OPENSSL_die(exprstr, file, line); + + return expr; +} + +#define ossl_assert(x) ossl_assert_int((x) != 0, "Assertion failed: "#x, \ + __FILE__, __LINE__) + +#endif + +#define LOW_BIT_SIZE 8 +#define BYTES_TO_BITS_OFFSET 8 + +typedef struct { + /* Pointer to where we are currently reading from */ + const unsigned char *curr; + /* Number of bytes remaining */ + size_t remaining; +} PACKET; + +/* Internal unchecked shorthand; don't use outside this file. */ +static ossl_inline void packet_forward(PACKET *pkt, size_t len) +{ + pkt->curr += len; + pkt->remaining -= len; +} + +/* + * Returns the number of bytes remaining to be read in the PACKET + */ +static ossl_inline size_t PACKET_remaining(const PACKET *pkt) +{ + return pkt->remaining; +} + +/* + * Returns a pointer to the first byte after the packet data. + * Useful for integrating with non-PACKET parsing code. + * Specifically, we use PACKET_end() to verify that a d2i_... call + * has consumed the entire packet contents. + */ +static ossl_inline const unsigned char *PACKET_end(const PACKET *pkt) +{ + return pkt->curr + pkt->remaining; +} + +/* + * Returns a pointer to the PACKET's current position. + * For use in non-PACKETized APIs. + */ +static ossl_inline const unsigned char *PACKET_data(const PACKET *pkt) +{ + return pkt->curr; +} + +/* + * Initialise a PACKET with |len| bytes held in |buf|. This does not make a + * copy of the data so |buf| must be present for the whole time that the PACKET + * is being used. + */ +__owur static ossl_inline int PACKET_buf_init(PACKET *pkt, + const unsigned char *buf, + size_t len) +{ + /* Sanity check for negative values. */ + if (len > (size_t)(SIZE_MAX / 2)) + return 0; + + pkt->curr = buf; + pkt->remaining = len; + return 1; +} + +/* Initialize a PACKET to hold zero bytes. */ +static ossl_inline void PACKET_null_init(PACKET *pkt) +{ + pkt->curr = NULL; + pkt->remaining = 0; +} + +/* + * Returns 1 if the packet has length |num| and its contents equal the |num| + * bytes read from |ptr|. Returns 0 otherwise (lengths or contents not equal). + * If lengths are equal, performs the comparison in constant time. + */ +__owur static ossl_inline int PACKET_equal(const PACKET *pkt, const void *ptr, + size_t num) +{ + if (PACKET_remaining(pkt) != num) + return 0; + return CRYPTO_memcmp(pkt->curr, ptr, num) == 0; +} + +/* + * Peek ahead and initialize |subpkt| with the next |len| bytes read from |pkt|. + * Data is not copied: the |subpkt| packet will share its underlying buffer with + * the original |pkt|, so data wrapped by |pkt| must outlive the |subpkt|. + */ +__owur static ossl_inline int PACKET_peek_sub_packet(const PACKET *pkt, + PACKET *subpkt, size_t len) +{ + if (PACKET_remaining(pkt) < len) + return 0; + + return PACKET_buf_init(subpkt, pkt->curr, len); +} + +/* + * Initialize |subpkt| with the next |len| bytes read from |pkt|. Data is not + * copied: the |subpkt| packet will share its underlying buffer with the + * original |pkt|, so data wrapped by |pkt| must outlive the |subpkt|. + */ +__owur static ossl_inline int PACKET_get_sub_packet(PACKET *pkt, + PACKET *subpkt, size_t len) +{ + if (!PACKET_peek_sub_packet(pkt, subpkt, len)) + return 0; + + packet_forward(pkt, len); + + return 1; +} + +/* + * Peek ahead at 2 bytes in network order from |pkt| and store the value in + * |*data| + */ +__owur static ossl_inline int PACKET_peek_net_2(const PACKET *pkt, + unsigned int *data) +{ + if (PACKET_remaining(pkt) < 2) + return 0; + + *data = ((unsigned int)(*pkt->curr)) << 8; + *data |= *(pkt->curr + 1); + + return 1; +} + +/* Equivalent of n2s */ +/* Get 2 bytes in network order from |pkt| and store the value in |*data| */ +__owur static ossl_inline int PACKET_get_net_2(PACKET *pkt, unsigned int *data) +{ + if (!PACKET_peek_net_2(pkt, data)) + return 0; + + packet_forward(pkt, 2); + + return 1; +} + +/* Same as PACKET_get_net_2() but for a size_t */ +__owur static ossl_inline int PACKET_get_net_2_len(PACKET *pkt, size_t *data) +{ + unsigned int i; + int ret = PACKET_get_net_2(pkt, &i); + + if (ret) + *data = (size_t)i; + + return ret; +} + +/* + * Peek ahead at 3 bytes in network order from |pkt| and store the value in + * |*data| + */ +__owur static ossl_inline int PACKET_peek_net_3(const PACKET *pkt, + unsigned long *data) +{ + if (PACKET_remaining(pkt) < 3) + return 0; + + *data = ((unsigned long)(*pkt->curr)) << 16; + *data |= ((unsigned long)(*(pkt->curr + 1))) << 8; + *data |= *(pkt->curr + 2); + + return 1; +} + +/* Equivalent of n2l3 */ +/* Get 3 bytes in network order from |pkt| and store the value in |*data| */ +__owur static ossl_inline int PACKET_get_net_3(PACKET *pkt, unsigned long *data) +{ + if (!PACKET_peek_net_3(pkt, data)) + return 0; + + packet_forward(pkt, 3); + + return 1; +} + +/* Same as PACKET_get_net_3() but for a size_t */ +__owur static ossl_inline int PACKET_get_net_3_len(PACKET *pkt, size_t *data) +{ + unsigned long i; + int ret = PACKET_get_net_3(pkt, &i); + + if (ret) + *data = (size_t)i; + + return ret; +} + +/* + * Peek ahead at 4 bytes in network order from |pkt| and store the value in + * |*data| + */ +__owur static ossl_inline int PACKET_peek_net_4(const PACKET *pkt, + unsigned long *data) +{ + if (PACKET_remaining(pkt) < 4) + return 0; + + *data = ((unsigned long)(*pkt->curr)) << 24; + *data |= ((unsigned long)(*(pkt->curr + 1))) << 16; + *data |= ((unsigned long)(*(pkt->curr + 2))) << 8; + *data |= *(pkt->curr + 3); + + return 1; +} + +/* + * Peek ahead at 8 bytes in network order from |pkt| and store the value in + * |*data| + */ +__owur static ossl_inline int PACKET_peek_net_8(const PACKET *pkt, + uint64_t *data) +{ + if (PACKET_remaining(pkt) < 8) + return 0; + + *data = ((uint64_t)(*pkt->curr)) << 56; + *data |= ((uint64_t)(*(pkt->curr + 1))) << 48; + *data |= ((uint64_t)(*(pkt->curr + 2))) << 40; + *data |= ((uint64_t)(*(pkt->curr + 3))) << 32; + *data |= ((uint64_t)(*(pkt->curr + 4))) << 24; + *data |= ((uint64_t)(*(pkt->curr + 5))) << 16; + *data |= ((uint64_t)(*(pkt->curr + 6))) << 8; + *data |= *(pkt->curr + 7); + + return 1; +} + +/* Equivalent of n2l */ +/* Get 4 bytes in network order from |pkt| and store the value in |*data| */ +__owur static ossl_inline int PACKET_get_net_4(PACKET *pkt, unsigned long *data) +{ + if (!PACKET_peek_net_4(pkt, data)) + return 0; + + packet_forward(pkt, 4); + + return 1; +} + +/* Same as PACKET_get_net_4() but for a size_t */ +__owur static ossl_inline int PACKET_get_net_4_len(PACKET *pkt, size_t *data) +{ + unsigned long i; + int ret = PACKET_get_net_4(pkt, &i); + + if (ret) + *data = (size_t)i; + + return ret; +} + +/* Get 8 bytes in network order from |pkt| and store the value in |*data| */ +__owur static ossl_inline int PACKET_get_net_8(PACKET *pkt, uint64_t *data) +{ + if (!PACKET_peek_net_8(pkt, data)) + return 0; + + packet_forward(pkt, 8); + + return 1; +} + +/* Peek ahead at 1 byte from |pkt| and store the value in |*data| */ +__owur static ossl_inline int PACKET_peek_1(const PACKET *pkt, + unsigned int *data) +{ + if (!PACKET_remaining(pkt)) + return 0; + + *data = *pkt->curr; + + return 1; +} + +/* Get 1 byte from |pkt| and store the value in |*data| */ +__owur static ossl_inline int PACKET_get_1(PACKET *pkt, unsigned int *data) +{ + if (!PACKET_peek_1(pkt, data)) + return 0; + + packet_forward(pkt, 1); + + return 1; +} + +/* Same as PACKET_get_1() but for a size_t */ +__owur static ossl_inline int PACKET_get_1_len(PACKET *pkt, size_t *data) +{ + unsigned int i; + int ret = PACKET_get_1(pkt, &i); + + if (ret) + *data = (size_t)i; + + return ret; +} + +/* + * Peek ahead at 4 bytes in reverse network order from |pkt| and store the value + * in |*data| + */ +__owur static ossl_inline int PACKET_peek_4(const PACKET *pkt, + unsigned long *data) +{ + if (PACKET_remaining(pkt) < 4) + return 0; + + *data = *pkt->curr; + *data |= ((unsigned long)(*(pkt->curr + 1))) << 8; + *data |= ((unsigned long)(*(pkt->curr + 2))) << 16; + *data |= ((unsigned long)(*(pkt->curr + 3))) << 24; + + return 1; +} + +/* Equivalent of c2l */ +/* + * Get 4 bytes in reverse network order from |pkt| and store the value in + * |*data| + */ +__owur static ossl_inline int PACKET_get_4(PACKET *pkt, unsigned long *data) +{ + if (!PACKET_peek_4(pkt, data)) + return 0; + + packet_forward(pkt, 4); + + return 1; +} + +/* + * Peek ahead at |len| bytes from the |pkt| and store a pointer to them in + * |*data|. This just points at the underlying buffer that |pkt| is using. The + * caller should not free this data directly (it will be freed when the + * underlying buffer gets freed + */ +__owur static ossl_inline int PACKET_peek_bytes(const PACKET *pkt, + const unsigned char **data, + size_t len) +{ + if (PACKET_remaining(pkt) < len) + return 0; + + *data = pkt->curr; + + return 1; +} + +/* + * Read |len| bytes from the |pkt| and store a pointer to them in |*data|. This + * just points at the underlying buffer that |pkt| is using. The caller should + * not free this data directly (it will be freed when the underlying buffer gets + * freed + */ +__owur static ossl_inline int PACKET_get_bytes(PACKET *pkt, + const unsigned char **data, + size_t len) +{ + if (!PACKET_peek_bytes(pkt, data, len)) + return 0; + + packet_forward(pkt, len); + + return 1; +} + +/* Peek ahead at |len| bytes from |pkt| and copy them to |data| */ +__owur static ossl_inline int PACKET_peek_copy_bytes(const PACKET *pkt, + unsigned char *data, + size_t len) +{ + if (PACKET_remaining(pkt) < len) + return 0; + + memcpy(data, pkt->curr, len); + + return 1; +} + +/* + * Read |len| bytes from |pkt| and copy them to |data|. + * The caller is responsible for ensuring that |data| can hold |len| bytes. + */ +__owur static ossl_inline int PACKET_copy_bytes(PACKET *pkt, + unsigned char *data, size_t len) +{ + if (!PACKET_peek_copy_bytes(pkt, data, len)) + return 0; + + packet_forward(pkt, len); + + return 1; +} + +/* + * Copy packet data to |dest|, and set |len| to the number of copied bytes. + * If the packet has more than |dest_len| bytes, nothing is copied. + * Returns 1 if the packet data fits in |dest_len| bytes, 0 otherwise. + * Does not forward PACKET position (because it is typically the last thing + * done with a given PACKET). + */ +__owur static ossl_inline int PACKET_copy_all(const PACKET *pkt, + unsigned char *dest, + size_t dest_len, size_t *len) +{ + if (PACKET_remaining(pkt) > dest_len) { + *len = 0; + return 0; + } + + *len = pkt->remaining; + memcpy(dest, pkt->curr, pkt->remaining); + + return 1; +} + +/* + * Copy |pkt| bytes to a newly allocated buffer and store a pointer to the + * result in |*data|, and the length in |len|. + * If |*data| is not NULL, the old data is OPENSSL_free'd. + * If the packet is empty, or malloc fails, |*data| will be set to NULL. + * Returns 1 if the malloc succeeds and 0 otherwise. + * Does not forward PACKET position (because it is typically the last thing + * done with a given PACKET). + */ +__owur static ossl_inline int PACKET_memdup(const PACKET *pkt, + unsigned char **data, size_t *len) +{ + size_t length; + + OPENSSL_free(*data); + *data = NULL; + *len = 0; + + length = PACKET_remaining(pkt); + + if (length == 0) + return 1; + + *data = OPENSSL_memdup(pkt->curr, length); + if (*data == NULL) + return 0; + + *len = length; + return 1; +} + +/* + * Read a C string from |pkt| and copy to a newly allocated, NUL-terminated + * buffer. Store a pointer to the result in |*data|. + * If |*data| is not NULL, the old data is OPENSSL_free'd. + * If the data in |pkt| does not contain a NUL-byte, the entire data is + * copied and NUL-terminated. + * Returns 1 if the malloc succeeds and 0 otherwise. + * Does not forward PACKET position (because it is typically the last thing done + * with a given PACKET). + */ +__owur static ossl_inline int PACKET_strndup(const PACKET *pkt, char **data) +{ + OPENSSL_free(*data); + + /* This will succeed on an empty packet, unless pkt->curr == NULL. */ + *data = OPENSSL_strndup((const char *)pkt->curr, PACKET_remaining(pkt)); + return (*data != NULL); +} + +/* Returns 1 if |pkt| contains at least one 0-byte, 0 otherwise. */ +static ossl_inline int PACKET_contains_zero_byte(const PACKET *pkt) +{ + return memchr(pkt->curr, 0, pkt->remaining) != NULL; +} + +/* Move the current reading position forward |len| bytes */ +__owur static ossl_inline int PACKET_forward(PACKET *pkt, size_t len) +{ + if (PACKET_remaining(pkt) < len) + return 0; + + packet_forward(pkt, len); + + return 1; +} + +/* + * Reads a variable-length vector prefixed with a one-byte length, and stores + * the contents in |subpkt|. |pkt| can equal |subpkt|. + * Data is not copied: the |subpkt| packet will share its underlying buffer with + * the original |pkt|, so data wrapped by |pkt| must outlive the |subpkt|. + * Upon failure, the original |pkt| and |subpkt| are not modified. + */ +__owur static ossl_inline int PACKET_get_length_prefixed_1(PACKET *pkt, + PACKET *subpkt) +{ + unsigned int length; + const unsigned char *data; + PACKET tmp = *pkt; + + if (!PACKET_get_1(&tmp, &length) || + !PACKET_get_bytes(&tmp, &data, (size_t)length)) { + return 0; + } + + *pkt = tmp; + subpkt->curr = data; + subpkt->remaining = length; + + return 1; +} + +/* + * Like PACKET_get_length_prefixed_1, but additionally, fails when there are + * leftover bytes in |pkt|. + */ +__owur static ossl_inline int PACKET_as_length_prefixed_1(PACKET *pkt, + PACKET *subpkt) +{ + unsigned int length; + const unsigned char *data; + PACKET tmp = *pkt; + + if (!PACKET_get_1(&tmp, &length) || + !PACKET_get_bytes(&tmp, &data, (size_t)length) || + PACKET_remaining(&tmp) != 0) { + return 0; + } + + *pkt = tmp; + subpkt->curr = data; + subpkt->remaining = length; + + return 1; +} + +/* + * Reads a variable-length vector prefixed with a two-byte length, and stores + * the contents in |subpkt|. |pkt| can equal |subpkt|. + * Data is not copied: the |subpkt| packet will share its underlying buffer with + * the original |pkt|, so data wrapped by |pkt| must outlive the |subpkt|. + * Upon failure, the original |pkt| and |subpkt| are not modified. + */ +__owur static ossl_inline int PACKET_get_length_prefixed_2(PACKET *pkt, + PACKET *subpkt) +{ + unsigned int length; + const unsigned char *data; + PACKET tmp = *pkt; + + if (!PACKET_get_net_2(&tmp, &length) || + !PACKET_get_bytes(&tmp, &data, (size_t)length)) { + return 0; + } + + *pkt = tmp; + subpkt->curr = data; + subpkt->remaining = length; + + return 1; +} + +/* + * Like PACKET_get_length_prefixed_2, but additionally, fails when there are + * leftover bytes in |pkt|. + */ +__owur static ossl_inline int PACKET_as_length_prefixed_2(PACKET *pkt, + PACKET *subpkt) +{ + unsigned int length; + const unsigned char *data; + PACKET tmp = *pkt; + + if (!PACKET_get_net_2(&tmp, &length) || + !PACKET_get_bytes(&tmp, &data, (size_t)length) || + PACKET_remaining(&tmp) != 0) { + return 0; + } + + *pkt = tmp; + subpkt->curr = data; + subpkt->remaining = length; + + return 1; +} + +/* + * Reads a variable-length vector prefixed with a three-byte length, and stores + * the contents in |subpkt|. |pkt| can equal |subpkt|. + * Data is not copied: the |subpkt| packet will share its underlying buffer with + * the original |pkt|, so data wrapped by |pkt| must outlive the |subpkt|. + * Upon failure, the original |pkt| and |subpkt| are not modified. + */ +__owur static ossl_inline int PACKET_get_length_prefixed_3(PACKET *pkt, + PACKET *subpkt) +{ + unsigned long length; + const unsigned char *data; + PACKET tmp = *pkt; + + if (!PACKET_get_net_3(&tmp, &length) || + !PACKET_get_bytes(&tmp, &data, (size_t)length)) { + return 0; + } + + *pkt = tmp; + subpkt->curr = data; + subpkt->remaining = length; + + return 1; +} + +/* Writeable packets */ + +typedef struct wpacket_sub WPACKET_SUB; +struct wpacket_sub { + /* The parent WPACKET_SUB if we have one or NULL otherwise */ + WPACKET_SUB *parent; + + /* + * Offset into the buffer where the length of this WPACKET goes. We use an + * offset in case the buffer grows and gets reallocated. + */ + size_t packet_len; + + /* Number of bytes in the packet_len or 0 if we don't write the length */ + size_t lenbytes; + + /* Number of bytes written to the buf prior to this packet starting */ + size_t pwritten; + + /* Flags for this sub-packet */ + unsigned int flags; +}; + +typedef struct wpacket_st WPACKET; +struct wpacket_st { + /* The buffer where we store the output data */ + BUF_MEM *buf; + + /* Fixed sized buffer which can be used as an alternative to buf */ + unsigned char *staticbuf; + + /* + * Offset into the buffer where we are currently writing. We use an offset + * in case the buffer grows and gets reallocated. + */ + size_t curr; + + /* Number of bytes written so far */ + size_t written; + + /* Maximum number of bytes we will allow to be written to this WPACKET */ + size_t maxsize; + + /* Our sub-packets (always at least one if not finished) */ + WPACKET_SUB *subs; + + /* Writing from the end first? */ + unsigned int endfirst : 1; +}; + +/* Flags */ + +/* Default */ +#define WPACKET_FLAGS_NONE 0 + +/* Error on WPACKET_close() if no data written to the WPACKET */ +#define WPACKET_FLAGS_NON_ZERO_LENGTH 1 + +/* + * Abandon all changes on WPACKET_close() if no data written to the WPACKET, + * i.e. this does not write out a zero packet length + */ +#define WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH 2 + + +/* + * Initialise a WPACKET with the buffer in |buf|. The buffer must exist + * for the whole time that the WPACKET is being used. Additionally |lenbytes| of + * data is preallocated at the start of the buffer to store the length of the + * WPACKET once we know it. + */ +int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes); + +/* + * Same as WPACKET_init_len except there is no preallocation of the WPACKET + * length. + */ +int WPACKET_init(WPACKET *pkt, BUF_MEM *buf); + +/* + * Same as WPACKET_init_len except there is no underlying buffer. No data is + * ever actually written. We just keep track of how much data would have been + * written if a buffer was there. + */ +int WPACKET_init_null(WPACKET *pkt, size_t lenbytes); + +/* + * Same as WPACKET_init_null except we set the WPACKET to assume DER length + * encoding for sub-packets. + */ +int WPACKET_init_null_der(WPACKET *pkt); + +/* + * Same as WPACKET_init_len except we do not use a growable BUF_MEM structure. + * A fixed buffer of memory |buf| of size |len| is used instead. A failure will + * occur if you attempt to write beyond the end of the buffer + */ +int WPACKET_init_static_len(WPACKET *pkt, unsigned char *buf, size_t len, + size_t lenbytes); + +/* + * Same as WPACKET_init_static_len except lenbytes is always 0, and we set the + * WPACKET to write to the end of the buffer moving towards the start and use + * DER length encoding for sub-packets. + */ +int WPACKET_init_der(WPACKET *pkt, unsigned char *buf, size_t len); + +/* + * Set the flags to be applied to the current sub-packet + */ +int WPACKET_set_flags(WPACKET *pkt, unsigned int flags); + +/* + * Closes the most recent sub-packet. It also writes out the length of the + * packet to the required location (normally the start of the WPACKET) if + * appropriate. The top level WPACKET should be closed using WPACKET_finish() + * instead of this function. + */ +int WPACKET_close(WPACKET *pkt); + +/* + * The same as WPACKET_close() but only for the top most WPACKET. Additionally + * frees memory resources for this WPACKET. + */ +int WPACKET_finish(WPACKET *pkt); + +/* + * Iterate through all the sub-packets and write out their lengths as if they + * were being closed. The lengths will be overwritten with the final lengths + * when the sub-packets are eventually closed (which may be different if more + * data is added to the WPACKET). This function fails if a sub-packet is of 0 + * length and WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH is set. + */ +int WPACKET_fill_lengths(WPACKET *pkt); + +/* + * Initialise a new sub-packet. Additionally |lenbytes| of data is preallocated + * at the start of the sub-packet to store its length once we know it. Don't + * call this directly. Use the convenience macros below instead. + */ +int WPACKET_start_sub_packet_len__(WPACKET *pkt, size_t lenbytes); + +/* + * Convenience macros for calling WPACKET_start_sub_packet_len with different + * lengths + */ +#define WPACKET_start_sub_packet_u8(pkt) \ + WPACKET_start_sub_packet_len__((pkt), 1) +#define WPACKET_start_sub_packet_u16(pkt) \ + WPACKET_start_sub_packet_len__((pkt), 2) +#define WPACKET_start_sub_packet_u24(pkt) \ + WPACKET_start_sub_packet_len__((pkt), 3) +#define WPACKET_start_sub_packet_u32(pkt) \ + WPACKET_start_sub_packet_len__((pkt), 4) + +/* + * Same as WPACKET_start_sub_packet_len__() except no bytes are pre-allocated + * for the sub-packet length. + */ +int WPACKET_start_sub_packet(WPACKET *pkt); + +/* + * Allocate bytes in the WPACKET for the output. This reserves the bytes + * and counts them as "written", but doesn't actually do the writing. A pointer + * to the allocated bytes is stored in |*allocbytes|. |allocbytes| may be NULL. + * WARNING: the allocated bytes must be filled in immediately, without further + * WPACKET_* calls. If not then the underlying buffer may be realloc'd and + * change its location. + */ +int WPACKET_allocate_bytes(WPACKET *pkt, size_t len, + unsigned char **allocbytes); + +/* + * The same as WPACKET_allocate_bytes() except additionally a new sub-packet is + * started for the allocated bytes, and then closed immediately afterwards. The + * number of length bytes for the sub-packet is in |lenbytes|. Don't call this + * directly. Use the convenience macros below instead. + */ +int WPACKET_sub_allocate_bytes__(WPACKET *pkt, size_t len, + unsigned char **allocbytes, size_t lenbytes); + +/* + * Convenience macros for calling WPACKET_sub_allocate_bytes with different + * lengths + */ +#define WPACKET_sub_allocate_bytes_u8(pkt, len, bytes) \ + WPACKET_sub_allocate_bytes__((pkt), (len), (bytes), 1) +#define WPACKET_sub_allocate_bytes_u16(pkt, len, bytes) \ + WPACKET_sub_allocate_bytes__((pkt), (len), (bytes), 2) +#define WPACKET_sub_allocate_bytes_u24(pkt, len, bytes) \ + WPACKET_sub_allocate_bytes__((pkt), (len), (bytes), 3) +#define WPACKET_sub_allocate_bytes_u32(pkt, len, bytes) \ + WPACKET_sub_allocate_bytes__((pkt), (len), (bytes), 4) + +/* + * The same as WPACKET_allocate_bytes() except the reserved bytes are not + * actually counted as written. Typically this will be for when we don't know + * how big arbitrary data is going to be up front, but we do know what the + * maximum size will be. If this function is used, then it should be immediately + * followed by a WPACKET_allocate_bytes() call before any other WPACKET + * functions are called (unless the write to the allocated bytes is abandoned). + * + * For example: If we are generating a signature, then the size of that + * signature may not be known in advance. We can use WPACKET_reserve_bytes() to + * handle this: + * if (!WPACKET_sub_reserve_bytes_u16(&pkt, EVP_PKEY_get_size(pkey), &sigbytes1) + * || EVP_SignFinal(md_ctx, sigbytes1, &siglen, pkey) <= 0 + * || !WPACKET_sub_allocate_bytes_u16(&pkt, siglen, &sigbytes2) + * || sigbytes1 != sigbytes2) + * goto err; + */ +int WPACKET_reserve_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes); + +/* + * The "reserve_bytes" equivalent of WPACKET_sub_allocate_bytes__() + */ +int WPACKET_sub_reserve_bytes__(WPACKET *pkt, size_t len, + unsigned char **allocbytes, size_t lenbytes); + +/* + * Convenience macros for WPACKET_sub_reserve_bytes with different lengths + */ +#define WPACKET_sub_reserve_bytes_u8(pkt, len, bytes) \ + WPACKET_reserve_bytes__((pkt), (len), (bytes), 1) +#define WPACKET_sub_reserve_bytes_u16(pkt, len, bytes) \ + WPACKET_sub_reserve_bytes__((pkt), (len), (bytes), 2) +#define WPACKET_sub_reserve_bytes_u24(pkt, len, bytes) \ + WPACKET_sub_reserve_bytes__((pkt), (len), (bytes), 3) +#define WPACKET_sub_reserve_bytes_u32(pkt, len, bytes) \ + WPACKET_sub_reserve_bytes__((pkt), (len), (bytes), 4) + +/* + * Write the value stored in |val| into the WPACKET. The value will consume + * |bytes| amount of storage. An error will occur if |val| cannot be + * accommodated in |bytes| storage, e.g. attempting to write the value 256 into + * 1 byte will fail. Don't call this directly. Use the convenience macros below + * instead. + */ +int WPACKET_put_bytes__(WPACKET *pkt, uint64_t val, size_t bytes); + +/* + * Convenience macros for calling WPACKET_put_bytes with different + * lengths + */ +#define WPACKET_put_bytes_u8(pkt, val) \ + WPACKET_put_bytes__((pkt), (val), 1) +#define WPACKET_put_bytes_u16(pkt, val) \ + WPACKET_put_bytes__((pkt), (val), 2) +#define WPACKET_put_bytes_u24(pkt, val) \ + WPACKET_put_bytes__((pkt), (val), 3) +#define WPACKET_put_bytes_u32(pkt, val) \ + WPACKET_put_bytes__((pkt), (val), 4) +#define WPACKET_put_bytes_u64(pkt, val) \ + WPACKET_put_bytes__((pkt), (val), 8) + +/* Set a maximum size that we will not allow the WPACKET to grow beyond */ +int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize); + +/* Copy |len| bytes of data from |*src| into the WPACKET. */ +int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len); + +/* Set |len| bytes of data to |ch| into the WPACKET. */ +int WPACKET_memset(WPACKET *pkt, int ch, size_t len); + +/* + * Copy |len| bytes of data from |*src| into the WPACKET and prefix with its + * length (consuming |lenbytes| of data for the length). Don't call this + * directly. Use the convenience macros below instead. + */ +int WPACKET_sub_memcpy__(WPACKET *pkt, const void *src, size_t len, + size_t lenbytes); + +/* Convenience macros for calling WPACKET_sub_memcpy with different lengths */ +#define WPACKET_sub_memcpy_u8(pkt, src, len) \ + WPACKET_sub_memcpy__((pkt), (src), (len), 1) +#define WPACKET_sub_memcpy_u16(pkt, src, len) \ + WPACKET_sub_memcpy__((pkt), (src), (len), 2) +#define WPACKET_sub_memcpy_u24(pkt, src, len) \ + WPACKET_sub_memcpy__((pkt), (src), (len), 3) +#define WPACKET_sub_memcpy_u32(pkt, src, len) \ + WPACKET_sub_memcpy__((pkt), (src), (len), 4) + +/* + * Return the total number of bytes written so far to the underlying buffer + * including any storage allocated for length bytes + */ +int WPACKET_get_total_written(WPACKET *pkt, size_t *written); + +/* + * Returns the length of the current sub-packet. This excludes any bytes + * allocated for the length itself. + */ +int WPACKET_get_length(WPACKET *pkt, size_t *len); + +/* + * Returns a pointer to the current write location, but does not allocate any + * bytes. + */ +unsigned char *WPACKET_get_curr(WPACKET *pkt); + +/* Returns true if the underlying buffer is actually NULL */ +int WPACKET_is_null_buf(WPACKET *pkt); + +/* Release resources in a WPACKET if a failure has occurred. */ +void WPACKET_cleanup(WPACKET *pkt); + +#endif /* OSSL_INTERNAL_PACKET_H */
Support SM2 keypair generation in uadk_provider. Test: openssl list -provider uadk_provider -key-managers openssl ecparam -name SM2 -genkey -out sm2.key -provider uadk_provider openssl ec -in sm2.key -pubout -out sm2.pub -provider uadk_provider
Support SM2 encrypt, decrypt, sign and verify. Test: openssl list -provider uadk_provider -signature-algorithms openssl list -provider uadk_provider -public-key-algorithms openssl dgst -provider uadk_provider -SM3 -sign sm2.key -out \ sm2_ec.sig sign.data openssl dgst -provider uadk_provider -SM3 -verify sm2.pub \ -signature sm2_ec.sig sign.data openssl pkeyutl -encrypt -in plaintext.txt -out ciphertext.bin \ -inkey sm2.pub -pubin -provider uadk_provider openssl pkeyutl -decrypt -in ciphertext.bin -out plaintext.txt \ -inkey sm2.key -provider uadk_provider
Signed-off-by: Zhiqi Song songzhiqi1@huawei.com Signed-off-by: JiangShui Yang yangjiangshui@h-partners.com --- src/Makefile.am | 2 + src/uadk_prov.h | 15 +- src/uadk_prov_init.c | 11 + src/uadk_prov_pkey.c | 770 +++++++++++ src/uadk_prov_pkey.h | 429 ++++++ src/uadk_prov_sm2.c | 3146 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 4369 insertions(+), 4 deletions(-) create mode 100644 src/uadk_prov_pkey.c create mode 100644 src/uadk_prov_pkey.h create mode 100644 src/uadk_prov_sm2.c
diff --git a/src/Makefile.am b/src/Makefile.am index b911ab5..971354f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -64,8 +64,10 @@ uadk_provider_la_SOURCES=uadk_prov_init.c uadk_async.c uadk_utils.c \ uadk_prov_digest.c uadk_prov_cipher.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_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 uadk_provider_la_CFLAGS+=-DOPENSSL_SUPPRESS_DEPRECATED diff --git a/src/uadk_prov.h b/src/uadk_prov.h index 508f113..f641dce 100644 --- a/src/uadk_prov.h +++ b/src/uadk_prov.h @@ -35,11 +35,13 @@ struct ossl_provider_st { unsigned int flag_fallback:1; /* Can be used as fallback */
/* Getting and setting the flags require synchronization */ - CRYPTO_RWLOCK *flag_lock; + void *flag_lock;
/* OpenSSL library side data */ - CRYPTO_REF_COUNT refcnt; - CRYPTO_RWLOCK *refcnt_lock; /* For the ref counter */ + /* Crypto reference counter */ + int refcnt; + /* Lock for the ref counter */ + void *refcnt_lock; int activatecnt; char *name; char *path; @@ -75,7 +77,7 @@ struct ossl_provider_st { */ unsigned char *operation_bits; size_t operation_bits_sz; - CRYPTO_RWLOCK *opbits_lock; + void *opbits_lock;
#ifndef FIPS_MODULE /* Whether this provider is the child of some other provider */ @@ -147,10 +149,15 @@ extern const OSSL_DISPATCH uadk_rsa_asym_cipher_functions[]; extern const OSSL_DISPATCH uadk_dh_keymgmt_functions[]; extern const OSSL_DISPATCH uadk_dh_keyexch_functions[];
+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]; + void uadk_prov_destroy_digest(void); void uadk_prov_destroy_cipher(void); void uadk_prov_destroy_rsa(void); void uadk_prov_destroy_dh(void); +void uadk_prov_sm2_uninit(void);
/* offload small packets to sw */ extern int enable_sw_offload; diff --git a/src/uadk_prov_init.c b/src/uadk_prov_init.c index f521160..8c9067e 100644 --- a/src/uadk_prov_init.c +++ b/src/uadk_prov_init.c @@ -29,6 +29,7 @@ #include "uadk_async.h" #include "uadk_prov.h" #include "uadk_prov_bio.h" +#include "uadk_prov_pkey.h"
static const char UADK_DEFAULT_PROPERTIES[] = "provider=uadk_provider"; static OSSL_PROVIDER *prov; @@ -102,6 +103,8 @@ const OSSL_ALGORITHM uadk_prov_ciphers[] = { static const OSSL_ALGORITHM uadk_prov_signature[] = { { "RSA", UADK_DEFAULT_PROPERTIES, uadk_rsa_signature_functions, "uadk_provider rsa_signature" }, + { "SM2", UADK_DEFAULT_PROPERTIES, + uadk_sm2_signature_functions, "uadk_provider sm2_signature" }, { NULL, NULL, NULL } };
@@ -109,11 +112,15 @@ static const OSSL_ALGORITHM uadk_prov_keymgmt[] = { { "RSA", UADK_DEFAULT_PROPERTIES, uadk_rsa_keymgmt_functions, "uadk RSA Keymgmt implementation." }, { "DH", UADK_DEFAULT_PROPERTIES, uadk_dh_keymgmt_functions }, + { "SM2", UADK_DEFAULT_PROPERTIES, + uadk_sm2_keymgmt_functions, "uadk SM2 Keymgmt implementation."}, { NULL, NULL, NULL } };
static const OSSL_ALGORITHM uadk_prov_asym_cipher[] = { { "RSA", UADK_DEFAULT_PROPERTIES, uadk_rsa_asym_cipher_functions }, + { "SM2", UADK_DEFAULT_PROPERTIES, + uadk_sm2_asym_cipher_functions, "uadk SM2 asym cipher implementation." }, { NULL, NULL, NULL } };
@@ -144,10 +151,13 @@ static const OSSL_ALGORITHM *uadk_query(void *provctx, int operation_id, case OSSL_OP_CIPHER: return uadk_prov_ciphers; case OSSL_OP_SIGNATURE: + (void)uadk_prov_signature_alg(); return uadk_prov_signature; case OSSL_OP_KEYMGMT: + (void)uadk_prov_keymgmt_alg(); return uadk_prov_keymgmt; case OSSL_OP_ASYM_CIPHER: + (void)uadk_prov_asym_cipher_alg(); return uadk_prov_asym_cipher; case OSSL_OP_KEYEXCH: return uadk_prov_keyexch; @@ -164,6 +174,7 @@ static void uadk_teardown(void *provctx) uadk_prov_destroy_digest(); uadk_prov_destroy_cipher(); uadk_prov_destroy_rsa(); + uadk_prov_sm2_uninit(); OPENSSL_free(ctx); OSSL_PROVIDER_unload(prov); async_poll_task_free(); diff --git a/src/uadk_prov_pkey.c b/src/uadk_prov_pkey.c new file mode 100644 index 0000000..d02b165 --- /dev/null +++ b/src/uadk_prov_pkey.c @@ -0,0 +1,770 @@ +// 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 "uadk_prov_pkey.h" + +#define ECC_TYPE 5 +#define CTX_ASYNC 1 +#define CTX_SYNC 0 +#define UADK_UNINIT 0 +#define UADK_INIT_SUCCESS 1 +#define UADK_INIT_FAIL 2 +#define UADK_DEVICE_ERROR 3 +#define KEYMGMT_TYPE 6 +#define PROV_SUPPORT 1 +#define SIGNATURE_TYPE 3 +#define ASYM_CIPHER_TYPE 3 + +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]; + +/* Mapping between a flag and a name */ +static const OSSL_ITEM encoding_nameid_map[] = { + { OPENSSL_EC_EXPLICIT_CURVE, OSSL_PKEY_EC_ENCODING_EXPLICIT }, + { OPENSSL_EC_NAMED_CURVE, OSSL_PKEY_EC_ENCODING_GROUP }, +}; + +static const OSSL_ITEM format_nameid_map[] = { + { (int)POINT_CONVERSION_UNCOMPRESSED, OSSL_PKEY_EC_POINT_CONVERSION_FORMAT_UNCOMPRESSED }, + { (int)POINT_CONVERSION_COMPRESSED, OSSL_PKEY_EC_POINT_CONVERSION_FORMAT_COMPRESSED }, + { (int)POINT_CONVERSION_HYBRID, OSSL_PKEY_EC_POINT_CONVERSION_FORMAT_HYBRID }, +}; + +int uadk_prov_keymgmt_get_support_state(int alg_tag) +{ + return p_keymgmt_support_state[alg_tag]; +} + +static void uadk_prov_keymgmt_set_support_state(int alg_tag, int value) +{ + p_keymgmt_support_state[alg_tag] = value; +} + +int uadk_prov_signature_get_support_state(int alg_tag) +{ + return p_signature_support_state[alg_tag]; +} + +static void uadk_prov_signature_set_support_state(int alg_tag, int value) +{ + p_signature_support_state[alg_tag] = value; +} + +int uadk_prov_asym_cipher_get_support_state(int alg_tag) +{ + return p_asym_cipher_support_state[alg_tag]; +} +static void uadk_prov_asym_cipher_set_support_state(int alg_tag, int value) +{ + p_asym_cipher_support_state[alg_tag] = value; +} + +static int uadk_prov_ecc_get_hw_keybits(int bits) +{ + if (bits > ECC384BITS) + return ECC521BITS; + else if (bits > ECC320BITS) + return ECC384BITS; + else if (bits > ECC256BITS) + return ECC320BITS; + else if (bits > ECC192BITS) + return ECC256BITS; + else if (bits > ECC128BITS) + return ECC192BITS; + else + return ECC128BITS; +} + +void uadk_prov_ecc_fill_req(struct wd_ecc_req *req, unsigned int op, + void *in, void *out) +{ + req->op_type = op; + req->src = in; + req->dst = out; +} + +int uadk_prov_ecc_get_rand(char *out, size_t out_len, void *usr) +{ + int count = GET_RAND_MAX_CNT; + BIGNUM *k; + int ret; + + if (!out) { + fprintf(stderr, "out is NULL\n"); + return -1; + } + + k = BN_new(); + if (!k) + return -ENOMEM; + + do { + ret = BN_priv_rand_range(k, usr); + if (!ret) { + fprintf(stderr, "failed to BN_priv_rand_range\n"); + ret = -EINVAL; + goto err; + } + + ret = BN_bn2binpad(k, (void *)out, (int)out_len); + if (ret < 0) { + ret = -EINVAL; + fprintf(stderr, "failed to BN_bn2binpad\n"); + goto err; + } + } while (--count >= 0 && BN_is_zero(k)); + + ret = 0; + if (count < 0) + ret = -1; +err: + BN_free(k); + + return ret; +} + +static void uadk_prov_init_dtb_param(void *dtb, char *start, + __u32 dsz, __u32 bsz, __u32 num) +{ + struct wd_dtb *tmp = dtb; + char *buff = start; + __u32 i = 0; + + while (i++ < num) { + tmp->data = buff; + tmp->dsize = dsz; + tmp->bsize = bsz; + tmp += 1; + buff += bsz; + } +} + +int uadk_prov_get_affine_coordinates(const EC_GROUP *group, const EC_POINT *p, + BIGNUM *x, BIGNUM *y, BN_CTX *ctx) +{ +# if OPENSSL_VERSION_NUMBER > 0x10101000L + if (!EC_POINT_get_affine_coordinates(group, p, x, y, ctx)) + return -1; +# else + if (!EC_POINT_get_affine_coordinates_GFp(group, p, x, y, ctx)) + return -1; +# endif + return 0; +} + +int uadk_prov_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, + BIGNUM *b, BN_CTX *ctx) +{ +# if OPENSSL_VERSION_NUMBER > 0x10101000L + if (!EC_GROUP_get_curve(group, p, a, b, ctx)) + return -1; +# else + if (!EC_GROUP_get_curve_GFp(group, p, a, b, ctx)) + return -1; +# endif + return 0; +} + +static void uadk_prov_fill_ecc_cv_param(struct wd_ecc_curve *pparam, + struct curve_param *cv_param, + BIGNUM *g_x, BIGNUM *g_y) +{ + pparam->p.dsize = BN_bn2bin(cv_param->p, (void *)pparam->p.data); + pparam->a.dsize = BN_bn2bin(cv_param->a, (void *)pparam->a.data); + if (!pparam->a.dsize) { + pparam->a.dsize = 1; + pparam->a.data[0] = 0; + } + + pparam->b.dsize = BN_bn2bin(cv_param->b, (void *)pparam->b.data); + if (!pparam->b.dsize) { + pparam->b.dsize = 1; + pparam->b.data[0] = 0; + } + + pparam->g.x.dsize = BN_bn2bin(g_x, (void *)pparam->g.x.data); + pparam->g.y.dsize = BN_bn2bin(g_y, (void *)pparam->g.y.data); + pparam->n.dsize = BN_bn2bin(cv_param->order, (void *)pparam->n.data); +} + +static int uadk_prov_set_sess_setup_cv(const EC_GROUP *group, + struct wd_ecc_curve_cfg *cv) +{ + struct wd_ecc_curve *pparam = cv->cfg.pparam; + struct curve_param *cv_param; + BIGNUM *g_x, *g_y; + int ret = -1; + BN_CTX *ctx; + + ctx = BN_CTX_new(); + if (!ctx) + return ret; + + BN_CTX_start(ctx); + + cv_param = OPENSSL_malloc(sizeof(struct curve_param)); + if (!cv_param) + goto free_ctx; + + cv_param->p = BN_CTX_get(ctx); + if (!cv_param->p) + goto free_cv; + + cv_param->a = BN_CTX_get(ctx); + if (!cv_param->a) + goto free_cv; + + cv_param->b = BN_CTX_get(ctx); + if (!cv_param->b) + goto free_cv; + + g_x = BN_CTX_get(ctx); + if (!g_x) + goto free_cv; + + g_y = BN_CTX_get(ctx); + if (!g_y) + goto free_cv; + + ret = uadk_prov_get_curve(group, cv_param->p, cv_param->a, cv_param->b, ctx); + if (ret) + goto free_cv; + + cv_param->g = EC_GROUP_get0_generator(group); + if (!cv_param->g) + goto free_cv; + + ret = uadk_prov_get_affine_coordinates(group, cv_param->g, g_x, g_y, ctx); + if (ret) + goto free_cv; + + cv_param->order = EC_GROUP_get0_order(group); + if (!cv_param->order) + goto free_cv; + + uadk_prov_fill_ecc_cv_param(pparam, cv_param, g_x, g_y); + cv->type = WD_CV_CFG_PARAM; + ret = 0; + +free_cv: + OPENSSL_free(cv_param); +free_ctx: + BN_CTX_end(ctx); + BN_CTX_free(ctx); + + return ret; +} + +handle_t uadk_prov_ecc_alloc_sess(const EC_KEY *eckey, char *alg) +{ + char buff[UADK_ECC_MAX_KEY_BYTES * UADK_ECC_CV_PARAM_NUM]; + struct sched_params sch_p = {0}; + struct wd_ecc_sess_setup sp; + struct wd_ecc_curve param; + const EC_GROUP *group; + const BIGNUM *order; + int ret, key_bits; + handle_t sess; + + uadk_prov_init_dtb_param(¶m, buff, 0, UADK_ECC_MAX_KEY_BYTES, + UADK_ECC_CV_PARAM_NUM); + + memset(&sp, 0, sizeof(sp)); + sp.cv.cfg.pparam = ¶m; + group = EC_KEY_get0_group(eckey); + ret = uadk_prov_set_sess_setup_cv(group, &sp.cv); + if (ret) { + fprintf(stderr, "failed to set_sess_setup_cv\n"); + return (handle_t)0; + } + + order = EC_GROUP_get0_order(group); + if (!order) { + fprintf(stderr, "failed to get ecc order\n"); + return (handle_t)0; + } + + key_bits = BN_num_bits(order); + sp.alg = alg; + sp.key_bits = uadk_prov_ecc_get_hw_keybits(key_bits); + sp.rand.cb = uadk_prov_ecc_get_rand; + sp.rand.usr = (void *)order; + /* Use the default numa parameters */ + sch_p.numa_id = -1; + sp.sched_param = &sch_p; + sess = wd_ecc_alloc_sess(&sp); + if (!sess) + fprintf(stderr, "failed to alloc ecc sess\n"); + + return sess; +} + +void uadk_prov_ecc_cb(void *req_t) +{ + struct wd_ecc_req *req_new = (struct wd_ecc_req *)req_t; + struct uadk_e_cb_info *cb_param; + struct wd_ecc_req *req_origin; + struct async_op *op; + + if (!req_new) + return; + + cb_param = req_new->cb_param; + if (!cb_param) + return; + + req_origin = cb_param->priv; + if (!req_origin) + return; + + req_origin->status = req_new->status; + + op = cb_param->op; + if (op && op->job && !op->done) { + op->done = 1; + op->ret = 0; + async_free_poll_task(op->idx, 1); + async_wake_job(op->job); + } +} + +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; + + ret = async_setup_async_event_notification(&op); + if (ret == 0) { + fprintf(stderr, "failed to setup async event notification\n"); + return ret; + } + + if (op.job == NULL) { + ret = wd_do_ecc_sync(sess, req); + if (ret) + goto err; + + return UADK_P_SUCCESS; + } + + cb_param.op = &op; + cb_param.priv = req; + req->cb = uadk_prov_ecc_cb; + req->cb_param = &cb_param; + req->status = -1; + + ret = async_get_free_task(&idx); + if (ret == 0) + goto err; + + op.idx = idx; + do { + ret = wd_do_ecc_async(sess, req); + if (ret < 0 && ret != -EBUSY) { + async_free_poll_task(op.idx, 0); + goto err; + } + } while (ret == -EBUSY); + + ret = async_pause_job(usr, &op, ASYNC_TASK_ECC); + if (!ret) + goto err; + + if (req->status) + return UADK_P_FAIL; + + return UADK_P_SUCCESS; + +err: + (void)async_clear_async_event_notification(); + return UADK_P_FAIL; +} + +int uadk_prov_ecc_poll(void *ctx) +{ + unsigned int recv = 0; + __u64 rx_cnt = 0; + int expt = 1; + int ret; + + do { + ret = wd_ecc_poll(expt, &recv); + if (ret < 0 || recv == expt) + return ret; + rx_cnt++; + } while (rx_cnt < PROV_RECV_MAX_CNT); + + fprintf(stderr, "failed to recv msg: timeout!\n"); + + return -ETIMEDOUT; +} + +static int set_group(OSSL_PARAM_BLD *bld, struct ec_gen_ctx *gctx) +{ + OSSL_PARAM *params = NULL; + EC_GROUP *group = NULL; + + params = OSSL_PARAM_BLD_to_param(bld); + if (params == NULL) { + fprintf(stderr, "failed to get params from bld\n"); + return UADK_P_FAIL; + } + + group = EC_GROUP_new_from_params(params, gctx->libctx, NULL); + if (group == NULL) { + fprintf(stderr, "failed to get group from params\n"); + OSSL_PARAM_free(params); + return UADK_P_FAIL; + } + + if (gctx->gen_group) + EC_GROUP_free(gctx->gen_group); + + gctx->gen_group = group; + OSSL_PARAM_free(params); + + return UADK_P_SUCCESS; +} + +static int check_curve_params(OSSL_PARAM_BLD *bld, struct ec_gen_ctx *gctx) +{ + if (gctx->p == NULL || gctx->a == NULL || gctx->b == NULL || gctx->order == NULL + || !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_P, gctx->p) + || !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_A, gctx->a) + || !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_B, gctx->b) + || !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_ORDER, gctx->order)) { + fprintf(stderr, "failed to set curve params\n"); + return UADK_P_FAIL; + } + + if (gctx->cofactor != NULL + && !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_COFACTOR, gctx->cofactor)) { + fprintf(stderr, "failed to set cofactor\n"); + return UADK_P_FAIL; + } + + if (gctx->seed != NULL + && !OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_EC_SEED, + gctx->seed, gctx->seed_len)) { + fprintf(stderr, "failed to set seed\n"); + return UADK_P_FAIL; + } + + if (gctx->gen == NULL + || !OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_EC_GENERATOR, + gctx->gen, gctx->gen_len)) { + fprintf(stderr, "failed to set gen params\n"); + return UADK_P_FAIL; + } + + return UADK_P_SUCCESS; +} + +static int ec_gen_set_group_from_params(struct ec_gen_ctx *gctx) +{ + OSSL_PARAM_BLD *bld; + int ret = 0; + + bld = OSSL_PARAM_BLD_new(); + if (bld == NULL) { + fprintf(stderr, "failed to OSSL_PARAM_BLD_new\n"); + return UADK_P_FAIL; + } + + if (gctx->encoding != NULL + && !OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_EC_ENCODING, + gctx->encoding, 0)) { + fprintf(stderr, "failed to set encoding\n"); + goto free_bld; + } + + if (gctx->pt_format != NULL + && !OSSL_PARAM_BLD_push_utf8_string(bld, + OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, gctx->pt_format, 0)) { + fprintf(stderr, "failed to set point format\n"); + goto free_bld; + } + + if (gctx->group_name != NULL) { + if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME, + gctx->group_name, 0)) { + fprintf(stderr, "failed to set group name\n"); + goto free_bld; + } + /* Ignore any other parameters if there is a group name */ + ret = set_group(bld, gctx); + goto free_bld; + } else if (gctx->field_type != NULL) { + if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_EC_FIELD_TYPE, + gctx->field_type, 0)) { + fprintf(stderr, "failed to set filed type\n"); + goto free_bld; + } + } else { + /* No need to continue the setup */ + goto free_bld; + } + + if (check_curve_params(bld, gctx) == 0) + goto free_bld; + + ret = UADK_P_SUCCESS; + +free_bld: + OSSL_PARAM_BLD_free(bld); + return ret; +} + +static int ec_gen_assign_group(EC_KEY *ec, EC_GROUP *group) +{ + if (group == NULL) { + fprintf(stderr, "invalid: ec group is NULL\n"); + return UADK_P_FAIL; + } + + return EC_KEY_set_group(ec, group) > 0; +} + +static int ossl_ec_encoding_name2id(const char *name) +{ + size_t i, sz; + + /* Return the default value if there is no name */ + if (name == NULL) + return OPENSSL_EC_NAMED_CURVE; + + for (i = 0, sz = OSSL_NELEM(encoding_nameid_map); i < sz; i++) { + if (OPENSSL_strcasecmp(name, encoding_nameid_map[i].ptr) == 0) + return encoding_nameid_map[i].id; + } + + return -1; +} + +static int ossl_ec_pt_format_name2id(const char *name) +{ + size_t i, sz; + + /* Return the default value if there is no name */ + if (name == NULL) + return (int)POINT_CONVERSION_UNCOMPRESSED; + + for (i = 0, sz = OSSL_NELEM(format_nameid_map); i < sz; i++) { + if (OPENSSL_strcasecmp(name, format_nameid_map[i].ptr) == 0) + return format_nameid_map[i].id; + } + + return -1; +} + +int uadk_prov_ecc_genctx_check(struct ec_gen_ctx *gctx, EC_KEY *ec) +{ + int ret; + + if (gctx->gen_group == NULL) { + ret = ec_gen_set_group_from_params(gctx); + if (ret == 0) { + fprintf(stderr, "failed to set group from params\n"); + return UADK_P_FAIL; + } + } else { + if (gctx->encoding) { + /* + * If an encoding is specified, the encoding name is converted + * to an encoding flag and set into the key group. + */ + ret = ossl_ec_encoding_name2id(gctx->encoding); + if (ret < 0) { + fprintf(stderr, "failed to encoding name to id\n"); + return UADK_P_FAIL; + } + EC_GROUP_set_asn1_flag(gctx->gen_group, ret); + } + if (gctx->pt_format) { + /* + * If a point format is specified, the point format name is converted + * to a point format flag and set into the key group + */ + ret = ossl_ec_pt_format_name2id(gctx->pt_format); + if (ret < 0) { + fprintf(stderr, "failed to point format name to id\n"); + return UADK_P_FAIL; + } + EC_GROUP_set_point_conversion_form(gctx->gen_group, ret); + } + } + + /* We must always assign a group, no matter what */ + ret = ec_gen_assign_group(ec, gctx->gen_group); + if (ret == 0) { + fprintf(stderr, "invalid: ec group is NULL\n"); + return UADK_P_FAIL; + } + + return UADK_P_SUCCESS; +} + +static bool uadk_prov_support_algorithm(const char *alg) +{ + struct uacce_dev_list *list = wd_get_accel_list(alg); + + if (list) { + wd_free_list_accels(list); + return true; + } + + return false; +} + +void uadk_prov_keymgmt_alg(void) +{ + static const char * const keymgmt_alg[] = {"sm2"}; + __u32 i, size; + bool sp; + + /* Enumerate keymgmt algs to check whether it is supported and set tags */ + size = ARRAY_SIZE(keymgmt_alg); + for (i = 0; i < size; i++) { + sp = uadk_prov_support_algorithm(*(keymgmt_alg + i)); + if (sp) + uadk_prov_keymgmt_set_support_state(i, PROV_SUPPORT); + } +} + +void uadk_prov_signature_alg(void) +{ + static const char * const signature_alg[] = {"sm2"}; + __u32 i, size; + bool sp; + + /* Enumerate keymgmt 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)); + if (sp) + uadk_prov_signature_set_support_state(i, PROV_SUPPORT); + } +} + +int uadk_prov_ecc_set_private_key(handle_t sess, const EC_KEY *eckey) +{ + unsigned char bin[UADK_ECC_MAX_KEY_BYTES]; + struct wd_ecc_key *ecc_key; + const EC_GROUP *group; + struct wd_dtb prikey; + const BIGNUM *d; + size_t degree; + int buflen; + int ret; + + d = EC_KEY_get0_private_key(eckey); + if (!d) { + fprintf(stderr, "private key not set\n"); + return UADK_P_FAIL; + } + + group = EC_KEY_get0_group(eckey); + if (!group) { + fprintf(stderr, "failed to get ecc group\n"); + return UADK_P_FAIL; + } + + degree = EC_GROUP_get_degree(group); + buflen = BITS_TO_BYTES(degree); + ecc_key = wd_ecc_get_key(sess); + prikey.data = (void *)bin; + prikey.dsize = BN_bn2binpad(d, bin, buflen); + + 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; +} + +bool uadk_prov_is_all_zero(const unsigned char *data, size_t dlen) +{ + size_t i; + + for (i = 0; i < dlen; i++) { + if (data[i]) + return false; + } + + return true; +} + +int uadk_prov_ecc_set_public_key(handle_t sess, const EC_KEY *eckey) +{ + unsigned char *point_bin = NULL; + struct wd_ecc_point pubkey; + struct wd_ecc_key *ecc_key; + const EC_POINT *point; + const EC_GROUP *group; + int ret, len; + + point = EC_KEY_get0_public_key(eckey); + if (!point) { + fprintf(stderr, "pubkey not set!\n"); + return UADK_P_FAIL; + } + + group = EC_KEY_get0_group(eckey); + len = EC_POINT_point2buf(group, point, UADK_OCTET_STRING, + &point_bin, NULL); + if (!len) { + fprintf(stderr, "EC_POINT_point2buf error.\n"); + return UADK_P_FAIL; + } + + len /= UADK_ECC_PUBKEY_PARAM_NUM; + pubkey.x.data = (char *)point_bin + 1; + pubkey.x.dsize = len; + pubkey.y.data = pubkey.x.data + len; + pubkey.y.dsize = len; + ecc_key = wd_ecc_get_key(sess); + ret = wd_ecc_set_pubkey(ecc_key, &pubkey); + if (ret) { + fprintf(stderr, "failed to set ecc pubkey\n"); + OPENSSL_free(point_bin); + return UADK_P_FAIL; + } + + OPENSSL_free(point_bin); + + return UADK_P_SUCCESS; +} + +void uadk_prov_asym_cipher_alg(void) +{ + static const char * const asym_cipher_alg[] = {"sm2"}; + __u32 i, size; + bool sp; + + /* Enumerate keymgmt 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)); + if (sp) + uadk_prov_asym_cipher_set_support_state(i, PROV_SUPPORT); + } +} diff --git a/src/uadk_prov_pkey.h b/src/uadk_prov_pkey.h new file mode 100644 index 0000000..c495649 --- /dev/null +++ b/src/uadk_prov_pkey.h @@ -0,0 +1,429 @@ +/* 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. + * + */ +#ifndef UADK_PROV_PKEY_H +#define UADK_PROV_PKEY_H +#include <openssl/asn1t.h> +#include <openssl/bn.h> +#include <openssl/buffer.h> +#include <openssl/core.h> +#include <openssl/core_dispatch.h> +#include <openssl/core_names.h> +#include <openssl/crypto.h> +#include <openssl/ec.h> +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/ossl_typ.h> +#include <openssl/params.h> +#include <openssl/param_build.h> +#include <openssl/proverr.h> +#include <openssl/types.h> +#include <uadk/wd_ecc.h> +#include <uadk/wd_sched.h> +#include "uadk_async.h" +#include "uadk_prov.h" + +#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 PROV_SEND_MAX_CNT 90000000 +#define PROV_RECV_MAX_CNT 60000000 +#define PROV_ENV_RECV_MAX_CNT 60000 +#define PROV_KEYMGMT_ALG_NUM 7 +#define ECC_POINT_SIZE(n) ((n) << 1) +#define UADK_OCTET_STRING 0x04 +#define ECC128BITS 128 +#define ECC192BITS 192 +#define ECC224BITS 224 +#define ECC256BITS 256 +#define ECC320BITS 320 +#define ECC384BITS 384 +#define ECC521BITS 521 +#define GET_RAND_MAX_CNT 100 +#define OSSL_NELEM(x) (sizeof(x)/sizeof((x)[0])) +#define UADK_ECC_PUBKEY_PARAM_NUM 2 +#define OSSL_MAX_NAME_SIZE 50 /* Algorithm name */ +#define OSSL_MAX_ALGORITHM_ID_SIZE 256 /* AlgorithmIdentifier DER */ +#define TRANS_BITS_BYTES_SHIFT 3 +#define GET_MS_BYTE(n) ((n) >> 8) +#define GET_LS_BYTE(n) ((n) & 0xFF) + +enum { + KEYMGMT_SM2 = 0x0, + KEYMGMT_MAX = 0x6 +}; + +enum { + SIGNATURE_SM2 = 0x0, + SIGNATURE_MAX = 0x3 +}; + +struct curve_param { + /* Prime */ + BIGNUM *p; + /* ECC coefficient 'a' */ + BIGNUM *a; + /* ECC coefficient 'b' */ + BIGNUM *b; + /* Base point */ + const EC_POINT *g; + /* Order of base point */ + const BIGNUM *order; +}; + +struct ec_gen_ctx { + OSSL_LIB_CTX *libctx; + char *group_name; + char *encoding; + char *pt_format; + char *group_check; + char *field_type; + BIGNUM *p, *a, *b, *order, *cofactor; + unsigned char *gen, *seed; + size_t gen_len, seed_len; + int selection; + int ecdh_mode; + EC_GROUP *gen_group; +}; + +typedef struct { + /* libcrypto internal */ + int id; + + int name_id; + char *type_name; + const char *description; + OSSL_PROVIDER *prov; + int refcnt; + void *lock; + + /* Constructor(s), destructor, information */ + OSSL_FUNC_keymgmt_new_fn *new_fun; + OSSL_FUNC_keymgmt_free_fn *free; + OSSL_FUNC_keymgmt_get_params_fn *get_params; + OSSL_FUNC_keymgmt_gettable_params_fn *gettable_params; + OSSL_FUNC_keymgmt_set_params_fn *set_params; + OSSL_FUNC_keymgmt_settable_params_fn *settable_params; + + /* Generation, a complex constructor */ + OSSL_FUNC_keymgmt_gen_init_fn *gen_init; + OSSL_FUNC_keymgmt_gen_set_template_fn *gen_set_template; + OSSL_FUNC_keymgmt_gen_set_params_fn *gen_set_params; + OSSL_FUNC_keymgmt_gen_settable_params_fn *gen_settable_params; + OSSL_FUNC_keymgmt_gen_fn *gen; + OSSL_FUNC_keymgmt_gen_cleanup_fn *gen_cleanup; + OSSL_FUNC_keymgmt_load_fn *load; + + /* Key object checking */ + OSSL_FUNC_keymgmt_query_operation_name_fn *query_operation_name; + OSSL_FUNC_keymgmt_has_fn *has; + OSSL_FUNC_keymgmt_validate_fn *validate; + OSSL_FUNC_keymgmt_match_fn *match; + + /* Import and export routines */ + OSSL_FUNC_keymgmt_import_fn *import; + OSSL_FUNC_keymgmt_import_types_fn *import_types; + OSSL_FUNC_keymgmt_export_fn *export_fun; + OSSL_FUNC_keymgmt_export_types_fn *export_types; + OSSL_FUNC_keymgmt_dup_fn *dup; +} UADK_PKEY_KEYMGMT; + +#define UADK_PKEY_KEYMGMT_DESCR(nm, alg) \ +static OSSL_FUNC_keymgmt_new_fn uadk_keymgmt_##nm##_new; \ +static OSSL_FUNC_keymgmt_free_fn uadk_keymgmt_##nm##_free; \ +static OSSL_FUNC_keymgmt_get_params_fn uadk_keymgmt_##nm##_get_params; \ +static OSSL_FUNC_keymgmt_gettable_params_fn uadk_keymgmt_##nm##_gettable_params; \ +static OSSL_FUNC_keymgmt_set_params_fn uadk_keymgmt_##nm##_set_params; \ +static OSSL_FUNC_keymgmt_settable_params_fn uadk_keymgmt_##nm##_settable_params; \ +static OSSL_FUNC_keymgmt_gen_init_fn uadk_keymgmt_##nm##_gen_init; \ +static OSSL_FUNC_keymgmt_gen_set_template_fn uadk_keymgmt_##nm##_gen_set_template; \ +static OSSL_FUNC_keymgmt_gen_set_params_fn uadk_keymgmt_##nm##_gen_set_params; \ +static OSSL_FUNC_keymgmt_gen_settable_params_fn uadk_keymgmt_##nm##_gen_settable_params; \ +static OSSL_FUNC_keymgmt_gen_fn uadk_keymgmt_##nm##_gen; \ +static OSSL_FUNC_keymgmt_gen_cleanup_fn uadk_keymgmt_##nm##_gen_cleanup; \ +static OSSL_FUNC_keymgmt_load_fn uadk_keymgmt_##nm##_load; \ +static OSSL_FUNC_keymgmt_has_fn uadk_keymgmt_##nm##_has; \ +static OSSL_FUNC_keymgmt_validate_fn uadk_keymgmt_##nm##_validate; \ +static OSSL_FUNC_keymgmt_match_fn uadk_keymgmt_##nm##_match; \ +static OSSL_FUNC_keymgmt_import_fn uadk_keymgmt_##nm##_import; \ +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; \ +const OSSL_DISPATCH uadk_##nm##_keymgmt_functions[] = { \ + { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))uadk_keymgmt_##nm##_new }, \ + { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))uadk_keymgmt_##nm##_free }, \ + { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))uadk_keymgmt_##nm##_get_params }, \ + { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, \ + (void (*) (void))uadk_keymgmt_##nm##_gettable_params }, \ + { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*) (void))uadk_keymgmt_##nm##_set_params }, \ + { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, \ + (void (*) (void))uadk_keymgmt_##nm##_settable_params }, \ + { OSSL_FUNC_KEYMGMT_GEN_INIT, (void (*)(void))uadk_keymgmt_##nm##_gen_init }, \ + { OSSL_FUNC_KEYMGMT_GEN_SET_TEMPLATE, \ + (void (*)(void))uadk_keymgmt_##nm##_gen_set_template }, \ + { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, \ + (void (*)(void))uadk_keymgmt_##nm##_gen_set_params }, \ + { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, \ + (void (*)(void))uadk_keymgmt_##nm##_gen_settable_params }, \ + { OSSL_FUNC_KEYMGMT_GEN, (void (*)(void))uadk_keymgmt_##nm##_gen }, \ + { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void (*)(void))uadk_keymgmt_##nm##_gen_cleanup }, \ + { OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))uadk_keymgmt_##nm##_load }, \ + { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))uadk_keymgmt_##nm##_has }, \ + { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))uadk_keymgmt_##nm##_validate }, \ + { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))uadk_keymgmt_##nm##_match }, \ + { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))uadk_keymgmt_##nm##_import }, \ + { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, \ + (void (*)(void))uadk_keymgmt_##nm##_import_types }, \ + { 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 }, \ + {0, NULL} \ +}; \ +static UADK_PKEY_KEYMGMT get_default_keymgmt(void) \ +{ \ + static UADK_PKEY_KEYMGMT s_keymgmt; \ + static int initilazed; \ + \ + if (!initilazed) { \ + UADK_PKEY_KEYMGMT *keymgmt = \ + (UADK_PKEY_KEYMGMT *)EVP_KEYMGMT_fetch(NULL, #alg, "provider=default"); \ + \ + if (keymgmt) { \ + s_keymgmt = *keymgmt; \ + EVP_KEYMGMT_free((EVP_KEYMGMT *)keymgmt); \ + initilazed = 1; \ + } else { \ + fprintf(stderr, "failed to EVP_KEYMGMT_fetch default provider"); \ + } \ + } \ + return s_keymgmt; \ +} \ + +typedef struct { + int name_id; + char *type_name; + const char *description; + OSSL_PROVIDER *prov; + int refcnt; + void *lock; + + OSSL_FUNC_signature_newctx_fn *newctx; + OSSL_FUNC_signature_sign_init_fn *sign_init; + OSSL_FUNC_signature_sign_fn *sign; + OSSL_FUNC_signature_verify_init_fn *verify_init; + OSSL_FUNC_signature_verify_fn *verify; + OSSL_FUNC_signature_verify_recover_init_fn *verify_recover_init; + OSSL_FUNC_signature_verify_recover_fn *verify_recover; + OSSL_FUNC_signature_digest_sign_init_fn *digest_sign_init; + OSSL_FUNC_signature_digest_sign_update_fn *digest_sign_update; + OSSL_FUNC_signature_digest_sign_final_fn *digest_sign_final; + OSSL_FUNC_signature_digest_sign_fn *digest_sign; + OSSL_FUNC_signature_digest_verify_init_fn *digest_verify_init; + OSSL_FUNC_signature_digest_verify_update_fn *digest_verify_update; + OSSL_FUNC_signature_digest_verify_final_fn *digest_verify_final; + OSSL_FUNC_signature_digest_verify_fn *digest_verify; + OSSL_FUNC_signature_freectx_fn *freectx; + OSSL_FUNC_signature_dupctx_fn *dupctx; + OSSL_FUNC_signature_get_ctx_params_fn *get_ctx_params; + OSSL_FUNC_signature_gettable_ctx_params_fn *gettable_ctx_params; + OSSL_FUNC_signature_set_ctx_params_fn *set_ctx_params; + OSSL_FUNC_signature_settable_ctx_params_fn *settable_ctx_params; + OSSL_FUNC_signature_get_ctx_md_params_fn *get_ctx_md_params; + OSSL_FUNC_signature_gettable_ctx_md_params_fn *gettable_ctx_md_params; + OSSL_FUNC_signature_set_ctx_md_params_fn *set_ctx_md_params; + OSSL_FUNC_signature_settable_ctx_md_params_fn *settable_ctx_md_params; +} UADK_PKEY_SIGNATURE; + +#define UADK_PKEY_SIGNATURE_DESCR(nm, alg) \ +static OSSL_FUNC_signature_newctx_fn uadk_signature_##nm##_newctx; \ +static OSSL_FUNC_signature_sign_init_fn uadk_signature_##nm##_sign_init; \ +static OSSL_FUNC_signature_verify_init_fn uadk_signature_##nm##_verify_init; \ +static OSSL_FUNC_signature_sign_fn uadk_signature_##nm##_sign; \ +static OSSL_FUNC_signature_verify_fn uadk_signature_##nm##_verify; \ +static OSSL_FUNC_signature_digest_sign_init_fn uadk_signature_##nm##_digest_sign_init; \ +static OSSL_FUNC_signature_digest_sign_update_fn uadk_signature_##nm##_digest_sign_update; \ +static OSSL_FUNC_signature_digest_sign_final_fn uadk_signature_##nm##_digest_sign_final; \ +static OSSL_FUNC_signature_digest_verify_init_fn uadk_signature_##nm##_digest_verify_init; \ +static OSSL_FUNC_signature_digest_verify_update_fn uadk_signature_##nm##_digest_verify_update; \ +static OSSL_FUNC_signature_digest_verify_final_fn uadk_signature_##nm##_digest_verify_final; \ +static OSSL_FUNC_signature_freectx_fn uadk_signature_##nm##_freectx; \ +static OSSL_FUNC_signature_dupctx_fn uadk_signature_##nm##_dupctx; \ +static OSSL_FUNC_signature_get_ctx_params_fn uadk_signature_##nm##_get_ctx_params; \ +static OSSL_FUNC_signature_gettable_ctx_params_fn uadk_signature_##nm##_gettable_ctx_params; \ +static OSSL_FUNC_signature_set_ctx_params_fn uadk_signature_##nm##_set_ctx_params; \ +static OSSL_FUNC_signature_settable_ctx_params_fn uadk_signature_##nm##_settable_ctx_params; \ +static OSSL_FUNC_signature_get_ctx_md_params_fn uadk_signature_##nm##_get_ctx_md_params; \ +static OSSL_FUNC_signature_gettable_ctx_md_params_fn uadk_signature_##nm##_gettable_ctx_md_params; \ +static OSSL_FUNC_signature_set_ctx_md_params_fn uadk_signature_##nm##_set_ctx_md_params; \ +static OSSL_FUNC_signature_settable_ctx_md_params_fn uadk_signature_##nm##_settable_ctx_md_params; \ +const OSSL_DISPATCH uadk_##nm##_signature_functions[] = { \ + { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))uadk_signature_##nm##_newctx }, \ + { OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))uadk_signature_##nm##_sign_init }, \ + { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))uadk_signature_##nm##_sign }, \ + { OSSL_FUNC_SIGNATURE_VERIFY_INIT, (void (*)(void))uadk_signature_##nm##_verify_init }, \ + { OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))uadk_signature_##nm##_verify }, \ + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_INIT, \ + (void (*)(void))uadk_signature_##nm##_digest_sign_init }, \ + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_UPDATE, \ + (void (*)(void))uadk_signature_##nm##_digest_sign_update }, \ + { OSSL_FUNC_SIGNATURE_DIGEST_SIGN_FINAL, \ + (void (*)(void))uadk_signature_##nm##_digest_sign_final }, \ + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_INIT, \ + (void (*)(void))uadk_signature_##nm##_digest_verify_init }, \ + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_UPDATE, \ + (void (*)(void))uadk_signature_##nm##_digest_verify_update }, \ + { OSSL_FUNC_SIGNATURE_DIGEST_VERIFY_FINAL, \ + (void (*)(void))uadk_signature_##nm##_digest_verify_final }, \ + { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))uadk_signature_##nm##_freectx }, \ + { OSSL_FUNC_SIGNATURE_DUPCTX, (void (*)(void))uadk_signature_##nm##_dupctx }, \ + { OSSL_FUNC_SIGNATURE_GET_CTX_PARAMS, \ + (void (*)(void))uadk_signature_##nm##_get_ctx_params }, \ + { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_PARAMS, \ + (void (*)(void))uadk_signature_##nm##_gettable_ctx_params }, \ + { OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS, \ + (void (*)(void))uadk_signature_##nm##_set_ctx_params }, \ + { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_PARAMS, \ + (void (*)(void))uadk_signature_##nm##_settable_ctx_params }, \ + { OSSL_FUNC_SIGNATURE_GET_CTX_MD_PARAMS, \ + (void (*)(void))uadk_signature_##nm##_get_ctx_md_params }, \ + { OSSL_FUNC_SIGNATURE_GETTABLE_CTX_MD_PARAMS, \ + (void (*)(void))uadk_signature_##nm##_gettable_ctx_md_params }, \ + { OSSL_FUNC_SIGNATURE_SET_CTX_MD_PARAMS, \ + (void (*)(void))uadk_signature_##nm##_set_ctx_md_params }, \ + { OSSL_FUNC_SIGNATURE_SETTABLE_CTX_MD_PARAMS, \ + (void (*)(void))uadk_signature_##nm##_settable_ctx_md_params }, \ + { 0, NULL } \ +}; \ +static UADK_PKEY_SIGNATURE get_default_signature(void) \ +{ \ + static UADK_PKEY_SIGNATURE s_signature; \ + static int initilazed; \ + \ + if (!initilazed) { \ + UADK_PKEY_SIGNATURE *signature = \ + (UADK_PKEY_SIGNATURE *)EVP_SIGNATURE_fetch(NULL, #alg, \ + "provider=default"); \ + \ + if (signature) { \ + s_signature = *signature; \ + EVP_SIGNATURE_free((EVP_SIGNATURE *)signature); \ + initilazed = 1; \ + } else { \ + fprintf(stderr, "failed to EVP_SIGNATURE_fetch default provider"); \ + } \ + } \ + return s_signature; \ +} \ + +typedef struct { + int name_id; + char *type_name; + const char *description; + OSSL_PROVIDER *prov; + int refcnt; + void *lock; + + OSSL_FUNC_asym_cipher_newctx_fn *newctx; + OSSL_FUNC_asym_cipher_encrypt_init_fn *encrypt_init; + OSSL_FUNC_asym_cipher_encrypt_fn *encrypt; + OSSL_FUNC_asym_cipher_decrypt_init_fn *decrypt_init; + OSSL_FUNC_asym_cipher_decrypt_fn *decrypt; + OSSL_FUNC_asym_cipher_freectx_fn *freectx; + OSSL_FUNC_asym_cipher_dupctx_fn *dupctx; + OSSL_FUNC_asym_cipher_get_ctx_params_fn *get_ctx_params; + OSSL_FUNC_asym_cipher_gettable_ctx_params_fn *gettable_ctx_params; + OSSL_FUNC_asym_cipher_set_ctx_params_fn *set_ctx_params; + OSSL_FUNC_asym_cipher_settable_ctx_params_fn *settable_ctx_params; +} UADK_PKEY_ASYM_CIPHER; + +#define UADK_PKEY_ASYM_CIPHER_DESCR(nm, alg) \ +static OSSL_FUNC_asym_cipher_newctx_fn uadk_asym_cipher_##nm##_newctx; \ +static OSSL_FUNC_asym_cipher_encrypt_init_fn uadk_asym_cipher_##nm##_encrypt_init; \ +static OSSL_FUNC_asym_cipher_encrypt_fn uadk_asym_cipher_##nm##_encrypt; \ +static OSSL_FUNC_asym_cipher_decrypt_init_fn uadk_asym_cipher_##nm##_decrypt_init; \ +static OSSL_FUNC_asym_cipher_decrypt_fn uadk_asym_cipher_##nm##_decrypt; \ +static OSSL_FUNC_asym_cipher_freectx_fn uadk_asym_cipher_##nm##_freectx; \ +static OSSL_FUNC_asym_cipher_dupctx_fn uadk_asym_cipher_##nm##_dupctx; \ +static OSSL_FUNC_asym_cipher_get_ctx_params_fn uadk_asym_cipher_##nm##_get_ctx_params; \ +static OSSL_FUNC_asym_cipher_gettable_ctx_params_fn uadk_asym_cipher_##nm##_gettable_ctx_params; \ +static OSSL_FUNC_asym_cipher_set_ctx_params_fn uadk_asym_cipher_##nm##_set_ctx_params; \ +static OSSL_FUNC_asym_cipher_settable_ctx_params_fn uadk_asym_cipher_##nm##_settable_ctx_params; \ +const OSSL_DISPATCH uadk_##nm##_asym_cipher_functions[] = { \ + { OSSL_FUNC_ASYM_CIPHER_NEWCTX, (void (*)(void))uadk_asym_cipher_##nm##_newctx }, \ + { OSSL_FUNC_ASYM_CIPHER_ENCRYPT_INIT, \ + (void (*)(void))uadk_asym_cipher_##nm##_encrypt_init }, \ + { OSSL_FUNC_ASYM_CIPHER_ENCRYPT, (void (*)(void))uadk_asym_cipher_##nm##_encrypt }, \ + { OSSL_FUNC_ASYM_CIPHER_DECRYPT_INIT, \ + (void (*)(void))uadk_asym_cipher_##nm##_decrypt_init }, \ + { OSSL_FUNC_ASYM_CIPHER_DECRYPT, (void (*)(void))uadk_asym_cipher_##nm##_decrypt }, \ + { OSSL_FUNC_ASYM_CIPHER_FREECTX, (void (*)(void))uadk_asym_cipher_##nm##_freectx }, \ + { OSSL_FUNC_ASYM_CIPHER_DUPCTX, (void (*)(void))uadk_asym_cipher_##nm##_dupctx }, \ + { OSSL_FUNC_ASYM_CIPHER_GET_CTX_PARAMS, \ + (void (*)(void))uadk_asym_cipher_##nm##_get_ctx_params }, \ + { OSSL_FUNC_ASYM_CIPHER_GETTABLE_CTX_PARAMS, \ + (void (*)(void))uadk_asym_cipher_##nm##_gettable_ctx_params }, \ + { OSSL_FUNC_ASYM_CIPHER_SET_CTX_PARAMS, \ + (void (*)(void))uadk_asym_cipher_##nm##_set_ctx_params }, \ + { OSSL_FUNC_ASYM_CIPHER_SETTABLE_CTX_PARAMS, \ + (void (*)(void))uadk_asym_cipher_##nm##_settable_ctx_params }, \ + { 0, NULL } \ +}; \ +static UADK_PKEY_ASYM_CIPHER get_default_asym_cipher(void) \ +{ \ + static UADK_PKEY_ASYM_CIPHER s_asym_cipher; \ + static int initilazed; \ + \ + if (!initilazed) { \ + UADK_PKEY_ASYM_CIPHER *asym_cipher = \ + (UADK_PKEY_ASYM_CIPHER *)EVP_ASYM_CIPHER_fetch(NULL, #alg, \ + "provider=default"); \ + \ + if (asym_cipher) { \ + s_asym_cipher = *asym_cipher; \ + EVP_ASYM_CIPHER_free((EVP_ASYM_CIPHER *)asym_cipher); \ + initilazed = 1; \ + } else { \ + fprintf(stderr, "failed to EVP_ASYM_CIPHER_fetch default provider"); \ + } \ + } \ + return s_asym_cipher; \ +} \ + +handle_t uadk_prov_ecc_alloc_sess(const EC_KEY *eckey, char *alg); +int uadk_prov_ecc_crypto(handle_t sess, struct wd_ecc_req *req, void *usr); +int uadk_prov_keymgmt_get_support_state(int alg_tag); +int uadk_prov_ecc_get_numa_id(void); +void uadk_prov_ecc_cb(void *req_t); +int uadk_prov_ecc_get_rand(char *out, size_t out_len, void *usr); +int uadk_prov_ecc_poll(void *ctx); +int uadk_prov_ecc_genctx_check(struct ec_gen_ctx *gctx, EC_KEY *ec); +void uadk_prov_keymgmt_alg(void); +void uadk_prov_ecc_fill_req(struct wd_ecc_req *req, unsigned int op, void *in, void *out); +int uadk_prov_signature_get_support_state(int alg_tag); +int uadk_prov_ecc_set_private_key(handle_t sess, const EC_KEY *eckey); +bool uadk_prov_is_all_zero(const unsigned char *data, size_t dlen); +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); + +#endif diff --git a/src/uadk_prov_sm2.c b/src/uadk_prov_sm2.c new file mode 100644 index 0000000..2aaf10a --- /dev/null +++ b/src/uadk_prov_sm2.c @@ -0,0 +1,3146 @@ +// 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 <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/bn.h> +#include <uadk/wd_ecc.h> +#include <uadk/wd_sched.h> +#include "uadk.h" +#include "uadk_async.h" +#include "uadk_prov.h" +#include "uadk_prov_der_writer.h" +#include "uadk_prov_packet.h" +#include "uadk_prov_pkey.h" + +#define SM2_KEY_BYTES 32 +#define SM2_GET_SIGNLEN 1 +#define SM3_DIGEST_LENGTH 32 + +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), + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_ENGINE, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM sm2_asym_cipher_known_gettable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM sm2_sig_known_settable_ctx_params[] = { + OSSL_PARAM_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, NULL), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_DIST_ID, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM sm2_sig_known_gettable_ctx_params[] = { + OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0), + OSSL_PARAM_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, NULL), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_END +}; + +struct sm2_prov { + int pid; +}; + +static struct sm2_prov g_sm2_prov; + +enum { + CTX_INIT_FAIL = -1, + CTX_UNINIT, + CTX_INIT_SUCC +}; + +/* Structure for sm2 key related data */ +typedef struct { + BIGNUM *order; + /* Key and paramgen group */ + EC_GROUP *gen_group; + const BIGNUM *prikey; + const EC_POINT *pubkey; +} SM2_PKEY_DATA; + +/* Structure for sm2 digest method related data */ +typedef struct { + /* The nid of digest method */ + int md_nid; + /* Legacy: update status of digest method, changed (1), unchanged (0) */ + int md_update_status; + /* + * References to the underlying digest implementation. + * |md| caches the digest, always. + * |alloc_md| only holds a reference to an explicitly fetched digest. + */ + EVP_MD_CTX *mdctx; + EVP_MD *md; + EVP_MD *alloc_md; + size_t mdsize; +} SM2_MD_DATA; + +/* Structure for SM2 private context in uadk_provider, related to UADK */ +typedef struct { + int init_status; + /* The session related to UADK */ + handle_t sess; + SM2_PKEY_DATA *sm2_pd; + SM2_MD_DATA *sm2_md; +} SM2_PROV_CTX; + +/* + * Provider sm2 signature algorithm context structure. + * Upper application will use, such as, EVP_PKEY_CTX *ctx, + * this structure will be called like: ctx->op.sig.algctx, + * the 'algctx' can be defined by our uadk_provider, which is + * the structure below. + */ +typedef struct { + OSSL_LIB_CTX *libctx; + char *propq; + /* Use EC_KEY refer to keymgmt */ + EC_KEY *key; + + /* + * Flag to termine if the 'z' digest needs to be computed and fed to the + * hash function. + * This flag should be set on initialization and the compuation should + * be performed only once, on first update. + */ + unsigned int flag_compute_z_digest : 1; + + /* Will used by openssl, but not used by UADK, so put it outside SM2_PROV_CTX */ + char mdname[OSSL_MAX_NAME_SIZE]; + + /* The Algorithm Identifier of the combined signature algorithm */ + unsigned char aid_buf[OSSL_MAX_ALGORITHM_ID_SIZE]; + unsigned char *aid; + size_t aid_len; + + /* + * SM2 ID used for calculating the Z value, + * distinguishing Identifier, ISO/IEC 15946-3 + */ + unsigned char *id; + size_t id_len; + /* Indicates if the 'id' field is set (1) or not (0) */ + int id_set; + + SM2_PROV_CTX *sm2_pctx; +} PROV_SM2_SIGN_CTX; + +typedef struct { + OSSL_LIB_CTX *libctx; + /* Use EC_KEY refer to keymgmt */ + EC_KEY *key; + char mdname[OSSL_MAX_NAME_SIZE]; + + SM2_PROV_CTX *sm2_pctx; +} PROV_SM2_ASYM_CTX; + +struct sm2_param { + /* + * p: BIGNUM with the prime number (GFp) or the polynomial + * defining the underlying field (GF2m) + */ + BIGNUM *p; + /* a: BIGNUM for parameter a of the equation */ + BIGNUM *a; + /* b: BIGNUM for parameter b of the equation */ + BIGNUM *b; + /* xG: BIGNUM for the x-coordinate value of G point */ + BIGNUM *xG; + /* yG: BIGNUM for the y-coordinate value of G point */ + BIGNUM *yG; + /* xA: BIGNUM for the x-coordinate value of PA point */ + BIGNUM *xA; + /* yA: BIGNUM for the y-coordinate value of PA point */ + BIGNUM *yA; +}; + +typedef struct sm2_ciphertext { + BIGNUM *C1x; + BIGNUM *C1y; + ASN1_OCTET_STRING *C3; + ASN1_OCTET_STRING *C2; +} SM2_Ciphertext; + +DECLARE_ASN1_FUNCTIONS(SM2_Ciphertext) + +ASN1_SEQUENCE(SM2_Ciphertext) = { + ASN1_SIMPLE(SM2_Ciphertext, C1x, BIGNUM), + ASN1_SIMPLE(SM2_Ciphertext, C1y, BIGNUM), + ASN1_SIMPLE(SM2_Ciphertext, C3, ASN1_OCTET_STRING), + ASN1_SIMPLE(SM2_Ciphertext, C2, ASN1_OCTET_STRING), +} ASN1_SEQUENCE_END(SM2_Ciphertext) + +IMPLEMENT_ASN1_FUNCTIONS(SM2_Ciphertext) + +/** + * Create an uadk provider side sm2 key object. + * + * @param provctx The provider context. + * @return Return created key object if success, return NULL if failed. + */ +static void *uadk_keymgmt_sm2_new(void *provctx) +{ + if (!get_default_keymgmt().new_fun) { + fprintf(stderr, "failed to get keymgmt new function\n"); + return NULL; + } + + return get_default_keymgmt().new_fun(provctx); +} + +/** + * Release an uadk provider side sm2 key object + * + * @param keydata Key object related data. + */ +static void uadk_keymgmt_sm2_free(void *keydata) +{ + if (!get_default_keymgmt().free) { + fprintf(stderr, "failed to get keymgmt free function\n"); + return; + } + + get_default_keymgmt().free(keydata); +} + +static int uadk_keymgmt_sm2_get_params(void *key, OSSL_PARAM params[]) +{ + if (!get_default_keymgmt().get_params) { + fprintf(stderr, "failed to get keymgmt get_params function\n"); + return UADK_P_FAIL; + } + + return get_default_keymgmt().get_params(key, params); +} + +static const OSSL_PARAM *uadk_keymgmt_sm2_gettable_params(void *provctx) +{ + if (!get_default_keymgmt().gettable_params) { + fprintf(stderr, "failed to get keymgmt gettable_params function\n"); + return NULL; + } + + return get_default_keymgmt().gettable_params(provctx); +} + +static int uadk_keymgmt_sm2_set_params(void *key, const OSSL_PARAM params[]) +{ + if (!get_default_keymgmt().set_params) { + fprintf(stderr, "failed to get keymgmt set_params function\n"); + return UADK_P_FAIL; + } + + return get_default_keymgmt().set_params(key, params); +} + +static int uadk_keymgmt_sm2_gen_set_template(void *genctx, void *templates) +{ + if (!get_default_keymgmt().gen_set_template) { + fprintf(stderr, "failed to get keymgmt gen_set_template function\n"); + return UADK_P_FAIL; + } + + return get_default_keymgmt().gen_set_template(genctx, templates); +} + +static void uadk_keymgmt_sm2_gen_cleanup(void *genctx) +{ + if (!get_default_keymgmt().gen_cleanup) { + fprintf(stderr, "failed to get keymgmt gen_cleanup function\n"); + return; + } + + get_default_keymgmt().gen_cleanup(genctx); +} + +static void *uadk_keymgmt_sm2_load(const void *reference, size_t reference_sz) +{ + if (!get_default_keymgmt().load) { + fprintf(stderr, "failed to get keymgmt load function\n"); + return NULL; + } + + return get_default_keymgmt().load(reference, reference_sz); +} + +static int uadk_keymgmt_sm2_validate(const void *keydata, int selection, int checktype) +{ + if (!get_default_keymgmt().validate) { + fprintf(stderr, "failed to get keymgmt validate function\n"); + return UADK_P_FAIL; + } + + return get_default_keymgmt().validate(keydata, selection, checktype); +} + +static int uadk_keymgmt_sm2_match(const void *keydata1, const void *keydata2, int selection) +{ + if (!get_default_keymgmt().match) { + fprintf(stderr, "failed to get keymgmt validate function\n"); + return UADK_P_FAIL; + } + + return get_default_keymgmt().match(keydata1, keydata2, selection); +} + +/** + * Check if a sm2 key object has specific options, such as public key, + * private key, domain params etc. + * + * @param keydata The key object to check. + * @param selection Check options, like public key, private key, domain params etc. + * @return Return 1 if success, return 0 if failed. + */ +static int uadk_keymgmt_sm2_has(const void *keydata, int selection) +{ + if (!get_default_keymgmt().has) { + fprintf(stderr, "failed to get keymgmt has function\n"); + return UADK_P_FAIL; + } + + return get_default_keymgmt().has(keydata, selection); +} + +/** + * Import a sm2 key object with key related params. + * + * @param keydata The key object to import. + * @param selection The key params to import. + * @param params OSSL params. + * @return Return 1 if success, return 0 if failed. + */ +static int uadk_keymgmt_sm2_import(void *keydata, int selection, const OSSL_PARAM params[]) +{ + if (!get_default_keymgmt().import) { + fprintf(stderr, "failed to get keymgmt import function\n"); + return UADK_P_FAIL; + } + + return get_default_keymgmt().import(keydata, selection, params); +} + +/** + * Returns an array of argument types based on the type selected. + * + * @param selection Type of the selected key. + * @return Return param type array. + */ +static const OSSL_PARAM *uadk_keymgmt_sm2_import_types(int selection) +{ + if (!get_default_keymgmt().import_types) { + fprintf(stderr, "failed to get keymgmt import_types function\n"); + return NULL; + } + + return get_default_keymgmt().import_types(selection); +} + +static int uadk_keymgmt_sm2_export(void *keydata, int selection, + OSSL_CALLBACK *param_callback, void *cbarg) +{ + if (!get_default_keymgmt().export_fun) { + fprintf(stderr, "failed to get keymgmt export function\n"); + return UADK_P_FAIL; + } + + return get_default_keymgmt().export_fun(keydata, selection, param_callback, cbarg); +} + +static const OSSL_PARAM *uadk_keymgmt_sm2_export_types(int selection) +{ + if (!get_default_keymgmt().export_types) { + fprintf(stderr, "failed to get keymgmt export_types function\n"); + return NULL; + } + + return get_default_keymgmt().export_types(selection); +} + +static void *uadk_keymgmt_sm2_dup(const void *keydata_from, int selection) +{ + if (!get_default_keymgmt().dup) { + fprintf(stderr, "failed to get keymgmt dup function\n"); + return NULL; + } + + return get_default_keymgmt().dup(keydata_from, selection); +} + +/** + * Init sm2 key generation context. + * + * @param provctx The provider context. + * @param selection The selected params related to the key. + * @param params OSSL params. + * @return Return inited key generation context if success, return NULL if failed. + */ +static void *uadk_keymgmt_sm2_gen_init(void *provctx, int selection, + const OSSL_PARAM params[]) +{ + if (!get_default_keymgmt().gen_init) { + fprintf(stderr, "failed to get keymgmt gen_init function\n"); + return NULL; + } + + return get_default_keymgmt().gen_init(provctx, selection, params); +} + +/** + * Set sm2 key params + * + * @param genctx The pkey generation context. + * @param params OSSL params array. + * @return Return 1 if success, return 0 if failed. + */ +static int uadk_keymgmt_sm2_gen_set_params(void *genctx, const OSSL_PARAM params[]) +{ + if (!get_default_keymgmt().gen_set_params) { + fprintf(stderr, "failed to get keymgmt gen_set_params function\n"); + return UADK_P_FAIL; + } + + return get_default_keymgmt().gen_set_params(genctx, params); +} + +static const OSSL_PARAM *uadk_keymgmt_sm2_settable_params(ossl_unused void *provctx) +{ + if (!get_default_keymgmt().settable_params) { + fprintf(stderr, "failed to get keymgmt settable_params function\n"); + return NULL; + } + + return get_default_keymgmt().settable_params(provctx); +} + +/** + * Get the settable params list. + * + * @param genctx key generation context. + * @param provctx provider context. + * @return Return params list if success, return NULL if failed. + */ +static const OSSL_PARAM *uadk_keymgmt_sm2_gen_settable_params(ossl_unused void *genctx, + ossl_unused void *provctx) +{ + if (!get_default_keymgmt().gen_settable_params) { + fprintf(stderr, "failed to get keymgmt gen_settable_params function\n"); + return NULL; + } + + return get_default_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; +} + +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); + + if (!ecc_out) { + fprintf(stderr, "failed to new sign out\n"); + return UADK_P_FAIL; + } + + uadk_prov_ecc_fill_req(req, WD_SM2_KG, NULL, ecc_out); + + return UADK_P_SUCCESS; +} + +static int uadk_prov_sm2_set_key_to_ec_key(EC_KEY *ec, struct wd_ecc_req *req) +{ + unsigned char buff[ECC_POINT_SIZE(SM2_KEY_BYTES) + 1] = {0}; + struct wd_ecc_point *pubkey = NULL; + struct wd_dtb *privkey = NULL; + int x_offset, y_offset, ret; + const EC_GROUP *group; + EC_POINT *point, *ptr; + BIGNUM *tmp; + + wd_sm2_get_kg_out_params(req->dst, &privkey, &pubkey); + if (!privkey || !pubkey) { + fprintf(stderr, "failed to get privkey or pubkey\n"); + return UADK_P_FAIL; + } + + if (pubkey->x.dsize > SM2_KEY_BYTES || pubkey->y.dsize > SM2_KEY_BYTES) { + fprintf(stderr, "invalid pubkey size: %u, %u\n", pubkey->x.dsize, pubkey->y.dsize); + return UADK_P_FAIL; + } + + tmp = BN_bin2bn((unsigned char *)privkey->data, privkey->dsize, NULL); + ret = EC_KEY_set_private_key(ec, tmp); + BN_free(tmp); + if (!ret) { + fprintf(stderr, "failed to EC KEY set private key\n"); + return UADK_P_FAIL; + } + + group = EC_KEY_get0_group(ec); + point = EC_POINT_new(group); + if (!point) { + fprintf(stderr, "failed to EC POINT new\n"); + return UADK_P_FAIL; + } + + buff[0] = UADK_OCTET_STRING; + /* The component of sm2 pubkey need a SM2_KEY_BYTES align */ + x_offset = 1 + SM2_KEY_BYTES - pubkey->x.dsize; + y_offset = 1 + ECC_POINT_SIZE(SM2_KEY_BYTES) - pubkey->y.dsize; + memcpy(buff + x_offset, pubkey->x.data, pubkey->x.dsize); + memcpy(buff + y_offset, pubkey->y.data, pubkey->y.dsize); + tmp = BN_bin2bn(buff, ECC_POINT_SIZE(SM2_KEY_BYTES) + 1, NULL); + ptr = EC_POINT_bn2point(group, tmp, point, NULL); + BN_free(tmp); + if (!ptr) { + fprintf(stderr, "failed to EC_POINT_bn2point\n"); + EC_POINT_free(point); + return UADK_P_FAIL; + } + + ret = EC_KEY_set_public_key(ec, point); + EC_POINT_free(point); + if (!ret) { + fprintf(stderr, "failed to EC_KEY_set_public_key\n"); + return UADK_P_FAIL; + } + + return UADK_P_SUCCESS; +} + +static int uadk_prov_sm2_check_priv_key(EC_KEY *eckey) +{ + BIGNUM *priv_key; + int ret; + + priv_key = (BIGNUM *)EC_KEY_get0_private_key(eckey); + if (priv_key) + return UADK_P_SUCCESS; + + priv_key = BN_new(); + if (!priv_key) { + fprintf(stderr, "failed to BN_new priv_key\n"); + return UADK_P_FAIL; + } + + ret = EC_KEY_set_private_key(eckey, priv_key); + if (!ret) + fprintf(stderr, "failed to set private key\n"); + + BN_free(priv_key); + + return ret; +} + +static int uadk_prov_sm2_keygen(EC_KEY *eckey) +{ + struct wd_ecc_req req = {0}; + handle_t sess; + int ret; + + ret = uadk_prov_sm2_check_priv_key(eckey); + if (ret == UADK_P_FAIL) + goto error; + + sess = uadk_prov_ecc_alloc_sess(eckey, "sm2"); + if (sess == (handle_t)0) + goto error; + + ret = uadk_prov_sm2_keygen_init_iot(sess, &req); + if (ret == UADK_P_FAIL) + goto free_sess; + + ret = uadk_prov_ecc_crypto(sess, &req, (void *)sess); + if (ret == UADK_P_FAIL) + goto uninit_iot; + + ret = uadk_prov_sm2_set_key_to_ec_key(eckey, &req); + if (ret == UADK_P_FAIL) + goto uninit_iot; + + wd_ecc_del_out(sess, req.dst); + wd_ecc_free_sess(sess); + + return UADK_P_SUCCESS; + +uninit_iot: + wd_ecc_del_out(sess, req.dst); +free_sess: + wd_ecc_free_sess(sess); +error: + return UADK_P_FAIL; +} + +/** + * @brief Generate SM2 key pair. + * + * @param genctx Key generation context. + * @param osslcb Callback function. + * @param cbarg The param of callback function. + * + * @return Return generated key pair if success, return NULL if failed. + */ +static void *uadk_keymgmt_sm2_gen(void *genctx, OSSL_CALLBACK *osslcb, void *cbarg) +{ + struct ec_gen_ctx *gctx = genctx; + EC_KEY *ec = NULL; + int ret; + + if (gctx == NULL) { + fprintf(stderr, "invalid: the generation context is NULL\n"); + return NULL; + } + + ec = EC_KEY_new_ex(gctx->libctx, NULL); + if (ec == NULL) { + fprintf(stderr, "failed to EC_KEY_new_ex\n"); + return NULL; + } + + ret = uadk_prov_ecc_genctx_check(genctx, ec); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to check genctx\n"); + goto free_ec_key; + } + + ret = uadk_prov_keymgmt_get_support_state(KEYMGMT_SM2); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to get hardware sm2 keygen support\n"); + goto free_ec_key; + } + + /* SM2 hardware init */ + ret = uadk_prov_sm2_init(); + if (ret) { + fprintf(stderr, "failed to init sm2\n"); + goto free_ec_key; + } + + /* Do sm2 keygen with hardware */ + if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) { + fprintf(stderr, "invalid keymgmt keypair selection\n"); + goto uninit; + } + + ret = uadk_prov_sm2_keygen(ec); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to generate sm2 key\n"); + goto uninit; + } + + return ec; + +uninit: + uadk_prov_sm2_uninit(); +free_ec_key: + /* Something went wrong, throw the key away */ + EC_KEY_free(ec); + return NULL; +} + +static void *uadk_signature_sm2_newctx(void *provctx, const char *propq) +{ + PROV_SM2_SIGN_CTX *psm2ctx = OPENSSL_zalloc(sizeof(PROV_SM2_SIGN_CTX)); + SM2_PROV_CTX *smctx; + + if (psm2ctx == NULL) { + fprintf(stderr, "failed to alloc sm2 signature ctx\n"); + return NULL; + } + /* The libctx maybe NULL, if libctx is NULL, will use default ctx. */ + psm2ctx->libctx = prov_libctx_of(provctx); + + smctx = OPENSSL_zalloc(sizeof(SM2_PROV_CTX)); + if (smctx == NULL) { + fprintf(stderr, "failed to alloc sm2 prov ctx\n"); + goto free_ctx; + } + + smctx->sm2_pd = OPENSSL_zalloc(sizeof(SM2_PKEY_DATA)); + if (smctx->sm2_pd == NULL) { + fprintf(stderr, "failed to alloc sm2 pkey data\n"); + goto free_smctx; + } + + smctx->sm2_md = OPENSSL_zalloc(sizeof(SM2_MD_DATA)); + if (smctx->sm2_md == NULL) { + fprintf(stderr, "failed to alloc sm2 md data\n"); + goto free_pd; + } + + /* + * Use SM3 for digest method in default, other digest algs + * can be set with set_ctx_params API. + */ + smctx->sm2_md->mdsize = SM3_DIGEST_LENGTH; + smctx->sm2_md->md_nid = NID_sm3; + strcpy(psm2ctx->mdname, OSSL_DIGEST_NAME_SM3); + smctx->sm2_md->mdctx = EVP_MD_CTX_new(); + if (smctx->sm2_md->mdctx == NULL) { + fprintf(stderr, "failed to alloc sm2 mdctx\n"); + goto free_md; + } + + psm2ctx->sm2_pctx = smctx; + + if (propq) { + psm2ctx->propq = OPENSSL_strdup(propq); + if (psm2ctx->propq == NULL) { + fprintf(stderr, "failed to dup propq\n"); + goto free_mdctx; + } + } + + return psm2ctx; + +free_mdctx: + EVP_MD_CTX_free(smctx->sm2_md->mdctx); +free_md: + OPENSSL_free(smctx->sm2_md); +free_pd: + OPENSSL_free(smctx->sm2_pd); +free_smctx: + OPENSSL_free(smctx); +free_ctx: + OPENSSL_free(psm2ctx); + return NULL; +} + +static void uadk_signature_sm2_freectx(void *vpsm2ctx) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + + if (psm2ctx == NULL) + return; + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) + goto free_psm2ctx; + + /* + * Pkey and md related data in smctx->sm2_md and smctx->sm2_pd will + * release by some openssl tools, such as dgst, after call freectx. + * Free pkey and md related data in our provider will cause double-free + * with openssl dgst tool, maybe it is an openssl bug, fix it later. + */ + OPENSSL_free(smctx); + +free_psm2ctx: + if (psm2ctx->propq) + OPENSSL_free(psm2ctx->propq); + if (psm2ctx->key) + EC_KEY_free(psm2ctx->key); + if (psm2ctx->id) + OPENSSL_free(psm2ctx->id); + + OPENSSL_free(psm2ctx); + return; +} + +static int uadk_prov_sm2_check_md_params(SM2_PROV_CTX *smctx) +{ + if (smctx->sm2_md == NULL) { + fprintf(stderr, "invalid: sm2_md is NULL\n"); + return UADK_P_FAIL; + } + + if (smctx->sm2_md->md == NULL) { + fprintf(stderr, "invalid: md is NULL\n"); + return UADK_P_FAIL; + } + + if (smctx->sm2_md->mdctx == NULL) { + fprintf(stderr, "invalid: mdctx is NULL\n"); + return UADK_P_FAIL; + } + + return UADK_P_SUCCESS; +} + +static int uadk_prov_sm2_sig_set_mdname(PROV_SM2_SIGN_CTX *psm2ctx, const char *mdname) +{ + SM2_PROV_CTX *smctx; + + /* If mdname is NULL, no need to set, just return */ + if (mdname == NULL) + return UADK_P_SUCCESS; + + /* 'psm2ctx' has already been checked when call this function, no need to check again */ + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid: smctx is NULL\n"); + return UADK_P_FAIL; + } + + if (smctx->sm2_md == NULL) { + fprintf(stderr, "invalid: smctx->sm2_md is NULL\n"); + return UADK_P_FAIL; + } + + if (smctx->sm2_md->md == NULL) { + smctx->sm2_md->md = EVP_MD_fetch(psm2ctx->libctx, + psm2ctx->mdname, psm2ctx->propq); + if (smctx->sm2_md->md == NULL) { + fprintf(stderr, "failed to fetch digest method\n"); + return UADK_P_FAIL; + } + } + + if (strlen(mdname) >= sizeof(psm2ctx->mdname) || + !EVP_MD_is_a(smctx->sm2_md->md, mdname)) { + fprintf(stderr, "failed to check mdname, digest=%s", mdname); + return UADK_P_FAIL; + } + + OPENSSL_strlcpy(psm2ctx->mdname, mdname, sizeof(psm2ctx->mdname)); + + return UADK_P_SUCCESS; +} + +static int uadk_prov_compute_hash(const char *in, size_t in_len, + char *out, size_t out_len, void *usr) +{ + const EVP_MD *digest = (const EVP_MD *)usr; + int ret = WD_SUCCESS; + EVP_MD_CTX *hash; + + hash = EVP_MD_CTX_new(); + if (!hash) + return -WD_EINVAL; + + if (EVP_DigestInit(hash, digest) == 0 || + EVP_DigestUpdate(hash, in, in_len) == 0 || + EVP_DigestFinal(hash, (void *)out, NULL) == 0) { + fprintf(stderr, "compute hash failed\n"); + ret = -WD_EINVAL; + } + + EVP_MD_CTX_free(hash); + + return ret; +} + +static int uadk_prov_get_hash_type(int nid_hash) +{ + switch (nid_hash) { + case NID_sha1: + return WD_HASH_SHA1; + case NID_sha224: + return WD_HASH_SHA224; + case NID_sha256: + return WD_HASH_SHA256; + case NID_sha384: + return WD_HASH_SHA384; + case NID_sha512: + return WD_HASH_SHA512; + case NID_md4: + return WD_HASH_MD4; + case NID_md5: + return WD_HASH_MD5; + case NID_sm3: + return WD_HASH_SM3; + default: + return -WD_EINVAL; + } +} + +static int uadk_prov_sm2_update_sess(SM2_PROV_CTX *smctx) +{ + const unsigned char sm2_order[] = { + 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x72, 0x03, 0xdf, 0x6b, 0x21, 0xc6, 0x05, 0x2b, + 0x53, 0xbb, 0xf4, 0x09, 0x39, 0xd5, 0x41, 0x23 + }; + struct wd_ecc_sess_setup setup = {0}; + handle_t sess; + BIGNUM *order; + int type; + + setup.alg = "sm2"; + if (smctx->sm2_md->md) { + /* Set hash method */ + setup.hash.cb = uadk_prov_compute_hash; + setup.hash.usr = (void *)smctx->sm2_md->md; + type = uadk_prov_get_hash_type(smctx->sm2_md->md_nid); + if (type < 0) { + fprintf(stderr, "uadk not support hash nid %d\n", + smctx->sm2_md->md_nid); + return UADK_P_FAIL; + } + setup.hash.type = type; + } + + order = BN_bin2bn((void *)sm2_order, sizeof(sm2_order), NULL); + setup.rand.cb = uadk_prov_ecc_get_rand; + setup.rand.usr = (void *)order; + sess = wd_ecc_alloc_sess(&setup); + if (!sess) { + fprintf(stderr, "failed to alloc sess\n"); + BN_free(order); + smctx->init_status = CTX_INIT_FAIL; + return UADK_P_FAIL; + } + + /* Free old session before setting new session */ + if (smctx->sess) + wd_ecc_free_sess(smctx->sess); + smctx->sess = sess; + + smctx->sm2_pd->prikey = NULL; + smctx->sm2_pd->pubkey = NULL; + smctx->sm2_pd->order = order; + + return UADK_P_SUCCESS; +} + +static int uadk_signature_sm2_sign_init(void *vpsm2ctx, void *ec, + const OSSL_PARAM params[]) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + int ret; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: vpsm2ctx is NULL\n"); + return UADK_P_FAIL; + } + + if (ec == NULL && psm2ctx->key == NULL) { + fprintf(stderr, "invalid: sm2 key is NULL\n"); + return UADK_P_FAIL; + } + + if (ec) { + if (!EC_KEY_up_ref(ec)) { + fprintf(stderr, "failed to EC_KEY_up_ref\n"); + return UADK_P_FAIL; + } + EC_KEY_free(psm2ctx->key); + psm2ctx->key = (EC_KEY *)ec; + } + + if (psm2ctx->sm2_pctx == NULL) { + fprintf(stderr, "failed to get smctx\n"); + return UADK_P_FAIL; + } + + /* openssl dgst tool will call sign_init twice, avoid repeated initialization */ + if (psm2ctx->sm2_pctx->init_status == CTX_INIT_SUCC) + return UADK_P_SUCCESS; + + ret = uadk_signature_sm2_set_ctx_params((void *)psm2ctx, params); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to set sm2 sig ctx params\n"); + return ret; + } + + ret = uadk_prov_signature_get_support_state(SIGNATURE_SM2); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to get hardware sm2 signature support\n"); + return ret; + } + + /* Init with UADK */ + ret = uadk_prov_sm2_init(); + if (ret) { + fprintf(stderr, "failed to init sm2\n"); + return UADK_P_FAIL; + } + + psm2ctx->sm2_pctx->init_status = CTX_INIT_SUCC; + + ret = uadk_prov_sm2_update_sess(psm2ctx->sm2_pctx); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to update sess in sign init\n"); + return ret; + } + + return UADK_P_SUCCESS; +} + +static int uadk_signature_sm2_verify_init(void *vpsm2ctx, void *ec, + const OSSL_PARAM params[]) +{ + return uadk_signature_sm2_sign_init(vpsm2ctx, ec, params); +} + +static int uadk_prov_sm2_check_tbs_params(PROV_SM2_SIGN_CTX *psm2ctx, + const unsigned char *tbs, size_t tbslen) +{ + SM2_PROV_CTX *smctx = psm2ctx->sm2_pctx; + + if (smctx == NULL) { + fprintf(stderr, "invalid: ctx is NULL\n"); + return UADK_P_FAIL; + } + + if (smctx->sess == (handle_t)0) { + fprintf(stderr, "invalid: smctx->sess is NULL\n"); + return UADK_P_FAIL; + } + + if (smctx->init_status != CTX_INIT_SUCC) { + fprintf(stderr, "sm2 ctx init did not init\n"); + return UADK_P_FAIL; + } + + if (smctx->sm2_md == NULL) { + fprintf(stderr, "invalid: sm2_md is NULL\n"); + return UADK_P_FAIL; + } + + if (smctx->sm2_md->mdsize != 0 && tbslen != smctx->sm2_md->mdsize) { + fprintf(stderr, "invalid: tbslen(%zu) != mdsize(%zu)\n", + tbslen, smctx->sm2_md->mdsize); + return UADK_P_FAIL; + } + + if (tbslen > SM2_KEY_BYTES) { + fprintf(stderr, "invalid: tbslen(%zu) > SM2_KEY_BYTES(32)\n", tbslen); + return UADK_P_FAIL; + } + + if (uadk_prov_is_all_zero(tbs, tbslen)) { + fprintf(stderr, "invalid: tbs all zero\n"); + return UADK_P_FAIL; + } + + return UADK_P_SUCCESS; +} + +static int uadk_prov_sm2_sign_init_iot(handle_t sess, struct wd_ecc_req *req, + unsigned char *digest, size_t digest_len) +{ + struct wd_ecc_out *ecc_out; + struct wd_ecc_in *ecc_in; + struct wd_dtb e = {0}; + + ecc_out = wd_sm2_new_sign_out(sess); + if (ecc_out == NULL) { + fprintf(stderr, "failed to new sign out\n"); + return UADK_P_FAIL; + } + + e.data = (void *)digest; + e.dsize = digest_len; + ecc_in = wd_sm2_new_sign_in(sess, &e, NULL, NULL, 1); + if (ecc_in == NULL) { + fprintf(stderr, "failed to new sign in\n"); + wd_ecc_del_out(sess, ecc_out); + return UADK_P_FAIL; + } + + uadk_prov_ecc_fill_req(req, WD_SM2_SIGN, ecc_in, ecc_out); + + return UADK_P_SUCCESS; +} + +static int uadk_prov_sm2_update_prikey(PROV_SM2_SIGN_CTX *psm2ctx) +{ + SM2_PROV_CTX *smctx = psm2ctx->sm2_pctx; + EC_KEY *eckey = psm2ctx->key; + const BIGNUM *d; + int ret; + + d = EC_KEY_get0_private_key(eckey); + if (!d) { + fprintf(stderr, "private key not set\n"); + return UADK_P_FAIL; + } + + if (smctx->sm2_pd->prikey && !BN_cmp(d, smctx->sm2_pd->prikey)) { + fprintf(stderr, "private key not set\n"); + return UADK_P_FAIL; + } + + ret = uadk_prov_ecc_set_private_key(smctx->sess, eckey); + if (ret == UADK_P_FAIL) + return ret; + + smctx->sm2_pd->prikey = d; + + return UADK_P_SUCCESS; +} + +static int uadk_prov_sm2_sign_bin_to_ber(struct wd_dtb *r, struct wd_dtb *s, + unsigned char *sig, size_t *siglen) +{ + ECDSA_SIG *e_sig; + BIGNUM *br, *bs; + int sltmp, ret; + + e_sig = ECDSA_SIG_new(); + if (!e_sig) { + fprintf(stderr, "failed to ECDSA_SIG_new\n"); + return UADK_P_FAIL; + } + + br = BN_bin2bn((void *)r->data, r->dsize, NULL); + if (!br) { + fprintf(stderr, "failed to BN_bin2bn r\n"); + goto free_sig; + } + + bs = BN_bin2bn((void *)s->data, s->dsize, NULL); + if (!bs) { + fprintf(stderr, "failed to BN_bin2bn s\n"); + goto free_r; + } + + ret = ECDSA_SIG_set0(e_sig, br, bs); + if (!ret) { + fprintf(stderr, "failed to ECDSA_SIG_set0\n"); + goto free_s; + } + + sltmp = i2d_ECDSA_SIG(e_sig, &sig); + if (sltmp < 0) { + fprintf(stderr, "failed to i2d_ECDSA_SIG\n"); + goto free_s; + } + *siglen = (size_t)sltmp; + + return UADK_P_SUCCESS; + +free_s: + BN_free(bs); +free_r: + BN_free(br); +free_sig: + ECDSA_SIG_free(e_sig); + + return UADK_P_FAIL; +} + +static int uadk_prov_sm2_sign_ber_to_bin(unsigned char *sig, size_t sig_len, + struct wd_dtb *r, struct wd_dtb *s) +{ + const unsigned char *p = sig; + unsigned char *der = NULL; + ECDSA_SIG *e_sig = NULL; + int len1, len2; + BIGNUM *b_r, *b_s; + + e_sig = ECDSA_SIG_new(); + if (!e_sig) { + fprintf(stderr, "failed to ECDSA_SIG_new\n"); + return UADK_P_FAIL; + } + + if (d2i_ECDSA_SIG(&e_sig, &p, sig_len) == NULL) { + fprintf(stderr, "d2i_ECDSA_SIG error\n"); + goto free_sig; + } + + /* Ensure signature uses DER and doesn't have trailing garbage */ + len1 = i2d_ECDSA_SIG(e_sig, &der); + if (len1 != sig_len || memcmp(sig, der, len1) != 0) { + fprintf(stderr, "sig data error, der_len(%d), sig_len(%zu)\n", + len1, sig_len); + goto free_der; + } + + b_r = (void *)ECDSA_SIG_get0_r((const ECDSA_SIG *)e_sig); + if (!b_r) { + fprintf(stderr, "failed to get r\n"); + goto free_der; + } + + b_s = (void *)ECDSA_SIG_get0_s((const ECDSA_SIG *)e_sig); + if (!b_s) { + fprintf(stderr, "failed to get s\n"); + goto free_der; + } + + len1 = BN_num_bytes(b_r); + len2 = BN_num_bytes(b_s); + if (len1 > UADK_ECC_MAX_KEY_BYTES || len2 > UADK_ECC_MAX_KEY_BYTES) { + fprintf(stderr, "r or s bytes = (%d, %d) error\n", len1, len2); + goto free_der; + } + r->dsize = BN_bn2bin(b_r, (void *)r->data); + s->dsize = BN_bn2bin(b_s, (void *)s->data); + + OPENSSL_free(der); + ECDSA_SIG_free(e_sig); + + return UADK_P_SUCCESS; + +free_der: + OPENSSL_free(der); +free_sig: + ECDSA_SIG_free(e_sig); + + return UADK_P_FAIL; +} + +static int uadk_prov_sm2_sign(PROV_SM2_SIGN_CTX *psm2ctx, + unsigned char *sig, size_t *siglen, + const unsigned char *tbs, size_t tbslen) +{ + SM2_PROV_CTX *smctx = psm2ctx->sm2_pctx; + struct wd_ecc_req req = {0}; + struct wd_dtb *r = NULL; + struct wd_dtb *s = NULL; + int ret; + + ret = uadk_prov_sm2_sign_init_iot(smctx->sess, &req, (void *)tbs, tbslen); + if (ret == UADK_P_FAIL) + return ret; + + ret = uadk_prov_sm2_update_prikey(psm2ctx); + if (ret == UADK_P_FAIL) + return ret; + + ret = uadk_prov_ecc_crypto(smctx->sess, &req, smctx); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to uadk_ecc_crypto, ret = %d\n", ret); + return ret; + } + + wd_sm2_get_sign_out_params(req.dst, &r, &s); + if (!r || !s) { + fprintf(stderr, "failed to get sign result\n"); + return UADK_P_FAIL; + } + + ret = uadk_prov_sm2_sign_bin_to_ber(r, s, sig, siglen); + if (ret == UADK_P_FAIL) + goto uninit_iot; + + wd_ecc_del_in(smctx->sess, req.src); + wd_ecc_del_out(smctx->sess, req.dst); + + return UADK_P_SUCCESS; + +uninit_iot: + wd_ecc_del_in(smctx->sess, req.src); + wd_ecc_del_out(smctx->sess, req.dst); + + return UADK_P_FAIL; +} + +static int uadk_signature_sm2_sign(void *vpsm2ctx, unsigned char *sig, size_t *siglen, + size_t sigsize, const unsigned char *tbs, size_t tbslen) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + int ret, ecsize; + size_t sltmp; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: psm2ctx is NULL\n"); + return UADK_P_FAIL; + } + + if (psm2ctx->key == NULL) { + fprintf(stderr, "invalid: sm2 ec is NULL\n"); + return UADK_P_FAIL; + } + + ecsize = ECDSA_size(psm2ctx->key); + if (ecsize <= 0) { + fprintf(stderr, "ecsize error %d\n", ecsize); + return UADK_P_FAIL; + } + + /* + * If 'sig' is NULL, users can use sm2_decrypt API to obtain the valid 'siglen' first, + * then users use the value of 'signlen' to alloc the memory of 'sig' and call the + * sm2_decrypt API a second time to do the decryption task. + */ + if (sig == NULL) { + *siglen = (size_t)ecsize; + return SM2_GET_SIGNLEN; + } + + if (sigsize < (size_t)ecsize) { + fprintf(stderr, "sigsize(%zu) < ecsize(%d)\n", sigsize, ecsize); + return UADK_P_FAIL; + } + + ret = uadk_prov_sm2_check_tbs_params(psm2ctx, tbs, tbslen); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to check sm2 signature params\n"); + return ret; + } + + ret = uadk_prov_sm2_sign(psm2ctx, sig, &sltmp, tbs, tbslen); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to do sm2 sign\n"); + return ret; + } + + *siglen = sltmp; + + return UADK_P_SUCCESS; +} + +static int uadk_prov_sm2_verify_init_iot(handle_t sess, struct wd_ecc_req *req, + struct wd_dtb *e, struct wd_dtb *r, + struct wd_dtb *s) +{ + struct wd_ecc_in *ecc_in; + + ecc_in = wd_sm2_new_verf_in(sess, e, r, s, NULL, 1); + if (!ecc_in) { + fprintf(stderr, "failed to new verf in\n"); + return UADK_E_FAIL; + } + + uadk_prov_ecc_fill_req(req, WD_SM2_VERIFY, ecc_in, NULL); + + return UADK_E_SUCCESS; +} + +static int uadk_prov_sm2_update_public_key(SM2_PROV_CTX *smctx, EC_KEY *eckey) +{ + SM2_PKEY_DATA *spd = smctx->sm2_pd; + const EC_GROUP *group; + const EC_POINT *point; + int ret; + + point = EC_KEY_get0_public_key(eckey); + if (point == NULL) { + fprintf(stderr, "pubkey not set!\n"); + return UADK_E_FAIL; + } + + if (spd->pubkey) { + group = EC_KEY_get0_group(eckey); + if (group == NULL) { + fprintf(stderr, "failed to get group\n"); + return UADK_E_FAIL; + } + + ret = EC_POINT_cmp(group, (void *)spd->pubkey, point, NULL); + if (ret == UADK_E_FAIL) { + fprintf(stderr, "failed to do EC_POINT_cmp\n"); + return ret; + } + } + + ret = uadk_prov_ecc_set_public_key(smctx->sess, eckey); + if (ret == UADK_E_FAIL) + return ret; + + spd->pubkey = point; + + return UADK_E_SUCCESS; +} + +static int uadk_prov_sm2_verify(PROV_SM2_SIGN_CTX *psm2ctx, + const unsigned char *sig, size_t siglen, + const unsigned char *tbs, size_t tbslen) +{ + unsigned char buf_r[UADK_ECC_MAX_KEY_BYTES] = {0}; + unsigned char buf_s[UADK_ECC_MAX_KEY_BYTES] = {0}; + SM2_PROV_CTX *smctx = psm2ctx->sm2_pctx; + struct wd_ecc_req req = {0}; + EC_KEY *ec = psm2ctx->key; + struct wd_dtb e = {0}; + struct wd_dtb r = {0}; + struct wd_dtb s = {0}; + int ret; + + r.data = (void *)buf_r; + s.data = (void *)buf_s; + r.bsize = UADK_ECC_MAX_KEY_BYTES; + s.bsize = UADK_ECC_MAX_KEY_BYTES; + ret = uadk_prov_sm2_sign_ber_to_bin((void *)sig, siglen, &r, &s); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to uadk_prov_sm2_sign_ber_to_bin\n"); + return ret; + } + + e.data = (void *)tbs; + e.dsize = tbslen; + ret = uadk_prov_sm2_verify_init_iot(smctx->sess, &req, &e, &r, &s); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to uadk_prov_sm2_verify_init_iot\n"); + return ret; + } + + ret = uadk_prov_sm2_update_public_key(smctx, ec); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to uadk_prov_sm2_update_public_key\n"); + goto uninit_iot; + } + + ret = uadk_prov_ecc_crypto(smctx->sess, &req, smctx); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to uadk_ecc_crypto, ret = %d\n", ret); + goto uninit_iot; + } + + wd_ecc_del_in(smctx->sess, req.src); + + return UADK_P_SUCCESS; + +uninit_iot: + wd_ecc_del_in(smctx->sess, req.src); + + return UADK_P_FAIL; +} + +static int uadk_signature_sm2_verify(void *vpsm2ctx, const unsigned char *sig, size_t siglen, + const unsigned char *tbs, size_t tbslen) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + int ret; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: psm2ctx is NULL\n"); + return UADK_P_FAIL; + } + + ret = uadk_prov_sm2_check_tbs_params(psm2ctx, tbs, tbslen); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to check sm2 verify params\n"); + return ret; + } + + ret = uadk_prov_sm2_verify(psm2ctx, sig, siglen, tbs, tbslen); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to do sm2 verify\n"); + return ret; + } + + return UADK_P_SUCCESS; +} + +static int uadk_signature_sm2_digest_sign_init(void *vpsm2ctx, const char *mdname, + void *ec, const OSSL_PARAM params[]) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + SM2_MD_DATA *smd; + int md_nid; + WPACKET pkt; + + if (!uadk_signature_sm2_sign_init(vpsm2ctx, ec, params) + || !uadk_prov_sm2_sig_set_mdname(psm2ctx, mdname)) + return UADK_P_FAIL; + + smctx = psm2ctx->sm2_pctx; + + if (smctx->sm2_md->mdctx == NULL) { + smctx->sm2_md->mdctx = EVP_MD_CTX_new(); + if (unlikely(smctx->sm2_md->mdctx == NULL)) { + fprintf(stderr, "failed to EVP_MD_CTX_new\n"); + return UADK_P_FAIL; + } + } + + /* + * We do not care about DER writing errors. + * All it really means is that for some reason, there's no + * AlgorithmIdentifier to be had, but the operation itself is + * still valid, just as long as it's not used to construct + * anything that needs an AlgorithmIdentifier. + */ + md_nid = EVP_MD_get_type(smctx->sm2_md->md); + smctx->sm2_md->md_nid = md_nid; + psm2ctx->aid_len = 0; + if (WPACKET_init_der(&pkt, psm2ctx->aid_buf, sizeof(psm2ctx->aid_buf)) + && ossl_DER_w_algorithmIdentifier_SM2_with_MD(&pkt, -1, psm2ctx->key, md_nid) + && WPACKET_finish(&pkt)) { + WPACKET_get_total_written(&pkt, &psm2ctx->aid_len); + psm2ctx->aid = WPACKET_get_curr(&pkt); + } + WPACKET_cleanup(&pkt); + + if (!EVP_DigestInit_ex2(smctx->sm2_md->mdctx, smctx->sm2_md->md, params)) { + fprintf(stderr, "failed to do digest init\n"); + EVP_MD_CTX_free(smd->mdctx); + return UADK_P_FAIL; + } + + psm2ctx->flag_compute_z_digest = 1; + + return UADK_P_SUCCESS; +} + +static int uadk_prov_check_equation_param(struct sm2_param *param, EVP_MD_CTX *hash, + uint8_t *buf, int p_bytes) +{ + if (BN_bn2binpad(param->a, buf, p_bytes) < 0 || + !EVP_DigestUpdate(hash, buf, p_bytes) || + BN_bn2binpad(param->b, buf, p_bytes) < 0 || + !EVP_DigestUpdate(hash, buf, p_bytes)) { + fprintf(stderr, "failed to check equation param\n"); + return UADK_P_FAIL; + } + + return UADK_P_SUCCESS; +} + +static int uadk_prov_check_base_point_group_param(struct sm2_param *param, BN_CTX *ctx, + const EC_KEY *key) +{ + const EC_GROUP *group = EC_KEY_get0_group(key); + + if (!EC_POINT_get_affine_coordinates(group, + EC_GROUP_get0_generator(group), + param->xG, param->yG, ctx)) { + fprintf(stderr, "failed to check base point group param\n"); + return UADK_P_FAIL; + } + + return UADK_P_SUCCESS; +} + +static int uadk_prov_check_base_point_param(struct sm2_param *param, EVP_MD_CTX *hash, + uint8_t *buf, int p_bytes) +{ + if (BN_bn2binpad(param->xG, buf, p_bytes) < 0 || + !EVP_DigestUpdate(hash, buf, p_bytes) || + BN_bn2binpad(param->yG, buf, p_bytes) < 0 || + !EVP_DigestUpdate(hash, buf, p_bytes)) { + fprintf(stderr, "failed to check base point param\n"); + return UADK_P_FAIL; + } + + return UADK_P_SUCCESS; +} + +static int uadk_prov_check_pkey_point_group_param(struct sm2_param *param, BN_CTX *ctx, + const EC_KEY *key) +{ + const EC_GROUP *group = EC_KEY_get0_group(key); + + if (!EC_POINT_get_affine_coordinates(group, + EC_KEY_get0_public_key(key), + param->xA, param->yA, ctx)) { + fprintf(stderr, "failed to check pkey point group param\n"); + return UADK_P_FAIL; + } + return UADK_P_SUCCESS; +} + +static int uadk_prov_check_pkey_point_param(struct sm2_param *param, EVP_MD_CTX *hash, + uint8_t *buf, int p_bytes, uint8_t *out) +{ + if (BN_bn2binpad(param->xA, buf, p_bytes) < 0 || + !EVP_DigestUpdate(hash, buf, p_bytes) || + BN_bn2binpad(param->yA, buf, p_bytes) < 0 || + !EVP_DigestUpdate(hash, buf, p_bytes) || + !EVP_DigestFinal(hash, out, NULL)) { + fprintf(stderr, "failed to check pkey point param\n"); + return UADK_P_FAIL; + } + + return UADK_P_SUCCESS; +} + +static int uadk_prov_get_sm2_param(struct sm2_param *sm2_param, BN_CTX *ctx) +{ + sm2_param->p = BN_CTX_get(ctx); + if (!sm2_param->p) + goto end; + + sm2_param->a = BN_CTX_get(ctx); + if (!sm2_param->a) + goto end; + + sm2_param->b = BN_CTX_get(ctx); + if (!sm2_param->b) + goto end; + + sm2_param->xG = BN_CTX_get(ctx); + if (!sm2_param->xG) + goto end; + + sm2_param->yG = BN_CTX_get(ctx); + if (!sm2_param->yG) + goto end; + + sm2_param->xA = BN_CTX_get(ctx); + if (!sm2_param->xA) + goto end; + + sm2_param->yA = BN_CTX_get(ctx); + if (!sm2_param->yA) + goto end; + + return UADK_P_SUCCESS; + +end: + fprintf(stderr, "failed to get bn ctx for sm2 params\n"); + return UADK_P_FAIL; +} + +static int uadk_prov_check_digest_evp_lib(const EVP_MD *digest, EVP_MD_CTX *hash, + const size_t id_len, const uint8_t *id) +{ + uint8_t e_byte; + uint16_t entl; + + if (!EVP_DigestInit(hash, digest)) { + fprintf(stderr, "error evp lib\n"); + return UADK_P_FAIL; + } + + /* Z = h(ENTL || ID || a || b || xG || yG || xA || yA) */ + if (id_len >= (UINT16_MAX >> TRANS_BITS_BYTES_SHIFT)) { + fprintf(stderr, "invalid: id too large\n"); + return UADK_P_FAIL; + } + + entl = (uint16_t)(id_len << TRANS_BITS_BYTES_SHIFT); + + /* Update the most significant (first) byte of 'entl' */ + e_byte = GET_MS_BYTE(entl); + if (!EVP_DigestUpdate(hash, &e_byte, 1)) { + fprintf(stderr, "failed to do EVP_DigestUpdate for e_byte's first byte\n"); + return UADK_P_FAIL; + } + + /* Update the least significant (second) byte of 'entl' */ + e_byte = GET_LS_BYTE(entl); + if (!EVP_DigestUpdate(hash, &e_byte, 1)) { + fprintf(stderr, "failed to do EVP_DigestUpdate for e_byte's second byte\n"); + return UADK_P_FAIL; + } + + if (id_len > 0 && !EVP_DigestUpdate(hash, id, id_len)) { + fprintf(stderr, "failed to do EVP_DigestUpdate for id\n"); + return UADK_P_FAIL; + } + + return UADK_P_SUCCESS; +} + +static int uadk_prov_sm2_compute_z_digest(uint8_t *out, const EVP_MD *digest, + const uint8_t *id, const size_t id_len, + const EC_KEY *key) +{ + const EC_GROUP *group = EC_KEY_get0_group(key); + struct sm2_param *param = NULL; + int ret = UADK_P_FAIL; + uint8_t *buf = NULL; + BN_CTX *ctx = NULL; + EVP_MD_CTX *hash; + int p_bytes; + + hash = EVP_MD_CTX_new(); + if (hash == NULL) + return ret; + + ctx = BN_CTX_new_ex(key->libctx); + if (ctx == NULL) + goto free_hash; + + param = OPENSSL_zalloc(sizeof(struct sm2_param)); + if (param == NULL) { + fprintf(stderr, "failed to malloc sm2 param\n"); + goto free_ctx; + } + + if (uadk_prov_get_sm2_param(param, ctx) == UADK_P_FAIL) + goto free_param; + + if (uadk_prov_check_digest_evp_lib(digest, hash, id_len, id) == UADK_P_FAIL) + goto free_param; + + if (EC_GROUP_get_curve(group, param->p, param->a, param->b, ctx) == 0) { + fprintf(stderr, "failed to EC_GROUP_get_curve\n"); + goto free_param; + } + + p_bytes = BN_num_bytes(param->p); + buf = OPENSSL_zalloc(p_bytes); + if (buf == NULL) { + fprintf(stderr, "failed to alloc buffer\n"); + goto free_param; + } + + if (!uadk_prov_check_equation_param(param, hash, buf, p_bytes) || + !uadk_prov_check_base_point_group_param(param, ctx, key) || + !uadk_prov_check_base_point_param(param, hash, buf, p_bytes) || + !uadk_prov_check_pkey_point_group_param(param, ctx, key) || + !uadk_prov_check_pkey_point_param(param, hash, buf, p_bytes, out)) + goto free_buf; + + ret = UADK_P_SUCCESS; + +free_buf: + OPENSSL_free(buf); +free_param: + OPENSSL_free(param); +free_ctx: + BN_CTX_free(ctx); +free_hash: + EVP_MD_CTX_free(hash); + return ret; +} + +static int sm2_sig_compute_z_digest(PROV_SM2_SIGN_CTX *psm2ctx) +{ + SM2_PROV_CTX *smctx = psm2ctx->sm2_pctx; + uint8_t *z = NULL; + int ret; + + if (psm2ctx->flag_compute_z_digest) { + /* Only do this once */ + psm2ctx->flag_compute_z_digest = 0; + + z = OPENSSL_zalloc(smctx->sm2_md->mdsize); + if (z == NULL) { + fprintf(stderr, "failed to alloc z\n"); + return UADK_P_FAIL; + } + + /* get hashed prefix 'z' of tbs message */ + ret = uadk_prov_sm2_compute_z_digest(z, smctx->sm2_md->md, psm2ctx->id, + psm2ctx->id_len, psm2ctx->key); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to uadk_prov_sm2_compute_z_digest\n"); + goto free_z; + } + + ret = EVP_DigestUpdate(smctx->sm2_md->mdctx, z, smctx->sm2_md->mdsize); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to EVP_DigestUpdate\n"); + goto free_z; + } + OPENSSL_free(z); + } + + return UADK_P_SUCCESS; + +free_z: + OPENSSL_free(z); + return UADK_P_FAIL; +} + +static int uadk_signature_sm2_digest_sign_update(void *vpsm2ctx, const unsigned char *data, + size_t datalen) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + int ret; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: sign update psm2ctx is NULL\n"); + return UADK_P_FAIL; + } + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid smctx is NULL in compute z digest\n"); + return UADK_P_FAIL; + } + + ret = uadk_prov_sm2_check_md_params(smctx); + if (ret == UADK_P_FAIL) + return ret; + + ret = sm2_sig_compute_z_digest(psm2ctx); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to compute z digest\n"); + return ret; + } + + ret = EVP_DigestUpdate(smctx->sm2_md->mdctx, data, datalen); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to EVP_DigestUpdate\n"); + return ret; + } + + return UADK_P_SUCCESS; +} + +static int uadk_signature_sm2_digest_sign_final(void *vpsm2ctx, + unsigned char *sig, size_t *siglen, + size_t sigsize) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int dlen = 0; + SM2_PROV_CTX *smctx; + int ret; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: psm2ctx is NULL\n"); + return UADK_P_FAIL; + } + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid: smctx is NULL\n"); + return UADK_P_FAIL; + } + + ret = uadk_prov_sm2_check_md_params(smctx); + if (ret == UADK_P_FAIL) + return ret; + + /* + * If sig is NULL then we're just finding out the sig size. Other fields + * are ignored. Defer to sm2sig_sign. + */ + if (sig != NULL) { + ret = sm2_sig_compute_z_digest(psm2ctx); + if (ret == UADK_P_FAIL) + return ret; + + ret = EVP_DigestFinal_ex(smctx->sm2_md->mdctx, digest, &dlen); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to do EVP_DigestFinal_ex\n"); + return ret; + } + } + + return uadk_signature_sm2_sign(vpsm2ctx, sig, siglen, sigsize, digest, (size_t)dlen); +} + +static int uadk_signature_sm2_digest_verify_init(void *vpsm2ctx, const char *mdname, + void *ec, const OSSL_PARAM params[]) +{ + return uadk_signature_sm2_digest_sign_init(vpsm2ctx, mdname, ec, params); +} + +static int uadk_signature_sm2_digest_verify_update(void *vpsm2ctx, const unsigned char *data, + size_t datalen) +{ + return uadk_signature_sm2_digest_sign_update(vpsm2ctx, data, datalen); +} + +static int uadk_signature_sm2_digest_verify_final(void *vpsm2ctx, const unsigned char *sig, + size_t siglen) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int dlen = 0; + SM2_PROV_CTX *smctx; + int ret, size; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: psm2ctx is NULL\n"); + return UADK_P_FAIL; + } + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid: smctx is NULL\n"); + return UADK_P_FAIL; + } + + ret = uadk_prov_sm2_check_md_params(smctx); + if (ret == UADK_P_FAIL) + return ret; + + size = EVP_MD_get_size(smctx->sm2_md->md); + if (size > EVP_MAX_MD_SIZE) { + fprintf(stderr, "invalid: md size(%d) > %d\n", size, EVP_MAX_MD_SIZE); + return UADK_P_FAIL; + } + + ret = sm2_sig_compute_z_digest(psm2ctx); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to do sm2_sig_compute_z_digest\n"); + return ret; + } + + ret = EVP_DigestFinal_ex(smctx->sm2_md->mdctx, digest, &dlen); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to do EVP_DigestFinal_ex, dlen = %u\n", dlen); + return ret; + } + + return uadk_signature_sm2_verify(vpsm2ctx, sig, siglen, digest, (size_t)dlen); +} + +static int check_signature_src_ctx(PROV_SM2_SIGN_CTX *srcctx) +{ + SM2_PROV_CTX *src_smctx; + + if (srcctx == NULL) { + fprintf(stderr, "invalid: src ctx is NULL\n"); + return UADK_P_FAIL; + } + + if (srcctx->key != NULL && !EC_KEY_up_ref(srcctx->key)) { + fprintf(stderr, "failed to check srcctx key reference\n"); + return UADK_P_FAIL; + } + + src_smctx = srcctx->sm2_pctx; + if (src_smctx == NULL) { + fprintf(stderr, "invalid: src_smctx is NULL\n"); + return UADK_P_FAIL; + } + + if (src_smctx->sm2_md == NULL) { + fprintf(stderr, "invalid: sm2_md is NULL\n"); + return UADK_P_FAIL; + } + + if (src_smctx->sm2_md->md != NULL && !EVP_MD_up_ref(src_smctx->sm2_md->md)) { + fprintf(stderr, "failed to check srcctx md reference\n"); + return UADK_P_FAIL; + } + + return UADK_P_SUCCESS; +} + +static int create_dst_ctx_data(SM2_PROV_CTX *dst_smctx) +{ + dst_smctx->sm2_md = OPENSSL_zalloc(sizeof(SM2_MD_DATA)); + if (dst_smctx->sm2_md == NULL) { + fprintf(stderr, "failed to alloc dst_smctx->sm2_md\n"); + return UADK_P_FAIL; + } + + dst_smctx->sm2_pd = OPENSSL_zalloc(sizeof(SM2_PKEY_DATA)); + if (dst_smctx->sm2_pd == NULL) { + fprintf(stderr, "failed to alloc dst_smctx->sm2_pd\n"); + OPENSSL_free(dst_smctx->sm2_md); + return UADK_P_FAIL; + } + + return UADK_P_SUCCESS; +} + +static void release_dst_ctx_data(SM2_PROV_CTX *dst_smctx) +{ + if (dst_smctx->sm2_md) + OPENSSL_free(dst_smctx->sm2_md); + + if (dst_smctx->sm2_pd) + OPENSSL_free(dst_smctx->sm2_pd); +} + +static void copy_ctx_data(SM2_PROV_CTX *dst_smctx, SM2_PROV_CTX *src_smctx) +{ + dst_smctx->sm2_md->md = src_smctx->sm2_md->md; + dst_smctx->sm2_md->mdsize = src_smctx->sm2_md->mdsize; + dst_smctx->sm2_md->md_nid = src_smctx->sm2_md->md_nid; + dst_smctx->sm2_pd = src_smctx->sm2_pd; + dst_smctx->sess = src_smctx->sess; + dst_smctx->init_status = src_smctx->init_status; +} + +static void *uadk_signature_sm2_dupctx(void *vpsm2ctx) +{ + PROV_SM2_SIGN_CTX *srcctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + SM2_PROV_CTX *dst_smctx, *src_smctx; + PROV_SM2_SIGN_CTX *dstctx; + + if (check_signature_src_ctx(srcctx) == UADK_P_FAIL) + return NULL; + src_smctx = srcctx->sm2_pctx; + + dstctx = OPENSSL_zalloc(sizeof(PROV_SM2_SIGN_CTX)); + if (dstctx == NULL) { + fprintf(stderr, "failed to alloc dst ctx\n"); + return NULL; + } + + memcpy(dstctx, srcctx, sizeof(PROV_SM2_SIGN_CTX)); + dstctx->key = srcctx->key; + + dst_smctx = OPENSSL_zalloc(sizeof(SM2_PROV_CTX)); + if (dst_smctx == NULL) { + fprintf(stderr, "failed to alloc dst_smctx\n"); + goto free_dstctx; + } + dstctx->sm2_pctx = dst_smctx; + + if (create_dst_ctx_data(dst_smctx) == UADK_P_FAIL) + goto free_dst_smctx; + + if (src_smctx->sm2_md->mdctx != NULL) { + dst_smctx->sm2_md->mdctx = EVP_MD_CTX_new(); + if (dst_smctx->sm2_md->mdctx == NULL || + EVP_MD_CTX_copy_ex(dst_smctx->sm2_md->mdctx, src_smctx->sm2_md->mdctx) == 0) { + fprintf(stderr, "failed to new dst mdctx or copy src mdctx\n"); + goto free_dst_ctx_data; + } + } + + copy_ctx_data(dst_smctx, src_smctx); + + if (srcctx->id != NULL) { + dstctx->id = OPENSSL_malloc(srcctx->id_len); + if (dstctx->id == NULL) { + fprintf(stderr, "failed to alloc id\n"); + goto free_dst_mdctx; + } + dstctx->id_len = srcctx->id_len; + memcpy(dstctx->id, srcctx->id, srcctx->id_len); + } + + return dstctx; + +free_dst_mdctx: + EVP_MD_CTX_free(dst_smctx->sm2_md->mdctx); +free_dst_ctx_data: + release_dst_ctx_data(dst_smctx); +free_dst_smctx: + OPENSSL_free(dst_smctx); +free_dstctx: + OPENSSL_free(dstctx); + return NULL; +} + +static int uadk_prov_sm2_locate_id_digest(PROV_SM2_SIGN_CTX *psm2ctx, const OSSL_PARAM params[]) +{ + size_t tmp_idlen = 0; + const OSSL_PARAM *p; + void *tmp_id = NULL; + char *mdname = NULL; + size_t mdsize; + + p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DIST_ID); + if (p) { + /*If the 'z' digest has already been computed, the ID is set too late */ + if (psm2ctx->flag_compute_z_digest == 0) { + fprintf(stderr, "invalid: should set ID param before z digest\n"); + return UADK_P_FAIL; + } + + if (p->data_size != 0 && + !OSSL_PARAM_get_octet_string(p, &tmp_id, 0, &tmp_idlen)) { + fprintf(stderr, "failed to OSSL_PARAM_get_octet_string\n"); + return UADK_P_FAIL; + } + if (psm2ctx->id != NULL) + OPENSSL_free(psm2ctx->id); + psm2ctx->id = tmp_id; + psm2ctx->id_len = tmp_idlen; + } + + /* + * The following code checks that the size is the same as the SM3 digest + * size returning an error otherwise. + * If there is ever any different digest algorithm allowed with SM2 + * this needs to be adjusted accordingly. + */ + p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE); + if (p != NULL && (!OSSL_PARAM_get_size_t(p, &mdsize) + || mdsize != psm2ctx->sm2_pctx->sm2_md->mdsize)) { + fprintf(stderr, "failed to locate digest size\n"); + return UADK_P_FAIL; + } + + p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST); + if (p) { + if (!OSSL_PARAM_get_utf8_string(p, &mdname, 0)) { + fprintf(stderr, "failed to OSSL_PARAM_get_utf8_string\n"); + return UADK_P_FAIL; + } + + if (!uadk_prov_sm2_sig_set_mdname(psm2ctx, mdname)) { + OPENSSL_free(mdname); + fprintf(stderr, "failed to OSSL_PARAM_get_utf8_string\n"); + return UADK_P_FAIL; + } + + if (mdname != NULL) + OPENSSL_free(mdname); + } + + return UADK_P_SUCCESS; +} + +static int uadk_signature_sm2_set_ctx_params(void *vpsm2ctx, const OSSL_PARAM params[]) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + int ret; + + /* + * 'set_ctx_param' function can be called independently, + * so check 'psm2ctx' again here. + */ + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: sm2 ctx is NULL\n"); + return UADK_P_FAIL; + } + + /* If params is NULL, no need to set ctx params, just return */ + if (params == NULL) + return UADK_P_SUCCESS; + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid: smctx is NULL\n"); + return UADK_P_FAIL; + } + + ret = uadk_prov_sm2_locate_id_digest(psm2ctx, params); + if (ret == UADK_P_FAIL) + return ret; + + /* If not init, do not need to update session, just set the data before */ + if (smctx->init_status == CTX_INIT_SUCC) { + ret = uadk_prov_sm2_update_sess(smctx); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to update sess in set_ctx\n"); + return ret; + } + } + + return UADK_P_SUCCESS; +} + +static int uadk_signature_sm2_get_ctx_params(void *vpsm2ctx, OSSL_PARAM *params) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + OSSL_PARAM *p; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: psm2ctx is NULL\n"); + return UADK_P_FAIL; + } + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID); + if (p != NULL && !OSSL_PARAM_set_octet_string(p, psm2ctx->aid, psm2ctx->aid_len)) { + fprintf(stderr, "failed to locate algorithm id\n"); + return UADK_P_FAIL; + } + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE); + if (p != NULL && !OSSL_PARAM_set_size_t(p, psm2ctx->sm2_pctx->sm2_md->mdsize)) { + fprintf(stderr, "failed to locate digest size\n"); + return UADK_P_FAIL; + } + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST); + if (p != NULL && !OSSL_PARAM_set_utf8_string(p, psm2ctx->sm2_pctx->sm2_md->md == NULL + ? psm2ctx->mdname : EVP_MD_get0_name(psm2ctx->sm2_pctx->sm2_md->md))) { + fprintf(stderr, "failed to locate digest\n"); + return UADK_P_FAIL; + } + + return UADK_P_SUCCESS; +} + +static const OSSL_PARAM *uadk_signature_sm2_settable_ctx_params(ossl_unused void *vpsm2ctx, + ossl_unused void *provctx) +{ + return sm2_sig_known_settable_ctx_params; +} + +static const OSSL_PARAM *uadk_signature_sm2_gettable_ctx_params(ossl_unused void *vpsm2ctx, + ossl_unused void *provctx) +{ + return sm2_sig_known_gettable_ctx_params; +} + +static int uadk_signature_sm2_set_ctx_md_params(void *vpsm2ctx, const OSSL_PARAM params[]) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid: smctx is NULL\n"); + return UADK_P_FAIL; + } + + if (smctx->sm2_md->mdctx == NULL) { + fprintf(stderr, "invalid: mdctx is NULL\n"); + return UADK_P_FAIL; + } + + return EVP_MD_CTX_set_params(smctx->sm2_md->mdctx, params); +} + +static int uadk_signature_sm2_get_ctx_md_params(void *vpsm2ctx, OSSL_PARAM *params) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid: smctx is NULL\n"); + return UADK_P_FAIL; + } + + if (smctx->sm2_md->mdctx == NULL) { + fprintf(stderr, "invalid: mdctx is NULL\n"); + return UADK_P_FAIL; + } + + return EVP_MD_CTX_get_params(smctx->sm2_md->mdctx, params); +} + +static const OSSL_PARAM *uadk_signature_sm2_settable_ctx_md_params(void *vpsm2ctx) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid: smctx is NULL\n"); + return UADK_P_FAIL; + } + + if (smctx->sm2_md->md == NULL) { + fprintf(stderr, "invalid: md is NULL\n"); + return UADK_P_FAIL; + } + + return EVP_MD_settable_ctx_params(smctx->sm2_md->md); +} + +static const OSSL_PARAM *uadk_signature_sm2_gettable_ctx_md_params(void *vpsm2ctx) +{ + PROV_SM2_SIGN_CTX *psm2ctx = (PROV_SM2_SIGN_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid: smctx is NULL\n"); + return UADK_P_FAIL; + } + + if (smctx->sm2_md->md == NULL) { + fprintf(stderr, "invalid: md is NULL\n"); + return UADK_P_FAIL; + } + + return EVP_MD_gettable_ctx_params(smctx->sm2_md->md); +} + +static void *uadk_asym_cipher_sm2_newctx(void *provctx) +{ + PROV_SM2_ASYM_CTX *psm2ctx = OPENSSL_zalloc(sizeof(PROV_SM2_ASYM_CTX)); + SM2_PROV_CTX *smctx; + + if (psm2ctx == NULL) { + fprintf(stderr, "failed to alloc PROV_SM2_ASYM_CTX\n"); + return NULL; + } + + psm2ctx->libctx = prov_libctx_of(provctx); + + smctx = OPENSSL_zalloc(sizeof(SM2_PROV_CTX)); + if (smctx == NULL) { + fprintf(stderr, "failed to alloc sm2 prov ctx\n"); + goto free_psm2ctx; + } + + smctx->sm2_md = OPENSSL_zalloc(sizeof(SM2_MD_DATA)); + if (smctx->sm2_md == NULL) { + fprintf(stderr, "failed to alloc sm2 md data\n"); + goto free_smctx; + } + /* Use SM3 in default, other digest can be set with set_ctx_params API. */ + smctx->sm2_md->mdsize = SM3_DIGEST_LENGTH; + strcpy(psm2ctx->mdname, OSSL_DIGEST_NAME_SM3); + + smctx->sm2_pd = OPENSSL_zalloc(sizeof(SM2_PKEY_DATA)); + if (smctx->sm2_pd == NULL) { + fprintf(stderr, "failed to alloc sm2 pkey data\n"); + goto free_sm2_md; + } + + psm2ctx->sm2_pctx = smctx; + + return psm2ctx; + +free_sm2_md: + OPENSSL_free(smctx->sm2_md); +free_smctx: + OPENSSL_free(smctx); +free_psm2ctx: + OPENSSL_free(psm2ctx); + + return NULL; +} + +static void uadk_asym_cipher_sm2_freectx(void *vpsm2ctx) +{ + PROV_SM2_ASYM_CTX *psm2ctx = (PROV_SM2_ASYM_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + + if (psm2ctx == NULL) + return; + + smctx = psm2ctx->sm2_pctx; + if (smctx) { + if (smctx->sm2_md) + OPENSSL_free(smctx->sm2_md); + if (smctx->sm2_pd) + OPENSSL_free(smctx->sm2_pd); + OPENSSL_free(smctx); + } + + if (psm2ctx->key) + EC_KEY_free(psm2ctx->key); + + OPENSSL_free(psm2ctx); +} + +static void uadk_prov_sm2_set_default_md(PROV_SM2_ASYM_CTX *psm2ctx) +{ + SM2_PROV_CTX *smctx = psm2ctx->sm2_pctx; + SM2_MD_DATA *smd = smctx->sm2_md; + + /* Set SM3 as default digest method */ + if (smd->alloc_md) + EVP_MD_free(smd->alloc_md); + smd->md = smd->alloc_md = EVP_MD_fetch(psm2ctx->libctx, "SM3", NULL); + smd->md_nid = NID_sm3; +} + +static int uadk_asym_cipher_sm2_encrypt_init(void *vpsm2ctx, void *vkey, + const OSSL_PARAM params[]) +{ + PROV_SM2_ASYM_CTX *psm2ctx = (PROV_SM2_ASYM_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + int ret; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: psm2ctx is NULL\n"); + return UADK_P_FAIL; + } + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid: smctx is NULL\n"); + return UADK_P_FAIL; + } + + if (vkey == NULL || !EC_KEY_up_ref(vkey)) { + fprintf(stderr, "invalid: vkey is NULL\n"); + return UADK_P_FAIL; + } + EC_KEY_free(psm2ctx->key); + psm2ctx->key = vkey; + + /* Set default digest method as SM3 */ + uadk_prov_sm2_set_default_md(psm2ctx); + + ret = uadk_asym_cipher_sm2_set_ctx_params(psm2ctx, params); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to set_ctx_params\n"); + return ret; + } + + ret = uadk_prov_asym_cipher_get_support_state(SIGNATURE_SM2); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to get hardware sm2 signature support\n"); + return ret; + } + + /* Init with UADK */ + ret = uadk_prov_sm2_init(); + if (ret) { + fprintf(stderr, "failed to init sm2\n"); + return UADK_P_FAIL; + } + + smctx->init_status = CTX_INIT_SUCC; + + ret = uadk_prov_sm2_update_sess(smctx); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to update sess\n"); + return ret; + } + + return UADK_P_SUCCESS; +} + +static int uadk_prov_sm2_encrypt_check(PROV_SM2_ASYM_CTX *psm2ctx, + unsigned char *out, size_t *outlen, + const unsigned char *in, size_t inlen) +{ + SM2_PROV_CTX *smctx = psm2ctx->sm2_pctx; + const EVP_MD *md; + int c3_size; + + if (!smctx || !smctx->sess) { + fprintf(stderr, "smctx or sess NULL\n"); + return UADK_P_FAIL; + } + + if (smctx->init_status != CTX_INIT_SUCC) { + fprintf(stderr, "sm2 ctx init failed\n"); + return UADK_P_FAIL; + } + + /* + * As we have already set md method in init, if not set, will use default digest. + * The md is unlikey to be NULL here, so if the md is still NULL when encrypt start, + * just return fail. + */ + md = smctx->sm2_md->md; + if (md == NULL) { + fprintf(stderr, "failed to get md method\n"); + return UADK_P_FAIL; + } + + c3_size = EVP_MD_size(md); + if (c3_size <= 0) { + fprintf(stderr, "c3 size error\n"); + return UADK_P_FAIL; + } + + if (inlen > UINT_MAX) { + fprintf(stderr, "invalid: inlen is out of range\n"); + return UADK_P_FAIL; + } + + return UADK_P_SUCCESS; +} + +static int uadk_prov_sm2_encrypt_init_iot(handle_t sess, struct wd_ecc_req *req, + unsigned char *in, size_t inlen) +{ + struct wd_ecc_out *ecc_out; + struct wd_ecc_in *ecc_in; + struct wd_dtb e = {0}; + + ecc_out = wd_sm2_new_enc_out(sess, inlen); + if (!ecc_out) { + fprintf(stderr, "failed to new enc out\n"); + return UADK_P_FAIL; + } + + e.data = (void *)in; + e.dsize = inlen; + ecc_in = wd_sm2_new_enc_in(sess, NULL, &e); + if (!ecc_in) { + fprintf(stderr, "failed to new enc in\n"); + wd_ecc_del_out(sess, ecc_out); + return UADK_P_FAIL; + } + + uadk_prov_ecc_fill_req(req, WD_SM2_ENCRYPT, ecc_in, ecc_out); + + return UADK_P_SUCCESS; +} + +static int uadk_prov_sm2_asym_bin_to_ber(struct wd_ecc_point *c1, + struct wd_dtb *c2, struct wd_dtb *c3, + unsigned char *ber, size_t *ber_len) +{ + struct sm2_ciphertext ctext_struct; + int ciphertext_leni, ret; + BIGNUM *x1, *y1; + + x1 = BN_bin2bn((void *)c1->x.data, c1->x.dsize, NULL); + if (!x1) { + fprintf(stderr, "failed to BN_bin2bn x1\n"); + return UADK_P_FAIL; + } + + y1 = BN_bin2bn((void *)c1->y.data, c1->y.dsize, NULL); + if (!y1) { + fprintf(stderr, "failed to BN_bin2bn y1\n"); + ret = UADK_P_FAIL; + goto free_x1; + } + + ctext_struct.C1x = x1; + ctext_struct.C1y = y1; + ctext_struct.C3 = ASN1_OCTET_STRING_new(); + if (!ctext_struct.C3) { + ret = UADK_P_FAIL; + goto free_y1; + } + + ret = ASN1_OCTET_STRING_set(ctext_struct.C3, (void *)c3->data, c3->dsize); + if (!ret) + goto free_c3; + + ctext_struct.C2 = ASN1_OCTET_STRING_new(); + if (!ctext_struct.C2) { + ret = UADK_P_FAIL; + goto free_c3; + } + + ret = ASN1_OCTET_STRING_set(ctext_struct.C2, (void *)c2->data, c2->dsize); + if (!ret) + goto free_c2; + + ciphertext_leni = i2d_SM2_Ciphertext(&ctext_struct, &ber); + /* Ensure cast to size_t is safe */ + if (ciphertext_leni < 0) { + ret = UADK_P_FAIL; + goto free_c2; + } + *ber_len = (size_t)ciphertext_leni; + ret = UADK_P_SUCCESS; + +free_c2: + ASN1_OCTET_STRING_free(ctext_struct.C2); +free_c3: + ASN1_OCTET_STRING_free(ctext_struct.C3); +free_y1: + BN_free(y1); +free_x1: + BN_free(x1); + + return ret; +} + +static int uadk_prov_sm2_encrypt(PROV_SM2_ASYM_CTX *vpsm2ctx, + unsigned char *out, size_t *outlen, + const unsigned char *in, size_t inlen) +{ + SM2_PROV_CTX *smctx = vpsm2ctx->sm2_pctx; + struct wd_ecc_point *c1 = NULL; + struct wd_ecc_req req = {0}; + struct wd_dtb *c2 = NULL; + struct wd_dtb *c3 = NULL; + const EVP_MD *md; + int md_size, ret; + + ret = uadk_prov_sm2_encrypt_init_iot(smctx->sess, &req, (void *)in, inlen); + if (ret == UADK_P_FAIL) + return ret; + + ret = uadk_prov_sm2_update_public_key(smctx, vpsm2ctx->key); + if (ret == UADK_P_FAIL) + goto uninit_iot; + + ret = uadk_prov_ecc_crypto(smctx->sess, &req, smctx); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to uadk_ecc_crypto, ret = %d\n", ret); + goto uninit_iot; + } + + wd_sm2_get_enc_out_params(req.dst, &c1, &c2, &c3); + if (!c1 || !c2 || !c3) + goto uninit_iot; + + ret = uadk_prov_sm2_asym_bin_to_ber(c1, c2, c3, out, outlen); + if (ret == UADK_P_FAIL) + goto uninit_iot; + + md = (smctx->sm2_md->md == NULL) ? EVP_sm3() : smctx->sm2_md->md; + md_size = EVP_MD_size(md); + if (c3->dsize != md_size) { + fprintf(stderr, "invalid: c3 dsize(%u) != hash_size(%d)\n", c3->dsize, md_size); + goto uninit_iot; + } + + wd_ecc_del_in(smctx->sess, req.src); + wd_ecc_del_out(smctx->sess, req.dst); + + return UADK_P_SUCCESS; + +uninit_iot: + wd_ecc_del_in(smctx->sess, req.src); + wd_ecc_del_out(smctx->sess, req.dst); + + return UADK_P_FAIL; +} + +static size_t uadk_prov_ec_field_size(const EC_GROUP *group) +{ + BIGNUM *p = BN_new(); + BIGNUM *a = BN_new(); + BIGNUM *b = BN_new(); + size_t field_size = 0; + size_t p_bits; + + if (p == NULL || a == NULL || b == NULL) { + fprintf(stderr, "failed to new bignumber\n"); + goto done; + } + + if (!EC_GROUP_get_curve(group, p, a, b, NULL)) { + fprintf(stderr, "failed to get curve from group\n"); + goto done; + } + + p_bits = BN_num_bits(p); + field_size = BITS_TO_BYTES(p_bits); + +done: + BN_free(p); + BN_free(a); + BN_free(b); + + return field_size; +} + +static int uadk_prov_sm2_ciphertext_size(const EC_KEY *key, + const EVP_MD *digest, size_t msg_len, + size_t *ct_size) +{ + const size_t field_size = uadk_prov_ec_field_size(EC_KEY_get0_group(key)); + const int md_size = EVP_MD_size(digest); + size_t sz; + + if (field_size == 0) + return UADK_P_FAIL; + + if (md_size < 0) { + fprintf(stderr, "invalid md_size: %d\n", md_size); + return UADK_P_FAIL; + } + + /* + * Integer and string are simple type; set constructed = 0, means + * primitive and definite length encoding. + */ + sz = ECC_POINT_SIZE(ASN1_object_size(0, field_size + 1, V_ASN1_INTEGER)) + + ASN1_object_size(0, md_size, V_ASN1_OCTET_STRING) + + ASN1_object_size(0, msg_len, V_ASN1_OCTET_STRING); + *ct_size = ASN1_object_size(1, sz, V_ASN1_SEQUENCE); + + return UADK_P_SUCCESS; +} + +static int uadk_asym_cipher_sm2_encrypt(void *vpsm2ctx, unsigned char *out, size_t *outlen, + size_t outsize, const unsigned char *in, + size_t inlen) +{ + PROV_SM2_ASYM_CTX *psm2ctx = (PROV_SM2_ASYM_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + SM2_MD_DATA *smd; + const EVP_MD *md; + int ret; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: psm2ctx is NULL\n"); + return UADK_P_FAIL; + } + + ret = uadk_prov_sm2_encrypt_check(psm2ctx, out, outlen, in, inlen); + if (ret == UADK_P_FAIL) + return ret; + + /* If out is NULL, compute outlen size and return */ + if (out == NULL) { + smctx = psm2ctx->sm2_pctx; + smd = smctx->sm2_md; + md = (const EVP_MD *)smd->md; + if (!uadk_prov_sm2_ciphertext_size(psm2ctx->key, md, inlen, outlen)) + return UADK_P_FAIL; + else + return UADK_P_SUCCESS; + } + + return uadk_prov_sm2_encrypt(psm2ctx, out, outlen, in, inlen); +} + +static int uadk_asym_cipher_sm2_decrypt_init(void *vpsm2ctx, void *vkey, + const OSSL_PARAM params[]) +{ + return uadk_asym_cipher_sm2_encrypt_init(vpsm2ctx, vkey, params); +} + +static int uadk_prov_sm2_decrypt_check(SM2_PROV_CTX *smctx, + unsigned char *out, size_t *outlen, + const unsigned char *in, size_t inlen) +{ + const EVP_MD *md; + int hash_size; + + if (!smctx || !smctx->sess) { + fprintf(stderr, "smctx or sess NULL\n"); + return UADK_P_FAIL; + } + + if (smctx->init_status != CTX_INIT_SUCC) { + fprintf(stderr, "sm2 ctx init failed\n"); + return UADK_P_FAIL; + } + + /* + * As we have already set md method in init, if not set, will use default digest. + * The md is unlikey to be NULL here, so if the md is still NULL when encrypt start, + * just return fail. + */ + md = smctx->sm2_md->md; + if (md == NULL) { + fprintf(stderr, "failed to get md method\n"); + return UADK_P_FAIL; + } + + hash_size = EVP_MD_size(md); + if (hash_size <= 0) { + fprintf(stderr, "hash size = %d error\n", hash_size); + return UADK_P_FAIL; + } + + return UADK_P_SUCCESS; +} + +static int uadk_prov_sm2_asym_ber_to_bin(const EVP_MD *md, struct sm2_ciphertext *ctext_struct, + struct wd_ecc_point *c1, struct wd_dtb *c2, struct wd_dtb *c3) +{ + int len, len1, md_size; + + if (md == NULL) { + fprintf(stderr, "invalid: md is NULL\n"); + return UADK_P_FAIL; + } + + len = BN_num_bytes(ctext_struct->C1x); + len1 = BN_num_bytes(ctext_struct->C1y); + c1->x.data = malloc(len + len1 + ctext_struct->C2->length + ctext_struct->C3->length); + if (!c1->x.data) + return UADK_P_FAIL; + + c1->y.data = c1->x.data + len; + c3->data = c1->y.data + len1; + c2->data = c3->data + ctext_struct->C3->length; + memcpy(c2->data, ctext_struct->C2->data, ctext_struct->C2->length); + memcpy(c3->data, ctext_struct->C3->data, ctext_struct->C3->length); + c2->dsize = ctext_struct->C2->length; + c3->dsize = ctext_struct->C3->length; + md_size = EVP_MD_size(md); + if (c3->dsize != md_size) { + fprintf(stderr, "invalid: c3 dsize(%u) != hash_size(%d)\n", c3->dsize, md_size); + free(c1->x.data); + return UADK_P_FAIL; + } + + c1->x.dsize = BN_bn2bin(ctext_struct->C1x, (void *)c1->x.data); + c1->y.dsize = BN_bn2bin(ctext_struct->C1y, (void *)c1->y.data); + + return UADK_P_SUCCESS; +} + +static int uadk_prov_sm2_decrypt_init_iot(handle_t sess, struct wd_ecc_req *req, + struct wd_ecc_point *c1, struct wd_dtb *c2, struct wd_dtb *c3) +{ + struct wd_ecc_out *ecc_out; + struct wd_ecc_in *ecc_in; + + ecc_out = wd_sm2_new_dec_out(sess, c2->dsize); + if (!ecc_out) { + fprintf(stderr, "failed to new dec out\n"); + return UADK_P_FAIL; + } + + ecc_in = wd_sm2_new_dec_in(sess, c1, c2, c3); + if (!ecc_in) { + fprintf(stderr, "failed to new dec in\n"); + wd_ecc_del_out(sess, ecc_out); + return UADK_P_FAIL; + } + + uadk_prov_ecc_fill_req(req, WD_SM2_DECRYPT, ecc_in, ecc_out); + + return UADK_P_SUCCESS; +} + +static int uadk_prov_update_private_key(PROV_SM2_ASYM_CTX *ctx) +{ + SM2_PROV_CTX *smctx = ctx->sm2_pctx; + EC_KEY *eckey = ctx->key; + const BIGNUM *d; + int ret; + + d = EC_KEY_get0_private_key(eckey); + if (!d) { + fprintf(stderr, "private key not set\n"); + return UADK_P_FAIL; + } + + if (smctx->sm2_pd->prikey && !BN_cmp(d, smctx->sm2_pd->prikey)) + return UADK_P_FAIL; + + ret = uadk_prov_ecc_set_private_key(smctx->sess, eckey); + if (ret == UADK_P_FAIL) + return ret; + + smctx->sm2_pd->prikey = d; + + return UADK_P_SUCCESS; +} + +static int uadk_prov_sm2_get_plaintext(struct wd_ecc_req *req, + unsigned char *out, size_t *outlen) +{ + struct wd_dtb *ptext = NULL; + + wd_sm2_get_dec_out_params(req->dst, &ptext); + if (!ptext) { + fprintf(stderr, "failed to get ptext\n"); + return UADK_P_FAIL; + } + + if (*outlen < ptext->dsize) { + fprintf(stderr, "outlen(%zu) < (%u)\n", *outlen, ptext->dsize); + return UADK_P_FAIL; + } + + memcpy(out, ptext->data, ptext->dsize); + *outlen = ptext->dsize; + + return UADK_P_SUCCESS; +} + +static int uadk_prov_sm2_decrypt(PROV_SM2_ASYM_CTX *ctx, + unsigned char *out, size_t *outlen, + const unsigned char *in, size_t inlen) +{ + SM2_PROV_CTX *smctx = ctx->sm2_pctx; + struct sm2_ciphertext *ctext_struct; + struct wd_ecc_req req = {0}; + struct wd_ecc_point c1; + struct wd_dtb c2, c3; + const EVP_MD *md; + int ret; + + ret = uadk_prov_sm2_decrypt_check(smctx, out, outlen, in, inlen); + if (ret == UADK_P_FAIL) + return ret; + + ctext_struct = d2i_SM2_Ciphertext(NULL, &in, inlen); + if (ctext_struct == NULL) + return UADK_P_FAIL; + + md = (smctx->sm2_md->md == NULL) ? EVP_sm3() : smctx->sm2_md->md; + ret = uadk_prov_sm2_asym_ber_to_bin(md, ctext_struct, &c1, &c2, &c3); + if (ret == UADK_P_FAIL) + goto free_ctext; + + ret = uadk_prov_sm2_decrypt_init_iot(smctx->sess, &req, &c1, &c2, &c3); + if (ret == UADK_P_FAIL) + goto free_c1; + + ret = uadk_prov_update_private_key(ctx); + if (ret == UADK_P_FAIL) + goto uninit_iot; + + ret = uadk_prov_ecc_crypto(smctx->sess, &req, smctx); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to uadk_ecc_crypto, ret = %d\n", ret); + goto uninit_iot; + } + + ret = uadk_prov_sm2_get_plaintext(&req, out, outlen); + if (ret == UADK_P_FAIL) + goto uninit_iot; + + wd_ecc_del_in(smctx->sess, req.src); + wd_ecc_del_out(smctx->sess, req.dst); + free(c1.x.data); + SM2_Ciphertext_free(ctext_struct); + + return UADK_P_SUCCESS; + +uninit_iot: + wd_ecc_del_in(smctx->sess, req.src); + wd_ecc_del_out(smctx->sess, req.dst); +free_c1: + free(c1.x.data); +free_ctext: + SM2_Ciphertext_free(ctext_struct); + return UADK_P_FAIL; +} + +static int uadk_prov_sm2_plaintext_size(const unsigned char *ct, size_t ct_size, size_t *pt_size) +{ + struct sm2_ciphertext *sm2_ctext; + + sm2_ctext = d2i_SM2_Ciphertext(NULL, &ct, ct_size); + if (!sm2_ctext) { + fprintf(stderr, "invalid sm2 encoding\n"); + return UADK_P_FAIL; + } + + *pt_size = sm2_ctext->C2->length; + SM2_Ciphertext_free(sm2_ctext); + + return UADK_P_SUCCESS; +} + +static int uadk_asym_cipher_sm2_decrypt(void *vpsm2ctx, unsigned char *out, size_t *outlen, + size_t outsize, const unsigned char *in, + size_t inlen) +{ + PROV_SM2_ASYM_CTX *psm2ctx = (PROV_SM2_ASYM_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + int ret; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: psm2ctx is NULL\n"); + return UADK_P_FAIL; + } + + smctx = psm2ctx->sm2_pctx; + ret = uadk_prov_sm2_decrypt_check(smctx, out, outlen, in, inlen); + if (ret == UADK_P_FAIL) + return ret; + + if (out == NULL) { + if (!uadk_prov_sm2_plaintext_size(in, inlen, outlen)) + return UADK_P_FAIL; + else + return UADK_P_SUCCESS; + } + + return uadk_prov_sm2_decrypt(psm2ctx, out, outlen, in, inlen); +} + +static void *uadk_asym_cipher_sm2_dupctx(void *vpsm2ctx) +{ + PROV_SM2_ASYM_CTX *srcctx = (PROV_SM2_ASYM_CTX *)vpsm2ctx; + SM2_PROV_CTX *dst_smctx, *src_smctx; + PROV_SM2_ASYM_CTX *dstctx; + + if (srcctx == NULL) { + fprintf(stderr, "src ctx is NULL\n"); + return NULL; + } + + src_smctx = srcctx->sm2_pctx; + if (src_smctx == NULL) { + fprintf(stderr, "src_smctx is NULL\n"); + return NULL; + } + + if (src_smctx->sm2_md == NULL) { + fprintf(stderr, "src_smctx is NULL\n"); + return NULL; + } + + dstctx = OPENSSL_zalloc(sizeof(PROV_SM2_ASYM_CTX)); + if (dstctx == NULL) { + fprintf(stderr, "failed to alloc dst ctx\n"); + return NULL; + } + *dstctx = *srcctx; + + dst_smctx = OPENSSL_zalloc(sizeof(SM2_PROV_CTX)); + if (dst_smctx == NULL) { + fprintf(stderr, "failed to alloc dst_smctx\n"); + goto free; + } + + dst_smctx->sm2_md = OPENSSL_zalloc(sizeof(SM2_MD_DATA)); + if (dst_smctx->sm2_md == NULL) { + fprintf(stderr, "failed to alloc dst_smd\n"); + goto free; + } + + if (dstctx->key != NULL && !EC_KEY_up_ref(dstctx->key)) { + fprintf(stderr, "failed to check dstctx key reference\n"); + goto free; + } + + if (dst_smctx->sm2_md->alloc_md && !EVP_MD_up_ref(dst_smctx->sm2_md->alloc_md)) { + fprintf(stderr, "failed to check alloc_md reference\n"); + goto free; + } + + dst_smctx->sm2_md->md = src_smctx->sm2_md->md; + dst_smctx->sm2_md->alloc_md = src_smctx->sm2_md->alloc_md; + + dstctx->sm2_pctx = dst_smctx; + + return dstctx; + +free: + uadk_asym_cipher_sm2_freectx(dstctx); + return NULL; +} + +static int uadk_asym_cipher_sm2_get_ctx_params(void *vpsm2ctx, OSSL_PARAM *params) +{ + PROV_SM2_ASYM_CTX *psm2ctx = (PROV_SM2_ASYM_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + SM2_MD_DATA *smd; + OSSL_PARAM *p; + EVP_MD *md; + + if (psm2ctx == NULL) { + fprintf(stderr, "failed to get psm2ctx\n"); + return UADK_P_FAIL; + } + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "failed to get smctx\n"); + return UADK_P_FAIL; + } + + smd = smctx->sm2_md; + if (smd == NULL) { + fprintf(stderr, "failed to get sm2 md\n"); + return UADK_P_FAIL; + } + + if (params == NULL) { + fprintf(stderr, "params is NULL\n"); + return UADK_P_FAIL; + } + + p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_DIGEST); + if (p != NULL) { + md = smd->md; + if (!OSSL_PARAM_set_utf8_string(p, md == NULL ? "" : EVP_MD_get0_name(md))) { + fprintf(stderr, "failed to set utf8 string\n"); + return UADK_P_FAIL; + } + smd->md_nid = EVP_MD_type(md); + } else { + return UADK_P_FAIL; + } + + return UADK_P_SUCCESS; +} + +static EVP_MD *uadk_prov_load_digest_from_params(SM2_MD_DATA *smd, const OSSL_PARAM params[], + OSSL_LIB_CTX *ctx) +{ + const char *propquery; + const OSSL_PARAM *p; + + /* Load common param properties, p can be NULL */ + p = OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_PROPERTIES); + if (p) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) { + fprintf(stderr, "data_type != OSSL_PARAM_UTF8_STRING\n"); + return NULL; + } + propquery = p->data; + } + + /* Load digest related params */ + p = OSSL_PARAM_locate_const(params, OSSL_ALG_PARAM_DIGEST); + if (p) { + if (p->data_type != OSSL_PARAM_UTF8_STRING) { + fprintf(stderr, "data_type != OSSL_PARAM_UTF8_STRING\n"); + return NULL; + } + } else { + /* If digest related params is NULL, no need to set digest */ + return NULL; + } + + /* Fetch digest */ + EVP_MD_free(smd->alloc_md); + smd->md = smd->alloc_md = EVP_MD_fetch(ctx, p->data, propquery); + if (smd->md == NULL) { + fprintf(stderr, "failed to fetch MD method\n"); + return NULL; + } + + return smd->md; +} + +static int uadk_asym_cipher_sm2_set_ctx_params(void *vpsm2ctx, const OSSL_PARAM params[]) +{ + PROV_SM2_ASYM_CTX *psm2ctx = (PROV_SM2_ASYM_CTX *)vpsm2ctx; + SM2_PROV_CTX *smctx; + SM2_MD_DATA *smd; + int ret; + + if (psm2ctx == NULL) { + fprintf(stderr, "invalid: sm2 ctx is NULL\n"); + return UADK_P_FAIL; + } + + /* No need to set */ + if (params == NULL) + return UADK_P_SUCCESS; + + smctx = psm2ctx->sm2_pctx; + if (smctx == NULL) { + fprintf(stderr, "invalid: smctx is NULL\n"); + return UADK_P_FAIL; + } + + /* Set digest method */ + smd = smctx->sm2_md; + if (smd == NULL) { + fprintf(stderr, "invalid: sm2 md is NULL\n"); + return UADK_P_FAIL; + } + + smd->md = uadk_prov_load_digest_from_params(smctx->sm2_md, params, psm2ctx->libctx); + if (smd->md == NULL) { + fprintf(stderr, "failed to set digest with set_ctx_params\n"); + return UADK_P_FAIL; + } + smd->md_nid = EVP_MD_type(smd->md); + + /* If not init, do not need to update session, just set the data before */ + if (smctx->init_status == CTX_INIT_SUCC) { + ret = uadk_prov_sm2_update_sess(smctx); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to update sess\n"); + return ret; + } + } + + return UADK_P_SUCCESS; +} + +static const OSSL_PARAM *uadk_asym_cipher_sm2_gettable_ctx_params(ossl_unused void *vpsm2ctx, + ossl_unused void *provctx) +{ + return sm2_asym_cipher_known_gettable_ctx_params; +} + +static const OSSL_PARAM *uadk_asym_cipher_sm2_settable_ctx_params(ossl_unused void *vpsm2ctx, + ossl_unused void *provctx) +{ + return sm2_asym_cipher_known_settable_ctx_params; +}