Home | History | Annotate | Download | only in rand
      1 /* crypto/rand/rand_unix.c */
      2 /* Copyright (C) 1995-1998 Eric Young (eay (at) cryptsoft.com)
      3  * All rights reserved.
      4  *
      5  * This package is an SSL implementation written
      6  * by Eric Young (eay (at) 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 (at) 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 (at) 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 (at) 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 (at) 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 (at) cryptsoft.com).  This product includes software written by Tim
    108  * Hudson (tjh (at) 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 #ifdef __VOS__
    137 int RAND_poll(void)
    138 {
    139 	unsigned char buf[ENTROPY_NEEDED];
    140 	pid_t curr_pid;
    141 	uid_t curr_uid;
    142 	static int first=1;
    143 	int i;
    144 	long rnd = 0;
    145 	struct timespec ts;
    146 	unsigned seed;
    147 
    148 /* The VOS random() function starts from a static seed so its
    149    initial value is predictable.  If random() returns the
    150    initial value, reseed it with dynamic data.  The VOS
    151    real-time clock has a granularity of 1 nsec so it should be
    152    reasonably difficult to predict its exact value.  Do not
    153    gratuitously reseed the PRNG because other code in this
    154    process or thread may be using it.  */
    155 
    156 	if (first) {
    157 		first = 0;
    158 		rnd = random ();
    159 		if (rnd == 1804289383) {
    160 			clock_gettime (CLOCK_REALTIME, &ts);
    161 			curr_pid = getpid();
    162 			curr_uid = getuid();
    163 			seed = ts.tv_sec ^ ts.tv_nsec ^ curr_pid ^ curr_uid;
    164 			srandom (seed);
    165 		}
    166 	}
    167 
    168 	for (i = 0; i < sizeof(buf); i++) {
    169 		if (i % 4 == 0)
    170 			rnd = random();
    171 		buf[i] = rnd;
    172 		rnd >>= 8;
    173 	}
    174 	RAND_add(buf, sizeof(buf), ENTROPY_NEEDED);
    175 	memset(buf, 0, sizeof(buf));
    176 
    177 	return 1;
    178 }
    179 #elif defined __OpenBSD__
    180 int RAND_poll(void)
    181 {
    182 	u_int32_t rnd = 0, i;
    183 	unsigned char buf[ENTROPY_NEEDED];
    184 
    185 	for (i = 0; i < sizeof(buf); i++) {
    186 		if (i % 4 == 0)
    187 			rnd = arc4random();
    188 		buf[i] = rnd;
    189 		rnd >>= 8;
    190 	}
    191 	RAND_add(buf, sizeof(buf), ENTROPY_NEEDED);
    192 	memset(buf, 0, sizeof(buf));
    193 
    194 	return 1;
    195 }
    196 #else /* !defined(__OpenBSD__) */
    197 int RAND_poll(void)
    198 {
    199 	unsigned long l;
    200 	pid_t curr_pid = getpid();
    201 #if defined(DEVRANDOM) || defined(DEVRANDOM_EGD)
    202 	unsigned char tmpbuf[ENTROPY_NEEDED];
    203 	int n = 0;
    204 #endif
    205 #ifdef DEVRANDOM
    206 	static const char *randomfiles[] = { DEVRANDOM };
    207 	struct stat randomstats[sizeof(randomfiles)/sizeof(randomfiles[0])];
    208 	int fd;
    209 	unsigned int i;
    210 #endif
    211 #ifdef DEVRANDOM_EGD
    212 	static const char *egdsockets[] = { DEVRANDOM_EGD, NULL };
    213 	const char **egdsocket = NULL;
    214 #endif
    215 
    216 #ifdef DEVRANDOM
    217 	memset(randomstats,0,sizeof(randomstats));
    218 	/* Use a random entropy pool device. Linux, FreeBSD and OpenBSD
    219 	 * have this. Use /dev/urandom if you can as /dev/random may block
    220 	 * if it runs out of random entries.  */
    221 
    222 	for (i = 0; (i < sizeof(randomfiles)/sizeof(randomfiles[0])) &&
    223 			(n < ENTROPY_NEEDED); i++)
    224 		{
    225 		if ((fd = open(randomfiles[i], O_RDONLY
    226 #ifdef O_NONBLOCK
    227 			|O_NONBLOCK
    228 #endif
    229 #ifdef O_BINARY
    230 			|O_BINARY
    231 #endif
    232 #ifdef O_NOCTTY /* If it happens to be a TTY (god forbid), do not make it
    233 		   our controlling tty */
    234 			|O_NOCTTY
    235 #endif
    236 			)) >= 0)
    237 			{
    238 			int usec = 10*1000; /* spend 10ms on each file */
    239 			int r;
    240 			unsigned int j;
    241 			struct stat *st=&randomstats[i];
    242 
    243 			/* Avoid using same input... Used to be O_NOFOLLOW
    244 			 * above, but it's not universally appropriate... */
    245 			if (fstat(fd,st) != 0)	{ close(fd); continue; }
    246 			for (j=0;j<i;j++)
    247 				{
    248 				if (randomstats[j].st_ino==st->st_ino &&
    249 				    randomstats[j].st_dev==st->st_dev)
    250 					break;
    251 				}
    252 			if (j<i)		{ close(fd); continue; }
    253 
    254 			do
    255 				{
    256 				int try_read = 0;
    257 
    258 #if defined(OPENSSL_SYS_BEOS_R5)
    259 				/* select() is broken in BeOS R5, so we simply
    260 				 *  try to read something and snooze if we couldn't */
    261 				try_read = 1;
    262 
    263 #elif defined(OPENSSL_SYS_LINUX)
    264 				/* use poll() */
    265 				struct pollfd pset;
    266 
    267 				pset.fd = fd;
    268 				pset.events = POLLIN;
    269 				pset.revents = 0;
    270 
    271 				if (poll(&pset, 1, usec / 1000) < 0)
    272 					usec = 0;
    273 				else
    274 					try_read = (pset.revents & POLLIN) != 0;
    275 
    276 #else
    277 				/* use select() */
    278 				fd_set fset;
    279 				struct timeval t;
    280 
    281 				t.tv_sec = 0;
    282 				t.tv_usec = usec;
    283 
    284 				if (FD_SETSIZE > 0 && (unsigned)fd >= FD_SETSIZE)
    285 					{
    286 					/* can't use select, so just try to read once anyway */
    287 					try_read = 1;
    288 					}
    289 				else
    290 					{
    291 					FD_ZERO(&fset);
    292 					FD_SET(fd, &fset);
    293 
    294 					if (select(fd+1,&fset,NULL,NULL,&t) >= 0)
    295 						{
    296 						usec = t.tv_usec;
    297 						if (FD_ISSET(fd, &fset))
    298 							try_read = 1;
    299 						}
    300 					else
    301 						usec = 0;
    302 					}
    303 #endif
    304 
    305 				if (try_read)
    306 					{
    307 					r = read(fd,(unsigned char *)tmpbuf+n, ENTROPY_NEEDED-n);
    308 					if (r > 0)
    309 						n += r;
    310 #if defined(OPENSSL_SYS_BEOS_R5)
    311 					if (r == 0)
    312 						snooze(t.tv_usec);
    313 #endif
    314 					}
    315 				else
    316 					r = -1;
    317 
    318 				/* Some Unixen will update t in select(), some
    319 				   won't.  For those who won't, or if we
    320 				   didn't use select() in the first place,
    321 				   give up here, otherwise, we will do
    322 				   this once again for the remaining
    323 				   time. */
    324 				if (usec == 10*1000)
    325 					usec = 0;
    326 				}
    327 			while ((r > 0 ||
    328 			       (errno == EINTR || errno == EAGAIN)) && usec != 0 && n < ENTROPY_NEEDED);
    329 
    330 			close(fd);
    331 			}
    332 		}
    333 #endif /* defined(DEVRANDOM) */
    334 
    335 #ifdef DEVRANDOM_EGD
    336 	/* Use an EGD socket to read entropy from an EGD or PRNGD entropy
    337 	 * collecting daemon. */
    338 
    339 	for (egdsocket = egdsockets; *egdsocket && n < ENTROPY_NEEDED; egdsocket++)
    340 		{
    341 		int r;
    342 
    343 		r = RAND_query_egd_bytes(*egdsocket, (unsigned char *)tmpbuf+n,
    344 					 ENTROPY_NEEDED-n);
    345 		if (r > 0)
    346 			n += r;
    347 		}
    348 #endif /* defined(DEVRANDOM_EGD) */
    349 
    350 #if defined(DEVRANDOM) || defined(DEVRANDOM_EGD)
    351 	if (n > 0)
    352 		{
    353 		RAND_add(tmpbuf,sizeof tmpbuf,(double)n);
    354 		OPENSSL_cleanse(tmpbuf,n);
    355 		}
    356 #endif
    357 
    358 	/* put in some default random data, we need more than just this */
    359 	l=curr_pid;
    360 	RAND_add(&l,sizeof(l),0.0);
    361 	l=getuid();
    362 	RAND_add(&l,sizeof(l),0.0);
    363 
    364 	l=time(NULL);
    365 	RAND_add(&l,sizeof(l),0.0);
    366 
    367 #if defined(OPENSSL_SYS_BEOS)
    368 	{
    369 	system_info sysInfo;
    370 	get_system_info(&sysInfo);
    371 	RAND_add(&sysInfo,sizeof(sysInfo),0);
    372 	}
    373 #endif
    374 
    375 #if defined(DEVRANDOM) || defined(DEVRANDOM_EGD)
    376 	return 1;
    377 #else
    378 	return 0;
    379 #endif
    380 }
    381 
    382 #endif /* defined(__OpenBSD__) */
    383 #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)) */
    384 
    385 
    386 #if defined(OPENSSL_SYS_VXWORKS)
    387 int RAND_poll(void)
    388 	{
    389 	return 0;
    390 	}
    391 #endif
    392