diff options
-rwxr-xr-x | Configure | 23 | ||||
-rw-r--r-- | apps/version.c | 38 | ||||
-rw-r--r-- | crypto/rand/drbg_rand.c | 6 | ||||
-rw-r--r-- | crypto/rand/rand_lcl.h | 28 | ||||
-rw-r--r-- | crypto/rand/rand_lib.c | 64 | ||||
-rw-r--r-- | crypto/rand/rand_unix.c | 292 | ||||
-rw-r--r-- | crypto/rand/rand_vms.c | 6 | ||||
-rw-r--r-- | crypto/rand/rand_win.c | 98 | ||||
-rw-r--r-- | doc/man3/RAND_add.pod | 65 | ||||
-rw-r--r-- | doc/man3/RAND_load_file.pod | 10 |
10 files changed, 324 insertions, 306 deletions
@@ -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. |