Browse Source

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)
Shane Lontis 3 years ago
parent
commit
35e6ea3bdc

+ 32 - 16
apps/fipsinstall.c

@@ -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");

+ 2 - 0
crypto/dsa/dsa_key.c

@@ -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;

+ 2 - 0
crypto/ec/ec_key.c

@@ -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);

+ 2 - 1
crypto/err/openssl.txt

@@ -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

+ 2 - 0
crypto/rsa/rsa_gen.c

@@ -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);

+ 18 - 0
doc/man1/openssl-fipsinstall.pod.in

@@ -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>.

+ 7 - 0
include/openssl/fips_names.h

@@ -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

+ 1 - 0
include/openssl/self_test.h

@@ -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"

+ 1 - 1
providers/common/include/prov/providercommon.h

@@ -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);

+ 2 - 1
providers/common/include/prov/providercommonerr.h

@@ -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

+ 2 - 0
providers/common/provider_err.c

@@ -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),

+ 7 - 0
providers/fips/fipsprov.c

@@ -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

+ 16 - 4
providers/fips/self_test.c

@@ -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)

+ 5 - 0
providers/fips/self_test.h

@@ -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);

+ 2 - 1
providers/implementations/rands/crngt.c

@@ -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;
 }
 

+ 2 - 2
providers/prov_running.c

@@ -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;