|
- /*
- * Non-physical true random number generator based on timing jitter.
- *
- * Copyright Stephan Mueller <smueller@chronox.de>, 2014 - 2022
- *
- * Design
- * ======
- *
- * See documentation in doc/ folder.
- *
- * Interface
- * =========
- *
- * See documentation in jitterentropy(3) man page.
- *
- * License: see LICENSE file in root directory
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
- * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
- * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- */
-
- #include "jitterentropy.h"
-
- #include "jitterentropy-base.h"
- #include "jitterentropy-gcd.h"
- #include "jitterentropy-health.h"
- #include "jitterentropy-noise.h"
- #include "jitterentropy-timer.h"
- #include "jitterentropy-sha3.h"
-
- #define MAJVERSION 3 /* API / ABI incompatible changes, functional changes that
- * require consumer to be updated (as long as this number
- * is zero, the API is not considered stable and can
- * change without a bump of the major version) */
- #define MINVERSION 4 /* API compatible, ABI may change, functional
- * enhancements only, consumer can be left unchanged if
- * enhancements are not considered */
- #define PATCHLEVEL 1 /* API / ABI compatible, no functional changes, no
- * enhancements, bug fixes only */
-
- /***************************************************************************
- * Jitter RNG Static Definitions
- *
- * None of the following should be altered
- ***************************************************************************/
-
- #ifdef __OPTIMIZE__
- #error "The CPU Jitter random number generator must not be compiled with optimizations. See documentation. Use the compiler switch -O0 for compiling jitterentropy.c."
- #endif
-
- /*
- * JENT_POWERUP_TESTLOOPCOUNT needs some loops to identify edge
- * systems. 100 is definitely too little.
- *
- * SP800-90B requires at least 1024 initial test cycles.
- */
- #define JENT_POWERUP_TESTLOOPCOUNT 1024
-
- /**
- * jent_version() - Return machine-usable version number of jent library
- *
- * The function returns a version number that is monotonic increasing
- * for newer versions. The version numbers are multiples of 100. For example,
- * version 1.2.3 is converted to 1020300 -- the last two digits are reserved
- * for future use.
- *
- * The result of this function can be used in comparing the version number
- * in a calling program if version-specific calls need to be make.
- *
- * @return Version number of jitterentropy library
- */
- JENT_PRIVATE_STATIC
- unsigned int jent_version(void)
- {
- unsigned int version = 0;
-
- version = MAJVERSION * 1000000;
- version += MINVERSION * 10000;
- version += PATCHLEVEL * 100;
-
- return version;
- }
-
- /***************************************************************************
- * Helper
- ***************************************************************************/
-
- /* Calculate log2 of given value assuming that the value is a power of 2 */
- static inline unsigned int jent_log2_simple(unsigned int val)
- {
- unsigned int idx = 0;
-
- while (val >>= 1)
- idx++;
- return idx;
- }
-
- /* Increase the memory size by one step */
- static inline unsigned int jent_update_memsize(unsigned int flags)
- {
- unsigned int global_max = JENT_FLAGS_TO_MAX_MEMSIZE(
- JENT_MAX_MEMSIZE_MAX);
- unsigned int max;
-
- max = JENT_FLAGS_TO_MAX_MEMSIZE(flags);
-
- if (!max) {
- /*
- * The safe starting value is the amount of memory we allocated
- * last round.
- */
- max = jent_log2_simple(JENT_MEMORY_SIZE);
- /* Adjust offset */
- max = (max > JENT_MAX_MEMSIZE_OFFSET) ?
- max - JENT_MAX_MEMSIZE_OFFSET : 0;
- } else {
- max++;
- }
-
- max = (max > global_max) ? global_max : max;
-
- /* Clear out the max size */
- flags &= ~JENT_MAX_MEMSIZE_MASK;
- /* Set the freshly calculated max size */
- flags |= JENT_MAX_MEMSIZE_TO_FLAGS(max);
-
- return flags;
- }
-
- /***************************************************************************
- * Random Number Generation
- ***************************************************************************/
-
- /**
- * Entry function: Obtain entropy for the caller.
- *
- * This function invokes the entropy gathering logic as often to generate
- * as many bytes as requested by the caller. The entropy gathering logic
- * creates 64 bit per invocation.
- *
- * This function truncates the last 64 bit entropy value output to the exact
- * size specified by the caller.
- *
- * @ec [in] Reference to entropy collector
- * @data [out] pointer to buffer for storing random data -- buffer must
- * already exist
- * @len [in] size of the buffer, specifying also the requested number of random
- * in bytes
- *
- * @return number of bytes returned when request is fulfilled or an error
- *
- * The following error codes can occur:
- * -1 entropy_collector is NULL
- * -2 RCT failed
- * -3 APT test failed
- * -4 The timer cannot be initialized
- * -5 LAG failure
- */
- JENT_PRIVATE_STATIC
- ssize_t jent_read_entropy(struct rand_data *ec, char *data, size_t len)
- {
- char *p = data;
- size_t orig_len = len;
- int ret = 0;
-
- if (NULL == ec)
- return -1;
-
- if (jent_notime_settick(ec))
- return -4;
-
- while (len > 0) {
- size_t tocopy;
- unsigned int health_test_result;
-
- jent_random_data(ec);
-
- if ((health_test_result = jent_health_failure(ec))) {
- if (health_test_result & JENT_RCT_FAILURE)
- ret = -2;
- else if (health_test_result & JENT_APT_FAILURE)
- ret = -3;
- else
- ret = -5;
-
- goto err;
- }
-
- if ((DATA_SIZE_BITS / 8) < len)
- tocopy = (DATA_SIZE_BITS / 8);
- else
- tocopy = len;
-
- jent_read_random_block(ec, p, tocopy);
-
- len -= tocopy;
- p += tocopy;
- }
-
- /*
- * Enhanced backtracking support: At this point, the hash state
- * contains the digest of the previous Jitter RNG collection round
- * which is inserted there by jent_read_random_block with the SHA
- * update operation. At the current code location we completed
- * one request for a caller and we do not know how long it will
- * take until a new request is sent to us. To guarantee enhanced
- * backtracking resistance at this point (i.e. ensure that an attacker
- * cannot obtain information about prior random numbers we generated),
- * but still stirring the hash state with old data the Jitter RNG
- * obtains a new message digest from its state and re-inserts it.
- * After this operation, the Jitter RNG state is still stirred with
- * the old data, but an attacker who gets access to the memory after
- * this point cannot deduce the random numbers produced by the
- * Jitter RNG prior to this point.
- */
- /*
- * If we use secured memory, where backtracking support may not be
- * needed because the state is protected in a different method,
- * it is permissible to drop this support. But strongly weigh the
- * pros and cons considering that the SHA3 operation is not that
- * expensive.
- */
- #ifndef CONFIG_CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY
- jent_read_random_block(ec, NULL, 0);
- #endif
-
- err:
- jent_notime_unsettick(ec);
- return ret ? ret : (ssize_t)orig_len;
- }
-
- static struct rand_data *_jent_entropy_collector_alloc(unsigned int osr,
- unsigned int flags);
-
- /**
- * Entry function: Obtain entropy for the caller.
- *
- * This is a service function to jent_read_entropy() with the difference
- * that it automatically re-allocates the entropy collector if a health
- * test failure is observed. Before reallocation, a new power-on health test
- * is performed. The allocation of the new entropy collector automatically
- * increases the OSR by one. This is done based on the idea that a health
- * test failure indicates that the assumed entropy rate is too high.
- *
- * Note the function returns with an health test error if the OSR is
- * getting too large. If an error is returned by this function, the Jitter RNG
- * is not safe to be used on the current system.
- *
- * @ec [in] Reference to entropy collector - this is a double pointer as
- * The entropy collector may be freed and reallocated.
- * @data [out] pointer to buffer for storing random data -- buffer must
- * already exist
- * @len [in] size of the buffer, specifying also the requested number of random
- * in bytes
- *
- * @return see jent_read_entropy()
- */
- JENT_PRIVATE_STATIC
- ssize_t jent_read_entropy_safe(struct rand_data **ec, char *data, size_t len)
- {
- char *p = data;
- size_t orig_len = len;
- ssize_t ret = 0;
-
- if (!ec)
- return -1;
-
- while (len > 0) {
- unsigned int osr, flags, max_mem_set;
-
- ret = jent_read_entropy(*ec, p, len);
-
- switch (ret) {
- case -1:
- case -4:
- return ret;
- case -2:
- case -3:
- case -5:
- osr = (*ec)->osr + 1;
- flags = (*ec)->flags;
- max_mem_set = (*ec)->max_mem_set;
-
- /* generic arbitrary cutoff */
- if (osr > 20)
- return ret;
-
- /*
- * If the caller did not set any specific maximum value
- * let the Jitter RNG increase the maximum memory by
- * one step.
- */
- if (!max_mem_set)
- flags = jent_update_memsize(flags);
-
- /*
- * re-allocate entropy collector with higher OSR and
- * memory size
- */
- jent_entropy_collector_free(*ec);
-
- /* Perform new health test with updated OSR */
- if (jent_entropy_init_ex(osr, flags))
- return -1;
-
- *ec = _jent_entropy_collector_alloc(osr, flags);
- if (!*ec)
- return -1;
-
- /* Remember whether caller configured memory size */
- (*ec)->max_mem_set = !!max_mem_set;
-
- break;
-
- default:
- len -= (size_t)ret;
- p += (size_t)ret;
- }
- }
-
- return (ssize_t)orig_len;
- }
-
- /***************************************************************************
- * Initialization logic
- ***************************************************************************/
-
- /*
- * Obtain memory size to allocate for memory access variations.
- *
- * The maximum variations we can get from the memory access is when we allocate
- * a bit more memory than we have as data cache. But allocating as much
- * memory as we have as data cache might strain the resources on the system
- * more than necessary.
- *
- * On a lot of systems it is not necessary to need so much memory as the
- * variations coming from the general Jitter RNG execution commonly provide
- * large amount of variations.
- *
- * Thus, the default is:
- *
- * min(JENT_MEMORY_SIZE, data cache size)
- *
- * In case the data cache size cannot be obtained, use JENT_MEMORY_SIZE.
- *
- * If the caller provides a maximum memory size, use
- * min(provided max memory, data cache size).
- */
- static inline uint32_t jent_memsize(unsigned int flags)
- {
- uint32_t memsize, max_memsize;
-
- max_memsize = JENT_FLAGS_TO_MAX_MEMSIZE(flags);
-
- if (max_memsize == 0) {
- max_memsize = JENT_MEMORY_SIZE;
- } else {
- max_memsize = UINT32_C(1) << (max_memsize +
- JENT_MAX_MEMSIZE_OFFSET);
- }
-
- /* Allocate memory for adding variations based on memory access */
- memsize = jent_cache_size_roundup();
-
- /* Limit the memory as defined by caller */
- memsize = (memsize > max_memsize) ? max_memsize : memsize;
-
- /* Set a value if none was found */
- if (!memsize)
- memsize = JENT_MEMORY_SIZE;
-
- return memsize;
- }
-
- static int jent_selftest_run = 0;
-
- static struct rand_data
- *jent_entropy_collector_alloc_internal(unsigned int osr, unsigned int flags)
- {
- struct rand_data *entropy_collector;
- uint32_t memsize = 0;
-
- /*
- * Requesting disabling and forcing of internal timer
- * makes no sense.
- */
- if ((flags & JENT_DISABLE_INTERNAL_TIMER) &&
- (flags & JENT_FORCE_INTERNAL_TIMER))
- return NULL;
-
- /* Force the self test to be run */
- if (!jent_selftest_run && jent_entropy_init_ex(osr, flags))
- return NULL;
-
- /*
- * If the initial test code concludes to force the internal timer
- * and the user requests it not to be used, do not allocate
- * the Jitter RNG instance.
- */
- if (jent_notime_forced() && (flags & JENT_DISABLE_INTERNAL_TIMER))
- return NULL;
-
- entropy_collector = jent_zalloc(sizeof(struct rand_data));
- if (NULL == entropy_collector)
- return NULL;
-
- if (!(flags & JENT_DISABLE_MEMORY_ACCESS)) {
- memsize = jent_memsize(flags);
- entropy_collector->mem = (unsigned char *)jent_zalloc(memsize);
-
- #ifdef JENT_RANDOM_MEMACCESS
- /*
- * Transform the size into a mask - it is assumed that size is
- * a power of 2.
- */
- entropy_collector->memmask = memsize - 1;
- #else /* JENT_RANDOM_MEMACCESS */
- entropy_collector->memblocksize = memsize / JENT_MEMORY_BLOCKS;
- entropy_collector->memblocks = JENT_MEMORY_BLOCKS;
-
- /* sanity check */
- if (entropy_collector->memblocksize *
- entropy_collector->memblocks != memsize)
- goto err;
-
- #endif /* JENT_RANDOM_MEMACCESS */
-
- if (entropy_collector->mem == NULL)
- goto err;
- entropy_collector->memaccessloops = JENT_MEMORY_ACCESSLOOPS;
- }
-
- if (sha3_alloc(&entropy_collector->hash_state))
- goto err;
-
- /* Initialize the hash state */
- sha3_256_init(entropy_collector->hash_state);
-
- /* verify and set the oversampling rate */
- if (osr < JENT_MIN_OSR)
- osr = JENT_MIN_OSR;
- entropy_collector->osr = osr;
- entropy_collector->flags = flags;
-
- if ((flags & JENT_FORCE_FIPS) || jent_fips_enabled())
- entropy_collector->fips_enabled = 1;
-
- /* Initialize the APT */
- jent_apt_init(entropy_collector, osr);
-
- /* Initialize the Lag Predictor Test */
- jent_lag_init(entropy_collector, osr);
-
- /* Was jent_entropy_init run (establishing the common GCD)? */
- if (jent_gcd_get(&entropy_collector->jent_common_timer_gcd)) {
- /*
- * It was not. This should probably be an error, but this
- * behavior breaks the test code. Set the gcd to a value that
- * won't hurt anything.
- */
- entropy_collector->jent_common_timer_gcd = 1;
- }
-
- /*
- * Use timer-less noise source - note, OSR must be set in
- * entropy_collector!
- */
- if (!(flags & JENT_DISABLE_INTERNAL_TIMER)) {
- if (jent_notime_enable(entropy_collector, flags))
- goto err;
- }
-
- return entropy_collector;
-
- err:
- if (entropy_collector->mem != NULL)
- jent_zfree(entropy_collector->mem, memsize);
- jent_zfree(entropy_collector, sizeof(struct rand_data));
- return NULL;
- }
-
- static struct rand_data *_jent_entropy_collector_alloc(unsigned int osr,
- unsigned int flags)
- {
- struct rand_data *ec = jent_entropy_collector_alloc_internal(osr,
- flags);
-
- if (!ec)
- return ec;
-
- /* fill the data pad with non-zero values */
- if (jent_notime_settick(ec)) {
- jent_entropy_collector_free(ec);
- return NULL;
- }
- jent_random_data(ec);
- jent_notime_unsettick(ec);
-
- return ec;
- }
-
- JENT_PRIVATE_STATIC
- struct rand_data *jent_entropy_collector_alloc(unsigned int osr,
- unsigned int flags)
- {
- struct rand_data *ec = _jent_entropy_collector_alloc(osr, flags);
-
- /* Remember that the caller provided a maximum size flag */
- if (ec)
- ec->max_mem_set = !!JENT_FLAGS_TO_MAX_MEMSIZE(flags);
-
- return ec;
- }
-
- JENT_PRIVATE_STATIC
- void jent_entropy_collector_free(struct rand_data *entropy_collector)
- {
- if (entropy_collector != NULL) {
- sha3_dealloc(entropy_collector->hash_state);
- jent_notime_disable(entropy_collector);
- if (entropy_collector->mem != NULL) {
- jent_zfree(entropy_collector->mem,
- jent_memsize(entropy_collector->flags));
- entropy_collector->mem = NULL;
- }
- jent_zfree(entropy_collector, sizeof(struct rand_data));
- }
- }
-
- int jent_time_entropy_init(unsigned int osr, unsigned int flags)
- {
- struct rand_data *ec;
- uint64_t *delta_history;
- int i, time_backwards = 0, count_stuck = 0, ret = 0;
- unsigned int health_test_result;
-
- delta_history = jent_gcd_init(JENT_POWERUP_TESTLOOPCOUNT);
- if (!delta_history)
- return EMEM;
-
- if (flags & JENT_FORCE_INTERNAL_TIMER)
- jent_notime_force();
- else
- flags |= JENT_DISABLE_INTERNAL_TIMER;
-
- /*
- * If the start-up health tests (including the APT and RCT) are not
- * run, then the entropy source is not 90B compliant. We could test if
- * fips_enabled should be set using the jent_fips_enabled() function,
- * but this can be overridden using the JENT_FORCE_FIPS flag, which
- * isn't passed in yet. It is better to run the tests on the small
- * amount of data that we have, which should not fail unless things
- * are really bad.
- */
- flags |= JENT_FORCE_FIPS;
- ec = jent_entropy_collector_alloc_internal(osr, flags);
- if (!ec) {
- ret = EMEM;
- goto out;
- }
-
- if (jent_notime_settick(ec)) {
- ret = EMEM;
- goto out;
- }
-
- /* To initialize the prior time. */
- jent_measure_jitter(ec, 0, NULL);
-
- /* We could perform statistical tests here, but the problem is
- * that we only have a few loop counts to do testing. These
- * loop counts may show some slight skew leading to false positives.
- */
-
- /*
- * We could add a check for system capabilities such as clock_getres or
- * check for CONFIG_X86_TSC, but it does not make much sense as the
- * following sanity checks verify that we have a high-resolution
- * timer.
- */
- #define CLEARCACHE 100
- for (i = -CLEARCACHE; i < JENT_POWERUP_TESTLOOPCOUNT; i++) {
- uint64_t start_time = 0, end_time = 0, delta = 0;
- unsigned int stuck;
-
- /* Invoke core entropy collection logic */
- stuck = jent_measure_jitter(ec, 0, &delta);
- end_time = ec->prev_time;
- start_time = ec->prev_time - delta;
-
- /* test whether timer works */
- if (!start_time || !end_time) {
- ret = ENOTIME;
- goto out;
- }
-
- /*
- * test whether timer is fine grained enough to provide
- * delta even when called shortly after each other -- this
- * implies that we also have a high resolution timer
- */
- if (!delta || (end_time == start_time)) {
- ret = ECOARSETIME;
- goto out;
- }
-
- /*
- * up to here we did not modify any variable that will be
- * evaluated later, but we already performed some work. Thus we
- * already have had an impact on the caches, branch prediction,
- * etc. with the goal to clear it to get the worst case
- * measurements.
- */
- if (i < 0)
- continue;
-
- if (stuck)
- count_stuck++;
-
- /* test whether we have an increasing timer */
- if (!(end_time > start_time))
- time_backwards++;
-
- /* Watch for common adjacent GCD values */
- jent_gcd_add_value(delta_history, delta, i);
- }
-
- /*
- * we allow up to three times the time running backwards.
- * CLOCK_REALTIME is affected by adjtime and NTP operations. Thus,
- * if such an operation just happens to interfere with our test, it
- * should not fail. The value of 3 should cover the NTP case being
- * performed during our test run.
- */
- if (time_backwards > 3) {
- ret = ENOMONOTONIC;
- goto out;
- }
-
- /* First, did we encounter a health test failure? */
- if ((health_test_result = jent_health_failure(ec))) {
- ret = (health_test_result & JENT_RCT_FAILURE) ? ERCT : EHEALTH;
- goto out;
- }
-
- ret = jent_gcd_analyze(delta_history, JENT_POWERUP_TESTLOOPCOUNT);
- if (ret)
- goto out;
-
- /*
- * If we have more than 90% stuck results, then this Jitter RNG is
- * likely to not work well.
- */
- if (JENT_STUCK_INIT_THRES(JENT_POWERUP_TESTLOOPCOUNT) < count_stuck)
- ret = ESTUCK;
-
- out:
- jent_gcd_fini(delta_history, JENT_POWERUP_TESTLOOPCOUNT);
-
- if ((flags & JENT_FORCE_INTERNAL_TIMER) && ec)
- jent_notime_unsettick(ec);
-
- jent_entropy_collector_free(ec);
-
- return ret;
- }
-
- static inline int jent_entropy_init_common_pre(void)
- {
- int ret;
-
- jent_notime_block_switch();
- jent_health_cb_block_switch();
-
- if (sha3_tester())
- return EHASH;
-
- ret = jent_gcd_selftest();
-
- jent_selftest_run = 1;
-
- return ret;
- }
-
- static inline int jent_entropy_init_common_post(int ret)
- {
- /* Unmark the execution of the self tests if they failed. */
- if (ret)
- jent_selftest_run = 0;
-
- return ret;
- }
-
- JENT_PRIVATE_STATIC
- int jent_entropy_init(void)
- {
- int ret = jent_entropy_init_common_pre();
-
- if (ret)
- return ret;
-
- ret = jent_time_entropy_init(0, JENT_DISABLE_INTERNAL_TIMER);
-
- #ifdef JENT_CONF_ENABLE_INTERNAL_TIMER
- if (ret)
- ret = jent_time_entropy_init(0, JENT_FORCE_INTERNAL_TIMER);
- #endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */
-
- return jent_entropy_init_common_post(ret);
- }
-
- JENT_PRIVATE_STATIC
- int jent_entropy_init_ex(unsigned int osr, unsigned int flags)
- {
- int ret = jent_entropy_init_common_pre();
-
- if (ret)
- return ret;
-
- ret = ENOTIME;
-
- /* Test without internal timer unless caller does not want it */
- if (!(flags & JENT_FORCE_INTERNAL_TIMER))
- ret = jent_time_entropy_init(osr,
- flags | JENT_DISABLE_INTERNAL_TIMER);
-
- #ifdef JENT_CONF_ENABLE_INTERNAL_TIMER
- /* Test with internal timer unless caller does not want it */
- if (ret && !(flags & JENT_DISABLE_INTERNAL_TIMER))
- ret = jent_time_entropy_init(osr,
- flags | JENT_FORCE_INTERNAL_TIMER);
- #endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */
-
- return jent_entropy_init_common_post(ret);
- }
-
- JENT_PRIVATE_STATIC
- int jent_entropy_switch_notime_impl(struct jent_notime_thread *new_thread)
- {
- return jent_notime_switch(new_thread);
- }
-
- JENT_PRIVATE_STATIC
- int jent_set_fips_failure_callback(jent_fips_failure_cb cb)
- {
- return jent_set_fips_failure_callback_internal(cb);
- }
|