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