summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xConfigure23
-rw-r--r--apps/version.c38
-rw-r--r--crypto/rand/drbg_rand.c6
-rw-r--r--crypto/rand/rand_lcl.h28
-rw-r--r--crypto/rand/rand_lib.c64
-rw-r--r--crypto/rand/rand_unix.c292
-rw-r--r--crypto/rand/rand_vms.c6
-rw-r--r--crypto/rand/rand_win.c98
-rw-r--r--doc/man3/RAND_add.pod65
-rw-r--r--doc/man3/RAND_load_file.pod10
10 files changed, 324 insertions, 306 deletions
diff --git a/Configure b/Configure
index 9612976cfa..ebfe01d290 100755
--- a/Configure
+++ b/Configure
@@ -561,6 +561,9 @@ $config{build_type} = "release";
my %unsupported_options = ();
my %deprecated_options = ();
+# If you change this, update apps/version.c
+my @known_seed_sources = qw(getrandom devrandom os egd none rdcpu librandom);
+my @seed_sources = ();
while (@argvcopy)
{
$_ = shift @argvcopy;
@@ -729,6 +732,15 @@ while (@argvcopy)
{
$withargs{fuzzer_include}=$1;
}
+ elsif (/^--with-rand-seed=(.*)$/)
+ {
+ foreach my $x (split(m|,|, $1))
+ {
+ die "Unknown --with-rand-seed choice $x\n"
+ if ! grep { $x eq $_ } @known_seed_sources;
+ push @seed_sources, $x;
+ }
+ }
elsif (/^--cross-compile-prefix=(.*)$/)
{
$config{cross_compile_prefix}=$1;
@@ -812,6 +824,17 @@ if ($libs =~ /(^|\s)-Wl,-rpath,/
"***** any of asan, msan or ubsan\n";
}
+if (scalar(@seed_sources) == 0) {
+ print "Using implicit seed configuration\n";
+ push @seed_sources, 'os';
+}
+die "Cannot seed with none and anything else"
+ if scalar(grep { $_ eq 'none' } @seed_sources) > 0
+ && scalar(@seed_sources) > 1;
+push @{$config{openssl_other_defines}},
+ map { (my $x = $_) =~ tr|[\-a-z]|[_A-Z]|; "OPENSSL_RAND_SEED_$x" }
+ @seed_sources;
+
my @tocheckfor = (keys %disabled);
while (@tocheckfor) {
my %new_tocheckfor = ();
diff --git a/apps/version.c b/apps/version.c
index 24f1a80fdf..298d837f5a 100644
--- a/apps/version.c
+++ b/apps/version.c
@@ -32,7 +32,7 @@
typedef enum OPTION_choice {
OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
- OPT_B, OPT_D, OPT_E, OPT_F, OPT_O, OPT_P, OPT_V, OPT_A
+ OPT_B, OPT_D, OPT_E, OPT_F, OPT_O, OPT_P, OPT_V, OPT_A, OPT_R
} OPTION_CHOICE;
const OPTIONS version_options[] = {
@@ -44,13 +44,14 @@ const OPTIONS version_options[] = {
{"f", OPT_F, '-', "Show compiler flags used"},
{"o", OPT_O, '-', "Show some internal datatype options"},
{"p", OPT_P, '-', "Show target build platform"},
+ {"r", OPT_R, '-', "Show random seeding options"},
{"v", OPT_V, '-', "Show library version"},
{NULL}
};
int version_main(int argc, char **argv)
{
- int ret = 1, dirty = 0;
+ int ret = 1, dirty = 0, seed = 0;
int cflags = 0, version = 0, date = 0, options = 0, platform = 0, dir = 0;
int engdir = 0;
char *prog;
@@ -85,11 +86,14 @@ int version_main(int argc, char **argv)
case OPT_P:
dirty = platform = 1;
break;
+ case OPT_R:
+ dirty = seed = 1;
+ break;
case OPT_V:
dirty = version = 1;
break;
case OPT_A:
- cflags = version = date = platform = dir = engdir = 1;
+ seed = cflags = version = date = platform = dir = engdir = 1;
break;
}
}
@@ -133,6 +137,34 @@ int version_main(int argc, char **argv)
printf("%s\n", OpenSSL_version(OPENSSL_DIR));
if (engdir)
printf("%s\n", OpenSSL_version(OPENSSL_ENGINES_DIR));
+ if (seed) {
+ printf("Seeding source:");
+#ifdef OPENSSL_RAND_SEED_RTDSC
+ printf(" rtdsc");
+#endif
+#ifdef OPENSSL_RAND_SEED_RDCPU
+ printf(" rdrand-hardware");
+#endif
+#ifdef OPENSSL_RAND_SEED_LIBRANDOM
+ printf(" C-library-random");
+#endif
+#ifdef OPENSSL_RAND_SEED_GETRANDOM
+ printf(" getrandom-syscall");
+#endif
+#ifdef OPENSSL_RAND_SEED_DEVRANDOM
+ printf(" random-device");
+#endif
+#ifdef OPENSSL_RAND_SEED_EGD
+ printf(" EGD");
+#endif
+#ifdef OPENSSL_RAND_SEED_NONE
+ printf(" none");
+#endif
+#ifdef OPENSSL_RAND_SEED_OS
+ printf(" os-specific");
+#endif
+ printf("\n");
+ }
ret = 0;
end:
return (ret);
diff --git a/crypto/rand/drbg_rand.c b/crypto/rand/drbg_rand.c
index 77d59ec813..8b30cd8a0d 100644
--- a/crypto/rand/drbg_rand.c
+++ b/crypto/rand/drbg_rand.c
@@ -29,8 +29,12 @@ static CRYPTO_ONCE ossl_drbg_init = CRYPTO_ONCE_STATIC_INIT;
DEFINE_RUN_ONCE_STATIC(do_ossl_drbg_init)
{
+ int st = 1;
+
ossl_drbg.lock = CRYPTO_THREAD_lock_new();
- return ossl_drbg.lock != NULL;
+ st &= ossl_drbg.lock != NULL;
+ st &= RAND_DRBG_set(&ossl_drbg, NID_aes_128_ctr, 0) == 1;
+ return st;
}
void rand_drbg_cleanup(void)
diff --git a/crypto/rand/rand_lcl.h b/crypto/rand/rand_lcl.h
index de1f2cd4e6..b9df5d18e2 100644
--- a/crypto/rand/rand_lcl.h
+++ b/crypto/rand/rand_lcl.h
@@ -17,21 +17,24 @@
# include <openssl/ec.h>
# include "internal/rand.h"
-/* we require 256 bits of randomness */
-# define RANDOMNESS_NEEDED (256 / 8)
+/* Amount of randomness (in bytes) we want for initial seeding. */
+# define RANDOMNESS_NEEDED (128 / 8)
/* Maximum count allowed in reseeding */
#define MAX_RESEED (1 << 24)
/* DRBG status values */
-#define DRBG_STATUS_UNINITIALISED 0
-#define DRBG_STATUS_READY 1
-#define DRBG_STATUS_RESEED 2
-#define DRBG_STATUS_ERROR 3
+# define DRBG_STATUS_UNINITIALISED 0
+# define DRBG_STATUS_READY 1
+# define DRBG_STATUS_RESEED 2
+# define DRBG_STATUS_ERROR 3
/* A default maximum length: larger than any reasonable value used in pratice */
-#define DRBG_MAX_LENGTH 0x7ffffff0
+# define DRBG_MAX_LENGTH 0x7ffffff0
+/*
+ * The context for DRBG AES-CTR
+ */
typedef struct drbg_ctr_ctx_st {
AES_KEY ks;
size_t keylen;
@@ -46,6 +49,10 @@ typedef struct drbg_ctr_ctx_st {
unsigned char KX[48];
} DRBG_CTR_CTX;
+
+/*
+ * The context for all DRBG's
+ */
struct drbg_ctx_st {
CRYPTO_RWLOCK *lock;
DRBG_CTX *parent;
@@ -84,9 +91,12 @@ struct drbg_ctx_st {
extern RAND_METHOD openssl_rand_meth;
void rand_drbg_cleanup(void);
+/* Hardware-based seeding functions. */
+void rand_rdtsc(void);
+int rand_rdcpu(void);
+
+/* DRBG functions implementing AES-CTR */
int ctr_init(DRBG_CTX *dctx);
-int drbg_hash_init(DRBG_CTX *dctx);
-int drbg_hmac_init(DRBG_CTX *dctx);
int ctr_uninstantiate(DRBG_CTX *dctx);
int ctr_instantiate(DRBG_CTX *dctx,
const unsigned char *ent, size_t entlen,
diff --git a/crypto/rand/rand_lib.c b/crypto/rand/rand_lib.c
index 3168d84b47..05aa45cd64 100644
--- a/crypto/rand/rand_lib.c
+++ b/crypto/rand/rand_lib.c
@@ -25,6 +25,70 @@ static CRYPTO_RWLOCK *rand_meth_lock;
static const RAND_METHOD *default_RAND_meth;
static CRYPTO_ONCE rand_init = CRYPTO_ONCE_STATIC_INIT;
+#ifdef OPENSSL_RAND_SEED_RDTSC
+/*
+ * IMPORTANT NOTE: It is not currently possible to use this code
+ * because we are not sure about the amount of randomness. Some
+ * SP900 tests have been run, but there is internal skepticism.
+ * So for now this code is not used.
+ */
+# error "RDTSC enabled? Should not be possible!"
+
+/*
+ * Since we get some randomness from the low-order bits of the
+ * high-speec clock, it can help. But don't return a status since
+ * it's not sufficient to indicate whether or not the seeding was
+ * done.
+ */
+void rand_rdtsc(void)
+{
+ unsigned char c;
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ c = (unsigned char)(OPENSSL_rdtsc() & 0xFF);
+ RAND_add(&c, 1, 0.5);
+ }
+}
+#endif
+
+#ifdef OPENSSL_RAND_SEED_RDCPU
+size_t OPENSSL_ia32_rdseed(void);
+size_t OPENSSL_ia32_rdrand(void);
+
+extern unsigned int OPENSSL_ia32cap_P[];
+
+int rand_rdcpu(void)
+{
+ size_t i, s;
+
+ /* If RDSEED is available, use that. */
+ if ((OPENSSL_ia32cap_P[1] & (1 << 18)) != 0) {
+ for (i = 0; i < RANDOMNESS_NEEDED; i += sizeof(s)) {
+ s = OPENSSL_ia32_rdseed();
+ if (s == 0)
+ break;
+ RAND_add(&s, (int)sizeof(s), sizeof(s));
+ }
+ if (i >= RANDOMNESS_NEEDED)
+ return 1;
+ }
+
+ /* Second choice is RDRAND. */
+ if ((OPENSSL_ia32cap_P[1] & (1 << (62 - 32))) != 0) {
+ for (i = 0; i < RANDOMNESS_NEEDED; i += sizeof(s)) {
+ s = OPENSSL_ia32_rdrand();
+ if (s == 0)
+ break;
+ RAND_add(&s, (int)sizeof(s), sizeof(s));
+ }
+ if (i >= RANDOMNESS_NEEDED)
+ return 1;
+ }
+
+ return 0;
+}
+#endif
DEFINE_RUN_ONCE_STATIC(do_rand_init)
{
diff --git a/crypto/rand/rand_unix.c b/crypto/rand/rand_unix.c
index bfdd3e6efa..2cfd20dd50 100644
--- a/crypto/rand/rand_unix.c
+++ b/crypto/rand/rand_unix.c
@@ -1,5 +1,5 @@
/*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
@@ -9,32 +9,32 @@
#include <stdio.h>
-#define USE_SOCKETS
#include "e_os.h"
#include "internal/cryptlib.h"
#include <openssl/rand.h>
#include "rand_lcl.h"
+#include <stdio.h>
#if !(defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_UEFI))
-# include <sys/types.h>
-# include <sys/time.h>
-# include <sys/times.h>
-# include <sys/stat.h>
-# include <fcntl.h>
-# include <unistd.h>
-# include <time.h>
-# if defined(OPENSSL_SYS_LINUX) /* should actually be available virtually
- * everywhere */
-# include <poll.h>
-# endif
-# include <limits.h>
-# ifndef FD_SETSIZE
-# define FD_SETSIZE (8*sizeof(fd_set))
+# if (defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_UEFI)) && \
+ !defined(OPENSSL_RAND_SEED_NONE)
+# error "UEFI and VXWorks only support seeding NONE"
# endif
# if defined(OPENSSL_SYS_VOS)
+# ifndef OPENSSL_RAND_SEED_OS
+# error "Unsupported seeding method configured; must be os"
+# endif
+
+# if defined(OPENSSL_SYS_VOS_HPPA) && defined(OPENSSL_SYS_VOS_IA32)
+# error "Unsupported HP-PA and IA32 at the same time."
+# endif
+# if !defined(OPENSSL_SYS_VOS_HPPA) && !defined(OPENSSL_SYS_VOS_IA32)
+# error "Must have one of HP-PA or IA32"
+# endif
+
/*
* The following algorithm repeatedly samples the real-time clock (RTC) to
* generate a sequence of unpredictable data. The algorithm relies upon the
@@ -51,7 +51,6 @@
* As a precaution, we generate 4 times the minimum required amount of seed
* data.
*/
-
int RAND_poll(void)
{
short int code;
@@ -61,35 +60,24 @@ int RAND_poll(void)
int i, k;
struct timespec ts;
unsigned char v;
-
# ifdef OPENSSL_SYS_VOS_HPPA
long duration;
extern void s$sleep(long *_duration, short int *_code);
# else
-# ifdef OPENSSL_SYS_VOS_IA32
long long duration;
extern void s$sleep2(long long *_duration, short int *_code);
-# else
-# error "Unsupported Platform."
-# endif /* OPENSSL_SYS_VOS_IA32 */
-# endif /* OPENSSL_SYS_VOS_HPPA */
+# endif
/*
* Seed with the gid, pid, and uid, to ensure *some* variation between
* different processes.
*/
-
curr_gid = getgid();
- RAND_add(&curr_gid, sizeof curr_gid, 1);
- curr_gid = 0;
-
+ RAND_add(&curr_gid, sizeof curr_gid, 0);
curr_pid = getpid();
- RAND_add(&curr_pid, sizeof curr_pid, 1);
- curr_pid = 0;
-
+ RAND_add(&curr_pid, sizeof curr_pid, 0);
curr_uid = getuid();
- RAND_add(&curr_uid, sizeof curr_uid, 1);
- curr_uid = 0;
+ RAND_add(&curr_uid, sizeof curr_uid, 0);
for (i = 0; i < (RANDOMNESS_NEEDED * 4); i++) {
/*
@@ -104,203 +92,111 @@ int RAND_poll(void)
duration = 1;
s$sleep(&duration, &code);
# else
-# ifdef OPENSSL_SYS_VOS_IA32
/* sleep for 1/65536 of a second (15 us). */
duration = 1;
s$sleep2(&duration, &code);
-# endif /* OPENSSL_SYS_VOS_IA32 */
-# endif /* OPENSSL_SYS_VOS_HPPA */
+# endif
- /* get wall clock time. */
+ /* Get wall clock time, take 8 bits. */
clock_gettime(CLOCK_REALTIME, &ts);
-
- /* take 8 bits */
- v = (unsigned char)(ts.tv_nsec % 256);
+ v = (unsigned char)(ts.tv_nsec & 0xFF);
RAND_add(&v, sizeof v, 1);
- v = 0;
}
return 1;
}
+
# else
-int RAND_poll(void)
-{
- unsigned long l;
- pid_t curr_pid = getpid();
-# if defined(DEVRANDOM) || (!defined(OPENSS_NO_EGD) && defined(DEVRANDOM_EGD))
- unsigned char tmpbuf[RANDOMNESS_NEEDED];
- int n = 0;
-# endif
-# ifdef DEVRANDOM
- static const char *randomfiles[] = { DEVRANDOM };
- struct stat randomstats[OSSL_NELEM(randomfiles)];
- int fd;
- unsigned int i;
-# endif
-# if !defined(OPENSSL_NO_EGD) && defined(DEVRANDOM_EGD)
- static const char *egdsockets[] = { DEVRANDOM_EGD, NULL };
- const char **egdsocket = NULL;
+
+# if defined(OPENSSL_RAND_SEED_EGD) && \
+ (defined(OPENSSL_NO_EGD) || !defined(DEVRANDOM_EGD))
+# error "Seeding uses EGD but EGD is turned off or no device given"
# endif
-# ifdef DEVRANDOM
- memset(randomstats, 0, sizeof(randomstats));
- /*
- * Use a randomness device. Linux, FreeBSD and OpenBSD have
- * this. Use /dev/urandom if you can as /dev/random may block if it runs
- * out of random entries.
- */
+# if defined(OPENSSL_RAND_SEED_DEVRANDOM) && !defined(DEVRANDOM)
+# error "Seeding uses urandom but DEVRANDOM is not configured"
+# endif
- for (i = 0; (i < OSSL_NELEM(randomfiles)) && (n < RANDOMNESS_NEEDED); i++) {
- if ((fd = open(randomfiles[i], O_RDONLY
-# ifdef O_NONBLOCK
- | O_NONBLOCK
-# endif
-# ifdef O_BINARY
- | O_BINARY
-# endif
-# ifdef O_NOCTTY /* If it happens to be a TTY (god forbid), do
- * not make it our controlling tty */
- | O_NOCTTY
+# if defined(OPENSSL_RAND_SEED_OS)
+# if defined(DEVRANDOM)
+# define OPENSSL_RAND_SEED_DEVRANDOM
+# else
+# error "OS seeding requires DEVRANDOM to be configured"
# endif
- )) >= 0) {
- int usec = 10 * 1000; /* spend 10ms on each file */
- int r;
- unsigned int j;
- struct stat *st = &randomstats[i];
-
- /*
- * Avoid using same input... Used to be O_NOFOLLOW above, but
- * it's not universally appropriate...
- */
- if (fstat(fd, st) != 0) {
- close(fd);
- continue;
- }
- for (j = 0; j < i; j++) {
- if (randomstats[j].st_ino == st->st_ino &&
- randomstats[j].st_dev == st->st_dev)
- break;
- }
- if (j < i) {
- close(fd);
- continue;
- }
-
- do {
- int try_read = 0;
-
-# if defined(OPENSSL_SYS_LINUX)
- /* use poll() */
- struct pollfd pset;
-
- pset.fd = fd;
- pset.events = POLLIN;
- pset.revents = 0;
-
- if (poll(&pset, 1, usec / 1000) < 0)
- usec = 0;
- else
- try_read = (pset.revents & POLLIN) != 0;
+# endif
-# else
- /* use select() */
- fd_set fset;
- struct timeval t;
+# if defined(OPENSSL_RAND_SEED_LIBRANDOM)
+# error "librandom not (yet) supported"
+# endif
- t.tv_sec = 0;
- t.tv_usec = usec;
+int RAND_poll(void)
+{
+# ifdef OPENSSL_RAND_SEED_NONE
+ return 0;
+# else
+ int ok = 0;
+ char temp[RANDOMNESS_NEEDED];
+# define TEMPSIZE (int)sizeof(temp)
- if (FD_SETSIZE > 0 && (unsigned)fd >= FD_SETSIZE) {
- /*
- * can't use select, so just try to read once anyway
- */
- try_read = 1;
- } else {
- FD_ZERO(&fset);
- FD_SET(fd, &fset);
+# ifdef OPENSSL_RAND_SEED_RDTSC
+ rand_rdtsc();
+# endif
- if (select(fd + 1, &fset, NULL, NULL, &t) >= 0) {
- usec = t.tv_usec;
- if (FD_ISSET(fd, &fset))
- try_read = 1;
- } else
- usec = 0;
- }
+# ifdef OPENSSL_RAND_SEED_RDCPU
+ if (rand_rdcpu())
+ ok++;
# endif
- if (try_read) {
- r = read(fd, (unsigned char *)tmpbuf + n,
- RANDOMNESS_NEEDED - n);
- if (r > 0)
- n += r;
- } else
- r = -1;
+# ifdef OPENSSL_RAND_SEED_EGD
+ {
+ static const char *paths[] = { DEVRANDOM_EGD, NULL };
+ int i;
- /*
- * Some Unixen will update t in select(), some won't. For
- * those who won't, or if we didn't use select() in the first
- * place, give up here, otherwise, we will do this once again
- * for the remaining time.
- */
- if (usec == 10 * 1000)
- usec = 0;
+ for (i = 0; paths[i] != NULL; i++) {
+ if (RAND_query_egd_bytes(paths[i], temp, TEMPSIZE) == TEMPSIZE) {
+ RAND_add(temp, TEMPSIZE, TEMPSIZE);
+ ok++;
+ break;
}
- while ((r > 0 ||
- (errno == EINTR || errno == EAGAIN)) && usec != 0
- && n < RANDOMNESS_NEEDED);
-
- close(fd);
}
}
-# endif /* defined(DEVRANDOM) */
-
-# if !defined(OPENSSL_NO_EGD) && defined(DEVRANDOM_EGD)
- /*
- * Use an EGD socket to read randomness from the daemon.
- */
-
- for (egdsocket = egdsockets; *egdsocket && n < RANDOMNESS_NEEDED;
- egdsocket++) {
- int r;
+# endif
- r = RAND_query_egd_bytes(*egdsocket, (unsigned char *)tmpbuf + n,
- RANDOMNESS_NEEDED - n);
- if (r > 0)
- n += r;
- }
-# endif /* defined(DEVRANDOM_EGD) */
+# ifdef OPENSSL_RAND_SEED_DEVRANDOM
+ {
+ static const char *paths[] = { DEVRANDOM, NULL };
+ FILE *fp;
+ int i;
-# if defined(DEVRANDOM) || (!defined(OPENSSL_NO_EGD) && defined(DEVRANDOM_EGD))
- if (n > 0) {
- RAND_add(tmpbuf, sizeof tmpbuf, (double)n);
- OPENSSL_cleanse(tmpbuf, n);
+ for (i = 0; paths[i] != NULL; i++) {
+ if ((fp = fopen(paths[i], "rb")) == NULL)
+ continue;
+ setbuf(fp, NULL);
+ if (fread(temp, 1, TEMPSIZE, fp) == TEMPSIZE) {
+ RAND_add(temp, TEMPSIZE, TEMPSIZE);
+ ok++;
+ fclose(fp);
+ break;
+ }
+ }
}
-# endif
+# endif
- /* put in some default random data, we need more than just this */
- l = curr_pid;
- RAND_add(&l, sizeof(l), 0.0);
- l = getuid();
- RAND_add(&l, sizeof(l), 0.0);
+# ifdef OPENSSL_RAND_SEED_GETRANDOM
+ {
+ int i = getrandom(temp, TEMPSIZE, 0);
- l = time(NULL);
- RAND_add(&l, sizeof(l), 0.0);
+ if (i >= 0) {
+ RAND_add(temp, i, i);
+ if (i == TEMPSIZE)
+ ok++;
+ }
+ }
+# endif
-# if defined(DEVRANDOM) || (!defined(OPENSSL_NO_EGD) && defined(DEVRANDOM_EGD))
- return 1;
-# else
- return 0;
+ OPENSSL_cleanse(temp, TEMPSIZE);
+ return ok > 0 ? 1 : 0;
# endif
}
+# endif
-# endif /* defined(__OpenBSD__) */
-#endif /* !(defined(OPENSSL_SYS_WINDOWS) ||
- * defined(OPENSSL_SYS_WIN32) ||
- * defined(OPENSSL_SYS_VMS) ||
- * defined(OPENSSL_SYS_VXWORKS) */
-
-#if defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_UEFI)
-int RAND_poll(void)
-{
- return 0;
-}
#endif
diff --git a/crypto/rand/rand_vms.c b/crypto/rand/rand_vms.c
index ec99dbfe26..16afae7a2e 100644
--- a/crypto/rand/rand_vms.c
+++ b/crypto/rand/rand_vms.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2001-2017 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
@@ -21,6 +21,10 @@
# pragma message disable DOLLARID
# endif
+# ifndef OPENSSL_RAND_SEED_OS
+# error "Unsupported seeding method configured; must be os"
+# endif
+
/*
* Use 32-bit pointers almost everywhere. Define the type to which to cast a
* pointer passed to an external function.
diff --git a/crypto/rand/rand_win.c b/crypto/rand/rand_win.c
index 1be0ed3c9a..acc428640e 100644
--- a/crypto/rand/rand_win.c
+++ b/crypto/rand/rand_win.c
@@ -1,5 +1,5 @@
/*
- * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
@@ -12,13 +12,18 @@
#include "rand_lcl.h"
#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
+
+# ifndef OPENSSL_RAND_SEED_OS
+# error "Unsupported seeding method configured; must be os"
+# endif
+
# include <windows.h>
/* On Windows 7 or higher use BCrypt instead of the legacy CryptoAPI */
-# if defined(_MSC_VER) && defined(_WIN32_WINNT) && _WIN32_WINNT>=0x0601
-# define RAND_WINDOWS_USE_BCRYPT
+# if defined(_MSC_VER) && defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0601
+# define USE_BCRYPTGENRANDOM
# endif
-# ifdef RAND_WINDOWS_USE_BCRYPT
+# ifdef USE_BCRYPTGENRANDOM
# include <bcrypt.h>
# pragma comment(lib, "bcrypt.lib")
# ifndef STATUS_SUCCESS
@@ -34,52 +39,52 @@
# define INTEL_DEF_PROV L"Intel Hardware Cryptographic Service Provider"
# endif
-static void readtimer(void);
-
int RAND_poll(void)
{
- MEMORYSTATUS mst;
-# ifndef RAND_WINDOWS_USE_BCRYPT
+# ifndef USE_BCRYPTGENRANDOM
HCRYPTPROV hProvider;
# endif
DWORD w;
- BYTE buf[64];
+ BYTE buf[RANDOMNESS_NEEDED];
+ int ok = 0;
-# ifdef RAND_WINDOWS_USE_BCRYPT
- if (BCryptGenRandom(NULL, buf, (ULONG)sizeof(buf), BCRYPT_USE_SYSTEM_PREFERRED_RNG) == STATUS_SUCCESS) {
- RAND_add(buf, sizeof(buf), sizeof(buf));
- }
+# ifdef OPENSSL_RAND_SEED_RDTSC
+ rand_rdtsc();
+# endif
+# ifdef OPENSSL_RAND_SEED_RDCPU
+ if (rand_rdcpu())
+ ok++;
+# endif
+
+# ifdef USE_BCRYPTGENRANDOM
+ if (BCryptGenRandom(NULL, buf, (ULONG)sizeof(buf),
+ BCRYPT_USE_SYSTEM_PREFERRED_RNG) != STATUS_SUCCESS)
+ return 0;
+ RAND_add(buf, sizeof(buf), sizeof(buf));
+ return 1;
# else
/* poll the CryptoAPI PRNG */
- /* The CryptoAPI returns sizeof(buf) bytes of randomness */
- if (CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
+ if (CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT | CRYPT_SILENT) != 0) {
if (CryptGenRandom(hProvider, (DWORD)sizeof(buf), buf) != 0) {
RAND_add(buf, sizeof(buf), sizeof(buf));
+ ok++;
}
CryptReleaseContext(hProvider, 0);
}
/* poll the Pentium PRG with CryptoAPI */
- if (CryptAcquireContextW(&hProvider, NULL, INTEL_DEF_PROV, PROV_INTEL_SEC, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
+ if (CryptAcquireContextW(&hProvider, NULL, INTEL_DEF_PROV, PROV_INTEL_SEC,
+ CRYPT_VERIFYCONTEXT | CRYPT_SILENT) != 0) {
if (CryptGenRandom(hProvider, (DWORD)sizeof(buf), buf) != 0) {
RAND_add(buf, sizeof(buf), sizeof(buf));
+ ok++;
}
CryptReleaseContext(hProvider, 0);
}
# endif
- /* timer data */
- readtimer();
-
- /* memory usage statistics */
- GlobalMemoryStatus(&mst);
- RAND_add(&mst, sizeof(mst), 1);
-
- /* process ID */
- w = GetCurrentProcessId();
- RAND_add(&w, sizeof(w), 1);
-
- return (1);
+ return ok ? 1 : 0;
}
#if OPENSSL_API_COMPAT < 0x10100000L
@@ -95,41 +100,4 @@ void RAND_screen(void)
}
#endif
-/* feed timing information to the PRNG */
-static void readtimer(void)
-{
- DWORD w;
- LARGE_INTEGER l;
- static int have_perfc = 1;
-# if defined(_MSC_VER) && defined(_M_X86)
- static int have_tsc = 1;
- DWORD cyclecount;
-
- if (have_tsc) {
- __try {
- __asm {
- _emit 0x0f _emit 0x31 mov cyclecount, eax}
- RAND_add(&cyclecount, sizeof(cyclecount), 1);
- }
- __except(EXCEPTION_EXECUTE_HANDLER) {
- have_tsc = 0;
- }
- }
-# else
-# define have_tsc 0
-# endif
-
- if (have_perfc) {
- if (QueryPerformanceCounter(&l) == 0)
- have_perfc = 0;
- else
- RAND_add(&l, sizeof(l), 0);
- }
-
- if (!have_tsc && !have_perfc) {
- w = GetTickCount();
- RAND_add(&w, sizeof(w), 0);
- }
-}
-
#endif
diff --git a/doc/man3/RAND_add.pod b/doc/man3/RAND_add.pod
index f5514f092e..ee54390669 100644
--- a/doc/man3/RAND_add.pod
+++ b/doc/man3/RAND_add.pod
@@ -2,63 +2,76 @@
=head1 NAME
-RAND_add, RAND_seed, RAND_status, RAND_event, RAND_screen - add
-randomness to the PRNG
+RAND_add, RAND_poll, RAND_seed, RAND_status, RAND_event, RAND_screen
+- add randomness to the PRNG or get its status
=head1 SYNOPSIS
#include <openssl/rand.h>
- void RAND_seed(const void *buf, int num);
+ int RAND_status(void);
+ int RAND_poll()
void RAND_add(const void *buf, int num, double randomness);
+ void RAND_seed(const void *buf, int num);
- int RAND_status(void);
+Deprecated:
#if OPENSSL_API_COMPAT < 0x10100000L
- int RAND_event(UINT iMsg, WPARAM wParam, LPARAM lParam);
+ int RAND_event(UINT iMsg, WPARAM wParam, LPARAM lParam);
void RAND_screen(void);
#endif
=head1 DESCRIPTION
-RAND_add() mixes the B<num> bytes at B<buf> into the PRNG state. Thus,
-if the data at B<buf> are unpredictable to an adversary, this
-increases the uncertainty about the state and makes the PRNG output
-less predictable. Suitable input comes from user interaction (random
-key presses, mouse movements) and certain hardware events. The
-B<randomness> argument is an estimate of how much randomness is contained in
+Random numbers are a vital part of cryptography, including key generation,
+creating salts, etc., and software-based
+generators must be "seeded" with external randomness before they can be
+used as a cryptographically-secure pseudo-random number generator (CSPRNG).
+The availability of common hardware with special instructions and
+modern operating systems, which may use items such as interrupt jitter
+and network packet timings, can be reasonable sources of seeding material.
+
+RAND_status() indicates whether or not the CSPRNG has been sufficiently
+seeded. If not, functions such as RAND_bytes(3) will fail.
+
+RAND_poll() uses the current capabilities to seed the CSPRNG. The
+exact features used depends on how OpenSSL was configured, and can
+be displayed with the OpenSSL L<version(1)> command. This function is
+normally called automatically during OpenSSL initialization, but
+can be called by the application to reseed the CSPRNG.
+
+RAND_add() mixes the B<num> bytes at B<buf> into the PRNG state.
+The B<randomness> argument is an estimate of how much randomness is
+contained in
B<buf>, in bytes, and should be a number between zero and B<num>.
Details about sources of randomness and how to estimate their randomness
-can be found in the literature; for example IETF RFC 4086.
-
-RAND_add() may be called with sensitive data such as user entered
-passwords. The seed values cannot be recovered from the PRNG output.
+can be found in the literature; for example NIST SP 800-90B.
+The content of B<buf> cannot be recovered from subsequent CSPRNG output.
+This function will not normally be needed, as RAND_poll() should have been
+configured to do the appropriate seeding for the local platform.
+Applications that need to keep random state in an external file should
+use L<RAND_load_file(3)>.
RAND_seed() is equivalent to RAND_add() with B<randomness> set to B<num>.
-On systems that provide C</dev/urandom> or similar source of randomess,
-it will be used
-to seed the PRNG transparently. On older systems, however, it might
-be necessary to use RAND_add(), L<RAND_egd(3)> or L<RAND_load_file(3)>.
-
-RAND_event() and RAND_screen() are deprecated and should not be called.
+RAND_event() and RAND_screen() are equivalent to RAND_poll().
=head1 RETURN VALUES
-RAND_status() returns 1 if the PRNG has been seeded
+RAND_status() returns 1 if the CSPRNG has been seeded
with enough data, 0 otherwise.
-RAND_event() calls RAND_poll() and returns RAND_status().
+RAND_poll() returns 1 if it generated seed data, 0 otherwise.
-RAND_screen calls RAND_poll().
+RAND_event() returns RAND_status().
The other functions do not return values.
=head1 HISTORY
-RAND_event() and RAND_screen() are deprecated since OpenSSL
-1.1.0. Use the functions described above instead.
+RAND_event() and RAND_screen() were deprecated in OpenSSL 1.1.0 and should
+not be used.
=head1 SEE ALSO
diff --git a/doc/man3/RAND_load_file.pod b/doc/man3/RAND_load_file.pod
index 8907bdc77c..3cb7084862 100644
--- a/doc/man3/RAND_load_file.pod
+++ b/doc/man3/RAND_load_file.pod
@@ -20,8 +20,12 @@ RAND_load_file() reads a number of bytes from file B<filename> and
adds them to the PRNG. If B<max_bytes> is non-negative,
up to B<max_bytes> are read;
if B<max_bytes> is -1, the complete file is read.
+Do not load the same file multiple times unless its contents have
+been updated by RAND_write_file() between reads.
+Also, note that B<filename> should be adequately protected so that an
+attacker cannot replace or examine the contents.
-RAND_write_file() writes a number of random bytes (currently 256) to
+RAND_write_file() writes a number of random bytes (currently 128) to
file B<filename> which can be used to initialize the PRNG by calling
RAND_load_file() in a later session.
@@ -56,8 +60,8 @@ B<num> is too small for the path name, an error occurs.
RAND_load_file() returns the number of bytes read.
-RAND_write_file() returns the number of bytes written, and -1 if the
-bytes written were generated without appropriate seed.
+RAND_write_file() returns the number of bytes written, or -1 if the
+bytes written were generated without appropriate seeding.
RAND_file_name() returns a pointer to B<buf> on success, and NULL on
error.