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