#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;
/* 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 }
};
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;
};
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) {
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
{
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);
{ 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;
"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)
goto err;
prov = NULL;
+ OSSL_PROVIDER_unload(legacy);
+ legacy = NULL;
/*
* We must free the libctx to force the provider to really be unloaded from
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;
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)
{
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;
}