keygen: add FIPS error state management to conditional self tests

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/12801)
This commit is contained in:
Shane Lontis 2020-09-10 14:01:30 +10:00 committed by Pauli
parent 801ed9edba
commit 35e6ea3bdc
16 changed files with 103 additions and 26 deletions

View File

@ -38,7 +38,8 @@ 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_NO_LOG, OPT_CORRUPT_DESC, OPT_CORRUPT_TYPE, OPT_QUIET, OPT_CONFIG
OPT_NO_LOG, OPT_CORRUPT_DESC, OPT_CORRUPT_TYPE, OPT_QUIET, OPT_CONFIG,
OPT_NO_CONDITIONAL_ERRORS
} OPTION_CHOICE;
const OPTIONS fipsinstall_options[] = {
@ -50,7 +51,9 @@ const OPTIONS fipsinstall_options[] = {
{"provider_name", OPT_PROV_NAME, 's', "FIPS provider name"},
{"section_name", OPT_SECTION_NAME, 's',
"FIPS Provider config section name (optional)"},
{"no_conditional_errors", OPT_NO_CONDITIONAL_ERRORS, '-',
"Disable the ability of the fips module to enter an error state if"
" any conditional self tests fail"},
OPT_SECTION("Input"),
{"in", OPT_IN, '<', "Input config file, used when verifying"},
@ -132,24 +135,28 @@ static int write_config_header(BIO *out, const char *prov_name,
/*
* Outputs a fips related config file that contains entries for the fips
* module checksum and the installation indicator checksum.
* module checksum, installation indicator checksum and the option
* conditional_errors.
*
* Returns 1 if the config file is written otherwise it returns 0 on error.
*/
static int write_config_fips_section(BIO *out, const char *section,
unsigned char *module_mac,
size_t module_mac_len,
int conditional_errors,
unsigned char *install_mac,
size_t install_mac_len)
{
int ret = 0;
if (!(BIO_printf(out, "[%s]\n", section) > 0
&& BIO_printf(out, "activate = 1\n") > 0
&& BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_INSTALL_VERSION,
VERSION_VAL) > 0
&& print_mac(out, OSSL_PROV_FIPS_PARAM_MODULE_MAC, module_mac,
module_mac_len)))
if (BIO_printf(out, "[%s]\n", section) <= 0
|| BIO_printf(out, "activate = 1\n") <= 0
|| BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_INSTALL_VERSION,
VERSION_VAL) <= 0
|| BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_CONDITIONAL_ERRORS,
conditional_errors ? "1" : "0") <= 0
|| !print_mac(out, OSSL_PROV_FIPS_PARAM_MODULE_MAC, module_mac,
module_mac_len))
goto end;
if (install_mac != NULL) {
@ -168,7 +175,8 @@ end:
static CONF *generate_config_and_load(const char *prov_name,
const char *section,
unsigned char *module_mac,
size_t module_mac_len)
size_t module_mac_len,
int conditional_errors)
{
BIO *mem_bio = NULL;
CONF *conf = NULL;
@ -177,8 +185,10 @@ static CONF *generate_config_and_load(const char *prov_name,
if (mem_bio == NULL)
return 0;
if (!write_config_header(mem_bio, prov_name, section)
|| !write_config_fips_section(mem_bio, section, module_mac,
module_mac_len, NULL, 0))
|| !write_config_fips_section(mem_bio, section,
module_mac, module_mac_len,
conditional_errors,
NULL, 0))
goto end;
conf = app_load_config_bio(mem_bio, NULL);
@ -272,6 +282,7 @@ end:
int fipsinstall_main(int argc, char **argv)
{
int ret = 1, verify = 0, gotkey = 0, gotdigest = 0;
int enable_conditional_errors = 1;
const char *section_name = "fips_sect";
const char *mac_name = "HMAC";
const char *prov_name = "fips";
@ -311,6 +322,9 @@ opthelp:
case OPT_OUT:
out_fname = opt_arg();
break;
case OPT_NO_CONDITIONAL_ERRORS:
enable_conditional_errors = 0;
break;
case OPT_QUIET:
quiet = 1;
/* FALLTHROUGH */
@ -457,7 +471,8 @@ opthelp:
} else {
conf = generate_config_and_load(prov_name, section_name, module_mac,
module_mac_len);
module_mac_len,
enable_conditional_errors);
if (conf == NULL)
goto end;
if (!load_fips_prov_and_run_self_test(prov_name))
@ -468,9 +483,10 @@ opthelp:
BIO_printf(bio_err, "Failed to open file\n");
goto end;
}
if (!write_config_fips_section(fout, section_name, module_mac,
module_mac_len, install_mac,
install_mac_len))
if (!write_config_fips_section(fout, section_name,
module_mac, module_mac_len,
enable_conditional_errors,
install_mac, install_mac_len))
goto end;
if (!quiet)
BIO_printf(bio_out, "INSTALL PASSED\n");

View File

@ -18,6 +18,7 @@
#include "internal/cryptlib.h"
#include <openssl/bn.h>
#include <openssl/self_test.h>
#include "prov/providercommon.h"
#include "crypto/dsa.h"
#include "dsa_local.h"
@ -113,6 +114,7 @@ static int dsa_keygen(DSA *dsa, int pairwise_test)
OSSL_SELF_TEST_get_callback(dsa->libctx, &cb, &cbarg);
ok = dsa_keygen_pairwise_test(dsa, cb, cbarg);
if (!ok) {
ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT);
BN_free(dsa->pub_key);
BN_clear_free(dsa->priv_key);
dsa->pub_key = NULL;

View File

@ -21,6 +21,7 @@
#include <openssl/err.h>
#include <openssl/engine.h>
#include <openssl/self_test.h>
#include "prov/providercommon.h"
#include "crypto/bn.h"
static int ecdsa_keygen_pairwise_test(EC_KEY *eckey, OSSL_CALLBACK *cb,
@ -330,6 +331,7 @@ int ec_generate_key(OPENSSL_CTX *libctx, EC_KEY *eckey, int pairwise_test)
err:
/* Step (9): If there is an error return an invalid keypair. */
if (!ok) {
ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT);
BN_clear(eckey->priv_key);
if (eckey->pub_key != NULL)
EC_POINT_set_to_infinity(group, eckey->pub_key);

View File

@ -2877,6 +2877,7 @@ PROV_R_FAILED_TO_GENERATE_KEY:121:failed to generate key
PROV_R_FAILED_TO_GET_PARAMETER:103:failed to get parameter
PROV_R_FAILED_TO_SET_PARAMETER:104:failed to set parameter
PROV_R_FAILED_TO_SIGN:175:failed to sign
PROV_R_FIPS_MODULE_CONDITIONAL_ERROR:227:fips module conditional error
PROV_R_FIPS_MODULE_ENTERING_ERROR_STATE:224:fips module entering error state
PROV_R_FIPS_MODULE_IN_ERROR_STATE:225:fips module in error state
PROV_R_GENERATE_ERROR:191:generate error
@ -2936,7 +2937,7 @@ PROV_R_MODULE_INTEGRITY_FAILURE:214:module integrity failure
PROV_R_NOT_A_PRIVATE_KEY:221:not a private key
PROV_R_NOT_A_PUBLIC_KEY:220:not a public key
PROV_R_NOT_INSTANTIATED:193:not instantiated
PROV_R_NOT_PARAMETERS:224:not parameters
PROV_R_NOT_PARAMETERS:226:not parameters
PROV_R_NOT_SUPPORTED:136:not supported
PROV_R_NOT_XOF_OR_INVALID_LENGTH:113:not xof or invalid length
PROV_R_NO_KEY_SET:114:no key set

View File

@ -24,6 +24,7 @@
#include "internal/cryptlib.h"
#include <openssl/bn.h>
#include <openssl/self_test.h>
#include "prov/providercommon.h"
#include "rsa_local.h"
static int rsa_keygen_pairwise_test(RSA *rsa, OSSL_CALLBACK *cb, void *cbarg);
@ -444,6 +445,7 @@ static int rsa_keygen(OPENSSL_CTX *libctx, RSA *rsa, int bits, int primes,
OSSL_SELF_TEST_get_callback(libctx, &stcb, &stcbarg);
ok = rsa_keygen_pairwise_test(rsa, stcb, stcbarg);
if (!ok) {
ossl_set_error_state(OSSL_SELF_TEST_TYPE_PCT);
/* Clear intermediate results */
BN_clear_free(rsa->d);
BN_clear_free(rsa->p);

View File

@ -19,6 +19,7 @@ B<openssl fipsinstall>
[B<-macopt> I<nm>:I<v>]
[B<-noout>]
[B<-quiet>]
[B<-no_conditional_errors>]
[B<-corrupt_desc> I<selftest_description>]
[B<-corrupt_type> I<selftest_type>]
[B<-config> I<parent_config>]
@ -43,6 +44,17 @@ This indicates if the Known Answer Self Tests (KAT's) have successfully run.
=item - A MAC of the status indicator.
=item - A control for conditional self tests errors.
By default if a continuous test (e.g a key pair test) fails then the FIPS module
will enter an error state, and no services or cryptographic algorithms will be
able to be accessed after this point.
The default value of '1' will cause the fips module error state to be entered.
If the value is '0' then the module error state will not be entered.
Regardless of whether the error state is entered or not, the current operation
(e.g. key generation) will return an error. The user is responsible for retrying
the operation if the module error state is not entered.
=back
This file is described in L<fips_config(5)>.
@ -133,6 +145,12 @@ The default digest is SHA-256.
Disable logging of the self tests.
=item B<-no_conditional_errors>
Configure the module to not enter an error state if a conditional self test
fails as described above.
=item B<-quiet>
Do not output pass/fail messages. Implies B<-noout>.

View File

@ -39,6 +39,13 @@ extern "C" {
*/
# define OSSL_PROV_FIPS_PARAM_INSTALL_STATUS "install-status"
/*
* A boolean that determines if the FIPS conditional test errors result in
* the module entering an error state.
* Type: OSSL_PARAM_UTF8_STRING
*/
# define OSSL_PROV_FIPS_PARAM_CONDITIONAL_ERRORS "conditional-errors"
# ifdef __cplusplus
}
# endif

View File

@ -27,6 +27,7 @@ extern "C" {
# 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_CRNG "Continuous_RNG_Test"
# 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"

View File

@ -20,7 +20,7 @@ int cipher_capable_aes_cbc_hmac_sha256(void);
OSSL_FUNC_provider_get_capabilities_fn provider_get_capabilities;
/* Set the error state if this is a FIPS module */
void ossl_set_error_state(void);
void ossl_set_error_state(const char *type);
/* Return true if the module is in a usable condition */
int ossl_prov_is_running(void);

View File

@ -75,6 +75,7 @@ int ERR_load_PROV_strings(void);
# define PROV_R_FAILED_TO_GET_PARAMETER 103
# define PROV_R_FAILED_TO_SET_PARAMETER 104
# define PROV_R_FAILED_TO_SIGN 175
# define PROV_R_FIPS_MODULE_CONDITIONAL_ERROR 227
# define PROV_R_FIPS_MODULE_ENTERING_ERROR_STATE 224
# define PROV_R_FIPS_MODULE_IN_ERROR_STATE 225
# define PROV_R_GENERATE_ERROR 191
@ -133,7 +134,7 @@ int ERR_load_PROV_strings(void);
# define PROV_R_NOT_A_PRIVATE_KEY 221
# define PROV_R_NOT_A_PUBLIC_KEY 220
# define PROV_R_NOT_INSTANTIATED 193
# define PROV_R_NOT_PARAMETERS 224
# define PROV_R_NOT_PARAMETERS 226
# define PROV_R_NOT_SUPPORTED 136
# define PROV_R_NOT_XOF_OR_INVALID_LENGTH 113
# define PROV_R_NO_KEY_SET 114

View File

@ -58,6 +58,8 @@ static const ERR_STRING_DATA PROV_str_reasons[] = {
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_FAILED_TO_SET_PARAMETER),
"failed to set parameter"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_FAILED_TO_SIGN), "failed to sign"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_FIPS_MODULE_CONDITIONAL_ERROR),
"fips module conditional error"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_FIPS_MODULE_ENTERING_ERROR_STATE),
"fips module entering error state"},
{ERR_PACK(ERR_LIB_PROV, 0, PROV_R_FIPS_MODULE_IN_ERROR_STATE),

View File

@ -126,6 +126,9 @@ static OSSL_PARAM core_params[] =
OSSL_PARAM_utf8_ptr(OSSL_PROV_FIPS_PARAM_INSTALL_VERSION,
selftest_params.indicator_version,
sizeof(selftest_params.indicator_version)),
OSSL_PARAM_utf8_ptr(OSSL_PROV_FIPS_PARAM_CONDITIONAL_ERRORS,
selftest_params.conditional_error_check,
sizeof(selftest_params.conditional_error_check)),
OSSL_PARAM_END
};
@ -645,6 +648,10 @@ int OSSL_provider_init(const OSSL_CORE_HANDLE *handle,
ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER);
return 0;
}
/* Disable the conditional error check if is disabled in the fips config file*/
if (selftest_params.conditional_error_check != NULL
&& strcmp(selftest_params.conditional_error_check, "0") == 0)
SELF_TEST_disable_conditional_error_state();
/* Create a context. */
if ((*provctx = PROV_CTX_new()) == NULL

View File

@ -44,6 +44,7 @@
#define MAC_NAME "HMAC"
#define DIGEST_NAME "SHA256"
static int FIPS_conditional_error_check = 1;
static int FIPS_state = FIPS_STATE_INIT;
static CRYPTO_RWLOCK *self_test_lock = NULL;
static unsigned char fixed_key[32] = { FIPS_KEY_ELEMENTS };
@ -311,16 +312,27 @@ end:
if (ok)
FIPS_state = FIPS_STATE_RUNNING;
else
ossl_set_error_state();
ossl_set_error_state(OSSL_SELF_TEST_TYPE_NONE);
CRYPTO_THREAD_unlock(self_test_lock);
return ok;
}
void ossl_set_error_state(void)
void SELF_TEST_disable_conditional_error_state(void)
{
FIPS_state = FIPS_STATE_ERROR;
ERR_raise(ERR_LIB_PROV, PROV_R_FIPS_MODULE_ENTERING_ERROR_STATE);
FIPS_conditional_error_check = 0;
}
void ossl_set_error_state(const char *type)
{
int cond_test = (type != NULL && strcmp(type, OSSL_SELF_TEST_TYPE_PCT) == 0);
if (!cond_test || (FIPS_conditional_error_check == 1)) {
FIPS_state = FIPS_STATE_ERROR;
ERR_raise(ERR_LIB_PROV, PROV_R_FIPS_MODULE_ENTERING_ERROR_STATE);
} else {
ERR_raise(ERR_LIB_PROV, PROV_R_FIPS_MODULE_CONDITIONAL_ERROR);
}
}
int ossl_prov_is_running(void)

View File

@ -21,6 +21,9 @@ typedef struct self_test_post_params_st {
const char *indicator_data; /* data to perform MAC on */
const char *indicator_checksum_data; /* Expected MAC integrity value */
/* Used for continuous tests */
const char *conditional_error_check;
/* BIO callbacks supplied to the FIPS provider */
OSSL_FUNC_BIO_new_file_fn *bio_new_file_cb;
OSSL_FUNC_BIO_new_membuf_fn *bio_new_buffer_cb;
@ -34,3 +37,5 @@ typedef struct self_test_post_params_st {
int SELF_TEST_post(SELF_TEST_POST_PARAMS *st, int on_demand_test);
int SELF_TEST_kats(OSSL_SELF_TEST *event, OPENSSL_CTX *libctx);
void SELF_TEST_disable_conditional_error_state(void);

View File

@ -16,6 +16,7 @@
#include <openssl/evp.h>
#include <openssl/core_dispatch.h>
#include <openssl/params.h>
#include <openssl/self_test.h>
#include "prov/providercommon.h"
#include "prov/provider_ctx.h"
#include "internal/cryptlib.h"
@ -99,7 +100,7 @@ static int prov_crngt_compare_previous(const unsigned char *prev,
const int res = memcmp(prev, cur, sz) != 0;
if (!res)
ossl_set_error_state();
ossl_set_error_state(OSSL_SELF_TEST_TYPE_CRNG);
return res;
}

View File

@ -11,11 +11,11 @@
#include "prov/providercommon.h"
/* By default, our providers don't have an error state */
void ossl_set_error_state(void)
void ossl_set_error_state(const char *type)
{
}
/* By default, out providers are always in a happy state */
/* By default, our providers are always in a happy state */
int ossl_prov_is_running(void)
{
return 1;