diff --git a/apps/fipsinstall.c b/apps/fipsinstall.c index 739df23d44..564b208230 100644 --- a/apps/fipsinstall.c +++ b/apps/fipsinstall.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include "apps.h" #include "progs.h" @@ -25,10 +27,16 @@ #define VERSION_VAL "1" #define INSTALL_STATUS_VAL "INSTALL_SELF_TEST_KATS_RUN" +static OSSL_CALLBACK self_test_events; +static char *self_test_corrupt_desc = NULL; +static char *self_test_corrupt_type = NULL; +static int self_test_log = 1; + typedef enum OPTION_choice { OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, OPT_IN, OPT_OUT, OPT_MODULE, - OPT_PROV_NAME, OPT_SECTION_NAME, OPT_MAC_NAME, OPT_MACOPT, OPT_VERIFY + OPT_PROV_NAME, OPT_SECTION_NAME, OPT_MAC_NAME, OPT_MACOPT, OPT_VERIFY, + OPT_NO_LOG, OPT_CORRUPT_DESC, OPT_CORRUPT_TYPE } OPTION_CHOICE; const OPTIONS fipsinstall_options[] = { @@ -49,6 +57,9 @@ const OPTIONS fipsinstall_options[] = { {"mac_name", OPT_MAC_NAME, 's', "MAC name"}, {"macopt", OPT_MACOPT, 's', "MAC algorithm parameters in n:v form. " "See 'PARAMETER NAMES' in the EVP_MAC_ docs"}, + {"noout", OPT_NO_LOG, '-', "Disable logging of self test events"}, + {"corrupt_desc", OPT_CORRUPT_DESC, 's', "Corrupt a self test by description"}, + {"corrupt_type", OPT_CORRUPT_TYPE, 's', "Corrupt a self test by type"}, {NULL} }; @@ -287,6 +298,15 @@ opthelp: case OPT_OUT: out_fname = opt_arg(); break; + case OPT_NO_LOG: + self_test_log = 0; + break; + case OPT_CORRUPT_DESC: + self_test_corrupt_desc = opt_arg(); + break; + case OPT_CORRUPT_TYPE: + self_test_corrupt_type = opt_arg(); + break; case OPT_PROV_NAME: prov_name = opt_arg(); break; @@ -318,6 +338,11 @@ opthelp: || argc != 0) goto opthelp; + if (self_test_log + || self_test_corrupt_desc != NULL + || self_test_corrupt_type != NULL) + OSSL_SELF_TEST_set_callback(NULL, self_test_events, NULL); + module_bio = bio_open_default(module_fname, 'r', FORMAT_BINARY); if (module_bio == NULL) { BIO_printf(bio_err, "Failed to open module file\n"); @@ -420,3 +445,53 @@ end: free_config_and_unload(conf); return ret; } + +static int self_test_events(const OSSL_PARAM params[], void *arg) +{ + const OSSL_PARAM *p = NULL; + const char *phase = NULL, *type = NULL, *desc = NULL; + int ret = 0; + + 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 (self_test_log) { + 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 (strcmp(phase, OSSL_SELF_TEST_PHASE_CORRUPT) == 0 + && (self_test_corrupt_desc != NULL + || self_test_corrupt_type != NULL)) { + if (self_test_corrupt_desc != NULL + && strcmp(self_test_corrupt_desc, desc) != 0) + goto end; + if (self_test_corrupt_type != NULL + && strcmp(self_test_corrupt_type, type) != 0) + goto end; + BIO_printf(bio_out, "%s ", phase); + goto err; + } +end: + ret = 1; +err: + return ret; +} diff --git a/crypto/build.info b/crypto/build.info index ab10a1cfe6..daa26b8ed4 100644 --- a/crypto/build.info +++ b/crypto/build.info @@ -62,7 +62,7 @@ ENDIF $CORE_COMMON=provider_core.c provider_predefined.c \ core_fetch.c core_algorithm.c core_namemap.c -SOURCE[../libcrypto]=$CORE_COMMON provider_conf.c +SOURCE[../libcrypto]=$CORE_COMMON provider_conf.c self_test_core.c SOURCE[../providers/libfips.a]=$CORE_COMMON # Central utilities diff --git a/crypto/provider_core.c b/crypto/provider_core.c index c95615f882..2f2d69a0c3 100644 --- a/crypto/provider_core.c +++ b/crypto/provider_core.c @@ -18,6 +18,9 @@ #include "internal/provider.h" #include "internal/refcount.h" #include "provider_local.h" +#ifndef FIPS_MODE +# include +#endif static OSSL_PROVIDER *provider_new(const char *name, OSSL_provider_init_fn *init_function); @@ -874,8 +877,8 @@ static const OSSL_DISPATCH core_dispatch_[] = { { OSSL_FUNC_BIO_READ_EX, (void (*)(void))BIO_read_ex }, { OSSL_FUNC_BIO_FREE, (void (*)(void))BIO_free }, { OSSL_FUNC_BIO_VPRINTF, (void (*)(void))BIO_vprintf }, + { OSSL_FUNC_SELF_TEST_CB, (void (*)(void))OSSL_SELF_TEST_get_callback }, #endif - { OSSL_FUNC_CRYPTO_MALLOC, (void (*)(void))CRYPTO_malloc }, { OSSL_FUNC_CRYPTO_ZALLOC, (void (*)(void))CRYPTO_zalloc }, { OSSL_FUNC_CRYPTO_FREE, (void (*)(void))CRYPTO_free }, diff --git a/crypto/self_test_core.c b/crypto/self_test_core.c new file mode 100644 index 0000000000..77864a230b --- /dev/null +++ b/crypto/self_test_core.c @@ -0,0 +1,62 @@ +/* + * 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 +#include "internal/cryptlib.h" + +typedef struct self_test_cb_st +{ + OSSL_CALLBACK *cb; + void *cbarg; +} SELF_TEST_CB; + +static void *self_test_set_callback_new(OPENSSL_CTX *ctx) +{ + SELF_TEST_CB *stcb; + + stcb = OPENSSL_zalloc(sizeof(*stcb)); + return stcb; +} + +static void self_test_set_callback_free(void *stcb) +{ + OPENSSL_free(stcb); +} + +static const OPENSSL_CTX_METHOD self_test_set_callback_method = { + self_test_set_callback_new, + self_test_set_callback_free, +}; + +static SELF_TEST_CB *get_self_test_callback(OPENSSL_CTX *libctx) +{ + return openssl_ctx_get_data(libctx, OPENSSL_CTX_SELF_TEST_CB_INDEX, + &self_test_set_callback_method); +} + +void OSSL_SELF_TEST_set_callback(OPENSSL_CTX *libctx, OSSL_CALLBACK *cb, + void *cbarg) +{ + SELF_TEST_CB *stcb = get_self_test_callback(libctx); + + if (stcb != NULL) { + stcb->cb = cb; + stcb->cbarg = cbarg; + } +} +void OSSL_SELF_TEST_get_callback(OPENSSL_CTX *libctx, OSSL_CALLBACK **cb, + void **cbarg) +{ + SELF_TEST_CB *stcb = get_self_test_callback(libctx); + + if (cb != NULL) + *cb = (stcb != NULL ? stcb->cb : NULL); + if (cbarg != NULL) + *cbarg = (stcb != NULL ? stcb->cbarg : NULL); +} diff --git a/doc/man1/openssl-fipsinstall.pod b/doc/man1/openssl-fipsinstall.pod index 44f6e0e410..7cad6091e1 100644 --- a/doc/man1/openssl-fipsinstall.pod +++ b/doc/man1/openssl-fipsinstall.pod @@ -16,6 +16,9 @@ B [B<-verify>] [B<-mac_name> I] [B<-macopt> I:I] +[B<-noout>] +[B<-corrupt_desc> I] +[B<-corrupt_type> I] =head1 DESCRIPTION @@ -106,6 +109,20 @@ C. =back +=item B<-noout> + +Disable logging of the self tests. + +=item B<-corrupt_desc> I + +=item B<-corrupt_type> I + +The corrupt options can be used to test failure of one or more self test(s) by +name. +Either option or both may be used to select the self test(s) to corrupt. +Refer to the entries for "st-desc" and "st-type" in L for +values that can be used. + =back =head1 EXAMPLES @@ -123,6 +140,13 @@ Verify that the configuration file F contains the correct info: -section_name fips_install -mac_name HMAC -macopt digest:SHA256 \ -macopt hexkey:000102030405060708090A0B0C0D0E0F10111213 -verify +Corrupt any self tests which have the description 'SHA1': + + openssl fipsinstall -module ./fips.so -out fips.conf -provider_name fips \ + -section_name fipsinstall -mac_name HMAC -macopt digest:SHA256 \ + -macopt hexkey:000102030405060708090A0B0C0D0E0F10111213 \ + -corrupt_desc', 'SHA1' + =head1 NOTES The MAC mechanisms that are available will depend on the options @@ -132,6 +156,7 @@ The command C command can be used to list them. =head1 SEE ALSO L, +L, L =head1 COPYRIGHT diff --git a/doc/man3/OSSL_SELF_TEST_set_callback.pod b/doc/man3/OSSL_SELF_TEST_set_callback.pod new file mode 100644 index 0000000000..b2d38fbf7f --- /dev/null +++ b/doc/man3/OSSL_SELF_TEST_set_callback.pod @@ -0,0 +1,50 @@ +=pod + +=head1 NAME + +OSSL_SELF_TEST_set_callback, +OSSL_SELF_TEST_get_callback - specify a callback for processing self tests + +=head1 SYNOPSIS + + #include + + void OSSL_SELF_TEST_set_callback(OPENSSL_CTX *ctx, OSSL_CALLBACK *cb, void *cbarg); + void OSSL_SELF_TEST_get_callback(OPENSSL_CTX *ctx, OSSL_CALLBACK **cb, void **cbarg); + +=head1 DESCRIPTION + +Set or gets the optional application callback (and the callback argument) that +is called during self testing. +The application callback B is associated with a B. +The application callback function receives information about a running self test, +and may return a result to the calling self test. +See L for further information on the callback. + +=head1 RETURN VALUES + +OSSL_SELF_TEST_get_callback() returns the callback and callback argument that +has been set via OSSL_SELF_TEST_set_callback() for the given library context B. +These returned parameters will be NULL if OSSL_SELF_TEST_set_callback() has +not been called. + +=head1 SEE ALSO + +L, +L +L + +=head1 HISTORY + +The functions described here were added in OpenSSL 3.0. + +=head1 COPYRIGHT + +Copyright 2019-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 +L. + +=cut diff --git a/doc/man7/OSSL_PROVIDER-FIPS.pod b/doc/man7/OSSL_PROVIDER-FIPS.pod new file mode 100644 index 0000000000..a04ce4d6f2 --- /dev/null +++ b/doc/man7/OSSL_PROVIDER-FIPS.pod @@ -0,0 +1,260 @@ +=pod + +=head1 NAME + +OSSL_PROVIDER-FIPS - OPENSSL FIPS provider + +=head1 DESCRIPTION + +The OPENSSL FIPS provider is a special provider that conforms to the Federal +Information Processing Standards (FIPS) specified in FIPS 140-2. This 'module' +contains an approved set of cryptographic algorithms that is validated by an +accredited testing laboratory. + +=head1 SELF TESTING + +One of the requirements for the FIPS module is self testing. An optional callback +mechanism is available to return information to the user using +L. + +The OPENSSL FIPS module uses the following mechanism to provide information +about the self tests as they run. +This is useful for debugging if a self test is failing. +The callback also allows forcing any self test to fail, in order to check that +it operates correctly on failure. + +The 'args' parameter of B contains the B associated +with the provider that is triggering the self test. This may be useful if +multiple fips providers are present. + +The OSSL_PARAM names used are: + +=over 4 + +=item "st-phase" (B) + +Each self test calls the callback 3 times with the following string values +for the phase. + +=over 4 + +=item "Start" (B) + +This is the initial phase before the self test has run. +This is used for informational purposes only. +The value returned by the callback is ignored. + +=item "Corrupt" (B) + +The corrupt phase is run after the self test has calculated its known value. +The callback may be used to force the self test to fail by returning a value +of 0 from the callback during this phase. +Returning any other value from the callback causes the self test to run normally. + +=item "Pass" (B) + +=item "Fail" (B) + +The final phase runs after the self test is complete and indicates if a self +test passed or failed. This is used for informational purposes only. +The value returned by the callback is ignored. +"Fail" should normally only be returned if any self test was forced to fail +during the "Corrupt" phase (or if there was an error such as the integrity +check of the module failed). + +Note that all self tests run even if a self test failure occurs. + +=back + +=item "st-type" (B) + +Used as a category to identify the type of self test being run. +It includes the following string values: + +=over 4 + +=item "Module_Integrity" (B) + +Uses HMAC SHA256 on the module file to validate that the module has not been +modified. The integrity value is compared to a value written to a configuration +file during installation. + +=item "Install_Integrity" (B) + +Uses HMAC SHA256 on a fixed string to validate that the installation process +has already been performed and the self test KATS have already been tested, +The integrity value is compared to a value written to a configuration +file after successfully running the self tests during installation. + +=item "KAT_Cipher" (B) + +Known answer test for a symmetric cipher. + +=item "KAT_Digest" (B) + +Known answer test for a digest. + +=item "KAT_Signature" (B) + +Known answer test for a signature. + +=item "KAT_KDF" (B) + +Known answer test for a key derivation function. + +=item "KAT_KA" (B) + +Known answer test for key agreement. + +=item "DRBG" (B) + +Known answer test for a Deterministic Random Bit Generator. + +=item "Pairwise_Consistency_Test" (B) + +Conditional test that is run during the generation of key pairs. + +=back + +The "Module_Integrity" self test is always run at startup. +The "Install_Integrity" self test is used to check if the self tests have +already been run at installation time. If they have already run then the +self tests are not run on subsequent startups. +All other self test categories are run once at installation time, except for the +"Pairwise_Consistency_Test". + +There is only one instance of the "Module_Integrity" and "Install_Integrity" +self tests. All other self tests may have multiple instances. + +=item "st-desc" (B) + +Used as a sub category to identify an individual self test. +The following description strings are used. + +=over 4 + +=item "HMAC" (B) + +"Module_Integrity" and "Install_Integrity" use this. + +=item "RSA" (B) + +=item "ECDSA" (B) + +=item "DSA" (B) + +Key generation tests used with the "Pairwise_Consistency_Test" type. + +=item "AES_GCM" (B) + +=item "TDES" (B) + +Symmetric cipher tests used with the "KAT_Cipher" type. + +=item "SHA1" (B) + +=item "SHA2" (B) + +=item "SHA3" (B) + +Digest tests used with the "KAT_Digest" type. + +=item "DSA" (B) + +=item "RSA" (B) + +=item "ECDSA" (B) + +Signature tests used with the "KAT_Signature" type. + +=item "ECDH" (B) + +=item "ECDSA" (B) + +Key agreement tests used with the "KAT_KA" type. + +=item "HKDF" (B) + +Key Derivation Function tests used with the "KAT_KDF" type. + +=item "CTR" (B) + +=item "HASH" (B) + +=item "HMAC" (B) + +DRBG tests used with the "DRBG" type. + +=back + +=back + +=head1 EXAMPLES + +A simple self test callback is shown below for illustrative purposes. + + #include + + static OSSL_CALLBACK self_test_cb; + + static int self_test_cb(const OSSL_PARAM params[], void *arg) + { + int ret = 0; + const OSSL_PARAM *p = NULL; + const char *phase = NULL, *type = NULL, *desc = NULL; + + 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; + + /* Do some logging */ + if (strcmp(phase, OSSL_SELF_TEST_PHASE_START) == 0) + BIO_printf(bio_out, "%s : (%s) : ", desc, type); + if (strcmp(phase, OSSL_SELF_TEST_PHASE_PASS) == 0 + || strcmp(phase, OSSL_SELF_TEST_PHASE_FAIL) == 0) + BIO_printf(bio_out, "%s\n", phase); + + /* Corrupt the SHA1 self test during the 'corrupt' phase by returning 0 */ + if (strcmp(phase, OSSL_SELF_TEST_PHASE_CORRUPT) == 0 + && strcmp(desc, OSSL_SELF_TEST_DESC_MD_SHA1) == 0) { + BIO_printf(bio_out, "%s %s", phase, desc); + return 0; + } + ret = 1; + err: + return ret; + } + +=head1 SEE ALSO + +L, +L, +L, +L, +L + +=head1 HISTORY + +The type and functions described here were added in OpenSSL 3.0. + +=head1 COPYRIGHT + +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 +L. + +=cut diff --git a/doc/man7/provider-base.pod b/doc/man7/provider-base.pod index ccc5bf309a..7e86b2b2ed 100644 --- a/doc/man7/provider-base.pod +++ b/doc/man7/provider-base.pod @@ -115,6 +115,7 @@ provider): BIO_vprintf OSSL_FUNC_BIO_VPRINTF OPENSSL_cleanse OSSL_FUNC_OPENSSL_CLEANSE OPENSSL_hexstr2buf OSSL_FUNC_OPENSSL_HEXSTR2BUF + OSSL_SELF_TEST_set_callback OSSL_FUNC_SELF_TEST_CB For I<*out> (the B array passed from the provider to F): @@ -188,6 +189,8 @@ BIO_vprintf(), 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 array are direct pointers to those public functions. +OSSL_SELF_TEST_set_callback() is used to set an optional callback that can be +passed into a provider. This may be ignored by a provider. =head2 Provider functions diff --git a/include/internal/cryptlib.h b/include/internal/cryptlib.h index 8be3861d4f..dbb68f2c44 100644 --- a/include/internal/cryptlib.h +++ b/include/internal/cryptlib.h @@ -155,7 +155,8 @@ typedef struct ossl_ex_data_global_st { # define OPENSSL_CTX_THREAD_EVENT_HANDLER_INDEX 8 # define OPENSSL_CTX_FIPS_PROV_INDEX 9 # define OPENSSL_CTX_SERIALIZER_STORE_INDEX 10 -# define OPENSSL_CTX_MAX_INDEXES 11 +# define OPENSSL_CTX_SELF_TEST_CB_INDEX 11 +# define OPENSSL_CTX_MAX_INDEXES 12 typedef struct openssl_ctx_method { void *(*new_func)(OPENSSL_CTX *ctx); diff --git a/include/internal/provider.h b/include/internal/provider.h index a037233a30..8856d2fdd5 100644 --- a/include/internal/provider.h +++ b/include/internal/provider.h @@ -11,6 +11,7 @@ # define OSSL_INTERNAL_PROVIDER_H # include +# include # include "internal/dso.h" # include "internal/symhacks.h" diff --git a/include/openssl/core_names.h b/include/openssl/core_names.h index db9cb9ab2d..0bc51b3589 100644 --- a/include/openssl/core_names.h +++ b/include/openssl/core_names.h @@ -14,31 +14,16 @@ extern "C" { # endif -/* - * Well known parameter names that Providers can define - */ +/* Well known parameter names that Providers can define */ +#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_MODULE_FILENAME "module-filename" /* octet_string */ -/* - * A printable name for this provider - * Type: OSSL_PARAM_UTF8_STRING - */ -#define OSSL_PROV_PARAM_NAME "name" -/* - * A version string for this provider - * Type: OSSL_PARAM_UTF8_STRING - */ -#define OSSL_PROV_PARAM_VERSION "version" -/* - * A string providing provider specific build information - * Type: OSSL_PARAM_UTF8_STRING - */ -#define OSSL_PROV_PARAM_BUILDINFO "buildinfo" - -/* - * The module filename - * Type: OSSL_PARAM_OCTET_STRING - */ -#define OSSL_PROV_PARAM_MODULE_FILENAME "module-filename" +/* Self test callback parameters */ +#define OSSL_PROV_PARAM_SELF_TEST_PHASE "st-phase" /* utf8_string */ +#define OSSL_PROV_PARAM_SELF_TEST_TYPE "st-type" /* utf8_string */ +#define OSSL_PROV_PARAM_SELF_TEST_DESC "st-desc" /* utf8_string */ /* * Algorithm parameters diff --git a/include/openssl/core_numbers.h b/include/openssl/core_numbers.h index 9f49599dab..f41f7c02d0 100644 --- a/include/openssl/core_numbers.h +++ b/include/openssl/core_numbers.h @@ -12,6 +12,7 @@ # include # include +# include # ifdef __cplusplus extern "C" { @@ -135,6 +136,10 @@ OSSL_CORE_MAKE_FUNC(int, BIO_free, (BIO *bio)) OSSL_CORE_MAKE_FUNC(int, BIO_vprintf, (BIO *bio, const char *format, va_list args)) +#define OSSL_FUNC_SELF_TEST_CB 28 +OSSL_CORE_MAKE_FUNC(void, self_test_cb, (OPENSSL_CTX *ctx, OSSL_CALLBACK **cb, + void **cbarg)) + /* Functions provided by the provider to the Core, reserved numbers 1024-1535 */ # define OSSL_FUNC_PROVIDER_TEARDOWN 1024 OSSL_CORE_MAKE_FUNC(void,provider_teardown,(void *provctx)) diff --git a/include/openssl/self_test.h b/include/openssl/self_test.h new file mode 100644 index 0000000000..31dd6bd6c5 --- /dev/null +++ b/include/openssl/self_test.h @@ -0,0 +1,68 @@ +/* + * 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 + */ + +#ifndef OPENSSL_SELF_TEST_H +# define OPENSSL_SELF_TEST_H + +# include /* OSSL_CALLBACK */ + +# ifdef __cplusplus +extern "C" { +# endif + +/* The test event phases */ +# define OSSL_SELF_TEST_PHASE_NONE "None" +# define OSSL_SELF_TEST_PHASE_START "Start" +# define OSSL_SELF_TEST_PHASE_CORRUPT "Corrupt" +# define OSSL_SELF_TEST_PHASE_PASS "Pass" +# define OSSL_SELF_TEST_PHASE_FAIL "Fail" + +/* Test event categories */ +# define OSSL_SELF_TEST_TYPE_NONE "None" +# define OSSL_SELF_TEST_TYPE_MODULE_INTEGRITY "Module_Integrity" +# define OSSL_SELF_TEST_TYPE_INSTALL_INTEGRITY "Install_Integrity" +# define OSSL_SELF_TEST_TYPE_PCT "Pairwise_Consistency_Test" +# define OSSL_SELF_TEST_TYPE_KAT_CIPHER "KAT_Cipher" +# define OSSL_SELF_TEST_TYPE_KAT_DIGEST "KAT_Digest" +# define OSSL_SELF_TEST_TYPE_KAT_SIGNATURE "KAT_Signature" +# define OSSL_SELF_TEST_TYPE_KAT_KDF "KAT_KDF" +# define OSSL_SELF_TEST_TYPE_KAT_KA "KAT_KA" +# define OSSL_SELF_TEST_TYPE_DRBG "DRBG" + +/* Test event sub categories */ +# define OSSL_SELF_TEST_DESC_NONE "None" +# define OSSL_SELF_TEST_DESC_INTEGRITY_HMAC "HMAC" +# define OSSL_SELF_TEST_DESC_PCT_RSA_PKCS1 "RSA" +# define OSSL_SELF_TEST_DESC_PCT_ECDSA "ECDSA" +# define OSSL_SELF_TEST_DESC_PCT_DSA "DSA" +# define OSSL_SELF_TEST_DESC_CIPHER_AES_GCM "AES_GCM" +# define OSSL_SELF_TEST_DESC_CIPHER_TDES "TDES" +# define OSSL_SELF_TEST_DESC_MD_SHA1 "SHA1" +# define OSSL_SELF_TEST_DESC_MD_SHA2 "SHA2" +# define OSSL_SELF_TEST_DESC_MD_SHA3 "SHA3" +# define OSSL_SELF_TEST_DESC_SIGN_DSA "DSA" +# define OSSL_SELF_TEST_DESC_SIGN_RSA "RSA" +# define OSSL_SELF_TEST_DESC_SIGN_ECDSA "ECDSA" +# define OSSL_SELF_TEST_DESC_DRBG_CTR "CTR" +# define OSSL_SELF_TEST_DESC_DRBG_HASH "HASH" +# define OSSL_SELF_TEST_DESC_DRBG_HMAC "HMAC" +# define OSSL_SELF_TEST_DESC_KA_ECDH "ECDH" +# define OSSL_SELF_TEST_DESC_KA_ECDSA "ECDSA" +# define OSSL_SELF_TEST_DESC_KDF_HKDF "HKDF" + +# ifdef __cplusplus +} +# endif + +void OSSL_SELF_TEST_set_callback(OPENSSL_CTX *libctx, OSSL_CALLBACK *cb, + void *cbarg); +void OSSL_SELF_TEST_get_callback(OPENSSL_CTX *libctx, OSSL_CALLBACK **cb, + void **cbarg); + +#endif /* OPENSSL_SELF_TEST_H */ diff --git a/providers/fips/build.info b/providers/fips/build.info index 12ca452073..d12849ebb0 100644 --- a/providers/fips/build.info +++ b/providers/fips/build.info @@ -1,3 +1,2 @@ - -SOURCE[../fips]=fipsprov.c selftest.c +SOURCE[../fips]=fipsprov.c self_test.c self_test_kats.c self_test_event.c INCLUDE[../fips]=../implementations/include ../common/include ../.. diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c index 788963911b..cf4181dd2a 100644 --- a/providers/fips/fipsprov.c +++ b/providers/fips/fipsprov.c @@ -31,7 +31,7 @@ #include "prov/provider_ctx.h" #include "prov/providercommon.h" #include "prov/provider_util.h" -#include "selftest.h" +#include "self_test.h" #define ALGC(NAMES, FUNC, CHECK) { { NAMES, "fips=yes", FUNC }, CHECK } #define ALG(NAMES, FUNC) ALGC(NAMES, FUNC, NULL) @@ -649,9 +649,14 @@ int OSSL_provider_init(const OSSL_PROVIDER *provider, { FIPS_GLOBAL *fgbl; OPENSSL_CTX *ctx; + OSSL_self_test_cb_fn *stcbfn = NULL; + OSSL_core_get_library_context_fn *c_get_libctx = NULL; for (; in->function_id != 0; in++) { switch (in->function_id) { + case OSSL_FUNC_CORE_GET_LIBRARY_CONTEXT: + c_get_libctx = OSSL_get_core_get_library_context(in); + break; case OSSL_FUNC_CORE_GETTABLE_PARAMS: c_gettable_params = OSSL_get_core_gettable_params(in); break; @@ -715,12 +720,25 @@ int OSSL_provider_init(const OSSL_PROVIDER *provider, case OSSL_FUNC_BIO_FREE: selftest_params.bio_free_cb = OSSL_get_BIO_free(in); break; + case OSSL_FUNC_SELF_TEST_CB: { + stcbfn = OSSL_get_self_test_cb(in); + break; + } default: /* Just ignore anything we don't understand */ break; } } + if (stcbfn != NULL && c_get_libctx != NULL) { + stcbfn(c_get_libctx(provider), &selftest_params.event_cb, + &selftest_params.event_cb_arg); + } + else { + selftest_params.event_cb = NULL; + selftest_params.event_cb_arg = NULL; + } + if (!c_get_params(provider, core_params)) return 0; diff --git a/providers/fips/selftest.c b/providers/fips/self_test.c similarity index 92% rename from providers/fips/selftest.c rename to providers/fips/self_test.c index 91e4bb07f5..e486dd0db0 100644 --- a/providers/fips/selftest.c +++ b/providers/fips/self_test.c @@ -20,7 +20,7 @@ */ #define ALLOW_RUN_ONCE_IN_FIPS #include -#include "selftest.h" +#include "self_test.h" #define FIPS_STATE_INIT 0 #define FIPS_STATE_SELFTEST 1 @@ -132,7 +132,8 @@ DEP_FINI_ATTRIBUTE void cleanup(void) */ static int verify_integrity(BIO *bio, OSSL_BIO_read_ex_fn read_ex_cb, unsigned char *expected, size_t expected_len, - OPENSSL_CTX *libctx) + OPENSSL_CTX *libctx, OSSL_ST_EVENT *ev, + const char *event_type) { int ret = 0, status; unsigned char out[MAX_MD_SIZE]; @@ -142,6 +143,8 @@ static int verify_integrity(BIO *bio, OSSL_BIO_read_ex_fn read_ex_cb, EVP_MAC_CTX *ctx = NULL; OSSL_PARAM params[3], *p = params; + SELF_TEST_EVENT_onbegin(ev, event_type, OSSL_SELF_TEST_DESC_INTEGRITY_HMAC); + mac = EVP_MAC_fetch(libctx, MAC_NAME, NULL); ctx = EVP_MAC_CTX_new(mac); if (mac == NULL || ctx == NULL) @@ -167,11 +170,13 @@ static int verify_integrity(BIO *bio, OSSL_BIO_read_ex_fn read_ex_cb, if (!EVP_MAC_final(ctx, out, &out_len, sizeof(out))) goto err; + SELF_TEST_EVENT_oncorrupt_byte(ev, out); if (expected_len != out_len || memcmp(expected, out, out_len) != 0) goto err; ret = 1; err: + SELF_TEST_EVENT_onend(ev, ret); EVP_MAC_CTX_free(ctx); EVP_MAC_free(mac); return ret; @@ -187,6 +192,7 @@ int SELF_TEST_post(SELF_TEST_POST_PARAMS *st, int on_demand_test) unsigned char *module_checksum = NULL; unsigned char *indicator_checksum = NULL; int loclstate; + OSSL_ST_EVENT ev; if (!RUN_ONCE(&fips_self_test_init, do_fips_self_test_init)) return 0; @@ -217,6 +223,8 @@ int SELF_TEST_post(SELF_TEST_POST_PARAMS *st, int on_demand_test) || st->module_checksum_data == NULL) goto end; + SELF_TEST_EVENT_init(&ev, st->event_cb, st->event_cb_arg); + module_checksum = OPENSSL_hexstr2buf(st->module_checksum_data, &checksum_len); if (module_checksum == NULL) @@ -226,7 +234,8 @@ int SELF_TEST_post(SELF_TEST_POST_PARAMS *st, int on_demand_test) /* 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)) + module_checksum, checksum_len, st->libctx, + &ev, OSSL_SELF_TEST_TYPE_MODULE_INTEGRITY)) goto end; /* This will be NULL during installation - so the self test KATS will run */ @@ -248,7 +257,8 @@ int SELF_TEST_post(SELF_TEST_POST_PARAMS *st, int on_demand_test) if (bio_indicator == NULL || !verify_integrity(bio_indicator, st->bio_read_ex_cb, indicator_checksum, checksum_len, - st->libctx)) + st->libctx, &ev, + OSSL_SELF_TEST_TYPE_INSTALL_INTEGRITY)) goto end; else kats_already_passed = 1; @@ -256,7 +266,8 @@ int SELF_TEST_post(SELF_TEST_POST_PARAMS *st, int on_demand_test) /* 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 */ + if (!SELF_TEST_kats(&ev, st->libctx)) + goto end; } ok = 1; end: diff --git a/providers/fips/selftest.h b/providers/fips/self_test.h similarity index 62% rename from providers/fips/selftest.h rename to providers/fips/self_test.h index a56e42c7ab..5d995adac3 100644 --- a/providers/fips/selftest.h +++ b/providers/fips/self_test.h @@ -9,6 +9,7 @@ #include #include +#include typedef struct self_test_post_params_st { /* FIPS module integrity check parameters */ @@ -25,8 +26,31 @@ typedef struct self_test_post_params_st { OSSL_BIO_new_membuf_fn *bio_new_buffer_cb; OSSL_BIO_read_ex_fn *bio_read_ex_cb; OSSL_BIO_free_fn *bio_free_cb; + OSSL_CALLBACK *event_cb; + void *event_cb_arg; OPENSSL_CTX *libctx; } SELF_TEST_POST_PARAMS; +typedef struct st_event_st +{ + /* local state variables */ + const char *phase; + const char *type; + const char *desc; + OSSL_CALLBACK *cb; + + /* callback related variables used to pass the state back to the user */ + OSSL_PARAM params[4]; + void *cb_arg; + +} OSSL_ST_EVENT; + int SELF_TEST_post(SELF_TEST_POST_PARAMS *st, int on_demand_test); +int SELF_TEST_kats(OSSL_ST_EVENT *event, OPENSSL_CTX *libctx); + +void SELF_TEST_EVENT_init(OSSL_ST_EVENT *ev, OSSL_CALLBACK *cb, void *cbarg); +void SELF_TEST_EVENT_onbegin(OSSL_ST_EVENT *ev, const char *type, + const char *desc); +void SELF_TEST_EVENT_onend(OSSL_ST_EVENT *ev, int ret); +void SELF_TEST_EVENT_oncorrupt_byte(OSSL_ST_EVENT *ev, unsigned char *bytes); diff --git a/providers/fips/self_test_data.inc b/providers/fips/self_test_data.inc new file mode 100644 index 0000000000..28616a0079 --- /dev/null +++ b/providers/fips/self_test_data.inc @@ -0,0 +1,191 @@ +/* + * 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 + */ + +typedef struct st_kat_st { + const char *desc; + const char *algorithm; + const unsigned char *pt; + size_t pt_len; + const unsigned char *expected; + size_t expected_len; +} ST_KAT; + +typedef ST_KAT ST_KAT_DIGEST; +typedef struct st_kat_cipher_st { + ST_KAT base; + const unsigned char *key; + size_t key_len; + const unsigned char *iv; + size_t iv_len; + const unsigned char *aad; + size_t aad_len; + const unsigned char *tag; + size_t tag_len; +} ST_KAT_CIPHER; + +typedef struct st_kat_nvp_st { + const char *name; + const char *value; +} ST_KAT_NVP; + +typedef struct st_kat_kdf_st { + const char *desc; + const char *algorithm; + const ST_KAT_NVP *ctrls; + const unsigned char *expected; + size_t expected_len; +} ST_KAT_KDF; + +/* Macros to build Self test data */ +#define ITM(x) x, sizeof(x) +#define ITM_STR(x) x, sizeof(x) - 1 + +/*- DIGEST TEST DATA */ +static const unsigned char sha1_pt[] = "abc"; +static const unsigned char sha1_digest[] = { + 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E, 0x25, 0x71, + 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D +}; + +static const unsigned char sha512_pt[] = "abc"; +static const unsigned char sha512_digest[] = { + 0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA, 0xCC, 0x41, 0x73, 0x49, + 0xAE, 0x20, 0x41, 0x31, 0x12, 0xE6, 0xFA, 0x4E, 0x89, 0xA9, 0x7E, 0xA2, + 0x0A, 0x9E, 0xEE, 0xE6, 0x4B, 0x55, 0xD3, 0x9A, 0x21, 0x92, 0x99, 0x2A, + 0x27, 0x4F, 0xC1, 0xA8, 0x36, 0xBA, 0x3C, 0x23, 0xA3, 0xFE, 0xEB, 0xBD, + 0x45, 0x4D, 0x44, 0x23, 0x64, 0x3C, 0xE8, 0x0E, 0x2A, 0x9A, 0xC9, 0x4F, + 0xA5, 0x4C, 0xA4, 0x9F +}; +static const unsigned char sha3_256_pt[] = { 0xe7, 0x37, 0x21, 0x05 }; +static const unsigned char sha3_256_digest[] = { + 0x3a, 0x42, 0xb6, 0x8a, 0xb0, 0x79, 0xf2, 0x8c, 0x4c, 0xa3, 0xc7, 0x52, + 0x29, 0x6f, 0x27, 0x90, 0x06, 0xc4, 0xfe, 0x78, 0xb1, 0xeb, 0x79, 0xd9, + 0x89, 0x77, 0x7f, 0x05, 0x1e, 0x40, 0x46, 0xae +}; + +static const ST_KAT_DIGEST st_kat_digest_tests[] = +{ + { + OSSL_SELF_TEST_DESC_MD_SHA1, + "SHA1", + ITM_STR(sha1_pt), + ITM(sha1_digest), + }, + { + OSSL_SELF_TEST_DESC_MD_SHA2, + "SHA512", + ITM_STR(sha512_pt), + ITM(sha512_digest), + }, + { + OSSL_SELF_TEST_DESC_MD_SHA3, + "SHA3-256", + ITM(sha3_256_pt), + ITM(sha3_256_digest), + }, +}; + + +/*- CIPHER TEST DATA */ + +/* DES3 test data */ +static const unsigned char des_ede3_cbc_pt[] = { + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, 0xE9, 0x3D, 0x7E, 0x11, + 0x73, 0x93, 0x17, 0x2A, 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51 +}; + +static const unsigned char des_ede3_cbc_key[] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, + 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23 +}; +static const unsigned char des_ede3_cbc_iv[] = { + 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17 +}; +static const unsigned char des_ede3_cbc_ct[] = { + 0x20, 0x79, 0xC3, 0xD5, 0x3A, 0xA7, 0x63, 0xE1, 0x93, 0xB7, 0x9E, 0x25, + 0x69, 0xAB, 0x52, 0x62, 0x51, 0x65, 0x70, 0x48, 0x1F, 0x25, 0xB5, 0x0F, + 0x73, 0xC0, 0xBD, 0xA8, 0x5C, 0x8E, 0x0D, 0xA7 +}; + +static const unsigned char aes_256_gcm_key[] = { + 0x92,0xe1,0x1d,0xcd,0xaa,0x86,0x6f,0x5c,0xe7,0x90,0xfd,0x24, + 0x50,0x1f,0x92,0x50,0x9a,0xac,0xf4,0xcb,0x8b,0x13,0x39,0xd5, + 0x0c,0x9c,0x12,0x40,0x93,0x5d,0xd0,0x8b +}; +static const unsigned char aes_256_gcm_iv[] = { + 0xac,0x93,0xa1,0xa6,0x14,0x52,0x99,0xbd,0xe9,0x02,0xf2,0x1a +}; +static const unsigned char aes_256_gcm_pt[] = { + 0x2d,0x71,0xbc,0xfa,0x91,0x4e,0x4a,0xc0,0x45,0xb2,0xaa,0x60, + 0x95,0x5f,0xad,0x24 +}; +static const unsigned char aes_256_gcm_aad[] = { + 0x1e,0x08,0x89,0x01,0x6f,0x67,0x60,0x1c,0x8e,0xbe,0xa4,0x94, + 0x3b,0xc2,0x3a,0xd6 +}; +static const unsigned char aes_256_gcm_ct[] = { + 0x89,0x95,0xae,0x2e,0x6d,0xf3,0xdb,0xf9,0x6f,0xac,0x7b,0x71, + 0x37,0xba,0xe6,0x7f +}; +static const unsigned char aes_256_gcm_tag[] = { + 0xec,0xa5,0xaa,0x77,0xd5,0x1d,0x4a,0x0a,0x14,0xd9,0xc5,0x1e, + 0x1d,0xa4,0x74,0xab +}; + +static const ST_KAT_CIPHER st_kat_cipher_tests[] = { + { + { + OSSL_SELF_TEST_DESC_CIPHER_TDES, + "DES-EDE3-CBC", + ITM(des_ede3_cbc_pt), + ITM(des_ede3_cbc_ct) + }, + ITM(des_ede3_cbc_key), + ITM(des_ede3_cbc_iv), + }, + { + { + OSSL_SELF_TEST_DESC_CIPHER_AES_GCM, + "AES-256-GCM", + ITM(aes_256_gcm_pt), + ITM(aes_256_gcm_ct), + }, + ITM(aes_256_gcm_key), + ITM(aes_256_gcm_iv), + ITM(aes_256_gcm_aad), + ITM(aes_256_gcm_tag) + } +}; + +/*- KDF TEST DATA */ + +static const ST_KAT_NVP hkdf_ctrl[] = +{ + { "digest", "SHA256" }, + { "key", "secret" }, + { "salt", "salt" }, + { "info", "label" }, + { NULL, NULL } +}; +static const unsigned char hkdf_expected[] = { + 0x2a, 0xc4, 0x36, 0x9f, 0x52, 0x59, 0x96, 0xf8, 0xde, 0x13 +}; + +static const ST_KAT_KDF st_kat_kdf_tests[] = +{ + { + OSSL_SELF_TEST_DESC_KDF_HKDF, + "HKDF", + hkdf_ctrl, + ITM(hkdf_expected) + } +}; + diff --git a/providers/fips/self_test_event.c b/providers/fips/self_test_event.c new file mode 100644 index 0000000000..887b9dd17d --- /dev/null +++ b/providers/fips/self_test_event.c @@ -0,0 +1,93 @@ +/* + * 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 +#include +#include "self_test.h" + +static void self_test_event_setparams(OSSL_ST_EVENT *ev) +{ + size_t n = 0; + + if (ev->cb != NULL) { + ev->params[n++] = + OSSL_PARAM_construct_utf8_string(OSSL_PROV_PARAM_SELF_TEST_PHASE, + (char *)ev->phase, 0); + ev->params[n++] = + OSSL_PARAM_construct_utf8_string(OSSL_PROV_PARAM_SELF_TEST_TYPE, + (char *)ev->type, 0); + ev->params[n++] = + OSSL_PARAM_construct_utf8_string(OSSL_PROV_PARAM_SELF_TEST_DESC, + (char *)ev->desc, 0); + } + ev->params[n++] = OSSL_PARAM_construct_end(); +} + +void SELF_TEST_EVENT_init(OSSL_ST_EVENT *ev, OSSL_CALLBACK *cb, void *cbarg) +{ + if (ev == NULL) + return; + + ev->cb = cb; + ev->cb_arg = cbarg; + ev->phase = ""; + ev->type = ""; + ev->desc = ""; + self_test_event_setparams(ev); +} + +/* Can be used during application testing to log that a test has started. */ +void SELF_TEST_EVENT_onbegin(OSSL_ST_EVENT *ev, const char *type, + const char *desc) +{ + if (ev != NULL && ev->cb != NULL) { + ev->phase = OSSL_SELF_TEST_PHASE_START; + ev->type = type; + ev->desc = desc; + self_test_event_setparams(ev); + (void)ev->cb(ev->params, ev->cb_arg); + } +} + +/* + * Can be used during application testing to log that a test has either + * passed or failed. + */ +void SELF_TEST_EVENT_onend(OSSL_ST_EVENT *ev, int ret) +{ + if (ev != NULL && ev->cb != NULL) { + ev->phase = + (ret == 1 ? OSSL_SELF_TEST_PHASE_PASS : OSSL_SELF_TEST_PHASE_FAIL); + self_test_event_setparams(ev); + (void)ev->cb(ev->params, ev->cb_arg); + + ev->phase = OSSL_SELF_TEST_PHASE_NONE; + ev->type = OSSL_SELF_TEST_TYPE_NONE; + ev->desc = OSSL_SELF_TEST_DESC_NONE; + } +} + +/* + * Used for failure testing. + * + * Call the applications SELF_TEST_cb() if it exists. + * If the application callback decides to return 0 then the first byte of 'bytes' + * is modified (corrupted). This is used to modify output signatures or + * ciphertext before they are verified or decrypted. + */ +void SELF_TEST_EVENT_oncorrupt_byte(OSSL_ST_EVENT *ev, unsigned char *bytes) +{ + if (ev != NULL && ev->cb != NULL) { + ev->phase = OSSL_SELF_TEST_PHASE_CORRUPT; + self_test_event_setparams(ev); + if (!ev->cb(ev->params, ev->cb_arg)) + bytes[0] ^= 1; + } +} + diff --git a/providers/fips/self_test_kats.c b/providers/fips/self_test_kats.c new file mode 100644 index 0000000000..3ccd3f66ed --- /dev/null +++ b/providers/fips/self_test_kats.c @@ -0,0 +1,246 @@ +/* + * 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 +#include +#include +#include "internal/nelem.h" +#include "self_test.h" +#include "self_test_data.inc" + +static int self_test_digest(const ST_KAT_DIGEST *t, OSSL_ST_EVENT *event, + OPENSSL_CTX *libctx) +{ + int ok = 0; + unsigned char out[EVP_MAX_MD_SIZE]; + unsigned int out_len = 0; + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + EVP_MD *md = EVP_MD_fetch(libctx, t->algorithm, NULL); + + SELF_TEST_EVENT_onbegin(event, OSSL_SELF_TEST_TYPE_KAT_DIGEST, t->desc); + + if (ctx == NULL + || md == NULL + || !EVP_DigestInit_ex(ctx, md, NULL) + || !EVP_DigestUpdate(ctx, t->pt, t->pt_len) + || !EVP_DigestFinal(ctx, out, &out_len)) + goto err; + + /* Optional corruption */ + SELF_TEST_EVENT_oncorrupt_byte(event, out); + + if (out_len != t->expected_len + || memcmp(out, t->expected, out_len) != 0) + goto err; + ok = 1; +err: + SELF_TEST_EVENT_onend(event, ok); + EVP_MD_free(md); + EVP_MD_CTX_free(ctx); + + return ok; +} + +/* + * Helper function to setup a EVP_CipherInit + * Used to hide the complexity of Authenticated ciphers. + */ +static int cipher_init(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + const ST_KAT_CIPHER *t, int enc) +{ + unsigned char *in_tag = NULL; + int pad = 0, tmp; + + /* Flag required for Key wrapping */ + EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); + if (t->tag == NULL) { + /* Use a normal cipher init */ + return EVP_CipherInit_ex(ctx, cipher, NULL, t->key, t->iv, enc) + && EVP_CIPHER_CTX_set_padding(ctx, pad); + } + + /* The authenticated cipher init */ + if (!enc) + in_tag = (unsigned char *)t->tag; + + return EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, enc) + && EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, t->iv_len, NULL) + && (in_tag == NULL + || EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, t->tag_len, + in_tag)) + && EVP_CipherInit_ex(ctx, NULL, NULL, t->key, t->iv, enc) + && EVP_CIPHER_CTX_set_padding(ctx, pad) + && EVP_CipherUpdate(ctx, NULL, &tmp, t->aad, t->aad_len); +} + +/* Test a single KAT for encrypt/decrypt */ +static int self_test_cipher(const ST_KAT_CIPHER *t, OSSL_ST_EVENT *event, + OPENSSL_CTX *libctx) +{ + int ret = 0, encrypt = 1, len, ct_len = 0, pt_len = 0; + EVP_CIPHER_CTX *ctx = NULL; + EVP_CIPHER *cipher = NULL; + unsigned char ct_buf[256] = { 0 }; + unsigned char pt_buf[256] = { 0 }; + + SELF_TEST_EVENT_onbegin(event, OSSL_SELF_TEST_TYPE_KAT_CIPHER, t->base.desc); + + ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) + goto end; + cipher = EVP_CIPHER_fetch(libctx, t->base.algorithm, ""); + if (cipher == NULL) + goto end; + + /* Encrypt plain text message */ + if (!cipher_init(ctx, cipher, t, encrypt) + || !EVP_CipherUpdate(ctx, ct_buf, &len, t->base.pt, t->base.pt_len) + || !EVP_CipherFinal_ex(ctx, ct_buf + len, &ct_len)) + goto end; + + SELF_TEST_EVENT_oncorrupt_byte(event, ct_buf); + ct_len += len; + if (ct_len != (int)t->base.expected_len + || memcmp(t->base.expected, ct_buf, ct_len) != 0) + goto end; + + if (t->tag != NULL) { + unsigned char tag[16] = { 0 }; + + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, t->tag_len, tag) + || memcmp(tag, t->tag, t->tag_len) != 0) + goto end; + } + + if (!(cipher_init(ctx, cipher, t, !encrypt) + && EVP_CipherUpdate(ctx, pt_buf, &len, ct_buf, ct_len) + && EVP_CipherFinal_ex(ctx, pt_buf + len, &pt_len))) + goto end; + pt_len += len; + + if (pt_len != (int)t->base.pt_len + || memcmp(pt_buf, t->base.pt, pt_len) != 0) + goto end; + + ret = 1; +end: + EVP_CIPHER_free(cipher); + EVP_CIPHER_CTX_free(ctx); + SELF_TEST_EVENT_onend(event, ret); + return ret; +} + +static int self_test_kdf(const ST_KAT_KDF *t, OSSL_ST_EVENT *event, + OPENSSL_CTX *libctx) +{ + int ret = 0; + int i; + unsigned char out[64]; + EVP_KDF *kdf = NULL; + EVP_KDF_CTX *ctx = NULL; + OSSL_PARAM params[16]; + const OSSL_PARAM *settables = NULL; + + SELF_TEST_EVENT_onbegin(event, OSSL_SELF_TEST_TYPE_KAT_KDF, t->desc); + + kdf = EVP_KDF_fetch(libctx, t->algorithm, ""); + ctx = EVP_KDF_CTX_new(kdf); + if (ctx == NULL) + goto end; + + settables = EVP_KDF_settable_ctx_params(kdf); + for (i = 0; t->ctrls[i].name != NULL; ++i) { + if (!OSSL_PARAM_allocate_from_text(¶ms[i], settables, + t->ctrls[i].name, + t->ctrls[i].value, + strlen(t->ctrls[i].value))) + goto end; + } + params[i] = OSSL_PARAM_construct_end(); + if (!EVP_KDF_CTX_set_params(ctx, params)) + goto end; + + if (t->expected_len > sizeof(out)) + goto end; + if (EVP_KDF_derive(ctx, out, t->expected_len) <= 0) + goto end; + + SELF_TEST_EVENT_oncorrupt_byte(event, out); + + if (memcmp(out, t->expected, t->expected_len) != 0) + goto end; + + ret = 1; +end: + for (i = 0; params[i].key != NULL; ++i) + OPENSSL_free(params[i].data); + EVP_KDF_free(kdf); + EVP_KDF_CTX_free(ctx); + SELF_TEST_EVENT_onend(event, ret); + return ret; +} + +/* + * Test a data driven list of KAT's for digest algorithms. + * All tests are run regardless of if they fail or not. + * Return 0 if any test fails. + */ +static int self_test_digests(OSSL_ST_EVENT *event, OPENSSL_CTX *libctx) +{ + int i, ret = 1; + + for (i = 0; i < (int)OSSL_NELEM(st_kat_digest_tests); ++i) { + if (!self_test_digest(&st_kat_digest_tests[i], event, libctx)) + ret = 0; + } + return ret; +} + +static int self_test_ciphers(OSSL_ST_EVENT *event, OPENSSL_CTX *libctx) +{ + int i, ret = 1; + + for (i = 0; i < (int)OSSL_NELEM(st_kat_cipher_tests); ++i) { + if (!self_test_cipher(&st_kat_cipher_tests[i], event, libctx)) + ret = 0; + } + return ret; +} + +static int self_test_kdfs(OSSL_ST_EVENT *event, OPENSSL_CTX *libctx) +{ + int i, ret = 1; + + for (i = 0; i < (int)OSSL_NELEM(st_kat_kdf_tests); ++i) { + if (!self_test_kdf(&st_kat_kdf_tests[i], event, libctx)) + ret = 0; + } + return ret; +} + +/* + * Run the algorithm KAT's. + * Return 1 is successful, otherwise return 0. + * This runs all the tests regardless of if any fail. + * + * TODO(3.0) Add self tests for KA, DRBG, Sign/Verify when they become available + */ +int SELF_TEST_kats(OSSL_ST_EVENT *event, OPENSSL_CTX *libctx) +{ + int ret = 1; + + if (!self_test_digests(event, libctx)) + ret = 0; + if (!self_test_ciphers(event, libctx)) + ret = 0; + if (!self_test_kdfs(event, libctx)) + ret = 0; + + return ret; +} diff --git a/test/recipes/03-test_fipsinstall.t b/test/recipes/03-test_fipsinstall.t index 40a962253d..e77e09d550 100644 --- a/test/recipes/03-test_fipsinstall.t +++ b/test/recipes/03-test_fipsinstall.t @@ -24,7 +24,7 @@ use platform; plan skip_all => "Test only supported in a fips build" if disabled("fips"); -plan tests => 6; +plan tests => 9; my $infile = bldtop_file('providers', platform->dso('fips')); $ENV{OPENSSL_MODULES} = bldtop_dir("providers"); @@ -71,3 +71,24 @@ ok(!run(app(['openssl', 'fipsinstall', '-in', 'fips.conf', '-module', $infile, '-macopt', 'digest:SHA512', '-macopt', 'hexkey:00', '-section_name', 'fips_install', '-verify'])), "fipsinstall verify fail incorrect digest"); + +# corrupt the module hmac +ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips.conf', '-module', $infile, + '-provider_name', 'fips', '-mac_name', 'HMAC', + '-macopt', 'digest:SHA256', '-macopt', 'hexkey:00', + '-section_name', 'fips_install', '-corrupt_desc', 'HMAC'])), + "fipsinstall fails when the module integrity is corrupted"); + +# corrupt the first digest +ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips.conf', '-module', $infile, + '-provider_name', 'fips', '-mac_name', 'HMAC', + '-macopt', 'digest:SHA256', '-macopt', 'hexkey:00', + '-section_name', 'fips_install', '-corrupt_desc', 'SHA1'])), + "fipsinstall fails when the digest result is corrupted"); + +# corrupt another digest +ok(!run(app(['openssl', 'fipsinstall', '-out', 'fips.conf', '-module', $infile, + '-provider_name', 'fips', '-mac_name', 'HMAC', + '-macopt', 'digest:SHA256', '-macopt', 'hexkey:00', + '-section_name', 'fips_install', '-corrupt_desc', 'SHA3'])), + "fipsinstall fails when the digest result is corrupted"); diff --git a/util/libcrypto.num b/util/libcrypto.num index d18e1a3ebb..c2eff0edb9 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4913,3 +4913,5 @@ OSSL_CMP_MSG_get0_header ? 3_0_0 EXIST::FUNCTION:CMP BIO_f_prefix ? 3_0_0 EXIST::FUNCTION: EVP_PKEY_CTX_new_from_name ? 3_0_0 EXIST::FUNCTION: EVP_PKEY_CTX_new_from_pkey ? 3_0_0 EXIST::FUNCTION: +OSSL_SELF_TEST_set_callback ? 3_0_0 EXIST::FUNCTION: +OSSL_SELF_TEST_get_callback ? 3_0_0 EXIST::FUNCTION: