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.
8296465Sdelphij *
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).
15296465Sdelphij *
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.
22296465Sdelphij *
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 :-).
37296465Sdelphij * 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)"
40296465Sdelphij *
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.
52296465Sdelphij *
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
66296465Sdelphij *    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
121296465Sdelphij# include <sys/types.h>
122296465Sdelphij# include <sys/time.h>
123296465Sdelphij# include <sys/times.h>
124296465Sdelphij# include <sys/stat.h>
125296465Sdelphij# include <fcntl.h>
126296465Sdelphij# include <unistd.h>
127296465Sdelphij# include <time.h>
128296465Sdelphij# if defined(OPENSSL_SYS_LINUX) /* should actually be available virtually
129296465Sdelphij                                 * everywhere */
130296465Sdelphij#  include <poll.h>
131296465Sdelphij# endif
132296465Sdelphij# include <limits.h>
133296465Sdelphij# ifndef FD_SETSIZE
134296465Sdelphij#  define FD_SETSIZE (8*sizeof(fd_set))
135296465Sdelphij# endif
136109998Smarkm
137296465Sdelphij# ifdef __OpenBSD__
138109998Smarkmint RAND_poll(void)
139109998Smarkm{
140296465Sdelphij    u_int32_t rnd = 0, i;
141296465Sdelphij    unsigned char buf[ENTROPY_NEEDED];
142127128Snectar
143296465Sdelphij    for (i = 0; i < sizeof(buf); i++) {
144296465Sdelphij        if (i % 4 == 0)
145296465Sdelphij            rnd = arc4random();
146296465Sdelphij        buf[i] = rnd;
147296465Sdelphij        rnd >>= 8;
148296465Sdelphij    }
149296465Sdelphij    RAND_add(buf, sizeof(buf), ENTROPY_NEEDED);
150296465Sdelphij    memset(buf, 0, sizeof(buf));
151127128Snectar
152296465Sdelphij    return 1;
153127128Snectar}
154296465Sdelphij# else                          /* !defined(__OpenBSD__) */
155127128Snectarint RAND_poll(void)
156127128Snectar{
157296465Sdelphij    unsigned long l;
158296465Sdelphij    pid_t curr_pid = getpid();
159296465Sdelphij#  if defined(DEVRANDOM) || defined(DEVRANDOM_EGD)
160296465Sdelphij    unsigned char tmpbuf[ENTROPY_NEEDED];
161296465Sdelphij    int n = 0;
162296465Sdelphij#  endif
163296465Sdelphij#  ifdef DEVRANDOM
164296465Sdelphij    static const char *randomfiles[] = { DEVRANDOM };
165296465Sdelphij    struct stat randomstats[sizeof(randomfiles) / sizeof(randomfiles[0])];
166296465Sdelphij    int fd;
167296465Sdelphij    size_t i;
168296465Sdelphij#  endif
169296465Sdelphij#  ifdef DEVRANDOM_EGD
170296465Sdelphij    static const char *egdsockets[] = { DEVRANDOM_EGD, NULL };
171296465Sdelphij    const char **egdsocket = NULL;
172296465Sdelphij#  endif
173109998Smarkm
174296465Sdelphij#  ifdef DEVRANDOM
175296465Sdelphij    memset(randomstats, 0, sizeof(randomstats));
176296465Sdelphij    /*
177296465Sdelphij     * Use a random entropy pool device. Linux, FreeBSD and OpenBSD have
178296465Sdelphij     * this. Use /dev/urandom if you can as /dev/random may block if it runs
179296465Sdelphij     * out of random entries.
180296465Sdelphij     */
181109998Smarkm
182296465Sdelphij    for (i = 0; i < sizeof(randomfiles) / sizeof(randomfiles[0])
183296465Sdelphij         && n < ENTROPY_NEEDED; i++) {
184296465Sdelphij        if ((fd = open(randomfiles[i], O_RDONLY
185296465Sdelphij#   ifdef O_NONBLOCK
186296465Sdelphij                       | O_NONBLOCK
187296465Sdelphij#   endif
188296465Sdelphij#   ifdef O_BINARY
189296465Sdelphij                       | O_BINARY
190296465Sdelphij#   endif
191296465Sdelphij#   ifdef O_NOCTTY              /* If it happens to be a TTY (god forbid), do
192296465Sdelphij                                 * not make it our controlling tty */
193296465Sdelphij                       | O_NOCTTY
194296465Sdelphij#   endif
195296465Sdelphij             )) >= 0) {
196296465Sdelphij            int usec = 10 * 1000; /* spend 10ms on each file */
197296465Sdelphij            int r;
198296465Sdelphij            size_t j;
199296465Sdelphij            struct stat *st = &randomstats[i];
200109998Smarkm
201296465Sdelphij            /*
202296465Sdelphij             * Avoid using same input... Used to be O_NOFOLLOW above, but
203296465Sdelphij             * it's not universally appropriate...
204296465Sdelphij             */
205296465Sdelphij            if (fstat(fd, st) != 0) {
206296465Sdelphij                close(fd);
207296465Sdelphij                continue;
208296465Sdelphij            }
209296465Sdelphij            for (j = 0; j < i; j++) {
210296465Sdelphij                if (randomstats[j].st_ino == st->st_ino &&
211296465Sdelphij                    randomstats[j].st_dev == st->st_dev)
212296465Sdelphij                    break;
213296465Sdelphij            }
214296465Sdelphij            if (j < i) {
215296465Sdelphij                close(fd);
216296465Sdelphij                continue;
217296465Sdelphij            }
218160814Ssimon
219296465Sdelphij            do {
220296465Sdelphij                int try_read = 0;
221109998Smarkm
222296465Sdelphij#   if defined(OPENSSL_SYS_LINUX)
223296465Sdelphij                /* use poll() */
224296465Sdelphij                struct pollfd pset;
225162911Ssimon
226296465Sdelphij                pset.fd = fd;
227296465Sdelphij                pset.events = POLLIN;
228296465Sdelphij                pset.revents = 0;
229162911Ssimon
230296465Sdelphij                if (poll(&pset, 1, usec / 1000) < 0)
231296465Sdelphij                    usec = 0;
232296465Sdelphij                else
233296465Sdelphij                    try_read = (pset.revents & POLLIN) != 0;
234162911Ssimon
235296465Sdelphij#   else
236296465Sdelphij                /* use select() */
237296465Sdelphij                fd_set fset;
238296465Sdelphij                struct timeval t;
239109998Smarkm
240296465Sdelphij                t.tv_sec = 0;
241296465Sdelphij                t.tv_usec = usec;
242109998Smarkm
243296465Sdelphij                if (FD_SETSIZE > 0 && (unsigned)fd >= FD_SETSIZE) {
244296465Sdelphij                    /*
245296465Sdelphij                     * can't use select, so just try to read once anyway
246296465Sdelphij                     */
247296465Sdelphij                    try_read = 1;
248296465Sdelphij                } else {
249296465Sdelphij                    FD_ZERO(&fset);
250296465Sdelphij                    FD_SET(fd, &fset);
251109998Smarkm
252296465Sdelphij                    if (select(fd + 1, &fset, NULL, NULL, &t) >= 0) {
253296465Sdelphij                        usec = t.tv_usec;
254296465Sdelphij                        if (FD_ISSET(fd, &fset))
255296465Sdelphij                            try_read = 1;
256296465Sdelphij                    } else
257296465Sdelphij                        usec = 0;
258296465Sdelphij                }
259296465Sdelphij#   endif
260109998Smarkm
261296465Sdelphij                if (try_read) {
262296465Sdelphij                    r = read(fd, (unsigned char *)tmpbuf + n,
263296465Sdelphij                             ENTROPY_NEEDED - n);
264296465Sdelphij                    if (r > 0)
265296465Sdelphij                        n += r;
266296465Sdelphij                } else
267296465Sdelphij                    r = -1;
268109998Smarkm
269296465Sdelphij                /*
270296465Sdelphij                 * Some Unixen will update t in select(), some won't.  For
271296465Sdelphij                 * those who won't, or if we didn't use select() in the first
272296465Sdelphij                 * place, give up here, otherwise, we will do this once again
273296465Sdelphij                 * for the remaining time.
274296465Sdelphij                 */
275296465Sdelphij                if (usec == 10 * 1000)
276296465Sdelphij                    usec = 0;
277296465Sdelphij            }
278296465Sdelphij            while ((r > 0 ||
279296465Sdelphij                    (errno == EINTR || errno == EAGAIN)) && usec != 0
280296465Sdelphij                   && n < ENTROPY_NEEDED);
281109998Smarkm
282296465Sdelphij            close(fd);
283296465Sdelphij        }
284296465Sdelphij    }
285296465Sdelphij#  endif                        /* defined(DEVRANDOM) */
286109998Smarkm
287296465Sdelphij#  ifdef DEVRANDOM_EGD
288296465Sdelphij    /*
289296465Sdelphij     * Use an EGD socket to read entropy from an EGD or PRNGD entropy
290296465Sdelphij     * collecting daemon.
291296465Sdelphij     */
292109998Smarkm
293296465Sdelphij    for (egdsocket = egdsockets; *egdsocket && n < ENTROPY_NEEDED;
294296465Sdelphij         egdsocket++) {
295296465Sdelphij        int r;
296296465Sdelphij
297296465Sdelphij        r = RAND_query_egd_bytes(*egdsocket, (unsigned char *)tmpbuf + n,
298296465Sdelphij                                 ENTROPY_NEEDED - n);
299296465Sdelphij        if (r > 0)
300296465Sdelphij            n += r;
301296465Sdelphij    }
302296465Sdelphij#  endif                        /* defined(DEVRANDOM_EGD) */
303296465Sdelphij
304296465Sdelphij#  if defined(DEVRANDOM) || defined(DEVRANDOM_EGD)
305296465Sdelphij    if (n > 0) {
306296465Sdelphij        RAND_add(tmpbuf, sizeof tmpbuf, (double)n);
307296465Sdelphij        OPENSSL_cleanse(tmpbuf, n);
308296465Sdelphij    }
309296465Sdelphij#  endif
310296465Sdelphij
311296465Sdelphij    /* put in some default random data, we need more than just this */
312296465Sdelphij    l = curr_pid;
313296465Sdelphij    RAND_add(&l, sizeof(l), 0.0);
314296465Sdelphij    l = getuid();
315296465Sdelphij    RAND_add(&l, sizeof(l), 0.0);
316296465Sdelphij
317296465Sdelphij    l = time(NULL);
318296465Sdelphij    RAND_add(&l, sizeof(l), 0.0);
319296465Sdelphij
320296465Sdelphij#  if defined(DEVRANDOM) || defined(DEVRANDOM_EGD)
321296465Sdelphij    return 1;
322296465Sdelphij#  else
323296465Sdelphij    return 0;
324296465Sdelphij#  endif
325109998Smarkm}
326109998Smarkm
327296465Sdelphij# endif                         /* defined(__OpenBSD__) */
328296465Sdelphij#endif                          /* !(defined(OPENSSL_SYS_WINDOWS) ||
329296465Sdelphij                                 * defined(OPENSSL_SYS_WIN32) ||
330296465Sdelphij                                 * defined(OPENSSL_SYS_VMS) ||
331296465Sdelphij                                 * defined(OPENSSL_SYS_OS2) ||
332296465Sdelphij                                 * defined(OPENSSL_SYS_VXWORKS) ||
333296465Sdelphij                                 * defined(OPENSSL_SYS_NETWARE)) */
334109998Smarkm
335109998Smarkm#if defined(OPENSSL_SYS_VXWORKS)
336109998Smarkmint RAND_poll(void)
337296465Sdelphij{
338296465Sdelphij    return 0;
339296465Sdelphij}
340109998Smarkm#endif
341