rand_unix.c revision 194206
1/* crypto/rand/rand_unix.c */ 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay@cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58/* ==================================================================== 59 * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. 60 * 61 * Redistribution and use in source and binary forms, with or without 62 * modification, are permitted provided that the following conditions 63 * are met: 64 * 65 * 1. Redistributions of source code must retain the above copyright 66 * notice, this list of conditions and the following disclaimer. 67 * 68 * 2. Redistributions in binary form must reproduce the above copyright 69 * notice, this list of conditions and the following disclaimer in 70 * the documentation and/or other materials provided with the 71 * distribution. 72 * 73 * 3. All advertising materials mentioning features or use of this 74 * software must display the following acknowledgment: 75 * "This product includes software developed by the OpenSSL Project 76 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 77 * 78 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 79 * endorse or promote products derived from this software without 80 * prior written permission. For written permission, please contact 81 * openssl-core@openssl.org. 82 * 83 * 5. Products derived from this software may not be called "OpenSSL" 84 * nor may "OpenSSL" appear in their names without prior written 85 * permission of the OpenSSL Project. 86 * 87 * 6. Redistributions of any form whatsoever must retain the following 88 * acknowledgment: 89 * "This product includes software developed by the OpenSSL Project 90 * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 91 * 92 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 93 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 94 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 95 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 96 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 97 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 98 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 99 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 100 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 101 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 102 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 103 * OF THE POSSIBILITY OF SUCH DAMAGE. 104 * ==================================================================== 105 * 106 * This product includes cryptographic software written by Eric Young 107 * (eay@cryptsoft.com). This product includes software written by Tim 108 * Hudson (tjh@cryptsoft.com). 109 * 110 */ 111#include <stdio.h> 112 113#define USE_SOCKETS 114#include "e_os.h" 115#include "cryptlib.h" 116#include <openssl/rand.h> 117#include "rand_lcl.h" 118 119#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)) 120 121#include <sys/types.h> 122#include <sys/time.h> 123#include <sys/times.h> 124#include <sys/stat.h> 125#include <fcntl.h> 126#include <unistd.h> 127#include <time.h> 128#if defined(OPENSSL_SYS_LINUX) /* should actually be available virtually everywhere */ 129# include <poll.h> 130#endif 131#include <limits.h> 132#ifndef FD_SETSIZE 133# define FD_SETSIZE (8*sizeof(fd_set)) 134#endif 135 136#ifdef __OpenBSD__ 137int RAND_poll(void) 138{ 139 u_int32_t rnd = 0, i; 140 unsigned char buf[ENTROPY_NEEDED]; 141 142 for (i = 0; i < sizeof(buf); i++) { 143 if (i % 4 == 0) 144 rnd = arc4random(); 145 buf[i] = rnd; 146 rnd >>= 8; 147 } 148 RAND_add(buf, sizeof(buf), ENTROPY_NEEDED); 149 memset(buf, 0, sizeof(buf)); 150 151 return 1; 152} 153#else /* !defined(__OpenBSD__) */ 154int RAND_poll(void) 155{ 156 unsigned long l; 157 pid_t curr_pid = getpid(); 158#if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 159 unsigned char tmpbuf[ENTROPY_NEEDED]; 160 int n = 0; 161#endif 162#ifdef DEVRANDOM 163 static const char *randomfiles[] = { DEVRANDOM }; 164 struct stat randomstats[sizeof(randomfiles)/sizeof(randomfiles[0])]; 165 int fd; 166 size_t i; 167#endif 168#ifdef DEVRANDOM_EGD 169 static const char *egdsockets[] = { DEVRANDOM_EGD, NULL }; 170 const char **egdsocket = NULL; 171#endif 172 173#ifdef DEVRANDOM 174 memset(randomstats,0,sizeof(randomstats)); 175 /* Use a random entropy pool device. Linux, FreeBSD and OpenBSD 176 * have this. Use /dev/urandom if you can as /dev/random may block 177 * if it runs out of random entries. */ 178 179 for (i=0; i<sizeof(randomfiles)/sizeof(randomfiles[0]) && n < ENTROPY_NEEDED; i++) 180 { 181 if ((fd = open(randomfiles[i], O_RDONLY 182#ifdef O_NONBLOCK 183 |O_NONBLOCK 184#endif 185#ifdef O_BINARY 186 |O_BINARY 187#endif 188#ifdef O_NOCTTY /* If it happens to be a TTY (god forbid), do not make it 189 our controlling tty */ 190 |O_NOCTTY 191#endif 192 )) >= 0) 193 { 194 int usec = 10*1000; /* spend 10ms on each file */ 195 int r; 196 size_t j; 197 struct stat *st=&randomstats[i]; 198 199 /* Avoid using same input... Used to be O_NOFOLLOW 200 * above, but it's not universally appropriate... */ 201 if (fstat(fd,st) != 0) { close(fd); continue; } 202 for (j=0;j<i;j++) 203 { 204 if (randomstats[j].st_ino==st->st_ino && 205 randomstats[j].st_dev==st->st_dev) 206 break; 207 } 208 if (j<i) { close(fd); continue; } 209 210 do 211 { 212 int try_read = 0; 213 214#if defined(OPENSSL_SYS_LINUX) 215 /* use poll() */ 216 struct pollfd pset; 217 218 pset.fd = fd; 219 pset.events = POLLIN; 220 pset.revents = 0; 221 222 if (poll(&pset, 1, usec / 1000) < 0) 223 usec = 0; 224 else 225 try_read = (pset.revents & POLLIN) != 0; 226 227#else 228 /* use select() */ 229 fd_set fset; 230 struct timeval t; 231 232 t.tv_sec = 0; 233 t.tv_usec = usec; 234 235 if (FD_SETSIZE > 0 && (unsigned)fd >= FD_SETSIZE) 236 { 237 /* can't use select, so just try to read once anyway */ 238 try_read = 1; 239 } 240 else 241 { 242 FD_ZERO(&fset); 243 FD_SET(fd, &fset); 244 245 if (select(fd+1,&fset,NULL,NULL,&t) >= 0) 246 { 247 usec = t.tv_usec; 248 if (FD_ISSET(fd, &fset)) 249 try_read = 1; 250 } 251 else 252 usec = 0; 253 } 254#endif 255 256 if (try_read) 257 { 258 r = read(fd,(unsigned char *)tmpbuf+n, ENTROPY_NEEDED-n); 259 if (r > 0) 260 n += r; 261 } 262 else 263 r = -1; 264 265 /* Some Unixen will update t in select(), some 266 won't. For those who won't, or if we 267 didn't use select() in the first place, 268 give up here, otherwise, we will do 269 this once again for the remaining 270 time. */ 271 if (usec == 10*1000) 272 usec = 0; 273 } 274 while ((r > 0 || 275 (errno == EINTR || errno == EAGAIN)) && usec != 0 && n < ENTROPY_NEEDED); 276 277 close(fd); 278 } 279 } 280#endif /* defined(DEVRANDOM) */ 281 282#ifdef DEVRANDOM_EGD 283 /* Use an EGD socket to read entropy from an EGD or PRNGD entropy 284 * collecting daemon. */ 285 286 for (egdsocket = egdsockets; *egdsocket && n < ENTROPY_NEEDED; egdsocket++) 287 { 288 int r; 289 290 r = RAND_query_egd_bytes(*egdsocket, (unsigned char *)tmpbuf+n, 291 ENTROPY_NEEDED-n); 292 if (r > 0) 293 n += r; 294 } 295#endif /* defined(DEVRANDOM_EGD) */ 296 297#if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 298 if (n > 0) 299 { 300 RAND_add(tmpbuf,sizeof tmpbuf,(double)n); 301 OPENSSL_cleanse(tmpbuf,n); 302 } 303#endif 304 305 /* put in some default random data, we need more than just this */ 306 l=curr_pid; 307 RAND_add(&l,sizeof(l),0.0); 308 l=getuid(); 309 RAND_add(&l,sizeof(l),0.0); 310 311 l=time(NULL); 312 RAND_add(&l,sizeof(l),0.0); 313 314#if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 315 return 1; 316#else 317 return 0; 318#endif 319} 320 321#endif /* defined(__OpenBSD__) */ 322#endif /* !(defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_OS2) || defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_NETWARE)) */ 323 324 325#if defined(OPENSSL_SYS_VXWORKS) 326int RAND_poll(void) 327 { 328 return 0; 329 } 330#endif 331