Add --with-rand-seed

Add a new config param to specify how the CSPRNG should be seeded.
Illegal values or nonsensical combinations (e.g., anything other
than "os" on VMS or HP VOS etc) result in build failures.
Add RDSEED support.
Add RDTSC but leave it disabled for now pending more investigation.

Refactor and reorganization all seeding files (rand_unix/win/vms) so
that they are simpler.

Only require 128 bits of seeding material.

Many document improvements, including why to not use RAND_add() and the
limitations around using load_file/write_file.
Document RAND_poll().

Cleanup Windows RAND_poll and return correct status

More completely initialize the default DRBG.

Reviewed-by: Paul Dale <paul.dale@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/3965)
This commit is contained in:
Rich Salz 2017-07-18 09:39:21 -04:00
parent 0d7903f83f
commit 8389ec4b49
10 changed files with 331 additions and 313 deletions

View File

@ -561,6 +561,9 @@ $config{build_type} = "release";
my %unsupported_options = (); my %unsupported_options = ();
my %deprecated_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) while (@argvcopy)
{ {
$_ = shift @argvcopy; $_ = shift @argvcopy;
@ -729,6 +732,15 @@ while (@argvcopy)
{ {
$withargs{fuzzer_include}=$1; $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=(.*)$/) elsif (/^--cross-compile-prefix=(.*)$/)
{ {
$config{cross_compile_prefix}=$1; $config{cross_compile_prefix}=$1;
@ -812,6 +824,17 @@ if ($libs =~ /(^|\s)-Wl,-rpath,/
"***** any of asan, msan or ubsan\n"; "***** 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); my @tocheckfor = (keys %disabled);
while (@tocheckfor) { while (@tocheckfor) {
my %new_tocheckfor = (); my %new_tocheckfor = ();

View File

@ -32,7 +32,7 @@
typedef enum OPTION_choice { typedef enum OPTION_choice {
OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, 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; } OPTION_CHOICE;
const OPTIONS version_options[] = { const OPTIONS version_options[] = {
@ -44,13 +44,14 @@ const OPTIONS version_options[] = {
{"f", OPT_F, '-', "Show compiler flags used"}, {"f", OPT_F, '-', "Show compiler flags used"},
{"o", OPT_O, '-', "Show some internal datatype options"}, {"o", OPT_O, '-', "Show some internal datatype options"},
{"p", OPT_P, '-', "Show target build platform"}, {"p", OPT_P, '-', "Show target build platform"},
{"r", OPT_R, '-', "Show random seeding options"},
{"v", OPT_V, '-', "Show library version"}, {"v", OPT_V, '-', "Show library version"},
{NULL} {NULL}
}; };
int version_main(int argc, char **argv) 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 cflags = 0, version = 0, date = 0, options = 0, platform = 0, dir = 0;
int engdir = 0; int engdir = 0;
char *prog; char *prog;
@ -85,11 +86,14 @@ int version_main(int argc, char **argv)
case OPT_P: case OPT_P:
dirty = platform = 1; dirty = platform = 1;
break; break;
case OPT_R:
dirty = seed = 1;
break;
case OPT_V: case OPT_V:
dirty = version = 1; dirty = version = 1;
break; break;
case OPT_A: case OPT_A:
cflags = version = date = platform = dir = engdir = 1; seed = cflags = version = date = platform = dir = engdir = 1;
break; break;
} }
} }
@ -133,6 +137,34 @@ int version_main(int argc, char **argv)
printf("%s\n", OpenSSL_version(OPENSSL_DIR)); printf("%s\n", OpenSSL_version(OPENSSL_DIR));
if (engdir) if (engdir)
printf("%s\n", OpenSSL_version(OPENSSL_ENGINES_DIR)); 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; ret = 0;
end: end:
return (ret); return (ret);

View File

@ -29,8 +29,12 @@ static CRYPTO_ONCE ossl_drbg_init = CRYPTO_ONCE_STATIC_INIT;
DEFINE_RUN_ONCE_STATIC(do_ossl_drbg_init) DEFINE_RUN_ONCE_STATIC(do_ossl_drbg_init)
{ {
int st = 1;
ossl_drbg.lock = CRYPTO_THREAD_lock_new(); 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) void rand_drbg_cleanup(void)

View File

@ -17,21 +17,24 @@
# include <openssl/ec.h> # include <openssl/ec.h>
# include "internal/rand.h" # include "internal/rand.h"
/* we require 256 bits of randomness */ /* Amount of randomness (in bytes) we want for initial seeding. */
# define RANDOMNESS_NEEDED (256 / 8) # define RANDOMNESS_NEEDED (128 / 8)
/* Maximum count allowed in reseeding */ /* Maximum count allowed in reseeding */
#define MAX_RESEED (1 << 24) #define MAX_RESEED (1 << 24)
/* DRBG status values */ /* DRBG status values */
#define DRBG_STATUS_UNINITIALISED 0 # define DRBG_STATUS_UNINITIALISED 0
#define DRBG_STATUS_READY 1 # define DRBG_STATUS_READY 1
#define DRBG_STATUS_RESEED 2 # define DRBG_STATUS_RESEED 2
#define DRBG_STATUS_ERROR 3 # define DRBG_STATUS_ERROR 3
/* A default maximum length: larger than any reasonable value used in pratice */ /* 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 { typedef struct drbg_ctr_ctx_st {
AES_KEY ks; AES_KEY ks;
size_t keylen; size_t keylen;
@ -46,6 +49,10 @@ typedef struct drbg_ctr_ctx_st {
unsigned char KX[48]; unsigned char KX[48];
} DRBG_CTR_CTX; } DRBG_CTR_CTX;
/*
* The context for all DRBG's
*/
struct drbg_ctx_st { struct drbg_ctx_st {
CRYPTO_RWLOCK *lock; CRYPTO_RWLOCK *lock;
DRBG_CTX *parent; DRBG_CTX *parent;
@ -84,9 +91,12 @@ struct drbg_ctx_st {
extern RAND_METHOD openssl_rand_meth; extern RAND_METHOD openssl_rand_meth;
void rand_drbg_cleanup(void); 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 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_uninstantiate(DRBG_CTX *dctx);
int ctr_instantiate(DRBG_CTX *dctx, int ctr_instantiate(DRBG_CTX *dctx,
const unsigned char *ent, size_t entlen, const unsigned char *ent, size_t entlen,

View File

@ -25,6 +25,70 @@ static CRYPTO_RWLOCK *rand_meth_lock;
static const RAND_METHOD *default_RAND_meth; static const RAND_METHOD *default_RAND_meth;
static CRYPTO_ONCE rand_init = CRYPTO_ONCE_STATIC_INIT; 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) DEFINE_RUN_ONCE_STATIC(do_rand_init)
{ {

View File

@ -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 * Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy * this file except in compliance with the License. You can obtain a copy
@ -9,32 +9,32 @@
#include <stdio.h> #include <stdio.h>
#define USE_SOCKETS
#include "e_os.h" #include "e_os.h"
#include "internal/cryptlib.h" #include "internal/cryptlib.h"
#include <openssl/rand.h> #include <openssl/rand.h>
#include "rand_lcl.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)) #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> # if (defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_UEFI)) && \
# include <sys/time.h> !defined(OPENSSL_RAND_SEED_NONE)
# include <sys/times.h> # error "UEFI and VXWorks only support seeding NONE"
# 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))
# endif # endif
# if defined(OPENSSL_SYS_VOS) # 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 * The following algorithm repeatedly samples the real-time clock (RTC) to
* generate a sequence of unpredictable data. The algorithm relies upon the * 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 * As a precaution, we generate 4 times the minimum required amount of seed
* data. * data.
*/ */
int RAND_poll(void) int RAND_poll(void)
{ {
short int code; short int code;
@ -61,35 +60,24 @@ int RAND_poll(void)
int i, k; int i, k;
struct timespec ts; struct timespec ts;
unsigned char v; unsigned char v;
# ifdef OPENSSL_SYS_VOS_HPPA # ifdef OPENSSL_SYS_VOS_HPPA
long duration; long duration;
extern void s$sleep(long *_duration, short int *_code); extern void s$sleep(long *_duration, short int *_code);
# else # else
# ifdef OPENSSL_SYS_VOS_IA32
long long duration; long long duration;
extern void s$sleep2(long long *_duration, short int *_code); extern void s$sleep2(long long *_duration, short int *_code);
# else # endif
# error "Unsupported Platform."
# endif /* OPENSSL_SYS_VOS_IA32 */
# endif /* OPENSSL_SYS_VOS_HPPA */
/* /*
* Seed with the gid, pid, and uid, to ensure *some* variation between * Seed with the gid, pid, and uid, to ensure *some* variation between
* different processes. * different processes.
*/ */
curr_gid = getgid(); curr_gid = getgid();
RAND_add(&curr_gid, sizeof curr_gid, 1); RAND_add(&curr_gid, sizeof curr_gid, 0);
curr_gid = 0;
curr_pid = getpid(); curr_pid = getpid();
RAND_add(&curr_pid, sizeof curr_pid, 1); RAND_add(&curr_pid, sizeof curr_pid, 0);
curr_pid = 0;
curr_uid = getuid(); curr_uid = getuid();
RAND_add(&curr_uid, sizeof curr_uid, 1); RAND_add(&curr_uid, sizeof curr_uid, 0);
curr_uid = 0;
for (i = 0; i < (RANDOMNESS_NEEDED * 4); i++) { for (i = 0; i < (RANDOMNESS_NEEDED * 4); i++) {
/* /*
@ -104,203 +92,111 @@ int RAND_poll(void)
duration = 1; duration = 1;
s$sleep(&duration, &code); s$sleep(&duration, &code);
# else # else
# ifdef OPENSSL_SYS_VOS_IA32
/* sleep for 1/65536 of a second (15 us). */ /* sleep for 1/65536 of a second (15 us). */
duration = 1; duration = 1;
s$sleep2(&duration, &code); s$sleep2(&duration, &code);
# endif /* OPENSSL_SYS_VOS_IA32 */ # endif
# endif /* OPENSSL_SYS_VOS_HPPA */
/* get wall clock time. */ /* Get wall clock time, take 8 bits. */
clock_gettime(CLOCK_REALTIME, &ts); clock_gettime(CLOCK_REALTIME, &ts);
v = (unsigned char)(ts.tv_nsec & 0xFF);
/* take 8 bits */
v = (unsigned char)(ts.tv_nsec % 256);
RAND_add(&v, sizeof v, 1); RAND_add(&v, sizeof v, 1);
v = 0;
} }
return 1; return 1;
} }
# else # else
# 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
# if defined(OPENSSL_RAND_SEED_DEVRANDOM) && !defined(DEVRANDOM)
# error "Seeding uses urandom but DEVRANDOM is not configured"
# endif
# if defined(OPENSSL_RAND_SEED_OS)
# if defined(DEVRANDOM)
# define OPENSSL_RAND_SEED_DEVRANDOM
# else
# error "OS seeding requires DEVRANDOM to be configured"
# endif
# endif
# if defined(OPENSSL_RAND_SEED_LIBRANDOM)
# error "librandom not (yet) supported"
# endif
int RAND_poll(void) int RAND_poll(void)
{ {
unsigned long l; # ifdef OPENSSL_RAND_SEED_NONE
pid_t curr_pid = getpid(); return 0;
# if defined(DEVRANDOM) || (!defined(OPENSS_NO_EGD) && defined(DEVRANDOM_EGD)) # else
unsigned char tmpbuf[RANDOMNESS_NEEDED]; int ok = 0;
int n = 0; char temp[RANDOMNESS_NEEDED];
# endif # define TEMPSIZE (int)sizeof(temp)
# 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;
# endif
# ifdef DEVRANDOM # ifdef OPENSSL_RAND_SEED_RDTSC
memset(randomstats, 0, sizeof(randomstats)); rand_rdtsc();
/*
* 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.
*/
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
# 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;
# else
/* use select() */
fd_set fset;
struct timeval t;
t.tv_sec = 0;
t.tv_usec = usec;
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);
if (select(fd + 1, &fset, NULL, NULL, &t) >= 0) {
usec = t.tv_usec;
if (FD_ISSET(fd, &fset))
try_read = 1;
} else
usec = 0;
}
# endif # endif
if (try_read) { # ifdef OPENSSL_RAND_SEED_RDCPU
r = read(fd, (unsigned char *)tmpbuf + n, if (rand_rdcpu())
RANDOMNESS_NEEDED - n); ok++;
if (r > 0) # endif
n += r;
} else
r = -1;
/* # ifdef OPENSSL_RAND_SEED_EGD
* 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 static const char *paths[] = { DEVRANDOM_EGD, NULL };
* place, give up here, otherwise, we will do this once again int i;
* for the remaining time.
*/ for (i = 0; paths[i] != NULL; i++) {
if (usec == 10 * 1000) if (RAND_query_egd_bytes(paths[i], temp, TEMPSIZE) == TEMPSIZE) {
usec = 0; RAND_add(temp, TEMPSIZE, TEMPSIZE);
ok++;
break;
} }
while ((r > 0 ||
(errno == EINTR || errno == EAGAIN)) && usec != 0
&& n < RANDOMNESS_NEEDED);
close(fd);
} }
} }
# endif /* defined(DEVRANDOM) */ # endif
# if !defined(OPENSSL_NO_EGD) && defined(DEVRANDOM_EGD) # ifdef OPENSSL_RAND_SEED_DEVRANDOM
/* {
* Use an EGD socket to read randomness from the daemon. static const char *paths[] = { DEVRANDOM, NULL };
*/ FILE *fp;
int i;
for (egdsocket = egdsockets; *egdsocket && n < RANDOMNESS_NEEDED; for (i = 0; paths[i] != NULL; i++) {
egdsocket++) { if ((fp = fopen(paths[i], "rb")) == NULL)
int r; continue;
setbuf(fp, NULL);
r = RAND_query_egd_bytes(*egdsocket, (unsigned char *)tmpbuf + n, if (fread(temp, 1, TEMPSIZE, fp) == TEMPSIZE) {
RANDOMNESS_NEEDED - n); RAND_add(temp, TEMPSIZE, TEMPSIZE);
if (r > 0) ok++;
n += r; fclose(fp);
break;
}
}
} }
# endif /* defined(DEVRANDOM_EGD) */ # endif
# if defined(DEVRANDOM) || (!defined(OPENSSL_NO_EGD) && defined(DEVRANDOM_EGD)) # ifdef OPENSSL_RAND_SEED_GETRANDOM
if (n > 0) { {
RAND_add(tmpbuf, sizeof tmpbuf, (double)n); int i = getrandom(temp, TEMPSIZE, 0);
OPENSSL_cleanse(tmpbuf, n);
if (i >= 0) {
RAND_add(temp, i, i);
if (i == TEMPSIZE)
ok++;
}
} }
# endif # endif
/* put in some default random data, we need more than just this */ OPENSSL_cleanse(temp, TEMPSIZE);
l = curr_pid; return ok > 0 ? 1 : 0;
RAND_add(&l, sizeof(l), 0.0);
l = getuid();
RAND_add(&l, sizeof(l), 0.0);
l = time(NULL);
RAND_add(&l, sizeof(l), 0.0);
# if defined(DEVRANDOM) || (!defined(OPENSSL_NO_EGD) && defined(DEVRANDOM_EGD))
return 1;
# else
return 0;
# endif # 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 #endif

View File

@ -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 * Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy * this file except in compliance with the License. You can obtain a copy
@ -21,6 +21,10 @@
# pragma message disable DOLLARID # pragma message disable DOLLARID
# endif # 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 * Use 32-bit pointers almost everywhere. Define the type to which to cast a
* pointer passed to an external function. * pointer passed to an external function.

View File

@ -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 * Licensed under the OpenSSL license (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy * this file except in compliance with the License. You can obtain a copy
@ -12,13 +12,18 @@
#include "rand_lcl.h" #include "rand_lcl.h"
#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
# include <windows.h>
/* On Windows 7 or higher use BCrypt instead of the legacy CryptoAPI */ # ifndef OPENSSL_RAND_SEED_OS
# if defined(_MSC_VER) && defined(_WIN32_WINNT) && _WIN32_WINNT>=0x0601 # error "Unsupported seeding method configured; must be os"
# define RAND_WINDOWS_USE_BCRYPT
# endif # endif
# ifdef RAND_WINDOWS_USE_BCRYPT # 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 USE_BCRYPTGENRANDOM
# endif
# ifdef USE_BCRYPTGENRANDOM
# include <bcrypt.h> # include <bcrypt.h>
# pragma comment(lib, "bcrypt.lib") # pragma comment(lib, "bcrypt.lib")
# ifndef STATUS_SUCCESS # ifndef STATUS_SUCCESS
@ -34,52 +39,52 @@
# define INTEL_DEF_PROV L"Intel Hardware Cryptographic Service Provider" # define INTEL_DEF_PROV L"Intel Hardware Cryptographic Service Provider"
# endif # endif
static void readtimer(void);
int RAND_poll(void) int RAND_poll(void)
{ {
MEMORYSTATUS mst; # ifndef USE_BCRYPTGENRANDOM
# ifndef RAND_WINDOWS_USE_BCRYPT
HCRYPTPROV hProvider; HCRYPTPROV hProvider;
# endif # endif
DWORD w; DWORD w;
BYTE buf[64]; BYTE buf[RANDOMNESS_NEEDED];
int ok = 0;
# ifdef RAND_WINDOWS_USE_BCRYPT # ifdef OPENSSL_RAND_SEED_RDTSC
if (BCryptGenRandom(NULL, buf, (ULONG)sizeof(buf), BCRYPT_USE_SYSTEM_PREFERRED_RNG) == STATUS_SUCCESS) { rand_rdtsc();
RAND_add(buf, sizeof(buf), sizeof(buf)); # 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 # else
/* poll the CryptoAPI PRNG */ /* poll the CryptoAPI PRNG */
/* The CryptoAPI returns sizeof(buf) bytes of randomness */ if (CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL,
if (CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { CRYPT_VERIFYCONTEXT | CRYPT_SILENT) != 0) {
if (CryptGenRandom(hProvider, (DWORD)sizeof(buf), buf) != 0) { if (CryptGenRandom(hProvider, (DWORD)sizeof(buf), buf) != 0) {
RAND_add(buf, sizeof(buf), sizeof(buf)); RAND_add(buf, sizeof(buf), sizeof(buf));
ok++;
} }
CryptReleaseContext(hProvider, 0); CryptReleaseContext(hProvider, 0);
} }
/* poll the Pentium PRG with CryptoAPI */ /* 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) { if (CryptGenRandom(hProvider, (DWORD)sizeof(buf), buf) != 0) {
RAND_add(buf, sizeof(buf), sizeof(buf)); RAND_add(buf, sizeof(buf), sizeof(buf));
ok++;
} }
CryptReleaseContext(hProvider, 0); CryptReleaseContext(hProvider, 0);
} }
# endif # endif
/* timer data */ return ok ? 1 : 0;
readtimer();
/* memory usage statistics */
GlobalMemoryStatus(&mst);
RAND_add(&mst, sizeof(mst), 1);
/* process ID */
w = GetCurrentProcessId();
RAND_add(&w, sizeof(w), 1);
return (1);
} }
#if OPENSSL_API_COMPAT < 0x10100000L #if OPENSSL_API_COMPAT < 0x10100000L
@ -95,41 +100,4 @@ void RAND_screen(void)
} }
#endif #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 #endif

View File

@ -2,63 +2,76 @@
=head1 NAME =head1 NAME
RAND_add, RAND_seed, RAND_status, RAND_event, RAND_screen - add RAND_add, RAND_poll, RAND_seed, RAND_status, RAND_event, RAND_screen
randomness to the PRNG - add randomness to the PRNG or get its status
=head1 SYNOPSIS =head1 SYNOPSIS
#include <openssl/rand.h> #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_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 #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); void RAND_screen(void);
#endif #endif
=head1 DESCRIPTION =head1 DESCRIPTION
RAND_add() mixes the B<num> bytes at B<buf> into the PRNG state. Thus, Random numbers are a vital part of cryptography, including key generation,
if the data at B<buf> are unpredictable to an adversary, this creating salts, etc., and software-based
increases the uncertainty about the state and makes the PRNG output generators must be "seeded" with external randomness before they can be
less predictable. Suitable input comes from user interaction (random used as a cryptographically-secure pseudo-random number generator (CSPRNG).
key presses, mouse movements) and certain hardware events. The The availability of common hardware with special instructions and
B<randomness> argument is an estimate of how much randomness is contained in 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>. 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 Details about sources of randomness and how to estimate their randomness
can be found in the literature; for example IETF RFC 4086. can be found in the literature; for example NIST SP 800-90B.
The content of B<buf> cannot be recovered from subsequent CSPRNG output.
RAND_add() may be called with sensitive data such as user entered This function will not normally be needed, as RAND_poll() should have been
passwords. The seed values cannot be recovered from the PRNG output. 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>. 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, RAND_event() and RAND_screen() are equivalent to RAND_poll().
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.
=head1 RETURN VALUES =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. 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. The other functions do not return values.
=head1 HISTORY =head1 HISTORY
RAND_event() and RAND_screen() are deprecated since OpenSSL RAND_event() and RAND_screen() were deprecated in OpenSSL 1.1.0 and should
1.1.0. Use the functions described above instead. not be used.
=head1 SEE ALSO =head1 SEE ALSO

View File

@ -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, adds them to the PRNG. If B<max_bytes> is non-negative,
up to B<max_bytes> are read; up to B<max_bytes> are read;
if B<max_bytes> is -1, the complete file is 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 file B<filename> which can be used to initialize the PRNG by calling
RAND_load_file() in a later session. 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_load_file() returns the number of bytes read.
RAND_write_file() returns the number of bytes written, and -1 if the RAND_write_file() returns the number of bytes written, or -1 if the
bytes written were generated without appropriate seed. bytes written were generated without appropriate seeding.
RAND_file_name() returns a pointer to B<buf> on success, and NULL on RAND_file_name() returns a pointer to B<buf> on success, and NULL on
error. error.