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 #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 	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__) */
    237 int 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)
    427 int RAND_poll(void)
    428 	{
    429 	return 0;
    430 	}
    431 #endif
    432