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) || defined(__NetBSD__) /* 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 153 int 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__ 220 int RAND_poll(void) 221 { 222 u_int32_t rnd = 0, i; 223 unsigned char buf[ENTROPY_NEEDED]; 224 225 /* 226 * XXX is this really a good idea? It has the seemingly 227 * XXX very undesirable eventual result of keying the CTR_DRBG 228 * XXX generator exclusively with key material produced by 229 * XXX the libc arc4random(). It also guarantees that even 230 * XXX if the generator tries to use RAND_poll() to rekey 231 * XXX itself after a call to fork() etc, it will end up with 232 * XXX the same state, since the libc arc4 state will be the same 233 * XXX unless explicitly updated by the application. 234 */ 235 for (i = 0; i < sizeof(buf); i++) { 236 if (i % 4 == 0) 237 rnd = arc4random(); 238 buf[i] = rnd; 239 rnd >>= 8; 240 } 241 RAND_add(buf, sizeof(buf), ENTROPY_NEEDED); 242 memset(buf, 0, sizeof(buf)); 243 244 return 1; 245 } 246 #else /* !defined(__OpenBSD__) */ 247 int RAND_poll(void) 248 { 249 unsigned long l; 250 pid_t curr_pid = getpid(); 251 #if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 252 unsigned char tmpbuf[ENTROPY_NEEDED]; 253 int n = 0; 254 #endif 255 #ifdef DEVRANDOM 256 static const char *randomfiles[] = { DEVRANDOM }; 257 struct stat randomstats[sizeof(randomfiles)/sizeof(randomfiles[0])]; 258 int fd; 259 unsigned int i; 260 #endif 261 #ifdef DEVRANDOM_EGD 262 static const char *egdsockets[] = { DEVRANDOM_EGD, NULL }; 263 const char **egdsocket = NULL; 264 #endif 265 266 #ifdef DEVRANDOM 267 memset(randomstats,0,sizeof(randomstats)); 268 /* Use a random entropy pool device. Linux, FreeBSD and OpenBSD 269 * have this. Use /dev/urandom if you can as /dev/random may block 270 * if it runs out of random entries. */ 271 272 for (i = 0; (i < sizeof(randomfiles)/sizeof(randomfiles[0])) && 273 (n < ENTROPY_NEEDED); i++) 274 { 275 if ((fd = open(randomfiles[i], O_RDONLY 276 #ifdef O_NONBLOCK 277 |O_NONBLOCK 278 #endif 279 #ifdef O_BINARY 280 |O_BINARY 281 #endif 282 #ifdef O_NOCTTY /* If it happens to be a TTY (god forbid), do not make it 283 our controlling tty */ 284 |O_NOCTTY 285 #endif 286 )) >= 0) 287 { 288 int usec = 10*1000; /* spend 10ms on each file */ 289 int r; 290 unsigned int j; 291 struct stat *st=&randomstats[i]; 292 293 /* Avoid using same input... Used to be O_NOFOLLOW 294 * above, but it's not universally appropriate... */ 295 if (fstat(fd,st) != 0) { close(fd); continue; } 296 for (j=0;j<i;j++) 297 { 298 if (randomstats[j].st_ino==st->st_ino && 299 randomstats[j].st_dev==st->st_dev) 300 break; 301 } 302 if (j<i) { close(fd); continue; } 303 304 do 305 { 306 int try_read = 0; 307 308 #if defined(OPENSSL_SYS_BEOS_R5) 309 /* select() is broken in BeOS R5, so we simply 310 * try to read something and snooze if we couldn't */ 311 try_read = 1; 312 313 #elif defined(OPENSSL_SYS_LINUX) || defined(__NetBSD__) 314 /* use poll() */ 315 struct pollfd pset; 316 317 pset.fd = fd; 318 pset.events = POLLIN; 319 pset.revents = 0; 320 321 if (poll(&pset, 1, usec / 1000) < 0) 322 usec = 0; 323 else 324 try_read = (pset.revents & POLLIN) != 0; 325 326 #else 327 /* use select() */ 328 fd_set fset; 329 struct timeval t; 330 331 t.tv_sec = 0; 332 t.tv_usec = usec; 333 334 if (FD_SETSIZE > 0 && (unsigned)fd >= FD_SETSIZE) 335 { 336 /* can't use select, so just try to read once anyway */ 337 try_read = 1; 338 } 339 else 340 { 341 FD_ZERO(&fset); 342 FD_SET(fd, &fset); 343 344 if (select(fd+1,&fset,NULL,NULL,&t) >= 0) 345 { 346 usec = t.tv_usec; 347 if (FD_ISSET(fd, &fset)) 348 try_read = 1; 349 } 350 else 351 usec = 0; 352 } 353 #endif 354 355 if (try_read) 356 { 357 r = read(fd,(unsigned char *)tmpbuf+n, ENTROPY_NEEDED-n); 358 if (r > 0) 359 n += r; 360 #if defined(OPENSSL_SYS_BEOS_R5) 361 if (r == 0) 362 snooze(t.tv_usec); 363 #endif 364 } 365 else 366 r = -1; 367 368 /* Some Unixen will update t in select(), some 369 won't. For those who won't, or if we 370 didn't use select() in the first place, 371 give up here, otherwise, we will do 372 this once again for the remaining 373 time. */ 374 if (usec == 10*1000) 375 usec = 0; 376 } 377 while ((r > 0 || 378 (errno == EINTR || errno == EAGAIN)) && usec != 0 && n < ENTROPY_NEEDED); 379 380 close(fd); 381 } 382 } 383 #endif /* defined(DEVRANDOM) */ 384 385 #ifdef DEVRANDOM_EGD 386 /* Use an EGD socket to read entropy from an EGD or PRNGD entropy 387 * collecting daemon. */ 388 389 for (egdsocket = egdsockets; *egdsocket && n < ENTROPY_NEEDED; egdsocket++) 390 { 391 int r; 392 393 r = RAND_query_egd_bytes(*egdsocket, (unsigned char *)tmpbuf+n, 394 ENTROPY_NEEDED-n); 395 if (r > 0) 396 n += r; 397 } 398 #endif /* defined(DEVRANDOM_EGD) */ 399 400 #if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 401 if (n > 0) 402 { 403 RAND_add(tmpbuf,sizeof tmpbuf,(double)n); 404 OPENSSL_cleanse(tmpbuf,n); 405 } 406 #endif 407 408 /* put in some default random data, we need more than just this */ 409 l=curr_pid; 410 RAND_add(&l,sizeof(l),0.0); 411 l=getuid(); 412 RAND_add(&l,sizeof(l),0.0); 413 414 l=time(NULL); 415 RAND_add(&l,sizeof(l),0.0); 416 417 #if defined(OPENSSL_SYS_BEOS) 418 { 419 system_info sysInfo; 420 get_system_info(&sysInfo); 421 RAND_add(&sysInfo,sizeof(sysInfo),0); 422 } 423 #endif 424 425 #if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 426 return 1; 427 #else 428 return 0; 429 #endif 430 } 431 432 #endif /* defined(__OpenBSD__) */ 433 #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)) */ 434 435 436 #if defined(OPENSSL_SYS_VXWORKS) 437 int RAND_poll(void) 438 { 439 return 0; 440 } 441 #endif 442