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