xref: /lighttpd1.4/src/rand.c (revision e11f72b1)
1 #include "first.h"
2 
3 #include "rand.h"
4 #include "fdevent.h"
5 #include "safe_memclear.h"
6 
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <time.h>
14 #include <unistd.h>
15 
16 #include "sys-crypto.h"
17 #ifdef USE_OPENSSL_CRYPTO
18 #include <openssl/opensslv.h> /* OPENSSL_VERSION_NUMBER */
19 #include <openssl/rand.h>
20 #endif
21 #ifdef HAVE_GETENTROPY
22 #include <sys/random.h>
23 #endif
24 #ifdef HAVE_LINUX_RANDOM_H
25 #include <sys/syscall.h>
26 #include <linux/random.h>
27 #endif
28 #ifdef RNDGETENTCNT
29 #include <sys/ioctl.h>
30 #endif
31 
32 /* Take some reasonable steps to attempt to *seed* random number generators with
33  * cryptographically random data.  Some of these initialization routines may
34  * block, and are intended to be called only at startup in lighttpd, or
35  * immediately after fork() to start lighttpd workers.
36  *
37  * Update: li_rand_init() is now deferred until first use so that installations
38  * that do not use modules which use these routines do need to potentially block
39  * at startup.  Current use by core lighttpd modules is in mod_auth HTTP Digest
40  * auth and in mod_usertrack.  Deferring collection of random data until first
41  * use may allow sufficient entropy to be collected by kernel before first use,
42  * helping reduce or avoid situations in low-entropy-generating embedded devices
43  * which might otherwise block lighttpd for minutes at device startup.
44  * Further discussion in https://redmine.lighttpd.net/boards/2/topics/6981
45  *
46  * Note: results from li_rand_pseudo_bytes() are not necessarily
47  * cryptographically random and must not be used for purposes such
48  * as key generation which require cryptographic randomness.
49  *
50  * https://wiki.openssl.org/index.php/Random_Numbers
51  * https://wiki.openssl.org/index.php/Random_fork-safety
52  *
53  * openssl random number generators are not thread-safe by default
54  * https://wiki.openssl.org/index.php/Manual:Threads(3)
55  *
56  * RFE: add more paranoid checks from the following to improve confidence:
57  * http://insanecoding.blogspot.co.uk/2014/05/a-good-idea-with-bad-usage-devurandom.html
58  * RFE: retry on EINTR
59  * RFE: check RAND_status()
60  */
61 
62 static int li_getentropy (void *buf, size_t buflen)
63 {
64   #ifdef HAVE_GETENTROPY
65     return getentropy(buf, buflen);
66   #else
67     /*(see NOTES section in 'man getrandom' on Linux)*/
68    #if defined(HAVE_GETRANDOM) || defined(SYS_getrandom)
69     if (buflen <= 256) {
70       #ifdef HAVE_GETRANDOM /*(not implemented in glibc yet)*/
71         int num = getrandom(buf, buflen, 0);
72       #elif defined(SYS_getrandom)
73         /* https://lwn.net/Articles/605828/ */
74         /* https://bbs.archlinux.org/viewtopic.php?id=200039 */
75         int num = (int)syscall(SYS_getrandom, buf, buflen, 0);
76       #endif
77         if (num == (int)buflen) return 0;
78         if (num < 0)            return num; /* -1 */
79     }
80    #else
81     UNUSED(buf);
82     UNUSED(buflen);
83    #endif
84     errno = EIO;
85     return -1;
86   #endif
87 }
88 
89 static int li_rand_device_bytes (unsigned char *buf, int num)
90 {
91     /* randomness from these devices is cryptographically strong,
92      * unless /dev/urandom is low on entropy */
93 
94     static const char * const devices[] = {
95       #ifdef __OpenBSD__
96         "/dev/arandom",
97       #endif
98         "/dev/urandom",
99         "/dev/random"
100     };
101 
102     /* device files might not be available in chroot environment,
103      * so prefer syscall, if available */
104     if (0 == li_getentropy(buf, (size_t)num)) return 1;
105 
106     for (unsigned int u = 0; u < sizeof(devices)/sizeof(devices[0]); ++u) {
107         /*(some systems might have symlink to another device; omit O_NOFOLLOW)*/
108         int fd = fdevent_open_cloexec(devices[u], 0, O_RDONLY, 0);
109         if (fd >= 0) {
110             ssize_t rd = 0;
111           #ifdef RNDGETENTCNT
112             int entropy;
113             if (0 == ioctl(fd, (unsigned long)(RNDGETENTCNT), &entropy)
114                 && entropy >= num*8)
115           #endif
116                 rd = read(fd, buf, (size_t)num);
117             close(fd);
118             if (rd == num) {
119                 return 1;
120             }
121         }
122     }
123 
124     return 0;
125 }
126 
127 static int li_rand_inited;
128 static unsigned short xsubi[3];
129 
130 static void li_rand_init (void)
131 {
132     /* (intended to be called at init and after fork() in order to re-seed PRNG
133      *  so that forked children, grandchildren, etc do not share PRNG seed)
134      * https://github.com/ramsey/uuid/issues/80
135      * https://www.agwa.name/blog/post/libressls_prng_is_unsafe_on_linux
136      *   (issue in early version of libressl has since been fixed)
137      * https://github.com/libressl-portable/portable/commit/32d9eeeecf4e951e1566d5f4a42b36ea37b60f35
138      */
139     unsigned int u;
140     li_rand_inited = 1;
141     if (1 == li_rand_device_bytes((unsigned char *)xsubi, (int)sizeof(xsubi))) {
142         u = ((unsigned int)xsubi[0] << 16) | xsubi[1];
143     }
144     else {
145       #ifdef HAVE_ARC4RANDOM_BUF
146         u = arc4random();
147         arc4random_buf(xsubi, sizeof(xsubi));
148       #else
149         /* NOTE: not cryptographically random !!! */
150         srand((unsigned int)(time(NULL) ^ getpid()));
151         for (u = 0; u < sizeof(unsigned short); ++u)
152             /* coverity[dont_call : FALSE] */
153             xsubi[u] = (unsigned short)(rand() & 0xFFFF);
154         u = ((unsigned int)xsubi[0] << 16) | xsubi[1];
155       #endif
156     }
157     srand(u);   /*(initialize just in case rand() used elsewhere)*/
158   #ifdef HAVE_SRANDOM
159     srandom(u); /*(initialize just in case random() used elsewhere)*/
160   #endif
161   #ifdef USE_OPENSSL_CRYPTO
162     RAND_poll();
163     RAND_seed(xsubi, (int)sizeof(xsubi));
164   #endif
165 }
166 
167 void li_rand_reseed (void)
168 {
169     if (li_rand_inited) li_rand_init();
170 }
171 
172 int li_rand_pseudo (void)
173 {
174     /* randomness *is not* cryptographically strong */
175     /* (attempt to use better mechanisms to replace the more portable rand()) */
176   #ifdef USE_OPENSSL_CRYPTO /* (openssl 1.1.0 deprecates RAND_pseudo_bytes()) */
177   #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
178     int i;
179     if (-1 != RAND_pseudo_bytes((unsigned char *)&i, sizeof(i))) return i;
180   #endif
181   #endif
182     if (!li_rand_inited) li_rand_init();
183   #ifdef HAVE_ARC4RANDOM_BUF
184     return (int)arc4random();
185   #elif defined(HAVE_SRANDOM)
186     /* coverity[dont_call : FALSE] */
187     return (int)random();
188   #elif defined(HAVE_JRAND48)
189     /*(FYI: jrand48() reentrant, but use of file-scoped static xsubi[] is not)*/
190     /* coverity[dont_call : FALSE] */
191     return (int)jrand48(xsubi);
192   #else
193     /* coverity[dont_call : FALSE] */
194     return rand();
195   #endif
196 }
197 
198 void li_rand_pseudo_bytes (unsigned char *buf, int num)
199 {
200     for (int i = 0; i < num; ++i)
201         buf[i] = li_rand_pseudo() & 0xFF;
202 }
203 
204 int li_rand_bytes (unsigned char *buf, int num)
205 {
206   #ifdef USE_OPENSSL_CRYPTO
207     int rc = RAND_bytes(buf, num);
208     if (-1 != rc) {
209         return rc;
210     }
211   #endif
212     if (1 == li_rand_device_bytes(buf, num)) {
213         return 1;
214     }
215     else {
216         /* NOTE: not cryptographically random !!! */
217         li_rand_pseudo_bytes(buf, num);
218         /*(openssl RAND_pseudo_bytes rc for non-cryptographically random data)*/
219         return 0;
220     }
221 }
222 
223 void li_rand_cleanup (void)
224 {
225   #ifdef USE_OPENSSL_CRYPTO
226   #if OPENSSL_VERSION_NUMBER < 0x10100000L
227     RAND_cleanup();
228   #endif
229   #endif
230     safe_memclear(xsubi, sizeof(xsubi));
231 }
232