rand_unix.c revision 160814
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. 8109998Smarkm * 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). 15109998Smarkm * 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. 22109998Smarkm * 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 :-). 37109998Smarkm * 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)" 40109998Smarkm * 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. 52109998Smarkm * 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/* ==================================================================== 59109998Smarkm * Copyright (c) 1998-2000 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 66109998Smarkm * 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 119160814Ssimon#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 121109998Smarkm#include <sys/types.h> 122109998Smarkm#include <sys/time.h> 123109998Smarkm#include <sys/times.h> 124160814Ssimon#include <sys/stat.h> 125109998Smarkm#include <fcntl.h> 126109998Smarkm#include <unistd.h> 127109998Smarkm#include <time.h> 128109998Smarkm 129127128Snectar#ifdef __OpenBSD__ 130109998Smarkmint RAND_poll(void) 131109998Smarkm{ 132127128Snectar u_int32_t rnd = 0, i; 133127128Snectar unsigned char buf[ENTROPY_NEEDED]; 134127128Snectar 135127128Snectar for (i = 0; i < sizeof(buf); i++) { 136127128Snectar if (i % 4 == 0) 137127128Snectar rnd = arc4random(); 138127128Snectar buf[i] = rnd; 139127128Snectar rnd >>= 8; 140127128Snectar } 141127128Snectar RAND_add(buf, sizeof(buf), ENTROPY_NEEDED); 142127128Snectar memset(buf, 0, sizeof(buf)); 143127128Snectar 144127128Snectar return 1; 145127128Snectar} 146127128Snectar#else 147127128Snectarint RAND_poll(void) 148127128Snectar{ 149109998Smarkm unsigned long l; 150109998Smarkm pid_t curr_pid = getpid(); 151109998Smarkm#if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 152109998Smarkm unsigned char tmpbuf[ENTROPY_NEEDED]; 153109998Smarkm int n = 0; 154109998Smarkm#endif 155109998Smarkm#ifdef DEVRANDOM 156160814Ssimon static const char *randomfiles[] = { DEVRANDOM }; 157160814Ssimon struct stat randomstats[sizeof(randomfiles)/sizeof(randomfiles[0])]; 158109998Smarkm int fd; 159160814Ssimon size_t i; 160109998Smarkm#endif 161109998Smarkm#ifdef DEVRANDOM_EGD 162109998Smarkm static const char *egdsockets[] = { DEVRANDOM_EGD, NULL }; 163109998Smarkm const char **egdsocket = NULL; 164109998Smarkm#endif 165109998Smarkm 166109998Smarkm#ifdef DEVRANDOM 167160814Ssimon memset(randomstats,0,sizeof(randomstats)); 168109998Smarkm /* Use a random entropy pool device. Linux, FreeBSD and OpenBSD 169109998Smarkm * have this. Use /dev/urandom if you can as /dev/random may block 170109998Smarkm * if it runs out of random entries. */ 171109998Smarkm 172160814Ssimon for (i=0; i<sizeof(randomfiles)/sizeof(randomfiles[0]) && n < ENTROPY_NEEDED; i++) 173109998Smarkm { 174160814Ssimon if ((fd = open(randomfiles[i], O_RDONLY 175160814Ssimon#ifdef O_NONBLOCK 176160814Ssimon |O_NONBLOCK 177160814Ssimon#endif 178160814Ssimon#ifdef O_BINARY 179160814Ssimon |O_BINARY 180160814Ssimon#endif 181109998Smarkm#ifdef O_NOCTTY /* If it happens to be a TTY (god forbid), do not make it 182109998Smarkm our controlling tty */ 183109998Smarkm |O_NOCTTY 184109998Smarkm#endif 185109998Smarkm )) >= 0) 186109998Smarkm { 187109998Smarkm struct timeval t = { 0, 10*1000 }; /* Spend 10ms on 188109998Smarkm each file. */ 189109998Smarkm int r; 190160814Ssimon size_t j; 191109998Smarkm fd_set fset; 192160814Ssimon struct stat *st=&randomstats[i]; 193109998Smarkm 194160814Ssimon /* Avoid using same input... Used to be O_NOFOLLOW 195160814Ssimon * above, but it's not universally appropriate... */ 196160814Ssimon if (fstat(fd,st) != 0) { close(fd); continue; } 197160814Ssimon for (j=0;j<i;j++) 198160814Ssimon { 199160814Ssimon if (randomstats[j].st_ino==st->st_ino && 200160814Ssimon randomstats[j].st_dev==st->st_dev) 201160814Ssimon break; 202160814Ssimon } 203160814Ssimon if (j<i) { close(fd); continue; } 204160814Ssimon 205109998Smarkm do 206109998Smarkm { 207109998Smarkm FD_ZERO(&fset); 208109998Smarkm FD_SET(fd, &fset); 209109998Smarkm r = -1; 210109998Smarkm 211109998Smarkm if (select(fd+1,&fset,NULL,NULL,&t) < 0) 212109998Smarkm t.tv_usec=0; 213109998Smarkm else if (FD_ISSET(fd, &fset)) 214109998Smarkm { 215109998Smarkm r=read(fd,(unsigned char *)tmpbuf+n, 216109998Smarkm ENTROPY_NEEDED-n); 217109998Smarkm if (r > 0) 218109998Smarkm n += r; 219109998Smarkm } 220109998Smarkm 221109998Smarkm /* Some Unixen will update t, some 222109998Smarkm won't. For those who won't, give 223109998Smarkm up here, otherwise, we will do 224109998Smarkm this once again for the remaining 225109998Smarkm time. */ 226109998Smarkm if (t.tv_usec == 10*1000) 227109998Smarkm t.tv_usec=0; 228109998Smarkm } 229109998Smarkm while ((r > 0 || (errno == EINTR || errno == EAGAIN)) 230109998Smarkm && t.tv_usec != 0 && n < ENTROPY_NEEDED); 231109998Smarkm 232109998Smarkm close(fd); 233109998Smarkm } 234109998Smarkm } 235109998Smarkm#endif 236109998Smarkm 237109998Smarkm#ifdef DEVRANDOM_EGD 238109998Smarkm /* Use an EGD socket to read entropy from an EGD or PRNGD entropy 239109998Smarkm * collecting daemon. */ 240109998Smarkm 241109998Smarkm for (egdsocket = egdsockets; *egdsocket && n < ENTROPY_NEEDED; egdsocket++) 242109998Smarkm { 243109998Smarkm int r; 244109998Smarkm 245109998Smarkm r = RAND_query_egd_bytes(*egdsocket, (unsigned char *)tmpbuf+n, 246109998Smarkm ENTROPY_NEEDED-n); 247109998Smarkm if (r > 0) 248109998Smarkm n += r; 249109998Smarkm } 250109998Smarkm#endif 251109998Smarkm 252109998Smarkm#if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 253109998Smarkm if (n > 0) 254109998Smarkm { 255160814Ssimon RAND_add(tmpbuf,sizeof tmpbuf,(double)n); 256109998Smarkm OPENSSL_cleanse(tmpbuf,n); 257109998Smarkm } 258109998Smarkm#endif 259109998Smarkm 260109998Smarkm /* put in some default random data, we need more than just this */ 261109998Smarkm l=curr_pid; 262160814Ssimon RAND_add(&l,sizeof(l),0.0); 263109998Smarkm l=getuid(); 264160814Ssimon RAND_add(&l,sizeof(l),0.0); 265109998Smarkm 266109998Smarkm l=time(NULL); 267160814Ssimon RAND_add(&l,sizeof(l),0.0); 268109998Smarkm 269109998Smarkm#if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 270109998Smarkm return 1; 271109998Smarkm#else 272109998Smarkm return 0; 273109998Smarkm#endif 274109998Smarkm} 275109998Smarkm 276109998Smarkm#endif 277127128Snectar#endif 278109998Smarkm 279109998Smarkm#if defined(OPENSSL_SYS_VXWORKS) 280109998Smarkmint RAND_poll(void) 281109998Smarkm{ 282109998Smarkm return 0; 283109998Smarkm} 284109998Smarkm#endif 285