rand_unix.c revision 296465
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 129 * everywhere */ 130# include <poll.h> 131# endif 132# include <limits.h> 133# ifndef FD_SETSIZE 134# define FD_SETSIZE (8*sizeof(fd_set)) 135# endif 136 137# ifdef __OpenBSD__ 138int RAND_poll(void) 139{ 140 u_int32_t rnd = 0, i; 141 unsigned char buf[ENTROPY_NEEDED]; 142 143 for (i = 0; i < sizeof(buf); i++) { 144 if (i % 4 == 0) 145 rnd = arc4random(); 146 buf[i] = rnd; 147 rnd >>= 8; 148 } 149 RAND_add(buf, sizeof(buf), ENTROPY_NEEDED); 150 memset(buf, 0, sizeof(buf)); 151 152 return 1; 153} 154# else /* !defined(__OpenBSD__) */ 155int RAND_poll(void) 156{ 157 unsigned long l; 158 pid_t curr_pid = getpid(); 159# if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 160 unsigned char tmpbuf[ENTROPY_NEEDED]; 161 int n = 0; 162# endif 163# ifdef DEVRANDOM 164 static const char *randomfiles[] = { DEVRANDOM }; 165 struct stat randomstats[sizeof(randomfiles) / sizeof(randomfiles[0])]; 166 int fd; 167 size_t i; 168# endif 169# ifdef DEVRANDOM_EGD 170 static const char *egdsockets[] = { DEVRANDOM_EGD, NULL }; 171 const char **egdsocket = NULL; 172# endif 173 174# ifdef DEVRANDOM 175 memset(randomstats, 0, sizeof(randomstats)); 176 /* 177 * Use a random entropy pool device. Linux, FreeBSD and OpenBSD have 178 * this. Use /dev/urandom if you can as /dev/random may block if it runs 179 * out of random entries. 180 */ 181 182 for (i = 0; i < sizeof(randomfiles) / sizeof(randomfiles[0]) 183 && n < ENTROPY_NEEDED; i++) { 184 if ((fd = open(randomfiles[i], O_RDONLY 185# ifdef O_NONBLOCK 186 | O_NONBLOCK 187# endif 188# ifdef O_BINARY 189 | O_BINARY 190# endif 191# ifdef O_NOCTTY /* If it happens to be a TTY (god forbid), do 192 * not make it our controlling tty */ 193 | O_NOCTTY 194# endif 195 )) >= 0) { 196 int usec = 10 * 1000; /* spend 10ms on each file */ 197 int r; 198 size_t j; 199 struct stat *st = &randomstats[i]; 200 201 /* 202 * Avoid using same input... Used to be O_NOFOLLOW above, but 203 * it's not universally appropriate... 204 */ 205 if (fstat(fd, st) != 0) { 206 close(fd); 207 continue; 208 } 209 for (j = 0; j < i; j++) { 210 if (randomstats[j].st_ino == st->st_ino && 211 randomstats[j].st_dev == st->st_dev) 212 break; 213 } 214 if (j < i) { 215 close(fd); 216 continue; 217 } 218 219 do { 220 int try_read = 0; 221 222# if defined(OPENSSL_SYS_LINUX) 223 /* use poll() */ 224 struct pollfd pset; 225 226 pset.fd = fd; 227 pset.events = POLLIN; 228 pset.revents = 0; 229 230 if (poll(&pset, 1, usec / 1000) < 0) 231 usec = 0; 232 else 233 try_read = (pset.revents & POLLIN) != 0; 234 235# else 236 /* use select() */ 237 fd_set fset; 238 struct timeval t; 239 240 t.tv_sec = 0; 241 t.tv_usec = usec; 242 243 if (FD_SETSIZE > 0 && (unsigned)fd >= FD_SETSIZE) { 244 /* 245 * can't use select, so just try to read once anyway 246 */ 247 try_read = 1; 248 } else { 249 FD_ZERO(&fset); 250 FD_SET(fd, &fset); 251 252 if (select(fd + 1, &fset, NULL, NULL, &t) >= 0) { 253 usec = t.tv_usec; 254 if (FD_ISSET(fd, &fset)) 255 try_read = 1; 256 } else 257 usec = 0; 258 } 259# endif 260 261 if (try_read) { 262 r = read(fd, (unsigned char *)tmpbuf + n, 263 ENTROPY_NEEDED - n); 264 if (r > 0) 265 n += r; 266 } else 267 r = -1; 268 269 /* 270 * Some Unixen will update t in select(), some won't. For 271 * those who won't, or if we didn't use select() in the first 272 * place, give up here, otherwise, we will do this once again 273 * for the remaining time. 274 */ 275 if (usec == 10 * 1000) 276 usec = 0; 277 } 278 while ((r > 0 || 279 (errno == EINTR || errno == EAGAIN)) && usec != 0 280 && n < ENTROPY_NEEDED); 281 282 close(fd); 283 } 284 } 285# endif /* defined(DEVRANDOM) */ 286 287# ifdef DEVRANDOM_EGD 288 /* 289 * Use an EGD socket to read entropy from an EGD or PRNGD entropy 290 * collecting daemon. 291 */ 292 293 for (egdsocket = egdsockets; *egdsocket && n < ENTROPY_NEEDED; 294 egdsocket++) { 295 int r; 296 297 r = RAND_query_egd_bytes(*egdsocket, (unsigned char *)tmpbuf + n, 298 ENTROPY_NEEDED - n); 299 if (r > 0) 300 n += r; 301 } 302# endif /* defined(DEVRANDOM_EGD) */ 303 304# if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 305 if (n > 0) { 306 RAND_add(tmpbuf, sizeof tmpbuf, (double)n); 307 OPENSSL_cleanse(tmpbuf, n); 308 } 309# endif 310 311 /* put in some default random data, we need more than just this */ 312 l = curr_pid; 313 RAND_add(&l, sizeof(l), 0.0); 314 l = getuid(); 315 RAND_add(&l, sizeof(l), 0.0); 316 317 l = time(NULL); 318 RAND_add(&l, sizeof(l), 0.0); 319 320# if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 321 return 1; 322# else 323 return 0; 324# endif 325} 326 327# endif /* defined(__OpenBSD__) */ 328#endif /* !(defined(OPENSSL_SYS_WINDOWS) || 329 * defined(OPENSSL_SYS_WIN32) || 330 * defined(OPENSSL_SYS_VMS) || 331 * defined(OPENSSL_SYS_OS2) || 332 * defined(OPENSSL_SYS_VXWORKS) || 333 * defined(OPENSSL_SYS_NETWARE)) */ 334 335#if defined(OPENSSL_SYS_VXWORKS) 336int RAND_poll(void) 337{ 338 return 0; 339} 340#endif 341