diff options
author | Shane Lontis <shane.lontis@oracle.com> | 2019-09-15 19:55:10 +1000 |
---|---|---|
committer | Shane Lontis <shane.lontis@oracle.com> | 2019-09-15 19:55:10 +1000 |
commit | 7bb82f92d94375e7673fe02cb8186595b2c539f2 (patch) | |
tree | 9ad368205615d359374430b91906e4c704135fae | |
parent | dd11c5f0fa809063b152cd2851c4c1e56fbd20c8 (diff) |
Add fips module integrity check
Add environment variable for setting CONF .include path
Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/9769)
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | apps/fipsinstall.c | 1 | ||||
-rw-r--r-- | crypto/conf/conf_def.c | 25 | ||||
-rw-r--r-- | crypto/provider_core.c | 2 | ||||
-rw-r--r-- | doc/man5/config.pod | 7 | ||||
-rw-r--r-- | doc/man7/provider-base.pod | 4 | ||||
-rw-r--r-- | include/openssl/core_numbers.h | 6 | ||||
-rw-r--r-- | providers/fips/build.info | 2 | ||||
-rw-r--r-- | providers/fips/fipsprov.c | 12 | ||||
-rw-r--r-- | providers/fips/selftest.c | 150 | ||||
-rw-r--r-- | providers/fips/selftest.h | 7 | ||||
-rw-r--r-- | test/build.info | 6 | ||||
-rw-r--r-- | test/default-and-fips.cnf | 13 | ||||
-rw-r--r-- | test/evp_extra_test.c | 336 | ||||
-rw-r--r-- | test/evp_fetch_prov_test.c | 251 | ||||
-rw-r--r-- | test/fips.cnf | 5 | ||||
-rw-r--r-- | test/recipes/30-test_evp.t | 20 | ||||
-rw-r--r-- | test/recipes/30-test_evp_fetch_prov.t | 79 |
18 files changed, 573 insertions, 355 deletions
diff --git a/.gitignore b/.gitignore index fb08a3c5b0..9fdd588e4f 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/apps/fipsinstall.c b/apps/fipsinstall.c index 2aedcbaa6c..78200c5876 100644 --- a/apps/fipsinstall.c +++ b/apps/fipsinstall.c @@ -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, diff --git a/crypto/conf/conf_def.c b/crypto/conf/conf_def.c index cbf0b2b183..ff4c43fc75 100644 --- a/crypto/conf/conf_def.c +++ b/crypto/conf/conf_def.c @@ -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) { diff --git a/crypto/provider_core.c b/crypto/provider_core.c index 356327f375..f8a002aa16 100644 --- a/crypto/provider_core.c +++ b/crypto/provider_core.c @@ -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 diff --git a/doc/man5/config.pod b/doc/man5/config.pod index deed6d9e16..5e950d740a 100644 --- a/doc/man5/config.pod +++ b/doc/man5/config.pod @@ -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 diff --git a/doc/man7/provider-base.pod b/doc/man7/provider-base.pod index 6c43cdd59c..1b4b47d02a 100644 --- a/doc/man7/provider-base.pod +++ b/doc/man7/provider-base.pod @@ -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 diff --git a/include/openssl/core_numbers.h b/include/openssl/core_numbers.h index 002582012e..d3189a3c18 100644 --- a/include/openssl/core_numbers.h +++ b/include/openssl/core_numbers.h @@ -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 */ diff --git a/providers/fips/build.info b/providers/fips/build.info index 9372062261..9b8effa85c 100644 --- a/providers/fips/build.info +++ b/providers/fips/build.info @@ -1,2 +1,2 @@ -SOURCE[../fips]=fipsprov.c +SOURCE[../fips]=fipsprov.c selftest.c diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c index cff172921c..67ce90ac13 100644 --- a/providers/fips/fipsprov.c +++ b/providers/fips/fipsprov.c @@ -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 index 0000000000..a817b070e0 --- /dev/null +++ b/providers/fips/selftest.c @@ -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; +} diff --git a/providers/fips/selftest.h b/providers/fips/selftest.h index 3a183f4d02..3e97e0d786 100644 --- a/providers/fips/selftest.h +++ b/providers/fips/selftest.h @@ -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); diff --git a/test/build.info b/test/build.info index eb344fd6c3..f41c72c21e 100644 --- a/test/build.info +++ b/test/build.info @@ -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 index 0000000000..6db1a940ee --- /dev/null +++ b/test/default-and-fips.cnf @@ -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 diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c index bbb846e6fd..1898e31de8 100644 --- a/test/evp_extra_test.c +++ b/test/evp_extra_test.c @@ -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 index 0000000000..3fd695e84b --- /dev/null +++ b/test/evp_fetch_prov_test.c @@ -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 cont |