Browse Source

Add option to fipsinstall to disable fips security checks at run time.

Changes merged from a patch by @richsalz.

Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org>
(Merged from https://github.com/openssl/openssl/pull/12745)
Shane Lontis 3 years ago
parent
commit
991a6bb581

+ 5 - 0
INSTALL.md

@@ -695,6 +695,11 @@ memory allocation).
 
 Don't compile the FIPS provider
 
+### no-fips-securitychecks
+
+Don't perform FIPS module run-time checks related to enforcement of security
+parameters such as minimum security strength of keys.
+
 ### enable-fuzz-libfuzzer, enable-fuzz-afl
 
 Build with support for fuzzing using either libfuzzer or AFL.

+ 23 - 11
apps/fipsinstall.c

@@ -37,7 +37,8 @@ typedef enum OPTION_choice {
     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_CONDITIONAL_ERRORS
+    OPT_NO_CONDITIONAL_ERRORS,
+    OPT_NO_SECURITY_CHECKS
 } OPTION_CHOICE;
 
 const OPTIONS fipsinstall_options[] = {
@@ -52,6 +53,8 @@ const OPTIONS fipsinstall_options[] = {
      {"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"},
+    {"no_security_checks", OPT_NO_SECURITY_CHECKS, '-',
+     "Disable the run-time FIPS security checks in the module"},
     OPT_SECTION("Input"),
     {"in", OPT_IN, '<', "Input config file, used when verifying"},
 
@@ -133,8 +136,8 @@ 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, installation indicator checksum and the option
- * conditional_errors.
+ * module checksum, installation indicator checksum and the options
+ * conditional_errors and security_checks.
  *
  * Returns 1 if the config file is written otherwise it returns 0 on error.
  */
@@ -142,6 +145,7 @@ static int write_config_fips_section(BIO *out, const char *section,
                                      unsigned char *module_mac,
                                      size_t module_mac_len,
                                      int conditional_errors,
+                                     int security_checks,
                                      unsigned char *install_mac,
                                      size_t install_mac_len)
 {
@@ -153,16 +157,17 @@ static int write_config_fips_section(BIO *out, const char *section,
                       VERSION_VAL) <= 0
         || BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_CONDITIONAL_ERRORS,
                       conditional_errors ? "1" : "0") <= 0
+        || BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_SECURITY_CHECKS,
+                      security_checks ? "1" : "0") <= 0
         || !print_mac(out, OSSL_PROV_FIPS_PARAM_MODULE_MAC, module_mac,
                       module_mac_len))
         goto end;
 
     if (install_mac != NULL) {
-        if (!(print_mac(out, OSSL_PROV_FIPS_PARAM_INSTALL_MAC, install_mac,
-                      install_mac_len)
-              && BIO_printf(out, "%s = %s\n",
-                            OSSL_PROV_FIPS_PARAM_INSTALL_STATUS,
-                            INSTALL_STATUS_VAL) > 0))
+        if (!print_mac(out, OSSL_PROV_FIPS_PARAM_INSTALL_MAC, install_mac,
+                       install_mac_len)
+            || BIO_printf(out, "%s = %s\n", OSSL_PROV_FIPS_PARAM_INSTALL_STATUS,
+                          INSTALL_STATUS_VAL) <= 0)
         goto end;
     }
     ret = 1;
@@ -174,7 +179,8 @@ static CONF *generate_config_and_load(const char *prov_name,
                                       const char *section,
                                       unsigned char *module_mac,
                                       size_t module_mac_len,
-                                      int conditional_errors)
+                                      int conditional_errors,
+                                      int security_checks)
 {
     BIO *mem_bio = NULL;
     CONF *conf = NULL;
@@ -186,6 +192,7 @@ static CONF *generate_config_and_load(const char *prov_name,
          || !write_config_fips_section(mem_bio, section,
                                        module_mac, module_mac_len,
                                        conditional_errors,
+                                       security_checks,
                                        NULL, 0))
         goto end;
 
@@ -280,7 +287,7 @@ end:
 int fipsinstall_main(int argc, char **argv)
 {
     int ret = 1, verify = 0, gotkey = 0, gotdigest = 0;
-    int enable_conditional_errors = 1;
+    int enable_conditional_errors = 1, enable_security_checks = 1;
     const char *section_name = "fips_sect";
     const char *mac_name = "HMAC";
     const char *prov_name = "fips";
@@ -323,6 +330,9 @@ opthelp:
         case OPT_NO_CONDITIONAL_ERRORS:
             enable_conditional_errors = 0;
             break;
+        case OPT_NO_SECURITY_CHECKS:
+            enable_security_checks = 0;
+            break;
         case OPT_QUIET:
             quiet = 1;
             /* FALLTHROUGH */
@@ -470,7 +480,8 @@ opthelp:
 
         conf = generate_config_and_load(prov_name, section_name, module_mac,
                                         module_mac_len,
-                                        enable_conditional_errors);
+                                        enable_conditional_errors,
+                                        enable_security_checks);
         if (conf == NULL)
             goto end;
         if (!load_fips_prov_and_run_self_test(prov_name))
@@ -484,6 +495,7 @@ opthelp:
         if (!write_config_fips_section(fout, section_name,
                                        module_mac, module_mac_len,
                                        enable_conditional_errors,
+                                       enable_security_checks,
                                        install_mac, install_mac_len))
             goto end;
         if (!quiet)

+ 14 - 8
doc/man1/openssl-fipsinstall.pod.in

@@ -20,6 +20,7 @@ B<openssl fipsinstall>
 [B<-noout>]
 [B<-quiet>]
 [B<-no_conditional_errors>]
+[B<-no_security_checks>]
 [B<-corrupt_desc> I<selftest_description>]
 [B<-corrupt_type> I<selftest_type>]
 [B<-config> I<parent_config>]
@@ -55,6 +56,14 @@ 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.
 
+=item - A control to indicate whether run-time security checks are done.
+
+This indicates if run-time checks related to enforcement of security parameters
+such as minimum security strength of keys and approved curve names are used.
+The default value of '1' will perform the checks.
+If the value is '0' the checks are not performed and FIPS compliance must
+be done by procedures documented in the relevant Security Policy.
+
 =back
 
 This file is described in L<fips_config(5)>.
@@ -150,6 +159,9 @@ Disable logging of the self tests.
 Configure the module to not enter an error state if a conditional self test
 fails as described above.
 
+=item B<-no_security_checks>
+
+Configure the module to not perform run-time security checks as described above.
 
 =item B<-quiet>
 
@@ -179,21 +191,15 @@ All other options are ignored if '-config' is used.
 Calculate the mac of a FIPS module F<fips.so> and run a FIPS self test
 for the module, and save the F<fips.cnf> configuration file:
 
- openssl fipsinstall -module ./fips.so -out fips.cnf -provider_name fips \
-         -section_name fipsinstall -mac_name HMAC -macopt digest:SHA256 \
-         -macopt hexkey:000102030405060708090A0B0C0D0E0F10111213
+ openssl fipsinstall -module ./fips.so -out fips.cnf -provider_name fips
 
 Verify that the configuration file F<fips.cnf> contains the correct info:
 
- openssl fipsinstall -module ./fips.so -in fips.cnf  -provider_name fips \
-          -section_name fips_install -mac_name HMAC -macopt digest:SHA256 \
-          -macopt hexkey:000102030405060708090A0B0C0D0E0F10111213 -verify
+ openssl fipsinstall -module ./fips.so -in fips.cnf  -provider_name fips -verify
 
 Corrupt any self tests which have the description C<SHA1>:
 
  openssl fipsinstall -module ./fips.so -out fips.cnf -provider_name fips \
-         -section_name fipsinstall -mac_name HMAC -macopt digest:SHA256 \
-         -macopt hexkey:000102030405060708090A0B0C0D0E0F10111213 \
          -corrupt_desc 'SHA1'
 
 Validate that the fips module can be loaded from a base configuration file:

+ 33 - 3
doc/man5/fips_config.pod

@@ -33,17 +33,43 @@ section, as described in L<config(5)/Provider Configuration Module>.
 
 =over 4
 
-=item B<module-mac>
+=item B<activate>
 
-The calculated MAC of the FIPS provider file.
+If present, the module is activated. The value assigned to this name is not
+significant.
 
 =item B<install-version>
 
 A version number for the fips install process. Should be 1.
 
+=item B<conditional-errors>
+
+The FIPS module normally enters an internal error mode if any self test fails.
+Once this error mode is active, no services or cryptographic algorithms are
+accessible from this point on.
+Continuous tests are a subset of the self tests (e.g., a key pair test during key
+generation, or the CRNG output test).
+Setting this value to C<0> allows the error mode to not be triggered if any
+continuous test fails. The default value of C<1> will trigger the error mode.
+Regardless of the value, the operation (e.g., key generation) that called the
+continuous test will return an error code if its continuous test fails. The
+operation may then be retried if the error mode has not been triggered.
+
+=item B<security-checks>
+
+This indicates if run-time checks related to enforcement of security parameters
+such as minimum security strength of keys and approved curve names are used.
+A value of '1' will perform the checks, otherwise if the value is '0' the checks
+are not performed and FIPS compliance must be done by procedures documented in
+the relevant Security Policy.
+
+=item B<module-mac>
+
+The calculated MAC of the FIPS provider file.
+
 =item B<install-status>
 
-An indicator that the self-tests were run.
+An indicator that the self-tests were successfully run.
 This should only be written after the module has
 successfully passed its self tests during installation.
 If this field is not present, then the self tests will run when the module
@@ -60,7 +86,10 @@ It is written-to at the same time as B<install-status> is updated.
 For example:
 
  [fips_sect]
+ activate = 1
  install-version = 1
+ conditional-errors = 1
+ security-checks = 1
  module-mac = 41:D0:FA:C2:5D:41:75:CD:7D:C3:90:55:6F:A4:DC
  install-mac = FE:10:13:5A:D3:B4:C7:82:1B:1E:17:4C:AC:84:0C
  install-status = INSTALL_SELF_TEST_KATS_RUN
@@ -68,6 +97,7 @@ For example:
 =head1 SEE ALSO
 
 L<config(5)>
+L<openssl-fipsinstall(1)>
 
 =head1 COPYRIGHT
 

+ 1 - 0
include/openssl/core_names.h

@@ -24,6 +24,7 @@ extern "C" {
 #define OSSL_PROV_PARAM_VERSION         "version"             /* utf8_string */
 #define OSSL_PROV_PARAM_BUILDINFO       "buildinfo"           /* utf8_string */
 #define OSSL_PROV_PARAM_STATUS          "status"              /* uint */
+#define OSSL_PROV_PARAM_SECURITY_CHECKS "security-checks"     /* uint */
 
 /* Self test callback parameters */
 #define OSSL_PROV_PARAM_SELF_TEST_PHASE  "st-phase" /* utf8_string */

+ 6 - 0
include/openssl/fips_names.h

@@ -46,6 +46,12 @@ extern "C" {
  */
 # define OSSL_PROV_FIPS_PARAM_CONDITIONAL_ERRORS "conditional-errors"
 
+/*
+ * A boolean that determines if the runtime FIPS security checks are performed.
+ * Type: OSSL_PARAM_UTF8_STRING
+ */
+# define OSSL_PROV_FIPS_PARAM_SECURITY_CHECKS "security-checks"
+
 # ifdef __cplusplus
 }
 # endif

+ 1 - 1
providers/common/securitycheck.c

@@ -203,7 +203,7 @@ int digest_is_allowed(const EVP_MD *md)
 {
 # if !defined(OPENSSL_NO_FIPS_SECURITYCHECKS)
     if (securitycheck_enabled())
-        return (digest_get_approved_nid(md) != NID_undef);
+        return digest_get_approved_nid(md) != NID_undef;
 # endif /* OPENSSL_NO_FIPS_SECURITYCHECKS */
     return 1;
 }

+ 3 - 2
providers/common/securitycheck_fips.c

@@ -19,11 +19,12 @@
 #include "prov/securitycheck.h"
 #include "prov/providercommonerr.h"
 
+extern int FIPS_security_check_enabled(void);
+
 int securitycheck_enabled(void)
 {
 #if !defined(OPENSSL_NO_FIPS_SECURITYCHECKS)
-    /* TODO(3.0): make this configurable */
-    return 1;
+    return FIPS_security_check_enabled();
 #else
     return 0;
 #endif /* OPENSSL_NO_FIPS_SECURITYCHECKS */

+ 21 - 0
providers/fips/fipsprov.c

@@ -37,6 +37,7 @@ static OSSL_FUNC_provider_query_operation_fn fips_query;
 #define ALG(NAMES, FUNC) ALGC(NAMES, FUNC, NULL)
 
 extern OSSL_FUNC_core_thread_start_fn *c_thread_start;
+int FIPS_security_check_enabled(void);
 
 /*
  * TODO(3.0): Should these be stored in the provider side provctx? Could they
@@ -46,6 +47,8 @@ extern OSSL_FUNC_core_thread_start_fn *c_thread_start;
  */
 
 static SELF_TEST_POST_PARAMS selftest_params;
+static int fips_security_checks = 1;
+static const char *fips_security_check_option = "1";
 
 /* Functions provided by the core */
 static OSSL_FUNC_core_gettable_params_fn *c_gettable_params;
@@ -100,6 +103,7 @@ static const OSSL_PARAM fips_param_types[] = {
     OSSL_PARAM_DEFN(OSSL_PROV_PARAM_VERSION, OSSL_PARAM_UTF8_PTR, NULL, 0),
     OSSL_PARAM_DEFN(OSSL_PROV_PARAM_BUILDINFO, OSSL_PARAM_UTF8_PTR, NULL, 0),
     OSSL_PARAM_DEFN(OSSL_PROV_PARAM_STATUS, OSSL_PARAM_INTEGER, NULL, 0),
+    OSSL_PARAM_DEFN(OSSL_PROV_PARAM_SECURITY_CHECKS, OSSL_PARAM_INTEGER, NULL, 0),
     OSSL_PARAM_END
 };
 
@@ -108,6 +112,7 @@ static const OSSL_PARAM fips_param_types[] = {
  * NOTE: inside core_get_params() these will be loaded from config items
  * stored inside prov->parameters (except for
  * OSSL_PROV_PARAM_CORE_MODULE_FILENAME).
+ * OSSL_PROV_FIPS_PARAM_SECURITY_CHECKS is not a self test parameter.
  */
 static OSSL_PARAM core_params[] =
 {
@@ -129,6 +134,9 @@ static OSSL_PARAM core_params[] =
     OSSL_PARAM_utf8_ptr(OSSL_PROV_FIPS_PARAM_CONDITIONAL_ERRORS,
                         selftest_params.conditional_error_check,
                         sizeof(selftest_params.conditional_error_check)),
+    OSSL_PARAM_utf8_ptr(OSSL_PROV_FIPS_PARAM_SECURITY_CHECKS,
+                        fips_security_check_option,
+                        sizeof(fips_security_check_option)),
     OSSL_PARAM_END
 };
 
@@ -153,6 +161,9 @@ static int fips_get_params(void *provctx, OSSL_PARAM params[])
     p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_STATUS);
     if (p != NULL && !OSSL_PARAM_set_int(p, ossl_prov_is_running()))
         return 0;
+    p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_SECURITY_CHECKS);
+    if (p != NULL && !OSSL_PARAM_set_int(p, fips_security_checks))
+        return 0;
     return 1;
 }
 
@@ -653,6 +664,11 @@ int OSSL_provider_init(const OSSL_CORE_HANDLE *handle,
         && strcmp(selftest_params.conditional_error_check, "0") == 0)
         SELF_TEST_disable_conditional_error_state();
 
+    /* Disable the security check if is disabled in the fips config file*/
+    if (fips_security_check_option != NULL
+        && strcmp(fips_security_check_option, "0") == 0)
+        fips_security_checks = 0;
+
     /*  Create a context. */
     if ((*provctx = PROV_CTX_new()) == NULL
         || (libctx = OPENSSL_CTX_new()) == NULL) {
@@ -858,3 +874,8 @@ int BIO_snprintf(char *buf, size_t n, const char *format, ...)
     va_end(args);
     return ret;
 }
+
+int FIPS_security_check_enabled(void)
+{
+    return fips_security_checks;
+}

+ 1 - 1
providers/implementations/signature/rsa.c

@@ -1244,7 +1244,7 @@ static const OSSL_PARAM known_settable_ctx_params[] = {
     OSSL_PARAM_END
 };
 
-static const OSSL_PARAM *rsa_settable_ctx_params(void *provctx)
+static const OSSL_PARAM *rsa_settable_ctx_params(ossl_unused void *provctx)
 {
     /*
      * TODO(3.0): Should this function return a different set of settable ctx

+ 36 - 4
test/evp_test.c

@@ -21,6 +21,7 @@
 #include <openssl/kdf.h>
 #include <openssl/params.h>
 #include <openssl/core_names.h>
+#include <openssl/fips_names.h>
 #include "internal/numbers.h"
 #include "internal/nelem.h"
 #include "crypto/evp.h"
@@ -3286,6 +3287,33 @@ static char *take_value(PAIR *pp)
     return p;
 }
 
+static int securitycheck_enabled(void)
+{
+    static int enabled = -1;
+
+    if (enabled == -1) {
+        if (OSSL_PROVIDER_available(libctx, "fips")) {
+            OSSL_PARAM params[2];
+            OSSL_PROVIDER *prov = NULL;
+            int check = 1;
+
+            prov = OSSL_PROVIDER_load(libctx, "fips");
+            if (prov != NULL) {
+                params[0] =
+                    OSSL_PARAM_construct_int(OSSL_PROV_PARAM_SECURITY_CHECKS,
+                                             &check);
+                params[1] = OSSL_PARAM_construct_end();
+                OSSL_PROVIDER_get_params(prov, params);
+                OSSL_PROVIDER_unload(prov);
+            }
+            enabled = check;
+            return enabled;
+        }
+        enabled = 0;
+    }
+    return enabled;
+}
+
 /*
  * Return 1 if one of the providers named in the string is available.
  * The provider names are separated with whitespace.
@@ -3445,11 +3473,15 @@ start:
     for (pp++, i = 1; i < (t->s.numpairs - skip_availablein); pp++, i++) {
         if (strcmp(pp->key, "Securitycheck") == 0) {
 #if defined(OPENSSL_NO_FIPS_SECURITYCHECKS)
-            TEST_info("skipping, securitycheck is not available: %s:%d",
-                      t->s.test_file, t->s.start);
-            t->skip = 1;
-            return 0;
+#else
+            if (!securitycheck_enabled())
 #endif
+            {
+                TEST_info("skipping, Securitycheck is disabled: %s:%d",
+                          t->s.test_file, t->s.start);
+                t->skip = 1;
+                return 0;
+            }
         } else if (strcmp(pp->key, "Availablein") == 0) {
             TEST_info("Line %d: 'Availablein' should be the first option",
                       t->s.curr);

+ 1 - 1
test/recipes/30-test_evp_data/evppkey_rsa.txt

@@ -14,7 +14,7 @@
 
 # Private keys used for PKEY operations.
 
-# Any Tests that keys <2048 bits OR sign with SHA1 are in this file.
+# Any Tests that have keys < 2048 bits OR sign with SHA1 are in this file.
 
 # RSA 2048 bit key.