rand_unix.c revision 238405
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. 8109998Smarkm * 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). 15109998Smarkm * 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. 22109998Smarkm * 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 :-). 37109998Smarkm * 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)" 40109998Smarkm * 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. 52109998Smarkm * 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 66109998Smarkm * 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 121109998Smarkm#include <sys/types.h> 122109998Smarkm#include <sys/time.h> 123109998Smarkm#include <sys/times.h> 124160814Ssimon#include <sys/stat.h> 125109998Smarkm#include <fcntl.h> 126109998Smarkm#include <unistd.h> 127109998Smarkm#include <time.h> 128162911Ssimon#if defined(OPENSSL_SYS_LINUX) /* should actually be available virtually everywhere */ 129162911Ssimon# include <poll.h> 130162911Ssimon#endif 131162911Ssimon#include <limits.h> 132162911Ssimon#ifndef FD_SETSIZE 133162911Ssimon# define FD_SETSIZE (8*sizeof(fd_set)) 134162911Ssimon#endif 135109998Smarkm 136238405Sjkim#if defined(OPENSSL_SYS_VOS) 137238405Sjkim 138238405Sjkim/* The following algorithm repeatedly samples the real-time clock 139238405Sjkim (RTC) to generate a sequence of unpredictable data. The algorithm 140238405Sjkim relies upon the uneven execution speed of the code (due to factors 141238405Sjkim such as cache misses, interrupts, bus activity, and scheduling) and 142238405Sjkim upon the rather large relative difference between the speed of the 143238405Sjkim clock and the rate at which it can be read. 144238405Sjkim 145238405Sjkim If this code is ported to an environment where execution speed is 146238405Sjkim more constant or where the RTC ticks at a much slower rate, or the 147238405Sjkim clock can be read with fewer instructions, it is likely that the 148238405Sjkim results would be far more predictable. 149238405Sjkim 150238405Sjkim As a precaution, we generate 4 times the minimum required amount of 151238405Sjkim seed data. */ 152238405Sjkim 153109998Smarkmint RAND_poll(void) 154109998Smarkm{ 155238405Sjkim short int code; 156238405Sjkim gid_t curr_gid; 157238405Sjkim pid_t curr_pid; 158238405Sjkim uid_t curr_uid; 159238405Sjkim int i, k; 160238405Sjkim struct timespec ts; 161238405Sjkim unsigned char v; 162238405Sjkim 163238405Sjkim#ifdef OPENSSL_SYS_VOS_HPPA 164238405Sjkim long duration; 165238405Sjkim extern void s$sleep (long *_duration, short int *_code); 166238405Sjkim#else 167238405Sjkim#ifdef OPENSSL_SYS_VOS_IA32 168238405Sjkim long long duration; 169238405Sjkim extern void s$sleep2 (long long *_duration, short int *_code); 170238405Sjkim#else 171238405Sjkim#error "Unsupported Platform." 172238405Sjkim#endif /* OPENSSL_SYS_VOS_IA32 */ 173238405Sjkim#endif /* OPENSSL_SYS_VOS_HPPA */ 174238405Sjkim 175238405Sjkim /* Seed with the gid, pid, and uid, to ensure *some* 176238405Sjkim variation between different processes. */ 177238405Sjkim 178238405Sjkim curr_gid = getgid(); 179238405Sjkim RAND_add (&curr_gid, sizeof curr_gid, 1); 180238405Sjkim curr_gid = 0; 181238405Sjkim 182238405Sjkim curr_pid = getpid(); 183238405Sjkim RAND_add (&curr_pid, sizeof curr_pid, 1); 184238405Sjkim curr_pid = 0; 185238405Sjkim 186238405Sjkim curr_uid = getuid(); 187238405Sjkim RAND_add (&curr_uid, sizeof curr_uid, 1); 188238405Sjkim curr_uid = 0; 189238405Sjkim 190238405Sjkim for (i=0; i<(ENTROPY_NEEDED*4); i++) 191238405Sjkim { 192238405Sjkim /* burn some cpu; hope for interrupts, cache 193238405Sjkim collisions, bus interference, etc. */ 194238405Sjkim for (k=0; k<99; k++) 195238405Sjkim ts.tv_nsec = random (); 196238405Sjkim 197238405Sjkim#ifdef OPENSSL_SYS_VOS_HPPA 198238405Sjkim /* sleep for 1/1024 of a second (976 us). */ 199238405Sjkim duration = 1; 200238405Sjkim s$sleep (&duration, &code); 201238405Sjkim#else 202238405Sjkim#ifdef OPENSSL_SYS_VOS_IA32 203238405Sjkim /* sleep for 1/65536 of a second (15 us). */ 204238405Sjkim duration = 1; 205238405Sjkim s$sleep2 (&duration, &code); 206238405Sjkim#endif /* OPENSSL_SYS_VOS_IA32 */ 207238405Sjkim#endif /* OPENSSL_SYS_VOS_HPPA */ 208238405Sjkim 209238405Sjkim /* get wall clock time. */ 210238405Sjkim clock_gettime (CLOCK_REALTIME, &ts); 211238405Sjkim 212238405Sjkim /* take 8 bits */ 213238405Sjkim v = (unsigned char) (ts.tv_nsec % 256); 214238405Sjkim RAND_add (&v, sizeof v, 1); 215238405Sjkim v = 0; 216238405Sjkim } 217238405Sjkim return 1; 218238405Sjkim} 219238405Sjkim#elif defined __OpenBSD__ 220238405Sjkimint RAND_poll(void) 221238405Sjkim{ 222127128Snectar u_int32_t rnd = 0, i; 223127128Snectar unsigned char buf[ENTROPY_NEEDED]; 224127128Snectar 225127128Snectar for (i = 0; i < sizeof(buf); i++) { 226127128Snectar if (i % 4 == 0) 227127128Snectar rnd = arc4random(); 228127128Snectar buf[i] = rnd; 229127128Snectar rnd >>= 8; 230127128Snectar } 231127128Snectar RAND_add(buf, sizeof(buf), ENTROPY_NEEDED); 232127128Snectar memset(buf, 0, sizeof(buf)); 233127128Snectar 234127128Snectar return 1; 235127128Snectar} 236162911Ssimon#else /* !defined(__OpenBSD__) */ 237127128Snectarint RAND_poll(void) 238127128Snectar{ 239109998Smarkm unsigned long l; 240109998Smarkm pid_t curr_pid = getpid(); 241109998Smarkm#if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 242109998Smarkm unsigned char tmpbuf[ENTROPY_NEEDED]; 243109998Smarkm int n = 0; 244109998Smarkm#endif 245109998Smarkm#ifdef DEVRANDOM 246160814Ssimon static const char *randomfiles[] = { DEVRANDOM }; 247160814Ssimon struct stat randomstats[sizeof(randomfiles)/sizeof(randomfiles[0])]; 248109998Smarkm int fd; 249238405Sjkim unsigned int i; 250109998Smarkm#endif 251109998Smarkm#ifdef DEVRANDOM_EGD 252109998Smarkm static const char *egdsockets[] = { DEVRANDOM_EGD, NULL }; 253109998Smarkm const char **egdsocket = NULL; 254109998Smarkm#endif 255109998Smarkm 256109998Smarkm#ifdef DEVRANDOM 257160814Ssimon memset(randomstats,0,sizeof(randomstats)); 258109998Smarkm /* Use a random entropy pool device. Linux, FreeBSD and OpenBSD 259109998Smarkm * have this. Use /dev/urandom if you can as /dev/random may block 260109998Smarkm * if it runs out of random entries. */ 261109998Smarkm 262238405Sjkim for (i = 0; (i < sizeof(randomfiles)/sizeof(randomfiles[0])) && 263238405Sjkim (n < ENTROPY_NEEDED); i++) 264109998Smarkm { 265160814Ssimon if ((fd = open(randomfiles[i], O_RDONLY 266160814Ssimon#ifdef O_NONBLOCK 267160814Ssimon |O_NONBLOCK 268160814Ssimon#endif 269160814Ssimon#ifdef O_BINARY 270160814Ssimon |O_BINARY 271160814Ssimon#endif 272109998Smarkm#ifdef O_NOCTTY /* If it happens to be a TTY (god forbid), do not make it 273109998Smarkm our controlling tty */ 274109998Smarkm |O_NOCTTY 275109998Smarkm#endif 276109998Smarkm )) >= 0) 277109998Smarkm { 278162911Ssimon int usec = 10*1000; /* spend 10ms on each file */ 279109998Smarkm int r; 280238405Sjkim unsigned int j; 281160814Ssimon struct stat *st=&randomstats[i]; 282109998Smarkm 283160814Ssimon /* Avoid using same input... Used to be O_NOFOLLOW 284160814Ssimon * above, but it's not universally appropriate... */ 285160814Ssimon if (fstat(fd,st) != 0) { close(fd); continue; } 286160814Ssimon for (j=0;j<i;j++) 287160814Ssimon { 288160814Ssimon if (randomstats[j].st_ino==st->st_ino && 289160814Ssimon randomstats[j].st_dev==st->st_dev) 290160814Ssimon break; 291160814Ssimon } 292160814Ssimon if (j<i) { close(fd); continue; } 293160814Ssimon 294109998Smarkm do 295109998Smarkm { 296162911Ssimon int try_read = 0; 297109998Smarkm 298238405Sjkim#if defined(OPENSSL_SYS_BEOS_R5) 299238405Sjkim /* select() is broken in BeOS R5, so we simply 300238405Sjkim * try to read something and snooze if we couldn't */ 301238405Sjkim try_read = 1; 302238405Sjkim 303238405Sjkim#elif defined(OPENSSL_SYS_LINUX) 304162911Ssimon /* use poll() */ 305162911Ssimon struct pollfd pset; 306162911Ssimon 307162911Ssimon pset.fd = fd; 308162911Ssimon pset.events = POLLIN; 309162911Ssimon pset.revents = 0; 310162911Ssimon 311162911Ssimon if (poll(&pset, 1, usec / 1000) < 0) 312162911Ssimon usec = 0; 313162911Ssimon else 314162911Ssimon try_read = (pset.revents & POLLIN) != 0; 315162911Ssimon 316162911Ssimon#else 317162911Ssimon /* use select() */ 318162911Ssimon fd_set fset; 319162911Ssimon struct timeval t; 320162911Ssimon 321162911Ssimon t.tv_sec = 0; 322162911Ssimon t.tv_usec = usec; 323162911Ssimon 324194206Ssimon if (FD_SETSIZE > 0 && (unsigned)fd >= FD_SETSIZE) 325109998Smarkm { 326162911Ssimon /* can't use select, so just try to read once anyway */ 327162911Ssimon try_read = 1; 328162911Ssimon } 329162911Ssimon else 330162911Ssimon { 331162911Ssimon FD_ZERO(&fset); 332162911Ssimon FD_SET(fd, &fset); 333162911Ssimon 334162911Ssimon if (select(fd+1,&fset,NULL,NULL,&t) >= 0) 335162911Ssimon { 336162911Ssimon usec = t.tv_usec; 337162911Ssimon if (FD_ISSET(fd, &fset)) 338162911Ssimon try_read = 1; 339162911Ssimon } 340162911Ssimon else 341162911Ssimon usec = 0; 342162911Ssimon } 343162911Ssimon#endif 344162911Ssimon 345162911Ssimon if (try_read) 346162911Ssimon { 347162911Ssimon r = read(fd,(unsigned char *)tmpbuf+n, ENTROPY_NEEDED-n); 348109998Smarkm if (r > 0) 349109998Smarkm n += r; 350238405Sjkim#if defined(OPENSSL_SYS_BEOS_R5) 351238405Sjkim if (r == 0) 352238405Sjkim snooze(t.tv_usec); 353238405Sjkim#endif 354109998Smarkm } 355162911Ssimon else 356162911Ssimon r = -1; 357162911Ssimon 358162911Ssimon /* Some Unixen will update t in select(), some 359162911Ssimon won't. For those who won't, or if we 360162911Ssimon didn't use select() in the first place, 361162911Ssimon give up here, otherwise, we will do 362109998Smarkm this once again for the remaining 363109998Smarkm time. */ 364162911Ssimon if (usec == 10*1000) 365162911Ssimon usec = 0; 366109998Smarkm } 367162911Ssimon while ((r > 0 || 368162911Ssimon (errno == EINTR || errno == EAGAIN)) && usec != 0 && n < ENTROPY_NEEDED); 369109998Smarkm 370109998Smarkm close(fd); 371109998Smarkm } 372109998Smarkm } 373162911Ssimon#endif /* defined(DEVRANDOM) */ 374109998Smarkm 375109998Smarkm#ifdef DEVRANDOM_EGD 376109998Smarkm /* Use an EGD socket to read entropy from an EGD or PRNGD entropy 377109998Smarkm * collecting daemon. */ 378109998Smarkm 379109998Smarkm for (egdsocket = egdsockets; *egdsocket && n < ENTROPY_NEEDED; egdsocket++) 380109998Smarkm { 381109998Smarkm int r; 382109998Smarkm 383109998Smarkm r = RAND_query_egd_bytes(*egdsocket, (unsigned char *)tmpbuf+n, 384109998Smarkm ENTROPY_NEEDED-n); 385109998Smarkm if (r > 0) 386109998Smarkm n += r; 387109998Smarkm } 388162911Ssimon#endif /* defined(DEVRANDOM_EGD) */ 389109998Smarkm 390109998Smarkm#if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 391109998Smarkm if (n > 0) 392109998Smarkm { 393160814Ssimon RAND_add(tmpbuf,sizeof tmpbuf,(double)n); 394109998Smarkm OPENSSL_cleanse(tmpbuf,n); 395109998Smarkm } 396109998Smarkm#endif 397109998Smarkm 398109998Smarkm /* put in some default random data, we need more than just this */ 399109998Smarkm l=curr_pid; 400160814Ssimon RAND_add(&l,sizeof(l),0.0); 401109998Smarkm l=getuid(); 402160814Ssimon RAND_add(&l,sizeof(l),0.0); 403109998Smarkm 404109998Smarkm l=time(NULL); 405160814Ssimon RAND_add(&l,sizeof(l),0.0); 406109998Smarkm 407238405Sjkim#if defined(OPENSSL_SYS_BEOS) 408238405Sjkim { 409238405Sjkim system_info sysInfo; 410238405Sjkim get_system_info(&sysInfo); 411238405Sjkim RAND_add(&sysInfo,sizeof(sysInfo),0); 412238405Sjkim } 413238405Sjkim#endif 414238405Sjkim 415109998Smarkm#if defined(DEVRANDOM) || defined(DEVRANDOM_EGD) 416109998Smarkm return 1; 417109998Smarkm#else 418109998Smarkm return 0; 419109998Smarkm#endif 420109998Smarkm} 421109998Smarkm 422162911Ssimon#endif /* defined(__OpenBSD__) */ 423162911Ssimon#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)) */ 424109998Smarkm 425162911Ssimon 426109998Smarkm#if defined(OPENSSL_SYS_VXWORKS) 427109998Smarkmint RAND_poll(void) 428162911Ssimon { 429162911Ssimon return 0; 430162911Ssimon } 431109998Smarkm#endif 432