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 #if !defined(OPENSSL_WINDOWS) && !defined(OPENSSL_FUCHSIA) && \
22 !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE) && !defined(OPENSSL_TRUSTY)
23
24 #include <assert.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <unistd.h>
30
31 #if defined(OPENSSL_LINUX)
32 #include <linux/random.h>
33 #include <sys/ioctl.h>
34 #include <sys/syscall.h>
35 #endif
36
37 #include <openssl/thread.h>
38 #include <openssl/mem.h>
39
40 #include "internal.h"
41 #include "../delocate.h"
42 #include "../../internal.h"
43
44
45 #if defined(OPENSSL_LINUX)
46
47 #if defined(OPENSSL_X86_64)
48 #define EXPECTED_SYS_getrandom 318
49 #elif defined(OPENSSL_X86)
50 #define EXPECTED_SYS_getrandom 355
51 #elif defined(OPENSSL_AARCH64)
52 #define EXPECTED_SYS_getrandom 278
53 #elif defined(OPENSSL_ARM)
54 #define EXPECTED_SYS_getrandom 384
55 #elif defined(OPENSSL_PPC64LE)
56 #define EXPECTED_SYS_getrandom 359
57 #endif
58
59 #if defined(EXPECTED_SYS_getrandom)
60 #define USE_SYS_getrandom
61
62 #if defined(SYS_getrandom)
63
64 #if SYS_getrandom != EXPECTED_SYS_getrandom
65 #error "system call number for getrandom is not the expected value"
66 #endif
67
68 #else /* SYS_getrandom */
69
70 #define SYS_getrandom EXPECTED_SYS_getrandom
71
72 #endif /* SYS_getrandom */
73
74 #endif /* EXPECTED_SYS_getrandom */
75
76 #if !defined(GRND_NONBLOCK)
77 #define GRND_NONBLOCK 1
78 #endif
79
80 #endif /* OPENSSL_LINUX */
81
82 /* rand_lock is used to protect the |*_requested| variables. */
83 DEFINE_STATIC_MUTEX(rand_lock);
84
85 /* The following constants are magic values of |urandom_fd|. */
86 static const int kUnset = 0;
87 static const int kHaveGetrandom = -3;
88
89 /* urandom_fd_requested is set by |RAND_set_urandom_fd|. It's protected by
90 * |rand_lock|. */
91 DEFINE_BSS_GET(int, urandom_fd_requested);
92
93 /* urandom_fd is a file descriptor to /dev/urandom. It's protected by |once|. */
94 DEFINE_BSS_GET(int, urandom_fd);
95
96 DEFINE_STATIC_ONCE(rand_once);
97
98 #if defined(USE_SYS_getrandom) || defined(BORINGSSL_FIPS)
99 /* message writes |msg| to stderr. We use this because referencing |stderr|
100 * with |fprintf| generates relocations, which is a problem inside the FIPS
101 * module. */
message(const char * msg)102 static void message(const char *msg) {
103 ssize_t r;
104 do {
105 r = write(2, msg, strlen(msg));
106 } while (r == -1 && errno == EINTR);
107 }
108 #endif
109
110 /* init_once initializes the state of this module to values previously
111 * requested. This is the only function that modifies |urandom_fd| and
112 * |urandom_buffering|, whose values may be read safely after calling the
113 * once. */
init_once(void)114 static void init_once(void) {
115 CRYPTO_STATIC_MUTEX_lock_read(rand_lock_bss_get());
116 int fd = *urandom_fd_requested_bss_get();
117 CRYPTO_STATIC_MUTEX_unlock_read(rand_lock_bss_get());
118
119 #if defined(USE_SYS_getrandom)
120 uint8_t dummy;
121 long getrandom_ret =
122 syscall(SYS_getrandom, &dummy, sizeof(dummy), GRND_NONBLOCK);
123
124 if (getrandom_ret == 1) {
125 *urandom_fd_bss_get() = kHaveGetrandom;
126 return;
127 } else if (getrandom_ret == -1 && errno == EAGAIN) {
128 message(
129 "getrandom indicates that the entropy pool has not been initialized. "
130 "Rather than continue with poor entropy, this process will block until "
131 "entropy is available.\n");
132
133 do {
134 getrandom_ret =
135 syscall(SYS_getrandom, &dummy, sizeof(dummy), 0 /* no flags */);
136 } while (getrandom_ret == -1 && errno == EINTR);
137
138 if (getrandom_ret == 1) {
139 *urandom_fd_bss_get() = kHaveGetrandom;
140 return;
141 }
142 }
143 #endif /* USE_SYS_getrandom */
144
145 if (fd == kUnset) {
146 do {
147 fd = open("/dev/urandom", O_RDONLY);
148 } while (fd == -1 && errno == EINTR);
149 }
150
151 if (fd < 0) {
152 abort();
153 }
154
155 assert(kUnset == 0);
156 if (fd == kUnset) {
157 /* Because we want to keep |urandom_fd| in the BSS, we have to initialise
158 * it to zero. But zero is a valid file descriptor too. Thus if open
159 * returns zero for /dev/urandom, we dup it to get a non-zero number. */
160 fd = dup(fd);
161 close(kUnset);
162
163 if (fd <= 0) {
164 abort();
165 }
166 }
167
168 #if defined(BORINGSSL_FIPS)
169 /* In FIPS mode we ensure that the kernel has sufficient entropy before
170 * continuing. This is automatically handled by getrandom, which requires
171 * that the entropy pool has been initialised, but for urandom we have to
172 * poll. */
173 for (;;) {
174 int entropy_bits;
175 if (ioctl(fd, RNDGETENTCNT, &entropy_bits)) {
176 message(
177 "RNDGETENTCNT on /dev/urandom failed. We cannot continue in this "
178 "case when in FIPS mode.\n");
179 abort();
180 }
181
182 static const int kBitsNeeded = 256;
183 if (entropy_bits >= kBitsNeeded) {
184 break;
185 }
186
187 usleep(250000);
188 }
189 #endif
190
191 int flags = fcntl(fd, F_GETFD);
192 if (flags == -1) {
193 /* Native Client doesn't implement |fcntl|. */
194 if (errno != ENOSYS) {
195 abort();
196 }
197 } else {
198 flags |= FD_CLOEXEC;
199 if (fcntl(fd, F_SETFD, flags) == -1) {
200 abort();
201 }
202 }
203 *urandom_fd_bss_get() = fd;
204 }
205
RAND_set_urandom_fd(int fd)206 void RAND_set_urandom_fd(int fd) {
207 fd = dup(fd);
208 if (fd < 0) {
209 abort();
210 }
211
212 assert(kUnset == 0);
213 if (fd == kUnset) {
214 /* Because we want to keep |urandom_fd| in the BSS, we have to initialise
215 * it to zero. But zero is a valid file descriptor too. Thus if dup
216 * returned zero we dup it again to get a non-zero number. */
217 fd = dup(fd);
218 close(kUnset);
219
220 if (fd <= 0) {
221 abort();
222 }
223 }
224
225 CRYPTO_STATIC_MUTEX_lock_write(rand_lock_bss_get());
226 *urandom_fd_requested_bss_get() = fd;
227 CRYPTO_STATIC_MUTEX_unlock_write(rand_lock_bss_get());
228
229 CRYPTO_once(rand_once_bss_get(), init_once);
230 if (*urandom_fd_bss_get() == kHaveGetrandom) {
231 close(fd);
232 } else if (*urandom_fd_bss_get() != fd) {
233 abort(); // Already initialized.
234 }
235 }
236
237 #if defined(USE_SYS_getrandom) && defined(OPENSSL_MSAN)
238 void __msan_unpoison(void *, size_t);
239 #endif
240
241 /* fill_with_entropy writes |len| bytes of entropy into |out|. It returns one
242 * on success and zero on error. */
fill_with_entropy(uint8_t * out,size_t len)243 static char fill_with_entropy(uint8_t *out, size_t len) {
244 while (len > 0) {
245 ssize_t r;
246
247 if (*urandom_fd_bss_get() == kHaveGetrandom) {
248 #if defined(USE_SYS_getrandom)
249 do {
250 r = syscall(SYS_getrandom, out, len, 0 /* no flags */);
251 } while (r == -1 && errno == EINTR);
252
253 #if defined(OPENSSL_MSAN)
254 if (r > 0) {
255 /* MSAN doesn't recognise |syscall| and thus doesn't notice that we
256 * have initialised the output buffer. */
257 __msan_unpoison(out, r);
258 }
259 #endif /* OPENSSL_MSAN */
260
261 #else /* USE_SYS_getrandom */
262 abort();
263 #endif
264 } else {
265 do {
266 r = read(*urandom_fd_bss_get(), out, len);
267 } while (r == -1 && errno == EINTR);
268 }
269
270 if (r <= 0) {
271 return 0;
272 }
273 out += r;
274 len -= r;
275 }
276
277 return 1;
278 }
279
280 /* CRYPTO_sysrand puts |requested| random bytes into |out|. */
CRYPTO_sysrand(uint8_t * out,size_t requested)281 void CRYPTO_sysrand(uint8_t *out, size_t requested) {
282 if (requested == 0) {
283 return;
284 }
285
286 CRYPTO_once(rand_once_bss_get(), init_once);
287
288 if (!fill_with_entropy(out, requested)) {
289 abort();
290 }
291
292 #if defined(BORINGSSL_FIPS_BREAK_CRNG)
293 // This breaks the "continuous random number generator test" defined in FIPS
294 // 140-2, section 4.9.2, and implemented in rand_get_seed().
295 OPENSSL_memset(out, 0, requested);
296 #endif
297 }
298
299 #endif /* !OPENSSL_WINDOWS && !defined(OPENSSL_FUCHSIA) && \
300 !BORINGSSL_UNSAFE_DETERMINISTIC_MODE && !OPENSSL_TRUSTY */
301