blob: 2ea8730c6ecb8dce3735e40aaa31f4eff7f4947a [file] [log] [blame]
Adam Langleyd9e397b2015-01-22 14:27:53 -08001/* 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
Robert Sloan8ff03552017-06-14 12:40:58 -070015#if !defined(_GNU_SOURCE)
16#define _GNU_SOURCE /* needed for syscall() on Linux. */
17#endif
18
Adam Langleyd9e397b2015-01-22 14:27:53 -080019#include <openssl/rand.h>
20
Steven Valdezb0b45c62017-01-17 16:23:54 -050021#if !defined(OPENSSL_WINDOWS) && !defined(OPENSSL_FUCHSIA) && \
Michael Ryleev938d65f2017-05-01 09:39:18 -070022 !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE) && !defined(OPENSSL_TRUSTY)
Adam Langleyd9e397b2015-01-22 14:27:53 -080023
24#include <assert.h>
25#include <errno.h>
26#include <fcntl.h>
David Benjamin1b249672016-12-06 18:25:50 -050027#include <stdio.h>
Adam Langleyd9e397b2015-01-22 14:27:53 -080028#include <string.h>
29#include <unistd.h>
30
Steven Valdez909b19f2016-11-21 15:35:44 -050031#if defined(OPENSSL_LINUX)
Robert Sloan572a4e22017-04-17 10:52:19 -070032#include <linux/random.h>
33#include <sys/ioctl.h>
Steven Valdez909b19f2016-11-21 15:35:44 -050034#include <sys/syscall.h>
35#endif
36
Adam Langleyd9e397b2015-01-22 14:27:53 -080037#include <openssl/thread.h>
38#include <openssl/mem.h>
39
Adam Langleye9ada862015-05-11 17:20:37 -070040#include "internal.h"
Robert Sloan9254e682017-04-24 09:42:06 -070041#include "../delocate.h"
42#include "../../internal.h"
Adam Langleye9ada862015-05-11 17:20:37 -070043
Adam Langleyd9e397b2015-01-22 14:27:53 -080044
Steven Valdez909b19f2016-11-21 15:35:44 -050045#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
Robert Sloan9254e682017-04-24 09:42:06 -070082/* rand_lock is used to protect the |*_requested| variables. */
83DEFINE_STATIC_MUTEX(rand_lock);
Adam Langleyd9e397b2015-01-22 14:27:53 -080084
David Benjamin1b249672016-12-06 18:25:50 -050085/* The following constants are magic values of |urandom_fd|. */
Robert Sloan9254e682017-04-24 09:42:06 -070086static const int kUnset = 0;
David Benjamin1b249672016-12-06 18:25:50 -050087static const int kHaveGetrandom = -3;
88
89/* urandom_fd_requested is set by |RAND_set_urandom_fd|. It's protected by
Robert Sloan9254e682017-04-24 09:42:06 -070090 * |rand_lock|. */
91DEFINE_BSS_GET(int, urandom_fd_requested);
Adam Langleye9ada862015-05-11 17:20:37 -070092
Kenny Rootb8494592015-09-25 02:29:14 +000093/* urandom_fd is a file descriptor to /dev/urandom. It's protected by |once|. */
Robert Sloan9254e682017-04-24 09:42:06 -070094DEFINE_BSS_GET(int, urandom_fd);
Adam Langleyd9e397b2015-01-22 14:27:53 -080095
Robert Sloan9254e682017-04-24 09:42:06 -070096DEFINE_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. */
102static 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
Kenny Rootb8494592015-09-25 02:29:14 +0000109
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. */
114static void init_once(void) {
Robert Sloan9254e682017-04-24 09:42:06 -0700115 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());
Kenny Rootb8494592015-09-25 02:29:14 +0000118
Steven Valdez909b19f2016-11-21 15:35:44 -0500119#if defined(USE_SYS_getrandom)
Steven Valdez909b19f2016-11-21 15:35:44 -0500120 uint8_t dummy;
David Benjamin1b249672016-12-06 18:25:50 -0500121 long getrandom_ret =
122 syscall(SYS_getrandom, &dummy, sizeof(dummy), GRND_NONBLOCK);
Steven Valdez909b19f2016-11-21 15:35:44 -0500123
David Benjamin1b249672016-12-06 18:25:50 -0500124 if (getrandom_ret == 1) {
Robert Sloan9254e682017-04-24 09:42:06 -0700125 *urandom_fd_bss_get() = kHaveGetrandom;
David Benjamin1b249672016-12-06 18:25:50 -0500126 return;
127 } else if (getrandom_ret == -1 && errno == EAGAIN) {
Robert Sloan9254e682017-04-24 09:42:06 -0700128 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
David Benjamin1b249672016-12-06 18:25:50 -0500133 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) {
Robert Sloan9254e682017-04-24 09:42:06 -0700139 *urandom_fd_bss_get() = kHaveGetrandom;
David Benjamin1b249672016-12-06 18:25:50 -0500140 return;
141 }
142 }
143#endif /* USE_SYS_getrandom */
144
145 if (fd == kUnset) {
Kenny Rootb8494592015-09-25 02:29:14 +0000146 do {
147 fd = open("/dev/urandom", O_RDONLY);
148 } while (fd == -1 && errno == EINTR);
Adam Langleye9ada862015-05-11 17:20:37 -0700149 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800150
Kenny Rootb8494592015-09-25 02:29:14 +0000151 if (fd < 0) {
152 abort();
153 }
154
Robert Sloan9254e682017-04-24 09:42:06 -0700155 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
Robert Sloan572a4e22017-04-17 10:52:19 -0700168#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. */
Robert Sloan572a4e22017-04-17 10:52:19 -0700173 for (;;) {
174 int entropy_bits;
175 if (ioctl(fd, RNDGETENTCNT, &entropy_bits)) {
Robert Sloan9254e682017-04-24 09:42:06 -0700176 message(
177 "RNDGETENTCNT on /dev/urandom failed. We cannot continue in this "
178 "case when in FIPS mode.\n");
Robert Sloan572a4e22017-04-17 10:52:19 -0700179 abort();
180 }
181
182 static const int kBitsNeeded = 256;
183 if (entropy_bits >= kBitsNeeded) {
184 break;
185 }
186
Robert Sloan572a4e22017-04-17 10:52:19 -0700187 usleep(250000);
188 }
189#endif
190
Kenny Rootb8494592015-09-25 02:29:14 +0000191 int flags = fcntl(fd, F_GETFD);
192 if (flags == -1) {
Adam Langley4139edb2016-01-13 15:00:54 -0800193 /* 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 }
Kenny Rootb8494592015-09-25 02:29:14 +0000202 }
Robert Sloan9254e682017-04-24 09:42:06 -0700203 *urandom_fd_bss_get() = fd;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800204}
205
Kenny Rootb8494592015-09-25 02:29:14 +0000206void RAND_set_urandom_fd(int fd) {
207 fd = dup(fd);
208 if (fd < 0) {
209 abort();
Adam Langleyd9e397b2015-01-22 14:27:53 -0800210 }
Kenny Rootb8494592015-09-25 02:29:14 +0000211
Robert Sloan9254e682017-04-24 09:42:06 -0700212 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);
Kenny Rootb8494592015-09-25 02:29:14 +0000219
Robert Sloan9254e682017-04-24 09:42:06 -0700220 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) {
David Benjamin1b249672016-12-06 18:25:50 -0500231 close(fd);
Robert Sloan9254e682017-04-24 09:42:06 -0700232 } else if (*urandom_fd_bss_get() != fd) {
Kenny Rootb8494592015-09-25 02:29:14 +0000233 abort(); // Already initialized.
Adam Langleyd9e397b2015-01-22 14:27:53 -0800234 }
Kenny Rootb8494592015-09-25 02:29:14 +0000235}
236
Robert Sloan8ff03552017-06-14 12:40:58 -0700237#if defined(USE_SYS_getrandom) && defined(OPENSSL_MSAN)
Robert Sloan69939df2017-01-09 10:53:07 -0800238void __msan_unpoison(void *, size_t);
239#endif
Robert Sloan69939df2017-01-09 10:53:07 -0800240
Steven Valdez909b19f2016-11-21 15:35:44 -0500241/* fill_with_entropy writes |len| bytes of entropy into |out|. It returns one
242 * on success and zero on error. */
243static char fill_with_entropy(uint8_t *out, size_t len) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800244 while (len > 0) {
Robert Sloan69939df2017-01-09 10:53:07 -0800245 ssize_t r;
246
Robert Sloan9254e682017-04-24 09:42:06 -0700247 if (*urandom_fd_bss_get() == kHaveGetrandom) {
David Benjamin1b249672016-12-06 18:25:50 -0500248#if defined(USE_SYS_getrandom)
249 do {
250 r = syscall(SYS_getrandom, out, len, 0 /* no flags */);
251 } while (r == -1 && errno == EINTR);
Robert Sloan69939df2017-01-09 10:53:07 -0800252
Robert Sloan8ff03552017-06-14 12:40:58 -0700253#if defined(OPENSSL_MSAN)
Robert Sloan69939df2017-01-09 10:53:07 -0800254 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 }
Robert Sloan8ff03552017-06-14 12:40:58 -0700259#endif /* OPENSSL_MSAN */
Robert Sloan69939df2017-01-09 10:53:07 -0800260
261#else /* USE_SYS_getrandom */
David Benjamin1b249672016-12-06 18:25:50 -0500262 abort();
263#endif
264 } else {
265 do {
Robert Sloan9254e682017-04-24 09:42:06 -0700266 r = read(*urandom_fd_bss_get(), out, len);
David Benjamin1b249672016-12-06 18:25:50 -0500267 } while (r == -1 && errno == EINTR);
268 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800269
270 if (r <= 0) {
271 return 0;
272 }
273 out += r;
274 len -= r;
275 }
276
277 return 1;
278}
279
Kenny Rootb8494592015-09-25 02:29:14 +0000280/* CRYPTO_sysrand puts |requested| random bytes into |out|. */
281void CRYPTO_sysrand(uint8_t *out, size_t requested) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800282 if (requested == 0) {
Adam Langleye9ada862015-05-11 17:20:37 -0700283 return;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800284 }
285
Robert Sloan9254e682017-04-24 09:42:06 -0700286 CRYPTO_once(rand_once_bss_get(), init_once);
Kenny Roota04d78d2015-09-25 00:26:37 +0000287
Steven Valdez909b19f2016-11-21 15:35:44 -0500288 if (!fill_with_entropy(out, requested)) {
Kenny Roota04d78d2015-09-25 00:26:37 +0000289 abort();
Adam Langley1e4884f2015-09-24 10:57:52 -0700290 }
Robert Sloan8ff03552017-06-14 12:40:58 -0700291
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
Adam Langleyd9e397b2015-01-22 14:27:53 -0800297}
298
Steven Valdezb0b45c62017-01-17 16:23:54 -0500299#endif /* !OPENSSL_WINDOWS && !defined(OPENSSL_FUCHSIA) && \
Michael Ryleev938d65f2017-05-01 09:39:18 -0700300 !BORINGSSL_UNSAFE_DETERMINISTIC_MODE && !OPENSSL_TRUSTY */