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 | 14 +- src/uadk_prov_pkey.c | 770 +++++++++++ src/uadk_prov_pkey.h | 389 ++++++ src/uadk_prov_sm2.c | 3127 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 4312 insertions(+), 5 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..698bbbc 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(); @@ -223,7 +234,7 @@ static int uadk_prov_ctx_set_core_bio_method(struct uadk_prov_ctx *ctx)
static void ossl_prov_core_from_dispatch(const OSSL_DISPATCH *fns) { - for (fns; fns->function_id != 0; fns++) { + while (fns && fns->function_id != 0) { switch (fns->function_id) { case OSSL_FUNC_CORE_GETTABLE_PARAMS: c_gettable_params = OSSL_FUNC_core_gettable_params(fns); @@ -238,6 +249,7 @@ static void ossl_prov_core_from_dispatch(const OSSL_DISPATCH *fns) /* Just ignore anything we don't understand */ break; } + fns++; } }
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..d044597 --- /dev/null +++ b/src/uadk_prov_pkey.h @@ -0,0 +1,389 @@ +/* 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; \ +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\n"); \ + } \ + } \ + return s_keymgmt; \ +} \ +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 } \ +} \ + +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 } \ +} \ + +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 } \ +} \ + +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..19d983a --- /dev/null +++ b/src/uadk_prov_sm2.c @@ -0,0 +1,3127 @@ +// 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; +} + +/* Uninit only when the process exits, will not uninit when thread exits. */ +void uadk_prov_sm2_uninit(void) +{ + pthread_mutex_lock(&sm2_mutex); + if (g_sm2_prov.pid == getpid()) { + wd_ecc_uninit2(); + g_sm2_prov.pid = 0; + } + pthread_mutex_unlock(&sm2_mutex); +} + +static int uadk_prov_sm2_keygen_init_iot(handle_t sess, struct wd_ecc_req *req) +{ + struct wd_ecc_out *ecc_out = wd_sm2_new_kg_out(sess); + + 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 free_ec_key; + } + + ret = uadk_prov_sm2_keygen(ec); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to generate sm2 key\n"); + goto free_ec_key; + } + + return ec; + +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\n", 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_private_key(SM2_PROV_CTX *smctx, EC_KEY *eckey) +{ + const BIGNUM *d; + int ret; + + d = EC_KEY_get0_private_key(eckey); + if (d == NULL) { + fprintf(stderr, "failed to set private key\n"); + return UADK_P_FAIL; + } + + if (smctx->sm2_pd == NULL) { + fprintf(stderr, "invalid: sm2_pd is NULL\n"); + return UADK_P_FAIL; + } + + if (smctx->sm2_pd->prikey && !BN_cmp(d, smctx->sm2_pd->prikey)) { + fprintf(stderr, "invalid: private key mismatch\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_private_key(smctx, psm2ctx->key); + 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 == NULL) { + fprintf(stderr, "invalid: sm2_pd is NULL\n"); + return UADK_P_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; + 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(smctx->sm2_md->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_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_sm2_update_private_key(smctx, ctx->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; + } + + 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; +}