diff options
Diffstat (limited to 'crypto/rand/rand_unix.c')
-rw-r--r-- | crypto/rand/rand_unix.c | 292 |
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 |