diff options
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | NEWS | 5 | ||||
-rw-r--r-- | TODO | 17 | ||||
-rw-r--r-- | cipher/ChangeLog | 9 | ||||
-rw-r--r-- | cipher/random.c | 151 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | tests/ChangeLog | 12 | ||||
-rw-r--r-- | tests/ac-data.c | 14 | ||||
-rw-r--r-- | tests/ac.c | 2 | ||||
-rw-r--r-- | tests/basic.c | 8 | ||||
-rw-r--r-- | tests/keygen.c | 5 | ||||
-rw-r--r-- | tests/pkbench.c | 3 | ||||
-rw-r--r-- | tests/pubkey.c | 2 |
13 files changed, 194 insertions, 43 deletions
@@ -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 @@ -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 @@ -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); @@ -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 (); |