blob: f3aab4485f3c815cfb3eff89c345fb0c3cc3b3cb [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 Sloan4d1ac502017-02-06 08:36:14 -080015#if !defined(_GNU_SOURCE)
Steven Valdez909b19f2016-11-21 15:35:44 -050016#define _GNU_SOURCE /* needed for syscall() on Linux. */
Robert Sloan4d1ac502017-02-06 08:36:14 -080017#endif
Steven Valdez909b19f2016-11-21 15:35:44 -050018
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) && \
22 !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
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"
41#include "../internal.h"
42
Adam Langleyd9e397b2015-01-22 14:27:53 -080043
Steven Valdez909b19f2016-11-21 15:35:44 -050044#if defined(OPENSSL_LINUX)
45
46#if defined(OPENSSL_X86_64)
47#define EXPECTED_SYS_getrandom 318
48#elif defined(OPENSSL_X86)
49#define EXPECTED_SYS_getrandom 355
50#elif defined(OPENSSL_AARCH64)
51#define EXPECTED_SYS_getrandom 278
52#elif defined(OPENSSL_ARM)
53#define EXPECTED_SYS_getrandom 384
54#elif defined(OPENSSL_PPC64LE)
55#define EXPECTED_SYS_getrandom 359
56#endif
57
58#if defined(EXPECTED_SYS_getrandom)
59#define USE_SYS_getrandom
60
61#if defined(SYS_getrandom)
62
63#if SYS_getrandom != EXPECTED_SYS_getrandom
64#error "system call number for getrandom is not the expected value"
65#endif
66
67#else /* SYS_getrandom */
68
69#define SYS_getrandom EXPECTED_SYS_getrandom
70
71#endif /* SYS_getrandom */
72
73#endif /* EXPECTED_SYS_getrandom */
74
75#if !defined(GRND_NONBLOCK)
76#define GRND_NONBLOCK 1
77#endif
78
79#endif /* OPENSSL_LINUX */
80
Kenny Rootb8494592015-09-25 02:29:14 +000081/* requested_lock is used to protect the |*_requested| variables. */
82static struct CRYPTO_STATIC_MUTEX requested_lock = CRYPTO_STATIC_MUTEX_INIT;
Adam Langleyd9e397b2015-01-22 14:27:53 -080083
David Benjamin1b249672016-12-06 18:25:50 -050084/* The following constants are magic values of |urandom_fd|. */
85static const int kUnset = -2;
86static const int kHaveGetrandom = -3;
87
88/* urandom_fd_requested is set by |RAND_set_urandom_fd|. It's protected by
Kenny Rootb8494592015-09-25 02:29:14 +000089 * |requested_lock|. */
David Benjamin1b249672016-12-06 18:25:50 -050090static int urandom_fd_requested = -2 /* kUnset */;
Adam Langleye9ada862015-05-11 17:20:37 -070091
Kenny Rootb8494592015-09-25 02:29:14 +000092/* urandom_fd is a file descriptor to /dev/urandom. It's protected by |once|. */
David Benjamin1b249672016-12-06 18:25:50 -050093static int urandom_fd = -2 /* kUnset */;
Adam Langleyd9e397b2015-01-22 14:27:53 -080094
Kenny Rootb8494592015-09-25 02:29:14 +000095static CRYPTO_once_t once = CRYPTO_ONCE_INIT;
96
97/* init_once initializes the state of this module to values previously
98 * requested. This is the only function that modifies |urandom_fd| and
99 * |urandom_buffering|, whose values may be read safely after calling the
100 * once. */
101static void init_once(void) {
102 CRYPTO_STATIC_MUTEX_lock_read(&requested_lock);
Kenny Rootb8494592015-09-25 02:29:14 +0000103 int fd = urandom_fd_requested;
David Benjamind316cba2016-06-02 16:17:39 -0400104 CRYPTO_STATIC_MUTEX_unlock_read(&requested_lock);
Kenny Rootb8494592015-09-25 02:29:14 +0000105
Steven Valdez909b19f2016-11-21 15:35:44 -0500106#if defined(USE_SYS_getrandom)
Steven Valdez909b19f2016-11-21 15:35:44 -0500107 uint8_t dummy;
David Benjamin1b249672016-12-06 18:25:50 -0500108 long getrandom_ret =
109 syscall(SYS_getrandom, &dummy, sizeof(dummy), GRND_NONBLOCK);
Steven Valdez909b19f2016-11-21 15:35:44 -0500110
David Benjamin1b249672016-12-06 18:25:50 -0500111 if (getrandom_ret == 1) {
112 urandom_fd = kHaveGetrandom;
113 return;
114 } else if (getrandom_ret == -1 && errno == EAGAIN) {
115 fprintf(stderr,
116 "getrandom indicates that the entropy pool has not been "
117 "initialized. Rather than continue with poor entropy, this process "
118 "will block until entropy is available.\n");
119 do {
120 getrandom_ret =
121 syscall(SYS_getrandom, &dummy, sizeof(dummy), 0 /* no flags */);
122 } while (getrandom_ret == -1 && errno == EINTR);
123
124 if (getrandom_ret == 1) {
125 urandom_fd = kHaveGetrandom;
126 return;
127 }
128 }
129#endif /* USE_SYS_getrandom */
130
131 if (fd == kUnset) {
Kenny Rootb8494592015-09-25 02:29:14 +0000132 do {
133 fd = open("/dev/urandom", O_RDONLY);
134 } while (fd == -1 && errno == EINTR);
Adam Langleye9ada862015-05-11 17:20:37 -0700135 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800136
Kenny Rootb8494592015-09-25 02:29:14 +0000137 if (fd < 0) {
138 abort();
139 }
140
Robert Sloan572a4e22017-04-17 10:52:19 -0700141#if defined(BORINGSSL_FIPS)
142 /* In FIPS mode we ensure that the kernel has sufficient entropy before
143 * continuing. This is automatically handled by getrandom, which requires
144 * that the entropy pool has been initialised, but for urandom we have to
145 * poll. */
146 int first_iteration = 1;
147 for (;;) {
148 int entropy_bits;
149 if (ioctl(fd, RNDGETENTCNT, &entropy_bits)) {
150 fprintf(stderr,
151 "RNDGETENTCNT on /dev/urandom failed. We cannot continue in this "
152 "case when in FIPS mode.\n");
153 abort();
154 }
155
156 static const int kBitsNeeded = 256;
157 if (entropy_bits >= kBitsNeeded) {
158 break;
159 }
160
161 if (first_iteration) {
162 fprintf(stderr,
163 "The kernel entropy pool contains too few bits: have %d, want "
164 "%d. This process is built in FIPS mode and will block until "
165 "sufficient entropy is available.\n", entropy_bits, kBitsNeeded);
166 }
167 first_iteration = 0;
168
169 usleep(250000);
170 }
171#endif
172
Kenny Rootb8494592015-09-25 02:29:14 +0000173 int flags = fcntl(fd, F_GETFD);
174 if (flags == -1) {
Adam Langley4139edb2016-01-13 15:00:54 -0800175 /* Native Client doesn't implement |fcntl|. */
176 if (errno != ENOSYS) {
177 abort();
178 }
179 } else {
180 flags |= FD_CLOEXEC;
181 if (fcntl(fd, F_SETFD, flags) == -1) {
182 abort();
183 }
Kenny Rootb8494592015-09-25 02:29:14 +0000184 }
185 urandom_fd = fd;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800186}
187
Kenny Rootb8494592015-09-25 02:29:14 +0000188void RAND_set_urandom_fd(int fd) {
189 fd = dup(fd);
190 if (fd < 0) {
191 abort();
Adam Langleyd9e397b2015-01-22 14:27:53 -0800192 }
Kenny Rootb8494592015-09-25 02:29:14 +0000193
194 CRYPTO_STATIC_MUTEX_lock_write(&requested_lock);
195 urandom_fd_requested = fd;
David Benjamind316cba2016-06-02 16:17:39 -0400196 CRYPTO_STATIC_MUTEX_unlock_write(&requested_lock);
Kenny Rootb8494592015-09-25 02:29:14 +0000197
198 CRYPTO_once(&once, init_once);
David Benjamin1b249672016-12-06 18:25:50 -0500199 if (urandom_fd == kHaveGetrandom) {
200 close(fd);
201 } else if (urandom_fd != fd) {
Kenny Rootb8494592015-09-25 02:29:14 +0000202 abort(); // Already initialized.
Adam Langleyd9e397b2015-01-22 14:27:53 -0800203 }
Kenny Rootb8494592015-09-25 02:29:14 +0000204}
205
Robert Sloan69939df2017-01-09 10:53:07 -0800206#if defined(USE_SYS_getrandom) && defined(__has_feature)
207#if __has_feature(memory_sanitizer)
208void __msan_unpoison(void *, size_t);
209#endif
210#endif
211
Steven Valdez909b19f2016-11-21 15:35:44 -0500212/* fill_with_entropy writes |len| bytes of entropy into |out|. It returns one
213 * on success and zero on error. */
214static char fill_with_entropy(uint8_t *out, size_t len) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800215 while (len > 0) {
Robert Sloan69939df2017-01-09 10:53:07 -0800216 ssize_t r;
217
David Benjamin1b249672016-12-06 18:25:50 -0500218 if (urandom_fd == kHaveGetrandom) {
219#if defined(USE_SYS_getrandom)
220 do {
221 r = syscall(SYS_getrandom, out, len, 0 /* no flags */);
222 } while (r == -1 && errno == EINTR);
Robert Sloan69939df2017-01-09 10:53:07 -0800223
224#if defined(__has_feature)
225#if __has_feature(memory_sanitizer)
226 if (r > 0) {
227 /* MSAN doesn't recognise |syscall| and thus doesn't notice that we
228 * have initialised the output buffer. */
229 __msan_unpoison(out, r);
230 }
231#endif /* memory_sanitizer */
232#endif /*__has_feature */
233
234#else /* USE_SYS_getrandom */
David Benjamin1b249672016-12-06 18:25:50 -0500235 abort();
236#endif
237 } else {
238 do {
239 r = read(urandom_fd, out, len);
240 } while (r == -1 && errno == EINTR);
241 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800242
243 if (r <= 0) {
244 return 0;
245 }
246 out += r;
247 len -= r;
248 }
249
250 return 1;
251}
252
Kenny Rootb8494592015-09-25 02:29:14 +0000253/* CRYPTO_sysrand puts |requested| random bytes into |out|. */
254void CRYPTO_sysrand(uint8_t *out, size_t requested) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800255 if (requested == 0) {
Adam Langleye9ada862015-05-11 17:20:37 -0700256 return;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800257 }
258
Kenny Rootb8494592015-09-25 02:29:14 +0000259 CRYPTO_once(&once, init_once);
Kenny Roota04d78d2015-09-25 00:26:37 +0000260
Steven Valdez909b19f2016-11-21 15:35:44 -0500261 if (!fill_with_entropy(out, requested)) {
Kenny Roota04d78d2015-09-25 00:26:37 +0000262 abort();
Adam Langley1e4884f2015-09-24 10:57:52 -0700263 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800264}
265
Steven Valdezb0b45c62017-01-17 16:23:54 -0500266#endif /* !OPENSSL_WINDOWS && !defined(OPENSSL_FUCHSIA) && \
267 !BORINGSSL_UNSAFE_DETERMINISTIC_MODE */