diff options
Diffstat (limited to 'test/testutil/provider.c')
-rw-r--r-- | test/testutil/provider.c | 242 |
1 files changed, 242 insertions, 0 deletions
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; +} |