diff options
author | Tomas Mraz <tomas@openssl.org> | 2021-10-06 19:21:53 +0200 |
---|---|---|
committer | Richard Levitte <levitte@openssl.org> | 2021-10-27 12:41:51 +0200 |
commit | 051228353a9842eede597294603cc06a55e3a22c (patch) | |
tree | 1fb7213f26ea9d6d89976ae9ad8a4710efc57499 | |
parent | dc010ca6ec01d313a84c3c4b040232655a1772ad (diff) |
test: fetching proper signature provider for non-exportable keys
Co-author: Selva Nair <selva.nair@gmail.com>
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/16725)
-rw-r--r-- | test/build.info | 5 | ||||
-rw-r--r-- | test/fake_rsaprov.c | 234 | ||||
-rw-r--r-- | test/fake_rsaprov.h | 14 | ||||
-rw-r--r-- | test/provider_pkey_test.c | 132 | ||||
-rw-r--r-- | test/recipes/04-test_provider_pkey.t | 18 |
5 files changed, 403 insertions, 0 deletions
diff --git a/test/build.info b/test/build.info index 1e4205ddb3..0f379e11e2 100644 --- a/test/build.info +++ b/test/build.info @@ -844,6 +844,11 @@ IF[{- !$disabled{tests} -}] INCLUDE[provider_fallback_test]=../include ../apps/include DEPEND[provider_fallback_test]=../libcrypto libtestutil.a + PROGRAMS{noinst}=provider_pkey_test + SOURCE[provider_pkey_test]=provider_pkey_test.c fake_rsaprov.c + INCLUDE[provider_pkey_test]=../include ../apps/include + DEPEND[provider_pkey_test]=../libcrypto libtestutil.a + PROGRAMS{noinst}=params_test SOURCE[params_test]=params_test.c INCLUDE[params_test]=.. ../include ../apps/include diff --git a/test/fake_rsaprov.c b/test/fake_rsaprov.c new file mode 100644 index 0000000000..e4833a6a99 --- /dev/null +++ b/test/fake_rsaprov.c @@ -0,0 +1,234 @@ +/* + * Copyright 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 may obtain a copy of the License at + * https://www.openssl.org/source/license.html + * or in the file LICENSE in the source distribution. + */ + +#include <string.h> +#include <openssl/core_names.h> +#include <openssl/rand.h> +#include <openssl/provider.h> +#include "testutil.h" +#include "fake_rsaprov.h" + +static OSSL_FUNC_keymgmt_new_fn fake_rsa_keymgmt_new; +static OSSL_FUNC_keymgmt_free_fn fake_rsa_keymgmt_free; +static OSSL_FUNC_keymgmt_has_fn fake_rsa_keymgmt_has; +static OSSL_FUNC_keymgmt_query_operation_name_fn fake_rsa_keymgmt_query; +static OSSL_FUNC_keymgmt_import_fn fake_rsa_keymgmt_import; +static OSSL_FUNC_keymgmt_import_types_fn fake_rsa_keymgmt_imptypes; + +static int has_selection; +static int imptypes_selection; +static int query_id; + +static void *fake_rsa_keymgmt_new(void *provctx) +{ + unsigned char *keydata = OPENSSL_zalloc(1); + + TEST_ptr(keydata); + + /* clear test globals */ + has_selection = 0; + imptypes_selection = 0; + query_id = 0; + + return keydata; +} + +static void fake_rsa_keymgmt_free(void *keydata) +{ + OPENSSL_free(keydata); +} + +static int fake_rsa_keymgmt_has(const void *key, int selection) +{ + /* record global for checking */ + has_selection = selection; + + return 1; +} + + +static const char *fake_rsa_keymgmt_query(int id) +{ + /* record global for checking */ + query_id = id; + + return "RSA"; +} + +static int fake_rsa_keymgmt_import(void *keydata, int selection, + const OSSL_PARAM *p) +{ + unsigned char *fake_rsa_key = keydata; + + /* key was imported */ + *fake_rsa_key = 1; + + return 1; +} + +static const OSSL_PARAM fake_rsa_import_key_types[] = { + OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_N, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_E, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_D, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR1, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_FACTOR2, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT1, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_EXPONENT2, NULL, 0), + OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_COEFFICIENT1, NULL, 0), + OSSL_PARAM_END +}; + +static const OSSL_PARAM *fake_rsa_keymgmt_imptypes(int selection) +{ + /* record global for checking */ + imptypes_selection = selection; + + return fake_rsa_import_key_types; +} + +static const OSSL_DISPATCH fake_rsa_keymgmt_funcs[] = { + { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))fake_rsa_keymgmt_new }, + { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))fake_rsa_keymgmt_free} , + { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))fake_rsa_keymgmt_has }, + { OSSL_FUNC_KEYMGMT_QUERY_OPERATION_NAME, + (void (*)(void))fake_rsa_keymgmt_query }, + { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))fake_rsa_keymgmt_import }, + { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, + (void (*)(void))fake_rsa_keymgmt_imptypes }, + { 0, NULL } +}; + +static const OSSL_ALGORITHM fake_rsa_keymgmt_algs[] = { + { "RSA:rsaEncryption", "provider=fake-rsa", fake_rsa_keymgmt_funcs, "Fake RSA Key Management" }, + { NULL, NULL, NULL, NULL } +}; + +static OSSL_FUNC_signature_newctx_fn fake_rsa_sig_newctx; +static OSSL_FUNC_signature_freectx_fn fake_rsa_sig_freectx; +static OSSL_FUNC_signature_sign_init_fn fake_rsa_sig_sign_init; +static OSSL_FUNC_signature_sign_fn fake_rsa_sig_sign; + +static void *fake_rsa_sig_newctx(void *provctx, const char *propq) +{ + unsigned char *sigctx = OPENSSL_zalloc(1); + + TEST_ptr(sigctx); + + return sigctx; +} + +static void fake_rsa_sig_freectx(void *sigctx) +{ + OPENSSL_free(sigctx); +} + +static int fake_rsa_sig_sign_init(void *ctx, void *provkey, + const OSSL_PARAM params[]) +{ + unsigned char *sigctx = ctx; + unsigned char *keydata = provkey; + + /* we must have a ctx */ + if (!TEST_ptr(sigctx)) + return 0; + + /* we must have some initialized key */ + if (!TEST_ptr(keydata) || !TEST_int_gt(keydata[0], 0)) + return 0; + + /* record that sign init was called */ + *sigctx = 1; + return 1; +} + +static int fake_rsa_sig_sign(void *ctx, unsigned char *sig, + size_t *siglen, size_t sigsize, + const unsigned char *tbs, size_t tbslen) +{ + unsigned char *sigctx = ctx; + + /* we must have a ctx and init was called upon it */ + if (!TEST_ptr(sigctx) || !TEST_int_eq(*sigctx, 1)) + return 0; + + *siglen = 256; + /* record that the real sign operation was called */ + if (sig != NULL) { + if (!TEST_int_ge(sigsize, *siglen)) + return 0; + *sigctx = 2; + /* produce a fake signature */ + memset(sig, 'a', *siglen); + } + + return 1; +} + +static const OSSL_DISPATCH fake_rsa_sig_funcs[] = { + { OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))fake_rsa_sig_newctx }, + { OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))fake_rsa_sig_freectx }, + { OSSL_FUNC_SIGNATURE_SIGN_INIT, (void (*)(void))fake_rsa_sig_sign_init }, + { OSSL_FUNC_SIGNATURE_SIGN, (void (*)(void))fake_rsa_sig_sign }, + { 0, NULL } +}; + +static const OSSL_ALGORITHM fake_rsa_sig_algs[] = { + { "RSA:rsaEncryption", "provider=fake-rsa", fake_rsa_sig_funcs, "Fake RSA Signature" }, + { NULL, NULL, NULL, NULL } +}; + +static const OSSL_ALGORITHM *fake_rsa_query(void *provctx, + int operation_id, + int *no_cache) +{ + *no_cache = 0; + switch (operation_id) { + case OSSL_OP_SIGNATURE: + return fake_rsa_sig_algs; + + case OSSL_OP_KEYMGMT: + return fake_rsa_keymgmt_algs; + } + return NULL; +} + +/* Functions we provide to the core */ +static const OSSL_DISPATCH fake_rsa_method[] = { + { OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))OSSL_LIB_CTX_free }, + { OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))fake_rsa_query }, + { 0, NULL } +}; + +static int fake_rsa_provider_init(const OSSL_CORE_HANDLE *handle, + const OSSL_DISPATCH *in, + const OSSL_DISPATCH **out, void **provctx) +{ + if (!TEST_ptr(*provctx = OSSL_LIB_CTX_new())) + return 0; + *out = fake_rsa_method; + return 1; +} + +OSSL_PROVIDER *fake_rsa_start(OSSL_LIB_CTX *libctx) +{ + OSSL_PROVIDER *p; + + if (!TEST_true(OSSL_PROVIDER_add_builtin(libctx, "fake-rsa", + fake_rsa_provider_init)) + || !TEST_ptr(p = OSSL_PROVIDER_try_load(libctx, "fake-rsa", 1))) + return NULL; + + return p; +} + +void fake_rsa_finish(OSSL_PROVIDER *p) +{ + OSSL_PROVIDER_unload(p); +} diff --git a/test/fake_rsaprov.h b/test/fake_rsaprov.h new file mode 100644 index 0000000000..57de1ecf8d --- /dev/null +++ b/test/fake_rsaprov.h @@ -0,0 +1,14 @@ +/* + * Copyright 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 <openssl/core_dispatch.h> + +/* Fake RSA provider implementation */ +OSSL_PROVIDER *fake_rsa_start(OSSL_LIB_CTX *libctx); +void fake_rsa_finish(OSSL_PROVIDER *p); diff --git a/test/provider_pkey_test.c b/test/provider_pkey_test.c new file mode 100644 index 0000000000..d360c0cf30 --- /dev/null +++ b/test/provider_pkey_test.c @@ -0,0 +1,132 @@ +/* + * Copyright 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 <stddef.h> +#include <string.h> +#include <openssl/provider.h> +#include <openssl/params.h> +#include <openssl/core_names.h> +#include <openssl/evp.h> +#include "testutil.h" +#include "fake_rsaprov.h" + +static OSSL_LIB_CTX *libctx = NULL; + +/* Fetch SIGNATURE method using a libctx and propq */ +static int fetch_sig(OSSL_LIB_CTX *ctx, const char *alg, const char *propq, + OSSL_PROVIDER *expected_prov) +{ + OSSL_PROVIDER *prov; + EVP_SIGNATURE *sig = EVP_SIGNATURE_fetch(ctx, "RSA", propq); + int ret = 0; + + if (!TEST_ptr(sig)) + return 0; + + if (!TEST_ptr(prov = EVP_SIGNATURE_get0_provider(sig))) + goto end; + + if (!TEST_ptr_eq(prov, expected_prov)) { + TEST_info("Fetched provider: %s, Expected provider: %s", + OSSL_PROVIDER_get0_name(prov), + OSSL_PROVIDER_get0_name(expected_prov)); + goto end; + } + + ret = 1; +end: + EVP_SIGNATURE_free(sig); + return ret; +} + + +static int test_pkey_sig(void) +{ + OSSL_PROVIDER *deflt = NULL; + OSSL_PROVIDER *fake_rsa = NULL; + int i, ret = 0; + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + + if (!TEST_ptr(fake_rsa = fake_rsa_start(libctx))) + return 0; + + if (!TEST_ptr(deflt = OSSL_PROVIDER_load(libctx, "default"))) + goto end; + + /* Do a direct fetch to see it works */ + if (!TEST_true(fetch_sig(libctx, "RSA", "provider=fake-rsa", fake_rsa)) + || !TEST_true(fetch_sig(libctx, "RSA", "?provider=fake-rsa", fake_rsa))) + goto end; + + /* Construct a pkey using precise propq to use our provider */ + if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_name(libctx, "RSA", + "provider=fake-rsa")) + || !TEST_true(EVP_PKEY_fromdata_init(ctx)) + || !TEST_true(EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_KEYPAIR, NULL)) + || !TEST_ptr(pkey)) + goto end; + + EVP_PKEY_CTX_free(ctx); + ctx = NULL; + + /* try exercising signature_init ops a few times */ + for (i = 0; i < 3; i++) { + size_t siglen; + + /* + * Create a signing context for our pkey with optional propq. + * The sign init should pick both keymgmt and signature from + * fake-rsa as the key is not exportable. + */ + if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, + "?provider=default"))) + goto end; + + /* + * If this picks the wrong signature without realizing it + * we can get a segfault or some internal error. At least watch + * whether fake-rsa sign_init is is exercised by calling sign. + */ + if (!TEST_int_eq(EVP_PKEY_sign_init(ctx), 1)) + goto end; + + if (!TEST_int_eq(EVP_PKEY_sign(ctx, NULL, &siglen, NULL, 0), 1) + || !TEST_size_t_eq(siglen, 256)) + goto end; + + EVP_PKEY_CTX_free(ctx); + ctx = NULL; + } + + ret = 1; + +end: + fake_rsa_finish(fake_rsa); + OSSL_PROVIDER_unload(deflt); + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(pkey); + return ret; +} + +int setup_tests(void) +{ + libctx = OSSL_LIB_CTX_new(); + if (libctx == NULL) + return 0; + + ADD_TEST(test_pkey_sig); + + return 1; +} + +void cleanup_tests(void) +{ + OSSL_LIB_CTX_free(libctx); +} diff --git a/test/recipes/04-test_provider_pkey.t b/test/recipes/04-test_provider_pkey.t new file mode 100644 index 0000000000..f593ac5725 --- /dev/null +++ b/test/recipes/04-test_provider_pkey.t @@ -0,0 +1,18 @@ +#! /usr/bin/env perl +# Copyright 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 + +use strict; +use File::Spec; +use OpenSSL::Test::Simple; + +# We must ensure that OPENSSL_CONF points at an empty file. Otherwise, we +# risk that the configuration file contains statements that load providers, +# which defeats the purpose of this test. The NUL device is good enough. +$ENV{OPENSSL_CONF} = File::Spec->devnull(); + +simple_test("test_provider_pkey", "provider_pkey_test"); |