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 #include <openssl/rand.h>
     16 
     17 #if !defined(OPENSSL_WINDOWS)
     18 
     19 #include <assert.h>
     20 #include <errno.h>
     21 #include <fcntl.h>
     22 #include <string.h>
     23 #include <unistd.h>
     24 
     25 #include <openssl/thread.h>
     26 #include <openssl/mem.h>
     27 
     28 #include "internal.h"
     29 #include "../internal.h"
     30 
     31 
     32 /* This file implements a PRNG by reading from /dev/urandom, optionally with a
     33  * buffer, which is unsafe across |fork|. */
     34 
     35 #define BUF_SIZE 4096
     36 
     37 /* rand_buffer contains unused, random bytes, some of which may have been
     38  * consumed already. */
     39 struct rand_buffer {
     40   size_t used;
     41   uint8_t rand[BUF_SIZE];
     42 };
     43 
     44 /* requested_lock is used to protect the |*_requested| variables. */
     45 static struct CRYPTO_STATIC_MUTEX requested_lock = CRYPTO_STATIC_MUTEX_INIT;
     46 
     47 /* urandom_fd_requested is set by |RAND_set_urandom_fd|.  It's protected by
     48  * |requested_lock|. */
     49 static int urandom_fd_requested = -2;
     50 
     51 /* urandom_fd is a file descriptor to /dev/urandom. It's protected by |once|. */
     52 static int urandom_fd = -2;
     53 
     54 /* urandom_buffering_requested is set by |RAND_enable_fork_unsafe_buffering|.
     55  * It's protected by |requested_lock|. */
     56 static int urandom_buffering_requested = 0;
     57 
     58 /* urandom_buffering controls whether buffering is enabled (1) or not (0). This
     59  * is protected by |once|. */
     60 static int urandom_buffering = 0;
     61 
     62 static CRYPTO_once_t once = CRYPTO_ONCE_INIT;
     63 
     64 /* init_once initializes the state of this module to values previously
     65  * requested. This is the only function that modifies |urandom_fd| and
     66  * |urandom_buffering|, whose values may be read safely after calling the
     67  * once. */
     68 static void init_once(void) {
     69   CRYPTO_STATIC_MUTEX_lock_read(&requested_lock);
     70   urandom_buffering = urandom_buffering_requested;
     71   int fd = urandom_fd_requested;
     72   CRYPTO_STATIC_MUTEX_unlock(&requested_lock);
     73 
     74   if (fd == -2) {
     75     do {
     76       fd = open("/dev/urandom", O_RDONLY);
     77     } while (fd == -1 && errno == EINTR);
     78   }
     79 
     80   if (fd < 0) {
     81     abort();
     82   }
     83 
     84   int flags = fcntl(fd, F_GETFD);
     85   if (flags == -1) {
     86     /* Native Client doesn't implement |fcntl|. */
     87     if (errno != ENOSYS) {
     88       abort();
     89     }
     90   } else {
     91     flags |= FD_CLOEXEC;
     92     if (fcntl(fd, F_SETFD, flags) == -1) {
     93       abort();
     94     }
     95   }
     96   urandom_fd = fd;
     97 }
     98 
     99 void RAND_cleanup(void) {}
    100 
    101 void RAND_set_urandom_fd(int fd) {
    102   fd = dup(fd);
    103   if (fd < 0) {
    104     abort();
    105   }
    106 
    107   CRYPTO_STATIC_MUTEX_lock_write(&requested_lock);
    108   urandom_fd_requested = fd;
    109   CRYPTO_STATIC_MUTEX_unlock(&requested_lock);
    110 
    111   CRYPTO_once(&once, init_once);
    112   if (urandom_fd != fd) {
    113     abort();  // Already initialized.
    114   }
    115 }
    116 
    117 void RAND_enable_fork_unsafe_buffering(int fd) {
    118   if (fd >= 0) {
    119     fd = dup(fd);
    120     if (fd < 0) {
    121       abort();
    122     }
    123   } else {
    124     fd = -2;
    125   }
    126 
    127   CRYPTO_STATIC_MUTEX_lock_write(&requested_lock);
    128   urandom_buffering_requested = 1;
    129   urandom_fd_requested = fd;
    130   CRYPTO_STATIC_MUTEX_unlock(&requested_lock);
    131 
    132   CRYPTO_once(&once, init_once);
    133   if (urandom_buffering != 1 || (fd >= 0 && urandom_fd != fd)) {
    134     abort();  // Already initialized.
    135   }
    136 }
    137 
    138 static struct rand_buffer *get_thread_local_buffer(void) {
    139   struct rand_buffer *buf =
    140       CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_URANDOM_BUF);
    141   if (buf != NULL) {
    142     return buf;
    143   }
    144 
    145   buf = OPENSSL_malloc(sizeof(struct rand_buffer));
    146   if (buf == NULL) {
    147     return NULL;
    148   }
    149   buf->used = BUF_SIZE;  /* To trigger a |read_full| on first use. */
    150   if (!CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_URANDOM_BUF, buf,
    151                                OPENSSL_free)) {
    152     OPENSSL_free(buf);
    153     return NULL;
    154   }
    155 
    156   return buf;
    157 }
    158 
    159 /* read_full reads exactly |len| bytes from |fd| into |out| and returns 1. In
    160  * the case of an error it returns 0. */
    161 static char read_full(int fd, uint8_t *out, size_t len) {
    162   ssize_t r;
    163 
    164   while (len > 0) {
    165     do {
    166       r = read(fd, out, len);
    167     } while (r == -1 && errno == EINTR);
    168 
    169     if (r <= 0) {
    170       return 0;
    171     }
    172     out += r;
    173     len -= r;
    174   }
    175 
    176   return 1;
    177 }
    178 
    179 /* read_from_buffer reads |requested| random bytes from the buffer into |out|,
    180  * refilling it if necessary to satisfy the request. */
    181 static void read_from_buffer(struct rand_buffer *buf,
    182                              uint8_t *out, size_t requested) {
    183   size_t remaining = BUF_SIZE - buf->used;
    184 
    185   while (requested > remaining) {
    186     memcpy(out, &buf->rand[buf->used], remaining);
    187     buf->used += remaining;
    188     out += remaining;
    189     requested -= remaining;
    190 
    191     if (!read_full(urandom_fd, buf->rand, BUF_SIZE)) {
    192       abort();
    193       return;
    194     }
    195     buf->used = 0;
    196     remaining = BUF_SIZE;
    197   }
    198 
    199   memcpy(out, &buf->rand[buf->used], requested);
    200   buf->used += requested;
    201 }
    202 
    203 /* CRYPTO_sysrand puts |requested| random bytes into |out|. */
    204 void CRYPTO_sysrand(uint8_t *out, size_t requested) {
    205   if (requested == 0) {
    206     return;
    207   }
    208 
    209   CRYPTO_once(&once, init_once);
    210   if (urandom_buffering && requested < BUF_SIZE) {
    211     struct rand_buffer *buf = get_thread_local_buffer();
    212     if (buf != NULL) {
    213       read_from_buffer(buf, out, requested);
    214       return;
    215     }
    216   }
    217 
    218   if (!read_full(urandom_fd, out, requested)) {
    219     abort();
    220   }
    221 }
    222 
    223 #endif  /* !OPENSSL_WINDOWS */
    224