#endif
#include "e_os.h"
+/* 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
+
#ifndef OPENSSL_NO_ENGINE
/* non-NULL if default_RAND_meth is ENGINE-provided */
static ENGINE *funct_ref;
/*
* Get random from parent, include our state as additional input.
* Our lock is already held, but we need to lock our parent before
- * generating bits from it.
+ * generating bits from it. (Note: taking the lock will be a no-op
+ * if locking if drbg->parent->lock == NULL.)
*/
- if (drbg->parent->lock)
- CRYPTO_THREAD_write_lock(drbg->parent->lock);
+ rand_drbg_lock(drbg->parent);
if (RAND_DRBG_generate(drbg->parent,
buffer, bytes_needed,
0,
(unsigned char *)drbg, sizeof(*drbg)) != 0)
bytes = bytes_needed;
- if (drbg->parent->lock)
- CRYPTO_THREAD_unlock(drbg->parent->lock);
+ rand_drbg_unlock(drbg->parent);
entropy_available = RAND_POOL_add_end(pool, bytes, 8 * bytes);
}
return ret;
}
+/*
+ * Find a suitable system time. Start with the highest resolution source
+ * and work down to the slower ones. This is added as additional data and
+ * isn't counted as randomness, so any result is acceptable.
+ */
+static uint64_t get_timer_bits(void)
+{
+ uint64_t res = OPENSSL_rdtsc();
+
+ if (res != 0)
+ return res;
+#if defined(_WIN32)
+ {
+ LARGE_INTEGER t;
+ FILETIME ft;
+
+ if (QueryPerformanceCounter(&t) != 0)
+ return t.QuadPart;
+ GetSystemTimeAsFileTime(&ft);
+ return TWO32TO64(ft.dwHighDateTime, ft.dwLowDateTime);
+ }
+#elif 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);
+ }
+#else
+
+#if defined(OSSL_POSIX_TIMER_OKAY)
+ {
+ struct timespec ts;
+ clockid_t cid;
+
+# ifdef CLOCK_BOOTTIME
+ cid = CLOCK_BOOTTIME;
+# elif defined(_POSIX_MONOTONIC_CLOCK)
+ cid = CLOCK_MONOTONIC;
+# else
+ cid = CLOCK_REALTIME;
+# endif
+
+ if (clock_gettime(cid, &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
+}
+
/*
* Generate additional data that can be used for the drbg. The data does
* not need to contain entropy, but it's useful if it contains at least
size_t len;
#ifdef OPENSSL_SYS_UNIX
pid_t pid;
- struct timeval tv;
#elif defined(OPENSSL_SYS_WIN32)
DWORD pid;
- FILETIME ft;
- LARGE_INTEGER pc;
-#endif
-#ifdef OPENSSL_CPUID_OBJ
- uint32_t tsc = 0;
#endif
+ uint64_t tbits;
pool = RAND_POOL_new(0, 0, max_len);
if (pool == NULL)
if (thread_id != 0)
RAND_POOL_add(pool, (unsigned char *)&thread_id, sizeof(thread_id), 0);
-#ifdef OPENSSL_CPUID_OBJ
- tsc = OPENSSL_rdtsc();
- if (tsc != 0)
- RAND_POOL_add(pool, (unsigned char *)&tsc, sizeof(tsc), 0);
-#endif
-
-#ifdef OPENSSL_SYS_UNIX
- if (gettimeofday(&tv, NULL) == 0)
- RAND_POOL_add(pool, (unsigned char *)&tv, sizeof(tv), 0);
-#elif defined(OPENSSL_SYS_WIN32)
- if (QueryPerformanceCounter(&pc) != 0)
- RAND_POOL_add(pool, (unsigned char *)&pc, sizeof(pc), 0);
- GetSystemTimeAsFileTime(&ft);
- RAND_POOL_add(pool, (unsigned char *)&ft, sizeof(ft), 0);
-#endif
+ tbits = get_timer_bits();
+ RAND_POOL_add(pool, (unsigned char *)&tbits, sizeof(tbits), 0);
/* TODO: Use RDSEED? */
if (drbg == NULL)
return 0;
- CRYPTO_THREAD_write_lock(drbg->lock);
+ rand_drbg_lock(drbg);
ret = rand_drbg_restart(drbg, NULL, 0, 0);
- CRYPTO_THREAD_unlock(drbg->lock);
+ rand_drbg_unlock(drbg);
return ret;
return 0;
/* We have to lock the DRBG before generating bits from it. */
- CRYPTO_THREAD_write_lock(drbg->lock);
+ rand_drbg_lock(drbg);
ret = RAND_DRBG_bytes(drbg, buf, num);
- CRYPTO_THREAD_unlock(drbg->lock);
+ rand_drbg_unlock(drbg);
return ret;
}