summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/nettle/Makefile.am8
-rw-r--r--lib/nettle/rnd-common.c209
-rw-r--r--lib/nettle/rnd-common.h51
-rw-r--r--lib/nettle/rnd.c272
4 files changed, 297 insertions, 243 deletions
diff --git a/lib/nettle/Makefile.am b/lib/nettle/Makefile.am
index e73db1a66d..67f7fdaf51 100644
--- a/lib/nettle/Makefile.am
+++ b/lib/nettle/Makefile.am
@@ -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
index 0000000000..da8d4f08f4
--- /dev/null
+++ b/lib/nettle/rnd-common.c
@@ -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
index 0000000000..9c63f50645
--- /dev/null
+++ b/lib/nettle/rnd-common.h
@@ -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;
diff --git a/lib/nettle/rnd.c b/lib/nettle/rnd.c
index cd988c2be6..8a6e059f5f 100644
--- a/lib/nettle/rnd.c
+++ b/lib/nettle/rnd.c
@@ -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);