Add fips module integrity check
authorShane Lontis <shane.lontis@oracle.com>
Sun, 15 Sep 2019 09:55:10 +0000 (19:55 +1000)
committerShane Lontis <shane.lontis@oracle.com>
Sun, 15 Sep 2019 09:55:10 +0000 (19:55 +1000)
Add environment variable for setting CONF .include path

Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/9769)

18 files changed:
.gitignore
apps/fipsinstall.c
crypto/conf/conf_def.c
crypto/provider_core.c
doc/man5/config.pod
doc/man7/provider-base.pod
include/openssl/core_numbers.h
providers/fips/build.info
providers/fips/fipsprov.c
providers/fips/selftest.c [new file with mode: 0644]
providers/fips/selftest.h
test/build.info
test/default-and-fips.cnf [new file with mode: 0644]
test/evp_extra_test.c
test/evp_fetch_prov_test.c [new file with mode: 0644]
test/fips.cnf
test/recipes/30-test_evp.t
test/recipes/30-test_evp_fetch_prov.t [new file with mode: 0644]

index fb08a3c..9fdd588 100644 (file)
@@ -61,6 +61,8 @@ Makefile
 /test/rsa_complex
 # Other generated files in test/
 /test/provider_internal_test.conf
+/test/fipsinstall.conf
+/providers/fipsinstall.conf
 
 # Certain files that get created by tests on the fly
 /test/test-runs
index 2aedcba..78200c5 100644 (file)
@@ -128,6 +128,7 @@ static int write_config_fips_section(BIO *out, const char *section,
     int ret = 0;
 
     if (!(BIO_printf(out, "[%s]\n", section) > 0
+          && BIO_printf(out, "activate = 1\n") > 0
           && BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_INSTALL_VERSION,
                         VERSION_VAL) > 0
           && print_mac(out, OSSL_PROV_FIPS_PARAM_MODULE_MAC, module_mac,
index cbf0b2b..ff4c43f 100644 (file)
@@ -352,6 +352,8 @@ static int def_load_bio(CONF *conf, BIO *in, long *line)
                 && (p != pname + 8 || *p == '=')) {
                 char *include = NULL;
                 BIO *next;
+                const char *include_dir = ossl_safe_getenv("OPENSSL_CONF_INCLUDE");
+                char *include_path = NULL;
 
                 if (*p == '=') {
                     p++;
@@ -360,17 +362,34 @@ static int def_load_bio(CONF *conf, BIO *in, long *line)
                 trim_ws(conf, p);
                 if (!str_copy(conf, psection, &include, p))
                     goto err;
+
+                if (include_dir != NULL) {
+                    size_t newlen = strlen(include_dir) + strlen(include) + 2;
+
+                    include_path = OPENSSL_malloc(newlen);
+                    OPENSSL_strlcpy(include_path, include_dir, newlen);
+                    OPENSSL_strlcat(include_path, "/", newlen);
+                    OPENSSL_strlcat(include_path, include, newlen);
+                } else {
+                    include_path = include;
+                }
+
                 /* get the BIO of the included file */
 #ifndef OPENSSL_NO_POSIX_IO
-                next = process_include(include, &dirctx, &dirpath);
-                if (include != dirpath) {
+                next = process_include(include_path, &dirctx, &dirpath);
+                if (include_path != dirpath) {
                     /* dirpath will contain include in case of a directory */
                     OPENSSL_free(include);
+                    if (include_path != include)
+                        OPENSSL_free(include_path);
                 }
 #else
-                next = BIO_new_file(include, "r");
+                next = BIO_new_file(include_path, "r");
                 OPENSSL_free(include);
+                if (include_path != include)
+                    OPENSSL_free(include_path);
 #endif
+
                 if (next != NULL) {
                     /* push the currently processing BIO onto stack */
                     if (biosk == NULL) {
index 356327f..f8a002a 100644 (file)
@@ -871,7 +871,7 @@ static const OSSL_DISPATCH core_dispatch_[] = {
     { OSSL_FUNC_CORE_VSET_ERROR, (void (*)(void))core_vset_error },
     { OSSL_FUNC_BIO_NEW_FILE, (void (*)(void))BIO_new_file },
     { OSSL_FUNC_BIO_NEW_MEMBUF, (void (*)(void))BIO_new_mem_buf },
-    { OSSL_FUNC_BIO_READ, (void (*)(void))BIO_read },
+    { OSSL_FUNC_BIO_READ_EX, (void (*)(void))BIO_read_ex },
     { OSSL_FUNC_BIO_FREE, (void (*)(void))BIO_free },
 #endif
 
index deed6d9..5e950d7 100644 (file)
@@ -40,7 +40,8 @@ It is strongly recommended to use absolute paths with the B<.include>
 directive. Relative paths are evaluated based on the application current
 working directory so unless the configuration file containing the
 B<.include> directive is application specific the inclusion will not
-work as expected.
+work as expected. The environment variable B<OPENSSL_CONF_INCLUDE> can also be
+used to specify the path to prepend to all .include paths.
 
 There can be optional B<=> character and whitespace characters between
 B<.include> directive and the path which can be useful in cases the
@@ -487,6 +488,10 @@ Ignored in set-user-ID and set-group-ID programs.
 The path to the directory with OpenSSL modules, such as providers.
 Ignored in set-user-ID and set-group-ID programs.
 
+=item B<OPENSSL_CONF_INCLUDE>
+
+The optional path to prepend to all .include paths.
+
 =back
 
 =head1 BUGS
index 6c43cdd..1b4b47d 100644 (file)
@@ -110,7 +110,7 @@ provider):
  CRYPTO_secure_allocated        OSSL_FUNC_CRYPTO_SECURE_ALLOCATED
  BIO_new_file                   OSSL_FUNC_BIO_NEW_FILE
  BIO_new_mem_buf                OSSL_FUNC_BIO_NEW_MEMBUF
- BIO_read                       OSSL_FUNC_BIO_READ
+ BIO_read_ex                    OSSL_FUNC_BIO_READ_EX
  BIO_free                       OSSL_FUNC_BIO_FREE
  OPENSSL_cleanse                OSSL_FUNC_OPENSSL_CLEANSE
  OPENSSL_hexstr2buf             OSSL_FUNC_OPENSSL_HEXSTR2BUF
@@ -182,7 +182,7 @@ CRYPTO_strndup(), CRYPTO_free(), CRYPTO_clear_free(),
 CRYPTO_realloc(), CRYPTO_clear_realloc(), CRYPTO_secure_malloc(),
 CRYPTO_secure_zalloc(), CRYPTO_secure_free(),
 CRYPTO_secure_clear_free(), CRYPTO_secure_allocated(),
-BIO_new_file(), BIO_new_mem_buf(), BIO_read(), BIO_free(),
+BIO_new_file(), BIO_new_mem_buf(), BIO_read_ex(), BIO_free(),
 OPENSSL_cleanse(), and OPENSSL_hexstr2buf() correspond exactly to the
 public functions with the same name.
 As a matter of fact, the pointers in the B<OSSL_DISPATCH> array are
index 0025820..d3189a3 100644 (file)
@@ -123,13 +123,13 @@ OSSL_CORE_MAKE_FUNC(void,
 /* Bio functions provided by the core */
 #define OSSL_FUNC_BIO_NEW_FILE                22
 #define OSSL_FUNC_BIO_NEW_MEMBUF              23
-#define OSSL_FUNC_BIO_READ                    24
+#define OSSL_FUNC_BIO_READ_EX                 24
 #define OSSL_FUNC_BIO_FREE                    25
 
 OSSL_CORE_MAKE_FUNC(BIO *, BIO_new_file, (const char *filename, const char *mode))
 OSSL_CORE_MAKE_FUNC(BIO *, BIO_new_membuf, (const void *buf, int len))
-OSSL_CORE_MAKE_FUNC(int, BIO_read, (BIO *bio, void *data, size_t data_len,
-                                    size_t *bytes_read))
+OSSL_CORE_MAKE_FUNC(int, BIO_read_ex, (BIO *bio, void *data, size_t data_len,
+                                       size_t *bytes_read))
 OSSL_CORE_MAKE_FUNC(int, BIO_free, (BIO *bio))
 
 /* Functions provided by the provider to the Core, reserved numbers 1024-1535 */
index 9372062..9b8effa 100644 (file)
@@ -1,2 +1,2 @@
 
-SOURCE[../fips]=fipsprov.c
+SOURCE[../fips]=fipsprov.c selftest.c
index cff1729..67ce90a 100644 (file)
@@ -464,8 +464,8 @@ int OSSL_provider_init(const OSSL_PROVIDER *provider,
         case OSSL_FUNC_BIO_NEW_MEMBUF:
             selftest_params.bio_new_buffer_cb = OSSL_get_BIO_new_membuf(in);
             break;
-        case OSSL_FUNC_BIO_READ:
-            selftest_params.bio_read_cb = OSSL_get_BIO_read(in);
+        case OSSL_FUNC_BIO_READ_EX:
+            selftest_params.bio_read_ex_cb = OSSL_get_BIO_read_ex(in);
             break;
         case OSSL_FUNC_BIO_FREE:
             selftest_params.bio_free_cb = OSSL_get_BIO_free(in);
@@ -487,7 +487,15 @@ int OSSL_provider_init(const OSSL_PROVIDER *provider,
         OPENSSL_CTX_free(ctx);
         return 0;
     }
+
     fgbl->prov = provider;
+
+    selftest_params.libctx = PROV_LIBRARY_CONTEXT_OF(ctx);
+    if (!SELF_TEST_post(&selftest_params)) {
+        OPENSSL_CTX_free(ctx);
+        return 0;
+    }
+
     *out = fips_dispatch_table;
     *provctx = ctx;
 
diff --git a/providers/fips/selftest.c b/providers/fips/selftest.c
new file mode 100644 (file)
index 0000000..a817b07
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (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/evp.h>
+#include <openssl/params.h>
+#include "selftest.h"
+
+#define FIPS_STATE_INIT     0
+#define FIPS_STATE_RUNNING  1
+#define FIPS_STATE_SELFTEST 2
+#define FIPS_STATE_ERROR    3
+
+/* The size of a temp buffer used to read in data */
+#define INTEGRITY_BUF_SIZE (4096)
+#define MAX_MD_SIZE 64
+#define MAC_NAME    "HMAC"
+#define DIGEST_NAME "SHA256"
+
+static int FIPS_state = FIPS_STATE_INIT;
+static unsigned char fixed_key[32] = { 0 };
+
+/*
+ * Calculate the HMAC SHA256 of data read using a BIO and read_cb, and verify
+ * the result matches the expected value.
+ * Return 1 if verified, or 0 if it fails.
+ */
+static int verify_integrity(BIO *bio, OSSL_BIO_read_ex_fn read_ex_cb,
+                            unsigned char *expected, size_t expected_len,
+                            OPENSSL_CTX *libctx)
+{
+    int ret = 0, status;
+    unsigned char out[MAX_MD_SIZE];
+    unsigned char buf[INTEGRITY_BUF_SIZE];
+    size_t bytes_read = 0, out_len = 0;
+    EVP_MAC *mac = NULL;
+    EVP_MAC_CTX *ctx = NULL;
+    OSSL_PARAM params[3], *p = params;
+
+    mac = EVP_MAC_fetch(libctx, MAC_NAME, NULL);
+    ctx = EVP_MAC_CTX_new(mac);
+    if (mac == NULL || ctx == NULL)
+        goto err;
+
+    *p++ = OSSL_PARAM_construct_utf8_string("digest", DIGEST_NAME,
+                                            strlen(DIGEST_NAME) + 1);
+    *p++ = OSSL_PARAM_construct_octet_string("key", fixed_key,
+                                             sizeof(fixed_key));
+    *p = OSSL_PARAM_construct_end();
+
+    if (EVP_MAC_CTX_set_params(ctx, params) <= 0
+        || !EVP_MAC_init(ctx))
+        goto err;
+
+    while (1) {
+        status = read_ex_cb(bio, buf, sizeof(buf), &bytes_read);
+        if (status != 1)
+            break;
+        if (!EVP_MAC_update(ctx, buf, bytes_read))
+            goto err;
+    }
+    if (!EVP_MAC_final(ctx, out, &out_len, sizeof(out)))
+        goto err;
+
+    if (expected_len != out_len
+            || memcmp(expected, out, out_len) != 0)
+        goto err;
+    ret = 1;
+err:
+    EVP_MAC_CTX_free(ctx);
+    EVP_MAC_free(mac);
+    return ret;
+}
+
+/* This API is triggered either on loading of the FIPS module or on demand */
+int SELF_TEST_post(SELF_TEST_POST_PARAMS *st)
+{
+    int ok = 0;
+    int kats_already_passed = 0;
+    int on_demand_test = (FIPS_state != FIPS_STATE_INIT);
+    long checksum_len;
+    BIO *bio_module = NULL, *bio_indicator = NULL;
+    unsigned char *module_checksum = NULL;
+    unsigned char *indicator_checksum = NULL;
+
+    if (st == NULL
+            || FIPS_state == FIPS_STATE_ERROR
+            || FIPS_state == FIPS_STATE_SELFTEST
+            || st->module_checksum_data == NULL)
+        goto end;
+
+    module_checksum = OPENSSL_hexstr2buf(st->module_checksum_data,
+                                         &checksum_len);
+    if (module_checksum == NULL)
+        goto end;
+    bio_module = (*st->bio_new_file_cb)(st->module_filename, "rb");
+
+    /* Always check the integrity of the fips module */
+    if (bio_module == NULL
+            || !verify_integrity(bio_module, st->bio_read_ex_cb,
+                                 module_checksum, checksum_len, st->libctx))
+        goto end;
+
+    /* This will be NULL during installation - so the self test KATS will run */
+    if (st->indicator_data != NULL) {
+        /*
+         * If the kats have already passed indicator is set - then check the
+         * integrity of the indicator.
+         */
+        if (st->indicator_checksum_data == NULL)
+            goto end;
+        indicator_checksum = OPENSSL_hexstr2buf(st->indicator_checksum_data,
+                                                &checksum_len);
+        if (indicator_checksum == NULL)
+            goto end;
+
+        bio_indicator =
+            (*st->bio_new_buffer_cb)(st->indicator_data,
+                                     strlen(st->indicator_data));
+        if (bio_indicator == NULL
+                || !verify_integrity(bio_indicator, st->bio_read_ex_cb,
+                                     indicator_checksum, checksum_len,
+                                     st->libctx))
+            goto end;
+        else
+            kats_already_passed = 1;
+    }
+
+    /* Only runs the KAT's during installation OR on_demand() */
+    if (on_demand_test || kats_already_passed == 0) {
+        /*TODO (3.0) Add self test KATS */
+    }
+    ok = 1;
+end:
+    OPENSSL_free(module_checksum);
+    OPENSSL_free(indicator_checksum);
+
+    (*st->bio_free_cb)(bio_indicator);
+    (*st->bio_free_cb)(bio_module);
+
+    FIPS_state = ok ? FIPS_STATE_RUNNING : FIPS_STATE_ERROR;
+
+    return ok;
+}
index 3a183f4..3e97e0d 100644 (file)
@@ -7,8 +7,8 @@
  * https://www.openssl.org/source/license.html
  */
 
-#include <openssl/params.h>
 #include <openssl/core_numbers.h>
+#include <openssl/ossl_typ.h>
 
 typedef struct self_test_post_params_st {
     /* FIPS module integrity check parameters */
@@ -23,7 +23,10 @@ typedef struct self_test_post_params_st {
     /* BIO callbacks supplied to the FIPS provider */
     OSSL_BIO_new_file_fn *bio_new_file_cb;
     OSSL_BIO_new_membuf_fn *bio_new_buffer_cb;
-    OSSL_BIO_read_fn *bio_read_cb;
+    OSSL_BIO_read_ex_fn *bio_read_ex_cb;
     OSSL_BIO_free_fn *bio_free_cb;
+    OPENSSL_CTX *libctx;
 
 } SELF_TEST_POST_PARAMS;
+
+int SELF_TEST_post(SELF_TEST_POST_PARAMS *st);
index eb344fd..f41c72c 100644 (file)
@@ -38,7 +38,7 @@ IF[{- !$disabled{tests} -}]
           destest mdc2test \
           dhtest enginetest casttest \
           bftest ssltest_old dsatest dsa_no_digest_size_test exptest rsa_test \
-          evp_test evp_extra_test igetest v3nametest v3ext \
+          evp_test evp_extra_test evp_fetch_prov_test igetest v3nametest v3ext \
           crltest danetest bad_dtls_test lhash_test sparse_array_test \
           conf_include_test params_api_test params_conversion_test \
           constant_time_test verify_extra_test clienthellotest \
@@ -195,6 +195,10 @@ IF[{- !$disabled{tests} -}]
   SOURCE[evp_extra_test]=evp_extra_test.c
   INCLUDE[evp_extra_test]=../include ../apps/include ../crypto/include
   DEPEND[evp_extra_test]=../libcrypto libtestutil.a
+
+  SOURCE[evp_fetch_prov_test]=evp_fetch_prov_test.c
+  INCLUDE[evp_fetch_prov_test]=../include ../apps/include ../crypto/include
+  DEPEND[evp_fetch_prov_test]=../libcrypto libtestutil.a
   IF[{- $disabled{fips} || !$target{dso_scheme} -}]
     DEFINE[evp_extra_test]=NO_FIPS_MODULE
   ENDIF
diff --git a/test/default-and-fips.cnf b/test/default-and-fips.cnf
new file mode 100644 (file)
index 0000000..6db1a94
--- /dev/null
@@ -0,0 +1,13 @@
+openssl_conf = openssl_init
+
+.include fipsinstall.conf
+
+[openssl_init]
+providers = provider_sect
+
+[provider_sect]
+default = default_sect
+fips = fips_sect
+
+[default_sect]
+activate = 1
index bbb846e..1898e31 100644 (file)
@@ -11,6 +11,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <openssl/bio.h>
+#include <openssl/conf.h>
 #include <openssl/crypto.h>
 #include <openssl/err.h>
 #include <openssl/evp.h>
@@ -1070,333 +1071,7 @@ done:
   X509_PUBKEY_free(xp);
   return ret;
 }
-#endif
-
-
-static int calculate_digest(const EVP_MD *md, const char *msg, size_t len,
-                            const unsigned char *exptd)
-{
-    unsigned char out[SHA256_DIGEST_LENGTH];
-    EVP_MD_CTX *ctx;
-    int ret = 0;
-
-    if (!TEST_ptr(ctx = EVP_MD_CTX_new())
-            || !TEST_true(EVP_DigestInit_ex(ctx, md, NULL))
-            || !TEST_true(EVP_DigestUpdate(ctx, msg, len))
-            || !TEST_true(EVP_DigestFinal_ex(ctx, out, NULL))
-            || !TEST_mem_eq(out, SHA256_DIGEST_LENGTH, exptd,
-                            SHA256_DIGEST_LENGTH)
-            || !TEST_true(md == EVP_MD_CTX_md(ctx)))
-        goto err;
-
-    ret = 1;
- err:
-    EVP_MD_CTX_free(ctx);
-    return ret;
-}
-/*
- * Test EVP_MD_fetch()
- *
- * Test 0: Test with the default OPENSSL_CTX
- * Test 1: Test with an explicit OPENSSL_CTX
- * Test 2: Explicit OPENSSL_CTX with explicit load of default provider
- * Test 3: Explicit OPENSSL_CTX with explicit load of default and fips provider
- * Test 4: Explicit OPENSSL_CTX with explicit load of fips provider
- */
-static int test_EVP_MD_fetch(int tst)
-{
-    OPENSSL_CTX *ctx = NULL;
-    EVP_MD *md = NULL;
-    OSSL_PROVIDER *defltprov = NULL, *fipsprov = NULL;
-    int ret = 0;
-    const char testmsg[] = "Hello world";
-    const unsigned char exptd[] = {
-      0x27, 0x51, 0x8b, 0xa9, 0x68, 0x30, 0x11, 0xf6, 0xb3, 0x96, 0x07, 0x2c,
-      0x05, 0xf6, 0x65, 0x6d, 0x04, 0xf5, 0xfb, 0xc3, 0x78, 0x7c, 0xf9, 0x24,
-      0x90, 0xec, 0x60, 0x6e, 0x50, 0x92, 0xe3, 0x26
-    };
-
-    if (tst > 0) {
-        ctx = OPENSSL_CTX_new();
-        if (!TEST_ptr(ctx))
-            goto err;
-
-        if (tst == 2 || tst == 3) {
-            defltprov = OSSL_PROVIDER_load(ctx, "default");
-            if (!TEST_ptr(defltprov))
-                goto err;
-        }
-        if (tst == 3 || tst == 4) {
-            fipsprov = OSSL_PROVIDER_load(ctx, "fips");
-            if (!TEST_ptr(fipsprov))
-                goto err;
-        }
-    }
-
-    /* Implicit fetching of the MD should produce the expected result */
-    if (!TEST_true(calculate_digest(EVP_sha256(), testmsg, sizeof(testmsg),
-                                    exptd))
-            || !TEST_int_eq(EVP_MD_size(EVP_sha256()), SHA256_DIGEST_LENGTH)
-            || !TEST_int_eq(EVP_MD_block_size(EVP_sha256()), SHA256_CBLOCK))
-        goto err;
-
-    /*
-     * Test that without specifying any properties we can get a sha256 md from a
-     * provider.
-     */
-    if (!TEST_ptr(md = EVP_MD_fetch(ctx, "SHA256", NULL))
-            || !TEST_ptr(md)
-            || !TEST_int_eq(EVP_MD_nid(md), NID_sha256)
-            || !TEST_true(calculate_digest(md, testmsg, sizeof(testmsg), exptd))
-            || !TEST_int_eq(EVP_MD_size(md), SHA256_DIGEST_LENGTH)
-            || !TEST_int_eq(EVP_MD_block_size(md), SHA256_CBLOCK))
-        goto err;
-
-    /* Also test EVP_MD_up_ref() while we're doing this */
-    if (!TEST_true(EVP_MD_up_ref(md)))
-        goto err;
-    /* Ref count should now be 2. Release both */
-    EVP_MD_free(md);
-    EVP_MD_free(md);
-    md = NULL;
-
-    /*
-     * In tests 0 - 2 we've only loaded the default provider so explicitly
-     * asking for a non-default implementation should fail. In tests 3 and 4 we
-     * have the FIPS provider loaded so we should succeed in that case.
-     */
-    md = EVP_MD_fetch(ctx, "SHA256", "default=no");
-    if (tst == 3 || tst == 4) {
-        if (!TEST_ptr(md)
-                || !TEST_true(calculate_digest(md, testmsg, sizeof(testmsg),
-                                               exptd)))
-            goto err;
-    } else  {
-        if (!TEST_ptr_null(md))
-            goto err;
-    }
-
-    EVP_MD_free(md);
-    md = NULL;
-
-    /*
-     * Explicitly asking for the default implementation should succeed except
-     * in test 4 where the default provider is not loaded.
-     */
-    md = EVP_MD_fetch(ctx, "SHA256", "default=yes");
-    if (tst != 4) {
-        if (!TEST_ptr(md)
-                || !TEST_int_eq(EVP_MD_nid(md), NID_sha256)
-                || !TEST_true(calculate_digest(md, testmsg, sizeof(testmsg),
-                                               exptd))
-                || !TEST_int_eq(EVP_MD_size(md), SHA256_DIGEST_LENGTH)
-                || !TEST_int_eq(EVP_MD_block_size(md), SHA256_CBLOCK))
-            goto err;
-    } else {
-        if (!TEST_ptr_null(md))
-            goto err;
-    }
-
-    EVP_MD_free(md);
-    md = NULL;
-
-    /*
-     * Explicitly asking for a fips implementation should succeed if we have
-     * the FIPS provider loaded and fail otherwise
-     */
-    md = EVP_MD_fetch(ctx, "SHA256", "fips=yes");
-    if (tst == 3 || tst == 4) {
-        if (!TEST_ptr(md)
-                || !TEST_true(calculate_digest(md, testmsg, sizeof(testmsg),
-                                               exptd)))
-            goto err;
-    } else  {
-        if (!TEST_ptr_null(md))
-            goto err;
-    }
-
-
-    ret = 1;
-
- err:
-    EVP_MD_free(md);
-    OSSL_PROVIDER_unload(defltprov);
-    OSSL_PROVIDER_unload(fipsprov);
-    /* Not normally needed, but we would like to test that
-     * OPENSSL_thread_stop_ex() behaves as expected.
-     */
-    if (ctx != NULL)
-        OPENSSL_thread_stop_ex(ctx);
-    OPENSSL_CTX_free(ctx);
-    return ret;
-}
-
-static int encrypt_decrypt(const EVP_CIPHER *cipher, const unsigned char *msg,
-                           size_t len)
-{
-    int ret = 0, ctlen, ptlen;
-    EVP_CIPHER_CTX *ctx = NULL;
-    unsigned char key[128 / 8];
-    unsigned char ct[64], pt[64];
-
-    memset(key, 0, sizeof(key));
-    if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new())
-            || !TEST_int_eq(EVP_CIPHER_CTX_tag_length(ctx), 0)
-            || !TEST_true(EVP_CipherInit_ex(ctx, cipher, NULL, key, NULL, 1))
-            || !TEST_int_eq(EVP_CIPHER_CTX_tag_length(ctx), 0)
-            || !TEST_true(EVP_CipherUpdate(ctx, ct, &ctlen, msg, len))
-            || !TEST_true(EVP_CipherFinal_ex(ctx, ct, &ctlen))
-            || !TEST_true(EVP_CipherInit_ex(ctx, cipher, NULL, key, NULL, 0))
-            || !TEST_int_eq(EVP_CIPHER_CTX_tag_length(ctx), 0)
-            || !TEST_true(EVP_CipherUpdate(ctx, pt, &ptlen, ct, ctlen))
-            || !TEST_true(EVP_CipherFinal_ex(ctx, pt, &ptlen))
-            || !TEST_mem_eq(pt, ptlen, msg, len))
-        goto err;
-
-    ret = 1;
- err:
-    EVP_CIPHER_CTX_free(ctx);
-    return ret;
-}
-
-static int get_num_params(const OSSL_PARAM *params)
-{
-    int i = 0;
-
-    if (params != NULL) {
-        while (params[i].key != NULL)
-            ++i;
-        ++i;
-    }
-    return i;
-}
-
-/*
- * Test EVP_CIPHER_fetch()
- *
- * Test 0: Test with the default OPENSSL_CTX
- * Test 1: Test with an explicit OPENSSL_CTX
- * Test 2: Explicit OPENSSL_CTX with explicit load of default provider
- * Test 3: Explicit OPENSSL_CTX with explicit load of default and fips provider
- * Test 4: Explicit OPENSSL_CTX with explicit load of fips provider
- */
-static int test_EVP_CIPHER_fetch(int tst)
-{
-    OPENSSL_CTX *ctx = NULL;
-    EVP_CIPHER *cipher = NULL;
-    OSSL_PROVIDER *defltprov = NULL, *fipsprov = NULL;
-    int ret = 0;
-    const unsigned char testmsg[] = "Hello world";
-    const OSSL_PARAM *params;
-
-    if (tst > 0) {
-        ctx = OPENSSL_CTX_new();
-        if (!TEST_ptr(ctx))
-            goto err;
-
-        if (tst == 2 || tst == 3) {
-            defltprov = OSSL_PROVIDER_load(ctx, "default");
-            if (!TEST_ptr(defltprov))
-                goto err;
-        }
-        if (tst == 3 || tst == 4) {
-            fipsprov = OSSL_PROVIDER_load(ctx, "fips");
-            if (!TEST_ptr(fipsprov))
-                goto err;
-        }
-    }
-
-    /* Implicit fetching of the cipher should produce the expected result */
-    if (!TEST_true(encrypt_decrypt(EVP_aes_128_cbc(), testmsg, sizeof(testmsg))))
-        goto err;
-
-    /*
-     * Test that without specifying any properties we can get a cipher from a
-     * provider.
-     */
-    if (!TEST_ptr(cipher = EVP_CIPHER_fetch(ctx, "AES-128-CBC", NULL))
-            || !TEST_true(encrypt_decrypt(cipher, testmsg, sizeof(testmsg))))
-        goto err;
-
-    /* Also test EVP_CIPHER_up_ref() while we're doing this */
-    if (!TEST_true(EVP_CIPHER_up_ref(cipher)))
-        goto err;
-    /* Ref count should now be 2. Release both */
-    EVP_CIPHER_free(cipher);
-    EVP_CIPHER_free(cipher);
-    cipher = NULL;
-
-    /*
-     * In tests 0 - 2 we've only loaded the default provider so explicitly
-     * asking for a non-default implementation should fail. In tests 3 and 4 we
-     * have the FIPS provider loaded so we should succeed in that case.
-     */
-    cipher = EVP_CIPHER_fetch(ctx, "AES-128-CBC", "default=no");
-    if (tst == 3 || tst == 4) {
-        if (!TEST_ptr(cipher)
-                || !TEST_true(encrypt_decrypt(cipher, testmsg, sizeof(testmsg))))
-            goto err;
-    } else  {
-        if (!TEST_ptr_null(cipher))
-            goto err;
-    }
-
-    EVP_CIPHER_free(cipher);
-    cipher = NULL;
-
-    /*
-     * Explicitly asking for the default implementation should succeed except
-     * in test 4 where the default provider is not loaded.
-     */
-    cipher = EVP_CIPHER_fetch(ctx, "AES-128-CBC", "default=yes");
-    if (tst != 4) {
-        if (!TEST_ptr(cipher)
-                || !TEST_int_eq(EVP_CIPHER_nid(cipher), NID_aes_128_cbc)
-                || !TEST_true(encrypt_decrypt(cipher, testmsg, sizeof(testmsg)))
-                || !TEST_int_eq(EVP_CIPHER_block_size(cipher), 128/8))
-            goto err;
-    } else {
-        if (!TEST_ptr_null(cipher))
-            goto err;
-    }
-
-    EVP_CIPHER_free(cipher);
-    cipher = NULL;
-
-    /*
-     * Explicitly asking for a fips implementation should succeed if we have
-     * the FIPS provider loaded and fail otherwise
-     */
-    cipher = EVP_CIPHER_fetch(ctx, "AES-128-CBC", "fips=yes");
-    if (tst == 3 || tst == 4) {
-        if (!TEST_ptr(cipher)
-                || !TEST_true(encrypt_decrypt(cipher, testmsg, sizeof(testmsg)))
-                || !TEST_ptr(params = cipher->gettable_params())
-                || !TEST_int_gt(get_num_params(params), 1)
-                || !TEST_ptr(params = cipher->gettable_ctx_params())
-                || !TEST_int_gt(get_num_params(params), 1)
-                || !TEST_ptr(params = cipher->settable_ctx_params())
-                || !TEST_int_gt(get_num_params(params), 1))
-            goto err;
-    } else  {
-        if (!TEST_ptr_null(cipher))
-            goto err;
-    }
-
-    ret = 1;
-
- err:
-    EVP_CIPHER_free(cipher);
-    OSSL_PROVIDER_unload(defltprov);
-    OSSL_PROVIDER_unload(fipsprov);
-    /* Not normally needed, but we would like to test that
-     * OPENSSL_thread_stop_ex() behaves as expected.
-     */
-    if (ctx != NULL)
-        OPENSSL_thread_stop_ex(ctx);
-    OPENSSL_CTX_free(ctx);
-    return ret;
-}
+#endif /* OPENSSL_NO_EC */
 
 #ifndef OPENSSL_NO_DSA
 /* Test getting and setting parameters on an EVP_PKEY_CTX */
@@ -1540,13 +1215,6 @@ int setup_tests(void)
     ADD_ALL_TESTS(test_invalide_ec_char2_pub_range_decode,
                   OSSL_NELEM(ec_der_pub_keys));
 #endif
-#ifdef NO_FIPS_MODULE
-    ADD_ALL_TESTS(test_EVP_MD_fetch, 3);
-    ADD_ALL_TESTS(test_EVP_CIPHER_fetch, 3);
-#else
-    ADD_ALL_TESTS(test_EVP_MD_fetch, 5);
-    ADD_ALL_TESTS(test_EVP_CIPHER_fetch, 5);
-#endif
 #ifndef OPENSSL_NO_DSA
     ADD_TEST(test_EVP_PKEY_CTX_get_set_params);
 #endif
diff --git a/test/evp_fetch_prov_test.c b/test/evp_fetch_prov_test.c
new file mode 100644 (file)
index 0000000..3fd695e
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * 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 <string.h>
+#include <openssl/sha.h>
+#include <openssl/evp.h>
+#include <openssl/provider.h>
+#include "testutil.h"
+
+static char *alg = "digest";
+static int use_default_ctx = 0;
+static char *fetch_property = NULL;
+static int expected_fetch_result = 1;
+
+typedef enum OPTION_choice {
+    OPT_ERR = -1,
+    OPT_EOF = 0,
+    OPT_ALG_FETCH_TYPE,
+    OPT_FETCH_PROPERTY,
+    OPT_FETCH_FAILURE,
+    OPT_USE_DEFAULTCTX,
+    OPT_TEST_ENUM
+} OPTION_CHOICE;
+
+const OPTIONS *test_get_options(void)
+{
+    static const OPTIONS test_options[] = {
+        OPT_TEST_OPTIONS_WITH_EXTRA_USAGE("[provname...]\n"),
+        { "type", OPT_ALG_FETCH_TYPE, 's', "The fetch type to test" },
+        { "property", OPT_FETCH_PROPERTY, 's', "The fetch property e.g. fips=yes" },
+        { "fetchfail", OPT_FETCH_FAILURE, '-', "fetch is expected to fail" },
+        { "defaultctx", OPT_USE_DEFAULTCTX, '-',
+          "Use the default context if this is set" },
+        { OPT_HELP_STR, 1, '-',
+          "file\tProvider names to explicitly load\n" },
+        { NULL }
+    };
+    return test_options;
+}
+
+static int calculate_digest(const EVP_MD *md, const char *msg, size_t len,
+                            const unsigned char *exptd)
+{
+    unsigned char out[SHA256_DIGEST_LENGTH];
+    EVP_MD_CTX *ctx;
+    int ret = 0;
+
+    if (!TEST_ptr(ctx = EVP_MD_CTX_new())
+            || !TEST_true(EVP_DigestInit_ex(ctx, md, NULL))
+            || !TEST_true(EVP_DigestUpdate(ctx, msg, len))
+            || !TEST_true(EVP_DigestFinal_ex(ctx, out, NULL))
+            || !TEST_mem_eq(out, SHA256_DIGEST_LENGTH, exptd,
+                            SHA256_DIGEST_LENGTH)
+            || !TEST_true(md == EVP_MD_CTX_md(ctx)))
+        goto err;
+
+    ret = 1;
+ err:
+    EVP_MD_CTX_free(ctx);
+    return ret;
+}
+
+static int load_providers(OPENSSL_CTX **libctx, OSSL_PROVIDER *prov[])
+{
+    OPENSSL_CTX *ctx;
+    int ret = 0;
+    size_t i;
+
+    ctx = OPENSSL_CTX_new();
+    if (!TEST_ptr(ctx))
+        goto err;
+
+    if (test_get_argument_count() > 2)
+        goto err;
+
+    for (i = 0; i < test_get_argument_count(); ++i) {
+        char *provname = test_get_argument(i);
+        prov[i] = OSSL_PROVIDER_load(ctx, provname);
+        if (!TEST_ptr(prov[i]))
+            goto err;
+    }
+    ret = 1;
+    *libctx = ctx;
+err:
+    return ret;
+}
+
+/*
+ * Test EVP_MD_fetch()
+ */
+static int test_EVP_MD_fetch(void)
+{
+    OPENSSL_CTX *ctx = NULL;
+    EVP_MD *md = NULL;
+    OSSL_PROVIDER *prov[2] = {NULL, NULL};
+    int ret = 0;
+    const char testmsg[] = "Hello world";
+    const unsigned char exptd[] = {
+      0x27, 0x51, 0x8b, 0xa9, 0x68, 0x30, 0x11, 0xf6, 0xb3, 0x96, 0x07, 0x2c,
+      0x05, 0xf6, 0x65, 0x6d, 0x04, 0xf5, 0xfb, 0xc3, 0x78, 0x7c, 0xf9, 0x24,
+      0x90, 0xec, 0x60, 0x6e, 0x50, 0x92, 0xe3, 0x26
+    };
+
+    if (use_default_ctx == 0 && !load_providers(&ctx, prov))
+        goto err;
+
+    /* Implicit fetching of the MD should produce the expected result */
+    if (!TEST_true(calculate_digest(EVP_sha256(), testmsg, sizeof(testmsg),
+                                    exptd))
+            || !TEST_int_eq(EVP_MD_size(EVP_sha256()), SHA256_DIGEST_LENGTH)
+            || !TEST_int_eq(EVP_MD_block_size(EVP_sha256()), SHA256_CBLOCK))
+        goto err;
+
+    /* Fetch the digest from a provider using properties. */
+    md = EVP_MD_fetch(ctx, "SHA256", fetch_property);
+    if (expected_fetch_result != 0) {
+        if (!TEST_ptr(md)
+            || !TEST_int_eq(EVP_MD_nid(md), NID_sha256)
+            || !TEST_true(calculate_digest(md, testmsg, sizeof(testmsg), exptd))
+            || !TEST_int_eq(EVP_MD_size(md), SHA256_DIGEST_LENGTH)
+            || !TEST_int_eq(EVP_MD_block_size(md), SHA256_CBLOCK))
+        goto err;
+
+        /* Also test EVP_MD_up_ref() while we're doing this */
+        if (!TEST_true(EVP_MD_up_ref(md)))
+            goto err;
+        /* Ref count should now be 2. Release first one here */
+        EVP_MD_meth_free(md);
+    } else {
+        if (!TEST_ptr_null(md))
+            goto err;
+    }
+    ret = 1;
+
+err:
+    EVP_MD_meth_free(md);
+    OSSL_PROVIDER_unload(prov[0]);
+    OSSL_PROVIDER_unload(prov[1]);
+    /* Not normally needed, but we would like to test that
+     * OPENSSL_thread_stop_ex() behaves as expected.
+     */
+    if (ctx != NULL) {
+        OPENSSL_thread_stop_ex(ctx);
+        OPENSSL_CTX_free(ctx);
+    }
+    return ret;
+}
+
+static int encrypt_decrypt(const EVP_CIPHER *cipher, const unsigned char *msg,
+                           size_t len)
+{
+    int ret = 0, ctlen, ptlen;
+    EVP_CIPHER_CTX *ctx = NULL;
+    unsigned char key[128 / 8];
+    unsigned char ct[64], pt[64];
+
+    memset(key, 0, sizeof(key));
+    if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new())
+            || !TEST_true(EVP_CipherInit_ex(ctx, cipher, NULL, key, NULL, 1))
+            || !TEST_true(EVP_CipherUpdate(ctx, ct, &ctlen, msg, len))
+            || !TEST_true(EVP_CipherFinal_ex(ctx, ct, &ctlen))
+            || !TEST_true(EVP_CipherInit_ex(ctx, cipher, NULL, key, NULL, 0))
+            || !TEST_true(EVP_CipherUpdate(ctx, pt, &ptlen, ct, ctlen))
+            || !TEST_true(EVP_CipherFinal_ex(ctx, pt, &ptlen))
+            || !TEST_mem_eq(pt, ptlen, msg, len))
+        goto err;
+
+    ret = 1;
+err:
+    EVP_CIPHER_CTX_free(ctx);
+    return ret;
+}
+
+/*
+ * Test EVP_CIPHER_fetch()
+ */
+static int test_EVP_CIPHER_fetch(void)
+{
+    OPENSSL_CTX *ctx = NULL;
+    EVP_CIPHER *cipher = NULL;
+    OSSL_PROVIDER *prov[2] = {NULL, NULL};
+    int ret = 0;
+    const unsigned char testmsg[] = "Hello world";
+
+    if (use_default_ctx == 0 && !load_providers(&ctx, prov))
+        goto err;
+
+    /* Implicit fetching of the cipher should produce the expected result */
+    if (!TEST_true(encrypt_decrypt(EVP_aes_128_cbc(), testmsg, sizeof(testmsg))))
+        goto err;
+
+    /* Fetch the cipher from a provider using properties. */
+    cipher = EVP_CIPHER_fetch(ctx, "AES-128-CBC", fetch_property);
+    if (expected_fetch_result != 0) {
+        if (!TEST_ptr(cipher)
+            || !TEST_true(encrypt_decrypt(cipher, testmsg, sizeof(testmsg)))) {
+            if (!TEST_true(EVP_CIPHER_up_ref(cipher)))
+                goto err;
+            /* Ref count should now be 2. Release first one here */
+            EVP_CIPHER_meth_free(cipher);
+        }
+    } else {
+        if (!TEST_ptr_null(cipher))
+            goto err;
+    }
+    ret = 1;
+err:
+    EVP_CIPHER_meth_free(cipher);
+    OSSL_PROVIDER_unload(prov[0]);
+    OSSL_PROVIDER_unload(prov[1]);
+    OPENSSL_CTX_free(ctx);
+    return ret;
+}
+
+int setup_tests(void)
+{
+    OPTION_CHOICE o;
+
+    while ((o = opt_next()) != OPT_EOF) {
+        switch (o) {
+        case OPT_ALG_FETCH_TYPE:
+            alg = opt_arg();
+            break;
+        case OPT_FETCH_PROPERTY:
+            fetch_property = opt_arg();
+            break;
+        case OPT_FETCH_FAILURE:
+            expected_fetch_result = 0;
+            break;
+        case OPT_USE_DEFAULTCTX:
+            use_default_ctx = 1;
+            break;
+        case OPT_TEST_CASES:
+           break;
+        default:
+        case OPT_ERR:
+            return 0;
+        }
+    }
+    if (strcmp(alg, "digest") == 0)
+        ADD_TEST(test_EVP_MD_fetch);
+    else
+        ADD_TEST(test_EVP_CIPHER_fetch);
+    return 1;
+}
index 0578c84..d77d35b 100644 (file)
@@ -1,10 +1,9 @@
 openssl_conf = openssl_init
 
+.include fipsinstall.conf
+
 [openssl_init]
 providers = provider_sect
 
 [provider_sect]
 fips = fips_sect
-
-[fips_sect]
-activate = 1
index 7e0be81..e99299f 100644 (file)
 use strict;
 use warnings;
 
-use OpenSSL::Test qw(:DEFAULT data_file bldtop_dir srctop_file);
+use OpenSSL::Test qw(:DEFAULT data_file bldtop_dir srctop_file srctop_dir bldtop_file);
 use OpenSSL::Test::Utils;
 
+BEGIN {
 setup("test_evp");
+}
+
+use lib srctop_dir('Configurations');
+use lib bldtop_dir('.');
+use platform;
 
 # Default config depends on if the legacy module is built or not
 my $defaultcnf = disabled('legacy') ? 'default.cnf' : 'default-and-legacy.cnf';
@@ -27,7 +33,17 @@ my @defltfiles = qw( evpencod.txt evpkdf.txt evppkey_kdf.txt evpmac.txt
     evppbe.txt evppkey.txt evppkey_ecc.txt evpcase.txt evpaessiv.txt
     evpccmcavs.txt );
 
-plan tests => (scalar(@configs) * scalar(@files)) + scalar(@defltfiles);
+plan tests => (scalar(@configs) * scalar(@files)) + scalar(@defltfiles) + 1;
+
+my $infile = bldtop_file('providers', platform->dso('fips'));
+$ENV{OPENSSL_MODULES} = bldtop_dir("providers");
+$ENV{OPENSSL_CONF_INCLUDE} = bldtop_dir("providers");
+
+ok(run(app(['openssl', 'fipsinstall', '-out', bldtop_file('providers', 'fipsinstall.conf'),
+            '-module', $infile,
+            '-provider_name', 'fips', '-mac_name', 'HMAC',
+            '-macopt', 'digest:SHA256', '-macopt', 'hexkey:00',
+            '-section_name', 'fips_sect'])), "fipinstall");
 
 foreach (@configs) {
     $ENV{OPENSSL_CONF} = srctop_file("test", $_);
diff --git a/test/recipes/30-test_evp_fetch_prov.t b/test/recipes/30-test_evp_fetch_prov.t
new file mode 100644 (file)
index 0000000..4aa1a10
--- /dev/null
@@ -0,0 +1,79 @@
+#! /usr/bin/env perl
+# Copyright 2015-2016 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 bldtop_dir srctop_file srctop_dir bldtop_file);
+use OpenSSL::Test::Utils;
+
+BEGIN {
+setup("test_evp_fetch_prov");
+}
+
+use lib srctop_dir('Configurations');
+use lib bldtop_dir('.');
+use platform;
+
+my @types = ( "digest", "cipher" );
+
+plan tests => 2 + 16 * scalar(@types);
+
+$ENV{OPENSSL_MODULES} = bldtop_dir("providers");
+$ENV{OPENSSL_CONF_INCLUDE} = bldtop_dir("providers");
+
+my $infile = bldtop_file('providers', platform->dso('fips'));
+ok(run(app(['openssl', 'fipsinstall', '-out', bldtop_file('providers', 'fipsinstall.conf'),
+            '-module', $infile,
+            '-provider_name', 'fips', '-mac_name', 'HMAC',
+            '-macopt', 'digest:SHA256', '-macopt', 'hexkey:00',
+            '-section_name', 'fips_sect'])), "fipinstall");
+
+# Do implicit fetch using the default context
+ok(run(test(["evp_fetch_prov_test", "-defaultctx"])),
+    "running evp_fetch_prov_test using implicit fetch using the default libctx");
+
+foreach my $alg(@types) {
+   $ENV{OPENSSL_CONF} = srctop_file("test", "default.cnf");
+   ok(run(test(["evp_fetch_prov_test", "-type", "$alg"])),
+       "running evp_fetch_prov_test using implicit fetch using a created libctx");
+   ok(run(test(["evp_fetch_prov_test", "-type", "$alg", "default"])),
+       "running evp_fetch_prov_test with implicit fetch using default provider loaded");
+   ok(run(test(["evp_fetch_prov_test", "-type", "$alg", "-property", "default=yes", "default"])),
+       "running evp_fetch_prov_test with $alg fetch 'default=yes' using default provider loaded");
+   ok(run(test(["evp_fetch_prov_test", "-type", "$alg", "-property", "fips=no", "default"])),
+       "running evp_fetch_prov_test with $alg fetch 'fips=no' using default provider loaded");
+   ok(run(test(["evp_fetch_prov_test", "-type", "$alg", "-property", "default=no", "-fetchfail", "default"])),
+       "running evp_fetch_prov_test with $alg fetch 'default=no' using default provider loaded should fail");
+   ok(run(test(["evp_fetch_prov_test", "-type", "$alg", "-property", "fips=yes", "-fetchfail", "default"])),
+       "running evp_fetch_prov_test with $alg fetch 'fips=yes' using default provider loaded should fail");
+
+   $ENV{OPENSSL_CONF} = srctop_file("test", "fips.cnf");
+   ok(run(test(["evp_fetch_prov_test", "-type", "$alg", "-property", "", "fips"])),
+       "running evp_fetch_prov_test with $alg fetch '' using loaded fips provider");
+   ok(run(test(["evp_fetch_prov_test", "-type", "$alg", "-property", "fips=yes", "fips"])),
+       "running evp_fetch_prov_test with $alg fetch 'fips=yes' using loaded fips provider");
+   ok(run(test(["evp_fetch_prov_test", "-type", "$alg", "-property", "default=no", "fips"])),
+       "running evp_fetch_prov_test with $alg fetch 'default=no' using loaded fips provider");
+   ok(run(test(["evp_fetch_prov_test", "-type", "$alg", "-property", "default=yes", "-fetchfail", "fips"])),
+       "running evp_fetch_prov_test with $alg fetch 'default=yes' using loaded fips provider should fail");
+   ok(run(test(["evp_fetch_prov_test", "-type", "$alg", "-property", "fips=no", "-fetchfail", "fips"])),
+       "running evp_fetch_prov_test with $alg fetch 'fips=no' using loaded fips provider should fail");
+
+   $ENV{OPENSSL_CONF} = srctop_file("test", "default-and-fips.cnf");
+   ok(run(test(["evp_fetch_prov_test", "-type", "$alg", "-property", "", "default", "fips"])),
+       "running evp_fetch_prov_test with $alg fetch '' using loaded default & fips provider");
+   ok(run(test(["evp_fetch_prov_test", "-type", "$alg", "-property", "default=no", "default", "fips"])),
+       "running evp_fetch_prov_test with $alg fetch 'default=no' using loaded default & fips provider");
+   ok(run(test(["evp_fetch_prov_test", "-type", "$alg", "-property", "default=yes", "default", "fips"])),
+       "running evp_fetch_prov_test with $alg fetch 'default=yes' using loaded default & fips provider");
+   ok(run(test(["evp_fetch_prov_test", "-type", "$alg", "-property", "fips=no", "default", "fips"])),
+       "running evp_fetch_prov_test with $alg fetch 'fips=no' using loaded default & fips provider");
+   ok(run(test(["evp_fetch_prov_test", "-type", "$alg", "-property", "fips=yes", "default", "fips"])),
+       "running evp_fetch_prov_test with $alg fetch 'fips=yes' using loaded default & fips provider");
+}
\ No newline at end of file