xref: /freebsd/crypto/openssl/providers/implementations/rands/seeding/rand_unix.c (revision e7be843b4a162e68651d3911f0357ed464915629)
1b077aed3SPierre Pronchery /*
2*e7be843bSPierre Pronchery  * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
3b077aed3SPierre Pronchery  *
4b077aed3SPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5b077aed3SPierre Pronchery  * this file except in compliance with the License.  You can obtain a copy
6b077aed3SPierre Pronchery  * in the file LICENSE in the source distribution or at
7b077aed3SPierre Pronchery  * https://www.openssl.org/source/license.html
8b077aed3SPierre Pronchery  */
9b077aed3SPierre Pronchery 
10b077aed3SPierre Pronchery #ifndef _GNU_SOURCE
11b077aed3SPierre Pronchery # define _GNU_SOURCE
12b077aed3SPierre Pronchery #endif
13*e7be843bSPierre Pronchery #include "internal/e_os.h"
14b077aed3SPierre Pronchery #include <stdio.h>
15b077aed3SPierre Pronchery #include "internal/cryptlib.h"
16b077aed3SPierre Pronchery #include <openssl/rand.h>
17b077aed3SPierre Pronchery #include <openssl/crypto.h>
18b077aed3SPierre Pronchery #include "crypto/rand_pool.h"
19b077aed3SPierre Pronchery #include "crypto/rand.h"
20b077aed3SPierre Pronchery #include "internal/dso.h"
21*e7be843bSPierre Pronchery #include "internal/nelem.h"
22b077aed3SPierre Pronchery #include "prov/seeding.h"
23b077aed3SPierre Pronchery 
24*e7be843bSPierre Pronchery #ifndef OPENSSL_SYS_UEFI
25b077aed3SPierre Pronchery # ifdef __linux
26b077aed3SPierre Pronchery #  include <sys/syscall.h>
27b077aed3SPierre Pronchery #  ifdef DEVRANDOM_WAIT
28b077aed3SPierre Pronchery #   include <sys/shm.h>
29b077aed3SPierre Pronchery #   include <sys/utsname.h>
30b077aed3SPierre Pronchery #  endif
31b077aed3SPierre Pronchery # endif
32*e7be843bSPierre Pronchery # if defined(__FreeBSD__) || defined(__NetBSD__)
33b077aed3SPierre Pronchery #  include <sys/types.h>
34b077aed3SPierre Pronchery #  include <sys/sysctl.h>
35b077aed3SPierre Pronchery #  include <sys/param.h>
36b077aed3SPierre Pronchery # endif
37*e7be843bSPierre Pronchery # if defined(__FreeBSD__) && __FreeBSD_version >= 1200061
38*e7be843bSPierre Pronchery #  include <sys/random.h>
39*e7be843bSPierre Pronchery # endif
40b077aed3SPierre Pronchery # if defined(__OpenBSD__)
41b077aed3SPierre Pronchery #  include <sys/param.h>
42b077aed3SPierre Pronchery # endif
43*e7be843bSPierre Pronchery # if defined(__DragonFly__)
44b077aed3SPierre Pronchery #  include <sys/param.h>
45b077aed3SPierre Pronchery #  include <sys/random.h>
46b077aed3SPierre Pronchery # endif
47*e7be843bSPierre Pronchery #endif
48b077aed3SPierre Pronchery 
49b077aed3SPierre Pronchery #if (defined(OPENSSL_SYS_UNIX) && !defined(OPENSSL_SYS_VXWORKS)) \
50b077aed3SPierre Pronchery      || defined(__DJGPP__)
51b077aed3SPierre Pronchery # include <sys/types.h>
52b077aed3SPierre Pronchery # include <sys/stat.h>
53b077aed3SPierre Pronchery # include <fcntl.h>
54b077aed3SPierre Pronchery # include <unistd.h>
55b077aed3SPierre Pronchery # include <sys/time.h>
56b077aed3SPierre Pronchery 
57b077aed3SPierre Pronchery static uint64_t get_time_stamp(void);
58b077aed3SPierre Pronchery 
59b077aed3SPierre Pronchery /* Macro to convert two thirty two bit values into a sixty four bit one */
60b077aed3SPierre Pronchery # define TWO32TO64(a, b) ((((uint64_t)(a)) << 32) + (b))
61b077aed3SPierre Pronchery 
62b077aed3SPierre Pronchery /*
63b077aed3SPierre Pronchery  * Check for the existence and support of POSIX timers.  The standard
64b077aed3SPierre Pronchery  * says that the _POSIX_TIMERS macro will have a positive value if they
65b077aed3SPierre Pronchery  * are available.
66b077aed3SPierre Pronchery  *
67b077aed3SPierre Pronchery  * However, we want an additional constraint: that the timer support does
68b077aed3SPierre Pronchery  * not require an extra library dependency.  Early versions of glibc
69b077aed3SPierre Pronchery  * require -lrt to be specified on the link line to access the timers,
70b077aed3SPierre Pronchery  * so this needs to be checked for.
71b077aed3SPierre Pronchery  *
72b077aed3SPierre Pronchery  * It is worse because some libraries define __GLIBC__ but don't
73b077aed3SPierre Pronchery  * support the version testing macro (e.g. uClibc).  This means
74b077aed3SPierre Pronchery  * an extra check is needed.
75b077aed3SPierre Pronchery  *
76b077aed3SPierre Pronchery  * The final condition is:
77b077aed3SPierre Pronchery  *      "have posix timers and either not glibc or glibc without -lrt"
78b077aed3SPierre Pronchery  *
79b077aed3SPierre Pronchery  * The nested #if sequences are required to avoid using a parameterised
80b077aed3SPierre Pronchery  * macro that might be undefined.
81b077aed3SPierre Pronchery  */
82b077aed3SPierre Pronchery # undef OSSL_POSIX_TIMER_OKAY
83b077aed3SPierre Pronchery /* On some systems, _POSIX_TIMERS is defined but empty.
84b077aed3SPierre Pronchery  * Subtracting by 0 when comparing avoids an error in this case. */
85b077aed3SPierre Pronchery # if defined(_POSIX_TIMERS) && _POSIX_TIMERS -0 > 0
86b077aed3SPierre Pronchery #  if defined(__GLIBC__)
87b077aed3SPierre Pronchery #   if defined(__GLIBC_PREREQ)
88b077aed3SPierre Pronchery #    if __GLIBC_PREREQ(2, 17)
89b077aed3SPierre Pronchery #     define OSSL_POSIX_TIMER_OKAY
90b077aed3SPierre Pronchery #    endif
91b077aed3SPierre Pronchery #   endif
92b077aed3SPierre Pronchery #  else
93b077aed3SPierre Pronchery #   define OSSL_POSIX_TIMER_OKAY
94b077aed3SPierre Pronchery #  endif
95b077aed3SPierre Pronchery # endif
96b077aed3SPierre Pronchery #endif /* (defined(OPENSSL_SYS_UNIX) && !defined(OPENSSL_SYS_VXWORKS))
97b077aed3SPierre Pronchery           || defined(__DJGPP__) */
98b077aed3SPierre Pronchery 
99b077aed3SPierre Pronchery #if defined(OPENSSL_RAND_SEED_NONE)
100b077aed3SPierre Pronchery /* none means none. this simplifies the following logic */
101b077aed3SPierre Pronchery # undef OPENSSL_RAND_SEED_OS
102b077aed3SPierre Pronchery # undef OPENSSL_RAND_SEED_GETRANDOM
103b077aed3SPierre Pronchery # undef OPENSSL_RAND_SEED_DEVRANDOM
104b077aed3SPierre Pronchery # undef OPENSSL_RAND_SEED_RDTSC
105b077aed3SPierre Pronchery # undef OPENSSL_RAND_SEED_RDCPU
106b077aed3SPierre Pronchery # undef OPENSSL_RAND_SEED_EGD
107b077aed3SPierre Pronchery #endif
108b077aed3SPierre Pronchery 
109b077aed3SPierre Pronchery #if defined(OPENSSL_SYS_UEFI) && !defined(OPENSSL_RAND_SEED_NONE)
110b077aed3SPierre Pronchery # error "UEFI only supports seeding NONE"
111b077aed3SPierre Pronchery #endif
112b077aed3SPierre Pronchery 
113b077aed3SPierre Pronchery #if !(defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) \
114b077aed3SPierre Pronchery     || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_VXWORKS) \
115b077aed3SPierre Pronchery     || defined(OPENSSL_SYS_UEFI))
116b077aed3SPierre Pronchery 
117b077aed3SPierre Pronchery # if defined(OPENSSL_SYS_VOS)
118b077aed3SPierre Pronchery 
119b077aed3SPierre Pronchery #  ifndef OPENSSL_RAND_SEED_OS
120b077aed3SPierre Pronchery #   error "Unsupported seeding method configured; must be os"
121b077aed3SPierre Pronchery #  endif
122b077aed3SPierre Pronchery 
123b077aed3SPierre Pronchery #  if defined(OPENSSL_SYS_VOS_HPPA) && defined(OPENSSL_SYS_VOS_IA32)
124b077aed3SPierre Pronchery #   error "Unsupported HP-PA and IA32 at the same time."
125b077aed3SPierre Pronchery #  endif
126b077aed3SPierre Pronchery #  if !defined(OPENSSL_SYS_VOS_HPPA) && !defined(OPENSSL_SYS_VOS_IA32)
127b077aed3SPierre Pronchery #   error "Must have one of HP-PA or IA32"
128b077aed3SPierre Pronchery #  endif
129b077aed3SPierre Pronchery 
130b077aed3SPierre Pronchery /*
131b077aed3SPierre Pronchery  * The following algorithm repeatedly samples the real-time clock (RTC) to
132b077aed3SPierre Pronchery  * generate a sequence of unpredictable data.  The algorithm relies upon the
133b077aed3SPierre Pronchery  * uneven execution speed of the code (due to factors such as cache misses,
134b077aed3SPierre Pronchery  * interrupts, bus activity, and scheduling) and upon the rather large
135b077aed3SPierre Pronchery  * relative difference between the speed of the clock and the rate at which
136b077aed3SPierre Pronchery  * it can be read.  If it is ported to an environment where execution speed
137b077aed3SPierre Pronchery  * is more constant or where the RTC ticks at a much slower rate, or the
138b077aed3SPierre Pronchery  * clock can be read with fewer instructions, it is likely that the results
139b077aed3SPierre Pronchery  * would be far more predictable.  This should only be used for legacy
140b077aed3SPierre Pronchery  * platforms.
141b077aed3SPierre Pronchery  *
142b077aed3SPierre Pronchery  * As a precaution, we assume only 2 bits of entropy per byte.
143b077aed3SPierre Pronchery  */
ossl_pool_acquire_entropy(RAND_POOL * pool)144b077aed3SPierre Pronchery size_t ossl_pool_acquire_entropy(RAND_POOL *pool)
145b077aed3SPierre Pronchery {
146b077aed3SPierre Pronchery     short int code;
147b077aed3SPierre Pronchery     int i, k;
148b077aed3SPierre Pronchery     size_t bytes_needed;
149b077aed3SPierre Pronchery     struct timespec ts;
150b077aed3SPierre Pronchery     unsigned char v;
151b077aed3SPierre Pronchery #  ifdef OPENSSL_SYS_VOS_HPPA
152b077aed3SPierre Pronchery     long duration;
153b077aed3SPierre Pronchery     extern void s$sleep(long *_duration, short int *_code);
154b077aed3SPierre Pronchery #  else
155b077aed3SPierre Pronchery     long long duration;
156b077aed3SPierre Pronchery     extern void s$sleep2(long long *_duration, short int *_code);
157b077aed3SPierre Pronchery #  endif
158b077aed3SPierre Pronchery 
159b077aed3SPierre Pronchery     bytes_needed = ossl_rand_pool_bytes_needed(pool, 4 /*entropy_factor*/);
160b077aed3SPierre Pronchery 
161b077aed3SPierre Pronchery     for (i = 0; i < bytes_needed; i++) {
162b077aed3SPierre Pronchery         /*
163b077aed3SPierre Pronchery          * burn some cpu; hope for interrupts, cache collisions, bus
164b077aed3SPierre Pronchery          * interference, etc.
165b077aed3SPierre Pronchery          */
166b077aed3SPierre Pronchery         for (k = 0; k < 99; k++)
167b077aed3SPierre Pronchery             ts.tv_nsec = random();
168b077aed3SPierre Pronchery 
169b077aed3SPierre Pronchery #  ifdef OPENSSL_SYS_VOS_HPPA
170b077aed3SPierre Pronchery         /* sleep for 1/1024 of a second (976 us).  */
171b077aed3SPierre Pronchery         duration = 1;
172b077aed3SPierre Pronchery         s$sleep(&duration, &code);
173b077aed3SPierre Pronchery #  else
174b077aed3SPierre Pronchery         /* sleep for 1/65536 of a second (15 us).  */
175b077aed3SPierre Pronchery         duration = 1;
176b077aed3SPierre Pronchery         s$sleep2(&duration, &code);
177b077aed3SPierre Pronchery #  endif
178b077aed3SPierre Pronchery 
179b077aed3SPierre Pronchery         /* Get wall clock time, take 8 bits. */
180b077aed3SPierre Pronchery         clock_gettime(CLOCK_REALTIME, &ts);
181b077aed3SPierre Pronchery         v = (unsigned char)(ts.tv_nsec & 0xFF);
182b077aed3SPierre Pronchery         ossl_rand_pool_add(pool, arg, &v, sizeof(v), 2);
183b077aed3SPierre Pronchery     }
184b077aed3SPierre Pronchery     return ossl_rand_pool_entropy_available(pool);
185b077aed3SPierre Pronchery }
186b077aed3SPierre Pronchery 
ossl_rand_pool_cleanup(void)187b077aed3SPierre Pronchery void ossl_rand_pool_cleanup(void)
188b077aed3SPierre Pronchery {
189b077aed3SPierre Pronchery }
190b077aed3SPierre Pronchery 
ossl_rand_pool_keep_random_devices_open(int keep)191b077aed3SPierre Pronchery void ossl_rand_pool_keep_random_devices_open(int keep)
192b077aed3SPierre Pronchery {
193b077aed3SPierre Pronchery }
194b077aed3SPierre Pronchery 
195b077aed3SPierre Pronchery # else
196b077aed3SPierre Pronchery 
197b077aed3SPierre Pronchery #  if defined(OPENSSL_RAND_SEED_EGD) && \
198b077aed3SPierre Pronchery         (defined(OPENSSL_NO_EGD) || !defined(DEVRANDOM_EGD))
199b077aed3SPierre Pronchery #   error "Seeding uses EGD but EGD is turned off or no device given"
200b077aed3SPierre Pronchery #  endif
201b077aed3SPierre Pronchery 
202b077aed3SPierre Pronchery #  if defined(OPENSSL_RAND_SEED_DEVRANDOM) && !defined(DEVRANDOM)
203b077aed3SPierre Pronchery #   error "Seeding uses urandom but DEVRANDOM is not configured"
204b077aed3SPierre Pronchery #  endif
205b077aed3SPierre Pronchery 
206b077aed3SPierre Pronchery #  if defined(OPENSSL_RAND_SEED_OS)
207b077aed3SPierre Pronchery #   if !defined(DEVRANDOM)
208b077aed3SPierre Pronchery #    error "OS seeding requires DEVRANDOM to be configured"
209b077aed3SPierre Pronchery #   endif
210b077aed3SPierre Pronchery #   define OPENSSL_RAND_SEED_GETRANDOM
211b077aed3SPierre Pronchery #   define OPENSSL_RAND_SEED_DEVRANDOM
212b077aed3SPierre Pronchery #  endif
213b077aed3SPierre Pronchery 
214*e7be843bSPierre Pronchery #  if (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(KERN_ARND)
215b077aed3SPierre Pronchery /*
216b077aed3SPierre Pronchery  * sysctl_random(): Use sysctl() to read a random number from the kernel
217b077aed3SPierre Pronchery  * Returns the number of bytes returned in buf on success, -1 on failure.
218b077aed3SPierre Pronchery  */
sysctl_random(char * buf,size_t buflen)219b077aed3SPierre Pronchery static ssize_t sysctl_random(char *buf, size_t buflen)
220b077aed3SPierre Pronchery {
221b077aed3SPierre Pronchery     int mib[2];
222b077aed3SPierre Pronchery     size_t done = 0;
223b077aed3SPierre Pronchery     size_t len;
224b077aed3SPierre Pronchery 
225b077aed3SPierre Pronchery     /*
226b077aed3SPierre Pronchery      * Note: sign conversion between size_t and ssize_t is safe even
227b077aed3SPierre Pronchery      * without a range check, see comment in syscall_random()
228b077aed3SPierre Pronchery      */
229b077aed3SPierre Pronchery 
230b077aed3SPierre Pronchery     /*
231b077aed3SPierre Pronchery      * On FreeBSD old implementations returned longs, newer versions support
232b077aed3SPierre Pronchery      * variable sizes up to 256 byte. The code below would not work properly
233b077aed3SPierre Pronchery      * when the sysctl returns long and we want to request something not a
234b077aed3SPierre Pronchery      * multiple of longs, which should never be the case.
235b077aed3SPierre Pronchery      */
236b077aed3SPierre Pronchery #if   defined(__FreeBSD__)
237b077aed3SPierre Pronchery     if (!ossl_assert(buflen % sizeof(long) == 0)) {
238b077aed3SPierre Pronchery         errno = EINVAL;
239b077aed3SPierre Pronchery         return -1;
240b077aed3SPierre Pronchery     }
241b077aed3SPierre Pronchery #endif
242b077aed3SPierre Pronchery 
243b077aed3SPierre Pronchery     /*
244b077aed3SPierre Pronchery      * On NetBSD before 4.0 KERN_ARND was an alias for KERN_URND, and only
245b077aed3SPierre Pronchery      * filled in an int, leaving the rest uninitialized. Since NetBSD 4.0
246b077aed3SPierre Pronchery      * it returns a variable number of bytes with the current version supporting
247b077aed3SPierre Pronchery      * up to 256 bytes.
248b077aed3SPierre Pronchery      * Just return an error on older NetBSD versions.
249b077aed3SPierre Pronchery      */
250b077aed3SPierre Pronchery #if   defined(__NetBSD__) && __NetBSD_Version__ < 400000000
251b077aed3SPierre Pronchery     errno = ENOSYS;
252b077aed3SPierre Pronchery     return -1;
253b077aed3SPierre Pronchery #endif
254b077aed3SPierre Pronchery 
255b077aed3SPierre Pronchery     mib[0] = CTL_KERN;
256b077aed3SPierre Pronchery     mib[1] = KERN_ARND;
257b077aed3SPierre Pronchery 
258b077aed3SPierre Pronchery     do {
259b077aed3SPierre Pronchery         len = buflen > 256 ? 256 : buflen;
260b077aed3SPierre Pronchery         if (sysctl(mib, 2, buf, &len, NULL, 0) == -1)
261b077aed3SPierre Pronchery             return done > 0 ? done : -1;
262b077aed3SPierre Pronchery         done += len;
263b077aed3SPierre Pronchery         buf += len;
264b077aed3SPierre Pronchery         buflen -= len;
265b077aed3SPierre Pronchery     } while (buflen > 0);
266b077aed3SPierre Pronchery 
267b077aed3SPierre Pronchery     return done;
268b077aed3SPierre Pronchery }
269b077aed3SPierre Pronchery #  endif
270b077aed3SPierre Pronchery 
271b077aed3SPierre Pronchery #  if defined(OPENSSL_RAND_SEED_GETRANDOM)
272b077aed3SPierre Pronchery 
273b077aed3SPierre Pronchery #   if defined(__linux) && !defined(__NR_getrandom)
274b077aed3SPierre Pronchery #    if defined(__arm__)
275b077aed3SPierre Pronchery #     define __NR_getrandom    (__NR_SYSCALL_BASE+384)
276b077aed3SPierre Pronchery #    elif defined(__i386__)
277b077aed3SPierre Pronchery #     define __NR_getrandom    355
278b077aed3SPierre Pronchery #    elif defined(__x86_64__)
279b077aed3SPierre Pronchery #     if defined(__ILP32__)
280b077aed3SPierre Pronchery #      define __NR_getrandom   (__X32_SYSCALL_BIT + 318)
281b077aed3SPierre Pronchery #     else
282b077aed3SPierre Pronchery #      define __NR_getrandom   318
283b077aed3SPierre Pronchery #     endif
284b077aed3SPierre Pronchery #    elif defined(__xtensa__)
285b077aed3SPierre Pronchery #     define __NR_getrandom    338
286b077aed3SPierre Pronchery #    elif defined(__s390__) || defined(__s390x__)
287b077aed3SPierre Pronchery #     define __NR_getrandom    349
288b077aed3SPierre Pronchery #    elif defined(__bfin__)
289b077aed3SPierre Pronchery #     define __NR_getrandom    389
290b077aed3SPierre Pronchery #    elif defined(__powerpc__)
291b077aed3SPierre Pronchery #     define __NR_getrandom    359
292b077aed3SPierre Pronchery #    elif defined(__mips__) || defined(__mips64)
293b077aed3SPierre Pronchery #     if _MIPS_SIM == _MIPS_SIM_ABI32
294b077aed3SPierre Pronchery #      define __NR_getrandom   (__NR_Linux + 353)
295b077aed3SPierre Pronchery #     elif _MIPS_SIM == _MIPS_SIM_ABI64
296b077aed3SPierre Pronchery #      define __NR_getrandom   (__NR_Linux + 313)
297b077aed3SPierre Pronchery #     elif _MIPS_SIM == _MIPS_SIM_NABI32
298b077aed3SPierre Pronchery #      define __NR_getrandom   (__NR_Linux + 317)
299b077aed3SPierre Pronchery #     endif
300b077aed3SPierre Pronchery #    elif defined(__hppa__)
301b077aed3SPierre Pronchery #     define __NR_getrandom    (__NR_Linux + 339)
302b077aed3SPierre Pronchery #    elif defined(__sparc__)
303b077aed3SPierre Pronchery #     define __NR_getrandom    347
304b077aed3SPierre Pronchery #    elif defined(__ia64__)
305b077aed3SPierre Pronchery #     define __NR_getrandom    1339
306b077aed3SPierre Pronchery #    elif defined(__alpha__)
307b077aed3SPierre Pronchery #     define __NR_getrandom    511
308b077aed3SPierre Pronchery #    elif defined(__sh__)
309b077aed3SPierre Pronchery #     if defined(__SH5__)
310b077aed3SPierre Pronchery #      define __NR_getrandom   373
311b077aed3SPierre Pronchery #     else
312b077aed3SPierre Pronchery #      define __NR_getrandom   384
313b077aed3SPierre Pronchery #     endif
314b077aed3SPierre Pronchery #    elif defined(__avr32__)
315b077aed3SPierre Pronchery #     define __NR_getrandom    317
316b077aed3SPierre Pronchery #    elif defined(__microblaze__)
317b077aed3SPierre Pronchery #     define __NR_getrandom    385
318b077aed3SPierre Pronchery #    elif defined(__m68k__)
319b077aed3SPierre Pronchery #     define __NR_getrandom    352
320b077aed3SPierre Pronchery #    elif defined(__cris__)
321b077aed3SPierre Pronchery #     define __NR_getrandom    356
322*e7be843bSPierre Pronchery #    else /* generic (f.e. aarch64, loongarch, loongarch64) */
323b077aed3SPierre Pronchery #     define __NR_getrandom    278
324b077aed3SPierre Pronchery #    endif
325b077aed3SPierre Pronchery #   endif
326b077aed3SPierre Pronchery 
327b077aed3SPierre Pronchery /*
328b077aed3SPierre Pronchery  * syscall_random(): Try to get random data using a system call
329b077aed3SPierre Pronchery  * returns the number of bytes returned in buf, or < 0 on error.
330b077aed3SPierre Pronchery  */
syscall_random(void * buf,size_t buflen)331b077aed3SPierre Pronchery static ssize_t syscall_random(void *buf, size_t buflen)
332b077aed3SPierre Pronchery {
333b077aed3SPierre Pronchery     /*
334b077aed3SPierre Pronchery      * Note: 'buflen' equals the size of the buffer which is used by the
335b077aed3SPierre Pronchery      * get_entropy() callback of the RAND_DRBG. It is roughly bounded by
336b077aed3SPierre Pronchery      *
337b077aed3SPierre Pronchery      *   2 * RAND_POOL_FACTOR * (RAND_DRBG_STRENGTH / 8) = 2^14
338b077aed3SPierre Pronchery      *
339b077aed3SPierre Pronchery      * which is way below the OSSL_SSIZE_MAX limit. Therefore sign conversion
340b077aed3SPierre Pronchery      * between size_t and ssize_t is safe even without a range check.
341b077aed3SPierre Pronchery      */
342b077aed3SPierre Pronchery 
343b077aed3SPierre Pronchery     /*
344b077aed3SPierre Pronchery      * Do runtime detection to find getentropy().
345b077aed3SPierre Pronchery      *
346b077aed3SPierre Pronchery      * Known OSs that should support this:
347b077aed3SPierre Pronchery      * - Darwin since 16 (OSX 10.12, IOS 10.0).
348b077aed3SPierre Pronchery      * - Solaris since 11.3
349b077aed3SPierre Pronchery      * - OpenBSD since 5.6
350b077aed3SPierre Pronchery      * - Linux since 3.17 with glibc 2.25
351b077aed3SPierre Pronchery      *
352b077aed3SPierre Pronchery      * Note: Sometimes getentropy() can be provided but not implemented
353b077aed3SPierre Pronchery      * internally. So we need to check errno for ENOSYS
354b077aed3SPierre Pronchery      */
355838b6caaSKyle Evans #  if !defined(__DragonFly__) && !defined(__NetBSD__) && !defined(__FreeBSD__)
356b077aed3SPierre Pronchery #    if defined(__GNUC__) && __GNUC__>=2 && defined(__ELF__) && !defined(__hpux)
357b077aed3SPierre Pronchery     extern int getentropy(void *buffer, size_t length) __attribute__((weak));
358b077aed3SPierre Pronchery 
359b077aed3SPierre Pronchery     if (getentropy != NULL) {
360b077aed3SPierre Pronchery         if (getentropy(buf, buflen) == 0)
361b077aed3SPierre Pronchery             return (ssize_t)buflen;
362b077aed3SPierre Pronchery         if (errno != ENOSYS)
363b077aed3SPierre Pronchery             return -1;
364b077aed3SPierre Pronchery     }
365b077aed3SPierre Pronchery #    elif defined(OPENSSL_APPLE_CRYPTO_RANDOM)
366b077aed3SPierre Pronchery 
367b077aed3SPierre Pronchery     if (CCRandomGenerateBytes(buf, buflen) == kCCSuccess)
368b077aed3SPierre Pronchery 	    return (ssize_t)buflen;
369b077aed3SPierre Pronchery 
370b077aed3SPierre Pronchery     return -1;
371b077aed3SPierre Pronchery #    else
372b077aed3SPierre Pronchery     union {
373b077aed3SPierre Pronchery         void *p;
374b077aed3SPierre Pronchery         int (*f)(void *buffer, size_t length);
375b077aed3SPierre Pronchery     } p_getentropy;
376b077aed3SPierre Pronchery 
377b077aed3SPierre Pronchery     /*
378b077aed3SPierre Pronchery      * We could cache the result of the lookup, but we normally don't
379b077aed3SPierre Pronchery      * call this function often.
380b077aed3SPierre Pronchery      */
381b077aed3SPierre Pronchery     ERR_set_mark();
382b077aed3SPierre Pronchery     p_getentropy.p = DSO_global_lookup("getentropy");
383b077aed3SPierre Pronchery     ERR_pop_to_mark();
384b077aed3SPierre Pronchery     if (p_getentropy.p != NULL)
385b077aed3SPierre Pronchery         return p_getentropy.f(buf, buflen) == 0 ? (ssize_t)buflen : -1;
386b077aed3SPierre Pronchery #    endif
387*e7be843bSPierre Pronchery #  endif /* !__DragonFly__ && !__NetBSD__ && !__FreeBSD__ */
388b077aed3SPierre Pronchery 
389b077aed3SPierre Pronchery     /* Linux supports this since version 3.17 */
390b077aed3SPierre Pronchery #  if defined(__linux) && defined(__NR_getrandom)
391b077aed3SPierre Pronchery     return syscall(__NR_getrandom, buf, buflen, 0);
392b077aed3SPierre Pronchery #  elif (defined(__DragonFly__)  && __DragonFly_version >= 500700) \
393838b6caaSKyle Evans      || (defined(__NetBSD__) && __NetBSD_Version >= 1000000000) \
394*e7be843bSPierre Pronchery      || (defined(__FreeBSD__) && __FreeBSD_version >= 1200061)
395b077aed3SPierre Pronchery     return getrandom(buf, buflen, 0);
396*e7be843bSPierre Pronchery #  elif (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(KERN_ARND)
397838b6caaSKyle Evans     return sysctl_random(buf, buflen);
398*e7be843bSPierre Pronchery #  elif defined(__wasi__)
399*e7be843bSPierre Pronchery     if (getentropy(buf, buflen) == 0)
400*e7be843bSPierre Pronchery       return (ssize_t)buflen;
401*e7be843bSPierre Pronchery     return -1;
402b077aed3SPierre Pronchery #  else
403b077aed3SPierre Pronchery     errno = ENOSYS;
404b077aed3SPierre Pronchery     return -1;
405b077aed3SPierre Pronchery #  endif
406b077aed3SPierre Pronchery }
407b077aed3SPierre Pronchery #  endif    /* defined(OPENSSL_RAND_SEED_GETRANDOM) */
408b077aed3SPierre Pronchery 
409b077aed3SPierre Pronchery #  if defined(OPENSSL_RAND_SEED_DEVRANDOM)
410b077aed3SPierre Pronchery static const char *random_device_paths[] = { DEVRANDOM };
411b077aed3SPierre Pronchery static struct random_device {
412b077aed3SPierre Pronchery     int fd;
413b077aed3SPierre Pronchery     dev_t dev;
414b077aed3SPierre Pronchery     ino_t ino;
415b077aed3SPierre Pronchery     mode_t mode;
416b077aed3SPierre Pronchery     dev_t rdev;
417b077aed3SPierre Pronchery } random_devices[OSSL_NELEM(random_device_paths)];
418b077aed3SPierre Pronchery static int keep_random_devices_open = 1;
419b077aed3SPierre Pronchery 
420b077aed3SPierre Pronchery #   if defined(__linux) && defined(DEVRANDOM_WAIT) \
421b077aed3SPierre Pronchery        && defined(OPENSSL_RAND_SEED_GETRANDOM)
422b077aed3SPierre Pronchery static void *shm_addr;
423b077aed3SPierre Pronchery 
cleanup_shm(void)424b077aed3SPierre Pronchery static void cleanup_shm(void)
425b077aed3SPierre Pronchery {
426b077aed3SPierre Pronchery     shmdt(shm_addr);
427b077aed3SPierre Pronchery }
428b077aed3SPierre Pronchery 
429b077aed3SPierre Pronchery /*
430b077aed3SPierre Pronchery  * Ensure that the system randomness source has been adequately seeded.
431b077aed3SPierre Pronchery  * This is done by having the first start of libcrypto, wait until the device
432b077aed3SPierre Pronchery  * /dev/random becomes able to supply a byte of entropy.  Subsequent starts
433b077aed3SPierre Pronchery  * of the library and later reseedings do not need to do this.
434b077aed3SPierre Pronchery  */
wait_random_seeded(void)435b077aed3SPierre Pronchery static int wait_random_seeded(void)
436b077aed3SPierre Pronchery {
437b077aed3SPierre Pronchery     static int seeded = OPENSSL_RAND_SEED_DEVRANDOM_SHM_ID < 0;
438b077aed3SPierre Pronchery     static const int kernel_version[] = { DEVRANDOM_SAFE_KERNEL };
439b077aed3SPierre Pronchery     int kernel[2];
440b077aed3SPierre Pronchery     int shm_id, fd, r;
441b077aed3SPierre Pronchery     char c, *p;
442b077aed3SPierre Pronchery     struct utsname un;
443b077aed3SPierre Pronchery     fd_set fds;
444b077aed3SPierre Pronchery 
445b077aed3SPierre Pronchery     if (!seeded) {
446b077aed3SPierre Pronchery         /* See if anything has created the global seeded indication */
447b077aed3SPierre Pronchery         if ((shm_id = shmget(OPENSSL_RAND_SEED_DEVRANDOM_SHM_ID, 1, 0)) == -1) {
448b077aed3SPierre Pronchery             /*
449b077aed3SPierre Pronchery              * Check the kernel's version and fail if it is too recent.
450b077aed3SPierre Pronchery              *
451b077aed3SPierre Pronchery              * Linux kernels from 4.8 onwards do not guarantee that
452b077aed3SPierre Pronchery              * /dev/urandom is properly seeded when /dev/random becomes
453b077aed3SPierre Pronchery              * readable.  However, such kernels support the getentropy(2)
454b077aed3SPierre Pronchery              * system call and this should always succeed which renders
455b077aed3SPierre Pronchery              * this alternative but essentially identical source moot.
456b077aed3SPierre Pronchery              */
457b077aed3SPierre Pronchery             if (uname(&un) == 0) {
458b077aed3SPierre Pronchery                 kernel[0] = atoi(un.release);
459b077aed3SPierre Pronchery                 p = strchr(un.release, '.');
460b077aed3SPierre Pronchery                 kernel[1] = p == NULL ? 0 : atoi(p + 1);
461b077aed3SPierre Pronchery                 if (kernel[0] > kernel_version[0]
462b077aed3SPierre Pronchery                     || (kernel[0] == kernel_version[0]
463b077aed3SPierre Pronchery                         && kernel[1] >= kernel_version[1])) {
464b077aed3SPierre Pronchery                     return 0;
465b077aed3SPierre Pronchery                 }
466b077aed3SPierre Pronchery             }
467b077aed3SPierre Pronchery             /* Open /dev/random and wait for it to be readable */
468b077aed3SPierre Pronchery             if ((fd = open(DEVRANDOM_WAIT, O_RDONLY)) != -1) {
469b077aed3SPierre Pronchery                 if (DEVRANDM_WAIT_USE_SELECT && fd < FD_SETSIZE) {
470b077aed3SPierre Pronchery                     FD_ZERO(&fds);
471b077aed3SPierre Pronchery                     FD_SET(fd, &fds);
472b077aed3SPierre Pronchery                     while ((r = select(fd + 1, &fds, NULL, NULL, NULL)) < 0
473b077aed3SPierre Pronchery                            && errno == EINTR);
474b077aed3SPierre Pronchery                 } else {
475b077aed3SPierre Pronchery                     while ((r = read(fd, &c, 1)) < 0 && errno == EINTR);
476b077aed3SPierre Pronchery                 }
477b077aed3SPierre Pronchery                 close(fd);
478b077aed3SPierre Pronchery                 if (r == 1) {
479b077aed3SPierre Pronchery                     seeded = 1;
480b077aed3SPierre Pronchery                     /* Create the shared memory indicator */
481b077aed3SPierre Pronchery                     shm_id = shmget(OPENSSL_RAND_SEED_DEVRANDOM_SHM_ID, 1,
482b077aed3SPierre Pronchery                                     IPC_CREAT | S_IRUSR | S_IRGRP | S_IROTH);
483b077aed3SPierre Pronchery                 }
484b077aed3SPierre Pronchery             }
485b077aed3SPierre Pronchery         }
486b077aed3SPierre Pronchery         if (shm_id != -1) {
487b077aed3SPierre Pronchery             seeded = 1;
488b077aed3SPierre Pronchery             /*
489b077aed3SPierre Pronchery              * Map the shared memory to prevent its premature destruction.
490b077aed3SPierre Pronchery              * If this call fails, it isn't a big problem.
491b077aed3SPierre Pronchery              */
492b077aed3SPierre Pronchery             shm_addr = shmat(shm_id, NULL, SHM_RDONLY);
493b077aed3SPierre Pronchery             if (shm_addr != (void *)-1)
494b077aed3SPierre Pronchery                 OPENSSL_atexit(&cleanup_shm);
495b077aed3SPierre Pronchery         }
496b077aed3SPierre Pronchery     }
497b077aed3SPierre Pronchery     return seeded;
498b077aed3SPierre Pronchery }
499b077aed3SPierre Pronchery #   else /* defined __linux && DEVRANDOM_WAIT && OPENSSL_RAND_SEED_GETRANDOM */
wait_random_seeded(void)500b077aed3SPierre Pronchery static int wait_random_seeded(void)
501b077aed3SPierre Pronchery {
502b077aed3SPierre Pronchery     return 1;
503b077aed3SPierre Pronchery }
504b077aed3SPierre Pronchery #   endif
505b077aed3SPierre Pronchery 
506b077aed3SPierre Pronchery /*
507b077aed3SPierre Pronchery  * Verify that the file descriptor associated with the random source is
508b077aed3SPierre Pronchery  * still valid. The rationale for doing this is the fact that it is not
509b077aed3SPierre Pronchery  * uncommon for daemons to close all open file handles when daemonizing.
510b077aed3SPierre Pronchery  * So the handle might have been closed or even reused for opening
511b077aed3SPierre Pronchery  * another file.
512b077aed3SPierre Pronchery  */
check_random_device(struct random_device * rd)513b077aed3SPierre Pronchery static int check_random_device(struct random_device *rd)
514b077aed3SPierre Pronchery {
515b077aed3SPierre Pronchery     struct stat st;
516b077aed3SPierre Pronchery 
517b077aed3SPierre Pronchery     return rd->fd != -1
518b077aed3SPierre Pronchery            && fstat(rd->fd, &st) != -1
519b077aed3SPierre Pronchery            && rd->dev == st.st_dev
520b077aed3SPierre Pronchery            && rd->ino == st.st_ino
521b077aed3SPierre Pronchery            && ((rd->mode ^ st.st_mode) & ~(S_IRWXU | S_IRWXG | S_IRWXO)) == 0
522b077aed3SPierre Pronchery            && rd->rdev == st.st_rdev;
523b077aed3SPierre Pronchery }
524b077aed3SPierre Pronchery 
525b077aed3SPierre Pronchery /*
526b077aed3SPierre Pronchery  * Open a random device if required and return its file descriptor or -1 on error
527b077aed3SPierre Pronchery  */
get_random_device(size_t n)528b077aed3SPierre Pronchery static int get_random_device(size_t n)
529b077aed3SPierre Pronchery {
530b077aed3SPierre Pronchery     struct stat st;
531b077aed3SPierre Pronchery     struct random_device *rd = &random_devices[n];
532b077aed3SPierre Pronchery 
533b077aed3SPierre Pronchery     /* reuse existing file descriptor if it is (still) valid */
534b077aed3SPierre Pronchery     if (check_random_device(rd))
535b077aed3SPierre Pronchery         return rd->fd;
536b077aed3SPierre Pronchery 
537b077aed3SPierre Pronchery     /* open the random device ... */
538b077aed3SPierre Pronchery     if ((rd->fd = open(random_device_paths[n], O_RDONLY)) == -1)
539b077aed3SPierre Pronchery         return rd->fd;
540b077aed3SPierre Pronchery 
541b077aed3SPierre Pronchery     /* ... and cache its relevant stat(2) data */
542b077aed3SPierre Pronchery     if (fstat(rd->fd, &st) != -1) {
543b077aed3SPierre Pronchery         rd->dev = st.st_dev;
544b077aed3SPierre Pronchery         rd->ino = st.st_ino;
545b077aed3SPierre Pronchery         rd->mode = st.st_mode;
546b077aed3SPierre Pronchery         rd->rdev = st.st_rdev;
547b077aed3SPierre Pronchery     } else {
548b077aed3SPierre Pronchery         close(rd->fd);
549b077aed3SPierre Pronchery         rd->fd = -1;
550b077aed3SPierre Pronchery     }
551b077aed3SPierre Pronchery 
552b077aed3SPierre Pronchery     return rd->fd;
553b077aed3SPierre Pronchery }
554b077aed3SPierre Pronchery 
555b077aed3SPierre Pronchery /*
556b077aed3SPierre Pronchery  * Close a random device making sure it is a random device
557b077aed3SPierre Pronchery  */
close_random_device(size_t n)558b077aed3SPierre Pronchery static void close_random_device(size_t n)
559b077aed3SPierre Pronchery {
560b077aed3SPierre Pronchery     struct random_device *rd = &random_devices[n];
561b077aed3SPierre Pronchery 
562b077aed3SPierre Pronchery     if (check_random_device(rd))
563b077aed3SPierre Pronchery         close(rd->fd);
564b077aed3SPierre Pronchery     rd->fd = -1;
565b077aed3SPierre Pronchery }
566b077aed3SPierre Pronchery 
ossl_rand_pool_init(void)567b077aed3SPierre Pronchery int ossl_rand_pool_init(void)
568b077aed3SPierre Pronchery {
569b077aed3SPierre Pronchery     size_t i;
570b077aed3SPierre Pronchery 
571b077aed3SPierre Pronchery     for (i = 0; i < OSSL_NELEM(random_devices); i++)
572b077aed3SPierre Pronchery         random_devices[i].fd = -1;
573b077aed3SPierre Pronchery 
574b077aed3SPierre Pronchery     return 1;
575b077aed3SPierre Pronchery }
576b077aed3SPierre Pronchery 
ossl_rand_pool_cleanup(void)577b077aed3SPierre Pronchery void ossl_rand_pool_cleanup(void)
578b077aed3SPierre Pronchery {
579b077aed3SPierre Pronchery     size_t i;
580b077aed3SPierre Pronchery 
581b077aed3SPierre Pronchery     for (i = 0; i < OSSL_NELEM(random_devices); i++)
582b077aed3SPierre Pronchery         close_random_device(i);
583b077aed3SPierre Pronchery }
584b077aed3SPierre Pronchery 
ossl_rand_pool_keep_random_devices_open(int keep)585b077aed3SPierre Pronchery void ossl_rand_pool_keep_random_devices_open(int keep)
586b077aed3SPierre Pronchery {
587b077aed3SPierre Pronchery     if (!keep)
588b077aed3SPierre Pronchery         ossl_rand_pool_cleanup();
589b077aed3SPierre Pronchery 
590b077aed3SPierre Pronchery     keep_random_devices_open = keep;
591b077aed3SPierre Pronchery }
592b077aed3SPierre Pronchery 
593b077aed3SPierre Pronchery #  else     /* !defined(OPENSSL_RAND_SEED_DEVRANDOM) */
594b077aed3SPierre Pronchery 
ossl_rand_pool_init(void)595b077aed3SPierre Pronchery int ossl_rand_pool_init(void)
596b077aed3SPierre Pronchery {
597b077aed3SPierre Pronchery     return 1;
598b077aed3SPierre Pronchery }
599b077aed3SPierre Pronchery 
ossl_rand_pool_cleanup(void)600b077aed3SPierre Pronchery void ossl_rand_pool_cleanup(void)
601b077aed3SPierre Pronchery {
602b077aed3SPierre Pronchery }
603b077aed3SPierre Pronchery 
ossl_rand_pool_keep_random_devices_open(int keep)604b077aed3SPierre Pronchery void ossl_rand_pool_keep_random_devices_open(int keep)
605b077aed3SPierre Pronchery {
606b077aed3SPierre Pronchery }
607b077aed3SPierre Pronchery 
608b077aed3SPierre Pronchery #  endif    /* defined(OPENSSL_RAND_SEED_DEVRANDOM) */
609b077aed3SPierre Pronchery 
610b077aed3SPierre Pronchery /*
611b077aed3SPierre Pronchery  * Try the various seeding methods in turn, exit when successful.
612b077aed3SPierre Pronchery  *
613b077aed3SPierre Pronchery  * If more than one entropy source is available, is it
614b077aed3SPierre Pronchery  * preferable to stop as soon as enough entropy has been collected
615b077aed3SPierre Pronchery  * (as favored by @rsalz) or should one rather be defensive and add
616b077aed3SPierre Pronchery  * more entropy than requested and/or from different sources?
617b077aed3SPierre Pronchery  *
618b077aed3SPierre Pronchery  * Currently, the user can select multiple entropy sources in the
619b077aed3SPierre Pronchery  * configure step, yet in practice only the first available source
620b077aed3SPierre Pronchery  * will be used. A more flexible solution has been requested, but
621b077aed3SPierre Pronchery  * currently it is not clear how this can be achieved without
622b077aed3SPierre Pronchery  * overengineering the problem. There are many parameters which
623b077aed3SPierre Pronchery  * could be taken into account when selecting the order and amount
624b077aed3SPierre Pronchery  * of input from the different entropy sources (trust, quality,
625b077aed3SPierre Pronchery  * possibility of blocking).
626b077aed3SPierre Pronchery  */
ossl_pool_acquire_entropy(RAND_POOL * pool)627b077aed3SPierre Pronchery size_t ossl_pool_acquire_entropy(RAND_POOL *pool)
628b077aed3SPierre Pronchery {
629b077aed3SPierre Pronchery #  if defined(OPENSSL_RAND_SEED_NONE)
630b077aed3SPierre Pronchery     return ossl_rand_pool_entropy_available(pool);
631b077aed3SPierre Pronchery #  else
632b077aed3SPierre Pronchery     size_t entropy_available = 0;
633b077aed3SPierre Pronchery 
634b077aed3SPierre Pronchery     (void)entropy_available;    /* avoid compiler warning */
635b077aed3SPierre Pronchery 
636b077aed3SPierre Pronchery #   if defined(OPENSSL_RAND_SEED_GETRANDOM)
637b077aed3SPierre Pronchery     {
638b077aed3SPierre Pronchery         size_t bytes_needed;
639b077aed3SPierre Pronchery         unsigned char *buffer;
640b077aed3SPierre Pronchery         ssize_t bytes;
641b077aed3SPierre Pronchery         /* Maximum allowed number of consecutive unsuccessful attempts */
642b077aed3SPierre Pronchery         int attempts = 3;
643b077aed3SPierre Pronchery 
644b077aed3SPierre Pronchery         bytes_needed = ossl_rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);
645b077aed3SPierre Pronchery         while (bytes_needed != 0 && attempts-- > 0) {
646b077aed3SPierre Pronchery             buffer = ossl_rand_pool_add_begin(pool, bytes_needed);
647b077aed3SPierre Pronchery             bytes = syscall_random(buffer, bytes_needed);
648b077aed3SPierre Pronchery             if (bytes > 0) {
649b077aed3SPierre Pronchery                 ossl_rand_pool_add_end(pool, bytes, 8 * bytes);
650b077aed3SPierre Pronchery                 bytes_needed -= bytes;
651b077aed3SPierre Pronchery                 attempts = 3; /* reset counter after successful attempt */
652b077aed3SPierre Pronchery             } else if (bytes < 0 && errno != EINTR) {
653b077aed3SPierre Pronchery                 break;
654b077aed3SPierre Pronchery             }
655b077aed3SPierre Pronchery         }
656b077aed3SPierre Pronchery     }
657b077aed3SPierre Pronchery     entropy_available = ossl_rand_pool_entropy_available(pool);
658b077aed3SPierre Pronchery     if (entropy_available > 0)
659b077aed3SPierre Pronchery         return entropy_available;
660b077aed3SPierre Pronchery #   endif
661b077aed3SPierre Pronchery 
662b077aed3SPierre Pronchery #   if defined(OPENSSL_RAND_SEED_DEVRANDOM)
663b077aed3SPierre Pronchery     if (wait_random_seeded()) {
664b077aed3SPierre Pronchery         size_t bytes_needed;
665b077aed3SPierre Pronchery         unsigned char *buffer;
666b077aed3SPierre Pronchery         size_t i;
667b077aed3SPierre Pronchery 
668b077aed3SPierre Pronchery         bytes_needed = ossl_rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);
669b077aed3SPierre Pronchery         for (i = 0; bytes_needed > 0 && i < OSSL_NELEM(random_device_paths);
670b077aed3SPierre Pronchery              i++) {
671b077aed3SPierre Pronchery             ssize_t bytes = 0;
672b077aed3SPierre Pronchery             /* Maximum number of consecutive unsuccessful attempts */
673b077aed3SPierre Pronchery             int attempts = 3;
674b077aed3SPierre Pronchery             const int fd = get_random_device(i);
675b077aed3SPierre Pronchery 
676b077aed3SPierre Pronchery             if (fd == -1)
677b077aed3SPierre Pronchery                 continue;
678b077aed3SPierre Pronchery 
679b077aed3SPierre Pronchery             while (bytes_needed != 0 && attempts-- > 0) {
680b077aed3SPierre Pronchery                 buffer = ossl_rand_pool_add_begin(pool, bytes_needed);
681b077aed3SPierre Pronchery                 bytes = read(fd, buffer, bytes_needed);
682b077aed3SPierre Pronchery 
683b077aed3SPierre Pronchery                 if (bytes > 0) {
684b077aed3SPierre Pronchery                     ossl_rand_pool_add_end(pool, bytes, 8 * bytes);
685b077aed3SPierre Pronchery                     bytes_needed -= bytes;
686b077aed3SPierre Pronchery                     attempts = 3; /* reset counter on successful attempt */
687b077aed3SPierre Pronchery                 } else if (bytes < 0 && errno != EINTR) {
688b077aed3SPierre Pronchery                     break;
689b077aed3SPierre Pronchery                 }
690b077aed3SPierre Pronchery             }
691b077aed3SPierre Pronchery             if (bytes < 0 || !keep_random_devices_open)
692b077aed3SPierre Pronchery                 close_random_device(i);
693b077aed3SPierre Pronchery 
694b077aed3SPierre Pronchery             bytes_needed = ossl_rand_pool_bytes_needed(pool, 1);
695b077aed3SPierre Pronchery         }
696b077aed3SPierre Pronchery         entropy_available = ossl_rand_pool_entropy_available(pool);
697b077aed3SPierre Pronchery         if (entropy_available > 0)
698b077aed3SPierre Pronchery             return entropy_available;
699b077aed3SPierre Pronchery     }
700b077aed3SPierre Pronchery #   endif
701b077aed3SPierre Pronchery 
702b077aed3SPierre Pronchery #   if defined(OPENSSL_RAND_SEED_RDTSC)
703b077aed3SPierre Pronchery     entropy_available = ossl_prov_acquire_entropy_from_tsc(pool);
704b077aed3SPierre Pronchery     if (entropy_available > 0)
705b077aed3SPierre Pronchery         return entropy_available;
706b077aed3SPierre Pronchery #   endif
707b077aed3SPierre Pronchery 
708b077aed3SPierre Pronchery #   if defined(OPENSSL_RAND_SEED_RDCPU)
709b077aed3SPierre Pronchery     entropy_available = ossl_prov_acquire_entropy_from_cpu(pool);
710b077aed3SPierre Pronchery     if (entropy_available > 0)
711b077aed3SPierre Pronchery         return entropy_available;
712b077aed3SPierre Pronchery #   endif
713b077aed3SPierre Pronchery 
714b077aed3SPierre Pronchery #   if defined(OPENSSL_RAND_SEED_EGD)
715b077aed3SPierre Pronchery     {
716b077aed3SPierre Pronchery         static const char *paths[] = { DEVRANDOM_EGD, NULL };
717b077aed3SPierre Pronchery         size_t bytes_needed;
718b077aed3SPierre Pronchery         unsigned char *buffer;
719b077aed3SPierre Pronchery         int i;
720b077aed3SPierre Pronchery 
721b077aed3SPierre Pronchery         bytes_needed = ossl_rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);
722b077aed3SPierre Pronchery         for (i = 0; bytes_needed > 0 && paths[i] != NULL; i++) {
723b077aed3SPierre Pronchery             size_t bytes = 0;
724b077aed3SPierre Pronchery             int num;
725b077aed3SPierre Pronchery 
726b077aed3SPierre Pronchery             buffer = ossl_rand_pool_add_begin(pool, bytes_needed);
727b077aed3SPierre Pronchery             num = RAND_query_egd_bytes(paths[i],
728b077aed3SPierre Pronchery                                        buffer, (int)bytes_needed);
729b077aed3SPierre Pronchery             if (num == (int)bytes_needed)
730b077aed3SPierre Pronchery                 bytes = bytes_needed;
731b077aed3SPierre Pronchery 
732b077aed3SPierre Pronchery             ossl_rand_pool_add_end(pool, bytes, 8 * bytes);
733b077aed3SPierre Pronchery             bytes_needed = ossl_rand_pool_bytes_needed(pool, 1);
734b077aed3SPierre Pronchery         }
735b077aed3SPierre Pronchery         entropy_available = ossl_rand_pool_entropy_available(pool);
736b077aed3SPierre Pronchery         if (entropy_available > 0)
737b077aed3SPierre Pronchery             return entropy_available;
738b077aed3SPierre Pronchery     }
739b077aed3SPierre Pronchery #   endif
740b077aed3SPierre Pronchery 
741b077aed3SPierre Pronchery     return ossl_rand_pool_entropy_available(pool);
742b077aed3SPierre Pronchery #  endif
743b077aed3SPierre Pronchery }
744b077aed3SPierre Pronchery # endif
745b077aed3SPierre Pronchery #endif
746b077aed3SPierre Pronchery 
747b077aed3SPierre Pronchery #if (defined(OPENSSL_SYS_UNIX) && !defined(OPENSSL_SYS_VXWORKS)) \
748b077aed3SPierre Pronchery      || defined(__DJGPP__)
ossl_pool_add_nonce_data(RAND_POOL * pool)749b077aed3SPierre Pronchery int ossl_pool_add_nonce_data(RAND_POOL *pool)
750b077aed3SPierre Pronchery {
751b077aed3SPierre Pronchery     struct {
752b077aed3SPierre Pronchery         pid_t pid;
753b077aed3SPierre Pronchery         CRYPTO_THREAD_ID tid;
754b077aed3SPierre Pronchery         uint64_t time;
755b077aed3SPierre Pronchery     } data;
756b077aed3SPierre Pronchery 
757b077aed3SPierre Pronchery     /* Erase the entire structure including any padding */
758b077aed3SPierre Pronchery     memset(&data, 0, sizeof(data));
759b077aed3SPierre Pronchery 
760b077aed3SPierre Pronchery     /*
761b077aed3SPierre Pronchery      * Add process id, thread id, and a high resolution timestamp to
762b077aed3SPierre Pronchery      * ensure that the nonce is unique with high probability for
763b077aed3SPierre Pronchery      * different process instances.
764b077aed3SPierre Pronchery      */
765b077aed3SPierre Pronchery     data.pid = getpid();
766b077aed3SPierre Pronchery     data.tid = CRYPTO_THREAD_get_current_id();
767b077aed3SPierre Pronchery     data.time = get_time_stamp();
768b077aed3SPierre Pronchery 
769b077aed3SPierre Pronchery     return ossl_rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0);
770b077aed3SPierre Pronchery }
771b077aed3SPierre Pronchery 
772b077aed3SPierre Pronchery /*
773b077aed3SPierre Pronchery  * Get the current time with the highest possible resolution
774b077aed3SPierre Pronchery  *
775b077aed3SPierre Pronchery  * The time stamp is added to the nonce, so it is optimized for not repeating.
776b077aed3SPierre Pronchery  * The current time is ideal for this purpose, provided the computer's clock
777b077aed3SPierre Pronchery  * is synchronized.
778b077aed3SPierre Pronchery  */
get_time_stamp(void)779b077aed3SPierre Pronchery static uint64_t get_time_stamp(void)
780b077aed3SPierre Pronchery {
781b077aed3SPierre Pronchery # if defined(OSSL_POSIX_TIMER_OKAY)
782b077aed3SPierre Pronchery     {
783b077aed3SPierre Pronchery         struct timespec ts;
784b077aed3SPierre Pronchery 
785b077aed3SPierre Pronchery         if (clock_gettime(CLOCK_REALTIME, &ts) == 0)
786b077aed3SPierre Pronchery             return TWO32TO64(ts.tv_sec, ts.tv_nsec);
787b077aed3SPierre Pronchery     }
788b077aed3SPierre Pronchery # endif
789b077aed3SPierre Pronchery # if defined(__unix__) \
790b077aed3SPierre Pronchery      || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L)
791b077aed3SPierre Pronchery     {
792b077aed3SPierre Pronchery         struct timeval tv;
793b077aed3SPierre Pronchery 
794b077aed3SPierre Pronchery         if (gettimeofday(&tv, NULL) == 0)
795b077aed3SPierre Pronchery             return TWO32TO64(tv.tv_sec, tv.tv_usec);
796b077aed3SPierre Pronchery     }
797b077aed3SPierre Pronchery # endif
798b077aed3SPierre Pronchery     return time(NULL);
799b077aed3SPierre Pronchery }
800b077aed3SPierre Pronchery 
801b077aed3SPierre Pronchery #endif /* (defined(OPENSSL_SYS_UNIX) && !defined(OPENSSL_SYS_VXWORKS))
802b077aed3SPierre Pronchery           || defined(__DJGPP__) */
803