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. 8280297Sjkim * 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). 15280297Sjkim * 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. 22280297Sjkim * 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 :-). 37280297Sjkim * 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)" 40280297Sjkim * 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. 52280297Sjkim * 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 66280297Sjkim * 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 121280297Sjkim# include <sys/types.h> 122280297Sjkim# include <sys/time.h> 123280297Sjkim# include <sys/times.h> 124280297Sjkim# include <sys/stat.h> 125280297Sjkim# include <fcntl.h> 126280297Sjkim# include <unistd.h> 127280297Sjkim# include <time.h> 128280297Sjkim# if defined(OPENSSL_SYS_LINUX) /* should actually be available virtually 129280297Sjkim * everywhere */ 130280297Sjkim# include <poll.h> 131280297Sjkim# endif 132280297Sjkim# include <limits.h> 133280297Sjkim# ifndef FD_SETSIZE 134280297Sjkim# define FD_SETSIZE (8*sizeof(fd_set)) 135280297Sjkim# endif 136109998Smarkm 137280297Sjkim# if defined(OPENSSL_SYS_VOS) 138238405Sjkim 139280297Sjkim/* 140280297Sjkim * The following algorithm repeatedly samples the real-time clock (RTC) to 141280297Sjkim * generate a sequence of unpredictable data. The algorithm relies upon the 142280297Sjkim * uneven execution speed of the code (due to factors such as cache misses, 143280297Sjkim * interrupts, bus activity, and scheduling) and upon the rather large 144280297Sjkim * relative difference between the speed of the clock and the rate at which 145280297Sjkim * it can be read. 146280297Sjkim * 147280297Sjkim * If this code is ported to an environment where execution speed is more 148280297Sjkim * constant or where the RTC ticks at a much slower rate, or the clock can be 149280297Sjkim * read with fewer instructions, it is likely that the results would be far 150280297Sjkim * more predictable. 151280297Sjkim * 152280297Sjkim * As a precaution, we generate 4 times the minimum required amount of seed 153280297Sjkim * data. 154280297Sjkim */ 155238405Sjkim 156109998Smarkmint RAND_poll(void) 157109998Smarkm{ 158280297Sjkim short int code; 159280297Sjkim gid_t curr_gid; 160280297Sjkim pid_t curr_pid; 161280297Sjkim uid_t curr_uid; 162280297Sjkim int i, k; 163280297Sjkim struct timespec ts; 164280297Sjkim unsigned char v; 165238405Sjkim 166280297Sjkim# ifdef OPENSSL_SYS_VOS_HPPA 167280297Sjkim long duration; 168280297Sjkim extern void s$sleep(long *_duration, short int *_code); 169280297Sjkim# else 170280297Sjkim# ifdef OPENSSL_SYS_VOS_IA32 171280297Sjkim long long duration; 172280297Sjkim extern void s$sleep2(long long *_duration, short int *_code); 173280297Sjkim# else 174280297Sjkim# error "Unsupported Platform." 175280297Sjkim# endif /* OPENSSL_SYS_VOS_IA32 */ 176280297Sjkim# endif /* OPENSSL_SYS_VOS_HPPA */ 177238405Sjkim 178280297Sjkim /* 179280297Sjkim * Seed with the gid, pid, and uid, to ensure *some* variation between 180280297Sjkim * different processes. 181280297Sjkim */ 182238405Sjkim 183280297Sjkim curr_gid = getgid(); 184331638Sjkim RAND_add(&curr_gid, sizeof(curr_gid), 1); 185280297Sjkim curr_gid = 0; 186238405Sjkim 187280297Sjkim curr_pid = getpid(); 188331638Sjkim RAND_add(&curr_pid, sizeof(curr_pid), 1); 189280297Sjkim curr_pid = 0; 190238405Sjkim 191280297Sjkim curr_uid = getuid(); 192331638Sjkim RAND_add(&curr_uid, sizeof(curr_uid), 1); 193280297Sjkim curr_uid = 0; 194238405Sjkim 195280297Sjkim for (i = 0; i < (ENTROPY_NEEDED * 4); i++) { 196280297Sjkim /* 197280297Sjkim * burn some cpu; hope for interrupts, cache collisions, bus 198280297Sjkim * interference, etc. 199280297Sjkim */ 200280297Sjkim for (k = 0; k < 99; k++) 201280297Sjkim ts.tv_nsec = random(); 202238405Sjkim 203280297Sjkim# ifdef OPENSSL_SYS_VOS_HPPA 204280297Sjkim /* sleep for 1/1024 of a second (976 us). */ 205280297Sjkim duration = 1; 206280297Sjkim s$sleep(&duration, &code); 207280297Sjkim# else 208280297Sjkim# ifdef OPENSSL_SYS_VOS_IA32 209280297Sjkim /* sleep for 1/65536 of a second (15 us). */ 210280297Sjkim duration = 1; 211280297Sjkim s$sleep2(&duration, &code); 212280297Sjkim# endif /* OPENSSL_SYS_VOS_IA32 */ 213280297Sjkim# endif /* OPENSSL_SYS_VOS_HPPA */ 214238405Sjkim 215280297Sjkim /* get wall clock time. */ 216280297Sjkim clock_gettime(CLOCK_REALTIME, &ts); 217238405Sjkim 218280297Sjkim /* take 8 bits */ 219280297Sjkim v = (unsigned char)(ts.tv_nsec % 256); 220331638Sjkim RAND_add(&v, sizeof(v), 1); 221280297Sjkim v = 0; 222280297Sjkim } 223280297Sjkim return 1; 224238405Sjkim} 225280297Sjkim# elif defined(__FreeBSD__) || defined(__OpenBSD__) 226238405Sjkimint RAND_poll(void) 227238405Sjkim{ 228280297Sjkim u_int32_t rnd = 0, i; 229280297Sjkim unsigned char buf[ENTROPY_NEEDED]; 230127128Snectar 231280297Sjkim for (i = 0; i < sizeof(buf); i++) { 232280297Sjkim if (i % 4 == 0) 233280297Sjkim rnd = arc4random(); 234280297Sjkim buf[i] = rnd; 235280297Sjkim rnd >>= 8; 236280297Sjkim } 237280297Sjkim RAND_add(buf, sizeof(buf), ENTROPY_NEEDED); 238306195Sjkim OPENSSL_cleanse(buf, sizeof(buf)); 239127128Snectar 240280297Sjkim return 1; 241127128Snectar} 242280297Sjkim# else /* !(defined(__FreeBSD__) || 243280297Sjkim * defined(__OpenBSD__)) */ 244127128Snectarint RAND_poll(void) 245127128Snectar{ 246280297Sjkim unsigned long l; 247280297Sjkim pid_t curr_pid = getpid(); 248280297Sjkim# if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 249280297Sjkim unsigned char tmpbuf[ENTROPY_NEEDED]; 250280297Sjkim int n = 0; 251280297Sjkim# endif 252280297Sjkim# ifdef DEVRANDOM 253280297Sjkim static const char *randomfiles[] = { DEVRANDOM }; 254280297Sjkim struct stat randomstats[sizeof(randomfiles) / sizeof(randomfiles[0])]; 255280297Sjkim int fd; 256280297Sjkim unsigned int i; 257280297Sjkim# endif 258280297Sjkim# ifdef DEVRANDOM_EGD 259280297Sjkim static const char *egdsockets[] = { DEVRANDOM_EGD, NULL }; 260280297Sjkim const char **egdsocket = NULL; 261280297Sjkim# endif 262109998Smarkm 263280297Sjkim# ifdef DEVRANDOM 264280297Sjkim memset(randomstats, 0, sizeof(randomstats)); 265280297Sjkim /* 266280297Sjkim * Use a random entropy pool device. Linux, FreeBSD and OpenBSD have 267280297Sjkim * this. Use /dev/urandom if you can as /dev/random may block if it runs 268280297Sjkim * out of random entries. 269280297Sjkim */ 270109998Smarkm 271280297Sjkim for (i = 0; (i < sizeof(randomfiles) / sizeof(randomfiles[0])) && 272280297Sjkim (n < ENTROPY_NEEDED); i++) { 273280297Sjkim if ((fd = open(randomfiles[i], O_RDONLY 274280297Sjkim# ifdef O_NONBLOCK 275280297Sjkim | O_NONBLOCK 276280297Sjkim# endif 277280297Sjkim# ifdef O_BINARY 278280297Sjkim | O_BINARY 279280297Sjkim# endif 280280297Sjkim# ifdef O_NOCTTY /* If it happens to be a TTY (god forbid), do 281280297Sjkim * not make it our controlling tty */ 282280297Sjkim | O_NOCTTY 283280297Sjkim# endif 284280297Sjkim )) >= 0) { 285280297Sjkim int usec = 10 * 1000; /* spend 10ms on each file */ 286280297Sjkim int r; 287280297Sjkim unsigned int j; 288280297Sjkim struct stat *st = &randomstats[i]; 289109998Smarkm 290280297Sjkim /* 291280297Sjkim * Avoid using same input... Used to be O_NOFOLLOW above, but 292280297Sjkim * it's not universally appropriate... 293280297Sjkim */ 294280297Sjkim if (fstat(fd, st) != 0) { 295280297Sjkim close(fd); 296280297Sjkim continue; 297280297Sjkim } 298280297Sjkim for (j = 0; j < i; j++) { 299280297Sjkim if (randomstats[j].st_ino == st->st_ino && 300280297Sjkim randomstats[j].st_dev == st->st_dev) 301280297Sjkim break; 302280297Sjkim } 303280297Sjkim if (j < i) { 304280297Sjkim close(fd); 305280297Sjkim continue; 306280297Sjkim } 307160814Ssimon 308280297Sjkim do { 309280297Sjkim int try_read = 0; 310109998Smarkm 311280297Sjkim# if defined(OPENSSL_SYS_BEOS_R5) 312280297Sjkim /* 313280297Sjkim * select() is broken in BeOS R5, so we simply try to read 314280297Sjkim * something and snooze if we couldn't 315280297Sjkim */ 316280297Sjkim try_read = 1; 317238405Sjkim 318280297Sjkim# elif defined(OPENSSL_SYS_LINUX) 319280297Sjkim /* use poll() */ 320280297Sjkim struct pollfd pset; 321162911Ssimon 322280297Sjkim pset.fd = fd; 323280297Sjkim pset.events = POLLIN; 324280297Sjkim pset.revents = 0; 325162911Ssimon 326280297Sjkim if (poll(&pset, 1, usec / 1000) < 0) 327280297Sjkim usec = 0; 328280297Sjkim else 329280297Sjkim try_read = (pset.revents & POLLIN) != 0; 330162911Ssimon 331280297Sjkim# else 332280297Sjkim /* use select() */ 333280297Sjkim fd_set fset; 334280297Sjkim struct timeval t; 335109998Smarkm 336280297Sjkim t.tv_sec = 0; 337280297Sjkim t.tv_usec = usec; 338109998Smarkm 339280297Sjkim if (FD_SETSIZE > 0 && (unsigned)fd >= FD_SETSIZE) { 340280297Sjkim /* 341280297Sjkim * can't use select, so just try to read once anyway 342280297Sjkim */ 343280297Sjkim try_read = 1; 344280297Sjkim } else { 345280297Sjkim FD_ZERO(&fset); 346280297Sjkim FD_SET(fd, &fset); 347109998Smarkm 348280297Sjkim if (select(fd + 1, &fset, NULL, NULL, &t) >= 0) { 349280297Sjkim usec = t.tv_usec; 350280297Sjkim if (FD_ISSET(fd, &fset)) 351280297Sjkim try_read = 1; 352280297Sjkim } else 353280297Sjkim usec = 0; 354280297Sjkim } 355280297Sjkim# endif 356109998Smarkm 357280297Sjkim if (try_read) { 358280297Sjkim r = read(fd, (unsigned char *)tmpbuf + n, 359280297Sjkim ENTROPY_NEEDED - n); 360280297Sjkim if (r > 0) 361280297Sjkim n += r; 362280297Sjkim# if defined(OPENSSL_SYS_BEOS_R5) 363280297Sjkim if (r == 0) 364280297Sjkim snooze(t.tv_usec); 365280297Sjkim# endif 366280297Sjkim } else 367280297Sjkim r = -1; 368109998Smarkm 369280297Sjkim /* 370280297Sjkim * Some Unixen will update t in select(), some won't. For 371280297Sjkim * those who won't, or if we didn't use select() in the first 372280297Sjkim * place, give up here, otherwise, we will do this once again 373280297Sjkim * for the remaining time. 374280297Sjkim */ 375280297Sjkim if (usec == 10 * 1000) 376280297Sjkim usec = 0; 377280297Sjkim } 378280297Sjkim while ((r > 0 || 379280297Sjkim (errno == EINTR || errno == EAGAIN)) && usec != 0 380280297Sjkim && n < ENTROPY_NEEDED); 381109998Smarkm 382280297Sjkim close(fd); 383280297Sjkim } 384280297Sjkim } 385280297Sjkim# endif /* defined(DEVRANDOM) */ 386109998Smarkm 387280297Sjkim# ifdef DEVRANDOM_EGD 388280297Sjkim /* 389280297Sjkim * Use an EGD socket to read entropy from an EGD or PRNGD entropy 390280297Sjkim * collecting daemon. 391280297Sjkim */ 392109998Smarkm 393280297Sjkim for (egdsocket = egdsockets; *egdsocket && n < ENTROPY_NEEDED; 394280297Sjkim egdsocket++) { 395280297Sjkim int r; 396238405Sjkim 397280297Sjkim r = RAND_query_egd_bytes(*egdsocket, (unsigned char *)tmpbuf + n, 398280297Sjkim ENTROPY_NEEDED - n); 399280297Sjkim if (r > 0) 400280297Sjkim n += r; 401280297Sjkim } 402280297Sjkim# endif /* defined(DEVRANDOM_EGD) */ 403280297Sjkim 404280297Sjkim# if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 405280297Sjkim if (n > 0) { 406331638Sjkim RAND_add(tmpbuf, sizeof(tmpbuf), (double)n); 407280297Sjkim OPENSSL_cleanse(tmpbuf, n); 408280297Sjkim } 409280297Sjkim# endif 410280297Sjkim 411280297Sjkim /* put in some default random data, we need more than just this */ 412280297Sjkim l = curr_pid; 413280297Sjkim RAND_add(&l, sizeof(l), 0.0); 414280297Sjkim l = getuid(); 415280297Sjkim RAND_add(&l, sizeof(l), 0.0); 416280297Sjkim 417280297Sjkim l = time(NULL); 418280297Sjkim RAND_add(&l, sizeof(l), 0.0); 419280297Sjkim 420280297Sjkim# if defined(OPENSSL_SYS_BEOS) 421280297Sjkim { 422280297Sjkim system_info sysInfo; 423280297Sjkim get_system_info(&sysInfo); 424280297Sjkim RAND_add(&sysInfo, sizeof(sysInfo), 0); 425280297Sjkim } 426280297Sjkim# endif 427280297Sjkim 428280297Sjkim# if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 429280297Sjkim return 1; 430280297Sjkim# else 431280297Sjkim return 0; 432280297Sjkim# endif 433109998Smarkm} 434109998Smarkm 435280297Sjkim# endif /* defined(__FreeBSD__) || 436280297Sjkim * defined(__OpenBSD__) */ 437280297Sjkim#endif /* !(defined(OPENSSL_SYS_WINDOWS) || 438280297Sjkim * defined(OPENSSL_SYS_WIN32) || 439280297Sjkim * defined(OPENSSL_SYS_VMS) || 440280297Sjkim * defined(OPENSSL_SYS_OS2) || 441280297Sjkim * defined(OPENSSL_SYS_VXWORKS) || 442280297Sjkim * defined(OPENSSL_SYS_NETWARE)) */ 443109998Smarkm 444109998Smarkm#if defined(OPENSSL_SYS_VXWORKS) 445109998Smarkmint RAND_poll(void) 446280297Sjkim{ 447280297Sjkim return 0; 448280297Sjkim} 449109998Smarkm#endif 450