This version fixup some compile warning and add sanity test for SM2.
Zhiqi Song (4): uadk_provider: add der encode and packet for SM2 uadk_provider: support sm2 hardware acceleration uadk_provider: add sanity test command for SM2 uadk_engine/digest: cleanup pointer type
src/Makefile.am | 4 +- src/uadk_digest.c | 2 +- src/uadk_prov.h | 15 +- src/uadk_prov_bio.c | 3 +- src/uadk_prov_der_writer.c | 236 +++ src/uadk_prov_der_writer.h | 129 ++ src/uadk_prov_init.c | 14 +- src/uadk_prov_packet.c | 514 ++++++ src/uadk_prov_packet.h | 959 +++++++++++ src/uadk_prov_pkey.c | 770 +++++++++ src/uadk_prov_pkey.h | 389 +++++ src/uadk_prov_sm2.c | 3127 ++++++++++++++++++++++++++++++++++ test/sanity_test_provider.sh | 18 + 13 files changed, 6172 insertions(+), 8 deletions(-) create mode 100644 src/uadk_prov_der_writer.c create mode 100644 src/uadk_prov_der_writer.h create mode 100644 src/uadk_prov_packet.c create mode 100644 src/uadk_prov_packet.h create mode 100644 src/uadk_prov_pkey.c create mode 100644 src/uadk_prov_pkey.h create mode 100644 src/uadk_prov_sm2.c
As SM2 needs DER encode/decode API of OpenSSL, but the OpenSSL3.x does not place these APIs in externel header files currently. Therefore, we put the related APIs in independent files of uadk_provider.
Signed-off-by: Zhiqi Song songzhiqi1@huawei.com Signed-off-by: JiangShui Yang yangjiangshui@h-partners.com --- src/Makefile.am | 2 +- src/uadk_prov_bio.c | 3 +- src/uadk_prov_der_writer.c | 236 +++++++++ src/uadk_prov_der_writer.h | 129 +++++ src/uadk_prov_packet.c | 514 ++++++++++++++++++++ src/uadk_prov_packet.h | 959 +++++++++++++++++++++++++++++++++++++ 6 files changed, 1841 insertions(+), 2 deletions(-) create mode 100644 src/uadk_prov_der_writer.c create mode 100644 src/uadk_prov_der_writer.h create mode 100644 src/uadk_prov_packet.c create mode 100644 src/uadk_prov_packet.h
diff --git a/src/Makefile.am b/src/Makefile.am index fe57b9d..b911ab5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -63,7 +63,7 @@ endif #WD_KAE uadk_provider_la_SOURCES=uadk_prov_init.c uadk_async.c uadk_utils.c \ uadk_prov_digest.c uadk_prov_cipher.c \ uadk_prov_rsa.c uadk_prov_dh.c \ - uadk_prov_bio.c + uadk_prov_bio.c uadk_prov_der_writer.c uadk_prov_packet.c \
uadk_provider_la_LDFLAGS=-module -version-number $(VERSION) uadk_provider_la_LIBADD=$(WD_LIBS) -lpthread diff --git a/src/uadk_prov_bio.c b/src/uadk_prov_bio.c index 09383aa..46656c2 100644 --- a/src/uadk_prov_bio.c +++ b/src/uadk_prov_bio.c @@ -26,7 +26,7 @@ static OSSL_FUNC_BIO_vprintf_fn *c_bio_vprintf;
int ossl_prov_bio_from_dispatch(const OSSL_DISPATCH *fns) { - for (fns; fns->function_id != 0; fns++) { + while (fns && fns->function_id != 0) { switch (fns->function_id) { case OSSL_FUNC_BIO_NEW_FILE: if (c_bio_new_file == NULL) @@ -69,6 +69,7 @@ int ossl_prov_bio_from_dispatch(const OSSL_DISPATCH *fns) c_bio_vprintf = OSSL_FUNC_BIO_vprintf(fns); break; } + fns++; }
return 1; diff --git a/src/uadk_prov_der_writer.c b/src/uadk_prov_der_writer.c new file mode 100644 index 0000000..3876d49 --- /dev/null +++ b/src/uadk_prov_der_writer.c @@ -0,0 +1,236 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdlib.h> +#include <string.h> +#include "uadk_prov_der_writer.h" + +#define DER_OID_SZ_sm2_with_SM3 10 +#define PACKET_LEN_TAG 30 + +unsigned char ossl_der_oid_sm2_with_SM3[DER_OID_SZ_sm2_with_SM3] = { + 6, 8, 0x2A, 0x81, 0x1C, 0xCF, 0x55, 0x01, 0x83, 0x75 +}; + +static int int_start_context(WPACKET *pkt, int tag) +{ + if (tag < 0) + return 1; + if (!ossl_assert(tag <= PACKET_LEN_TAG)) + return 0; + + return WPACKET_start_sub_packet(pkt); +} + +static int int_end_context(WPACKET *pkt, int tag) +{ + /* + * If someone set the flag WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH on this + * sub-packet and this sub-packet has nothing written to it, the DER length + * will not be written, and the total written size will be unchanged before + * and after WPACKET_close(). We use size1 and size2 to determine if + * anything was written, and only write our tag if it has. + * + */ + size_t size1, size2; + + if (tag < 0) + return 1; + if (!ossl_assert(tag <= PACKET_LEN_TAG)) + return 0; + + /* Context specific are normally (?) constructed */ + tag |= DER_F_CONSTRUCTED | DER_C_CONTEXT; + + return WPACKET_get_total_written(pkt, &size1) + && WPACKET_close(pkt) + && WPACKET_get_total_written(pkt, &size2) + && (size1 == size2 || WPACKET_put_bytes_u8(pkt, tag)); +} + +int ossl_DER_w_precompiled(WPACKET *pkt, int tag, + const unsigned char *precompiled, + size_t precompiled_n) +{ + return int_start_context(pkt, tag) + && WPACKET_memcpy(pkt, precompiled, precompiled_n) + && int_end_context(pkt, tag); +} + +int ossl_DER_w_boolean(WPACKET *pkt, int tag, int b) +{ + return int_start_context(pkt, tag) + && WPACKET_start_sub_packet(pkt) + && (!b || WPACKET_put_bytes_u8(pkt, 0xFF)) + && !WPACKET_close(pkt) + && !WPACKET_put_bytes_u8(pkt, DER_P_BOOLEAN) + && int_end_context(pkt, tag); +} + +int ossl_DER_w_octet_string(WPACKET *pkt, int tag, + const unsigned char *data, size_t data_n) +{ + return int_start_context(pkt, tag) + && WPACKET_start_sub_packet(pkt) + && WPACKET_memcpy(pkt, data, data_n) + && WPACKET_close(pkt) + && WPACKET_put_bytes_u8(pkt, DER_P_OCTET_STRING) + && int_end_context(pkt, tag); +} + +int ossl_DER_w_octet_string_uint32(WPACKET *pkt, int tag, uint32_t value) +{ + unsigned char tmp[4] = { 0, 0, 0, 0 }; + unsigned char *pbuf = tmp + (sizeof(tmp) - 1); + + while (value > 0) { + *pbuf-- = (value & 0xFF); + value >>= LOW_BIT_SIZE; + } + + return ossl_DER_w_octet_string(pkt, tag, tmp, sizeof(tmp)); +} + +static int int_der_w_integer(WPACKET *pkt, int tag, + int (*put_bytes)(WPACKET *pkt, const void *v, + unsigned int *top_byte), + const void *v) +{ + unsigned int top_byte = 0; + + return int_start_context(pkt, tag) + && WPACKET_start_sub_packet(pkt) + && put_bytes(pkt, v, &top_byte) + && ((top_byte & 0x80) == 0 || WPACKET_put_bytes_u8(pkt, 0)) + && WPACKET_close(pkt) + && WPACKET_put_bytes_u8(pkt, DER_P_INTEGER) + && int_end_context(pkt, tag); +} + +static int int_put_bytes_uint32(WPACKET *pkt, const void *v, + unsigned int *top_byte) +{ + const uint32_t *value = v; + uint32_t tmp = *value; + size_t n = 0; + + while (tmp != 0) { + n++; + *top_byte = (tmp & 0xFF); + tmp >>= LOW_BIT_SIZE; + } + + if (n == 0) + n = 1; + + return WPACKET_put_bytes__(pkt, *value, n); +} + +/* For integers, we only support unsigned values for now */ +int ossl_DER_w_uint32(WPACKET *pkt, int tag, uint32_t v) +{ + return int_der_w_integer(pkt, tag, int_put_bytes_uint32, &v); +} + +BN_ULONG *bn_get_words(const BIGNUM *a) +{ + return a->d; +} + +static int int_put_bytes_bn(WPACKET *pkt, const void *v, + unsigned int *top_byte) +{ + unsigned char *p = NULL; + size_t n = BN_num_bytes(v); + + /* The BIGNUM limbs are in LE order */ + *top_byte = + ((bn_get_words(v)[(n - 1) / BN_BYTES]) + >> (BYTES_TO_BITS_OFFSET * ((n - 1) % BN_BYTES))) + & 0xFF; + + if (!WPACKET_allocate_bytes(pkt, n, &p)) + return 0; + + if (p != NULL) + BN_bn2bin(v, p); + + return 1; +} + +int ossl_DER_w_bn(WPACKET *pkt, int tag, const BIGNUM *v) +{ + if (v == NULL || BN_is_negative(v)) + return 0; + + if (BN_is_zero(v)) + return ossl_DER_w_uint32(pkt, tag, 0); + + return int_der_w_integer(pkt, tag, int_put_bytes_bn, v); +} + +int ossl_DER_w_null(WPACKET *pkt, int tag) +{ + return int_start_context(pkt, tag) + && WPACKET_start_sub_packet(pkt) + && WPACKET_close(pkt) + && WPACKET_put_bytes_u8(pkt, DER_P_NULL) + && int_end_context(pkt, tag); +} + +/* Constructed things need a start and an end */ +int ossl_DER_w_begin_sequence(WPACKET *pkt, int tag) +{ + return int_start_context(pkt, tag) + && WPACKET_start_sub_packet(pkt); +} + +int ossl_DER_w_end_sequence(WPACKET *pkt, int tag) +{ + /* + * If someone set the flag WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH on this + * sub-packet and this sub-packet has nothing written to it, the DER length + * will not be written, and the total written size will be unchanged before + * and after WPACKET_close(). We use size1 and size2 to determine if + * anything was written, and only write our tag if it has. + * Because we know that int_end_context() needs to do the same check, + * we reproduce this flag if the written length was unchanged, or we will + * have an erroneous context tag. + */ + size_t size1, size2; + + return WPACKET_get_total_written(pkt, &size1) + && WPACKET_close(pkt) + && WPACKET_get_total_written(pkt, &size2) + && (size1 == size2 + ? WPACKET_set_flags(pkt, WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) + : WPACKET_put_bytes_u8(pkt, DER_F_CONSTRUCTED | DER_P_SEQUENCE)) + && int_end_context(pkt, tag); +} + +int ossl_DER_w_algorithmIdentifier_SM2_with_MD(WPACKET *pkt, int cont, + EC_KEY *ec, int mdnid) +{ + const unsigned char *precompiled = NULL; + size_t precompiled_sz = 0; + + switch (mdnid) { + case NID_sm3: + precompiled = ossl_der_oid_sm2_with_SM3; + precompiled_sz = sizeof(ossl_der_oid_sm2_with_SM3); + break; + default: + return 0; + } + + return ossl_DER_w_begin_sequence(pkt, cont) /* No parameters (yet?) */ + && ossl_DER_w_precompiled(pkt, -1, precompiled, precompiled_sz) + && ossl_DER_w_end_sequence(pkt, cont); +} diff --git a/src/uadk_prov_der_writer.h b/src/uadk_prov_der_writer.h new file mode 100644 index 0000000..39308e0 --- /dev/null +++ b/src/uadk_prov_der_writer.h @@ -0,0 +1,129 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright 2020-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ +#ifndef UADK_PROV_DER_WRITER_H +#define UADK_PROV_DER_WRITER_H +#include <openssl/bn.h> +#include <openssl/ec.h> +#include <openssl/obj_mac.h> +#include <openssl/types.h> +#include "uadk_prov_packet.h" +#include "uadk_utils.h" + +/* + * NOTE: X.690 numbers the identifier octet bits 1 to 8. + * We use the same numbering in comments here. + */ + +/* Well known primitive tags */ + +/* + * DER UNIVERSAL tags, occupying bits 1-5 in the DER identifier byte + * These are only valid for the UNIVERSAL class. With the other classes, + * these bits have a different meaning. + */ +#define DER_P_EOC 0 /* BER End Of Contents tag */ +#define DER_P_BOOLEAN 1 +#define DER_P_INTEGER 2 +#define DER_P_BIT_STRING 3 +#define DER_P_OCTET_STRING 4 +#define DER_P_NULL 5 +#define DER_P_OBJECT 6 +#define DER_P_OBJECT_DESCRIPTOR 7 +#define DER_P_EXTERNAL 8 +#define DER_P_REAL 9 +#define DER_P_ENUMERATED 10 +#define DER_P_UTF8STRING 12 +#define DER_P_SEQUENCE 16 +#define DER_P_SET 17 +#define DER_P_NUMERICSTRING 18 +#define DER_P_PRINTABLESTRING 19 +#define DER_P_T61STRING 20 +#define DER_P_VIDEOTEXSTRING 21 +#define DER_P_IA5STRING 22 +#define DER_P_UTCTIME 23 +#define DER_P_GENERALIZEDTIME 24 +#define DER_P_GRAPHICSTRING 25 +#define DER_P_ISO64STRING 26 +#define DER_P_GENERALSTRING 27 +#define DER_P_UNIVERSALSTRING 28 +#define DER_P_BMPSTRING 30 + +/* DER Flags, occupying bit 6 in the DER identifier byte */ +#define DER_F_PRIMITIVE 0x00 +#define DER_F_CONSTRUCTED 0x20 + +/* DER classes tags, occupying bits 7-8 in the DER identifier byte */ +#define DER_C_UNIVERSAL 0x00 +#define DER_C_APPLICATION 0x40 +#define DER_C_CONTEXT 0x80 +#define DER_C_PRIVATE 0xC0 + +/* + * Run-time constructors. + * + * They all construct DER backwards, so care should be taken to use them + * that way. + */ + +/* This can be used for all items that don't have a context */ +#define DER_NO_CONTEXT -1 + +struct bignum_st { + BN_ULONG *d; /* Pointer to an array of 'BN_BITS2' bit chunks. */ + int top; /* Index of last used d +1. */ + /* The next are internal book keeping for bn_expand. */ + int dmax; /* Size of the d array. */ + int neg; /* one if the number is negative */ + int flags; +}; + +struct ec_key_st { + const EC_KEY_METHOD *meth; + ENGINE *engine; + int version; + EC_GROUP *group; + EC_POINT *pub_key; + BIGNUM *priv_key; + unsigned int enc_flag; + point_conversion_form_t conv_form; + int references; + int flags; +#ifndef FIPS_MODULE + CRYPTO_EX_DATA ex_data; +#endif + void *lock; + OSSL_LIB_CTX *libctx; + char *propq; + + /* Provider data */ + size_t dirty_cnt; /* If any key material changes, increment this */ +}; + +int ossl_DER_w_precompiled(WPACKET *pkt, int tag, + const unsigned char *precompiled, + size_t precompiled_n); + +int ossl_DER_w_boolean(WPACKET *pkt, int tag, int b); +int ossl_DER_w_uint32(WPACKET *pkt, int tag, uint32_t v); +int ossl_DER_w_bn(WPACKET *pkt, int tag, const BIGNUM *v); +int ossl_DER_w_null(WPACKET *pkt, int tag); +int ossl_DER_w_octet_string(WPACKET *pkt, int tag, + const unsigned char *data, size_t data_n); +int ossl_DER_w_octet_string_uint32(WPACKET *pkt, int tag, uint32_t value); + +/* + * All constructors for constructed elements have a begin and a end function + */ +int ossl_DER_w_begin_sequence(WPACKET *pkt, int tag); +int ossl_DER_w_end_sequence(WPACKET *pkt, int tag); + +int ossl_DER_w_algorithmIdentifier_SM2_with_MD(WPACKET *pkt, int cont, + EC_KEY *ec, int mdnid); +#endif diff --git a/src/uadk_prov_packet.c b/src/uadk_prov_packet.c new file mode 100644 index 0000000..3c84de8 --- /dev/null +++ b/src/uadk_prov_packet.c @@ -0,0 +1,514 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ +#include <openssl/err.h> +#include "uadk_prov_packet.h" + +#define DEFAULT_BUF_SIZE 256 +#define REF_SIZE_LIMIT 2 + +#define GETBUF(p) (((p)->staticbuf != NULL) \ + ? (p)->staticbuf \ + : ((p)->buf != NULL \ + ? (unsigned char *)(p)->buf->data \ + : NULL)) + +int WPACKET_allocate_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes) +{ + if (!WPACKET_reserve_bytes(pkt, len, allocbytes)) + return 0; + + pkt->written += len; + pkt->curr += len; + return 1; +} + +int WPACKET_sub_allocate_bytes__(WPACKET *pkt, size_t len, + unsigned char **allocbytes, size_t lenbytes) +{ + if (!WPACKET_start_sub_packet_len__(pkt, lenbytes) + || !WPACKET_allocate_bytes(pkt, len, allocbytes) + || !WPACKET_close(pkt)) + return 0; + + return 1; +} + +int WPACKET_reserve_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes) +{ + size_t newlen; + size_t reflen; + + /* Internal API, so should not fail */ + if (!ossl_assert(pkt->subs != NULL && len != 0)) + return 0; + + if (pkt->maxsize - pkt->written < len) + return 0; + + if (pkt->buf != NULL && (pkt->buf->length - pkt->written < len)) { + reflen = (len > pkt->buf->length) ? len : pkt->buf->length; + if (reflen > SIZE_MAX / REF_SIZE_LIMIT) { + newlen = SIZE_MAX; + } else { + newlen = reflen * REF_SIZE_LIMIT; + if (newlen < DEFAULT_BUF_SIZE) + newlen = DEFAULT_BUF_SIZE; + } + + if (BUF_MEM_grow(pkt->buf, newlen) == 0) + return 0; + } + + if (allocbytes != NULL) { + *allocbytes = WPACKET_get_curr(pkt); + if (pkt->endfirst && *allocbytes != NULL) + *allocbytes -= len; + } + + return 1; +} + +int WPACKET_sub_reserve_bytes__(WPACKET *pkt, size_t len, + unsigned char **allocbytes, size_t lenbytes) +{ + if (pkt->endfirst && lenbytes > 0) + return 0; + + if (!WPACKET_reserve_bytes(pkt, lenbytes + len, allocbytes)) + return 0; + + if (*allocbytes != NULL) + *allocbytes += lenbytes; + + return 1; +} + +static size_t maxmaxsize(size_t lenbytes) +{ + if (lenbytes >= sizeof(size_t) || lenbytes == 0) + return SIZE_MAX; + + return ((size_t)1 << (lenbytes * BYTES_TO_BITS_OFFSET)) - 1 + lenbytes; +} + +static int wpacket_intern_init_len(WPACKET *pkt, size_t lenbytes) +{ + unsigned char *lenchars; + + pkt->curr = 0; + pkt->written = 0; + + pkt->subs = OPENSSL_zalloc(sizeof(*pkt->subs)); + if (pkt->subs == NULL) { + ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (lenbytes == 0) + return 1; + + pkt->subs->pwritten = lenbytes; + pkt->subs->lenbytes = lenbytes; + + if (!WPACKET_allocate_bytes(pkt, lenbytes, &lenchars)) { + OPENSSL_free(pkt->subs); + pkt->subs = NULL; + return 0; + } + pkt->subs->packet_len = 0; + + return 1; +} + +int WPACKET_init_static_len(WPACKET *pkt, unsigned char *buf, size_t len, + size_t lenbytes) +{ + size_t max = maxmaxsize(lenbytes); + + /* Internal API, so should not fail */ + if (!ossl_assert(buf != NULL && len > 0)) + return 0; + + pkt->staticbuf = buf; + pkt->buf = NULL; + pkt->maxsize = (max < len) ? max : len; + pkt->endfirst = 0; + + return wpacket_intern_init_len(pkt, lenbytes); +} + +int WPACKET_init_der(WPACKET *pkt, unsigned char *buf, size_t len) +{ + /* Internal API, so should not fail */ + if (!ossl_assert(buf != NULL && len > 0)) + return 0; + + pkt->staticbuf = buf; + pkt->buf = NULL; + pkt->maxsize = len; + pkt->endfirst = 1; + + return wpacket_intern_init_len(pkt, 0); +} + +int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes) +{ + /* Internal API, so should not fail */ + if (!ossl_assert(buf != NULL)) + return 0; + + pkt->staticbuf = NULL; + pkt->buf = buf; + pkt->maxsize = maxmaxsize(lenbytes); + pkt->endfirst = 0; + + return wpacket_intern_init_len(pkt, lenbytes); +} + +int WPACKET_init(WPACKET *pkt, BUF_MEM *buf) +{ + return WPACKET_init_len(pkt, buf, 0); +} + +int WPACKET_init_null(WPACKET *pkt, size_t lenbytes) +{ + pkt->staticbuf = NULL; + pkt->buf = NULL; + pkt->maxsize = maxmaxsize(lenbytes); + pkt->endfirst = 0; + + return wpacket_intern_init_len(pkt, 0); +} + +int WPACKET_init_null_der(WPACKET *pkt) +{ + pkt->staticbuf = NULL; + pkt->buf = NULL; + pkt->maxsize = SIZE_MAX; + pkt->endfirst = 1; + + return wpacket_intern_init_len(pkt, 0); +} + +int WPACKET_set_flags(WPACKET *pkt, unsigned int flags) +{ + /* Internal API, so should not fail */ + if (!ossl_assert(pkt->subs != NULL)) + return 0; + + pkt->subs->flags = flags; + + return 1; +} + +/* Store the |value| of length |len| at location |data| */ +static int put_value(unsigned char *data, uint64_t value, size_t len) +{ + if (data == NULL) + return 1; + + for (data += len - 1; len > 0; len--) { + *data = (unsigned char)(value & 0xff); + data--; + value >>= LOW_BIT_SIZE; + } + + /* Check whether we could fit the value in the assigned number of bytes */ + if (value > 0) + return 0; + + return 1; +} + +/* + * Internal helper function used by WPACKET_close(), WPACKET_finish() and + * WPACKET_fill_lengths() to close a sub-packet and write out its length if + * necessary. If |doclose| is 0 then it goes through the motions of closing + * (i.e. it fills in all the lengths), but doesn't actually close anything. + */ +static int wpacket_intern_close(WPACKET *pkt, WPACKET_SUB *sub, int doclose) +{ + size_t packlen = pkt->written - sub->pwritten; + + if (packlen == 0 + && (sub->flags & WPACKET_FLAGS_NON_ZERO_LENGTH) != 0) + return 0; + + if (packlen == 0 + && sub->flags & WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) { + /* We can't handle this case. Return an error */ + if (!doclose) + return 0; + + /* Deallocate any bytes allocated for the length of the WPACKET */ + if ((pkt->curr - sub->lenbytes) == sub->packet_len) { + pkt->written -= sub->lenbytes; + pkt->curr -= sub->lenbytes; + } + + /* Don't write out the packet length */ + sub->packet_len = 0; + sub->lenbytes = 0; + } + + /* Write out the WPACKET length if needed */ + if (sub->lenbytes > 0) { + unsigned char *buf = GETBUF(pkt); + + if (buf != NULL + && !put_value(&buf[sub->packet_len], packlen, + sub->lenbytes)) + return 0; + } else if (pkt->endfirst && sub->parent != NULL + && (packlen != 0 || (sub->flags + & WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH) == 0)) { + size_t tmplen = packlen; + size_t numlenbytes = 1; + + while ((tmplen = tmplen >> LOW_BIT_SIZE) > 0) + numlenbytes++; + if (!WPACKET_put_bytes__(pkt, packlen, numlenbytes)) + return 0; + if (packlen > 0x7f) { + numlenbytes |= 0x80; + if (!WPACKET_put_bytes_u8(pkt, numlenbytes)) + return 0; + } + } + + if (doclose) { + pkt->subs = sub->parent; + OPENSSL_free(sub); + } + + return 1; +} + +int WPACKET_fill_lengths(WPACKET *pkt) +{ + WPACKET_SUB *sub; + + if (!ossl_assert(pkt->subs != NULL)) + return 0; + + for (sub = pkt->subs; sub != NULL; sub = sub->parent) { + if (!wpacket_intern_close(pkt, sub, 0)) + return 0; + } + + return 1; +} + +int WPACKET_close(WPACKET *pkt) +{ + /* + * Internal API, so should not fail - but we do negative testing of this + * so no assert (otherwise the tests fail) + */ + if (pkt->subs == NULL || pkt->subs->parent == NULL) + return 0; + + return wpacket_intern_close(pkt, pkt->subs, 1); +} + +int WPACKET_finish(WPACKET *pkt) +{ + int ret; + + /* + * Internal API, so should not fail - but we do negative testing of this + * so no assert (otherwise the tests fail) + */ + if (pkt->subs == NULL || pkt->subs->parent != NULL) + return 0; + + ret = wpacket_intern_close(pkt, pkt->subs, 1); + if (ret) { + OPENSSL_free(pkt->subs); + pkt->subs = NULL; + } + + return ret; +} + +int WPACKET_start_sub_packet_len__(WPACKET *pkt, size_t lenbytes) +{ + WPACKET_SUB *sub; + unsigned char *lenchars; + + /* Internal API, so should not fail */ + if (!ossl_assert(pkt->subs != NULL)) + return 0; + + /* We don't support lenbytes greater than 0 when doing endfirst writing */ + if (lenbytes > 0 && pkt->endfirst) + return 0; + + sub = OPENSSL_zalloc(sizeof(*sub)); + if (sub == NULL) { + ERR_raise(ERR_LIB_CRYPTO, ERR_R_MALLOC_FAILURE); + return 0; + } + + sub->parent = pkt->subs; + pkt->subs = sub; + sub->pwritten = pkt->written + lenbytes; + sub->lenbytes = lenbytes; + + if (lenbytes == 0) { + sub->packet_len = 0; + return 1; + } + + sub->packet_len = pkt->written; + + if (!WPACKET_allocate_bytes(pkt, lenbytes, &lenchars)) + return 0; + + return 1; +} + +int WPACKET_start_sub_packet(WPACKET *pkt) +{ + return WPACKET_start_sub_packet_len__(pkt, 0); +} + +int WPACKET_put_bytes__(WPACKET *pkt, uint64_t val, size_t size) +{ + unsigned char *data; + + /* Internal API, so should not fail */ + if (!ossl_assert(size <= sizeof(uint64_t)) + || !WPACKET_allocate_bytes(pkt, size, &data) + || !put_value(data, val, size)) + return 0; + + return 1; +} + +int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize) +{ + WPACKET_SUB *sub; + size_t lenbytes; + + /* Internal API, so should not fail */ + if (!ossl_assert(pkt->subs != NULL)) + return 0; + + /* Find the WPACKET_SUB for the top level */ + for (sub = pkt->subs; sub->parent != NULL; sub = sub->parent) + continue; + + lenbytes = sub->lenbytes; + if (lenbytes == 0) + lenbytes = sizeof(pkt->maxsize); + + if (maxmaxsize(lenbytes) < maxsize || maxsize < pkt->written) + return 0; + + pkt->maxsize = maxsize; + + return 1; +} + +int WPACKET_memset(WPACKET *pkt, int ch, size_t len) +{ + unsigned char *dest; + + if (len == 0) + return 1; + + if (!WPACKET_allocate_bytes(pkt, len, &dest)) + return 0; + + if (dest != NULL) + memset(dest, ch, len); + + return 1; +} + +int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len) +{ + unsigned char *dest; + + if (len == 0) + return 1; + + if (!WPACKET_allocate_bytes(pkt, len, &dest)) + return 0; + + if (dest != NULL) + memcpy(dest, src, len); + + return 1; +} + +int WPACKET_sub_memcpy__(WPACKET *pkt, const void *src, size_t len, + size_t lenbytes) +{ + if (!WPACKET_start_sub_packet_len__(pkt, lenbytes) + || !WPACKET_memcpy(pkt, src, len) + || !WPACKET_close(pkt)) + return 0; + + return 1; +} + +int WPACKET_get_total_written(WPACKET *pkt, size_t *written) +{ + /* Internal API, so should not fail */ + if (!ossl_assert(written != NULL)) + return 0; + + *written = pkt->written; + + return 1; +} + +int WPACKET_get_length(WPACKET *pkt, size_t *len) +{ + /* Internal API, so should not fail */ + if (!ossl_assert(pkt->subs != NULL && len != NULL)) + return 0; + + *len = pkt->written - pkt->subs->pwritten; + + return 1; +} + +unsigned char *WPACKET_get_curr(WPACKET *pkt) +{ + unsigned char *buf = GETBUF(pkt); + + if (buf == NULL) + return NULL; + + if (pkt->endfirst) + return buf + pkt->maxsize - pkt->curr; + + return buf + pkt->curr; +} + +int WPACKET_is_null_buf(WPACKET *pkt) +{ + return pkt->buf == NULL && pkt->staticbuf == NULL; +} + +void WPACKET_cleanup(WPACKET *pkt) +{ + WPACKET_SUB *sub, *parent; + + for (sub = pkt->subs; sub != NULL; sub = parent) { + parent = sub->parent; + OPENSSL_free(sub); + } + + pkt->subs = NULL; +} diff --git a/src/uadk_prov_packet.h b/src/uadk_prov_packet.h new file mode 100644 index 0000000..aabd042 --- /dev/null +++ b/src/uadk_prov_packet.h @@ -0,0 +1,959 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#ifndef UADK_PROV_PACKET_H +#define UADK_PROV_PACKET_H + +#include <string.h> +#include <openssl/bn.h> +#include <openssl/buffer.h> +#include <openssl/crypto.h> +#include <openssl/e_os2.h> + +#ifdef NDEBUG +#define ossl_assert(x) ((x) != 0) +#else +__owur static ossl_inline int ossl_assert_int(int expr, const char *exprstr, + const char *file, int line) +{ + if (!expr) + OPENSSL_die(exprstr, file, line); + + return expr; +} + +#define ossl_assert(x) ossl_assert_int((x) != 0, "Assertion failed: "#x, \ + __FILE__, __LINE__) + +#endif + +#define LOW_BIT_SIZE 8 +#define BYTES_TO_BITS_OFFSET 8 + +typedef struct { + /* Pointer to where we are currently reading from */ + const unsigned char *curr; + /* Number of bytes remaining */ + size_t remaining; +} PACKET; + +/* Internal unchecked shorthand; don't use outside this file. */ +static ossl_inline void packet_forward(PACKET *pkt, size_t len) +{ + pkt->curr += len; + pkt->remaining -= len; +} + +/* + * Returns the number of bytes remaining to be read in the PACKET + */ +static ossl_inline size_t PACKET_remaining(const PACKET *pkt) +{ + return pkt->remaining; +} + +/* + * Returns a pointer to the first byte after the packet data. + * Useful for integrating with non-PACKET parsing code. + * Specifically, we use PACKET_end() to verify that a d2i_... call + * has consumed the entire packet contents. + */ +static ossl_inline const unsigned char *PACKET_end(const PACKET *pkt) +{ + return pkt->curr + pkt->remaining; +} + +/* + * Returns a pointer to the PACKET's current position. + * For use in non-PACKETized APIs. + */ +static ossl_inline const unsigned char *PACKET_data(const PACKET *pkt) +{ + return pkt->curr; +} + +/* + * Initialise a PACKET with |len| bytes held in |buf|. This does not make a + * copy of the data so |buf| must be present for the whole time that the PACKET + * is being used. + */ +__owur static ossl_inline int PACKET_buf_init(PACKET *pkt, + const unsigned char *buf, + size_t len) +{ + /* Sanity check for negative values. */ + if (len > (size_t)(SIZE_MAX / 2)) + return 0; + + pkt->curr = buf; + pkt->remaining = len; + return 1; +} + +/* Initialize a PACKET to hold zero bytes. */ +static ossl_inline void PACKET_null_init(PACKET *pkt) +{ + pkt->curr = NULL; + pkt->remaining = 0; +} + +/* + * Returns 1 if the packet has length |num| and its contents equal the |num| + * bytes read from |ptr|. Returns 0 otherwise (lengths or contents not equal). + * If lengths are equal, performs the comparison in constant time. + */ +__owur static ossl_inline int PACKET_equal(const PACKET *pkt, const void *ptr, + size_t num) +{ + if (PACKET_remaining(pkt) != num) + return 0; + return CRYPTO_memcmp(pkt->curr, ptr, num) == 0; +} + +/* + * Peek ahead and initialize |subpkt| with the next |len| bytes read from |pkt|. + * Data is not copied: the |subpkt| packet will share its underlying buffer with + * the original |pkt|, so data wrapped by |pkt| must outlive the |subpkt|. + */ +__owur static ossl_inline int PACKET_peek_sub_packet(const PACKET *pkt, + PACKET *subpkt, size_t len) +{ + if (PACKET_remaining(pkt) < len) + return 0; + + return PACKET_buf_init(subpkt, pkt->curr, len); +} + +/* + * Initialize |subpkt| with the next |len| bytes read from |pkt|. Data is not + * copied: the |subpkt| packet will share its underlying buffer with the + * original |pkt|, so data wrapped by |pkt| must outlive the |subpkt|. + */ +__owur static ossl_inline int PACKET_get_sub_packet(PACKET *pkt, + PACKET *subpkt, size_t len) +{ + if (!PACKET_peek_sub_packet(pkt, subpkt, len)) + return 0; + + packet_forward(pkt, len); + + return 1; +} + +/* + * Peek ahead at 2 bytes in network order from |pkt| and store the value in + * |*data| + */ +__owur static ossl_inline int PACKET_peek_net_2(const PACKET *pkt, + unsigned int *data) +{ + if (PACKET_remaining(pkt) < 2) + return 0; + + *data = ((unsigned int)(*pkt->curr)) << 8; + *data |= *(pkt->curr + 1); + + return 1; +} + +/* Equivalent of n2s */ +/* Get 2 bytes in network order from |pkt| and store the value in |*data| */ +__owur static ossl_inline int PACKET_get_net_2(PACKET *pkt, unsigned int *data) +{ + if (!PACKET_peek_net_2(pkt, data)) + return 0; + + packet_forward(pkt, 2); + + return 1; +} + +/* Same as PACKET_get_net_2() but for a size_t */ +__owur static ossl_inline int PACKET_get_net_2_len(PACKET *pkt, size_t *data) +{ + unsigned int i; + int ret = PACKET_get_net_2(pkt, &i); + + if (ret) + *data = (size_t)i; + + return ret; +} + +/* + * Peek ahead at 3 bytes in network order from |pkt| and store the value in + * |*data| + */ +__owur static ossl_inline int PACKET_peek_net_3(const PACKET *pkt, + unsigned long *data) +{ + if (PACKET_remaining(pkt) < 3) + return 0; + + *data = ((unsigned long)(*pkt->curr)) << 16; + *data |= ((unsigned long)(*(pkt->curr + 1))) << 8; + *data |= *(pkt->curr + 2); + + return 1; +} + +/* Equivalent of n2l3 */ +/* Get 3 bytes in network order from |pkt| and store the value in |*data| */ +__owur static ossl_inline int PACKET_get_net_3(PACKET *pkt, unsigned long *data) +{ + if (!PACKET_peek_net_3(pkt, data)) + return 0; + + packet_forward(pkt, 3); + + return 1; +} + +/* Same as PACKET_get_net_3() but for a size_t */ +__owur static ossl_inline int PACKET_get_net_3_len(PACKET *pkt, size_t *data) +{ + unsigned long i; + int ret = PACKET_get_net_3(pkt, &i); + + if (ret) + *data = (size_t)i; + + return ret; +} + +/* + * Peek ahead at 4 bytes in network order from |pkt| and store the value in + * |*data| + */ +__owur static ossl_inline int PACKET_peek_net_4(const PACKET *pkt, + unsigned long *data) +{ + if (PACKET_remaining(pkt) < 4) + return 0; + + *data = ((unsigned long)(*pkt->curr)) << 24; + *data |= ((unsigned long)(*(pkt->curr + 1))) << 16; + *data |= ((unsigned long)(*(pkt->curr + 2))) << 8; + *data |= *(pkt->curr + 3); + + return 1; +} + +/* + * Peek ahead at 8 bytes in network order from |pkt| and store the value in + * |*data| + */ +__owur static ossl_inline int PACKET_peek_net_8(const PACKET *pkt, + uint64_t *data) +{ + if (PACKET_remaining(pkt) < 8) + return 0; + + *data = ((uint64_t)(*pkt->curr)) << 56; + *data |= ((uint64_t)(*(pkt->curr + 1))) << 48; + *data |= ((uint64_t)(*(pkt->curr + 2))) << 40; + *data |= ((uint64_t)(*(pkt->curr + 3))) << 32; + *data |= ((uint64_t)(*(pkt->curr + 4))) << 24; + *data |= ((uint64_t)(*(pkt->curr + 5))) << 16; + *data |= ((uint64_t)(*(pkt->curr + 6))) << 8; + *data |= *(pkt->curr + 7); + + return 1; +} + +/* Equivalent of n2l */ +/* Get 4 bytes in network order from |pkt| and store the value in |*data| */ +__owur static ossl_inline int PACKET_get_net_4(PACKET *pkt, unsigned long *data) +{ + if (!PACKET_peek_net_4(pkt, data)) + return 0; + + packet_forward(pkt, 4); + + return 1; +} + +/* Same as PACKET_get_net_4() but for a size_t */ +__owur static ossl_inline int PACKET_get_net_4_len(PACKET *pkt, size_t *data) +{ + unsigned long i; + int ret = PACKET_get_net_4(pkt, &i); + + if (ret) + *data = (size_t)i; + + return ret; +} + +/* Get 8 bytes in network order from |pkt| and store the value in |*data| */ +__owur static ossl_inline int PACKET_get_net_8(PACKET *pkt, uint64_t *data) +{ + if (!PACKET_peek_net_8(pkt, data)) + return 0; + + packet_forward(pkt, 8); + + return 1; +} + +/* Peek ahead at 1 byte from |pkt| and store the value in |*data| */ +__owur static ossl_inline int PACKET_peek_1(const PACKET *pkt, + unsigned int *data) +{ + if (!PACKET_remaining(pkt)) + return 0; + + *data = *pkt->curr; + + return 1; +} + +/* Get 1 byte from |pkt| and store the value in |*data| */ +__owur static ossl_inline int PACKET_get_1(PACKET *pkt, unsigned int *data) +{ + if (!PACKET_peek_1(pkt, data)) + return 0; + + packet_forward(pkt, 1); + + return 1; +} + +/* Same as PACKET_get_1() but for a size_t */ +__owur static ossl_inline int PACKET_get_1_len(PACKET *pkt, size_t *data) +{ + unsigned int i; + int ret = PACKET_get_1(pkt, &i); + + if (ret) + *data = (size_t)i; + + return ret; +} + +/* + * Peek ahead at 4 bytes in reverse network order from |pkt| and store the value + * in |*data| + */ +__owur static ossl_inline int PACKET_peek_4(const PACKET *pkt, + unsigned long *data) +{ + if (PACKET_remaining(pkt) < 4) + return 0; + + *data = *pkt->curr; + *data |= ((unsigned long)(*(pkt->curr + 1))) << 8; + *data |= ((unsigned long)(*(pkt->curr + 2))) << 16; + *data |= ((unsigned long)(*(pkt->curr + 3))) << 24; + + return 1; +} + +/* Equivalent of c2l */ +/* + * Get 4 bytes in reverse network order from |pkt| and store the value in + * |*data| + */ +__owur static ossl_inline int PACKET_get_4(PACKET *pkt, unsigned long *data) +{ + if (!PACKET_peek_4(pkt, data)) + return 0; + + packet_forward(pkt, 4); + + return 1; +} + +/* + * Peek ahead at |len| bytes from the |pkt| and store a pointer to them in + * |*data|. This just points at the underlying buffer that |pkt| is using. The + * caller should not free this data directly (it will be freed when the + * underlying buffer gets freed + */ +__owur static ossl_inline int PACKET_peek_bytes(const PACKET *pkt, + const unsigned char **data, + size_t len) +{ + if (PACKET_remaining(pkt) < len) + return 0; + + *data = pkt->curr; + + return 1; +} + +/* + * Read |len| bytes from the |pkt| and store a pointer to them in |*data|. This + * just points at the underlying buffer that |pkt| is using. The caller should + * not free this data directly (it will be freed when the underlying buffer gets + * freed + */ +__owur static ossl_inline int PACKET_get_bytes(PACKET *pkt, + const unsigned char **data, + size_t len) +{ + if (!PACKET_peek_bytes(pkt, data, len)) + return 0; + + packet_forward(pkt, len); + + return 1; +} + +/* Peek ahead at |len| bytes from |pkt| and copy them to |data| */ +__owur static ossl_inline int PACKET_peek_copy_bytes(const PACKET *pkt, + unsigned char *data, + size_t len) +{ + if (PACKET_remaining(pkt) < len) + return 0; + + memcpy(data, pkt->curr, len); + + return 1; +} + +/* + * Read |len| bytes from |pkt| and copy them to |data|. + * The caller is responsible for ensuring that |data| can hold |len| bytes. + */ +__owur static ossl_inline int PACKET_copy_bytes(PACKET *pkt, + unsigned char *data, size_t len) +{ + if (!PACKET_peek_copy_bytes(pkt, data, len)) + return 0; + + packet_forward(pkt, len); + + return 1; +} + +/* + * Copy packet data to |dest|, and set |len| to the number of copied bytes. + * If the packet has more than |dest_len| bytes, nothing is copied. + * Returns 1 if the packet data fits in |dest_len| bytes, 0 otherwise. + * Does not forward PACKET position (because it is typically the last thing + * done with a given PACKET). + */ +__owur static ossl_inline int PACKET_copy_all(const PACKET *pkt, + unsigned char *dest, + size_t dest_len, size_t *len) +{ + if (PACKET_remaining(pkt) > dest_len) { + *len = 0; + return 0; + } + + *len = pkt->remaining; + memcpy(dest, pkt->curr, pkt->remaining); + + return 1; +} + +/* + * Copy |pkt| bytes to a newly allocated buffer and store a pointer to the + * result in |*data|, and the length in |len|. + * If |*data| is not NULL, the old data is OPENSSL_free'd. + * If the packet is empty, or malloc fails, |*data| will be set to NULL. + * Returns 1 if the malloc succeeds and 0 otherwise. + * Does not forward PACKET position (because it is typically the last thing + * done with a given PACKET). + */ +__owur static ossl_inline int PACKET_memdup(const PACKET *pkt, + unsigned char **data, size_t *len) +{ + size_t length; + + OPENSSL_free(*data); + *data = NULL; + *len = 0; + + length = PACKET_remaining(pkt); + + if (length == 0) + return 1; + + *data = OPENSSL_memdup(pkt->curr, length); + if (*data == NULL) + return 0; + + *len = length; + return 1; +} + +/* + * Read a C string from |pkt| and copy to a newly allocated, NUL-terminated + * buffer. Store a pointer to the result in |*data|. + * If |*data| is not NULL, the old data is OPENSSL_free'd. + * If the data in |pkt| does not contain a NUL-byte, the entire data is + * copied and NUL-terminated. + * Returns 1 if the malloc succeeds and 0 otherwise. + * Does not forward PACKET position (because it is typically the last thing done + * with a given PACKET). + */ +__owur static ossl_inline int PACKET_strndup(const PACKET *pkt, char **data) +{ + OPENSSL_free(*data); + + /* This will succeed on an empty packet, unless pkt->curr == NULL. */ + *data = OPENSSL_strndup((const char *)pkt->curr, PACKET_remaining(pkt)); + return (*data != NULL); +} + +/* Returns 1 if |pkt| contains at least one 0-byte, 0 otherwise. */ +static ossl_inline int PACKET_contains_zero_byte(const PACKET *pkt) +{ + return memchr(pkt->curr, 0, pkt->remaining) != NULL; +} + +/* Move the current reading position forward |len| bytes */ +__owur static ossl_inline int PACKET_forward(PACKET *pkt, size_t len) +{ + if (PACKET_remaining(pkt) < len) + return 0; + + packet_forward(pkt, len); + + return 1; +} + +/* + * Reads a variable-length vector prefixed with a one-byte length, and stores + * the contents in |subpkt|. |pkt| can equal |subpkt|. + * Data is not copied: the |subpkt| packet will share its underlying buffer with + * the original |pkt|, so data wrapped by |pkt| must outlive the |subpkt|. + * Upon failure, the original |pkt| and |subpkt| are not modified. + */ +__owur static ossl_inline int PACKET_get_length_prefixed_1(PACKET *pkt, + PACKET *subpkt) +{ + unsigned int length; + const unsigned char *data; + PACKET tmp = *pkt; + + if (!PACKET_get_1(&tmp, &length) || + !PACKET_get_bytes(&tmp, &data, (size_t)length)) { + return 0; + } + + *pkt = tmp; + subpkt->curr = data; + subpkt->remaining = length; + + return 1; +} + +/* + * Like PACKET_get_length_prefixed_1, but additionally, fails when there are + * leftover bytes in |pkt|. + */ +__owur static ossl_inline int PACKET_as_length_prefixed_1(PACKET *pkt, + PACKET *subpkt) +{ + unsigned int length; + const unsigned char *data; + PACKET tmp = *pkt; + + if (!PACKET_get_1(&tmp, &length) || + !PACKET_get_bytes(&tmp, &data, (size_t)length) || + PACKET_remaining(&tmp) != 0) { + return 0; + } + + *pkt = tmp; + subpkt->curr = data; + subpkt->remaining = length; + + return 1; +} + +/* + * Reads a variable-length vector prefixed with a two-byte length, and stores + * the contents in |subpkt|. |pkt| can equal |subpkt|. + * Data is not copied: the |subpkt| packet will share its underlying buffer with + * the original |pkt|, so data wrapped by |pkt| must outlive the |subpkt|. + * Upon failure, the original |pkt| and |subpkt| are not modified. + */ +__owur static ossl_inline int PACKET_get_length_prefixed_2(PACKET *pkt, + PACKET *subpkt) +{ + unsigned int length; + const unsigned char *data; + PACKET tmp = *pkt; + + if (!PACKET_get_net_2(&tmp, &length) || + !PACKET_get_bytes(&tmp, &data, (size_t)length)) { + return 0; + } + + *pkt = tmp; + subpkt->curr = data; + subpkt->remaining = length; + + return 1; +} + +/* + * Like PACKET_get_length_prefixed_2, but additionally, fails when there are + * leftover bytes in |pkt|. + */ +__owur static ossl_inline int PACKET_as_length_prefixed_2(PACKET *pkt, + PACKET *subpkt) +{ + unsigned int length; + const unsigned char *data; + PACKET tmp = *pkt; + + if (!PACKET_get_net_2(&tmp, &length) || + !PACKET_get_bytes(&tmp, &data, (size_t)length) || + PACKET_remaining(&tmp) != 0) { + return 0; + } + + *pkt = tmp; + subpkt->curr = data; + subpkt->remaining = length; + + return 1; +} + +/* + * Reads a variable-length vector prefixed with a three-byte length, and stores + * the contents in |subpkt|. |pkt| can equal |subpkt|. + * Data is not copied: the |subpkt| packet will share its underlying buffer with + * the original |pkt|, so data wrapped by |pkt| must outlive the |subpkt|. + * Upon failure, the original |pkt| and |subpkt| are not modified. + */ +__owur static ossl_inline int PACKET_get_length_prefixed_3(PACKET *pkt, + PACKET *subpkt) +{ + unsigned long length; + const unsigned char *data; + PACKET tmp = *pkt; + + if (!PACKET_get_net_3(&tmp, &length) || + !PACKET_get_bytes(&tmp, &data, (size_t)length)) { + return 0; + } + + *pkt = tmp; + subpkt->curr = data; + subpkt->remaining = length; + + return 1; +} + +/* Writeable packets */ + +typedef struct wpacket_sub WPACKET_SUB; +struct wpacket_sub { + /* The parent WPACKET_SUB if we have one or NULL otherwise */ + WPACKET_SUB *parent; + + /* + * Offset into the buffer where the length of this WPACKET goes. We use an + * offset in case the buffer grows and gets reallocated. + */ + size_t packet_len; + + /* Number of bytes in the packet_len or 0 if we don't write the length */ + size_t lenbytes; + + /* Number of bytes written to the buf prior to this packet starting */ + size_t pwritten; + + /* Flags for this sub-packet */ + unsigned int flags; +}; + +typedef struct wpacket_st WPACKET; +struct wpacket_st { + /* The buffer where we store the output data */ + BUF_MEM *buf; + + /* Fixed sized buffer which can be used as an alternative to buf */ + unsigned char *staticbuf; + + /* + * Offset into the buffer where we are currently writing. We use an offset + * in case the buffer grows and gets reallocated. + */ + size_t curr; + + /* Number of bytes written so far */ + size_t written; + + /* Maximum number of bytes we will allow to be written to this WPACKET */ + size_t maxsize; + + /* Our sub-packets (always at least one if not finished) */ + WPACKET_SUB *subs; + + /* Writing from the end first? */ + unsigned int endfirst : 1; +}; + +/* Flags */ + +/* Default */ +#define WPACKET_FLAGS_NONE 0 + +/* Error on WPACKET_close() if no data written to the WPACKET */ +#define WPACKET_FLAGS_NON_ZERO_LENGTH 1 + +/* + * Abandon all changes on WPACKET_close() if no data written to the WPACKET, + * i.e. this does not write out a zero packet length + */ +#define WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH 2 + + +/* + * Initialise a WPACKET with the buffer in |buf|. The buffer must exist + * for the whole time that the WPACKET is being used. Additionally |lenbytes| of + * data is preallocated at the start of the buffer to store the length of the + * WPACKET once we know it. + */ +int WPACKET_init_len(WPACKET *pkt, BUF_MEM *buf, size_t lenbytes); + +/* + * Same as WPACKET_init_len except there is no preallocation of the WPACKET + * length. + */ +int WPACKET_init(WPACKET *pkt, BUF_MEM *buf); + +/* + * Same as WPACKET_init_len except there is no underlying buffer. No data is + * ever actually written. We just keep track of how much data would have been + * written if a buffer was there. + */ +int WPACKET_init_null(WPACKET *pkt, size_t lenbytes); + +/* + * Same as WPACKET_init_null except we set the WPACKET to assume DER length + * encoding for sub-packets. + */ +int WPACKET_init_null_der(WPACKET *pkt); + +/* + * Same as WPACKET_init_len except we do not use a growable BUF_MEM structure. + * A fixed buffer of memory |buf| of size |len| is used instead. A failure will + * occur if you attempt to write beyond the end of the buffer + */ +int WPACKET_init_static_len(WPACKET *pkt, unsigned char *buf, size_t len, + size_t lenbytes); + +/* + * Same as WPACKET_init_static_len except lenbytes is always 0, and we set the + * WPACKET to write to the end of the buffer moving towards the start and use + * DER length encoding for sub-packets. + */ +int WPACKET_init_der(WPACKET *pkt, unsigned char *buf, size_t len); + +/* + * Set the flags to be applied to the current sub-packet + */ +int WPACKET_set_flags(WPACKET *pkt, unsigned int flags); + +/* + * Closes the most recent sub-packet. It also writes out the length of the + * packet to the required location (normally the start of the WPACKET) if + * appropriate. The top level WPACKET should be closed using WPACKET_finish() + * instead of this function. + */ +int WPACKET_close(WPACKET *pkt); + +/* + * The same as WPACKET_close() but only for the top most WPACKET. Additionally + * frees memory resources for this WPACKET. + */ +int WPACKET_finish(WPACKET *pkt); + +/* + * Iterate through all the sub-packets and write out their lengths as if they + * were being closed. The lengths will be overwritten with the final lengths + * when the sub-packets are eventually closed (which may be different if more + * data is added to the WPACKET). This function fails if a sub-packet is of 0 + * length and WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH is set. + */ +int WPACKET_fill_lengths(WPACKET *pkt); + +/* + * Initialise a new sub-packet. Additionally |lenbytes| of data is preallocated + * at the start of the sub-packet to store its length once we know it. Don't + * call this directly. Use the convenience macros below instead. + */ +int WPACKET_start_sub_packet_len__(WPACKET *pkt, size_t lenbytes); + +/* + * Convenience macros for calling WPACKET_start_sub_packet_len with different + * lengths + */ +#define WPACKET_start_sub_packet_u8(pkt) \ + WPACKET_start_sub_packet_len__((pkt), 1) +#define WPACKET_start_sub_packet_u16(pkt) \ + WPACKET_start_sub_packet_len__((pkt), 2) +#define WPACKET_start_sub_packet_u24(pkt) \ + WPACKET_start_sub_packet_len__((pkt), 3) +#define WPACKET_start_sub_packet_u32(pkt) \ + WPACKET_start_sub_packet_len__((pkt), 4) + +/* + * Same as WPACKET_start_sub_packet_len__() except no bytes are pre-allocated + * for the sub-packet length. + */ +int WPACKET_start_sub_packet(WPACKET *pkt); + +/* + * Allocate bytes in the WPACKET for the output. This reserves the bytes + * and counts them as "written", but doesn't actually do the writing. A pointer + * to the allocated bytes is stored in |*allocbytes|. |allocbytes| may be NULL. + * WARNING: the allocated bytes must be filled in immediately, without further + * WPACKET_* calls. If not then the underlying buffer may be realloc'd and + * change its location. + */ +int WPACKET_allocate_bytes(WPACKET *pkt, size_t len, + unsigned char **allocbytes); + +/* + * The same as WPACKET_allocate_bytes() except additionally a new sub-packet is + * started for the allocated bytes, and then closed immediately afterwards. The + * number of length bytes for the sub-packet is in |lenbytes|. Don't call this + * directly. Use the convenience macros below instead. + */ +int WPACKET_sub_allocate_bytes__(WPACKET *pkt, size_t len, + unsigned char **allocbytes, size_t lenbytes); + +/* + * Convenience macros for calling WPACKET_sub_allocate_bytes with different + * lengths + */ +#define WPACKET_sub_allocate_bytes_u8(pkt, len, bytes) \ + WPACKET_sub_allocate_bytes__((pkt), (len), (bytes), 1) +#define WPACKET_sub_allocate_bytes_u16(pkt, len, bytes) \ + WPACKET_sub_allocate_bytes__((pkt), (len), (bytes), 2) +#define WPACKET_sub_allocate_bytes_u24(pkt, len, bytes) \ + WPACKET_sub_allocate_bytes__((pkt), (len), (bytes), 3) +#define WPACKET_sub_allocate_bytes_u32(pkt, len, bytes) \ + WPACKET_sub_allocate_bytes__((pkt), (len), (bytes), 4) + +/* + * The same as WPACKET_allocate_bytes() except the reserved bytes are not + * actually counted as written. Typically this will be for when we don't know + * how big arbitrary data is going to be up front, but we do know what the + * maximum size will be. If this function is used, then it should be immediately + * followed by a WPACKET_allocate_bytes() call before any other WPACKET + * functions are called (unless the write to the allocated bytes is abandoned). + * + * For example: If we are generating a signature, then the size of that + * signature may not be known in advance. We can use WPACKET_reserve_bytes() to + * handle this: + * if (!WPACKET_sub_reserve_bytes_u16(&pkt, EVP_PKEY_get_size(pkey), &sigbytes1) + * || EVP_SignFinal(md_ctx, sigbytes1, &siglen, pkey) <= 0 + * || !WPACKET_sub_allocate_bytes_u16(&pkt, siglen, &sigbytes2) + * || sigbytes1 != sigbytes2) + * goto err; + */ +int WPACKET_reserve_bytes(WPACKET *pkt, size_t len, unsigned char **allocbytes); + +/* + * The "reserve_bytes" equivalent of WPACKET_sub_allocate_bytes__() + */ +int WPACKET_sub_reserve_bytes__(WPACKET *pkt, size_t len, + unsigned char **allocbytes, size_t lenbytes); + +/* + * Convenience macros for WPACKET_sub_reserve_bytes with different lengths + */ +#define WPACKET_sub_reserve_bytes_u8(pkt, len, bytes) \ + WPACKET_reserve_bytes__((pkt), (len), (bytes), 1) +#define WPACKET_sub_reserve_bytes_u16(pkt, len, bytes) \ + WPACKET_sub_reserve_bytes__((pkt), (len), (bytes), 2) +#define WPACKET_sub_reserve_bytes_u24(pkt, len, bytes) \ + WPACKET_sub_reserve_bytes__((pkt), (len), (bytes), 3) +#define WPACKET_sub_reserve_bytes_u32(pkt, len, bytes) \ + WPACKET_sub_reserve_bytes__((pkt), (len), (bytes), 4) + +/* + * Write the value stored in |val| into the WPACKET. The value will consume + * |bytes| amount of storage. An error will occur if |val| cannot be + * accommodated in |bytes| storage, e.g. attempting to write the value 256 into + * 1 byte will fail. Don't call this directly. Use the convenience macros below + * instead. + */ +int WPACKET_put_bytes__(WPACKET *pkt, uint64_t val, size_t bytes); + +/* + * Convenience macros for calling WPACKET_put_bytes with different + * lengths + */ +#define WPACKET_put_bytes_u8(pkt, val) \ + WPACKET_put_bytes__((pkt), (val), 1) +#define WPACKET_put_bytes_u16(pkt, val) \ + WPACKET_put_bytes__((pkt), (val), 2) +#define WPACKET_put_bytes_u24(pkt, val) \ + WPACKET_put_bytes__((pkt), (val), 3) +#define WPACKET_put_bytes_u32(pkt, val) \ + WPACKET_put_bytes__((pkt), (val), 4) +#define WPACKET_put_bytes_u64(pkt, val) \ + WPACKET_put_bytes__((pkt), (val), 8) + +/* Set a maximum size that we will not allow the WPACKET to grow beyond */ +int WPACKET_set_max_size(WPACKET *pkt, size_t maxsize); + +/* Copy |len| bytes of data from |*src| into the WPACKET. */ +int WPACKET_memcpy(WPACKET *pkt, const void *src, size_t len); + +/* Set |len| bytes of data to |ch| into the WPACKET. */ +int WPACKET_memset(WPACKET *pkt, int ch, size_t len); + +/* + * Copy |len| bytes of data from |*src| into the WPACKET and prefix with its + * length (consuming |lenbytes| of data for the length). Don't call this + * directly. Use the convenience macros below instead. + */ +int WPACKET_sub_memcpy__(WPACKET *pkt, const void *src, size_t len, + size_t lenbytes); + +/* Convenience macros for calling WPACKET_sub_memcpy with different lengths */ +#define WPACKET_sub_memcpy_u8(pkt, src, len) \ + WPACKET_sub_memcpy__((pkt), (src), (len), 1) +#define WPACKET_sub_memcpy_u16(pkt, src, len) \ + WPACKET_sub_memcpy__((pkt), (src), (len), 2) +#define WPACKET_sub_memcpy_u24(pkt, src, len) \ + WPACKET_sub_memcpy__((pkt), (src), (len), 3) +#define WPACKET_sub_memcpy_u32(pkt, src, len) \ + WPACKET_sub_memcpy__((pkt), (src), (len), 4) + +/* + * Return the total number of bytes written so far to the underlying buffer + * including any storage allocated for length bytes + */ +int WPACKET_get_total_written(WPACKET *pkt, size_t *written); + +/* + * Returns the length of the current sub-packet. This excludes any bytes + * allocated for the length itself. + */ +int WPACKET_get_length(WPACKET *pkt, size_t *len); + +/* + * Returns a pointer to the current write location, but does not allocate any + * bytes. + */ +unsigned char *WPACKET_get_curr(WPACKET *pkt); + +/* Returns true if the underlying buffer is actually NULL */ +int WPACKET_is_null_buf(WPACKET *pkt); + +/* Release resources in a WPACKET if a failure has occurred. */ +void WPACKET_cleanup(WPACKET *pkt); + +#endif /* OSSL_INTERNAL_PACKET_H */
Support SM2 keypair generation in uadk_provider. Test: openssl list -provider uadk_provider -key-managers openssl ecparam -name SM2 -genkey -out sm2.key -provider uadk_provider openssl ec -in sm2.key -pubout -out sm2.pub -provider uadk_provider
Support SM2 encrypt, decrypt, sign and verify. Test: openssl list -provider uadk_provider -signature-algorithms openssl list -provider uadk_provider -public-key-algorithms openssl dgst -provider uadk_provider -SM3 -sign sm2.key -out \ sm2_ec.sig sign.data openssl dgst -provider uadk_provider -SM3 -verify sm2.pub \ -signature sm2_ec.sig sign.data openssl pkeyutl -encrypt -in plaintext.txt -out ciphertext.bin \ -inkey sm2.pub -pubin -provider uadk_provider openssl pkeyutl -decrypt -in ciphertext.bin -out plaintext.txt \ -inkey sm2.key -provider uadk_provider
Signed-off-by: Zhiqi Song songzhiqi1@huawei.com Signed-off-by: JiangShui Yang yangjiangshui@h-partners.com --- src/Makefile.am | 2 + src/uadk_prov.h | 15 +- src/uadk_prov_init.c | 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; +}
Add sanity test command for SM2, including performance and basic function test command.
Signed-off-by: Zhiqi Song songzhiqi1@huawei.com --- test/sanity_test_provider.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
diff --git a/test/sanity_test_provider.sh b/test/sanity_test_provider.sh index 37b9f51..2ba468c 100755 --- a/test/sanity_test_provider.sh +++ b/test/sanity_test_provider.sh @@ -87,6 +87,24 @@ if [[ $signature_algs =~ "uadk_provider" ]]; then
openssl pkeyutl -decrypt -in enc.txt -inkey prikey.pem -out dec.txt \ -pkeyopt rsa_padding_mode:pkcs1 -provider $engine_id + + echo "uadk_provider testing SM2" + openssl speed -provider $engine_id sm2 + openssl speed -provider $engine_id -async_job 1 sm2 + #generate keypair + openssl ecparam -name SM2 -genkey -out sm2.key -provider $engine_id + #get pubkey + openssl ec -in sm2.key -pubout -out sm2.pub + #sign + echo "Content to be signed" > sign.data + openssl dgst -provider $engine_id -SM3 -sign sm2.key -out sm2_ec.sig sign.data + #verify + openssl dgst -provider $engine_id -SM3 -verify sm2.pub -signature sm2_ec.sig sign.data + #encrypt + echo "Content to be encrypted" > plaintext.txt + openssl pkeyutl -encrypt -in plaintext.txt -out ciphertext.bin -inkey sm2.pub -pubin -provider $engine_id + #decrypt + openssl pkeyutl -decrypt -in ciphertext.bin -out plaintext.txt -inkey sm2.key -provider $engine_id fi
if [[ $keyexch_algs =~ "uadk_provider" ]]; then
Cleanup the following warning: xxx:warning: assignment discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers] 702 | priv->req.in = tmpdata;
Signed-off-by: Zhiqi Song songzhiqi1@huawei.com --- src/uadk_digest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/uadk_digest.c b/src/uadk_digest.c index dfce8a9..f460fcf 100644 --- a/src/uadk_digest.c +++ b/src/uadk_digest.c @@ -699,7 +699,7 @@ static int digest_update_inner(EVP_MD_CTX *ctx, const void *data, size_t data_le processing_len = left_len - (left_len % DIGEST_BLOCK_SIZE);
priv->req.in_bytes = processing_len; - priv->req.in = tmpdata; + priv->req.in = (unsigned char *)tmpdata; }
if (priv->state == SEC_DIGEST_INIT)