Implemented an Enforced FIPS mode.
authorWerner Koch <wk@gnupg.org>
Thu, 18 Sep 2008 12:14:09 +0000 (12:14 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 18 Sep 2008 12:14:09 +0000 (12:14 +0000)
Documentation updates.

12 files changed:
NEWS
TODO
doc/ChangeLog
doc/gcrypt.texi
src/ChangeLog
src/fips.c
src/g10lib.h
src/global.c
src/secmem.c
tests/ChangeLog
tests/basic.c
tests/cavs_driver.pl

diff --git a/NEWS b/NEWS
index 2bc44e4..df3788d 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -8,7 +8,12 @@ Noteworthy changes in version 1.4.3
    cases.  Folks, please read the manual to learn how to properly
    initialize Libgcrypt!
 
- * Log fatal error via syslog.
+ * Log fatal errors via syslog.
+
+ * Auto-initialize the secure memory to 32k instead of aborting the
+   process.
+
+ * Changed the name and the semantics of the fips mode config file.
 
  * More self-tests.
 
diff --git a/TODO b/TODO
index 1d61390..070bde4 100644 (file)
--- a/TODO
+++ b/TODO
@@ -22,32 +22,6 @@ What's left to do                                 -*- outline -*-
   Don't rely on the secure memory based wiping function but add an
   extra wiping.
   
-* update/improve documentation
-** it's outdated for e.g. gcry_pk_algo_info.
-** document algorithm capabilities
-** Init requirements for random
-   The documentation says in "Controlling the library" that some
-   functions can only be used at initialization time, but it does not
-   explain what that means.  Initialization is a multi-step procedure:
-   First the thread callbacks have to be set up (optional), then the
-   gcry_check_version() function must be called (mandatory), then
-   further functions can be used.
-
-   The manual also says that something happens when the seed file is
-   registered berfore the PRNG is initialized, but it does not say how
-   one can guarantee to call it early enough.
-
-   Suggested fix: Specify initialization time as the time after
-   gcry_check_version and before calling any other function except
-   gcry_control().
-
-   All functions which modify global state without a lock must be
-   documented as "can only be called during initialization time" (but
-   see item 1).  Then the extraneous calls to _gcry_random_initialize
-   in gcry_control() can be removed, and the comments "not thread
-   safe" in various initialization-time-only functions like
-   _gcry_use_random_daemon become superfluous.
-
 * Use builtin bit functions of gcc 3.4
 
 * Consider using a daemon to maintain the random pool
index 5844e31..d312ce2 100644 (file)
@@ -1,3 +1,8 @@
+2008-09-18  Werner Koch  <wk@g10code.com>
+
+       * gcrypt.texi: Add a couple of index items.
+       (FIPS Mode): Reflect recent changes. 
+
 2008-09-16  Werner Koch  <wk@g10code.com>
 
        * gcrypt.texi (FIPS Mode): Describe new transitions 18 and 19.
@@ -407,7 +412,7 @@ Wed Feb 10 17:15:39 CET 1999  Werner Koch  <wk@isil.d.shuttle.de>
        * FAQ: Ditto.
        * DETAILS: Ditto.
 
- Copyright 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
+ Copyright 1999, 2000, 2002, 2003, 2008 Free Software Foundation, Inc.
 
  This file is free software; as a special exception the author gives
  unlimited permission to copy and/or distribute it, with or without
index e5f3de0..9be66d6 100644 (file)
@@ -519,6 +519,7 @@ programmers might have to wrap these macros in an ``extern C'' body.
 
 @node Enabling FIPS mode
 @section How to enable the FIPS mode
+@cindex FIPS mode
 
 Libgcrypt may be used in a FIPS 140-2 mode.  Note, that this does not
 necessary mean that Libcgrypt is an appoved FIPS 140-2 module.  Check the
@@ -538,7 +539,7 @@ initialization time.  Obviously this works only on systems with a
 @code{proc} file system (i.e. GNU/Linux).
 
 @item 
-If the file @file{/etc/gcrypt/fips140.force} exists, Libgcrypt is put
+If the file @file{/etc/gcrypt/fips_enabled} exists, Libgcrypt is put
 into FIPS mode at initialization time.  Note that this filename is
 hardwired and does not depend on any configuration options.
 
@@ -549,6 +550,14 @@ initialization (i.e. before @code{gcry_check_version}).
 
 @end itemize
 
+@cindex Enforced FIPS mode
+
+In addition to the standard FIPS mode, Libgcrypt may also be put into
+an Enforced FIPS mode by writing a non-zero value into the file
+@file{/etc/gcrypt/fips_enabled}.  The Enforced FIPS mode helps to
+detect applications which don't fulfill all requirements for using
+Libgcrypt in FIPS mode (@pxref{FIPS Mode}).
+
 Once Libgcrypt has been put into FIPS mode, it is not possible to
 switch back to standard mode without terminating the process first.
 If the logging verbosity level of Libgcrypt has been set to at least
@@ -616,13 +625,14 @@ to disable secure memory is to use @code{GCRYCTL_DISABLE_SECMEM} right
 after initialization.
 
 @item GCRYCTL_DISABLE_SECMEM; Arguments: none
-This command disables the use of secure memory. 
+This command disables the use of secure memory.  If this command is
+used in FIPS mode, FIPS mode will be disabled and the command
+@code{GCRYCTL_FIPS_MODE_P} returns false.  However, in Enforced FIPS
+mode this command has no effect at all.
 
 Many applications do not require secure memory, so they should disable
-it right away.  There won't be a problem if not disabling it unless one
-makes use of a feature which requires secure memory - in that case the
-process will abort because the secmem is not initialized.  This command
-should be executed right after @code{gcry_check_version}.
+it right away.  This command should be executed right after
+@code{gcry_check_version}. 
 
 @item GCRYCTL_INIT_SECMEM; Arguments: int nbytes
 This command is used to allocate a pool of secure memory and thus
@@ -766,7 +776,8 @@ the intialization has been finished but not before a gcry_version_check.
 This command returns true if the library is in FIPS mode.  Note, that
 this is no indication about the current state of the library.  This
 command may be used before the intialization has been finished but not
-before a gcry_version_check.
+before a gcry_version_check.  An application may use this function to
+check whether FIPS mode is still active.
 
 @item GCRYCTL_FORCE_FIPS_MODE; Arguments: none
 Running this command puts the library into FIPS mode.  If the library is
@@ -1360,18 +1371,25 @@ This is not a real algorithm but used by some functions as error return.
 The value always evaluates to false.
 
 @item GCRY_CIPHER_IDEA
+@cindex IDEA
 This is the IDEA algorithm.  The constant is provided but there is
 currently no implementation for it because the algorithm is patented.
 
 @item GCRY_CIPHER_3DES
+@cindex 3DES
+@cindex Triple-DES
+@cindex DES-EDE
+@cindex Digital Encryption Standard
 Triple-DES with 3 Keys as EDE.  The key size of this algorithm is 168 but
 you have to pass 192 bits because the most significant bits of each byte
 are ignored.
 
 @item GCRY_CIPHER_CAST5
+@cindex CAST5
 CAST128-5 block cipher algorithm.  The key size is 128 bits.
        
 @item GCRY_CIPHER_BLOWFISH
+@cindex Blowfish
 The blowfish algorithm. The current implementation allows only for a key
 size of 128 bits.
 
@@ -1385,6 +1403,9 @@ Reserved and not currently implemented.
 @itemx GCRY_CIPHER_AES128
 @itemx GCRY_CIPHER_RIJNDAEL
 @itemx GCRY_CIPHER_RIJNDAEL128
+@cindex Rijndael
+@cindex AES
+@cindex Advanced Encryption Standard
 AES (Rijndael) with a 128 bit key.
 
 @item  GCRY_CIPHER_AES192     
@@ -1396,17 +1417,21 @@ AES (Rijndael) with a 192 bit key.
 AES (Rijndael) with a 256 bit key.
     
 @item  GCRY_CIPHER_TWOFISH
+@cindex Twofish
 The Twofish algorithm with a 256 bit key.
     
 @item  GCRY_CIPHER_TWOFISH128
 The Twofish algorithm with a 128 bit key.
     
 @item  GCRY_CIPHER_ARCFOUR   
+@cindex Arcfour
+@cindex RC4
 An algorithm which is 100% compatible with RSA Inc.'s RC4 algorithm.
 Note that this is a stream cipher and must be used very carefully to
 avoid a couple of weaknesses. 
 
-@item  GCRY_CIPHER_DES       
+@item  GCRY_CIPHER_DES
+@cindex DES
 Standard DES with a 56 bit key. You need to pass 64 bit but the high
 bits of each byte are ignored.  Note, that this is a weak algorithm
 which can be broken in reasonable time using a brute force approach.
@@ -1414,20 +1439,25 @@ which can be broken in reasonable time using a brute force approach.
 @item  GCRY_CIPHER_SERPENT128
 @itemx GCRY_CIPHER_SERPENT192
 @itemx GCRY_CIPHER_SERPENT256
+@cindex Serpent
 The Serpent cipher from the AES contest.
 
 @item  GCRY_CIPHER_RFC2268_40
 @itemx GCRY_CIPHER_RFC2268_128
+@cindex rfc-2268
+@cindex RC2
 Ron's Cipher 2 in the 40 and 128 bit variants.  Note, that we currently
 only support the 40 bit variant.  The identifier for 128 is reserved for
 future use.
 
 @item GCRY_CIPHER_SEED
+@cindex Seed (cipher)
 A 128 bit cipher as described by RFC4269.
 
 @item  GCRY_CIPHER_CAMELLIA128
 @itemx GCRY_CIPHER_CAMELLIA192
 @itemx GCRY_CIPHER_CAMELLIA256
+@cindex Camellia
 The Camellia cipher by NTT.  See
 @uref{http://info.isl.ntt.co.jp/@/crypt/@/eng/@/camellia/@/specifications.html}.
 
@@ -1555,22 +1585,27 @@ if Libgcrypt is not used in FIPS mode and if any debug flag has been
 set, this mode may be used to bypass the actual encryption.
 
 @item GCRY_CIPHER_MODE_ECB
+@cindex ECB, Electronic Codebook mode
 Electronic Codebook mode.  
 
 @item GCRY_CIPHER_MODE_CFB
+@cindex CFB, Cipher Feedback mode
 Cipher Feedback mode.  The shift size equals the block size of the
 cipher (e.g. for AES it is CFB-128).
 
 @item  GCRY_CIPHER_MODE_CBC
+@cindex CBC, Cipher Block Chaining mode
 Cipher Block Chaining mode.
 
 @item GCRY_CIPHER_MODE_STREAM
 Stream mode, only to be used with stream cipher algorithms.
 
 @item GCRY_CIPHER_MODE_OFB
+@cindex OFB, Output Feedback mode
 Output Feedback mode.
 
 @item  GCRY_CIPHER_MODE_CTR
+@cindex CTR, Counter mode
 Counter mode.
 
 @end table
@@ -1613,15 +1648,18 @@ the bit-wise OR of the following constants.
 Make sure that all operations are allocated in secure memory.  This is
 useful when the key material is highly confidential.
 @item GCRY_CIPHER_ENABLE_SYNC
+@cindex sync mode (OpenPGP)
 This flag enables the CFB sync mode, which is a special feature of
 Libgcrypt's CFB mode implementation to allow for OpenPGP's CFB variant. 
 See @code{gcry_cipher_sync}.
 @item GCRY_CIPHER_CBC_CTS
+@cindex cipher text stealing
 Enable cipher text stealing (CTS) for the CBC mode.  Cannot be used
 simultaneous as GCRY_CIPHER_CBC_MAC.  CTS mode makes it possible to
 transform data of almost arbitrary size (only limitation is that it
 must be greater than the algorithm's block size).
 @item GCRY_CIPHER_CBC_MAC
+@cindex CBC-MAC
 Compute CBC-MAC keyed checksums.  This is the same as CBC mode, but
 only output the last block.  Cannot be used simultaneous as
 GCRY_CIPHER_CBC_CTS.
@@ -3250,6 +3288,14 @@ are also supported.
 @section Available hash algorithms
 
 @c begin table of hash algorithms
+@cindex SHA-1
+@cindex SHA-224, SHA-256, SHA-384, SHA-512
+@cindex RIPE-MD-160
+@cindex MD2, MD4, MD5
+@cindex TIGER
+@cindex HAVAL
+@cindex Whirlpool
+@cindex CRC32
 @table @code
 @item GCRY_MD_NONE
 This is not a real algorithm but used by some functions as an error
@@ -3441,6 +3487,7 @@ Allocate all buffers and the resulting digest in "secure memory".  Use
 this is the hashed data is highly confidential.
 
 @item GCRY_MD_FLAG_HMAC
+@cindex HMAC
 Turn the algorithm into a HMAC message authentication algorithm.  This
 only works if just one algorithm is enabled for the handle.  Note that
 the function @code{gcry_md_setkey} must be used to set the MAC key.
@@ -5409,17 +5456,21 @@ FIPS mode may only be used on systems with a /dev/random device.
 Switching into FIPS mode on other systems will fail at runtime.
 
 @item
-Saving and loading a random seed file is not ignored.
+Saving and loading a random seed file is ignored.
 
 @item
 An X9.31 style random number generator is used in place of the
 large-pool-CSPRNG generator.
 
 @item
+The command @code{GCRYCTL_ENABLE_QUICK_RANDOM} is ignored.
+
+@item
 The Alternative Public Key Interface (@code{gcry_ac_xxx}) is not
 supported and all API calls return an error.
 
-@item Registration of external modules is not supported.
+@item
+Registration of external modules is not supported.
 
 @item 
 Message digest debugging is disabled.
@@ -5428,21 +5479,29 @@ Message digest debugging is disabled.
 All debug output related to cryptographic data is suppressed.
 
 @item 
-On-the-fly self-tests are not performed, instead of this self-tests are
-run before entering operational state.
+On-the-fly self-tests are not performed, instead self-tests are run
+before entering operational state.
 
 @item
-The function @code{gcry_set_allocation_handler} may not be used.  If it
-is used Libgcrypt will enter the error state.
+The function @code{gcry_set_allocation_handler} may not be used.  If
+it is used Libgcrypt disables FIPS mode unless Enforced FIPS mode is
+enabled, in which case Libgcrypt will enter the error state.
+
+@item 
+In Enforced FIPS mode the command @code{GCRYCTL_DISABLE_SECMEM} is
+ignored.  In standard FIPS mode it disables FIPS mode.
 
 @item
 A handler set by @code{gcry_set_outofcore_handler} is ignored.
 @item
 A handler set by @code{gcry_set_fatalerror_handler} is ignored.
 
-
 @end itemize
 
+Note that when we speak about disabling FIPS mode, it merely means
+that the command @code{GCRYCTL_FIPS_MODE_P} returns false; it does not
+mean that any non FIPS algorithms are allowed.
+
 
 @c ********************************************
 @section FIPS Finite State Machine
index b96f8bb..e29f05e 100644 (file)
@@ -1,3 +1,26 @@
+2008-09-18  Werner Koch  <wk@g10code.com>
+
+       * secmem.c (_gcry_secmem_init): Factor most code out to ..
+       (secmem_init): .. new.
+       (DEFAULT_POOL_SIZE): Rename to MINIMUM_POOL_SIZE.
+       (STANDARD_POOL_SIZE): New.
+       (_gcry_secmem_malloc_internal): Don't abort if the pool is not
+       initialized but try to out intialize it first and only then print
+       an error message and return NULL.  If the pool is not locked while
+       in FIPS mode, return NULL.
+
+       * fips.c (FIPS_FORCE_FILE): New constant.  Change the file name to
+       "/etc/gcrypt/fips_enabled".
+       (enforced_fips_mode): New.
+       (_gcry_initialize_fips_mode): Set that flag.
+       (_gcry_enforced_fips_mode): New.
+       * global.c (inactive_fips_mode): New.
+       (_gcry_vcontrol): Take that flag in account for GCRYCTL_FIPS_MODE_P.
+       (gcry_set_allocation_handler): Take care of the enforced fips mdoe
+       flag.
+       (get_no_secure_memory): New.
+       (do_malloc, gcry_is_secure): Use it.
+
 2008-09-16  Werner Koch  <wk@g10code.com>
 
        * global.c (print_config): Use y/n for fips mode.
index e98930d..90fb3e2 100644 (file)
 #include "cipher-proto.h"
 #include "hmac256.h"
 
+
+/* The name of the file used to foce libgcrypt into fips mode. */
+#define FIPS_FORCE_FILE "/etc/gcrypt/fips_enabled"
+
+
 /* The states of the finite state machine used in fips mode.  */
 enum module_states 
   {
@@ -55,6 +60,9 @@ enum module_states
    fips_mode()! */
 static int no_fips_mode_required;
 
+/* Flag to indicate that we are in the enforced FIPS mode.  */
+static int enforced_fips_mode;
+
 /* This is the lock we use to protect the FSM.  */
 static ath_mutex_t fsm_lock = ATH_MUTEX_INITIALIZER;
 
@@ -103,7 +111,7 @@ _gcry_initialize_fips_mode (int force)
     }
   done = 1;
 
-  /* If the calling applicatione explicitly requested fipsmode, do so.  */
+  /* If the calling application explicitly requested fipsmode, do so.  */
   if (force)
     {
       gcry_assert (!no_fips_mode_required);
@@ -114,11 +122,8 @@ _gcry_initialize_fips_mode (int force)
      provided detection of the FIPS mode and force FIPS mode using a
      file.  The filename is hardwired so that there won't be any
      confusion on whether /etc/gcrypt/ or /usr/local/etc/gcrypt/ is
-     actually used.  The file itself may be empty.  A comment may be
-     included in the file, but comment lines need to be prefixed with
-     a hash mark; only such comment lines and empty lines are
-     allowed.  */
-  if ( !access ("/etc/gcrypt/fips140.force", F_OK) )
+     actually used.  The file itself may be empty.  */
+  if ( !access (FIPS_FORCE_FILE, F_OK) )
     {
       gcry_assert (!no_fips_mode_required);
       goto leave;
@@ -167,6 +172,7 @@ _gcry_initialize_fips_mode (int force)
   if (!no_fips_mode_required)
     {
       /* Yes, we are in FIPS mode.  */
+      FILE *fp;
 
       /* Intitialize the lock to protect the FSM.  */
       err = ath_mutex_init (&fsm_lock);
@@ -184,7 +190,20 @@ _gcry_initialize_fips_mode (int force)
 #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");
+      if (fp)
+        {
+          char line[256];
+          
+          if (fgets (line, sizeof line, fp) && atoi (line))
+            enforced_fips_mode = 1;
+          fclose (fp);
+        }
+
       /* Now get us into the INIT state.  */
       fips_new_state (STATE_INIT);
       
@@ -245,6 +264,14 @@ _gcry_fips_mode (void)
 }
 
 
+/* Return a flag telling whether we are in the enforced fips mode.  */
+int 
+_gcry_enforced_fips_mode (void)
+{
+  return enforced_fips_mode;
+}
+
+
 static const char *
 state2str (enum module_states state)
 {
index 0d0aea6..6a23f26 100644 (file)
@@ -293,6 +293,8 @@ void _gcry_initialize_fips_mode (int force);
 int _gcry_fips_mode (void);
 #define fips_mode() _gcry_fips_mode ()
 
+int _gcry_enforced_fips_mode (void);
+
 void _gcry_fips_signal_error (const char *srcfile, 
                               int srcline, 
                               const char *srcfunc,
index 4af7412..b8f7126 100644 (file)
@@ -50,6 +50,10 @@ static unsigned int debug_flags;
    intialization code swicthed fips mode on.  */
 static int force_fips_mode;
 
+/* If this flag is set, the application may no longer assume that the
+   process is running in FIPS mode.  */
+static int inactive_fips_mode;
+
 /* Controlled by global_init().  */
 static int any_init_done;
 
@@ -297,7 +301,9 @@ print_config ( int (*fnc)(FILE *fp, const char *format, ...), FILE *fp)
   /* We use y/n instead of 1/0 for the simple reason that Emacsen's
      compile error parser would accidently flag that line when printed
      during "make check" as an error.  */
-  fnc (fp, "fips-mode:%c:\n", fips_mode ()? 'y':'n' );
+  fnc (fp, "fips-mode:%c:%c:\n", 
+       fips_mode ()? 'y':'n';
+       _gcry_enforced_fips_mode ()? 'y':'n' );
 }
 
 
@@ -489,7 +495,7 @@ _gcry_vcontrol (enum gcry_ctl_cmds cmd, va_list arg_ptr)
       break;
 
     case GCRYCTL_FIPS_MODE_P:
-      if (fips_mode ())
+      if (fips_mode () && !inactive_fips_mode && !no_secure_memory)
        err = GPG_ERR_GENERAL; /* Used as TRUE value */
       break;
 
@@ -636,7 +642,10 @@ gcry_error_from_errno (int err)
   return gcry_error (gpg_err_code_from_errno (err));
 }
 
-/****************
+
+/* Set custom allocation handlers.  This is in general not useful
+ * because the libgcrypt allocation functions are guaranteed to
+ * provide proper allocation handlers which zeroize memory if needed.
  * NOTE: All 5 functions should be set.  */
 void
 gcry_set_allocation_handler (gcry_handler_alloc_t new_alloc_func,
@@ -647,10 +656,22 @@ gcry_set_allocation_handler (gcry_handler_alloc_t new_alloc_func,
 {
   global_init ();
 
-  if (fips_mode () )
+  if (fips_mode ())
     {
-      fips_signal_error ("custom allocation handler used");
-      return;
+      if (_gcry_enforced_fips_mode () )
+        {
+          /* Get us into the error state. */
+          fips_signal_error ("custom allocation handler used");
+          return;
+        }
+      /* We do not want to enforce the fips mode, but merely set a
+         flag so that the application may check wheter it is still in
+         fips mode.  */
+      inactive_fips_mode = 1;
+#ifdef HAVE_SYSLOG
+      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
+              "custom allocation handler used - FIPS mode disabled");
+#endif /*HAVE_SYSLOG*/
     }
 
   alloc_func = new_alloc_func;
@@ -692,13 +713,28 @@ gcry_set_outofcore_handler( int (*f)( void*, size_t, unsigned int ),
   outofcore_handler_value = value;
 }
 
+/* Return the no_secure_memory flag.  */
+static int
+get_no_secure_memory (void)
+{
+  if (!no_secure_memory)
+    return 0;
+  if (_gcry_enforced_fips_mode ())
+    {
+      no_secure_memory = 0;
+      return 0;
+    }
+  return no_secure_memory;
+}
+
+
 static gcry_err_code_t
 do_malloc (size_t n, unsigned int flags, void **mem)
 {
   gcry_err_code_t err = 0;
   void *m;
 
-  if ((flags & GCRY_ALLOC_FLAG_SECURE) && !no_secure_memory)
+  if ((flags & GCRY_ALLOC_FLAG_SECURE) && !get_no_secure_memory ())
     {
       if (alloc_secure_func)
        m = (*alloc_secure_func) (n);
@@ -750,7 +786,7 @@ gcry_malloc_secure (size_t n)
 int
 gcry_is_secure (const void *a)
 {
-  if (no_secure_memory)
+  if (get_no_secure_memory ())
     return 0;
   if (is_secure_func)
     return is_secure_func (a) ;
index 6525db0..a12af58 100644 (file)
@@ -44,7 +44,8 @@
 #define MAP_ANONYMOUS MAP_ANON
 #endif
 
-#define DEFAULT_POOL_SIZE 16384
+#define MINIMUM_POOL_SIZE 16384
+#define STANDARD_POOL_SIZE 32768
 #define DEFAULT_PAGE_SIZE 4096
 
 typedef struct memblock
@@ -442,15 +443,12 @@ _gcry_secmem_get_flags (void)
   return flags;
 }
 
-/* Initialize the secure memory system.  If running with the necessary
-   privileges, the secure memory pool will be locked into the core in
-   order to prevent page-outs of the data.  Furthermore allocated
-   secure memory will be wiped out when released.  */
-void
-_gcry_secmem_init (size_t n)
-{
-  SECMEM_LOCK;
 
+/* See _gcry_secmem_init.  This function is expected to be called with
+   the secmem lock held. */
+static void
+secmem_init (size_t n)
+{
   if (!n)
     {
 #ifdef USE_CAPABILITIES
@@ -471,8 +469,8 @@ _gcry_secmem_init (size_t n)
     }
   else
     {
-      if (n < DEFAULT_POOL_SIZE)
-       n = DEFAULT_POOL_SIZE;
+      if (n < MINIMUM_POOL_SIZE)
+       n = MINIMUM_POOL_SIZE;
       if (! pool_okay)
        {
          init_pool (n);
@@ -481,6 +479,20 @@ _gcry_secmem_init (size_t n)
       else
        log_error ("Oops, secure memory pool already initialized\n");
     }
+}
+
+
+
+/* Initialize the secure memory system.  If running with the necessary
+   privileges, the secure memory pool will be locked into the core in
+   order to prevent page-outs of the data.  Furthermore allocated
+   secure memory will be wiped out when released.  */
+void
+_gcry_secmem_init (size_t n)
+{
+  SECMEM_LOCK;
+
+  secmem_init (n);
 
   SECMEM_UNLOCK;
 }
@@ -493,8 +505,19 @@ _gcry_secmem_malloc_internal (size_t size)
 
   if (!pool_okay)
     {
-      log_bug (_
-       ("operation is not possible without initialized secure memory\n"));
+      /* Try to initialize the pool if the user forgot about it.  */
+      secmem_init (STANDARD_POOL_SIZE);
+      if (!pool_okay)
+        {
+          log_info (_("operation is not possible without "
+                      "initialized secure memory\n"));
+          return NULL;
+        }
+    }
+  if (not_locked && fips_mode ())
+    {
+      log_info (_("secure memory pool is not locked while in FIPS mode\n"));
+      return NULL;
     }
   if (show_warning && !suspend_warning)
     {
index de5381d..6e6a311 100644 (file)
@@ -1,3 +1,7 @@
+2008-09-18  Werner Koch  <wk@g10code.com>
+
+       * basic.c (main): Do not disable secure memory in FIPS mode.
+
 2008-09-16  Werner Koch  <wk@g10code.com>
 
        * fipsrngdrv.c (main): Bail out on write error.  Implement verbose
index b51f8f8..e33a043 100644 (file)
@@ -2089,19 +2089,21 @@ main (int argc, char **argv)
   if (!gcry_check_version (GCRYPT_VERSION))
     die ("version mismatch\n");
 
+  if ( gcry_control (GCRYCTL_FIPS_MODE_P, 0) )
+    in_fips_mode = 1;
+
+  if (!in_fips_mode)
+    gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+
   if (verbose)
     gcry_set_progress_handler (progress_handler, NULL);
-  
-  gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+
   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
   if (debug)
     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
   /* No valuable keys are create, so we can speed up our RNG. */
   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
 
-  if ( gcry_control (GCRYCTL_FIPS_MODE_P, 0) )
-    in_fips_mode = 1;
-
   if (!selftest_only)
     {
       check_ciphers ();
index 3ebd2e3..55c238f 100644 (file)
@@ -1,5 +1,7 @@
 #!/usr/bin/env perl
 #
+# $Id: cavs_driver.pl 1236 2008-09-17 13:00:06Z smueller $
+#
 # CAVS test driver (based on the OpenSSL driver)
 # Written by: Stephan Müller <sm@atsec.com>
 # Copyright (c) atsec information security corporation
 # but have not been tested)
 #
 # AES
-#      CBCGFSbox[128|192|256]
-#      CBCMCT[128|192|256]
-#      CBCVarKey[128|192|256]
-#      CBCKeySbox[128|192|256]
-#      CBCMMT[128|192|256]
-#      CBCVarTxt[128|192|256]
+#      [CBC|CFB128|ECB|OFB]GFSbox[128|192|256]
+#      [CBC|CFB128|ECB|OFB]MCT[128|192|256]
+#      [CBC|CFB128|ECB|OFB]VarKey[128|192|256]
+#      [CBC|CFB128|ECB|OFB]KeySbox[128|192|256]
+#      [CBC|CFB128|ECB|OFB]MMT[128|192|256]
+#      [CBC|CFB128|ECB|OFB]VarTxt[128|192|256]
 #
 # RSA
 #      SigGen[15|RSA]
 #              is not done through openssl dgst)
 #
 # SHA
-#      SHA1ShortMsg
-#      SHA1LongMsg
-#      SHA1Monte
+#      SHA[1|224|256|384|512]ShortMsg
+#      SHA[1|224|256|384|512]LongMsg
+#      SHA[1|224|256|384|512]Monte
+#
+# HMAC (SHA - caveat: we only support hash output equal to the block size of
+#      of the hash - we do not support truncation of the hash; to support
+#      that, we first need to decipher the HMAC.req file - see hmac_kat() )
+#      HMAC
 #
 # TDES
-#      TCBCMonte[1|2|3]
-#      TCBCpermop
-#      TCBCMMT[1|2|3]
-#      TCBCsubtab
-#      TCBCvarkey
-#      TCBCinvperm
-#      TCBCvartext
+#      T[CBC|CFB??|ECB|OFB]Monte[1|2|3]
+#      T[CBC|CFB??|ECB|OFB]permop
+#      T[CBC|CFB??|ECB|OFB]MMT[1|2|3]
+#      T[CBC|CFB??|ECB|OFB]subtab
+#      T[CBC|CFB??|ECB|OFB]varkey
+#      T[CBC|CFB??|ECB|OFB]invperm
+#      T[CBC|CFB??|ECB|OFB]vartext
 #
 # ANSI X9.31 RNG
 #      ANSI931_AES128MCT
@@ -110,9 +117,15 @@ my %opt;
 # function to the given variables.
 
 # common encryption/decryption routine
-# $1 key in hex form
+# $1 key in hex form (please note for 3DES: even when ede3 for three
+#    independent ciphers is given with the cipher specification, we hand in
+#    either one key for k1 = k2 = k3, two keys which are concatinated for
+#    k1 = k3, k2 independent, or three keys which are concatinated for
+#    k1, k2, k3 independent)
 # $2 iv in hex form
-# $3 cipher
+# $3 cipher - the cipher string is defined as specified in the openssl
+#    enc(1ssl) specification for the option "-ciphername"
+#    (e.g. aes-128-cbc or des-ede3-cbc)
 # $4 encrypt=1/decrypt=0
 # $5 de/encrypted data in hex form
 # return en/decrypted data in hex form
@@ -133,15 +146,18 @@ my $rsa_sign;
 # return: 1 == verfied / 0 == not verified
 my $rsa_verify;
 
-# generate a new private RSA key in PEM format
+# generate a new private RSA key with the following properties:
+#      exponent is 65537
+#      PEM format
 # $1 key size in bit
 # $2 keyfile name
 # return: nothing, but file created
 my $gen_rsakey;
 
 # Creating a hash
-# $1: Plaintext
-# $2: hash type
+# $1: Plaintext in hex form
+# $2: hash type in the form documented in openssl's dgst(1ssl) - e.g.
+#     sha1, sha224, sha256, sha384, sha512
 # return: hash in hex form
 my $hash;
 
@@ -172,6 +188,14 @@ my $state_cipher;
 # between the reads. The output of the RNG on STDOUT is assumed to be binary.
 my $state_rng;
 
+# Generate an HMAC based on SHAx
+# $1: Key to be used for the HMAC in hex format
+# $2: length of the hash to be calculated in bits
+# $3: Message for which the HMAC shall be calculated in hex format
+# $4: hash type (1 - SHA1, 224 - SHA224, and so on)
+# return: calculated HMAC in hex format
+my $hmac;
+
 ################################################################
 ##### OpenSSL interface functions
 ################################################################
@@ -266,6 +290,16 @@ sub libgcrypt_state_rng($$$) {
        return "fipsrngdrv --binary --loop $key $v $dt";
 }
 
+sub libgcrypt_hmac($$$$) {
+       my $key = shift;
+       my $maclen = shift;
+       my $msg = shift;
+       my $hashtype = shift;
+
+       die "libgcrypt HMAC test not yet implemented: key $key, maclen $maclen, msg $msg, hashtype $hashtype";
+       
+}
+
 ######### End of libgcrypt implementation ################
 
 ##### No other interface functions below this point ######
@@ -757,14 +791,12 @@ sub kat($$$$$$$$) {
 
        my $out = "";
 
+       $out .= "$keytype = $key1\n";
+
        # this is the concardination of the keys for 3DES
-       # as used in OpenSSL
        if (defined($key2)) {
-               $out .= "$keytype = $key1\n";
                $out .= "KEY2 = $key2\n";
                $key1 = $key1 . $key2;
-       } else {
-               $out .= "$keytype = $key1\n";
        }
        if (defined($key3)) {
                $out .= "KEY3 = $key3\n";
@@ -800,6 +832,46 @@ sub hash_kat($$$) {
        return $out;
 }
 
+# Known Answer Test for HMAC hash
+# $1: key length in bytes
+# $2: MAC length in bytes
+# $3: key for HMAC in hex form
+# $4: message to be hashed
+# return: string formatted as expected by CAVS
+sub hmac_kat($$$$) {
+       my $klen = shift;
+       my $tlen = shift;
+       my $key  = shift;
+       my $msg  = shift;
+
+       # XXX this is a hack - we need to decipher the HMAC REQ files in a more
+       # sane way
+       #
+       # This is a conversion table from the expected hash output size
+       # to the assumed hash type - we only define here the block size of
+       # the underlying hashes and do not allow any truncation
+       my %hashtype = (
+               20 => 1,
+               28 => 224,
+               32 => 256,
+               48 => 384,
+               64 => 512
+       );
+
+       die "Hash output size $tlen is not supported!"
+               if(!defined($hashtype{$tlen}));
+
+       my $out = "";
+       $out .= "Klen = $klen\n";
+       $out .= "Tlen = $tlen\n";
+       $out .= "Key = $key\n";
+       $out .= "Msg = $msg\n";
+       $out .= "Mac = " . &$hmac($key, $tlen, $msg, $hashtype{$tlen}) . "\n\n";
+
+       return $out;
+}
+
+
 # Cipher Monte Carlo Testing
 # $1: the string that we have to put in front of the key
 #     when printing the key
@@ -1132,6 +1204,8 @@ sub parse($$) {
        my $rsa_keyfile = "";
        my $dt = "";
        my $v = "";
+       my $klen = "";
+       my $tlen = "";
 
        my $mode = "";
 
@@ -1162,13 +1236,17 @@ sub parse($$) {
 
                ##### Extract cipher
                # XXX there may be more - to be added
-               if ($tmpline =~ /^#.*(CBC|ECB|OFB|CFB|SHA-1|SigGen|SigVer|RC4VS|ANSI X9\.31)/) {
+               if ($tmpline =~ /^#.*(CBC|ECB|OFB|CFB|SHA-|SigGen|SigVer|RC4VS|ANSI X9\.31|Hash sizes tested)/) {
                        if ($tmpline    =~ /CBC/)   { $mode="cbc"; }
                        elsif ($tmpline =~ /ECB/)   { $mode="ecb"; }
                        elsif ($tmpline =~ /OFB/)   { $mode="ofb"; }
                        elsif ($tmpline =~ /CFB/)   { $mode="cfb"; }
                        #we do not need mode as the cipher is already clear
                        elsif ($tmpline =~ /SHA-1/) { $cipher="sha1"; }
+                       elsif ($tmpline =~ /SHA-224/) { $cipher="sha224"; }
+                       elsif ($tmpline =~ /SHA-256/) { $cipher="sha256"; }
+                       elsif ($tmpline =~ /SHA-384/) { $cipher="sha384"; }
+                       elsif ($tmpline =~ /SHA-512/) { $cipher="sha512"; }
                        #we do not need mode as the cipher is already clear
                        elsif ($tmpline =~ /RC4VS/) { $cipher="rc4"; }
                        elsif ($tmpline =~ /SigGen|SigVer/) {
@@ -1211,7 +1289,11 @@ sub parse($$) {
 
 
                        ##### Identify the test type
-                       if ($tmpline =~ /ANSI X9\.31/ && $tmpline =~ /MCT/) {
+                       if ($tmpline =~ /Hash sizes tested/) {
+                               $tt = 9;
+                               die "Interface function hmac for HMAC testing not defined for tested library"
+                                       if (!defined($hmac));
+                       } elsif ($tmpline =~ /ANSI X9\.31/ && $tmpline =~ /MCT/) {
                                $tt = 8;
                                die "Interface function state_rng for RNG MCT not defined for tested library"
                                        if (!defined($state_rng));
@@ -1227,7 +1309,7 @@ sub parse($$) {
                                $tt = 5;
                                die "Interface function rsa_sign or gen_rsakey for RSA sign not defined for tested library"
                                        if (!defined($rsa_sign) || !defined($gen_rsakey));
-                       } elsif ($tmpline =~ /Monte|MCT|Carlo/ && $cipher eq "sha1") {
+                       } elsif ($tmpline =~ /Monte|MCT|Carlo/ && $cipher eq "sha") {
                                $tt = 4;
                                die "Interface function hash for Hashing not defined for tested library"
                                        if (!defined($hash));
@@ -1235,7 +1317,7 @@ sub parse($$) {
                                $tt = 2;
                                die "Interface function state_cipher for Stateful Cipher operation defined for tested library"
                                        if (!defined($state_cipher));
-                       } elsif ($cipher eq "sha1" && $tt!=5 && $tt!=6) {
+                       } elsif ($cipher eq "sha" && $tt!=5 && $tt!=6) {
                                $tt = 3;
                                die "Interface function hash for Hashing not defined for tested library"
                                        if (!defined($hash));
@@ -1276,7 +1358,7 @@ sub parse($$) {
                }
                elsif ($line =~ /^KEY3\s*=\s*(.*)/) { # found in TDES
                        die "Second key not set, but got already third key - input file crap" if ($key2 eq "");
-                       die "KEY2 seen twice - input file crap" if (defined($key3));
+                       die "KEY3 seen twice - input file crap" if (defined($key3));
                        $key3=$1;
                        $key3 =~ s/\s//g; #replace potential white spaces
                }
@@ -1348,6 +1430,16 @@ sub parse($$) {
                                if ($v ne "");
                        $v=$1;
                }
+               elsif ($line =~ /^Klen\s*=\s*(.*)/) { # HMAC requests
+                       die "Klen seen twice - check input file"
+                               if ($klen ne "");
+                       $klen=$1;
+               }
+               elsif ($line =~ /^Tlen\s*=\s*(.*)/) { # HMAC RNG requests
+                       die "Tlen seen twice - check input file"
+                               if ($tlen ne "");
+                       $tlen=$1;
+               }
                else {
                        $out .= $line . "\n";
                }
@@ -1417,6 +1509,15 @@ sub parse($$) {
                                $v = "";
                        }
                }
+               elsif ($tt == 9) {
+                       if ($klen ne "" && $tlen ne "" && $key1 ne "" && $pt ne "") {
+                               $out .= hmac_kat($klen, $tlen, $key1, $pt);
+                               $key1 = "";
+                               $tlen = "";
+                               $klen = "";
+                               $pt = "";
+                       }
+               }
                elsif ($tt > 0) {
                        die "Test case $tt not defined";
                }
@@ -1452,15 +1553,16 @@ sub main() {
        ##### Set library
 
        #print STDERR "Using OpenSSL interface functions\n";
-       #$encdec=\&openssl_encdec;
-       #$rsa_sign=\&openssl_rsa_sign;
-       #$rsa_verify=\&openssl_rsa_verify;
-       #$gen_rsakey=\&openssl_gen_rsakey;
-       #$hash=\&openssl_hash;
-       #$state_cipher=\&openssl_state_cipher;
+       #$encdec =              \&openssl_encdec;
+       #$rsa_sign =            \&openssl_rsa_sign;
+       #$rsa_verify =          \&openssl_rsa_verify;
+       #$gen_rsakey =          \&openssl_gen_rsakey;
+       #$hash =                \&openssl_hash;
+       #$state_cipher =        \&openssl_state_cipher;
 
        print STDERR "Using libgcrypt interface functions\n";
-       $state_rng=\&libgcrypt_state_rng;
+       $state_rng =    \&libgcrypt_state_rng;
+       $hmac =         \&libgcrypt_hmac;
 
        my $infile=$ARGV[0];
        die "Error: Test vector file $infile not found" if (! -f $infile);