/*
- * Copyright 2019 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_numbers.h>
+#include <openssl/core_dispatch.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/crypto.h>
+#include <openssl/provider.h>
-static OSSL_core_get_param_types_fn *c_get_param_types = NULL;
-static OSSL_core_get_params_fn *c_get_params = NULL;
+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 }
};
/* This is a trick to ensure we define the provider functions correctly */
-static OSSL_provider_get_param_types_fn p_get_param_types;
-static OSSL_provider_get_params_fn p_get_params;
+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_get_param_types(void *_)
+static const OSSL_PARAM *p_gettable_params(void *_)
{
return p_param_types;
}
-static int p_get_params(void *vprov, OSSL_PARAM params[])
+static int p_get_params(void *provctx, OSSL_PARAM params[])
{
- const OSSL_PROVIDER *prov = vprov;
+ P_TEST_CTX *ctx = (P_TEST_CTX *)provctx;
+ const OSSL_CORE_HANDLE *hand = ctx->handle;
OSSL_PARAM *p = params;
int ok = 1;
opensslv = provname = greeting = NULL;
- if (c_get_params(prov, counter_request)) {
+ if (c_get_params(hand, counter_request)) {
if (greeting) {
strcpy(buf, greeting);
} else {
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 *p_get_reason_strings(void *_)
+{
+ 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}
+ };
+
+ return reason_strings;
+}
+
static const OSSL_DISPATCH p_test_table[] = {
- { OSSL_FUNC_PROVIDER_GET_PARAM_TYPES, (void (*)(void))p_get_param_types },
+ { OSSL_FUNC_PROVIDER_GETTABLE_PARAMS, (void (*)(void))p_gettable_params },
{ 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_PROVIDER *provider,
- const OSSL_DISPATCH *in,
+int OSSL_provider_init(const OSSL_CORE_HANDLE *handle,
+ 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_GET_PARAM_TYPES:
- c_get_param_types = OSSL_get_core_get_param_types(in);
+ case OSSL_FUNC_CORE_GETTABLE_PARAMS:
+ c_gettable_params = OSSL_FUNC_core_gettable_params(in);
break;
case OSSL_FUNC_CORE_GET_PARAMS:
- c_get_params = OSSL_get_core_get_params(in);
+ 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 */
}
}
- /* Because we use this in get_params, we need to pass it back */
- *provctx = (void *)provider;
+ /*
+ * 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);
+}