diff --git a/CMakeLists.txt b/CMakeLists.txt index 5223abb..b2a0571 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,6 +95,11 @@ find_package(json-c REQUIRED ) +find_package(OpenSSL + 3.5.0 + REQUIRED +) + add_definitions( -D_GNU_SOURCE ) @@ -137,6 +142,80 @@ install( DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) +########################################################### +# ASN.1 + +set (ASN1_SOURCES + src/asn1.c +) + +add_custom_command( + OUTPUT asn1_gen.c + COMMAND ${CMAKE_C_COMPILER} -I${OPENSSL_INCLUDE_DIR} -x c -E ${CMAKE_SOURCE_DIR}/src/asn1_gen.c.in + | grep -v "^#" + | sed -n -e "1,/^BEGIN:$$/!p" + | clang-format --assume-filename=.c + > asn1_gen.c + MAIN_DEPENDENCY ${CMAKE_SOURCE_DIR}/src/asn1_gen.c.in + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} +) +add_custom_target(asn1_gen ALL DEPENDS asn1_gen.c) + +add_library(asn1 OBJECT ${ASN1_SOURCES}) +set_property(TARGET asn1 PROPERTY POSITION_INDEPENDENT_CODE ON) +target_include_directories(asn1 PRIVATE ${OPENSSL_INCLUDE_DIR} ${CMAKE_BINARY_DIR}) +add_dependencies(asn1 asn1_gen) + +########################################################### +# zpcprovider + +set(ZPCPROVIDER_SOURCES + src/provider.c + src/object.c + src/uri.c + src/map.c + src/store.c + src/keymgmt.c + src/signature.c + src/tls.c + src/decoder.c +) + +add_library(zpcprovider MODULE ${ZPCPROVIDER_SOURCES}) +set_target_properties(zpcprovider PROPERTIES PREFIX "") + +target_include_directories(zpcprovider PRIVATE src include ${OPENSSL_INCLUDE_DIR}) +target_link_libraries(zpcprovider PRIVATE zpc OpenSSL::Crypto $) + +install( + TARGETS zpcprovider + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBEXECDIR} +) + +set(OPENSSL_CONF + ${CMAKE_BINARY_DIR}/openssl.cnf +) +set(OPENSSL_CONF_IN + ${CMAKE_SOURCE_DIR}/openssl.cnf.in +) +set(ZPCPROVIDER_MODULE + ${CMAKE_BINARY_DIR}/zpcprovider.so +) +configure_file(${OPENSSL_CONF_IN} ${OPENSSL_CONF} @ONLY) + +# install( +# FILES ${CMAKE_SOURCE_DIR}/man/zpcprovider.cnf.5 +# DESTINATION ${CMAKE_INSTALL_MANDIR}/man5 +# ) +# +# install( +# FILES ${CMAKE_SOURCE_DIR}/man/zpcprovider.7 +# DESTINATION ${CMAKE_INSTALL_MANDIR}/man7 +# ) + +########################################################### +# Test + option(BUILD_TEST OFF) if (BUILD_TEST) @@ -420,6 +499,14 @@ target_include_directories(runtest PRIVATE include src ${GTEST_INCLUDE_DIR}) include(GoogleTest) gtest_discover_tests(runtest) +set (ZPCPROVIDER_TEST_SOURCES + test/tprovider.c +) +add_executable(runprovidertest ${ZPCPROVIDER_TEST_SOURCES}) +add_dependencies(runprovidertest zpcprovider) +target_include_directories(runprovidertest PRIVATE src ${OPENSSL_INCLUDE_DIR}) +target_link_libraries(runprovidertest PRIVATE OpenSSL::Crypto $) + endif () ########################################################### diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 662d462..097b967 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,8 @@ Contributing {#contrib} === -You can contribute to `libzpc` by submitting issues (feature requests, bug reports) or pull requests (code contributions) to the GitHub repository. +You can contribute to `libzpc` by submitting issues (feature requests, bug +reports) or pull requests (code contributions) to the GitHub repository. Bug reports @@ -9,9 +10,11 @@ Bug reports When filing a bug report, please include all relevant information. -In all cases include the `libzpc` version, operating system and kernel version used. +In all cases include the `libzpc` version, operating system and kernel version +used. -Additionally, if it is a build error, include the toolchain version used. If it is a runtime error, include the crypto adapter config and processor model used. +Additionally, if it is a build error, include the toolchain version used. If it +is a runtime error, include the crypto adapter config and processor model used. Ideally, detailed steps on how to reproduce the issue would be included. @@ -19,12 +22,20 @@ Ideally, detailed steps on how to reproduce the issue would be included. Code contributions --- -All code contributions are reviewed by the `libzpc` maintainers who reverve the right to accept or reject a pull request. +All code contributions are reviewed by the `libzpc` maintainers who reverve the +right to accept or reject a pull request. -Please state clearly if your pull request changes the `libzpc` API or ABI, and if so, whether the changes are backward compatible. +Please state clearly if your pull request changes the `libzpc` API or ABI, and +if so, whether the changes are backward compatible. -If your pull request resolves an issue, please put a `"Fixes #"` line in the commit message. Ideally, the pull request would add a corresponding regression test. +If your pull request resolves an issue, please put a `"Fixes #"` +line in the commit message. Ideally, the pull request would add a corresponding +regression test. If your pull request adds a new feature, please add a corresponding unit test. -The code base is formatted using the `indent` tool with the options specified in the enclosed `.indent.pro` file. All code contributions must not violate this coding style. When formatting `libzpc` code, you can use `indent` with the prescribed options by copying the file to your home directory or by setting the `INDENT_PROFILE` environment variable's value to name the file. +The code base is formatted using the `indent` tool with the options specified in +the enclosed `.indent.pro` file. All code contributions must not violate this +coding style. When formatting `libzpc` code, you can use `indent` with the +prescribed options by copying the file to your home directory or by setting the +`INDENT_PROFILE` environment variable's value to name the file. diff --git a/include/zpc/ecc_key.h b/include/zpc/ecc_key.h index ec0e529..301ff72 100644 --- a/include/zpc/ecc_key.h +++ b/include/zpc/ecc_key.h @@ -125,7 +125,7 @@ int zpc_ec_key_set_apqns(struct zpc_ec_key *key, const char *apqns[]); */ __attribute__((visibility("default"))) int zpc_ec_key_import(struct zpc_ec_key *key, const unsigned char *seckey, - unsigned int seckeylen); + size_t seckeylen); /** * Import an EC clear-key pair. At least one of the key parts must be non-NULL. @@ -150,8 +150,8 @@ int zpc_ec_key_import(struct zpc_ec_key *key, const unsigned char *seckey, */ __attribute__((visibility("default"))) int zpc_ec_key_import_clear(struct zpc_ec_key *key, - const unsigned char *pubkey, unsigned int publen, - const unsigned char *privkey, unsigned int privlen); + const unsigned char *pubkey, size_t publen, + const unsigned char *privkey, size_t privlen); /** * Export an EC secure-key. Depending on the key type (CCA or EP11), the secure @@ -166,7 +166,7 @@ int zpc_ec_key_import_clear(struct zpc_ec_key *key, */ __attribute__((visibility("default"))) int zpc_ec_key_export(struct zpc_ec_key *key, unsigned char *seckey, - unsigned int *seckeylen); + size_t *seckeylen); /** * Export an EC public-key. @@ -180,7 +180,7 @@ int zpc_ec_key_export(struct zpc_ec_key *key, unsigned char *seckey, */ __attribute__((visibility("default"))) int zpc_ec_key_export_public(struct zpc_ec_key *key, unsigned char *pubkey, - unsigned int *pubkeylen); + size_t *pubkeylen); /** * Generate an EC secure-key. diff --git a/include/zpc/ecdsa_ctx.h b/include/zpc/ecdsa_ctx.h index 7607b46..e72d85c 100644 --- a/include/zpc/ecdsa_ctx.h +++ b/include/zpc/ecdsa_ctx.h @@ -58,8 +58,8 @@ int zpc_ecdsa_ctx_set_key(struct zpc_ecdsa_ctx *ctx, struct zpc_ec_key *key); */ __attribute__((visibility("default"))) int zpc_ecdsa_sign(struct zpc_ecdsa_ctx *ctx, - const unsigned char *hash, unsigned int hash_len, - unsigned char *signature, unsigned int *sig_len); + const unsigned char *hash, size_t hash_len, + unsigned char *signature, size_t *sig_len); /** * Do an ECDSA verify operation. @@ -72,8 +72,8 @@ int zpc_ecdsa_sign(struct zpc_ecdsa_ctx *ctx, */ __attribute__((visibility("default"))) int zpc_ecdsa_verify(struct zpc_ecdsa_ctx *ctx, - const unsigned char *hash, unsigned int hash_len, - const unsigned char *signature, unsigned int sig_len); + const unsigned char *hash, size_t hash_len, + const unsigned char *signature, size_t sig_len); /** * Free an ECDSA context. diff --git a/misc/dbg/decoder.gdb b/misc/dbg/decoder.gdb new file mode 100644 index 0000000..3d9d7d1 --- /dev/null +++ b/misc/dbg/decoder.gdb @@ -0,0 +1,5 @@ +set breakpoint pending on +break decoder_newctx +break decoder_freectx +break decoder_pem_hbkzpc_der_decode +break decoder_der_hbkzpc_ec_decode diff --git a/misc/dbg/kmgmt.gdb b/misc/dbg/kmgmt.gdb new file mode 100644 index 0000000..c08fb02 --- /dev/null +++ b/misc/dbg/kmgmt.gdb @@ -0,0 +1,6 @@ +set breakpoint pending on +break ec_new +break ec_free +break ec_load +break ec_has +# disable diff --git a/misc/dbg/store.gdb b/misc/dbg/store.gdb new file mode 100644 index 0000000..6bee834 --- /dev/null +++ b/misc/dbg/store.gdb @@ -0,0 +1,12 @@ +set breakpoint pending on +break store_ctx_init +break store_ctx_free +break store_ctx_expect +break store_open +break store_open_ex +break store_load +break store_eof +break store_close +break store_set_ctx_params +break store_settable_ctx_params +disable diff --git a/openssl.cnf.in b/openssl.cnf.in new file mode 100644 index 0000000..8d3edc0 --- /dev/null +++ b/openssl.cnf.in @@ -0,0 +1,28 @@ +HOME = . + +# Use this in order to automatically load providers. +openssl_conf = openssl_init + +config_diagnostics = 1 + +[openssl_init] +providers = provider_sect +alg_section = evp_properties + +[provider_sect] +default = default_sect +base = base_sect +hbkzpc = hbkzpc_sect + +[evp_properties] + +[base_sect] +activate = 1 + +[default_sect] +activate = 1 + +[hbkzpc_sect] +module = @ZPCPROVIDER_MODULE@ +identity = hbkzpc +activate = 1 diff --git a/s390x-tc-debian.cmake b/s390x-tc-debian.cmake index a4120c6..e5aabc6 100644 --- a/s390x-tc-debian.cmake +++ b/s390x-tc-debian.cmake @@ -1,4 +1,5 @@ set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_PROCESSOR s390x) set(CMAKE_C_COMPILER s390x-linux-gnu-gcc) set(CMAKE_CXX_COMPILER s390x-linux-gnu-g++) diff --git a/src/asn1.c b/src/asn1.c new file mode 100644 index 0000000..ca0749f --- /dev/null +++ b/src/asn1.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include "asn1.h" + +ASN1_SEQUENCE(ZPCHBK) = { + ASN1_EXP(ZPCHBK, desc, ASN1_VISIBLESTRING, 0), + ASN1_EXP(ZPCHBK, uri, ASN1_UTF8STRING, 1), +} ASN1_SEQUENCE_END(ZPCHBK); + +#include "asn1_gen.c" + +int i2d_ZPCHBK_bio(BIO *bp, const ZPCHBK *hbkp) +{ + return ASN1_i2d_bio_of(ZPCHBK, i2d_ZPCHBK, bp, hbkp); +} + +ZPCHBK *d2i_ZPCHBK_bio(BIO *bp, ZPCHBK **hbkpp) +{ + return ASN1_d2i_bio_of(ZPCHBK, ZPCHBK_new, d2i_ZPCHBK, + bp, hbkpp); +} diff --git a/src/asn1.h b/src/asn1.h new file mode 100644 index 0000000..21e91b4 --- /dev/null +++ b/src/asn1.h @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _ASN1_H +#define _ASN1_H + +#include +#include + +#define HBKZPC_PEM_STRING "ZPC HARDWARE BACKED KEY" +#define HBKZPC_DER_DESC "HBKZPC Provider URI v1.0" + +struct zpc_hardware_backed_key_sequence_st { + ASN1_VISIBLESTRING *desc; + ASN1_UTF8STRING *uri; +}; +typedef struct zpc_hardware_backed_key_sequence_st ZPCHBK; +DECLARE_ASN1_FUNCTIONS(ZPCHBK) + +int i2d_ZPCHBK_bio(BIO *bp, const ZPCHBK *hbkp); +ZPCHBK *d2i_ZPCHBK_bio(BIO *bp, ZPCHBK **hbkpp); + +DECLARE_PEM_write_bio(ZPCHBK, ZPCHBK) +DECLARE_PEM_read_bio(ZPCHBK, ZPCHBK) +#endif /* _ASN1_H */ diff --git a/src/asn1_gen.c.in b/src/asn1_gen.c.in new file mode 100644 index 0000000..1f719c0 --- /dev/null +++ b/src/asn1_gen.c.in @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include +#include +#include + +BEGIN: +IMPLEMENT_ASN1_FUNCTIONS(ZPCHBK) +IMPLEMENT_PEM_write_bio(ZPCHBK, ZPCHBK, HBKZPC_PEM_STRING, ZPCHBK) +IMPLEMENT_PEM_read_bio(ZPCHBK, ZPCHBK, HBKZPC_PEM_STRING, ZPCHBK) diff --git a/src/decoder.c b/src/decoder.c new file mode 100644 index 0000000..7f0696b --- /dev/null +++ b/src/decoder.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include +#include +#include + +#include "store_local.h" + +#include "provider.h" +#include "decoder.h" +#include "ossl.h" +#include "asn1.h" +#include "uri.h" +#include "map.h" + +#define DECODER_DER_STRUCTURE "zpchbk" +#define DECODER_PROP_PEM PROV_PROP",input=pem" +#define DECODER_PROP_DER PROV_PROP",input=der,structure="DECODER_DER_STRUCTURE + +#define DECODER_CARRYON OSSL_RV_TRUE +#define DECODER_STOP OSSL_RV_FALSE + +struct decoder_ctx { + struct provider_ctx *pctx; +}; + +static void *dec_newctx(void *vpctx) +{ + struct provider_ctx *pctx = (struct provider_ctx *)vpctx; + struct decoder_ctx *dctx; + + if (!pctx) + return NULL; + + dctx = OPENSSL_zalloc(sizeof(struct decoder_ctx)); + if (!dctx) + return NULL; + + dctx->pctx = pctx; + return dctx; +} + +static void dec_freectx(void *vdctx) +{ + OPENSSL_free(vdctx); +} + +static int dec_pem_der_decode(void *vdctx, OSSL_CORE_BIO *in, + int selection __unused, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *cb __unused, + void *cbarg __unused) +{ + char *label = NULL, *header = NULL; + struct decoder_ctx *dctx = vdctx; + unsigned char *data = NULL; + int rc = DECODER_CARRYON; + OSSL_PARAM params[3]; + long datalen; + BIO *bin; + + bin = BIO_new_from_core_bio(dctx->pctx->libctx, in); + if (!bin) + goto out; + + if (PEM_read_bio(bin, &label, &header, &data, &datalen) != OSSL_RV_OK || + strcmp (label, HBKZPC_PEM_STRING) != 0) + goto out; + + params[0] = OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA, + data, datalen); + params[1] = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_STRUCTURE, + DECODER_DER_STRUCTURE, 0); + params[2] = OSSL_PARAM_construct_end(); + rc = data_cb(params, data_cbarg); +out: + OPENSSL_free(header); + OPENSSL_free(label); + OPENSSL_free(data); + BIO_free(bin); + + return rc; +} + +static int dec_der_decode(struct decoder_ctx *dctx, OSSL_CORE_BIO *in, + int selection __unused, const char *data_type, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + const char *uri_data_type; + struct parsed_uri *puri = NULL; + int rv = DECODER_STOP; + ZPCHBK *hbk = NULL; + BIO *bin; + + bin = BIO_new_from_core_bio(dctx->pctx->libctx, in); + if (!bin) + goto out; + + if (!d2i_ZPCHBK_bio(bin, &hbk)) + goto out; + + puri = parsed_uri_new((const char *)ASN1_STRING_get0_data(hbk->uri)); + if (!puri) + goto out; + + rv = DECODER_CARRYON; + uri_data_type = alg2data_type(puri->origin_alg.value); + + if (OPENSSL_strcasecmp(data_type, uri_data_type) != 0) + goto out; + + rv = store_load_uri(dctx->pctx, puri, data_cb, data_cbarg, cb, cbarg); +out: + parsed_uri_free(puri); + OPENSSL_free(hbk); + BIO_free(bin); + return rv; +} + +static int dec_der_ec_decode(void *vdctx, OSSL_CORE_BIO *in, + int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + return dec_der_decode(vdctx, in, selection, PROV_NAME_EC, + data_cb, data_cbarg, cb, cbarg); +} + +static int dec_der_ed25519_decode(void *vdctx, OSSL_CORE_BIO *in, + int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + return dec_der_decode(vdctx, in, selection, PROV_NAME_ED25519, + data_cb, data_cbarg, cb, cbarg); +} + +static int dec_der_ed448_decode(void *vdctx, OSSL_CORE_BIO *in, + int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) +{ + return dec_der_decode(vdctx, in, selection, PROV_NAME_ED448, + data_cb, data_cbarg, cb, cbarg); +} + +static const OSSL_DISPATCH decoder_der_ec_functions[] = { + DISPATCH_DEFN(DECODER, NEWCTX, dec_newctx), + DISPATCH_DEFN(DECODER, FREECTX, dec_freectx), + DISPATCH_DEFN(DECODER, DECODE, dec_der_ec_decode), + DISPATCH_END, +}; + +static const OSSL_DISPATCH decoder_der_ed25519_functions[] = { + DISPATCH_DEFN(DECODER, NEWCTX, dec_newctx), + DISPATCH_DEFN(DECODER, FREECTX, dec_freectx), + DISPATCH_DEFN(DECODER, DECODE, dec_der_ed25519_decode), + DISPATCH_END, +}; + +static const OSSL_DISPATCH decoder_der_ed448_functions[] = { + DISPATCH_DEFN(DECODER, NEWCTX, dec_newctx), + DISPATCH_DEFN(DECODER, FREECTX, dec_freectx), + DISPATCH_DEFN(DECODER, DECODE, dec_der_ed448_decode), + DISPATCH_END, +}; + +static const OSSL_DISPATCH decoder_pem_der_functions[] = { + DISPATCH_DEFN(DECODER, NEWCTX, dec_newctx), + DISPATCH_DEFN(DECODER, FREECTX, dec_freectx), + DISPATCH_DEFN(DECODER, DECODE, dec_pem_der_decode), + DISPATCH_END, +}; + +const OSSL_ALGORITHM decoder_ops[] = { + ALGORITHM_DEFN("DER", DECODER_PROP_PEM, decoder_pem_der_functions, NULL), + ALGORITHM_DEFN(PROV_NAME_EC, DECODER_PROP_DER, decoder_der_ec_functions, NULL), + ALGORITHM_DEFN(PROV_NAME_ED25519, DECODER_PROP_DER, decoder_der_ed25519_functions, NULL), + ALGORITHM_DEFN(PROV_NAME_ED448, DECODER_PROP_DER, decoder_der_ed448_functions, NULL), + ALGORITHM_END, +}; diff --git a/src/decoder.h b/src/decoder.h new file mode 100644 index 0000000..3c40016 --- /dev/null +++ b/src/decoder.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _DECODER_H +#define _DECODER_H + +#include + +extern const OSSL_ALGORITHM decoder_ops[]; + +#endif /* _DECODER_H */ diff --git a/src/ecc_key.c b/src/ecc_key.c index 8cbe6f5..a6fad19 100644 --- a/src/ecc_key.c +++ b/src/ecc_key.c @@ -43,13 +43,13 @@ const u16 curve2pvsecret_type[] = { static void __ec_key_reset(struct zpc_ec_key *); static int ec_key_check_ep11_spki(const struct zpc_ec_key *ec_key, - const unsigned char *spki, unsigned int spki_len); + const unsigned char *spki, size_t spki_len); static void ec_key_use_maced_spki_from_buf(struct zpc_ec_key *ec_key, - const unsigned char *spki, unsigned int spki_len); + const unsigned char *spki, size_t spki_len); static int ec_key_use_raw_spki_from_buf(struct zpc_ec_key *ec_key, - const unsigned char *spki, unsigned int spki_len); + const unsigned char *spki, size_t spki_len); static int ec_key_spki_has_valid_mkvp(const struct zpc_ec_key *ec_key, - const unsigned char *spki, unsigned int spki_len); + const unsigned char *spki, size_t spki_len); static int ec_key_blob_has_valid_mkvp(struct zpc_ec_key *ec_key, const unsigned char *buf); static int ec_key_blob_is_pkey_extractable(struct zpc_ec_key *ec_key, @@ -492,7 +492,7 @@ int zpc_ec_key_set_apqns(struct zpc_ec_key *ec_key, const char *apqns[]) int zpc_ec_key_export(struct zpc_ec_key *ec_key, unsigned char *buf, - unsigned int *buflen) + size_t *buflen) { int rc, rv; @@ -558,7 +558,7 @@ zpc_ec_key_export(struct zpc_ec_key *ec_key, unsigned char *buf, } int zpc_ec_key_export_public(struct zpc_ec_key *ec_key, - unsigned char *buf, unsigned int *buflen) + unsigned char *buf, size_t *buflen) { int rc, rv; @@ -613,7 +613,7 @@ int zpc_ec_key_export_public(struct zpc_ec_key *ec_key, } int zpc_ec_key_import(struct zpc_ec_key *ec_key, const unsigned char *buf, - unsigned int buflen) + size_t buflen) { target_t target; int rc, rv, seclen; @@ -789,8 +789,8 @@ int zpc_ec_key_import(struct zpc_ec_key *ec_key, const unsigned char *buf, } int zpc_ec_key_import_clear(struct zpc_ec_key *ec_key, const unsigned char *pubkey, - unsigned int publen, const unsigned char *privkey, - unsigned int privlen) + size_t publen, const unsigned char *privkey, + size_t privlen) { unsigned int flags; int rc, rv; @@ -1057,7 +1057,7 @@ int zpc_ec_key_generate(struct zpc_ec_key *ec_key) int zpc_ec_key_reencipher(struct zpc_ec_key *ec_key, unsigned int method) { struct ec_key reenc; - unsigned int seckeylen; + size_t seckeylen; target_t target; int rv, rc = ZPC_ERROR_APQNSNOTSET; size_t i; @@ -1343,8 +1343,8 @@ int ec_key_pvsec2prot(struct zpc_ec_key *ec_key) } int ec_key_clr2sec(struct zpc_ec_key *ec_key, unsigned int flags, - const unsigned char *pubkey, unsigned int publen, - const unsigned char *privkey, unsigned int privlen) + const unsigned char *pubkey, size_t publen, + const unsigned char *privkey, size_t privlen) { target_t target; int rv, rc = ZPC_ERROR_APQNSNOTSET; @@ -1400,7 +1400,7 @@ int ec_key_sec2prot(struct zpc_ec_key *ec_key, enum ec_key_sec sec) { struct pkey_kblob2pkey3 io; struct ec_key *key = NULL; - unsigned int keybuf_len; + size_t keybuf_len; int rc, i; assert(sec == EC_KEY_SEC_OLD || sec == EC_KEY_SEC_CUR); @@ -1442,7 +1442,7 @@ int ec_key_sec2prot(struct zpc_ec_key *ec_key, enum ec_key_sec sec) } int ec_key_clr2prot(struct zpc_ec_key *ec_key, const unsigned char *privkey, - unsigned int privlen) + size_t privlen) { struct pkey_kblob2pkey3 io; unsigned char buf[sizeof(struct clearkeytoken) + 80]; @@ -1529,7 +1529,7 @@ int ec_key_spki_valid_for_pubkey(const struct zpc_ec_key *ec_key, } static int ec_key_check_ep11_spki(const struct zpc_ec_key *ec_key, - const unsigned char *spki, unsigned int spki_len) + const unsigned char *spki, size_t spki_len) { if (spki_len > curve2macedspkilen[ec_key->curve] && spki_len < curve2rawspkilen[ec_key->curve]) @@ -1550,7 +1550,7 @@ static int ec_key_check_ep11_spki(const struct zpc_ec_key *ec_key, } static void ec_key_use_maced_spki_from_buf(struct zpc_ec_key *ec_key, - const unsigned char *spki, unsigned int spki_len) + const unsigned char *spki, size_t spki_len) { memcpy(ec_key->pub.spki, spki, spki_len); ec_key->pub.spkilen = spki_len; @@ -1563,7 +1563,7 @@ static void ec_key_use_maced_spki_from_buf(struct zpc_ec_key *ec_key, } static int ec_key_use_raw_spki_from_buf(struct zpc_ec_key *ec_key, - const unsigned char *spki, unsigned int spki_len) + const unsigned char *spki, size_t spki_len) { target_t target; int rc = -EIO, rv; @@ -1600,7 +1600,7 @@ static int ec_key_use_raw_spki_from_buf(struct zpc_ec_key *ec_key, } static int ec_key_spki_has_valid_mkvp(const struct zpc_ec_key *ec_key, - const unsigned char *spki, unsigned int spki_len) + const unsigned char *spki, size_t spki_len) { (void)spki_len; /* suppress unused parm compiler warning */ @@ -1618,7 +1618,7 @@ static int ec_key_spki_has_valid_mkvp(const struct zpc_ec_key *ec_key, static int ec_key_blob_has_valid_mkvp(struct zpc_ec_key *ec_key, const unsigned char *buf) { const unsigned char *mkvp; - unsigned int mkvp_len; + size_t mkvp_len; if (ec_key->mkvp_set == 0) return 1; /* cannot judge */ diff --git a/src/ecc_key_local.h b/src/ecc_key_local.h index e5ca013..22a0369 100644 --- a/src/ecc_key_local.h +++ b/src/ecc_key_local.h @@ -59,10 +59,10 @@ struct zpc_ec_key { }; int ec_key_clr2sec(struct zpc_ec_key *ec_key, unsigned int flags, - const unsigned char *pubkey, unsigned int publen, - const unsigned char *privkey, unsigned int privlen); + const unsigned char *pubkey, size_t publen, + const unsigned char *privkey, size_t privlen); int ec_key_sec2prot(struct zpc_ec_key *, enum ec_key_sec sec); int ec_key_check(const struct zpc_ec_key *); int ec_key_clr2prot(struct zpc_ec_key *ec_key, const unsigned char *privkey, - unsigned int privlen); + size_t privlen); #endif diff --git a/src/ecdsa_ctx.c b/src/ecdsa_ctx.c index d5aa853..3bf9eb5 100644 --- a/src/ecdsa_ctx.c +++ b/src/ecdsa_ctx.c @@ -27,19 +27,19 @@ extern const size_t curve2siglen[]; static int __ec_sign(struct zpc_ecdsa_ctx *, const unsigned char *hash, - unsigned int hash_len, unsigned char *signature, unsigned int *sig_len); + size_t hash_len, unsigned char *signature, size_t *sig_len); static int __ec_verify(struct zpc_ecdsa_ctx *, const unsigned char *hash, - unsigned int hash_len, const unsigned char *signature, unsigned int sig_len); + size_t hash_len, const unsigned char *signature, size_t sig_len); static void __ec_ctx_reset(struct zpc_ecdsa_ctx *); static void __copy_hash_to_sign_param(struct zpc_ecdsa_ctx *ctx, - const unsigned char *hash, unsigned int hash_len); + const unsigned char *hash, size_t hash_len); static void __get_signature_from_sign_param(struct zpc_ecdsa_ctx *ctx, - unsigned char *signature, unsigned int sig_len); + unsigned char *signature, size_t sig_len); static void __copy_pubkey_to_verify_param(struct zpc_ecdsa_ctx *ctx); static void __copy_protkey_to_sign_param(struct zpc_ecdsa_ctx *ctx); static void __copy_args_to_verify_param(struct zpc_ecdsa_ctx *ctx, - const unsigned char *hash, unsigned int hash_len, - const unsigned char *signature, unsigned int sig_len); + const unsigned char *hash, size_t hash_len, + const unsigned char *signature, size_t sig_len); static void __cleanup_verify_param(struct zpc_ecdsa_ctx *ctx); static void __cleanup_sign_param(struct zpc_ecdsa_ctx *ctx); @@ -182,8 +182,8 @@ int zpc_ecdsa_ctx_set_key(struct zpc_ecdsa_ctx *ec_ctx, struct zpc_ec_key *ec_ke } int zpc_ecdsa_sign(struct zpc_ecdsa_ctx *ctx, - const unsigned char *hash, unsigned int hash_len, - unsigned char *signature, unsigned int *sig_len) + const unsigned char *hash, size_t hash_len, + unsigned char *signature, size_t *sig_len) { int rc, rv, i; @@ -274,8 +274,8 @@ int zpc_ecdsa_sign(struct zpc_ecdsa_ctx *ctx, } int zpc_ecdsa_verify(struct zpc_ecdsa_ctx *ctx, - const unsigned char *hash, unsigned int hash_len, - const unsigned char *signature, unsigned int sig_len) + const unsigned char *hash, size_t hash_len, + const unsigned char *signature, size_t sig_len) { int rc, rv; @@ -358,8 +358,8 @@ void zpc_ecdsa_ctx_free(struct zpc_ecdsa_ctx **ctx) } static int __ec_sign(struct zpc_ecdsa_ctx *ctx, - const unsigned char *hash, unsigned int hash_len, - unsigned char *signature, unsigned int *sig_len) + const unsigned char *hash, size_t hash_len, + unsigned char *signature, size_t *sig_len) { void *param; int rc, cc; @@ -391,8 +391,8 @@ static int __ec_sign(struct zpc_ecdsa_ctx *ctx, } static int __ec_verify(struct zpc_ecdsa_ctx *ctx, - const unsigned char *hash, unsigned int hash_len, - const unsigned char *signature, unsigned int sig_len) + const unsigned char *hash, size_t hash_len, + const unsigned char *signature, size_t sig_len) { void *param; int rc = ZPC_ERROR_EC_SIGNATURE_INVALID, cc; @@ -431,7 +431,7 @@ static void __ec_ctx_reset(struct zpc_ecdsa_ctx *ctx) } static void __copy_hash_to_sign_param(struct zpc_ecdsa_ctx *ctx, - const unsigned char *hash, unsigned int hash_len) + const unsigned char *hash, size_t hash_len) { switch (ctx->ec_key->curve) { case ZPC_EC_CURVE_P256: @@ -455,7 +455,7 @@ static void __copy_hash_to_sign_param(struct zpc_ecdsa_ctx *ctx, } static void __get_signature_from_sign_param(struct zpc_ecdsa_ctx *ctx, - unsigned char *signature, unsigned int sig_len) + unsigned char *signature, size_t sig_len) { switch (ctx->ec_key->curve) { case ZPC_EC_CURVE_P256: @@ -538,8 +538,8 @@ static void __copy_protkey_to_sign_param(struct zpc_ecdsa_ctx *ctx) } static void __copy_args_to_verify_param(struct zpc_ecdsa_ctx *ctx, - const unsigned char *hash, unsigned int hash_len, - const unsigned char *signature, unsigned int sig_len) + const unsigned char *hash, size_t hash_len, + const unsigned char *signature, size_t sig_len) { switch (ctx->ec_key->curve) { case ZPC_EC_CURVE_P256: diff --git a/src/keymgmt.c b/src/keymgmt.c new file mode 100644 index 0000000..411e351 --- /dev/null +++ b/src/keymgmt.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include +#include +#include +#include + +#include +#include +#include + +#include "provider.h" +#include "object.h" +#include "ossl.h" +#include "map.h" + +static struct { + const char *str; + int type; +} type_map[] = { + { .str = "uv", .type = ZPC_EC_KEY_TYPE_PVSECRET, }, + { .str = "cca", .type = ZPC_EC_KEY_TYPE_CCA, }, + { .str = "ep11", .type = ZPC_EC_KEY_TYPE_EP11, }, + { 0 }, +}; + +static int str2type(const char *str) +{ + for (int i = 0; type_map[i].str; i++) { + if (OPENSSL_strcasecmp(type_map[i].str, str) == 0) + return type_map[i].type; + } + return 0; +} + +#define SPKI_HDR_SIZE (4) +static int zpc_key_update_pubkey(struct zpc_ec_key *key, unsigned char *hex, + size_t hexlen) +{ + const unsigned char *spki; + size_t spkilen; + + if (hexlen < SPKI_HDR_SIZE || + hex[0] != 0x03 || + hex[3] != 0x04) + return ZPC_ERROR_NOTSUP; + + spki = hex + SPKI_HDR_SIZE; + spkilen = hexlen - SPKI_HDR_SIZE; + + return zpc_ec_key_import_clear(key, spki, spkilen, NULL, 0); +} + +static int zpc_key_update(struct obj *obj) +{ + struct zpc_ec_key *key = NULL; + int rc; + + if ((rc = zpc_ec_key_alloc(&key))) + goto err; + + if ((rc = zpc_ec_key_set_type(key, str2type(obj->origin_type)))) + goto err; + + if ((rc = zpc_ec_key_set_curve(key, obj_key_curve(obj)))) + goto err; + + if ((rc = zpc_ec_key_import(key, obj->origin_blob.p, obj->origin_blob.plen))) + goto err; + + if (strcmp(obj->origin_type, "uv") == 0) { + /* uv only: import spki */ + if ((rc = zpc_key_update_pubkey(key, obj->origin_spki.p, + obj->origin_spki.plen))) + goto err; + } else { + if (obj->mkvp && (rc = zpc_ec_key_set_mkvp(key, obj->mkvp))) + goto err; + /* TODO: apqns */ + } + + obj->ec_key = key; + return OSSL_RV_OK; +err: + PROV_ERR_raise(obj->pctx, rc); + zpc_ec_key_free(&key); + return OSSL_RV_ERR; +} + +#define DECL_KMGMT_FN(tname, name) DECL_DISPATCH_FUNC(keymgmt, tname, name) +DECL_KMGMT_FN(new, ec_new); +DECL_KMGMT_FN(free, ec_free); +DECL_KMGMT_FN(load, ec_load); +DECL_KMGMT_FN(has, ec_has); +#undef DECL_SKMGMT_FN + +static void *ec_new(void *provctx) +{ + return obj_new((struct provider_ctx *)provctx); +} + +static void ec_free(void *keydata) +{ + struct obj *obj = (struct obj *)keydata; + + zpc_ec_key_free(&obj->ec_key); + obj_free(obj); +} + +static void *ec_load(const void *reference, size_t reference_sz) +{ + struct obj *obj; + + if (!reference || reference_sz != sizeof(struct obj)) + return NULL; + obj = (struct obj *)reference; + + if (zpc_key_update(obj) == OSSL_RV_ERR) + return NULL; + + return obj_get(obj); +} + +static int ec_has(const void *keydata, int selection) +{ + struct obj *obj = (struct obj *)keydata; + int rv = OSSL_RV_FALSE; + + if (!obj) + return OSSL_RV_ERR; + + if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) { + if (obj->origin_blob.p && obj->ec_key) + rv = OSSL_RV_TRUE; + } else if (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) { + if (obj->origin_spki.p) + rv = OSSL_RV_TRUE; + } + + return rv; +} + +static const char *ec_query_operation_name(int operation_id) +{ + switch (operation_id) { + case OSSL_OP_SIGNATURE: + return "ECDSA"; + default: + break; + } + + return NULL; +} + +static const OSSL_DISPATCH keymgmt_ec_functions[] = { + DISPATCH_DEFN(KEYMGMT, NEW, ec_new), + DISPATCH_DEFN(KEYMGMT, FREE, ec_free), + DISPATCH_DEFN(KEYMGMT, LOAD, ec_load), + DISPATCH_DEFN(KEYMGMT, HAS, ec_has), + DISPATCH_DEFN(KEYMGMT, QUERY_OPERATION_NAME, ec_query_operation_name), + DISPATCH_END, +}; + +const OSSL_ALGORITHM keymgmt_ops[] = { + ALGORITHM_DEFN(PROV_NAME_EC, PROV_PROP, keymgmt_ec_functions, + PROV_DESC_EC), + ALGORITHM_END, +}; diff --git a/src/keymgmt.h b/src/keymgmt.h new file mode 100644 index 0000000..359ec42 --- /dev/null +++ b/src/keymgmt.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _KEYMGMT_H +#define _KEYMGMT_H + +#include + +extern const OSSL_ALGORITHM keymgmt_ops[]; + +#endif /* _KEYMGMT_H */ diff --git a/src/map.c b/src/map.c new file mode 100644 index 0000000..049790f --- /dev/null +++ b/src/map.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include +#include +#include +#include + +#include "provider.h" +#include "map.h" + +static struct { + const char *alg; + union { + int key_size; + zpc_ec_curve_t key_curve; + }; + int object_type; + char *data_type; +} alg_map[] = { + { + .alg = SN_X9_62_prime256v1, + .key_curve = ZPC_EC_CURVE_P256, + .object_type = OSSL_OBJECT_PKEY, + .data_type = PROV_NAME_EC, + }, { + .alg = "1.2.840.10045.3.1.7", + .key_curve = ZPC_EC_CURVE_P256, + .object_type = OSSL_OBJECT_PKEY, + .data_type = PROV_NAME_EC, + }, { + .alg = SN_secp384r1, + .key_curve = ZPC_EC_CURVE_P384, + .object_type = OSSL_OBJECT_PKEY, + .data_type = PROV_NAME_EC, + }, { + .alg = "1.3.132.0.34", + .key_curve = ZPC_EC_CURVE_P384, + .object_type = OSSL_OBJECT_PKEY, + .data_type = PROV_NAME_EC, + }, { + .alg = SN_secp521r1, + .key_curve = ZPC_EC_CURVE_P521, + .object_type = OSSL_OBJECT_PKEY, + .data_type = PROV_NAME_EC, + }, { + .alg = "1.3.132.0.35", + .key_curve = ZPC_EC_CURVE_P521, + .object_type = OSSL_OBJECT_PKEY, + .data_type = PROV_NAME_EC, + }, { + .alg = SN_ED25519, + .key_curve = ZPC_EC_CURVE_ED25519, + .object_type = OSSL_OBJECT_PKEY, + .data_type = PROV_NAME_ED25519, + }, { + .alg = "1.3.101.112", + .key_curve = ZPC_EC_CURVE_ED25519, + .object_type = OSSL_OBJECT_PKEY, + .data_type = PROV_NAME_ED25519, + }, { + .alg = SN_ED448, + .key_curve = ZPC_EC_CURVE_ED448, + .object_type = OSSL_OBJECT_PKEY, + .data_type = PROV_NAME_ED448, + }, { + .alg = "1.3.101.113", + .key_curve = ZPC_EC_CURVE_ED448, + .object_type = OSSL_OBJECT_PKEY, + .data_type = PROV_NAME_ED448, + }, { 0 }, +}; + +char *alg2data_type(const char *alg) +{ + char *rv = NULL; + size_t i; + + if (!alg) + return rv; + + for (i = 0; alg_map[i].alg; i++) { + if (OPENSSL_strcasecmp(alg_map[i].alg, alg) == 0) { + rv = alg_map[i].data_type; + break; + } + } + + return rv; +} + +int alg2object_type(const char *alg) +{ + int rv = OSSL_OBJECT_UNKNOWN; + size_t i; + + if (!alg) + return rv; + + for (i = 0; alg_map[i].alg; i++) { + if (OPENSSL_strcasecmp(alg_map[i].alg, alg) == 0) { + rv = alg_map[i].object_type; + break; + } + } + + return rv; +} + +zpc_ec_curve_t alg2key_curve(const char *alg) +{ + zpc_ec_curve_t rv = ZPC_EC_CURVE_INVALID; + size_t i; + + if (!alg) + return rv; + + for (i = 0; alg_map[i].alg; i++) { + if (OPENSSL_strcasecmp(alg_map[i].alg, alg) == 0) { + rv = alg_map[i].key_curve; + break; + } + } + + return rv; +} + +int alg2key_size(const char *alg) +{ + int rv = 0; + size_t i; + + if (!alg) + return rv; + + for (i = 0; alg_map[i].alg; i++) { + if (OPENSSL_strcasecmp(alg_map[i].alg, alg) == 0) { + rv = alg_map[i].key_size; + break; + } + } + + return rv; +} + +char *obj_data_type(const struct obj *obj) +{ + const char *alg = obj ? obj->origin_alg : NULL; + return alg2data_type(alg); +} + +int obj_object_type(const struct obj *obj) +{ + const char *alg = obj ? obj->origin_alg : NULL; + return alg2object_type(alg); +} + +zpc_ec_curve_t obj_key_curve(const struct obj *obj) +{ + const char *alg = obj ? obj->origin_alg : NULL; + return alg2key_curve(alg); +} + +int obj_key_size(const struct obj *obj) +{ + const char *alg = obj ? obj->origin_alg : NULL; + return alg2key_size(alg); +} diff --git a/src/map.h b/src/map.h new file mode 100644 index 0000000..1993b4e --- /dev/null +++ b/src/map.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _MAP_H +#define _MAP_H + +#include + +#include "object.h" + +char *alg2data_type(const char *alg); +int alg2object_type(const char *alg); +zpc_ec_curve_t alg2key_curve(const char *alg); +int alg2key_size(const char *alg); + +char *obj_data_type(const struct obj *alg); +int obj_object_type(const struct obj *alg); +zpc_ec_curve_t obj_key_curve(const struct obj *alg); +int obj_key_size(const struct obj *alg); + +#endif /* _MAP_H */ diff --git a/src/object.c b/src/object.c new file mode 100644 index 0000000..241d86b --- /dev/null +++ b/src/object.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include + +#include + +#include "object.h" + +static void _obj_free(struct obj *obj) +{ + zpc_ec_key_free(&obj->ec_key); + + OPENSSL_free(obj->origin_type); + OPENSSL_free(obj->origin_alg); + OPENSSL_free(obj->origin_blob.p); + OPENSSL_free(obj->origin_flags.p); + OPENSSL_free(obj->origin_spki.p); + OPENSSL_free(obj->apqns); + OPENSSL_free(obj->mkvp); + + OPENSSL_free(obj->id); + OPENSSL_free(obj); +} + +void obj_free(struct obj *obj) +{ + if (!obj) + return; + + if (__atomic_sub_fetch(&obj->refcnt, 1, __ATOMIC_SEQ_CST)) + return; + + _obj_free(obj); +} + +struct obj *obj_get(struct obj *obj) +{ + if (!obj) + return NULL; + + __atomic_fetch_add(&obj->refcnt, 1, __ATOMIC_SEQ_CST); + return obj; +} + +struct obj *obj_new(struct provider_ctx *pctx) +{ + struct obj *obj; + + obj = OPENSSL_zalloc(sizeof(struct obj)); + if (!obj) + return NULL; + + obj->pctx = pctx; + + return obj_get(obj); +} diff --git a/src/object.h b/src/object.h new file mode 100644 index 0000000..ddc3536 --- /dev/null +++ b/src/object.h @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _OBJECT_H +#define _OBJECT_H + +#include + +#include "provider.h" + +#define OBJ_PARAMS_MAX (8 + 1) + +struct data { + size_t plen; + unsigned char *p; +}; + +struct obj { + /* common */ + unsigned int refcnt; + struct provider_ctx *pctx; + + /* prototype - will be replaced by origin_blob */ + char *id; + + /* zpc keys */ + struct zpc_ec_key *ec_key; + + /* origin path attrs */ + char *origin_type; + char *origin_alg; + struct data origin_blob; + struct data origin_flags; + struct data origin_spki; + + /* origin qeuery attrs */ + char *apqns; + char *mkvp; +}; + +struct obj *obj_new(struct provider_ctx *pctx); +struct obj *obj_get(struct obj *obj); +void obj_free(struct obj *obj); + +#endif /* _OBJECT_H */ diff --git a/src/ossl.h b/src/ossl.h new file mode 100644 index 0000000..c671af1 --- /dev/null +++ b/src/ossl.h @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _OSSL_H +#define _OSSL_H + +#include + +#define OSSL_RV_TRUE (1) +#define OSSL_RV_FALSE (0) +#define OSSL_RV_OK (1) +#define OSSL_RV_ERR (0) + +#define ALGORITHM_DEFN(name, prop, fn, desc) { name, prop, fn, desc } +#define ALGORITHM_END { NULL, NULL, NULL, NULL } + +#define DISPATCH_DEFN(MODULE, NAME, name) { OSSL_FUNC_##MODULE##_##NAME, (void (*)(void))name } +#define DISPATCH_END { 0, NULL } + +#define DECL_DISPATCH_FUNC(MODULE, NAME, name) \ + static OSSL_FUNC_##MODULE##_##NAME##_fn name + +#endif /* _OSSL_H */ diff --git a/src/provider.c b/src/provider.c new file mode 100644 index 0000000..bb92fa3 --- /dev/null +++ b/src/provider.c @@ -0,0 +1,380 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include +#include +#include +#include +#include + +#include + +#include "ossl.h" +#include "provider.h" +#include "store.h" +#include "keymgmt.h" +#include "signature.h" +#include "tls.h" +#include "decoder.h" + +#define C(str) (void *)(str) +static const OSSL_ITEM reason_strings[] = { + { ZPC_ERROR_ARG1NULL, + C("argument 1 NULL") }, + { ZPC_ERROR_ARG2NULL, + C("argument 2 NULL") }, + { ZPC_ERROR_ARG3NULL, + C("argument 3 NULL") }, + { ZPC_ERROR_ARG4NULL, + C("argument 4 NULL") }, + { ZPC_ERROR_ARG5NULL, + C("argument 5 NULL") }, + { ZPC_ERROR_ARG6NULL, + C("argument 6 NULL") }, + { ZPC_ERROR_ARG7NULL, + C("argument 7 NULL") }, + { ZPC_ERROR_ARG8NULL, + C("argument 8 NULL") }, + { ZPC_ERROR_ARG1RANGE, + C("argument 1 out of range") }, + { ZPC_ERROR_ARG2RANGE, + C("argument 2 out of range") }, + { ZPC_ERROR_ARG3RANGE, + C("argument 3 out of range") }, + { ZPC_ERROR_ARG4RANGE, + C("argument 4 out of range") }, + { ZPC_ERROR_ARG5RANGE, + C("argument 5 out of range") }, + { ZPC_ERROR_ARG6RANGE, + C("argument 6 out of range") }, + { ZPC_ERROR_ARG7RANGE, + C("argument 7 out of range") }, + { ZPC_ERROR_ARG8RANGE, + C("argument 8 out of range") }, + { ZPC_ERROR_MALLOC, + C("malloc failed") }, + { ZPC_ERROR_KEYNOTSET, + C("no key is set") }, + { ZPC_ERROR_KEYSIZE, + C("invalid key size") }, + { ZPC_ERROR_IVNOTSET, + C("IV not set") }, + { ZPC_ERROR_IVSIZE, + C("invalid IV size") }, + { ZPC_ERROR_TAGSIZE, + C("invalid tag size") }, + { ZPC_ERROR_TAGMISMATCH, + C("tag mismatch") }, + { ZPC_ERROR_HWCAPS, + C("function not supported") }, + { ZPC_ERROR_SMALLOUTBUF, + C("output buffer too small") }, + { ZPC_ERROR_APQNSNOTSET, + C("APQNs not set") }, + { ZPC_ERROR_KEYTYPE, + C("invalid key type") }, + { ZPC_ERROR_KEYTYPENOTSET, + C("key type not set") }, + { ZPC_ERROR_IOCTLGENSECK2, + C("PKEY_GENSECK2 ioctl failed") }, + { ZPC_ERROR_IOCTLCLR2SECK2, + C("PKEY_CLR2SECK2 ioctl failed") }, + { ZPC_ERROR_IOCTLBLOB2PROTK2, + C("PKEY_BLOB2PROTK2 ioctl failed") }, + { ZPC_ERROR_WKVPMISMATCH, + C("wrapping key verification pattern mismatch") }, + { ZPC_ERROR_DEVPKEY, + C("opening /dev/pkey failed") }, + { ZPC_ERROR_CLEN, + C("ciphertext too long") }, + { ZPC_ERROR_MLEN, + C("message too long") }, + { ZPC_ERROR_AADLEN, + C("additional authenticated data too long") }, + { ZPC_ERROR_PARSE, + C("parse error") }, + { ZPC_ERROR_APQNNOTFOUND, + C("APQN not found in APQN list") }, + { ZPC_ERROR_MKVPLEN, + C("MKVP too long") }, + { ZPC_ERROR_INITLOCK, + C("initializing a lock failed") }, + { ZPC_ERROR_OBJINUSE, + C("object is in use") }, + { ZPC_ERROR_IOCTLAPQNS4KT, + C("PKEY_APQNS4KT ioctl failed") }, + { ZPC_ERROR_KEYSIZENOTSET, + C("key-size not set") }, + { ZPC_ERROR_IOCTLGENPROTK, + C("PKEY_GENPROTK ioctl failed") }, + { ZPC_ERROR_PROTKEYONLY, + C("protected-key only") }, + { ZPC_ERROR_KEYSEQUAL, + C("keys are equal") }, + { ZPC_ERROR_NOTSUP, + C("not supported") }, + { ZPC_ERROR_EC_INVALID_CURVE, + C("Invalid EC curve") }, + { ZPC_ERROR_EC_CURVE_NOTSET, + C("EC curve not set") }, + { ZPC_ERROR_EC_PRIVKEY_NOTSET, + C("EC private key not set") }, + { ZPC_ERROR_EC_PUBKEY_NOTSET, + C("EC public key not set") }, + { ZPC_ERROR_EC_NO_KEY_PARTS, + C("No EC key parts given") }, + { ZPC_ERROR_EC_SIGNATURE_INVALID, + C("signature invalid") }, + { ZPC_ERROR_IOCTLBLOB2PROTK3, + C("PKEY_BLOB2PROTK3 ioctl failed") }, + { ZPC_ERROR_IOCTLCLR2SECK3, + C("PKEY_CLR2SECK3 ioctl failed") }, + { ZPC_ERROR_APQNS_NOTSET, + C("No APQNs set for this key,but required for this operation") }, + { ZPC_ERROR_EC_SIGNATURE_LENGTH, + C("Signature length is invalid for this EC key") }, + { ZPC_ERROR_EC_KEY_PARTS_INCONSISTENT, + C("Given public/private key parts are inconsistent") }, + { ZPC_ERROR_CCA_HOST_LIB_NOT_AVAILABLE, + C("CCA host library not available,but required for this operation") }, + { ZPC_ERROR_EP11_HOST_LIB_NOT_AVAILABLE, + C("EP11 host library not available,but required for this operation") }, + { ZPC_ERROR_EC_PUBKEY_LENGTH, + C("The given EC public key length is invalid") }, + { ZPC_ERROR_EC_PRIVKEY_LENGTH, + C("The given EC private key length is invalid") }, + { ZPC_ERROR_EC_NO_CCA_SECUREKEY_TOKEN, + C("The given buffer does not contain a valid CCA secure key token") }, + { ZPC_ERROR_EC_NO_EP11_SECUREKEY_TOKEN, + C("The given buffer does not contain a valid EP11 secure key token") }, + { ZPC_ERROR_EC_EP11_SPKI_INVALID_LENGTH, + C("The imported buffer contains an EP11 SPKI with an invalid length") }, + { ZPC_ERROR_EC_EP11_SPKI_INVALID_CURVE, + C("The imported buffer contains an EP11 SPKI with an invalid EC curve") }, + { ZPC_ERROR_EC_EP11_SPKI_INVALID_PUBKEY, + C("The imported buffer contains an EP11 SPKI with an invalid public key") }, + { ZPC_ERROR_EC_EP11_SPKI_INVALID_MKVP, + C("The imported buffer contains an EP11 MACed SPKI with an invalid MKVP") }, + { ZPC_ERROR_BLOB_NOT_PKEY_EXTRACTABLE, + C("The imported buffer contains a key blob that cannot be transformed into a protected key.") }, + { ZPC_ERROR_APQNS_INVALID_VERSION, + C("At least one APQN version is invalid for this function.") }, + { ZPC_ERROR_AES_NO_EP11_SECUREKEY_TOKEN, + C("The given buffer does not contain a valid EP11 AES secure key token.") }, + { ZPC_ERROR_AES_NO_CCA_DATAKEY_TOKEN, + C("The given buffer does not contain a valid CCA datakey token") }, + { ZPC_ERROR_AES_NO_CCA_CIPHERKEY_TOKEN, + C("The given buffer does not contain a valid CCA cipherkey token") }, + { ZPC_ERROR_RNDGEN, + C("Error creating random bytes") }, + { ZPC_ERROR_GCM_IV_CREATED_INTERNALLY, + C("Invalid usage of a gcm context with an internally created iv") }, + { ZPC_ERROR_UV_PVSECRETS_NOT_AVAILABLE, + C("Support for UV retrievable secrets is not available,but required for this function.") }, + { ZPC_ERROR_PVSECRET_TYPE_NOT_SUPPORTED, + C("The given pvsecret type is not supported by libzpc.") }, + { ZPC_ERROR_PVSECRET_ID_NOT_FOUND_IN_UV_OR_INVALID_TYPE, + C("The given pvsecret ID does either not exist or belongs to a different secret type.") }, + { ZPC_ERROR_IOCTLVERIFYKEY2, + C("PKEY_VERIFYKEY2 ioctl failed.") }, + { ZPC_ERROR_HMAC_HASH_FUNCTION_NOTSET, + C("HMAC hash function not set.") }, + { ZPC_ERROR_HMAC_HASH_FUNCTION_INVALID, + C("HMAC hash function invalid.") }, + { ZPC_ERROR_HMAC_KEYGEN_VIA_SYSFS, + C("HMAC key generation via sysfs attributes failed.") }, + { ZPC_ERROR_CREATE_BLOCKSIZED_KEY, + C("Creating a block-sized HMAC key failed.") }, + { ZPC_ERROR_XTS_KEYGEN_VIA_SYSFS, + C("Creating a full-xts key via sysfs attributes failed") }, + { 0, NULL }, +}; +#undef C + +static const OSSL_PARAM prov_param_types[] = { + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_NAME, OSSL_PARAM_UTF8_PTR, NULL, 0), + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_VERSION, OSSL_PARAM_UTF8_PTR, NULL, 0), + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_BUILDINFO, OSSL_PARAM_UTF8_PTR, NULL, 0), + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_STATUS, OSSL_PARAM_INTEGER, NULL, 0), + OSSL_PARAM_END, +}; + +static int prov_ctx_init(struct provider_ctx *pctx, const OSSL_CORE_HANDLE *handle, + const OSSL_DISPATCH *in) +{ + const OSSL_DISPATCH *iter_in; + OSSL_LIB_CTX *libctx; + + if (!pctx) + return OSSL_RV_ERR; + + libctx = OSSL_LIB_CTX_new_from_dispatch(handle, in); + if (!libctx) + return OSSL_RV_ERR; + + pctx->libctx = libctx; + pctx->handle = handle; + pctx->state = PROVIDER_INITIALIZED; + + for (iter_in = in; iter_in->function_id != 0; iter_in++) { + switch (iter_in->function_id) { + case OSSL_FUNC_CORE_NEW_ERROR: + pctx->core_new_error = OSSL_FUNC_core_new_error(iter_in); + break; + case OSSL_FUNC_CORE_SET_ERROR_DEBUG: + pctx->core_set_error_debug = OSSL_FUNC_core_set_error_debug(iter_in); + break; + case OSSL_FUNC_CORE_VSET_ERROR: + pctx->core_vset_error = OSSL_FUNC_core_vset_error(iter_in); + break; + default: + continue; + } + } + return OSSL_RV_OK; +} + +static void prov_teardown(void *vpctx) +{ + OPENSSL_free(vpctx); +} + +static const OSSL_PARAM *prov_gettable_params(void *vpctx __unused) +{ + return prov_param_types; +} + +static int prov_get_params(void *vpctx, OSSL_PARAM params[]) +{ + struct provider_ctx *pctx = vpctx; + OSSL_PARAM *p; + + if (!pctx) + return OSSL_RV_ERR; + + p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_NAME); + if (p && (OSSL_PARAM_set_utf8_ptr(p, PROV_NAME) != OSSL_RV_OK)) + return OSSL_RV_ERR; + + p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_VERSION); + if (p && (OSSL_PARAM_set_utf8_ptr(p, PROV_VERSION) != OSSL_RV_OK)) + return OSSL_RV_ERR; + + p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_BUILDINFO); + if (p && (OSSL_PARAM_set_utf8_ptr(p, PROV_VERSION) != OSSL_RV_OK)) + return OSSL_RV_ERR; + + p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_STATUS); + if (p && (OSSL_PARAM_set_int(p, pctx->state) != OSSL_RV_OK)) + return OSSL_RV_ERR; + + return OSSL_RV_OK; +} + +static const OSSL_ALGORITHM *prov_query_operation(void *vpctx, int operation_id, int *no_cache) +{ + struct provider_ctx *pctx = vpctx; + const OSSL_ALGORITHM *ops; + + if (!pctx || pctx->state == PROVIDER_UNINITIALIZED) + return NULL; + + switch (operation_id) { + case OSSL_OP_STORE: + ops = store_ops; + break; + case OSSL_OP_KEYMGMT: + ops = keymgmt_ops; + break; + case OSSL_OP_SIGNATURE: + ops = signature_ops; + break; + case OSSL_OP_DECODER: + ops = decoder_ops; + break; + default: + ops = NULL; + break; + } + + *no_cache = 1; + return ops; +} + +static int prov_get_capabilities(void *vpctx __unused, const char *capability, + OSSL_CALLBACK *cb, void *arg) +{ + int rv = OSSL_RV_OK; + + if (OPENSSL_strcasecmp(capability, "TLS-GROUP") == 0) + rv = tls_group_capabilities(cb, arg); + + return rv; +} + +static const OSSL_ITEM *prov_get_reason_strings(void *vpctx __unused) +{ + return reason_strings; +} + +static const OSSL_DISPATCH provider_dispatch_table[] = { +#define FUNC(func) (void (*)(void))(func) + { OSSL_FUNC_PROVIDER_TEARDOWN, FUNC(prov_teardown) }, + { OSSL_FUNC_PROVIDER_GETTABLE_PARAMS, FUNC(prov_gettable_params) }, + { OSSL_FUNC_PROVIDER_GET_PARAMS, FUNC(prov_get_params) }, + { OSSL_FUNC_PROVIDER_QUERY_OPERATION, FUNC(prov_query_operation) }, + { OSSL_FUNC_PROVIDER_GET_CAPABILITIES, FUNC(prov_get_capabilities) }, + { OSSL_FUNC_PROVIDER_GET_REASON_STRINGS, FUNC(prov_get_reason_strings) }, + { 0, NULL } +#undef FUNC +}; + +static int prov_init(const OSSL_CORE_HANDLE *handle, + const OSSL_DISPATCH *in, + const OSSL_DISPATCH **out, + void **vpctx) +{ + struct provider_ctx *pctx; + int rv = OSSL_RV_ERR; + + if (!handle || !in || !out || !vpctx) + return OSSL_RV_ERR; + + pctx = OPENSSL_zalloc(sizeof(*pctx)); + if (!pctx) + return OSSL_RV_ERR; + + if (!prov_ctx_init(pctx, handle, in)) + goto err; + + *vpctx = pctx; + *out = provider_dispatch_table; + return OSSL_RV_OK; + +err: + OPENSSL_free(pctx); + return rv; +} + +void prov_err_raise(struct provider_ctx *pctx, const char *file, int line, + const char *func, int reason, const char *fmt, ...) +{ + va_list args; + + if (!pctx || !pctx->core_new_error || + !pctx->core_set_error_debug || !pctx->core_vset_error) + return ERR_raise(ERR_LIB_PROV, reason); + + va_start(args, fmt); + pctx->core_new_error(pctx->handle); + pctx->core_set_error_debug(pctx->handle, file, line, func); + pctx->core_vset_error(pctx->handle, reason, fmt, args); + va_end(args); +} + +int OSSL_provider_init(const OSSL_CORE_HANDLE *handle, + const OSSL_DISPATCH *in, + const OSSL_DISPATCH **out, + void **provctx) +{ + return prov_init(handle, in, out, provctx); +} diff --git a/src/provider.h b/src/provider.h new file mode 100644 index 0000000..701e745 --- /dev/null +++ b/src/provider.h @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _PROVIDER_H +#define _PROVIDER_H + +#include +#include +#include + +#define PROV_NAME "hbkzpc" +#define PROV_VERSION "2.0.0" +#define PROV_PROP "provider="PROV_NAME +#define PROV_PROP_FWD "provider!="PROV_NAME + +#define PROV_NAME_EC "EC" +#define PROV_NAMES_EC "EC:id-ecPublicKey:1.2.840.10045.2.1" +#define PROV_DESC_EC "hbkzpc EC implementation" + +#define PROV_NAME_ED25519 "ED25519" +#define PROV_NAMES_ED25519 "ED25519:1.3.101.112" +#define PROV_DESCS_ED25519 "hkkzpc ED25519 Implementation" + +#define PROV_NAME_ED448 "ED448" +#define PROV_NAMES_ED448 "ED448:1.3.101.113" +#define PROV_DESCS_ED448 "hbkzpc ED448 Implementation" + +#define __unused __attribute__((unused)) + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) +#endif + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +enum provider_state { + PROVIDER_UNINITIALIZED = 0, + PROVIDER_INITIALIZED, +}; + +struct provider_ctx { + const OSSL_CORE_HANDLE *handle; + OSSL_LIB_CTX *libctx; + + enum provider_state state; + + OSSL_FUNC_core_new_error_fn *core_new_error; + OSSL_FUNC_core_set_error_debug_fn *core_set_error_debug; + OSSL_FUNC_core_vset_error_fn *core_vset_error; +}; + +void prov_err_raise(struct provider_ctx *pctx, const char *file, int line, + const char *func, int reason, const char *fmt, ...); +#define PROV_ERR_raise(pctx, reason) \ + prov_err_raise(pctx, OPENSSL_FILE, OPENSSL_LINE, OPENSSL_FUNC, reason, NULL) + +#endif /* _PROVIDER_H */ diff --git a/src/signature.c b/src/signature.c new file mode 100644 index 0000000..6fde63f --- /dev/null +++ b/src/signature.c @@ -0,0 +1,482 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include +#include +#include +#include +#include +#include + +#include + +#include "provider.h" +#include "signature.h" +#include "object.h" +#include "ossl.h" +#include "map.h" + +/* TODO: OSSL_SIGNATURE_PARAM_NONCE_TYPE support */ + +#define ASN1_SIG_HDR 8 + +enum sig_op { + SIG_OP_UNDEF = 0, + SIG_OP_SIGN, + SIG_OP_VERIFY, +}; + +static int ecdsa_curves[] = { + ZPC_EC_CURVE_P256, + ZPC_EC_CURVE_P384, + ZPC_EC_CURVE_P521, +}; + +static int eddsa_curves[] = { + ZPC_EC_CURVE_ED25519, + ZPC_EC_CURVE_ED448, +}; + +struct sig_ctx { + struct provider_ctx *pctx; + char *propq; + + unsigned int nid; + enum sig_op op; + struct zpc_ecdsa_ctx *zpc_ctx; + + int *curves; + size_t curves_len; + + EVP_MD_CTX *fwd_md_ctx; + bool raw_sig; +}; + +static bool valid_curve(int curve, int *curves, size_t curves_len) +{ + for (size_t i = 0; i < curves_len; i++) + if (curve == curves[i]) + return true; + + return false; +} + +static int raw2der(const unsigned char *raw, size_t rawlen, + unsigned char *der, size_t *derlen) +{ + ECDSA_SIG *ec_sig = NULL; + int rv = OSSL_RV_ERR; + size_t _derlen; + + if (!raw || !rawlen || !derlen || + (*derlen < (rawlen + ASN1_SIG_HDR))) + goto out; + + ec_sig = ECDSA_SIG_new(); + if (!ec_sig) + goto out; + + rv = ECDSA_SIG_set0(ec_sig, + BN_bin2bn(raw, rawlen / 2, NULL), + BN_bin2bn(raw + rawlen / 2, rawlen / 2, NULL)); + if (rv != OSSL_RV_OK) + goto out; + + _derlen = i2d_ECDSA_SIG(ec_sig, &der); + if (_derlen <= 0) + goto out; + + *derlen = _derlen; + rv = OSSL_RV_OK; +out: + ECDSA_SIG_free(ec_sig); + return rv; +} + +static int der2raw(const unsigned char *der, size_t derlen, + unsigned char *raw, size_t *rawlen) +{ + ECDSA_SIG *ec_sig = NULL; + int rv = OSSL_RV_ERR; + const BIGNUM *r, *s; + size_t _rawlen; + + if (!der || !derlen || !rawlen) + goto out; + _rawlen = *rawlen; + + ec_sig = d2i_ECDSA_SIG(NULL, &der, derlen); + if (!ec_sig) + goto out; + + r = ECDSA_SIG_get0_r(ec_sig); + s = ECDSA_SIG_get0_s(ec_sig); + if (!r || !s) + goto out; + + if ((BN_bn2binpad(r, raw, _rawlen / 2) == -1) || + (BN_bn2binpad(s, raw + _rawlen / 2, _rawlen / 2) == -1)) + goto out; + + rv = OSSL_RV_OK; +out: + ECDSA_SIG_free(ec_sig); + return rv; +} + +static struct sig_ctx *sig_newctx(struct provider_ctx *pctx, const char *propq, + int *curves, size_t curves_len, bool raw_sig) +{ + struct zpc_ecdsa_ctx *zpc_ctx = NULL; + struct sig_ctx *sctx = NULL; + char *pq; + int rc; + + rc = zpc_ecdsa_ctx_alloc(&zpc_ctx); + if (rc) { + PROV_ERR_raise(pctx, rc); + return NULL; + } + + sctx = OPENSSL_zalloc(sizeof(struct sig_ctx)); + if (!sctx) + goto err; + + pq = OPENSSL_strdup(propq); + if (pq) + goto err; + + sctx->pctx = pctx; + sctx->zpc_ctx = zpc_ctx; + sctx->propq = pq; + sctx->curves = curves; + sctx->curves_len = curves_len; + sctx->raw_sig = raw_sig; + + return sctx; +err: + OPENSSL_free(sctx); + zpc_ecdsa_ctx_free(&zpc_ctx); + return NULL; +} + +static int sig_init(struct sig_ctx *sctx, struct obj *obj, + const OSSL_PARAM params[] __unused, + enum sig_op op) +{ + int rc; + + if (!sctx) + return OSSL_RV_ERR; + + if (obj) { + if (!valid_curve(obj_key_curve(obj), + sctx->curves, sctx->curves_len)) + return OSSL_RV_ERR; + rc = zpc_ecdsa_ctx_set_key(sctx->zpc_ctx, obj->ec_key); + if (rc) { + PROV_ERR_raise(sctx->pctx, rc); + return OSSL_RV_ERR; + } + } + + /* TODO: params */ + + sctx->op = op; + return OSSL_RV_OK; +} + +static int sig_digest_init(struct sig_ctx *sctx, const char *mdname, + struct obj *obj, const OSSL_PARAM params[], + enum sig_op op) +{ + const EVP_MD *md; + EVP_MD_CTX *md_ctx; + + if (!sctx) + return OSSL_RV_ERR; + + md = EVP_MD_fetch(sctx->pctx->libctx, mdname, PROV_PROP_FWD); + if (!md) + return OSSL_RV_ERR; + + if (!sctx->fwd_md_ctx) { + md_ctx = EVP_MD_CTX_new(); + if (!md_ctx) + return OSSL_RV_ERR; + sctx->fwd_md_ctx = md_ctx; + + if (EVP_DigestInit_ex2(sctx->fwd_md_ctx, md, params) != OSSL_RV_OK) + return OSSL_RV_ERR; + } else { + if (EVP_MD_CTX_reset(sctx->fwd_md_ctx)) + return OSSL_RV_ERR; + } + + return sig_init(sctx, obj, params, op); +} + +static int sig_sign_raw(struct sig_ctx *sctx, + unsigned char *sig, size_t *siglen, size_t sigsize, + const unsigned char *tbs, size_t tbslen) +{ + *siglen = sigsize; + return zpc_ecdsa_sign(sctx->zpc_ctx, tbs, tbslen, sig, siglen) + ? OSSL_RV_ERR + : OSSL_RV_OK; +} + +static int sig_sign_der(struct sig_ctx *sctx, + unsigned char *sig, size_t *siglen, size_t sigsize, + const unsigned char *tbs, size_t tbslen) +{ + unsigned char raw[EVP_MAX_MD_SIZE]; + unsigned char *_sig; + size_t rawlen; + int rv; + + rawlen = MIN(sigsize, EVP_MAX_MD_SIZE); + _sig = sig ? raw : NULL; + + rv = sig_sign_raw(sctx, _sig, &rawlen, rawlen, tbs, tbslen); + if (rv != OSSL_RV_OK) + return rv; + + if (!sig) + *siglen = rawlen + ASN1_SIG_HDR; + else + rv = raw2der(raw, rawlen, sig, siglen); + + return rv; +} + +static int sig_verify_raw(struct sig_ctx *sctx, + const unsigned char *sig, size_t siglen, + const unsigned char *tbs, size_t tbslen) +{ + if (!sctx || + !sctx->zpc_ctx || + sctx->op != SIG_OP_VERIFY) + return OSSL_RV_ERR; + + return zpc_ecdsa_verify(sctx->zpc_ctx, tbs, tbslen, sig, siglen) + ? OSSL_RV_ERR + : OSSL_RV_OK; +} + +static int sig_verify_der(struct sig_ctx *sctx, + const unsigned char *sig, size_t siglen, + const unsigned char *tbs, size_t tbslen) +{ + unsigned char raw[EVP_MAX_MD_SIZE]; + size_t rawlen; + int rv; + + /* calculate raw signature size */ + if (zpc_ecdsa_sign(sctx->zpc_ctx, tbs, tbslen, NULL, &rawlen)) + return OSSL_RV_ERR; + + rv = der2raw(sig, siglen, raw, &rawlen); + if (rv != OSSL_RV_OK) + return rv; + + return sig_verify_raw(sctx, raw, rawlen, tbs, tbslen); +} + +#define DISP_SIG(tname, name) DECL_DISPATCH_FUNC(signature, tname, name) +DISP_SIG(newctx, ecdsa_newctx); +DISP_SIG(newctx, eddsa_newctx); +DISP_SIG(freectx, sig_freectx); + +DISP_SIG(sign_init, sig_sign_init); +DISP_SIG(sign, sig_sign); +DISP_SIG(verify_init, sig_verify_init); +DISP_SIG(verify, sig_verify); + +DISP_SIG(digest_sign_init, sig_digest_sign_init); +DISP_SIG(digest_sign_update, sig_digest_update); +DISP_SIG(digest_sign_final, sig_digest_sign_final); +DISP_SIG(digest_verify_init, sig_digest_verify_init); +DISP_SIG(digest_verify_update, sig_digest_update); +DISP_SIG(digest_verify_final, sig_digest_verify_final); +#undef DISP_SIG + +static void *ecdsa_newctx(void *vpctx, const char *propq) +{ + return sig_newctx(vpctx, propq, ecdsa_curves, ARRAY_SIZE(ecdsa_curves), + false); +} + +static void *eddsa_newctx(void *vpctx, const char *propq) +{ + return sig_newctx(vpctx, propq, eddsa_curves, ARRAY_SIZE(eddsa_curves), + true); +} + +static void sig_freectx(void *vsctx) +{ + struct sig_ctx *sctx = (struct sig_ctx *)vsctx; + + if (!sctx) + return; + + zpc_ecdsa_ctx_free(&sctx->zpc_ctx); + OPENSSL_free(sctx->propq); + OPENSSL_free(sctx); +} + +/* pre-hashed sign/verify */ +static int sig_sign_init(void *vsctx, void *provkey, + const OSSL_PARAM params[]) +{ + return sig_init(vsctx, provkey, params, SIG_OP_SIGN); +} + +static int sig_verify_init(void *vsctx, void *provkey, + const OSSL_PARAM params[]) +{ + return sig_init(vsctx, provkey, params, SIG_OP_VERIFY); +} + +static int sig_sign(void *vsctx, unsigned char *sig, size_t *siglen, + size_t sigsize, const unsigned char *tbs, size_t tbslen) +{ + struct sig_ctx *sctx = (struct sig_ctx *)vsctx; + size_t _siglen; + int rv; + + if (!sctx || !tbs || + !sctx->zpc_ctx || + sctx->op != SIG_OP_SIGN) + return OSSL_RV_ERR; + + _siglen = siglen ? *siglen : sigsize; + + rv = sctx->raw_sig ? + sig_sign_raw(sctx, sig, &_siglen, sigsize, tbs, tbslen) : + sig_sign_der(sctx, sig, &_siglen, sigsize, tbs, tbslen); + + if (siglen) + *siglen = _siglen; + + return rv; +} + +static int sig_verify(void *vsctx, const unsigned char *sig, size_t siglen, + const unsigned char *tbs, size_t tbslen) +{ + struct sig_ctx *sctx = (struct sig_ctx *)vsctx; + + if (!sctx || !sig || !tbs || + !sctx->zpc_ctx || + sctx->op != SIG_OP_VERIFY) + return OSSL_RV_ERR; + + return sctx->raw_sig ? + sig_verify_raw(sctx, sig, siglen, tbs, tbslen) : + sig_verify_der(sctx, sig, siglen, tbs, tbslen); +} + +/* digest sign/verify */ +static int sig_digest_sign_init(void *vsctx, const char *mdname, + void *provkey, const OSSL_PARAM params[]) +{ + return sig_digest_init(vsctx, mdname, provkey, params, SIG_OP_SIGN); +} + +static int sig_digest_verify_init(void *vsctx, const char *mdname, + void *provkey, const OSSL_PARAM params[]) +{ + return sig_digest_init(vsctx, mdname, provkey, params, SIG_OP_VERIFY); +} + +static int sig_digest_update(void *vsctx, const unsigned char *data, + size_t datalen) +{ + struct sig_ctx *sctx = (struct sig_ctx *)vsctx; + + if (!sctx) + return OSSL_RV_ERR; + + return EVP_DigestUpdate(sctx->fwd_md_ctx, data, datalen); +} + +static int sig_digest_sign_final(void *vsctx, unsigned char *sig, + size_t *siglen, size_t sigsize) +{ + struct sig_ctx *sctx = (struct sig_ctx *)vsctx; + unsigned char tbs[EVP_MAX_MD_SIZE]; + unsigned int tbslen = EVP_MAX_MD_SIZE; + + if (!sctx) + return OSSL_RV_ERR; + + if (sig && + EVP_DigestFinal_ex(sctx->fwd_md_ctx, tbs, &tbslen) != OSSL_RV_OK) + return OSSL_RV_ERR; + + return sig_sign(sctx, sig, siglen, sigsize, tbs, tbslen); +} + +static int sig_digest_verify_final(void *vsctx, const unsigned char *sig, + size_t siglen) +{ + struct sig_ctx *sctx = (struct sig_ctx *)vsctx; + unsigned char tbs[EVP_MAX_MD_SIZE]; + unsigned int tbslen = EVP_MAX_MD_SIZE; + + if (!sctx) + return OSSL_RV_ERR; + + if (EVP_DigestFinal_ex(sctx->fwd_md_ctx, tbs, &tbslen) != OSSL_RV_OK) + return OSSL_RV_ERR; + + return sig_verify(sctx, sig, siglen, tbs, tbslen); +} + +static const OSSL_DISPATCH ecdsa_functions[] = { + DISPATCH_DEFN(SIGNATURE, NEWCTX, ecdsa_newctx), + DISPATCH_DEFN(SIGNATURE, FREECTX, sig_freectx), + + DISPATCH_DEFN(SIGNATURE, SIGN_INIT, sig_sign_init), + DISPATCH_DEFN(SIGNATURE, SIGN, sig_sign), + + DISPATCH_DEFN(SIGNATURE, VERIFY_INIT, sig_verify_init), + DISPATCH_DEFN(SIGNATURE, VERIFY, sig_verify), + + DISPATCH_DEFN(SIGNATURE, DIGEST_SIGN_INIT, sig_digest_sign_init), + DISPATCH_DEFN(SIGNATURE, DIGEST_SIGN_UPDATE, sig_digest_update), + DISPATCH_DEFN(SIGNATURE, DIGEST_SIGN_FINAL, sig_digest_sign_final), + + DISPATCH_DEFN(SIGNATURE, DIGEST_VERIFY_INIT, sig_digest_verify_init), + DISPATCH_DEFN(SIGNATURE, DIGEST_VERIFY_UPDATE, sig_digest_update), + DISPATCH_DEFN(SIGNATURE, DIGEST_VERIFY_FINAL, sig_digest_verify_final), + + DISPATCH_END, +}; + +static const OSSL_DISPATCH eddsa_functions[] = { + DISPATCH_DEFN(SIGNATURE, NEWCTX, eddsa_newctx), + DISPATCH_DEFN(SIGNATURE, FREECTX, sig_freectx), + + DISPATCH_DEFN(SIGNATURE, SIGN_INIT, sig_sign_init), + DISPATCH_DEFN(SIGNATURE, SIGN, sig_sign), + + DISPATCH_DEFN(SIGNATURE, VERIFY_INIT, sig_verify_init), + DISPATCH_DEFN(SIGNATURE, VERIFY, sig_verify), + + DISPATCH_DEFN(SIGNATURE, DIGEST_SIGN_INIT, sig_digest_sign_init), + DISPATCH_DEFN(SIGNATURE, DIGEST_SIGN_UPDATE, sig_digest_update), + DISPATCH_DEFN(SIGNATURE, DIGEST_SIGN_FINAL, sig_digest_sign_final), + + DISPATCH_DEFN(SIGNATURE, DIGEST_VERIFY_INIT, sig_digest_verify_init), + DISPATCH_DEFN(SIGNATURE, DIGEST_VERIFY_UPDATE, sig_digest_update), + DISPATCH_DEFN(SIGNATURE, DIGEST_VERIFY_FINAL, sig_digest_verify_final), + + DISPATCH_END, +}; + +const OSSL_ALGORITHM signature_ops[] = { + ALGORITHM_DEFN("ECDSA", PROV_PROP, ecdsa_functions, NULL), + ALGORITHM_DEFN("EDDSA", PROV_PROP, eddsa_functions, NULL), + ALGORITHM_END, +}; diff --git a/src/signature.h b/src/signature.h new file mode 100644 index 0000000..fbeed32 --- /dev/null +++ b/src/signature.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _SIGNATURE_H +#define _SIGNATURE_H + +#include + +extern const OSSL_ALGORITHM signature_ops[]; + +#endif /* _SIGNATURE_H */ diff --git a/src/store.c b/src/store.c new file mode 100644 index 0000000..76fe83b --- /dev/null +++ b/src/store.c @@ -0,0 +1,327 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include +#include +#include +#include +#include + +#include "provider.h" +#include "object.h" +#include "ossl.h" +#include "uri.h" +#include "map.h" +#include "store_local.h" + +struct store_ctx { + struct provider_ctx *pctx; + struct parsed_uri *puri; + + int type_exp; + bool eof; +}; + +#define DISP_STORE_FN(tname, name) DECL_DISPATCH_FUNC(store, tname, name) +DISP_STORE_FN(open, store_open); +#ifdef OSSL_FUNC_STORE_OPEN_EX +DISP_STORE_FN(open_ex, store_open_ex); +#endif +DISP_STORE_FN(load, store_load); +DISP_STORE_FN(eof, store_eof); +DISP_STORE_FN(close, store_close); +DISP_STORE_FN(set_ctx_params, store_set_ctx_params); +DISP_STORE_FN(settable_ctx_params, store_settable_ctx_params); +#undef DISP_STORE_FN + +static struct store_ctx *store_ctx_init(struct provider_ctx *pctx) +{ + struct store_ctx *sctx; + + sctx = OPENSSL_zalloc(sizeof(struct store_ctx)); + if (!sctx) + return NULL; + + sctx->pctx = pctx; + sctx->eof = false; + + return sctx; +} + +static void store_ctx_free(struct store_ctx *sctx) +{ + if (!sctx) + return; + + parsed_uri_free(sctx->puri); + OPENSSL_free(sctx); + + return; +} + +static int store_ctx_expect(struct store_ctx *sctx, int type_exp) +{ + int rv = OSSL_RV_OK; + + switch (type_exp) { + case OSSL_STORE_INFO_PUBKEY: + case OSSL_STORE_INFO_PKEY: + sctx->type_exp = type_exp; + break; + default: + rv = OSSL_RV_ERR; + break; + } + + return rv; +} + +static void *store_open(void *vpctx, const char *uri) +{ + struct store_ctx *sctx; + + sctx = store_ctx_init(vpctx); + if (!sctx) + return NULL; + + sctx->puri = parsed_uri_new(uri); + if (!sctx->puri) + goto err; + + return sctx; +err: + store_ctx_free(sctx); + return NULL; +} + +static void *store_open_ex(void *vpctx, const char *uri, + const OSSL_PARAM params[], + OSSL_PASSPHRASE_CALLBACK *pw_cb __unused, + void *pw_cbarg __unused) +{ + struct store_ctx *sctx; + + sctx = store_open(vpctx, uri); + if (!sctx) + return NULL; + + if (store_set_ctx_params(sctx, params) != OSSL_RV_OK) + goto err; + + return sctx; +err: + store_ctx_free(sctx); + return NULL; + +} + +static int attr2str(const struct attr *attr, char **str) +{ + if (!attr->value) + return OSSL_RV_OK; + + if (*str) + return OSSL_RV_ERR; + + *str = OPENSSL_strdup(attr->value); + return (*str) ? OSSL_RV_OK : OSSL_RV_ERR; +} + +static int attr2data(const struct attr *attr, struct data *data) +{ + size_t plen; + + if (!attr || !data) + return OSSL_RV_ERR; + + /* data already set */ + if (data->p || data->plen) + return OSSL_RV_ERR; + + if (!attr->value) + return OSSL_RV_OK; + plen = strlen(attr->value); + + if (OPENSSL_hexstr2buf_ex(NULL, 0, &plen, + attr->value, '\0') != 1) + return OSSL_RV_ERR; + + data->p = OPENSSL_zalloc(plen); + if (!data->p) + return OSSL_RV_ERR; + data->plen = plen; + + if (OPENSSL_hexstr2buf_ex(data->p, data->plen, &data->plen, + attr->value, '\0') != 1) { + OPENSSL_free(data->p); + return OSSL_RV_ERR; + } + + return OSSL_RV_OK; +} + +static struct obj *uri2obj(struct provider_ctx *pctx, const struct parsed_uri *puri) +{ + struct obj *obj; + + obj = obj_new(pctx); + if (!obj) + return NULL; + + if (attr2str(&puri->origin_type, &obj->origin_type) != OSSL_RV_OK) + goto err; + if (attr2str(&puri->origin_alg, &obj->origin_alg) != OSSL_RV_OK) + goto err; + if (attr2data(&puri->origin_blob, &obj->origin_blob) != OSSL_RV_OK) + goto err; + if (attr2data(&puri->origin_flags, &obj->origin_flags) != OSSL_RV_OK) + goto err; + if (attr2data(&puri->origin_spki, &obj->origin_spki) != OSSL_RV_OK) + goto err; + if (attr2str(&puri->mkvp, &obj->mkvp) != OSSL_RV_OK) + goto err; + if (attr2str(&puri->apqns, &obj->apqns) != OSSL_RV_OK) + goto err; + + return obj; +err: + obj_free(obj); + return NULL; +} + +static int store_load(void *vsctx, + OSSL_CALLBACK *object_cb, void *object_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + struct store_ctx *sctx = (struct store_ctx *)vsctx; + struct parsed_uri *puri; + int object_type; + + if (!sctx) + return OSSL_RV_ERR; + puri = sctx->puri; + + object_type = alg2object_type(puri->origin_alg.value); + if (object_type == OSSL_OBJECT_UNKNOWN) + return OSSL_RV_ERR; + + /* early checks */ + switch (sctx->type_exp) { + case OSSL_STORE_INFO_PKEY: + if (object_type != OSSL_OBJECT_PKEY) + return OSSL_RV_ERR; + break; + case 0: + /* no expected type */ + break; + default: + return OSSL_RV_ERR; + } + + sctx->eof = true; + return store_load_uri(sctx->pctx, puri, object_cb, object_cbarg, + pw_cb, pw_cbarg); +} + +static int store_eof(void *vsctx) +{ + struct store_ctx *sctx = (struct store_ctx *)vsctx; + + if (!sctx) + return OSSL_RV_TRUE; + + return sctx->eof ? OSSL_RV_TRUE : OSSL_RV_FALSE; +} + +static int store_close(void *vsctx) +{ + store_ctx_free((struct store_ctx *)vsctx); + return OSSL_RV_OK; +} + +static int store_set_ctx_params(void *vsctx, const OSSL_PARAM params[]) +{ + struct store_ctx *sctx = (struct store_ctx *)vsctx; + const OSSL_PARAM *p; + int type_exp; + + if (!sctx) + return OSSL_RV_ERR; + + if (!params) + return OSSL_RV_OK; + + p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_EXPECT); + if (p) { + if ((OSSL_PARAM_get_int(p, &type_exp) != OSSL_RV_OK) || + (store_ctx_expect(sctx, type_exp) != OSSL_RV_OK)) + return OSSL_RV_ERR; + } + + return OSSL_RV_OK; +} + +static const OSSL_PARAM *store_settable_ctx_params(void *pctx __unused) +{ + static const OSSL_PARAM known_settable_ctx_params[] = { + OSSL_PARAM_int(OSSL_STORE_PARAM_EXPECT, NULL), + OSSL_PARAM_END, + }; + return known_settable_ctx_params; +} + +int store_load_uri(struct provider_ctx *pctx, struct parsed_uri *puri, + OSSL_CALLBACK *object_cb, void *object_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb __unused, + void *pw_cbarg __unused) +{ + OSSL_PARAM params[4]; + struct obj *obj; + char *data_type; + int object_type; + int rv; + + if (!pctx || !puri) + return OSSL_RV_ERR; + + object_type = alg2object_type(puri->origin_alg.value); + if (object_type == OSSL_OBJECT_UNKNOWN) + return OSSL_RV_ERR; + + data_type = alg2data_type(puri->origin_alg.value); + if (!data_type) + return OSSL_RV_ERR; + + obj = uri2obj(pctx, puri); + if (!obj) + return OSSL_RV_ERR; + + params[0] = OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, + &object_type); + params[1] = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, + data_type, 0); + params[2] = OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_REFERENCE, + obj, sizeof(struct obj)); + params[3] = OSSL_PARAM_construct_end(); + + rv = object_cb(params, object_cbarg); + obj_free(obj); + return rv; +} + +static const OSSL_DISPATCH store_functions[] = { + DISPATCH_DEFN(STORE, OPEN, store_open), +#ifdef OSSL_FUNC_STORE_OPEN_EX + DISPATCH_DEFN(STORE, OPEN_EX, store_open_ex), +#endif + DISPATCH_DEFN(STORE, LOAD, store_load), + DISPATCH_DEFN(STORE, EOF, store_eof), + DISPATCH_DEFN(STORE, CLOSE, store_close), + DISPATCH_DEFN(STORE, SET_CTX_PARAMS, store_set_ctx_params), + DISPATCH_DEFN(STORE, SETTABLE_CTX_PARAMS, store_settable_ctx_params), + DISPATCH_END +}; + +const OSSL_ALGORITHM store_ops[] = { + { URI_PROTOCOL_PREFIX, "provider=" PROV_NAME, store_functions, "HBKZPC URI Store" }, + { NULL, NULL, NULL, NULL }, +}; diff --git a/src/store.h b/src/store.h new file mode 100644 index 0000000..a03c60f --- /dev/null +++ b/src/store.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _STORE_H +#define _STORE_H + +#include + +extern const OSSL_ALGORITHM store_ops[]; + +#endif /* _STORE_H */ diff --git a/src/store_local.h b/src/store_local.h new file mode 100644 index 0000000..55a3c62 --- /dev/null +++ b/src/store_local.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _STORE_LOCAL_H +#define _STORE_LOCAL_H + +#include + +#include "provider.h" +#include "uri.h" + +int store_load_uri(struct provider_ctx *pctx, struct parsed_uri *puri, + OSSL_CALLBACK *object_cb, void *object_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb , void *pw_cbarg); + +#endif /* _STORE_LOCAL_H */ diff --git a/src/tls.c b/src/tls.c new file mode 100644 index 0000000..28f7a9f --- /dev/null +++ b/src/tls.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +// Derived from OpenSSL source +#include +#include +#include + +#include "provider.h" +#include "ossl.h" +#include "tls.h" + +/* taken from include/internal/tlsgroups.h */ +#define OSSL_TLS_GROUP_ID_secp256r1 0x0017 +#define OSSL_TLS_GROUP_ID_secp384r1 0x0018 +#define OSSL_TLS_GROUP_ID_secp521r1 0x0019 +#define OSSL_TLS_GROUP_ID_x25519 0x001D +#define OSSL_TLS_GROUP_ID_x448 0x001E + +/* taken from providers/common/capabilities.c */ +#define TLS_GROUP_ENTRY(tlsname, realname, algorithm, idx) \ +{ \ + OSSL_PARAM_utf8_string(OSSL_CAPABILITY_TLS_GROUP_NAME, \ + tlsname, sizeof(tlsname)), \ + OSSL_PARAM_utf8_string(OSSL_CAPABILITY_TLS_GROUP_NAME_INTERNAL, \ + realname, sizeof(realname)), \ + OSSL_PARAM_utf8_string(OSSL_CAPABILITY_TLS_GROUP_ALG, \ + algorithm, sizeof(algorithm)), \ + OSSL_PARAM_uint(OSSL_CAPABILITY_TLS_GROUP_ID, \ + (unsigned int *)&group_list[idx].group_id), \ + OSSL_PARAM_uint(OSSL_CAPABILITY_TLS_GROUP_SECURITY_BITS, \ + (unsigned int *)&group_list[idx].secbits), \ + OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MIN_TLS, \ + (unsigned int *)&group_list[idx].mintls), \ + OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MAX_TLS, \ + (unsigned int *)&group_list[idx].maxtls), \ + OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MIN_DTLS, \ + (unsigned int *)&group_list[idx].mindtls), \ + OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MAX_DTLS, \ + (unsigned int *)&group_list[idx].maxdtls), \ + OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_IS_KEM, \ + (unsigned int *)&group_list[idx].is_kem), \ + OSSL_PARAM_END \ +} + +typedef struct tls_group_constants_st { + unsigned int group_id; /* Group ID */ + unsigned int secbits; /* Bits of security */ + int mintls; /* Minimum TLS version, -1 unsupported */ + int maxtls; /* Maximum TLS version (or 0 for undefined) */ + int mindtls; /* Minimum DTLS version, -1 unsupported */ + int maxdtls; /* Maximum DTLS version (or 0 for undefined) */ + int is_kem; /* Indicates utility as KEM */ +} TLS_GROUP_CONSTANTS; + +static const TLS_GROUP_CONSTANTS group_list[] = { + [0] = { OSSL_TLS_GROUP_ID_secp256r1, 128, TLS1_VERSION, 0, DTLS1_VERSION, 0, 0 }, + [1] = { OSSL_TLS_GROUP_ID_secp384r1, 192, TLS1_VERSION, 0, DTLS1_VERSION, 0, 0 }, + [2] = { OSSL_TLS_GROUP_ID_secp521r1, 256, TLS1_VERSION, 0, DTLS1_VERSION, 0, 0 }, + [3] = { OSSL_TLS_GROUP_ID_x25519, 128, TLS1_VERSION, 0, DTLS1_VERSION, 0, 0 }, + [4] = { OSSL_TLS_GROUP_ID_x448, 224, TLS1_VERSION, 0, DTLS1_VERSION, 0, 0 }, +}; + +static const OSSL_PARAM tls_group_list[][11] = { + TLS_GROUP_ENTRY("secp256r1", "prime256v1", "EC", 0), + TLS_GROUP_ENTRY("P-256", "prime256v1", "EC", 0), + TLS_GROUP_ENTRY("secp384r1", "secp384r1", "EC", 1), + TLS_GROUP_ENTRY("P-384", "secp384r1", "EC", 1), + TLS_GROUP_ENTRY("secp521r1", "secp521r1", "EC", 2), + TLS_GROUP_ENTRY("P-521", "secp521r1", "EC", 2), + TLS_GROUP_ENTRY("x25519", "X25519", "X25519", 3), + TLS_GROUP_ENTRY("x448", "X448", "X448", 4), +}; + +int tls_group_capabilities(OSSL_CALLBACK *cb, void *arg) +{ + int rv = OSSL_RV_ERR; + size_t i; + + for (i = 0; i < ARRAY_SIZE(tls_group_list); i++) { + if (cb(tls_group_list[i], arg) != OSSL_RV_OK) + return OSSL_RV_ERR; + } + + return rv; +} diff --git a/src/tls.h b/src/tls.h new file mode 100644 index 0000000..3dd4c6d --- /dev/null +++ b/src/tls.h @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _TLS_H +#define _TLS_H + +#include + +int tls_group_capabilities(OSSL_CALLBACK *cb, void *arg); + +#endif /* _TLS_H */ diff --git a/src/uri.c b/src/uri.c new file mode 100644 index 0000000..a7269c7 --- /dev/null +++ b/src/uri.c @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include +#include + +#include "uri.h" + +#define SEP_PROTOCOL ":" +#define SEP_PATHQUERY "?" +#define SEP_KEYVALUE "=" +#define SEP_PATHATTRS ";" +#define SEP_QUERYATTRS "&" + +#define URI_PROTOCOL URI_PROTOCOL_PREFIX SEP_PROTOCOL + +#define URI_P_ORIGIN_TYPE "origin-type" SEP_KEYVALUE +#define URI_P_ORIGIN_ALG "origin-alg" SEP_KEYVALUE +#define URI_P_ORIGIN_BLOB "origin-blob" SEP_KEYVALUE +#define URI_P_ORIGIN_FLAGS "origin-flags" SEP_KEYVALUE +#define URI_P_ORIGIN_PUBKEY "origin-spki" SEP_KEYVALUE +#define URI_P_COMMENT "comment" SEP_KEYVALUE + +#define URI_Q_MKVP "mkvp" SEP_KEYVALUE +#define URI_Q_APQNS "apqns" SEP_KEYVALUE + +static void decode_pct(char *s) +{ + char *rp, *wp, *endptr; + unsigned long tmp; + char hex[3] = {0}; + size_t wp_len = 0; + + if (!s) + return; + + if (!strchr(s, '%')) + return; + + rp = wp = s; + while(*rp) { + switch(*rp) { + case '%': + if (strlen(rp) < 3) + goto out; /* invalid format */ + + rp++; /* skip % */ + memcpy(hex, rp, 2); /* 2 chars only */ + + tmp = strtoul(hex, &endptr, 16);/* convert */ + if (*endptr != '\0') + goto out; /* non-hex chars */ + *wp = (char)(tmp & 0xff); + + rp++; + break; + default: + *wp = *rp; + } + + rp++; + wp++; + wp_len++; + } +out: + *wp = '\0'; +} + +static int parse_attr(char *str, struct attr *attr) +{ + char *key, **p; + int rc = 1; + + if (!str || !attr) + goto out; + + /* skip already parsed attribute */ + if (attr->value) + goto out; + + p = &str; + key = strsep(p, SEP_KEYVALUE); + if (!p) + goto out; + + decode_pct(*p); + attr->key = key; + attr->value = *p; + + rc = 0; +out: + return rc; +} + +static inline int match_elem_attrkey(const char *elem, const char *attrkey) +{ + return (strncmp(elem, attrkey, strlen(attrkey)) == 0); +} + +static int parse_query(char *qattr, struct parsed_uri *puri) +{ + char **next; + + /* query attributes are optional */ + if (!qattr || !strlen(qattr)) + return 0; + + next = &qattr; + do { + char *e = strsep(next, SEP_QUERYATTRS); + int rc = 0; + + if (match_elem_attrkey(e, URI_Q_MKVP)) + rc = parse_attr(e, &puri->mkvp); + else if (match_elem_attrkey(e, URI_Q_APQNS)) + rc = parse_attr(e, &puri->apqns); + else + rc = 1; /* unknown attribute */ + if (rc) + return rc; + } while (*next); + + return 0; +} + +static int parse_path(char *pattr, struct parsed_uri *puri) +{ + char **next; + + /* path attributes are mandatory */ + if (!pattr || !strlen(pattr)) + return 1; + + next = &pattr; + do { + char *e = strsep(next, SEP_PATHATTRS); + int rc = 0; + + if (match_elem_attrkey(e, URI_P_ORIGIN_TYPE)) + rc = parse_attr(e, &puri->origin_type); + else if (match_elem_attrkey(e, URI_P_ORIGIN_ALG)) + rc = parse_attr(e, &puri->origin_alg); + else if (match_elem_attrkey(e, URI_P_ORIGIN_BLOB)) + rc = parse_attr(e, &puri->origin_blob); + else if (match_elem_attrkey(e, URI_P_ORIGIN_FLAGS)) + rc = parse_attr(e, &puri->origin_flags); + else if (match_elem_attrkey(e, URI_P_ORIGIN_PUBKEY)) + rc = parse_attr(e, &puri->origin_spki); + else if (match_elem_attrkey(e, URI_P_COMMENT)) + rc = parse_attr(e, &puri->comment); + else + rc = 1; /* unknown attribute */ + if (rc) + return rc; + } while (*next); + + return 0; +} + +static int parse(char *uri, struct parsed_uri *puri) +{ + char *pattr, *qattr; + char **next; + int rc; + + if (!uri || !puri) + return 1; + + if (strncmp(uri, URI_PROTOCOL, strlen(URI_PROTOCOL)) != 0) + return 1; + + next = &uri; + + /* drop protocol */ + strsep(next, SEP_PROTOCOL); + + pattr = strsep(next, SEP_PATHQUERY); + qattr = *next; + + rc = parse_path(pattr, puri); + if (rc) { + return rc; + } + + rc = parse_query(qattr, puri); + if (rc) { + return rc; + } + + return 0; +} + +void parsed_uri_free(struct parsed_uri *puri) +{ + if (!puri) + return; + + if (puri->priv) + OPENSSL_clear_free(puri->priv, + puri->privlen); + + OPENSSL_free(puri); +} + +struct parsed_uri *parsed_uri_new(const char *uri) +{ + struct parsed_uri *puri; + + puri = OPENSSL_zalloc(sizeof(struct parsed_uri)); + if (!puri) + return NULL; + + puri->priv = OPENSSL_strdup(uri); + if (!puri->priv) + goto err; + puri->privlen = strlen(uri); + + if(parse(puri->priv, puri)) + goto err; + + return puri; + +err: + parsed_uri_free(puri); + return NULL; +} diff --git a/src/uri.h b/src/uri.h new file mode 100644 index 0000000..cf2115e --- /dev/null +++ b/src/uri.h @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#ifndef _URI_H +#define _URI_H + +#include + +#define URI_PROTOCOL_PREFIX "hbkzpc" + +struct attr { + const char *key; + const char *value; + //unsigned char *data; + //size_t datalen; +}; + +struct parsed_uri { + char *priv; + size_t privlen; + + /* path attributes */ + struct attr origin_type; + struct attr origin_alg; + struct attr origin_blob; + struct attr origin_flags; + struct attr origin_spki; + struct attr comment; + + /* query attributes */ + struct attr mkvp; + struct attr apqns; +}; + +struct parsed_uri *parsed_uri_new(const char *uri); +void parsed_uri_free(struct parsed_uri *puri); + +#endif /* _URI_H */ diff --git a/test/t_ecc_key.cc b/test/t_ecc_key.cc index 7e2b567..a9f3baa 100644 --- a/test/t_ecc_key.cc +++ b/test/t_ecc_key.cc @@ -489,7 +489,7 @@ TEST(ec_key, export) { struct zpc_ec_key *ec_key, *ec_key2; u8 buf[2000], buf2[2000]; - unsigned int buflen, buflen2, flags; + size_t buflen, buflen2, flags; const char *apqns[257]; int rc, type; zpc_ec_curve_t curve; @@ -583,7 +583,8 @@ TEST(ec_key, export_public) { struct zpc_ec_key *ec_key; u8 buf[132]; - unsigned int buflen, flags; + unsigned int flags; + size_t buflen; const char *apqns[257]; int rc, type; zpc_ec_curve_t curve; @@ -656,8 +657,8 @@ TEST(ec_key, import) { struct zpc_ec_key *ec_key, *ec_key2; u8 buf[10000], buf2[10000]; - unsigned int buflen = sizeof(buf); - unsigned int buf2len = sizeof(buf2); + size_t buflen = sizeof(buf); + size_t buf2len = sizeof(buf2); unsigned int flags; const char *apqns[257]; const char *mkvp; @@ -757,10 +758,10 @@ TEST(ec_key, spki_test) struct zpc_ec_key *ec_key, *ec_key2; unsigned int pubkeylen, privkeylen, blob_len, pubkey_offset; u8 buf[3000] = {0}, buf2[3000] = {0}, buf3[132] = {0}, buf4[3000] = {0}; - unsigned int buflen = sizeof(buf); - unsigned int buf2len = sizeof(buf2); - unsigned int buf3len = sizeof(buf3); - unsigned int buf4len = sizeof(buf4); + size_t buflen = sizeof(buf); + size_t buf2len = sizeof(buf2); + size_t buf3len = sizeof(buf3); + size_t buf4len = sizeof(buf4); unsigned int flags; const char *apqns[257]; const char *mkvp; diff --git a/test/t_ecdsa_ctx.cc b/test/t_ecdsa_ctx.cc index e6110e1..cb2d7e6 100644 --- a/test/t_ecdsa_ctx.cc +++ b/test/t_ecdsa_ctx.cc @@ -105,7 +105,8 @@ TEST(ecdsa_ctx, set_key) { struct zpc_ec_key *ec_key; struct zpc_ecdsa_ctx *ec_ctx; - unsigned int pubkeylen, privkeylen, flags = 0; + size_t pubkeylen, privkeylen; + unsigned int flags = 0; const char *mkvp, *apqns[257]; int rc, type; zpc_ec_curve_t curve; @@ -183,7 +184,8 @@ TEST(ecdsa_ctx, sign) struct zpc_ecdsa_ctx *ec_ctx; const char *mkvp, *apqns[257]; u8 msg[1000], signature[200]; - unsigned int msg_len, sig_len, flags; + size_t msg_len, sig_len; + unsigned int flags; int rc, type; zpc_ec_curve_t curve; const unsigned int test_msglen_from_curve[] = { 32, 48, 64, 500, 1000 }; @@ -260,8 +262,8 @@ TEST(ecdsa_ctx, verify) const char *mkvp, *apqns[257]; u8 signature[200]; u8 buf[200]; - unsigned int signature_len, hash_len, sig_len, buflen; - unsigned int pubkeylen, flags; + size_t signature_len, hash_len, sig_len, buflen, pubkeylen; + unsigned int flags; int rc, type; zpc_ec_curve_t curve; @@ -397,7 +399,7 @@ TEST(ecdsa_ctx, sv) struct zpc_ec_key *ec_key1, *ec_key2; struct zpc_ecdsa_ctx *ec_ctx1, *ec_ctx2; u8 sigbuf[200]; - unsigned int hash_len, sig_len, pubkeylen, privkeylen; + size_t hash_len, sig_len, pubkeylen, privkeylen; const char *mkvp, *apqns[257]; unsigned int flags; int rc, type; @@ -607,8 +609,8 @@ static zpc_ec_curve_t __str2curve(const char *str) } static void __get_ec_params_from_json(json_object *jtmp, zpc_ec_curve_t curve, - u8 *priv, unsigned int *privlen, u8 *pub, unsigned int *publen, - u8 *msg, unsigned int *msglen, u8 *sig, unsigned int *siglen) + u8 *priv, size_t *privlen, u8 *pub, size_t *publen, + u8 *msg, size_t *msglen, u8 *sig, size_t *siglen) { json_object *jd, *jx, *jy, *jmsg, *jsig_r, *jsig_s; json_bool b; @@ -683,8 +685,8 @@ static void __get_ec_params_from_json(json_object *jtmp, zpc_ec_curve_t curve, } static void __get_ed_params_from_json(json_object *jtmp, - u8 *priv, unsigned int *privlen, u8 *pub, unsigned int *publen, - u8 *msg, unsigned int *msglen, u8 *sig, unsigned int *siglen) + u8 *priv, size_t *privlen, u8 *pub, size_t *publen, + u8 *msg, size_t *msglen, u8 *sig, size_t *siglen) { json_object *jd, *jq, *jm, *js; json_bool b; @@ -763,8 +765,8 @@ static void __get_result_from_json(json_object *jresult, int *valid) * Get key material from json 'key' entry */ static void __get_key_from_json(json_object *jkey, zpc_ec_curve_t curve, - unsigned char *pubbuf, unsigned int *publen, - unsigned char *privbuf, unsigned int *privlen) + unsigned char *pubbuf, size_t *publen, + unsigned char *privbuf, size_t *privlen) { json_object *jwx, *jwy, *jsk, *jpk; json_bool b; @@ -827,7 +829,7 @@ static void __get_key_from_json(json_object *jkey, zpc_ec_curve_t curve, } static void __get_bytes_from_json(json_object *jobj, unsigned char *buf, - unsigned int *len) + size_t *len) { const char *str; u8 *bytes = NULL; @@ -849,9 +851,9 @@ static void __get_bytes_from_json(json_object *jobj, unsigned char *buf, } static void __run_sign_verify_test(zpc_ecdsa_ctx *ec_ctx, - unsigned char *msgbuf, unsigned int msglen, - unsigned char *sigbuf1, unsigned int *siglen1, - unsigned int privlen) + unsigned char *msgbuf, size_t msglen, + unsigned char *sigbuf1, size_t *siglen1, + size_t privlen) { int rc; @@ -865,8 +867,8 @@ static void __run_sign_verify_test(zpc_ecdsa_ctx *ec_ctx, } static void __run_verify_kat_test(zpc_ecdsa_ctx *ec_ctx, zpc_ec_curve_t curve, - unsigned char *msgbuf, unsigned int msglen, - unsigned char *sigbuf2, unsigned int siglen2, + unsigned char *msgbuf, size_t msglen, + unsigned char *sigbuf2, size_t siglen2, int expected_valid) { int rc; @@ -933,8 +935,8 @@ static void __run_nist_tests(json_object *jtestgroups, struct zpc_ec_key *ec_key u8 pubbuf[200] = { 0 }, privbuf[100] = { 0 }; u8 sigbuf1[200] = { 0 }, sigbuf2[200] = { 0 }, msgbuf[4096] = { 0 }; - unsigned int siglen1 = sizeof(sigbuf1), siglen2 = sizeof(sigbuf2); - unsigned int privlen, publen, msglen; + size_t siglen1 = sizeof(sigbuf1), siglen2 = sizeof(sigbuf2); + size_t privlen, publen, msglen; jtmp = json_object_array_get_idx(jtests, j); ASSERT_NE(jtmp, nullptr); @@ -1002,8 +1004,8 @@ static void __run_wycheproof_tests(json_object *jtestgroups, struct zpc_ec_key * u8 sigbuf1[200] = { 0 }, sigbuf2[200] = { 0 }, msgbuf[4096] = { 0 }; u8 pubbuf[200] = { 0 }, privbuf[100] = { 0 }; - unsigned int siglen1 = sizeof(sigbuf1), siglen2 = sizeof(sigbuf2); - unsigned int privlen, publen, msglen; + size_t siglen1 = sizeof(sigbuf1), siglen2 = sizeof(sigbuf2); + size_t privlen, publen, msglen; jtmp = json_object_array_get_idx(jtestgroups, i); ASSERT_NE(jtmp, nullptr); @@ -1115,7 +1117,7 @@ static void __run_json(const char *json) TEST(ecdsa_ctx, rederive_protected_key) { - unsigned int pubkeylen, privkeylen, msg_len, sig_len; + size_t pubkeylen, privkeylen, msg_len, sig_len; zpc_ec_curve_t curve; unsigned char buf[4096]; const char *mkvp, *apqns[257]; @@ -1206,7 +1208,7 @@ TEST(ecdsa_ctx, rederive_protected_key) TEST(ecdsa_ctx, reencipher) { - unsigned int pubkeylen, privkeylen, msg_len, sig_len; + size_t pubkeylen, privkeylen, msg_len, sig_len; unsigned char buf[4096]; const char *mkvp, *apqns[257]; struct zpc_ec_key *ec_key; @@ -1298,9 +1300,9 @@ TEST(ecdsa_ctx, reencipher) TEST(ecdsa_ctx, use_existing) { - unsigned int pubkeylen, privkeylen, msg_len, sig_len, signature_len; + size_t pubkeylen, privkeylen, msg_len, sig_len, signature_len; unsigned char buf[4096], signature[132]; - unsigned int buflen; + size_t buflen; const char *mkvp, *apqns[257]; struct zpc_ec_key *ec_key, *ec_key2; struct zpc_ecdsa_ctx *ec_ctx; @@ -1435,8 +1437,8 @@ TEST(ecdsa_ctx, use_existing) TEST(ecdsa_ctx, pvsecret_kat) { unsigned char sig1[132], sig2[132], pubkey[200], msg[32]; - unsigned int sig1_len = sizeof(sig1), sig2_len = sizeof(sig2); - unsigned int msg_len = sizeof(msg), publen = sizeof(pubkey); + size_t sig1_len = sizeof(sig1), sig2_len = sizeof(sig2); + size_t msg_len = sizeof(msg), publen = sizeof(pubkey); const char *mkvp, *apqns[257]; struct zpc_ec_key *ec_key1, *ec_key2; struct zpc_ecdsa_ctx *ec_ctx1, *ec_ctx2; @@ -1579,7 +1581,7 @@ static void __task(struct zpc_ec_key *ec_key) { struct zpc_ecdsa_ctx *ec_ctx; unsigned char sigbuf[200]; - unsigned int msglen, siglen; + size_t msglen, siglen; int rc, i; const u8 *msg = ec_tv[ec_key->curve].msg; @@ -1624,7 +1626,7 @@ static void __task(struct zpc_ec_key *ec_key) TEST(ecdsa_ctx, threads) { - unsigned int pubkeylen, privkeylen; + size_t pubkeylen, privkeylen; const char *mkvp, *apqns[257]; struct zpc_ec_key *ec_key; unsigned int flags; diff --git a/test/tprovider.c b/test/tprovider.c new file mode 100644 index 0000000..c36734d --- /dev/null +++ b/test/tprovider.c @@ -0,0 +1,631 @@ +// SPDX-License-Identifier: MIT +// Copyright contributors to the libzpc project +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ossl.h" +#include "asn1.h" + +#define PROVIDER "hbkzpc" +#define PROP_PROVIDER "provider=" PROVIDER + +#define HBKZPC_URI_ECDSA_UV "hbkzpc:comment=uv-secret-name=ecdsa" \ + ";origin-alg=prime256v1" \ + ";origin-type=uv" \ + ";origin-blob=318f9f812b9e89ec3bd948c00afc751749a5a275b3a709436288da62f4cb36fb" \ + ";origin-spki=0342000424873fcb06306adc8f65c8ec" \ + "d5aaf7bc6b62db8db50d8ce01677e49d" \ + "48e3be50af733b6e30a4c24fb52209cf" \ + "6254b2b87c6ffb65a50583cea136a048" \ + "8d431923" + +#define HBKZPC_FILE_ECDSA_DER "ecdsa.der" +#define HBKZPC_FILE_ECDSA_PEM "ecdsa.pem" + +static const char *default_file_der = HBKZPC_FILE_ECDSA_DER; +static const char *default_file_pem = HBKZPC_FILE_ECDSA_PEM; + +enum rv { + PASS = 0, + SKIP = 77, + FAIL = 99, +}; + +static unsigned char text[32]; + +static unsigned char sha256[32]; + +static unsigned char *sig = NULL; +static size_t siglen = 0; + +static unsigned char *dgst_sig = NULL; +static size_t dgst_siglen = 0; + +static const char *file_der = NULL; +static const char *file_pem = NULL; + +/* helpers */ + +static const char *stringify(int rv) +{ + switch(rv) { + case PASS: + return "PASS"; + case FAIL: + return "FAIL"; + case SKIP: + return "SKIP"; + }; + return "n/a"; +} + +static EVP_PKEY *uri_pkey_get1(const char *uri) +{ + OSSL_STORE_CTX *sctx; + void *key = NULL; + + sctx = OSSL_STORE_open(uri, NULL, NULL, NULL, NULL); + if (!sctx) { + fprintf(stderr, "fail: OSSL_STORE_open() [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto out; + } + + while (!OSSL_STORE_eof(sctx)) { + OSSL_STORE_INFO *info = OSSL_STORE_load(sctx); + if (!info) { + fprintf(stderr, "fail: OSSL_STORE_load() [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto out_close; + } + + switch (OSSL_STORE_INFO_get_type(info)) { + case OSSL_STORE_INFO_PKEY: + key = OSSL_STORE_INFO_get1_PKEY(info); + break; + default: + OSSL_STORE_INFO_free(info); + continue; + } + + OSSL_STORE_INFO_free(info); + break; + } +out_close: + OSSL_STORE_close(sctx); +out: + return key; +} + +static int sha2_256(unsigned char *in, size_t inlen) +{ + size_t len = sizeof(sha256); + + return EVP_Q_digest(NULL, "SHA2-256", NULL, + in, inlen, + sha256, &len); +} + +static int uri2file(const char *uri, const char *path, bool der) +{ + int rv = OSSL_RV_ERR; + ZPCHBK *zpchbk = NULL; + BIO *bo = NULL; + + if (!uri || !path) + goto out; + + zpchbk = ZPCHBK_new(); + if (!zpchbk) { + fprintf(stderr, "Unable to create hbk\n"); + goto out; + } + + ASN1_STRING_set(zpchbk->desc, HBKZPC_DER_DESC, -1); + ASN1_STRING_set(zpchbk->uri, uri, -1); + + bo = BIO_new_file(path, "w"); + if (!bo) { + fprintf(stderr, "Unable to open file: %s\n", path); + goto out; + } + + if (der) { + if (!i2d_ZPCHBK_bio(bo, zpchbk)) { + fprintf(stderr, "Unable to write DER file %s\n", path); + goto out; + } + } else { + if (!PEM_write_bio_ZPCHBK(bo, zpchbk)) { + fprintf(stderr, "Unable to write PEM file %s\n", path); + goto out; + } + } + + rv = OSSL_RV_OK; +out: + ZPCHBK_free(zpchbk); + BIO_free(bo); + return rv; +} + +/* tests */ + +static int test_provider(void) +{ + OSSL_LIB_CTX *libctx = NULL; + OSSL_PROVIDER *provider = NULL; + int rv = FAIL; + + provider = OSSL_PROVIDER_load(libctx, PROVIDER); + if (!provider) { + fprintf(stderr, "no provider %s\n", PROVIDER); + ERR_print_errors_fp(stderr); + goto out; + } + + rv = PASS; +out: + return rv; +} + +static int test_store_load_eof(void) +{ + const char *uri = HBKZPC_URI_ECDSA_UV; + OSSL_STORE_INFO *info; + OSSL_STORE_CTX *sctx; + int rv = FAIL; + + sctx = OSSL_STORE_open(uri, NULL, NULL, NULL, NULL); + if (!sctx) { + fprintf(stderr, "fail: OSSL_STORE_open() [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto out; + } + + if (OSSL_STORE_eof(sctx) != 0) { + fprintf(stderr, "fail: OSSL_STORE_eof() != 0 [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto out_close; + } + + info = OSSL_STORE_load(sctx); + if (!info) { + fprintf(stderr, "fail: OSSL_STORE_load() [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto out_close; + } + + if (OSSL_STORE_eof(sctx) != 1) { + fprintf(stderr, "fail: OSSL_STORE_eof() != 1 [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto out_close; + } + + rv = PASS; +out_close: + OSSL_STORE_close(sctx); +out: + return rv; +} + +static int test_store_get_pkey(void) +{ + const char *uri = HBKZPC_URI_ECDSA_UV; + OSSL_STORE_CTX *sctx; + void *key = NULL; + int rv = FAIL; + + sctx = OSSL_STORE_open(uri, NULL, NULL, NULL, NULL); + if (!sctx) { + fprintf(stderr, "fail: OSSL_STORE_open() [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto out; + } + + while (!OSSL_STORE_eof(sctx)) { + OSSL_STORE_INFO *info = OSSL_STORE_load(sctx); + if (!info) { + fprintf(stderr, "fail: OSSL_STORE_load() [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto out_close; + } + + switch (OSSL_STORE_INFO_get_type(info)) { + case OSSL_STORE_INFO_PUBKEY: + key = OSSL_STORE_INFO_get1_PUBKEY(info); + break; + case OSSL_STORE_INFO_PKEY: + key = OSSL_STORE_INFO_get1_PKEY(info); + break; + default: + OSSL_STORE_INFO_free(info); + continue; + } + + OSSL_STORE_INFO_free(info); + break; + } + + if (!key) { + fprintf(stderr, "fail: OSSL_STORE_INFO_[PUBKEY|PKEY] lookup [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto out_close; + } + + EVP_PKEY_free(key); + rv = PASS; +out_close: + OSSL_STORE_close(sctx); +out: + return rv; +} + +static int test_signature_sign(void) +{ + const char *uri = HBKZPC_URI_ECDSA_UV; + EVP_PKEY *signing_key; + EVP_PKEY_CTX *ctx; + int rv = FAIL; + + signing_key = uri_pkey_get1(uri); + if (!signing_key) { + fprintf(stderr, "fail: EVP_PKEY_get1 [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + rv = SKIP; + goto out; + } + + ctx = EVP_PKEY_CTX_new(signing_key, NULL); + if (ctx == NULL) { + fprintf(stderr, "fail: EVP_PKEY_CTX_new [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto pkey_out; + } + + if (EVP_PKEY_sign_init(ctx) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_PKEY_sign_init [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto ctx_out; + } + + /* Determine buffer length */ + if (EVP_PKEY_sign(ctx, NULL, &siglen, sha256, sizeof(sha256)) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_PKEY_sign [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto ctx_out; + } + + sig = OPENSSL_malloc(siglen); + if (sig == NULL) { + fprintf(stderr, "fail: malloc [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto ctx_out; + } + + if (EVP_PKEY_sign(ctx, sig, &siglen, sha256, sizeof(sha256)) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_PKEY_sign [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + OPENSSL_free(sig); + sig = NULL; + goto ctx_out; + } + + rv = PASS; +ctx_out: + EVP_PKEY_CTX_free(ctx); +pkey_out: + EVP_PKEY_free(signing_key); +out: + return rv; +} + +static int _test_signature_verify(unsigned char *s, size_t slen) +{ + const char *uri = HBKZPC_URI_ECDSA_UV; + EVP_PKEY *verify_key; + EVP_PKEY_CTX *ctx; + int rv = FAIL; + + if (!sig || !siglen) + return SKIP; + + verify_key = uri_pkey_get1(uri); + if (!verify_key) { + fprintf(stderr, "fail: EVP_PKEY_get1 [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + rv = SKIP; + goto out; + } + + ctx = EVP_PKEY_CTX_new(verify_key, NULL); + if (ctx == NULL) { + fprintf(stderr, "fail: EVP_PKEY_CTX_new [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto pkey_out; + } + + if (EVP_PKEY_verify_init(ctx) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_PKEY_verify_init [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto ctx_out; + } + + if (EVP_PKEY_verify(ctx, s, slen, sha256, sizeof(sha256)) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_PKEY_verify [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + OPENSSL_free(s); + s = NULL; + goto ctx_out; + } + + rv = PASS; +ctx_out: + EVP_PKEY_CTX_free(ctx); +pkey_out: + EVP_PKEY_free(verify_key); +out: + return rv; +} + +static int test_signature_verify(void) +{ + return _test_signature_verify(sig, siglen); +} + +static int test_signature_cross_verify(void) +{ + return _test_signature_verify(dgst_sig, dgst_siglen); +} + +static int _test_signature_digest_sign(EVP_PKEY *signing_key, + const char *msg) +{ + EVP_MD_CTX *md_ctx = NULL; + EVP_PKEY_CTX *ctx = NULL; + int rv = FAIL; + + /* just to make sure... */ + if (!signing_key) + return SKIP; + + md_ctx = EVP_MD_CTX_new(); + if (!md_ctx) { + fprintf(stderr, "fail: EVP_MD_CTX_new [%s]\n", msg); + ERR_print_errors_fp(stderr); + goto out; + } + + if (EVP_DigestSignInit_ex(md_ctx, &ctx, "SHA256", NULL, NULL, signing_key, NULL) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_DigestSignInit_ex [%s]\n", msg); + ERR_print_errors_fp(stderr); + goto out; + } + + if (EVP_DigestSignUpdate(md_ctx, text, sizeof(text)) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_DigestSignUpdate [%s]\n", msg); + ERR_print_errors_fp(stderr); + goto out; + } + + /* Determine buffer length */ + if (EVP_DigestSignFinal(md_ctx, NULL, &dgst_siglen) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_DigestSignFinal [%s]\n", msg); + ERR_print_errors_fp(stderr); + goto out; + } + + dgst_sig = OPENSSL_malloc(dgst_siglen); + if (dgst_sig == NULL) { + fprintf(stderr, "fail: malloc [%s]\n", msg); + ERR_print_errors_fp(stderr); + goto out; + } + + if (EVP_DigestSignFinal(md_ctx, dgst_sig, &dgst_siglen) != OSSL_RV_OK) { + fprintf(stderr, "fail: DigestSignFinal [%s]\n", msg); + ERR_print_errors_fp(stderr); + OPENSSL_free(dgst_sig); + dgst_sig = NULL; + goto out; + } + + rv = PASS; +out: + EVP_MD_CTX_free(md_ctx); + return rv; +} + +static int test_signature_digest_sign_uri(void) +{ + const char *uri = HBKZPC_URI_ECDSA_UV; + EVP_PKEY *signing_key = NULL; + int rv = SKIP; + + signing_key = uri_pkey_get1(uri); + if (!signing_key) { + fprintf(stderr, "fail: EVP_PKEY_get1 [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto out; + } + + rv = _test_signature_digest_sign(signing_key, "uri=" HBKZPC_URI_ECDSA_UV); +out: + EVP_PKEY_free(signing_key); + return rv; +} + +static int test_signature_digest_sign_pem(void) +{ + EVP_PKEY *signing_key = NULL; + BIO *bin = NULL; + int rv = SKIP; + + bin = BIO_new_file(default_file_pem, "r"); + if (!bin) { + fprintf(stderr, "fail: BIO_new_file [path=%s]\n", default_file_pem); + ERR_print_errors_fp(stderr); + goto out; + } + + signing_key = PEM_read_bio_PrivateKey(bin, &signing_key, NULL, ""); + if (!signing_key) { + fprintf(stderr, "fail: PEM_read_bio_PrivateKey [path=%s]\n", default_file_pem); + ERR_print_errors_fp(stderr); + goto out; + } + + rv = _test_signature_digest_sign(signing_key, "path=" HBKZPC_FILE_ECDSA_PEM); +out: + EVP_PKEY_free(signing_key); + BIO_free(bin); + return rv; +} + +static int _test_signature_digest_verify(unsigned char *t, size_t tlen, + unsigned char *s, size_t slen) +{ + const char *uri = HBKZPC_URI_ECDSA_UV; + EVP_PKEY *verify_key; + EVP_MD_CTX *md_ctx; + EVP_PKEY_CTX *ctx; + int rv = FAIL; + + if (!s || !slen) + return SKIP; + + verify_key = uri_pkey_get1(uri); + if (!verify_key) { + fprintf(stderr, "fail: EVP_PKEY_get1 [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + rv = SKIP; + goto out; + } + + md_ctx = EVP_MD_CTX_new(); + if (!md_ctx) { + fprintf(stderr, "fail: EVP_MD_CTX_new [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto pkey_out; + } + + if (EVP_DigestVerifyInit_ex(md_ctx, &ctx, "SHA256", NULL, NULL, verify_key, NULL) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_DigestVerifyInit_ex [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto md_out; + } + + if (EVP_DigestVerifyUpdate(md_ctx, t, tlen) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_DigestVerifyUpdate [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + goto md_out; + } + + if (EVP_DigestVerifyFinal(md_ctx, s, slen) != OSSL_RV_OK) { + fprintf(stderr, "fail: EVP_DigestVerifyFinal [uri=%s]\n", uri); + ERR_print_errors_fp(stderr); + s = NULL; + goto md_out; + } + + rv = PASS; +md_out: + EVP_MD_CTX_free(md_ctx); +pkey_out: + EVP_PKEY_free(verify_key); +out: + return rv; +} + +static int test_signature_digest_verify(void) +{ + return _test_signature_digest_verify(text, sizeof(text), dgst_sig, dgst_siglen); +} + +static int test_signature_cross_digest_verify(void) +{ + return _test_signature_digest_verify(text, sizeof(text), sig, siglen); +} + +static int test_uri_der_file(void) +{ + const char *uri = HBKZPC_URI_ECDSA_UV; + const char *file = default_file_der; + int rv = FAIL; + + rv = uri2file(uri, file, true) == OSSL_RV_OK ? PASS : FAIL; + if (rv == PASS) + file_der = file; + + return rv; +} + +static int test_uri_pem_file(void) +{ + const char *uri = HBKZPC_URI_ECDSA_UV; + const char *file = default_file_pem; + int rv = OSSL_RV_ERR; + + rv = uri2file(uri, file, false) == OSSL_RV_OK ? PASS : FAIL; + if (rv == PASS) + file_pem = file; + + return rv; +} + +static int test_pem_pkey(void) +{ + EVP_PKEY *signing_key = NULL; + BIO *bin = NULL; + int rv = FAIL; + + bin = BIO_new_file(default_file_pem, "r"); + if (!bin) { + fprintf(stderr, "fail: BIO_new_file [path=%s]\n", default_file_pem); + ERR_print_errors_fp(stderr); + rv = SKIP; + goto out; + } + + signing_key = PEM_read_bio_PrivateKey(bin, &signing_key, NULL, ""); + if (!signing_key) { + fprintf(stderr, "fail: PEM_read_bio_PrivateKey [path=%s]\n", default_file_pem); + ERR_print_errors_fp(stderr); + goto out; + } + + rv = PASS; + EVP_PKEY_free(signing_key); +out: + BIO_free(bin); + return rv; +} + +#define RUNTEST(t) do { fprintf(stdout, "%s - %s\n", #t, stringify(t())); } while (0) + +int main(void) +{ + RAND_bytes(text, sizeof(text)); + sha2_256(text, sizeof(text)); + + RUNTEST(test_provider); + RUNTEST(test_store_load_eof); + RUNTEST(test_store_get_pkey); + RUNTEST(test_signature_sign); + RUNTEST(test_signature_verify); + RUNTEST(test_signature_digest_sign_uri); + RUNTEST(test_signature_digest_verify); + RUNTEST(test_signature_cross_verify); + RUNTEST(test_signature_cross_digest_verify); + RUNTEST(test_uri_der_file); + RUNTEST(test_uri_pem_file); + RUNTEST(test_pem_pkey); + RUNTEST(test_signature_digest_sign_pem); + RUNTEST(test_signature_digest_verify); +}