diff options
-rw-r--r-- | crypto/evp/evp_fetch.c | 11 | ||||
-rw-r--r-- | crypto/property/property.c | 21 | ||||
-rw-r--r-- | crypto/provider.c | 6 | ||||
-rw-r--r-- | crypto/provider_core.c | 19 | ||||
-rw-r--r-- | crypto/sparse_array.c | 2 | ||||
-rw-r--r-- | doc/man3/OSSL_PROVIDER.pod | 14 | ||||
-rw-r--r-- | doc/man7/provider-base.pod | 11 | ||||
-rw-r--r-- | include/crypto/evp.h | 1 | ||||
-rw-r--r-- | include/internal/property.h | 3 | ||||
-rw-r--r-- | include/internal/provider.h | 1 | ||||
-rw-r--r-- | include/openssl/core_dispatch.h | 2 | ||||
-rw-r--r-- | include/openssl/core_names.h | 1 | ||||
-rw-r--r-- | include/openssl/provider.h | 1 | ||||
-rw-r--r-- | providers/defltprov.c | 4 | ||||
-rw-r--r-- | providers/fips/fipsprov.c | 56 | ||||
-rw-r--r-- | providers/fips/self_test.c | 7 | ||||
-rw-r--r-- | providers/fips/self_test.h | 1 | ||||
-rw-r--r-- | providers/legacyprov.c | 4 | ||||
-rw-r--r-- | test/build.info | 6 | ||||
-rw-r--r-- | test/provider_status_test.c | 185 | ||||
-rw-r--r-- | test/recipes/30-test_provider_status.t | 40 | ||||
-rw-r--r-- | util/libcrypto.num | 1 |
22 files changed, 364 insertions, 33 deletions
diff --git a/crypto/evp/evp_fetch.c b/crypto/evp/evp_fetch.c index 5cb59d98fc..4c3992ab40 100644 --- a/crypto/evp/evp_fetch.c +++ b/crypto/evp/evp_fetch.c @@ -17,6 +17,7 @@ #include "internal/core.h" #include "internal/provider.h" #include "internal/namemap.h" +#include "internal/property.h" #include "crypto/evp.h" /* evp_local.h needs it */ #include "evp_local.h" @@ -368,6 +369,14 @@ void *evp_generic_fetch_by_number(OPENSSL_CTX *libctx, int operation_id, return ret; } +void evp_method_store_flush(OPENSSL_CTX *libctx) +{ + OSSL_METHOD_STORE *store = get_evp_method_store(libctx); + + if (store != NULL) + ossl_method_store_flush_cache(store, 1); +} + static int evp_set_default_properties(OPENSSL_CTX *libctx, OSSL_PROPERTY_LIST *def_prop) { @@ -378,7 +387,7 @@ static int evp_set_default_properties(OPENSSL_CTX *libctx, ossl_property_free(*plp); *plp = def_prop; if (store != NULL) - ossl_method_store_flush_cache(store); + ossl_method_store_flush_cache(store, 0); return 1; } EVPerr(0, ERR_R_INTERNAL_ERROR); diff --git a/crypto/property/property.c b/crypto/property/property.c index 645e361b0a..cb82f8956b 100644 --- a/crypto/property/property.c +++ b/crypto/property/property.c @@ -394,10 +394,19 @@ fin: return ret; } -static void impl_cache_flush_alg(ossl_uintmax_t idx, ALGORITHM *alg) +static void impl_cache_flush_alg(ossl_uintmax_t idx, ALGORITHM *alg, void *arg) { + SPARSE_ARRAY_OF(ALGORITHM) *algs = arg; + lh_QUERY_doall(alg->cache, &impl_cache_free); - lh_QUERY_flush(alg->cache); + if (algs != NULL) { + sk_IMPLEMENTATION_pop_free(alg->impls, &impl_free); + lh_QUERY_free(alg->cache); + OPENSSL_free(alg); + ossl_sa_ALGORITHM_set(algs, idx, NULL); + } else { + lh_QUERY_flush(alg->cache); + } } static void ossl_method_cache_flush(OSSL_METHOD_STORE *store, int nid) @@ -406,14 +415,16 @@ static void ossl_method_cache_flush(OSSL_METHOD_STORE *store, int nid) if (alg != NULL) { store->nelem -= lh_QUERY_num_items(alg->cache); - impl_cache_flush_alg(0, alg); + impl_cache_flush_alg(0, alg, NULL); } } -void ossl_method_store_flush_cache(OSSL_METHOD_STORE *store) +void ossl_method_store_flush_cache(OSSL_METHOD_STORE *store, int all) { + void *arg = (all != 0 ? store->algs : NULL); + ossl_property_write_lock(store); - ossl_sa_ALGORITHM_doall(store->algs, &impl_cache_flush_alg); + ossl_sa_ALGORITHM_doall_arg(store->algs, &impl_cache_flush_alg, arg); store->nelem = 0; ossl_property_unlock(store); } diff --git a/crypto/provider.c b/crypto/provider.c index 8646aef771..40c837d8c0 100644 --- a/crypto/provider.c +++ b/crypto/provider.c @@ -10,6 +10,7 @@ #include <openssl/err.h> #include <openssl/cryptoerr.h> #include <openssl/provider.h> +#include <openssl/core_names.h> #include "internal/provider.h" OSSL_PROVIDER *OSSL_PROVIDER_load(OPENSSL_CTX *libctx, const char *name) @@ -69,6 +70,11 @@ void *OSSL_PROVIDER_get0_provider_ctx(const OSSL_PROVIDER *prov) return ossl_provider_prov_ctx(prov); } +int OSSL_PROVIDER_self_test(const OSSL_PROVIDER *prov) +{ + return ossl_provider_self_test(prov); +} + int OSSL_PROVIDER_get_capabilities(const OSSL_PROVIDER *prov, const char *capability, OSSL_CALLBACK *cb, diff --git a/crypto/provider_core.c b/crypto/provider_core.c index 79c330383c..4b5b013608 100644 --- a/crypto/provider_core.c +++ b/crypto/provider_core.c @@ -14,6 +14,7 @@ #include <openssl/params.h> #include <openssl/opensslv.h> #include "crypto/cryptlib.h" +#include "crypto/evp.h" /* evp_method_store_flush */ #include "internal/nelem.h" #include "internal/thread_once.h" #include "internal/provider.h" @@ -71,6 +72,7 @@ struct ossl_provider_st { OSSL_FUNC_provider_gettable_params_fn *gettable_params; OSSL_FUNC_provider_get_params_fn *get_params; OSSL_FUNC_provider_get_capabilities_fn *get_capabilities; + OSSL_FUNC_provider_self_test_fn *self_test; OSSL_FUNC_provider_query_operation_fn *query_operation; /* @@ -544,6 +546,10 @@ static int provider_activate(OSSL_PROVIDER *prov) prov->get_params = OSSL_FUNC_provider_get_params(provider_dispatch); break; + case OSSL_FUNC_PROVIDER_SELF_TEST: + prov->self_test = + OSSL_FUNC_provider_self_test(provider_dispatch); + break; case OSSL_FUNC_PROVIDER_GET_CAPABILITIES: prov->get_capabilities = OSSL_FUNC_provider_get_capabilities(provider_dispatch); @@ -824,6 +830,18 @@ int ossl_provider_get_params(const OSSL_PROVIDER *prov, OSSL_PARAM params[]) ? 0 : prov->get_params(prov->provctx, params); } +int ossl_provider_self_test(const OSSL_PROVIDER *prov) +{ + int ret; + + if (prov->self_test == NULL) + return 1; + ret = prov->self_test(prov->provctx); + if (ret == 0) + evp_method_store_flush(ossl_provider_library_context(prov)); + return ret; +} + int ossl_provider_get_capabilities(const OSSL_PROVIDER *prov, const char *capability, OSSL_CALLBACK *cb, @@ -833,7 +851,6 @@ int ossl_provider_get_capabilities(const OSSL_PROVIDER *prov, ? 1 : prov->get_capabilities(prov->provctx, capability, cb, arg); } - const OSSL_ALGORITHM *ossl_provider_query_operation(const OSSL_PROVIDER *prov, int operation_id, int *no_cache) diff --git a/crypto/sparse_array.c b/crypto/sparse_array.c index 9d444739f5..69a56db01c 100644 --- a/crypto/sparse_array.c +++ b/crypto/sparse_array.c @@ -162,7 +162,7 @@ void *OPENSSL_SA_get(const OPENSSL_SA *sa, ossl_uintmax_t n) int level; void **p, *r = NULL; - if (sa == NULL) + if (sa == NULL || sa->nelem == 0) return NULL; if (n <= sa->top) { diff --git a/doc/man3/OSSL_PROVIDER.pod b/doc/man3/OSSL_PROVIDER.pod index 63633842fa..6a1fdd204e 100644 --- a/doc/man3/OSSL_PROVIDER.pod +++ b/doc/man3/OSSL_PROVIDER.pod @@ -8,7 +8,8 @@ OSSL_PROVIDER_available, OSSL_PROVIDER_do_all, OSSL_PROVIDER_gettable_params, OSSL_PROVIDER_get_params, OSSL_PROVIDER_query_operation, OSSL_PROVIDER_get0_provider_ctx, OSSL_PROVIDER_add_builtin, OSSL_PROVIDER_name, -OSSL_PROVIDER_get_capabilities - provider routines +OSSL_PROVIDER_get_capabilities, OSSL_PROVIDER_self_test +- provider routines =head1 SYNOPSIS @@ -43,7 +44,7 @@ OSSL_PROVIDER_get_capabilities - provider routines const char *capability, OSSL_CALLBACK *cb, void *arg); - + int OSSL_PROVIDER_self_test(const OSSL_PROVIDER *prov); =head1 DESCRIPTION @@ -95,6 +96,11 @@ The caller must prepare the B<OSSL_PARAM> array before calling this function, and the variables acting as buffers for this parameter array should be filled with data when it returns successfully. +OSSL_PROVIDER_self_test() is used to run a provider's self tests on demand. +If the self tests fail then the provider will fail to provide any further +services and algorithms. L<OSSL_SELF_TEST_set_callback(3)> may be called +beforehand in order to display diagnostics for the running self tests. + OSSL_PROVIDER_query_operation() calls the provider's I<query_operation> function (see L<provider(7)>), if the provider has one. It returns an array of I<OSSL_ALGORITHM> for the given I<operation_id> terminated by an all @@ -133,11 +139,13 @@ otherwise 0. OSSL_PROVIDER_gettable_params() returns a pointer to an array of constant B<OSSL_PARAM>, or NULL if none is provided. -OSSL_PROVIDER_get_params() returns 1 on success, or 0 on error. +OSSL_PROVIDER_get_params() and returns 1 on success, or 0 on error. OSSL_PROVIDER_query_operation() returns an array of OSSL_ALGORITHM or NULL on error. +OSSL_PROVIDER_self_test() returns 1 if the self tests pass, or 0 on error. + =head1 EXAMPLES This demonstrates how to load the provider module "foo" and ask for diff --git a/doc/man7/provider-base.pod b/doc/man7/provider-base.pod index d61645f961..efec869e25 100644 --- a/doc/man7/provider-base.pod +++ b/doc/man7/provider-base.pod @@ -139,6 +139,7 @@ F<libcrypto>): provider_query_operation OSSL_FUNC_PROVIDER_QUERY_OPERATION provider_get_reason_strings OSSL_FUNC_PROVIDER_GET_REASON_STRINGS provider_get_capabilities OSSL_FUNC_PROVIDER_GET_CAPABILITIES + provider_self_test OSSL_FUNC_PROVIDER_SELF_TEST =head2 Core functions @@ -241,6 +242,11 @@ callback multiple times (one for each capability). Capabilities can be useful fo describing the services that a provider can offer. For further details see the L</CAPABILITIES> section below. It should return 1 on success or 0 on error. +The provider_self_test() function should perform known answer tests on a subset +of the algorithms that it uses, and may also verify the integrity of the +provider module. It should return 1 on success or 0 on error. It will return 1 +if this function is not used. + None of these functions are mandatory, but a provider is fairly useless without at least provider_query_operation(), and provider_gettable_params() is fairly useless if not accompanied by @@ -268,6 +274,11 @@ This points to a string that is a build information associated with this provide OpenSSL in-built providers use OPENSSL_FULL_VERSION_STR, but this may be different for any third party provider. +=item "status" (B<OSSL_PROV_PARAM_STATUS>) <unsigned integer> + +This returns 0 if the provider has entered an error state, otherwise it returns +1. + =back provider_gettable_params() should return the above parameters. diff --git a/include/crypto/evp.h b/include/crypto/evp.h index f60ae9bc09..07e9ef4bb3 100644 --- a/include/crypto/evp.h +++ b/include/crypto/evp.h @@ -778,3 +778,4 @@ int evp_pkey_ctx_get_params_strict(EVP_PKEY_CTX *ctx, OSSL_PARAM *params); EVP_PKEY *evp_pkcs82pkey_int(const PKCS8_PRIV_KEY_INFO *p8, OPENSSL_CTX *libctx, const char *propq); #endif /* !defined(FIPS_MODULE) */ +void evp_method_store_flush(OPENSSL_CTX *libctx); diff --git a/include/internal/property.h b/include/internal/property.h index d8ff3582eb..ca1d1e055c 100644 --- a/include/internal/property.h +++ b/include/internal/property.h @@ -54,7 +54,8 @@ int ossl_method_store_cache_set(OSSL_METHOD_STORE *store, int nid, const char *prop_query, void *result, int (*method_up_ref)(void *), void (*method_destruct)(void *)); -void ossl_method_store_flush_cache(OSSL_METHOD_STORE *store); + +void ossl_method_store_flush_cache(OSSL_METHOD_STORE *store, int all); /* Merge two property queries together */ OSSL_PROPERTY_LIST *ossl_property_merge(const OSSL_PROPERTY_LIST *a, diff --git a/include/internal/provider.h b/include/internal/provider.h index dcd57708ba..38bbd3bbef 100644 --- a/include/internal/provider.h +++ b/include/internal/provider.h @@ -75,6 +75,7 @@ int ossl_provider_get_capabilities(const OSSL_PROVIDER *prov, const char *capability, OSSL_CALLBACK *cb, void *arg); +int ossl_provider_self_test(const OSSL_PROVIDER *prov); const OSSL_ALGORITHM *ossl_provider_query_operation(const OSSL_PROVIDER *prov, int operation_id, int *no_cache); diff --git a/include/openssl/core_dispatch.h b/include/openssl/core_dispatch.h index a3f5107aff..55144f126b 100644 --- a/include/openssl/core_dispatch.h +++ b/include/openssl/core_dispatch.h @@ -176,6 +176,8 @@ OSSL_CORE_MAKE_FUNC(const OSSL_ITEM *,provider_get_reason_strings, # define OSSL_FUNC_PROVIDER_GET_CAPABILITIES 1029 OSSL_CORE_MAKE_FUNC(int, provider_get_capabilities, (void *provctx, const char *capability, OSSL_CALLBACK *cb, void *arg)) +# define OSSL_FUNC_PROVIDER_SELF_TEST 1030 +OSSL_CORE_MAKE_FUNC(int, provider_self_test, (void *provctx)) /* Operations */ diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h index 9ce4115a89..b511571fb3 100644 --- a/include/openssl/core_names.h +++ b/include/openssl/core_names.h @@ -23,6 +23,7 @@ extern "C" { #define OSSL_PROV_PARAM_NAME "name" /* utf8_string */ #define OSSL_PROV_PARAM_VERSION "version" /* utf8_string */ #define OSSL_PROV_PARAM_BUILDINFO "buildinfo" /* utf8_string */ +#define OSSL_PROV_PARAM_STATUS "status" /* uint */ /* Self test callback parameters */ #define OSSL_PROV_PARAM_SELF_TEST_PHASE "st-phase" /* utf8_string */ diff --git a/include/openssl/provider.h b/include/openssl/provider.h index cb5fc9f8bf..5470984e13 100644 --- a/include/openssl/provider.h +++ b/include/openssl/provider.h @@ -29,6 +29,7 @@ int OSSL_PROVIDER_do_all(OPENSSL_CTX *ctx, const OSSL_PARAM *OSSL_PROVIDER_gettable_params(const OSSL_PROVIDER *prov); int OSSL_PROVIDER_get_params(const OSSL_PROVIDER *prov, OSSL_PARAM params[]); +int OSSL_PROVIDER_self_test(const OSSL_PROVIDER *prov); int OSSL_PROVIDER_get_capabilities(const OSSL_PROVIDER *prov, const char *capability, OSSL_CALLBACK *cb, diff --git a/providers/defltprov.c b/providers/defltprov.c index 0ee717acac..4ab39e6531 100644 --- a/providers/defltprov.c +++ b/providers/defltprov.c @@ -62,7 +62,9 @@ static int deflt_get_params(void *provctx, OSSL_PARAM params[]) p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_BUILDINFO); if (p != NULL && !OSSL_PARAM_set_utf8_ptr(p, OPENSSL_FULL_VERSION_STR)) return 0; - + p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_STATUS); + if (p != NULL && !OSSL_PARAM_set_uint(p, 1)) + return 0; return 1; } diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c index 73bba5b3a9..e39c306e48 100644 --- a/providers/fips/fipsprov.c +++ b/providers/fips/fipsprov.c @@ -69,6 +69,8 @@ static OSSL_FUNC_CRYPTO_secure_free_fn *c_CRYPTO_secure_free; static OSSL_FUNC_CRYPTO_secure_clear_free_fn *c_CRYPTO_secure_clear_free; static OSSL_FUNC_CRYPTO_secure_allocated_fn *c_CRYPTO_secure_allocated; static OSSL_FUNC_BIO_vsnprintf_fn *c_BIO_vsnprintf; +static OSSL_FUNC_self_test_cb_fn *c_stcbfn = NULL; +static OSSL_FUNC_core_get_library_context_fn *c_get_libctx = NULL; typedef struct fips_global_st { const OSSL_CORE_HANDLE *handle; @@ -97,6 +99,7 @@ static const OSSL_PARAM fips_param_types[] = { OSSL_PARAM_DEFN(OSSL_PROV_PARAM_NAME, OSSL_PARAM_UTF8_PTR, NULL, 0), OSSL_PARAM_DEFN(OSSL_PROV_PARAM_VERSION, OSSL_PARAM_UTF8_PTR, NULL, 0), OSSL_PARAM_DEFN(OSSL_PROV_PARAM_BUILDINFO, OSSL_PARAM_UTF8_PTR, NULL, 0), + OSSL_PARAM_DEFN(OSSL_PROV_PARAM_STATUS, OSSL_PARAM_UNSIGNED_INTEGER, NULL, 0), OSSL_PARAM_END }; @@ -144,10 +147,29 @@ static int fips_get_params(void *provctx, OSSL_PARAM params[]) p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_BUILDINFO); if (p != NULL && !OSSL_PARAM_set_utf8_ptr(p, OPENSSL_FULL_VERSION_STR)) return 0; - + p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_STATUS); + if (p != NULL && !OSSL_PARAM_set_uint(p, FIPS_is_running())) + return 0; return 1; } +static void set_self_test_cb(const OSSL_CORE_HANDLE *handle) +{ + if (c_stcbfn != NULL && c_get_libctx != NULL) { + c_stcbfn(c_get_libctx(handle), &selftest_params.cb, + &selftest_params.cb_arg); + } else { + selftest_params.cb = NULL; + selftest_params.cb_arg = NULL; + } +} + +static int fips_self_test(void *provctx) +{ + set_self_test_cb(FIPS_get_core_handle(selftest_params.libctx)); + return SELF_TEST_post(&selftest_params, 1) ? 1 : 0; +} + /* FIPS specific version of the function of the same name in provlib.c */ /* TODO(3.0) - Is this function needed ? */ const char *ossl_prov_util_nid_to_name(int nid) @@ -444,6 +466,10 @@ static const OSSL_ALGORITHM *fips_query(void *provctx, int operation_id, int *no_cache) { *no_cache = 0; + + if (!FIPS_is_running()) + return NULL; + switch (operation_id) { case OSSL_OP_DIGEST: return fips_digests; @@ -489,7 +515,9 @@ static const OSSL_DISPATCH fips_dispatch_table[] = { { OSSL_FUNC_PROVIDER_GETTABLE_PARAMS, (void (*)(void))fips_gettable_params }, { OSSL_FUNC_PROVIDER_GET_PARAMS, (void (*)(void))fips_get_params }, { OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))fips_query }, - { OSSL_FUNC_PROVIDER_GET_CAPABILITIES, (void (*)(void))provider_get_capabilities }, + { OSSL_FUNC_PROVIDER_GET_CAPABILITIES, + (void (*)(void))provider_get_capabilities }, + { OSSL_FUNC_PROVIDER_SELF_TEST, (void (*)(void))fips_self_test }, { 0, NULL } }; @@ -500,7 +528,6 @@ static const OSSL_DISPATCH intern_dispatch_table[] = { { 0, NULL } }; - int OSSL_provider_init(const OSSL_CORE_HANDLE *handle, const OSSL_DISPATCH *in, const OSSL_DISPATCH **out, @@ -508,8 +535,6 @@ int OSSL_provider_init(const OSSL_CORE_HANDLE *handle, { FIPS_GLOBAL *fgbl; OPENSSL_CTX *libctx = NULL; - OSSL_FUNC_self_test_cb_fn *stcbfn = NULL; - OSSL_FUNC_core_get_library_context_fn *c_get_libctx = NULL; for (; in->function_id != 0; in++) { switch (in->function_id) { @@ -592,7 +617,7 @@ int OSSL_provider_init(const OSSL_CORE_HANDLE *handle, c_BIO_vsnprintf = OSSL_FUNC_BIO_vsnprintf(in); break; case OSSL_FUNC_SELF_TEST_CB: { - stcbfn = OSSL_FUNC_self_test_cb(in); + c_stcbfn = OSSL_FUNC_self_test_cb(in); break; } default: @@ -601,14 +626,7 @@ int OSSL_provider_init(const OSSL_CORE_HANDLE *handle, } } - if (stcbfn != NULL && c_get_libctx != NULL) { - stcbfn(c_get_libctx(handle), &selftest_params.cb, - &selftest_params.cb_arg); - } - else { - selftest_params.cb = NULL; - selftest_params.cb_arg = NULL; - } + set_self_test_cb(handle); if (!c_get_params(handle, core_params)) { ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); @@ -665,29 +683,31 @@ int fips_intern_provider_init(const OSSL_CORE_HANDLE *handle, const OSSL_DISPATCH **out, void **provctx) { - OSSL_FUNC_core_get_library_context_fn *c_get_libctx = NULL; + OSSL_FUNC_core_get_library_context_fn *c_internal_get_libctx = NULL; for (; in->function_id != 0; in++) { switch (in->function_id) { case OSSL_FUNC_CORE_GET_LIBRARY_CONTEXT: - c_get_libctx = OSSL_FUNC_core_get_library_context(in); + c_internal_get_libctx = OSSL_FUNC_core_get_library_context(in); break; default: break; } } - if (c_get_libctx == NULL) + if (c_internal_get_libctx == NULL) return 0; if ((*provctx = PROV_CTX_new()) == NULL) return 0; + /* * Using the parent library context only works because we are a built-in * internal provider. This is not something that most providers would be * able to do. */ - PROV_CTX_set0_library_context(*provctx, (OPENSSL_CTX *)c_get_libctx(handle)); + PROV_CTX_set0_library_context(*provctx, + (OPENSSL_CTX *)c_internal_get_libctx(handle)); PROV_CTX_set0_handle(*provctx, handle); *out = intern_dispatch_table; diff --git a/providers/fips/self_test.c b/providers/fips/self_test.c index 8902510b44..978440adf1 100644 --- a/providers/fips/self_test.c +++ b/providers/fips/self_test.c @@ -305,3 +305,10 @@ end: return ok; } + + +unsigned int FIPS_is_running(void) +{ + return FIPS_state == FIPS_STATE_RUNNING + || FIPS_state == FIPS_STATE_SELFTEST; +} diff --git a/providers/fips/self_test.h b/providers/fips/self_test.h index 20f8a12472..f40788581c 100644 --- a/providers/fips/self_test.h +++ b/providers/fips/self_test.h @@ -34,3 +34,4 @@ typedef struct self_test_post_params_st { int SELF_TEST_post(SELF_TEST_POST_PARAMS *st, int on_demand_test); int SELF_TEST_kats(OSSL_SELF_TEST *event, OPENSSL_CTX *libctx); +unsigned int FIPS_is_running(void); diff --git a/providers/legacyprov.c b/providers/legacyprov.c index 40d24873a2..549906a68a 100644 --- a/providers/legacyprov.c +++ b/providers/legacyprov.c @@ -61,7 +61,9 @@ static int legacy_get_params(void *provctx, OSSL_PARAM params[]) p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_BUILDINFO); if (p != NULL && !OSSL_PARAM_set_utf8_ptr(p, OPENSSL_FULL_VERSION_STR)) return 0; - + p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_STATUS); + if (p != NULL && !OSSL_PARAM_set_uint(p, 1)) + return 0; return 1; } diff --git a/test/build.info b/test/build.info index d8a585e615..1dd3db7c79 100644 --- a/test/build.info +++ b/test/build.info @@ -57,7 +57,7 @@ IF[{- !$disabled{tests} -}] http_test servername_test ocspapitest fatalerrtest tls13ccstest \ sysdefaulttest errtest ssl_ctx_test gosttest \ context_internal_test aesgcmtest params_test evp_pkey_dparams_test \ - keymgmt_internal_test hexstr_test + keymgmt_internal_test hexstr_test provider_status_test IF[{- !$disabled{'deprecated-3.0'} -}] PROGRAMS{noinst}=enginetest @@ -166,6 +166,10 @@ IF[{- !$disabled{tests} -}] DEPEND[acvp_test]=../libcrypto.a libtestutil.a ENDIF + SOURCE[provider_status_test]=provider_status_test.c + INCLUDE[provider_status_test]=../include ../apps/include + DEPEND[provider_status_test]=../libcrypto.a libtestutil.a + IF[{- !$disabled{'deprecated-3.0'} -}] PROGRAMS{noinst}=igetest bftest casttest diff --git a/test/provider_status_test.c b/test/provider_status_test.c new file mode 100644 index 0000000000..83572e81f8 --- /dev/null +++ b/test/provider_status_test.c @@ -0,0 +1,185 @@ +/* + * Copyright 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 <stddef.h> +#include <string.h> +#include <openssl/provider.h> +#include <openssl/params.h> +#include <openssl/core_names.h> +#include <openssl/self_test.h> +#include <openssl/evp.h> +#include "testutil.h" + +typedef enum OPTION_choice { + OPT_ERR = -1, + OPT_EOF = 0, + OPT_PROVIDER_NAME, + OPT_CONFIG_FILE, + OPT_TEST_ENUM +} OPTION_CHOICE; + +struct self_test_arg { + int count; +}; + +static OPENSSL_CTX *libctx = NULL; +static char *provider_name = NULL; +static struct self_test_arg self_test_args = { 0 }; + +const OPTIONS *test_get_options(void) +{ + static const OPTIONS test_options[] = { + OPT_TEST_OPTIONS_DEFAULT_USAGE, + { "provider_name", OPT_PROVIDER_NAME, 's', + "The name of the provider to load" }, + { "config", OPT_CONFIG_FILE, '<', + "The configuration file to use for the libctx" }, + { NULL } + }; + return test_options; +} + +static int self_test_events(const OSSL_PARAM params[], void *arg, + const char *title, int corrupt) +{ + struct self_test_arg *args = arg; + const OSSL_PARAM *p = NULL; + const char *phase = NULL, *type = NULL, *desc = NULL; + int ret = 0; + + if (args->count == 0) + BIO_printf(bio_out, "\n%s\n", title); + args->count++; + + p = OSSL_PARAM_locate_const(params, OSSL_PROV_PARAM_SELF_TEST_PHASE); + if (p == NULL || p->data_type != OSSL_PARAM_UTF8_STRING) + goto err; + phase = (const char *)p->data; + + p = OSSL_PARAM_locate_const(params, OSSL_PROV_PARAM_SELF_TEST_DESC); + if (p == NULL || p->data_type != OSSL_PARAM_UTF8_STRING) + goto err; + desc = (const char *)p->data; + + p = OSSL_PARAM_locate_const(params, OSSL_PROV_PARAM_SELF_TEST_TYPE); + if (p == NULL || p->data_type != OSSL_PARAM_UTF8_STRING) + goto err; + type = (const char *)p->data; + + if (strcmp(phase, OSSL_SELF_TEST_PHASE_START) == 0) + BIO_printf(bio_out, "%s : (%s) : ", desc, type); + else if (strcmp(phase, OSSL_SELF_TEST_PHASE_PASS) == 0 + || strcmp(phase, OSSL_SELF_TEST_PHASE_FAIL) == 0) + BIO_printf(bio_out, "%s\n", phase); + /* + * The self test code will internally corrupt the KAT test result if an + * error is returned during the corrupt phase. + */ + if (corrupt && strcmp(phase, OSSL_SELF_TEST_PHASE_CORRUPT) == 0) + goto err; + ret = 1; +err: + return ret; +} + +static int self_test_on_demand_fail(const OSSL_PARAM params[], void *arg) +{ + return self_test_events(params, arg, "On Demand Failure", 1); +} + +static int self_test_on_demand(const OSSL_PARAM params[], void *arg) +{ + return self_test_events(params, arg, "On Demand", 0); +} + +static int self_test_on_load(const OSSL_PARAM params[], void *arg) +{ + return self_test_events(params, arg, "On Loading", 0); +} + +static int test_provider_status(void) +{ + int ret = 0; + unsigned int status = 0; + OSSL_PROVIDER *prov = NULL; + OSSL_PARAM params[2]; + EVP_MD *fetch = NULL; + + if (!TEST_ptr(prov = OSSL_PROVIDER_load(libctx, provider_name))) + goto err; + + /* Test that the provider status is ok */ + params[0] = OSSL_PARAM_construct_uint(OSSL_PROV_PARAM_STATUS, &status); + params[1] = OSSL_PARAM_construct_end(); + if (!TEST_true(OSSL_PROVIDER_get_params(prov, params)) + || !TEST_true(status == 1)) + goto err; + if (!TEST_ptr(fetch = EVP_MD_fetch(libctx, "SHA256", NULL))) + goto err; + EVP_MD_free(fetch); + fetch = NULL; + + /* Test that the provider self test is ok */ + self_test_args.count = 0; + OSSL_SELF_TEST_set_callback(libctx, self_test_on_demand, &self_test_args); + if (!TEST_true(OSSL_PROVIDER_self_test(prov))) + goto err; + + /* Setup a callback that corrupts the self tests and causes status failures */ + self_test_args.count = 0; + OSSL_SELF_TEST_set_callback(libctx, self_test_on_demand_fail, &self_test_args); + if (!TEST_false(OSSL_PROVIDER_self_test(prov))) + goto err; + if (!TEST_true(OSSL_PROVIDER_get_params(prov, params)) + || !TEST_uint_eq(status, 0)) + goto err; + if (!TEST_ptr_null(fetch = EVP_MD_fetch(libctx, "SHA256", NULL))) + goto err; + + ret = 1; +err: + EVP_MD_free(fetch); + OSSL_PROVIDER_unload(prov); + return ret; +} + +int setup_tests(void) +{ + OPTION_CHOICE o; + char *config_file = NULL; + + while ((o = opt_next()) != OPT_EOF) { + switch (o) { + case OPT_CONFIG_FILE: + config_file = opt_arg(); + break; + case OPT_PROVIDER_NAME: + provider_name = opt_arg(); + break; + case OPT_TEST_CASES: + break; + default: + case OPT_ERR: + return 0; + } + } + + libctx = OPENSSL_CTX_new(); + if (libctx == NULL) + return 0; + self_test_args.count = 0; + OSSL_SELF_TEST_set_callback(libctx, self_test_on_load, &self_test_args); + + if (!OPENSSL_CTX_load_config(libctx, config_file)) { + opt_printf_stderr("Failed to load config\n"); + return 0; + } + ADD_TEST(test_provider_status); + return 1; +} diff --git a/test/recipes/30-test_provider_status.t b/test/recipes/30-test_provider_status.t new file mode 100644 index 0000000000..03304ba4a2 --- /dev/null +++ b/test/recipes/30-test_provider_status.t @@ -0,0 +1,40 @@ +#! /usr/bin/env perl +# Copyright 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 + + +use strict; +use warnings; + +use OpenSSL::Test qw(:DEFAULT data_file bldtop_dir srctop_file srctop_dir bldtop_file); +use OpenSSL::Test::Utils; + +BEGIN { +setup("test_provider_status"); +} + +use lib srctop_dir('Configurations'); +use lib bldtop_dir('.'); +use platform; + +my $no_fips = disabled('fips') || ($ENV{NO_FIPS} // 0); + +plan skip_all => "provider_status is not supported by this test" + if $no_fips; + +plan tests => 2; + +my $infile = bldtop_file('providers', platform->dso('fips')); + +ok(run(app(['openssl', 'fipsinstall', + '-out', bldtop_file('providers', 'fipsmodule.cnf'), + '-module', $infile])), + "fipsinstall"); + +ok(run(test(["provider_status_test", "-config", srctop_file("test","fips.cnf"), + "-provider_name", "fips"])), + "running provider_status_test"); diff --git a/util/libcrypto.num b/util/libcrypto.num index 8cfe55f4fa..fe875f188d 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5225,3 +5225,4 @@ PKCS7_new_with_libctx ? 3_0_0 EXIST::FUNCTION: PKCS7_sign_with_libctx ? 3_0_0 EXIST::FUNCTION: PKCS7_encrypt_with_libctx ? 3_0_0 EXIST::FUNCTION: SMIME_read_PKCS7_ex ? 3_0_0 EXIST::FUNCTION: +OSSL_PROVIDER_self_test ? 3_0_0 EXIST::FUNCTION: |