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