Skip to content

Commit

Permalink
Add a test for OSSL_LIB_CTX_new_child()
Browse files Browse the repository at this point in the history
Check that we can create such a libctx and usable providers are loaded
into it.

Reviewed-by: Paul Dale <[email protected]>
(Merged from openssl#14991)
  • Loading branch information
mattcaswell committed May 11, 2021
1 parent d0efad4 commit 5442611
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 10 deletions.
48 changes: 47 additions & 1 deletion test/p_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,14 @@
#include <openssl/core.h>
#include <openssl/core_dispatch.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/crypto.h>

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;
Expand All @@ -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 }
};

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand Down
95 changes: 88 additions & 7 deletions test/provider_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -31,15 +39,23 @@ 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)
|| !TEST_true(OSSL_PROVIDER_unload(prov)))
goto err;

prov = NULL;
OSSL_PROVIDER_unload(legacy);
legacy = NULL;

/*
* We must free the libctx to force the provider to really be unloaded from
Expand All @@ -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;
Expand All @@ -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)
{
Expand All @@ -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;
}
Expand Down
7 changes: 5 additions & 2 deletions test/recipes/04-test_provider.t
Original file line number Diff line number Diff line change
Expand Up @@ -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");

0 comments on commit 5442611

Please sign in to comment.