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