Implement global config file /etc/gcrypt/random.conf
authorWerner Koch <wk@gnupg.org>
Fri, 16 Jun 2017 08:42:44 +0000 (10:42 +0200)
committerWerner Koch <wk@gnupg.org>
Fri, 16 Jun 2017 08:42:44 +0000 (10:42 +0200)
* src/hwfeatures.c (my_isascii): Move macro to ...
* src/g10lib.h: here.
* tests/random.c (main): Dump random stats.
* random/random.c (RANDOM_CONF_FILE): New.
(_gcry_random_read_conf): New.
(_gcry_random_dump_stats): Call rndjent stats.
* random/rndjent.c (jent_rng_totalcalls, jent_rng_totalbytes): New.
(_gcry_rndjent_poll): Take care of config option disable-jent.  Wipe
buffer.  Bump counters.
(_gcry_rndjent_dump_stats): New.

Signed-off-by: Werner Koch <wk@gnupg.org>
doc/gcrypt.texi
random/rand-internal.h
random/random.c
random/rndjent.c
src/g10lib.h
src/hwfeatures.c
tests/random.c

index ae66dfc..3567582 100644 (file)
@@ -5455,6 +5455,21 @@ are:
 This file can be used to disable the use of hardware based
 optimizations, @pxref{hardware features}.
 
+
+@item /etc/gcrypt/random.conf
+@cindex /etc/gcrypt/random.conf
+This file can be used to globally change parameters of the random
+generator.  The file is a simple text file where empty lines and
+lines with the first non white-space character being '#' are
+ignored.  Supported options are
+
+@table @file
+@item disable-jent
+@cindex disable-jent
+Disable the use of the jitter based entropy generator.
+
+@end table
+
 @item /etc/gcrypt/fips_enabled
 @itemx /proc/sys/crypto/fips_enabled
 @cindex /etc/gcrypt/fips_enabled
index 7a798e9..ec4550c 100644 (file)
@@ -35,9 +35,11 @@ enum random_origins
                                     random request.  */
   };
 
+#define RANDOM_CONF_DISABLE_JENT 1
 
 
 /*-- random.c --*/
+unsigned int _gcry_random_read_conf (void);
 void _gcry_random_progress (const char *what, int printchar,
                             int current, int total);
 
@@ -128,6 +130,7 @@ size_t _gcry_rndjent_poll (void (*add)(const void*,
                                        size_t, enum random_origins),
                            enum random_origins origin,
                            size_t length);
+void _gcry_rndjent_dump_stats (void);
 
 /*-- rndhw.c --*/
 int _gcry_rndhw_failed_p (void);
index ff9be16..4a2a61b 100644 (file)
 #include <time.h>
 #include <sys/types.h>
 #include <unistd.h>
+#ifdef HAVE_SYSLOG
+# include <syslog.h>
+#endif /*HAVE_SYSLOG*/
+#include <ctype.h>
 
 #include "g10lib.h"
 #include "random.h"
 #include "rand-internal.h"
 #include "cipher.h"         /* For _gcry_sha1_hash_buffer().  */
 
+/* The name of a file used to globally configure the RNG. */
+#define RANDOM_CONF_FILE "/etc/gcrypt/random.conf"
+
 
 /* If not NULL a progress function called from certain places and the
    opaque value passed along.  Registered by
@@ -81,6 +88,71 @@ _gcry_random_progress (const char *what, int printchar, int current, int total)
 }
 
 
+/* Read a file with configure options.  The file is a simple text file
+ * where empty lines and lines with the first non white-space
+ * character being '#' are ignored.  Supported configure options are:
+ *
+ *  disable-jent - Disable the jitter based extra entropy generator.
+ *                 This sets the RANDOM_CONF_DISABLE_JENT bit.
+ *
+ * The function returns a bit vector with flags read from the file.
+ */
+unsigned int
+_gcry_random_read_conf (void)
+{
+  const char *fname = RANDOM_CONF_FILE;
+  FILE *fp;
+  char buffer[256];
+  char *p, *pend;
+  int lnr = 0;
+  unsigned int result = 0;
+
+  fp = fopen (fname, "r");
+  if (!fp)
+    return result;
+
+  for (;;)
+    {
+      if (!fgets (buffer, sizeof buffer, fp))
+        {
+          if (!feof (fp))
+            {
+#ifdef HAVE_SYSLOG
+              syslog (LOG_USER|LOG_WARNING,
+                      "Libgcrypt warning: error reading '%s', line %d",
+                      fname, lnr);
+#endif /*HAVE_SYSLOG*/
+            }
+          fclose (fp);
+          return result;
+        }
+      lnr++;
+      for (p=buffer; my_isascii (*p) && isspace (*p); p++)
+        ;
+      pend = strchr (p, '\n');
+      if (pend)
+        *pend = 0;
+      pend = p + (*p? (strlen (p)-1):0);
+      for ( ;pend > p; pend--)
+        if (my_isascii (*pend) && isspace (*pend))
+          *pend = 0;
+      if (!*p || *p == '#')
+        continue;
+
+      if (!strcmp (p, "disable-jent"))
+        result |= RANDOM_CONF_DISABLE_JENT;
+      else
+        {
+#ifdef HAVE_SYSLOG
+          syslog (LOG_USER|LOG_WARNING,
+                  "Libgcrypt warning: unknown option in '%s', line %d",
+                  fname, lnr);
+#endif /*HAVE_SYSLOG*/
+        }
+    }
+}
+
+
 /* Set the preferred RNG type.  This may be called at any time even
    before gcry_check_version.  Thus we can't assume any thread system
    initialization.  A type of 0 is used to indicate that any Libgcrypt
@@ -202,6 +274,7 @@ _gcry_random_dump_stats (void)
     _gcry_rngdrbg_dump_stats ();
   else
     _gcry_rngcsprng_dump_stats ();
+  _gcry_rndjent_dump_stats ();
 }
 
 
index fa3bb99..f997850 100644 (file)
@@ -120,6 +120,11 @@ static int jent_rng_is_initialized;
  * NULL.  Protected by JENT_RNG_LOCK.  */
 struct rand_data *jent_rng_collector;
 
+/* The number of times the core entropy function has been called and
+ * the number of random bytes retrieved.  */
+static unsigned long jent_rng_totalcalls;
+static unsigned long jent_rng_totalbytes;
+
 
 /* Acquire the jent_rng_lock.  */
 static void
@@ -177,13 +182,16 @@ _gcry_rndjent_poll (void (*add)(const void*, size_t, enum random_origins),
           jent_rng_is_initialized = 1;
           jent_entropy_collector_free (jent_rng_collector);
           jent_rng_collector = NULL;
-          if (!jent_entropy_init ())
-            jent_rng_collector = jent_entropy_collector_alloc (1, 0);
+          if ( !(_gcry_random_read_conf () & RANDOM_CONF_DISABLE_JENT))
+            {
+              if (!jent_entropy_init ())
+                jent_rng_collector = jent_entropy_collector_alloc (1, 0);
+            }
         }
 
       if (jent_rng_collector)
         {
-          /* We have a working JENT.  */
+          /* We have a working JENT and it has not been disabled.  */
           char buffer[256];
 
           while (length)
@@ -191,13 +199,16 @@ _gcry_rndjent_poll (void (*add)(const void*, size_t, enum random_origins),
               int rc;
               size_t n = length < sizeof(buffer)? length : sizeof (buffer);
 
+              jent_rng_totalcalls++;
               rc = jent_read_entropy (jent_rng_collector, buffer, n);
               if (rc < 0)
                 break;
               (*add) (buffer, rc, origin);
               length -= rc;
               nbytes += rc;
+              jent_rng_totalbytes += rc;
             }
+          wipememory (buffer, sizeof buffer);
         }
 
       unlock_rng ();
@@ -206,3 +217,23 @@ _gcry_rndjent_poll (void (*add)(const void*, size_t, enum random_origins),
 
   return nbytes;
 }
+
+
+/* Log statistical informantion about the use of this module.  */
+void
+_gcry_rndjent_dump_stats (void)
+{
+  /* In theory we would need to lock the stats here.  However this
+     function is usually called during cleanup and then we _might_ run
+     into problems.  */
+
+#ifdef USE_JENT
+  if ((_gcry_get_hw_features () & HWF_INTEL_RDTSC))
+    {
+
+      log_info ("rndjent stat: collector=%p calls=%lu bytes=%lu\n",
+                jent_rng_collector, jent_rng_totalcalls, jent_rng_totalbytes);
+
+    }
+#endif /*USE_JENT*/
+}
index 82562c7..ec8aab5 100644 (file)
@@ -96,6 +96,9 @@
 #define DIM(v) (sizeof(v)/sizeof((v)[0]))
 #define DIMof(type,member)   DIM(((type *)0)->member)
 
+#define my_isascii(c) (!((c) & 0x80))
+
+
 \f
 
 /*-- src/global.c -*/
index 45d7680..1cad546 100644 (file)
@@ -73,9 +73,6 @@ static unsigned int disabled_hw_features;
    available. */
 static unsigned int hw_features;
 
-/* Convenience macros.  */
-#define my_isascii(c) (!((c) & 0x80))
-
 
 \f
 /* Disable a feature by name.  This function must be called *before*
index 37a52b8..8a85429 100644 (file)
@@ -650,5 +650,8 @@ main (int argc, char **argv)
   if (!in_recursion)
     run_all_rng_tests (program);
 
+  if (debug)
+    xgcry_control (GCRYCTL_DUMP_RANDOM_STATS);
+
   return 0;
 }