diff options
-rw-r--r-- | lib/nettle/Makefile.am | 8 | ||||
-rw-r--r-- | lib/nettle/rnd-common.c | 209 | ||||
-rw-r--r-- | lib/nettle/rnd-common.h | 51 | ||||
-rw-r--r-- | lib/nettle/rnd.c | 272 |
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, ¤t_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(¤t_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, ¤t_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(¤t_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, ¤t_time, sizeof(device_last_read)); @@ -228,34 +130,13 @@ static int do_device_source_urandom(int init) if ((init || (timespec_sub_sec(¤t_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, ¤t_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, ¤t_time, - sizeof(device_last_read)); - - read_size = DEVICE_READ_SIZE_MAX; /* initially read more data */ - } - - if ((device_fd > 0) - && (init - || (timespec_sub_sec(¤t_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, ¤t_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(¤t_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(¤t_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(¤t_time); - do_trivia_source(0); do_device_source(0); |