summaryrefslogtreecommitdiffstats
path: root/crypto/rand/rand_unix.c
diff options
context:
space:
mode:
authorRich Salz <rsalz@openssl.org>2017-07-18 09:39:21 -0400
committerRich Salz <rsalz@openssl.org>2017-07-22 14:00:07 -0400
commit8389ec4b4950b9474e72a959eb0b0a6ce77ac1e8 (patch)
tree433fb30336963d2bd5a8cd7bb87a4dba32313f92 /crypto/rand/rand_unix.c
parent0d7903f83f84bba1d29225efd999c633a0c5ba01 (diff)
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)
Diffstat (limited to 'crypto/rand/rand_unix.c')
-rw-r--r--crypto/rand/rand_unix.c292
1 files changed, 94 insertions, 198 deletions
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