]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
split some functionality of nettle's RNG.
authorNikos Mavrogiannopoulos <nmav@redhat.com>
Thu, 14 Nov 2013 14:09:16 +0000 (15:09 +0100)
committerNikos Mavrogiannopoulos <nmav@redhat.com>
Wed, 27 Nov 2013 10:41:43 +0000 (11:41 +0100)
lib/nettle/Makefile.am
lib/nettle/rnd-common.c [new file with mode: 0644]
lib/nettle/rnd-common.h [new file with mode: 0644]
lib/nettle/rnd.c

index e73db1a66db193235d2bba44596d5ff99489f973..67f7fdaf5198629dc2a093e5222b715897deb37b 100644 (file)
@@ -37,5 +37,11 @@ endif
 
 noinst_LTLIBRARIES = libcrypto.la
 
-libcrypto_la_SOURCES = pk.c mpi.c mac.c cipher.c rnd.c init.c egd.c egd.h \
+libcrypto_la_SOURCES = pk.c mpi.c mac.c cipher.c init.c egd.c egd.h \
        gnettle.h gcm-camellia.h gcm-camellia.c
+
+if ENABLE_FIPS140
+libcrypto_la_SOURCES += rnd-fips.c
+else
+libcrypto_la_SOURCES += rnd.c
+endif
diff --git a/lib/nettle/rnd-common.c b/lib/nettle/rnd-common.c
new file mode 100644 (file)
index 0000000..da8d4f0
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2010-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2000, 2001, 2008 Niels Möller
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/* Here are the common parts of the random generator layer. 
+ * Some of this code was based on the LSH 
+ * random generator (the trivia and device source functions for POSIX)
+ * and modified to fit gnutls' needs. Relicenced with permission. 
+ * Original author Niels Möller.
+ */
+
+#include <gnutls_int.h>
+#include <gnutls_errors.h>
+#include <locks.h>
+#include <gnutls_num.h>
+#include <nettle/yarrow.h>
+#include <errno.h>
+#include <rnd-common.h>
+
+void _rnd_get_event(struct event_st *e)
+{
+       static unsigned count = 0;
+       static struct event_st event;
+
+       gettime(&event.now);
+
+#ifdef HAVE_GETRUSAGE
+       if (getrusage(RUSAGE_SELF, &event.rusage) < 0) {
+               _gnutls_debug_log("getrusage failed: %s\n",
+                                 strerror(errno));
+               abort();
+       }
+#endif
+
+       event.count = count++;
+#ifdef HAVE_GETPID
+       event.pid = getpid();
+#endif
+       event.err = errno;
+
+       return;
+}
+
+#ifdef _WIN32
+
+#include <windows.h>
+#include <wincrypt.h>
+
+static HCRYPTPROV device_fd = 0;
+
+int _rnd_get_system_entropy_win32(void* rnd, size_t size)
+{
+       if (!CryptGenRandom(device_fd, (DWORD) size, rnd)) {
+               _gnutls_debug_log("Error in CryptGenRandom: %s\n",
+                                       GetLastError());
+               return GNUTLS_E_RANDOM_DEVICE_ERROR;
+       }
+
+       return 0;
+}
+
+get_entropy_func _rnd_get_system_entropy = _rnd_get_system_entropy_win32;
+
+int _rnd_system_entropy_init(void)
+{
+       int old;
+
+       if (!CryptAcquireContext
+               (&device_fd, NULL, NULL, PROV_RSA_FULL,
+                CRYPT_SILENT | CRYPT_VERIFYCONTEXT)) {
+               _gnutls_debug_log
+                       ("error in CryptAcquireContext!\n");
+               return GNUTLS_E_RANDOM_DEVICE_ERROR;
+       }
+       
+       return 0;
+}
+
+void _rnd_system_entropy_deinit(void)
+{
+       CryptReleaseContext(device_fd, 0);
+}
+
+#else /* POSIX */
+
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <locks.h>
+#include "egd.h"
+
+static int device_fd;
+
+static int _rnd_get_system_entropy_urandom(void* _rnd, size_t size)
+{
+       uint8_t* rnd = _rnd;
+       uint32_t done;
+
+       for (done = 0; done < size;) {
+               int res;
+               do {
+                       res = read(device_fd, rnd + done, size - done);
+               } while (res < 0 && errno == EINTR);
+
+               if (res <= 0) {
+                       if (res < 0) {
+                               _gnutls_debug_log
+                                       ("Failed to read /dev/urandom: %s\n",
+                                        strerror(errno));
+                       } else {
+                               _gnutls_debug_log
+                                       ("Failed to read /dev/urandom: end of file\n");
+                       }
+
+                       return GNUTLS_E_RANDOM_DEVICE_ERROR;
+               }
+
+               done += res;
+       }
+
+       return 0;
+}
+
+static
+int _rnd_get_system_entropy_egd(void* _rnd, size_t size)
+{
+       unsigned int done;
+       uint8_t* rnd = _rnd;
+       int res;
+
+       for (done = 0; done < size;) {
+               res =
+                   _rndegd_read(&device_fd, rnd + done, size - done);
+               if (res <= 0) {
+                       if (res < 0) {
+                               _gnutls_debug_log("Failed to read egd.\n");
+                       } else {
+                               _gnutls_debug_log("Failed to read egd: end of file\n");
+                       }
+
+                       return gnutls_assert_val(GNUTLS_E_RANDOM_DEVICE_ERROR);
+               }
+               done += res;
+       }
+
+       return 0;
+}
+
+typedef int (*get_entropy_func)(void* rnd, size_t size);
+
+get_entropy_func _rnd_get_system_entropy = NULL;
+
+int _rnd_system_entropy_init(void)
+{
+int old;
+       
+       device_fd = open("/dev/urandom", O_RDONLY);
+       if (device_fd < 0) {
+               _gnutls_debug_log("Cannot open urandom!\n");
+               goto fallback;
+       }
+
+       old = fcntl(device_fd, F_GETFD);
+       if (old != -1)
+               fcntl(device_fd, F_SETFD, old | FD_CLOEXEC);
+
+       _rnd_get_system_entropy = _rnd_get_system_entropy_urandom;
+
+       return 0;
+fallback:
+       device_fd = _rndegd_connect_socket();
+       if (device_fd < 0) {
+               _gnutls_debug_log("Cannot open egd socket!\n");
+               return
+                       gnutls_assert_val
+                       (GNUTLS_E_RANDOM_DEVICE_ERROR);
+       }
+       _rnd_get_system_entropy = _rnd_get_system_entropy_egd;
+       
+       return 0;
+}
+
+void _rnd_system_entropy_deinit(void)
+{
+       close(device_fd);
+}
+#endif
+
diff --git a/lib/nettle/rnd-common.h b/lib/nettle/rnd-common.h
new file mode 100644 (file)
index 0000000..9c63f50
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2000, 2001, 2008 Niels Möller
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GNUTLS.
+ *
+ * The GNUTLS library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include <gnutls_int.h>
+#ifdef HAVE_GETPID
+# include <unistd.h>           /* getpid */
+#endif
+#ifdef HAVE_GETRUSAGE
+# include <sys/resource.h>
+#endif
+
+struct event_st {
+               struct timespec now; /* current time */
+#ifdef HAVE_GETRUSAGE
+               struct rusage rusage;
+#endif
+#ifdef HAVE_GETPID
+               pid_t pid;      /* the process PID */
+#endif
+               unsigned count; /* a running counter */
+               unsigned err; /* the last errno */
+};
+
+void _rnd_get_event(struct event_st *e);
+
+int _rnd_system_entropy_init(void);
+void _rnd_system_entropy_deinit(void);
+
+typedef int (*get_entropy_func)(void* rnd, size_t size);
+
+extern get_entropy_func _rnd_get_system_entropy;
index cd988c2be623b50c9f9885c97ccef1721883d5f7..8a6e059f5f2ab90a32f33c4ffae12d85bf847caf 100644 (file)
@@ -35,9 +35,7 @@
 #ifdef HAVE_GETPID
 #include <unistd.h>            /* getpid */
 #endif
-#ifdef HAVE_GETRUSAGE
-#include <sys/resource.h>
-#endif
+#include <rnd-common.h>
 #include <errno.h>
 
 #define SOURCES 2
@@ -54,7 +52,6 @@ static struct yarrow256_ctx yctx;
 static struct yarrow_source ysources[SOURCES];
 
 static struct timespec device_last_read = { 0, 0 };
-static struct timespec current_time = { 0, 0 };
 
 static time_t trivia_previous_time = 0;
 static time_t trivia_time_count = 0;
@@ -75,151 +72,56 @@ timespec_sub_sec(struct timespec *a, struct timespec *b)
 
 static int do_trivia_source(int init)
 {
-       static struct {
-               struct timespec now;
-#ifdef HAVE_GETRUSAGE
-               struct rusage rusage;
-#endif
-#ifdef HAVE_GETPID
-               pid_t pid;
-#endif
-               unsigned count;
-       } event;
+       static struct event_st event;
        unsigned entropy = 0;
+       
+       _rnd_get_event(&event);
 
-       memcpy(&event.now, &current_time, sizeof(event.now));
-#ifdef HAVE_GETRUSAGE
-       if (getrusage(RUSAGE_SELF, &event.rusage) < 0) {
-               _gnutls_debug_log("getrusage failed: %s\n",
-                                 strerror(errno));
-               abort();
-       }
-#endif
-
-       event.count = 0;
        if (init) {
                trivia_time_count = 0;
        } else {
-               event.count = trivia_time_count++;
+               trivia_time_count++;
 
                if (event.now.tv_sec != trivia_previous_time) {
                        /* Count one bit of entropy if we either have more than two
                         * invocations in one second, or more than two seconds
                         * between invocations. */
                        if ((trivia_time_count > 2)
-                           || ((event.now.tv_sec - trivia_previous_time) >
-                               2))
+                           || ((event.now.tv_sec - trivia_previous_time) > 2))
                                entropy++;
 
                        trivia_time_count = 0;
                }
        }
        trivia_previous_time = event.now.tv_sec;
-#ifdef HAVE_GETPID
-       event.pid = pid;
-#endif
 
        return yarrow256_update(&yctx, RANDOM_SOURCE_TRIVIA, entropy,
                                sizeof(event), (void *) &event);
 }
 
-
-
-/* System specific functions */
-#ifdef _WIN32
-
-#include <windows.h>
-#include <wincrypt.h>
-
 #define DEVICE_READ_SIZE 16
 #define DEVICE_READ_SIZE_MAX 32
 
-static HCRYPTPROV device_fd = 0;
-
 static int do_device_source(int init)
-{
-       int read_size = DEVICE_READ_SIZE;
-
-       if (init) {
-               int old;
-
-               if (!CryptAcquireContext
-                   (&device_fd, NULL, NULL, PROV_RSA_FULL,
-                    CRYPT_SILENT | CRYPT_VERIFYCONTEXT)) {
-                       _gnutls_debug_log
-                           ("error in CryptAcquireContext!\n");
-                       return GNUTLS_E_RANDOM_DEVICE_ERROR;
-               }
-               gettime(&device_last_read);
-               read_size = DEVICE_READ_SIZE_MAX;       /* initially read more data */
-       }
-
-       if ((device_fd != 0)
-           && (init
-               || timespec_sub_sec(&current_time,
-                                   &device_last_read) >
-               DEVICE_READ_INTERVAL)) {
-
-               /* More than 20 minutes since we last read the device */
-               uint8_t buf[DEVICE_READ_SIZE_MAX];
-
-               if (!CryptGenRandom(device_fd, (DWORD) read_size, buf)) {
-                       _gnutls_debug_log("Error in CryptGenRandom: %s\n",
-                                         GetLastError());
-                       return GNUTLS_E_RANDOM_DEVICE_ERROR;
-               }
-
-               memcpy(&device_last_read, &current_time,
-                      sizeof(device_last_read));
-               return yarrow256_update(&yctx, RANDOM_SOURCE_DEVICE,
-                                       read_size * 8 /
-                                       2 /* we trust the system RNG */ ,
-                                       read_size, buf);
-       }
-       return 0;
-}
-
-static void wrap_nettle_rnd_deinit(void *ctx)
-{
-       RND_LOCK;
-       CryptReleaseContext(device_fd, 0);
-       RND_UNLOCK;
-
-       gnutls_mutex_deinit(&rnd_mutex);
-       rnd_mutex = NULL;
-}
-
-#else                          /* POSIX */
-
-#include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <fcntl.h>
-#include <locks.h>
-#include "egd.h"
-
-#define DEVICE_READ_SIZE 16
-#define DEVICE_READ_SIZE_MAX 32
-
-static int device_fd;
-
-static int do_device_source_urandom(int init)
 {
        unsigned int read_size = DEVICE_READ_SIZE;
+       struct timespec current_time;
+       int ret;
+
+       gettime(&current_time);
 
        if (init) {
-               int old;
 
-               device_fd = open("/dev/urandom", O_RDONLY);
-               if (device_fd < 0) {
-                       _gnutls_debug_log("Cannot open urandom!\n");
-                       return GNUTLS_E_FILE_ERROR;
+#ifdef HAVE_GETPID
+               pid = getpid();
+#endif
+
+               ret = _rnd_system_entropy_init();
+               if (ret < 0) {
+                       _gnutls_debug_log("Cannot initialize entropy gatherer\n");
+                       return gnutls_assert_val(ret);
                }
 
-               old = fcntl(device_fd, F_GETFD);
-               if (old != -1)
-                       fcntl(device_fd, F_SETFD, old | FD_CLOEXEC);
                memcpy(&device_last_read, &current_time,
                       sizeof(device_last_read));
 
@@ -228,34 +130,13 @@ static int do_device_source_urandom(int init)
 
        if ((init
             || (timespec_sub_sec(&current_time, &device_last_read) >
-                DEVICE_READ_INTERVAL)) && (device_fd > 0)) {
+                DEVICE_READ_INTERVAL))) {
                /* More than 20 minutes since we last read the device */
                uint8_t buf[DEVICE_READ_SIZE_MAX];
-               uint32_t done;
-
-               for (done = 0; done < read_size;) {
-                       int res;
-                       do
-                               res =
-                                   read(device_fd, buf + done,
-                                        sizeof(buf) - done);
-                       while (res < 0 && errno == EINTR);
-
-                       if (res <= 0) {
-                               if (res < 0) {
-                                       _gnutls_debug_log
-                                           ("Failed to read /dev/urandom: %s\n",
-                                            strerror(errno));
-                               } else {
-                                       _gnutls_debug_log
-                                           ("Failed to read /dev/urandom: end of file\n");
-                               }
-
-                               return GNUTLS_E_RANDOM_DEVICE_ERROR;
-                       }
-
-                       done += res;
-               }
+
+               ret = _rnd_get_system_entropy(buf, read_size);
+               if (ret < 0)
+                       return gnutls_assert_val(ret);
 
                memcpy(&device_last_read, &current_time,
                       sizeof(device_last_read));
@@ -267,109 +148,16 @@ static int do_device_source_urandom(int init)
        return 0;
 }
 
-static int do_device_source_egd(int init)
-{
-       unsigned int read_size = DEVICE_READ_SIZE;
-
-       if (init) {
-               device_fd = _rndegd_connect_socket();
-               if (device_fd < 0) {
-                       _gnutls_debug_log("Cannot open egd socket!\n");
-                       return
-                           gnutls_assert_val
-                           (GNUTLS_E_RANDOM_DEVICE_ERROR);
-               }
-
-               memcpy(&device_last_read, &current_time,
-                      sizeof(device_last_read));
-
-               read_size = DEVICE_READ_SIZE_MAX;       /* initially read more data */
-       }
-
-       if ((device_fd > 0)
-           && (init
-               || (timespec_sub_sec(&current_time, &device_last_read) >
-                   DEVICE_READ_INTERVAL))) {
-
-               /* More than 20 minutes since we last read the device */
-               uint8_t buf[DEVICE_READ_SIZE_MAX];
-               uint32_t done;
-
-               for (done = 0; done < read_size;) {
-                       int res;
-                       res =
-                           _rndegd_read(&device_fd, buf + done,
-                                        sizeof(buf) - done);
-                       if (res <= 0) {
-                               if (res < 0) {
-                                       _gnutls_debug_log
-                                           ("Failed to read egd.\n");
-                               } else {
-                                       _gnutls_debug_log
-                                           ("Failed to read egd: end of file\n");
-                               }
-
-                               return
-                                   gnutls_assert_val
-                                   (GNUTLS_E_RANDOM_DEVICE_ERROR);
-                       }
-                       done += res;
-               }
-
-               memcpy(&device_last_read, &current_time,
-                      sizeof(device_last_read));
-               return yarrow256_update(&yctx, RANDOM_SOURCE_DEVICE,
-                                       read_size * 8 / 2, read_size, buf);
-       }
-       return 0;
-}
-
-static int do_device_source(int init)
-{
-       int ret;
-       static int (*do_source) (int init) = NULL;
-/* using static var here is ok since we are
- * always called with mutexes down 
- */
-       if (init == 1) {
-#ifdef HAVE_GETPID
-               pid = getpid();
-#endif
-
-               do_source = do_device_source_urandom;
-               ret = do_source(init);
-               if (ret < 0) {
-                       do_source = do_device_source_egd;
-                       ret = do_source(init);
-               }
-
-               if (ret < 0) {
-                       gnutls_assert();
-                       return ret;
-               }
-
-               return ret;
-       } else {
-               ret = do_source(init);
-
-               return ret;
-       }
-}
-
-
 static void wrap_nettle_rnd_deinit(void *ctx)
 {
        RND_LOCK;
-       close(device_fd);
+       _rnd_system_entropy_deinit();
        RND_UNLOCK;
 
        gnutls_mutex_deinit(&rnd_mutex);
        rnd_mutex = NULL;
 }
 
-#endif
-
-
 /* API functions */
 
 static int wrap_nettle_rnd_init(void **ctx)
@@ -381,9 +169,13 @@ static int wrap_nettle_rnd_init(void **ctx)
                gnutls_assert();
                return ret;
        }
-
+       
+       ret = _rnd_system_entropy_init();
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
        yarrow256_init(&yctx, SOURCES, ysources);
-       gettime(&current_time);
 
        ret = do_device_source(1);
        if (ret < 0) {
@@ -424,8 +216,6 @@ wrap_nettle_rnd(void *_ctx, int level, void *data, size_t datasize)
         * The reason we do that is to avoid any delays when generating nonces.
         */
        if (level != GNUTLS_RND_NONCE || reseed != 0) {
-               gettime(&current_time);
-
                ret = do_trivia_source(0);
                if (ret < 0) {
                        RND_UNLOCK;
@@ -452,8 +242,6 @@ wrap_nettle_rnd(void *_ctx, int level, void *data, size_t datasize)
 static void wrap_nettle_rnd_refresh(void *_ctx)
 {
        RND_LOCK;
-       gettime(&current_time);
-
        do_trivia_source(0);
        do_device_source(0);