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