[svn] gcry - r1103 - in branches/LIBGCRYPT-1-2-BRANCH: . cipher
tests
svn author wk
cvs at cvs.gnupg.org
Tue Sep 13 12:18:55 CEST 2005
Author: wk
Date: 2005-09-13 12:18:54 +0200 (Tue, 13 Sep 2005)
New Revision: 1103
Added:
branches/LIBGCRYPT-1-2-BRANCH/tests/random.c
Modified:
branches/LIBGCRYPT-1-2-BRANCH/NEWS
branches/LIBGCRYPT-1-2-BRANCH/cipher/ChangeLog
branches/LIBGCRYPT-1-2-BRANCH/cipher/random.c
branches/LIBGCRYPT-1-2-BRANCH/tests/ChangeLog
branches/LIBGCRYPT-1-2-BRANCH/tests/Makefile.am
Log:
* 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.
Modified: branches/LIBGCRYPT-1-2-BRANCH/NEWS
===================================================================
--- branches/LIBGCRYPT-1-2-BRANCH/NEWS 2005-08-22 09:30:25 UTC (rev 1102)
+++ branches/LIBGCRYPT-1-2-BRANCH/NEWS 2005-09-13 10:18:54 UTC (rev 1103)
@@ -1,6 +1,8 @@
Noteworthy changes in version 1.2.2
------------------------------------------------
+ * Made the RNG immune against fork without exec.
+
* Minor changes to some function declarations. Buffer arguments are
now typed as void pointer. This should not affect any compilation.
A bug in the definition of gcry_cipher_register has been fixed.
Modified: branches/LIBGCRYPT-1-2-BRANCH/cipher/ChangeLog
===================================================================
--- branches/LIBGCRYPT-1-2-BRANCH/cipher/ChangeLog 2005-08-22 09:30:25 UTC (rev 1102)
+++ branches/LIBGCRYPT-1-2-BRANCH/cipher/ChangeLog 2005-09-13 10:18:54 UTC (rev 1103)
@@ -1,3 +1,9 @@
+2005-09-13 Werner Koch <wk at g10code.com>
+
+ * 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.
+
2005-06-16 Werner Koch <wk at g10code.com>
* cipher.c (gcry_cipher_register): Changed arg ALGORITHM_ID
Modified: branches/LIBGCRYPT-1-2-BRANCH/cipher/random.c
===================================================================
--- branches/LIBGCRYPT-1-2-BRANCH/cipher/random.c 2005-08-22 09:30:25 UTC (rev 1102)
+++ branches/LIBGCRYPT-1-2-BRANCH/cipher/random.c 2005-09-13 10:18:54 UTC (rev 1103)
@@ -1,6 +1,6 @@
/* random.c - random number generator
* Copyright (C) 1998, 2000, 2001, 2002, 2003,
- * 2004 Free Software Foundation, Inc.
+ * 2004, 2005 Free Software Foundation, Inc.
*
* This file is part of Libgcrypt.
*
@@ -693,29 +693,46 @@
/* 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 special and in fact
+ an alias for level 1. */
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. */
+ size_t n;
+ /* 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);
/* Our code does not allow to extract more than POOLSIZE. Better
check it here. */
if (length > POOLSIZE)
{
- log_bug("too many random bits requested\n");
+ log_bug("too many random bits requested (%lu)\n", (unsigned long)length);
}
if (!pool_filled)
@@ -787,7 +804,7 @@
/* Read the required data. We use a readpointer to read from a
different position each time */
- while (length--)
+ for (n=0; n < length; n++)
{
*buffer++ = keypool[pool_readpos++];
if (pool_readpos >= POOLSIZE)
@@ -803,17 +820,14 @@
/* 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;
}
}
@@ -1103,6 +1117,10 @@
{
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;
@@ -1123,6 +1141,8 @@
pid_t apid = getpid ();
time_t atime = time (NULL);
+ my_pid = apid;
+
if ((sizeof apid + sizeof atime) > sizeof nonce_buffer)
BUG ();
@@ -1139,6 +1159,12 @@
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. */
Modified: branches/LIBGCRYPT-1-2-BRANCH/tests/ChangeLog
===================================================================
--- branches/LIBGCRYPT-1-2-BRANCH/tests/ChangeLog 2005-08-22 09:30:25 UTC (rev 1102)
+++ branches/LIBGCRYPT-1-2-BRANCH/tests/ChangeLog 2005-09-13 10:18:54 UTC (rev 1103)
@@ -1,3 +1,7 @@
+2005-09-13 Werner Koch <wk at g10code.com>
+
+ * random.c: New.
+
2005-06-16 Werner Koch <wk at g10code.com>
* basic.c (check_one_md): Made P unsigned.
Modified: branches/LIBGCRYPT-1-2-BRANCH/tests/Makefile.am
===================================================================
--- branches/LIBGCRYPT-1-2-BRANCH/tests/Makefile.am 2005-08-22 09:30:25 UTC (rev 1102)
+++ branches/LIBGCRYPT-1-2-BRANCH/tests/Makefile.am 2005-09-13 10:18:54 UTC (rev 1103)
@@ -18,7 +18,7 @@
## Process this file with automake to produce Makefile.in
-TESTS = prime register ac basic tsexp keygen pubkey benchmark
+TESTS = prime register ac basic tsexp keygen pubkey benchmark random
INCLUDES = -I$(top_srcdir)/src
LDADD = ../src/libgcrypt.la
Added: branches/LIBGCRYPT-1-2-BRANCH/tests/random.c
===================================================================
--- branches/LIBGCRYPT-1-2-BRANCH/tests/random.c 2005-08-22 09:30:25 UTC (rev 1102)
+++ branches/LIBGCRYPT-1-2-BRANCH/tests/random.c 2005-09-13 10:18:54 UTC (rev 1103)
@@ -0,0 +1,252 @@
+/* random.c - part of the Libgcrypt test suite.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA. */
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include "../src/gcrypt.h"
+
+static int verbose;
+
+static void
+die (const char *format, ...)
+{
+ va_list arg_ptr;
+
+ va_start (arg_ptr, format);
+ vfprintf (stderr, format, arg_ptr);
+ va_end (arg_ptr);
+ exit (1);
+}
+
+
+static void
+print_hex (const char *text, const void *buf, size_t n)
+{
+ const unsigned char *p = buf;
+
+ fputs (text, stdout);
+ for (; n; n--, p++)
+ printf ("%02X", *p);
+ putchar ('\n');
+}
+
+
+static int
+writen (int fd, const void *buf, size_t nbytes)
+{
+ size_t nleft = nbytes;
+ int nwritten;
+
+ while (nleft > 0)
+ {
+ nwritten = write (fd, buf, nleft);
+ if (nwritten < 0)
+ {
+ if (errno == EINTR)
+ nwritten = 0;
+ else
+ return -1;
+ }
+ nleft -= nwritten;
+ buf = (const char*)buf + nwritten;
+ }
+
+ return 0;
+}
+
+static int
+readn (int fd, void *buf, size_t buflen, size_t *ret_nread)
+{
+ size_t nleft = buflen;
+ int nread;
+ char *p;
+
+ p = buf;
+ while ( nleft > 0 )
+ {
+ nread = read ( fd, buf, nleft );
+ if (nread < 0)
+ {
+ if (nread == EINTR)
+ nread = 0;
+ else
+ return -1;
+ }
+ else if (!nread)
+ break; /* EOF */
+ nleft -= nread;
+ buf = (char*)buf + nread;
+ }
+ if (ret_nread)
+ *ret_nread = buflen - nleft;
+ return 0;
+}
+
+
+
+/* Check that forking won't return the same random. */
+static void
+check_forking (void)
+{
+ pid_t pid;
+ int rp[2];
+ int i, status;
+ size_t nread;
+ char tmp1[16], tmp1c[16], tmp1p[16];
+
+ /* We better make sure that the RNG has been initialzied. */
+ gcry_randomize (tmp1, sizeof tmp1, GCRY_STRONG_RANDOM);
+ if (verbose)
+ print_hex ("initial random: ", tmp1, sizeof tmp1);
+
+ if (pipe (rp) == -1)
+ die ("pipe failed: %s\n", strerror (errno));
+
+ pid = fork ();
+ if (pid == (pid_t)(-1))
+ die ("fork failed: %s\n", strerror (errno));
+ if (!pid)
+ {
+ gcry_randomize (tmp1c, sizeof tmp1c, GCRY_STRONG_RANDOM);
+ if (writen (rp[1], tmp1c, sizeof tmp1c))
+ die ("write failed: %s\n", strerror (errno));
+ if (verbose)
+ {
+ print_hex (" child random: ", tmp1c, sizeof tmp1c);
+ fflush (stdout);
+ }
+ _exit (0);
+ }
+ gcry_randomize (tmp1p, sizeof tmp1p, GCRY_STRONG_RANDOM);
+ if (verbose)
+ print_hex (" parent random: ", tmp1p, sizeof tmp1p);
+
+ close (rp[1]);
+ if (readn (rp[0], tmp1c, sizeof tmp1c, &nread))
+ die ("read failed: %s\n", strerror (errno));
+ if (nread != sizeof tmp1c)
+ die ("read too short\n");
+
+ while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
+ ;
+ if (i != (pid_t)(-1)
+ && WIFEXITED (status) && !WEXITSTATUS (status))
+ ;
+ else
+ die ("child failed\n");
+
+ if (!memcmp (tmp1p, tmp1c, sizeof tmp1c))
+ die ("parent and child got the same random number\n");
+}
+
+
+
+/* Check that forking won't return the same nonce. */
+static void
+check_nonce_forking (void)
+{
+ pid_t pid;
+ int rp[2];
+ int i, status;
+ size_t nread;
+ char nonce1[10], nonce1c[10], nonce1p[10];
+
+ /* We won't get the same nonce back if we never initialized the
+ nonce subsystem, thus we get one nonce here and forget about
+ it. */
+ gcry_create_nonce (nonce1, sizeof nonce1);
+ if (verbose)
+ print_hex ("initial nonce: ", nonce1, sizeof nonce1);
+
+ if (pipe (rp) == -1)
+ die ("pipe failed: %s\n", strerror (errno));
+
+ pid = fork ();
+ if (pid == (pid_t)(-1))
+ die ("fork failed: %s\n", strerror (errno));
+ if (!pid)
+ {
+ gcry_create_nonce (nonce1c, sizeof nonce1c);
+ if (writen (rp[1], nonce1c, sizeof nonce1c))
+ die ("write failed: %s\n", strerror (errno));
+ if (verbose)
+ {
+ print_hex (" child nonce: ", nonce1c, sizeof nonce1c);
+ fflush (stdout);
+ }
+ _exit (0);
+ }
+ gcry_create_nonce (nonce1p, sizeof nonce1p);
+ if (verbose)
+ print_hex (" parent nonce: ", nonce1p, sizeof nonce1p);
+
+ close (rp[1]);
+ if (readn (rp[0], nonce1c, sizeof nonce1c, &nread))
+ die ("read failed: %s\n", strerror (errno));
+ if (nread != sizeof nonce1c)
+ die ("read too short\n");
+
+ while ( (i=waitpid (pid, &status, 0)) == -1 && errno == EINTR)
+ ;
+ if (i != (pid_t)(-1)
+ && WIFEXITED (status) && !WEXITSTATUS (status))
+ ;
+ else
+ die ("child failed\n");
+
+ if (!memcmp (nonce1p, nonce1c, sizeof nonce1c))
+ die ("parent and child got the same nonce\n");
+}
+
+
+
+
+
+
+int
+main (int argc, char **argv)
+{
+ int debug = 0;
+
+ if ((argc > 1) && (! strcmp (argv[1], "--verbose")))
+ verbose = 1;
+ else if ((argc > 1) && (! strcmp (argv[1], "--debug")))
+ verbose = debug = 1;
+
+ signal (SIGPIPE, SIG_IGN);
+
+ gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+ if (!gcry_check_version (GCRYPT_VERSION))
+ die ("version mismatch\n");
+
+ gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+ if (debug)
+ gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
+
+ check_forking ();
+ check_nonce_forking ();
+
+ return 0;
+}
More information about the Gnupg-commits
mailing list