summaryrefslogtreecommitdiff
path: root/src/platform
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2017-01-08 15:28:37 -0800
committerGarrett D'Amore <garrett@damore.org>2017-01-08 17:33:05 -0800
commitc5b5bd910507520f7974a156a1de9d187f23bc2f (patch)
tree9766716c795d88fe902c7196696c1389d76717ba /src/platform
parent4b166dd8ae417b818a5ba214d8f2e648ac1d5be9 (diff)
downloadnng-c5b5bd910507520f7974a156a1de9d187f23bc2f.tar.gz
nng-c5b5bd910507520f7974a156a1de9d187f23bc2f.tar.bz2
nng-c5b5bd910507520f7974a156a1de9d187f23bc2f.zip
New ISAAC pRNG. This replaces other local hacks for random data.
Platforms must seed the pRNGs by offering an nni_plat_seed_prng() routine. Implementations for POSIX using various options (including the /dev/urandom device) are supplied.
Diffstat (limited to 'src/platform')
-rw-r--r--src/platform/posix/posix_config.h25
-rw-r--r--src/platform/posix/posix_debug.c56
-rw-r--r--src/platform/posix/posix_rand.c86
-rw-r--r--src/platform/posix/posix_thread.c32
4 files changed, 134 insertions, 65 deletions
diff --git a/src/platform/posix/posix_config.h b/src/platform/posix/posix_config.h
index 6d282f63..e1bafd5c 100644
--- a/src/platform/posix/posix_config.h
+++ b/src/platform/posix/posix_config.h
@@ -27,23 +27,38 @@
// is defined. Platforms that don't use POSIX clocks will probably
// ignore any setting here.
//
-// #define NNG_HAVE_ARC4RANDOM
-// This indicates that the platform has the superior arc4random function
-// for getting entropy.
-//
// #define NNG_HAVE_BACKTRACE
// If your system has a working backtrace(), and backtrace_symbols(),
// along with <execinfo.h>, you can define this to get richer backtrace
// information for debugging.
+//
+// #define NNG_USE_GETRANDOM
+// #define NNG_USE_GETENTROPY
+// #define NNG_USE_ARC4RANDOM
+// #define NNG_USE_DEVURANDOM
+// Thesse are options for obtaining entropy to seed the pRNG.
+// All known modern UNIX variants can support NNG_USE_DEVURANDOM,
+// but the other options are better still, but not portable.
#include <time.h>
+// These are things about systems we know about.
+#ifdef __APPLE__
// MacOS X used to lack CLOCK_MONOTONIC. Now it has it, but its
// buggy, condition variables set to use it wake early.
-#ifdef __APPLE__
#define NNG_USE_CLOCKID CLOCK_REALTIME
+// macOS 10.12 has getentropy(), but arc4random() is good enough
+// and works on older releases.
+#define NNG_USE_ARC4RANDOM 1
#endif // __APPLE__
+// It should never hurt to use DEVURANDOM, since if the device does not
+// exist then we won't open it. (Provided: it would be bad if the device
+// exists but has somehow very very different semantics. We don't know
+// of any such concerns.) This won't be used if any of the other options
+// are defined and work.
+#define NNG_USE_DEVURANDOM 1
+
#define NNG_USE_CLOCKID CLOCK_REALTIME
#ifndef CLOCK_REALTIME
#define NNG_USE_GETTIMEOFDAY
diff --git a/src/platform/posix/posix_debug.c b/src/platform/posix/posix_debug.c
index a956d777..71006b25 100644
--- a/src/platform/posix/posix_debug.c
+++ b/src/platform/posix/posix_debug.c
@@ -55,35 +55,35 @@ static struct {
int nng_err;
}
nni_plat_errnos[] = {
- NNI_ERR(EINTR, NNG_EINTR)
- NNI_ERR(EINVAL, NNG_EINVAL)
- NNI_ERR(ENOMEM, NNG_ENOMEM)
- NNI_ERR(EACCES, NNG_EPERM)
- NNI_ERR(EADDRINUSE, NNG_EADDRINUSE)
- NNI_ERR(EADDRNOTAVAIL, NNG_EADDRINVAL)
- NNI_ERR(EAFNOSUPPORT, NNG_ENOTSUP)
- NNI_ERR(EAGAIN, NNG_EAGAIN)
- NNI_ERR(EBADF, NNG_ECLOSED)
- NNI_ERR(EBUSY, NNG_EBUSY)
- NNI_ERR(ECONNABORTED, NNG_ECLOSED)
- NNI_ERR(ECONNREFUSED, NNG_ECONNREFUSED)
- NNI_ERR(ECONNRESET, NNG_ECLOSED)
- NNI_ERR(EHOSTUNREACH, NNG_EUNREACHABLE)
- NNI_ERR(ENETUNREACH, NNG_EUNREACHABLE)
- NNI_ERR(ENAMETOOLONG, NNG_EINVAL)
- NNI_ERR(ENOENT, NNG_ENOENT)
- NNI_ERR(ENOBUFS, NNG_ENOMEM)
- NNI_ERR(ENOPROTOOPT, NNG_ENOTSUP)
- NNI_ERR(ENOSYS, NNG_ENOTSUP)
- NNI_ERR(ENOTSUP, NNG_ENOTSUP)
- NNI_ERR(EPERM, NNG_EPERM)
- NNI_ERR(EPIPE, NNG_ECLOSED)
- NNI_ERR(EPROTO, NNG_EPROTO)
+ NNI_ERR(EINTR, NNG_EINTR)
+ NNI_ERR(EINVAL, NNG_EINVAL)
+ NNI_ERR(ENOMEM, NNG_ENOMEM)
+ NNI_ERR(EACCES, NNG_EPERM)
+ NNI_ERR(EADDRINUSE, NNG_EADDRINUSE)
+ NNI_ERR(EADDRNOTAVAIL, NNG_EADDRINVAL)
+ NNI_ERR(EAFNOSUPPORT, NNG_ENOTSUP)
+ NNI_ERR(EAGAIN, NNG_EAGAIN)
+ NNI_ERR(EBADF, NNG_ECLOSED)
+ NNI_ERR(EBUSY, NNG_EBUSY)
+ NNI_ERR(ECONNABORTED, NNG_ECLOSED)
+ NNI_ERR(ECONNREFUSED, NNG_ECONNREFUSED)
+ NNI_ERR(ECONNRESET, NNG_ECLOSED)
+ NNI_ERR(EHOSTUNREACH, NNG_EUNREACHABLE)
+ NNI_ERR(ENETUNREACH, NNG_EUNREACHABLE)
+ NNI_ERR(ENAMETOOLONG, NNG_EINVAL)
+ NNI_ERR(ENOENT, NNG_ENOENT)
+ NNI_ERR(ENOBUFS, NNG_ENOMEM)
+ NNI_ERR(ENOPROTOOPT, NNG_ENOTSUP)
+ NNI_ERR(ENOSYS, NNG_ENOTSUP)
+ NNI_ERR(ENOTSUP, NNG_ENOTSUP)
+ NNI_ERR(EPERM, NNG_EPERM)
+ NNI_ERR(EPIPE, NNG_ECLOSED)
+ NNI_ERR(EPROTO, NNG_EPROTO)
NNI_ERR(EPROTONOSUPPORT, NNG_ENOTSUP)
- NNI_ERR(ETIME, NNG_ETIMEDOUT)
- NNI_ERR(ETIMEDOUT, NNG_ETIMEDOUT)
- NNI_ERR(EWOULDBLOCK, NNG_EAGAIN)
- NNI_ERR(0, 0) // must be last
+ NNI_ERR(ETIME, NNG_ETIMEDOUT)
+ NNI_ERR(ETIMEDOUT, NNG_ETIMEDOUT)
+ NNI_ERR(EWOULDBLOCK, NNG_EAGAIN)
+ NNI_ERR(0, 0) // must be last
};
int
diff --git a/src/platform/posix/posix_rand.c b/src/platform/posix/posix_rand.c
new file mode 100644
index 00000000..65d1c031
--- /dev/null
+++ b/src/platform/posix/posix_rand.c
@@ -0,0 +1,86 @@
+//
+// Copyright 2017 Garrett D'Amore <garrett@damore.org>
+//
+// This software is supplied under the terms of the MIT License, a
+// copy of which should be located in the distribution where this
+// file was obtained (LICENSE.txt). A copy of the license may also be
+// found online at https://opensource.org/licenses/MIT.
+//
+
+// POSIX clock stuff.
+#include "core/nng_impl.h"
+
+#ifdef PLATFORM_POSIX_RANDOM
+
+#include <time.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/utsname.h>
+#include <fcntl.h>
+
+#ifdef NNG_USE_GETRANDOM
+#include <linux/random.h>
+#endif
+
+#ifdef NNG_USE_GETENTROPY
+#include <sys/random.h>
+#endif
+
+// This structure represents the very barest minimum that we can use as
+// a source of entropy. We mix these into our initial entropy, but really
+// really really you want to have more data than this available, especially
+// for cryptographic applications.
+struct nni_plat_prng_x {
+ nni_time now;
+ pid_t pid;
+ uid_t uid;
+ struct utsname uts;
+};
+
+void
+nni_plat_seed_prng(void *buf, size_t bufsz)
+{
+ struct nni_plat_prng_x x;
+ int i;
+
+#if defined(NNG_USE_GETRANDOM)
+ // Latest Linux has a nice API here.
+ (void) getrandom(buf, bufsz, 0);
+#elif defined(NNG_USE_GETENTROPY)
+ // Modern BSD systems prefer this, but can only generate 256 bytes
+ (void) getentropy(buf, bufsz > 256 ? 256 : 0);
+#elif defined(NNG_USE_ARC4RANDOM)
+ // This uses BSD style pRNG seeded from the kernel in libc.
+ (void) arc4random_buf(buf, bufsz);
+#elif defined(NNG_USE_DEVURANDOM)
+ // The historic /dev/urandom device. This is not as a good as
+ // a system call, since file descriptor attacks are possible,
+ // and it may need special permissions. We choose /dev/urandom
+ // over /dev/random to avoid diminishing the system entropy.
+ int fd;
+
+ if ((fd = open("/dev/urandom", O_RDONLY)) >= 0) {
+ (void) read(fd, buf, buffz);
+ (void) close(fd);
+ }
+#endif
+
+ // As a speical extra guard, let's mixin the data from the
+ // following system calls. This ensures that even on the most
+ // limited of systems, we have at least *some* level of randomness.
+ // The mixing is done in a way to avoid diminishing entropy we may
+ // have already collected.
+ x.now = nni_clock();
+ x.pid = getpid();
+ x.uid = getuid();
+ uname(&x.uts);
+
+ for (i = 0; (i < bufsz) && (i < sizeof (x)); i++) {
+ ((uint8_t *) buf)[i] ^= ((uint8_t *) &x)[i];
+ }
+}
+
+
+#endif // PLATFORM_POSIX_RANDOM
diff --git a/src/platform/posix/posix_thread.c b/src/platform/posix/posix_thread.c
index e4e5e74b..991a08db 100644
--- a/src/platform/posix/posix_thread.c
+++ b/src/platform/posix/posix_thread.c
@@ -24,7 +24,6 @@
static pthread_mutex_t nni_plat_lock = PTHREAD_MUTEX_INITIALIZER;
static int nni_plat_inited = 0;
static int nni_plat_forked = 0;
-static int nni_plat_next = 0;
pthread_condattr_t nni_cvattr;
pthread_mutexattr_t nni_mxattr;
@@ -34,18 +33,6 @@ pthread_mutexattr_t nni_mxattr;
int nni_plat_devnull = -1;
-uint32_t
-nni_plat_nextid(void)
-{
- uint32_t id;
-
- pthread_mutex_lock(&nni_plat_lock);
- id = nni_plat_next++;
- pthread_mutex_unlock(&nni_plat_lock);
- return (id);
-}
-
-
int
nni_plat_mtx_init(nni_plat_mtx *mtx)
{
@@ -270,25 +257,6 @@ nni_plat_init(int (*helper)(void))
return (NNG_ENOMEM);
}
- // Generate a starting ID (used for Pipe IDs)
-#ifdef NNG_HAVE_ARC4RANDOM
- nni_plat_next = arc4random();
-#else
- while (nni_plat_next == 0) {
- uint16_t xsub[3];
- nni_time now = nni_clock();
- pid_t pid = getpid();
-
- xsub[0] = (uint16_t) now;
- xsub[1] = (uint16_t) (now >> 16);
- xsub[2] = (uint16_t) (now >> 24);
- xsub[0] ^= (uint16_t) pid;
- xsub[1] ^= (uint16_t) (pid >> 16);
- xsub[2] ^= (uint16_t) (pid >> 24);
- nni_plat_next = nrand48(xsub);
- }
-#endif
-
if (pthread_atfork(NULL, NULL, nni_atfork_child) != 0) {
pthread_mutex_unlock(&nni_plat_lock);
(void) close(nni_plat_devnull);