From: Weili Qian qianweili@huawei.com
Support ecdsa signature and verify.
openssl speed -provider uadk_provider -seconds 10 ecdsap521
Signed-off-by: Weili Qian qianweili@huawei.com --- src/Makefile.am | 2 +- src/uadk_prov.h | 2 + src/uadk_prov_der_writer.c | 112 +++- src/uadk_prov_der_writer.h | 2 + src/uadk_prov_ecdsa.c | 1151 ++++++++++++++++++++++++++++++++++++ src/uadk_prov_init.c | 2 + src/uadk_prov_pkey.c | 2 +- src/uadk_prov_pkey.h | 1 + 8 files changed, 1269 insertions(+), 5 deletions(-) create mode 100644 src/uadk_prov_ecdsa.c
diff --git a/src/Makefile.am b/src/Makefile.am index c143edd..66650d2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -75,7 +75,7 @@ uadk_provider_la_SOURCES=uadk_prov_init.c uadk_async.c uadk_utils.c \ uadk_prov_pkey.c uadk_prov_sm2.c \ uadk_prov_ffc.c uadk_prov_aead.c \ uadk_prov_ec_kmgmt.c uadk_prov_ecdh_exch.c \ - uadk_prov_ecx.c + uadk_prov_ecx.c uadk_prov_ecdsa.c
uadk_provider_la_LDFLAGS=-module -version-number $(VERSION) uadk_provider_la_LIBADD=$(WD_LIBS) -lpthread diff --git a/src/uadk_prov.h b/src/uadk_prov.h index 84a3f01..2786e79 100644 --- a/src/uadk_prov.h +++ b/src/uadk_prov.h @@ -185,6 +185,8 @@ extern const OSSL_DISPATCH uadk_ecdh_keyexch_functions[FUNC_MAX_NUM]; extern const OSSL_DISPATCH uadk_x448_keymgmt_functions[FUNC_MAX_NUM]; extern const OSSL_DISPATCH uadk_x448_keyexch_functions[FUNC_MAX_NUM];
+extern const OSSL_DISPATCH uadk_ecdsa_signature_functions[FUNC_MAX_NUM]; + void uadk_prov_destroy_digest(void); void uadk_prov_destroy_cipher(void); void uadk_prov_destroy_aead(void); diff --git a/src/uadk_prov_der_writer.c b/src/uadk_prov_der_writer.c index e7e7e49..7e5ee31 100644 --- a/src/uadk_prov_der_writer.c +++ b/src/uadk_prov_der_writer.c @@ -12,10 +12,66 @@ #include <string.h> #include "uadk_prov_der_writer.h"
-#define DER_OID_SZ_sm2_with_SM3 10 -#define PACKET_LEN_TAG 30 +#define PACKET_LEN_TAG 30 +#define DER_P_OBJECT 6 +#define DER_OID_SZ_sm2_with_SM3 10 +#define DER_OID_SZ_ecdsa_with_SHA1 9 +#define DER_OID_SZ_ecdsa_with_SHA224 10 +#define DER_OID_SZ_ecdsa_with_SHA256 10 +#define DER_OID_SZ_ecdsa_with_SHA384 10 +#define DER_OID_SZ_ecdsa_with_SHA512 10 +#define DER_OID_SZ_id_ecdsa_with_sha3_224 11 +#define DER_OID_SZ_id_ecdsa_with_sha3_256 11 +#define DER_OID_SZ_id_ecdsa_with_sha3_384 11 +#define DER_OID_SZ_id_ecdsa_with_sha3_512 11 + +static const unsigned char +ossl_der_oid_id_ecdsa_with_sha1[DER_OID_SZ_ecdsa_with_SHA1] = { + DER_P_OBJECT, 7, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x01 +}; + +static const unsigned char +ossl_der_oid_id_ecdsa_with_sha224[DER_OID_SZ_ecdsa_with_SHA224] = { + DER_P_OBJECT, 8, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x01 +}; + +static const unsigned char +ossl_der_oid_id_ecdsa_with_sha256[DER_OID_SZ_ecdsa_with_SHA256] = { + DER_P_OBJECT, 8, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02 +};
-unsigned char ossl_der_oid_sm2_with_SM3[DER_OID_SZ_sm2_with_SM3] = { +static const unsigned char +ossl_der_oid_id_ecdsa_with_sha384[DER_OID_SZ_ecdsa_with_SHA384] = { + DER_P_OBJECT, 8, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x03 +}; + +static const unsigned char +ossl_der_oid_id_ecdsa_with_sha512[DER_OID_SZ_ecdsa_with_SHA384] = { + DER_P_OBJECT, 8, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x04 +}; + +static const unsigned char +ossl_der_oid_id_ecdsa_with_sha3_224[DER_OID_SZ_id_ecdsa_with_sha3_224] = { + DER_P_OBJECT, 9, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x09 +}; + +static const unsigned char +ossl_der_oid_id_ecdsa_with_sha3_256[DER_OID_SZ_id_ecdsa_with_sha3_256] = { + DER_P_OBJECT, 9, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x0A +}; + +static const unsigned char +ossl_der_oid_id_ecdsa_with_sha3_384[DER_OID_SZ_id_ecdsa_with_sha3_384] = { + DER_P_OBJECT, 9, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x0B +}; + +static const unsigned char +ossl_der_oid_id_ecdsa_with_sha3_512[DER_OID_SZ_id_ecdsa_with_sha3_512] = { + DER_P_OBJECT, 9, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x0C +}; + +static const unsigned char +ossl_der_oid_sm2_with_SM3[DER_OID_SZ_sm2_with_SM3] = { 6, 8, 0x2A, 0x81, 0x1C, 0xCF, 0x55, 0x01, 0x83, 0x75 };
@@ -234,3 +290,53 @@ int ossl_DER_w_algorithmIdentifier_SM2_with_MD(WPACKET *pkt, int cont, && ossl_DER_w_precompiled(pkt, -1, precompiled, precompiled_sz) && ossl_DER_w_end_sequence(pkt, cont); } + +int ossl_DER_w_algorithmIdentifier_ECDSA_with_MD(WPACKET *pkt, int cont, + EC_KEY *ec, int mdnid) +{ + const unsigned char *precompiled = NULL; + size_t precompiled_sz = 0; + +#define MD_CASE(name) \ +do { \ + precompiled = ossl_der_oid_id_ecdsa_with_##name; \ + precompiled_sz = sizeof(ossl_der_oid_id_ecdsa_with_##name); \ +} while (0) + + switch (mdnid) { + case NID_sha1: + MD_CASE(sha1); + break; + case NID_sha224: + MD_CASE(sha224); + break; + case NID_sha256: + MD_CASE(sha256); + break; + case NID_sha384: + MD_CASE(sha384); + break; + case NID_sha512: + MD_CASE(sha512); + break; + case NID_sha3_224: + MD_CASE(sha3_224); + break; + case NID_sha3_256: + MD_CASE(sha3_256); + break; + case NID_sha3_384: + MD_CASE(sha3_384); + break; + case NID_sha3_512: + MD_CASE(sha3_512); + break; + default: + return 0; + } + + return ossl_DER_w_begin_sequence(pkt, cont) && + /* No parameters (yet?) */ + ossl_DER_w_precompiled(pkt, -1, precompiled, precompiled_sz) && + ossl_DER_w_end_sequence(pkt, cont); +} diff --git a/src/uadk_prov_der_writer.h b/src/uadk_prov_der_writer.h index 39308e0..4f0bab5 100644 --- a/src/uadk_prov_der_writer.h +++ b/src/uadk_prov_der_writer.h @@ -126,4 +126,6 @@ int ossl_DER_w_end_sequence(WPACKET *pkt, int tag);
int ossl_DER_w_algorithmIdentifier_SM2_with_MD(WPACKET *pkt, int cont, EC_KEY *ec, int mdnid); +int ossl_DER_w_algorithmIdentifier_ECDSA_with_MD(WPACKET *pkt, int cont, + EC_KEY *ec, int mdnid); #endif diff --git a/src/uadk_prov_ecdsa.c b/src/uadk_prov_ecdsa.c new file mode 100644 index 0000000..774e8ee --- /dev/null +++ b/src/uadk_prov_ecdsa.c @@ -0,0 +1,1151 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + * Copyright 2024 Huawei Technologies Co.,Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/err.h> +#include <openssl/kdf.h> +#include "uadk_async.h" +#include "uadk_prov.h" +#include "uadk_prov_der_writer.h" +#include "uadk_prov_pkey.h" + +#define DIGEST_MAX_NAME_SIZE 50 +#define MAX_ALGORITHM_ID_SIZE 256 +#define MAX_PROPQUERY_SIZE 256 +#define UADK_SIGN_SIG_NULL 2 +#define DGST_SHIFT_NUM(n) (8 - ((n) & 0x7)) +#define UADK_PROV_ECDSA "ecdsa" + +/* + * What's passed as an actual key is defined by the KEYMGMT interface. + * We happen to know that our KEYMGMT simply passes DSA structures, so + * we use that here too. + */ +struct ecdsa_ctx { + OSSL_LIB_CTX *libctx; + char *propq; + EC_KEY *ec; + char mdname[DIGEST_MAX_NAME_SIZE]; + + /* + * Flag to determine if the hash function can be changed (true) or not (false) + * Because it's dangerous to change during a DigestSign or DigestVerify + * operation, this flag is cleared by their Init function, and set again + * by their Final function. + */ + bool flag_allow_md; + + /* The Algorithm Identifier of the combined signature algorithm */ + unsigned char aid_buf[MAX_ALGORITHM_ID_SIZE]; + unsigned char *aid; + size_t aid_len; + size_t mdsize; + int operation; + + EVP_MD *md; + EVP_MD_CTX *mdctx; + /* + * Internally used to cache the results of calling the EC group + * sign_setup() methods which are then passed to the sign operation. + * This is used by CAVS failure tests to terminate a loop if the signature + * is not valid. + * This could of also been done with a simple flag. + */ + BIGNUM *kinv; + BIGNUM *r; +}; + +struct ecdsa_opdata { + const unsigned char *tbs; + size_t tbslen; + ECDSA_SIG *sig; + EC_KEY *ec; +}; + +UADK_PKEY_SIGNATURE_DESCR(ecdsa, ECDSA); + +static void *uadk_signature_ecdsa_newctx(void *provctx, const char *propq) +{ + struct ecdsa_ctx *ctx; + + ctx = OPENSSL_zalloc(sizeof(*ctx)); + if (!ctx) + return NULL; + + ctx->flag_allow_md = true; + ctx->libctx = prov_libctx_of(provctx); + + if (propq) { + ctx->propq = OPENSSL_strdup(propq); + if (!ctx->propq) { + fprintf(stderr, "failed to strdup propq!\n"); + OPENSSL_free(ctx); + ctx = NULL; + } + } + + return ctx; +} + +static void uadk_signature_ecdsa_freectx(void *vctx) +{ + struct ecdsa_ctx *ctx = (struct ecdsa_ctx *)vctx; + + if (!ctx) + return; + + OPENSSL_free(ctx->propq); + EVP_MD_CTX_free(ctx->mdctx); + EVP_MD_free(ctx->md); + EC_KEY_free(ctx->ec); + BN_clear_free(ctx->kinv); + BN_clear_free(ctx->r); + OPENSSL_clear_free(ctx, sizeof(*ctx)); +} + +static void *uadk_signature_ecdsa_dupctx(void *vctx) +{ + struct ecdsa_ctx *src_ctx = (struct ecdsa_ctx *)vctx; + struct ecdsa_ctx *dst_ctx; + + if (!src_ctx) { + fprintf(stderr, "invalid: src ctx is NULL to dupctx!\n"); + return NULL; + } + + /* Test KATS should not need to be supported */ + if (src_ctx->kinv || src_ctx->r) { + fprintf(stderr, "invalid: src ctx kinv or r is not NULL!\n"); + return NULL; + } + + dst_ctx = OPENSSL_zalloc(sizeof(*dst_ctx)); + if (!dst_ctx) + return NULL; + + *dst_ctx = *src_ctx; + dst_ctx->ec = NULL; + dst_ctx->md = NULL; + dst_ctx->mdctx = NULL; + dst_ctx->propq = NULL; + + if (src_ctx->ec && !EC_KEY_up_ref(src_ctx->ec)) + goto err; + dst_ctx->ec = src_ctx->ec; + + if (src_ctx->md && !EVP_MD_up_ref(src_ctx->md)) + goto err; + dst_ctx->md = src_ctx->md; + + if (src_ctx->mdctx) { + dst_ctx->mdctx = EVP_MD_CTX_new(); + if (!dst_ctx->mdctx || !EVP_MD_CTX_copy_ex(dst_ctx->mdctx, src_ctx->mdctx)) + goto err; + } + + if (src_ctx->propq) { + dst_ctx->propq = OPENSSL_strdup(src_ctx->propq); + if (!dst_ctx->propq) + goto err; + } + + return dst_ctx; + +err: + uadk_signature_ecdsa_freectx(dst_ctx); + return NULL; +} + +static void ecdsa_set_aid(struct ecdsa_ctx *ctx, int md_nid) +{ + WPACKET pkt; + + ctx->aid_len = 0; + if (WPACKET_init_der(&pkt, ctx->aid_buf, sizeof(ctx->aid_buf)) && + ossl_DER_w_algorithmIdentifier_ECDSA_with_MD(&pkt, -1, ctx->ec, md_nid) && + WPACKET_finish(&pkt)) { + WPACKET_get_total_written(&pkt, &ctx->aid_len); + ctx->aid = WPACKET_get_curr(&pkt); + } + WPACKET_cleanup(&pkt); +} + +/* + * Internal library code deals with NIDs, so we need to translate from a name. + * We do so using EVP_MD_is_a(), and therefore need a name to NID map. + */ +static int ecdsa_digest_md_to_nid(const EVP_MD *md, const OSSL_ITEM *it, size_t it_len) +{ + size_t i; + + if (!md) + return NID_undef; + + for (i = 0; i < it_len; i++) + if (EVP_MD_is_a(md, it[i].ptr)) + return (int)it[i].id; + + return NID_undef; +} + +/* + * Retrieve one of the FIPS approved hash algorithms by nid. + * See FIPS 180-4 "Secure Hash Standard" and FIPS 202 - SHA-3. + */ +static int ecdsa_digest_get_nid(const EVP_MD *md) +{ + static const OSSL_ITEM name_to_nid[] = { + {NID_sha1, OSSL_DIGEST_NAME_SHA1}, + {NID_sha224, OSSL_DIGEST_NAME_SHA2_224}, + {NID_sha256, OSSL_DIGEST_NAME_SHA2_256}, + {NID_sha384, OSSL_DIGEST_NAME_SHA2_384}, + {NID_sha512, OSSL_DIGEST_NAME_SHA2_512}, + {NID_sha512_224, OSSL_DIGEST_NAME_SHA2_512_224}, + {NID_sha512_256, OSSL_DIGEST_NAME_SHA2_512_256}, + {NID_sha3_224, OSSL_DIGEST_NAME_SHA3_224}, + {NID_sha3_256, OSSL_DIGEST_NAME_SHA3_256}, + {NID_sha3_384, OSSL_DIGEST_NAME_SHA3_384}, + {NID_sha3_512, OSSL_DIGEST_NAME_SHA3_512}, + }; + + return ecdsa_digest_md_to_nid(md, name_to_nid, OSSL_NELEM(name_to_nid)); +} + +static int ecdsa_digest_get_approved_nid(struct ecdsa_ctx *ctx, const EVP_MD *md) +{ + int mdnid = ecdsa_digest_get_nid(md); + +#ifndef OPENSSL_NO_FIPS_SECURITYCHECKS + int sha1_allowed = (ctx->operation != EVP_PKEY_OP_SIGN); + + if (uadk_prov_securitycheck_enabled(ctx->libctx)) { + if (mdnid == NID_undef || (mdnid == NID_sha1 && !sha1_allowed)) + mdnid = -1; /* disallowed by security checks */ + } +# endif /* OPENSSL_NO_FIPS_SECURITYCHECKS */ + + return mdnid; +} + +static int ecdsa_setup_md(struct ecdsa_ctx *ctx, const char *mdname, const char *mdprops) +{ + size_t mdname_len; + EVP_MD *md = NULL; + int md_nid; + + if (!mdname) + return UADK_P_SUCCESS; + + mdname_len = strlen(mdname); + if (mdname_len >= DIGEST_MAX_NAME_SIZE) { + fprintf(stderr, "invalid: %s size %zu exceeds name buffer length %d!\n", + mdname, mdname_len, DIGEST_MAX_NAME_SIZE); + return UADK_P_FAIL; + } + + if (!mdprops) + mdprops = ctx->propq; + + md = EVP_MD_fetch(ctx->libctx, mdname, mdprops); + if (!md) { + fprintf(stderr, "failed to fetch %s!\n", mdname); + return UADK_P_FAIL; + } + + md_nid = ecdsa_digest_get_approved_nid(ctx, md); + if (md_nid < 0) { + fprintf(stderr, "digest %s not allowed!\n", mdname); + goto err; + } + + if (!ctx->flag_allow_md) { + if (ctx->mdname[0] != '\0' && !EVP_MD_is_a(md, ctx->mdname)) { + fprintf(stderr, "digest %s is not same ctx digest %s!\n", + mdname, ctx->mdname); + goto err; + } + EVP_MD_free(md); + return UADK_P_SUCCESS; + } + + EVP_MD_CTX_free(ctx->mdctx); + ctx->mdctx = NULL; + + EVP_MD_free(ctx->md); + ctx->md = md; + ctx->mdsize = EVP_MD_get_size(ctx->md); + OPENSSL_strlcpy(ctx->mdname, mdname, DIGEST_MAX_NAME_SIZE); + + ecdsa_set_aid(ctx, md_nid); + + return UADK_P_SUCCESS; + +err: + EVP_MD_free(md); + return UADK_P_FAIL; +} + +static int ecdsa_signverify_init(void *vctx, void *ec, + const OSSL_PARAM params[], + int operation) +{ + struct ecdsa_ctx *ctx = (struct ecdsa_ctx *)vctx; + const EC_KEY *eckey = (const EC_KEY *)ec; + int ret; + + if (!ctx || (!ec && !ctx->ec)) { + fprintf(stderr, "invalid: ctx or ec is NULL to digest init!\n"); + return UADK_P_FAIL; + } + + ret = uadk_signature_ecdsa_set_ctx_params(ctx, params); + if (!ret) + return ret; + + if (eckey) { + if (!uadk_prov_ecc_check_key(ctx->libctx, eckey, + operation == EVP_PKEY_OP_SIGN)) + return UADK_P_FAIL; + + if (!EC_KEY_up_ref(ec)) + return UADK_P_FAIL; + EC_KEY_free(ctx->ec); + ctx->ec = ec; + } + + ctx->operation = operation; + + return UADK_P_SUCCESS; +} + +static int uadk_signature_ecdsa_sign_init(void *vctx, void *ec, const OSSL_PARAM params[]) +{ + return ecdsa_signverify_init(vctx, ec, params, EVP_PKEY_OP_SIGN); +} + +static int uadk_signature_ecdsa_verify_init(void *vctx, void *ec, const OSSL_PARAM params[]) +{ + return ecdsa_signverify_init(vctx, ec, params, EVP_PKEY_OP_VERIFY); +} + +static int ecdsa_common_params_check(struct ecdsa_ctx *ctx, + struct ecdsa_opdata *opdata) +{ + const EC_GROUP *group; + int type; + + if (unlikely(!opdata->tbs || !opdata->tbslen)) { + fprintf(stderr, "invalid: tbs is NULL or tbslen %zu error!\n", opdata->tbslen); + return UADK_P_FAIL; + } + + if (ctx->mdsize && opdata->tbslen != ctx->mdsize) { + fprintf(stderr, "invalid: ctx->mdsize %zu not equal tbslen %zu!\n", + ctx->mdsize, opdata->tbslen); + return UADK_P_FAIL; + } + + group = EC_KEY_get0_group(ctx->ec); + if (unlikely(!group)) { + fprintf(stderr, "invalid: group is NULL!\n"); + return UADK_P_FAIL; + } + + /* Field GF(2m) is not supported by uadk */ + type = EC_METHOD_get_field_type(EC_GROUP_method_of(group)); + if (type != NID_X9_62_prime_field) { + fprintf(stderr, "invalid: uadk unsupport Field GF(2m)!\n"); + return UADK_P_FAIL; + } + + opdata->ec = ctx->ec; + + return uadk_prov_ecc_bit_check(group); +} + +static handle_t ecdsa_alloc_sess(EC_KEY *ec) +{ + int ret; + + ret = uadk_prov_signature_get_support_state(SIGNATURE_ECDSA); + if (!ret) { + fprintf(stderr, "failed to get hardware ecdsa support!\n"); + return ret; + } + + ret = uadk_prov_ecc_init(UADK_PROV_ECDSA); + if (!ret) { + fprintf(stderr, "failed to init ecdsa!\n"); + return ret; + } + + return uadk_prov_ecc_alloc_sess(ec, UADK_PROV_ECDSA); +} + +static void ecdsa_free_sess(handle_t sess) +{ + wd_ecc_free_sess(sess); +} + +static bool ecdsa_data_is_all_zero(struct wd_dtb *e) +{ + __u32 i; + + for (i = 0; i < e->dsize; i++) { + if (e->data[i]) + return false; + } + + return true; +} + +static int ecdsa_set_digest(struct ecdsa_opdata *opdata, struct wd_dtb *e) +{ + const EC_GROUP *group = EC_KEY_get0_group(opdata->ec); + size_t order_bits = EC_GROUP_order_bits(group); + size_t data_len = opdata->tbslen; + BIGNUM *m; + + if (BYTES_TO_BITS(data_len) > order_bits) { + m = BN_new(); + if (!m) { + fprintf(stderr, "failed to BN_new m!\n"); + return UADK_P_FAIL; + } + + /* + * Need to truncate digest if it is too long: first truncate + * whole bytes + */ + data_len = BITS_TO_BYTES(order_bits); + if (!BN_bin2bn(opdata->tbs, data_len, m)) { + fprintf(stderr, "failed to BN_bin2bn tbs!\n"); + BN_free(m); + return UADK_P_FAIL; + } + + /* + * If the length of digest is still longer than the length + * of the base point order, truncate remaining bits with a + * shift to that length. + */ + if (BYTES_TO_BITS(data_len) > order_bits && + !BN_rshift(m, m, DGST_SHIFT_NUM(order_bits))) { + fprintf(stderr, "failed to truncate input tbs!\n"); + BN_free(m); + return UADK_P_FAIL; + } + e->dsize = BN_bn2bin(m, (void *)e->data); + e->bsize = UADK_ECC_MAX_KEY_BYTES; + BN_free(m); + } else { + e->data = (char *)opdata->tbs; + e->dsize = data_len; + e->bsize = data_len; + } + + if (ecdsa_data_is_all_zero(e)) + return UADK_P_FAIL; + + return UADK_P_SUCCESS; +} + +static int ecdsa_sign_init_iot(handle_t sess, struct wd_ecc_req *req, + struct ecdsa_opdata *opdata) +{ + char buff[UADK_ECC_MAX_KEY_BYTES] = {0}; + struct wd_ecc_out *ecc_out; + struct wd_ecc_in *ecc_in; + struct wd_dtb e = {0}; + int ret; + + e.data = buff; + ret = ecdsa_set_digest(opdata, &e); + if (!ret) + return ret; + + ecc_in = wd_ecdsa_new_sign_in(sess, &e, NULL); + if (unlikely(!ecc_in)) { + fprintf(stderr, "failed to new ecdsa sign in!\n"); + return UADK_P_FAIL; + } + + ecc_out = wd_ecdsa_new_sign_out(sess); + if (unlikely(!ecc_out)) { + fprintf(stderr, "failed to new ecdsa sign out!\n"); + wd_ecc_del_in(sess, ecc_in); + return UADK_P_FAIL; + } + + uadk_prov_ecc_fill_req(req, WD_ECDSA_SIGN, ecc_in, ecc_out); + + return UADK_P_SUCCESS; +} + +static void ecdsa_uninit_req_iot(handle_t sess, struct wd_ecc_req *req) +{ + if (req->src) + wd_ecc_del_in(sess, req->src); + if (req->dst) + wd_ecc_del_out(sess, req->dst); +} + +static ECDSA_SIG *ecdsa_get_sign_data(struct wd_ecc_req *req) +{ + struct wd_dtb *r = NULL; + struct wd_dtb *s = NULL; + BIGNUM *br, *bs; + ECDSA_SIG *sig; + int ret; + + br = BN_new(); + bs = BN_new(); + if (unlikely(!br || !bs)) { + fprintf(stderr, "failed to new br or bs!\n"); + goto free_bn; + } + + wd_ecdsa_get_sign_out_params(req->dst, &r, &s); + if (unlikely(!r || !s)) { + fprintf(stderr, "failed to get r or s\n"); + goto free_bn; + } + + if (!BN_bin2bn((void *)r->data, r->dsize, br) || + !BN_bin2bn((void *)s->data, s->dsize, bs)) { + fprintf(stderr, "failed to BN_bin2bn r or s\n"); + goto free_bn; + } + + sig = ECDSA_SIG_new(); + if (unlikely(!sig)) { + fprintf(stderr, "failed to new sig!\n"); + goto free_bn; + } + + ret = ECDSA_SIG_set0(sig, br, bs); + if (unlikely(!ret)) { + fprintf(stderr, "failed to set br or bs to sig!\n"); + goto free_sig; + } + + return sig; +free_sig: + ECDSA_SIG_free(sig); +free_bn: + BN_clear_free(br); + BN_clear_free(bs); + return NULL; +} + +static int ecdsa_hw_sign(struct ecdsa_opdata *opdata) +{ + struct wd_ecc_req req = {0}; + handle_t sess; + int ret; + + sess = ecdsa_alloc_sess(opdata->ec); + if (unlikely(!sess)) { + fprintf(stderr, "failed to alloc ecdsa sess!\n"); + return UADK_P_FAIL; + } + + ret = ecdsa_sign_init_iot(sess, &req, opdata); + if (unlikely(!ret)) { + fprintf(stderr, "failed to ecdsa_sign_init_iot!\n"); + goto free_sess; + } + + ret = uadk_prov_ecc_set_private_key(sess, opdata->ec); + if (unlikely(!ret)) { + fprintf(stderr, "failed to set private key!\n"); + goto free_iot; + } + + ret = uadk_prov_ecc_crypto(sess, &req, (void *)sess); + if (unlikely(!ret)) { + fprintf(stderr, "failed to sign!\n"); + goto free_iot; + } + + opdata->sig = ecdsa_get_sign_data(&req); + if (!opdata->sig) + ret = UADK_P_FAIL; + +free_iot: + ecdsa_uninit_req_iot(sess, &req); +free_sess: + ecdsa_free_sess(sess); + return ret; +} + +static int ecdsa_sign_params_check(struct ecdsa_ctx *ctx, + struct ecdsa_opdata *opdata, + unsigned char *sig, size_t *siglen, + size_t sigsize) +{ + size_t ecsize; + + if (unlikely(!siglen)) { + fprintf(stderr, "invalid: siglen is NULL to sign!\n"); + return UADK_P_FAIL; + } + + if (unlikely(!ctx || !ctx->ec)) { + fprintf(stderr, "invalid: ctx or ec is NULL to sign!\n"); + return UADK_P_FAIL; + } + + ecsize = ECDSA_size(ctx->ec); + if (unlikely(!sig)) { + *siglen = ecsize; + return UADK_SIGN_SIG_NULL; + } + + if (unlikely(sigsize < ecsize)) { + fprintf(stderr, "invalid: sigsize %zu is less than ecsize %zu!\n", + sigsize, ecsize); + return UADK_P_FAIL; + } + + return ecdsa_common_params_check(ctx, opdata); +} + +static int uadk_signature_ecdsa_sign(void *vctx, unsigned char *sig, size_t *siglen, + size_t sigsize, const unsigned char *tbs, size_t tbslen) +{ + struct ecdsa_ctx *ctx = (struct ecdsa_ctx *)vctx; + struct ecdsa_opdata opdata = {0}; + int ret; + + opdata.tbs = tbs; + opdata.tbslen = tbslen; + ret = ecdsa_sign_params_check(ctx, &opdata, sig, siglen, sigsize); + if (ret == UADK_SIGN_SIG_NULL) { + return UADK_P_SUCCESS; + } else if (unlikely(!ret)) { + fprintf(stderr, "failed to check params to sign!\n"); + goto err; + } + + ret = ecdsa_hw_sign(&opdata); + if (unlikely(!ret)) + goto err; + ret = i2d_ECDSA_SIG(opdata.sig, &sig); + /* ECDSA_SIG_free will free br and bs applied for in ecdsa_get_sign_data() */ + ECDSA_SIG_free(opdata.sig); + if (ret < 0) + goto err; + + *siglen = (size_t)ret; + + return UADK_P_SUCCESS; +err: + if (siglen) + *siglen = 0; + return UADK_P_FAIL; +} + +static int ecdsa_verify_init_iot(handle_t sess, struct wd_ecc_req *req, + struct ecdsa_opdata *opdata) +{ + char buf_r[UADK_ECC_MAX_KEY_BYTES] = {0}; + char buf_s[UADK_ECC_MAX_KEY_BYTES] = {0}; + char buf_e[UADK_ECC_MAX_KEY_BYTES] = {0}; + const BIGNUM *sig_r = NULL; + const BIGNUM *sig_s = NULL; + struct wd_ecc_in *ecc_in; + struct wd_dtb e = {0}; + struct wd_dtb r = {0}; + struct wd_dtb s = {0}; + int ret; + + e.data = buf_e; + ret = ecdsa_set_digest(opdata, &e); + if (!ret) + return ret; + + r.data = buf_r; + s.data = buf_s; + r.bsize = UADK_ECC_MAX_KEY_BYTES; + s.bsize = UADK_ECC_MAX_KEY_BYTES; + ECDSA_SIG_get0(opdata->sig, &sig_r, &sig_s); + r.dsize = BN_bn2bin(sig_r, (void *)r.data); + s.dsize = BN_bn2bin(sig_s, (void *)s.data); + ecc_in = wd_ecdsa_new_verf_in(sess, &e, &r, &s); + if (unlikely(!ecc_in)) { + fprintf(stderr, "failed to new ecdsa verf in\n"); + return UADK_P_FAIL; + } + + uadk_prov_ecc_fill_req(req, WD_ECDSA_VERIFY, ecc_in, NULL); + + return UADK_P_SUCCESS; +} + +static int ecdsa_hw_verify(struct ecdsa_opdata *opdata) +{ + struct wd_ecc_req req = {0}; + handle_t sess; + int ret; + + sess = ecdsa_alloc_sess(opdata->ec); + if (!sess) { + fprintf(stderr, "failed to alloc ecdsa sess!\n"); + return UADK_P_FAIL; + } + + ret = ecdsa_verify_init_iot(sess, &req, opdata); + if (!ret) + goto free_sess; + + ret = uadk_prov_ecc_set_public_key(sess, opdata->ec); + if (!ret) + goto free_iot; + + ret = uadk_prov_ecc_crypto(sess, &req, (void *)sess); + +free_iot: + ecdsa_uninit_req_iot(sess, &req); +free_sess: + ecdsa_free_sess(sess); + return ret; +} + +static int ecdsa_verify_params_check(struct ecdsa_ctx *ctx, struct ecdsa_opdata *opdata, + const unsigned char *sig, size_t siglen) +{ + if (!ctx || !ctx->ec) { + fprintf(stderr, "invalid: ctx or ec is NULL to verify!\n"); + return UADK_P_FAIL; + } + + if (!sig || !siglen) { + fprintf(stderr, "invalid: sig is NULL or siglen %zu error!\n", siglen); + return UADK_P_FAIL; + } + + return ecdsa_common_params_check(ctx, opdata); +} + +static ECDSA_SIG *ecdsa_create_sig(const unsigned char *sig, size_t siglen) +{ + const unsigned char *p = sig; + unsigned char *der = NULL; + ECDSA_SIG *s; + int derlen; + + s = ECDSA_SIG_new(); + if (!s) { + fprintf(stderr, "failed to new s to verify!\n"); + return NULL; + } + + if (!d2i_ECDSA_SIG(&s, &p, siglen)) { + fprintf(stderr, "failed to d2i_ECDSA_SIG: siglen = %zu!\n", + siglen); + goto err; + } + + /* Ensure signature uses DER and doesn't have trailing garbage */ + derlen = i2d_ECDSA_SIG(s, &der); + if (derlen != siglen || memcmp(sig, der, derlen) != 0) { + fprintf(stderr, "sig have trailing garbage, derlen %d!\n", derlen); + OPENSSL_free(der); + goto err; + } + + OPENSSL_free(der); + + return s; + +err: + ECDSA_SIG_free(s); + return NULL; +} + +static int uadk_signature_ecdsa_verify(void *vctx, const unsigned char *sig, + size_t siglen, const unsigned char *tbs, + size_t tbslen) +{ + struct ecdsa_ctx *ctx = (struct ecdsa_ctx *)vctx; + struct ecdsa_opdata opdata = {0}; + int ret; + + opdata.tbs = tbs; + opdata.tbslen = tbslen; + ret = ecdsa_verify_params_check(ctx, &opdata, sig, siglen); + if (!ret) { + fprintf(stderr, "failed to check params to sign!\n"); + return UADK_P_FAIL; + } + + opdata.sig = ecdsa_create_sig(sig, siglen); + if (!opdata.sig) { + fprintf(stderr, "failed to create s to verify!\n"); + return UADK_P_FAIL; + } + + ret = ecdsa_hw_verify(&opdata); + + ECDSA_SIG_free(opdata.sig); + return ret; +} + +static int ecdsa_digest_singverify_init(void *vctx, const char *mdname, void *ec, + const OSSL_PARAM params[], int operation) +{ + struct ecdsa_ctx *ctx = (struct ecdsa_ctx *)vctx; + int ret; + + ret = ecdsa_signverify_init(vctx, ec, params, operation); + if (!ret) + return ret; + + ret = ecdsa_setup_md(ctx, mdname, NULL); + if (!ret) + return ret; + + ctx->flag_allow_md = false; + if (!ctx->mdctx) { + ctx->mdctx = EVP_MD_CTX_new(); + if (!ctx->mdctx) + goto err; + } + + ret = EVP_DigestInit_ex2(ctx->mdctx, ctx->md, params); + if (!ret) + goto err; + + return UADK_P_SUCCESS; + +err: + EVP_MD_CTX_free(ctx->mdctx); + ctx->mdctx = NULL; + return UADK_P_FAIL; +} + +static int uadk_signature_ecdsa_digest_sign_init(void *vctx, const char *mdname, + void *ec, const OSSL_PARAM params[]) +{ + return ecdsa_digest_singverify_init(vctx, mdname, ec, params, EVP_PKEY_OP_SIGN); +} + +static int ecdsa_digest_signverify_update(void *vctx, const unsigned char *data, + size_t datalen) +{ + struct ecdsa_ctx *ctx = (struct ecdsa_ctx *)vctx; + + if (!ctx || !ctx->mdctx) { + fprintf(stderr, "invalid: ctx or mdctx is NULL to digest update!\n"); + return UADK_P_FAIL; + } + + return EVP_DigestUpdate(ctx->mdctx, data, datalen); +} + +static int uadk_signature_ecdsa_digest_sign_update(void *vctx, const unsigned char *data, + size_t datalen) +{ + return ecdsa_digest_signverify_update(vctx, data, datalen); +} + +static int uadk_signature_ecdsa_digest_sign_final(void *vctx, unsigned char *sig, + size_t *siglen, size_t sigsize) +{ + struct ecdsa_ctx *ctx = (struct ecdsa_ctx *)vctx; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int dlen = 0; + + if (!ctx || !ctx->mdctx) { + fprintf(stderr, "invalid: ctx or mdctx is NULL to sign digest final!\n"); + return UADK_P_FAIL; + } + + /* + * If sig is NULL then we're just finding out the sig size. Other fields + * are ignored. Defer to uadk_signature_ecdsa_sign. + */ + if (sig && !EVP_DigestFinal_ex(ctx->mdctx, digest, &dlen)) + return UADK_P_FAIL; + + ctx->flag_allow_md = true; + + return uadk_signature_ecdsa_sign(vctx, sig, siglen, sigsize, digest, (size_t)dlen); +} + +static int uadk_signature_ecdsa_digest_verify_init(void *vctx, const char *mdname, + void *ec, const OSSL_PARAM params[]) +{ + return ecdsa_digest_singverify_init(vctx, mdname, ec, params, EVP_PKEY_OP_VERIFY); +} + +static int uadk_signature_ecdsa_digest_verify_update(void *vctx, const unsigned char *data, + size_t datalen) +{ + return ecdsa_digest_signverify_update(vctx, data, datalen); +} + +static int uadk_signature_ecdsa_digest_verify_final(void *vctx, const unsigned char *sig, + size_t siglen) +{ + struct ecdsa_ctx *ctx = (struct ecdsa_ctx *)vctx; + unsigned char digest[EVP_MAX_MD_SIZE]; + unsigned int dlen = 0; + + if (!ctx || !ctx->mdctx) { + fprintf(stderr, "invalid: ctx or mdctx is NULL to verify digest final!\n"); + return UADK_P_FAIL; + } + + if (!EVP_DigestFinal_ex(ctx->mdctx, digest, &dlen)) + return UADK_P_FAIL; + + ctx->flag_allow_md = true; + + return uadk_signature_ecdsa_verify(vctx, sig, siglen, digest, (size_t)dlen); +} + +static int ecdsa_get_ctx_aid(struct ecdsa_ctx *ctx, OSSL_PARAM *params) +{ + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID); + if (!p) + return UADK_P_SUCCESS; + + return OSSL_PARAM_set_octet_string(p, ctx->aid, ctx->aid_len); +} + +static int ecdsa_get_ctx_digest_size(struct ecdsa_ctx *ctx, OSSL_PARAM *params) +{ + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE); + if (!p) + return UADK_P_SUCCESS; + + return OSSL_PARAM_set_size_t(p, ctx->mdsize); +} + +static int ecdsa_get_ctx_digest(struct ecdsa_ctx *ctx, OSSL_PARAM *params) +{ + const char *mdname; + OSSL_PARAM *p; + + p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST); + if (!p) + return UADK_P_SUCCESS; + + mdname = ctx->md ? EVP_MD_get0_name(ctx->md) : ctx->mdname; + + return OSSL_PARAM_set_utf8_string(p, mdname); +} + +static int uadk_signature_ecdsa_get_ctx_params(void *vctx, OSSL_PARAM *params) +{ + struct ecdsa_ctx *ctx = (struct ecdsa_ctx *)vctx; + int ret; + + if (!ctx) { + fprintf(stderr, "invalid: ctx is NULL to get_ctx_params!\n"); + return UADK_P_FAIL; + } + + if (!params) + return UADK_P_SUCCESS; + + ret = ecdsa_get_ctx_digest(ctx, params); + if (!ret) + return ret; + + ret = ecdsa_get_ctx_digest_size(ctx, params); + if (!ret) + return ret; + + return ecdsa_get_ctx_aid(ctx, params); +} + +static const OSSL_PARAM 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 +}; + +static const OSSL_PARAM * +uadk_signature_ecdsa_gettable_ctx_params(ossl_unused void *vctx, + ossl_unused void *provctx) +{ + return known_gettable_ctx_params; +} + +static int ecdsa_set_ctx_digest(struct ecdsa_ctx *ctx, const OSSL_PARAM params[]) +{ + char mdname[DIGEST_MAX_NAME_SIZE] = {0}; + char mdprops[MAX_PROPQUERY_SIZE] = {0}; + const OSSL_PARAM *p_digest, *propsp; + char *pmdprops = mdprops; + char *pmdname = mdname; + int ret; + + p_digest = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST); + if (!p_digest) + return UADK_P_SUCCESS; + + ret = OSSL_PARAM_get_utf8_string(p_digest, &pmdname, DIGEST_MAX_NAME_SIZE); + if (!ret) + return UADK_P_FAIL; + + propsp = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_PROPERTIES); + if (propsp) { + ret = OSSL_PARAM_get_utf8_string(propsp, &pmdprops, MAX_PROPQUERY_SIZE); + if (!ret) + return UADK_P_FAIL; + } + + return ecdsa_setup_md(ctx, mdname, mdprops); +} + +static int ecdsa_set_ctx_digest_size(struct ecdsa_ctx *ctx, const OSSL_PARAM params[]) +{ + const OSSL_PARAM *p; + size_t mdsize = 0; + int ret; + + p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE); + if (!p) + return UADK_P_SUCCESS; + + ret = OSSL_PARAM_get_size_t(p, &mdsize); + if (!ret) + return UADK_P_FAIL; + + if (!ctx->flag_allow_md && mdsize != ctx->mdsize) + return UADK_P_FAIL; + + ctx->mdsize = mdsize; + + return UADK_P_SUCCESS; +} + +static int uadk_signature_ecdsa_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + struct ecdsa_ctx *ctx = (struct ecdsa_ctx *)vctx; + int ret; + + if (!ctx) { + fprintf(stderr, "invalid: ctx is NULL to set_ctx_params!\n"); + return UADK_P_FAIL; + } + + if (!params) + return UADK_P_SUCCESS; + + ret = ecdsa_set_ctx_digest(ctx, params); + if (!ret) + return ret; + + return ecdsa_set_ctx_digest_size(ctx, params); +} + +static const OSSL_PARAM settable_ctx_params[] = { + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), + OSSL_PARAM_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, NULL), + OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_uint(OSSL_SIGNATURE_PARAM_KAT, NULL), + OSSL_PARAM_END +}; + +static const OSSL_PARAM settable_ctx_params_no_digest[] = { + OSSL_PARAM_uint(OSSL_SIGNATURE_PARAM_KAT, NULL), + OSSL_PARAM_END +}; + +static const OSSL_PARAM * +uadk_signature_ecdsa_settable_ctx_params(void *vctx, ossl_unused void *provctx) +{ + struct ecdsa_ctx *ctx = (struct ecdsa_ctx *)vctx; + + if (ctx && !ctx->flag_allow_md) + return settable_ctx_params_no_digest; + + return settable_ctx_params; +} + +static int uadk_signature_ecdsa_get_ctx_md_params(void *vctx, OSSL_PARAM *params) +{ + struct ecdsa_ctx *ctx = (struct ecdsa_ctx *)vctx; + + if (!ctx || !ctx->mdctx) { + fprintf(stderr, "invalid: ctx or md ctx is NULL to get_ctx_md_params!\n"); + return UADK_P_FAIL; + } + + return EVP_MD_CTX_get_params(ctx->mdctx, params); +} + +static const OSSL_PARAM *uadk_signature_ecdsa_gettable_ctx_md_params(void *vctx) +{ + struct ecdsa_ctx *ctx = (struct ecdsa_ctx *)vctx; + + if (!ctx || !ctx->md) { + fprintf(stderr, "invalid: ctx or md is NULL to gettable_ctx_md_params!\n"); + return NULL; + } + + return EVP_MD_gettable_ctx_params(ctx->md); +} + +static int uadk_signature_ecdsa_set_ctx_md_params(void *vctx, const OSSL_PARAM params[]) +{ + struct ecdsa_ctx *ctx = (struct ecdsa_ctx *)vctx; + + if (!ctx || !ctx->mdctx) { + fprintf(stderr, "invalid: ctx or md ctx is NULL to set_ctx_md_params!\n"); + return UADK_P_FAIL; + } + + return EVP_MD_CTX_set_params(ctx->mdctx, params); +} + +static const OSSL_PARAM *uadk_signature_ecdsa_settable_ctx_md_params(void *vctx) +{ + struct ecdsa_ctx *ctx = (struct ecdsa_ctx *)vctx; + + if (!ctx || !ctx->md) { + fprintf(stderr, "invalid: ctx or md is NULL to settable_ctx_md_params!\n"); + return NULL; + } + + return EVP_MD_settable_ctx_params(ctx->md); +} + +static int uadk_signature_ecdsa_verify_recover_init(void *vctx, void *vecdsa, + const OSSL_PARAM params[]) +{ + return UADK_P_SUCCESS; +} + +static int uadk_signature_ecdsa_verify_recover(void *vctx, unsigned char *rout, + size_t *routlen, size_t routsize, + const unsigned char *sig, size_t siglen) +{ + return UADK_P_SUCCESS; +} diff --git a/src/uadk_prov_init.c b/src/uadk_prov_init.c index 9a2baeb..52d0b90 100644 --- a/src/uadk_prov_init.c +++ b/src/uadk_prov_init.c @@ -165,6 +165,8 @@ static const OSSL_ALGORITHM uadk_prov_signature[] = { uadk_rsa_signature_functions, "uadk_provider rsa_signature" }, { "SM2", UADK_DEFAULT_PROPERTIES, uadk_sm2_signature_functions, "uadk_provider sm2_signature" }, + { "ECDSA", UADK_DEFAULT_PROPERTIES, + uadk_ecdsa_signature_functions, "uadk_provider ecdsa_signature" }, { NULL, NULL, NULL } };
diff --git a/src/uadk_prov_pkey.c b/src/uadk_prov_pkey.c index f654dd6..ebf90e4 100644 --- a/src/uadk_prov_pkey.c +++ b/src/uadk_prov_pkey.c @@ -680,7 +680,7 @@ void uadk_prov_keymgmt_alg(void)
void uadk_prov_signature_alg(void) { - static const char * const signature_alg[] = {"sm2"}; + static const char * const signature_alg[] = {"sm2", "ecdsa"}; __u32 i, size; bool sp;
diff --git a/src/uadk_prov_pkey.h b/src/uadk_prov_pkey.h index f40313d..38a67ac 100644 --- a/src/uadk_prov_pkey.h +++ b/src/uadk_prov_pkey.h @@ -75,6 +75,7 @@ enum {
enum { SIGNATURE_SM2 = 0x0, + SIGNATURE_ECDSA = 0x1, SIGNATURE_MAX = 0x3 };
From: Weili Qian qianweili@huawei.com
Currently, the async_get_queue_task() only checks whether op in task is NULL. However, instructions executed by the CPU core are out of order. Therefore, it cannot be ensured that type and ctx are assigned values when op is assigned values in async_add_poll_task(). If the value of ctx in the task is NULL or the value of type is invalid, the CPU core will access an abnormal address, resulting in segment error. Therefore, before using ctx or type, check whether the value is valid.
Signed-off-by: Weili Qian qianweili@huawei.com --- src/uadk_async.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/uadk_async.c b/src/uadk_async.c index 4f2ec6a..7536bd5 100644 --- a/src/uadk_async.c +++ b/src/uadk_async.c @@ -147,7 +147,8 @@ err: if (pthread_mutex_unlock(&poll_queue.async_task_mutex)) return NULL;
- if (cur_task && !cur_task->op) + if (!cur_task || !cur_task->op || + !cur_task->ctx || cur_task->type == ASYNC_TASK_MAX) return NULL;
return cur_task; @@ -197,6 +198,8 @@ int async_get_free_task(int *id) task_queue = poll_queue.head; task = &task_queue[idx]; task->op = NULL; + task->ctx = NULL; + task->type = ASYNC_TASK_MAX; ret = UADK_E_SUCCESS;
out:
From: Weili Qian qianweili@huawei.com
In asynchronous scenarios, if random numbers are obtained using uadk provider cipher, deadlocks may occur. Therefore, random numbers are obtained using default provider cipher.
logs like: 20808E99FFFF0000:error:1C8000B6:Provider routines:ossl_drbg_lock_parent: parent locking not enabled:providers/implementations/rands/drbg.c:70: 20808E99FFFF0000:error:1C8000C9:Provider routines:get_parent_strength: unable to lock parent:providers/implementations/rands/drbg.c:97: 20808E99FFFF0000:error:1C8000BD:Provider routines: ossl_prov_drbg_instantiate: error retrieving entropy: providers/implementations/rands/drbg.c:456: 20808E99FFFF0000:error:1C8000C0:Provider routines:ossl_prov_drbg_generate: in error state:providers/implementations/rands/drbg.c:630: 20808E99FFFF0000:error:030000D6:digital envelope routines: evp_rand_generate_locked:generate error:crypto/evp/evp_rand.c:560:
Signed-off-by: Weili Qian qianweili@huawei.com --- src/uadk_prov_init.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/uadk_prov_init.c b/src/uadk_prov_init.c index 52d0b90..41733b5 100644 --- a/src/uadk_prov_init.c +++ b/src/uadk_prov_init.c @@ -25,6 +25,7 @@ #include <openssl/crypto.h> #include <openssl/evp.h> #include <openssl/provider.h> +#include <openssl/rand.h>
#include "uadk_async.h" #include "uadk_prov.h" @@ -210,10 +211,18 @@ static const OSSL_ALGORITHM *uadk_query(void *provctx, int operation_id, prov = OSSL_PROVIDER_load(NULL, "default"); if (!prov_init) { prov_init = 1; - /* uadk_provider takes the highest priority + /* + * uadk_provider takes the highest priority * and overwrite the openssl.cnf property. */ EVP_set_default_properties(NULL, "?provider=uadk_provider"); + /* + * In asynchronous scenarios, if random numbers are obtained using + * uadk provider cipher, deadlocks may occur. Therefore, random numbers are + * obtained using default provider cipher. + */ + (void)RAND_set_DRBG_type(prov_libctx_of(provctx), NULL, + "provider=default", NULL, NULL); }
*no_cache = 0;
From: Chenghai Huang huangchenghai2@huawei.com
Modify redundant lines of code and extract the same code to separate functions.
Signed-off-by: Chenghai Huang huangchenghai2@huawei.com --- src/uadk_prov_aead.c | 88 +++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 47 deletions(-)
diff --git a/src/uadk_prov_aead.c b/src/uadk_prov_aead.c index d6e90ca..9861519 100644 --- a/src/uadk_prov_aead.c +++ b/src/uadk_prov_aead.c @@ -178,7 +178,6 @@ mutex_unlock:
static int uadk_prov_aead_ctx_init(struct aead_priv_ctx *priv) { - struct wd_aead_sess_setup setup = {0}; struct sched_params params = {0}; int ret;
@@ -201,11 +200,10 @@ static int uadk_prov_aead_ctx_init(struct aead_priv_ctx *priv) params.type = 0; /* Use the default numa parameters */ params.numa_id = -1; - memcpy(&setup, &priv->setup, sizeof(struct wd_aead_sess_setup)); - setup.sched_param = ¶ms; + priv->setup.sched_param = ¶ms;
if (!priv->sess) { - priv->sess = wd_aead_alloc_sess(&setup); + priv->sess = wd_aead_alloc_sess(&priv->setup); if (!priv->sess) { fprintf(stderr, "uadk failed to alloc session!\n"); return UADK_AEAD_FAIL; @@ -234,21 +232,17 @@ free_sess:
static void *uadk_prov_aead_cb(struct wd_aead_req *req, void *data) { - struct uadk_e_cb_info *cb_param; + struct uadk_e_cb_info *aead_cb_param; struct wd_aead_req *req_origin; struct async_op *op;
- if (!req) - return NULL; - - cb_param = req->cb_param; - if (!cb_param) + if (!req || !req->cb_param) return NULL;
- req_origin = cb_param->priv; + aead_cb_param = req->cb_param; + req_origin = aead_cb_param->priv; req_origin->state = req->state; - - op = cb_param->op; + op = aead_cb_param->op; if (op && op->job && !op->done) { op->done = 1; async_free_poll_task(op->idx, 1); @@ -280,18 +274,18 @@ static int do_aes_gcm_prepare(struct aead_priv_ctx *priv) return UADK_AEAD_SUCCESS; }
-static void uadk_do_aead_async_prepare(struct aead_priv_ctx *priv, unsigned char *out, - const unsigned char *in, size_t inlen) +static void uadk_do_aead_async_prepare(struct aead_priv_ctx *priv, unsigned char *output, + const unsigned char *input, size_t inlen) { priv->req.in_bytes = inlen; - /* AAD data is input or output together with plaintext or ciphertext. */ + /* AAD data will be input and output together with plaintext or ciphertext. */ if (priv->req.assoc_bytes) { - memcpy(priv->data + priv->req.assoc_bytes, in, inlen); + memcpy(priv->data + priv->req.assoc_bytes, input, inlen); priv->req.src = priv->data; priv->req.dst = priv->data + AEAD_BLOCK_SIZE; } else { - priv->req.src = (unsigned char *)in; - priv->req.dst = out; + priv->req.src = (unsigned char *)input; + priv->req.dst = output; } }
@@ -790,6 +784,25 @@ static const OSSL_PARAM *uadk_prov_aead_gettable_ctx_params(ossl_unused void *cc return uadk_prov_aead_ctx_params; }
+static int uadk_prov_aead_get_ctx_iv(OSSL_PARAM *p, struct aead_priv_ctx *priv) +{ + if (priv->iv_set == IV_STATE_UNINITIALISED) + return UADK_OSSL_FAIL; + + if (priv->ivlen > p->data_size) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); + return UADK_OSSL_FAIL; + } + + if (!OSSL_PARAM_set_octet_string(p, priv->iv, priv->ivlen) + && !OSSL_PARAM_set_octet_ptr(p, &priv->iv, priv->ivlen)) { + ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); + return UADK_OSSL_FAIL; + } + + return UADK_AEAD_SUCCESS; +} + static int uadk_prov_aead_get_ctx_params(void *vctx, OSSL_PARAM params[]) { struct aead_priv_ctx *priv = (struct aead_priv_ctx *)vctx; @@ -822,34 +835,12 @@ static int uadk_prov_aead_get_ctx_params(void *vctx, OSSL_PARAM params[]) }
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_IV); - if (p) { - if (priv->iv_set == IV_STATE_UNINITIALISED) - return UADK_OSSL_FAIL; - if (priv->ivlen > p->data_size) { - ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); - return UADK_OSSL_FAIL; - } - if (!OSSL_PARAM_set_octet_string(p, priv->iv, priv->ivlen) - && !OSSL_PARAM_set_octet_ptr(p, &priv->iv, priv->ivlen)) { - ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); - return UADK_OSSL_FAIL; - } - } + if (p && !uadk_prov_aead_get_ctx_iv(p, priv)) + return UADK_OSSL_FAIL;
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_UPDATED_IV); - if (p) { - if (priv->iv_set == IV_STATE_UNINITIALISED) - return UADK_OSSL_FAIL; - if (priv->ivlen > p->data_size) { - ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_IV_LENGTH); - return UADK_OSSL_FAIL; - } - if (!OSSL_PARAM_set_octet_string(p, priv->iv, priv->ivlen) - && !OSSL_PARAM_set_octet_ptr(p, &priv->iv, priv->ivlen)) { - ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); - return UADK_OSSL_FAIL; - } - } + if (p && !uadk_prov_aead_get_ctx_iv(p, priv)) + return UADK_OSSL_FAIL;
p = OSSL_PARAM_locate(params, OSSL_CIPHER_PARAM_AEAD_TAG); if (p) { @@ -958,10 +949,13 @@ static void uadk_prov_aead_freectx(void *ctx) priv->sess = 0; }
+ if (priv->data) { OPENSSL_clear_free(priv->data, AEAD_BLOCK_SIZE << 1); priv->data = NULL; } + + OPENSSL_clear_free(priv, sizeof(*priv)); }
@@ -974,9 +968,9 @@ static void *uadk_##nm##_newctx(void *provctx) \ if (!ctx) \ return NULL; \ \ - ctx->data = OPENSSL_zalloc(AEAD_BLOCK_SIZE << 1); \ + ctx->data = OPENSSL_clear_free(ctx, sizeof(*ctx)); \ if (!ctx->data) { \ - OPENSSL_clear_free(ctx, sizeof(*ctx)); \ + OPENSSL_free(ctx); \ return NULL; \ } \ \
From: Chenghai Huang huangchenghai2@huawei.com
1.Add unlock when fork to prevent deadlock. 2.Before executing uadk digest, check whether the pid is new. If the process is a new process, initialize resources.
Signed-off-by: Chenghai Huang huangchenghai2@huawei.com --- src/uadk_prov_digest.c | 115 +++++++++++++++++++++++++++++++---------- 1 file changed, 89 insertions(+), 26 deletions(-)
diff --git a/src/uadk_prov_digest.c b/src/uadk_prov_digest.c index 0fe31d2..820256f 100644 --- a/src/uadk_prov_digest.c +++ b/src/uadk_prov_digest.c @@ -53,6 +53,9 @@ #define DIGEST_BLOCK_SIZE (512 * 1024) #define ALG_NAME_SIZE 128
+#define UADK_DIGEST_DEF_CTXS 1 +#define UADK_DIGEST_OP_NUM 1 + enum sec_digest_state { SEC_DIGEST_INIT, SEC_DIGEST_FIRST_UPDATING, @@ -272,41 +275,73 @@ static int uadk_get_digest_info(struct digest_priv_ctx *priv) return UADK_DIGEST_SUCCESS; }
-static int uadk_digest_init(struct digest_priv_ctx *priv) +static void uadk_digest_mutex_infork(void) { - struct sched_params params = {0}; - int ret; + /* Release the replication lock of the child process */ + pthread_mutex_unlock(&digest_mutex); +} + +static int uadk_prov_digest_dev_init(struct digest_priv_ctx *priv) +{ + struct wd_ctx_params cparams = {0}; + struct wd_ctx_nums ctx_set_num; + int ret = UADK_DIGEST_SUCCESS;
+ pthread_atfork(NULL, NULL, uadk_digest_mutex_infork); pthread_mutex_lock(&digest_mutex); - if (dprov.pid != getpid()) { - ret = wd_digest_init2(priv->alg_name, 0, 0); - if (unlikely(ret)) { - priv->switch_flag = UADK_DO_SOFT; - goto soft_init; - } - dprov.pid = getpid(); - async_register_poll_fn(ASYNC_TASK_DIGEST, uadk_digest_poll); + if (dprov.pid == getpid()) + goto mutex_unlock; + + cparams.op_type_num = UADK_DIGEST_OP_NUM; + cparams.ctx_set_num = &ctx_set_num; + cparams.bmp = numa_allocate_nodemask(); + if (!cparams.bmp) { + ret = UADK_DIGEST_FAIL; + fprintf(stderr, "failed to create nodemask!\n"); + goto mutex_unlock; } + + numa_bitmask_setall(cparams.bmp); + + ctx_set_num.sync_ctx_num = UADK_DIGEST_DEF_CTXS; + ctx_set_num.async_ctx_num = UADK_DIGEST_DEF_CTXS; + + ret = wd_digest_init2_(priv->alg_name, TASK_MIX, SCHED_POLICY_RR, &cparams); + if (unlikely(ret)) { + fprintf(stderr, "uadk failed to initialize digest.\n"); + goto free_nodemask; + } + ret = UADK_DIGEST_SUCCESS; + + dprov.pid = getpid(); + async_register_poll_fn(ASYNC_TASK_DIGEST, uadk_digest_poll); + +free_nodemask: + numa_free_nodemask(cparams.bmp); +mutex_unlock: pthread_mutex_unlock(&digest_mutex); + return ret; +}
- ret = uadk_get_digest_info(priv); - if (unlikely(!ret)) - return ret; +static int uadk_digest_ctx_init(struct digest_priv_ctx *priv) +{ + struct sched_params params = {0}; + int ret; + + ret = uadk_prov_digest_dev_init(priv); + if (unlikely(ret <= 0)) + goto soft_init;
/* Use the default numa parameters */ params.numa_id = -1; priv->setup.sched_param = ¶ms; - priv->sess = wd_digest_alloc_sess(&priv->setup); - if (unlikely(!priv->sess)) { - fprintf(stderr, "uadk failed to alloc sess.\n"); - return UADK_DIGEST_FAIL; - }
- priv->data = OPENSSL_malloc(DIGEST_BLOCK_SIZE); - if (unlikely(!priv->data)) { - wd_digest_free_sess(priv->sess); - fprintf(stderr, "uadk failed to apply mem for data storage.\n"); - return UADK_DIGEST_FAIL; + if (!priv->sess) { + priv->sess = wd_digest_alloc_sess(&priv->setup); + if (unlikely(!priv->sess)) { + fprintf(stderr, "uadk failed to alloc sess.\n"); + return UADK_DIGEST_FAIL; + } }
if (enable_sw_offload) @@ -352,6 +387,10 @@ static int uadk_digest_update_inner(struct digest_priv_ctx *priv, const void *da size_t processing_len; int ret;
+ ret = uadk_digest_ctx_init(priv); + if (ret != UADK_DIGEST_SUCCESS) + return UADK_DIGEST_FAIL; + priv->req.has_next = DIGEST_DOING; uadk_fill_mac_buffer_len(priv);
@@ -530,6 +569,10 @@ static int uadk_digest_final(struct digest_priv_ctx *priv, unsigned char *digest return UADK_DIGEST_FAIL; }
+ ret = uadk_digest_ctx_init(priv); + if (ret != UADK_DIGEST_SUCCESS) + return UADK_DIGEST_FAIL; + priv->req.has_next = DIGEST_END; priv->req.in = priv->data; priv->req.out = priv->out; @@ -586,6 +629,10 @@ static int uadk_digest_digest(struct digest_priv_ctx *priv, const void *data, si return UADK_DIGEST_FAIL; }
+ ret = uadk_digest_ctx_init(priv); + if (ret != UADK_DIGEST_SUCCESS) + return UADK_DIGEST_FAIL; + ret = async_setup_async_event_notification(&op); if (unlikely(!ret)) { fprintf(stderr, "failed to setup async event notification.\n"); @@ -626,7 +673,7 @@ static void uadk_digest_cleanup(struct digest_priv_ctx *priv) OPENSSL_free(priv->data);
if (priv->soft_ctx) - OPENSSL_free(priv->soft_ctx); + OPENSSL_free(priv->data); }
/* some params related code is copied from OpenSSL v3.0 prov/digestcommon.h */ @@ -704,13 +751,22 @@ static void *uadk_prov_dupctx(void *dctx) static int uadk_prov_init(void *dctx, const OSSL_PARAM params[]) { struct digest_priv_ctx *priv = (struct digest_priv_ctx *)dctx; + int ret;
if (!dctx) { fprintf(stderr, "CTX is NULL.\n"); return UADK_DIGEST_FAIL; }
- return uadk_digest_init(priv); + ret = uadk_get_digest_info(priv); + if (unlikely(!ret)) + return UADK_DIGEST_FAIL; + + ret = uadk_prov_digest_dev_init(priv); + if (unlikely(ret <= 0)) + return UADK_DIGEST_FAIL; + + return UADK_DIGEST_SUCCESS; }
static int uadk_prov_update(void *dctx, const unsigned char *in, size_t inl) @@ -808,6 +864,13 @@ static void *uadk_##name##_newctx(void *provctx) \ char *ptr; \ if (!ctx) \ return NULL; \ + \ + ctx->data = OPENSSL_zalloc(DIGEST_BLOCK_SIZE); \ + if (!ctx->data) { \ + OPENSSL_free(ctx); \ + return NULL; \ + } \ + \ ctx->blk_size = blksize; \ ctx->md_size = mdsize; \ ctx->e_nid = nid; \
From: Chenghai Huang huangchenghai2@huawei.com
After the ctx is copied, the data in the buffer of the ctx needs to be copied to the new ctx.
In addition, the value of total_data_len in the sess also needs to be copied synchronously. The method is to change the NEXT flag in the req to WD_DIGEST_XXX. The UADK will synchronizes the long packet data to the new sess.
Signed-off-by: Chenghai Huang huangchenghai2@huawei.com --- src/uadk_prov_digest.c | 87 +++++++++++++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 19 deletions(-)
diff --git a/src/uadk_prov_digest.c b/src/uadk_prov_digest.c index 820256f..0810629 100644 --- a/src/uadk_prov_digest.c +++ b/src/uadk_prov_digest.c @@ -98,6 +98,8 @@ struct digest_priv_ctx { size_t md_size; size_t blk_size; char alg_name[ALG_NAME_SIZE]; + size_t total_data_len; + bool is_stream_copy; };
struct digest_info { @@ -355,24 +357,22 @@ soft_init: return uadk_digest_soft_init(priv); }
-static void uadk_fill_mac_buffer_len(struct digest_priv_ctx *priv) +static void uadk_fill_mac_buffer_len(struct digest_priv_ctx *priv, bool is_end) { /* Sha224 and Sha384 and Sha512-XXX need full length mac buffer as doing long hash */ switch (priv->e_nid) { case NID_sha224: - priv->req.out_bytes = (priv->req.has_next == DIGEST_DOING) ? - WD_DIGEST_SHA224_FULL_LEN : WD_DIGEST_SHA224_LEN; + priv->req.out_bytes = !is_end ? WD_DIGEST_SHA224_FULL_LEN : WD_DIGEST_SHA224_LEN; break; case NID_sha384: - priv->req.out_bytes = (priv->req.has_next == DIGEST_DOING) ? - WD_DIGEST_SHA384_FULL_LEN : WD_DIGEST_SHA384_LEN; + priv->req.out_bytes = !is_end ? WD_DIGEST_SHA384_FULL_LEN : WD_DIGEST_SHA384_LEN; break; case NID_sha512_224: - priv->req.out_bytes = (priv->req.has_next == DIGEST_DOING) ? + priv->req.out_bytes = !is_end ? WD_DIGEST_SHA512_224_FULL_LEN : WD_DIGEST_SHA512_224_LEN; break; case NID_sha512_256: - priv->req.out_bytes = (priv->req.has_next == DIGEST_DOING) ? + priv->req.out_bytes = !is_end ? WD_DIGEST_SHA512_256_FULL_LEN : WD_DIGEST_SHA512_256_LEN; break; default: @@ -380,6 +380,16 @@ static void uadk_fill_mac_buffer_len(struct digest_priv_ctx *priv) } }
+static void uadk_digest_set_msg_state(struct digest_priv_ctx *priv, bool is_end) +{ + if (unlikely(priv->is_stream_copy)) { + priv->req.has_next = is_end ? WD_DIGEST_STREAM_END : WD_DIGEST_STREAM_DOING; + priv->is_stream_copy = false; + } else { + priv->req.has_next = is_end ? WD_DIGEST_END : WD_DIGEST_DOING; + } +} + static int uadk_digest_update_inner(struct digest_priv_ctx *priv, const void *data, size_t data_len) { unsigned char *input_data = (unsigned char *)data; @@ -391,8 +401,8 @@ static int uadk_digest_update_inner(struct digest_priv_ctx *priv, const void *da if (ret != UADK_DIGEST_SUCCESS) return UADK_DIGEST_FAIL;
- priv->req.has_next = DIGEST_DOING; - uadk_fill_mac_buffer_len(priv); + uadk_digest_set_msg_state(priv, false); + uadk_fill_mac_buffer_len(priv, false);
do { /* @@ -467,6 +477,8 @@ static int uadk_digest_update(struct digest_priv_ctx *priv, const void *data, si if (unlikely(priv->switch_flag == UADK_DO_SOFT)) goto soft_update;
+ priv->total_data_len += data_len; + if (priv->last_update_bufflen + data_len <= DIGEST_BLOCK_SIZE) { uadk_memcpy(priv->data + priv->last_update_bufflen, data, data_len); priv->last_update_bufflen += data_len; @@ -573,12 +585,12 @@ static int uadk_digest_final(struct digest_priv_ctx *priv, unsigned char *digest if (ret != UADK_DIGEST_SUCCESS) return UADK_DIGEST_FAIL;
- priv->req.has_next = DIGEST_END; priv->req.in = priv->data; priv->req.out = priv->out; priv->req.in_bytes = priv->last_update_bufflen;
- uadk_fill_mac_buffer_len(priv); + uadk_digest_set_msg_state(priv, true); + uadk_fill_mac_buffer_len(priv, true);
ret = async_setup_async_event_notification(&op); if (unlikely(!ret)) { @@ -639,13 +651,13 @@ static int uadk_digest_digest(struct digest_priv_ctx *priv, const void *data, si return UADK_DIGEST_FAIL; }
- priv->req.has_next = DIGEST_END; priv->req.in = priv->data; priv->req.out = priv->out; priv->req.in_bytes = data_len; uadk_memcpy(priv->data, data, data_len);
- uadk_fill_mac_buffer_len(priv); + uadk_digest_set_msg_state(priv, true); + uadk_fill_mac_buffer_len(priv, true);
if (op.job == NULL) ret = uadk_do_digest_sync(priv); @@ -736,16 +748,53 @@ static void uadk_prov_freectx(void *dctx)
static void *uadk_prov_dupctx(void *dctx) { - struct digest_priv_ctx *in, *ret; + struct digest_priv_ctx *dst_ctx, *src_ctx; + int ret;
+ src_ctx = (struct digest_priv_ctx *)dctx; if (!dctx) return NULL;
- in = (struct digest_priv_ctx *)dctx; - ret = OPENSSL_malloc(sizeof(struct digest_priv_ctx)); - if (ret) - memcpy(ret, in, sizeof(struct digest_priv_ctx)); - return ret; + dst_ctx = OPENSSL_memdup(src_ctx, sizeof(struct digest_priv_ctx)); + if (!dst_ctx) + return NULL; + + /* + * When a copy is performed during digest execution, + * the status in the sess needs to be synchronized. + */ + if (dst_ctx->sess && dst_ctx->state != SEC_DIGEST_INIT) { + dst_ctx->is_stream_copy = true; + /* + * Length that the hardware has processed should be equal to + * total input data length minus software cache data length. + */ + dst_ctx->req.long_data_len = dst_ctx->total_data_len + - dst_ctx->last_update_bufflen; + } + + dst_ctx->sess = 0; + dst_ctx->data = OPENSSL_memdup(src_ctx->data, DIGEST_BLOCK_SIZE); + if (!dst_ctx->data) + goto free_ctx; + + if (dst_ctx->soft_ctx) { + dst_ctx->soft_ctx = EVP_MD_CTX_new(); + if (!dst_ctx->soft_ctx) { + fprintf(stderr, "EVP_MD_CTX_new failed in ctx copy.\n"); + goto free_data; + } + } + + return dst_ctx; + +free_soft: + digest_soft_cleanup(dst_ctx); +free_data: + OPENSSL_clear_free(dst_ctx->data, DIGEST_BLOCK_SIZE); +free_ctx: + OPENSSL_clear_free(dst_ctx, sizeof(*dst_ctx)); + return NULL; }
static int uadk_prov_init(void *dctx, const OSSL_PARAM params[])
From: Chenghai Huang huangchenghai2@huawei.com
1.The input and output pointers of the digest_digest interface can be directly used and do not need to be copied. 2. OPENSSL_clear_free can set pointer to zero and does not need to be set to NULL. 3.Pointer type conversion is added to avoid compilation alarms of inconsistent types. 4.Adjust the registration position of the digest function to avoid compilation alarms: note: previous definition of 'uadk_prov_freectx' was here 491 | static void uadk_prov_freectx(void *dctx) | ^~~~~~~~~~~~~~~~~ 5.Add a NULL pointer checking for cipher freectx.
Signed-off-by: Chenghai Huang huangchenghai2@huawei.com --- src/uadk_prov_aead.c | 12 +++--------- src/uadk_prov_cipher.c | 3 +++ src/uadk_prov_digest.c | 35 +++++++++++++++-------------------- 3 files changed, 21 insertions(+), 29 deletions(-)
diff --git a/src/uadk_prov_aead.c b/src/uadk_prov_aead.c index 9861519..d5f860e 100644 --- a/src/uadk_prov_aead.c +++ b/src/uadk_prov_aead.c @@ -944,17 +944,11 @@ static void uadk_prov_aead_freectx(void *ctx) if (!ctx) return;
- if (priv->sess) { + if (priv->sess) wd_aead_free_sess(priv->sess); - priv->sess = 0; - } -
- if (priv->data) { + if (priv->data) OPENSSL_clear_free(priv->data, AEAD_BLOCK_SIZE << 1); - priv->data = NULL; - } -
OPENSSL_clear_free(priv, sizeof(*priv)); } @@ -968,7 +962,7 @@ static void *uadk_##nm##_newctx(void *provctx) \ if (!ctx) \ return NULL; \ \ - ctx->data = OPENSSL_clear_free(ctx, sizeof(*ctx)); \ + ctx->data = OPENSSL_zalloc(AEAD_BLOCK_SIZE << 1); \ if (!ctx->data) { \ OPENSSL_free(ctx); \ return NULL; \ diff --git a/src/uadk_prov_cipher.c b/src/uadk_prov_cipher.c index f4a182e..04a6489 100644 --- a/src/uadk_prov_cipher.c +++ b/src/uadk_prov_cipher.c @@ -1265,6 +1265,9 @@ static void uadk_prov_cipher_freectx(void *ctx) { struct cipher_priv_ctx *priv = (struct cipher_priv_ctx *)ctx;
+ if (ctx == NULL) + return; + if (priv->sw_cipher) EVP_CIPHER_free(priv->sw_cipher);
diff --git a/src/uadk_prov_digest.c b/src/uadk_prov_digest.c index 0810629..d78475d 100644 --- a/src/uadk_prov_digest.c +++ b/src/uadk_prov_digest.c @@ -636,7 +636,7 @@ static int uadk_digest_digest(struct digest_priv_ctx *priv, const void *data, si struct async_op op; int ret;
- if (!priv->data) { + if (!data) { fprintf(stderr, "failed to do single digest, data in CTX is NULL.\n"); return UADK_DIGEST_FAIL; } @@ -651,11 +651,9 @@ static int uadk_digest_digest(struct digest_priv_ctx *priv, const void *data, si return UADK_DIGEST_FAIL; }
- priv->req.in = priv->data; - priv->req.out = priv->out; + priv->req.in = data; + priv->req.out = digest; priv->req.in_bytes = data_len; - uadk_memcpy(priv->data, data, data_len); - uadk_digest_set_msg_state(priv, true); uadk_fill_mac_buffer_len(priv, true);
@@ -669,25 +667,31 @@ static int uadk_digest_digest(struct digest_priv_ctx *priv, const void *data, si async_clear_async_event_notification(); return ret; } - memcpy(digest, priv->req.out, priv->req.out_bytes);
return UADK_DIGEST_SUCCESS; }
static void uadk_digest_cleanup(struct digest_priv_ctx *priv) { - if (priv->sess) { + if (priv->sess) wd_digest_free_sess(priv->sess); - priv->sess = 0; - }
if (priv->data) - OPENSSL_free(priv->data); + OPENSSL_clear_free(priv->data, DIGEST_BLOCK_SIZE);
if (priv->soft_ctx) - OPENSSL_free(priv->data); + OPENSSL_clear_free(priv->soft_ctx, sizeof(EVP_MD_CTX)); }
+static OSSL_FUNC_digest_freectx_fn uadk_prov_freectx; +static OSSL_FUNC_digest_dupctx_fn uadk_prov_dupctx; +static OSSL_FUNC_digest_init_fn uadk_prov_init; +static OSSL_FUNC_digest_update_fn uadk_prov_update; +static OSSL_FUNC_digest_final_fn uadk_prov_final; +static OSSL_FUNC_digest_digest_fn uadk_prov_digest; +static OSSL_FUNC_digest_gettable_params_fn + uadk_prov_gettable_params; + /* some params related code is copied from OpenSSL v3.0 prov/digestcommon.h */ static const OSSL_PARAM uadk_digest_default_known_gettable_params[] = { OSSL_PARAM_size_t(OSSL_DIGEST_PARAM_BLOCK_SIZE, NULL), @@ -896,15 +900,6 @@ void uadk_prov_destroy_digest(void) pthread_mutex_unlock(&digest_mutex); }
-static OSSL_FUNC_digest_freectx_fn uadk_prov_freectx; -static OSSL_FUNC_digest_dupctx_fn uadk_prov_dupctx; -static OSSL_FUNC_digest_init_fn uadk_prov_init; -static OSSL_FUNC_digest_update_fn uadk_prov_update; -static OSSL_FUNC_digest_final_fn uadk_prov_final; -static OSSL_FUNC_digest_digest_fn uadk_prov_digest; -static OSSL_FUNC_digest_gettable_params_fn - uadk_prov_gettable_params; - #define UADK_PROVIDER_IMPLEMENTATION(name, nid, mdsize, blksize) \ static OSSL_FUNC_digest_newctx_fn uadk_##name##_newctx; \ static void *uadk_##name##_newctx(void *provctx) \
From: Zhiqi Song songzhiqi1@huawei.com
The global pkey meth need to be released in destroy process. Otherwise memory leakage occurs.
Signed-off-by: Zhiqi Song songzhiqi1@huawei.com --- src/uadk_rsa.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/src/uadk_rsa.c b/src/uadk_rsa.c index 81d633f..445b51b 100644 --- a/src/uadk_rsa.c +++ b/src/uadk_rsa.c @@ -1938,6 +1938,14 @@ static EVP_PKEY_METHOD *uadk_rsa_get_pkey_meth(void) return g_hpre_pkey_meth; }
+static void uadk_rsa_free_pkey_meth(EVP_PKEY_METHOD *pmeth) +{ + if (g_hpre_pkey_meth) { + EVP_PKEY_meth_free(g_hpre_pkey_meth); + g_hpre_pkey_meth = NULL; + } +} + /** * uadk_e_bind_rsa() - Set the access to get rsa methods to the ENGINE. * @e: uadk engine @@ -1951,6 +1959,7 @@ int uadk_e_bind_rsa(ENGINE *e) void uadk_e_destroy_rsa(void) { pthread_spin_destroy(&g_rsa_res.lock); + uadk_rsa_free_pkey_meth(g_hpre_pkey_meth); uadk_e_delete_rsa_meth(); uadk_e_rsa_uninit(); }
From: Zhiqi Song songzhiqi1@huawei.com
When enable 'dynamic_path' of uadk_engine in openssl.cnf, and execute speed tool with '-multi' param, the uadk_engine will be bind and init before fork() operation. The fork() operation will copy memory resources from parent process and get a child process.
As uadk_engine will register a function in child process with pthread_atfork(), the child process will call the async_module_init() and alloc new memory, the memory copied from parent process will leak.
And in multi-engine and mulit-fork scenario, if resources have been forked by other engines, and the uadk_engine performs the fork operation and executes services at this time, the uadk_engine will destroy the asynchronous resources from the fork in the subprocess. If other engines are occupying the threads before the fork and do not end. The pthread_join() in async_module_uninit() of the uadk_engine cannot wait for the corresponding thread, and the entire service process is suspended. The call stack when the program is suspended is as follows:
Thread 2 (Thread 0xffff9b4ff0a0 (LWP 3242840) "openssl"): 0 0x0000ffffa6423b00 in __futex_abstimed_wait_common64 1 __futex_abstimed_wait_common 2 __GI___futex_abstimed_wait_cancelable64 3 0x0000ffffa642f3e4 in do_futex_wait 4 0x0000ffffa642f4ac in __new_sem_wait_slow64 5 0x0000ffffa30a2170 in async_poll_process_func 6 0x0000ffffa64272f8 in start_thread 7 0x0000ffffa648ea1c in thread_start ()
To solve this, call uninit operation before creating subprocess to prevent resource leakage after the fork subprocess and ensure that the uadk_engine service can exit normally in multi-engine and multi-fork scenarios.
Signed-off-by: Zhiqi Song songzhiqi1@huawei.com --- src/uadk_engine_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/uadk_engine_init.c b/src/uadk_engine_init.c index bba382f..1a2b1d4 100644 --- a/src/uadk_engine_init.c +++ b/src/uadk_engine_init.c @@ -417,7 +417,7 @@ static int bind_fn(ENGINE *e, const char *id) bind_fn_uadk_alg(e);
if (uadk_cipher || uadk_digest || uadk_rsa || uadk_dh || uadk_ecc) - pthread_atfork(NULL, NULL, engine_init_child_at_fork_handler); + pthread_atfork(async_module_uninit, NULL, engine_init_child_at_fork_handler);
ret = ENGINE_set_ctrl_function(e, uadk_engine_ctrl); if (ret != 1) {
From: Zhiqi Song songzhiqi1@huawei.com
openssl genpkey -provider uadk_provider -algorithm X25519 \ -out a_prikey_x25519.pem openssl pkey -in a_prikey_x25519.pem -text openssl pkey -in a_prikey_x25519.pem -pubout -out a_pubkey_x25519.pub openssl genpkey -provider uadk_provider -algorithm x25519 \ -out b_prikey_x25519.pem openssl pkey -in b_prikey_x25519.pem -text openssl pkey -in b_prikey_x25519.pem -pubout -out b_pubkey_x25519.pub openssl pkeyutl -derive -out ab_x25519.key -inkey a_prikey_x25519.pem \ -peerkey b_pubkey_x25519.pub -provider uadk_provider openssl pkeyutl -derive -out ba_x25519.key -inkey b_prikey_x25519.pem \ -peerkey a_pubkey_x25519.pub -provider uadk_provider
cmp ab_x25519.key ba_x25519.key xxd ab_x25519.key xxd ba_x25519.key
Signed-off-by: Zhiqi Song songzhiqi1@huawei.com --- src/uadk_prov.h | 3 + src/uadk_prov_ecx.c | 517 +++++++++++++++++++++++++++++++++++++++---- src/uadk_prov_init.c | 4 + src/uadk_prov_pkey.c | 26 +-- src/uadk_prov_pkey.h | 2 + 5 files changed, 494 insertions(+), 58 deletions(-)
diff --git a/src/uadk_prov.h b/src/uadk_prov.h index 2786e79..7cb1eee 100644 --- a/src/uadk_prov.h +++ b/src/uadk_prov.h @@ -185,6 +185,9 @@ extern const OSSL_DISPATCH uadk_ecdh_keyexch_functions[FUNC_MAX_NUM]; extern const OSSL_DISPATCH uadk_x448_keymgmt_functions[FUNC_MAX_NUM]; extern const OSSL_DISPATCH uadk_x448_keyexch_functions[FUNC_MAX_NUM];
+extern const OSSL_DISPATCH uadk_x25519_keymgmt_functions[FUNC_MAX_NUM]; +extern const OSSL_DISPATCH uadk_x25519_keyexch_functions[FUNC_MAX_NUM]; + extern const OSSL_DISPATCH uadk_ecdsa_signature_functions[FUNC_MAX_NUM];
void uadk_prov_destroy_digest(void); diff --git a/src/uadk_prov_ecx.c b/src/uadk_prov_ecx.c index d7954b7..47fe1a9 100644 --- a/src/uadk_prov_ecx.c +++ b/src/uadk_prov_ecx.c @@ -34,6 +34,9 @@ #define X448_KEYBITS 448 #define ECX_MAX_KEYLEN 57 #define X448_SECURITY_BITS 224 +#define X25519_KEYBITS 256 +#define X25519_KEYLEN 32 +#define X25519_SECURITY_BITS 128
#define ECX_POSSIBLE_SELECTIONS (OSSL_KEYMGMT_SELECT_KEYPAIR)
@@ -50,6 +53,11 @@ static inline int UADK_CRYPTO_DOWN_REF(int *val, int *ret,
UADK_PKEY_KEYMGMT_DESCR(x448, X448); UADK_PKEY_KEYEXCH_DESCR(x448, X448); +UADK_PKEY_KEYMGMT_DESCR(x25519, X25519); +UADK_PKEY_KEYEXCH_DESCR(x25519, X25519); + +static pthread_mutex_t x25519_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t x448_mutex = PTHREAD_MUTEX_INITIALIZER;
typedef enum { ECX_KEY_TYPE_X25519 = 0x0, @@ -349,20 +357,26 @@ static int ossl_ecx_gen_set_params(void *genctx, const OSSL_PARAM params[]) return UADK_P_SUCCESS; }
-static handle_t uadk_prov_x448_alloc_sess(void) +static handle_t uadk_prov_ecx_alloc_sess(int type) { struct wd_ecc_sess_setup setup = {0}; struct sched_params params = {0};
- setup.alg = "x448"; - setup.key_bits = X448_KEYBITS; + if (type == ECX_KEY_TYPE_X448) { + setup.alg = "x448"; + setup.key_bits = X448_KEYBITS; + } else { + setup.alg = "x25519"; + setup.key_bits = X25519_KEYBITS; + } + params.numa_id = -1; setup.sched_param = ¶ms;
return wd_ecc_alloc_sess(&setup); }
-static void uadk_prov_x448_free_sess(handle_t sess) +static void uadk_prov_ecx_free_sess(handle_t sess) { if (sess) wd_ecc_free_sess(sess); @@ -431,14 +445,18 @@ static ECX_KEY *uadk_prov_ecx_key_new(OSSL_LIB_CTX *libctx, ECX_KEY_TYPE type, i switch (type) { case ECX_KEY_TYPE_X448: ecx_key->keylen = X448_KEYLEN; - ecx_key->type = type; - ecx_key->references = 1; + break; + case ECX_KEY_TYPE_X25519: + ecx_key->keylen = X25519_KEYLEN; break; default: fprintf(stderr, "invalid: unsupported ecx type\n"); goto free_ecx_key; }
+ ecx_key->type = type; + ecx_key->references = 1; + if (propq) { ecx_key->propq = OPENSSL_strdup(propq); if (ecx_key->propq == NULL) @@ -493,7 +511,11 @@ static ECX_KEY *uadk_prov_ecx_create_prikey(PROV_ECX_KEYMGMT_CTX *gctx) fprintf(stderr, "failed to new ecx_key\n"); return UADK_P_FAIL; } - gctx->keylen = X448_KEYLEN; + + if (gctx->type == ECX_KEY_TYPE_X448) + gctx->keylen = X448_KEYLEN; + else + gctx->keylen = X25519_KEYLEN;
/* If we're doing parameter generation then we just return a blank key */ if ((gctx->selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) @@ -637,7 +659,7 @@ static int uadk_prov_ecx_set_pkey(PROV_ECX_KEYMGMT_CTX *gctx, struct wd_ecc_req return ret; } /* - * This is a pretreatment of X448 described in RFC 7748. + * This is a pretreatment of X448 and X25519 described in RFC 7748. * In order to decode the random bytes as an integer scaler, there * are some special data processing. And use little-endian mode for * decoding. @@ -648,6 +670,14 @@ static int uadk_prov_ecx_set_pkey(PROV_ECX_KEYMGMT_CTX *gctx, struct wd_ecc_req
/* Set the MSB of the last byte to 1 */ ecx_key->privkey[X448_KEYLEN - 1] |= 0x80; + } else if (gctx->type == ECX_KEY_TYPE_X25519) { + ecx_key->privkey[0] &= 0xF8; + + /* Set the MSB of the last byte to 0 */ + ecx_key->privkey[X25519_KEYLEN - 1] &= 0x7F; + + /* Set the second MSB of the last byte to 1 */ + ecx_key->privkey[X25519_KEYLEN - 1] |= 0x40; } else { fprintf(stderr, "invalid: unsupported ecx type\n"); return UADK_P_FAIL; @@ -744,7 +774,7 @@ static void *uadk_keymgmt_x448_gen(void *genctx, OSSL_CALLBACK *cb, void *cb_par return NULL; }
- gctx->sess = uadk_prov_x448_alloc_sess(); + gctx->sess = uadk_prov_ecx_alloc_sess(ECX_KEY_TYPE_X448); if (gctx->sess == (handle_t)0) { fprintf(stderr, "failed to alloc x448 sess\n"); return NULL; @@ -754,7 +784,7 @@ static void *uadk_keymgmt_x448_gen(void *genctx, OSSL_CALLBACK *cb, void *cb_par if (ecx_key == NULL) fprintf(stderr, "failed to generate x448 key\n");
- uadk_prov_x448_free_sess(gctx->sess); + uadk_prov_ecx_free_sess(gctx->sess);
return ecx_key; } @@ -764,6 +794,7 @@ static UADK_PKEY_KEYEXCH get_default_x448_keyexch(void) static UADK_PKEY_KEYEXCH s_keyexch; static int initilazed;
+ pthread_mutex_lock(&x448_mutex); if (!initilazed) { UADK_PKEY_KEYEXCH *keyexch = (UADK_PKEY_KEYEXCH *)EVP_KEYEXCH_fetch(NULL, "X448", "provider=default"); @@ -775,6 +806,8 @@ static UADK_PKEY_KEYEXCH get_default_x448_keyexch(void) fprintf(stderr, "failed to EVP_KEYEXCH_fetch default X448 provider\n"); } } + pthread_mutex_unlock(&x448_mutex); + return s_keyexch; }
@@ -838,7 +871,7 @@ static int uadk_keyexch_x448_get_ctx_params(void *ecxctx, OSSL_PARAM params[]) return get_default_x448_keyexch().get_ctx_params(ecxctx, params); }
-static int uadk_keyexch_x448_init(void *vecxctx, void *vkey, +static int uadk_keyexch_ecx_init(void *vecxctx, void *vkey, ossl_unused const OSSL_PARAM params[]) { PROV_ECX_KEYEXCH_CTX *ecxctx = (PROV_ECX_KEYEXCH_CTX *)vecxctx; @@ -866,6 +899,12 @@ static int uadk_keyexch_x448_init(void *vecxctx, void *vkey, return UADK_P_SUCCESS; }
+static int uadk_keyexch_x448_init(void *vecxctx, void *vkey, + ossl_unused const OSSL_PARAM params[]) +{ + return uadk_keyexch_ecx_init(vecxctx, vkey, params); +} + static int ossl_ecx_key_up_ref(ECX_KEY *key) { int i = 0; @@ -876,33 +915,38 @@ static int ossl_ecx_key_up_ref(ECX_KEY *key) return ((i > 1) ? UADK_P_SUCCESS : UADK_P_FAIL); }
-static int uadk_keyexch_x448_set_peer(void *vecxctx, void *vkey) +static int uadk_keyexch_ecx_set_peer(void *vecxctx, void *vkey) { PROV_ECX_KEYEXCH_CTX *ecxctx = (PROV_ECX_KEYEXCH_CTX *)vecxctx; - ECX_KEY *key = vkey; + ECX_KEY *peerkey = vkey;
if (ecxctx == NULL) { fprintf(stderr, "invalid: ecxctx is NULL\n"); return UADK_P_FAIL; }
- if (key == NULL) { + if (peerkey == NULL) { fprintf(stderr, "invalid: key is NULL\n"); return UADK_P_FAIL; }
- if (key->keylen != ecxctx->keylen || !ossl_ecx_key_up_ref(key)) { - fprintf(stderr, "invalid: key->keylen(%zu) != ecxctx->keylen(%zu)\n", - key->keylen, ecxctx->keylen); + if (peerkey->keylen != ecxctx->keylen || !ossl_ecx_key_up_ref(peerkey)) { + fprintf(stderr, "invalid: peerkey->keylen(%zu) != ecxctx->keylen(%zu)\n", + peerkey->keylen, ecxctx->keylen); return UADK_P_FAIL; }
uadk_prov_ecx_key_free(ecxctx->peerkey); - ecxctx->peerkey = key; + ecxctx->peerkey = peerkey;
return UADK_P_SUCCESS; }
+static int uadk_keyexch_x448_set_peer(void *vecxctx, void *vkey) +{ + return uadk_keyexch_ecx_set_peer(vecxctx, vkey); +} + static int uadk_prov_ecx_compkey_init_iot(PROV_ECX_KEYEXCH_CTX *ecxctx, struct wd_ecc_req *req) { char buffer_y[ECX_MAX_KEYLEN] = {0}; @@ -934,7 +978,7 @@ static int uadk_prov_ecx_compkey_init_iot(PROV_ECX_KEYEXCH_CTX *ecxctx, struct w if (ecx_out == NULL) { fprintf(stderr, "failed to new ecxdh out\n"); ret = UADK_P_FAIL; - goto del_in; + goto del_ecx_in; }
uadk_prov_ecc_fill_req(req, WD_ECXDH_COMPUTE_KEY, ecx_in, ecx_out); @@ -942,15 +986,15 @@ static int uadk_prov_ecx_compkey_init_iot(PROV_ECX_KEYEXCH_CTX *ecxctx, struct w /* Trans public key from big-endian to little-endian */ ret = uadk_prov_reverse_bytes(ecxctx->peerkey->pubkey, ecxctx->keylen); if (ret == UADK_P_FAIL) { - fprintf(stderr, "failed to trans public key\n"); - goto del_out; + fprintf(stderr, "failed to trans peer public key\n"); + goto del_ecx_out; }
return ret;
-del_out: +del_ecx_out: wd_ecc_del_out(sess, ecx_out); -del_in: +del_ecx_in: wd_ecc_del_in(sess, ecx_in);
return ret; @@ -995,25 +1039,31 @@ static int uadk_prov_ecx_derive_set_prikey(PROV_ECX_KEYEXCH_CTX *ecxctx) return UADK_P_SUCCESS; }
-static void uadk_prov_x448_pad_out_key(unsigned char *dst_key, unsigned char *src_key, - size_t len) +static void uadk_prov_ecx_pad_out_key(unsigned char *dst, unsigned char *src, + size_t len, int type) { unsigned char x448_pad_key[X448_KEYLEN] = {0}; + unsigned char x25519_pad_key[X25519_KEYLEN] = {0};
- if (len != X448_KEYLEN) { - memcpy(x448_pad_key, src_key, len); - memcpy(dst_key, x448_pad_key, X448_KEYLEN); - } else { - memcpy(dst_key, src_key, X448_KEYLEN); - } -} - -static void uadk_prov_ecx_pad_out_key(unsigned char *dst_key, unsigned char *src_key, - size_t len, int type) -{ - if (type == ECX_KEY_TYPE_X448) { - uadk_prov_x448_pad_out_key(dst_key, src_key, len); - return; + switch (type) { + case ECX_KEY_TYPE_X448: + if (len != X448_KEYLEN) { + memcpy(x448_pad_key, src, len); + memcpy(dst, x448_pad_key, X448_KEYLEN); + } else { + memcpy(dst, src, X448_KEYLEN); + } + break; + case ECX_KEY_TYPE_X25519: + if (len != X25519_KEYLEN) { + memcpy(x25519_pad_key, src, len); + memcpy(dst, x25519_pad_key, X25519_KEYLEN); + } else { + memcpy(dst, src, X25519_KEYLEN); + } + break; + default: + break; } }
@@ -1078,12 +1128,11 @@ static int uadk_keyexch_x448_derive(void *vecxctx, unsigned char *secret, size_t int ret;
if (ecxctx == NULL) { - fprintf(stderr, "invalid: ecxctx is NULL in derive op\n"); + fprintf(stderr, "invalid: ecxctx is NULL in x448 derive op\n"); return UADK_P_FAIL; }
- if (ecxctx->key == NULL || ecxctx->key->privkey == NULL || - ecxctx->peerkey == NULL) { + if (ecxctx->key == NULL || ecxctx->key->privkey == NULL || ecxctx->peerkey == NULL) { ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); return UADK_P_FAIL; } @@ -1115,7 +1164,7 @@ static int uadk_keyexch_x448_derive(void *vecxctx, unsigned char *secret, size_t return UADK_P_FAIL; }
- ecxctx->sess = uadk_prov_x448_alloc_sess(); + ecxctx->sess = uadk_prov_ecx_alloc_sess(ECX_KEY_TYPE_X448); if (ecxctx->sess == (handle_t)0) { fprintf(stderr, "failed to alloc sess\n"); return UADK_P_FAIL; @@ -1127,12 +1176,12 @@ static int uadk_keyexch_x448_derive(void *vecxctx, unsigned char *secret, size_t
*secretlen = ecxctx->keylen;
- uadk_prov_x448_free_sess(ecxctx->sess); + uadk_prov_ecx_free_sess(ecxctx->sess);
return ret; }
-static void *uadk_keyexch_x448_dupctx(void *vecxctx) +static void *uadk_keyexch_ecx_dupctx(void *vecxctx) { PROV_ECX_KEYEXCH_CTX *srcctx = (PROV_ECX_KEYEXCH_CTX *)vecxctx; PROV_ECX_KEYEXCH_CTX *dstctx; @@ -1162,3 +1211,381 @@ static void *uadk_keyexch_x448_dupctx(void *vecxctx)
return dstctx; } + +static void *uadk_keyexch_x448_dupctx(void *vecxctx) +{ + return uadk_keyexch_ecx_dupctx(vecxctx); +} + +static void *uadk_keymgmt_x25519_new(void *provctx) +{ + if (get_default_x25519_keymgmt().new_fun == NULL) + return NULL; + + return get_default_x25519_keymgmt().new_fun(provctx); +} + +void uadk_keymgmt_x25519_free(void *keydata) +{ + if (get_default_x25519_keymgmt().free == NULL) + return; + + get_default_x25519_keymgmt().free(keydata); +} + +static int uadk_keymgmt_x25519_has(const void *keydata, int selection) +{ + if (get_default_x25519_keymgmt().has == NULL) + return UADK_P_FAIL; + + return get_default_x25519_keymgmt().has(keydata, selection); +} + +static int uadk_keymgmt_x25519_match(const void *keydata1, const void *keydata2, int selection) +{ + if (get_default_x25519_keymgmt().match == NULL) + return UADK_P_FAIL; + + return get_default_x25519_keymgmt().match(keydata1, keydata2, selection); +} + +static int uadk_keymgmt_x25519_import(void *keydata, int selection, const OSSL_PARAM params[]) +{ + if (get_default_x25519_keymgmt().import == NULL) + return UADK_P_FAIL; + + return get_default_x25519_keymgmt().import(keydata, selection, params); +} + +static int uadk_keymgmt_x25519_export(void *keydata, int selection, + OSSL_CALLBACK *cb, void *cb_params) +{ + if (get_default_x25519_keymgmt().export_fun == NULL) + return UADK_P_FAIL; + + return get_default_x25519_keymgmt().export_fun(keydata, selection, cb, cb_params); +} + +static const OSSL_PARAM *uadk_keymgmt_x25519_import_types(int selection) +{ + if (get_default_x25519_keymgmt().import_types == NULL) + return NULL; + + return get_default_x25519_keymgmt().import_types(selection); +} + +static const OSSL_PARAM *uadk_keymgmt_x25519_export_types(int selection) +{ + if (get_default_x25519_keymgmt().export_types == NULL) + return NULL; + + return get_default_x25519_keymgmt().export_types(selection); +} + +void *uadk_keymgmt_x25519_load(const void *reference, size_t reference_sz) +{ + if (get_default_x25519_keymgmt().load == NULL) + return NULL; + + return get_default_x25519_keymgmt().load(reference, reference_sz); +} + +static void *uadk_keymgmt_x25519_dup(const void *keydata_from, int selection) +{ + if (get_default_x25519_keymgmt().dup == NULL) + return NULL; + + return get_default_x25519_keymgmt().dup(keydata_from, selection); +} + +static int uadk_keymgmt_x25519_validate(const void *keydata, int selection, int checktype) +{ + if (get_default_x25519_keymgmt().validate == NULL) + return UADK_P_FAIL; + + return get_default_x25519_keymgmt().validate(keydata, selection, checktype); +} + +static const OSSL_PARAM *uadk_keymgmt_x25519_gettable_params(void *provctx) +{ + if (get_default_x25519_keymgmt().gettable_params == NULL) + return NULL; + + return get_default_x25519_keymgmt().gettable_params(provctx); +} + +static int uadk_keymgmt_x25519_set_params(void *key, const OSSL_PARAM params[]) +{ + if (get_default_x25519_keymgmt().set_params == NULL) + return UADK_P_FAIL; + + return get_default_x25519_keymgmt().set_params(key, params); +} + +static const OSSL_PARAM *uadk_keymgmt_x25519_settable_params(void *provctx) +{ + if (get_default_x25519_keymgmt().settable_params == NULL) + return NULL; + + return get_default_x25519_keymgmt().settable_params(provctx); +} + +static int uadk_keymgmt_x25519_gen_set_params(void *genctx, + const OSSL_PARAM params[]) +{ + if (get_default_x25519_keymgmt().gen_set_params == NULL) + return UADK_P_FAIL; + + return get_default_x25519_keymgmt().gen_set_params(genctx, params); +} + +static const OSSL_PARAM *uadk_keymgmt_x25519_gen_settable_params(ossl_unused void *genctx, + ossl_unused void *provctx) +{ + if (get_default_x25519_keymgmt().gen_settable_params == NULL) + return NULL; + + return get_default_x25519_keymgmt().gen_settable_params(genctx, provctx); +} + +static int uadk_keymgmt_x25519_gen_set_template(void *genctx, void *templ) +{ + if (get_default_x25519_keymgmt().gen_set_template == NULL) + return UADK_P_FAIL; + + return get_default_x25519_keymgmt().gen_set_template(genctx, templ); +} + +static const char *uadk_keymgmt_x25519_query_operation_name(int operation_id) +{ + if (get_default_x25519_keymgmt().query_operation_name == NULL) + return NULL; + + return get_default_x25519_keymgmt().query_operation_name(operation_id); +} + +static int uadk_keymgmt_x25519_get_params(void *key, OSSL_PARAM params[]) +{ + return uadk_prov_ecx_get_params(key, params, X25519_KEYBITS, X25519_SECURITY_BITS, + X25519_KEYLEN); +} + +static void uadk_keymgmt_x25519_gen_cleanup(void *genctx) +{ + /* genctx will be freed in cleanup function */ + if (get_default_x25519_keymgmt().gen_cleanup == NULL) + return; + + get_default_x25519_keymgmt().gen_cleanup(genctx); +} + +static void *uadk_keymgmt_x25519_gen_init(void *provctx, int selection, + const OSSL_PARAM params[]) +{ + if (provctx == NULL) { + fprintf(stderr, "invalid: provctx is NULL\n"); + return NULL; + } + + return ossl_ecx_gen_init(provctx, selection, params, ECX_KEY_TYPE_X25519); +} + +static void *uadk_keymgmt_x25519_gen(void *genctx, OSSL_CALLBACK *cb, void *cb_params) +{ + PROV_ECX_KEYMGMT_CTX *gctx = (PROV_ECX_KEYMGMT_CTX *)genctx; + ECX_KEY *ecx_key = NULL; + int ret; + + if (gctx == NULL) { + fprintf(stderr, "invalid: ecx keygen ctx is NULL\n"); + return NULL; + } + + if (gctx->type != ECX_KEY_TYPE_X25519) { + fprintf(stderr, "invalid: unsupported ecx type\n"); + return NULL; + } + + ret = uadk_prov_keymgmt_get_support_state(KEYMGMT_X25519); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to get hardware x25519 keygen support\n"); + return NULL; + } + + ret = uadk_prov_ecc_init("x25519"); + if (ret != UADK_P_SUCCESS) { + fprintf(stderr, "failed to init x25519\n"); + return NULL; + } + + gctx->sess = uadk_prov_ecx_alloc_sess(ECX_KEY_TYPE_X25519); + if (gctx->sess == (handle_t)0) { + fprintf(stderr, "failed to alloc x25519 sess\n"); + return NULL; + } + + ecx_key = uadk_prov_ecx_keygen(gctx); + if (ecx_key == NULL) + fprintf(stderr, "failed to generate x25519 key\n"); + + uadk_prov_ecx_free_sess(gctx->sess); + + return ecx_key; +} + +static UADK_PKEY_KEYEXCH get_default_x25519_keyexch(void) +{ + static UADK_PKEY_KEYEXCH s_keyexch; + static int initilazed; + + pthread_mutex_lock(&x25519_mutex); + if (!initilazed) { + UADK_PKEY_KEYEXCH *keyexch = + (UADK_PKEY_KEYEXCH *)EVP_KEYEXCH_fetch(NULL, "X25519", "provider=default"); + if (keyexch) { + s_keyexch = *keyexch; + EVP_KEYEXCH_free((EVP_KEYEXCH *)keyexch); + initilazed = 1; + } else { + fprintf(stderr, "failed to EVP_KEYEXCH_fetch default X25519 provider\n"); + } + } + pthread_mutex_unlock(&x25519_mutex); + + return s_keyexch; +} + +static void *uadk_keyexch_x25519_newctx(void *provctx) +{ + PROV_ECX_KEYEXCH_CTX *ecxctx = NULL; + + ecxctx = OPENSSL_zalloc(sizeof(PROV_ECX_KEYEXCH_CTX)); + if (ecxctx == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + return NULL; + } + + ecxctx->keylen = X25519_KEYLEN; + + return ecxctx; +} + +static void uadk_keyexch_x25519_freectx(void *vecxctx) +{ + PROV_ECX_KEYEXCH_CTX *ecxctx = (PROV_ECX_KEYEXCH_CTX *)vecxctx; + + if (ecxctx == NULL) + return; + + OPENSSL_free(ecxctx); +} + +static int uadk_keyexch_x25519_set_ctx_params(void *ecxctx, const OSSL_PARAM params[]) +{ + if (get_default_x25519_keyexch().set_ctx_params == NULL) + return UADK_P_FAIL; + + return get_default_x25519_keyexch().set_ctx_params(ecxctx, params); +} + +static const OSSL_PARAM *uadk_keyexch_x25519_settable_ctx_params(ossl_unused void *ecxctx, + ossl_unused void *provctx) +{ + if (get_default_x25519_keyexch().settable_ctx_params == NULL) + return NULL; + + return get_default_x25519_keyexch().settable_ctx_params(ecxctx, provctx); +} + +static const OSSL_PARAM *uadk_keyexch_x25519_gettable_ctx_params(ossl_unused void *ecxctx, + ossl_unused void *provctx) +{ + if (get_default_x25519_keyexch().gettable_ctx_params == NULL) + return NULL; + + return get_default_x25519_keyexch().gettable_ctx_params(ecxctx, provctx); +} + +static int uadk_keyexch_x25519_get_ctx_params(void *ecxctx, OSSL_PARAM params[]) +{ + if (get_default_x25519_keyexch().get_ctx_params == NULL) + return UADK_P_FAIL; + + return get_default_x25519_keyexch().get_ctx_params(ecxctx, params); +} + +static int uadk_keyexch_x25519_init(void *vecxctx, void *vkey, + ossl_unused const OSSL_PARAM params[]) +{ + return uadk_keyexch_ecx_init(vecxctx, vkey, params); +} + +static int uadk_keyexch_x25519_set_peer(void *vecxctx, void *vkey) +{ + return uadk_keyexch_ecx_set_peer(vecxctx, vkey); +} + +static int uadk_keyexch_x25519_derive(void *vecxctx, unsigned char *secret, size_t *secretlen, + size_t outlen) +{ + PROV_ECX_KEYEXCH_CTX *ecxctx = (PROV_ECX_KEYEXCH_CTX *)vecxctx; + int ret; + + if (ecxctx == NULL) { + fprintf(stderr, "invalid: ecxctx is NULL in x25519 derive op\n"); + return UADK_P_FAIL; + } + + if (ecxctx->key == NULL || ecxctx->key->privkey == NULL || ecxctx->peerkey == NULL) { + ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); + return UADK_P_FAIL; + } + + if (ecxctx->keylen != X25519_KEYLEN) { + ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); + return UADK_P_FAIL; + } + + if (secret == NULL) { + *secretlen = ecxctx->keylen; + return UADK_P_SUCCESS; + } + + if (outlen < ecxctx->keylen) { + ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL); + return UADK_P_FAIL; + } + + ret = uadk_prov_keyexch_get_support_state(KEYEXCH_X25519); + if (ret == UADK_P_FAIL) { + fprintf(stderr, "failed to get hardware x25519 keyexch support\n"); + return UADK_P_FAIL; + } + + ret = uadk_prov_ecc_init("x25519"); + if (ret != UADK_P_SUCCESS) { + fprintf(stderr, "failed to init x25519\n"); + return UADK_P_FAIL; + } + + ecxctx->sess = uadk_prov_ecx_alloc_sess(ECX_KEY_TYPE_X25519); + if (ecxctx->sess == (handle_t)0) { + fprintf(stderr, "failed to alloc sess\n"); + return UADK_P_FAIL; + } + + ret = uadk_prov_ecx_derive(ecxctx, secret, &ecxctx->keylen); + if (ret == UADK_P_FAIL) + fprintf(stderr, "failed to do x25519 derive\n"); + + *secretlen = ecxctx->keylen; + + uadk_prov_ecx_free_sess(ecxctx->sess); + + return ret; +} + +static void *uadk_keyexch_x25519_dupctx(void *vecxctx) +{ + return uadk_keyexch_ecx_dupctx(vecxctx); +} diff --git a/src/uadk_prov_init.c b/src/uadk_prov_init.c index 41733b5..a6012ab 100644 --- a/src/uadk_prov_init.c +++ b/src/uadk_prov_init.c @@ -181,6 +181,8 @@ static const OSSL_ALGORITHM uadk_prov_keymgmt[] = { uadk_ec_keymgmt_functions, "uadk EC Keymgmt implementation."}, { "X448", UADK_DEFAULT_PROPERTIES, uadk_x448_keymgmt_functions, "uadk X448 Keymgmt implementation."}, + { "X25519", UADK_DEFAULT_PROPERTIES, + uadk_x25519_keymgmt_functions, "uadk X25519 Keymgmt implementation."}, { NULL, NULL, NULL } };
@@ -199,6 +201,8 @@ static const OSSL_ALGORITHM uadk_prov_keyexch[] = { uadk_ecdh_keyexch_functions, "uadk_provider ecdh_keyexch" }, { "X448", UADK_DEFAULT_PROPERTIES, uadk_x448_keyexch_functions, "uadk X448 keyexch implementation."}, + { "X25519", UADK_DEFAULT_PROPERTIES, + uadk_x25519_keyexch_functions, "uadk 25519 keyexch implementation."}, { NULL, NULL, NULL } };
diff --git a/src/uadk_prov_pkey.c b/src/uadk_prov_pkey.c index ebf90e4..ee702e1 100644 --- a/src/uadk_prov_pkey.c +++ b/src/uadk_prov_pkey.c @@ -209,13 +209,13 @@ static void uadk_prov_fill_ecc_cv_param(struct wd_ecc_curve *ecc_param, { ecc_param->p.dsize = BN_bn2bin(cv_param->p, (void *)ecc_param->p.data); ecc_param->a.dsize = BN_bn2bin(cv_param->a, (void *)ecc_param->a.data); - if (!ecc_param->a.dsize) { + if (ecc_param->a.dsize == 0) { ecc_param->a.dsize = 1; ecc_param->a.data[0] = 0; }
ecc_param->b.dsize = BN_bn2bin(cv_param->b, (void *)ecc_param->b.data); - if (!ecc_param->b.dsize) { + if (ecc_param->b.dsize == 0) { ecc_param->b.dsize = 1; ecc_param->b.data[0] = 0; } @@ -235,33 +235,33 @@ static int uadk_prov_set_sess_setup_cv(const EC_GROUP *group, BN_CTX *bn_ctx;
bn_ctx = BN_CTX_new(); - if (!bn_ctx) + if (bn_ctx == NULL) return ret;
BN_CTX_start(bn_ctx);
cv_param = OPENSSL_malloc(sizeof(struct curve_param)); - if (!cv_param) + if (cv_param == NULL) goto free_ctx;
cv_param->p = BN_CTX_get(bn_ctx); - if (!cv_param->p) + if (cv_param->p == NULL) goto free_cv;
cv_param->a = BN_CTX_get(bn_ctx); - if (!cv_param->a) + if (cv_param->a == NULL) goto free_cv;
cv_param->b = BN_CTX_get(bn_ctx); - if (!cv_param->b) + if (cv_param->b == NULL) goto free_cv;
g_x = BN_CTX_get(bn_ctx); - if (!g_x) + if (g_x == NULL) goto free_cv;
g_y = BN_CTX_get(bn_ctx); - if (!g_y) + if (g_y == NULL) goto free_cv;
ret = uadk_prov_get_curve(group, cv_param->p, cv_param->a, cv_param->b, bn_ctx); @@ -269,7 +269,7 @@ static int uadk_prov_set_sess_setup_cv(const EC_GROUP *group, goto free_cv;
cv_param->g = EC_GROUP_get0_generator(group); - if (!cv_param->g) + if (cv_param->g == NULL) goto free_cv;
ret = uadk_prov_get_affine_coordinates(group, cv_param->g, g_x, g_y, bn_ctx); @@ -277,7 +277,7 @@ static int uadk_prov_set_sess_setup_cv(const EC_GROUP *group, goto free_cv;
cv_param->order = EC_GROUP_get0_order(group); - if (!cv_param->order) + if (cv_param->order == NULL) goto free_cv;
uadk_prov_fill_ecc_cv_param(ecc_param, cv_param, g_x, g_y); @@ -665,7 +665,7 @@ static bool uadk_prov_support_algorithm(const char *alg)
void uadk_prov_keymgmt_alg(void) { - static const char * const keymgmt_alg[] = {"sm2", "x448", "ecdh"}; + static const char * const keymgmt_alg[] = {"sm2", "x448", "ecdh", "x25519"}; __u32 i, size; bool sp;
@@ -837,7 +837,7 @@ void uadk_prov_ecc_uninit(void)
void uadk_prov_keyexch_alg(void) { - static const char * const keyexch_alg[] = {"x448", "ecdh"}; + static const char * const keyexch_alg[] = {"x448", "ecdh", "x25519"}; __u32 i, size; bool sp;
diff --git a/src/uadk_prov_pkey.h b/src/uadk_prov_pkey.h index 38a67ac..0f01baf 100644 --- a/src/uadk_prov_pkey.h +++ b/src/uadk_prov_pkey.h @@ -70,6 +70,7 @@ enum { KEYMGMT_SM2 = 0x0, KEYMGMT_X448 = 0x1, KEYMGMT_ECDH = 0x2, + KEYMGMT_X25519 = 0x3, KEYMGMT_MAX = 0x6 };
@@ -88,6 +89,7 @@ enum { enum { KEYEXCH_X448 = 0x0, KEYEXCH_ECDH = 0x1, + KEYEXCH_X25519 = 0x2, };
struct curve_param {
From: Zhiqi Song songzhiqi1@huawei.com
There will be memory allocation in OpenSSL mod_exp methods, these resources need to be released by rsa_ossl_finish(), so add the rsa finish method by RSA_meth_set_finish().
Signed-off-by: Zhiqi Song songzhiqi1@huawei.com --- src/uadk_rsa.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/src/uadk_rsa.c b/src/uadk_rsa.c index 445b51b..76678a4 100644 --- a/src/uadk_rsa.c +++ b/src/uadk_rsa.c @@ -1909,6 +1909,8 @@ static RSA_METHOD *uadk_e_get_rsa_methods(void) RSA_PKCS1_OpenSSL())); (void)RSA_meth_set_mod_exp(rsa_hw_meth, RSA_meth_get_mod_exp( RSA_PKCS1_OpenSSL())); + (void)RSA_meth_set_finish(rsa_hw_meth, RSA_meth_get_finish( + RSA_PKCS1_OpenSSL()));
return rsa_hw_meth; }