aboutsummaryrefslogtreecommitdiff
path: root/test/testutil
diff options
context:
space:
mode:
Diffstat (limited to 'test/testutil')
-rw-r--r--test/testutil/apps_shims.c56
-rw-r--r--test/testutil/basic_output.c102
-rw-r--r--test/testutil/cb.c16
-rw-r--r--test/testutil/driver.c473
-rw-r--r--test/testutil/fake_random.c231
-rw-r--r--test/testutil/format_output.c535
-rw-r--r--test/testutil/load.c105
-rw-r--r--test/testutil/main.c41
-rw-r--r--test/testutil/options.c79
-rw-r--r--test/testutil/output.c58
-rw-r--r--test/testutil/output.h68
-rw-r--r--test/testutil/provider.c242
-rw-r--r--test/testutil/random.c40
-rw-r--r--test/testutil/stanza.c159
-rw-r--r--test/testutil/test_cleanup.c14
-rw-r--r--test/testutil/test_options.c21
-rw-r--r--test/testutil/tests.c472
-rw-r--r--test/testutil/testutil_init.c145
-rw-r--r--test/testutil/tu_local.h61
19 files changed, 2918 insertions, 0 deletions
diff --git a/test/testutil/apps_shims.c b/test/testutil/apps_shims.c
new file mode 100644
index 000000000000..53d851ffda3b
--- /dev/null
+++ b/test/testutil/apps_shims.c
@@ -0,0 +1,56 @@
+/*
+ * 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdlib.h>
+#include "apps.h"
+#include "../testutil.h"
+
+/* shim that avoids sucking in too much from apps/apps.c */
+
+void *app_malloc(size_t sz, const char *what)
+{
+ void *vp;
+
+ /*
+ * This isn't ideal but it is what the app's app_malloc() does on failure.
+ * Instead of exiting with a failure, abort() is called which makes sure
+ * that there will be a good stack trace for debugging purposes.
+ */
+ if (!TEST_ptr(vp = OPENSSL_malloc(sz))) {
+ TEST_info("Could not allocate %zu bytes for %s\n", sz, what);
+ abort();
+ }
+ return vp;
+}
+
+/* shim to prevent sucking in too much from apps */
+
+int opt_legacy_okay(void)
+{
+ return 1;
+}
+
+/*
+ * These three functions are defined here so that they don't need to come from
+ * the apps source code and pull in a lot of additional things.
+ */
+int opt_provider_option_given(void)
+{
+ return 0;
+}
+
+const char *app_get0_propq(void)
+{
+ return NULL;
+}
+
+OSSL_LIB_CTX *app_get0_libctx(void)
+{
+ return NULL;
+}
diff --git a/test/testutil/basic_output.c b/test/testutil/basic_output.c
new file mode 100644
index 000000000000..92f3de9300cc
--- /dev/null
+++ b/test/testutil/basic_output.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2017-2020 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "../testutil.h"
+#include "output.h"
+#include "tu_local.h"
+
+#include <openssl/crypto.h>
+#include <openssl/bio.h>
+
+/* These are available for any test program */
+BIO *bio_out = NULL;
+BIO *bio_err = NULL;
+
+/* These are available for TAP output only (internally) */
+static BIO *tap_out = NULL;
+static BIO *tap_err = NULL;
+
+void test_open_streams(void)
+{
+ tap_out = BIO_new_fp(stdout, BIO_NOCLOSE | BIO_FP_TEXT);
+ tap_err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT);
+#ifdef __VMS
+ tap_out = BIO_push(BIO_new(BIO_f_linebuffer()), tap_out);
+ tap_err = BIO_push(BIO_new(BIO_f_linebuffer()), tap_err);
+#endif
+ tap_out = BIO_push(BIO_new(BIO_f_prefix()), tap_out);
+ tap_err = BIO_push(BIO_new(BIO_f_prefix()), tap_err);
+
+ bio_out = BIO_push(BIO_new(BIO_f_prefix()), tap_out);
+ bio_err = BIO_push(BIO_new(BIO_f_prefix()), tap_err);
+ BIO_set_prefix(bio_out, "# ");
+ BIO_set_prefix(bio_err, "# ");
+
+ OPENSSL_assert(bio_out != NULL);
+ OPENSSL_assert(bio_err != NULL);
+}
+
+void test_adjust_streams_tap_level(int level)
+{
+ BIO_set_indent(tap_out, level);
+ BIO_set_indent(tap_err, level);
+}
+
+void test_close_streams(void)
+{
+ /*
+ * The rest of the chain is freed by the BIO_free_all() calls below, so
+ * we only need to free the last one in the bio_out and bio_err chains.
+ */
+ BIO_free(bio_out);
+ BIO_free(bio_err);
+
+ BIO_free_all(tap_out);
+ BIO_free_all(tap_err);
+}
+
+int test_vprintf_stdout(const char *fmt, va_list ap)
+{
+ return BIO_vprintf(bio_out, fmt, ap);
+}
+
+int test_vprintf_stderr(const char *fmt, va_list ap)
+{
+ return BIO_vprintf(bio_err, fmt, ap);
+}
+
+int test_flush_stdout(void)
+{
+ return BIO_flush(bio_out);
+}
+
+int test_flush_stderr(void)
+{
+ return BIO_flush(bio_err);
+}
+
+int test_vprintf_tapout(const char *fmt, va_list ap)
+{
+ return BIO_vprintf(tap_out, fmt, ap);
+}
+
+int test_vprintf_taperr(const char *fmt, va_list ap)
+{
+ return BIO_vprintf(tap_err, fmt, ap);
+}
+
+int test_flush_tapout(void)
+{
+ return BIO_flush(tap_out);
+}
+
+int test_flush_taperr(void)
+{
+ return BIO_flush(tap_err);
+}
diff --git a/test/testutil/cb.c b/test/testutil/cb.c
new file mode 100644
index 000000000000..5b583b147b53
--- /dev/null
+++ b/test/testutil/cb.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2017 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "output.h"
+#include "tu_local.h"
+
+int openssl_error_cb(const char *str, size_t len, void *u)
+{
+ return test_printf_stderr("%s", str);
+}
diff --git a/test/testutil/driver.c b/test/testutil/driver.c
new file mode 100644
index 000000000000..9a4b762f4169
--- /dev/null
+++ b/test/testutil/driver.c
@@ -0,0 +1,473 @@
+/*
+ * Copyright 2016-2022 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "../testutil.h"
+#include "output.h"
+#include "tu_local.h"
+
+#include <string.h>
+#include <assert.h>
+
+#include "internal/nelem.h"
+#include <openssl/bio.h>
+
+#include "platform.h" /* From libapps */
+
+#if defined(_WIN32) && !defined(__BORLANDC__)
+# define strdup _strdup
+#endif
+
+
+/*
+ * Declares the structures needed to register each test case function.
+ */
+typedef struct test_info {
+ const char *test_case_name;
+ int (*test_fn) (void);
+ int (*param_test_fn)(int idx);
+ int num;
+
+ /* flags */
+ int subtest:1;
+} TEST_INFO;
+
+static TEST_INFO all_tests[1024];
+static int num_tests = 0;
+static int show_list = 0;
+static int single_test = -1;
+static int single_iter = -1;
+static int level = 0;
+static int seed = 0;
+static int rand_order = 0;
+
+/*
+ * A parameterised test runs a loop of test cases.
+ * |num_test_cases| counts the total number of non-subtest test cases
+ * across all tests.
+ */
+static int num_test_cases = 0;
+
+static int process_shared_options(void);
+
+
+void add_test(const char *test_case_name, int (*test_fn) (void))
+{
+ assert(num_tests != OSSL_NELEM(all_tests));
+ all_tests[num_tests].test_case_name = test_case_name;
+ all_tests[num_tests].test_fn = test_fn;
+ all_tests[num_tests].num = -1;
+ ++num_tests;
+ ++num_test_cases;
+}
+
+void add_all_tests(const char *test_case_name, int(*test_fn)(int idx),
+ int num, int subtest)
+{
+ assert(num_tests != OSSL_NELEM(all_tests));
+ all_tests[num_tests].test_case_name = test_case_name;
+ all_tests[num_tests].param_test_fn = test_fn;
+ all_tests[num_tests].num = num;
+ all_tests[num_tests].subtest = subtest;
+ ++num_tests;
+ if (subtest)
+ ++num_test_cases;
+ else
+ num_test_cases += num;
+}
+
+static int gcd(int a, int b)
+{
+ while (b != 0) {
+ int t = b;
+ b = a % b;
+ a = t;
+ }
+ return a;
+}
+
+static void set_seed(int s)
+{
+ seed = s;
+ if (seed <= 0)
+ seed = (int)time(NULL);
+ test_random_seed(seed);
+}
+
+
+int setup_test_framework(int argc, char *argv[])
+{
+ char *test_seed = getenv("OPENSSL_TEST_RAND_ORDER");
+ char *TAP_levels = getenv("HARNESS_OSSL_LEVEL");
+
+ if (TAP_levels != NULL)
+ level = 4 * atoi(TAP_levels);
+ test_adjust_streams_tap_level(level);
+ if (test_seed != NULL) {
+ rand_order = 1;
+ set_seed(atoi(test_seed));
+ } else {
+ set_seed(0);
+ }
+
+#if defined(OPENSSL_SYS_VMS) && defined(__DECC)
+ argv = copy_argv(&argc, argv);
+#elif defined(_WIN32)
+ /*
+ * Replace argv[] with UTF-8 encoded strings.
+ */
+ win32_utf8argv(&argc, &argv);
+#endif
+
+ if (!opt_init(argc, argv, test_get_options()))
+ return 0;
+ return 1;
+}
+
+
+/*
+ * This can only be called after setup() has run, since num_tests and
+ * all_tests[] are setup at this point
+ */
+static int check_single_test_params(char *name, char *testname, char *itname)
+{
+ if (name != NULL) {
+ int i;
+ for (i = 0; i < num_tests; ++i) {
+ if (strcmp(name, all_tests[i].test_case_name) == 0) {
+ single_test = 1 + i;
+ break;
+ }
+ }
+ if (i >= num_tests)
+ single_test = atoi(name);
+ }
+
+
+ /* if only iteration is specified, assume we want the first test */
+ if (single_test == -1 && single_iter != -1)
+ single_test = 1;
+
+ if (single_test != -1) {
+ if (single_test < 1 || single_test > num_tests) {
+ test_printf_stderr("Invalid -%s value "
+ "(Value must be a valid test name OR a value between %d..%d)\n",
+ testname, 1, num_tests);
+ return 0;
+ }
+ }
+ if (single_iter != -1) {
+ if (all_tests[single_test - 1].num == -1) {
+ test_printf_stderr("-%s option is not valid for test %d:%s\n",
+ itname,
+ single_test,
+ all_tests[single_test - 1].test_case_name);
+ return 0;
+ } else if (single_iter < 1
+ || single_iter > all_tests[single_test - 1].num) {
+ test_printf_stderr("Invalid -%s value for test %d:%s\t"
+ "(Value must be in the range %d..%d)\n",
+ itname, single_test,
+ all_tests[single_test - 1].test_case_name,
+ 1, all_tests[single_test - 1].num);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int process_shared_options(void)
+{
+ OPTION_CHOICE_DEFAULT o;
+ int value;
+ int ret = -1;
+ char *flag_test = "";
+ char *flag_iter = "";
+ char *testname = NULL;
+
+ opt_begin();
+ while ((o = opt_next()) != OPT_EOF) {
+ switch (o) {
+ /* Ignore any test options at this level */
+ default:
+ break;
+ case OPT_ERR:
+ return ret;
+ case OPT_TEST_HELP:
+ opt_help(test_get_options());
+ return 0;
+ case OPT_TEST_LIST:
+ show_list = 1;
+ break;
+ case OPT_TEST_SINGLE:
+ flag_test = opt_flag();
+ testname = opt_arg();
+ break;
+ case OPT_TEST_ITERATION:
+ flag_iter = opt_flag();
+ if (!opt_int(opt_arg(), &single_iter))
+ goto end;
+ break;
+ case OPT_TEST_INDENT:
+ if (!opt_int(opt_arg(), &value))
+ goto end;
+ level = 4 * value;
+ test_adjust_streams_tap_level(level);
+ break;
+ case OPT_TEST_SEED:
+ if (!opt_int(opt_arg(), &value))
+ goto end;
+ set_seed(value);
+ break;
+ }
+ }
+ if (!check_single_test_params(testname, flag_test, flag_iter))
+ goto end;
+ ret = 1;
+end:
+ return ret;
+}
+
+
+int pulldown_test_framework(int ret)
+{
+ set_test_title(NULL);
+ return ret;
+}
+
+static void finalize(int success)
+{
+ if (success)
+ ERR_clear_error();
+ else
+ ERR_print_errors_cb(openssl_error_cb, NULL);
+}
+
+static char *test_title = NULL;
+
+void set_test_title(const char *title)
+{
+ free(test_title);
+ test_title = title == NULL ? NULL : strdup(title);
+}
+
+PRINTF_FORMAT(2, 3) static void test_verdict(int verdict,
+ const char *description, ...)
+{
+ va_list ap;
+
+ test_flush_stdout();
+ test_flush_stderr();
+
+ if (verdict == 0 && seed != 0)
+ test_printf_tapout("# OPENSSL_TEST_RAND_ORDER=%d\n", seed);
+ test_printf_tapout("%s ", verdict != 0 ? "ok" : "not ok");
+ va_start(ap, description);
+ test_vprintf_tapout(description, ap);
+ va_end(ap);
+ if (verdict == TEST_SKIP_CODE)
+ test_printf_tapout(" # skipped");
+ test_printf_tapout("\n");
+ test_flush_tapout();
+}
+
+int run_tests(const char *test_prog_name)
+{
+ int num_failed = 0;
+ int verdict = 1;
+ int ii, i, jj, j, jstep;
+ int test_case_count = 0;
+ int subtest_case_count = 0;
+ int permute[OSSL_NELEM(all_tests)];
+
+ i = process_shared_options();
+ if (i == 0)
+ return EXIT_SUCCESS;
+ if (i == -1)
+ return EXIT_FAILURE;
+
+ if (num_tests < 1) {
+ test_printf_tapout("1..0 # Skipped: %s\n", test_prog_name);
+ } else if (show_list == 0 && single_test == -1) {
+ if (level > 0) {
+ test_printf_stdout("Subtest: %s\n", test_prog_name);
+ test_flush_stdout();
+ }
+ test_printf_tapout("1..%d\n", num_test_cases);
+ }
+
+ test_flush_tapout();
+
+ for (i = 0; i < num_tests; i++)
+ permute[i] = i;
+ if (rand_order != 0)
+ for (i = num_tests - 1; i >= 1; i--) {
+ j = test_random() % (1 + i);
+ ii = permute[j];
+ permute[j] = permute[i];
+ permute[i] = ii;
+ }
+
+ for (ii = 0; ii != num_tests; ++ii) {
+ i = permute[ii];
+
+ if (single_test != -1 && ((i+1) != single_test)) {
+ continue;
+ }
+ else if (show_list) {
+ if (all_tests[i].num != -1) {
+ test_printf_tapout("%d - %s (%d..%d)\n", ii + 1,
+ all_tests[i].test_case_name, 1,
+ all_tests[i].num);
+ } else {
+ test_printf_tapout("%d - %s\n", ii + 1,
+ all_tests[i].test_case_name);
+ }
+ test_flush_tapout();
+ } else if (all_tests[i].num == -1) {
+ set_test_title(all_tests[i].test_case_name);
+ ERR_clear_error();
+ verdict = all_tests[i].test_fn();
+ finalize(verdict != 0);
+ test_verdict(verdict, "%d - %s", test_case_count + 1, test_title);
+ if (verdict == 0)
+ num_failed++;
+ test_case_count++;
+ } else {
+ verdict = TEST_SKIP_CODE;
+ set_test_title(all_tests[i].test_case_name);
+ if (all_tests[i].subtest) {
+ level += 4;
+ test_adjust_streams_tap_level(level);
+ if (single_iter == -1) {
+ test_printf_stdout("Subtest: %s\n", test_title);
+ test_printf_tapout("%d..%d\n", 1, all_tests[i].num);
+ test_flush_stdout();
+ test_flush_tapout();
+ }
+ }
+
+ j = -1;
+ if (rand_order == 0 || all_tests[i].num < 3)
+ jstep = 1;
+ else
+ do
+ jstep = test_random() % all_tests[i].num;
+ while (jstep == 0 || gcd(all_tests[i].num, jstep) != 1);
+
+ for (jj = 0; jj < all_tests[i].num; jj++) {
+ int v;
+
+ j = (j + jstep) % all_tests[i].num;
+ if (single_iter != -1 && ((jj + 1) != single_iter))
+ continue;
+ ERR_clear_error();
+ v = all_tests[i].param_test_fn(j);
+
+ if (v == 0) {
+ verdict = 0;
+ } else if (v != TEST_SKIP_CODE && verdict != 0) {
+ verdict = 1;
+ }
+
+ finalize(v != 0);
+
+ if (all_tests[i].subtest)
+ test_verdict(v, "%d - iteration %d",
+ subtest_case_count + 1, j + 1);
+ else
+ test_verdict(v, "%d - %s - iteration %d",
+ test_case_count + subtest_case_count + 1,
+ test_title, j + 1);
+ subtest_case_count++;
+ }
+
+ if (all_tests[i].subtest) {
+ level -= 4;
+ test_adjust_streams_tap_level(level);
+ }
+ if (verdict == 0)
+ ++num_failed;
+ if (all_tests[i].num == -1 || all_tests[i].subtest)
+ test_verdict(verdict, "%d - %s", test_case_count + 1,
+ all_tests[i].test_case_name);
+ test_case_count++;
+ }
+ }
+ if (num_failed != 0)
+ return EXIT_FAILURE;
+ return EXIT_SUCCESS;
+}
+
+/*
+ * Glue an array of strings together and return it as an allocated string.
+ * Optionally return the whole length of this string in |out_len|
+ */
+char *glue_strings(const char *list[], size_t *out_len)
+{
+ size_t len = 0;
+ char *p, *ret;
+ int i;
+
+ for (i = 0; list[i] != NULL; i++)
+ len += strlen(list[i]);
+
+ if (out_len != NULL)
+ *out_len = len;
+
+ if (!TEST_ptr(ret = p = OPENSSL_malloc(len + 1)))
+ return NULL;
+
+ for (i = 0; list[i] != NULL; i++)
+ p += strlen(strcpy(p, list[i]));
+
+ return ret;
+}
+
+char *test_mk_file_path(const char *dir, const char *file)
+{
+# ifndef OPENSSL_SYS_VMS
+ const char *sep = "/";
+# else
+ const char *sep = "";
+ char *dir_end;
+ char dir_end_sep;
+# endif
+ size_t dirlen = dir != NULL ? strlen(dir) : 0;
+ size_t len = dirlen + strlen(sep) + strlen(file) + 1;
+ char *full_file = OPENSSL_zalloc(len);
+
+ if (full_file != NULL) {
+ if (dir != NULL && dirlen > 0) {
+ OPENSSL_strlcpy(full_file, dir, len);
+# ifdef OPENSSL_SYS_VMS
+ /*
+ * If |file| contains a directory spec, we need to do some
+ * careful merging.
+ * "vol:[dir.dir]" + "[.certs]sm2-root.crt" should become
+ * "vol:[dir.dir.certs]sm2-root.crt"
+ */
+ dir_end = &full_file[strlen(full_file) - 1];
+ dir_end_sep = *dir_end;
+ if ((dir_end_sep == ']' || dir_end_sep == '>')
+ && (file[0] == '[' || file[0] == '<')) {
+ file++;
+ if (file[0] == '.')
+ *dir_end = '\0';
+ else
+ *dir_end = '.';
+ }
+#else
+ OPENSSL_strlcat(full_file, sep, len);
+#endif
+ }
+ OPENSSL_strlcat(full_file, file, len);
+ }
+
+ return full_file;
+}
diff --git a/test/testutil/fake_random.c b/test/testutil/fake_random.c
new file mode 100644
index 000000000000..f2f0e2793f76
--- /dev/null
+++ b/test/testutil/fake_random.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright 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 may obtain a copy of the License at
+ * https://www.openssl.org/source/license.html
+ * or in the file LICENSE in the source distribution.
+ */
+
+#include <string.h>
+#include <openssl/core_names.h>
+#include <openssl/rand.h>
+#include <openssl/provider.h>
+#include "../include/crypto/evp.h"
+#include "../../crypto/evp/evp_local.h"
+#include "../testutil.h"
+
+typedef struct {
+ fake_random_generate_cb *cb;
+ int state;
+ const char *name;
+ EVP_RAND_CTX *ctx;
+} FAKE_RAND;
+
+static OSSL_FUNC_rand_newctx_fn fake_rand_newctx;
+static OSSL_FUNC_rand_freectx_fn fake_rand_freectx;
+static OSSL_FUNC_rand_instantiate_fn fake_rand_instantiate;
+static OSSL_FUNC_rand_uninstantiate_fn fake_rand_uninstantiate;
+static OSSL_FUNC_rand_generate_fn fake_rand_generate;
+static OSSL_FUNC_rand_gettable_ctx_params_fn fake_rand_gettable_ctx_params;
+static OSSL_FUNC_rand_get_ctx_params_fn fake_rand_get_ctx_params;
+static OSSL_FUNC_rand_enable_locking_fn fake_rand_enable_locking;
+
+static void *fake_rand_newctx(void *provctx, void *parent,
+ const OSSL_DISPATCH *parent_dispatch)
+{
+ FAKE_RAND *r = OPENSSL_zalloc(sizeof(*r));
+
+ if (r != NULL)
+ r->state = EVP_RAND_STATE_UNINITIALISED;
+ return r;
+}
+
+static void fake_rand_freectx(void *vrng)
+{
+ OPENSSL_free(vrng);
+}
+
+static int fake_rand_instantiate(void *vrng, ossl_unused unsigned int strength,
+ ossl_unused int prediction_resistance,
+ ossl_unused const unsigned char *pstr,
+ size_t pstr_len,
+ ossl_unused const OSSL_PARAM params[])
+{
+ FAKE_RAND *frng = (FAKE_RAND *)vrng;
+
+ frng->state = EVP_RAND_STATE_READY;
+ return 1;
+}
+
+static int fake_rand_uninstantiate(void *vrng)
+{
+ FAKE_RAND *frng = (FAKE_RAND *)vrng;
+
+ frng->state = EVP_RAND_STATE_UNINITIALISED;
+ return 1;
+}
+
+static int fake_rand_generate(void *vrng, unsigned char *out, size_t outlen,
+ unsigned int strength, int prediction_resistance,
+ const unsigned char *adin, size_t adinlen)
+{
+ FAKE_RAND *frng = (FAKE_RAND *)vrng;
+ size_t l;
+ uint32_t r;
+
+ if (frng->cb != NULL)
+ return (*frng->cb)(out, outlen, frng->name, frng->ctx);
+ while (outlen > 0) {
+ r = test_random();
+ l = outlen < sizeof(r) ? outlen : sizeof(r);
+
+ memcpy(out, &r, l);
+ out += l;
+ outlen -= l;
+ }
+ return 1;
+}
+
+static int fake_rand_enable_locking(void *vrng)
+{
+ return 1;
+}
+
+static int fake_rand_get_ctx_params(ossl_unused void *vrng, OSSL_PARAM params[])
+{
+ FAKE_RAND *frng = (FAKE_RAND *)vrng;
+ OSSL_PARAM *p;
+
+ p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STATE);
+ if (p != NULL && !OSSL_PARAM_set_int(p, frng->state))
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_STRENGTH);
+ if (p != NULL && !OSSL_PARAM_set_int(p, 256))
+ return 0;
+
+ p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MAX_REQUEST);
+ if (p != NULL && !OSSL_PARAM_set_size_t(p, INT_MAX))
+ return 0;
+ return 1;
+}
+
+static const OSSL_PARAM *fake_rand_gettable_ctx_params(ossl_unused void *vrng,
+ ossl_unused void *provctx)
+{
+ static const OSSL_PARAM known_gettable_ctx_params[] = {
+ OSSL_PARAM_int(OSSL_RAND_PARAM_STATE, NULL),
+ OSSL_PARAM_uint(OSSL_RAND_PARAM_STRENGTH, NULL),
+ OSSL_PARAM_size_t(OSSL_RAND_PARAM_MAX_REQUEST, NULL),
+ OSSL_PARAM_END
+ };
+ return known_gettable_ctx_params;
+}
+
+static const OSSL_DISPATCH fake_rand_functions[] = {
+ { OSSL_FUNC_RAND_NEWCTX, (void (*)(void))fake_rand_newctx },
+ { OSSL_FUNC_RAND_FREECTX, (void (*)(void))fake_rand_freectx },
+ { OSSL_FUNC_RAND_INSTANTIATE, (void (*)(void))fake_rand_instantiate },
+ { OSSL_FUNC_RAND_UNINSTANTIATE, (void (*)(void))fake_rand_uninstantiate },
+ { OSSL_FUNC_RAND_GENERATE, (void (*)(void))fake_rand_generate },
+ { OSSL_FUNC_RAND_ENABLE_LOCKING, (void (*)(void))fake_rand_enable_locking },
+ { OSSL_FUNC_RAND_GETTABLE_CTX_PARAMS,
+ (void(*)(void))fake_rand_gettable_ctx_params },
+ { OSSL_FUNC_RAND_GET_CTX_PARAMS, (void(*)(void))fake_rand_get_ctx_params },
+ { 0, NULL }
+};
+
+static const OSSL_ALGORITHM fake_rand_rand[] = {
+ { "FAKE", "provider=fake", fake_rand_functions },
+ { NULL, NULL, NULL }
+};
+
+static const OSSL_ALGORITHM *fake_rand_query(void *provctx,
+ int operation_id,
+ int *no_cache)
+{
+ *no_cache = 0;
+ switch (operation_id) {
+ case OSSL_OP_RAND:
+ return fake_rand_rand;
+ }
+ return NULL;
+}
+
+/* Functions we provide to the core */
+static const OSSL_DISPATCH fake_rand_method[] = {
+ { OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))OSSL_LIB_CTX_free },
+ { OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))fake_rand_query },
+ { 0, NULL }
+};
+
+static int fake_rand_provider_init(const OSSL_CORE_HANDLE *handle,
+ const OSSL_DISPATCH *in,
+ const OSSL_DISPATCH **out, void **provctx)
+{
+ if (!TEST_ptr(*provctx = OSSL_LIB_CTX_new()))
+ return 0;
+ *out = fake_rand_method;
+ return 1;
+}
+
+static int check_rng(EVP_RAND_CTX *rng, const char *name)
+{
+ FAKE_RAND *f;
+
+ if (!TEST_ptr(rng)) {
+ TEST_info("random: %s", name);
+ return 0;
+ }
+ f = rng->algctx;
+ f->name = name;
+ f->ctx = rng;
+ return 1;
+}
+
+OSSL_PROVIDER *fake_rand_start(OSSL_LIB_CTX *libctx)
+{
+ OSSL_PROVIDER *p;
+
+ if (!TEST_true(OSSL_PROVIDER_add_builtin(libctx, "fake-rand",
+ fake_rand_provider_init))
+ || !TEST_true(RAND_set_DRBG_type(libctx, "fake", NULL, NULL, NULL))
+ || !TEST_ptr(p = OSSL_PROVIDER_try_load(libctx, "fake-rand", 1)))
+ return NULL;
+
+ /* Ensure that the fake rand is initialized. */
+ if (!TEST_true(check_rng(RAND_get0_primary(libctx), "primary"))
+ || !TEST_true(check_rng(RAND_get0_private(libctx), "private"))
+ || !TEST_true(check_rng(RAND_get0_public(libctx), "public"))) {
+ OSSL_PROVIDER_unload(p);
+ return NULL;
+ }
+
+ return p;
+}
+
+void fake_rand_finish(OSSL_PROVIDER *p)
+{
+ OSSL_PROVIDER_unload(p);
+}
+
+void fake_rand_set_callback(EVP_RAND_CTX *rng,
+ int (*cb)(unsigned char *out, size_t outlen,
+ const char *name, EVP_RAND_CTX *ctx))
+{
+ if (rng != NULL)
+ ((FAKE_RAND *)rng->algctx)->cb = cb;
+}
+
+void fake_rand_set_public_private_callbacks(OSSL_LIB_CTX *libctx,
+ int (*cb)(unsigned char *out,
+ size_t outlen,
+ const char *name,
+ EVP_RAND_CTX *ctx))
+{
+ fake_rand_set_callback(RAND_get0_private(libctx), cb);
+ fake_rand_set_callback(RAND_get0_public(libctx), cb);
+}
+
diff --git a/test/testutil/format_output.c b/test/testutil/format_output.c
new file mode 100644
index 000000000000..e101a7ecefb1
--- /dev/null
+++ b/test/testutil/format_output.c
@@ -0,0 +1,535 @@
+/*
+ * Copyright 2017-2020 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "../testutil.h"
+#include "output.h"
+#include "tu_local.h"
+
+#include <string.h>
+#include <ctype.h>
+#include "internal/nelem.h"
+
+/* The size of memory buffers to display on failure */
+#define MEM_BUFFER_SIZE (2000)
+#define MAX_STRING_WIDTH (80)
+#define BN_OUTPUT_SIZE (8)
+
+/* Output a diff header */
+static void test_diff_header(const char *left, const char *right)
+{
+ test_printf_stderr("--- %s\n", left);
+ test_printf_stderr("+++ %s\n", right);
+}
+
+/* Formatted string output routines */
+static void test_string_null_empty(const char *m, char c)
+{
+ if (m == NULL)
+ test_printf_stderr("%4s %c NULL\n", "", c);
+ else
+ test_printf_stderr("%4u:%c ''\n", 0u, c);
+}
+
+static void test_fail_string_common(const char *prefix, const char *file,
+ int line, const char *type,
+ const char *left, const char *right,
+ const char *op, const char *m1, size_t l1,
+ const char *m2, size_t l2)
+{
+ const size_t width =
+ (MAX_STRING_WIDTH - BIO_get_indent(bio_err) - 12) / 16 * 16;
+ char b1[MAX_STRING_WIDTH + 1], b2[MAX_STRING_WIDTH + 1];
+ char bdiff[MAX_STRING_WIDTH + 1];
+ size_t n1, n2, i;
+ unsigned int cnt = 0, diff;
+
+ test_fail_message_prefix(prefix, file, line, type, left, right, op);
+ if (m1 == NULL)
+ l1 = 0;
+ if (m2 == NULL)
+ l2 = 0;
+ if (l1 == 0 && l2 == 0) {
+ if ((m1 == NULL) == (m2 == NULL)) {
+ test_string_null_empty(m1, ' ');
+ } else {
+ test_diff_header(left, right);
+ test_string_null_empty(m1, '-');
+ test_string_null_empty(m2, '+');
+ }
+ goto fin;
+ }
+
+ if (l1 != l2 || strncmp(m1, m2, l1) != 0)
+ test_diff_header(left, right);
+
+ while (l1 > 0 || l2 > 0) {
+ n1 = n2 = 0;
+ if (l1 > 0) {
+ b1[n1 = l1 > width ? width : l1] = 0;
+ for (i = 0; i < n1; i++)
+ b1[i] = isprint((unsigned char)m1[i]) ? m1[i] : '.';
+ }
+ if (l2 > 0) {
+ b2[n2 = l2 > width ? width : l2] = 0;
+ for (i = 0; i < n2; i++)
+ b2[i] = isprint((unsigned char)m2[i]) ? m2[i] : '.';
+ }
+ diff = 0;
+ i = 0;
+ if (n1 > 0 && n2 > 0) {
+ const size_t j = n1 < n2 ? n1 : n2;
+
+ for (; i < j; i++)
+ if (m1[i] == m2[i]) {
+ bdiff[i] = ' ';
+ } else {
+ bdiff[i] = '^';
+ diff = 1;
+ }
+ bdiff[i] = '\0';
+ }
+ if (n1 == n2 && !diff) {
+ test_printf_stderr("%4u: '%s'\n", cnt, n2 > n1 ? b2 : b1);
+ } else {
+ if (cnt == 0 && (m1 == NULL || *m1 == '\0'))
+ test_string_null_empty(m1, '-');
+ else if (n1 > 0)
+ test_printf_stderr("%4u:- '%s'\n", cnt, b1);
+ if (cnt == 0 && (m2 == NULL || *m2 == '\0'))
+ test_string_null_empty(m2, '+');
+ else if (n2 > 0)
+ test_printf_stderr("%4u:+ '%s'\n", cnt, b2);
+ if (diff && i > 0)
+ test_printf_stderr("%4s %s\n", "", bdiff);
+ }
+ if (m1 != NULL)
+ m1 += n1;
+ if (m2 != NULL)
+ m2 += n2;
+ l1 -= n1;
+ l2 -= n2;
+ cnt += width;
+ }
+fin:
+ test_flush_stderr();
+}
+
+/*
+ * Wrapper routines so that the underlying code can be shared.
+ * The first is the call from inside the test utilities when a conditional
+ * fails. The second is the user's call to dump a string.
+ */
+void test_fail_string_message(const char *prefix, const char *file,
+ int line, const char *type,
+ const char *left, const char *right,
+ const char *op, const char *m1, size_t l1,
+ const char *m2, size_t l2)
+{
+ test_fail_string_common(prefix, file, line, type, left, right, op,
+ m1, l1, m2, l2);
+ test_printf_stderr("\n");
+}
+
+void test_output_string(const char *name, const char *m, size_t l)
+{
+ test_fail_string_common("string", NULL, 0, NULL, NULL, NULL, name,
+ m, l, m, l);
+}
+
+/* BIGNUM formatted output routines */
+
+/*
+ * A basic memory byte to hex digit converter with allowance for spacing
+ * every so often.
+ */
+static void hex_convert_memory(const unsigned char *m, size_t n, char *b,
+ size_t width)
+{
+ size_t i;
+
+ for (i = 0; i < n; i++) {
+ const unsigned char c = *m++;
+
+ *b++ = "0123456789abcdef"[c >> 4];
+ *b++ = "0123456789abcdef"[c & 15];
+ if (i % width == width - 1 && i != n - 1)
+ *b++ = ' ';
+ }
+ *b = '\0';
+}
+
+/*
+ * Constants to define the number of bytes to display per line and the number
+ * of characters these take.
+ */
+static const int bn_bytes = (MAX_STRING_WIDTH - 9) / (BN_OUTPUT_SIZE * 2 + 1)
+ * BN_OUTPUT_SIZE;
+static const int bn_chars = (MAX_STRING_WIDTH - 9) / (BN_OUTPUT_SIZE * 2 + 1)
+ * (BN_OUTPUT_SIZE * 2 + 1) - 1;
+
+/*
+ * Output the header line for the bignum
+ */
+static void test_bignum_header_line(void)
+{
+ test_printf_stderr(" %*s\n", bn_chars + 6, "bit position");
+}
+
+static const char *test_bignum_zero_null(const BIGNUM *bn)
+{
+ if (bn != NULL)
+ return BN_is_negative(bn) ? "-0" : "0";
+ return "NULL";
+}
+
+/*
+ * Print a bignum zero taking care to include the correct sign.
+ * This routine correctly deals with a NULL bignum pointer as input.
+ */
+static void test_bignum_zero_print(const BIGNUM *bn, char sep)
+{
+ const char *v = test_bignum_zero_null(bn);
+ const char *suf = bn != NULL ? ": 0" : "";
+
+ test_printf_stderr("%c%*s%s\n", sep, bn_chars, v, suf);
+}
+
+/*
+ * Convert a section of memory from inside a bignum into a displayable
+ * string with appropriate visual aid spaces inserted.
+ */
+static int convert_bn_memory(const unsigned char *in, size_t bytes,
+ char *out, int *lz, const BIGNUM *bn)
+{
+ int n = bytes * 2, i;
+ char *p = out, *q = NULL;
+ const char *r;
+
+ if (bn != NULL && !BN_is_zero(bn)) {
+ hex_convert_memory(in, bytes, out, BN_OUTPUT_SIZE);
+ if (*lz) {
+ for (; *p == '0' || *p == ' '; p++)
+ if (*p == '0') {
+ q = p;
+ *p = ' ';
+ n--;
+ }
+ if (*p == '\0') {
+ /*
+ * in[bytes] is defined because we're converting a non-zero
+ * number and we've not seen a non-zero yet.
+ */
+ if ((in[bytes] & 0xf0) != 0 && BN_is_negative(bn)) {
+ *lz = 0;
+ *q = '-';
+ n++;
+ }
+ } else {
+ *lz = 0;
+ if (BN_is_negative(bn)) {
+ /*
+ * This is valid because we always convert more digits than
+ * the number holds.
+ */
+ *q = '-';
+ n++;
+ }
+ }
+ }
+ return n;
+ }
+
+ for (i = 0; i < n; i++) {
+ *p++ = ' ';
+ if (i % (2 * BN_OUTPUT_SIZE) == 2 * BN_OUTPUT_SIZE - 1 && i != n - 1)
+ *p++ = ' ';
+ }
+ *p = '\0';
+ if (bn == NULL)
+ r = "NULL";
+ else
+ r = BN_is_negative(bn) ? "-0" : "0";
+ strcpy(p - strlen(r), r);
+ return 0;
+}
+
+/*
+ * Common code to display either one or two bignums, including the diff
+ * pointers for changes (only when there are two).
+ */
+static void test_fail_bignum_common(const char *prefix, const char *file,
+ int line, const char *type,
+ const char *left, const char *right,
+ const char *op,
+ const BIGNUM *bn1, const BIGNUM *bn2)
+{
+ const size_t bytes = bn_bytes;
+ char b1[MAX_STRING_WIDTH + 1], b2[MAX_STRING_WIDTH + 1];
+ char *p, bdiff[MAX_STRING_WIDTH + 1];
+ size_t l1, l2, n1, n2, i, len;
+ unsigned int cnt, diff, real_diff;
+ unsigned char *m1 = NULL, *m2 = NULL;
+ int lz1 = 1, lz2 = 1;
+ unsigned char buffer[MEM_BUFFER_SIZE * 2], *bufp = buffer;
+
+ test_fail_message_prefix(prefix, file, line, type, left, right, op);
+ l1 = bn1 == NULL ? 0 : (BN_num_bytes(bn1) + (BN_is_negative(bn1) ? 1 : 0));
+ l2 = bn2 == NULL ? 0 : (BN_num_bytes(bn2) + (BN_is_negative(bn2) ? 1 : 0));
+ if (l1 == 0 && l2 == 0) {
+ if ((bn1 == NULL) == (bn2 == NULL)) {
+ test_bignum_header_line();
+ test_bignum_zero_print(bn1, ' ');
+ } else {
+ test_diff_header(left, right);
+ test_bignum_header_line();
+ test_bignum_zero_print(bn1, '-');
+ test_bignum_zero_print(bn2, '+');
+ }
+ goto fin;
+ }
+
+ if (l1 != l2 || bn1 == NULL || bn2 == NULL || BN_cmp(bn1, bn2) != 0)
+ test_diff_header(left, right);
+ test_bignum_header_line();
+
+ len = ((l1 > l2 ? l1 : l2) + bytes - 1) / bytes * bytes;
+
+ if (len > MEM_BUFFER_SIZE && (bufp = OPENSSL_malloc(len * 2)) == NULL) {
+ bufp = buffer;
+ len = MEM_BUFFER_SIZE;
+ test_printf_stderr("WARNING: these BIGNUMs have been truncated\n");
+ }
+
+ if (bn1 != NULL) {
+ m1 = bufp;
+ BN_bn2binpad(bn1, m1, len);
+ }
+ if (bn2 != NULL) {
+ m2 = bufp + len;
+ BN_bn2binpad(bn2, m2, len);
+ }
+
+ while (len > 0) {
+ cnt = 8 * (len - bytes);
+ n1 = convert_bn_memory(m1, bytes, b1, &lz1, bn1);
+ n2 = convert_bn_memory(m2, bytes, b2, &lz2, bn2);
+
+ diff = real_diff = 0;
+ i = 0;
+ p = bdiff;
+ for (i=0; b1[i] != '\0'; i++)
+ if (b1[i] == b2[i] || b1[i] == ' ' || b2[i] == ' ') {
+ *p++ = ' ';
+ diff |= b1[i] != b2[i];
+ } else {
+ *p++ = '^';
+ real_diff = diff = 1;
+ }
+ *p++ = '\0';
+ if (!diff) {
+ test_printf_stderr(" %s:% 5d\n", n2 > n1 ? b2 : b1, cnt);
+ } else {
+ if (cnt == 0 && bn1 == NULL)
+ test_printf_stderr("-%s\n", b1);
+ else if (cnt == 0 || n1 > 0)
+ test_printf_stderr("-%s:% 5d\n", b1, cnt);
+ if (cnt == 0 && bn2 == NULL)
+ test_printf_stderr("+%s\n", b2);
+ else if (cnt == 0 || n2 > 0)
+ test_printf_stderr("+%s:% 5d\n", b2, cnt);
+ if (real_diff && (cnt == 0 || (n1 > 0 && n2 > 0))
+ && bn1 != NULL && bn2 != NULL)
+ test_printf_stderr(" %s\n", bdiff);
+ }
+ if (m1 != NULL)
+ m1 += bytes;
+ if (m2 != NULL)
+ m2 += bytes;
+ len -= bytes;
+ }
+fin:
+ test_flush_stderr();
+ if (bufp != buffer)
+ OPENSSL_free(bufp);
+}
+
+/*
+ * Wrapper routines so that the underlying code can be shared.
+ * The first two are calls from inside the test utilities when a conditional
+ * fails. The third is the user's call to dump a bignum.
+ */
+void test_fail_bignum_message(const char *prefix, const char *file,
+ int line, const char *type,
+ const char *left, const char *right,
+ const char *op,
+ const BIGNUM *bn1, const BIGNUM *bn2)
+{
+ test_fail_bignum_common(prefix, file, line, type, left, right, op, bn1, bn2);
+ test_printf_stderr("\n");
+}
+
+void test_fail_bignum_mono_message(const char *prefix, const char *file,
+ int line, const char *type,
+ const char *left, const char *right,
+ const char *op, const BIGNUM *bn)
+{
+ test_fail_bignum_common(prefix, file, line, type, left, right, op, bn, bn);
+ test_printf_stderr("\n");
+}
+
+void test_output_bignum(const char *name, const BIGNUM *bn)
+{
+ if (bn == NULL || BN_is_zero(bn)) {
+ test_printf_stderr("bignum: '%s' = %s\n", name,
+ test_bignum_zero_null(bn));
+ } else if (BN_num_bytes(bn) <= BN_OUTPUT_SIZE) {
+ unsigned char buf[BN_OUTPUT_SIZE];
+ char out[2 * sizeof(buf) + 1];
+ char *p = out;
+ int n = BN_bn2bin(bn, buf);
+
+ hex_convert_memory(buf, n, p, BN_OUTPUT_SIZE);
+ while (*p == '0' && *++p != '\0')
+ ;
+ test_printf_stderr("bignum: '%s' = %s0x%s\n", name,
+ BN_is_negative(bn) ? "-" : "", p);
+ } else {
+ test_fail_bignum_common("bignum", NULL, 0, NULL, NULL, NULL, name,
+ bn, bn);
+ }
+}
+
+/* Memory output routines */
+
+/*
+ * Handle zero length blocks of memory or NULL pointers to memory
+ */
+static void test_memory_null_empty(const unsigned char *m, char c)
+{
+ if (m == NULL)
+ test_printf_stderr("%4s %c%s\n", "", c, "NULL");
+ else
+ test_printf_stderr("%04x %c%s\n", 0u, c, "empty");
+}
+
+/*
+ * Common code to display one or two blocks of memory.
+ */
+static void test_fail_memory_common(const char *prefix, const char *file,
+ int line, const char *type,
+ const char *left, const char *right,
+ const char *op,
+ const unsigned char *m1, size_t l1,
+ const unsigned char *m2, size_t l2)
+{
+ const size_t bytes = (MAX_STRING_WIDTH - 9) / 17 * 8;
+ char b1[MAX_STRING_WIDTH + 1], b2[MAX_STRING_WIDTH + 1];
+ char *p, bdiff[MAX_STRING_WIDTH + 1];
+ size_t n1, n2, i;
+ unsigned int cnt = 0, diff;
+
+ test_fail_message_prefix(prefix, file, line, type, left, right, op);
+ if (m1 == NULL)
+ l1 = 0;
+ if (m2 == NULL)
+ l2 = 0;
+ if (l1 == 0 && l2 == 0) {
+ if ((m1 == NULL) == (m2 == NULL)) {
+ test_memory_null_empty(m1, ' ');
+ } else {
+ test_diff_header(left, right);
+ test_memory_null_empty(m1, '-');
+ test_memory_null_empty(m2, '+');
+ }
+ goto fin;
+ }
+
+ if (l1 != l2 || (m1 != m2 && memcmp(m1, m2, l1) != 0))
+ test_diff_header(left, right);
+
+ while (l1 > 0 || l2 > 0) {
+ n1 = n2 = 0;
+ if (l1 > 0) {
+ n1 = l1 > bytes ? bytes : l1;
+ hex_convert_memory(m1, n1, b1, 8);
+ }
+ if (l2 > 0) {
+ n2 = l2 > bytes ? bytes : l2;
+ hex_convert_memory(m2, n2, b2, 8);
+ }
+
+ diff = 0;
+ i = 0;
+ p = bdiff;
+ if (n1 > 0 && n2 > 0) {
+ const size_t j = n1 < n2 ? n1 : n2;
+
+ for (; i < j; i++) {
+ if (m1[i] == m2[i]) {
+ *p++ = ' ';
+ *p++ = ' ';
+ } else {
+ *p++ = '^';
+ *p++ = '^';
+ diff = 1;
+ }
+ if (i % 8 == 7 && i != j - 1)
+ *p++ = ' ';
+ }
+ *p++ = '\0';
+ }
+
+ if (n1 == n2 && !diff) {
+ test_printf_stderr("%04x: %s\n", cnt, b1);
+ } else {
+ if (cnt == 0 && (m1 == NULL || l1 == 0))
+ test_memory_null_empty(m1, '-');
+ else if (n1 > 0)
+ test_printf_stderr("%04x:-%s\n", cnt, b1);
+ if (cnt == 0 && (m2 == NULL || l2 == 0))
+ test_memory_null_empty(m2, '+');
+ else if (n2 > 0)
+ test_printf_stderr("%04x:+%s\n", cnt, b2);
+ if (diff && i > 0)
+ test_printf_stderr("%4s %s\n", "", bdiff);
+ }
+ if (m1 != NULL)
+ m1 += n1;
+ if (m2 != NULL)
+ m2 += n2;
+ l1 -= n1;
+ l2 -= n2;
+ cnt += bytes;
+ }
+fin:
+ test_flush_stderr();
+}
+
+/*
+ * Wrapper routines so that the underlying code can be shared.
+ * The first is the call from inside the test utilities when a conditional
+ * fails. The second is the user's call to dump memory.
+ */
+void test_fail_memory_message(const char *prefix, const char *file,
+ int line, const char *type,
+ const char *left, const char *right,
+ const char *op,
+ const unsigned char *m1, size_t l1,
+ const unsigned char *m2, size_t l2)
+{
+ test_fail_memory_common(prefix, file, line, type, left, right, op,
+ m1, l1, m2, l2);
+ test_printf_stderr("\n");
+}
+
+void test_output_memory(const char *name, const unsigned char *m, size_t l)
+{
+ test_fail_memory_common("memory", NULL, 0, NULL, NULL, NULL, name,
+ m, l, m, l);
+}
diff --git a/test/testutil/load.c b/test/testutil/load.c
new file mode 100644
index 000000000000..d776a7f167cf
--- /dev/null
+++ b/test/testutil/load.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2020-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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+
+#include "../testutil.h"
+
+X509 *load_cert_pem(const char *file, OSSL_LIB_CTX *libctx)
+{
+ X509 *cert = NULL;
+ BIO *bio = NULL;
+
+ if (!TEST_ptr(file) || !TEST_ptr(bio = BIO_new(BIO_s_file())))
+ return NULL;
+ if (TEST_int_gt(BIO_read_filename(bio, file), 0)
+ && TEST_ptr(cert = X509_new_ex(libctx, NULL)))
+ (void)TEST_ptr(cert = PEM_read_bio_X509(bio, &cert, NULL, NULL));
+
+ BIO_free(bio);
+ return cert;
+}
+
+STACK_OF(X509) *load_certs_pem(const char *file)
+{
+ STACK_OF(X509) *certs;
+ BIO *bio;
+ X509 *x;
+
+ if (!TEST_ptr(file) || (bio = BIO_new_file(file, "r")) == NULL)
+ return NULL;
+
+ certs = sk_X509_new_null();
+ if (certs == NULL) {
+ BIO_free(bio);
+ return NULL;
+ }
+
+ ERR_set_mark();
+ do {
+ x = PEM_read_bio_X509(bio, NULL, 0, NULL);
+ if (x != NULL && !sk_X509_push(certs, x)) {
+ sk_X509_pop_free(certs, X509_free);
+ BIO_free(bio);
+ return NULL;
+ } else if (x == NULL) {
+ /*
+ * We probably just ran out of certs, so ignore any errors
+ * generated
+ */
+ ERR_pop_to_mark();
+ }
+ } while (x != NULL);
+
+ BIO_free(bio);
+
+ return certs;
+}
+
+EVP_PKEY *load_pkey_pem(const char *file, OSSL_LIB_CTX *libctx)
+{
+ EVP_PKEY *key = NULL;
+ BIO *bio = NULL;
+
+ if (!TEST_ptr(file) || !TEST_ptr(bio = BIO_new(BIO_s_file())))
+ return NULL;
+ if (TEST_int_gt(BIO_read_filename(bio, file), 0)) {
+ unsigned long err = ERR_peek_error();
+
+ if (TEST_ptr(key = PEM_read_bio_PrivateKey_ex(bio, NULL, NULL, NULL,
+ libctx, NULL))
+ && err != ERR_peek_error()) {
+ TEST_info("Spurious error from reading PEM");
+ EVP_PKEY_free(key);
+ key = NULL;
+ }
+ }
+
+ BIO_free(bio);
+ return key;
+}
+
+X509_REQ *load_csr_der(const char *file, OSSL_LIB_CTX *libctx)
+{
+ X509_REQ *csr = NULL;
+ BIO *bio = NULL;
+
+ if (!TEST_ptr(file) || !TEST_ptr(bio = BIO_new_file(file, "rb")))
+ return NULL;
+
+ csr = X509_REQ_new_ex(libctx, NULL);
+ if (TEST_ptr(csr))
+ (void)TEST_ptr(d2i_X509_REQ_bio(bio, &csr));
+ BIO_free(bio);
+ return csr;
+}
diff --git a/test/testutil/main.c b/test/testutil/main.c
new file mode 100644
index 000000000000..32e32d832872
--- /dev/null
+++ b/test/testutil/main.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2016-2023 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "../testutil.h"
+#include "output.h"
+#include "tu_local.h"
+
+
+int main(int argc, char *argv[])
+{
+ int ret = EXIT_FAILURE;
+ int setup_res;
+
+ test_open_streams();
+
+ if (!global_init()) {
+ test_printf_stderr("Global init failed - aborting\n");
+ return ret;
+ }
+
+ if (!setup_test_framework(argc, argv))
+ goto end;
+
+ if ((setup_res = setup_tests()) > 0) {
+ ret = run_tests(argv[0]);
+ cleanup_tests();
+ opt_check_usage();
+ } else if (setup_res == 0) {
+ opt_help(test_get_options());
+ }
+end:
+ ret = pulldown_test_framework(ret);
+ test_close_streams();
+ return ret;
+}
diff --git a/test/testutil/options.c b/test/testutil/options.c
new file mode 100644
index 000000000000..35dfa320c48b
--- /dev/null
+++ b/test/testutil/options.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2018-2020 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "../testutil.h"
+#include "internal/nelem.h"
+#include "tu_local.h"
+#include "output.h"
+
+
+static int used[100] = { 0 };
+
+int test_skip_common_options(void)
+{
+ OPTION_CHOICE_DEFAULT o;
+
+ while ((o = (OPTION_CHOICE_DEFAULT)opt_next()) != OPT_EOF) {
+ switch (o) {
+ case OPT_TEST_CASES:
+ break;
+ default:
+ case OPT_ERR:
+ return 0;
+ }
+ }
+ return 1;
+}
+
+size_t test_get_argument_count(void)
+{
+ return opt_num_rest();
+}
+
+char *test_get_argument(size_t n)
+{
+ char **argv = opt_rest();
+
+ OPENSSL_assert(n < sizeof(used));
+ if ((int)n >= opt_num_rest() || argv == NULL)
+ return NULL;
+ used[n] = 1;
+ return argv[n];
+}
+
+void opt_check_usage(void)
+{
+ int i;
+ char **argv = opt_rest();
+ int n, arg_count = opt_num_rest();
+
+ if (arg_count > (int)OSSL_NELEM(used))
+ n = (int)OSSL_NELEM(used);
+ else
+ n = arg_count;
+ for (i = 0; i < n; i++) {
+ if (used[i] == 0)
+ test_printf_stderr("Warning ignored command-line argument %d: %s\n",
+ i, argv[i]);
+ }
+ if (i < arg_count)
+ test_printf_stderr("Warning arguments %d and later unchecked\n", i);
+}
+
+int opt_printf_stderr(const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = test_vprintf_stderr(fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
diff --git a/test/testutil/output.c b/test/testutil/output.c
new file mode 100644
index 000000000000..e9446a644997
--- /dev/null
+++ b/test/testutil/output.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017-2020 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "output.h"
+
+int test_printf_stdout(const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = test_vprintf_stdout(fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+int test_printf_stderr(const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = test_vprintf_stderr(fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+int test_printf_tapout(const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = test_vprintf_tapout(fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+int test_printf_taperr(const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = test_vprintf_taperr(fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
diff --git a/test/testutil/output.h b/test/testutil/output.h
new file mode 100644
index 000000000000..6fbad6f5bd0a
--- /dev/null
+++ b/test/testutil/output.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2014-2022 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#ifndef OSSL_TESTUTIL_OUTPUT_H
+# define OSSL_TESTUTIL_OUTPUT_H
+
+# include <stdarg.h>
+
+# define ossl_test__attr__(x)
+# if defined(__GNUC__) && defined(__STDC_VERSION__) \
+ && !defined(__MINGW32__) && !defined(__MINGW64__) \
+ && !defined(__APPLE__)
+ /*
+ * Because we support the 'z' modifier, which made its appearance in C99,
+ * we can't use __attribute__ with pre C99 dialects.
+ */
+# if __STDC_VERSION__ >= 199901L
+# undef ossl_test__attr__
+# define ossl_test__attr__ __attribute__
+# if __GNUC__*10 + __GNUC_MINOR__ >= 44
+# define ossl_test__printf__ __gnu_printf__
+# else
+# define ossl_test__printf__ __printf__
+# endif
+# endif
+# endif
+/*
+ * The basic I/O functions used internally by the test framework. These
+ * can be overridden when needed. Note that if one is, then all must be.
+ */
+void test_open_streams(void);
+void test_close_streams(void);
+void test_adjust_streams_tap_level(int level);
+/* The following ALL return the number of characters written */
+int test_vprintf_stdout(const char *fmt, va_list ap)
+ ossl_test__attr__((__format__(ossl_test__printf__, 1, 0)));
+int test_vprintf_tapout(const char *fmt, va_list ap)
+ ossl_test__attr__((__format__(ossl_test__printf__, 1, 0)));
+int test_vprintf_stderr(const char *fmt, va_list ap)
+ ossl_test__attr__((__format__(ossl_test__printf__, 1, 0)));
+int test_vprintf_taperr(const char *fmt, va_list ap)
+ ossl_test__attr__((__format__(ossl_test__printf__, 1, 0)));
+/* These return failure or success */
+int test_flush_stdout(void);
+int test_flush_tapout(void);
+int test_flush_stderr(void);
+int test_flush_taperr(void);
+
+/* Commodity functions. There's no need to override these */
+int test_printf_stdout(const char *fmt, ...)
+ ossl_test__attr__((__format__(ossl_test__printf__, 1, 2)));
+int test_printf_tapout(const char *fmt, ...)
+ ossl_test__attr__((__format__(ossl_test__printf__, 1, 2)));
+int test_printf_stderr(const char *fmt, ...)
+ ossl_test__attr__((__format__(ossl_test__printf__, 1, 2)));
+int test_printf_taperr(const char *fmt, ...)
+ ossl_test__attr__((__format__(ossl_test__printf__, 1, 2)));
+
+# undef ossl_test__printf__
+# undef ossl_test__attr__
+
+#endif /* OSSL_TESTUTIL_OUTPUT_H */
diff --git a/test/testutil/provider.c b/test/testutil/provider.c
new file mode 100644
index 000000000000..79ae13b42a1f
--- /dev/null
+++ b/test/testutil/provider.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright 2018-2023 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "../testutil.h"
+#include <ctype.h>
+#include <openssl/provider.h>
+#include <openssl/core_names.h>
+#include <string.h>
+
+int test_get_libctx(OSSL_LIB_CTX **libctx, OSSL_PROVIDER **default_null_prov,
+ const char *config_file,
+ OSSL_PROVIDER **provider, const char *module_name)
+{
+ OSSL_LIB_CTX *new_libctx = NULL;
+
+ if (libctx != NULL) {
+ if ((new_libctx = *libctx = OSSL_LIB_CTX_new()) == NULL) {
+ opt_printf_stderr("Failed to create libctx\n");
+ goto err;
+ }
+ }
+
+ if (default_null_prov != NULL
+ && (*default_null_prov = OSSL_PROVIDER_load(NULL, "null")) == NULL) {
+ opt_printf_stderr("Failed to load null provider into default libctx\n");
+ goto err;
+ }
+
+ if (config_file != NULL
+ && !OSSL_LIB_CTX_load_config(new_libctx, config_file)) {
+ opt_printf_stderr("Error loading config from file %s\n", config_file);
+ goto err;
+ }
+
+ if (provider != NULL && module_name != NULL
+ && (*provider = OSSL_PROVIDER_load(new_libctx, module_name)) == NULL) {
+ opt_printf_stderr("Failed to load provider %s\n", module_name);
+ goto err;
+ }
+ return 1;
+
+ err:
+ ERR_print_errors_fp(stderr);
+ return 0;
+}
+
+int test_arg_libctx(OSSL_LIB_CTX **libctx, OSSL_PROVIDER **default_null_prov,
+ OSSL_PROVIDER **provider, int argn, const char *usage)
+{
+ const char *module_name;
+
+ if (!TEST_ptr(module_name = test_get_argument(argn))) {
+ TEST_error("usage: <prog> %s", usage);
+ return 0;
+ }
+ if (strcmp(module_name, "none") == 0)
+ return 1;
+ return test_get_libctx(libctx, default_null_prov,
+ test_get_argument(argn + 1), provider, module_name);
+}
+
+typedef struct {
+ int major, minor, patch;
+} FIPS_VERSION;
+
+/*
+ * Query the FIPS provider to determine it's version number.
+ * Returns 1 if the version is retrieved correctly, 0 if the FIPS provider isn't
+ * loaded and -1 on error.
+ */
+static int fips_provider_version(OSSL_LIB_CTX *libctx, FIPS_VERSION *vers)
+{
+ OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
+ OSSL_PROVIDER *fips_prov;
+ char *vs;
+
+ if (!OSSL_PROVIDER_available(libctx, "fips"))
+ return 0;
+ *params = OSSL_PARAM_construct_utf8_ptr(OSSL_PROV_PARAM_VERSION, &vs, 0);
+ if ((fips_prov = OSSL_PROVIDER_load(libctx, "fips")) == NULL)
+ return -1;
+ if (!OSSL_PROVIDER_get_params(fips_prov, params)
+ || sscanf(vs, "%d.%d.%d", &vers->major, &vers->minor, &vers->patch) != 3)
+ goto err;
+ if (!OSSL_PROVIDER_unload(fips_prov))
+ return -1;
+ return 1;
+ err:
+ OSSL_PROVIDER_unload(fips_prov);
+ return -1;
+}
+
+int fips_provider_version_eq(OSSL_LIB_CTX *libctx, int major, int minor, int patch)
+{
+ FIPS_VERSION prov;
+ int res;
+
+ if ((res = fips_provider_version(libctx, &prov)) <= 0)
+ return res == 0;
+ return major == prov.major && minor == prov.minor && patch == prov.patch;
+}
+
+int fips_provider_version_ne(OSSL_LIB_CTX *libctx, int major, int minor, int patch)
+{
+ FIPS_VERSION prov;
+ int res;
+
+ if ((res = fips_provider_version(libctx, &prov)) <= 0)
+ return res == 0;
+ return major != prov.major || minor != prov.minor || patch != prov.patch;
+}
+
+int fips_provider_version_le(OSSL_LIB_CTX *libctx, int major, int minor, int patch)
+{
+ FIPS_VERSION prov;
+ int res;
+
+ if ((res = fips_provider_version(libctx, &prov)) <= 0)
+ return res == 0;
+ return prov.major < major
+ || (prov.major == major
+ && (prov.minor < minor
+ || (prov.minor == minor && prov.patch <= patch)));
+}
+
+int fips_provider_version_lt(OSSL_LIB_CTX *libctx, int major, int minor, int patch)
+{
+ FIPS_VERSION prov;
+ int res;
+
+ if ((res = fips_provider_version(libctx, &prov)) <= 0)
+ return res == 0;
+ return prov.major < major
+ || (prov.major == major
+ && (prov.minor < minor
+ || (prov.minor == minor && prov.patch < patch)));
+}
+
+int fips_provider_version_gt(OSSL_LIB_CTX *libctx, int major, int minor, int patch)
+{
+ FIPS_VERSION prov;
+ int res;
+
+ if ((res = fips_provider_version(libctx, &prov)) <= 0)
+ return res == 0;
+ return prov.major > major
+ || (prov.major == major
+ && (prov.minor > minor
+ || (prov.minor == minor && prov.patch > patch)));
+}
+
+int fips_provider_version_ge(OSSL_LIB_CTX *libctx, int major, int minor, int patch)
+{
+ FIPS_VERSION prov;
+ int res;
+
+ if ((res = fips_provider_version(libctx, &prov)) <= 0)
+ return res == 0;
+ return prov.major > major
+ || (prov.major == major
+ && (prov.minor > minor
+ || (prov.minor == minor && prov.patch >= patch)));
+}
+
+int fips_provider_version_match(OSSL_LIB_CTX *libctx, const char *versions)
+{
+ const char *p;
+ int major, minor, patch, r;
+ enum {
+ MODE_EQ, MODE_NE, MODE_LE, MODE_LT, MODE_GT, MODE_GE
+ } mode;
+
+ while (*versions != '\0') {
+ for (; isspace((unsigned char)(*versions)); versions++)
+ continue;
+ if (*versions == '\0')
+ break;
+ for (p = versions; *versions != '\0' && !isspace((unsigned char)(*versions)); versions++)
+ continue;
+ if (*p == '!') {
+ mode = MODE_NE;
+ p++;
+ } else if (*p == '=') {
+ mode = MODE_EQ;
+ p++;
+ } else if (*p == '<' && p[1] == '=') {
+ mode = MODE_LE;
+ p += 2;
+ } else if (*p == '>' && p[1] == '=') {
+ mode = MODE_GE;
+ p += 2;
+ } else if (*p == '<') {
+ mode = MODE_LT;
+ p++;
+ } else if (*p == '>') {
+ mode = MODE_GT;
+ p++;
+ } else if (isdigit((unsigned char)*p)) {
+ mode = MODE_EQ;
+ } else {
+ TEST_info("Error matching FIPS version: mode %s\n", p);
+ return -1;
+ }
+ if (sscanf(p, "%d.%d.%d", &major, &minor, &patch) != 3) {
+ TEST_info("Error matching FIPS version: version %s\n", p);
+ return -1;
+ }
+ switch (mode) {
+ case MODE_EQ:
+ r = fips_provider_version_eq(libctx, major, minor, patch);
+ break;
+ case MODE_NE:
+ r = fips_provider_version_ne(libctx, major, minor, patch);
+ break;
+ case MODE_LE:
+ r = fips_provider_version_le(libctx, major, minor, patch);
+ break;
+ case MODE_LT:
+ r = fips_provider_version_lt(libctx, major, minor, patch);
+ break;
+ case MODE_GT:
+ r = fips_provider_version_gt(libctx, major, minor, patch);
+ break;
+ case MODE_GE:
+ r = fips_provider_version_ge(libctx, major, minor, patch);
+ break;
+ }
+ if (r < 0) {
+ TEST_info("Error matching FIPS version: internal error\n");
+ return -1;
+ }
+ if (r == 0)
+ return 0;
+ }
+ return 1;
+}
diff --git a/test/testutil/random.c b/test/testutil/random.c
new file mode 100644
index 000000000000..45d0bb5f0589
--- /dev/null
+++ b/test/testutil/random.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "../testutil.h"
+
+/*
+ * This is an implementation of the algorithm used by the GNU C library's
+ * random(3) pseudorandom number generator as described:
+ * https://www.mscs.dal.ca/~selinger/random/
+ */
+static uint32_t test_random_state[31];
+
+uint32_t test_random(void) {
+ static unsigned int pos = 3;
+
+ if (pos == 31)
+ pos = 0;
+ test_random_state[pos] += test_random_state[(pos + 28) % 31];
+ return test_random_state[pos++] / 2;
+}
+
+void test_random_seed(uint32_t sd) {
+ int i;
+ int32_t s;
+ const unsigned int mod = (1u << 31) - 1;
+
+ test_random_state[0] = sd;
+ for (i = 1; i < 31; i++) {
+ s = (int32_t)test_random_state[i - 1];
+ test_random_state[i] = (uint32_t)((16807 * (int64_t)s) % mod);
+ }
+ for (i = 34; i < 344; i++)
+ test_random();
+}
diff --git a/test/testutil/stanza.c b/test/testutil/stanza.c
new file mode 100644
index 000000000000..ba62f84517f3
--- /dev/null
+++ b/test/testutil/stanza.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2017 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "internal/nelem.h"
+#include "../testutil.h"
+#include "tu_local.h"
+
+int test_start_file(STANZA *s, const char *testfile)
+{
+ TEST_info("Reading %s", testfile);
+ set_test_title(testfile);
+ memset(s, 0, sizeof(*s));
+ if (!TEST_ptr(s->fp = BIO_new_file(testfile, "r")))
+ return 0;
+ s->test_file = testfile;
+ return 1;
+}
+
+int test_end_file(STANZA *s)
+{
+ TEST_info("Completed %d tests with %d errors and %d skipped",
+ s->numtests, s->errors, s->numskip);
+ BIO_free(s->fp);
+ return 1;
+}
+
+/*
+ * Read a PEM block. Return 1 if okay, 0 on error.
+ */
+static int read_key(STANZA *s)
+{
+ char tmpbuf[128];
+
+ if (s->key == NULL) {
+ if (!TEST_ptr(s->key = BIO_new(BIO_s_mem())))
+ return 0;
+ } else if (!TEST_int_gt(BIO_reset(s->key), 0)) {
+ return 0;
+ }
+
+ /* Read to PEM end line and place content in memory BIO */
+ while (BIO_gets(s->fp, tmpbuf, sizeof(tmpbuf))) {
+ s->curr++;
+ if (!TEST_int_gt(BIO_puts(s->key, tmpbuf), 0))
+ return 0;
+ if (strncmp(tmpbuf, "-----END", 8) == 0)
+ return 1;
+ }
+ TEST_error("Can't find key end");
+ return 0;
+}
+
+
+/*
+ * Delete leading and trailing spaces from a string
+ */
+static char *strip_spaces(char *p)
+{
+ char *q;
+
+ /* Skip over leading spaces */
+ while (*p && isspace((unsigned char)*p))
+ p++;
+ if (*p == '\0')
+ return NULL;
+
+ for (q = p + strlen(p) - 1; q != p && isspace((unsigned char)*q); )
+ *q-- = '\0';
+ return *p ? p : NULL;
+}
+
+/*
+ * Read next test stanza; return 1 if found, 0 on EOF or error.
+ */
+int test_readstanza(STANZA *s)
+{
+ PAIR *pp = s->pairs;
+ char *p, *equals, *key;
+ const char *value;
+
+ for (s->numpairs = 0; BIO_gets(s->fp, s->buff, sizeof(s->buff)); ) {
+ s->curr++;
+ if (!TEST_ptr(p = strchr(s->buff, '\n'))) {
+ TEST_info("Line %d too long", s->curr);
+ return 0;
+ }
+ *p = '\0';
+
+ /* Blank line marks end of tests. */
+ if (s->buff[0] == '\0')
+ break;
+
+ /* Lines starting with a pound sign are ignored. */
+ if (s->buff[0] == '#')
+ continue;
+
+ /* Parse into key=value */
+ if (!TEST_ptr(equals = strchr(s->buff, '='))) {
+ TEST_info("Missing = at line %d\n", s->curr);
+ return 0;
+ }
+ *equals++ = '\0';
+ if (!TEST_ptr(key = strip_spaces(s->buff))) {
+ TEST_info("Empty field at line %d\n", s->curr);
+ return 0;
+ }
+ if ((value = strip_spaces(equals)) == NULL)
+ value = "";
+
+ if (strcmp(key, "Title") == 0) {
+ TEST_info("Starting \"%s\" tests at line %d", value, s->curr);
+ continue;
+ }
+
+ if (s->numpairs == 0)
+ s->start = s->curr;
+
+ if (strcmp(key, "PrivateKey") == 0) {
+ if (!read_key(s))
+ return 0;
+ }
+ if (strcmp(key, "PublicKey") == 0) {
+ if (!read_key(s))
+ return 0;
+ }
+
+ if (!TEST_int_lt(s->numpairs++, TESTMAXPAIRS)
+ || !TEST_ptr(pp->key = OPENSSL_strdup(key))
+ || !TEST_ptr(pp->value = OPENSSL_strdup(value)))
+ return 0;
+ pp++;
+ }
+
+ /* If we read anything, return ok. */
+ return 1;
+}
+
+void test_clearstanza(STANZA *s)
+{
+ PAIR *pp = s->pairs;
+ int i = s->numpairs;
+
+ for ( ; --i >= 0; pp++) {
+ OPENSSL_free(pp->key);
+ OPENSSL_free(pp->value);
+ }
+ s->numpairs = 0;
+}
diff --git a/test/testutil/test_cleanup.c b/test/testutil/test_cleanup.c
new file mode 100644
index 000000000000..669c54ce5abb
--- /dev/null
+++ b/test/testutil/test_cleanup.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2017 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "../testutil.h"
+
+void cleanup_tests(void)
+{
+}
diff --git a/test/testutil/test_options.c b/test/testutil/test_options.c
new file mode 100644
index 000000000000..51d880399bf2
--- /dev/null
+++ b/test/testutil/test_options.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2018-2020 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "../testutil.h"
+#include "tu_local.h"
+
+/* An overridable list of command line options */
+const OPTIONS *test_get_options(void)
+{
+ static const OPTIONS default_options[] = {
+ OPT_TEST_OPTIONS_DEFAULT_USAGE,
+ { NULL }
+ };
+ return default_options;
+}
diff --git a/test/testutil/tests.c b/test/testutil/tests.c
new file mode 100644
index 000000000000..ef7e224cd119
--- /dev/null
+++ b/test/testutil/tests.c
@@ -0,0 +1,472 @@
+/*
+ * Copyright 2017-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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "../testutil.h"
+#include "output.h"
+#include "tu_local.h"
+
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include "internal/nelem.h"
+#include <openssl/asn1.h>
+
+/*
+ * Output a failed test first line.
+ * All items are optional are generally not preinted if passed as NULL.
+ * The special cases are for prefix where "ERROR" is assumed and for left
+ * and right where a non-failure message is produced if either is NULL.
+ */
+void test_fail_message_prefix(const char *prefix, const char *file,
+ int line, const char *type,
+ const char *left, const char *right,
+ const char *op)
+{
+ test_printf_stderr("%s: ", prefix != NULL ? prefix : "ERROR");
+ if (type)
+ test_printf_stderr("(%s) ", type);
+ if (op != NULL) {
+ if (left != NULL && right != NULL)
+ test_printf_stderr("'%s %s %s' failed", left, op, right);
+ else
+ test_printf_stderr("'%s'", op);
+ }
+ if (file != NULL) {
+ test_printf_stderr(" @ %s:%d", file, line);
+ }
+ test_printf_stderr("\n");
+}
+
+/*
+ * A common routine to output test failure messages. Generally this should not
+ * be called directly, rather it should be called by the following functions.
+ *
+ * |desc| is a printf formatted description with arguments |args| that is
+ * supplied by the user and |desc| can be NULL. |type| is the data type
+ * that was tested (int, char, ptr, ...). |fmt| is a system provided
+ * printf format with following arguments that spell out the failure
+ * details i.e. the actual values compared and the operator used.
+ *
+ * The typical use for this is from an utility test function:
+ *
+ * int test6(const char *file, int line, int n) {
+ * if (n != 6) {
+ * test_fail_message(1, file, line, "int", "value %d is not %d", n, 6);
+ * return 0;
+ * }
+ * return 1;
+ * }
+ *
+ * calling test6(3, "oops") will return 0 and produce out along the lines of:
+ * FAIL oops: (int) value 3 is not 6\n
+ */
+static void test_fail_message(const char *prefix, const char *file, int line,
+ const char *type, const char *left,
+ const char *right, const char *op,
+ const char *fmt, ...)
+ PRINTF_FORMAT(8, 9);
+
+static void test_fail_message_va(const char *prefix, const char *file,
+ int line, const char *type,
+ const char *left, const char *right,
+ const char *op, const char *fmt, va_list ap)
+{
+ test_fail_message_prefix(prefix, file, line, type, left, right, op);
+ if (fmt != NULL) {
+ test_vprintf_stderr(fmt, ap);
+ test_printf_stderr("\n");
+ }
+ test_flush_stderr();
+}
+
+static void test_fail_message(const char *prefix, const char *file,
+ int line, const char *type,
+ const char *left, const char *right,
+ const char *op, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ test_fail_message_va(prefix, file, line, type, left, right, op, fmt, ap);
+ va_end(ap);
+}
+
+void test_info_c90(const char *desc, ...)
+{
+ va_list ap;
+
+ va_start(ap, desc);
+ test_fail_message_va("INFO", NULL, -1, NULL, NULL, NULL, NULL, desc, ap);
+ va_end(ap);
+}
+
+void test_info(const char *file, int line, const char *desc, ...)
+{
+ va_list ap;
+
+ va_start(ap, desc);
+ test_fail_message_va("INFO", file, line, NULL, NULL, NULL, NULL, desc, ap);
+ va_end(ap);
+}
+
+void test_error_c90(const char *desc, ...)
+{
+ va_list ap;
+
+ va_start(ap, desc);
+ test_fail_message_va(NULL, NULL, -1, NULL, NULL, NULL, NULL, desc, ap);
+ va_end(ap);
+ test_printf_stderr("\n");
+}
+
+void test_error(const char *file, int line, const char *desc, ...)
+{
+ va_list ap;
+
+ va_start(ap, desc);
+ test_fail_message_va(NULL, file, line, NULL, NULL, NULL, NULL, desc, ap);
+ va_end(ap);
+ test_printf_stderr("\n");
+}
+
+void test_perror(const char *s)
+{
+ /*
+ * Using openssl_strerror_r causes linking issues since it isn't
+ * exported from libcrypto.so
+ */
+ TEST_error("%s: %s", s, strerror(errno));
+}
+
+void test_note(const char *fmt, ...)
+{
+ if (fmt != NULL) {
+ va_list ap;
+
+ va_start(ap, fmt);
+ test_vprintf_stderr(fmt, ap);
+ va_end(ap);
+ test_printf_stderr("\n");
+ }
+ test_flush_stderr();
+}
+
+
+int test_skip(const char *file, int line, const char *desc, ...)
+{
+ va_list ap;
+
+ va_start(ap, desc);
+ test_fail_message_va("SKIP", file, line, NULL, NULL, NULL, NULL, desc, ap);
+ va_end(ap);
+ return TEST_SKIP_CODE;
+}
+
+int test_skip_c90(const char *desc, ...)
+{
+ va_list ap;
+
+ va_start(ap, desc);
+ test_fail_message_va("SKIP", NULL, -1, NULL, NULL, NULL, NULL, desc, ap);
+ va_end(ap);
+ test_printf_stderr("\n");
+ return TEST_SKIP_CODE;
+}
+
+
+void test_openssl_errors(void)
+{
+ ERR_print_errors_cb(openssl_error_cb, NULL);
+ ERR_clear_error();
+}
+
+/*
+ * Define some comparisons between pairs of various types.
+ * These functions return 1 if the test is true.
+ * Otherwise, they return 0 and pretty-print diagnostics.
+ *
+ * In each case the functions produced are:
+ * int test_name_eq(const type t1, const type t2, const char *desc, ...);
+ * int test_name_ne(const type t1, const type t2, const char *desc, ...);
+ * int test_name_lt(const type t1, const type t2, const char *desc, ...);
+ * int test_name_le(const type t1, const type t2, const char *desc, ...);
+ * int test_name_gt(const type t1, const type t2, const char *desc, ...);
+ * int test_name_ge(const type t1, const type t2, const char *desc, ...);
+ *
+ * The t1 and t2 arguments are to be compared for equality, inequality,
+ * less than, less than or equal to, greater than and greater than or
+ * equal to respectively. If the specified condition holds, the functions
+ * return 1. If the condition does not hold, the functions print a diagnostic
+ * message and return 0.
+ *
+ * The desc argument is a printf format string followed by its arguments and
+ * this is included in the output if the condition being tested for is false.
+ */
+#define DEFINE_COMPARISON(type, name, opname, op, fmt) \
+ int test_ ## name ## _ ## opname(const char *file, int line, \
+ const char *s1, const char *s2, \
+ const type t1, const type t2) \
+ { \
+ if (t1 op t2) \
+ return 1; \
+ test_fail_message(NULL, file, line, #type, s1, s2, #op, \
+ "[" fmt "] compared to [" fmt "]", \
+ t1, t2); \
+ return 0; \
+ }
+
+#define DEFINE_COMPARISONS(type, name, fmt) \
+ DEFINE_COMPARISON(type, name, eq, ==, fmt) \
+ DEFINE_COMPARISON(type, name, ne, !=, fmt) \
+ DEFINE_COMPARISON(type, name, lt, <, fmt) \
+ DEFINE_COMPARISON(type, name, le, <=, fmt) \
+ DEFINE_COMPARISON(type, name, gt, >, fmt) \
+ DEFINE_COMPARISON(type, name, ge, >=, fmt)
+
+DEFINE_COMPARISONS(int, int, "%d")
+DEFINE_COMPARISONS(unsigned int, uint, "%u")
+DEFINE_COMPARISONS(char, char, "%c")
+DEFINE_COMPARISONS(unsigned char, uchar, "%u")
+DEFINE_COMPARISONS(long, long, "%ld")
+DEFINE_COMPARISONS(unsigned long, ulong, "%lu")
+DEFINE_COMPARISONS(size_t, size_t, "%zu")
+DEFINE_COMPARISONS(double, double, "%g")
+
+DEFINE_COMPARISON(void *, ptr, eq, ==, "%p")
+DEFINE_COMPARISON(void *, ptr, ne, !=, "%p")
+
+int test_ptr_null(const char *file, int line, const char *s, const void *p)
+{
+ if (p == NULL)
+ return 1;
+ test_fail_message(NULL, file, line, "ptr", s, "NULL", "==", "%p", p);
+ return 0;
+}
+
+int test_ptr(const char *file, int line, const char *s, const void *p)
+{
+ if (p != NULL)
+ return 1;
+ test_fail_message(NULL, file, line, "ptr", s, "NULL", "!=", "%p", p);
+ return 0;
+}
+
+int test_true(const char *file, int line, const char *s, int b)
+{
+ if (b)
+ return 1;
+ test_fail_message(NULL, file, line, "bool", s, "true", "==", "false");
+ return 0;
+}
+
+int test_false(const char *file, int line, const char *s, int b)
+{
+ if (!b)
+ return 1;
+ test_fail_message(NULL, file, line, "bool", s, "false", "==", "true");
+ return 0;
+}
+
+int test_str_eq(const char *file, int line, const char *st1, const char *st2,
+ const char *s1, const char *s2)
+{
+ if (s1 == NULL && s2 == NULL)
+ return 1;
+ if (s1 == NULL || s2 == NULL || strcmp(s1, s2) != 0) {
+ test_fail_string_message(NULL, file, line, "string", st1, st2, "==",
+ s1, s1 == NULL ? 0 : strlen(s1),
+ s2, s2 == NULL ? 0 : strlen(s2));
+ return 0;
+ }
+ return 1;
+}
+
+int test_str_ne(const char *file, int line, const char *st1, const char *st2,
+ const char *s1, const char *s2)
+{
+ if ((s1 == NULL) ^ (s2 == NULL))
+ return 1;
+ if (s1 == NULL || strcmp(s1, s2) == 0) {
+ test_fail_string_message(NULL, file, line, "string", st1, st2, "!=",
+ s1, s1 == NULL ? 0 : strlen(s1),
+ s2, s2 == NULL ? 0 : strlen(s2));
+ return 0;
+ }
+ return 1;
+}
+
+int test_strn_eq(const char *file, int line, const char *st1, const char *st2,
+ const char *s1, size_t n1, const char *s2, size_t n2)
+{
+ if (s1 == NULL && s2 == NULL)
+ return 1;
+ if (n1 != n2 || s1 == NULL || s2 == NULL || strncmp(s1, s2, n1) != 0) {
+ test_fail_string_message(NULL, file, line, "string", st1, st2, "==",
+ s1, s1 == NULL ? 0 : OPENSSL_strnlen(s1, n1),
+ s2, s2 == NULL ? 0 : OPENSSL_strnlen(s2, n2));
+ return 0;
+ }
+ return 1;
+}
+
+int test_strn_ne(const char *file, int line, const char *st1, const char *st2,
+ const char *s1, size_t n1, const char *s2, size_t n2)
+{
+ if ((s1 == NULL) ^ (s2 == NULL))
+ return 1;
+ if (n1 != n2 || s1 == NULL || strncmp(s1, s2, n1) == 0) {
+ test_fail_string_message(NULL, file, line, "string", st1, st2, "!=",
+ s1, s1 == NULL ? 0 : OPENSSL_strnlen(s1, n1),
+ s2, s2 == NULL ? 0 : OPENSSL_strnlen(s2, n2));
+ return 0;
+ }
+ return 1;
+}
+
+int test_mem_eq(const char *file, int line, const char *st1, const char *st2,
+ const void *s1, size_t n1, const void *s2, size_t n2)
+{
+ if (s1 == NULL && s2 == NULL)
+ return 1;
+ if (n1 != n2 || s1 == NULL || s2 == NULL || memcmp(s1, s2, n1) != 0) {
+ test_fail_memory_message(NULL, file, line, "memory", st1, st2, "==",
+ s1, n1, s2, n2);
+ return 0;
+ }
+ return 1;
+}
+
+int test_mem_ne(const char *file, int line, const char *st1, const char *st2,
+ const void *s1, size_t n1, const void *s2, size_t n2)
+{
+ if ((s1 == NULL) ^ (s2 == NULL))
+ return 1;
+ if (n1 != n2)
+ return 1;
+ if (s1 == NULL || memcmp(s1, s2, n1) == 0) {
+ test_fail_memory_message(NULL, file, line, "memory", st1, st2, "!=",
+ s1, n1, s2, n2);
+ return 0;
+ }
+ return 1;
+}
+
+#define DEFINE_BN_COMPARISONS(opname, op, zero_cond) \
+ int test_BN_ ## opname(const char *file, int line, \
+ const char *s1, const char *s2, \
+ const BIGNUM *t1, const BIGNUM *t2) \
+ { \
+ if (BN_cmp(t1, t2) op 0) \
+ return 1; \
+ test_fail_bignum_message(NULL, file, line, "BIGNUM", s1, s2, \
+ #op, t1, t2); \
+ return 0; \
+ } \
+ int test_BN_ ## opname ## _zero(const char *file, int line, \
+ const char *s, const BIGNUM *a) \
+ { \
+ if (a != NULL &&(zero_cond)) \
+ return 1; \
+ test_fail_bignum_mono_message(NULL, file, line, "BIGNUM", \
+ s, "0", #op, a); \
+ return 0; \
+ }
+
+DEFINE_BN_COMPARISONS(eq, ==, BN_is_zero(a))
+DEFINE_BN_COMPARISONS(ne, !=, !BN_is_zero(a))
+DEFINE_BN_COMPARISONS(gt, >, !BN_is_negative(a) && !BN_is_zero(a))
+DEFINE_BN_COMPARISONS(ge, >=, !BN_is_negative(a) || BN_is_zero(a))
+DEFINE_BN_COMPARISONS(lt, <, BN_is_negative(a) && !BN_is_zero(a))
+DEFINE_BN_COMPARISONS(le, <=, BN_is_negative(a) || BN_is_zero(a))
+
+int test_BN_eq_one(const char *file, int line, const char *s, const BIGNUM *a)
+{
+ if (a != NULL && BN_is_one(a))
+ return 1;
+ test_fail_bignum_mono_message(NULL, file, line, "BIGNUM", s, "1", "==", a);
+ return 0;
+}
+
+int test_BN_odd(const char *file, int line, const char *s, const BIGNUM *a)
+{
+ if (a != NULL && BN_is_odd(a))
+ return 1;
+ test_fail_bignum_mono_message(NULL, file, line, "BIGNUM", "ODD(", ")", s, a);
+ return 0;
+}
+
+int test_BN_even(const char *file, int line, const char *s, const BIGNUM *a)
+{
+ if (a != NULL && !BN_is_odd(a))
+ return 1;
+ test_fail_bignum_mono_message(NULL, file, line, "BIGNUM", "EVEN(", ")", s,
+ a);
+ return 0;
+}
+
+int test_BN_eq_word(const char *file, int line, const char *bns, const char *ws,
+ const BIGNUM *a, BN_ULONG w)
+{
+ BIGNUM *bw;
+
+ if (a != NULL && BN_is_word(a, w))
+ return 1;
+ if ((bw = BN_new()) != NULL)
+ BN_set_word(bw, w);
+ test_fail_bignum_message(NULL, file, line, "BIGNUM", bns, ws, "==", a, bw);
+ BN_free(bw);
+ return 0;
+}
+
+int test_BN_abs_eq_word(const char *file, int line, const char *bns,
+ const char *ws, const BIGNUM *a, BN_ULONG w)
+{
+ BIGNUM *bw, *aa;
+
+ if (a != NULL && BN_abs_is_word(a, w))
+ return 1;
+ if ((aa = BN_dup(a)) != NULL)
+ BN_set_negative(aa, 0);
+ if ((bw = BN_new()) != NULL)
+ BN_set_word(bw, w);
+ test_fail_bignum_message(NULL, file, line, "BIGNUM", bns, ws, "abs==",
+ aa, bw);
+ BN_free(bw);
+ BN_free(aa);
+ return 0;
+}
+
+static const char *print_time(const ASN1_TIME *t)
+{
+ return t == NULL ? "<null>" : (const char *)ASN1_STRING_get0_data(t);
+}
+
+#define DEFINE_TIME_T_COMPARISON(opname, op) \
+ int test_time_t_ ## opname(const char *file, int line, \
+ const char *s1, const char *s2, \
+ const time_t t1, const time_t t2) \
+ { \
+ ASN1_TIME *at1 = ASN1_TIME_set(NULL, t1); \
+ ASN1_TIME *at2 = ASN1_TIME_set(NULL, t2); \
+ int r = at1 != NULL && at2 != NULL \
+ && ASN1_TIME_compare(at1, at2) op 0; \
+ if (!r) \
+ test_fail_message(NULL, file, line, "time_t", s1, s2, #op, \
+ "[%s] compared to [%s]", \
+ print_time(at1), print_time(at2)); \
+ ASN1_STRING_free(at1); \
+ ASN1_STRING_free(at2); \
+ return r; \
+ }
+DEFINE_TIME_T_COMPARISON(eq, ==)
+DEFINE_TIME_T_COMPARISON(ne, !=)
+DEFINE_TIME_T_COMPARISON(gt, >)
+DEFINE_TIME_T_COMPARISON(ge, >=)
+DEFINE_TIME_T_COMPARISON(lt, <)
+DEFINE_TIME_T_COMPARISON(le, <=)
diff --git a/test/testutil/testutil_init.c b/test/testutil/testutil_init.c
new file mode 100644
index 000000000000..87013694c29e
--- /dev/null
+++ b/test/testutil/testutil_init.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2017-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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <string.h>
+#include <openssl/opensslconf.h>
+#include <openssl/trace.h>
+#include "apps.h"
+#include "../testutil.h"
+
+#ifndef OPENSSL_NO_TRACE
+typedef struct tracedata_st {
+ BIO *bio;
+ unsigned int ingroup:1;
+} tracedata;
+
+static size_t internal_trace_cb(const char *buf, size_t cnt,
+ int category, int cmd, void *vdata)
+{
+ int ret = 0;
+ tracedata *trace_data = vdata;
+ char buffer[256], *hex;
+ CRYPTO_THREAD_ID tid;
+
+ switch (cmd) {
+ case OSSL_TRACE_CTRL_BEGIN:
+ trace_data->ingroup = 1;
+
+ tid = CRYPTO_THREAD_get_current_id();
+ hex = OPENSSL_buf2hexstr((const unsigned char *)&tid, sizeof(tid));
+ BIO_snprintf(buffer, sizeof(buffer), "TRACE[%s]:%s: ",
+ hex, OSSL_trace_get_category_name(category));
+ OPENSSL_free(hex);
+ BIO_set_prefix(trace_data->bio, buffer);
+ break;
+ case OSSL_TRACE_CTRL_WRITE:
+ ret = BIO_write(trace_data->bio, buf, cnt);
+ break;
+ case OSSL_TRACE_CTRL_END:
+ trace_data->ingroup = 0;
+
+ BIO_set_prefix(trace_data->bio, NULL);
+ break;
+ }
+
+ return ret < 0 ? 0 : ret;
+}
+
+DEFINE_STACK_OF(tracedata)
+static STACK_OF(tracedata) *trace_data_stack;
+
+static void tracedata_free(tracedata *data)
+{
+ BIO_free_all(data->bio);
+ OPENSSL_free(data);
+}
+
+static STACK_OF(tracedata) *trace_data_stack;
+
+static void cleanup_trace(void)
+{
+ sk_tracedata_pop_free(trace_data_stack, tracedata_free);
+}
+
+static void setup_trace_category(int category)
+{
+ BIO *channel;
+ tracedata *trace_data;
+ BIO *bio = NULL;
+
+ if (OSSL_trace_enabled(category))
+ return;
+
+ bio = BIO_new(BIO_f_prefix());
+ channel = BIO_push(bio,
+ BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT));
+ trace_data = OPENSSL_zalloc(sizeof(*trace_data));
+
+ if (trace_data == NULL
+ || bio == NULL
+ || (trace_data->bio = channel) == NULL
+ || OSSL_trace_set_callback(category, internal_trace_cb,
+ trace_data) == 0
+ || sk_tracedata_push(trace_data_stack, trace_data) == 0) {
+
+ fprintf(stderr,
+ "warning: unable to setup trace callback for category '%s'.\n",
+ OSSL_trace_get_category_name(category));
+
+ OSSL_trace_set_callback(category, NULL, NULL);
+ BIO_free_all(channel);
+ }
+}
+
+static void setup_trace(const char *str)
+{
+ char *val;
+
+ /*
+ * We add this handler as early as possible to ensure it's executed
+ * as late as possible, i.e. after the TRACE code has done its cleanup
+ * (which happens last in OPENSSL_cleanup).
+ */
+ atexit(cleanup_trace);
+
+ trace_data_stack = sk_tracedata_new_null();
+ val = OPENSSL_strdup(str);
+
+ if (val != NULL) {
+ char *valp = val;
+ char *item;
+
+ for (valp = val; (item = strtok(valp, ",")) != NULL; valp = NULL) {
+ int category = OSSL_trace_get_category_num(item);
+
+ if (category == OSSL_TRACE_CATEGORY_ALL) {
+ while (++category < OSSL_TRACE_CATEGORY_NUM)
+ setup_trace_category(category);
+ break;
+ } else if (category > 0) {
+ setup_trace_category(category);
+ } else {
+ fprintf(stderr,
+ "warning: unknown trace category: '%s'.\n", item);
+ }
+ }
+ }
+
+ OPENSSL_free(val);
+}
+#endif /* OPENSSL_NO_TRACE */
+
+int global_init(void)
+{
+#ifndef OPENSSL_NO_TRACE
+ setup_trace(getenv("OPENSSL_TRACE"));
+#endif
+
+ return 1;
+}
diff --git a/test/testutil/tu_local.h b/test/testutil/tu_local.h
new file mode 100644
index 000000000000..ede4546948ff
--- /dev/null
+++ b/test/testutil/tu_local.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2017-2018 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
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <stdlib.h> /* size_t */
+#include <openssl/bn.h>
+#include <openssl/bio.h>
+#include "../testutil.h"
+
+#define TEST_SKIP_CODE 123
+
+int subtest_level(void);
+int openssl_error_cb(const char *str, size_t len, void *u);
+const BIO_METHOD *BIO_f_tap(void);
+
+void test_fail_message_prefix(const char *prefix, const char *file,
+ int line, const char *type,
+ const char *left, const char *right,
+ const char *op);
+
+void test_fail_string_message(const char *prefix, const char *file,
+ int line, const char *type,
+ const char *left, const char *right,
+ const char *op, const char *m1, size_t l1,
+ const char *m2, size_t l2);
+
+void test_fail_bignum_message(const char *prefix, const char *file,
+ int line, const char *type,
+ const char *left, const char *right,
+ const char *op,
+ const BIGNUM *bn1, const BIGNUM *bn2);
+void test_fail_bignum_mono_message(const char *prefix, const char *file,
+ int line, const char *type,
+ const char *left, const char *right,
+ const char *op, const BIGNUM *bn);
+
+void test_fail_memory_message(const char *prefix, const char *file,
+ int line, const char *type,
+ const char *left, const char *right,
+ const char *op,
+ const unsigned char *m1, size_t l1,
+ const unsigned char *m2, size_t l2);
+
+__owur int setup_test_framework(int argc, char *argv[]);
+__owur int pulldown_test_framework(int ret);
+
+__owur int run_tests(const char *test_prog_name);
+void set_test_title(const char *title);
+
+typedef enum OPTION_choice_default {
+ OPT_ERR = -1,
+ OPT_EOF = 0,
+ OPT_TEST_ENUM
+} OPTION_CHOICE_DEFAULT;
+void opt_check_usage(void);
+