1109998Smarkm/* crypto/rand/rand_unix.c */ 2109998Smarkm/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3109998Smarkm * All rights reserved. 4109998Smarkm * 5109998Smarkm * This package is an SSL implementation written 6109998Smarkm * by Eric Young (eay@cryptsoft.com). 7109998Smarkm * The implementation was written so as to conform with Netscapes SSL. 8296465Sdelphij * 9109998Smarkm * This library is free for commercial and non-commercial use as long as 10109998Smarkm * the following conditions are aheared to. The following conditions 11109998Smarkm * apply to all code found in this distribution, be it the RC4, RSA, 12109998Smarkm * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13109998Smarkm * included with this distribution is covered by the same copyright terms 14109998Smarkm * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15296465Sdelphij * 16109998Smarkm * Copyright remains Eric Young's, and as such any Copyright notices in 17109998Smarkm * the code are not to be removed. 18109998Smarkm * If this package is used in a product, Eric Young should be given attribution 19109998Smarkm * as the author of the parts of the library used. 20109998Smarkm * This can be in the form of a textual message at program startup or 21109998Smarkm * in documentation (online or textual) provided with the package. 22296465Sdelphij * 23109998Smarkm * Redistribution and use in source and binary forms, with or without 24109998Smarkm * modification, are permitted provided that the following conditions 25109998Smarkm * are met: 26109998Smarkm * 1. Redistributions of source code must retain the copyright 27109998Smarkm * notice, this list of conditions and the following disclaimer. 28109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright 29109998Smarkm * notice, this list of conditions and the following disclaimer in the 30109998Smarkm * documentation and/or other materials provided with the distribution. 31109998Smarkm * 3. All advertising materials mentioning features or use of this software 32109998Smarkm * must display the following acknowledgement: 33109998Smarkm * "This product includes cryptographic software written by 34109998Smarkm * Eric Young (eay@cryptsoft.com)" 35109998Smarkm * The word 'cryptographic' can be left out if the rouines from the library 36109998Smarkm * being used are not cryptographic related :-). 37296465Sdelphij * 4. If you include any Windows specific code (or a derivative thereof) from 38109998Smarkm * the apps directory (application code) you must include an acknowledgement: 39109998Smarkm * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40296465Sdelphij * 41109998Smarkm * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42109998Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44109998Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45109998Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46109998Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47109998Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49109998Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50109998Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51109998Smarkm * SUCH DAMAGE. 52296465Sdelphij * 53109998Smarkm * The licence and distribution terms for any publically available version or 54109998Smarkm * derivative of this code cannot be changed. i.e. this code cannot simply be 55109998Smarkm * copied and put under another distribution licence 56109998Smarkm * [including the GNU Public Licence.] 57109998Smarkm */ 58109998Smarkm/* ==================================================================== 59162911Ssimon * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. 60109998Smarkm * 61109998Smarkm * Redistribution and use in source and binary forms, with or without 62109998Smarkm * modification, are permitted provided that the following conditions 63109998Smarkm * are met: 64109998Smarkm * 65109998Smarkm * 1. Redistributions of source code must retain the above copyright 66296465Sdelphij * notice, this list of conditions and the following disclaimer. 67109998Smarkm * 68109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright 69109998Smarkm * notice, this list of conditions and the following disclaimer in 70109998Smarkm * the documentation and/or other materials provided with the 71109998Smarkm * distribution. 72109998Smarkm * 73109998Smarkm * 3. All advertising materials mentioning features or use of this 74109998Smarkm * software must display the following acknowledgment: 75109998Smarkm * "This product includes software developed by the OpenSSL Project 76109998Smarkm * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 77109998Smarkm * 78109998Smarkm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 79109998Smarkm * endorse or promote products derived from this software without 80109998Smarkm * prior written permission. For written permission, please contact 81109998Smarkm * openssl-core@openssl.org. 82109998Smarkm * 83109998Smarkm * 5. Products derived from this software may not be called "OpenSSL" 84109998Smarkm * nor may "OpenSSL" appear in their names without prior written 85109998Smarkm * permission of the OpenSSL Project. 86109998Smarkm * 87109998Smarkm * 6. Redistributions of any form whatsoever must retain the following 88109998Smarkm * acknowledgment: 89109998Smarkm * "This product includes software developed by the OpenSSL Project 90109998Smarkm * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 91109998Smarkm * 92109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 93109998Smarkm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 94109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 95109998Smarkm * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 96109998Smarkm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 97109998Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 98109998Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 99109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 100109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 101109998Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 102109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 103109998Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE. 104109998Smarkm * ==================================================================== 105109998Smarkm * 106109998Smarkm * This product includes cryptographic software written by Eric Young 107109998Smarkm * (eay@cryptsoft.com). This product includes software written by Tim 108109998Smarkm * Hudson (tjh@cryptsoft.com). 109109998Smarkm * 110109998Smarkm */ 111160814Ssimon#include <stdio.h> 112109998Smarkm 113109998Smarkm#define USE_SOCKETS 114109998Smarkm#include "e_os.h" 115109998Smarkm#include "cryptlib.h" 116109998Smarkm#include <openssl/rand.h> 117109998Smarkm#include "rand_lcl.h" 118109998Smarkm 119162911Ssimon#if !(defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_OS2) || defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_NETWARE)) 120109998Smarkm 121296465Sdelphij# include <sys/types.h> 122296465Sdelphij# include <sys/time.h> 123296465Sdelphij# include <sys/times.h> 124296465Sdelphij# include <sys/stat.h> 125296465Sdelphij# include <fcntl.h> 126296465Sdelphij# include <unistd.h> 127296465Sdelphij# include <time.h> 128296465Sdelphij# if defined(OPENSSL_SYS_LINUX) /* should actually be available virtually 129296465Sdelphij * everywhere */ 130296465Sdelphij# include <poll.h> 131296465Sdelphij# endif 132296465Sdelphij# include <limits.h> 133296465Sdelphij# ifndef FD_SETSIZE 134296465Sdelphij# define FD_SETSIZE (8*sizeof(fd_set)) 135296465Sdelphij# endif 136109998Smarkm 137296465Sdelphij# ifdef __OpenBSD__ 138109998Smarkmint RAND_poll(void) 139109998Smarkm{ 140296465Sdelphij u_int32_t rnd = 0, i; 141296465Sdelphij unsigned char buf[ENTROPY_NEEDED]; 142127128Snectar 143296465Sdelphij for (i = 0; i < sizeof(buf); i++) { 144296465Sdelphij if (i % 4 == 0) 145296465Sdelphij rnd = arc4random(); 146296465Sdelphij buf[i] = rnd; 147296465Sdelphij rnd >>= 8; 148296465Sdelphij } 149296465Sdelphij RAND_add(buf, sizeof(buf), ENTROPY_NEEDED); 150296465Sdelphij memset(buf, 0, sizeof(buf)); 151127128Snectar 152296465Sdelphij return 1; 153127128Snectar} 154296465Sdelphij# else /* !defined(__OpenBSD__) */ 155127128Snectarint RAND_poll(void) 156127128Snectar{ 157296465Sdelphij unsigned long l; 158296465Sdelphij pid_t curr_pid = getpid(); 159296465Sdelphij# if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 160296465Sdelphij unsigned char tmpbuf[ENTROPY_NEEDED]; 161296465Sdelphij int n = 0; 162296465Sdelphij# endif 163296465Sdelphij# ifdef DEVRANDOM 164296465Sdelphij static const char *randomfiles[] = { DEVRANDOM }; 165296465Sdelphij struct stat randomstats[sizeof(randomfiles) / sizeof(randomfiles[0])]; 166296465Sdelphij int fd; 167296465Sdelphij size_t i; 168296465Sdelphij# endif 169296465Sdelphij# ifdef DEVRANDOM_EGD 170296465Sdelphij static const char *egdsockets[] = { DEVRANDOM_EGD, NULL }; 171296465Sdelphij const char **egdsocket = NULL; 172296465Sdelphij# endif 173109998Smarkm 174296465Sdelphij# ifdef DEVRANDOM 175296465Sdelphij memset(randomstats, 0, sizeof(randomstats)); 176296465Sdelphij /* 177296465Sdelphij * Use a random entropy pool device. Linux, FreeBSD and OpenBSD have 178296465Sdelphij * this. Use /dev/urandom if you can as /dev/random may block if it runs 179296465Sdelphij * out of random entries. 180296465Sdelphij */ 181109998Smarkm 182296465Sdelphij for (i = 0; i < sizeof(randomfiles) / sizeof(randomfiles[0]) 183296465Sdelphij && n < ENTROPY_NEEDED; i++) { 184296465Sdelphij if ((fd = open(randomfiles[i], O_RDONLY 185296465Sdelphij# ifdef O_NONBLOCK 186296465Sdelphij | O_NONBLOCK 187296465Sdelphij# endif 188296465Sdelphij# ifdef O_BINARY 189296465Sdelphij | O_BINARY 190296465Sdelphij# endif 191296465Sdelphij# ifdef O_NOCTTY /* If it happens to be a TTY (god forbid), do 192296465Sdelphij * not make it our controlling tty */ 193296465Sdelphij | O_NOCTTY 194296465Sdelphij# endif 195296465Sdelphij )) >= 0) { 196296465Sdelphij int usec = 10 * 1000; /* spend 10ms on each file */ 197296465Sdelphij int r; 198296465Sdelphij size_t j; 199296465Sdelphij struct stat *st = &randomstats[i]; 200109998Smarkm 201296465Sdelphij /* 202296465Sdelphij * Avoid using same input... Used to be O_NOFOLLOW above, but 203296465Sdelphij * it's not universally appropriate... 204296465Sdelphij */ 205296465Sdelphij if (fstat(fd, st) != 0) { 206296465Sdelphij close(fd); 207296465Sdelphij continue; 208296465Sdelphij } 209296465Sdelphij for (j = 0; j < i; j++) { 210296465Sdelphij if (randomstats[j].st_ino == st->st_ino && 211296465Sdelphij randomstats[j].st_dev == st->st_dev) 212296465Sdelphij break; 213296465Sdelphij } 214296465Sdelphij if (j < i) { 215296465Sdelphij close(fd); 216296465Sdelphij continue; 217296465Sdelphij } 218160814Ssimon 219296465Sdelphij do { 220296465Sdelphij int try_read = 0; 221109998Smarkm 222296465Sdelphij# if defined(OPENSSL_SYS_LINUX) 223296465Sdelphij /* use poll() */ 224296465Sdelphij struct pollfd pset; 225162911Ssimon 226296465Sdelphij pset.fd = fd; 227296465Sdelphij pset.events = POLLIN; 228296465Sdelphij pset.revents = 0; 229162911Ssimon 230296465Sdelphij if (poll(&pset, 1, usec / 1000) < 0) 231296465Sdelphij usec = 0; 232296465Sdelphij else 233296465Sdelphij try_read = (pset.revents & POLLIN) != 0; 234162911Ssimon 235296465Sdelphij# else 236296465Sdelphij /* use select() */ 237296465Sdelphij fd_set fset; 238296465Sdelphij struct timeval t; 239109998Smarkm 240296465Sdelphij t.tv_sec = 0; 241296465Sdelphij t.tv_usec = usec; 242109998Smarkm 243296465Sdelphij if (FD_SETSIZE > 0 && (unsigned)fd >= FD_SETSIZE) { 244296465Sdelphij /* 245296465Sdelphij * can't use select, so just try to read once anyway 246296465Sdelphij */ 247296465Sdelphij try_read = 1; 248296465Sdelphij } else { 249296465Sdelphij FD_ZERO(&fset); 250296465Sdelphij FD_SET(fd, &fset); 251109998Smarkm 252296465Sdelphij if (select(fd + 1, &fset, NULL, NULL, &t) >= 0) { 253296465Sdelphij usec = t.tv_usec; 254296465Sdelphij if (FD_ISSET(fd, &fset)) 255296465Sdelphij try_read = 1; 256296465Sdelphij } else 257296465Sdelphij usec = 0; 258296465Sdelphij } 259296465Sdelphij# endif 260109998Smarkm 261296465Sdelphij if (try_read) { 262296465Sdelphij r = read(fd, (unsigned char *)tmpbuf + n, 263296465Sdelphij ENTROPY_NEEDED - n); 264296465Sdelphij if (r > 0) 265296465Sdelphij n += r; 266296465Sdelphij } else 267296465Sdelphij r = -1; 268109998Smarkm 269296465Sdelphij /* 270296465Sdelphij * Some Unixen will update t in select(), some won't. For 271296465Sdelphij * those who won't, or if we didn't use select() in the first 272296465Sdelphij * place, give up here, otherwise, we will do this once again 273296465Sdelphij * for the remaining time. 274296465Sdelphij */ 275296465Sdelphij if (usec == 10 * 1000) 276296465Sdelphij usec = 0; 277296465Sdelphij } 278296465Sdelphij while ((r > 0 || 279296465Sdelphij (errno == EINTR || errno == EAGAIN)) && usec != 0 280296465Sdelphij && n < ENTROPY_NEEDED); 281109998Smarkm 282296465Sdelphij close(fd); 283296465Sdelphij } 284296465Sdelphij } 285296465Sdelphij# endif /* defined(DEVRANDOM) */ 286109998Smarkm 287296465Sdelphij# ifdef DEVRANDOM_EGD 288296465Sdelphij /* 289296465Sdelphij * Use an EGD socket to read entropy from an EGD or PRNGD entropy 290296465Sdelphij * collecting daemon. 291296465Sdelphij */ 292109998Smarkm 293296465Sdelphij for (egdsocket = egdsockets; *egdsocket && n < ENTROPY_NEEDED; 294296465Sdelphij egdsocket++) { 295296465Sdelphij int r; 296296465Sdelphij 297296465Sdelphij r = RAND_query_egd_bytes(*egdsocket, (unsigned char *)tmpbuf + n, 298296465Sdelphij ENTROPY_NEEDED - n); 299296465Sdelphij if (r > 0) 300296465Sdelphij n += r; 301296465Sdelphij } 302296465Sdelphij# endif /* defined(DEVRANDOM_EGD) */ 303296465Sdelphij 304296465Sdelphij# if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 305296465Sdelphij if (n > 0) { 306296465Sdelphij RAND_add(tmpbuf, sizeof tmpbuf, (double)n); 307296465Sdelphij OPENSSL_cleanse(tmpbuf, n); 308296465Sdelphij } 309296465Sdelphij# endif 310296465Sdelphij 311296465Sdelphij /* put in some default random data, we need more than just this */ 312296465Sdelphij l = curr_pid; 313296465Sdelphij RAND_add(&l, sizeof(l), 0.0); 314296465Sdelphij l = getuid(); 315296465Sdelphij RAND_add(&l, sizeof(l), 0.0); 316296465Sdelphij 317296465Sdelphij l = time(NULL); 318296465Sdelphij RAND_add(&l, sizeof(l), 0.0); 319296465Sdelphij 320296465Sdelphij# if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 321296465Sdelphij return 1; 322296465Sdelphij# else 323296465Sdelphij return 0; 324296465Sdelphij# endif 325109998Smarkm} 326109998Smarkm 327296465Sdelphij# endif /* defined(__OpenBSD__) */ 328296465Sdelphij#endif /* !(defined(OPENSSL_SYS_WINDOWS) || 329296465Sdelphij * defined(OPENSSL_SYS_WIN32) || 330296465Sdelphij * defined(OPENSSL_SYS_VMS) || 331296465Sdelphij * defined(OPENSSL_SYS_OS2) || 332296465Sdelphij * defined(OPENSSL_SYS_VXWORKS) || 333296465Sdelphij * defined(OPENSSL_SYS_NETWARE)) */ 334109998Smarkm 335109998Smarkm#if defined(OPENSSL_SYS_VXWORKS) 336109998Smarkmint RAND_poll(void) 337296465Sdelphij{ 338296465Sdelphij return 0; 339296465Sdelphij} 340109998Smarkm#endif 341