diff options
Diffstat (limited to 'crypto/rand/rand_unix.c')
-rw-r--r-- | crypto/rand/rand_unix.c | 179 |
1 files changed, 165 insertions, 14 deletions
diff --git a/crypto/rand/rand_unix.c b/crypto/rand/rand_unix.c index 0f9407f3ff..beb35a30a4 100644 --- a/crypto/rand/rand_unix.c +++ b/crypto/rand/rand_unix.c @@ -14,6 +14,50 @@ #include "rand_lcl.h" #include "internal/rand_int.h" #include <stdio.h> +#ifdef OPENSSL_SYS_UNIX +# include <sys/types.h> +# include <unistd.h> +# include <sys/time.h> + +static uint64_t get_time_stamp(void); +static uint64_t get_timer_bits(void); + +/* Macro to convert two thirty two bit values into a sixty four bit one */ +# define TWO32TO64(a, b) ((((uint64_t)(a)) << 32) + (b)) + +/* + * Check for the existence and support of POSIX timers. The standard + * says that the _POSIX_TIMERS macro will have a positive value if they + * are available. + * + * However, we want an additional constraint: that the timer support does + * not require an extra library dependency. Early versions of glibc + * require -lrt to be specified on the link line to access the timers, + * so this needs to be checked for. + * + * It is worse because some libraries define __GLIBC__ but don't + * support the version testing macro (e.g. uClibc). This means + * an extra check is needed. + * + * The final condition is: + * "have posix timers and either not glibc or glibc without -lrt" + * + * The nested #if sequences are required to avoid using a parameterised + * macro that might be undefined. + */ +# undef OSSL_POSIX_TIMER_OKAY +# if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 +# if defined(__GLIBC__) +# if defined(__GLIBC_PREREQ) +# if __GLIBC_PREREQ(2, 17) +# define OSSL_POSIX_TIMER_OKAY +# endif +# endif +# else +# define OSSL_POSIX_TIMER_OKAY +# endif +# endif +#endif #if (defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_UEFI)) && \ !defined(OPENSSL_RAND_SEED_NONE) @@ -54,9 +98,6 @@ size_t rand_pool_acquire_entropy(RAND_POOL *pool) { short int code; - gid_t curr_gid; - pid_t curr_pid; - uid_t curr_uid; int i, k; size_t bytes_needed; struct timespec ts; @@ -69,17 +110,6 @@ size_t rand_pool_acquire_entropy(RAND_POOL *pool) extern void s$sleep2(long long *_duration, short int *_code); # endif - /* - * Seed with the gid, pid, and uid, to ensure *some* variation between - * different processes. - */ - curr_gid = getgid(); - rand_pool_add(pool, &curr_gid, sizeof(curr_gid), 0); - curr_pid = getpid(); - rand_pool_add(pool, &curr_pid, sizeof(curr_pid), 0); - curr_uid = getuid(); - rand_pool_add(pool, &curr_uid, sizeof(curr_uid), 0); - bytes_needed = rand_pool_bytes_needed(pool, 2 /*entropy_per_byte*/); for (i = 0; i < bytes_needed; i++) { @@ -256,5 +286,126 @@ size_t rand_pool_acquire_entropy(RAND_POOL *pool) # endif } # endif +#endif + +#ifdef OPENSSL_SYS_UNIX +int rand_pool_add_nonce_data(RAND_POOL *pool) +{ + struct { + pid_t pid; + CRYPTO_THREAD_ID tid; + uint64_t time; + } data = { 0 }; + + /* + * Add process id, thread id, and a high resolution timestamp to + * ensure that the nonce is unique whith high probability for + * different process instances. + */ + data.pid = getpid(); + data.tid = CRYPTO_THREAD_get_current_id(); + data.time = get_time_stamp(); + + return rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0); +} + +int rand_pool_add_additional_data(RAND_POOL *pool) +{ + struct { + CRYPTO_THREAD_ID tid; + uint64_t time; + } data = { 0 }; + + /* + * Add some noise from the thread id and a high resolution timer. + * The thread id adds a little randomness if the drbg is accessed + * concurrently (which is the case for the <master> drbg). + */ + data.tid = CRYPTO_THREAD_get_current_id(); + data.time = get_timer_bits(); + + return rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0); +} + + + +/* + * Get the current time with the highest possible resolution + * + * The time stamp is added to the nonce, so it is optimized for not repeating. + * The current time is ideal for this purpose, provided the computer's clock + * is synchronized. + */ +static uint64_t get_time_stamp(void) +{ +# if defined(OSSL_POSIX_TIMER_OKAY) + { + struct timespec ts; + + if (clock_gettime(CLOCK_REALTIME, &ts) == 0) + return TWO32TO64(ts.tv_sec, ts.tv_nsec); + } +# endif +# if defined(__unix__) \ + || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) + { + struct timeval tv; + + if (gettimeofday(&tv, NULL) == 0) + return TWO32TO64(tv.tv_sec, tv.tv_usec); + } +# endif + return time(NULL); +} + +/* + * Get an arbitrary timer value of the highest possible resolution + * + * The timer value is added as random noise to the additional data, + * which is not considered a trusted entropy sourec, so any result + * is acceptable. + */ +static uint64_t get_timer_bits(void) +{ + uint64_t res = OPENSSL_rdtsc(); + + if (res != 0) + return res; + +# if defined(__sun) || defined(__hpux) + return gethrtime(); +# elif defined(_AIX) + { + timebasestruct_t t; + + read_wall_time(&t, TIMEBASE_SZ); + return TWO32TO64(t.tb_high, t.tb_low); + } +# elif defined(OSSL_POSIX_TIMER_OKAY) + { + struct timespec ts; + +# ifdef CLOCK_BOOTTIME +# define CLOCK_TYPE CLOCK_BOOTTIME +# elif defined(_POSIX_MONOTONIC_CLOCK) +# define CLOCK_TYPE CLOCK_MONOTONIC +# else +# define CLOCK_TYPE CLOCK_REALTIME +# endif + + if (clock_gettime(CLOCK_TYPE, &ts) == 0) + return TWO32TO64(ts.tv_sec, ts.tv_nsec); + } +# endif +# if defined(__unix__) \ + || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) + { + struct timeval tv; + if (gettimeofday(&tv, NULL) == 0) + return TWO32TO64(tv.tv_sec, tv.tv_usec); + } +# endif + return time(NULL); +} #endif |