/src/boringssl/crypto/rand_extra/urandom.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (c) 2014, Google Inc. |
2 | | * |
3 | | * Permission to use, copy, modify, and/or distribute this software for any |
4 | | * purpose with or without fee is hereby granted, provided that the above |
5 | | * copyright notice and this permission notice appear in all copies. |
6 | | * |
7 | | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
8 | | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
9 | | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
10 | | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
11 | | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
12 | | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
13 | | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ |
14 | | |
15 | | #if !defined(_GNU_SOURCE) |
16 | | #define _GNU_SOURCE // needed for syscall() on Linux. |
17 | | #endif |
18 | | |
19 | | #include <openssl/rand.h> |
20 | | |
21 | | #include "../bcm_support.h" |
22 | | #include "sysrand_internal.h" |
23 | | |
24 | | #if defined(OPENSSL_RAND_URANDOM) |
25 | | |
26 | | #include <assert.h> |
27 | | #include <errno.h> |
28 | | #include <fcntl.h> |
29 | | #include <stdio.h> |
30 | | #include <string.h> |
31 | | #include <unistd.h> |
32 | | |
33 | | #if defined(OPENSSL_LINUX) |
34 | | #if defined(BORINGSSL_FIPS) |
35 | | #include <linux/random.h> |
36 | | #include <sys/ioctl.h> |
37 | | #endif |
38 | | #include <sys/syscall.h> |
39 | | |
40 | | #if defined(OPENSSL_ANDROID) |
41 | | #include <sys/system_properties.h> |
42 | | #endif |
43 | | |
44 | | #if !defined(OPENSSL_ANDROID) |
45 | | #define OPENSSL_HAS_GETAUXVAL |
46 | | #endif |
47 | | // glibc prior to 2.16 does not have getauxval and sys/auxv.h. Android has some |
48 | | // host builds (i.e. not building for Android itself, so |OPENSSL_ANDROID| is |
49 | | // unset) which are still using a 2.15 sysroot. |
50 | | // |
51 | | // TODO(davidben): Remove this once Android updates their sysroot. |
52 | | #if defined(__GLIBC_PREREQ) |
53 | | #if !__GLIBC_PREREQ(2, 16) |
54 | | #undef OPENSSL_HAS_GETAUXVAL |
55 | | #endif |
56 | | #endif |
57 | | #if defined(OPENSSL_HAS_GETAUXVAL) |
58 | | #include <sys/auxv.h> |
59 | | #endif |
60 | | #endif // OPENSSL_LINUX |
61 | | |
62 | | #include <openssl/thread.h> |
63 | | #include <openssl/mem.h> |
64 | | |
65 | | #include "getrandom_fillin.h" |
66 | | #include "../internal.h" |
67 | | |
68 | | |
69 | | #if defined(USE_NR_getrandom) |
70 | | |
71 | | #if defined(OPENSSL_MSAN) |
72 | | void __msan_unpoison(void *, size_t); |
73 | | #endif |
74 | | |
75 | 4 | static ssize_t boringssl_getrandom(void *buf, size_t buf_len, unsigned flags) { |
76 | 4 | ssize_t ret; |
77 | 4 | do { |
78 | 4 | ret = syscall(__NR_getrandom, buf, buf_len, flags); |
79 | 4 | } while (ret == -1 && errno == EINTR); |
80 | | |
81 | | #if defined(OPENSSL_MSAN) |
82 | | if (ret > 0) { |
83 | | // MSAN doesn't recognise |syscall| and thus doesn't notice that we have |
84 | | // initialised the output buffer. |
85 | | __msan_unpoison(buf, ret); |
86 | | } |
87 | | #endif // OPENSSL_MSAN |
88 | | |
89 | 4 | return ret; |
90 | 4 | } |
91 | | |
92 | | #endif // USE_NR_getrandom |
93 | | |
94 | | // kHaveGetrandom in |urandom_fd| signals that |getrandom| or |getentropy| is |
95 | | // available and should be used instead. |
96 | | static const int kHaveGetrandom = -3; |
97 | | |
98 | | // urandom_fd is a file descriptor to /dev/urandom. It's protected by |once|. |
99 | | static int urandom_fd; |
100 | | |
101 | | #if defined(USE_NR_getrandom) |
102 | | |
103 | | // getrandom_ready is one if |getrandom| had been initialized by the time |
104 | | // |init_once| was called and zero otherwise. |
105 | | static int getrandom_ready; |
106 | | |
107 | | // extra_getrandom_flags_for_seed contains a value that is ORed into the flags |
108 | | // for getrandom() when reading entropy for a seed. |
109 | | static int extra_getrandom_flags_for_seed; |
110 | | |
111 | | // On Android, check a system property to decide whether to set |
112 | | // |extra_getrandom_flags_for_seed| otherwise they will default to zero. If |
113 | | // ro.oem_boringcrypto_hwrand is true then |extra_getrandom_flags_for_seed| will |
114 | | // be set to GRND_RANDOM, causing all random data to be drawn from the same |
115 | | // source as /dev/random. |
116 | 2 | static void maybe_set_extra_getrandom_flags(void) { |
117 | | #if defined(BORINGSSL_FIPS) && defined(OPENSSL_ANDROID) |
118 | | char value[PROP_VALUE_MAX + 1]; |
119 | | int length = __system_property_get("ro.boringcrypto.hwrand", value); |
120 | | if (length < 0 || length > PROP_VALUE_MAX) { |
121 | | return; |
122 | | } |
123 | | |
124 | | value[length] = 0; |
125 | | if (OPENSSL_strcasecmp(value, "true") == 0) { |
126 | | extra_getrandom_flags_for_seed = GRND_RANDOM; |
127 | | } |
128 | | #endif |
129 | 2 | } |
130 | | |
131 | | #endif // USE_NR_getrandom |
132 | | |
133 | | static CRYPTO_once_t rand_once = CRYPTO_ONCE_INIT; |
134 | | |
135 | | // init_once initializes the state of this module to values previously |
136 | | // requested. This is the only function that modifies |urandom_fd|, which may be |
137 | | // read safely after calling the once. |
138 | 2 | static void init_once(void) { |
139 | 2 | #if defined(USE_NR_getrandom) |
140 | 2 | int have_getrandom; |
141 | 2 | uint8_t dummy; |
142 | 2 | ssize_t getrandom_ret = |
143 | 2 | boringssl_getrandom(&dummy, sizeof(dummy), GRND_NONBLOCK); |
144 | 2 | if (getrandom_ret == 1) { |
145 | 2 | getrandom_ready = 1; |
146 | 2 | have_getrandom = 1; |
147 | 2 | } else if (getrandom_ret == -1 && errno == EAGAIN) { |
148 | | // We have getrandom, but the entropy pool has not been initialized yet. |
149 | 0 | have_getrandom = 1; |
150 | 0 | } else if (getrandom_ret == -1 && errno == ENOSYS) { |
151 | | // Fallthrough to using /dev/urandom, below. |
152 | 0 | have_getrandom = 0; |
153 | 0 | } else { |
154 | | // Other errors are fatal. |
155 | 0 | perror("getrandom"); |
156 | 0 | abort(); |
157 | 0 | } |
158 | | |
159 | 2 | if (have_getrandom) { |
160 | 2 | urandom_fd = kHaveGetrandom; |
161 | 2 | maybe_set_extra_getrandom_flags(); |
162 | 2 | return; |
163 | 2 | } |
164 | 0 | #endif // USE_NR_getrandom |
165 | | |
166 | | // FIPS builds must support getrandom. |
167 | | // |
168 | | // Historically, only Android FIPS builds required getrandom, while Linux FIPS |
169 | | // builds had a /dev/urandom fallback which used RNDGETENTCNT as a poor |
170 | | // approximation for getrandom's blocking behavior. This is now removed, but |
171 | | // avoid making assumptions on this removal until March 2023, in case it needs |
172 | | // to be restored. This comment can be deleted after March 2023. |
173 | | #if defined(BORINGSSL_FIPS) |
174 | | perror("getrandom not found"); |
175 | | abort(); |
176 | | #endif |
177 | | |
178 | 0 | int fd; |
179 | 0 | do { |
180 | 0 | fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); |
181 | 0 | } while (fd == -1 && errno == EINTR); |
182 | |
|
183 | 0 | if (fd < 0) { |
184 | 0 | perror("failed to open /dev/urandom"); |
185 | 0 | abort(); |
186 | 0 | } |
187 | | |
188 | 0 | urandom_fd = fd; |
189 | 0 | } |
190 | | |
191 | | static CRYPTO_once_t wait_for_entropy_once = CRYPTO_ONCE_INIT; |
192 | | |
193 | 2 | static void wait_for_entropy(void) { |
194 | 2 | int fd = urandom_fd; |
195 | 2 | if (fd == kHaveGetrandom) { |
196 | | // |getrandom| and |getentropy| support blocking in |fill_with_entropy| |
197 | | // directly. For |getrandom|, we first probe with a non-blocking call to aid |
198 | | // debugging. |
199 | 2 | #if defined(USE_NR_getrandom) |
200 | 2 | if (getrandom_ready) { |
201 | | // The entropy pool was already initialized in |init_once|. |
202 | 2 | return; |
203 | 2 | } |
204 | | |
205 | 0 | uint8_t dummy; |
206 | 0 | ssize_t getrandom_ret = |
207 | 0 | boringssl_getrandom(&dummy, sizeof(dummy), GRND_NONBLOCK); |
208 | 0 | if (getrandom_ret == -1 && errno == EAGAIN) { |
209 | | // Attempt to get the path of the current process to aid in debugging when |
210 | | // something blocks. |
211 | 0 | const char *current_process = "<unknown>"; |
212 | 0 | #if defined(OPENSSL_HAS_GETAUXVAL) |
213 | 0 | const unsigned long getauxval_ret = getauxval(AT_EXECFN); |
214 | 0 | if (getauxval_ret != 0) { |
215 | 0 | current_process = (const char *)getauxval_ret; |
216 | 0 | } |
217 | 0 | #endif |
218 | |
|
219 | 0 | fprintf( |
220 | 0 | stderr, |
221 | 0 | "%s: getrandom indicates that the entropy pool has not been " |
222 | 0 | "initialized. Rather than continue with poor entropy, this process " |
223 | 0 | "will block until entropy is available.\n", |
224 | 0 | current_process); |
225 | |
|
226 | 0 | getrandom_ret = |
227 | 0 | boringssl_getrandom(&dummy, sizeof(dummy), 0 /* no flags */); |
228 | 0 | } |
229 | |
|
230 | 0 | if (getrandom_ret != 1) { |
231 | 0 | perror("getrandom"); |
232 | 0 | abort(); |
233 | 0 | } |
234 | 0 | #endif // USE_NR_getrandom |
235 | 0 | return; |
236 | 0 | } |
237 | 2 | } |
238 | | |
239 | | // fill_with_entropy writes |len| bytes of entropy into |out|. It returns one |
240 | | // on success and zero on error. If |block| is one, this function will block |
241 | | // until the entropy pool is initialized. Otherwise, this function may fail, |
242 | | // setting |errno| to |EAGAIN| if the entropy pool has not yet been initialized. |
243 | | // If |seed| is one, this function will OR in the value of |
244 | | // |*extra_getrandom_flags_for_seed()| when using |getrandom|. |
245 | 2 | static int fill_with_entropy(uint8_t *out, size_t len, int block, int seed) { |
246 | 2 | if (len == 0) { |
247 | 0 | return 1; |
248 | 0 | } |
249 | | |
250 | 2 | #if defined(USE_NR_getrandom) || defined(FREEBSD_GETRANDOM) |
251 | 2 | int getrandom_flags = 0; |
252 | 2 | if (!block) { |
253 | 0 | getrandom_flags |= GRND_NONBLOCK; |
254 | 0 | } |
255 | 2 | #endif |
256 | | |
257 | 2 | #if defined (USE_NR_getrandom) |
258 | 2 | if (seed) { |
259 | 2 | getrandom_flags |= extra_getrandom_flags_for_seed; |
260 | 2 | } |
261 | 2 | #endif |
262 | | |
263 | 2 | CRYPTO_init_sysrand(); |
264 | 2 | if (block) { |
265 | 2 | CRYPTO_once(&wait_for_entropy_once, wait_for_entropy); |
266 | 2 | } |
267 | | |
268 | | // Clear |errno| so it has defined value if |read| or |getrandom| |
269 | | // "successfully" returns zero. |
270 | 2 | errno = 0; |
271 | 4 | while (len > 0) { |
272 | 2 | ssize_t r; |
273 | | |
274 | 2 | if (urandom_fd == kHaveGetrandom) { |
275 | 2 | #if defined(USE_NR_getrandom) |
276 | 2 | r = boringssl_getrandom(out, len, getrandom_flags); |
277 | | #else // USE_NR_getrandom |
278 | | fprintf(stderr, "urandom fd corrupt.\n"); |
279 | | abort(); |
280 | | #endif |
281 | 2 | } else { |
282 | 0 | do { |
283 | 0 | r = read(urandom_fd, out, len); |
284 | 0 | } while (r == -1 && errno == EINTR); |
285 | 0 | } |
286 | | |
287 | 2 | if (r <= 0) { |
288 | 0 | return 0; |
289 | 0 | } |
290 | 2 | out += r; |
291 | 2 | len -= r; |
292 | 2 | } |
293 | | |
294 | 2 | return 1; |
295 | 2 | } |
296 | | |
297 | 2 | void CRYPTO_init_sysrand(void) { |
298 | 2 | CRYPTO_once(&rand_once, init_once); |
299 | 2 | } |
300 | | |
301 | | // CRYPTO_sysrand puts |requested| random bytes into |out|. |
302 | 0 | void CRYPTO_sysrand(uint8_t *out, size_t requested) { |
303 | 0 | if (!fill_with_entropy(out, requested, /*block=*/1, /*seed=*/0)) { |
304 | 0 | perror("entropy fill failed"); |
305 | 0 | abort(); |
306 | 0 | } |
307 | 0 | } |
308 | | |
309 | 2 | void CRYPTO_sysrand_for_seed(uint8_t *out, size_t requested) { |
310 | 2 | if (!fill_with_entropy(out, requested, /*block=*/1, /*seed=*/1)) { |
311 | 0 | perror("entropy fill failed"); |
312 | 0 | abort(); |
313 | 0 | } |
314 | 2 | } |
315 | | |
316 | 0 | int CRYPTO_sysrand_if_available(uint8_t *out, size_t requested) { |
317 | 0 | if (fill_with_entropy(out, requested, /*block=*/0, /*seed=*/0)) { |
318 | 0 | return 1; |
319 | 0 | } else if (errno == EAGAIN) { |
320 | 0 | OPENSSL_memset(out, 0, requested); |
321 | 0 | return 0; |
322 | 0 | } else { |
323 | 0 | perror("opportunistic entropy fill failed"); |
324 | 0 | abort(); |
325 | 0 | } |
326 | 0 | } |
327 | | |
328 | | #endif // OPENSSL_RAND_URANDOM |