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