/*
- * Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2019-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
# define OSSL_provider_init PROVIDER_INIT_FUNCTION_NAME
#endif
+#include "e_os.h"
#include <openssl/core.h>
#include <openssl/core_dispatch.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/crypto.h>
+#include <openssl/provider.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;
static OSSL_FUNC_core_get_params_fn *c_get_params = NULL;
+static OSSL_FUNC_core_new_error_fn *c_new_error;
+static OSSL_FUNC_core_set_error_debug_fn *c_set_error_debug;
+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 }
};
static OSSL_FUNC_provider_gettable_params_fn p_gettable_params;
static OSSL_FUNC_provider_get_params_fn p_get_params;
static OSSL_FUNC_provider_get_reason_strings_fn p_get_reason_strings;
+static OSSL_FUNC_provider_teardown_fn p_teardown;
+
+static void p_set_error(int lib, int reason, const char *file, int line,
+ const char *func, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ c_new_error(NULL);
+ c_set_error_debug(NULL, file, line, func);
+ c_vset_error(NULL, ERR_PACK(lib, 0, reason), fmt, ap);
+ va_end(ap);
+}
static const OSSL_PARAM *p_gettable_params(void *_)
{
return p_param_types;
}
-static int p_get_params(void *vhand, OSSL_PARAM params[])
+static int p_get_params(void *provctx, OSSL_PARAM params[])
{
- const OSSL_CORE_HANDLE *hand = vhand;
+ P_TEST_CTX *ctx = (P_TEST_CTX *)provctx;
+ const OSSL_CORE_HANDLE *hand = ctx->handle;
OSSL_PARAM *p = params;
int ok = 1;
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];
+ OSSL_PROVIDER *deflt;
+
+ /*
+ * "default" has not been loaded into the parent libctx. We should be able
+ * to explicitly load it as a non-child provider.
+ */
+ deflt = OSSL_PROVIDER_load(ctx->libctx, "default");
+ if (deflt == NULL
+ || !OSSL_PROVIDER_available(ctx->libctx, "default")) {
+ /* We set error "3" for a failure to load the default provider */
+ p_set_error(ERR_LIB_PROV, 3, ctx->thisfile, OPENSSL_LINE,
+ ctx->thisfunc, NULL);
+ ok = 0;
+ }
+
+ /*
+ * We should have the default provider available that we loaded
+ * ourselves, and the base and legacy providers which we inherit
+ * from the parent libctx. We should also have "this" provider
+ * available.
+ */
+ if (ok
+ && OSSL_PROVIDER_available(ctx->libctx, "default")
+ && OSSL_PROVIDER_available(ctx->libctx, "base")
+ && OSSL_PROVIDER_available(ctx->libctx, "legacy")
+ && OSSL_PROVIDER_available(ctx->libctx, "p_test")
+ && 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);
+ OSSL_PROVIDER_unload(deflt);
+#endif
+ if (p->data_size >= sizeof(digestsuccess)) {
+ *(unsigned int *)p->data = digestsuccess;
+ p->return_size = sizeof(digestsuccess);
+ } else {
+ ok = 0;
+ }
}
}
return ok;
{
static const OSSL_ITEM reason_strings[] = {
{1, "dummy reason string"},
+ {2, "Can't create child library context"},
+ {3, "Can't load default provider"},
{0, NULL}
};
{ OSSL_FUNC_PROVIDER_GET_PARAMS, (void (*)(void))p_get_params },
{ OSSL_FUNC_PROVIDER_GET_REASON_STRINGS,
(void (*)(void))p_get_reason_strings},
+ { OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))p_teardown },
{ 0, NULL }
};
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) {
case OSSL_FUNC_CORE_GETTABLE_PARAMS:
case OSSL_FUNC_CORE_GET_PARAMS:
c_get_params = OSSL_FUNC_core_get_params(in);
break;
+ case OSSL_FUNC_CORE_NEW_ERROR:
+ c_new_error = OSSL_FUNC_core_new_error(in);
+ break;
+ case OSSL_FUNC_CORE_SET_ERROR_DEBUG:
+ c_set_error_debug = OSSL_FUNC_core_set_error_debug(in);
+ break;
+ case OSSL_FUNC_CORE_VSET_ERROR:
+ c_vset_error = OSSL_FUNC_core_vset_error(in);
+ break;
default:
/* Just ignore anything we don't understand */
break;
}
}
- /* Because we use this in get_params, we need to pass it back */
- *provctx = (void *)handle;
+ /*
+ * We want to test that libcrypto doesn't use the file and func pointers
+ * that we provide to it via c_set_error_debug beyond the time that they
+ * are valid for. Therefore we dynamically allocate these strings now and
+ * free them again when the provider is torn down. If anything tries to
+ * use those strings after that point there will be a use-after-free and
+ * asan will complain (and hence the tests will fail).
+ * This file isn't linked against libcrypto, so we use malloc and strdup
+ * instead of OPENSSL_malloc and OPENSSL_strdup
+ */
+ ctx = malloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return 0;
+ 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) {
+ /* We set error "2" for a failure to create the child libctx*/
+ p_set_error(ERR_LIB_PROV, 2, ctx->thisfile, OPENSSL_LINE, ctx->thisfunc,
+ NULL);
+ p_teardown(ctx);
+ return 0;
+ }
+#endif
+ /*
+ * Set a spurious error to check error handling works correctly. This will
+ * be ignored
+ */
+ p_set_error(ERR_LIB_PROV, 1, ctx->thisfile, OPENSSL_LINE, ctx->thisfunc, NULL);
+
+ *provctx = (void *)ctx;
*out = p_test_table;
return 1;
}
+
+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);
+}