X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Frand%2Frand_unix.c;h=39c4e7e7417a627640cdc0fae68cd682d5de6541;hp=74cc9e146fdf2030eff8cf8bfe4bca93b0aad0d7;hb=38023b87f037f4b832c236dfce2a76272be08763;hpb=9b5f1c8fd81c01bbaa0aeca0f97e65fee4ab9745 diff --git a/crypto/rand/rand_unix.c b/crypto/rand/rand_unix.c index 74cc9e146f..39c4e7e741 100644 --- a/crypto/rand/rand_unix.c +++ b/crypto/rand/rand_unix.c @@ -1,7 +1,7 @@ /* * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html @@ -19,7 +19,7 @@ #include #include "internal/dso.h" #if defined(__linux) -# include +# include #endif #if defined(__FreeBSD__) # include @@ -77,17 +77,47 @@ static uint64_t get_timer_bits(void); # endif #endif /* defined(OPENSSL_SYS_UNIX) || defined(__DJGPP__) */ +#if defined(OPENSSL_RAND_SEED_NONE) +/* none means none. this simplifies the following logic */ +# undef OPENSSL_RAND_SEED_OS +# undef OPENSSL_RAND_SEED_GETRANDOM +# undef OPENSSL_RAND_SEED_LIBRANDOM +# undef OPENSSL_RAND_SEED_DEVRANDOM +# undef OPENSSL_RAND_SEED_RDTSC +# undef OPENSSL_RAND_SEED_RDCPU +# undef OPENSSL_RAND_SEED_EGD +#endif + #if (defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_UEFI)) && \ !defined(OPENSSL_RAND_SEED_NONE) # error "UEFI and VXWorks only support seeding NONE" #endif +#if defined(OPENSSL_SYS_VXWORKS) +/* empty implementation */ +int rand_pool_init(void) +{ + return 1; +} + +void rand_pool_cleanup(void) +{ +} + +void rand_pool_keep_random_devices_open(int keep) +{ +} + +size_t rand_pool_acquire_entropy(RAND_POOL *pool) +{ + return rand_pool_entropy_available(pool); +} +#endif + #if !(defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32) \ || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_VXWORKS) \ || defined(OPENSSL_SYS_UEFI)) -static ssize_t syscall_random(void *buf, size_t buflen); - # if defined(OPENSSL_SYS_VOS) # ifndef OPENSSL_RAND_SEED_OS @@ -244,6 +274,7 @@ static ssize_t sysctl_random(char *buf, size_t buflen) } # endif +# if defined(OPENSSL_RAND_SEED_GETRANDOM) /* * syscall_random(): Try to get random data using a system call * returns the number of bytes returned in buf, or < 0 on error. @@ -254,7 +285,7 @@ static ssize_t syscall_random(void *buf, size_t buflen) * Note: 'buflen' equals the size of the buffer which is used by the * get_entropy() callback of the RAND_DRBG. It is roughly bounded by * - * 2 * DRBG_MINMAX_FACTOR * (RAND_DRBG_STRENGTH / 8) = 2^13 + * 2 * RAND_POOL_FACTOR * (RAND_DRBG_STRENGTH / 8) = 2^14 * * which is way below the OSSL_SSIZE_MAX limit. Therefore sign conversion * between size_t and ssize_t is safe even without a range check. @@ -293,8 +324,8 @@ static ssize_t syscall_random(void *buf, size_t buflen) # endif /* Linux supports this since version 3.17 */ -# if defined(__linux) && defined(SYS_getrandom) - return syscall(SYS_getrandom, buf, buflen, 0); +# if defined(__linux) && defined(__NR_getrandom) + return syscall(__NR_getrandom, buf, buflen, 0); # elif (defined(__FreeBSD__) || defined(__NetBSD__)) && defined(KERN_ARND) return sysctl_random(buf, buflen); # else @@ -302,8 +333,9 @@ static ssize_t syscall_random(void *buf, size_t buflen) return -1; # endif } +# endif /* defined(OPENSSL_RAND_SEED_GETRANDOM) */ -#if !defined(OPENSSL_RAND_SEED_NONE) && defined(OPENSSL_RAND_SEED_DEVRANDOM) +# if defined(OPENSSL_RAND_SEED_DEVRANDOM) static const char *random_device_paths[] = { DEVRANDOM }; static struct random_device { int fd; @@ -375,21 +407,13 @@ static void close_random_device(size_t n) rd->fd = -1; } -static void open_random_devices(void) -{ - size_t i; - - for (i = 0; i < OSSL_NELEM(random_devices); i++) - (void)get_random_device(i); -} - int rand_pool_init(void) { size_t i; for (i = 0; i < OSSL_NELEM(random_devices); i++) random_devices[i].fd = -1; - open_random_devices(); + return 1; } @@ -403,16 +427,13 @@ void rand_pool_cleanup(void) void rand_pool_keep_random_devices_open(int keep) { - if (keep) - open_random_devices(); - else + if (!keep) rand_pool_cleanup(); + keep_random_devices_open = keep; } -# else /* defined(OPENSSL_RAND_SEED_NONE) - * || !defined(OPENSSL_RAND_SEED_DEVRANDOM) - */ +# else /* !defined(OPENSSL_RAND_SEED_DEVRANDOM) */ int rand_pool_init(void) { @@ -427,9 +448,7 @@ void rand_pool_keep_random_devices_open(int keep) { } -# endif /* !defined(OPENSSL_RAND_SEED_NONE) - * && defined(OPENSSL_RAND_SEED_DEVRANDOM) - */ +# endif /* defined(OPENSSL_RAND_SEED_DEVRANDOM) */ /* * Try the various seeding methods in turn, exit when successful. @@ -450,25 +469,33 @@ void rand_pool_keep_random_devices_open(int keep) */ size_t rand_pool_acquire_entropy(RAND_POOL *pool) { -# ifdef OPENSSL_RAND_SEED_NONE +# if defined(OPENSSL_RAND_SEED_NONE) return rand_pool_entropy_available(pool); # else size_t bytes_needed; size_t entropy_available = 0; unsigned char *buffer; -# ifdef OPENSSL_RAND_SEED_GETRANDOM - bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); - buffer = rand_pool_add_begin(pool, bytes_needed); - if (buffer != NULL) { - size_t bytes = 0; - - if (syscall_random(buffer, bytes_needed) == (int)bytes_needed) - bytes = bytes_needed; +# if defined(OPENSSL_RAND_SEED_GETRANDOM) + { + ssize_t bytes; + /* Maximum allowed number of consecutive unsuccessful attempts */ + int attempts = 3; - rand_pool_add_end(pool, bytes, 8 * bytes); - entropy_available = rand_pool_entropy_available(pool); + bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); + while (bytes_needed != 0 && attempts-- > 0) { + buffer = rand_pool_add_begin(pool, bytes_needed); + bytes = syscall_random(buffer, bytes_needed); + if (bytes > 0) { + rand_pool_add_end(pool, bytes, 8 * bytes); + bytes_needed -= bytes; + attempts = 3; /* reset counter after successful attempt */ + } else if (bytes < 0 && errno != EINTR) { + break; + } + } } + entropy_available = rand_pool_entropy_available(pool); if (entropy_available > 0) return entropy_available; # endif @@ -479,28 +506,56 @@ size_t rand_pool_acquire_entropy(RAND_POOL *pool) } # endif -# ifdef OPENSSL_RAND_SEED_DEVRANDOM +# if defined(OPENSSL_RAND_SEED_DEVRANDOM) bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); { size_t i; +#ifdef DEVRANDOM_WAIT + static int wait_done = 0; + + /* + * On some implementations reading from /dev/urandom is possible + * before it is initialized. Therefore we wait for /dev/random + * to be readable to make sure /dev/urandom is initialized. + */ + if (!wait_done && bytes_needed > 0) { + int f = open(DEVRANDOM_WAIT, O_RDONLY); + + if (f >= 0) { + fd_set fds; + + FD_ZERO(&fds); + FD_SET(f, &fds); + while (select(f+1, &fds, NULL, NULL, NULL) < 0 + && errno == EINTR); + close(f); + } + wait_done = 1; + } +#endif for (i = 0; bytes_needed > 0 && i < OSSL_NELEM(random_device_paths); i++) { + ssize_t bytes = 0; + /* Maximum allowed number of consecutive unsuccessful attempts */ + int attempts = 3; const int fd = get_random_device(i); if (fd == -1) continue; - buffer = rand_pool_add_begin(pool, bytes_needed); - if (buffer != NULL) { - const ssize_t n = read(fd, buffer, bytes_needed); - if (n <= 0) { - close_random_device(i); - continue; - } + while (bytes_needed != 0 && attempts-- > 0) { + buffer = rand_pool_add_begin(pool, bytes_needed); + bytes = read(fd, buffer, bytes_needed); - rand_pool_add_end(pool, n, 8 * n); + if (bytes > 0) { + rand_pool_add_end(pool, bytes, 8 * bytes); + bytes_needed -= bytes; + attempts = 3; /* reset counter after successful attempt */ + } else if (bytes < 0 && errno != EINTR) { + break; + } } - if (!keep_random_devices_open) + if (bytes < 0 || !keep_random_devices_open) close_random_device(i); bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); @@ -511,19 +566,19 @@ size_t rand_pool_acquire_entropy(RAND_POOL *pool) } # endif -# ifdef OPENSSL_RAND_SEED_RDTSC +# if defined(OPENSSL_RAND_SEED_RDTSC) entropy_available = rand_acquire_entropy_from_tsc(pool); if (entropy_available > 0) return entropy_available; # endif -# ifdef OPENSSL_RAND_SEED_RDCPU +# if defined(OPENSSL_RAND_SEED_RDCPU) entropy_available = rand_acquire_entropy_from_cpu(pool); if (entropy_available > 0) return entropy_available; # endif -# ifdef OPENSSL_RAND_SEED_EGD +# if defined(OPENSSL_RAND_SEED_EGD) bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); if (bytes_needed > 0) { static const char *paths[] = { DEVRANDOM_EGD, NULL }; @@ -564,7 +619,7 @@ int rand_pool_add_nonce_data(RAND_POOL *pool) /* * Add process id, thread id, and a high resolution timestamp to - * ensure that the nonce is unique whith high probability for + * ensure that the nonce is unique with high probability for * different process instances. */ data.pid = getpid();