diff --git a/.circleci/config.yml b/.circleci/config.yml index 700553d9..3d1c9d73 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -15,6 +15,7 @@ jobs: docker: - image: openquantumsafe/ci-ubuntu-focal-x86_64:latest steps: + - setup_remote_docker - checkout # change this from "checkout" to "*localCheckout" when running CircleCI locally - run: name: Clone and build liboqs @@ -27,15 +28,15 @@ jobs: name: Clone and build OpenSSL(3) command: | git clone --branch master git://git.openssl.org/openssl.git openssl && - cd openssl && ./config --prefix=$(echo $(pwd)/../.local) && make -j 4 && make install_dev && cd .. + cd openssl && ./config --prefix=$(echo $(pwd)/../.local) && make -j 4 && make install_sw && cd .. - run: name: Build OQS-OpenSSL provider command: | ./scripts/preptests.sh && mkdir _build && cd _build && cmake -GNinja -DOPENSSL_ROOT_DIR=$(pwd)/../.local -DCMAKE_PREFIX_PATH=$(pwd)/../.local .. && ninja - run: - name: Run provider tests - command: cd _build; ctest - + name: Run tests + command: | + ./scripts/runtests.sh -V workflows: version: 2.1 build: diff --git a/README.md b/README.md index f0209b16..cc24d2db 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,8 @@ Status Currently this provider fully enables quantum-safe cryptography for KEM key establishment in TLS1.3 including management of such keys via the OpenSSL (3.0) provider interface and hybrid KEM schemes. Also, OQS -signatures are available via the OpenSSL EVP interface. +signatures are available via the OpenSSL EVP interface. Key persistence is +provided via the encode/decode mechanism (still WIP for X.509). For information about the available OQS algorithms, [refer to the OQS-OpenSSL documentation](https://github.com/open-quantum-safe/openssl#supported-algorithms). @@ -34,14 +35,25 @@ If any of these features are needed, please refer to and use the [OQS-OpenSSL1.1.1](https://github.com/open-quantum-safe/openssl) fork where they are already implemented. +*Note:* `oqsprovider` depends for TLS session setup and hybrid operations +on OpenSSL providers for classic crypto operations. Therefore it is essential +that a provider such as `default` or `fips` is configured to be active. See +`tests/oqs.cnf` for an example. + +Building and testing -- Quick start +----------------------------------- + +All component builds and testing described in detail below can be executed by +running the scripts `scripts/fullbuild.sh` and `scripts/runtests.sh` respectively (tested on Linux Ubuntu and Mint). + + Building and testing -------------------- ## Pre-requisites -To be able to build `oqsprovider`, OpenSSL (3.0.0) and liboqs -need to be installed. It's not important where they are installed, just -that they are. +To be able to build `oqsprovider`, OpenSSL 3.0 and liboqs need to be installed. +It's not important where they are installed, just that they are. For building, minimum requirements are a C compiler, git access and `cmake`. For Linux these commands can typically be installed by running for example @@ -85,7 +97,7 @@ Further `liboqs` build options are [documented here](https://github.com/open-qua ## Testing -Testing can be run via the following command: +Core component testing can be run via the following command: (cd _build; ctest) @@ -95,6 +107,9 @@ Add `-V` to the `ctest` command for verbose output. activated by executing `./scripts/preptests.sh` before building the provider. See [the test README](test/README.md) for details. +Additional interoperability tests (with OQS-OpenSSL1.1.1) are available in the +script `scripts/runtests.sh`. + ## Build options ### NDEBUG diff --git a/oqs-template/generate.py b/oqs-template/generate.py index 64379ace..f5b3ee7b 100644 --- a/oqs-template/generate.py +++ b/oqs-template/generate.py @@ -9,6 +9,39 @@ import subprocess import yaml +# For files generated, the copyright message can be adapted +# see https://github.com/open-quantum-safe/oqs-provider/issues/2#issuecomment-920904048 +# SPDX message to be leading, OpenSSL Copyright notice to be deleted +def fixup_copyright(filename): + with open(filename, "r") as origfile: + with open(filename+".new", "w") as newfile: + newfile.write("// SPDX-License-Identifier: Apache-2.0 AND MIT\n\n") + skipline = False + checkline = True + for line in origfile: + if checkline==True and " * Copyright" in line: + skipline=True + if "*/" in line: + skipline=False + checkline=False + if not skipline: + newfile.write(line) + os.rename(filename+".new", filename) + +def run_subprocess(command, outfilename=None, working_dir='.', expected_returncode=0, input=None, ignore_returncode=False): + result = subprocess.run( + command, + input=input, + stdout=(open(outfilename, "w") if outfilename!=None else subprocess.PIPE), + stderr=subprocess.PIPE, + cwd=working_dir, + ) + + if not(ignore_returncode) and (result.returncode != expected_returncode): + if outfilename == None: + print(result.stdout.decode('utf-8')) + assert False, "Got unexpected return code {}".format(result.returncode) + # For list.append in Jinja templates Jinja2 = jinja2.Environment(loader=jinja2.FileSystemLoader(searchpath="."),extensions=['jinja2.ext.do']) @@ -73,11 +106,19 @@ def load_config(): config = load_config() -# For now, only activate providers: populate('test/oqs_test_signatures.c', config, '/////') populate('test/oqs_test_groups.c', config, '/////') +populate('test/oqs_test_endecode.c', config, '/////') +populate('oqsprov/oqsencoders.inc', config, '/////') +populate('oqsprov/oqsdecoders.inc', config, '/////') +populate('oqsprov/oqs_prov.h', config, '/////') populate('oqsprov/oqsprov.c', config, '/////') populate('oqsprov/oqsprov_groups.c', config, '/////') populate('oqsprov/oqs_kmgmt.c', config, '/////') populate('oqsprov/oqs_sig.c', config, '/////') +populate('oqsprov/oqs_encode_key2any.c', config, '/////') +populate('oqsprov/oqs_decode_der2key.c', config, '/////') +populate('oqsprov/oqsprov_keys.c', config, '/////') +populate('scripts/runtests.sh', config, '#####') +print("All files generated") diff --git a/oqs-template/oqsprov/oqs_decode_der2key.c/decoder_make.fragment b/oqs-template/oqsprov/oqs_decode_der2key.c/decoder_make.fragment new file mode 100644 index 00000000..0032b2d5 --- /dev/null +++ b/oqs-template/oqsprov/oqs_decode_der2key.c/decoder_make.fragment @@ -0,0 +1,7 @@ +{% for sig in config['sigs'] %} + {%- for variant in sig['variants'] %} +MAKE_DECODER("{{ variant['name'] }}", {{ variant['name'] }}, oqsx, PrivateKeyInfo); +MAKE_DECODER("{{ variant['name'] }}", {{ variant['name'] }}, oqsx, SubjectPublicKeyInfo); + {%- endfor %} +{%- endfor %} + diff --git a/oqs-template/oqsprov/oqs_encode_key2any.c/encoder_defines.fragment b/oqs-template/oqsprov/oqs_encode_key2any.c/encoder_defines.fragment new file mode 100644 index 00000000..085fe1c8 --- /dev/null +++ b/oqs-template/oqsprov/oqs_encode_key2any.c/encoder_defines.fragment @@ -0,0 +1,8 @@ +{% for sig in config['sigs'] %} + {%- for variant in sig['variants'] %} +# define {{ variant['name'] }}_evp_type 0 +# define {{ variant['name'] }}_input_type "{{ variant['name'] }}" +# define {{ variant['name'] }}_pem_type "{{ variant['name'] }}" + {%- endfor %} +{%- endfor %} + diff --git a/oqs-template/oqsprov/oqs_encode_key2any.c/encoder_make.fragment b/oqs-template/oqsprov/oqs_encode_key2any.c/encoder_make.fragment new file mode 100644 index 00000000..a91b94d8 --- /dev/null +++ b/oqs-template/oqsprov/oqs_encode_key2any.c/encoder_make.fragment @@ -0,0 +1,11 @@ +{% for sig in config['sigs'] %} + {%- for variant in sig['variants'] %} +MAKE_ENCODER({{ variant['name'] }}, oqsx, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER({{ variant['name'] }}, oqsx, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER({{ variant['name'] }}, oqsx, PrivateKeyInfo, der); +MAKE_ENCODER({{ variant['name'] }}, oqsx, PrivateKeyInfo, pem); +MAKE_ENCODER({{ variant['name'] }}, oqsx, SubjectPublicKeyInfo, der); +MAKE_ENCODER({{ variant['name'] }}, oqsx, SubjectPublicKeyInfo, pem); + {%- endfor %} +{%- endfor %} + diff --git a/oqs-template/oqsprov/oqs_kmgmt.c/keymgmt_constructors.fragment b/oqs-template/oqsprov/oqs_kmgmt.c/keymgmt_constructors.fragment index 94ea12b7..a5367e0e 100644 --- a/oqs-template/oqsprov/oqs_kmgmt.c/keymgmt_constructors.fragment +++ b/oqs-template/oqsprov/oqs_kmgmt.c/keymgmt_constructors.fragment @@ -7,7 +7,7 @@ static void *{{variant['name']}}_new_key(void *provctx) static void *{{variant['name']}}_gen_init(void *provctx, int selection) { - return oqsx_gen_init(provctx, selection, {{variant['oqs_meth']}}, 0, {{variant['security']}}); + return oqsx_gen_init(provctx, selection, {{variant['oqs_meth']}}, "{{variant['name']}}", 0, {{variant['security']}}); } {%- endfor %} diff --git a/oqs-template/oqsprov/oqsprov.c/alg_functions.fragment b/oqs-template/oqsprov/oqs_prov.h/alg_functions.fragment similarity index 100% rename from oqs-template/oqsprov/oqsprov.c/alg_functions.fragment rename to oqs-template/oqsprov/oqs_prov.h/alg_functions.fragment diff --git a/oqs-template/oqsprov/oqs_prov.h/endecoder_functions.fragment b/oqs-template/oqsprov/oqs_prov.h/endecoder_functions.fragment new file mode 100644 index 00000000..ceaae869 --- /dev/null +++ b/oqs-template/oqsprov/oqs_prov.h/endecoder_functions.fragment @@ -0,0 +1,13 @@ +{% for sig in config['sigs'] %} + {%- for variant in sig['variants'] %} +extern const OSSL_DISPATCH oqs_{{ variant['name'] }}_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_{{ variant['name'] }}_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_{{ variant['name'] }}_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_{{ variant['name'] }}_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_{{ variant['name'] }}_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_{{ variant['name'] }}_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_PrivateKeyInfo_der_to_{{ variant['name'] }}_decoder_functions[]; +extern const OSSL_DISPATCH oqs_SubjectPublicKeyInfo_der_to_{{ variant['name'] }}_decoder_functions[]; + {%- endfor %} +{%- endfor %} + diff --git a/oqs-template/oqsprov/oqs_sig.c/sig_oids.fragment b/oqs-template/oqsprov/oqs_sig.c/sig_oids.fragment index b397abcf..660912a5 100644 --- a/oqs-template/oqsprov/oqs_sig.c/sig_oids.fragment +++ b/oqs-template/oqsprov/oqs_sig.c/sig_oids.fragment @@ -1,7 +1,7 @@ {% for sig in config['sigs'] %} {%- for variant in sig['variants'] %} if (!strcmp({{variant['oqs_meth']}}, oqs_name)) - return i2d_ASN1_OBJECT(OBJ_txt2obj("{{variant['oid']}}", 1), &oidbuf); + X509_ALGOR_set0(algor, OBJ_txt2obj("{{variant['name']}}", 0), V_ASN1_UNDEF, NULL); else {%- endfor %} {%- endfor %} diff --git a/oqs-template/oqsprov/oqsdecoders.inc/make.fragment b/oqs-template/oqsprov/oqsdecoders.inc/make.fragment new file mode 100644 index 00000000..243df7b2 --- /dev/null +++ b/oqs-template/oqsprov/oqsdecoders.inc/make.fragment @@ -0,0 +1,7 @@ +{% for sig in config['sigs'] %} + {%- for variant in sig['variants'] %} +DECODER_w_structure("{{ variant['name'] }}", der, PrivateKeyInfo, {{ variant['name'] }}), +DECODER_w_structure("{{ variant['name'] }}", der, SubjectPublicKeyInfo, {{ variant['name'] }}), + {%- endfor %} +{%- endfor %} + diff --git a/oqs-template/oqsprov/oqsencoders.inc/make.fragment b/oqs-template/oqsprov/oqsencoders.inc/make.fragment new file mode 100644 index 00000000..956db8bc --- /dev/null +++ b/oqs-template/oqsprov/oqsencoders.inc/make.fragment @@ -0,0 +1,11 @@ +{% for sig in config['sigs'] %} + {%- for variant in sig['variants'] %} +ENCODER_w_structure("{{ variant['name'] }}", {{ variant['name'] }}, der, PrivateKeyInfo), +ENCODER_w_structure("{{ variant['name'] }}", {{ variant['name'] }}, pem, PrivateKeyInfo), +ENCODER_w_structure("{{ variant['name'] }}", {{ variant['name'] }}, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("{{ variant['name'] }}", {{ variant['name'] }}, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("{{ variant['name'] }}", {{ variant['name'] }}, der, SubjectPublicKeyInfo), +ENCODER_w_structure("{{ variant['name'] }}", {{ variant['name'] }}, pem, SubjectPublicKeyInfo), + {%- endfor %} +{%- endfor %} + diff --git a/oqs-template/oqsprov/oqsprov.c/assign_sig_oids.fragment b/oqs-template/oqsprov/oqsprov.c/assign_sig_oids.fragment new file mode 100644 index 00000000..6d1ad264 --- /dev/null +++ b/oqs-template/oqsprov/oqsprov.c/assign_sig_oids.fragment @@ -0,0 +1,22 @@ +{% set count = namespace(val=0) %} +{%- for sig in config['sigs'] %} + {%- for variant in sig['variants'] %} +{%- set count.val = count.val + 1 -%} + {%- for classical_alg in variant['mix_with'] %} +{%- set count.val = count.val + 1 -%} + {%- endfor %} + {%- endfor %} +{%- endfor %} +#define OQS_OID_CNT {{ count.val*2 }} +static const char* oqs_oid_alg_list[OQS_OID_CNT] = +{ + +{%- for sig in config['sigs'] %} + {%- for variant in sig['variants'] %} +"{{ variant['oid'] }}", "{{ variant['name'] }}", + {%- for classical_alg in variant['mix_with'] %} +"{{ classical_alg['oid'] }}" , "{{ classical_alg['name'] }}_{{ variant['name'] }}", + {%- endfor %} + {%- endfor %} +{%- endfor %} + diff --git a/oqs-template/oqsprov/oqsprov_keys.c/oqsnames.fragment b/oqs-template/oqsprov/oqsprov_keys.c/oqsnames.fragment new file mode 100644 index 00000000..f9786916 --- /dev/null +++ b/oqs-template/oqsprov/oqsprov_keys.c/oqsnames.fragment @@ -0,0 +1,21 @@ +{% set count = namespace(val=0) %} +{%- for sig in config['sigs'] %} +{%- for variant in sig['variants'] -%} +{%- set count.val = count.val + 1 -%} +{%- for classical_alg in variant['mix_with'] %} +{%- set count.val = count.val + 1 -%} +{%- endfor -%} +{%- endfor -%} +{%- endfor %} +#define NID_TABLE_LEN {{ count.val }} + +static oqs_nid_name_t nid_names[NID_TABLE_LEN] = { +{%- for sig in config['sigs'] -%} + {%- for variant in sig['variants'] %} + { 0, "{{variant['name']}}", {{variant['oqs_meth']}}, {{variant['security']}} }, + {%- for classical_alg in variant['mix_with'] %} + { 0, "{{ classical_alg['name'] }}_{{variant['name']}}", {{variant['oqs_meth']}}, {{variant['security']}} }, + {%- endfor %} + {%- endfor %} +{%- endfor %} + diff --git a/oqs-template/scripts/runtests.sh/algs.fragment b/oqs-template/scripts/runtests.sh/algs.fragment new file mode 100644 index 00000000..a6a945d3 --- /dev/null +++ b/oqs-template/scripts/runtests.sh/algs.fragment @@ -0,0 +1,6 @@ +{% for sig in config['sigs'] %} + {%- for variant in sig['variants'] %} +interop {{ variant['name'] }} + {%- endfor %} +{%- endfor %} + diff --git a/oqs-template/test/oqs_test_endecode.c/add.fragment b/oqs-template/test/oqs_test_endecode.c/add.fragment new file mode 100644 index 00000000..d05d3785 --- /dev/null +++ b/oqs-template/test/oqs_test_endecode.c/add.fragment @@ -0,0 +1,7 @@ +{% for sig in config['sigs'] %} + {%- for variant in sig['variants'] %} + MAKE_KEYS({{ variant['name'] }}, "{{ variant['name'] }}", NULL); + ADD_TEST_SUITE({{ variant['name'] }}); + {%- endfor %} +{%- endfor %} + diff --git a/oqs-template/test/oqs_test_endecode.c/freekeys.fragment b/oqs-template/test/oqs_test_endecode.c/freekeys.fragment new file mode 100644 index 00000000..00238fe3 --- /dev/null +++ b/oqs-template/test/oqs_test_endecode.c/freekeys.fragment @@ -0,0 +1,6 @@ +{% for sig in config['sigs'] %} + {%- for variant in sig['variants'] %} + FREE_KEYS({{ variant['name'] }}); + {%- endfor %} +{%- endfor %} + diff --git a/oqs-template/test/oqs_test_endecode.c/implement.fragment b/oqs-template/test/oqs_test_endecode.c/implement.fragment new file mode 100644 index 00000000..db19c3c2 --- /dev/null +++ b/oqs-template/test/oqs_test_endecode.c/implement.fragment @@ -0,0 +1,7 @@ +{% for sig in config['sigs'] %} + {%- for variant in sig['variants'] %} +KEYS({{ variant['name'] }}); +IMPLEMENT_TEST_SUITE({{ variant['name'] }}, "{{ variant['name'] }}") + {%- endfor %} +{%- endfor %} + diff --git a/oqsprov/CMakeLists.txt b/oqsprov/CMakeLists.txt index b6a4173f..7826d232 100644 --- a/oqsprov/CMakeLists.txt +++ b/oqsprov/CMakeLists.txt @@ -1,9 +1,11 @@ +add_compile_options(-Wunused-function) set(PROVIDER_SOURCE_FILES oqsprov.c oqsprov_groups.c oqsprov_keys.c oqs_kmgmt.c oqs_sig.c oqs_kem.c + oqs_encode_key2any.c oqs_endecoder_common.c oqs_decode_der2key.c oqsprov_bio.c ) set(PROVIDER_HEADER_FILES - oqsx.h + oqs_prov.h oqs_endecoder_local.h ) add_library(oqsprovider MODULE ${PROVIDER_SOURCE_FILES}) set_target_properties(oqsprovider diff --git a/oqsprov/oqs_decode_der2key.c b/oqsprov/oqs_decode_der2key.c new file mode 100644 index 00000000..56b06239 --- /dev/null +++ b/oqsprov/oqs_decode_der2key.c @@ -0,0 +1,619 @@ +/* + * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include +#include +#include +#include +#include +#include /* PEM_BUFSIZE and public PEM functions */ +#include +#include +#include +#include +#include +//#include "internal/asn1.h" +//instead just: +int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb); // TBD: OK to use? + +#include "oqs_endecoder_local.h" + +#ifdef NDEBUG +#define OQS_DEC_PRINTF(a) +#define OQS_DEC_PRINTF2(a, b) +#define OQS_DEC_PRINTF3(a, b, c) +#else +#define OQS_DEC_PRINTF(a) if (getenv("OQSDEC")) printf(a) +#define OQS_DEC_PRINTF2(a, b) if (getenv("OQSDEC")) printf(a, b) +#define OQS_DEC_PRINTF3(a, b, c) if (getenv("OQSDEC")) printf(a, b, c) +#endif // NDEBUG + +struct der2key_ctx_st; /* Forward declaration */ +typedef int check_key_fn(void *, struct der2key_ctx_st *ctx); +typedef void adjust_key_fn(void *, struct der2key_ctx_st *ctx); +typedef void free_key_fn(void *); +typedef void *d2i_PKCS8_fn(void **, const unsigned char **, long, + struct der2key_ctx_st *); +struct keytype_desc_st { + const char *keytype_name; + const OSSL_DISPATCH *fns; /* Keymgmt (to pilfer functions from) */ + + /* The input structure name */ + const char *structure_name; + + /* + * The EVP_PKEY_xxx type macro. Should be zero for type specific + * structures, non-zero when the outermost structure is PKCS#8 or + * SubjectPublicKeyInfo. This determines which of the function + * pointers below will be used. + */ + int evp_type; + + /* The selection mask for OSSL_FUNC_decoder_does_selection() */ + int selection_mask; + + /* For type specific decoders, we use the corresponding d2i */ + d2i_of_void *d2i_private_key; /* From type-specific DER */ + d2i_of_void *d2i_public_key; /* From type-specific DER */ + d2i_of_void *d2i_key_params; /* From type-specific DER */ + d2i_PKCS8_fn *d2i_PKCS8; /* Wrapped in a PrivateKeyInfo */ + d2i_of_void *d2i_PUBKEY; /* Wrapped in a SubjectPublicKeyInfo */ + + /* + * For any key, we may need to check that the key meets expectations. + * This is useful when the same functions can decode several variants + * of a key. + */ + check_key_fn *check_key; + + /* + * For any key, we may need to make provider specific adjustments, such + * as ensure the key carries the correct library context. + */ + adjust_key_fn *adjust_key; + /* {type}_free() */ + free_key_fn *free_key; +}; + +// Start steal. Alternative: Open up d2i_X509_PUBKEY_INTERNAL +// as per https://github.com/openssl/openssl/issues/16697 (TBD) +// stolen from openssl/crypto/x509/x_pubkey.c as ossl_d2i_X509_PUBKEY_INTERNAL not public: +// dangerous internal struct dependency: Suggest opening up ossl_d2i_X509_PUBKEY_INTERNAL +// or find out how to decode X509 with own ASN1 calls +struct X509_pubkey_st { + X509_ALGOR *algor; + ASN1_BIT_STRING *public_key; + + EVP_PKEY *pkey; + + /* extra data for the callback, used by d2i_PUBKEY_ex */ + OSSL_LIB_CTX *libctx; + char *propq; + + /* Flag to force legacy keys */ + unsigned int flag_force_legacy : 1; +}; + +ASN1_SEQUENCE(X509_PUBKEY_INTERNAL) = { + ASN1_SIMPLE(X509_PUBKEY, algor, X509_ALGOR), + ASN1_SIMPLE(X509_PUBKEY, public_key, ASN1_BIT_STRING) +} static_ASN1_SEQUENCE_END_name(X509_PUBKEY, X509_PUBKEY_INTERNAL) + +X509_PUBKEY *oqsx_d2i_X509_PUBKEY_INTERNAL(const unsigned char **pp, + long len, OSSL_LIB_CTX *libctx) +{ + X509_PUBKEY *xpub = OPENSSL_zalloc(sizeof(*xpub)); + + if (xpub == NULL) + return NULL; + return (X509_PUBKEY *)ASN1_item_d2i_ex((ASN1_VALUE **)&xpub, pp, len, + ASN1_ITEM_rptr(X509_PUBKEY_INTERNAL), + libctx, NULL); +} +// end steal TBD + + +/* + * Context used for DER to key decoding. + */ +struct der2key_ctx_st { + PROV_OQS_CTX *provctx; + struct keytype_desc_st *desc; + /* The selection that is passed to oqs_der2key_decode() */ + int selection; + /* Flag used to signal that a failure is fatal */ + unsigned int flag_fatal : 1; +}; + +int oqs_read_der(PROV_OQS_CTX *provctx, OSSL_CORE_BIO *cin, unsigned char **data, + long *len) { + OQS_DEC_PRINTF("OQS DEC provider: oqs_read_der called.\n"); + + BUF_MEM *mem = NULL; + BIO *in = oqs_bio_new_from_core_bio(provctx, cin); + int ok = (asn1_d2i_read_bio(in, &mem) >= 0); + + if (ok) { + *data = (unsigned char *)mem->data; + *len = (long)mem->length; + OPENSSL_free(mem); + } + BIO_free(in); + return ok; +} + +typedef void *key_from_pkcs8_t(const PKCS8_PRIV_KEY_INFO *p8inf, + OSSL_LIB_CTX *libctx, const char *propq); +static void *oqs_der2key_decode_p8(const unsigned char **input_der, + long input_der_len, struct der2key_ctx_st *ctx, + key_from_pkcs8_t *key_from_pkcs8) +{ + PKCS8_PRIV_KEY_INFO *p8inf = NULL; + const X509_ALGOR *alg = NULL; + void *key = NULL; + + OQS_DEC_PRINTF2("OQS DEC provider: oqs_der2key_decode_p8 called. Keytype: %d.\n", ctx->desc->evp_type); + + if ((p8inf = d2i_PKCS8_PRIV_KEY_INFO(NULL, input_der, input_der_len)) != NULL + && PKCS8_pkey_get0(NULL, NULL, NULL, &alg, p8inf) + && OBJ_obj2nid(alg->algorithm) == ctx->desc->evp_type) + key = key_from_pkcs8(p8inf, PROV_OQS_LIBCTX_OF(ctx->provctx), NULL); + PKCS8_PRIV_KEY_INFO_free(p8inf); + + return key; +} + +OQSX_KEY *oqsx_d2i_PUBKEY(OQSX_KEY **a, + const unsigned char **pp, long length) +{ + OQSX_KEY *key = NULL; + // taken from internal code for d2i_PUBKEY_int: + X509_PUBKEY *xpk; + + OQS_DEC_PRINTF2("OQS DEC provider: oqsx_d2i_PUBKEY called with length %ld\n", length); + + // only way to re-create X509 object?? TBD + xpk = oqsx_d2i_X509_PUBKEY_INTERNAL(pp, length, NULL); + + key = oqsx_key_from_x509pubkey(xpk, NULL, NULL); + + if (key == NULL) + return NULL; + + if (a != NULL) { + oqsx_key_free(*a); + *a = key; + } + return key; +} + + +/* ---------------------------------------------------------------------- */ + +static OSSL_FUNC_decoder_freectx_fn der2key_freectx; +static OSSL_FUNC_decoder_decode_fn oqs_der2key_decode; +static OSSL_FUNC_decoder_export_object_fn der2key_export_object; + +static struct der2key_ctx_st * +der2key_newctx(void *provctx, struct keytype_desc_st *desc, const char* tls_name) +{ + struct der2key_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + OQS_DEC_PRINTF3("OQS DEC provider: der2key_newctx called with tls_name %s. Keytype: %d\n", tls_name, desc->evp_type); + + if (ctx != NULL) { + ctx->provctx = provctx; + ctx->desc = desc; + if (desc->evp_type == 0) { + ctx->desc->evp_type = OBJ_sn2nid(tls_name); + OQS_DEC_PRINTF2("OQS DEC provider: der2key_newctx set evp_type to %d\n", ctx->desc->evp_type); + } + } + return ctx; +} + +static void der2key_freectx(void *vctx) +{ + struct der2key_ctx_st *ctx = vctx; + + OPENSSL_free(ctx); +} + +static int der2key_check_selection(int selection, + const struct keytype_desc_st *desc) +{ + /* + * The selections are kinda sorta "levels", i.e. each selection given + * here is assumed to include those following. + */ + int checks[] = { + OSSL_KEYMGMT_SELECT_PRIVATE_KEY, + OSSL_KEYMGMT_SELECT_PUBLIC_KEY, + OSSL_KEYMGMT_SELECT_ALL_PARAMETERS + }; + size_t i; + + OQS_DEC_PRINTF3("OQS DEC provider: der2key_check_selection called with selection %d (%d).\n", selection, desc->selection_mask); + + /* The decoder implementations made here support guessing */ + if (selection == 0) + return 1; + + for (i = 0; i < OSSL_NELEM(checks); i++) { + int check1 = (selection & checks[i]) != 0; + int check2 = (desc->selection_mask & checks[i]) != 0; + + /* + * If the caller asked for the currently checked bit(s), return + * whether the decoder description says it's supported. + */ + OQS_DEC_PRINTF3("OQS DEC provider: der2key_check_selection returning %d (%d).\n", check1, check2); + + if (check1) + return check2; + } + + /* This should be dead code, but just to be safe... */ + return 0; +} + +static int oqs_der2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection, + OSSL_CALLBACK *data_cb, void *data_cbarg, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) +{ + struct der2key_ctx_st *ctx = vctx; + unsigned char *der = NULL; + const unsigned char *derp; + long der_len = 0; + void *key = NULL; + int ok = 0; + + OQS_DEC_PRINTF("OQS DEC provider: oqs_der2key_decode called.\n"); + + ctx->selection = selection; + /* + * The caller is allowed to specify 0 as a selection mark, to have the + * structure and key type guessed. For type-specific structures, this + * is not recommended, as some structures are very similar. + * Note that 0 isn't the same as OSSL_KEYMGMT_SELECT_ALL, as the latter + * signifies a private key structure, where everything else is assumed + * to be present as well. + */ + if (selection == 0) + selection = ctx->desc->selection_mask; + if ((selection & ctx->desc->selection_mask) == 0) { + ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + + ok = oqs_read_der(ctx->provctx, cin, &der, &der_len); + if (!ok) + goto next; + + ok = 0; /* Assume that we fail */ + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + derp = der; + if (ctx->desc->d2i_PKCS8 != NULL) { + key = ctx->desc->d2i_PKCS8(NULL, &derp, der_len, ctx); + if (ctx->flag_fatal) + goto end; + } else if (ctx->desc->d2i_private_key != NULL) { + key = ctx->desc->d2i_private_key(NULL, &derp, der_len); + } + if (key == NULL && ctx->selection != 0) + goto next; + } + if (key == NULL && (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { + derp = der; + if (ctx->desc->d2i_PUBKEY != NULL) + key = ctx->desc->d2i_PUBKEY(NULL, &derp, der_len); + else + key = ctx->desc->d2i_public_key(NULL, &derp, der_len); + if (key == NULL && ctx->selection != 0) + goto next; + } + if (key == NULL && (selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0) { + derp = der; + if (ctx->desc->d2i_key_params != NULL) + key = ctx->desc->d2i_key_params(NULL, &derp, der_len); + if (key == NULL && ctx->selection != 0) + goto next; + } + + /* + * Last minute check to see if this was the correct type of key. This + * should never lead to a fatal error, i.e. the decoding itself was + * correct, it was just an unexpected key type. This is generally for + * classes of key types that have subtle variants, like RSA-PSS keys as + * opposed to plain RSA keys. + */ + if (key != NULL + && ctx->desc->check_key != NULL + && !ctx->desc->check_key(key, ctx)) { + ctx->desc->free_key(key); + key = NULL; + } + + if (key != NULL && ctx->desc->adjust_key != NULL) + ctx->desc->adjust_key(key, ctx); + + next: + /* + * Indicated that we successfully decoded something, or not at all. + * Ending up "empty handed" is not an error. + */ + ok = 1; + + /* + * We free memory here so it's not held up during the callback, because + * we know the process is recursive and the allocated chunks of memory + * add up. + */ + OPENSSL_free(der); + der = NULL; + + if (key != NULL) { + OSSL_PARAM params[4]; + int object_type = OSSL_OBJECT_PKEY; + + params[0] = + OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &object_type); + params[1] = + OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, + (char *)ctx->desc->keytype_name, + 0); + /* The address of the key becomes the octet string */ + params[2] = + OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_REFERENCE, + &key, sizeof(key)); + params[3] = OSSL_PARAM_construct_end(); + + ok = data_cb(params, data_cbarg); + } + + end: + ctx->desc->free_key(key); + OPENSSL_free(der); + + return ok; +} + +static int der2key_export_object(void *vctx, + const void *reference, size_t reference_sz, + OSSL_CALLBACK *export_cb, void *export_cbarg) +{ + struct der2key_ctx_st *ctx = vctx; + OSSL_FUNC_keymgmt_export_fn *export = + oqs_prov_get_keymgmt_export(ctx->desc->fns); + void *keydata; + + OQS_DEC_PRINTF("OQS DEC provider: der2key_export_object called.\n"); + + if (reference_sz == sizeof(keydata) && export != NULL) { + /* The contents of the reference is the address to our object */ + keydata = *(void **)reference; + + return export(keydata, ctx->selection, export_cb, export_cbarg); + } + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static void *oqsx_d2i_PKCS8(void **key, const unsigned char **der, long der_len, + struct der2key_ctx_st *ctx) +{ + OQS_DEC_PRINTF("OQS DEC provider: oqsx_d2i_PKCS8 called.\n"); + + return oqs_der2key_decode_p8(der, der_len, ctx, + (key_from_pkcs8_t *)oqsx_key_from_pkcs8); +} + +static void oqsx_key_adjust(void *key, struct der2key_ctx_st *ctx) +{ + OQS_DEC_PRINTF("OQS DEC provider: oqsx_key_adjust called.\n"); + + oqsx_key_set0_libctx(key, PROV_OQS_LIBCTX_OF(ctx->provctx)); +} + + +// OQS provider uses NIDs generated at load time as EVP_type identifiers +// so initially this must be 0 and set to a real value by OBJ_sn2nid later + + +/* ---------------------------------------------------------------------- */ + +/* + * The DO_ macros help define the selection mask and the method functions + * for each kind of object we want to decode. + */ +#define DO_type_specific_keypair(keytype) \ + "type-specific", 0, \ + ( OSSL_KEYMGMT_SELECT_KEYPAIR ), \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + oqsx_key_adjust, \ + (free_key_fn *)oqsx_key_free + +#define DO_type_specific_pub(keytype) \ + "type-specific", 0, \ + ( OSSL_KEYMGMT_SELECT_PUBLIC_KEY ), \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + oqsx_key_adjust, \ + (free_key_fn *)oqsx_key_free + +#define DO_type_specific_priv(keytype) \ + "type-specific", 0, \ + ( OSSL_KEYMGMT_SELECT_PRIVATE_KEY ), \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + oqsx_key_adjust, \ + (free_key_fn *)oqsx_key_free + +#define DO_type_specific_params(keytype) \ + "type-specific", 0, \ + ( OSSL_KEYMGMT_SELECT_ALL_PARAMETERS ), \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + oqsx_key_adjust, \ + (free_key_fn *)oqsx_key_free + +#define DO_type_specific(keytype) \ + "type-specific", 0, \ + ( OSSL_KEYMGMT_SELECT_ALL ), \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + oqsx_key_adjust, \ + (free_key_fn *)oqsx_key_free + +#define DO_type_specific_no_pub(keytype) \ + "type-specific", 0, \ + ( OSSL_KEYMGMT_SELECT_PRIVATE_KEY \ + | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS ), \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + oqsx_key_adjust, \ + (free_key_fn *)oqsx_key_free + +#define DO_PrivateKeyInfo(keytype) \ + "PrivateKeyInfo", 0, \ + ( OSSL_KEYMGMT_SELECT_PRIVATE_KEY ), \ + NULL, \ + NULL, \ + NULL, \ + oqsx_d2i_PKCS8, \ + NULL, \ + NULL, \ + oqsx_key_adjust, \ + (free_key_fn *)oqsx_key_free + +#define DO_SubjectPublicKeyInfo(keytype) \ + "SubjectPublicKeyInfo", 0, \ + ( OSSL_KEYMGMT_SELECT_PUBLIC_KEY ), \ + NULL, \ + NULL, \ + NULL, \ + NULL, \ + (d2i_of_void *)oqsx_d2i_PUBKEY, \ + NULL, \ + oqsx_key_adjust, \ + (free_key_fn *)oqsx_key_free + +/* + * MAKE_DECODER is the single driver for creating OSSL_DISPATCH tables. + * It takes the following arguments: + * + * keytype_name The implementation key type as a string. + * keytype The implementation key type. This must correspond exactly + * to our existing keymgmt keytype names... in other words, + * there must exist an ossl_##keytype##_keymgmt_functions. + * type The type name for the set of functions that implement the + * decoder for the key type. This isn't necessarily the same + * as keytype. For example, the key types ed25519, ed448, + * x25519 and x448 are all handled by the same functions with + * the common type name ecx. + * kind The kind of support to implement. This translates into + * the DO_##kind macros above, to populate the keytype_desc_st + * structure. + */ +// reverted const to be able to change NID/evp_type after assignment +#define MAKE_DECODER(keytype_name, keytype, type, kind) \ + static struct keytype_desc_st kind##_##keytype##_desc = \ + { keytype_name, oqs_##keytype##_keymgmt_functions, \ + DO_##kind(keytype) }; \ + \ + static OSSL_FUNC_decoder_newctx_fn kind##_der2##keytype##_newctx; \ + \ + static void *kind##_der2##keytype##_newctx(void *provctx) \ + { \ + OQS_DEC_PRINTF("OQS DEC provider: _newctx called.\n"); \ + return der2key_newctx(provctx, &kind##_##keytype##_desc, keytype_name ); \ + } \ + static int kind##_der2##keytype##_does_selection(void *provctx, \ + int selection) \ + { \ + OQS_DEC_PRINTF("OQS DEC provider: _does_selection called.\n"); \ + return der2key_check_selection(selection, \ + &kind##_##keytype##_desc); \ + } \ + const OSSL_DISPATCH \ + oqs_##kind##_der_to_##keytype##_decoder_functions[] = { \ + { OSSL_FUNC_DECODER_NEWCTX, \ + (void (*)(void))kind##_der2##keytype##_newctx }, \ + { OSSL_FUNC_DECODER_FREECTX, \ + (void (*)(void))der2key_freectx }, \ + { OSSL_FUNC_DECODER_DOES_SELECTION, \ + (void (*)(void))kind##_der2##keytype##_does_selection }, \ + { OSSL_FUNC_DECODER_DECODE, \ + (void (*)(void))oqs_der2key_decode }, \ + { OSSL_FUNC_DECODER_EXPORT_OBJECT, \ + (void (*)(void))der2key_export_object }, \ + { 0, NULL } \ + } + +///// OQS_TEMPLATE_FRAGMENT_DECODER_MAKE_START +MAKE_DECODER("dilithium2", dilithium2, oqsx, PrivateKeyInfo); +MAKE_DECODER("dilithium2", dilithium2, oqsx, SubjectPublicKeyInfo); +MAKE_DECODER("dilithium3", dilithium3, oqsx, PrivateKeyInfo); +MAKE_DECODER("dilithium3", dilithium3, oqsx, SubjectPublicKeyInfo); +MAKE_DECODER("dilithium5", dilithium5, oqsx, PrivateKeyInfo); +MAKE_DECODER("dilithium5", dilithium5, oqsx, SubjectPublicKeyInfo); +MAKE_DECODER("dilithium2_aes", dilithium2_aes, oqsx, PrivateKeyInfo); +MAKE_DECODER("dilithium2_aes", dilithium2_aes, oqsx, SubjectPublicKeyInfo); +MAKE_DECODER("dilithium3_aes", dilithium3_aes, oqsx, PrivateKeyInfo); +MAKE_DECODER("dilithium3_aes", dilithium3_aes, oqsx, SubjectPublicKeyInfo); +MAKE_DECODER("dilithium5_aes", dilithium5_aes, oqsx, PrivateKeyInfo); +MAKE_DECODER("dilithium5_aes", dilithium5_aes, oqsx, SubjectPublicKeyInfo); +MAKE_DECODER("falcon512", falcon512, oqsx, PrivateKeyInfo); +MAKE_DECODER("falcon512", falcon512, oqsx, SubjectPublicKeyInfo); +MAKE_DECODER("falcon1024", falcon1024, oqsx, PrivateKeyInfo); +MAKE_DECODER("falcon1024", falcon1024, oqsx, SubjectPublicKeyInfo); +MAKE_DECODER("picnicl1full", picnicl1full, oqsx, PrivateKeyInfo); +MAKE_DECODER("picnicl1full", picnicl1full, oqsx, SubjectPublicKeyInfo); +MAKE_DECODER("picnic3l1", picnic3l1, oqsx, PrivateKeyInfo); +MAKE_DECODER("picnic3l1", picnic3l1, oqsx, SubjectPublicKeyInfo); +MAKE_DECODER("rainbowIclassic", rainbowIclassic, oqsx, PrivateKeyInfo); +MAKE_DECODER("rainbowIclassic", rainbowIclassic, oqsx, SubjectPublicKeyInfo); +MAKE_DECODER("rainbowVclassic", rainbowVclassic, oqsx, PrivateKeyInfo); +MAKE_DECODER("rainbowVclassic", rainbowVclassic, oqsx, SubjectPublicKeyInfo); +MAKE_DECODER("sphincsharaka128frobust", sphincsharaka128frobust, oqsx, PrivateKeyInfo); +MAKE_DECODER("sphincsharaka128frobust", sphincsharaka128frobust, oqsx, SubjectPublicKeyInfo); +MAKE_DECODER("sphincssha256128frobust", sphincssha256128frobust, oqsx, PrivateKeyInfo); +MAKE_DECODER("sphincssha256128frobust", sphincssha256128frobust, oqsx, SubjectPublicKeyInfo); +MAKE_DECODER("sphincsshake256128frobust", sphincsshake256128frobust, oqsx, PrivateKeyInfo); +MAKE_DECODER("sphincsshake256128frobust", sphincsshake256128frobust, oqsx, SubjectPublicKeyInfo); +///// OQS_TEMPLATE_FRAGMENT_DECODER_MAKE_END + diff --git a/oqsprov/oqs_encode_key2any.c b/oqsprov/oqs_encode_key2any.c new file mode 100644 index 00000000..6fe60438 --- /dev/null +++ b/oqsprov/oqs_encode_key2any.c @@ -0,0 +1,1095 @@ +// SPDX-License-Identifier: Apache-2.0 AND MIT + +/* + * OQS OpenSSL 3 provider + * + * Code strongly inspired by OpenSSL endecoder. + * + * ToDo: Adding hybrid alg support + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* PKCS8_encrypt() */ +//#include +//#include +//#include +#include +//#include "internal/passphrase.h" +//#include "internal/cryptlib.h" +//#include "crypto/ecx.h" +//#include "prov/bio.h" +#include +#include "oqs_endecoder_local.h" + +#ifdef NDEBUG +#define OQS_ENC_PRINTF(a) +#define OQS_ENC_PRINTF2(a, b) +#define OQS_ENC_PRINTF3(a, b, c) +#else +#define OQS_ENC_PRINTF(a) if (getenv("OQSENC")) printf(a) +#define OQS_ENC_PRINTF2(a, b) if (getenv("OQSENC")) printf(a, b) +#define OQS_ENC_PRINTF3(a, b, c) if (getenv("OQSENC")) printf(a, b, c) +#endif // NDEBUG + +void empty_func(void) { +printf("MIB was here\n"); +} + +struct key2any_ctx_st { + PROV_OQS_CTX *provctx; + + /* Set to 0 if parameters should not be saved (dsa only) */ + int save_parameters; + + /* Set to 1 if intending to encrypt/decrypt, otherwise 0 */ + int cipher_intent; + + EVP_CIPHER *cipher; + + OSSL_PASSPHRASE_CALLBACK *pwcb; + void *pwcbarg; +}; + +typedef int check_key_type_fn(const void *key, int nid); +typedef int key_to_paramstring_fn(const void *key, int nid, int save, + void **str, int *strtype); +typedef int key_to_der_fn(BIO *out, const void *key, + int key_nid, const char *pemname, + key_to_paramstring_fn *p2s, i2d_of_void *k2d, + struct key2any_ctx_st *ctx); +typedef int write_bio_of_void_fn(BIO *bp, const void *x); + + +/* Free the blob allocated during key_to_paramstring_fn */ +static void free_asn1_data(int type, void *data) +{ + switch(type) { + case V_ASN1_OBJECT: + ASN1_OBJECT_free(data); + break; + case V_ASN1_SEQUENCE: + ASN1_STRING_free(data); + break; + } +} + +static PKCS8_PRIV_KEY_INFO *key_to_p8info(const void *key, int key_nid, + void *params, int params_type, + i2d_of_void *k2d) +{ + /* der, derlen store the key DER output and its length */ + unsigned char *der = NULL; + int derlen; + /* The final PKCS#8 info */ + PKCS8_PRIV_KEY_INFO *p8info = NULL; + + OQS_ENC_PRINTF("OQS ENC provider: key_to_p8info called\n"); + + if ((p8info = PKCS8_PRIV_KEY_INFO_new()) == NULL + || (derlen = k2d(key, &der)) <= 0 + || !PKCS8_pkey_set0(p8info, OBJ_nid2obj(key_nid), 0, + // doesn't work with oqs-openssl: + // params_type, params, + // does work/interop: + V_ASN1_UNDEF, NULL, + der, derlen)) { + ERR_raise(ERR_LIB_USER, ERR_R_MALLOC_FAILURE); + PKCS8_PRIV_KEY_INFO_free(p8info); + OPENSSL_free(der); + p8info = NULL; + } + + return p8info; +} + +static X509_SIG *p8info_to_encp8(PKCS8_PRIV_KEY_INFO *p8info, + struct key2any_ctx_st *ctx) +{ + X509_SIG *p8 = NULL; + char kstr[PEM_BUFSIZE]; + size_t klen = 0; + OSSL_LIB_CTX *libctx = PROV_OQS_LIBCTX_OF(ctx->provctx); + + OQS_ENC_PRINTF("OQS ENC provider: p8info_to_encp8 called\n"); + + if (ctx->cipher == NULL || ctx->pwcb == NULL) + return NULL; + + if (!ctx->pwcb(kstr, PEM_BUFSIZE, &klen, NULL, ctx->pwcbarg)) { + ERR_raise(ERR_LIB_USER, PROV_R_UNABLE_TO_GET_PASSPHRASE); + return NULL; + } + /* First argument == -1 means "standard" */ + p8 = PKCS8_encrypt_ex(-1, ctx->cipher, kstr, klen, NULL, 0, 0, p8info, libctx, NULL); + OPENSSL_cleanse(kstr, klen); + return p8; +} + +static X509_SIG *key_to_encp8(const void *key, int key_nid, + void *params, int params_type, + i2d_of_void *k2d, struct key2any_ctx_st *ctx) +{ + PKCS8_PRIV_KEY_INFO *p8info = + key_to_p8info(key, key_nid, params, params_type, k2d); + X509_SIG *p8 = NULL; + + OQS_ENC_PRINTF("OQS ENC provider: key_to_encp8 called\n"); + + if (p8info == NULL) { + free_asn1_data(params_type, params); + } else { + p8 = p8info_to_encp8(p8info, ctx); + PKCS8_PRIV_KEY_INFO_free(p8info); + } + return p8; +} + +static X509_PUBKEY *oqsx_key_to_pubkey(const void *key, int key_nid, + void *params, int params_type, + i2d_of_void k2d) +{ + /* der, derlen store the key DER output and its length */ + unsigned char *der = NULL; + int derlen; + /* The final X509_PUBKEY */ + X509_PUBKEY *xpk = NULL; + + OQS_ENC_PRINTF("OQS ENC provider: oqsx_key_to_pubkey called\n"); + + if ((xpk = X509_PUBKEY_new()) == NULL + || (derlen = k2d(key, &der)) <= 0 + || !X509_PUBKEY_set0_param(xpk, OBJ_nid2obj(key_nid), + V_ASN1_UNDEF, NULL, // as per logic in oqs_meth.c in oqs-openssl + der, derlen)) { + ERR_raise(ERR_LIB_USER, ERR_R_MALLOC_FAILURE); + X509_PUBKEY_free(xpk); + OPENSSL_free(der); + xpk = NULL; + } + + return xpk; +} + +/* + * key_to_epki_* produce encoded output with the private key data in a + * EncryptedPrivateKeyInfo structure (defined by PKCS#8). They require + * that there's an intent to encrypt, anything else is an error. + * + * key_to_pki_* primarly produce encoded output with the private key data + * in a PrivateKeyInfo structure (also defined by PKCS#8). However, if + * there is an intent to encrypt the data, the corresponding key_to_epki_* + * function is used instead. + * + * key_to_spki_* produce encoded output with the public key data in an + * X.509 SubjectPublicKeyInfo. + * + * Key parameters don't have any defined envelopment of this kind, but are + * included in some manner in the output from the functions described above, + * either in the AlgorithmIdentifier's parameter field, or as part of the + * key data itself. + */ + +static int key_to_epki_der_priv_bio(BIO *out, const void *key, + int key_nid, + ossl_unused const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx) +{ + int ret = 0; + void *str = NULL; + int strtype = V_ASN1_UNDEF; + X509_SIG *p8; + + OQS_ENC_PRINTF("OQS ENC provider: key_to_epki_der_priv_bio called\n"); + + if (!ctx->cipher_intent) + return 0; + + if (p2s != NULL && !p2s(key, key_nid, ctx->save_parameters, + &str, &strtype)) + return 0; + + p8 = key_to_encp8(key, key_nid, str, strtype, k2d, ctx); + if (p8 != NULL) + ret = i2d_PKCS8_bio(out, p8); + + X509_SIG_free(p8); + + return ret; +} + +static int key_to_epki_pem_priv_bio(BIO *out, const void *key, + int key_nid, + ossl_unused const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx) +{ + int ret = 0; + void *str = NULL; + int strtype = V_ASN1_UNDEF; + X509_SIG *p8; + + OQS_ENC_PRINTF("OQS ENC provider: key_to_epki_pem_priv_bio called\n"); + + if (!ctx->cipher_intent) + return 0; + + if (p2s != NULL && !p2s(key, key_nid, ctx->save_parameters, + &str, &strtype)) + return 0; + + p8 = key_to_encp8(key, key_nid, str, strtype, k2d, ctx); + if (p8 != NULL) + ret = PEM_write_bio_PKCS8(out, p8); + + X509_SIG_free(p8); + + return ret; +} + +static int key_to_pki_der_priv_bio(BIO *out, const void *key, + int key_nid, + ossl_unused const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx) +{ + int ret = 0; + void *str = NULL; + int strtype = V_ASN1_UNDEF; + PKCS8_PRIV_KEY_INFO *p8info; + + OQS_ENC_PRINTF("OQS ENC provider: key_to_pki_der_priv_bio called\n"); + + if (ctx->cipher_intent) + return key_to_epki_der_priv_bio(out, key, key_nid, pemname, + p2s, k2d, ctx); + + if (p2s != NULL && !p2s(key, key_nid, ctx->save_parameters, + &str, &strtype)) + return 0; + + p8info = key_to_p8info(key, key_nid, str, strtype, k2d); + + if (p8info != NULL) + ret = i2d_PKCS8_PRIV_KEY_INFO_bio(out, p8info); + else + free_asn1_data(strtype, str); + + PKCS8_PRIV_KEY_INFO_free(p8info); + + return ret; +} + +static int key_to_pki_pem_priv_bio(BIO *out, const void *key, + int key_nid, + ossl_unused const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx) +{ + int ret = 0; + void *str = NULL; + int strtype = V_ASN1_UNDEF; + PKCS8_PRIV_KEY_INFO *p8info; + + OQS_ENC_PRINTF("OQS ENC provider: key_to_pki_pem_priv_bio called\n"); + + if (ctx->cipher_intent) + return key_to_epki_pem_priv_bio(out, key, key_nid, pemname, + p2s, k2d, ctx); + + if (p2s != NULL && !p2s(key, key_nid, ctx->save_parameters, + &str, &strtype)) + return 0; + + p8info = key_to_p8info(key, key_nid, str, strtype, k2d); + + if (p8info != NULL) + ret = PEM_write_bio_PKCS8_PRIV_KEY_INFO(out, p8info); + else + free_asn1_data(strtype, str); + + PKCS8_PRIV_KEY_INFO_free(p8info); + + return ret; +} + +static int key_to_spki_der_pub_bio(BIO *out, const void *key, + int key_nid, + ossl_unused const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx) +{ + int ret = 0; + OQSX_KEY* okey = (OQSX_KEY*)key; + X509_PUBKEY *xpk = NULL; + void *str = NULL; + int strtype = V_ASN1_UNDEF; + + OQS_ENC_PRINTF("OQS ENC provider: key_to_spki_der_pub_bio called\n"); + + if (p2s != NULL && !p2s(key, key_nid, ctx->save_parameters, + &str, &strtype)) + return 0; + + xpk = oqsx_key_to_pubkey(key, key_nid, str, strtype, k2d); + + if (xpk != NULL) + ret = i2d_X509_PUBKEY_bio(out, xpk); + + X509_PUBKEY_free(xpk); + return ret; +} + +static int key_to_spki_pem_pub_bio(BIO *out, const void *key, + int key_nid, + ossl_unused const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx) +{ + int ret = 0; + X509_PUBKEY *xpk = NULL; + void *str = NULL; + int strtype = V_ASN1_UNDEF; + + OQS_ENC_PRINTF("OQS ENC provider: key_to_spki_pem_pub_bio called\n"); + + if (p2s != NULL && !p2s(key, key_nid, ctx->save_parameters, + &str, &strtype)) + return 0; + + xpk = oqsx_key_to_pubkey(key, key_nid, str, strtype, k2d); + + if (xpk != NULL) + ret = PEM_write_bio_X509_PUBKEY(out, xpk); + else + free_asn1_data(strtype, str); + + /* Also frees |str| */ + X509_PUBKEY_free(xpk); + return ret; +} + +/* + * key_to_type_specific_* produce encoded output with type specific key data, + * no envelopment; the same kind of output as the type specific i2d_ and + * PEM_write_ functions, which is often a simple SEQUENCE of INTEGER. + * + * OpenSSL tries to discourage production of new keys in this form, because + * of the ambiguity when trying to recognise them, but can't deny that PKCS#1 + * et al still are live standards. + * + * Note that these functions completely ignore p2s, and rather rely entirely + * on k2d to do the complete work. + */ +/* +static int key_to_type_specific_der_bio(BIO *out, const void *key, + int key_nid, + ossl_unused const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx) +{ + unsigned char *der = NULL; + int derlen; + int ret; + + OQS_ENC_PRINTF("OQS ENC provider: key_to_type_specific_der_bio called\n"); + + if ((derlen = k2d(key, &der)) <= 0) { + ERR_raise(ERR_LIB_USER, ERR_R_MALLOC_FAILURE); + return 0; + } + + ret = BIO_write(out, der, derlen); + OPENSSL_free(der); + return ret > 0; +} +#define key_to_type_specific_der_priv_bio key_to_type_specific_der_bio +#define key_to_type_specific_der_pub_bio key_to_type_specific_der_bio +#define key_to_type_specific_der_param_bio key_to_type_specific_der_bio + +static int key_to_type_specific_pem_bio_cb(BIO *out, const void *key, + int key_nid, const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx) +{ + OQS_ENC_PRINTF("OQS ENC provider: key_to_type_specific_pem_bio_cb called \n"); + + return PEM_ASN1_write_bio(k2d, pemname, out, key, ctx->cipher, + NULL, 0, ctx->pwcb, ctx->pwcbarg) > 0; +} + +static int key_to_type_specific_pem_priv_bio(BIO *out, const void *key, + int key_nid, const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx) +{ + OQS_ENC_PRINTF("OQS ENC provider: key_to_type_specific_pem_priv_bio called\n"); + + return key_to_type_specific_pem_bio_cb(out, key, key_nid, pemname, + p2s, k2d, ctx, ctx->pwcb, ctx->pwcbarg); + +} + +static int key_to_type_specific_pem_pub_bio(BIO *out, const void *key, + int key_nid, const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx) +{ + OQS_ENC_PRINTF("OQS ENC provider: key_to_type_specific_pem_pub_bio called\n"); + + return key_to_type_specific_pem_bio_cb(out, key, key_nid, pemname, + p2s, k2d, ctx, NULL, NULL); +} + +#ifndef OPENSSL_NO_KEYPARAMS +static int key_to_type_specific_pem_param_bio(BIO *out, const void *key, + int key_nid, const char *pemname, + key_to_paramstring_fn *p2s, + i2d_of_void *k2d, + struct key2any_ctx_st *ctx) +{ + OQS_ENC_PRINTF("OQS ENC provider: key_to_type_specific_pem_param_bio called\n"); + + return key_to_type_specific_pem_bio_cb(out, key, key_nid, pemname, + p2s, k2d, ctx, NULL, NULL); +} +#endif +*/ +/* ---------------------------------------------------------------------- */ + +static int prepare_oqsx_params(const void *oqsxkey, int nid, int save, + void **pstr, int *pstrtype) +{ + ASN1_OBJECT *params = NULL; + OQSX_KEY *k = (OQSX_KEY*)oqsxkey; + + OQS_ENC_PRINTF3("OQS ENC provider: prepare_oqsx_params called with nid %d (tlsname: %s)\n", nid, k->tls_name); + + if (k->tls_name && OBJ_sn2nid(k->tls_name) != nid) { + ERR_raise(ERR_LIB_USER, OQSPROV_R_INVALID_KEY); + return 0; + } + + if (nid != NID_undef) { + params = OBJ_nid2obj(nid); + if (params == NULL) + return 0; + } + else { + ERR_raise(ERR_LIB_USER, OQSPROV_R_MISSING_OID); + return 0; + } + + + if (OBJ_length(params) == 0) { + /* unexpected error */ + ERR_raise(ERR_LIB_USER, OQSPROV_R_MISSING_OID); + ASN1_OBJECT_free(params); + return 0; + } + *pstr = params; + *pstrtype = V_ASN1_OBJECT; + return 1; +} + + +# define prepare_ecx_params NULL + +static int oqsx_spki_pub_to_der(const void *vecxkey, unsigned char **pder) +{ + const OQSX_KEY *oqsxkey = vecxkey; + unsigned char *keyblob; + + OQS_ENC_PRINTF("OQS ENC provider: oqsx_spki_pub_to_der called\n"); + + if (oqsxkey == NULL) { + ERR_raise(ERR_LIB_USER, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + keyblob = OPENSSL_memdup(oqsxkey->pubkey, oqsxkey->pubkeylen); + if (keyblob == NULL) { + ERR_raise(ERR_LIB_USER, ERR_R_MALLOC_FAILURE); + return 0; + } + + *pder = keyblob; + return oqsxkey->pubkeylen; +} + +static int oqsx_pki_priv_to_der(const void *vecxkey, unsigned char **pder) +{ + const OQSX_KEY *oqsxkey = vecxkey; + unsigned char* buf = NULL; + int buflen = 0; + ASN1_OCTET_STRING oct; + int keybloblen; + + OQS_ENC_PRINTF("OQS ENC provider: oqsx_pki_priv_to_der called\n"); + + // Encoding private _and_ public key concatenated ... seems unlogical and unnecessary, + // but is what oqs-openssl does, so we repeat it for interop... also from a security + // perspective not really smart to copy key material (side channel attacks, anyone?), + // but so be it. + if (oqsxkey == NULL || oqsxkey->privkey == NULL || oqsxkey->pubkey == NULL) { + ERR_raise(ERR_LIB_USER, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + // TBC: Extend with hybrid keys + buflen = oqsxkey->privkeylen+oqsxkey->pubkeylen; + buf = OPENSSL_secure_malloc(buflen); + OQS_ENC_PRINTF2("OQS ENC provider: saving priv+pubkey of length %d\n", buflen); + memcpy(buf, oqsxkey->privkey, oqsxkey->privkeylen); + memcpy(buf+oqsxkey->privkeylen, oqsxkey->pubkey, oqsxkey->pubkeylen); + + oct.data = buf; + oct.length = buflen; + // more logical: + //oct.data = oqsxkey->privkey; + //oct.length = oqsxkey->privkeylen; + oct.flags = 0; + + keybloblen = i2d_ASN1_OCTET_STRING(&oct, pder); + if (keybloblen < 0) { + ERR_raise(ERR_LIB_USER, ERR_R_MALLOC_FAILURE); + keybloblen = 0; // signal error + } + + OPENSSL_secure_clear_free(buf, buflen); + return keybloblen; +} + +# define oqsx_epki_priv_to_der oqsx_pki_priv_to_der + +/* + * OQSX only has PKCS#8 / SubjectPublicKeyInfo + * representation, so we don't define oqsx_type_specific_[priv,pub,params]_to_der. + */ + +# define oqsx_check_key_type NULL + +// OQS provider uses NIDs generated at load time as EVP_type identifiers +// so initially this must be 0 and set to a real value by OBJ_sn2nid later +///// OQS_TEMPLATE_FRAGMENT_ENCODER_DEFINES_START +# define dilithium2_evp_type 0 +# define dilithium2_input_type "dilithium2" +# define dilithium2_pem_type "dilithium2" +# define dilithium3_evp_type 0 +# define dilithium3_input_type "dilithium3" +# define dilithium3_pem_type "dilithium3" +# define dilithium5_evp_type 0 +# define dilithium5_input_type "dilithium5" +# define dilithium5_pem_type "dilithium5" +# define dilithium2_aes_evp_type 0 +# define dilithium2_aes_input_type "dilithium2_aes" +# define dilithium2_aes_pem_type "dilithium2_aes" +# define dilithium3_aes_evp_type 0 +# define dilithium3_aes_input_type "dilithium3_aes" +# define dilithium3_aes_pem_type "dilithium3_aes" +# define dilithium5_aes_evp_type 0 +# define dilithium5_aes_input_type "dilithium5_aes" +# define dilithium5_aes_pem_type "dilithium5_aes" +# define falcon512_evp_type 0 +# define falcon512_input_type "falcon512" +# define falcon512_pem_type "falcon512" +# define falcon1024_evp_type 0 +# define falcon1024_input_type "falcon1024" +# define falcon1024_pem_type "falcon1024" +# define picnicl1full_evp_type 0 +# define picnicl1full_input_type "picnicl1full" +# define picnicl1full_pem_type "picnicl1full" +# define picnic3l1_evp_type 0 +# define picnic3l1_input_type "picnic3l1" +# define picnic3l1_pem_type "picnic3l1" +# define rainbowIclassic_evp_type 0 +# define rainbowIclassic_input_type "rainbowIclassic" +# define rainbowIclassic_pem_type "rainbowIclassic" +# define rainbowVclassic_evp_type 0 +# define rainbowVclassic_input_type "rainbowVclassic" +# define rainbowVclassic_pem_type "rainbowVclassic" +# define sphincsharaka128frobust_evp_type 0 +# define sphincsharaka128frobust_input_type "sphincsharaka128frobust" +# define sphincsharaka128frobust_pem_type "sphincsharaka128frobust" +# define sphincssha256128frobust_evp_type 0 +# define sphincssha256128frobust_input_type "sphincssha256128frobust" +# define sphincssha256128frobust_pem_type "sphincssha256128frobust" +# define sphincsshake256128frobust_evp_type 0 +# define sphincsshake256128frobust_input_type "sphincsshake256128frobust" +# define sphincsshake256128frobust_pem_type "sphincsshake256128frobust" +///// OQS_TEMPLATE_FRAGMENT_ENCODER_DEFINES_END + +/* ---------------------------------------------------------------------- */ + +static OSSL_FUNC_decoder_newctx_fn key2any_newctx; +static OSSL_FUNC_decoder_freectx_fn key2any_freectx; + +static void *key2any_newctx(void *provctx) +{ + struct key2any_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + OQS_ENC_PRINTF("OQS ENC provider: key2any_newctx called\n"); + + if (ctx != NULL) { + ctx->provctx = provctx; + ctx->save_parameters = 1; + } + + return ctx; +} + +static void key2any_freectx(void *vctx) +{ + struct key2any_ctx_st *ctx = vctx; + + OQS_ENC_PRINTF("OQS ENC provider: key2any_freectx called\n"); + + EVP_CIPHER_free(ctx->cipher); + OPENSSL_free(ctx); +} + +static const OSSL_PARAM *key2any_settable_ctx_params(ossl_unused void *provctx) +{ + static const OSSL_PARAM settables[] = { + OSSL_PARAM_utf8_string(OSSL_ENCODER_PARAM_CIPHER, NULL, 0), + OSSL_PARAM_utf8_string(OSSL_ENCODER_PARAM_PROPERTIES, NULL, 0), + OSSL_PARAM_END, + }; + + OQS_ENC_PRINTF("OQS ENC provider: key2any_settable_ctx_params called\n"); + + return settables; +} + +static int key2any_set_ctx_params(void *vctx, const OSSL_PARAM params[]) +{ + struct key2any_ctx_st *ctx = vctx; + OSSL_LIB_CTX *libctx = ctx->provctx->libctx; + const OSSL_PARAM *cipherp = + OSSL_PARAM_locate_const(params, OSSL_ENCODER_PARAM_CIPHER); + const OSSL_PARAM *propsp = + OSSL_PARAM_locate_const(params, OSSL_ENCODER_PARAM_PROPERTIES); + const OSSL_PARAM *save_paramsp = + OSSL_PARAM_locate_const(params, OSSL_ENCODER_PARAM_SAVE_PARAMETERS); + + OQS_ENC_PRINTF("OQS ENC provider: key2any_set_ctx_params called\n"); + + if (cipherp != NULL) { + const char *ciphername = NULL; + const char *props = NULL; + + if (!OSSL_PARAM_get_utf8_string_ptr(cipherp, &ciphername)) + return 0; + OQS_ENC_PRINTF2(" setting cipher: %s\n", ciphername); + if (propsp != NULL && !OSSL_PARAM_get_utf8_string_ptr(propsp, &props)) + return 0; + + EVP_CIPHER_free(ctx->cipher); + ctx->cipher = NULL; + ctx->cipher_intent = ciphername != NULL; + if (ciphername != NULL + && ((ctx->cipher = + EVP_CIPHER_fetch(libctx, ciphername, props)) == NULL)) { + return 0; + } + } + + if (save_paramsp != NULL) { + if (!OSSL_PARAM_get_int(save_paramsp, &ctx->save_parameters)) { + return 0; + } + } + OQS_ENC_PRINTF2(" cipher set to %p: \n", ctx->cipher); + return 1; +} + +static int key2any_check_selection(int selection, int selection_mask) +{ + /* + * The selections are kinda sorta "levels", i.e. each selection given + * here is assumed to include those following. + */ + int checks[] = { + OSSL_KEYMGMT_SELECT_PRIVATE_KEY, + OSSL_KEYMGMT_SELECT_PUBLIC_KEY, + OSSL_KEYMGMT_SELECT_ALL_PARAMETERS + }; + size_t i; + + OQS_ENC_PRINTF3("OQS ENC provider: key2any_check_selection called with selection %d (%d)\n",selection, selection_mask); + + /* The decoder implementations made here support guessing */ + if (selection == 0) + return 1; + + for (i = 0; i < OSSL_NELEM(checks); i++) { + int check1 = (selection & checks[i]) != 0; + int check2 = (selection_mask & checks[i]) != 0; + + /* + * If the caller asked for the currently checked bit(s), return + * whether the decoder description says it's supported. + */ + if (check1) { + OQS_ENC_PRINTF2("OQS ENC provider: key2any_check_selection returns %d\n", check2); + return check2; + } + } + + /* This should be dead code, but just to be safe... */ + return 0; +} + +static int key2any_encode(struct key2any_ctx_st *ctx, OSSL_CORE_BIO *cout, + const void *key, const char* typestr, const char *pemname, + key_to_der_fn *writer, + OSSL_PASSPHRASE_CALLBACK *pwcb, void *pwcbarg, + key_to_paramstring_fn *key2paramstring, + i2d_of_void *key2der) +{ + int ret = 0; + int type = OBJ_sn2nid(typestr); + OQSX_KEY *oqsk = (OQSX_KEY*)key; + + OQS_ENC_PRINTF3("OQS ENC provider: key2any_encode called with type %d (%s)\n", type, typestr); + + if (key == NULL || type <= 0) { + ERR_raise(ERR_LIB_USER, ERR_R_PASSED_NULL_PARAMETER); + } else if (writer != NULL) { + // Is ref counting really needed? For now, do it as per https://beta.openssl.org/docs/manmaster/man3/BIO_new_from_core_bio.html: + BIO *out = oqs_bio_new_from_core_bio(ctx->provctx, cout); + + if (out != NULL) { + ctx->pwcb = pwcb; + ctx->pwcbarg = pwcbarg; + + ret = writer(out, key, type, pemname, key2paramstring, key2der, ctx); + } + + BIO_free(out); + } else { + ERR_raise(ERR_LIB_USER, ERR_R_PASSED_INVALID_ARGUMENT); + } + OQS_ENC_PRINTF2(" encode result: %d\n", ret); + return ret; +} + +#define DO_PRIVATE_KEY_selection_mask OSSL_KEYMGMT_SELECT_PRIVATE_KEY +#define DO_PRIVATE_KEY(impl, type, kind, output) \ + if ((selection & DO_PRIVATE_KEY_selection_mask) != 0) \ + return key2any_encode(ctx, cout, key, impl##_pem_type, \ + impl##_pem_type " PRIVATE KEY", \ + key_to_##kind##_##output##_priv_bio, \ + cb, cbarg, prepare_##type##_params, \ + type##_##kind##_priv_to_der); + +#define DO_PUBLIC_KEY_selection_mask OSSL_KEYMGMT_SELECT_PUBLIC_KEY +#define DO_PUBLIC_KEY(impl, type, kind, output) \ + if ((selection & DO_PUBLIC_KEY_selection_mask) != 0) \ + return key2any_encode(ctx, cout, key, impl##_pem_type, \ + impl##_pem_type " PUBLIC KEY", \ + key_to_##kind##_##output##_pub_bio, \ + cb, cbarg, prepare_##type##_params, \ + type##_##kind##_pub_to_der); + +#define DO_PARAMETERS_selection_mask OSSL_KEYMGMT_SELECT_ALL_PARAMETERS +#define DO_PARAMETERS(impl, type, kind, output) \ + if ((selection & DO_PARAMETERS_selection_mask) != 0) \ + return key2any_encode(ctx, cout, key, impl##_pem_type, \ + impl##_pem_type " PARAMETERS", \ + key_to_##kind##_##output##_param_bio, \ + NULL, NULL, NULL, \ + type##_##kind##_params_to_der); + +/*- + * Implement the kinds of output structure that can be produced. They are + * referred to by name, and for each name, the following macros are defined + * (braces not included): + * + * DO_{kind}_selection_mask + * + * A mask of selection bits that must not be zero. This is used as a + * selection criterion for each implementation. + * This mask must never be zero. + * + * DO_{kind} + * + * The performing macro. It must use the DO_ macros defined above, + * always in this order: + * + * - DO_PRIVATE_KEY + * - DO_PUBLIC_KEY + * - DO_PARAMETERS + * + * Any of those may be omitted, but the relative order must still be + * the same. + */ + +/* + * PKCS#8 defines two structures for private keys only: + * - PrivateKeyInfo (raw unencrypted form) + * - EncryptedPrivateKeyInfo (encrypted wrapping) + * + * To allow a certain amount of flexibility, we allow the routines + * for PrivateKeyInfo to also produce EncryptedPrivateKeyInfo if a + * passphrase callback has been passed to them. + */ +#define DO_PrivateKeyInfo_selection_mask DO_PRIVATE_KEY_selection_mask +#define DO_PrivateKeyInfo(impl, type, output) \ + DO_PRIVATE_KEY(impl, type, pki, output) + +#define DO_EncryptedPrivateKeyInfo_selection_mask DO_PRIVATE_KEY_selection_mask +#define DO_EncryptedPrivateKeyInfo(impl, type, output) \ + DO_PRIVATE_KEY(impl, type, epki, output) + +/* SubjectPublicKeyInfo is a structure for public keys only */ +#define DO_SubjectPublicKeyInfo_selection_mask DO_PUBLIC_KEY_selection_mask +#define DO_SubjectPublicKeyInfo(impl, type, output) \ + DO_PUBLIC_KEY(impl, type, spki, output) + +/* + * "type-specific" is a uniform name for key type specific output for private + * and public keys as well as key parameters. This is used internally in + * libcrypto so it doesn't have to have special knowledge about select key + * types, but also when no better name has been found. If there are more + * expressive DO_ names above, those are preferred. + * + * Three forms exist: + * + * - type_specific_keypair Only supports private and public key + * - type_specific_params Only supports parameters + * - type_specific Supports all parts of an EVP_PKEY + * - type_specific_no_pub Supports all parts of an EVP_PKEY + * except public key + */ +#define DO_type_specific_params_selection_mask DO_PARAMETERS_selection_mask +#define DO_type_specific_params(impl, type, output) \ + DO_PARAMETERS(impl, type, type_specific, output) +#define DO_type_specific_keypair_selection_mask \ + ( DO_PRIVATE_KEY_selection_mask | DO_PUBLIC_KEY_selection_mask ) +#define DO_type_specific_keypair(impl, type, output) \ + DO_PRIVATE_KEY(impl, type, type_specific, output) \ + DO_PUBLIC_KEY(impl, type, type_specific, output) +#define DO_type_specific_selection_mask \ + ( DO_type_specific_keypair_selection_mask \ + | DO_type_specific_params_selection_mask ) +#define DO_type_specific(impl, type, output) \ + DO_type_specific_keypair(impl, type, output) \ + DO_type_specific_params(impl, type, output) +#define DO_type_specific_no_pub_selection_mask \ + ( DO_PRIVATE_KEY_selection_mask | DO_PARAMETERS_selection_mask) +#define DO_type_specific_no_pub(impl, type, output) \ + DO_PRIVATE_KEY(impl, type, type_specific, output) \ + DO_type_specific_params(impl, type, output) + +/* + * MAKE_ENCODER is the single driver for creating OSSL_DISPATCH tables. + * It takes the following arguments: + * + * impl This is the key type name that's being implemented. + * type This is the type name for the set of functions that implement + * the key type. For example, ed25519, ed448, x25519 and x448 + * are all implemented with the exact same set of functions. + * kind What kind of support to implement. These translate into + * the DO_##kind macros above. + * output The output type to implement. may be der or pem. + * + * The resulting OSSL_DISPATCH array gets the following name (expressed in + * C preprocessor terms) from those arguments: + * + * oqs_##impl##_to_##kind##_##output##_encoder_functions + */ +#define MAKE_ENCODER(impl, type, kind, output) \ + static OSSL_FUNC_encoder_import_object_fn \ + impl##_to_##kind##_##output##_import_object; \ + static OSSL_FUNC_encoder_free_object_fn \ + impl##_to_##kind##_##output##_free_object; \ + static OSSL_FUNC_encoder_encode_fn \ + impl##_to_##kind##_##output##_encode; \ + \ + static void * \ + impl##_to_##kind##_##output##_import_object(void *vctx, int selection, \ + const OSSL_PARAM params[]) \ + { \ + struct key2any_ctx_st *ctx = vctx; \ + \ + OQS_ENC_PRINTF("OQS ENC provider: _import_object called\n"); \ + return oqs_prov_import_key(oqs_##impl##_keymgmt_functions, \ + ctx->provctx, selection, params); \ + } \ + static void impl##_to_##kind##_##output##_free_object(void *key) \ + { \ + OQS_ENC_PRINTF("OQS ENC provider: _free_object called\n"); \ + oqs_prov_free_key(oqs_##impl##_keymgmt_functions, key); \ + } \ + static int impl##_to_##kind##_##output##_does_selection(void *ctx, \ + int selection) \ + { \ + OQS_ENC_PRINTF("OQS ENC provider: _does_selection called\n"); \ + return key2any_check_selection(selection, \ + DO_##kind##_selection_mask); \ + } \ + static int \ + impl##_to_##kind##_##output##_encode(void *ctx, OSSL_CORE_BIO *cout, \ + const void *key, \ + const OSSL_PARAM key_abstract[], \ + int selection, \ + OSSL_PASSPHRASE_CALLBACK *cb, \ + void *cbarg) \ + { \ + /* We don't deal with abstract objects */ \ + OQS_ENC_PRINTF("OQS ENC provider: _encode called\n"); \ + if (key_abstract != NULL) { \ + ERR_raise(ERR_LIB_USER, ERR_R_PASSED_INVALID_ARGUMENT); \ + return 0; \ + } \ + DO_##kind(impl, type, output) \ + \ + ERR_raise(ERR_LIB_USER, ERR_R_PASSED_INVALID_ARGUMENT); \ + return 0; \ + } \ + const OSSL_DISPATCH \ + oqs_##impl##_to_##kind##_##output##_encoder_functions[] = { \ + { OSSL_FUNC_ENCODER_NEWCTX, \ + (void (*)(void))key2any_newctx }, \ + { OSSL_FUNC_ENCODER_FREECTX, \ + (void (*)(void))key2any_freectx }, \ + { OSSL_FUNC_ENCODER_SETTABLE_CTX_PARAMS, \ + (void (*)(void))key2any_settable_ctx_params }, \ + { OSSL_FUNC_ENCODER_SET_CTX_PARAMS, \ + (void (*)(void))key2any_set_ctx_params }, \ + { OSSL_FUNC_ENCODER_DOES_SELECTION, \ + (void (*)(void))impl##_to_##kind##_##output##_does_selection }, \ + { OSSL_FUNC_ENCODER_IMPORT_OBJECT, \ + (void (*)(void))impl##_to_##kind##_##output##_import_object }, \ + { OSSL_FUNC_ENCODER_FREE_OBJECT, \ + (void (*)(void))impl##_to_##kind##_##output##_free_object }, \ + { OSSL_FUNC_ENCODER_ENCODE, \ + (void (*)(void))impl##_to_##kind##_##output##_encode }, \ + { 0, NULL } \ + } + +/* + * Replacements for i2d_{TYPE}PrivateKey, i2d_{TYPE}PublicKey, + * i2d_{TYPE}params, as they exist. + */ + +/* + * PKCS#8 and SubjectPublicKeyInfo support. This may duplicate some of the + * implementations specified above, but are more specific. + * The SubjectPublicKeyInfo implementations also replace the + * PEM_write_bio_{TYPE}_PUBKEY functions. + * For PEM, these are expected to be used by PEM_write_bio_PrivateKey(), + * PEM_write_bio_PUBKEY() and PEM_write_bio_Parameters(). + */ +///// OQS_TEMPLATE_FRAGMENT_ENCODER_MAKE_START +MAKE_ENCODER(dilithium2, oqsx, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(dilithium2, oqsx, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(dilithium2, oqsx, PrivateKeyInfo, der); +MAKE_ENCODER(dilithium2, oqsx, PrivateKeyInfo, pem); +MAKE_ENCODER(dilithium2, oqsx, SubjectPublicKeyInfo, der); +MAKE_ENCODER(dilithium2, oqsx, SubjectPublicKeyInfo, pem); +MAKE_ENCODER(dilithium3, oqsx, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(dilithium3, oqsx, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(dilithium3, oqsx, PrivateKeyInfo, der); +MAKE_ENCODER(dilithium3, oqsx, PrivateKeyInfo, pem); +MAKE_ENCODER(dilithium3, oqsx, SubjectPublicKeyInfo, der); +MAKE_ENCODER(dilithium3, oqsx, SubjectPublicKeyInfo, pem); +MAKE_ENCODER(dilithium5, oqsx, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(dilithium5, oqsx, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(dilithium5, oqsx, PrivateKeyInfo, der); +MAKE_ENCODER(dilithium5, oqsx, PrivateKeyInfo, pem); +MAKE_ENCODER(dilithium5, oqsx, SubjectPublicKeyInfo, der); +MAKE_ENCODER(dilithium5, oqsx, SubjectPublicKeyInfo, pem); +MAKE_ENCODER(dilithium2_aes, oqsx, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(dilithium2_aes, oqsx, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(dilithium2_aes, oqsx, PrivateKeyInfo, der); +MAKE_ENCODER(dilithium2_aes, oqsx, PrivateKeyInfo, pem); +MAKE_ENCODER(dilithium2_aes, oqsx, SubjectPublicKeyInfo, der); +MAKE_ENCODER(dilithium2_aes, oqsx, SubjectPublicKeyInfo, pem); +MAKE_ENCODER(dilithium3_aes, oqsx, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(dilithium3_aes, oqsx, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(dilithium3_aes, oqsx, PrivateKeyInfo, der); +MAKE_ENCODER(dilithium3_aes, oqsx, PrivateKeyInfo, pem); +MAKE_ENCODER(dilithium3_aes, oqsx, SubjectPublicKeyInfo, der); +MAKE_ENCODER(dilithium3_aes, oqsx, SubjectPublicKeyInfo, pem); +MAKE_ENCODER(dilithium5_aes, oqsx, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(dilithium5_aes, oqsx, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(dilithium5_aes, oqsx, PrivateKeyInfo, der); +MAKE_ENCODER(dilithium5_aes, oqsx, PrivateKeyInfo, pem); +MAKE_ENCODER(dilithium5_aes, oqsx, SubjectPublicKeyInfo, der); +MAKE_ENCODER(dilithium5_aes, oqsx, SubjectPublicKeyInfo, pem); +MAKE_ENCODER(falcon512, oqsx, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(falcon512, oqsx, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(falcon512, oqsx, PrivateKeyInfo, der); +MAKE_ENCODER(falcon512, oqsx, PrivateKeyInfo, pem); +MAKE_ENCODER(falcon512, oqsx, SubjectPublicKeyInfo, der); +MAKE_ENCODER(falcon512, oqsx, SubjectPublicKeyInfo, pem); +MAKE_ENCODER(falcon1024, oqsx, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(falcon1024, oqsx, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(falcon1024, oqsx, PrivateKeyInfo, der); +MAKE_ENCODER(falcon1024, oqsx, PrivateKeyInfo, pem); +MAKE_ENCODER(falcon1024, oqsx, SubjectPublicKeyInfo, der); +MAKE_ENCODER(falcon1024, oqsx, SubjectPublicKeyInfo, pem); +MAKE_ENCODER(picnicl1full, oqsx, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(picnicl1full, oqsx, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(picnicl1full, oqsx, PrivateKeyInfo, der); +MAKE_ENCODER(picnicl1full, oqsx, PrivateKeyInfo, pem); +MAKE_ENCODER(picnicl1full, oqsx, SubjectPublicKeyInfo, der); +MAKE_ENCODER(picnicl1full, oqsx, SubjectPublicKeyInfo, pem); +MAKE_ENCODER(picnic3l1, oqsx, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(picnic3l1, oqsx, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(picnic3l1, oqsx, PrivateKeyInfo, der); +MAKE_ENCODER(picnic3l1, oqsx, PrivateKeyInfo, pem); +MAKE_ENCODER(picnic3l1, oqsx, SubjectPublicKeyInfo, der); +MAKE_ENCODER(picnic3l1, oqsx, SubjectPublicKeyInfo, pem); +MAKE_ENCODER(rainbowIclassic, oqsx, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(rainbowIclassic, oqsx, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(rainbowIclassic, oqsx, PrivateKeyInfo, der); +MAKE_ENCODER(rainbowIclassic, oqsx, PrivateKeyInfo, pem); +MAKE_ENCODER(rainbowIclassic, oqsx, SubjectPublicKeyInfo, der); +MAKE_ENCODER(rainbowIclassic, oqsx, SubjectPublicKeyInfo, pem); +MAKE_ENCODER(rainbowVclassic, oqsx, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(rainbowVclassic, oqsx, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(rainbowVclassic, oqsx, PrivateKeyInfo, der); +MAKE_ENCODER(rainbowVclassic, oqsx, PrivateKeyInfo, pem); +MAKE_ENCODER(rainbowVclassic, oqsx, SubjectPublicKeyInfo, der); +MAKE_ENCODER(rainbowVclassic, oqsx, SubjectPublicKeyInfo, pem); +MAKE_ENCODER(sphincsharaka128frobust, oqsx, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(sphincsharaka128frobust, oqsx, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(sphincsharaka128frobust, oqsx, PrivateKeyInfo, der); +MAKE_ENCODER(sphincsharaka128frobust, oqsx, PrivateKeyInfo, pem); +MAKE_ENCODER(sphincsharaka128frobust, oqsx, SubjectPublicKeyInfo, der); +MAKE_ENCODER(sphincsharaka128frobust, oqsx, SubjectPublicKeyInfo, pem); +MAKE_ENCODER(sphincssha256128frobust, oqsx, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(sphincssha256128frobust, oqsx, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(sphincssha256128frobust, oqsx, PrivateKeyInfo, der); +MAKE_ENCODER(sphincssha256128frobust, oqsx, PrivateKeyInfo, pem); +MAKE_ENCODER(sphincssha256128frobust, oqsx, SubjectPublicKeyInfo, der); +MAKE_ENCODER(sphincssha256128frobust, oqsx, SubjectPublicKeyInfo, pem); +MAKE_ENCODER(sphincsshake256128frobust, oqsx, EncryptedPrivateKeyInfo, der); +MAKE_ENCODER(sphincsshake256128frobust, oqsx, EncryptedPrivateKeyInfo, pem); +MAKE_ENCODER(sphincsshake256128frobust, oqsx, PrivateKeyInfo, der); +MAKE_ENCODER(sphincsshake256128frobust, oqsx, PrivateKeyInfo, pem); +MAKE_ENCODER(sphincsshake256128frobust, oqsx, SubjectPublicKeyInfo, der); +MAKE_ENCODER(sphincsshake256128frobust, oqsx, SubjectPublicKeyInfo, pem); +///// OQS_TEMPLATE_FRAGMENT_ENCODER_MAKE_END + diff --git a/oqsprov/oqs_endecoder_common.c b/oqsprov/oqs_endecoder_common.c new file mode 100644 index 00000000..be4e579f --- /dev/null +++ b/oqsprov/oqs_endecoder_common.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: Apache-2.0 AND MIT + +/* + * OQS OpenSSL 3 provider + * + * Code strongly inspired by OpenSSL endecoder. + * + * ToDo: Adding hybrid alg support + */ + +#include +#include +//#include "internal/asn1.h" +//#include "prov/bio.h" +#include +#include "oqs_endecoder_local.h" + +OSSL_FUNC_keymgmt_new_fn * +oqs_prov_get_keymgmt_new(const OSSL_DISPATCH *fns) +{ + /* Pilfer the keymgmt dispatch table */ + for (; fns->function_id != 0; fns++) + if (fns->function_id == OSSL_FUNC_KEYMGMT_NEW) + return OSSL_FUNC_keymgmt_new(fns); + + return NULL; +} + +OSSL_FUNC_keymgmt_free_fn * +oqs_prov_get_keymgmt_free(const OSSL_DISPATCH *fns) +{ + /* Pilfer the keymgmt dispatch table */ + for (; fns->function_id != 0; fns++) + if (fns->function_id == OSSL_FUNC_KEYMGMT_FREE) + return OSSL_FUNC_keymgmt_free(fns); + + return NULL; +} + +OSSL_FUNC_keymgmt_import_fn * +oqs_prov_get_keymgmt_import(const OSSL_DISPATCH *fns) +{ + /* Pilfer the keymgmt dispatch table */ + for (; fns->function_id != 0; fns++) + if (fns->function_id == OSSL_FUNC_KEYMGMT_IMPORT) + return OSSL_FUNC_keymgmt_import(fns); + + return NULL; +} + +OSSL_FUNC_keymgmt_export_fn * +oqs_prov_get_keymgmt_export(const OSSL_DISPATCH *fns) +{ + /* Pilfer the keymgmt dispatch table */ + for (; fns->function_id != 0; fns++) + if (fns->function_id == OSSL_FUNC_KEYMGMT_EXPORT) + return OSSL_FUNC_keymgmt_export(fns); + + return NULL; +} + +void *oqs_prov_import_key(const OSSL_DISPATCH *fns, void *provctx, + int selection, const OSSL_PARAM params[]) +{ + OSSL_FUNC_keymgmt_new_fn *kmgmt_new = oqs_prov_get_keymgmt_new(fns); + OSSL_FUNC_keymgmt_free_fn *kmgmt_free = oqs_prov_get_keymgmt_free(fns); + OSSL_FUNC_keymgmt_import_fn *kmgmt_import = + oqs_prov_get_keymgmt_import(fns); + void *key = NULL; + + if (kmgmt_new != NULL && kmgmt_import != NULL && kmgmt_free != NULL) { + if ((key = kmgmt_new(provctx)) == NULL + || !kmgmt_import(key, selection, params)) { + kmgmt_free(key); + key = NULL; + } + } + return key; +} + +void oqs_prov_free_key(const OSSL_DISPATCH *fns, void *key) +{ + OSSL_FUNC_keymgmt_free_fn *kmgmt_free = oqs_prov_get_keymgmt_free(fns); + + if (kmgmt_free != NULL) + kmgmt_free(key); +} + +// "crypto internal" function: TCB: OK to use??? +extern int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb); + +int ossl_read_der(PROV_OQS_CTX *provctx, OSSL_CORE_BIO *cin, unsigned char **data, + long *len) +{ + BUF_MEM *mem = NULL; + BIO *in = BIO_new_from_core_bio(PROV_OQS_LIBCTX_OF(provctx), cin); + // permissible/sensible to use this internal function? + int ok = (asn1_d2i_read_bio(in, &mem) >= 0); + + if (ok) { + *data = (unsigned char *)mem->data; + *len = (long)mem->length; + OPENSSL_free(mem); + } + BIO_free(in); + return ok; +} diff --git a/oqsprov/oqs_endecoder_local.h b/oqsprov/oqs_endecoder_local.h new file mode 100644 index 00000000..1abff738 --- /dev/null +++ b/oqsprov/oqs_endecoder_local.h @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: Apache-2.0 AND MIT + +/* + * OQS OpenSSL 3 provider + * + * Code strongly inspired by OpenSSL endecoder. + * + */ + +#include +#include +#include +#include "oqs_prov.h" + +OSSL_FUNC_keymgmt_new_fn *oqs_prov_get_keymgmt_new(const OSSL_DISPATCH *fns); +OSSL_FUNC_keymgmt_free_fn *oqs_prov_get_keymgmt_free(const OSSL_DISPATCH *fns); +OSSL_FUNC_keymgmt_import_fn *oqs_prov_get_keymgmt_import(const OSSL_DISPATCH *fns); +OSSL_FUNC_keymgmt_export_fn *oqs_prov_get_keymgmt_export(const OSSL_DISPATCH *fns); + +int oqs_prov_der_from_p8(unsigned char **new_der, long *new_der_len, + unsigned char *input_der, long input_der_len, + OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg); + +void *oqs_prov_import_key(const OSSL_DISPATCH *fns, void *provctx, + int selection, const OSSL_PARAM params[]); +void oqs_prov_free_key(const OSSL_DISPATCH *fns, void *key); +int oqs_read_der(PROV_OQS_CTX *provctx, OSSL_CORE_BIO *cin, unsigned char **data, + long *len); diff --git a/oqsprov/oqs_kem.c b/oqsprov/oqs_kem.c index 76478be1..22f8c78c 100644 --- a/oqsprov/oqs_kem.c +++ b/oqsprov/oqs_kem.c @@ -16,7 +16,7 @@ #include #include #include -#include "oqsx.h" +#include "oqs_prov.h" #ifdef NDEBUG #define OQS_KEM_PRINTF(a) @@ -33,7 +33,6 @@ static OSSL_FUNC_kem_newctx_fn oqs_kem_newctx; static OSSL_FUNC_kem_encapsulate_init_fn oqs_kem_encaps_init; static OSSL_FUNC_kem_encapsulate_fn oqs_qs_kem_encaps; static OSSL_FUNC_kem_encapsulate_fn oqs_hyb_kem_encaps; -static OSSL_FUNC_kem_decapsulate_init_fn oqs_qs_kem_decaps_init; static OSSL_FUNC_kem_decapsulate_fn oqs_qs_kem_decaps; static OSSL_FUNC_kem_decapsulate_fn oqs_hyb_kem_decaps; static OSSL_FUNC_kem_freectx_fn oqs_kem_freectx; diff --git a/oqsprov/oqs_kmgmt.c b/oqsprov/oqs_kmgmt.c index 8febe6ed..f3fa4369 100644 --- a/oqsprov/oqs_kmgmt.c +++ b/oqsprov/oqs_kmgmt.c @@ -18,7 +18,25 @@ #include #include #include "openssl/param_build.h" -#include "oqsx.h" +#include "oqs_prov.h" + +// stolen from openssl/crypto/param_build_set.c as ossl_param_build_set_octet_string not public API: + +int oqsx_param_build_set_octet_string(OSSL_PARAM_BLD *bld, OSSL_PARAM *p, + const char *key, + const unsigned char *data, + size_t data_len) +{ + if (bld != NULL) + return OSSL_PARAM_BLD_push_octet_string(bld, key, data, data_len); + + p = OSSL_PARAM_locate(p, key); + if (p != NULL) + return OSSL_PARAM_set_octet_string(p, data, data_len); + return 1; +} + + #ifdef NDEBUG #define OQS_KM_PRINTF(a) @@ -78,35 +96,49 @@ static int oqsx_has(const void *keydata, int selection) return ok; } +/* + * Key matching has a problem in OQS world: OpenSSL assumes all keys to (also) + * contain public key material (https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_eq.html). + * This is not the case with decoded private keys: Not all algorithms permit re-creating + * public key material from private keys (https://github.com/PQClean/PQClean/issues/415#issuecomment-910377682). + * Thus we implement the following logic: + * 1) Private keys are matched binary if available in both keys; only one key having private key material + * will be considered a mismatch + * 2) Public keys are matched binary if available in both keys; only one key having public key material + * will NOT be considered a mismatch if both private keys are present and match: The latter logic will + * only be triggered if domain parameter matching is requested to distinguish between a pure-play + * public key match/test and one checking OpenSSL-type "EVP-PKEY-equality". This is possible as domain + * parameters don't really play a role in OQS, so we consider them as a proxy for private key matching. + */ + static int oqsx_match(const void *keydata1, const void *keydata2, int selection) { const OQSX_KEY *key1 = keydata1; const OQSX_KEY *key2 = keydata2; int ok = 1; - OQS_KM_PRINTF("OQSKEYMGMT: match called\n"); + OQS_KM_PRINTF3("OQSKEYMGMT: match called for %p and %p\n", keydata1, keydata2); - if ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) - ok = ok && !strcmp(key1->oqs_name, key2->oqs_name); if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { if ((key1->privkey == NULL && key2->privkey != NULL) || (key1->privkey != NULL && key2->privkey == NULL) - || strcmp(key1->oqs_name, key2->oqs_name)) + || ((key1->tls_name!=NULL && key2->tls_name!=NULL) && strcmp(key1->tls_name, key2->tls_name))) ok = 0; else - ok = ok && (key1->privkey == NULL /* implies key2->privkey == NULL */ - || CRYPTO_memcmp(key1->privkey, key2->privkey, - key1->privkeylen) == 0); + ok = ok && ( (key1->privkey==NULL && key2->privkey==NULL) || ((key1->privkey != NULL) && CRYPTO_memcmp(key1->privkey, key2->privkey, key1->privkeylen) == 0) ); } if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { - if ((key1->pubkey!=NULL && key2->pubkey != NULL) - || strcmp(key1->oqs_name, key2->oqs_name)) - ok = 0; - else - ok = ok && (key1->pubkey == NULL /* implies key2->haspubkey == NULL */ - || CRYPTO_memcmp(key1->pubkey, key2->pubkey, - key1->pubkeylen) == 0); + if ((key1->pubkey == NULL && key2->pubkey != NULL) || + (key1->pubkey != NULL && key2->pubkey == NULL) || + ((key1->tls_name!=NULL && key2->tls_name!=NULL) && strcmp(key1->tls_name, key2->tls_name))) + // special case now: If domain parameter matching requested, consider private key match sufficient: + ok = ((selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) != 0) && + (key1->privkey != NULL && key2->privkey != NULL) && + (CRYPTO_memcmp(key1->privkey, key2->privkey, key1->privkeylen) == 0); + else + ok = ok && ( (key1->pubkey==NULL && key2->pubkey==NULL) || ((key1->pubkey != NULL) && CRYPTO_memcmp(key1->pubkey, key2->pubkey, key1->pubkeylen) == 0) ); } + if (!ok) OQS_KM_PRINTF("OQSKEYMGMT: match failed!\n"); return ok; } @@ -127,6 +159,56 @@ static int oqsx_import(void *keydata, int selection, const OSSL_PARAM params[]) return ok; } +int oqsx_key_to_params(const OQSX_KEY *key, OSSL_PARAM_BLD *tmpl, + OSSL_PARAM params[], int include_private) +{ + int ret = 0; + + if (key == NULL) + return 0; + + if (key->pubkey != NULL) { + OSSL_PARAM *p = NULL; + + if (tmpl == NULL) { + p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_PUB_KEY); + } + + if (p != NULL || tmpl != NULL) { + if ( key->pubkeylen == 0 + || !oqsx_param_build_set_octet_string(tmpl, p, + OSSL_PKEY_PARAM_PUB_KEY, + key->pubkey, key->pubkeylen)) + goto err; + } + } + if (key->privkey != NULL && include_private) { + OSSL_PARAM *p = NULL; + + /* + * Key import/export should never leak the bit length of the secret + * scalar in the key. Conceptually. OQS is not production strength + * so does not care. TBD. + * + */ + + if (tmpl == NULL) { + p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_PRIV_KEY); + } + + if (p != NULL || tmpl != NULL) { + if ( key->privkeylen == 0 + || !oqsx_param_build_set_octet_string(tmpl, p, + OSSL_PKEY_PARAM_PRIV_KEY, + key->privkey, key->privkeylen)) + goto err; + } + } + ret = 1; + err: + return ret; +} + static int oqsx_export(void *keydata, int selection, OSSL_CALLBACK *param_cb, void *cbarg) { @@ -134,9 +216,13 @@ static int oqsx_export(void *keydata, int selection, OSSL_CALLBACK *param_cb, OSSL_PARAM_BLD *tmpl; OSSL_PARAM *params = NULL; OSSL_PARAM *p; - int ret = 0; + int ok = 1; OQS_KM_PRINTF("OQSKEYMGMT: export called\n"); + + /* + * In this implementation, only public and private keys can be exported, nothing else + */ if (key == NULL) { ERR_raise(ERR_LIB_USER, OQSPROV_UNEXPECTED_NULL); return 0; @@ -148,27 +234,24 @@ static int oqsx_export(void *keydata, int selection, OSSL_CALLBACK *param_cb, return 0; } - if (((selection & OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) != 0) || - ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0)) { - if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_PUB_KEY)) != NULL) { - if (!OSSL_PARAM_set_octet_string(p, key->pubkey, key->pubkeylen)) - goto err; - } - if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_PRIV_KEY)) != NULL) { - if (!OSSL_PARAM_set_octet_string(p, key->privkey, key->privkeylen)) - goto err; - } + if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { + int include_private = + selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY ? 1 : 0; + + ok = ok && oqsx_key_to_params(key, tmpl, NULL, include_private); } params = OSSL_PARAM_BLD_to_param(tmpl); - if (params == NULL) + if (params == NULL) { + ok = 0; goto err; + } - ret = param_cb(params, cbarg); + ok = ok & param_cb(params, cbarg); OSSL_PARAM_free(params); err: OSSL_PARAM_BLD_free(tmpl); - return ret; + return ok; } #define OQS_KEY_TYPES() \ @@ -187,12 +270,13 @@ static const OSSL_PARAM *oqs_imexport_types(int selection) return NULL; } +// must handle param requests for KEM and SIG keys... static int oqsx_get_params(void *key, OSSL_PARAM params[]) { OQSX_KEY *oqsxk = key; OSSL_PARAM *p; - OQS_KM_PRINTF("OQSKEYMGMT: get_params called\n"); + OQS_KM_PRINTF2("OQSKEYMGMT: get_params called for %s\n", params[0].key); if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS)) != NULL && !OSSL_PARAM_set_int(p, oqsx_key_parambits(oqsxk))) return 0; @@ -241,7 +325,7 @@ static int set_property_query(OQSX_KEY *oqsxkey, const char *propq) if (propq != NULL) { oqsxkey->propq = OPENSSL_strdup(propq); if (oqsxkey->propq == NULL) { - ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_USER, ERR_R_MALLOC_FAILURE); return 0; } } @@ -288,16 +372,17 @@ static const OSSL_PARAM *oqsx_settable_params(void *provctx) return oqs_settable_params; } -static void *oqsx_gen_init(void *provctx, int selection, char* oqs_name, int primitive, int bit_security) +static void *oqsx_gen_init(void *provctx, int selection, char* oqs_name, char* tls_name, int primitive, int bit_security) { OSSL_LIB_CTX *libctx = PROV_OQS_LIBCTX_OF(provctx); struct oqsx_gen_ctx *gctx = NULL; - OQS_KM_PRINTF2("OQSKEYMGMT: gen_init called for key %s\n", oqs_name); + OQS_KM_PRINTF2("OQSKEYMGMT: gen_init called for key %s \n", oqs_name); if ((gctx = OPENSSL_zalloc(sizeof(*gctx))) != NULL) { gctx->libctx = libctx; gctx->oqs_name = OPENSSL_strdup(oqs_name); + gctx->tls_name = OPENSSL_strdup(tls_name); gctx->primitive = primitive; gctx->selection = selection; gctx->bit_security = bit_security; @@ -309,11 +394,11 @@ static void *oqsx_genkey(struct oqsx_gen_ctx *gctx) { OQSX_KEY *key; - OQS_KM_PRINTF2("OQSKEYMGMT: gen called for %s\n", gctx->oqs_name); + OQS_KM_PRINTF3("OQSKEYMGMT: gen called for %s (%s)\n", gctx->oqs_name, gctx->tls_name); if (gctx == NULL) return NULL; if ((key = oqsx_key_new(gctx->libctx, gctx->oqs_name, NULL, gctx->primitive, gctx->propq, gctx->bit_security)) == NULL) { - ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_USER, ERR_R_MALLOC_FAILURE); return NULL; } @@ -405,7 +490,7 @@ static void *dilithium2_new_key(void *provctx) static void *dilithium2_gen_init(void *provctx, int selection) { - return oqsx_gen_init(provctx, selection, OQS_SIG_alg_dilithium_2, 0, 128); + return oqsx_gen_init(provctx, selection, OQS_SIG_alg_dilithium_2, "dilithium2", 0, 128); } static void *dilithium3_new_key(void *provctx) { @@ -414,7 +499,7 @@ static void *dilithium3_new_key(void *provctx) static void *dilithium3_gen_init(void *provctx, int selection) { - return oqsx_gen_init(provctx, selection, OQS_SIG_alg_dilithium_3, 0, 192); + return oqsx_gen_init(provctx, selection, OQS_SIG_alg_dilithium_3, "dilithium3", 0, 192); } static void *dilithium5_new_key(void *provctx) { @@ -423,7 +508,7 @@ static void *dilithium5_new_key(void *provctx) static void *dilithium5_gen_init(void *provctx, int selection) { - return oqsx_gen_init(provctx, selection, OQS_SIG_alg_dilithium_5, 0, 256); + return oqsx_gen_init(provctx, selection, OQS_SIG_alg_dilithium_5, "dilithium5", 0, 256); } static void *dilithium2_aes_new_key(void *provctx) { @@ -432,7 +517,7 @@ static void *dilithium2_aes_new_key(void *provctx) static void *dilithium2_aes_gen_init(void *provctx, int selection) { - return oqsx_gen_init(provctx, selection, OQS_SIG_alg_dilithium_2_aes, 0, 128); + return oqsx_gen_init(provctx, selection, OQS_SIG_alg_dilithium_2_aes, "dilithium2_aes", 0, 128); } static void *dilithium3_aes_new_key(void *provctx) { @@ -441,7 +526,7 @@ static void *dilithium3_aes_new_key(void *provctx) static void *dilithium3_aes_gen_init(void *provctx, int selection) { - return oqsx_gen_init(provctx, selection, OQS_SIG_alg_dilithium_3_aes, 0, 192); + return oqsx_gen_init(provctx, selection, OQS_SIG_alg_dilithium_3_aes, "dilithium3_aes", 0, 192); } static void *dilithium5_aes_new_key(void *provctx) { @@ -450,7 +535,7 @@ static void *dilithium5_aes_new_key(void *provctx) static void *dilithium5_aes_gen_init(void *provctx, int selection) { - return oqsx_gen_init(provctx, selection, OQS_SIG_alg_dilithium_5_aes, 0, 256); + return oqsx_gen_init(provctx, selection, OQS_SIG_alg_dilithium_5_aes, "dilithium5_aes", 0, 256); } static void *falcon512_new_key(void *provctx) @@ -460,7 +545,7 @@ static void *falcon512_new_key(void *provctx) static void *falcon512_gen_init(void *provctx, int selection) { - return oqsx_gen_init(provctx, selection, OQS_SIG_alg_falcon_512, 0, 128); + return oqsx_gen_init(provctx, selection, OQS_SIG_alg_falcon_512, "falcon512", 0, 128); } static void *falcon1024_new_key(void *provctx) { @@ -469,7 +554,7 @@ static void *falcon1024_new_key(void *provctx) static void *falcon1024_gen_init(void *provctx, int selection) { - return oqsx_gen_init(provctx, selection, OQS_SIG_alg_falcon_1024, 0, 256); + return oqsx_gen_init(provctx, selection, OQS_SIG_alg_falcon_1024, "falcon1024", 0, 256); } static void *picnicl1full_new_key(void *provctx) @@ -479,7 +564,7 @@ static void *picnicl1full_new_key(void *provctx) static void *picnicl1full_gen_init(void *provctx, int selection) { - return oqsx_gen_init(provctx, selection, OQS_SIG_alg_picnic_L1_full, 0, 128); + return oqsx_gen_init(provctx, selection, OQS_SIG_alg_picnic_L1_full, "picnicl1full", 0, 128); } static void *picnic3l1_new_key(void *provctx) { @@ -488,7 +573,7 @@ static void *picnic3l1_new_key(void *provctx) static void *picnic3l1_gen_init(void *provctx, int selection) { - return oqsx_gen_init(provctx, selection, OQS_SIG_alg_picnic3_L1, 0, 128); + return oqsx_gen_init(provctx, selection, OQS_SIG_alg_picnic3_L1, "picnic3l1", 0, 128); } static void *rainbowIclassic_new_key(void *provctx) @@ -498,7 +583,7 @@ static void *rainbowIclassic_new_key(void *provctx) static void *rainbowIclassic_gen_init(void *provctx, int selection) { - return oqsx_gen_init(provctx, selection, OQS_SIG_alg_rainbow_I_classic, 0, 128); + return oqsx_gen_init(provctx, selection, OQS_SIG_alg_rainbow_I_classic, "rainbowIclassic", 0, 128); } static void *rainbowVclassic_new_key(void *provctx) { @@ -507,7 +592,7 @@ static void *rainbowVclassic_new_key(void *provctx) static void *rainbowVclassic_gen_init(void *provctx, int selection) { - return oqsx_gen_init(provctx, selection, OQS_SIG_alg_rainbow_V_classic, 0, 256); + return oqsx_gen_init(provctx, selection, OQS_SIG_alg_rainbow_V_classic, "rainbowVclassic", 0, 256); } static void *sphincsharaka128frobust_new_key(void *provctx) @@ -517,7 +602,7 @@ static void *sphincsharaka128frobust_new_key(void *provctx) static void *sphincsharaka128frobust_gen_init(void *provctx, int selection) { - return oqsx_gen_init(provctx, selection, OQS_SIG_alg_sphincs_haraka_128f_robust, 0, 128); + return oqsx_gen_init(provctx, selection, OQS_SIG_alg_sphincs_haraka_128f_robust, "sphincsharaka128frobust", 0, 128); } static void *sphincssha256128frobust_new_key(void *provctx) @@ -527,7 +612,7 @@ static void *sphincssha256128frobust_new_key(void *provctx) static void *sphincssha256128frobust_gen_init(void *provctx, int selection) { - return oqsx_gen_init(provctx, selection, OQS_SIG_alg_sphincs_sha256_128f_robust, 0, 128); + return oqsx_gen_init(provctx, selection, OQS_SIG_alg_sphincs_sha256_128f_robust, "sphincssha256128frobust", 0, 128); } static void *sphincsshake256128frobust_new_key(void *provctx) @@ -537,7 +622,7 @@ static void *sphincsshake256128frobust_new_key(void *provctx) static void *sphincsshake256128frobust_gen_init(void *provctx, int selection) { - return oqsx_gen_init(provctx, selection, OQS_SIG_alg_sphincs_shake256_128f_robust, 0, 128); + return oqsx_gen_init(provctx, selection, OQS_SIG_alg_sphincs_shake256_128f_robust, "sphincsshake256128frobust", 0, 128); } ///// OQS_TEMPLATE_FRAGMENT_KEYMGMT_CONSTRUCTORS_END @@ -575,7 +660,7 @@ static void *sphincsshake256128frobust_gen_init(void *provctx, int selection) \ static void *tokalg##_gen_init(void *provctx, int selection) \ { \ - return oqsx_gen_init(provctx, selection, tokoqsalg, KEY_TYPE_KEM, bit_security); \ + return oqsx_gen_init(provctx, selection, tokoqsalg, NULL /* TBD: create hybrid TLS alg name! */, KEY_TYPE_KEM, bit_security); \ } \ \ const OSSL_DISPATCH oqs_##tokalg##_keymgmt_functions[] = { \ @@ -607,7 +692,7 @@ static void *sphincsshake256128frobust_gen_init(void *provctx, int selection) \ static void *ecp_##tokalg##_gen_init(void *provctx, int selection) \ { \ - return oqsx_gen_init(provctx, selection, tokoqsalg, KEY_TYPE_ECP_HYB_KEM, bit_security); \ + return oqsx_gen_init(provctx, selection, tokoqsalg, NULL /* TBD: create hybrid TLS alg name! */, KEY_TYPE_ECP_HYB_KEM, bit_security); \ } \ \ const OSSL_DISPATCH oqs_ecp_##tokalg##_keymgmt_functions[] = { \ @@ -639,7 +724,7 @@ static void *sphincsshake256128frobust_gen_init(void *provctx, int selection) \ static void *ecx_##tokalg##_gen_init(void *provctx, int selection) \ { \ - return oqsx_gen_init(provctx, selection, tokoqsalg, KEY_TYPE_ECX_HYB_KEM, bit_security); \ + return oqsx_gen_init(provctx, selection, tokoqsalg, NULL /* TBD: create hybrid TLS alg name! */, KEY_TYPE_ECX_HYB_KEM, bit_security); \ } \ \ const OSSL_DISPATCH oqs_ecx_##tokalg##_keymgmt_functions[] = { \ diff --git a/oqsprov/oqs_prov.h b/oqsprov/oqs_prov.h new file mode 100644 index 00000000..078ef193 --- /dev/null +++ b/oqsprov/oqs_prov.h @@ -0,0 +1,430 @@ +// SPDX-License-Identifier: Apache-2.0 AND MIT + +/* + * OQS OpenSSL 3 key handler. + * + * Code strongly inspired by OpenSSL crypto/ecx key handler but relocated here to have code within provider. + * + * ToDo: Review whether more functions are needed for sig, hybrids. + */ + +/* Internal OQS functions for other submodules: not for application use */ + +#ifndef OQSX_H +# define OQSX_H + +# include +# include +# include + +# include +# include + +// internal, but useful OSSL define: +# define OSSL_NELEM(x) (sizeof(x)/sizeof((x)[0])) + +// our own error codes: +#define OQSPROV_R_INVALID_DIGEST 1 +#define OQSPROV_R_INVALID_SIZE 2 +#define OQSPROV_R_INVALID_KEY 3 +#define OQSPROV_R_UNSUPPORTED 4 +#define OQSPROV_R_MISSING_OID 5 +#define OQSPROV_R_OBJ_CREATE_ERR 6 +#define OQSPROV_R_INVALID_ENCODING 7 +#define OQSPROV_R_SIGN_ERROR 8 +#define OQSPROV_R_LIB_CREATE_ERR 9 + +/* Extras for OQS extension */ + +#define ON_ERR_SET_GOTO(condition, ret, code, gt) \ + if ((condition)) { \ + printf("ON_ERR_CONDITION: %d, setting code: %d\n", condition, code); fflush(stdout); \ + (ret) = (code); \ + goto gt; \ + } + +#define ON_ERR_GOTO(condition, gt) \ + if ((condition)) { \ + printf("ON_ERR_CONDITION: %d\n", condition); fflush(stdout); \ + goto gt; \ + } + +#define ECP_NAME(secbits, oqsname) \ + (secbits == 128 ? "p256_" #oqsname "" : \ + secbits == 192 ? "p384_" #oqsname "" : \ + "p521_" #oqsname "") +#define ECX_NAME(secbits, oqsname) \ + (secbits == 128 ? "x25519_" #oqsname "" : \ + "x448_" #oqsname "") + +typedef struct prov_oqs_ctx_st { + const OSSL_CORE_HANDLE *handle; + OSSL_LIB_CTX *libctx; /* For all provider modules */ + BIO_METHOD *corebiometh; +} PROV_OQS_CTX; + +PROV_OQS_CTX *oqsx_newprovctx(OSSL_LIB_CTX *libctx, const OSSL_CORE_HANDLE *handle, BIO_METHOD *bm); +void oqsx_freeprovctx(PROV_OQS_CTX *ctx); +# define PROV_OQS_LIBCTX_OF(provctx) (((PROV_OQS_CTX *)provctx)->libctx) + +#include "oqs/oqs.h" + +struct oqsx_kex_info_st { + int nid_kex; + int nid_kex_crv; + int raw_key_support; + size_t kex_length_public_key; + size_t kex_length_private_key; + size_t kex_length_secret; +}; + +typedef struct oqsx_kex_info_st OQSX_KEX_INFO; + +struct oqsx_evp_ctx_st { + EVP_PKEY_CTX *kex; + EVP_PKEY *kexParam; + const OQSX_KEX_INFO *kex_info; +}; + +typedef struct oqsx_evp_ctx_st OQSX_EVP_CTX; + +typedef union { + OQS_SIG *sig; + OQS_KEM *kem; +} OQSX_QS_CTX; + +struct oqsx_provider_ctx_st { + OQSX_QS_CTX oqsx_qs_ctx; + OQSX_EVP_CTX *oqsx_evp_ctx; +}; + +typedef struct oqsx_provider_ctx_st OQSX_PROVIDER_CTX; + +enum oqsx_key_type_en { + KEY_TYPE_SIG, KEY_TYPE_KEM, KEY_TYPE_ECP_HYB_KEM, KEY_TYPE_ECX_HYB_KEM +}; + +typedef enum oqsx_key_type_en OQSX_KEY_TYPE; + +struct oqsx_key_st { + OSSL_LIB_CTX *libctx; + char *propq; + OQSX_KEY_TYPE keytype; + OQSX_PROVIDER_CTX oqsx_provider_ctx; + size_t numkeys; + size_t privkeylen; + size_t pubkeylen; + size_t bit_security; + char *oqs_name; + char *tls_name; + _Atomic int references; + void **comp_privkey; + void **comp_pubkey; + void *privkey; + void *pubkey; +}; + +typedef struct oqsx_key_st OQSX_KEY; + +int oqs_set_nid(char* tlsname, int nid); +OQSX_KEY *oqsx_key_new(OSSL_LIB_CTX *libctx, char* oqs_name, char* tls_name, int is_kem, const char *propq, int bit_security); +int oqsx_key_allocate_keymaterial(OQSX_KEY *key); +void oqsx_key_free(OQSX_KEY *key); +int oqsx_key_up_ref(OQSX_KEY *key); +int oqsx_key_gen(OQSX_KEY *key); +OQSX_KEY *oqsx_key_from_pkcs8(const PKCS8_PRIV_KEY_INFO *p8inf, OSSL_LIB_CTX *libctx, const char *propq); +OQSX_KEY *oqsx_key_from_x509pubkey(const X509_PUBKEY *xpk, OSSL_LIB_CTX *libctx, const char *propq); + +/* Backend support */ +int oqsx_public_from_private(OQSX_KEY *key); +int oqsx_key_fromdata(OQSX_KEY *oqsxk, const OSSL_PARAM params[], + int include_private); +int oqsx_key_parambits(OQSX_KEY *k); +int oqsx_key_maxsize(OQSX_KEY *k); +void oqsx_key_set0_libctx(OQSX_KEY *key, OSSL_LIB_CTX *libctx); + +/* Function prototypes */ + +extern const OSSL_DISPATCH oqs_generic_kem_functions[]; +extern const OSSL_DISPATCH oqs_hybrid_kem_functions[]; +extern const OSSL_DISPATCH oqs_signature_functions[]; + +///// OQS_TEMPLATE_FRAGMENT_ENDECODER_FUNCTIONS_START +extern const OSSL_DISPATCH oqs_dilithium2_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium2_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium2_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium2_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium2_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium2_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_PrivateKeyInfo_der_to_dilithium2_decoder_functions[]; +extern const OSSL_DISPATCH oqs_SubjectPublicKeyInfo_der_to_dilithium2_decoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium3_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium3_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium3_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium3_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium3_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium3_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_PrivateKeyInfo_der_to_dilithium3_decoder_functions[]; +extern const OSSL_DISPATCH oqs_SubjectPublicKeyInfo_der_to_dilithium3_decoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium5_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium5_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium5_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium5_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium5_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium5_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_PrivateKeyInfo_der_to_dilithium5_decoder_functions[]; +extern const OSSL_DISPATCH oqs_SubjectPublicKeyInfo_der_to_dilithium5_decoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium2_aes_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium2_aes_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium2_aes_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium2_aes_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium2_aes_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium2_aes_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_PrivateKeyInfo_der_to_dilithium2_aes_decoder_functions[]; +extern const OSSL_DISPATCH oqs_SubjectPublicKeyInfo_der_to_dilithium2_aes_decoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium3_aes_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium3_aes_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium3_aes_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium3_aes_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium3_aes_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium3_aes_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_PrivateKeyInfo_der_to_dilithium3_aes_decoder_functions[]; +extern const OSSL_DISPATCH oqs_SubjectPublicKeyInfo_der_to_dilithium3_aes_decoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium5_aes_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium5_aes_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium5_aes_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium5_aes_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium5_aes_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_dilithium5_aes_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_PrivateKeyInfo_der_to_dilithium5_aes_decoder_functions[]; +extern const OSSL_DISPATCH oqs_SubjectPublicKeyInfo_der_to_dilithium5_aes_decoder_functions[]; +extern const OSSL_DISPATCH oqs_falcon512_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_falcon512_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_falcon512_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_falcon512_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_falcon512_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_falcon512_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_PrivateKeyInfo_der_to_falcon512_decoder_functions[]; +extern const OSSL_DISPATCH oqs_SubjectPublicKeyInfo_der_to_falcon512_decoder_functions[]; +extern const OSSL_DISPATCH oqs_falcon1024_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_falcon1024_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_falcon1024_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_falcon1024_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_falcon1024_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_falcon1024_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_PrivateKeyInfo_der_to_falcon1024_decoder_functions[]; +extern const OSSL_DISPATCH oqs_SubjectPublicKeyInfo_der_to_falcon1024_decoder_functions[]; +extern const OSSL_DISPATCH oqs_picnicl1full_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_picnicl1full_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_picnicl1full_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_picnicl1full_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_picnicl1full_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_picnicl1full_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_PrivateKeyInfo_der_to_picnicl1full_decoder_functions[]; +extern const OSSL_DISPATCH oqs_SubjectPublicKeyInfo_der_to_picnicl1full_decoder_functions[]; +extern const OSSL_DISPATCH oqs_picnic3l1_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_picnic3l1_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_picnic3l1_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_picnic3l1_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_picnic3l1_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_picnic3l1_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_PrivateKeyInfo_der_to_picnic3l1_decoder_functions[]; +extern const OSSL_DISPATCH oqs_SubjectPublicKeyInfo_der_to_picnic3l1_decoder_functions[]; +extern const OSSL_DISPATCH oqs_rainbowIclassic_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_rainbowIclassic_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_rainbowIclassic_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_rainbowIclassic_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_rainbowIclassic_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_rainbowIclassic_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_PrivateKeyInfo_der_to_rainbowIclassic_decoder_functions[]; +extern const OSSL_DISPATCH oqs_SubjectPublicKeyInfo_der_to_rainbowIclassic_decoder_functions[]; +extern const OSSL_DISPATCH oqs_rainbowVclassic_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_rainbowVclassic_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_rainbowVclassic_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_rainbowVclassic_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_rainbowVclassic_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_rainbowVclassic_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_PrivateKeyInfo_der_to_rainbowVclassic_decoder_functions[]; +extern const OSSL_DISPATCH oqs_SubjectPublicKeyInfo_der_to_rainbowVclassic_decoder_functions[]; +extern const OSSL_DISPATCH oqs_sphincsharaka128frobust_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_sphincsharaka128frobust_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_sphincsharaka128frobust_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_sphincsharaka128frobust_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_sphincsharaka128frobust_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_sphincsharaka128frobust_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_PrivateKeyInfo_der_to_sphincsharaka128frobust_decoder_functions[]; +extern const OSSL_DISPATCH oqs_SubjectPublicKeyInfo_der_to_sphincsharaka128frobust_decoder_functions[]; +extern const OSSL_DISPATCH oqs_sphincssha256128frobust_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_sphincssha256128frobust_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_sphincssha256128frobust_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_sphincssha256128frobust_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_sphincssha256128frobust_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_sphincssha256128frobust_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_PrivateKeyInfo_der_to_sphincssha256128frobust_decoder_functions[]; +extern const OSSL_DISPATCH oqs_SubjectPublicKeyInfo_der_to_sphincssha256128frobust_decoder_functions[]; +extern const OSSL_DISPATCH oqs_sphincsshake256128frobust_to_PrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_sphincsshake256128frobust_to_PrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_sphincsshake256128frobust_to_EncryptedPrivateKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_sphincsshake256128frobust_to_EncryptedPrivateKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_sphincsshake256128frobust_to_SubjectPublicKeyInfo_der_encoder_functions[]; +extern const OSSL_DISPATCH oqs_sphincsshake256128frobust_to_SubjectPublicKeyInfo_pem_encoder_functions[]; +extern const OSSL_DISPATCH oqs_PrivateKeyInfo_der_to_sphincsshake256128frobust_decoder_functions[]; +extern const OSSL_DISPATCH oqs_SubjectPublicKeyInfo_der_to_sphincsshake256128frobust_decoder_functions[]; +///// OQS_TEMPLATE_FRAGMENT_ENDECODER_FUNCTIONS_END + +///// OQS_TEMPLATE_FRAGMENT_ALG_FUNCTIONS_START +extern const OSSL_DISPATCH oqs_dilithium2_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_dilithium3_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_dilithium5_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_dilithium2_aes_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_dilithium3_aes_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_dilithium5_aes_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_falcon512_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_falcon1024_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_picnicl1full_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_picnic3l1_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_rainbowIclassic_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_rainbowVclassic_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_sphincsharaka128frobust_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_sphincssha256128frobust_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_sphincsshake256128frobust_keymgmt_functions[]; + +extern const OSSL_DISPATCH oqs_frodo640aes_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_frodo640shake_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_frodo976aes_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_frodo976shake_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_frodo1344aes_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_frodo1344shake_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_kyber512_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_kyber768_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_kyber1024_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ntru_hps2048509_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ntru_hps2048677_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ntru_hps4096821_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ntru_hrss701_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_lightsaber_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_saber_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_firesaber_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_sidhp434_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_sidhp503_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_sidhp610_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_sidhp751_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_sikep434_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_sikep503_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_sikep610_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_sikep751_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_bikel1_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_bikel3_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_kyber90s512_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_kyber90s768_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_kyber90s1024_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_hqc128_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_hqc192_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_hqc256_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ntrulpr653_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ntrulpr761_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ntrulpr857_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_sntrup653_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_sntrup761_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_sntrup857_keymgmt_functions[]; + +extern const OSSL_DISPATCH oqs_ecp_frodo640aes_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_frodo640shake_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_frodo976aes_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_frodo976shake_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_frodo1344aes_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_frodo1344shake_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_kyber512_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_kyber768_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_kyber1024_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_ntru_hps2048509_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_ntru_hps2048677_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_ntru_hps4096821_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_ntru_hrss701_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_lightsaber_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_saber_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_firesaber_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_sidhp434_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_sidhp503_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_sidhp610_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_sidhp751_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_sikep434_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_sikep503_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_sikep610_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_sikep751_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_bikel1_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_bikel3_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_kyber90s512_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_kyber90s768_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_kyber90s1024_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_hqc128_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_hqc192_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_hqc256_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_ntrulpr653_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_ntrulpr761_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_ntrulpr857_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_sntrup653_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_sntrup761_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecp_sntrup857_keymgmt_functions[]; + +extern const OSSL_DISPATCH oqs_ecx_frodo640aes_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_frodo640shake_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_frodo976aes_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_frodo976shake_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_frodo1344aes_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_frodo1344shake_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_kyber512_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_kyber768_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_kyber1024_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_ntru_hps2048509_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_ntru_hps2048677_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_ntru_hps4096821_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_ntru_hrss701_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_lightsaber_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_saber_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_firesaber_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_sidhp434_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_sidhp503_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_sidhp610_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_sidhp751_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_sikep434_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_sikep503_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_sikep610_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_sikep751_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_bikel1_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_bikel3_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_kyber90s512_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_kyber90s768_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_kyber90s1024_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_hqc128_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_hqc192_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_hqc256_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_ntrulpr653_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_ntrulpr761_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_ntrulpr857_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_sntrup653_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_sntrup761_keymgmt_functions[]; +extern const OSSL_DISPATCH oqs_ecx_sntrup857_keymgmt_functions[]; +///// OQS_TEMPLATE_FRAGMENT_ALG_FUNCTIONS_END + +/* BIO function declarations */ +int oqs_prov_bio_from_dispatch(const OSSL_DISPATCH *fns); + +OSSL_CORE_BIO *oqs_prov_bio_new_file(const char *filename, const char *mode); +OSSL_CORE_BIO *oqs_prov_bio_new_membuf(const char *filename, int len); +int oqs_prov_bio_read_ex(OSSL_CORE_BIO *bio, void *data, size_t data_len, + size_t *bytes_read); +int oqs_prov_bio_write_ex(OSSL_CORE_BIO *bio, const void *data, size_t data_len, + size_t *written); +int oqs_prov_bio_gets(OSSL_CORE_BIO *bio, char *buf, int size); +int oqs_prov_bio_puts(OSSL_CORE_BIO *bio, const char *str); +int oqs_prov_bio_ctrl(OSSL_CORE_BIO *bio, int cmd, long num, void *ptr); +int oqs_prov_bio_up_ref(OSSL_CORE_BIO *bio); +int oqs_prov_bio_free(OSSL_CORE_BIO *bio); +int oqs_prov_bio_vprintf(OSSL_CORE_BIO *bio, const char *format, va_list ap); +int oqs_prov_bio_printf(OSSL_CORE_BIO *bio, const char *format, ...); + +BIO_METHOD *oqs_bio_prov_init_bio_method(void); +BIO *oqs_bio_new_from_core_bio(PROV_OQS_CTX *provctx, OSSL_CORE_BIO *corebio); + +#endif diff --git a/oqsprov/oqs_sig.c b/oqsprov/oqs_sig.c index 646531cb..a20e3aac 100644 --- a/oqsprov/oqs_sig.c +++ b/oqsprov/oqs_sig.c @@ -24,20 +24,13 @@ #include #include #include -#include "oqsx.h" - -// our own error codes: -#define OQSPROV_R_INVALID_DIGEST 1 -#define OQSPROV_R_INVALID_SIZE 2 -#define OQSPROV_R_INVALID_KEY 3 +#include +#include "oqs_prov.h" // TBD: Review what we really need/want: For now go with OSSL settings: #define OSSL_MAX_NAME_SIZE 50 #define OSSL_MAX_PROPQUERY_SIZE 256 /* Property query strings */ -// internal, but useful OSSL define: -# define OSSL_NELEM(x) (sizeof(x)/sizeof((x)[0])) - #ifdef NDEBUG #define OQS_SIG_PRINTF(a) #define OQS_SIG_PRINTF2(a, b) @@ -71,55 +64,66 @@ static OSSL_FUNC_signature_set_ctx_md_params_fn oqs_sig_set_ctx_md_params; static OSSL_FUNC_signature_settable_ctx_md_params_fn oqs_sig_settable_ctx_md_params; // OIDS: -static int get_oqs_oid(unsigned char* oidbuf, const char *oqs_name) { +static int get_oqs_aid(unsigned char** oidbuf, const char *oqs_name) { + X509_ALGOR *algor = X509_ALGOR_new(); + int aidlen = 0; + ///// OQS_TEMPLATE_FRAGMENT_SIG_OIDS_START if (!strcmp(OQS_SIG_alg_dilithium_2, oqs_name)) - return i2d_ASN1_OBJECT(OBJ_txt2obj("1.3.6.1.4.1.2.267.7.4.4", 1), &oidbuf); + X509_ALGOR_set0(algor, OBJ_txt2obj("dilithium2", 0), V_ASN1_UNDEF, NULL); else if (!strcmp(OQS_SIG_alg_dilithium_3, oqs_name)) - return i2d_ASN1_OBJECT(OBJ_txt2obj("1.3.6.1.4.1.2.267.7.6.5", 1), &oidbuf); + X509_ALGOR_set0(algor, OBJ_txt2obj("dilithium3", 0), V_ASN1_UNDEF, NULL); else if (!strcmp(OQS_SIG_alg_dilithium_5, oqs_name)) - return i2d_ASN1_OBJECT(OBJ_txt2obj("1.3.6.1.4.1.2.267.7.8.7", 1), &oidbuf); + X509_ALGOR_set0(algor, OBJ_txt2obj("dilithium5", 0), V_ASN1_UNDEF, NULL); else if (!strcmp(OQS_SIG_alg_dilithium_2_aes, oqs_name)) - return i2d_ASN1_OBJECT(OBJ_txt2obj("1.3.6.1.4.1.2.267.11.4.4", 1), &oidbuf); + X509_ALGOR_set0(algor, OBJ_txt2obj("dilithium2_aes", 0), V_ASN1_UNDEF, NULL); else if (!strcmp(OQS_SIG_alg_dilithium_3_aes, oqs_name)) - return i2d_ASN1_OBJECT(OBJ_txt2obj("1.3.6.1.4.1.2.267.11.6.5", 1), &oidbuf); + X509_ALGOR_set0(algor, OBJ_txt2obj("dilithium3_aes", 0), V_ASN1_UNDEF, NULL); else if (!strcmp(OQS_SIG_alg_dilithium_5_aes, oqs_name)) - return i2d_ASN1_OBJECT(OBJ_txt2obj("1.3.6.1.4.1.2.267.11.8.7", 1), &oidbuf); + X509_ALGOR_set0(algor, OBJ_txt2obj("dilithium5_aes", 0), V_ASN1_UNDEF, NULL); else if (!strcmp(OQS_SIG_alg_falcon_512, oqs_name)) - return i2d_ASN1_OBJECT(OBJ_txt2obj("1.3.9999.3.1", 1), &oidbuf); + X509_ALGOR_set0(algor, OBJ_txt2obj("falcon512", 0), V_ASN1_UNDEF, NULL); else if (!strcmp(OQS_SIG_alg_falcon_1024, oqs_name)) - return i2d_ASN1_OBJECT(OBJ_txt2obj("1.3.9999.3.4", 1), &oidbuf); + X509_ALGOR_set0(algor, OBJ_txt2obj("falcon1024", 0), V_ASN1_UNDEF, NULL); else if (!strcmp(OQS_SIG_alg_picnic_L1_full, oqs_name)) - return i2d_ASN1_OBJECT(OBJ_txt2obj("1.3.6.1.4.1.311.89.2.1.7", 1), &oidbuf); + X509_ALGOR_set0(algor, OBJ_txt2obj("picnicl1full", 0), V_ASN1_UNDEF, NULL); else if (!strcmp(OQS_SIG_alg_picnic3_L1, oqs_name)) - return i2d_ASN1_OBJECT(OBJ_txt2obj("1.3.6.1.4.1.311.89.2.1.21", 1), &oidbuf); + X509_ALGOR_set0(algor, OBJ_txt2obj("picnic3l1", 0), V_ASN1_UNDEF, NULL); else if (!strcmp(OQS_SIG_alg_rainbow_I_classic, oqs_name)) - return i2d_ASN1_OBJECT(OBJ_txt2obj("1.3.9999.5.1.1.1", 1), &oidbuf); + X509_ALGOR_set0(algor, OBJ_txt2obj("rainbowIclassic", 0), V_ASN1_UNDEF, NULL); else if (!strcmp(OQS_SIG_alg_rainbow_V_classic, oqs_name)) - return i2d_ASN1_OBJECT(OBJ_txt2obj("1.3.9999.5.3.1.1", 1), &oidbuf); + X509_ALGOR_set0(algor, OBJ_txt2obj("rainbowVclassic", 0), V_ASN1_UNDEF, NULL); else if (!strcmp(OQS_SIG_alg_sphincs_haraka_128f_robust, oqs_name)) - return i2d_ASN1_OBJECT(OBJ_txt2obj("1.3.9999.6.1.1", 1), &oidbuf); + X509_ALGOR_set0(algor, OBJ_txt2obj("sphincsharaka128frobust", 0), V_ASN1_UNDEF, NULL); else if (!strcmp(OQS_SIG_alg_sphincs_sha256_128f_robust, oqs_name)) - return i2d_ASN1_OBJECT(OBJ_txt2obj("1.3.9999.6.4.1", 1), &oidbuf); + X509_ALGOR_set0(algor, OBJ_txt2obj("sphincssha256128frobust", 0), V_ASN1_UNDEF, NULL); else if (!strcmp(OQS_SIG_alg_sphincs_shake256_128f_robust, oqs_name)) - return i2d_ASN1_OBJECT(OBJ_txt2obj("1.3.9999.6.7.1", 1), &oidbuf); + X509_ALGOR_set0(algor, OBJ_txt2obj("sphincsshake256128frobust", 0), V_ASN1_UNDEF, NULL); else ///// OQS_TEMPLATE_FRAGMENT_SIG_OIDS_END - return(0); + // else closure: + { + X509_ALGOR_free(algor); + return 0; + } + + aidlen = i2d_X509_ALGOR(algor, oidbuf); + X509_ALGOR_free(algor); + return(aidlen); } /* @@ -149,6 +153,8 @@ typedef struct { EVP_MD *md; EVP_MD_CTX *mdctx; size_t mdsize; + // for collecting data if no MD is active: + char* mddata; int operation; } PROV_OQSSIG_CTX; @@ -172,7 +178,7 @@ static void *oqs_sig_newctx(void *provctx, const char *propq) return NULL; poqs_sigctx->libctx = ((PROV_OQS_CTX*)provctx)->libctx; - poqs_sigctx->flag_allow_md = 0; // TBC + poqs_sigctx->flag_allow_md = 0; if (propq != NULL && (poqs_sigctx->propq = OPENSSL_strdup(propq)) == NULL) { OPENSSL_free(poqs_sigctx); poqs_sigctx = NULL; @@ -202,9 +208,10 @@ static int oqs_sig_setup_md(PROV_OQSSIG_CTX *ctx, EVP_MD_CTX_free(ctx->mdctx); EVP_MD_free(ctx->md); - OPENSSL_free(ctx->aid); + if (ctx->aid) + OPENSSL_free(ctx->aid); ctx->aid = NULL; // ensure next function allocates memory - ctx->aid_len = get_oqs_oid(ctx->aid, ctx->sig->oqsx_provider_ctx.oqsx_qs_ctx.sig->method_name); + ctx->aid_len = get_oqs_aid(&(ctx->aid), ctx->sig->oqsx_provider_ctx.oqsx_qs_ctx.sig->method_name); ctx->mdctx = NULL; ctx->md = md; @@ -253,7 +260,8 @@ static int oqs_sig_sign(void *vpoqs_sigctx, unsigned char *sig, size_t *siglen, size_t oqs_sigsize = poqs_sigctx->sig->oqsx_provider_ctx.oqsx_qs_ctx.sig->length_signature; size_t mdsize = oqs_sig_get_md_size(poqs_sigctx); - OQS_SIG_PRINTF("OQS SIG provider: sign called\n"); + OQS_SIG_PRINTF2("OQS SIG provider: sign called for %ld bytes\n", tbslen); + OQS_SIG_PRINTF2("OQS SIG provider: mdsize %ld bytes\n", mdsize); if (sig == NULL) { *siglen = oqs_sigsize; @@ -272,7 +280,8 @@ static int oqs_sig_sign(void *vpoqs_sigctx, unsigned char *sig, size_t *siglen, ret = OQS_SIG_sign(poqs_sigctx->sig->oqsx_provider_ctx.oqsx_qs_ctx.sig, sig, siglen, tbs, tbslen, poqs_sigctx->sig->privkey); if (ret != OQS_SUCCESS) { - printf("OQS sign error\n"); + ERR_raise(ERR_LIB_USER, OQSPROV_R_SIGN_ERROR); + OQS_SIG_PRINTF("OQS sign error!!!\n"); return 0; } @@ -286,13 +295,15 @@ static int oqs_sig_verify(void *vpoqs_sigctx, const unsigned char *sig, size_t s size_t mdsize = oqs_sig_get_md_size(poqs_sigctx); int ret = 0; - OQS_SIG_PRINTF("OQS SIG provider: verify called\n"); + OQS_SIG_PRINTF3("OQS SIG provider: verify called with siglen %ld bytes and tbslen %ld\n", siglen, tbslen); + OQS_SIG_PRINTF2("OQS SIG provider: mdsize %ld bytes\n", mdsize); if (mdsize != 0 && tbslen != mdsize) return 0; ret = OQS_SIG_verify(poqs_sigctx->sig->oqsx_provider_ctx.oqsx_qs_ctx.sig, tbs, tbslen, sig, siglen, poqs_sigctx->sig->pubkey); if (ret != OQS_SUCCESS) { - printf("OQS sign error\n"); + ERR_raise(ERR_LIB_USER, OQSPROV_R_SIGN_ERROR); + OQS_SIG_PRINTF("OQS verify error!!\n"); return 0; } @@ -304,7 +315,7 @@ static int oqs_sig_digest_signverify_init(void *vpoqs_sigctx, const char *mdname { PROV_OQSSIG_CTX *poqs_sigctx = (PROV_OQSSIG_CTX *)vpoqs_sigctx; - OQS_SIG_PRINTF("OQS SIG provider: digest_signverify called\n"); + OQS_SIG_PRINTF2("OQS SIG provider: digest_signverify_init called for mdname %s\n", mdname); poqs_sigctx->flag_allow_md = 0; if (!oqs_sig_signverify_init(vpoqs_sigctx, voqssig, operation)) @@ -313,12 +324,15 @@ static int oqs_sig_digest_signverify_init(void *vpoqs_sigctx, const char *mdname if (!oqs_sig_setup_md(poqs_sigctx, mdname, NULL)) return 0; - poqs_sigctx->mdctx = EVP_MD_CTX_new(); - if (poqs_sigctx->mdctx == NULL) - goto error; + // TBD: review when hybrids get added + if (mdname != NULL) { + poqs_sigctx->mdctx = EVP_MD_CTX_new(); + if (poqs_sigctx->mdctx == NULL) + goto error; - if (!EVP_DigestInit_ex(poqs_sigctx->mdctx, poqs_sigctx->md, NULL)) - goto error; + if (!EVP_DigestInit_ex(poqs_sigctx->mdctx, poqs_sigctx->md, NULL)) + goto error; + } return 1; @@ -327,6 +341,7 @@ static int oqs_sig_digest_signverify_init(void *vpoqs_sigctx, const char *mdname EVP_MD_free(poqs_sigctx->md); poqs_sigctx->mdctx = NULL; poqs_sigctx->md = NULL; + OQS_SIG_PRINTF(" OQS SIG provider: digest_signverify FAILED\n"); return 0; } @@ -349,10 +364,29 @@ int oqs_sig_digest_signverify_update(void *vpoqs_sigctx, const unsigned char *da PROV_OQSSIG_CTX *poqs_sigctx = (PROV_OQSSIG_CTX *)vpoqs_sigctx; OQS_SIG_PRINTF("OQS SIG provider: digest_signverify_update called\n"); - if (poqs_sigctx == NULL || poqs_sigctx->mdctx == NULL) + + if (poqs_sigctx == NULL) return 0; - return EVP_DigestUpdate(poqs_sigctx->mdctx, data, datalen); + // unconditionally collect data for passing in full to OQS API + if (poqs_sigctx->mddata) { + int mdlen = poqs_sigctx->mdsize; + poqs_sigctx->mdsize += datalen; + char* newdata = OPENSSL_malloc(poqs_sigctx->mdsize); + memcpy(newdata, poqs_sigctx->mddata, mdlen); + memcpy(newdata+mdlen, data, datalen); + OPENSSL_free(poqs_sigctx->mddata); + poqs_sigctx->mddata = newdata; + } + else { // simple alloc and copy + poqs_sigctx->mdsize=datalen; + poqs_sigctx->mddata = OPENSSL_malloc(poqs_sigctx->mdsize); + memcpy(poqs_sigctx->mddata, data, poqs_sigctx->mdsize); + } + OQS_SIG_PRINTF2("OQS SIG provider: digest_signverify_update collected %ld bytes...\n", poqs_sigctx->mdsize); + if (poqs_sigctx->mdctx) + return EVP_DigestUpdate(poqs_sigctx->mdctx, data, datalen); + return 1; } int oqs_sig_digest_sign_final(void *vpoqs_sigctx, unsigned char *sig, size_t *siglen, @@ -363,7 +397,7 @@ int oqs_sig_digest_sign_final(void *vpoqs_sigctx, unsigned char *sig, size_t *si unsigned int dlen = 0; OQS_SIG_PRINTF("OQS SIG provider: digest_sign_final called\n"); - if (poqs_sigctx == NULL || poqs_sigctx->mdctx == NULL) + if (poqs_sigctx == NULL) return 0; /* @@ -376,13 +410,19 @@ int oqs_sig_digest_sign_final(void *vpoqs_sigctx, unsigned char *sig, size_t *si * digests exceed EVP_MAX_MD_SIZE. We should probably handle that somehow - * but that problem is much larger than just here. */ - if (!EVP_DigestFinal_ex(poqs_sigctx->mdctx, digest, &dlen)) - return 0; + if (poqs_sigctx->mdctx != NULL) + if (!EVP_DigestFinal_ex(poqs_sigctx->mdctx, digest, &dlen)) + return 0; } poqs_sigctx->flag_allow_md = 1; - return oqs_sig_sign(vpoqs_sigctx, sig, siglen, sigsize, digest, (size_t)dlen); + // TBC for hybrids: + if (poqs_sigctx->mdctx != NULL) + return oqs_sig_sign(vpoqs_sigctx, sig, siglen, sigsize, digest, (size_t)dlen); + else + return oqs_sig_sign(vpoqs_sigctx, sig, siglen, sigsize, poqs_sigctx->mddata, poqs_sigctx->mdsize); + } @@ -394,20 +434,20 @@ int oqs_sig_digest_verify_final(void *vpoqs_sigctx, const unsigned char *sig, unsigned int dlen = 0; OQS_SIG_PRINTF("OQS SIG provider: digest_verify_final called\n"); - if (poqs_sigctx == NULL || poqs_sigctx->mdctx == NULL) + if (poqs_sigctx == NULL) return 0; - /* - * TODO(3.0): There is the possibility that some externally provided - * digests exceed EVP_MAX_MD_SIZE. We should probably handle that somehow - - * but that problem is much larger than just here. - */ - if (!EVP_DigestFinal_ex(poqs_sigctx->mdctx, digest, &dlen)) - return 0; + // TBC for hybrids: + if (poqs_sigctx->mdctx) { + if (!EVP_DigestFinal_ex(poqs_sigctx->mdctx, digest, &dlen)) + return 0; - poqs_sigctx->flag_allow_md = 1; + poqs_sigctx->flag_allow_md = 1; - return oqs_sig_verify(vpoqs_sigctx, sig, siglen, digest, (size_t)dlen); + return oqs_sig_verify(vpoqs_sigctx, sig, siglen, digest, (size_t)dlen); + } + else + return oqs_sig_verify(vpoqs_sigctx, sig, siglen, poqs_sigctx->mddata, poqs_sigctx->mdsize); } static void oqs_sig_freectx(void *vpoqs_sigctx) @@ -421,8 +461,10 @@ static void oqs_sig_freectx(void *vpoqs_sigctx) ctx->propq = NULL; ctx->mdctx = NULL; ctx->md = NULL; - ctx->mdsize = 0; oqsx_key_free(ctx->sig); + OPENSSL_free(ctx->mddata); + ctx->mddata = NULL; + ctx->mdsize = 0; OPENSSL_free(ctx); } @@ -457,6 +499,11 @@ static void *oqs_sig_dupctx(void *vpoqs_sigctx) goto err; } + if (srcctx->mddata) { + dstctx->mddata=OPENSSL_memdup(srcctx->mddata, srcctx->mdsize); + dstctx->mdsize = srcctx->mdsize; + } + return dstctx; err: oqs_sig_freectx(dstctx); @@ -473,6 +520,10 @@ static int oqs_sig_get_ctx_params(void *vpoqs_sigctx, OSSL_PARAM *params) return 0; p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID); + + if (poqs_sigctx->aid == NULL) + poqs_sigctx->aid_len = get_oqs_aid(&(poqs_sigctx->aid), poqs_sigctx->sig->oqsx_provider_ctx.oqsx_qs_ctx.sig->method_name); + if (p != NULL && !OSSL_PARAM_set_octet_string(p, poqs_sigctx->aid, poqs_sigctx->aid_len)) return 0; @@ -596,7 +647,6 @@ static const OSSL_PARAM *oqs_sig_settable_ctx_md_params(void *vpoqs_sigctx) return EVP_MD_settable_ctx_params(poqs_sigctx->md); } -// TBD: Templatize for #ALG where/if necessary const OSSL_DISPATCH oqs_signature_functions[] = { { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))oqs_sig_newctx }, { OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))oqs_sig_sign_init }, diff --git a/oqsprov/oqsdecoders.inc b/oqsprov/oqsdecoders.inc new file mode 100644 index 00000000..d7708cb0 --- /dev/null +++ b/oqsprov/oqsdecoders.inc @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: Apache-2.0 AND MIT + +/* + * OQS OpenSSL 3 provider decoders + * + * Code strongly inspired by OpenSSL default provider. + * + */ + +#ifndef DECODER_PROVIDER +# error Macro DECODER_PROVIDER undefined +#endif + +#define DECODER_STRUCTURE_type_specific_keypair "type-specific" +#define DECODER_STRUCTURE_type_specific_params "type-specific" +#define DECODER_STRUCTURE_type_specific "type-specific" +#define DECODER_STRUCTURE_type_specific_no_pub "type-specific" +#define DECODER_STRUCTURE_PKCS8 "pkcs8" +#define DECODER_STRUCTURE_SubjectPublicKeyInfo "SubjectPublicKeyInfo" +#define DECODER_STRUCTURE_PrivateKeyInfo "PrivateKeyInfo" + +/* Arguments are prefixed with '_' to avoid build breaks on certain platforms */ +#define DECODER(_name, _input, _output) \ + { _name, \ + "provider=" DECODER_PROVIDER ",input=" #_input, \ + (oqs_##_input##_to_##_output##_decoder_functions) } +#define DECODER_w_structure(_name, _input, _structure, _output) \ + { _name, \ + "provider=" DECODER_PROVIDER ",input=" #_input \ + ",structure=" DECODER_STRUCTURE_##_structure, \ + (oqs_##_structure##_##_input##_to_##_output##_decoder_functions) } + +///// OQS_TEMPLATE_FRAGMENT_MAKE_START +DECODER_w_structure("dilithium2", der, PrivateKeyInfo, dilithium2), +DECODER_w_structure("dilithium2", der, SubjectPublicKeyInfo, dilithium2), +DECODER_w_structure("dilithium3", der, PrivateKeyInfo, dilithium3), +DECODER_w_structure("dilithium3", der, SubjectPublicKeyInfo, dilithium3), +DECODER_w_structure("dilithium5", der, PrivateKeyInfo, dilithium5), +DECODER_w_structure("dilithium5", der, SubjectPublicKeyInfo, dilithium5), +DECODER_w_structure("dilithium2_aes", der, PrivateKeyInfo, dilithium2_aes), +DECODER_w_structure("dilithium2_aes", der, SubjectPublicKeyInfo, dilithium2_aes), +DECODER_w_structure("dilithium3_aes", der, PrivateKeyInfo, dilithium3_aes), +DECODER_w_structure("dilithium3_aes", der, SubjectPublicKeyInfo, dilithium3_aes), +DECODER_w_structure("dilithium5_aes", der, PrivateKeyInfo, dilithium5_aes), +DECODER_w_structure("dilithium5_aes", der, SubjectPublicKeyInfo, dilithium5_aes), +DECODER_w_structure("falcon512", der, PrivateKeyInfo, falcon512), +DECODER_w_structure("falcon512", der, SubjectPublicKeyInfo, falcon512), +DECODER_w_structure("falcon1024", der, PrivateKeyInfo, falcon1024), +DECODER_w_structure("falcon1024", der, SubjectPublicKeyInfo, falcon1024), +DECODER_w_structure("picnicl1full", der, PrivateKeyInfo, picnicl1full), +DECODER_w_structure("picnicl1full", der, SubjectPublicKeyInfo, picnicl1full), +DECODER_w_structure("picnic3l1", der, PrivateKeyInfo, picnic3l1), +DECODER_w_structure("picnic3l1", der, SubjectPublicKeyInfo, picnic3l1), +DECODER_w_structure("rainbowIclassic", der, PrivateKeyInfo, rainbowIclassic), +DECODER_w_structure("rainbowIclassic", der, SubjectPublicKeyInfo, rainbowIclassic), +DECODER_w_structure("rainbowVclassic", der, PrivateKeyInfo, rainbowVclassic), +DECODER_w_structure("rainbowVclassic", der, SubjectPublicKeyInfo, rainbowVclassic), +DECODER_w_structure("sphincsharaka128frobust", der, PrivateKeyInfo, sphincsharaka128frobust), +DECODER_w_structure("sphincsharaka128frobust", der, SubjectPublicKeyInfo, sphincsharaka128frobust), +DECODER_w_structure("sphincssha256128frobust", der, PrivateKeyInfo, sphincssha256128frobust), +DECODER_w_structure("sphincssha256128frobust", der, SubjectPublicKeyInfo, sphincssha256128frobust), +DECODER_w_structure("sphincsshake256128frobust", der, PrivateKeyInfo, sphincsshake256128frobust), +DECODER_w_structure("sphincsshake256128frobust", der, SubjectPublicKeyInfo, sphincsshake256128frobust), +///// OQS_TEMPLATE_FRAGMENT_MAKE_END diff --git a/oqsprov/oqsencoders.inc b/oqsprov/oqsencoders.inc new file mode 100644 index 00000000..69435211 --- /dev/null +++ b/oqsprov/oqsencoders.inc @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: Apache-2.0 AND MIT + +/* + * OQS OpenSSL 3 provider encoders + * + * Code strongly inspired by OpenSSL default provider. + * + */ + +#ifndef ENCODER_PROVIDER +# error Macro ENCODER_PROVIDER undefined +#endif + +#define ENCODER_STRUCTURE_type_specific_keypair "type-specific" +#define ENCODER_STRUCTURE_type_specific_params "type-specific" +#define ENCODER_STRUCTURE_type_specific "type-specific" +#define ENCODER_STRUCTURE_type_specific_no_pub "type-specific" +#define ENCODER_STRUCTURE_PKCS8 "pkcs8" +#define ENCODER_STRUCTURE_SubjectPublicKeyInfo "SubjectPublicKeyInfo" +#define ENCODER_STRUCTURE_PrivateKeyInfo "PrivateKeyInfo" +#define ENCODER_STRUCTURE_EncryptedPrivateKeyInfo "EncryptedPrivateKeyInfo" +#define ENCODER_STRUCTURE_PKCS1 "pkcs1" +#define ENCODER_STRUCTURE_PKCS3 "pkcs3" + +/* Arguments are prefixed with '_' to avoid build breaks on certain platforms */ +#define ENCODER_TEXT(_name, _sym) \ + { _name, \ + "provider=" ENCODER_PROVIDER ",output=text", \ + (oqs_##_sym##_to_text_encoder_functions) } +#define ENCODER(_name, _sym, _fips, _output) \ + { _name, \ + "provider=" ENCODER_PROVIDER ",output=" #_output, \ + (oqs_##_sym##_to_##_output##_encoder_functions) } + +#define ENCODER_w_structure(_name, _sym, _output, _structure) \ + { _name, \ + "provider=" ENCODER_PROVIDER ",output=" #_output \ + ",structure=" ENCODER_STRUCTURE_##_structure, \ + (oqs_##_sym##_to_##_structure##_##_output##_encoder_functions) } + +/* + * Entries for human text "encoders" + */ + +/* + * Entries for key type specific output formats. The structure name on these + * is the same as the key type name. This allows us to say something like: + * + * To replace i2d_{TYPE}PrivateKey(), i2d_{TYPE}PublicKey() and + * i2d_{TYPE}Params(), use OSSL_ENCODER functions with an OSSL_ENCODER_CTX + * created like this: + * + * OSSL_ENCODER_CTX *ctx = + * OSSL_ENCODER_CTX_new_for_pkey(pkey, selection, "DER", "type-specific", + * NULL, NULL); + * + * To replace PEM_write_bio_{TYPE}PrivateKey(), PEM_write_bio_{TYPE}PublicKey() + * and PEM_write_bio_{TYPE}Params(), use OSSL_ENCODER functions with an + * OSSL_ENCODER_CTX created like this: + * + * OSSL_ENCODER_CTX *ctx = + * OSSL_ENCODER_CTX_new_for_pkey(pkey, selection, "PEM", "type-specific", + * NULL, NULL); + * + * We only implement those for which there are current i2d_ and PEM_write_bio + * implementations. + */ + +/* + * Entries for PKCS#8 and SubjectPublicKeyInfo. + * The "der" ones are added convenience for any user that wants to use + * OSSL_ENCODER directly. + * The "pem" ones also support PEM_write_bio_PrivateKey() and + * PEM_write_bio_PUBKEY(). + */ + +///// OQS_TEMPLATE_FRAGMENT_MAKE_START +ENCODER_w_structure("dilithium2", dilithium2, der, PrivateKeyInfo), +ENCODER_w_structure("dilithium2", dilithium2, pem, PrivateKeyInfo), +ENCODER_w_structure("dilithium2", dilithium2, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("dilithium2", dilithium2, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("dilithium2", dilithium2, der, SubjectPublicKeyInfo), +ENCODER_w_structure("dilithium2", dilithium2, pem, SubjectPublicKeyInfo), +ENCODER_w_structure("dilithium3", dilithium3, der, PrivateKeyInfo), +ENCODER_w_structure("dilithium3", dilithium3, pem, PrivateKeyInfo), +ENCODER_w_structure("dilithium3", dilithium3, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("dilithium3", dilithium3, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("dilithium3", dilithium3, der, SubjectPublicKeyInfo), +ENCODER_w_structure("dilithium3", dilithium3, pem, SubjectPublicKeyInfo), +ENCODER_w_structure("dilithium5", dilithium5, der, PrivateKeyInfo), +ENCODER_w_structure("dilithium5", dilithium5, pem, PrivateKeyInfo), +ENCODER_w_structure("dilithium5", dilithium5, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("dilithium5", dilithium5, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("dilithium5", dilithium5, der, SubjectPublicKeyInfo), +ENCODER_w_structure("dilithium5", dilithium5, pem, SubjectPublicKeyInfo), +ENCODER_w_structure("dilithium2_aes", dilithium2_aes, der, PrivateKeyInfo), +ENCODER_w_structure("dilithium2_aes", dilithium2_aes, pem, PrivateKeyInfo), +ENCODER_w_structure("dilithium2_aes", dilithium2_aes, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("dilithium2_aes", dilithium2_aes, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("dilithium2_aes", dilithium2_aes, der, SubjectPublicKeyInfo), +ENCODER_w_structure("dilithium2_aes", dilithium2_aes, pem, SubjectPublicKeyInfo), +ENCODER_w_structure("dilithium3_aes", dilithium3_aes, der, PrivateKeyInfo), +ENCODER_w_structure("dilithium3_aes", dilithium3_aes, pem, PrivateKeyInfo), +ENCODER_w_structure("dilithium3_aes", dilithium3_aes, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("dilithium3_aes", dilithium3_aes, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("dilithium3_aes", dilithium3_aes, der, SubjectPublicKeyInfo), +ENCODER_w_structure("dilithium3_aes", dilithium3_aes, pem, SubjectPublicKeyInfo), +ENCODER_w_structure("dilithium5_aes", dilithium5_aes, der, PrivateKeyInfo), +ENCODER_w_structure("dilithium5_aes", dilithium5_aes, pem, PrivateKeyInfo), +ENCODER_w_structure("dilithium5_aes", dilithium5_aes, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("dilithium5_aes", dilithium5_aes, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("dilithium5_aes", dilithium5_aes, der, SubjectPublicKeyInfo), +ENCODER_w_structure("dilithium5_aes", dilithium5_aes, pem, SubjectPublicKeyInfo), +ENCODER_w_structure("falcon512", falcon512, der, PrivateKeyInfo), +ENCODER_w_structure("falcon512", falcon512, pem, PrivateKeyInfo), +ENCODER_w_structure("falcon512", falcon512, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("falcon512", falcon512, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("falcon512", falcon512, der, SubjectPublicKeyInfo), +ENCODER_w_structure("falcon512", falcon512, pem, SubjectPublicKeyInfo), +ENCODER_w_structure("falcon1024", falcon1024, der, PrivateKeyInfo), +ENCODER_w_structure("falcon1024", falcon1024, pem, PrivateKeyInfo), +ENCODER_w_structure("falcon1024", falcon1024, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("falcon1024", falcon1024, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("falcon1024", falcon1024, der, SubjectPublicKeyInfo), +ENCODER_w_structure("falcon1024", falcon1024, pem, SubjectPublicKeyInfo), +ENCODER_w_structure("picnicl1full", picnicl1full, der, PrivateKeyInfo), +ENCODER_w_structure("picnicl1full", picnicl1full, pem, PrivateKeyInfo), +ENCODER_w_structure("picnicl1full", picnicl1full, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("picnicl1full", picnicl1full, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("picnicl1full", picnicl1full, der, SubjectPublicKeyInfo), +ENCODER_w_structure("picnicl1full", picnicl1full, pem, SubjectPublicKeyInfo), +ENCODER_w_structure("picnic3l1", picnic3l1, der, PrivateKeyInfo), +ENCODER_w_structure("picnic3l1", picnic3l1, pem, PrivateKeyInfo), +ENCODER_w_structure("picnic3l1", picnic3l1, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("picnic3l1", picnic3l1, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("picnic3l1", picnic3l1, der, SubjectPublicKeyInfo), +ENCODER_w_structure("picnic3l1", picnic3l1, pem, SubjectPublicKeyInfo), +ENCODER_w_structure("rainbowIclassic", rainbowIclassic, der, PrivateKeyInfo), +ENCODER_w_structure("rainbowIclassic", rainbowIclassic, pem, PrivateKeyInfo), +ENCODER_w_structure("rainbowIclassic", rainbowIclassic, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("rainbowIclassic", rainbowIclassic, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("rainbowIclassic", rainbowIclassic, der, SubjectPublicKeyInfo), +ENCODER_w_structure("rainbowIclassic", rainbowIclassic, pem, SubjectPublicKeyInfo), +ENCODER_w_structure("rainbowVclassic", rainbowVclassic, der, PrivateKeyInfo), +ENCODER_w_structure("rainbowVclassic", rainbowVclassic, pem, PrivateKeyInfo), +ENCODER_w_structure("rainbowVclassic", rainbowVclassic, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("rainbowVclassic", rainbowVclassic, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("rainbowVclassic", rainbowVclassic, der, SubjectPublicKeyInfo), +ENCODER_w_structure("rainbowVclassic", rainbowVclassic, pem, SubjectPublicKeyInfo), +ENCODER_w_structure("sphincsharaka128frobust", sphincsharaka128frobust, der, PrivateKeyInfo), +ENCODER_w_structure("sphincsharaka128frobust", sphincsharaka128frobust, pem, PrivateKeyInfo), +ENCODER_w_structure("sphincsharaka128frobust", sphincsharaka128frobust, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("sphincsharaka128frobust", sphincsharaka128frobust, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("sphincsharaka128frobust", sphincsharaka128frobust, der, SubjectPublicKeyInfo), +ENCODER_w_structure("sphincsharaka128frobust", sphincsharaka128frobust, pem, SubjectPublicKeyInfo), +ENCODER_w_structure("sphincssha256128frobust", sphincssha256128frobust, der, PrivateKeyInfo), +ENCODER_w_structure("sphincssha256128frobust", sphincssha256128frobust, pem, PrivateKeyInfo), +ENCODER_w_structure("sphincssha256128frobust", sphincssha256128frobust, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("sphincssha256128frobust", sphincssha256128frobust, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("sphincssha256128frobust", sphincssha256128frobust, der, SubjectPublicKeyInfo), +ENCODER_w_structure("sphincssha256128frobust", sphincssha256128frobust, pem, SubjectPublicKeyInfo), +ENCODER_w_structure("sphincsshake256128frobust", sphincsshake256128frobust, der, PrivateKeyInfo), +ENCODER_w_structure("sphincsshake256128frobust", sphincsshake256128frobust, pem, PrivateKeyInfo), +ENCODER_w_structure("sphincsshake256128frobust", sphincsshake256128frobust, der, EncryptedPrivateKeyInfo), +ENCODER_w_structure("sphincsshake256128frobust", sphincsshake256128frobust, pem, EncryptedPrivateKeyInfo), +ENCODER_w_structure("sphincsshake256128frobust", sphincsshake256128frobust, der, SubjectPublicKeyInfo), +ENCODER_w_structure("sphincsshake256128frobust", sphincsshake256128frobust, pem, SubjectPublicKeyInfo), +///// OQS_TEMPLATE_FRAGMENT_MAKE_END + diff --git a/oqsprov/oqsprov.c b/oqsprov/oqsprov.c index 6bdc8443..ca244d09 100644 --- a/oqsprov/oqsprov.c +++ b/oqsprov/oqsprov.c @@ -14,7 +14,20 @@ #include #include #include -#include "oqsx.h" +#include +#include +#include +#include "oqs_prov.h" + +#ifdef NDEBUG +#define OQS_PROV_PRINTF(a) +#define OQS_PROV_PRINTF2(a, b) +#define OQS_PROV_PRINTF3(a, b, c) +#else +#define OQS_PROV_PRINTF(a) if (getenv("OQSPROV")) printf(a) +#define OQS_PROV_PRINTF2(a, b) if (getenv("OQSPROV")) printf(a, b) +#define OQS_PROV_PRINTF3(a, b, c) if (getenv("OQSPROV")) printf(a, b, c) +#endif // NDEBUG /* * Forward declarations to ensure that interface functions are correctly @@ -25,6 +38,55 @@ static OSSL_FUNC_provider_get_params_fn oqsprovider_get_params; static OSSL_FUNC_provider_query_operation_fn oqsprovider_query; extern OSSL_FUNC_provider_get_capabilities_fn oqs_provider_get_capabilities; +/* + * List of all algorithms with given OIDs + */ +///// OQS_TEMPLATE_FRAGMENT_ASSIGN_SIG_OIDS_START +#define OQS_OID_CNT 78 +static const char* oqs_oid_alg_list[OQS_OID_CNT] = +{ +"1.3.6.1.4.1.2.267.7.4.4", "dilithium2", +"1.3.9999.2.7.1" , "p256_dilithium2", +"1.3.9999.2.7.2" , "rsa3072_dilithium2", +"1.3.6.1.4.1.2.267.7.6.5", "dilithium3", +"1.3.9999.2.7.3" , "p384_dilithium3", +"1.3.6.1.4.1.2.267.7.8.7", "dilithium5", +"1.3.9999.2.7.4" , "p521_dilithium5", +"1.3.6.1.4.1.2.267.11.4.4", "dilithium2_aes", +"1.3.9999.2.11.1" , "p256_dilithium2_aes", +"1.3.9999.2.11.2" , "rsa3072_dilithium2_aes", +"1.3.6.1.4.1.2.267.11.6.5", "dilithium3_aes", +"1.3.9999.2.11.3" , "p384_dilithium3_aes", +"1.3.6.1.4.1.2.267.11.8.7", "dilithium5_aes", +"1.3.9999.2.11.4" , "p521_dilithium5_aes", +"1.3.9999.3.1", "falcon512", +"1.3.9999.3.2" , "p256_falcon512", +"1.3.9999.3.3" , "rsa3072_falcon512", +"1.3.9999.3.4", "falcon1024", +"1.3.9999.3.5" , "p521_falcon1024", +"1.3.6.1.4.1.311.89.2.1.7", "picnicl1full", +"1.3.6.1.4.1.311.89.2.1.8" , "p256_picnicl1full", +"1.3.6.1.4.1.311.89.2.1.9" , "rsa3072_picnicl1full", +"1.3.6.1.4.1.311.89.2.1.21", "picnic3l1", +"1.3.6.1.4.1.311.89.2.1.22" , "p256_picnic3l1", +"1.3.6.1.4.1.311.89.2.1.23" , "rsa3072_picnic3l1", +"1.3.9999.5.1.1.1", "rainbowIclassic", +"1.3.9999.5.1.2.1" , "p256_rainbowIclassic", +"1.3.9999.5.1.3.1" , "rsa3072_rainbowIclassic", +"1.3.9999.5.3.1.1", "rainbowVclassic", +"1.3.9999.5.3.2.1" , "p521_rainbowVclassic", +"1.3.9999.6.1.1", "sphincsharaka128frobust", +"1.3.9999.6.1.2" , "p256_sphincsharaka128frobust", +"1.3.9999.6.1.3" , "rsa3072_sphincsharaka128frobust", +"1.3.9999.6.4.1", "sphincssha256128frobust", +"1.3.9999.6.4.2" , "p256_sphincssha256128frobust", +"1.3.9999.6.4.3" , "rsa3072_sphincssha256128frobust", +"1.3.9999.6.7.1", "sphincsshake256128frobust", +"1.3.9999.6.7.2" , "p256_sphincsshake256128frobust", +"1.3.9999.6.7.3" , "rsa3072_sphincsshake256128frobust", +///// OQS_TEMPLATE_FRAGMENT_ASSIGN_SIG_OIDS_END +}; + #define ALG(NAMES, FUNC) { NAMES, "provider=oqsprovider", FUNC } #define KEMALG3(NAMES, SECBITS) \ { "" #NAMES "", "provider=oqsprovider", oqs_generic_kem_functions }, \ @@ -48,144 +110,6 @@ static const OSSL_PARAM oqsprovider_param_types[] = { OSSL_PARAM_END }; -extern const OSSL_DISPATCH oqs_generic_kem_functions[]; -extern const OSSL_DISPATCH oqs_hybrid_kem_functions[]; -extern const OSSL_DISPATCH oqs_signature_functions[]; - -///// OQS_TEMPLATE_FRAGMENT_ALG_FUNCTIONS_START -extern const OSSL_DISPATCH oqs_dilithium2_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_dilithium3_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_dilithium5_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_dilithium2_aes_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_dilithium3_aes_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_dilithium5_aes_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_falcon512_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_falcon1024_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_picnicl1full_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_picnic3l1_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_rainbowIclassic_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_rainbowVclassic_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_sphincsharaka128frobust_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_sphincssha256128frobust_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_sphincsshake256128frobust_keymgmt_functions[]; - -extern const OSSL_DISPATCH oqs_frodo640aes_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_frodo640shake_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_frodo976aes_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_frodo976shake_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_frodo1344aes_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_frodo1344shake_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_kyber512_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_kyber768_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_kyber1024_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ntru_hps2048509_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ntru_hps2048677_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ntru_hps4096821_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ntru_hrss701_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_lightsaber_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_saber_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_firesaber_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_sidhp434_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_sidhp503_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_sidhp610_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_sidhp751_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_sikep434_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_sikep503_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_sikep610_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_sikep751_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_bikel1_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_bikel3_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_kyber90s512_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_kyber90s768_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_kyber90s1024_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_hqc128_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_hqc192_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_hqc256_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ntrulpr653_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ntrulpr761_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ntrulpr857_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_sntrup653_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_sntrup761_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_sntrup857_keymgmt_functions[]; - -extern const OSSL_DISPATCH oqs_ecp_frodo640aes_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_frodo640shake_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_frodo976aes_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_frodo976shake_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_frodo1344aes_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_frodo1344shake_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_kyber512_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_kyber768_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_kyber1024_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_ntru_hps2048509_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_ntru_hps2048677_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_ntru_hps4096821_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_ntru_hrss701_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_lightsaber_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_saber_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_firesaber_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_sidhp434_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_sidhp503_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_sidhp610_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_sidhp751_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_sikep434_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_sikep503_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_sikep610_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_sikep751_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_bikel1_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_bikel3_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_kyber90s512_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_kyber90s768_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_kyber90s1024_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_hqc128_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_hqc192_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_hqc256_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_ntrulpr653_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_ntrulpr761_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_ntrulpr857_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_sntrup653_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_sntrup761_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecp_sntrup857_keymgmt_functions[]; - -extern const OSSL_DISPATCH oqs_ecx_frodo640aes_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_frodo640shake_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_frodo976aes_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_frodo976shake_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_frodo1344aes_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_frodo1344shake_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_kyber512_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_kyber768_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_kyber1024_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_ntru_hps2048509_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_ntru_hps2048677_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_ntru_hps4096821_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_ntru_hrss701_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_lightsaber_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_saber_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_firesaber_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_sidhp434_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_sidhp503_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_sidhp610_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_sidhp751_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_sikep434_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_sikep503_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_sikep610_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_sikep751_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_bikel1_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_bikel3_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_kyber90s512_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_kyber90s768_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_kyber90s1024_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_hqc128_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_hqc192_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_hqc256_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_ntrulpr653_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_ntrulpr761_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_ntrulpr857_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_sntrup653_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_sntrup761_keymgmt_functions[]; -extern const OSSL_DISPATCH oqs_ecx_sntrup857_keymgmt_functions[]; -///// OQS_TEMPLATE_FRAGMENT_ALG_FUNCTIONS_END static const OSSL_ALGORITHM oqsprovider_signatures[] = { ///// OQS_TEMPLATE_FRAGMENT_SIG_FUNCTIONS_START @@ -313,6 +237,21 @@ static const OSSL_ALGORITHM oqsprovider_keymgmt[] = { { NULL, NULL, NULL } }; +static const OSSL_ALGORITHM oqsprovider_encoder[] = { +#define ENCODER_PROVIDER "oqsprovider" +#include "oqsencoders.inc" + { NULL, NULL, NULL } +#undef ENCODER_PROVIDER +}; + +static const OSSL_ALGORITHM oqsprovider_decoder[] = { +#define DECODER_PROVIDER "oqsprovider" +#include "oqsdecoders.inc" + { NULL, NULL, NULL } +#undef DECODER_PROVIDER +}; + + static const OSSL_PARAM *oqsprovider_gettable_params(void *provctx) { return oqsprovider_param_types; @@ -341,6 +280,7 @@ static const OSSL_ALGORITHM *oqsprovider_query(void *provctx, int operation_id, int *no_cache) { *no_cache = 0; + switch (operation_id) { case OSSL_OP_SIGNATURE: return oqsprovider_signatures; @@ -348,6 +288,10 @@ static const OSSL_ALGORITHM *oqsprovider_query(void *provctx, int operation_id, return oqsprovider_asym_kems; case OSSL_OP_KEYMGMT: return oqsprovider_keymgmt; + case OSSL_OP_ENCODER: + return oqsprovider_encoder; + case OSSL_OP_DECODER: + return oqsprovider_decoder; default: if (getenv("OQSPROV")) printf("Unknown operation %d requested from OQS provider\n", operation_id); } @@ -374,8 +318,16 @@ int OSSL_provider_init(const OSSL_CORE_HANDLE *handle, const OSSL_DISPATCH **out, void **provctx) { - OSSL_FUNC_core_get_libctx_fn *c_get_libctx = NULL; + const OSSL_DISPATCH *orig_in=in; + OSSL_FUNC_core_obj_create_fn *c_obj_create= NULL; + + OSSL_FUNC_core_obj_add_sigid_fn *c_obj_add_sigid= NULL; + BIO_METHOD *corebiometh; OSSL_LIB_CTX *libctx = NULL; + int i, rc = 0; + + if (!oqs_prov_bio_from_dispatch(in)) + return 0; for (; in->function_id != 0; in++) { switch (in->function_id) { @@ -385,8 +337,11 @@ int OSSL_provider_init(const OSSL_CORE_HANDLE *handle, case OSSL_FUNC_CORE_GET_PARAMS: c_get_params = OSSL_FUNC_core_get_params(in); break; - case OSSL_FUNC_CORE_GET_LIBCTX: - c_get_libctx = OSSL_FUNC_core_get_libctx(in); + case OSSL_FUNC_CORE_OBJ_CREATE: + c_obj_create = OSSL_FUNC_core_obj_create(in); + break; + case OSSL_FUNC_CORE_OBJ_ADD_SIGID: + c_obj_add_sigid = OSSL_FUNC_core_obj_add_sigid(in); break; /* Just ignore anything we don't understand */ default: @@ -394,18 +349,50 @@ int OSSL_provider_init(const OSSL_CORE_HANDLE *handle, } } - if (c_get_libctx == NULL) + // we need these functions: + if (c_obj_create == NULL || c_obj_add_sigid==NULL) return 0; - if ( ((libctx = OSSL_LIB_CTX_new()) == NULL) || - (*provctx = oqsx_newprovctx(libctx, handle)) == NULL ) { - OSSL_LIB_CTX_free(libctx); - oqsprovider_teardown(*provctx); - *provctx = NULL; - return 0; + // insert all OIDs to the global objects list + for (i=0; i +#include +//#include "internal/cryptlib.h" +#include "oqs_prov.h" + +static OSSL_FUNC_BIO_new_file_fn *c_bio_new_file = NULL; +static OSSL_FUNC_BIO_new_membuf_fn *c_bio_new_membuf = NULL; +static OSSL_FUNC_BIO_read_ex_fn *c_bio_read_ex = NULL; +static OSSL_FUNC_BIO_write_ex_fn *c_bio_write_ex = NULL; +static OSSL_FUNC_BIO_gets_fn *c_bio_gets = NULL; +static OSSL_FUNC_BIO_puts_fn *c_bio_puts = NULL; +static OSSL_FUNC_BIO_ctrl_fn *c_bio_ctrl = NULL; +static OSSL_FUNC_BIO_up_ref_fn *c_bio_up_ref = NULL; +static OSSL_FUNC_BIO_free_fn *c_bio_free = NULL; +static OSSL_FUNC_BIO_vprintf_fn *c_bio_vprintf = NULL; + +int oqs_prov_bio_from_dispatch(const OSSL_DISPATCH *fns) +{ + for (; fns->function_id != 0; fns++) { + switch (fns->function_id) { + case OSSL_FUNC_BIO_NEW_FILE: + if (c_bio_new_file == NULL) + c_bio_new_file = OSSL_FUNC_BIO_new_file(fns); + break; + case OSSL_FUNC_BIO_NEW_MEMBUF: + if (c_bio_new_membuf == NULL) + c_bio_new_membuf = OSSL_FUNC_BIO_new_membuf(fns); + break; + case OSSL_FUNC_BIO_READ_EX: + if (c_bio_read_ex == NULL) + c_bio_read_ex = OSSL_FUNC_BIO_read_ex(fns); + break; + case OSSL_FUNC_BIO_WRITE_EX: + if (c_bio_write_ex == NULL) + c_bio_write_ex = OSSL_FUNC_BIO_write_ex(fns); + break; + case OSSL_FUNC_BIO_GETS: + if (c_bio_gets == NULL) + c_bio_gets = OSSL_FUNC_BIO_gets(fns); + break; + case OSSL_FUNC_BIO_PUTS: + if (c_bio_puts == NULL) + c_bio_puts = OSSL_FUNC_BIO_puts(fns); + break; + case OSSL_FUNC_BIO_CTRL: + if (c_bio_ctrl == NULL) + c_bio_ctrl = OSSL_FUNC_BIO_ctrl(fns); + break; + case OSSL_FUNC_BIO_UP_REF: + if (c_bio_up_ref == NULL) + c_bio_up_ref = OSSL_FUNC_BIO_up_ref(fns); + break; + case OSSL_FUNC_BIO_FREE: + if (c_bio_free == NULL) + c_bio_free = OSSL_FUNC_BIO_free(fns); + break; + case OSSL_FUNC_BIO_VPRINTF: + if (c_bio_vprintf == NULL) + c_bio_vprintf = OSSL_FUNC_BIO_vprintf(fns); + break; + } + } + + return 1; +} + +OSSL_CORE_BIO *oqs_prov_bio_new_file(const char *filename, const char *mode) +{ + if (c_bio_new_file == NULL) + return NULL; + return c_bio_new_file(filename, mode); +} + +OSSL_CORE_BIO *oqs_prov_bio_new_membuf(const char *filename, int len) +{ + if (c_bio_new_membuf == NULL) + return NULL; + return c_bio_new_membuf(filename, len); +} + +int oqs_prov_bio_read_ex(OSSL_CORE_BIO *bio, void *data, size_t data_len, + size_t *bytes_read) +{ + if (c_bio_read_ex == NULL) + return 0; + return c_bio_read_ex(bio, data, data_len, bytes_read); +} + +int oqs_prov_bio_write_ex(OSSL_CORE_BIO *bio, const void *data, size_t data_len, + size_t *written) +{ + if (c_bio_write_ex == NULL) + return 0; + return c_bio_write_ex(bio, data, data_len, written); +} + +int oqs_prov_bio_gets(OSSL_CORE_BIO *bio, char *buf, int size) +{ + if (c_bio_gets == NULL) + return -1; + return c_bio_gets(bio, buf, size); +} + +int oqs_prov_bio_puts(OSSL_CORE_BIO *bio, const char *str) +{ + if (c_bio_puts == NULL) + return -1; + return c_bio_puts(bio, str); +} + +int oqs_prov_bio_ctrl(OSSL_CORE_BIO *bio, int cmd, long num, void *ptr) +{ + if (c_bio_ctrl == NULL) + return -1; + return c_bio_ctrl(bio, cmd, num, ptr); +} + +int oqs_prov_bio_up_ref(OSSL_CORE_BIO *bio) +{ + if (c_bio_up_ref == NULL) + return 0; + return c_bio_up_ref(bio); +} + +int oqs_prov_bio_free(OSSL_CORE_BIO *bio) +{ + if (c_bio_free == NULL) + return 0; + return c_bio_free(bio); +} + +int oqs_prov_bio_vprintf(OSSL_CORE_BIO *bio, const char *format, va_list ap) +{ + if (c_bio_vprintf == NULL) + return -1; + return c_bio_vprintf(bio, format, ap); +} + +int oqs_prov_bio_printf(OSSL_CORE_BIO *bio, const char *format, ...) +{ + va_list ap; + int ret; + + va_start(ap, format); + ret = oqs_prov_bio_vprintf(bio, format, ap); + va_end(ap); + + return ret; +} + +#ifndef FIPS_MODULE + +/* No direct BIO support in the FIPS module */ + +static int bio_core_read_ex(BIO *bio, char *data, size_t data_len, + size_t *bytes_read) +{ + return oqs_prov_bio_read_ex(BIO_get_data(bio), data, data_len, bytes_read); +} + +static int bio_core_write_ex(BIO *bio, const char *data, size_t data_len, + size_t *written) +{ + return oqs_prov_bio_write_ex(BIO_get_data(bio), data, data_len, written); +} + +static long bio_core_ctrl(BIO *bio, int cmd, long num, void *ptr) +{ + return oqs_prov_bio_ctrl(BIO_get_data(bio), cmd, num, ptr); +} + +static int bio_core_gets(BIO *bio, char *buf, int size) +{ + return oqs_prov_bio_gets(BIO_get_data(bio), buf, size); +} + +static int bio_core_puts(BIO *bio, const char *str) +{ + return oqs_prov_bio_puts(BIO_get_data(bio), str); +} + +static int bio_core_new(BIO *bio) +{ + BIO_set_init(bio, 1); + + return 1; +} + +static int bio_core_free(BIO *bio) +{ + BIO_set_init(bio, 0); + oqs_prov_bio_free(BIO_get_data(bio)); + + return 1; +} + +BIO_METHOD *oqs_bio_prov_init_bio_method(void) +{ + BIO_METHOD *corebiometh = NULL; + + corebiometh = BIO_meth_new(BIO_TYPE_CORE_TO_PROV, "BIO to Core filter"); + if (corebiometh == NULL + || !BIO_meth_set_write_ex(corebiometh, bio_core_write_ex) + || !BIO_meth_set_read_ex(corebiometh, bio_core_read_ex) + || !BIO_meth_set_puts(corebiometh, bio_core_puts) + || !BIO_meth_set_gets(corebiometh, bio_core_gets) + || !BIO_meth_set_ctrl(corebiometh, bio_core_ctrl) + || !BIO_meth_set_create(corebiometh, bio_core_new) + || !BIO_meth_set_destroy(corebiometh, bio_core_free)) { + BIO_meth_free(corebiometh); + return NULL; + } + + return corebiometh; +} + +BIO *oqs_bio_new_from_core_bio(PROV_OQS_CTX *provctx, OSSL_CORE_BIO *corebio) +{ + BIO *outbio; + BIO_METHOD *corebiometh = provctx->corebiometh; + + if (corebiometh == NULL) + return NULL; + + if ((outbio = BIO_new(corebiometh)) == NULL) + return NULL; + if (!oqs_prov_bio_up_ref(corebio)) { + BIO_free(outbio); + return NULL; + } + BIO_set_data(outbio, corebio); + return outbio; +} + +#endif diff --git a/oqsprov/oqsprov_keys.c b/oqsprov/oqsprov_keys.c index 62843168..fc0257bc 100644 --- a/oqsprov/oqsprov_keys.c +++ b/oqsprov/oqsprov_keys.c @@ -6,25 +6,125 @@ * Code strongly inspired by OpenSSL crypto/ec key handler but relocated here * to have code within provider. * - * TBC: Use/test in more than KEM and SIG cases. */ #include #include #include #include -#include +#include #include #include -#include "oqsx.h" +#include "oqs_prov.h" + +#ifdef NDEBUG +#define OQS_KEY_PRINTF(a) +#define OQS_KEY_PRINTF2(a, b) +#define OQS_KEY_PRINTF3(a, b, c) +#else +#define OQS_KEY_PRINTF(a) if (getenv("OQSKEY")) printf(a) +#define OQS_KEY_PRINTF2(a, b) if (getenv("OQSKEY")) printf(a, b) +#define OQS_KEY_PRINTF3(a, b, c) if (getenv("OQSKEY")) printf(a, b, c) +#endif // NDEBUG + +typedef enum { + KEY_OP_PUBLIC, + KEY_OP_PRIVATE, + KEY_OP_KEYGEN +} oqsx_key_op_t; + +/// NID/name table + +typedef struct { + int nid; + char* tlsname; + char* oqsname; + int secbits; +} oqs_nid_name_t; + +///// OQS_TEMPLATE_FRAGMENT_OQSNAMES_START +#define NID_TABLE_LEN 39 + +static oqs_nid_name_t nid_names[NID_TABLE_LEN] = { + { 0, "dilithium2", OQS_SIG_alg_dilithium_2, 128 }, + { 0, "p256_dilithium2", OQS_SIG_alg_dilithium_2, 128 }, + { 0, "rsa3072_dilithium2", OQS_SIG_alg_dilithium_2, 128 }, + { 0, "dilithium3", OQS_SIG_alg_dilithium_3, 192 }, + { 0, "p384_dilithium3", OQS_SIG_alg_dilithium_3, 192 }, + { 0, "dilithium5", OQS_SIG_alg_dilithium_5, 256 }, + { 0, "p521_dilithium5", OQS_SIG_alg_dilithium_5, 256 }, + { 0, "dilithium2_aes", OQS_SIG_alg_dilithium_2_aes, 128 }, + { 0, "p256_dilithium2_aes", OQS_SIG_alg_dilithium_2_aes, 128 }, + { 0, "rsa3072_dilithium2_aes", OQS_SIG_alg_dilithium_2_aes, 128 }, + { 0, "dilithium3_aes", OQS_SIG_alg_dilithium_3_aes, 192 }, + { 0, "p384_dilithium3_aes", OQS_SIG_alg_dilithium_3_aes, 192 }, + { 0, "dilithium5_aes", OQS_SIG_alg_dilithium_5_aes, 256 }, + { 0, "p521_dilithium5_aes", OQS_SIG_alg_dilithium_5_aes, 256 }, + { 0, "falcon512", OQS_SIG_alg_falcon_512, 128 }, + { 0, "p256_falcon512", OQS_SIG_alg_falcon_512, 128 }, + { 0, "rsa3072_falcon512", OQS_SIG_alg_falcon_512, 128 }, + { 0, "falcon1024", OQS_SIG_alg_falcon_1024, 256 }, + { 0, "p521_falcon1024", OQS_SIG_alg_falcon_1024, 256 }, + { 0, "picnicl1full", OQS_SIG_alg_picnic_L1_full, 128 }, + { 0, "p256_picnicl1full", OQS_SIG_alg_picnic_L1_full, 128 }, + { 0, "rsa3072_picnicl1full", OQS_SIG_alg_picnic_L1_full, 128 }, + { 0, "picnic3l1", OQS_SIG_alg_picnic3_L1, 128 }, + { 0, "p256_picnic3l1", OQS_SIG_alg_picnic3_L1, 128 }, + { 0, "rsa3072_picnic3l1", OQS_SIG_alg_picnic3_L1, 128 }, + { 0, "rainbowIclassic", OQS_SIG_alg_rainbow_I_classic, 128 }, + { 0, "p256_rainbowIclassic", OQS_SIG_alg_rainbow_I_classic, 128 }, + { 0, "rsa3072_rainbowIclassic", OQS_SIG_alg_rainbow_I_classic, 128 }, + { 0, "rainbowVclassic", OQS_SIG_alg_rainbow_V_classic, 256 }, + { 0, "p521_rainbowVclassic", OQS_SIG_alg_rainbow_V_classic, 256 }, + { 0, "sphincsharaka128frobust", OQS_SIG_alg_sphincs_haraka_128f_robust, 128 }, + { 0, "p256_sphincsharaka128frobust", OQS_SIG_alg_sphincs_haraka_128f_robust, 128 }, + { 0, "rsa3072_sphincsharaka128frobust", OQS_SIG_alg_sphincs_haraka_128f_robust, 128 }, + { 0, "sphincssha256128frobust", OQS_SIG_alg_sphincs_sha256_128f_robust, 128 }, + { 0, "p256_sphincssha256128frobust", OQS_SIG_alg_sphincs_sha256_128f_robust, 128 }, + { 0, "rsa3072_sphincssha256128frobust", OQS_SIG_alg_sphincs_sha256_128f_robust, 128 }, + { 0, "sphincsshake256128frobust", OQS_SIG_alg_sphincs_shake256_128f_robust, 128 }, + { 0, "p256_sphincsshake256128frobust", OQS_SIG_alg_sphincs_shake256_128f_robust, 128 }, + { 0, "rsa3072_sphincsshake256128frobust", OQS_SIG_alg_sphincs_shake256_128f_robust, 128 }, +///// OQS_TEMPLATE_FRAGMENT_OQSNAMES_END +}; + +int oqs_set_nid(char* tlsname, int nid) { + int i; + for(i=0;ilibctx = libctx; ret->handle = handle; + ret->corebiometh = bm; } return ret; } @@ -33,6 +133,127 @@ void oqsx_freeprovctx(PROV_OQS_CTX *ctx) { OPENSSL_free(ctx); } + +void oqsx_key_set0_libctx(OQSX_KEY *key, OSSL_LIB_CTX *libctx) +{ + key->libctx = libctx; +} + +// convenience function creating OQSX keys from nids (only for sigs; hybrids TBD) +static OQSX_KEY *oqsx_key_new_from_nid(OSSL_LIB_CTX *libctx, const char *propq, int id) { + return oqsx_key_new(libctx, get_oqsname(id), (char *)OBJ_nid2sn(id), KEY_TYPE_SIG, propq, get_secbits(id)); +} + + +OQSX_KEY *oqsx_key_op(const X509_ALGOR *palg, + const unsigned char *p, int plen, + oqsx_key_op_t op, + OSSL_LIB_CTX *libctx, const char *propq) +{ + OQSX_KEY *key = NULL; + void **privkey, **pubkey; + int id; + + if (op != KEY_OP_KEYGEN) { + if (palg != NULL) { + int ptype; + + /* Algorithm parameters must be absent */ + X509_ALGOR_get0(NULL, &ptype, NULL, palg); + if (ptype != V_ASN1_UNDEF) { + ERR_raise(ERR_LIB_USER, OQSPROV_R_INVALID_ENCODING); + return 0; + } + id = OBJ_obj2nid(palg->algorithm); + } + + if (p == NULL || id == EVP_PKEY_NONE) { + ERR_raise(ERR_LIB_USER, OQSPROV_R_INVALID_ENCODING); + return 0; + } + } + + key = oqsx_key_new_from_nid(libctx, propq, id); + if (key == NULL) { + ERR_raise(ERR_LIB_USER, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (op == KEY_OP_PUBLIC) { + if (key->pubkeylen != plen) { + ERR_raise(ERR_LIB_USER, OQSPROV_R_INVALID_ENCODING); + goto err; + } + key->pubkey = OPENSSL_secure_zalloc(key->pubkeylen); + if (key->pubkey == NULL) { + ERR_raise(ERR_LIB_USER, ERR_R_MALLOC_FAILURE); + goto err; + } + memcpy(key->pubkey, p, plen); + } else { + if (key->privkeylen+key->pubkeylen != plen) { + ERR_raise(ERR_LIB_USER, OQSPROV_R_INVALID_ENCODING); + goto err; + } + key->privkey = OPENSSL_secure_zalloc(key->privkeylen); + key->pubkey = OPENSSL_secure_zalloc(key->pubkeylen); + if (key->privkey == NULL || key->pubkey == NULL) { + ERR_raise(ERR_LIB_USER, ERR_R_MALLOC_FAILURE); + goto err; + } + memcpy(key->privkey, p, key->privkeylen); + memcpy(key->pubkey, p+key->privkeylen, key->pubkeylen); + } + + return key; + + err: + oqsx_key_free(key); + return NULL; +} + +OQSX_KEY *oqsx_key_from_x509pubkey(const X509_PUBKEY *xpk, + OSSL_LIB_CTX *libctx, const char *propq) +{ + const unsigned char *p; + int plen; + X509_ALGOR *palg; + OQSX_KEY* oqsx = NULL; + + if (!xpk || (!X509_PUBKEY_get0_param(NULL, &p, &plen, &palg, xpk))) { + return NULL; + } + oqsx = oqsx_key_op(palg, p, plen, KEY_OP_PUBLIC, libctx, propq); + return oqsx; +} + +OQSX_KEY *oqsx_key_from_pkcs8(const PKCS8_PRIV_KEY_INFO *p8inf, + OSSL_LIB_CTX *libctx, const char *propq) +{ + OQSX_KEY *oqsx = NULL; + const unsigned char *p; + int plen; + ASN1_OCTET_STRING *oct = NULL; + const X509_ALGOR *palg; + + if (!PKCS8_pkey_get0(NULL, &p, &plen, &palg, p8inf)) + return 0; + + oct = d2i_ASN1_OCTET_STRING(NULL, &p, plen); + if (oct == NULL) { + p = NULL; + plen = 0; + } else { + p = ASN1_STRING_get0_data(oct); + plen = ASN1_STRING_length(oct); + } + + oqsx = oqsx_key_op(palg, p, plen, KEY_OP_PRIVATE, + libctx, propq); + ASN1_OCTET_STRING_free(oct); + return oqsx; +} + /// Key code static const OQSX_KEX_INFO nids_ecp[] = { @@ -104,6 +325,11 @@ OQSX_KEY *oqsx_key_new(OSSL_LIB_CTX *libctx, char* oqs_name, char* tls_name, int if (ret == NULL) goto err; + if (oqs_name == NULL) { + OQS_KEY_PRINTF("OQSX_KEY: Fatal error: No OQS key name provided:\n"); + goto err; + } + if (primitive == KEY_TYPE_SIG) { ret->numkeys = 1; ret->comp_privkey = OPENSSL_malloc(sizeof(void *)); @@ -146,14 +372,15 @@ OQSX_KEY *oqsx_key_new(OSSL_LIB_CTX *libctx, char* oqs_name, char* tls_name, int if (propq != NULL) { ret->propq = OPENSSL_strdup(propq); - ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_USER, ERR_R_MALLOC_FAILURE); if (ret->propq == NULL) goto err; } + OQS_KEY_PRINTF2("OQSX_KEY: new key created: %p\n", ret); return ret; err: - ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_USER, ERR_R_MALLOC_FAILURE); OPENSSL_free(ret); return NULL; } @@ -169,9 +396,7 @@ void oqsx_key_free(OQSX_KEY *key) memory_order_relaxed) - 1; if (refcnt == 0) atomic_thread_fence(memory_order_acquire); -#ifndef NDEBUG - fprintf(stderr, "%p:%4d:OQSX_KEY\n", (void*)key, refcnt); -#endif + OQS_KEY_PRINTF3("%p:%4d:OQSX_KEY\n", (void*)key, refcnt); if (refcnt > 0) return; #ifndef NDEBUG @@ -201,8 +426,8 @@ int oqsx_key_up_ref(OQSX_KEY *key) refcnt = atomic_fetch_add_explicit(&key->references, 1, memory_order_relaxed) + 1; + OQS_KEY_PRINTF3("%p:%4d:OQSX_KEY\n", (void*)key, refcnt); #ifndef NDEBUG - fprintf(stderr, "%p:%4d:OQSX_KEY\n", (void*)key, refcnt); assert(refcnt > 1); #endif return (refcnt > 1); @@ -231,32 +456,38 @@ int oqsx_key_fromdata(OQSX_KEY *key, const OSSL_PARAM params[], int include_priv p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY); if (p != NULL) { if (p->data_type != OSSL_PARAM_OCTET_STRING) { - printf("invalid data type\n"); + ERR_raise(ERR_LIB_USER, OQSPROV_R_INVALID_ENCODING); + return 0; + } + if (key->privkeylen != p->data_size) { + ERR_raise(ERR_LIB_USER, OQSPROV_R_INVALID_SIZE); return 0; } OPENSSL_secure_clear_free(key->privkey, key->privkeylen); key->privkey = OPENSSL_secure_malloc(p->data_size); if (key->privkey == NULL) { - ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_USER, ERR_R_MALLOC_FAILURE); return 0; } memcpy(key->privkey, p->data, p->data_size); - key->privkeylen = p->data_size; } p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY); if (p != NULL) { if (p->data_type != OSSL_PARAM_OCTET_STRING) { - printf("invalid data type\n"); + OQS_KEY_PRINTF("invalid data type\n"); + return 0; + } + if (key->pubkeylen != p->data_size) { + ERR_raise(ERR_LIB_USER, OQSPROV_R_INVALID_SIZE); return 0; } OPENSSL_secure_clear_free(key->pubkey, key->pubkeylen); key->pubkey = OPENSSL_secure_malloc(p->data_size); if (key->pubkey == NULL) { - ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_USER, ERR_R_MALLOC_FAILURE); return 0; } memcpy(key->pubkey, p->data, p->data_size); - key->pubkeylen = p->data_size; } return 1; } diff --git a/oqsprov/oqsx.h b/oqsprov/oqsx.h deleted file mode 100644 index cf043374..00000000 --- a/oqsprov/oqsx.h +++ /dev/null @@ -1,126 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 AND MIT - -/* - * OQS OpenSSL 3 key handler. - * - * Code strongly inspired by OpenSSL crypto/ecx key handler but relocated here to have code within provider. - * - * ToDo: Review whether more functions are needed for sig, hybrids. - */ - -/* Internal OQS functions for other submodules: not for application use */ - -#ifndef OQSX_H -# define OQSX_H - -# include -# include - -# include -# include - -/* Extras for OQS extension */ - -#define ON_ERR_SET_GOTO(condition, ret, code, gt) \ - if ((condition)) { \ - printf("ON_ERR_CONDITION: %d, setting code: %d\n", condition, code); fflush(stdout); \ - (ret) = (code); \ - goto gt; \ - } - -#define ON_ERR_GOTO(condition, gt) \ - if ((condition)) { \ - printf("ON_ERR_CONDITION: %d\n", condition); fflush(stdout); \ - goto gt; \ - } - -#define ECP_NAME(secbits, oqsname) \ - (secbits == 128 ? "p256_" #oqsname "" : \ - secbits == 192 ? "p384_" #oqsname "" : \ - "p521_" #oqsname "") -#define ECX_NAME(secbits, oqsname) \ - (secbits == 128 ? "x25519_" #oqsname "" : \ - "x448_" #oqsname "") - -typedef struct prov_oqs_ctx_st { - const OSSL_CORE_HANDLE *handle; - OSSL_LIB_CTX *libctx; /* For all provider modules */ -// BIO_METHOD *corebiometh; // for the time being, do without BIO_METHOD -} PROV_OQS_CTX; - -PROV_OQS_CTX *oqsx_newprovctx(OSSL_LIB_CTX *libctx, const OSSL_CORE_HANDLE *handle); -void oqsx_freeprovctx(PROV_OQS_CTX *ctx); -# define PROV_OQS_LIBCTX_OF(provctx) (((PROV_OQS_CTX *)provctx)->libctx) - -#include "oqs/oqs.h" - -struct oqsx_kex_info_st { - int nid_kex; - int nid_kex_crv; - int raw_key_support; - size_t kex_length_public_key; - size_t kex_length_private_key; - size_t kex_length_secret; -}; - -typedef struct oqsx_kex_info_st OQSX_KEX_INFO; - -struct oqsx_evp_ctx_st { - EVP_PKEY_CTX *kex; - EVP_PKEY *kexParam; - const OQSX_KEX_INFO *kex_info; -}; - -typedef struct oqsx_evp_ctx_st OQSX_EVP_CTX; - -typedef union { - OQS_SIG *sig; - OQS_KEM *kem; -} OQSX_QS_CTX; - -struct oqsx_provider_ctx_st { - OQSX_QS_CTX oqsx_qs_ctx; - OQSX_EVP_CTX *oqsx_evp_ctx; -}; - -typedef struct oqsx_provider_ctx_st OQSX_PROVIDER_CTX; - -enum oqsx_key_type_en { - KEY_TYPE_SIG, KEY_TYPE_KEM, KEY_TYPE_ECP_HYB_KEM, KEY_TYPE_ECX_HYB_KEM -}; - -typedef enum oqsx_key_type_en OQSX_KEY_TYPE; - -struct oqsx_key_st { - OSSL_LIB_CTX *libctx; - char *propq; - OQSX_KEY_TYPE keytype; - OQSX_PROVIDER_CTX oqsx_provider_ctx; - size_t numkeys; - size_t privkeylen; - size_t pubkeylen; - size_t bit_security; - char *oqs_name; - char *tls_name; - _Atomic int references; - void **comp_privkey; - void **comp_pubkey; - void *privkey; - void *pubkey; -}; - -typedef struct oqsx_key_st OQSX_KEY; - -OQSX_KEY *oqsx_key_new(OSSL_LIB_CTX *libctx, char* oqs_name, char* tls_name, int is_kem, const char *propq, int bit_security); -int oqsx_key_allocate_keymaterial(OQSX_KEY *key); -void oqsx_key_free(OQSX_KEY *key); -int oqsx_key_up_ref(OQSX_KEY *key); -int oqsx_key_gen(OQSX_KEY *key); - -/* Backend support */ -int oqsx_public_from_private(OQSX_KEY *key); -int oqsx_key_fromdata(OQSX_KEY *oqsxk, const OSSL_PARAM params[], - int include_private); -int oqsx_key_parambits(OQSX_KEY *k); -int oqsx_key_maxsize(OQSX_KEY *k); -#endif diff --git a/scripts/fullbuild.sh b/scripts/fullbuild.sh new file mode 100755 index 00000000..e225550c --- /dev/null +++ b/scripts/fullbuild.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +if [ $# -gt 0 ]; then + rm -rf _build +fi + +if [ ! -d "openssl" ]; then + echo "openssl doesn't reside where expected: Cloning and building... Full debug and tracing and FIPS enabled:" + git clone git://git.openssl.org/openssl.git && cd openssl && ./config enable-trace enable-fips --debug --prefix=$(echo $(pwd)/../.local) && make && make install_sw && cd .. + if [ $? -ne 0 ]; then + echo "openssl build failed. Exiting." + exit -1 + fi +fi + +# Check whether liboqs is built: +if [ ! -f ".local/lib/liboqs.a" ]; then + echo "liboqs static lib not built: Cloning and building..." + git clone https://github.com/open-quantum-safe/liboqs.git && cd liboqs && cmake -DCMAKE_INSTALL_PREFIX=$(pwd)/../.local -S . -B _build && cmake --build _build && cmake --install _build && cd .. + if [ $? -ne 0 ]; then + echo "liboqs build failed. Exiting." + exit -1 + fi +fi + +# Check whether provider is built: +if [ ! -f "_build/oqsprov/oqsprovider.so" ]; then + echo "oqsprovider not built: Building..." + # possibly remove instruction to build for debugging: TBC + cmake -DCMAKE_BUILD_TYPE=Debug -DOPENSSL_ROOT_DIR=$(pwd)/.local -DCMAKE_PREFIX_PATH=$(pwd)/.local -S . -B _build && cmake --build _build + if [ $? -ne 0 ]; then + echo "provider build failed. Exiting." + exit -1 + fi +fi + +./scripts/runtests.sh $@ + + diff --git a/scripts/oqs-openssl-certgen.sh b/scripts/oqs-openssl-certgen.sh new file mode 100755 index 00000000..af167be9 --- /dev/null +++ b/scripts/oqs-openssl-certgen.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Use dockerimage to generate certs for alg $1 + +IMAGE=openquantumsafe/curl + +if [ $# -ne 1 ]; then + echo "Usage: $0 . Exiting." + exit 1 +fi + +rm -rf tmp +mkdir tmp + +if [[ -z "$CIRCLECI" ]]; then +docker run -v `pwd`/tmp:/home/oqs/data -it $IMAGE sh -c "cd /home/oqs/data && openssl req -x509 -new -newkey $1 -keyout $1_CA.key -out $1_CA.crt -nodes -subj \"/CN=oqstest CA\" -days 365 -config /opt/oqssa/ssl/openssl.cnf && openssl genpkey -algorithm $1 -out $1_srv.key && openssl req -new -newkey $1 -keyout $1_srv.key -out $1_srv.csr -nodes -subj \"/CN=oqstest server\" -config /opt/oqssa/ssl/openssl.cnf && openssl x509 -req -in $1_srv.csr -out $1_srv.crt -CA $1_CA.crt -CAkey $1_CA.key -CAcreateserial -days 365 && openssl verify -CAfile $1_CA.crt $1_srv.crt" +else +# CCI doesn't permit mounting, so let's do as per https://circleci.com/docs/2.0/building-docker-images/#mounting-folders: +docker run --name oqsossl -it $IMAGE sh -c "mkdir /home/oqs/tmp && cd /home/oqs/tmp && openssl req -x509 -new -newkey $1 -keyout $1_CA.key -out $1_CA.crt -nodes -subj \"/CN=oqstest CA\" -days 365 -config /opt/oqssa/ssl/openssl.cnf && openssl genpkey -algorithm $1 -out $1_srv.key && openssl req -new -newkey $1 -keyout $1_srv.key -out $1_srv.csr -nodes -subj \"/CN=oqstest server\" -config /opt/oqssa/ssl/openssl.cnf && openssl x509 -req -in $1_srv.csr -out $1_srv.crt -CA $1_CA.crt -CAkey $1_CA.key -CAcreateserial -days 365 && openssl verify -CAfile $1_CA.crt $1_srv.crt" +docker cp oqsossl:/home/oqs/tmp . +docker rm oqsossl +fi + diff --git a/scripts/oqs-openssl-certverify.sh b/scripts/oqs-openssl-certverify.sh new file mode 100755 index 00000000..6d6abd99 --- /dev/null +++ b/scripts/oqs-openssl-certverify.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# Use dockerimage to verify certs for alg $1 + +IMAGE=openquantumsafe/curl + +if [ $# -ne 1 ]; then + echo "Usage: $0 . Exiting." + exit 1 +fi + +if [ ! -d tmp ]; then + echo "Test folder tmp not existing. Exiting." + exit 1 +fi + +if [ ! -f tmp/$1_srv.crt ]; then + echo "Cert to test not present. Exiting." + exit 1 +fi + +if [[ -z "$CIRCLECI" ]]; then +docker run -v `pwd`/tmp:/home/oqs/data -it $IMAGE sh -c "cd /home/oqs/data && openssl verify -CAfile $1_CA.crt $1_srv.crt" +else +# CCI doesn't permit mounting, so let's do as per https://circleci.com/docs/2.0/building-docker-images/#mounting-folders: +docker create -v /certs --name certs alpine /bin/true && \ +docker cp tmp/ certs:/certs && \ +docker run --volumes-from certs -it $IMAGE sh -c "cd /certs/tmp && openssl verify -CAfile $1_CA.crt $1_srv.crt" && \ +docker rm /certs +fi diff --git a/scripts/oqsprovider-certgen.sh b/scripts/oqsprovider-certgen.sh new file mode 100755 index 00000000..e56c840c --- /dev/null +++ b/scripts/oqsprovider-certgen.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Use newly built oqsprovider to generate certs for alg $1 +# Assumes .local to contain openssl(3) and oqsprovider to be in _build folder + +if [ $# -ne 1 ]; then + echo "Usage: $0 . Exiting." + exit 1 +fi + +rm -rf tmp +mkdir tmp +export OPENSSL_MODULES=_build/oqsprov +export LD_LIBRARY_PATH=.local/lib64 +.local/bin/openssl req -x509 -new -newkey $1 -keyout tmp/$1_CA.key -out tmp/$1_CA.crt -nodes -subj "/CN=oqstest CA" -days 365 -config openssl/apps/openssl.cnf -provider oqsprovider -provider default && \ +.local/bin/openssl genpkey -algorithm $1 -out tmp/$1_srv.key -provider oqsprovider -provider default && \ +.local/bin/openssl req -new -newkey $1 -keyout tmp/$1_srv.key -out tmp/$1_srv.csr -nodes -subj "/CN=oqstest server" -config openssl/apps/openssl.cnf -provider oqsprovider -provider default && \ +.local/bin/openssl x509 -req -in tmp/$1_srv.csr -out tmp/$1_srv.crt -CA tmp/$1_CA.crt -CAkey tmp/$1_CA.key -CAcreateserial -days 365 -provider oqsprovider -provider default && \ +.local/bin/openssl verify -provider oqsprovider -provider default -CAfile tmp/$1_CA.crt tmp/$1_srv.crt + +#fails: +#.local/bin/openssl verify -CAfile tmp/$1_CA.crt tmp/$1_srv.crt -provider oqsprovider -provider default + diff --git a/scripts/oqsprovider-certverify.sh b/scripts/oqsprovider-certverify.sh new file mode 100755 index 00000000..c9213c2f --- /dev/null +++ b/scripts/oqsprovider-certverify.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# Use newly built oqsprovider to generate certs for alg $1 +# Assumes .local to contain openssl(3) and oqsprovider to be in _build folder + +if [ $# -ne 1 ]; then + echo "Usage: $0 . Exiting." + exit 1 +fi + +export OPENSSL_MODULES=_build/oqsprov +export LD_LIBRARY_PATH=.local/lib64 + + +.local/bin/openssl verify -provider oqsprovider -provider default -CAfile tmp/$1_CA.crt tmp/$1_srv.crt + diff --git a/scripts/runtests.sh b/scripts/runtests.sh new file mode 100755 index 00000000..fd08ad03 --- /dev/null +++ b/scripts/runtests.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +provider2openssl() { + echo "Testing oqsprovider->oqs-openssl interop for $1:" + ./scripts/oqsprovider-certgen.sh $1 && ./scripts/oqs-openssl-certverify.sh $1 +} + +openssl2provider() { + echo "Testing oqs-openssl->oqsprovider interop for $1:" + ./scripts/oqs-openssl-certgen.sh $1 && ./scripts/oqsprovider-certverify.sh $1 +} + +interop() { + provider2openssl $1 && openssl2provider $1 +} + +# Run built-in tests: +(cd _build; ctest $@) + +# Run interop-tests: +##### OQS_TEMPLATE_FRAGMENT_ALGS_START +interop dilithium2 +interop dilithium3 +interop dilithium5 +interop dilithium2_aes +interop dilithium3_aes +interop dilithium5_aes +interop falcon512 +interop falcon1024 +interop picnicl1full +interop picnic3l1 +interop rainbowIclassic +interop rainbowVclassic +interop sphincsharaka128frobust +interop sphincssha256128frobust +interop sphincsshake256128frobust +##### OQS_TEMPLATE_FRAGMENT_ALGS_END + +# cleanup +rm -rf tmp + + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9b3141a4..d3dc1945 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -11,6 +11,7 @@ set_tests_properties(oqs_signatures add_executable(oqs_test_signatures oqs_test_signatures.c) target_link_libraries(oqs_test_signatures ${OPENSSL_CRYPTO_LIBRARY}) + # oqs_test_groups.c relies on OpenSSL internals, which must be copied to # this directory to run this test: # @@ -46,3 +47,21 @@ if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/ssltestlib.h add_executable(oqs_test_groups oqs_test_groups.c ssltestlib.c) target_link_libraries(oqs_test_groups ${OPENSSL_SSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY}) endif() + +add_executable(oqs_test_endecode oqs_test_endecode.c) +target_include_directories(oqs_test_endecode PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../openssl/include) +target_include_directories(oqs_test_endecode PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../openssl/test) +target_include_directories(oqs_test_endecode PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../openssl/apps/include) + +#target_link_libraries(oqs_test_endecode ${CMAKE_CURRENT_SOURCE_DIR}/../openssl/test/libtestutil.a ${CMAKE_CURRENT_SOURCE_DIR}/../.local/lib64/libcrypto.a pthread dl) +target_link_libraries(oqs_test_endecode ${OPENSSL_CRYPTO_LIBRARY} ${CMAKE_CURRENT_SOURCE_DIR}/../openssl/test/libtestutil.a ) +add_test( + NAME oqs_endecode + COMMAND oqs_test_endecode + "oqsprovider" + "${CMAKE_SOURCE_DIR}/test/oqs.cnf" +) +set_tests_properties(oqs_endecode + PROPERTIES ENVIRONMENT "OPENSSL_MODULES=${CMAKE_BINARY_DIR}/oqsprov" +) + diff --git a/test/oqs.cnf b/test/oqs.cnf index da0e33a7..d93c60b2 100644 --- a/test/oqs.cnf +++ b/test/oqs.cnf @@ -6,9 +6,13 @@ providers = provider_sect [provider_sect] oqsprovider = oqsprovider_sect default = default_sect +# fips = fips_sect [default_sect] activate = 1 +#[fips_sect] +#activate = 1 + [oqsprovider_sect] activate = 1 diff --git a/test/oqs_test_endecode.c b/test/oqs_test_endecode.c new file mode 100644 index 00000000..bd000fe8 --- /dev/null +++ b/test/oqs_test_endecode.c @@ -0,0 +1,1090 @@ +// SPDX-License-Identifier: Apache-2.0 AND MIT + +// Code strongly inspired by test of the same name in OpenSSL + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "crypto/pem.h" /* For PVK and "blob" PEM headers */ +#include "crypto/evp.h" /* For evp_pkey_is_provided() */ + +#include "testutil.h" // output functions + +/* Extended test macros to allow passing file & line number */ +#define TEST_FL_ptr(a) test_ptr(file, line, #a, a) +#define TEST_FL_mem_eq(a, m, b, n) test_mem_eq(file, line, #a, #b, a, m, b, n) +#define TEST_FL_strn_eq(a, b, n) test_strn_eq(file, line, #a, #b, a, n, b, n) +#define TEST_FL_strn2_eq(a, m, b, n) test_strn_eq(file, line, #a, #b, a, m, b, n) +#define TEST_FL_int_eq(a, b) test_int_eq(file, line, #a, #b, a, b) +#define TEST_FL_int_ge(a, b) test_int_ge(file, line, #a, #b, a, b) +#define TEST_FL_int_gt(a, b) test_int_gt(file, line, #a, #b, a, b) +#define TEST_FL_long_gt(a, b) test_long_gt(file, line, #a, #b, a, b) +#define TEST_FL_true(a) test_true(file, line, #a, (a) != 0) + +static int default_libctx = 1; + +static OSSL_LIB_CTX *testctx = NULL; +static OSSL_LIB_CTX *keyctx = NULL; +static char *testpropq = NULL; + +static OSSL_PROVIDER *oqsprov = NULL; +static OSSL_PROVIDER *dfltprov = NULL; +static OSSL_PROVIDER *keyprov = NULL; + +static EVP_PKEY *oqstest_make_template(const char *type, OSSL_PARAM *genparams) +{ + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + + /* + * No real need to check the errors other than for the cascade + * effect. |pkey| will simply remain NULL if something goes wrong. + */ + (void)((ctx = EVP_PKEY_CTX_new_from_name(keyctx, type, testpropq)) != NULL + && EVP_PKEY_paramgen_init(ctx) > 0 + && (genparams == NULL + || EVP_PKEY_CTX_set_params(ctx, genparams) > 0) + && EVP_PKEY_generate(ctx, &pkey) > 0); + EVP_PKEY_CTX_free(ctx); + + return pkey; +} + +static EVP_PKEY *oqstest_make_key(const char *type, EVP_PKEY *template, + OSSL_PARAM *genparams) +{ + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = + template != NULL + ? EVP_PKEY_CTX_new_from_pkey(keyctx, template, testpropq) + : EVP_PKEY_CTX_new_from_name(keyctx, type, testpropq); + + /* + * No real need to check the errors other than for the cascade + * effect. |pkey| will simply remain NULL if something goes wrong. + */ + (void)(ctx != NULL + && EVP_PKEY_keygen_init(ctx) > 0 + && (genparams == NULL + || EVP_PKEY_CTX_set_params(ctx, genparams) > 0) + && EVP_PKEY_keygen(ctx, &pkey) > 0); + EVP_PKEY_CTX_free(ctx); + return pkey; +} + +/* Main test driver */ + +typedef int (encoder)(const char *file, const int line, + void **encoded, long *encoded_len, + void *object, int selection, + const char *output_type, const char *output_structure, + const char *pass, const char *pcipher); +typedef int (decoder)(const char *file, const int line, + void **object, void *encoded, long encoded_len, + const char *input_type, const char *structure_type, + const char *keytype, int selection, const char *pass); +typedef int (tester)(const char *file, const int line, + const void *data1, size_t data1_len, + const void *data2, size_t data2_len); +typedef int (checker)(const char *file, const int line, + const char *type, const void *data, size_t data_len); +typedef void (dumper)(const char *label, const void *data, size_t data_len); + +#define FLAG_DECODE_WITH_TYPE 0x0001 + +static int test_encode_decode(const char *file, const int line, + const char *type, EVP_PKEY *pkey, + int selection, const char *output_type, + const char *output_structure, + const char *pass, const char *pcipher, + encoder *encode_cb, decoder *decode_cb, + tester *test_cb, checker *check_cb, + dumper *dump_cb, int flags) +{ + void *encoded = NULL; + long encoded_len = 0; + EVP_PKEY *pkey2 = NULL; + void *encoded2 = NULL; + long encoded2_len = 0; + int ok = 0; + + /* + * Encode |pkey|, decode the result into |pkey2|, and finish off by + * encoding |pkey2| as well. That last encoding is for checking and + * dumping purposes. + */ + if (!TEST_true(encode_cb(file, line, &encoded, &encoded_len, pkey, selection, + output_type, output_structure, pass, pcipher)) + || !TEST_true(check_cb(file, line, type, encoded, encoded_len)) + || !TEST_true(decode_cb(file, line, (void **)&pkey2, encoded, encoded_len, + output_type, output_structure, + (flags & FLAG_DECODE_WITH_TYPE ? type : NULL), + selection, pass)) + || !TEST_true(encode_cb(file, line, &encoded2, &encoded2_len, pkey2, selection, + output_type, output_structure, pass, pcipher))) + goto end; + + if (selection == OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) { + if (!TEST_int_eq(EVP_PKEY_parameters_eq(pkey, pkey2), 1)) + goto end; + } else { + if (!TEST_int_eq(EVP_PKEY_eq(pkey, pkey2), 1)) + goto end; + } + + /* + * Double check the encoding, but only for unprotected keys, + * as protected keys have a random component, which makes the output + * differ. + */ + if ((pass == NULL && pcipher == NULL) + && !test_cb(file, line, encoded, encoded_len, encoded2, encoded2_len)) + goto end; + + ok = 1; + end: + if (!ok) { + if (encoded != NULL && encoded_len != 0) + dump_cb("|pkey| encoded", encoded, encoded_len); + if (encoded2 != NULL && encoded2_len != 0) + dump_cb("|pkey2| encoded", encoded2, encoded2_len); + } + + OPENSSL_free(encoded); + OPENSSL_free(encoded2); + EVP_PKEY_free(pkey2); + return ok; +} + +/* Encoding and decoding methods */ + +static int encode_EVP_PKEY_prov(const char *file, const int line, + void **encoded, long *encoded_len, + void *object, int selection, + const char *output_type, + const char *output_structure, + const char *pass, const char *pcipher) +{ + EVP_PKEY *pkey = object; + OSSL_ENCODER_CTX *ectx = NULL; + BIO *mem_ser = NULL; + BUF_MEM *mem_buf = NULL; + const unsigned char *upass = (const unsigned char *)pass; + int ok = 0; + + if (!TEST_FL_ptr(ectx = OSSL_ENCODER_CTX_new_for_pkey(pkey, selection, + output_type, + output_structure, + testpropq)) + || !TEST_FL_int_gt(OSSL_ENCODER_CTX_get_num_encoders(ectx), 0) + || (pass != NULL + && !TEST_FL_true(OSSL_ENCODER_CTX_set_passphrase(ectx, upass, + strlen(pass)))) + || (pcipher != NULL + && !TEST_FL_true(OSSL_ENCODER_CTX_set_cipher(ectx, pcipher, NULL))) + || !TEST_FL_ptr(mem_ser = BIO_new(BIO_s_mem())) + || !TEST_FL_true(OSSL_ENCODER_to_bio(ectx, mem_ser)) + || !TEST_FL_true(BIO_get_mem_ptr(mem_ser, &mem_buf) > 0) + || !TEST_FL_ptr(*encoded = mem_buf->data) + || !TEST_FL_long_gt(*encoded_len = mem_buf->length, 0)) + goto end; + + /* Detach the encoded output */ + mem_buf->data = NULL; + mem_buf->length = 0; + ok = 1; + end: + BIO_free(mem_ser); + OSSL_ENCODER_CTX_free(ectx); + return ok; +} + +static int decode_EVP_PKEY_prov(const char *file, const int line, + void **object, void *encoded, long encoded_len, + const char *input_type, + const char *structure_type, + const char *keytype, int selection, + const char *pass) +{ + EVP_PKEY *pkey = NULL, *testpkey = NULL; + OSSL_DECODER_CTX *dctx = NULL; + BIO *encoded_bio = NULL; + const unsigned char *upass = (const unsigned char *)pass; + int ok = 0; + int i; + const char *badtype; + + if (strcmp(input_type, "DER") == 0) + badtype = "PEM"; + else + badtype = "DER"; + + if (!TEST_FL_ptr(encoded_bio = BIO_new_mem_buf(encoded, encoded_len))) + goto end; + + /* + * We attempt the decode 3 times. The first time we provide the expected + * starting input type. The second time we provide NULL for the starting + * type. The third time we provide a bad starting input type. + * The bad starting input type should fail. The other two should succeed + * and produce the same result. + */ + for (i = 0; i < 3; i++) { + const char *testtype = (i == 0) ? input_type + : ((i == 1) ? NULL : badtype); + + if (!TEST_FL_ptr(dctx = OSSL_DECODER_CTX_new_for_pkey(&testpkey, + testtype, + structure_type, + keytype, + selection, + testctx, testpropq)) + || (pass != NULL + && !OSSL_DECODER_CTX_set_passphrase(dctx, upass, strlen(pass))) + || !TEST_FL_int_gt(BIO_reset(encoded_bio), 0) + /* We expect to fail when using a bad input type */ + || !TEST_FL_int_eq(OSSL_DECODER_from_bio(dctx, encoded_bio), + (i == 2) ? 0 : 1)) + goto end; + OSSL_DECODER_CTX_free(dctx); + dctx = NULL; + + if (i == 0) { + pkey = testpkey; + testpkey = NULL; + } else if (i == 1) { + if (selection == OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) { + if (!TEST_FL_int_eq(EVP_PKEY_parameters_eq(pkey, testpkey), 1)) + goto end; + } else { + if (!TEST_FL_int_eq(EVP_PKEY_eq(pkey, testpkey), 1)) + goto end; + } + } + } + ok = 1; + *object = pkey; + pkey = NULL; + + end: + EVP_PKEY_free(pkey); + EVP_PKEY_free(testpkey); + BIO_free(encoded_bio); + OSSL_DECODER_CTX_free(dctx); + return ok; +} + +static int encode_EVP_PKEY_legacy_PEM(const char *file, const int line, + void **encoded, long *encoded_len, + void *object, ossl_unused int selection, + ossl_unused const char *output_type, + ossl_unused const char *output_structure, + const char *pass, const char *pcipher) +{ + EVP_PKEY *pkey = object; + EVP_CIPHER *cipher = NULL; + BIO *mem_ser = NULL; + BUF_MEM *mem_buf = NULL; + const unsigned char *upass = (const unsigned char *)pass; + size_t passlen = 0; + int ok = 0; + + if (pcipher != NULL && pass != NULL) { + passlen = strlen(pass); + if (!TEST_FL_ptr(cipher = EVP_CIPHER_fetch(testctx, pcipher, testpropq))) + goto end; + } + if (!TEST_FL_ptr(mem_ser = BIO_new(BIO_s_mem())) + || !TEST_FL_true(PEM_write_bio_PrivateKey_traditional(mem_ser, pkey, + cipher, + upass, passlen, + NULL, NULL)) + || !TEST_FL_true(BIO_get_mem_ptr(mem_ser, &mem_buf) > 0) + || !TEST_FL_ptr(*encoded = mem_buf->data) + || !TEST_FL_long_gt(*encoded_len = mem_buf->length, 0)) + goto end; + + /* Detach the encoded output */ + mem_buf->data = NULL; + mem_buf->length = 0; + ok = 1; + end: + BIO_free(mem_ser); + EVP_CIPHER_free(cipher); + return ok; +} + +static int encode_EVP_PKEY_MSBLOB(const char *file, const int line, + void **encoded, long *encoded_len, + void *object, int selection, + ossl_unused const char *output_type, + ossl_unused const char *output_structure, + ossl_unused const char *pass, + ossl_unused const char *pcipher) +{ + EVP_PKEY *pkey = object; + BIO *mem_ser = NULL; + BUF_MEM *mem_buf = NULL; + int ok = 0; + + if (!TEST_FL_ptr(mem_ser = BIO_new(BIO_s_mem()))) + goto end; + + if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { + if (!TEST_FL_int_ge(i2b_PrivateKey_bio(mem_ser, pkey), 0)) + goto end; + } else { + if (!TEST_FL_int_ge(i2b_PublicKey_bio(mem_ser, pkey), 0)) + goto end; + } + + if (!TEST_FL_true(BIO_get_mem_ptr(mem_ser, &mem_buf) > 0) + || !TEST_FL_ptr(*encoded = mem_buf->data) + || !TEST_FL_long_gt(*encoded_len = mem_buf->length, 0)) + goto end; + + /* Detach the encoded output */ + mem_buf->data = NULL; + mem_buf->length = 0; + ok = 1; + end: + BIO_free(mem_ser); + return ok; +} + +static pem_password_cb pass_pw; +static int pass_pw(char *buf, int size, int rwflag, void *userdata) +{ + OPENSSL_strlcpy(buf, userdata, size); + return strlen(userdata); +} + +static int encode_EVP_PKEY_PVK(const char *file, const int line, + void **encoded, long *encoded_len, + void *object, int selection, + ossl_unused const char *output_type, + ossl_unused const char *output_structure, + const char *pass, + ossl_unused const char *pcipher) +{ + EVP_PKEY *pkey = object; + BIO *mem_ser = NULL; + BUF_MEM *mem_buf = NULL; + int enc = (pass != NULL); + int ok = 0; + + if (!TEST_FL_true(((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0)) + || !TEST_FL_ptr(mem_ser = BIO_new(BIO_s_mem())) + || !TEST_FL_int_ge(i2b_PVK_bio_ex(mem_ser, pkey, enc, + pass_pw, (void *)pass, testctx, testpropq), 0) + || !TEST_FL_true(BIO_get_mem_ptr(mem_ser, &mem_buf) > 0) + || !TEST_FL_ptr(*encoded = mem_buf->data) + || !TEST_FL_long_gt(*encoded_len = mem_buf->length, 0)) + goto end; + + /* Detach the encoded output */ + mem_buf->data = NULL; + mem_buf->length = 0; + ok = 1; + end: + BIO_free(mem_ser); + return ok; +} + +static int test_text(const char *file, const int line, + const void *data1, size_t data1_len, + const void *data2, size_t data2_len) +{ + return TEST_FL_strn2_eq(data1, data1_len, data2, data2_len); +} + +static int test_mem(const char *file, const int line, + const void *data1, size_t data1_len, + const void *data2, size_t data2_len) +{ + return TEST_FL_mem_eq(data1, data1_len, data2, data2_len); +} + +/* Test cases and their dumpers / checkers */ + +static void collect_name(const char *name, void *arg) +{ + char **namelist = arg; + char *new_namelist; + size_t space; + + space = strlen(name); + if (*namelist != NULL) + space += strlen(*namelist) + 2 /* for comma and space */; + space++; /* for terminating null byte */ + + new_namelist = OPENSSL_realloc(*namelist, space); + if (new_namelist == NULL) + return; + if (*namelist != NULL) { + strcat(new_namelist, ", "); + strcat(new_namelist, name); + } else { + strcpy(new_namelist, name); + } + *namelist = new_namelist; +} + +static void dump_der(const char *label, const void *data, size_t data_len) +{ + printf("Would print HEX for DER output\n"); + //test_output_memory(label, data, data_len); +} + +static void dump_pem(const char *label, const void *data, size_t data_len) +{ + printf("Would print string for PEM output\n"); + //test_output_string(label, data, data_len - 1); +} + +static int check_unprotected_PKCS8_DER(const char *file, const int line, + const char *type, + const void *data, size_t data_len) +{ + const unsigned char *datap = data; + PKCS8_PRIV_KEY_INFO *p8inf = + d2i_PKCS8_PRIV_KEY_INFO(NULL, &datap, data_len); + int ok = 0; + + if (TEST_FL_ptr(p8inf)) { + EVP_PKEY *pkey = EVP_PKCS82PKEY_ex(p8inf, testctx, testpropq); + char *namelist = NULL; + + if (TEST_FL_ptr(pkey)) { + if (!(ok = TEST_FL_true(EVP_PKEY_is_a(pkey, type)))) { + EVP_PKEY_type_names_do_all(pkey, collect_name, &namelist); + if (namelist != NULL) + TEST_note("%s isn't any of %s", type, namelist); + OPENSSL_free(namelist); + } + ok = ok && TEST_FL_true(evp_pkey_is_provided(pkey)); + EVP_PKEY_free(pkey); + } + } + PKCS8_PRIV_KEY_INFO_free(p8inf); + return ok; +} + +static int test_unprotected_via_DER(const char *type, EVP_PKEY *key) +{ + return test_encode_decode(__FILE__, __LINE__, type, key, + OSSL_KEYMGMT_SELECT_KEYPAIR + | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS, + "DER", "PrivateKeyInfo", NULL, NULL, + encode_EVP_PKEY_prov, decode_EVP_PKEY_prov, + test_mem, check_unprotected_PKCS8_DER, + dump_der, 0); +} + +static int check_unprotected_PKCS8_PEM(const char *file, const int line, + const char *type, + const void *data, size_t data_len) +{ + static const char expected_pem_header[] = + "-----BEGIN " PEM_STRING_PKCS8INF "-----"; + + return TEST_FL_strn_eq(data, expected_pem_header, + sizeof(expected_pem_header) - 1); +} + +static int test_unprotected_via_PEM(const char *type, EVP_PKEY *key) +{ + return test_encode_decode(__FILE__, __LINE__, type, key, + OSSL_KEYMGMT_SELECT_KEYPAIR + | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS, + "PEM", "PrivateKeyInfo", NULL, NULL, + encode_EVP_PKEY_prov, decode_EVP_PKEY_prov, + test_text, check_unprotected_PKCS8_PEM, + dump_pem, 0); +} + +#ifndef OPENSSL_NO_KEYPARAMS +static int check_params_DER(const char *file, const int line, + const char *type, const void *data, size_t data_len) +{ + const unsigned char *datap = data; + int ok = 0; + int itype = NID_undef; + EVP_PKEY *pkey = NULL; + + if (strcmp(type, "DH") == 0) + itype = EVP_PKEY_DH; + else if (strcmp(type, "X9.42 DH") == 0) + itype = EVP_PKEY_DHX; + else if (strcmp(type, "DSA") == 0) + itype = EVP_PKEY_DSA; + else if (strcmp(type, "EC") == 0) + itype = EVP_PKEY_EC; + + if (itype != NID_undef) { + pkey = d2i_KeyParams(itype, NULL, &datap, data_len); + ok = (pkey != NULL); + EVP_PKEY_free(pkey); + } + + return ok; +} + +static int check_params_PEM(const char *file, const int line, + const char *type, + const void *data, size_t data_len) +{ + static char expected_pem_header[80]; + + return + TEST_FL_int_gt(BIO_snprintf(expected_pem_header, + sizeof(expected_pem_header), + "-----BEGIN %s PARAMETERS-----", type), 0) + && TEST_FL_strn_eq(data, expected_pem_header, strlen(expected_pem_header)); +} + +static int test_params_via_DER(const char *type, EVP_PKEY *key) +{ + return test_encode_decode(__FILE__, __LINE__, type, key, OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, + "DER", "type-specific", NULL, NULL, + encode_EVP_PKEY_prov, decode_EVP_PKEY_prov, + test_mem, check_params_DER, + dump_der, FLAG_DECODE_WITH_TYPE); +} + +static int test_params_via_PEM(const char *type, EVP_PKEY *key) +{ + return test_encode_decode(__FILE__, __LINE__, type, key, OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, + "PEM", "type-specific", NULL, NULL, + encode_EVP_PKEY_prov, decode_EVP_PKEY_prov, + test_text, check_params_PEM, + dump_pem, 0); +} +#endif /* !OPENSSL_NO_KEYPARAMS */ + +static int check_unprotected_legacy_PEM(const char *file, const int line, + const char *type, + const void *data, size_t data_len) +{ + static char expected_pem_header[80]; + + return + TEST_FL_int_gt(BIO_snprintf(expected_pem_header, + sizeof(expected_pem_header), + "-----BEGIN %s PRIVATE KEY-----", type), 0) + && TEST_FL_strn_eq(data, expected_pem_header, strlen(expected_pem_header)); +} + +static int check_MSBLOB(const char *file, const int line, + const char *type, const void *data, size_t data_len) +{ + const unsigned char *datap = data; + EVP_PKEY *pkey = b2i_PrivateKey(&datap, data_len); + int ok = TEST_FL_ptr(pkey); + + EVP_PKEY_free(pkey); + return ok; +} + +static int test_unprotected_via_MSBLOB(const char *type, EVP_PKEY *key) +{ + return test_encode_decode(__FILE__, __LINE__, type, key, + OSSL_KEYMGMT_SELECT_KEYPAIR + | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, + "MSBLOB", NULL, NULL, NULL, + encode_EVP_PKEY_MSBLOB, decode_EVP_PKEY_prov, + test_mem, check_MSBLOB, + dump_der, 0); +} + +// start steal: Review TBD +// stolen from openssl/crypto/pem/pvkfmt.c as ossl_do_PVK_header not public API: +/* The PVK file magic number: seems to spell out "bobsfile", who is Bob? */ +# define MS_PVKMAGIC 0xb0b5f11eL +/* Salt length for PVK files */ +# define PVK_SALTLEN 0x10 +/* Maximum length in PVK header */ +# define PVK_MAX_KEYLEN 102400 +/* Maximum salt length */ +# define PVK_MAX_SALTLEN 10240 + +static unsigned int read_ledword(const unsigned char **in) +{ + const unsigned char *p = *in; + unsigned int ret; + + ret = (unsigned int)*p++; + ret |= (unsigned int)*p++ << 8; + ret |= (unsigned int)*p++ << 16; + ret |= (unsigned int)*p++ << 24; + *in = p; + return ret; +} + +static int oqsx_do_PVK_header(const unsigned char **in, unsigned int length, + int skip_magic, + unsigned int *psaltlen, unsigned int *pkeylen) +{ + const unsigned char *p = *in; + unsigned int pvk_magic, is_encrypted; + + if (skip_magic) { + if (length < 20) { + ERR_raise(ERR_LIB_PEM, PEM_R_PVK_TOO_SHORT); + return 0; + } + } else { + if (length < 24) { + ERR_raise(ERR_LIB_PEM, PEM_R_PVK_TOO_SHORT); + return 0; + } + pvk_magic = read_ledword(&p); + if (pvk_magic != MS_PVKMAGIC) { + ERR_raise(ERR_LIB_PEM, PEM_R_BAD_MAGIC_NUMBER); + return 0; + } + } + /* Skip reserved */ + p += 4; + /* + * keytype = + */ read_ledword(&p); + is_encrypted = read_ledword(&p); + *psaltlen = read_ledword(&p); + *pkeylen = read_ledword(&p); + + if (*pkeylen > PVK_MAX_KEYLEN || *psaltlen > PVK_MAX_SALTLEN) + return 0; + + if (is_encrypted && *psaltlen == 0) { + ERR_raise(ERR_LIB_PEM, PEM_R_INCONSISTENT_HEADER); + return 0; + } + + *in = p; + return 1; +} + +// end steal TBD + +static int check_PVK(const char *file, const int line, + const char *type, const void *data, size_t data_len) +{ + const unsigned char *in = data; + unsigned int saltlen = 0, keylen = 0; + int ok = oqsx_do_PVK_header(&in, data_len, 0, &saltlen, &keylen); + + printf("Returning %d from check_PVK\n", ok); + return ok; +} + +static int test_unprotected_via_PVK(const char *type, EVP_PKEY *key) +{ + return test_encode_decode(__FILE__, __LINE__, type, key, + OSSL_KEYMGMT_SELECT_KEYPAIR + | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, + "PVK", NULL, NULL, NULL, + encode_EVP_PKEY_PVK, decode_EVP_PKEY_prov, + test_mem, check_PVK, + dump_der, 0); +} + +static const char *pass_cipher = "AES-256-CBC"; +static const char *pass = "the holy handgrenade of antioch"; + +static int check_protected_PKCS8_DER(const char *file, const int line, + const char *type, + const void *data, size_t data_len) +{ + const unsigned char *datap = data; + X509_SIG *p8 = d2i_X509_SIG(NULL, &datap, data_len); + int ok = TEST_FL_ptr(p8); + + X509_SIG_free(p8); + return ok; +} + +static int test_protected_via_DER(const char *type, EVP_PKEY *key) +{ + return test_encode_decode(__FILE__, __LINE__, type, key, + OSSL_KEYMGMT_SELECT_KEYPAIR + | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, + "DER", "EncryptedPrivateKeyInfo", pass, pass_cipher, + encode_EVP_PKEY_prov, decode_EVP_PKEY_prov, + test_mem, check_protected_PKCS8_DER, + dump_der, 0); +} + +static int check_protected_PKCS8_PEM(const char *file, const int line, + const char *type, + const void *data, size_t data_len) +{ + static const char expected_pem_header[] = + "-----BEGIN " PEM_STRING_PKCS8 "-----"; + + return TEST_FL_strn_eq(data, expected_pem_header, + sizeof(expected_pem_header) - 1); +} + +static int test_protected_via_PEM(const char *type, EVP_PKEY *key) +{ + return test_encode_decode(__FILE__, __LINE__, type, key, + OSSL_KEYMGMT_SELECT_KEYPAIR + | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, + "PEM", "EncryptedPrivateKeyInfo", pass, pass_cipher, + encode_EVP_PKEY_prov, decode_EVP_PKEY_prov, + test_text, check_protected_PKCS8_PEM, + dump_pem, 0); +} + +static int check_public_DER(const char *file, const int line, + const char *type, const void *data, size_t data_len) +{ + const unsigned char *datap = data; + EVP_PKEY *pkey = d2i_PUBKEY_ex(NULL, &datap, data_len, testctx, testpropq); + int ok = (TEST_FL_ptr(pkey) && TEST_FL_true(EVP_PKEY_is_a(pkey, type))); + + EVP_PKEY_free(pkey); + return ok; +} + +static int test_public_via_DER(const char *type, EVP_PKEY *key) +{ + return test_encode_decode(__FILE__, __LINE__, type, key, + OSSL_KEYMGMT_SELECT_PUBLIC_KEY + | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS, + "DER", "SubjectPublicKeyInfo", NULL, NULL, + encode_EVP_PKEY_prov, decode_EVP_PKEY_prov, + test_mem, check_public_DER, dump_der, 0); +} + +static int check_public_PEM(const char *file, const int line, + const char *type, const void *data, size_t data_len) +{ + static const char expected_pem_header[] = + "-----BEGIN " PEM_STRING_PUBLIC "-----"; + + return + TEST_FL_strn_eq(data, expected_pem_header, + sizeof(expected_pem_header) - 1); +} + +static int test_public_via_PEM(const char *type, EVP_PKEY *key) +{ + return test_encode_decode(__FILE__, __LINE__, type, key, + OSSL_KEYMGMT_SELECT_PUBLIC_KEY + | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS, + "PEM", "SubjectPublicKeyInfo", NULL, NULL, + encode_EVP_PKEY_prov, decode_EVP_PKEY_prov, + test_text, check_public_PEM, dump_pem, 0); +} + +static int check_public_MSBLOB(const char *file, const int line, + const char *type, + const void *data, size_t data_len) +{ + const unsigned char *datap = data; + EVP_PKEY *pkey = b2i_PublicKey(&datap, data_len); + int ok = TEST_FL_ptr(pkey); + + EVP_PKEY_free(pkey); + return ok; +} + +static int test_public_via_MSBLOB(const char *type, EVP_PKEY *key) +{ + return test_encode_decode(__FILE__, __LINE__, type, key, OSSL_KEYMGMT_SELECT_PUBLIC_KEY + | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, + "MSBLOB", NULL, NULL, NULL, + encode_EVP_PKEY_MSBLOB, decode_EVP_PKEY_prov, + test_mem, check_public_MSBLOB, dump_der, 0); +} + +#define KEYS(KEYTYPE) \ + static EVP_PKEY *key_##KEYTYPE = NULL +#define MAKE_KEYS(KEYTYPE, KEYTYPEstr, params) \ + ok = ok \ + && TEST_ptr(key_##KEYTYPE = oqstest_make_key(KEYTYPEstr, NULL, params)) +#define FREE_KEYS(KEYTYPE) \ + EVP_PKEY_free(key_##KEYTYPE); \ + +#define DOMAIN_KEYS(KEYTYPE) \ + static EVP_PKEY *template_##KEYTYPE = NULL; \ + static EVP_PKEY *key_##KEYTYPE = NULL +#define MAKE_DOMAIN_KEYS(KEYTYPE, KEYTYPEstr, params) \ + ok = ok \ + && TEST_ptr(template_##KEYTYPE = \ + oqstest_make_template(KEYTYPEstr, params)) \ + && TEST_ptr(key_##KEYTYPE = \ + oqstest_make_key(KEYTYPEstr, template_##KEYTYPE, NULL)) +#define FREE_DOMAIN_KEYS(KEYTYPE) \ + EVP_PKEY_free(template_##KEYTYPE); \ + EVP_PKEY_free(key_##KEYTYPE) + +#define IMPLEMENT_TEST_SUITE(KEYTYPE, KEYTYPEstr) \ + static int test_unprotected_##KEYTYPE##_via_DER(void) \ + { \ + return test_unprotected_via_DER(KEYTYPEstr, key_##KEYTYPE); \ + } \ + static int test_unprotected_##KEYTYPE##_via_PEM(void) \ + { \ + return test_unprotected_via_PEM(KEYTYPEstr, key_##KEYTYPE); \ + } \ + static int test_public_##KEYTYPE##_via_DER(void) \ + { \ + return test_public_via_DER(KEYTYPEstr, key_##KEYTYPE); \ + } \ + static int test_protected_##KEYTYPE##_via_DER(void) \ + { \ + return test_protected_via_DER(KEYTYPEstr, key_##KEYTYPE); \ + } \ + static int test_protected_##KEYTYPE##_via_PEM(void) \ + { \ + return test_protected_via_PEM(KEYTYPEstr, key_##KEYTYPE); \ + } \ + static int test_public_##KEYTYPE##_via_PEM(void) \ + { \ + return test_public_via_PEM(KEYTYPEstr, key_##KEYTYPE); \ + } + +#define ADD_TEST_SUITE(KEYTYPE) \ + ADD_TEST(test_unprotected_##KEYTYPE##_via_DER); \ + ADD_TEST(test_unprotected_##KEYTYPE##_via_PEM); \ + ADD_TEST(test_public_##KEYTYPE##_via_DER); \ + ADD_TEST(test_protected_##KEYTYPE##_via_DER); \ + ADD_TEST(test_protected_##KEYTYPE##_via_PEM); \ + ADD_TEST(test_public_##KEYTYPE##_via_PEM) + +#define IMPLEMENT_TEST_SUITE_PARAMS(KEYTYPE, KEYTYPEstr) \ + static int test_params_##KEYTYPE##_via_DER(void) \ + { \ + return test_params_via_DER(KEYTYPEstr, key_##KEYTYPE); \ + } \ + static int test_params_##KEYTYPE##_via_PEM(void) \ + { \ + return test_params_via_PEM(KEYTYPEstr, key_##KEYTYPE); \ + } + +#define ADD_TEST_SUITE_PARAMS(KEYTYPE) \ + ADD_TEST(test_params_##KEYTYPE##_via_DER); \ + ADD_TEST(test_params_##KEYTYPE##_via_PEM) + +#define IMPLEMENT_TEST_SUITE_MSBLOB(KEYTYPE, KEYTYPEstr) \ + static int test_unprotected_##KEYTYPE##_via_MSBLOB(void) \ + { \ + return test_unprotected_via_MSBLOB(KEYTYPEstr, key_##KEYTYPE); \ + } \ + static int test_public_##KEYTYPE##_via_MSBLOB(void) \ + { \ + return test_public_via_MSBLOB(KEYTYPEstr, key_##KEYTYPE); \ + } + +#define ADD_TEST_SUITE_MSBLOB(KEYTYPE) \ + ADD_TEST(test_unprotected_##KEYTYPE##_via_MSBLOB); \ + ADD_TEST(test_public_##KEYTYPE##_via_MSBLOB) + +#define IMPLEMENT_TEST_SUITE_UNPROTECTED_PVK(KEYTYPE, KEYTYPEstr) \ + static int test_unprotected_##KEYTYPE##_via_PVK(void) \ + { \ + return test_unprotected_via_PVK(KEYTYPEstr, key_##KEYTYPE); \ + } +# define ADD_TEST_SUITE_UNPROTECTED_PVK(KEYTYPE) \ + ADD_TEST(test_unprotected_##KEYTYPE##_via_PVK) +#ifndef OPENSSL_NO_RC4 +# define IMPLEMENT_TEST_SUITE_PROTECTED_PVK(KEYTYPE, KEYTYPEstr) \ + static int test_protected_##KEYTYPE##_via_PVK(void) \ + { \ + return test_protected_via_PVK(KEYTYPEstr, key_##KEYTYPE); \ + } +# define ADD_TEST_SUITE_PROTECTED_PVK(KEYTYPE) \ + ADD_TEST(test_protected_##KEYTYPE##_via_PVK) +#endif + +///// OQS_TEMPLATE_FRAGMENT_IMPLEMENT_START +KEYS(dilithium2); +IMPLEMENT_TEST_SUITE(dilithium2, "dilithium2") +KEYS(dilithium3); +IMPLEMENT_TEST_SUITE(dilithium3, "dilithium3") +KEYS(dilithium5); +IMPLEMENT_TEST_SUITE(dilithium5, "dilithium5") +KEYS(dilithium2_aes); +IMPLEMENT_TEST_SUITE(dilithium2_aes, "dilithium2_aes") +KEYS(dilithium3_aes); +IMPLEMENT_TEST_SUITE(dilithium3_aes, "dilithium3_aes") +KEYS(dilithium5_aes); +IMPLEMENT_TEST_SUITE(dilithium5_aes, "dilithium5_aes") +KEYS(falcon512); +IMPLEMENT_TEST_SUITE(falcon512, "falcon512") +KEYS(falcon1024); +IMPLEMENT_TEST_SUITE(falcon1024, "falcon1024") +KEYS(picnicl1full); +IMPLEMENT_TEST_SUITE(picnicl1full, "picnicl1full") +KEYS(picnic3l1); +IMPLEMENT_TEST_SUITE(picnic3l1, "picnic3l1") +KEYS(rainbowIclassic); +IMPLEMENT_TEST_SUITE(rainbowIclassic, "rainbowIclassic") +KEYS(rainbowVclassic); +IMPLEMENT_TEST_SUITE(rainbowVclassic, "rainbowVclassic") +KEYS(sphincsharaka128frobust); +IMPLEMENT_TEST_SUITE(sphincsharaka128frobust, "sphincsharaka128frobust") +KEYS(sphincssha256128frobust); +IMPLEMENT_TEST_SUITE(sphincssha256128frobust, "sphincssha256128frobust") +KEYS(sphincsshake256128frobust); +IMPLEMENT_TEST_SUITE(sphincsshake256128frobust, "sphincsshake256128frobust") +///// OQS_TEMPLATE_FRAGMENT_IMPLEMENT_END + +typedef enum OPTION_choice { + OPT_ERR = -1, + OPT_EOF = 0, + OPT_CONTEXT, + OPT_TRACE_ENCODER, + OPT_TRACE_DECODER, + OPT_CONFIG_FILE, + OPT_PROVIDER_NAME, + OPT_TEST_ENUM +} OPTION_CHOICE; + +const OPTIONS *test_get_options(void) +{ + static const OPTIONS options[] = { + OPT_TEST_OPTIONS_DEFAULT_USAGE, + { "context", OPT_CONTEXT, '-', + "Explicitly use a non-default library context" }, + { "trace-encoder", OPT_TRACE_ENCODER, '-', + "Enable full encoder tracing" }, + { "trace-decoder", OPT_TRACE_DECODER, '-', + "Enable full decoder tracing" }, + { "config", OPT_CONFIG_FILE, '<', + "The configuration file to use for the library context" }, + { "provider", OPT_PROVIDER_NAME, 's', + "The provider to load (The default value is 'default')" }, + { NULL } + }; + return options; +} + +int setup_tests(void) +{ + const char *prov_name = "oqsprovider"; + char *config_file = NULL; + int ok = 1; + BIO *err = BIO_new_fp(stdout, BIO_NOCLOSE | BIO_FP_TEXT); + + OPTION_CHOICE o; + + while ((o = opt_next()) != OPT_EOF) { + switch (o) { + case OPT_CONTEXT: + default_libctx = 0; + break; + case OPT_TRACE_ENCODER: + OSSL_trace_set_channel(OSSL_TRACE_CATEGORY_ENCODER, err); + break; + case OPT_TRACE_DECODER: + OSSL_trace_set_channel(OSSL_TRACE_CATEGORY_DECODER, err); + break; + case OPT_PROVIDER_NAME: + prov_name = opt_arg(); + break; + case OPT_CONFIG_FILE: + config_file = opt_arg(); + break; + case OPT_TEST_CASES: + break; + default: + return 0; + } + } + + if (default_libctx) { + if (!test_get_libctx(NULL, NULL, config_file, &oqsprov, prov_name)) + return 0; + } else { + if (!test_get_libctx(&testctx, NULL, config_file, &oqsprov, prov_name)) + return 0; + } + + /* Separate provider/ctx for generating the test data */ + if (!TEST_ptr(keyctx = OSSL_LIB_CTX_new())) + return 0; + // Enabling DRBG via default provider, both for key and default context + if (!TEST_ptr(dfltprov = OSSL_PROVIDER_load(NULL, "default"))) + return 0; + if (!TEST_ptr(dfltprov = OSSL_PROVIDER_load(keyctx, "default"))) + return 0; + if (!TEST_ptr(keyprov = OSSL_PROVIDER_load(keyctx, prov_name))) + return 0; + + TEST_info("Generating keys..."); + +///// OQS_TEMPLATE_FRAGMENT_ADD_START + MAKE_KEYS(dilithium2, "dilithium2", NULL); + ADD_TEST_SUITE(dilithium2); + MAKE_KEYS(dilithium3, "dilithium3", NULL); + ADD_TEST_SUITE(dilithium3); + MAKE_KEYS(dilithium5, "dilithium5", NULL); + ADD_TEST_SUITE(dilithium5); + MAKE_KEYS(dilithium2_aes, "dilithium2_aes", NULL); + ADD_TEST_SUITE(dilithium2_aes); + MAKE_KEYS(dilithium3_aes, "dilithium3_aes", NULL); + ADD_TEST_SUITE(dilithium3_aes); + MAKE_KEYS(dilithium5_aes, "dilithium5_aes", NULL); + ADD_TEST_SUITE(dilithium5_aes); + MAKE_KEYS(falcon512, "falcon512", NULL); + ADD_TEST_SUITE(falcon512); + MAKE_KEYS(falcon1024, "falcon1024", NULL); + ADD_TEST_SUITE(falcon1024); + MAKE_KEYS(picnicl1full, "picnicl1full", NULL); + ADD_TEST_SUITE(picnicl1full); + MAKE_KEYS(picnic3l1, "picnic3l1", NULL); + ADD_TEST_SUITE(picnic3l1); + MAKE_KEYS(rainbowIclassic, "rainbowIclassic", NULL); + ADD_TEST_SUITE(rainbowIclassic); + MAKE_KEYS(rainbowVclassic, "rainbowVclassic", NULL); + ADD_TEST_SUITE(rainbowVclassic); + MAKE_KEYS(sphincsharaka128frobust, "sphincsharaka128frobust", NULL); + ADD_TEST_SUITE(sphincsharaka128frobust); + MAKE_KEYS(sphincssha256128frobust, "sphincssha256128frobust", NULL); + ADD_TEST_SUITE(sphincssha256128frobust); + MAKE_KEYS(sphincsshake256128frobust, "sphincsshake256128frobust", NULL); + ADD_TEST_SUITE(sphincsshake256128frobust); +///// OQS_TEMPLATE_FRAGMENT_ADD_END + + return 1; +} + +void cleanup_tests(void) +{ +///// OQS_TEMPLATE_FRAGMENT_FREEKEYS_START + FREE_KEYS(dilithium2); + FREE_KEYS(dilithium3); + FREE_KEYS(dilithium5); + FREE_KEYS(dilithium2_aes); + FREE_KEYS(dilithium3_aes); + FREE_KEYS(dilithium5_aes); + FREE_KEYS(falcon512); + FREE_KEYS(falcon1024); + FREE_KEYS(picnicl1full); + FREE_KEYS(picnic3l1); + FREE_KEYS(rainbowIclassic); + FREE_KEYS(rainbowVclassic); + FREE_KEYS(sphincsharaka128frobust); + FREE_KEYS(sphincssha256128frobust); + FREE_KEYS(sphincsshake256128frobust); +///// OQS_TEMPLATE_FRAGMENT_FREEKEYS_END + + OSSL_PROVIDER_unload(dfltprov); + OSSL_PROVIDER_unload(oqsprov); + OSSL_PROVIDER_unload(keyprov); + OSSL_LIB_CTX_free(testctx); + OSSL_LIB_CTX_free(keyctx); +} + diff --git a/test/oqs_test_groups.c b/test/oqs_test_groups.c index 04b16183..ba63d907 100644 --- a/test/oqs_test_groups.c +++ b/test/oqs_test_groups.c @@ -146,13 +146,8 @@ int main(int argc, char *argv[]) T(OSSL_LIB_CTX_load_config(libctx, configfile)); - /* Check we have the expected providers available: - * Note: default only needed if liboqs built using openssl, - * so may be left away (in test/oqs.cnf if suitably build, see - * https://github.com/open-quantum-safe/liboqs/wiki/Customizing-liboqs#OQS_USE_OPENSSL - */ T(OSSL_PROVIDER_available(libctx, modulename)); - T(OSSL_PROVIDER_available(libctx, "default")); + T(OSSL_PROVIDER_available(libctx, "default")); T(OSSL_PROVIDER_do_all(libctx, test_provider_groups, &errcnt)); diff --git a/test/oqs_test_signatures.c b/test/oqs_test_signatures.c index 952d68aa..7addc172 100644 --- a/test/oqs_test_signatures.c +++ b/test/oqs_test_signatures.c @@ -33,6 +33,7 @@ static const char *sigalg_names[] = { ///// OQS_TEMPLATE_FRAGMENT_SIGNATURE_CASES_END }; +// sign-and-hash must work with and without providing a digest algorithm static int test_oqs_signatures(const char *sigalg_name) { EVP_MD_CTX *mdctx = NULL; @@ -42,17 +43,37 @@ static int test_oqs_signatures(const char *sigalg_name) unsigned char *sig; size_t siglen; - int testresult = + int testresult = 1; + + // test with built-in digest only if default provider is active: + // TBD revisit when hybrids are activated: They always need default provider + if (OSSL_PROVIDER_available(libctx, "default")) + testresult &= + (mdctx = EVP_MD_CTX_new()) != NULL + && (ctx = EVP_PKEY_CTX_new_from_name(libctx, sigalg_name, NULL)) != NULL + && EVP_PKEY_keygen_init(ctx) + && EVP_PKEY_generate(ctx, &key) + && EVP_DigestSignInit_ex(mdctx, NULL, "SHA512", libctx, NULL, key, NULL) + && EVP_DigestSignUpdate(mdctx, msg, sizeof(msg)) + && EVP_DigestSignFinal(mdctx, NULL, &siglen) + && (sig = OPENSSL_malloc(siglen)) != NULL + && EVP_DigestSignFinal(mdctx, sig, &siglen) + && EVP_DigestVerifyInit_ex(mdctx, NULL, "SHA512", libctx, NULL, key, NULL) + && EVP_DigestVerifyUpdate(mdctx, msg, sizeof(msg)) + && EVP_DigestVerifyFinal(mdctx, sig, siglen); + + // this test must work also with default provider inactive: + testresult &= (mdctx = EVP_MD_CTX_new()) != NULL && (ctx = EVP_PKEY_CTX_new_from_name(libctx, sigalg_name, NULL)) != NULL && EVP_PKEY_keygen_init(ctx) && EVP_PKEY_generate(ctx, &key) - && EVP_DigestSignInit_ex(mdctx, NULL, "SHA512", libctx, NULL, key, NULL) + && EVP_DigestSignInit_ex(mdctx, NULL, NULL, libctx, NULL, key, NULL) && EVP_DigestSignUpdate(mdctx, msg, sizeof(msg)) && EVP_DigestSignFinal(mdctx, NULL, &siglen) && (sig = OPENSSL_malloc(siglen)) != NULL && EVP_DigestSignFinal(mdctx, sig, &siglen) - && EVP_DigestVerifyInit_ex(mdctx, NULL, "SHA512", libctx, NULL, key, NULL) + && EVP_DigestVerifyInit_ex(mdctx, NULL, NULL, libctx, NULL, key, NULL) && EVP_DigestVerifyUpdate(mdctx, msg, sizeof(msg)) && EVP_DigestVerifyFinal(mdctx, sig, siglen); @@ -76,13 +97,7 @@ int main(int argc, char *argv[]) T(OSSL_LIB_CTX_load_config(libctx, configfile)); - /* Check we have the expected providers available: - * Note: default only needed if liboqs built using openssl, - * so may be left away (in test/oqs.cnf if suitably build, see - * https://github.com/open-quantum-safe/liboqs/wiki/Customizing-liboqs#OQS_USE_OPENSSL - */ T(OSSL_PROVIDER_available(libctx, modulename)); - T(OSSL_PROVIDER_available(libctx, "default")); for (i = 0; i < nelem(sigalg_names); i++) { if (test_oqs_signatures(sigalg_names[i])) {