diff options
Diffstat (limited to 'freebsd/crypto/openssl/crypto/rand/rand_unix.c')
-rw-r--r-- | freebsd/crypto/openssl/crypto/rand/rand_unix.c | 187 |
1 files changed, 159 insertions, 28 deletions
diff --git a/freebsd/crypto/openssl/crypto/rand/rand_unix.c b/freebsd/crypto/openssl/crypto/rand/rand_unix.c index 7a93ceb4..d92cea7a 100644 --- a/freebsd/crypto/openssl/crypto/rand/rand_unix.c +++ b/freebsd/crypto/openssl/crypto/rand/rand_unix.c @@ -1,7 +1,7 @@ #include <machine/rtems-bsd-user-space.h> /* - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -16,14 +16,19 @@ #include <stdio.h> #include "internal/cryptlib.h" #include <openssl/rand.h> +#include <openssl/crypto.h> #include "rand_lcl.h" #include "internal/rand_int.h" #include <stdio.h> #include "internal/dso.h" -#if defined(__linux) +#ifdef __linux # include <sys/syscall.h> +# ifdef DEVRANDOM_WAIT +# include <sys/shm.h> +# include <sys/utsname.h> +# endif #endif -#if defined(__FreeBSD__) +#if defined(__FreeBSD__) && !defined(OPENSSL_SYS_UEFI) # include <sys/types.h> # include <sys/sysctl.h> # include <sys/param.h> @@ -95,6 +100,27 @@ static uint64_t get_timer_bits(void); # 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)) @@ -256,6 +282,17 @@ static ssize_t sysctl_random(char *buf, size_t buflen) # endif # if defined(OPENSSL_RAND_SEED_GETRANDOM) + +# if defined(__linux) && !defined(__NR_getrandom) +# if defined(__arm__) && defined(__NR_SYSCALL_BASE) +# define __NR_getrandom (__NR_SYSCALL_BASE+384) +# elif defined(__i386__) +# define __NR_getrandom 355 +# elif defined(__x86_64__) && !defined(__ILP32__) +# define __NR_getrandom 318 +# endif +# endif + /* * syscall_random(): Try to get random data using a system call * returns the number of bytes returned in buf, or < 0 on error. @@ -305,8 +342,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 @@ -327,6 +364,91 @@ static struct random_device { } random_devices[OSSL_NELEM(random_device_paths)]; static int keep_random_devices_open = 1; +# if defined(__linux) && defined(DEVRANDOM_WAIT) +static void *shm_addr; + +static void cleanup_shm(void) +{ + shmdt(shm_addr); +} + +/* + * Ensure that the system randomness source has been adequately seeded. + * This is done by having the first start of libcrypto, wait until the device + * /dev/random becomes able to supply a byte of entropy. Subsequent starts + * of the library and later reseedings do not need to do this. + */ +static int wait_random_seeded(void) +{ + static int seeded = OPENSSL_RAND_SEED_DEVRANDOM_SHM_ID < 0; + static const int kernel_version[] = { DEVRANDOM_SAFE_KERNEL }; + int kernel[2]; + int shm_id, fd, r; + char c, *p; + struct utsname un; + fd_set fds; + + if (!seeded) { + /* See if anything has created the global seeded indication */ + if ((shm_id = shmget(OPENSSL_RAND_SEED_DEVRANDOM_SHM_ID, 1, 0)) == -1) { + /* + * Check the kernel's version and fail if it is too recent. + * + * Linux kernels from 4.8 onwards do not guarantee that + * /dev/urandom is properly seeded when /dev/random becomes + * readable. However, such kernels support the getentropy(2) + * system call and this should always succeed which renders + * this alternative but essentially identical source moot. + */ + if (uname(&un) == 0) { + kernel[0] = atoi(un.release); + p = strchr(un.release, '.'); + kernel[1] = p == NULL ? 0 : atoi(p + 1); + if (kernel[0] > kernel_version[0] + || (kernel[0] == kernel_version[0] + && kernel[1] >= kernel_version[1])) { + return 0; + } + } + /* Open /dev/random and wait for it to be readable */ + if ((fd = open(DEVRANDOM_WAIT, O_RDONLY)) != -1) { + if (DEVRANDM_WAIT_USE_SELECT && fd < FD_SETSIZE) { + FD_ZERO(&fds); + FD_SET(fd, &fds); + while ((r = select(fd + 1, &fds, NULL, NULL, NULL)) < 0 + && errno == EINTR); + } else { + while ((r = read(fd, &c, 1)) < 0 && errno == EINTR); + } + close(fd); + if (r == 1) { + seeded = 1; + /* Create the shared memory indicator */ + shm_id = shmget(OPENSSL_RAND_SEED_DEVRANDOM_SHM_ID, 1, + IPC_CREAT | S_IRUSR | S_IRGRP | S_IROTH); + } + } + } + if (shm_id != -1) { + seeded = 1; + /* + * Map the shared memory to prevent its premature destruction. + * If this call fails, it isn't a big problem. + */ + shm_addr = shmat(shm_id, NULL, SHM_RDONLY); + if (shm_addr != (void *)-1) + OPENSSL_atexit(&cleanup_shm); + } + } + return seeded; +} +# else /* defined __linux */ +static int wait_random_seeded(void) +{ + return 1; +} +# endif + /* * Verify that the file descriptor associated with the random source is * still valid. The rationale for doing this is the fact that it is not @@ -453,12 +575,12 @@ size_t rand_pool_acquire_entropy(RAND_POOL *pool) # 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; + size_t entropy_available; # if defined(OPENSSL_RAND_SEED_GETRANDOM) { + size_t bytes_needed; + unsigned char *buffer; ssize_t bytes; /* Maximum allowed number of consecutive unsuccessful attempts */ int attempts = 3; @@ -488,13 +610,16 @@ size_t rand_pool_acquire_entropy(RAND_POOL *pool) # endif # if defined(OPENSSL_RAND_SEED_DEVRANDOM) - bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); - { + if (wait_random_seeded()) { + size_t bytes_needed; + unsigned char *buffer; size_t i; - for (i = 0; bytes_needed > 0 && i < OSSL_NELEM(random_device_paths); i++) { + bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); + for (i = 0; bytes_needed > 0 && i < OSSL_NELEM(random_device_paths); + i++) { ssize_t bytes = 0; - /* Maximum allowed number of consecutive unsuccessful attempts */ + /* Maximum number of consecutive unsuccessful attempts */ int attempts = 3; const int fd = get_random_device(i); @@ -508,7 +633,7 @@ size_t rand_pool_acquire_entropy(RAND_POOL *pool) if (bytes > 0) { rand_pool_add_end(pool, bytes, 8 * bytes); bytes_needed -= bytes; - attempts = 3; /* reset counter after successful attempt */ + attempts = 3; /* reset counter on successful attempt */ } else if (bytes < 0 && errno != EINTR) { break; } @@ -516,7 +641,7 @@ size_t rand_pool_acquire_entropy(RAND_POOL *pool) if (bytes < 0 || !keep_random_devices_open) close_random_device(i); - bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); + bytes_needed = rand_pool_bytes_needed(pool, 1); } entropy_available = rand_pool_entropy_available(pool); if (entropy_available > 0) @@ -537,26 +662,29 @@ size_t rand_pool_acquire_entropy(RAND_POOL *pool) # endif # 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 }; + size_t bytes_needed; + unsigned char *buffer; int i; - for (i = 0; paths[i] != NULL; i++) { + bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/); + for (i = 0; bytes_needed > 0 && paths[i] != NULL; i++) { + size_t bytes = 0; + int num; + buffer = rand_pool_add_begin(pool, bytes_needed); - if (buffer != NULL) { - size_t bytes = 0; - int num = RAND_query_egd_bytes(paths[i], - buffer, (int)bytes_needed); - if (num == (int)bytes_needed) - bytes = bytes_needed; + num = RAND_query_egd_bytes(paths[i], + buffer, (int)bytes_needed); + if (num == (int)bytes_needed) + bytes = bytes_needed; - rand_pool_add_end(pool, bytes, 8 * bytes); - entropy_available = rand_pool_entropy_available(pool); - } - if (entropy_available > 0) - return entropy_available; + rand_pool_add_end(pool, bytes, 8 * bytes); + bytes_needed = rand_pool_bytes_needed(pool, 1); } + entropy_available = rand_pool_entropy_available(pool); + if (entropy_available > 0) + return entropy_available; } # endif @@ -590,15 +718,18 @@ int rand_pool_add_nonce_data(RAND_POOL *pool) int rand_pool_add_additional_data(RAND_POOL *pool) { struct { + int fork_id; CRYPTO_THREAD_ID tid; uint64_t time; } data = { 0 }; /* * Add some noise from the thread id and a high resolution timer. + * The fork_id adds some extra fork-safety. * The thread id adds a little randomness if the drbg is accessed * concurrently (which is the case for the <master> drbg). */ + data.fork_id = openssl_get_fork_id(); data.tid = CRYPTO_THREAD_get_current_id(); data.time = get_timer_bits(); |