summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2006-03-14 13:13:11 +0000
committerWerner Koch <wk@gnupg.org>2006-03-14 13:13:11 +0000
commit7d2a1049d580d91fd56695594bd52ed5b0864253 (patch)
tree7789bfc75fcd3a94700397df631fa28f479f30e3
parent0e9cbec874e6841397d5b7c2936cf491c84909a0 (diff)
downloadlibgcrypt-7d2a1049d580d91fd56695594bd52ed5b0864253.tar.gz
Use quick key generation.
Cleaned up output; i.e. take care of --verbose.
-rw-r--r--ChangeLog6
-rw-r--r--NEWS5
-rw-r--r--TODO17
-rw-r--r--cipher/ChangeLog9
-rw-r--r--cipher/random.c151
-rw-r--r--configure.ac3
-rw-r--r--tests/ChangeLog12
-rw-r--r--tests/ac-data.c14
-rw-r--r--tests/ac.c2
-rw-r--r--tests/basic.c8
-rw-r--r--tests/keygen.c5
-rw-r--r--tests/pkbench.c3
-rw-r--r--tests/pubkey.c2
13 files changed, 194 insertions, 43 deletions
diff --git a/ChangeLog b/ChangeLog
index 46aecf7b..198a019b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2006-03-14 Werner Koch <wk@g10code.com>
+
+ * configure.ac: Check for fctnl and ftruncate.
+
2005-12-08 Werner Koch <wk@g10code.com>
* configure.ac: Changed the random device names for netbsd. From
@@ -1032,7 +1036,7 @@ Fri Feb 13 19:43:41 1998 Werner Koch (wk@isil.d.shuttle.de)
Copyright 1998, 1999, 2000, 2001, 2002, 2003,
- 2004 Free Software Foundation, Inc.
+ 2004, 2006 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
diff --git a/NEWS b/NEWS
index d43f2551..bd68be28 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,11 @@ Noteworthy changes in version 1.3.0 (unreleased)
general a good idea to spread this macro into the application code
to make sure that these polls happen often enough.
+ * Reading and writing the random seed file is now protected by a
+ fcntl style file lock on systems that provide this function.
+
+ * Support for SHA-224 and HMAC using SHA-384 and SHA-512.
+
* Interface changes relative to the 1.2.0 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gcry_fast_random_poll NEW
diff --git a/TODO b/TODO
index 6d6355ff..5986ddcd 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,6 @@
What's left to do -*- outline -*-
-* Add more tests. Even basic is very minimal.
+* Add more tests.
* udiv-qrnbd.o should get build as *.lo [HPUX]
@@ -26,9 +26,6 @@ What's left to do -*- outline -*-
with the ac interface (i.e. by using ac's `data sets') and the pk
interface could be changed to be a wrapper for the ac interface.
-* HMAC won't work with sha-512 due to the different block size. OTOH,
- I can imagine no cryptographic reason to use it.
-
* cipher/pubkey.c and pubkey implementaions.
Don't rely on the secure memory based wiping function but add an
extra wiping.
@@ -39,3 +36,15 @@ What's left to do -*- outline -*-
* Use builtin bit functions of gcc 3.4
+* Consider using a daemon to maintain he random pool
+
+ The down side of this is that we can't assume that the random das
+ has always been stored in "secure memory". And we rely on that
+ sniffing of Unix domain sockets is not possible. We can implement
+ this simply by detecting a special prefixed random seed name and
+ divert in this case to the daemon. There are several benefits with
+ such an approach: We keep the state of the RNG over invocations of
+ libgcrypt based applications, don't need time consuming
+ initialization of the pool and in case the entropy collectros need
+ to run that bunch of Unix utilities we don't waste their precious
+ results.
diff --git a/cipher/ChangeLog b/cipher/ChangeLog
index a1b5b8c8..dd17b998 100644
--- a/cipher/ChangeLog
+++ b/cipher/ChangeLog
@@ -1,3 +1,12 @@
+2006-03-14 Werner Koch <wk@g10code.com>
+
+ * random.c (lock_seed_file): New.
+ (read_seed_file, _gcry_update_random_seed_file): Use it.
+
+ * random.c (gcry_create_nonce): Detect a fork and re-seed.
+ (read_pool): Fixed the fork detection; it used to work only for
+ multi-threaded processes.
+
2006-03-12 Brad Hards <bradh@frogmouth.net> (wk)
* md.c (md_open): Use new variable macpads_Bsize instead of
diff --git a/cipher/random.c b/cipher/random.c
index 177cd6f9..9b9869b4 100644
--- a/cipher/random.c
+++ b/cipher/random.c
@@ -1,6 +1,6 @@
/* random.c - random number generator
* Copyright (C) 1998, 2000, 2001, 2002, 2003,
- * 2004 Free Software Foundation, Inc.
+ * 2004, 2005, 2006 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
@@ -62,6 +62,13 @@
#define RAND_MAX 32767
#endif
+/* Check whether we can lock the seed file read write. */
+#if defined(HAVE_FCNTL) && defined(HAVE_FTRUNCATE) && !defined(HAVE_W32_SYSTEM)
+#define LOCK_SEED_FILE 1
+#else
+#define LOCK_SEED_FILE 0
+#endif
+
#if SIZEOF_UNSIGNED_LONG == 8
#define ADD_VALUE 0xa5a5a5a5a5a5a5a5
@@ -259,7 +266,8 @@ get_random_bytes ( size_t nbytes, int level, int secure)
byte *buf, *p;
int err;
- /* First a hack toavoid the strong random using our regression test suite. */
+ /* First a hack to avoid the strong random using our regression test
+ suite. */
if (quick_test && level > 1)
level = 1;
@@ -531,6 +539,45 @@ _gcry_set_random_seed_file( const char *name )
}
+/* Lock an open file identified by file descriptor FD and wait a
+ reasonable time to succeed. With FOR_WRITE set to true a write
+ lock will be taken. FNAME is used only for diagnostics. Returns 0
+ on success or -1 on error. */
+static int
+lock_seed_file (int fd, const char *fname, int for_write)
+{
+#if LOCK_SEED_FILE
+ struct flock lck;
+ struct timeval tv;
+ int backoff=0;
+
+ /* We take a lock on the entire file. */
+ memset (&lck, 0, sizeof lck);
+ lck.l_type = for_write? F_WRLCK : F_RDLCK;
+ lck.l_whence = SEEK_SET;
+
+ while (fcntl (fd, F_SETLK, &lck) == -1)
+ {
+ if (errno != EAGAIN && errno != EACCES)
+ {
+ log_info (_("can't lock `%s': %s\n"), fname, strerror (errno));
+ return -1;
+ }
+
+ if (backoff > 2) /* Show the first message after ~2.25 seconds. */
+ log_info( _("waiting for lock on `%s'...\n"), fname);
+
+ tv.tv_sec = backoff;
+ tv.tv_usec = 250000;
+ select (0, NULL, NULL, NULL, &tv);
+ if (backoff < 10)
+ backoff++ ;
+ }
+#endif /*LOCK_SEED_FILE*/
+ return 0;
+}
+
+
/*
Read in a seed form the random_seed file
and return true if this was successful.
@@ -564,6 +611,11 @@ read_seed_file (void)
log_info(_("can't open `%s': %s\n"), seed_file_name, strerror(errno) );
return 0;
}
+ if (lock_seed_file (fd, seed_file_name, 0))
+ {
+ close (fd);
+ return 0;
+ }
if (fstat( fd, &sb ) )
{
log_info(_("can't stat `%s': %s\n"), seed_file_name, strerror(errno) );
@@ -652,7 +704,7 @@ _gcry_update_random_seed_file()
log_fatal ("failed to acquire the pool lock: %s\n", strerror (err));
pool_is_locked = 1;
- /* copy the entropy pool to a scratch pool and mix both of them */
+ /* Copy the entropy pool to a scratch pool and mix both of them. */
for (i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
i < POOLWORDS; i++, dp++, sp++ )
{
@@ -661,28 +713,41 @@ _gcry_update_random_seed_file()
mix_pool(rndpool); rndstats.mixrnd++;
mix_pool(keypool); rndstats.mixkey++;
-#ifdef HAVE_DOSISH_SYSTEM
+#if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__)
fd = open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,
S_IRUSR|S_IWUSR );
#else
- fd = open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR );
+# if LOCK_SEED_FILE
+ fd = open (seed_file_name, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR );
+# else
+ fd = open (seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR );
+# endif
#endif
if (fd == -1 )
log_info (_("can't create `%s': %s\n"), seed_file_name, strerror(errno) );
+ else if (lock_seed_file (fd, seed_file_name, 1))
+ {
+ close (fd);
+ }
+#if LOCK_SEED_FILE
+ else if (ftruncate (fd, 0))
+ {
+ log_info(_("can't write `%s': %s\n"), seed_file_name, strerror(errno));
+ close (fd);
+ }
+#endif /*LOCK_SEED_FILE*/
else
{
do
{
i = write (fd, keypool, POOLSIZE );
}
- while( i == -1 && errno == EINTR );
+ while (i == -1 && errno == EINTR);
if (i != POOLSIZE)
- log_info (_("can't write `%s': %s\n"),
- seed_file_name, strerror(errno) );
+ log_info (_("can't write `%s': %s\n"),seed_file_name, strerror(errno));
if (close(fd))
- log_info(_("can't close `%s': %s\n"),
- seed_file_name, strerror(errno) );
+ log_info (_("can't close `%s': %s\n"),seed_file_name, strerror(errno));
}
pool_is_locked = 0;
@@ -694,21 +759,39 @@ _gcry_update_random_seed_file()
/* Read random out of the pool. This function is the core of the
- public random fucntions. Note that Level 0 is not anymore handeld
- special and in fact an alias for level 1. */
+ public random functions. Note that Level 0 is not anymore handeld
+ special and in fact an alias for level 1. Must be called with the
+ pool already locked. */
static void
read_pool (byte *buffer, size_t length, int level)
{
int i;
unsigned long *sp, *dp;
- volatile pid_t my_pid; /* The volatile is there to make sure the
- compiler does not optimize the code away
- in case the getpid function is badly
- attributed. */
+ /* The volatile is there to make sure the compiler does not optimize
+ the code away in case the getpid function is badly attributed.
+ Note that we keep a pid in a static variable as well as in a
+ stack based one; the latter is to detect ill behaving thread
+ libraries, ignoring the pool mutexes. */
+ static volatile pid_t my_pid = (pid_t)(-1);
+ volatile pid_t my_pid2;
+
retry:
/* Get our own pid, so that we can detect a fork. */
- my_pid = getpid ();
+ my_pid2 = getpid ();
+ if (my_pid == (pid_t)(-1))
+ my_pid = my_pid2;
+ if ( my_pid != my_pid2 )
+ {
+ /* We detected a plain fork; i.e. we are now the child. Update
+ the static pid and add some randomness. */
+ pid_t x;
+
+ my_pid = my_pid2;
+ x = my_pid;
+ add_randomness (&x, sizeof(x), 0);
+ just_mixed = 0; /* Make sure it will get mixed. */
+ }
assert (pool_is_locked);
@@ -756,7 +839,7 @@ read_pool (byte *buffer, size_t length, int level)
pool_balance += needed;
}
- /* make sure the pool is filled */
+ /* Make sure the pool is filled. */
while (!pool_filled)
random_poll();
@@ -765,7 +848,10 @@ read_pool (byte *buffer, size_t length, int level)
/* Mix the pid in so that we for sure won't deliver the same random
after a fork. */
- add_randomness (&my_pid, sizeof (my_pid), 0);
+ {
+ pid_t apid = my_pid;
+ add_randomness (&apid, sizeof (apid), 0);
+ }
/* Mix the pool (if add_randomness() didn't it). */
if (!just_mixed)
@@ -783,8 +869,8 @@ read_pool (byte *buffer, size_t length, int level)
mix_pool(rndpool); rndstats.mixrnd++;
mix_pool(keypool); rndstats.mixkey++;
- /* Read the required data. We use a readpointer to read from a
- different position each time */
+ /* Read the requested data. We use a read pointer to read from a
+ different position each time. */
while (length--)
{
*buffer++ = keypool[pool_readpos++];
@@ -801,17 +887,14 @@ read_pool (byte *buffer, size_t length, int level)
/* We need to detect whether a fork has happened. A fork might have
an identical pool and thus the child and the parent could emit
- the very same random number. Obviously this can only happen when
- running multi-threaded and the pool lock should even catch this.
- However things do get wrong and thus we better check and retry it
- here. We assume that the thread library has no other fatal
- faults, though.
- */
- if ( getpid () != my_pid )
+ the very same random number. This test here is to detect forks
+ in a multi-threaded process. */
+ if ( getpid () != my_pid2 )
{
pid_t x = getpid();
add_randomness (&x, sizeof(x), 0);
just_mixed = 0; /* Make sure it will get mixed. */
+ my_pid = x; /* Also update the static pid. */
goto retry;
}
}
@@ -1101,6 +1184,10 @@ gcry_create_nonce (unsigned char *buffer, size_t length)
{
static unsigned char nonce_buffer[20+8];
static int nonce_buffer_initialized = 0;
+ static volatile pid_t my_pid; /* The volatile is there to make sure the
+ compiler does not optimize the code away
+ in case the getpid function is badly
+ attributed. */
unsigned char *p;
size_t n;
int err;
@@ -1121,6 +1208,8 @@ gcry_create_nonce (unsigned char *buffer, size_t length)
pid_t apid = getpid ();
time_t atime = time (NULL);
+ my_pid = apid;
+
if ((sizeof apid + sizeof atime) > sizeof nonce_buffer)
BUG ();
@@ -1137,6 +1226,12 @@ gcry_create_nonce (unsigned char *buffer, size_t length)
nonce_buffer_initialized = 1;
}
+ else if ( my_pid != getpid () )
+ {
+ /* We forked. Need to reseed the buffer - doing this for the
+ private part should be sufficient. */
+ gcry_randomize (nonce_buffer+20, 8, GCRY_WEAK_RANDOM);
+ }
/* Create the nonce by hashing the entire buffer, returning the hash
and updating the first 20 bytes of the buffer with this hash. */
diff --git a/configure.ac b/configure.ac
index f90ec84c..d677538d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
# Configure.ac script for Libgcrypt
# Copyright (C) 1998, 1999, 2000, 2001, 2002
-# 2003, 2004 Free Software Foundation, Inc.
+# 2003, 2004, 2006 Free Software Foundation, Inc.
#
# This file is part of Libgcrypt.
#
@@ -484,6 +484,7 @@ AC_CHECK_FUNCS(strtoul memmove stricmp atexit raise)
# Other checks
AC_CHECK_FUNCS(strerror rand mmap getpagesize waitpid wait4)
AC_CHECK_FUNCS(gettimeofday getrusage gethrtime clock_gettime)
+AC_CHECK_FUNCS(fcntl ftruncate)
GNUPG_CHECK_MLOCK
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 881cb642..2b75b786 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,15 @@
+2006-03-14 Werner Koch <wk@g10code.com>
+
+ * ac-data.c (check_sexp_conversion, check_run): Take care of VERBOSE.
+ * basic.c (main): Speed up test key generation.
+ (main): use progress handler only in verbose mode.
+ * ac.c (main): Ditto.
+ * pubkey.c (main): Ditto.
+ * keygen.c (main): Ditto.
+ (check_rsa_keys): Print key only in verbose mode.
+
+ * pkbench.c (main): Ditto.
+
2006-03-10 Brad Hards <bradh@frogmouth.net> (wk, patch 2006-02-18)
* basic.c (check_one_hmac, check_hmac): New.
diff --git a/tests/ac-data.c b/tests/ac-data.c
index 08ddba9e..9313da1a 100644
--- a/tests/ac-data.c
+++ b/tests/ac-data.c
@@ -63,7 +63,8 @@ check_sexp_conversion (gcry_ac_data_t data, const char **identifiers)
err = gcry_ac_data_to_sexp (data, &sexp, identifiers);
assert_err (err);
- gcry_sexp_dump (sexp);
+ if (verbose)
+ gcry_sexp_dump (sexp);
err = gcry_ac_data_from_sexp (&data2, sexp, identifiers);
assert_err (err);
@@ -128,7 +129,8 @@ check_run (void)
check_sexp_conversion (data, identifiers_null);
check_sexp_conversion (data, NULL);
- printf ("data-set-test-0 succeeded\n");
+ if (verbose)
+ printf ("data-set-test-0 succeeded\n");
gcry_ac_data_clear (data);
@@ -161,8 +163,9 @@ check_run (void)
assert_err (err);
gcry_free ((void *) label1); /* FIXME!! */
gcry_mpi_release (mpi1);
-
- printf ("data-set-test-1 succeeded\n");
+
+ if (verbose)
+ printf ("data-set-test-1 succeeded\n");
gcry_ac_data_clear (data);
assert (! gcry_ac_data_length (data));
@@ -170,7 +173,8 @@ check_run (void)
check_sexp_conversion (data, identifiers_null);
check_sexp_conversion (data, NULL);
- printf ("data-set-test-2 succeeded\n");
+ if (verbose)
+ printf ("data-set-test-2 succeeded\n");
gcry_ac_data_destroy (data);
diff --git a/tests/ac.c b/tests/ac.c
index 75fe2dae..d734360a 100644
--- a/tests/ac.c
+++ b/tests/ac.c
@@ -152,6 +152,8 @@ main (int argc, char **argv)
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);
for (; i > 0; i--)
check_run ();
diff --git a/tests/basic.c b/tests/basic.c
index 02466328..cb8b6aa7 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -1096,7 +1096,7 @@ check_digests (void)
{ GCRY_MD_SHA1, "!" /* kludge for "a"*1000000 */ ,
"\x34\xAA\x97\x3C\xD4\xC4\xDA\xA4\xF6\x1E"
"\xEB\x2B\xDB\xAD\x27\x31\x65\x34\x01\x6F" },
- // From RFC3874
+ /* From RFC3874 */
{ GCRY_MD_SHA224, "abc",
"\x23\x09\x7d\x22\x34\x05\xd8\x22\x86\x42\xa4\x77\xbd\xa2\x55\xb3"
"\x2a\xad\xbc\xe4\xbd\xa0\xb3\xf7\xe3\x6c\x9d\xa7" },
@@ -1920,12 +1920,16 @@ main (int argc, char **argv)
if (!gcry_check_version (GCRYPT_VERSION))
die ("version mismatch\n");
- gcry_set_progress_handler (progress_handler, NULL);
+ 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);
+
check_ciphers ();
check_aes128_cbc_cts_cipher ();
check_cbc_mac_cipher ();
diff --git a/tests/keygen.c b/tests/keygen.c
index d1d01fdd..abe88818 100644
--- a/tests/keygen.c
+++ b/tests/keygen.c
@@ -139,8 +139,9 @@ check_rsa_keys (void)
{
char buffer[20000];
gcry_sexp_sprint (key, GCRYSEXP_FMT_ADVANCED, buffer, sizeof buffer);
- printf ("=============================\n%s\n"
- "=============================\n", buffer);
+ if (verbose)
+ printf ("=============================\n%s\n"
+ "=============================\n", buffer);
}
gcry_sexp_release (key);
exit (0);
diff --git a/tests/pkbench.c b/tests/pkbench.c
index d69bc5f3..372fa0c9 100644
--- a/tests/pkbench.c
+++ b/tests/pkbench.c
@@ -335,6 +335,9 @@ main (int argc, char **argv)
char *algorithm = NULL;
char *key_size = NULL;
+ /* No valuable keys are create, so we can speed up our RNG. */
+ gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+
if (argv[2])
{
algorithm = argv[2];
diff --git a/tests/pubkey.c b/tests/pubkey.c
index e383f477..f71590d9 100644
--- a/tests/pubkey.c
+++ b/tests/pubkey.c
@@ -247,6 +247,8 @@ main (int argc, char **argv)
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);
for (; i > 0; i--)
check_run ();