From 5442611dffed2c345ef83d494f2ef7ffb9cf3883 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 22 Apr 2021 15:58:50 +0100 Subject: [PATCH] Add a test for OSSL_LIB_CTX_new_child() Check that we can create such a libctx and usable providers are loaded into it. Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/14991) --- test/p_test.c | 48 ++++++++++++++++- test/provider_test.c | 95 ++++++++++++++++++++++++++++++--- test/recipes/04-test_provider.t | 7 ++- 3 files changed, 140 insertions(+), 10 deletions(-) diff --git a/test/p_test.c b/test/p_test.c index 6f55abda01928..421287edb31b4 100644 --- a/test/p_test.c +++ b/test/p_test.c @@ -30,11 +30,14 @@ #include #include #include +#include +#include typedef struct p_test_ctx { char *thisfile; char *thisfunc; const OSSL_CORE_HANDLE *handle; + OSSL_LIB_CTX *libctx; } P_TEST_CTX; static OSSL_FUNC_core_gettable_params_fn *c_gettable_params = NULL; @@ -46,6 +49,7 @@ static OSSL_FUNC_core_vset_error_fn *c_vset_error; /* Tell the core what params we provide and what type they are */ static const OSSL_PARAM p_param_types[] = { { "greeting", OSSL_PARAM_UTF8_STRING, NULL, 0, 0 }, + { "digest-check", OSSL_PARAM_UNSIGNED_INTEGER, NULL, 0, 0}, { NULL, 0, NULL, 0, 0 } }; @@ -109,6 +113,36 @@ static int p_get_params(void *provctx, OSSL_PARAM params[]) strcpy(p->data, buf); else ok = 0; + } else if (strcmp(p->key, "digest-check") == 0) { + unsigned int digestsuccess = 0; + + /* + * Test we can use an algorithm from another provider. We're using + * legacy to check that legacy is actually available and we haven't + * just fallen back to default. + */ +#ifdef PROVIDER_INIT_FUNCTION_NAME + EVP_MD *md4 = EVP_MD_fetch(ctx->libctx, "MD4", NULL); + EVP_MD_CTX *mdctx = EVP_MD_CTX_new(); + const char *msg = "Hello world"; + unsigned char out[16]; + + if (md4 != NULL && mdctx != NULL) { + if (EVP_DigestInit_ex(mdctx, md4, NULL) + && EVP_DigestUpdate(mdctx, (const unsigned char *)msg, + strlen(msg)) + &&EVP_DigestFinal(mdctx, out, NULL)) + digestsuccess = 1; + } + EVP_MD_CTX_free(mdctx); + EVP_MD_free(md4); +#endif + if (p->data_size >= sizeof(digestsuccess)) { + *(unsigned int *)p->data = digestsuccess; + p->return_size = sizeof(digestsuccess); + } else { + ok = 0; + } } } return ok; @@ -146,11 +180,12 @@ static const OSSL_DISPATCH p_test_table[] = { }; int OSSL_provider_init(const OSSL_CORE_HANDLE *handle, - const OSSL_DISPATCH *in, + const OSSL_DISPATCH *oin, const OSSL_DISPATCH **out, void **provctx) { P_TEST_CTX *ctx; + const OSSL_DISPATCH *in = oin; for (; in->function_id != 0; in++) { switch (in->function_id) { @@ -191,6 +226,14 @@ int OSSL_provider_init(const OSSL_CORE_HANDLE *handle, ctx->thisfile = strdup(OPENSSL_FILE); ctx->thisfunc = strdup(OPENSSL_FUNC); ctx->handle = handle; +#ifdef PROVIDER_INIT_FUNCTION_NAME + /* We only do this if we are linked with libcrypto */ + ctx->libctx = OSSL_LIB_CTX_new_child(handle, oin); + if (ctx->libctx == NULL) { + p_teardown(ctx); + return 0; + } +#endif /* * Set a spurious error to check error handling works correctly. This will @@ -207,6 +250,9 @@ static void p_teardown(void *provctx) { P_TEST_CTX *ctx = (P_TEST_CTX *)provctx; +#ifdef PROVIDER_INIT_FUNCTION_NAME + OSSL_LIB_CTX_free(ctx->libctx); +#endif free(ctx->thisfile); free(ctx->thisfunc); free(ctx); diff --git a/test/provider_test.c b/test/provider_test.c index d89611b9b280e..0abf55e33d65b 100644 --- a/test/provider_test.c +++ b/test/provider_test.c @@ -19,7 +19,15 @@ static OSSL_PARAM greeting_request[] = { { NULL, 0, NULL, 0, 0 } }; -static int test_provider(OSSL_LIB_CTX **libctx, const char *name) +static unsigned int digestsuccess = 0; +static OSSL_PARAM digest_check[] = { + { "digest-check", OSSL_PARAM_UNSIGNED_INTEGER, &digestsuccess, + sizeof(digestsuccess) }, + { NULL, 0, NULL, 0, 0 } +}; + +static int test_provider(OSSL_LIB_CTX **libctx, const char *name, + OSSL_PROVIDER *legacy) { OSSL_PROVIDER *prov = NULL; const char *greeting = NULL; @@ -31,8 +39,14 @@ static int test_provider(OSSL_LIB_CTX **libctx, const char *name) "Hello OpenSSL %.20s, greetings from %s!", OPENSSL_VERSION_STR, name); - if (!TEST_ptr(prov = OSSL_PROVIDER_load(*libctx, name)) - || !TEST_true(OSSL_PROVIDER_get_params(prov, greeting_request)) + if (!TEST_ptr(prov = OSSL_PROVIDER_load(*libctx, name))) + goto err; + if (legacy != NULL) { + if (!TEST_true(OSSL_PROVIDER_get_params(prov, digest_check)) + || !TEST_true(digestsuccess)) + goto err; + } + if (!TEST_true(OSSL_PROVIDER_get_params(prov, greeting_request)) || !TEST_ptr(greeting = greeting_request[0].data) || !TEST_size_t_gt(greeting_request[0].data_size, 0) || !TEST_str_eq(greeting, expected_greeting) @@ -40,6 +54,8 @@ static int test_provider(OSSL_LIB_CTX **libctx, const char *name) goto err; prov = NULL; + OSSL_PROVIDER_unload(legacy); + legacy = NULL; /* * We must free the libctx to force the provider to really be unloaded from @@ -58,6 +74,8 @@ static int test_provider(OSSL_LIB_CTX **libctx, const char *name) ERR_print_errors_fp(stderr); ok = 1; err: + OSSL_PROVIDER_unload(legacy); + legacy = NULL; OSSL_PROVIDER_unload(prov); OSSL_LIB_CTX_free(*libctx); *libctx = NULL; @@ -74,13 +92,39 @@ static int test_builtin_provider(void) TEST_ptr(libctx) && TEST_true(OSSL_PROVIDER_add_builtin(libctx, name, PROVIDER_INIT_FUNCTION_NAME)) - && test_provider(&libctx, name); + && test_provider(&libctx, name, NULL); OSSL_LIB_CTX_free(libctx); return ok; } +static int test_builtin_provider_with_child(void) +{ + OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new(); + const char *name = "p_test"; + OSSL_PROVIDER *legacy; + + if (!TEST_ptr(libctx)) + return 0; + + legacy = OSSL_PROVIDER_load(libctx, "legacy"); + if (legacy == NULL) { + /* + * In this case we assume we've been built with "no-legacy" and skip + * this test (there is no OPENSSL_NO_LEGACY) + */ + return 1; + } + + if (!TEST_true(OSSL_PROVIDER_add_builtin(libctx, name, + PROVIDER_INIT_FUNCTION_NAME))) + return 0; + + /* test_provider will free libctx and unload legacy as part of the test */ + return test_provider(&libctx, name, legacy); +} + #ifndef NO_PROVIDER_MODULE static int test_loaded_provider(void) { @@ -91,15 +135,52 @@ static int test_loaded_provider(void) return 0; /* test_provider will free libctx as part of the test */ - return test_provider(&libctx, name); + return test_provider(&libctx, name, NULL); } #endif +typedef enum OPTION_choice { + OPT_ERR = -1, + OPT_EOF = 0, + OPT_LOADED, + OPT_TEST_ENUM +} OPTION_CHOICE; + +const OPTIONS *test_get_options(void) +{ + static const OPTIONS test_options[] = { + OPT_TEST_OPTIONS_DEFAULT_USAGE, + { "loaded", OPT_LOADED, '-', "Run test with a loaded provider" }, + { NULL } + }; + return test_options; +} + int setup_tests(void) { - ADD_TEST(test_builtin_provider); + OPTION_CHOICE o; + int loaded = 0; + + while ((o = opt_next()) != OPT_EOF) { + switch (o) { + case OPT_TEST_CASES: + break; + case OPT_LOADED: + loaded = 1; + break; + default: + return 0; + } + } + + if (!loaded) { + ADD_TEST(test_builtin_provider); + ADD_TEST(test_builtin_provider_with_child); + } #ifndef NO_PROVIDER_MODULE - ADD_TEST(test_loaded_provider); + else { + ADD_TEST(test_loaded_provider); + } #endif return 1; } diff --git a/test/recipes/04-test_provider.t b/test/recipes/04-test_provider.t index 9195a424cd2ef..44274f8f077df 100644 --- a/test/recipes/04-test_provider.t +++ b/test/recipes/04-test_provider.t @@ -8,11 +8,14 @@ use strict; use OpenSSL::Test qw(:DEFAULT bldtop_dir); -use OpenSSL::Test::Simple; use OpenSSL::Test::Utils; setup("test_provider"); +plan tests => 2; + +ok(run(test(['provider_test'])), "provider_test"); + $ENV{"OPENSSL_MODULES"} = bldtop_dir("test"); -simple_test("test_provider", "provider_test"); +ok(run(test(['provider_test', '-loaded'])), "provider_test -loaded");