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