/*
- * 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
#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
* uneven execution speed of the code (due to factors such as cache misses,
* interrupts, bus activity, and scheduling) and upon the rather large
* relative difference between the speed of the clock and the rate at which
- * it can be read.
+ * it can be read. If it is ported to an environment where execution speed
+ * is more constant or where the RTC ticks at a much slower rate, or the
+ * clock can be read with fewer instructions, it is likely that the results
+ * would be far more predictable. This should only be used for legacy
+ * platforms.
*
- * If this code is ported to an environment where execution speed is more
- * constant or where the RTC ticks at a much slower rate, or the clock can be
- * read with fewer instructions, it is likely that the results would be far
- * more predictable.
- *
- * As a precaution, we generate 4 times the minimum required amount of seed
+ * As a precaution, we generate four times the required amount of seed
* data.
*/
-
-int RAND_poll(void)
+int RAND_poll_ex(RAND_poll_cb rand_add, void *arg)
{
short int code;
gid_t curr_gid;
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(arg, &curr_gid, sizeof curr_gid, 0);
curr_pid = getpid();
- RAND_add(&curr_pid, sizeof curr_pid, 1);
- curr_pid = 0;
-
+ rand_add(arg, &curr_pid, sizeof curr_pid, 0);
curr_uid = getuid();
- RAND_add(&curr_uid, sizeof curr_uid, 1);
- curr_uid = 0;
+ rand_add(arg, &curr_uid, sizeof curr_uid, 0);
for (i = 0; i < (RANDOMNESS_NEEDED * 4); i++) {
/*
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);
- RAND_add(&v, sizeof v, 1);
- v = 0;
+ v = (unsigned char)(ts.tv_nsec & 0xFF);
+ rand_add(arg, &v, sizeof v, 1);
}
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;
-# 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.
- */
-
- 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;
+# else
- pset.fd = fd;
- pset.events = POLLIN;
- pset.revents = 0;
+# 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 (poll(&pset, 1, usec / 1000) < 0)
- usec = 0;
- else
- try_read = (pset.revents & POLLIN) != 0;
+# 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
- /* use select() */
- fd_set fset;
- struct timeval t;
+# error "OS seeding requires DEVRANDOM to be configured"
+# endif
+# endif
- t.tv_sec = 0;
- t.tv_usec = usec;
+# if defined(OPENSSL_RAND_SEED_LIBRANDOM)
+# error "librandom not (yet) supported"
+# endif
- 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);
+/*
+ * Try the various seeding methods in turn, exit when succesful.
+ */
+int RAND_poll_ex(RAND_poll_cb rand_add, void *arg)
+{
+# ifdef OPENSSL_RAND_SEED_NONE
+ return 0;
+# else
+ int ok = 1;
+ char temp[RANDOMNESS_NEEDED];
+# define TEMPSIZE (int)sizeof(temp)
+
+# ifdef OPENSSL_RAND_SEED_GETRANDOM
+ {
+ int i = getrandom(temp, TEMPSIZE, 0);
+
+ if (i >= 0) {
+ rand_add(arg, temp, i, i);
+ if (i == TEMPSIZE)
+ goto done;
+ }
+ }
+# 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;
- }
+# if defined(OPENSSL_RAND_SEED_LIBRANDOM)
+ {
+ /* Not yet implemented. */
+ }
# 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_DEVRANDOM
+ {
+ static const char *paths[] = { DEVRANDOM, NULL };
+ FILE *fp;
+ 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 ((fp = fopen(paths[i], "rb")) == NULL)
+ continue;
+ setbuf(fp, NULL);
+ if (fread(temp, 1, TEMPSIZE, fp) == TEMPSIZE) {
+ rand_add(arg, temp, TEMPSIZE, TEMPSIZE);
+ fclose(fp);
+ goto done;
}
- while ((r > 0 ||
- (errno == EINTR || errno == EAGAIN)) && usec != 0
- && n < RANDOMNESS_NEEDED);
-
- close(fd);
+ fclose(fp);
}
}
-# endif /* defined(DEVRANDOM) */
+# endif
-# if !defined(OPENSSL_NO_EGD) && defined(DEVRANDOM_EGD)
- /*
- * Use an EGD socket to read randomness from the daemon.
- */
+# ifdef OPENSSL_RAND_SEED_RDTSC
+ rand_read_tsc(cb, arg);
+# endif
- for (egdsocket = egdsockets; *egdsocket && n < RANDOMNESS_NEEDED;
- egdsocket++) {
- int r;
+# ifdef OPENSSL_RAND_SEED_RDCPU
+ if (rand_read_cpu(cb, arg))
+ goto done;
+# 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_EGD
+ {
+ static const char *paths[] = { DEVRANDOM_EGD, NULL };
+ 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 (RAND_query_egd_bytes(paths[i], temp, TEMPSIZE) == TEMPSIZE) {
+ rand_add(arg, temp, TEMPSIZE, TEMPSIZE);
+ goto done;
+ }
+ }
}
-# 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);
+# endif
- l = time(NULL);
- RAND_add(&l, sizeof(l), 0.0);
+ ok = 0;
-# if defined(DEVRANDOM) || (!defined(OPENSSL_NO_EGD) && defined(DEVRANDOM_EGD))
- return 1;
-# else
- return 0;
+done:
+ OPENSSL_cleanse(temp, TEMPSIZE);
+ return ok;
# 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