xref: /lighttpd1.4/src/rand.c (revision 2e0edb85)
1 /*
2  * rand - generate random bytes
3  *
4  * Copyright(c) 2016 Glenn Strauss gstrauss()gluelogic.com  All rights reserved
5  * License: BSD 3-clause (same as lighttpd)
6  */
7 #include "first.h"
8 
9 #include "rand.h"
10 #include "ck.h"
11 #include "fdevent.h"
12 
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include "sys-time.h"
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 
22 #include "sys-crypto-md.h" /* USE_LIB_CRYPTO and additional crypto lib config */
23 #ifdef USE_NETTLE_CRYPTO
24 #undef USE_MBEDTLS_CRYPTO
25 #undef USE_WOLFSSL_CRYPTO
26 #undef USE_OPENSSL_CRYPTO
27 #undef USE_GNUTLS_CRYPTO
28 #undef USE_NSS_CRYPTO
29 #include <nettle/knuth-lfib.h>
30 #include <nettle/arcfour.h>
31 #include <nettle/yarrow.h>
32 #endif
33 #ifdef USE_MBEDTLS_CRYPTO
34 #undef USE_WOLFSSL_CRYPTO
35 #undef USE_OPENSSL_CRYPTO
36 #undef USE_GNUTLS_CRYPTO
37 #undef USE_NSS_CRYPTO
38 #include <mbedtls/ctr_drbg.h>
39 #include <mbedtls/entropy.h>
40 #endif
41 #ifdef USE_WOLFSSL_CRYPTO
42 #undef USE_OPENSSL_CRYPTO
43 #undef USE_GNUTLS_CRYPTO
44 #undef USE_NSS_CRYPTO
45 #include <wolfssl/wolfcrypt/random.h>
46 #endif
47 #ifdef USE_OPENSSL_CRYPTO
48 #undef USE_GNUTLS_CRYPTO
49 #undef USE_NSS_CRYPTO
50 #include <openssl/opensslv.h> /* OPENSSL_VERSION_NUMBER */
51 #include <openssl/rand.h>
52 #endif
53 #ifdef USE_GNUTLS_CRYPTO
54 #undef USE_NSS_CRYPTO
55 #include <gnutls/crypto.h>
56 #endif
57 #ifdef USE_NSS_CRYPTO
58 #ifdef NSS_VER_INCLUDE
59 #include <nss3/nss.h>
60 #include <nss3/pk11pub.h>
61 #else
62 #include <nss/nss.h>
63 #include <nss/pk11pub.h>
64 #endif
65 #endif
66 #ifndef USE_LIB_CRYPTO
67 #undef USE_NETTLE_CRYPTO
68 #undef USE_MBEDTLS_CRYPTO
69 #undef USE_WOLFSSL_CRYPTO
70 #undef USE_OPENSSL_CRYPTO
71 #undef USE_GNUTLS_CRYPTO
72 #undef USE_NSS_CRYPTO
73 #endif
74 #ifdef HAVE_GETENTROPY
75 #include <sys/random.h>
76 #endif
77 #ifdef HAVE_LINUX_RANDOM_H
78 #include <sys/syscall.h>
79 #include <linux/random.h>
80 #endif
81 #ifdef RNDGETENTCNT
82 #include <sys/ioctl.h>
83 #endif
84 
85 /* Take some reasonable steps to attempt to *seed* random number generators with
86  * cryptographically random data.  Some of these initialization routines may
87  * block, and are intended to be called only at startup in lighttpd, or
88  * immediately after fork() to start lighttpd workers.
89  *
90  * Update: li_rand_init() is now deferred until first use so that installations
91  * that do not use modules which use these routines do need to potentially block
92  * at startup.  Current use by core lighttpd modules is in mod_auth HTTP Digest
93  * auth and in mod_usertrack.  Deferring collection of random data until first
94  * use may allow sufficient entropy to be collected by kernel before first use,
95  * helping reduce or avoid situations in low-entropy-generating embedded devices
96  * which might otherwise block lighttpd for minutes at device startup.
97  * Further discussion in https://redmine.lighttpd.net/boards/2/topics/6981
98  *
99  * Note: results from li_rand_pseudo_bytes() are not necessarily
100  * cryptographically random and must not be used for purposes such
101  * as key generation which require cryptographic randomness.
102  *
103  * https://wiki.openssl.org/index.php/Random_Numbers
104  * https://wiki.openssl.org/index.php/Random_fork-safety
105  *
106  * openssl random number generators are not thread-safe by default
107  * https://wiki.openssl.org/index.php/Manual:Threads(3)
108  *
109  * RFE: add more paranoid checks from the following to improve confidence:
110  * http://insanecoding.blogspot.co.uk/2014/05/a-good-idea-with-bad-usage-devurandom.html
111  * RFE: retry on EINTR
112  * RFE: check RAND_status()
113  */
114 
115 static int li_getentropy (void *buf, size_t buflen)
116 {
117   #ifdef HAVE_GETENTROPY
118     return getentropy(buf, buflen);
119   #else
120     /*(see NOTES section in 'man getrandom' on Linux)*/
121    #if defined(HAVE_GETRANDOM) || defined(SYS_getrandom)
122     if (buflen <= 256) {
123       #ifdef HAVE_GETRANDOM /*(not implemented in glibc yet)*/
124         int num = getrandom(buf, buflen, 0);
125       #elif defined(SYS_getrandom)
126         /* https://lwn.net/Articles/605828/ */
127         /* https://bbs.archlinux.org/viewtopic.php?id=200039 */
128         int num = (int)syscall(SYS_getrandom, buf, buflen, 0);
129       #endif
130         if (num == (int)buflen) return 0;
131         if (num < 0)            return num; /* -1 */
132     }
133    #else
134     UNUSED(buf);
135     UNUSED(buflen);
136    #endif
137     errno = EIO;
138     return -1;
139   #endif
140 }
141 
142 static int li_rand_device_bytes (unsigned char *buf, int num)
143 {
144     /* randomness from these devices is cryptographically strong,
145      * unless /dev/urandom is low on entropy */
146 
147     static const char * const devices[] = {
148       #ifdef __OpenBSD__
149         "/dev/arandom",
150       #endif
151         "/dev/urandom",
152         "/dev/random"
153     };
154 
155     /* device files might not be available in chroot environment,
156      * so prefer syscall, if available */
157     if (0 == li_getentropy(buf, (size_t)num)) return 1;
158 
159     for (unsigned int u = 0; u < sizeof(devices)/sizeof(devices[0]); ++u) {
160         /*(some systems might have symlink to another device; omit O_NOFOLLOW)*/
161         int fd = fdevent_open_cloexec(devices[u], 1, O_RDONLY, 0);
162         if (fd >= 0) {
163             ssize_t rd = 0;
164           #ifdef RNDGETENTCNT
165             int entropy;
166             if (0 == ioctl(fd, (unsigned long)(RNDGETENTCNT), &entropy)
167                 && entropy >= num*8)
168           #endif
169                 rd = read(fd, buf, (size_t)num);
170             close(fd);
171             if (rd == num) {
172                 return 1;
173             }
174         }
175     }
176 
177     return 0;
178 }
179 
180 static int li_rand_inited;
181 static unsigned short xsubi[3];
182 #ifdef USE_MBEDTLS_CRYPTO
183 #ifdef MBEDTLS_ENTROPY_C
184 static mbedtls_entropy_context entropy;
185 #ifdef MBEDTLS_CTR_DRBG_C
186 static mbedtls_ctr_drbg_context ctr_drbg;
187 #endif
188 #endif
189 #endif
190 #ifdef USE_WOLFSSL_CRYPTO
191 static WC_RNG wolf_globalRNG;
192 #endif
193 #ifdef USE_NETTLE_CRYPTO
194 static struct knuth_lfib_ctx knuth_lfib_ctx;
195 static struct arcfour_ctx    arcfour_ctx;
196 static struct yarrow256_ctx  yarrow256_ctx;
197 #endif
198 
199 #ifdef USE_NETTLE_CRYPTO
200 /* adapted from Nettle documentation arcfour_set_key_hashed() in nettle.pdf */
201 /* A more robust key setup function for ARCFOUR */
202 static void
203 li_arcfour_init_random_key_hashed(struct arcfour_ctx *ctx)
204 {
205     uint8_t key[ARCFOUR_KEY_SIZE];
206     const size_t length = sizeof(key);
207     if (1 != li_rand_device_bytes(key, (int)sizeof(key))) {
208         ck_bt_abort(__FILE__, __LINE__,
209                     "gathering entropy for arcfour seed failed");
210     }
211     memset(ctx, 0, sizeof(*ctx));
212 
213     struct sha256_ctx hash;
214     uint8_t digest[SHA256_DIGEST_SIZE];
215     uint8_t buf[0x200];
216     memset(buf, 0, sizeof(buf));
217     sha256_init(&hash);
218     sha256_update(&hash, length, key);
219     sha256_digest(&hash, SHA256_DIGEST_SIZE, digest);
220     nettle_arcfour_set_key(ctx, SHA256_DIGEST_SIZE, digest);
221     nettle_arcfour_crypt(ctx, sizeof(buf), buf, buf);
222     nettle_arcfour_crypt(ctx, sizeof(buf), buf, buf);
223     nettle_arcfour_crypt(ctx, sizeof(buf), buf, buf);
224 }
225 #endif
226 
227 __attribute_cold__
228 static void li_rand_init (void)
229 {
230     /* (intended to be called at init and after fork() in order to re-seed PRNG
231      *  so that forked children, grandchildren, etc do not share PRNG seed)
232      * https://github.com/ramsey/uuid/issues/80
233      * https://www.agwa.name/blog/post/libressls_prng_is_unsafe_on_linux
234      *   (issue in early version of libressl has since been fixed)
235      * https://github.com/libressl-portable/portable/commit/32d9eeeecf4e951e1566d5f4a42b36ea37b60f35
236      */
237     unsigned int u;
238     li_rand_inited = 1;
239     if (1 == li_rand_device_bytes((unsigned char *)xsubi, (int)sizeof(xsubi))) {
240         u = ((unsigned int)xsubi[0] << 16) | xsubi[1];
241     }
242     else {
243       #ifdef HAVE_ARC4RANDOM_BUF
244         u = arc4random();
245         arc4random_buf(xsubi, sizeof(xsubi));
246       #elif defined(__COVERITY__)
247         /* Coverity Scan ignores(?) annotation below,
248          * so hide fallback path from Coverity Scan */
249         u = (unsigned int)(time(NULL) ^ getpid());
250       #else
251         /* NOTE: not cryptographically random !!! */
252         srand((unsigned int)(time(NULL) ^ getpid()));
253         for (u = 0; u < sizeof(unsigned short); ++u)
254             /* coverity[dont_call : FALSE] */
255             xsubi[u] = (unsigned short)(rand() & 0xFFFF);
256         u = ((unsigned int)xsubi[0] << 16) | xsubi[1];
257       #endif
258     }
259     srand(u);   /*(initialize just in case rand() used elsewhere)*/
260   #ifdef HAVE_SRANDOM
261     srandom(u); /*(initialize just in case random() used elsewhere)*/
262   #endif
263   #ifdef USE_NETTLE_CRYPTO
264     nettle_knuth_lfib_init(&knuth_lfib_ctx, u);
265     nettle_yarrow256_init(&yarrow256_ctx, 0, NULL);
266     li_arcfour_init_random_key_hashed(&arcfour_ctx);
267   #endif
268   #ifdef USE_WOLFSSL_CRYPTO
269     /* xsubi[] is small, so use wc_InitRng() instead of wc_InitRngNonce()
270      * to get default behavior of a larger internally-generated nonce */
271     if (0 != wolfCrypt_Init() || 0 != wc_InitRng(&wolf_globalRNG))
272         ck_bt_abort(__FILE__,__LINE__,"wolfCrypt_Init or wc_InitRng() failed");
273   #endif
274   #ifdef USE_OPENSSL_CRYPTO
275     RAND_poll();
276     RAND_seed(xsubi, (int)sizeof(xsubi));
277   #endif
278   #ifdef USE_MBEDTLS_CRYPTO
279   #ifdef MBEDTLS_ENTROPY_C
280     mbedtls_entropy_init(&entropy);
281   #ifdef MBEDTLS_CTR_DRBG_C
282     mbedtls_ctr_drbg_init(&ctr_drbg);
283     int rc =
284       mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
285                             (unsigned char *)xsubi, sizeof(xsubi));
286     if (0 != rc) /*(not expecting built-in entropy function to fail)*/
287         ck_bt_abort(__FILE__, __LINE__, "mbedtls_ctr_drbg_seed() failed");
288   #endif
289   #endif
290   #endif
291   #ifdef USE_NSS_CRYPTO
292     if (!NSS_IsInitialized() && NSS_NoDB_Init(NULL) < 0)
293         ck_bt_abort(__FILE__, __LINE__, "aborted");
294     PK11_RandomUpdate(xsubi, sizeof(xsubi));
295   #endif
296 }
297 
298 void li_rand_reseed (void)
299 {
300   #ifdef USE_GNUTLS_CRYPTO
301     gnutls_rnd_refresh();
302     return;
303   #endif
304   #ifdef USE_WOLFSSL_CRYPTO
305     if (li_rand_inited) {
306       #if 0 /*(wc_RNG_DRBG_Reseed() is not part of public API)*/
307         /*(XXX: might use stack to procure larger seed;
308          * xsubi[] is short (6 bytes)) */
309         if (1 == li_rand_device_bytes((unsigned char *)xsubi,
310                                       (int)sizeof(xsubi))) {
311             if (0 != wc_RNG_DRBG_Reseed(&wolf_globalRNG,
312                                         (const byte *)xsubi,
313                                         (word32)sizeof(xsubi)))
314                 /*(not expecting this to fail)*/
315                 ck_bt_abort(__FILE__, __LINE__, "wc_RNG_DRBG_Reseed() failed");
316         }
317       #else
318         wc_FreeRng(&wolf_globalRNG);
319         if (0 != wc_InitRng(&wolf_globalRNG))
320             ck_bt_abort(__FILE__, __LINE__, "wc_InitRng() failed");
321       #endif
322         return;
323     }
324   #endif
325   #ifdef USE_MBEDTLS_CRYPTO
326     if (li_rand_inited) {
327       #ifdef MBEDTLS_ENTROPY_C
328       #ifdef MBEDTLS_CTR_DRBG_C
329         mbedtls_ctr_drbg_free(&ctr_drbg);
330       #endif
331         mbedtls_entropy_free(&entropy);
332       #endif
333     }
334   #endif
335     if (li_rand_inited) li_rand_init();
336 }
337 
338 int li_rand_pseudo (void)
339 {
340   #ifdef USE_GNUTLS_CRYPTO
341     int i;
342     if (0 == gnutls_rnd(GNUTLS_RND_NONCE, &i, sizeof(i))) return i;
343   #endif
344     if (!li_rand_inited) li_rand_init();
345     /* randomness *is not* cryptographically strong */
346     /* (attempt to use better mechanisms to replace the more portable rand()) */
347   #ifdef USE_OPENSSL_CRYPTO /* (openssl 1.1.0 deprecates RAND_pseudo_bytes()) */
348   #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
349     int i;
350     if (-1 != RAND_pseudo_bytes((unsigned char *)&i, sizeof(i))) return i;
351   #endif
352   #endif
353   #ifdef USE_WOLFSSL_CRYPTO
354     /* RAND_pseudo_bytes() in WolfSSL is equivalent to RAND_bytes() */
355     int i;
356     if (0 == wc_RNG_GenerateBlock(&wolf_globalRNG,(byte *)&i,(word32)sizeof(i)))
357         return i;
358   #endif
359   #ifdef USE_NETTLE_CRYPTO
360     int i = (int)nettle_knuth_lfib_get(&knuth_lfib_ctx);
361     nettle_arcfour_crypt(&arcfour_ctx, sizeof(i), (uint8_t *)&i, (uint8_t *)&i);
362     if (i) return i; /*(cond to avoid compiler warning for code after return)*/
363   #endif
364   #ifdef USE_MBEDTLS_CRYPTO
365   #ifdef MBEDTLS_CTR_DRBG_C
366     int i;
367     if (0 == mbedtls_ctr_drbg_random(&ctr_drbg, (unsigned char *)&i, sizeof(i)))
368         return i;
369   #endif
370   #endif
371   #ifdef USE_NSS_CRYPTO
372     int i;
373     if (SECSuccess == PK11_GenerateRandom((unsigned char *)&i, sizeof(i)))
374         return i;
375   #endif
376   #ifdef HAVE_ARC4RANDOM_BUF
377     return (int)arc4random();
378   #elif defined(__COVERITY__)
379     /* li_rand_pseudo() is not intended for cryptographic use */
380     /* Coverity Scan ignores(?) annotation below,
381      * so hide fallback paths from Coverity Scan */
382     return (int)(time(NULL) ^ getpid());
383   #elif defined(HAVE_SRANDOM)
384     /* coverity[dont_call : FALSE] */
385     return (int)random();
386   #elif defined(HAVE_JRAND48)
387     /*(FYI: jrand48() reentrant, but use of file-scoped static xsubi[] is not)*/
388     /* coverity[dont_call : FALSE] */
389     return (int)jrand48(xsubi);
390   #else
391     /* coverity[dont_call : FALSE] */
392     return rand();
393   #endif
394 }
395 
396 void li_rand_pseudo_bytes (unsigned char *buf, int num)
397 {
398   #ifdef USE_GNUTLS_CRYPTO
399     if (0 == gnutls_rnd(GNUTLS_RND_NONCE, buf, (size_t)num)) return;
400   #endif
401     if (!li_rand_inited) li_rand_init();
402   #ifdef USE_NSS_CRYPTO
403     if (SECSuccess == PK11_GenerateRandom(buf, num)) return;
404   #endif
405   #ifdef USE_MBEDTLS_CRYPTO
406   #ifdef MBEDTLS_CTR_DRBG_C
407     if (0 == mbedtls_ctr_drbg_random(&ctr_drbg, buf, (size_t)num)) return;
408   #endif
409   #endif
410   #ifdef USE_WOLFSSL_CRYPTO
411     /* RAND_pseudo_bytes() in WolfSSL is equivalent to RAND_bytes() */
412     if (0 == wc_RNG_GenerateBlock(&wolf_globalRNG, (byte *)buf, (word32)num))
413         return;
414   #endif
415     for (int i = 0; i < num; ++i)
416         buf[i] = li_rand_pseudo() & 0xFF;
417 }
418 
419 int li_rand_bytes (unsigned char *buf, int num)
420 {
421   #ifdef USE_GNUTLS_CRYPTO /* should use GNUTLS_RND_KEY for long-term keys */
422     if (0 == gnutls_rnd(GNUTLS_RND_RANDOM, buf, (size_t)num)) return 1;
423   #endif
424   #ifdef USE_NSS_CRYPTO
425     if (!li_rand_inited) li_rand_init();
426     if (SECSuccess == PK11_GenerateRandom(buf, num)) return 1;
427   #endif
428   #ifdef USE_NETTLE_CRYPTO
429   #if 0 /* not implemented: periodic nettle_yarrow256_update() and reseed */
430     if (!nettle_yarrow256_is_seeded(&yarrow256_ctx)) {
431         uint8_t seed_file[YARROW256_SEED_FILE_SIZE];
432         if (1 == li_rand_device_bytes((unsigned char *)seed_file,
433                                       (int)sizeof(seed_file))) {
434             nettle_yarrow256_seed(&yarrow256_ctx, sizeof(seed_file), seed_file);
435         }
436     }
437     if (nettle_yarrow256_is_seeded(&yarrow256_ctx)) {
438         nettle_yarrow256_random(&yarrow256_ctx, (size_t)num, (uint8_t *)buf);
439         return 1;
440     }
441   #endif
442   #endif
443   #ifdef USE_OPENSSL_CRYPTO
444     int rc = RAND_bytes(buf, num);
445     if (-1 != rc) {
446         return rc;
447     }
448   #endif
449   #ifdef USE_WOLFSSL_CRYPTO
450     if (0 == wc_RNG_GenerateBlock(&wolf_globalRNG, (byte *)buf, (word32)num)) {
451         return 1;
452     }
453   #endif
454   #ifdef USE_MBEDTLS_CRYPTO
455   #ifdef MBEDTLS_ENTROPY_C
456     /*(each call <= MBEDTLS_ENTROPY_BLOCK_SIZE; could implement loop here)*/
457     if (num <= MBEDTLS_ENTROPY_BLOCK_SIZE
458         && 0 == mbedtls_entropy_func(&entropy, buf, (size_t)num)) {
459         return 1;
460     }
461   #endif
462   #endif
463     if (1 == li_rand_device_bytes(buf, num)) {
464         return 1;
465     }
466     else {
467         /* NOTE: not cryptographically random !!! */
468         li_rand_pseudo_bytes(buf, num);
469         /*(openssl RAND_pseudo_bytes rc for non-cryptographically random data)*/
470         return 0;
471     }
472 }
473 
474 void li_rand_cleanup (void)
475 {
476   #ifdef USE_WOLFSSL_CRYPTO
477     if (li_rand_inited) {
478         wc_FreeRng(&wolf_globalRNG);
479         wolfCrypt_Cleanup();
480         li_rand_inited = 0;
481     }
482   #endif
483   #ifdef USE_OPENSSL_CRYPTO
484   #if OPENSSL_VERSION_NUMBER < 0x10100000L
485     RAND_cleanup();
486   #endif
487   #endif
488   #ifdef USE_MBEDTLS_CRYPTO
489   #ifdef MBEDTLS_ENTROPY_C
490   #ifdef MBEDTLS_CTR_DRBG_C
491     mbedtls_ctr_drbg_free(&ctr_drbg);
492   #endif
493     mbedtls_entropy_free(&entropy);
494   #endif
495   #endif
496     ck_memzero(xsubi, sizeof(xsubi));
497 }
498