File libgcrypt-1.8.3-fips-ctor.patch of Package libgcrypt

Index: libgcrypt-1.8.4/cipher/md.c
===================================================================
--- libgcrypt-1.8.4.orig/cipher/md.c	2019-03-25 16:58:52.844354398 +0100
+++ libgcrypt-1.8.4/cipher/md.c	2019-03-25 16:58:53.512358321 +0100
@@ -411,11 +411,8 @@ md_enable (gcry_md_hd_t hd, int algorith
 
   if (!err && algorithm == GCRY_MD_MD5 && fips_mode ())
     {
-      _gcry_inactivate_fips_mode ("MD5 used");
       if (_gcry_enforced_fips_mode () )
         {
-          /* We should never get to here because we do not register
-             MD5 in enforced fips mode. But better throw an error.  */
           err = GPG_ERR_DIGEST_ALGO;
         }
     }
Index: libgcrypt-1.8.4/src/fips.c
===================================================================
--- libgcrypt-1.8.4.orig/src/fips.c	2019-03-25 16:58:52.844354398 +0100
+++ libgcrypt-1.8.4/src/fips.c	2019-03-25 16:58:53.516358344 +0100
@@ -91,6 +91,31 @@ static void fips_new_state (enum module_
 
 
 
+/* Initialize the FSM lock - this function may only
+   be called once and is intended to be run from the library
+   constructor  */
+void
+_gcry_initialize_fsm_lock (void)
+{
+  gpg_error_t err;
+  /* Intitialize the lock to protect the FSM.  */
+  err = gpgrt_lock_init (&fsm_lock);
+  if (err)
+    {
+      /* If that fails we can't do anything but abort the
+         process. We need to use log_info so that the FSM won't
+         get involved.  */
+      log_info ("FATAL: failed to create the FSM lock in libgcrypt: %s\n",
+                gpg_strerror (err));
+#ifdef HAVE_SYSLOG
+      syslog (LOG_USER|LOG_ERR, "Libgcrypt error: "
+              "creating FSM lock failed: %s - abort",
+              gpg_strerror (err));
+#endif /*HAVE_SYSLOG*/
+      abort ();
+    }
+}
+
 /* Check whether the OS is in FIPS mode and record that in a module
    local variable.  If FORCE is passed as true, fips mode will be
    enabled anyway. Note: This function is not thread-safe and should
@@ -100,7 +125,6 @@ void
 _gcry_initialize_fips_mode (int force)
 {
   static int done;
-  gpg_error_t err;
 
   /* Make sure we are not accidentally called twice.  */
   if (done)
@@ -190,24 +214,6 @@ _gcry_initialize_fips_mode (int force)
       /* Yes, we are in FIPS mode.  */
       FILE *fp;
 
-      /* Intitialize the lock to protect the FSM.  */
-      err = gpgrt_lock_init (&fsm_lock);
-      if (err)
-        {
-          /* If that fails we can't do anything but abort the
-             process. We need to use log_info so that the FSM won't
-             get involved.  */
-          log_info ("FATAL: failed to create the FSM lock in libgcrypt: %s\n",
-                    gpg_strerror (err));
-#ifdef HAVE_SYSLOG
-          syslog (LOG_USER|LOG_ERR, "Libgcrypt error: "
-                  "creating FSM lock failed: %s - abort",
-                  gpg_strerror (err));
-#endif /*HAVE_SYSLOG*/
-          abort ();
-        }
-
-
       /* If the FIPS force files exists, is readable and has a number
          != 0 on its first line, we enable the enforced fips mode.  */
       fp = fopen (FIPS_FORCE_FILE, "r");
@@ -370,16 +376,20 @@ _gcry_fips_is_operational (void)
 {
   int result;
 
-  if (!fips_mode ())
+  lock_fsm ();
+  if (current_state == STATE_POWERON && !fips_mode ())
+    /* If we are at this point in POWERON state it means the FIPS
+       module installation was not completed. (/etc/system-fips
+      is not present.) */
     result = 1;
   else
     {
-      lock_fsm ();
-      if (current_state == STATE_INIT)
+      if (current_state == STATE_INIT || current_state == STATE_SELFTEST)
         {
-          /* If we are still in the INIT state, we need to run the
-             selftests so that the FSM can eventually get into
-             operational state.  Given that we would need a 2-phase
+          /* If we are still in the INIT (or SELFTEST) state,
+             we need to run (or finish) the selftests so
+             that the FSM can eventually get into operational
+             state. Given that we would need a 2-phase
              initialization of libgcrypt, but that has traditionally
              not been enforced, we use this on demand self-test
              checking.  Note that Proper applications would do the
@@ -395,9 +405,11 @@ _gcry_fips_is_operational (void)
           lock_fsm ();
         }
 
-      result = (current_state == STATE_OPERATIONAL);
-      unlock_fsm ();
+      result = (current_state == STATE_OPERATIONAL) || !fips_mode ();
+      /* We always run the selftests but ignore the result
+         in non-FIPS mode. */
     }
+  unlock_fsm ();
   return result;
 }
 
@@ -722,9 +734,25 @@ _gcry_fips_run_selftests (int extended)
 {
   enum module_states result = STATE_ERROR;
   gcry_err_code_t ec = GPG_ERR_SELFTEST_FAILED;
+  int in_poweron;
 
-  if (fips_mode ())
-    fips_new_state (STATE_SELFTEST);
+  lock_fsm ();
+  in_poweron = (current_state == STATE_POWERON);
+  unlock_fsm ();
+
+  fips_new_state (STATE_SELFTEST);
+
+  /* We first check the integrity of the binary.
+     If run from the constructor we are in POWERON state,
+     we return and finish the remaining selftests before
+     real use of the library. It will be in the POWERON
+     state meanwhile.  */
+  if (in_poweron)
+    if (check_binary_integrity ())
+      goto leave;
+
+  if (in_poweron)
+    return 0;
 
   if (run_cipher_selftests (extended))
     goto leave;
@@ -743,18 +771,12 @@ _gcry_fips_run_selftests (int extended)
   if (run_pubkey_selftests (extended))
     goto leave;
 
-  /* Now check the integrity of the binary.  We do this this after
-     having checked the HMAC code.  */
-  if (check_binary_integrity ())
-    goto leave;
-
   /* All selftests passed.  */
   result = STATE_OPERATIONAL;
   ec = 0;
 
  leave:
-  if (fips_mode ())
-    fips_new_state (result);
+  fips_new_state (result);
 
   return ec;
 }
@@ -810,6 +832,7 @@ fips_new_state (enum module_states new_s
     {
     case STATE_POWERON:
       if (new_state == STATE_INIT
+          || new_state == STATE_SELFTEST
           || new_state == STATE_ERROR
           || new_state == STATE_FATALERROR)
         ok = 1;
@@ -824,6 +847,8 @@ fips_new_state (enum module_states new_s
 
     case STATE_SELFTEST:
       if (new_state == STATE_OPERATIONAL
+          || new_state == STATE_INIT
+          || new_state == STATE_SELFTEST
           || new_state == STATE_ERROR
           || new_state == STATE_FATALERROR)
         ok = 1;
Index: libgcrypt-1.8.4/src/global.c
===================================================================
--- libgcrypt-1.8.4.orig/src/global.c	2019-03-25 16:58:52.844354398 +0100
+++ libgcrypt-1.8.4/src/global.c	2019-03-25 16:58:53.516358344 +0100
@@ -145,6 +145,29 @@ global_init (void)
 }
 
 
+#ifndef FIPS_MODULE_PATH
+#define FIPS_MODULE_PATH "/etc/system-fips"
+#endif
+
+void __attribute__ ((constructor)) _gcry_global_constructor (void)
+{
+  int rv;
+
+  /* We always need the FSM lock to be functional. */
+  _gcry_initialize_fsm_lock ();
+
+  rv = access (FIPS_MODULE_PATH, F_OK);
+  if (rv < 0 && errno != ENOENT)
+    rv = 0;
+
+  if (!rv)
+    {
+      /* We run the integrity check at this point. The remaining
+         selftests are run before use of the library by application. */
+      _gcry_fips_run_selftests (0);
+    }
+}
+
 /* This function is called by the macro fips_is_operational and makes
    sure that the minimal initialization has been done.  This is far
    from a perfect solution and hides problems with an improper
@@ -675,8 +698,7 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd,
 
     case GCRYCTL_FIPS_MODE_P:
       if (fips_mode ()
-          && !_gcry_is_fips_mode_inactive ()
-          && !no_secure_memory)
+          && !_gcry_is_fips_mode_inactive ())
 	rc = GPG_ERR_GENERAL; /* Used as TRUE value */
       break;
 
@@ -753,9 +775,9 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd,
       break;
 
     case GCRYCTL_SET_ENFORCED_FIPS_FLAG:
-      if (!any_init_done)
+      if (fips_mode ())
         {
-          /* Not yet initialized at all.  Set the enforced fips mode flag */
+          /* We are in FIPS mode, we can set the enforced fips mode flag. */
           _gcry_set_preferred_rng_type (0);
           _gcry_set_enforced_fips_mode ();
         }
Index: libgcrypt-1.8.4/src/g10lib.h
===================================================================
--- libgcrypt-1.8.4.orig/src/g10lib.h	2019-03-25 16:58:52.844354398 +0100
+++ libgcrypt-1.8.4/src/g10lib.h	2019-03-25 16:58:53.516358344 +0100
@@ -422,6 +422,8 @@ gpg_err_code_t _gcry_sexp_vextract_param
 
 /*-- fips.c --*/
 
+void _gcry_initialize_fsm_lock (void);
+
 void _gcry_initialize_fips_mode (int force);
 
 int _gcry_fips_mode (void);