Allow getting out of the FIPS error state by running a self-test.
authorWerner Koch <wk@gnupg.org>
Wed, 27 Aug 2008 10:10:47 +0000 (10:10 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 27 Aug 2008 10:10:47 +0000 (10:10 +0000)
cipher/md.c
src/ChangeLog
src/Makefile.am
src/fips.c
src/g10lib.h
src/global.c
tests/ChangeLog
tests/basic.c

index 7ca4a21..46f20e4 100644 (file)
@@ -1011,7 +1011,7 @@ md_get_algo (gcry_md_hd_t a)
   if (r && r->next)
     {
       fips_signal_error ("possible usage error");
-      log_error ("WARNING: more than algorithm in md_get_algo()\n");
+      log_error ("WARNING: more than one algorithm in md_get_algo()\n");
     }
   return r ? r->module->mod_id : 0;
 }
index 26b304c..578f5c8 100644 (file)
@@ -1,3 +1,11 @@
+2008-08-27  Werner Koch  <wk@g10code.com>
+
+       * global.c (_gcry_vcontrol): Allow running selftests from error
+       state.
+       * fips.c (_gcry_fips_test_error_or_operational): New.
+       (fips_new_state): Allow transtion from error into selftest.
+       Disallow error to init.
+
 2008-08-26  Werner Koch  <wk@g10code.com>
 
        * fips.c (fips_new_state): Print state transitions only at
index bb88520..dcec200 100644 (file)
@@ -122,9 +122,9 @@ install-data-local: install-def-file
 
 uninstall-local: uninstall-def-file
 
-# FIXME: We ned to figure out how to gte the actual name (parsing
+# FIXME: We need to figure out how to get the actual name (parsing
 # libgcrypt.la?) and how to create the hmac file already at link time
-# so that it can be used without first installing.
+# so that it can be used without installing libgcrypt first.
 #install-exec-hook:
 #      ./hmac256 --binary "What am I, a doctor or a moonshuttle conductor?" \
 #           $(DESTDIR)$(libdir)/libgcrypt.so.11.5.0 \
index 3089f76..c9f29bd 100644 (file)
@@ -289,6 +289,26 @@ _gcry_fips_test_operational (void)
 }
 
 
+/* This is a test on whether the library is in the error or
+   operational state. */
+int
+_gcry_fips_test_error_or_operational (void)
+{
+  int result;
+
+  if (!fips_mode ())
+    result = 1;
+  else
+    {
+      lock_fsm ();
+      result = (current_state == STATE_OPERATIONAL
+                || current_state == STATE_ERROR);
+      unlock_fsm ();
+    }
+  return result;
+}
+
+
 static void
 reporter (const char *domain, int algo, const char *what, const char *errtxt)
 {
@@ -604,7 +624,7 @@ fips_new_state (enum module_states new_state)
     case STATE_ERROR:
       if (new_state == STATE_SHUTDOWN
           || new_state == STATE_FATALERROR
-          || new_state == STATE_INIT)
+          || new_state == STATE_SELFTEST)
         ok = 1;
       break;
       
index 668dc30..9860252 100644 (file)
@@ -314,6 +314,7 @@ int _gcry_fips_is_operational (void);
 #define fips_not_operational()  (GCRY_GPG_ERR_NOT_OPERATIONAL)
 
 int _gcry_fips_test_operational (void);
+int _gcry_fips_test_error_or_operational (void);
 
 void _gcry_fips_run_selftests (void);
 
index 894146e..1d5314b 100644 (file)
@@ -469,7 +469,7 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
           /* Already initialized.  If we are already operational we
              run a selftest.  If not we use the is_operational call to
              force us into operational state if possible.  */
-          if (_gcry_fips_test_operational ())
+          if (_gcry_fips_test_error_or_operational ())
             _gcry_fips_run_selftests ();
           if (_gcry_fips_is_operational ())
             err = GPG_ERR_GENERAL; /* Used as TRUE value */
index 52e4db9..aea5ce3 100644 (file)
@@ -1,3 +1,7 @@
+2008-08-27  Werner Koch  <wk@g10code.com>
+
+       * basic.c (main): Extended FIPS self-test test.
+
 2008-08-26  Werner Koch  <wk@g10code.com>
 
        * basic.c (get_keys_new): Use transient-key flag. 
index a904554..70a76fe 100644 (file)
@@ -2042,6 +2042,7 @@ check_pubkey (void)
 int
 main (int argc, char **argv)
 { 
+  gpg_error_t err;
   int last_argc = -1;
   int debug = 0;
   int use_fips = 0;
@@ -2105,9 +2106,49 @@ main (int argc, char **argv)
   check_hmac ();
   check_pubkey ();
 
-  /* If we are in fips mode, trigger a selftest.  */
+  /* If we are in fips mode do some more tests. */
   if (in_fips_mode)
-    gcry_control (GCRYCTL_FORCE_FIPS_MODE, 0);
+    {
+      gcry_md_hd_t md;
+
+      /* First trigger a self-test.  */
+      gcry_control (GCRYCTL_FORCE_FIPS_MODE, 0);
+      if (!gcry_control (GCRYCTL_OPERATIONAL_P, 0))
+        fail ("not in operational state after self-test\n");
+      
+      /* Get us into the error state.  */
+      err = gcry_md_open (&md, GCRY_MD_SHA1, 0);
+      if (err)
+        fail ("failed to open SHA-1 hash context: %s\n", gpg_strerror (err));
+      else
+        {
+          err = gcry_md_enable (md, GCRY_MD_SHA256);
+          if (err)
+            fail ("failed to add SHA-256 hash context: %s\n",
+                  gpg_strerror (err));
+          else
+            {
+              /* gcry_md_get_algo is only defined for a context with
+                 just one digest algorithm.  With our setup it should
+                 put the oibrary intoerror state.  */
+              gcry_md_get_algo (md);
+              gcry_md_close (md);
+              if (gcry_control (GCRYCTL_OPERATIONAL_P, 0))
+                fail ("expected error state but still in operational state\n");
+              else
+                {
+                  /* Now run a self-test and to get back into
+                     operational state.  */
+                  gcry_control (GCRYCTL_FORCE_FIPS_MODE, 0);
+                  if (!gcry_control (GCRYCTL_OPERATIONAL_P, 0))
+                    fail ("did not reach operational after error "
+                          "and self-test\n");
+                }
+            }
+        }
+      
+    }
+  
 
   if (verbose)
     fprintf (stderr, "\nAll tests completed. Errors: %i\n", error_count);