Page MenuHome GnuPG

Provide a way to request non-FIPS service in FIPS mode
Closed, ResolvedPublic

Description

In the past the the libgcrypt in FIPS mode was started in "soft" FIPS mode and applications could elect to switch to enforced FIPS mode. This was removed during last months and when system is in FIPS mode, the libgcrypt is enforcing all the FIPS requirements. Some applications might use some algorithms for non-cryptographic or legacy uses, which will not work in FIPS mode. Therefore we need an API to switch from the FIPS mode to normal mode of operation.

My suggestion would be to use something like GCRYCTL_NO_FIPS_SERVICE, which could change the FIPS status to non-enforced.

Stephan mentioned that the only requirement to do that is to have it in two-step from the FIPS enforced mode. But in our case, it means calling gcry_control with the above argument and the second the actual operation with non-FIPS allowed key/cipher.

We can either allow this operation only before the init is finalized by the application and no threads were started or we would have to figure out if we can make this reliably thread-safe so the applications can "switch off" the FIPS mode only for the particular operations. It will probably require some modification to the documentation and the FIPS FSM.

This would be much easier if we would have some library contexts in place, but introducing it now would be probably overkill right now.

Event Timeline

FWIW, We have a similar mechanism for the secure memory

At first, I think that we need to change the way how libgcrypt rejects non-approved cipher/md/mac/pk.

Currently, from global_init function, _gcry_cipher_init, _gcry_md_init, _gcry_mac_init and _gcry_pk_init are called. At that time, .disabled flag will be modified to 1 for algos with .fips is 0, examining if it's fips_mode(). Later, algo with .disabled = 1 is rejected.

It will do:

  • no touch for .disabled flag from _init function
  • check fips_mode() and .fips when rejecting the algo
  • check fips_mode() and .fips when _selftest

Only after this change, running algo with .fips = 0 can be possible (or else, it will be rejected).

And I'm testing following:

diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 561da10b..2e27d406 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -327,7 +327,8 @@ enum gcry_ctl_cmds
     GCRYCTL_AUTO_EXPAND_SECMEM = 78,
     GCRYCTL_SET_ALLOW_WEAK_KEY = 79,
     GCRYCTL_SET_DECRYPTION_TAG = 80,
-    GCRYCTL_FIPS_SERVICE_INDICATOR = 81
+    GCRYCTL_FIPS_SERVICE_INDICATOR = 81,
+    GCRYCTL_NO_FIPS_MODE = 82
   };
 
 /* Perform various operations defined by CMD. */
diff --git a/src/global.c b/src/global.c
index ad2e95a4..a955c3fc 100644
--- a/src/global.c
+++ b/src/global.c
@@ -754,6 +754,27 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
       }
       break;
 
+    case GCRYCTL_NO_FIPS_MODE:
+      /* Performing this command puts the library into non-fips mode,
+         even if system has fips setting.  It is not possible to put
+         the libraty into non-fips mode after having passed the
+         initialization. */
+      _gcry_set_preferred_rng_type (0);
+      if (!_gcry_global_any_init_done)
+        {
+          /* Not yet initialized at all.  Set a flag so that we are put
+             into non-fips mode during initialization.  */
+          force_fips_mode = 0;
+        }
+      else if (!init_finished)
+        {
+          /* Already initialized.  */
+          _gcry_no_fips_mode_required = 1;
+        }
+      else
+	rc = GPG_ERR_GENERAL;
+      break;
+
     case GCRYCTL_SELFTEST:
       /* Run a selftest.  This works in fips mode as well as in
          standard mode.  In contrast to the power-up tests, we use an
diff --git a/tests/t-ed25519.c b/tests/t-ed25519.c
index 160bf980..ec71d1b4 100644
--- a/tests/t-ed25519.c
+++ b/tests/t-ed25519.c
@@ -35,6 +35,7 @@
 
 static int sign_with_pk;
 static int no_verify;
+static int no_fips;
 static int custom_data_file;
 static int in_fips_mode;
 
@@ -474,6 +475,11 @@ main (int argc, char **argv)
               argc--; argv++;
             }
         }
+      else if (!strcmp (*argv, "--no-fips"))
+        {
+          no_fips = 1;
+          argc--; argv++;
+        }
       else if (!strncmp (*argv, "--", 2))
         die ("unknown option '%s'", *argv);
 
@@ -489,6 +495,8 @@ main (int argc, char **argv)
     die ("version mismatch\n");
   if (debug)
     xgcry_control ((GCRYCTL_SET_DEBUG_FLAGS, 1u , 0));
+  if (no_fips)
+    xgcry_control ((GCRYCTL_NO_FIPS_MODE, 0));
   xgcry_control ((GCRYCTL_ENABLE_QUICK_RANDOM, 0));
   xgcry_control ((GCRYCTL_INITIALIZATION_FINISHED, 0));
gniibe moved this task from Backlog to Next on the FIPS board.
gniibe edited projects, added Feature Request; removed Bug Report.

Thanks. Looks good to me (both merged changes and the above proposal). In addition to the changes proposed above, we certainly need to update the documentation about this, probably also the FSM diagram.

werner triaged this task as Normal priority.Jan 5 2022, 11:50 AM

Patch applied, doc updated.
No change of FSM diagram.

gniibe removed a project: Testing.