From 36fc5fc6bd5ca53fb30aabc38e3fefbab0005b2c Mon Sep 17 00:00:00 2001 From: Shane Lontis Date: Wed, 15 Jan 2020 10:48:01 +1000 Subject: [PATCH] Add FIPS Self test kats for digests Added an API to optionally set a self test callback. The callback has the following 2 purposes (1) Output information about the KAT tests. (2) Allow the ability to corrupt one of the KAT's The fipsinstall program uses the API. Some KATS are not included in this PR since the required functionality did not yet exist in the provider. Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/10374) --- apps/fipsinstall.c | 77 +++++- crypto/build.info | 2 +- crypto/provider_core.c | 5 +- crypto/self_test_core.c | 62 +++++ doc/man1/openssl-fipsinstall.pod | 25 ++ doc/man3/OSSL_SELF_TEST_set_callback.pod | 50 ++++ doc/man7/OSSL_PROVIDER-FIPS.pod | 260 +++++++++++++++++++++ doc/man7/provider-base.pod | 3 + include/internal/cryptlib.h | 3 +- include/internal/provider.h | 1 + include/openssl/core_names.h | 35 +-- include/openssl/core_numbers.h | 5 + include/openssl/self_test.h | 68 ++++++ providers/fips/build.info | 3 +- providers/fips/fipsprov.c | 20 +- providers/fips/{selftest.c => self_test.c} | 21 +- providers/fips/{selftest.h => self_test.h} | 24 ++ providers/fips/self_test_data.inc | 191 +++++++++++++++ providers/fips/self_test_event.c | 93 ++++++++ providers/fips/self_test_kats.c | 246 +++++++++++++++++++ test/recipes/03-test_fipsinstall.t | 23 +- util/libcrypto.num | 2 + 22 files changed, 1181 insertions(+), 38 deletions(-) create mode 100644 crypto/self_test_core.c create mode 100644 doc/man3/OSSL_SELF_TEST_set_callback.pod create mode 100644 doc/man7/OSSL_PROVIDER-FIPS.pod create mode 100644 include/openssl/self_test.h rename providers/fips/{selftest.c => self_test.c} (92%) rename providers/fips/{selftest.h => self_test.h} (62%) create mode 100644 providers/fips/self_test_data.inc create mode 100644 providers/fips/self_test_event.c create mode 100644 providers/fips/self_test_kats.c 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 - */ - -/* - * 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" +/* 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 */ + +/* 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: -- 2.25.1