Add a configuration file to disable hardware features.
authorWerner Koch <wk@gnupg.org>
Thu, 12 Dec 2013 19:26:56 +0000 (20:26 +0100)
committerWerner Koch <wk@gnupg.org>
Thu, 12 Dec 2013 19:26:56 +0000 (20:26 +0100)
* src/hwfeatures.c: Inclyde syslog.h and ctype.h.
(HWF_DENY_FILE): New.
(my_isascii): New.
(parse_hwf_deny_file): New.
(_gcry_detect_hw_features): Call it.

* src/mpicalc.c (main): Correctly initialize Libgcrypt.  Add options
"--print-config" and "--disable-hwf".

Signed-off-by: Werner Koch <wk@gnupg.org>
NEWS
doc/gcrypt.texi
src/fips.c
src/hwfeatures.c
src/mpicalc.c

diff --git a/NEWS b/NEWS
index 4c95e8a..978047f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -46,6 +46,8 @@ Noteworthy changes in version 1.6.0 (unreleased)
  * Changed gcry_pk_genkey for "ecc" to only include the curve name and
    not the parameters.  The flag "param" may be used to revert this.
 
+ * Added a feature to globally disable selected hardware features.
+
  * Interface changes relative to the 1.5.0 release:
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  gcry_ac_*                      REMOVED.
index 97dac1c..f3af29f 100644 (file)
@@ -210,6 +210,7 @@ of the library are verified.
 * Initializing the library::    How to initialize the library.
 * Multi-Threading::             How Libgcrypt can be used in a MT environment.
 * Enabling FIPS mode::          How to enable the FIPS mode.
+* Hardware features::           How to disable hardware features.
 @end menu
 
 
@@ -609,6 +610,50 @@ switch back to standard mode without terminating the process first.
 If the logging verbosity level of Libgcrypt has been set to at least
 2, the state transitions and the self-tests are logged.
 
+@node Hardware features
+@section How to disable hardware features
+@cindex hardware features
+
+Libgcrypt makes use of certain hardware features.  If the use of a
+feature is not desired it may be either be disabled by a program or
+globally using a configuration file.  The currently supported features
+are
+
+@table @code
+@item padlock-rng
+@item padlock-aes
+@item padlock-sha
+@item padlock-mmul
+@item intel-pclmul
+@item intel-aesni
+@item intel-rdrand
+@item intel-avx
+@item intel-avx2
+@item arm-neon
+@end table
+
+To disable a feature for all processes using Libgcrypt 1.6 or newer,
+create the file @file{/etc/gcrypt/hwf.deny} and put each feature not
+to be used on a single line.  Empty lines, white space, and lines
+prefixed with a hash mark are ignored.  The file should be world
+readable.
+
+To disable a feature specifically for a program that program must tell
+it Libgcrypt before before calling @code{gcry_check_version}.
+Example:@footnote{NB. Libgcrypt uses the RDRAND feature only as one
+source of entropy.  A CPU with a broken RDRAND will thus not
+compromise of the random number generator}
+
+@example
+  gcry_control (GCRYCTL_DISABLE_HWF, "intel-rdrand", NULL);
+@end example
+
+@noindent
+To print the list of active features you may use this command:
+
+@example
+  mpicalc --print-config | grep ^hwflist: | tr : '\n' | tail -n +2
+@end example
 
 
 @c **********************************************************
index 1d7a6a4..8148dcd 100644 (file)
@@ -36,7 +36,7 @@
 #include "hmac256.h"
 
 
-/* The name of the file used to foce libgcrypt into fips mode. */
+/* The name of the file used to force libgcrypt into fips mode. */
 #define FIPS_FORCE_FILE "/etc/gcrypt/fips_enabled"
 
 
index 43847d2..6699816 100644 (file)
 
 #include <config.h>
 #include <stdio.h>
+#include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
 #include <unistd.h>
+#ifdef HAVE_SYSLOG
+# include <syslog.h>
+#endif /*HAVE_SYSLOG*/
 
 #include "g10lib.h"
 #include "hwf-common.h"
 
+/* The name of a file used to globally disable selected features. */
+#define HWF_DENY_FILE "/etc/gcrypt/hwf.deny"
 
 /* A table to map hardware features to a string.  */
 static struct
@@ -56,7 +62,11 @@ 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*
    _gcry_detect_hw_features is called.  */
 gpg_err_code_t
@@ -96,6 +106,70 @@ _gcry_enum_hw_features (int idx, unsigned int *r_feature)
 }
 
 
+/* Read a file with features which shall not be used.  The file is a
+   simple text file where empty lines and lines with the first non
+   white-space character being '#' are ignored.  */
+static void
+parse_hwf_deny_file (void)
+{
+  const char *fname = HWF_DENY_FILE;
+  FILE *fp;
+  char buffer[256];
+  char *p, *pend;
+  int i, lnr = 0;
+
+  fp = fopen (fname, "r");
+  if (!fp)
+    return;
+
+  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;
+        }
+      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;
+
+      for (i=0; i < DIM (hwflist); i++)
+        {
+          if (!strcmp (hwflist[i].desc, p))
+            {
+              disabled_hw_features |= hwflist[i].flag;
+              break;
+            }
+        }
+      if (i == DIM (hwflist))
+        {
+#ifdef HAVE_SYSLOG
+          syslog (LOG_USER|LOG_WARNING,
+                  "Libgcrypt warning: unknown feature in '%s', line %d",
+                  fname, lnr);
+#endif /*HAVE_SYSLOG*/
+        }
+    }
+}
+
+
 /* Detect the available hardware features.  This function is called
    once right at startup and we assume that no other threads are
    running.  */
@@ -107,6 +181,8 @@ _gcry_detect_hw_features (void)
   if (fips_mode ())
     return; /* Hardware support is not to be evaluated.  */
 
+  parse_hwf_deny_file ();
+
 #if defined (HAVE_CPU_ARCH_X86)
   {
     hw_features = _gcry_hwf_detect_x86 ();
index 335b7c3..b2b4335 100644 (file)
@@ -40,6 +40,7 @@
 
 
 #define MPICALC_VERSION "2.0"
+#define NEED_LIBGCRYPT_VERSION "1.6.0"
 
 #define STACKSIZE  500
 static gcry_mpi_t stack[STACKSIZE];
@@ -309,6 +310,7 @@ main (int argc, char **argv)
 {
   const char *pgm;
   int last_argc = -1;
+  int print_config = 0;
   int i, c;
   int state = 0;
   char strbuf[1000];
@@ -350,10 +352,28 @@ main (int argc, char **argv)
                   "Simple interactive big integer RPN calculator\n"
                   "\n"
                   "Options:\n"
-                  "  --version  print version information\n",
+                  "  --version           print version information\n"
+                  "  --print-config      print the Libgcrypt config\n"
+                  "  --disable-hwf NAME  disable feature NAME\n",
                   pgm, gcry_check_version (NULL));
           exit (0);
         }
+      else if (!strcmp (*argv, "--print-config"))
+        {
+          argc--; argv++;
+          print_config = 1;
+        }
+      else if (!strcmp (*argv, "--disable-hwf"))
+        {
+          argc--; argv++;
+          if (argc)
+            {
+              if (gcry_control (GCRYCTL_DISABLE_HWF, *argv, NULL))
+                fprintf (stderr, "%s: unknown hardware feature `%s'"
+                         " - option ignored\n", pgm, *argv);
+              argc--; argv++;
+            }
+        }
     }
 
   if (argc)
@@ -362,6 +382,20 @@ main (int argc, char **argv)
       exit (1);
     }
 
+  if (!gcry_check_version (NEED_LIBGCRYPT_VERSION))
+    {
+      fprintf (stderr, "%s: Libgcrypt is too old (need %s, have %s)\n",
+               pgm, NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
+      exit (1);
+    }
+  gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+  if (print_config)
+    {
+      gcry_control (GCRYCTL_PRINT_CONFIG, stdout);
+      exit (0);
+    }
+
   for (i = 0; i < STACKSIZE; i++)
     stack[i] = NULL;
   stackidx = 0;