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# if defined(OPENSSL_SYS_VOS) 138 139/* 140 * The following algorithm repeatedly samples the real-time clock (RTC) to 141 * generate a sequence of unpredictable data. The algorithm relies upon the 142 * uneven execution speed of the code (due to factors such as cache misses, 143 * interrupts, bus activity, and scheduling) and upon the rather large 144 * relative difference between the speed of the clock and the rate at which 145 * it can be read. 146 * 147 * If this code is ported to an environment where execution speed is more 148 * constant or where the RTC ticks at a much slower rate, or the clock can be 149 * read with fewer instructions, it is likely that the results would be far 150 * more predictable. 151 * 152 * As a precaution, we generate 4 times the minimum required amount of seed 153 * data. 154 */ 155 156int RAND_poll(void) 157{ 158 short int code; 159 gid_t curr_gid; 160 pid_t curr_pid; 161 uid_t curr_uid; 162 int i, k; 163 struct timespec ts; 164 unsigned char v; 165 166# ifdef OPENSSL_SYS_VOS_HPPA 167 long duration; 168 extern void s$sleep(long *_duration, short int *_code); 169# else 170# ifdef OPENSSL_SYS_VOS_IA32 171 long long duration; 172 extern void s$sleep2(long long *_duration, short int *_code); 173# else 174# error "Unsupported Platform." 175# endif /* OPENSSL_SYS_VOS_IA32 */ 176# endif /* OPENSSL_SYS_VOS_HPPA */ 177 178 /* 179 * Seed with the gid, pid, and uid, to ensure *some* variation between 180 * different processes. 181 */ 182 183 curr_gid = getgid(); 184 RAND_add(&curr_gid, sizeof curr_gid, 1); 185 curr_gid = 0; 186 187 curr_pid = getpid(); 188 RAND_add(&curr_pid, sizeof curr_pid, 1); 189 curr_pid = 0; 190 191 curr_uid = getuid(); 192 RAND_add(&curr_uid, sizeof curr_uid, 1); 193 curr_uid = 0; 194 195 for (i = 0; i < (ENTROPY_NEEDED * 4); i++) { 196 /* 197 * burn some cpu; hope for interrupts, cache collisions, bus 198 * interference, etc. 199 */ 200 for (k = 0; k < 99; k++) 201 ts.tv_nsec = random(); 202 203# ifdef OPENSSL_SYS_VOS_HPPA 204 /* sleep for 1/1024 of a second (976 us). */ 205 duration = 1; 206 s$sleep(&duration, &code); 207# else 208# ifdef OPENSSL_SYS_VOS_IA32 209 /* sleep for 1/65536 of a second (15 us). */ 210 duration = 1; 211 s$sleep2(&duration, &code); 212# endif /* OPENSSL_SYS_VOS_IA32 */ 213# endif /* OPENSSL_SYS_VOS_HPPA */ 214 215 /* get wall clock time. */ 216 clock_gettime(CLOCK_REALTIME, &ts); 217 218 /* take 8 bits */ 219 v = (unsigned char)(ts.tv_nsec % 256); 220 RAND_add(&v, sizeof v, 1); 221 v = 0; 222 } 223 return 1; 224} 225# elif defined __OpenBSD__ 226int RAND_poll(void) 227{ 228 u_int32_t rnd = 0, i; 229 unsigned char buf[ENTROPY_NEEDED]; 230 231 for (i = 0; i < sizeof(buf); i++) { 232 if (i % 4 == 0) 233 rnd = arc4random(); 234 buf[i] = rnd; 235 rnd >>= 8; 236 } 237 RAND_add(buf, sizeof(buf), ENTROPY_NEEDED); 238 memset(buf, 0, sizeof(buf)); 239 240 return 1; 241} 242# else /* !defined(__OpenBSD__) */ 243int RAND_poll(void) 244{ 245 unsigned long l; 246 pid_t curr_pid = getpid(); 247# if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 248 unsigned char tmpbuf[ENTROPY_NEEDED]; 249 int n = 0; 250# endif 251# ifdef DEVRANDOM 252 static const char *randomfiles[] = { DEVRANDOM }; 253 struct stat randomstats[sizeof(randomfiles) / sizeof(randomfiles[0])]; 254 int fd; 255 unsigned int i; 256# endif 257# ifdef DEVRANDOM_EGD 258 static const char *egdsockets[] = { DEVRANDOM_EGD, NULL }; 259 const char **egdsocket = NULL; 260# endif 261 262# ifdef DEVRANDOM 263 memset(randomstats, 0, sizeof(randomstats)); 264 /* 265 * Use a random entropy pool device. Linux, FreeBSD and OpenBSD have 266 * this. Use /dev/urandom if you can as /dev/random may block if it runs 267 * out of random entries. 268 */ 269 270 for (i = 0; (i < sizeof(randomfiles) / sizeof(randomfiles[0])) && 271 (n < ENTROPY_NEEDED); i++) { 272 if ((fd = open(randomfiles[i], O_RDONLY 273# ifdef O_NONBLOCK 274 | O_NONBLOCK 275# endif 276# ifdef O_BINARY 277 | O_BINARY 278# endif 279# ifdef O_NOCTTY /* If it happens to be a TTY (god forbid), do 280 * not make it our controlling tty */ 281 | O_NOCTTY 282# endif 283 )) >= 0) { 284 int usec = 10 * 1000; /* spend 10ms on each file */ 285 int r; 286 unsigned int j; 287 struct stat *st = &randomstats[i]; 288 289 /* 290 * Avoid using same input... Used to be O_NOFOLLOW above, but 291 * it's not universally appropriate... 292 */ 293 if (fstat(fd, st) != 0) { 294 close(fd); 295 continue; 296 } 297 for (j = 0; j < i; j++) { 298 if (randomstats[j].st_ino == st->st_ino && 299 randomstats[j].st_dev == st->st_dev) 300 break; 301 } 302 if (j < i) { 303 close(fd); 304 continue; 305 } 306 307 do { 308 int try_read = 0; 309 310# if defined(OPENSSL_SYS_BEOS_R5) 311 /* 312 * select() is broken in BeOS R5, so we simply try to read 313 * something and snooze if we couldn't 314 */ 315 try_read = 1; 316 317# elif defined(OPENSSL_SYS_LINUX) 318 /* use poll() */ 319 struct pollfd pset; 320 321 pset.fd = fd; 322 pset.events = POLLIN; 323 pset.revents = 0; 324 325 if (poll(&pset, 1, usec / 1000) < 0) 326 usec = 0; 327 else 328 try_read = (pset.revents & POLLIN) != 0; 329 330# else 331 /* use select() */ 332 fd_set fset; 333 struct timeval t; 334 335 t.tv_sec = 0; 336 t.tv_usec = usec; 337 338 if (FD_SETSIZE > 0 && (unsigned)fd >= FD_SETSIZE) { 339 /* 340 * can't use select, so just try to read once anyway 341 */ 342 try_read = 1; 343 } else { 344 FD_ZERO(&fset); 345 FD_SET(fd, &fset); 346 347 if (select(fd + 1, &fset, NULL, NULL, &t) >= 0) { 348 usec = t.tv_usec; 349 if (FD_ISSET(fd, &fset)) 350 try_read = 1; 351 } else 352 usec = 0; 353 } 354# endif 355 356 if (try_read) { 357 r = read(fd, (unsigned char *)tmpbuf + n, 358 ENTROPY_NEEDED - n); 359 if (r > 0) 360 n += r; 361# if defined(OPENSSL_SYS_BEOS_R5) 362 if (r == 0) 363 snooze(t.tv_usec); 364# endif 365 } else 366 r = -1; 367 368 /* 369 * Some Unixen will update t in select(), some won't. For 370 * those who won't, or if we didn't use select() in the first 371 * place, give up here, otherwise, we will do this once again 372 * for the remaining time. 373 */ 374 if (usec == 10 * 1000) 375 usec = 0; 376 } 377 while ((r > 0 || 378 (errno == EINTR || errno == EAGAIN)) && usec != 0 379 && n < ENTROPY_NEEDED); 380 381 close(fd); 382 } 383 } 384# endif /* defined(DEVRANDOM) */ 385 386# ifdef DEVRANDOM_EGD 387 /* 388 * Use an EGD socket to read entropy from an EGD or PRNGD entropy 389 * collecting daemon. 390 */ 391 392 for (egdsocket = egdsockets; *egdsocket && n < ENTROPY_NEEDED; 393 egdsocket++) { 394 int r; 395 396 r = RAND_query_egd_bytes(*egdsocket, (unsigned char *)tmpbuf + n, 397 ENTROPY_NEEDED - n); 398 if (r > 0) 399 n += r; 400 } 401# endif /* defined(DEVRANDOM_EGD) */ 402 403# if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 404 if (n > 0) { 405 RAND_add(tmpbuf, sizeof tmpbuf, (double)n); 406 OPENSSL_cleanse(tmpbuf, n); 407 } 408# endif 409 410 /* put in some default random data, we need more than just this */ 411 l = curr_pid; 412 RAND_add(&l, sizeof(l), 0.0); 413 l = getuid(); 414 RAND_add(&l, sizeof(l), 0.0); 415 416 l = time(NULL); 417 RAND_add(&l, sizeof(l), 0.0); 418 419# if defined(OPENSSL_SYS_BEOS) 420 { 421 system_info sysInfo; 422 get_system_info(&sysInfo); 423 RAND_add(&sysInfo, sizeof(sysInfo), 0); 424 } 425# endif 426 427# if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 428 return 1; 429# else 430 return 0; 431# endif 432} 433 434# endif /* defined(__OpenBSD__) */ 435#endif /* !(defined(OPENSSL_SYS_WINDOWS) || 436 * defined(OPENSSL_SYS_WIN32) || 437 * defined(OPENSSL_SYS_VMS) || 438 * defined(OPENSSL_SYS_OS2) || 439 * defined(OPENSSL_SYS_VXWORKS) || 440 * defined(OPENSSL_SYS_NETWARE)) */ 441 442#if defined(OPENSSL_SYS_VXWORKS) 443int RAND_poll(void) 444{ 445 return 0; 446} 447#endif 448