• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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