blob: 7161543d221cb7988c95cc13023ecadd2dd20c5d [file] [log] [blame]
diff --git a/crypto/Makefile b/crypto/Makefile
index 4e7a0a8f7..2b5a2a9c8 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -156,6 +156,7 @@ CFLAGS_jitterentropy.o = -O0
KASAN_SANITIZE_jitterentropy.o = n
UBSAN_SANITIZE_jitterentropy.o = n
jitterentropy_rng-y := jitterentropy.o jitterentropy-kcapi.o
+jitterentropy_rng-$(CONFIG_CRYPTO_CPU_JITTERENTROPY_DEBUG) += jitterentropy-dbg.o
obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
obj-$(CONFIG_CRYPTO_GHASH) += ghash-generic.o
obj-$(CONFIG_CRYPTO_USER_API) += af_alg.o
diff --git a/crypto/jitterentropy-dbg.c b/crypto/jitterentropy-dbg.c
new file mode 100644
index 000000000..2e7e98b9a
--- /dev/null
+++ b/crypto/jitterentropy-dbg.c
@@ -0,0 +1,242 @@
+/*
+ * Non-physical true random number generator based on timing jitter - DebugFS
+ *
+ * Copyright Stephan Mueller <smueller@chronox.de>, 2013
+ *
+ * License
+ * =======
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU General Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * 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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+#include <linux/string.h>
+#include <linux/compat.h>
+#include <linux/export.h>
+#include <linux/file.h>
+#include <linux/debugfs.h>
+
+#include "jitterentropy.h"
+#include "jitterentropy-dbg.h"
+
+struct jent_debugfs {
+ struct dentry *jent_debugfs_root;
+ struct dentry *jent_debugfs_entropy;
+ struct dentry *jent_debugfs_noise;
+};
+
+struct jent_raw
+{
+ spinlock_t raw_lock;
+ struct rand_data *entropy_collector;
+};
+
+static struct jent_debugfs jent_debugfs;
+static struct jent_raw raw_entropy;
+
+void jent_drng_cleanup_raw(struct jent_raw *raw)
+{
+ spin_lock_bh(&raw->raw_lock);
+ if (NULL != raw->entropy_collector)
+ jent_entropy_collector_free(raw->entropy_collector);
+ raw->entropy_collector = NULL;
+ spin_unlock_bh(&raw->raw_lock);
+}
+
+int jent_drng_get_bytes_raw(struct jent_raw *raw, char *data, size_t len)
+{
+ int ret = 0;
+
+ spin_lock_bh(&raw->raw_lock);
+ ret = jent_read_entropy(raw->entropy_collector, data, len);
+ if (0 > ret) {
+ printk(DRIVER_NAME": Unable to obtain %zu bytes of entropy\n", len);
+ ret = -EAGAIN;
+ }
+
+ spin_unlock_bh(&raw->raw_lock);
+ return ret;
+}
+
+
+static inline int jent_dbg_raw_bytes(char *data, size_t len)
+{
+ return jent_drng_get_bytes_raw(&raw_entropy, data, len);
+}
+
+static ssize_t jent_debugfs_read_func(struct file *file,
+ char __user *buf, size_t nbytes,
+ loff_t *ppos, size_t chunk,
+ int (*source)(char *out, size_t len))
+{
+ ssize_t total = 0;
+ int ret = 0;
+ loff_t pos = *ppos;
+ char *out;
+
+ if (!nbytes)
+ return -EINVAL;
+
+ out = kzalloc(chunk, GFP_KERNEL);
+ if (!out)
+ return -ENOMEM;
+
+ while (nbytes > 0) {
+ int copy = min_t(int, chunk, nbytes);
+ ret = source(out, copy);
+ if (0 > ret) {
+ printk(DRIVER_NAME": could not obtain random data: %d\n", ret);
+ ret = -EAGAIN;
+ break;
+ }
+ if (copy_to_user(buf+pos+total, out, copy)) {
+ ret = -EFAULT;
+ break;
+ }
+ nbytes -= copy;
+ total += copy;
+ }
+ kzfree(out);
+
+ return ((0 > ret) ? ret : total);
+}
+
+static ssize_t jent_debugfs_noise_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct rand_data *ec = raw_entropy.entropy_collector;
+ int total = 0;
+ loff_t pos = *ppos;
+ char *out;
+
+ out = kzalloc(8, GFP_KERNEL);
+
+ while (nbytes > 0) {
+ int len = min_t(int, 8, nbytes);
+ jent_lfsr_time(ec, 0, 0, 0);
+ memcpy(out, &ec->data, len);
+ if (copy_to_user(buf+pos+total, out, len)) {
+ break;
+ }
+ nbytes -= len;
+ total += len;
+ }
+ kzfree(out);
+ return total;
+
+}
+static ssize_t jent_debugfs_seed_read(struct file *file, char __user *buf,
+ size_t nbytes, loff_t *ppos)
+{
+ int ret = jent_debugfs_read_func(file, buf, nbytes, ppos, 8,
+ jent_dbg_raw_bytes);
+ return ret;
+}
+
+int jent_drng_init_raw(struct jent_raw *raw, unsigned int flags)
+{
+ int ret = 0;
+
+ raw->entropy_collector = jent_entropy_collector_alloc(1, flags);
+ if (!raw->entropy_collector)
+ ret = -ENOMEM;
+
+ spin_lock_init(&raw->raw_lock);
+ return ret;
+}
+
+static struct file_operations jent_seed_fops = {
+ .owner = THIS_MODULE,
+ .read = jent_debugfs_seed_read,
+};
+
+static struct file_operations jent_noise_fops = {
+ .owner = THIS_MODULE,
+ .read = jent_debugfs_noise_read,
+};
+
+
+int __init jent_dbg_init(void)
+{
+ int ret = -EINVAL;
+ jent_debugfs.jent_debugfs_root = NULL;
+ jent_debugfs.jent_debugfs_noise = NULL;
+ jent_debugfs.jent_debugfs_entropy = NULL;
+
+ ret = jent_drng_init_raw(&raw_entropy, JENT_DISABLE_STIR);
+ if (ret) {
+ printk(DRIVER_NAME": Raw entropy collector instantiation failed\n");
+ return ret;
+ }
+ jent_debugfs.jent_debugfs_root =
+ debugfs_create_dir(DRIVER_NAME, NULL);
+ if (IS_ERR(jent_debugfs.jent_debugfs_root)) {
+ printk(DRIVER_NAME": initialization of debugfs directory failed\n");
+ goto cleandir;
+ }
+
+ jent_debugfs.jent_debugfs_entropy =
+ debugfs_create_file("entropy", S_IRUGO,
+ jent_debugfs.jent_debugfs_root,
+ NULL, &jent_seed_fops);
+ if (IS_ERR(jent_debugfs.jent_debugfs_entropy)) {
+ printk(DRIVER_NAME": initialization of entropy file failed\n");
+ goto cleandir;
+ }
+
+ jent_debugfs.jent_debugfs_noise =
+ debugfs_create_file("noise", S_IRUGO,
+ jent_debugfs.jent_debugfs_root,
+ NULL, &jent_noise_fops);
+ if (IS_ERR(jent_debugfs.jent_debugfs_noise)) {
+ printk(DRIVER_NAME": initialization of noise file failed\n");
+ goto cleandir;
+ }
+ return 0;
+
+cleandir:
+ debugfs_remove_recursive(jent_debugfs.jent_debugfs_root);
+ jent_drng_cleanup_raw(&raw_entropy);
+
+ return ret;
+}
+
+void jent_dbg_exit(void)
+{
+ debugfs_remove_recursive(jent_debugfs.jent_debugfs_root);
+ jent_drng_cleanup_raw(&raw_entropy);
+}
diff --git a/crypto/jitterentropy-dbg.h b/crypto/jitterentropy-dbg.h
new file mode 100644
index 000000000..921bd65dc
--- /dev/null
+++ b/crypto/jitterentropy-dbg.h
@@ -0,0 +1,49 @@
+/*
+ * Non-physical true random number generator based on timing jitter.
+ *
+ * Copyright Stephan Mueller <smueller@chronox.de>, 2013
+ *
+ * License
+ * =======
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU General Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions. (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * 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.
+ */
+
+#ifndef _JITTERENTROPY_DBG_KERNEL_H
+#define _JITTERENTROPY_DBG_KERNEL_H
+
+int __init jent_dbg_init(void);
+void jent_dbg_exit(void);
+
+
+#endif /* _JITTERENTROPY_DBG_KERNEL_H */
diff --git a/crypto/jitterentropy-kcapi.c b/crypto/jitterentropy-kcapi.c
index 701b8d86a..7a3691fab 100644
--- a/crypto/jitterentropy-kcapi.c
+++ b/crypto/jitterentropy-kcapi.c
@@ -44,13 +44,11 @@
#include <linux/crypto.h>
#include <crypto/internal/rng.h>
-struct rand_data;
-int jent_read_entropy(struct rand_data *ec, unsigned char *data,
- unsigned int len);
-int jent_entropy_init(void);
-struct rand_data *jent_entropy_collector_alloc(unsigned int osr,
- unsigned int flags);
-void jent_entropy_collector_free(struct rand_data *entropy_collector);
+#include "jitterentropy.h"
+
+#ifdef CONFIG_CRYPTO_CPU_JITTERENTROPY_DEBUG
+#include "jitterentropy-dbg.h"
+#endif
/***************************************************************************
* Helper function
@@ -148,7 +146,31 @@ static int jent_kcapi_random(struct crypto_rng *tfm,
int ret = 0;
spin_lock(&rng->jent_lock);
+
ret = jent_read_entropy(rng->entropy_collector, rdata, dlen);
+
+ if (ret == -3) {
+ /* Handle permanent health test error */
+ /*
+ * If the kernel was booted with fips=1, it implies that
+ * the entire kernel acts as a FIPS 140 module. In this case
+ * an SP800-90B permanent health test error is treated as
+ * a FIPS module error.
+ */
+ if (fips_enabled)
+ panic("Jitter RNG permanent health test failure\n");
+
+ pr_err("Jitter RNG permanent health test failure\n");
+ ret = -EFAULT;
+ } else if (ret == -2) {
+ /* Handle intermittent health test error */
+ pr_warn_ratelimited("Reset Jitter RNG due to intermittent health test failure\n");
+ ret = -EAGAIN;
+ } else if (ret == -1) {
+ /* Handle other errors */
+ ret = -EINVAL;
+ }
+
spin_unlock(&rng->jent_lock);
return ret;
@@ -182,15 +204,31 @@ static int __init jent_mod_init(void)
ret = jent_entropy_init();
if (ret) {
+ /* Handle permanent health test error */
+ if (fips_enabled)
+ panic("jitterentropy: Initialization failed with host not compliant with requirements: %d\n", ret);
+
pr_info("jitterentropy: Initialization failed with host not compliant with requirements: %d\n", ret);
return -EFAULT;
}
+
+#ifdef CONFIG_CRYPTO_CPU_JITTERENTROPY_DEBUG
+ ret = jent_dbg_init();
+#endif
+ if(ret)
+ return ret;
+ printk("Debug interface error\n");
return crypto_register_rng(&jent_alg);
+
}
static void __exit jent_mod_exit(void)
{
crypto_unregister_rng(&jent_alg);
+
+#ifdef CONFIG_CRYPTO_CPU_JITTERENTROPY_DEBUG
+ jent_dbg_exit();
+#endif
}
module_init(jent_mod_init);
diff --git a/crypto/jitterentropy.c b/crypto/jitterentropy.c
index 77fa2120f..fea7a6d42 100644
--- a/crypto/jitterentropy.c
+++ b/crypto/jitterentropy.c
@@ -2,12 +2,12 @@
* Non-physical true random number generator based on timing jitter --
* Jitter RNG standalone code.
*
- * Copyright Stephan Mueller <smueller@chronox.de>, 2015 - 2019
+ * Copyright Stephan Mueller <smueller@chronox.de>, 2015 - 2020
*
* Design
* ======
*
- * See http://www.chronox.de/jent.html
+ * See https://www.chronox.de/jent.html
*
* License
* =======
@@ -47,7 +47,7 @@
/*
* This Jitterentropy RNG is based on the jitterentropy library
- * version 2.1.2 provided at http://www.chronox.de/jent.html
+ * version 2.2.0 provided at https://www.chronox.de/jent.html
*/
#ifdef __OPTIMIZE__
@@ -58,32 +58,8 @@ typedef unsigned long long __u64;
typedef long long __s64;
typedef unsigned int __u32;
#define NULL ((void *) 0)
+#include "jitterentropy.h"
-/* The entropy pool */
-struct rand_data {
- /* all data values that are vital to maintain the security
- * of the RNG are marked as SENSITIVE. A user must not
- * access that information while the RNG executes its loops to
- * calculate the next random value. */
- __u64 data; /* SENSITIVE Actual random number */
- __u64 old_data; /* SENSITIVE Previous random number */
- __u64 prev_time; /* SENSITIVE Previous time stamp */
-#define DATA_SIZE_BITS ((sizeof(__u64)) * 8)
- __u64 last_delta; /* SENSITIVE stuck test */
- __s64 last_delta2; /* SENSITIVE stuck test */
- unsigned int osr; /* Oversample rate */
-#define JENT_MEMORY_BLOCKS 64
-#define JENT_MEMORY_BLOCKSIZE 32
-#define JENT_MEMORY_ACCESSLOOPS 128
-#define JENT_MEMORY_SIZE (JENT_MEMORY_BLOCKS*JENT_MEMORY_BLOCKSIZE)
- unsigned char *mem; /* Memory access location with size of
- * memblocks * memblocksize */
- unsigned int memlocation; /* Pointer to byte in *mem */
- unsigned int memblocks; /* Number of memory blocks in *mem */
- unsigned int memblocksize; /* Size of one memory block in bytes */
- unsigned int memaccessloops; /* Number of memory accesses per random
- * bit generation */
-};
/* Flags that can be used to initialize the RNG */
#define JENT_DISABLE_MEMORY_ACCESS (1<<2) /* Disable memory access for more
@@ -98,19 +74,187 @@ struct rand_data {
* variations (2nd derivation of time is
* zero). */
#define JENT_ESTUCK 8 /* Too many stuck results during init. */
+#define JENT_EHEALTH 9 /* Health test failed during initialization */
+
+/*
+ * The output n bits can receive more than n bits of min entropy, of course,
+ * but the fixed output of the conditioning function can only asymptotically
+ * approach the output size bits of min entropy, not attain that bound. Random
+ * maps will tend to have output collisions, which reduces the creditable
+ * output entropy (that is what SP 800-90B Section 3.1.5.1.2 attempts to bound).
+ *
+ * The value "64" is justified in Appendix A.4 of the current 90C draft,
+ * and aligns with NIST's in "epsilon" definition in this document, which is
+ * that a string can be considered "full entropy" if you can bound the min
+ * entropy in each bit of output to at least 1-epsilon, where epsilon is
+ * required to be <= 2^(-32).
+ */
+#define JENT_ENTROPY_SAFETY_FACTOR 64
+
+#include <linux/fips.h>
+#include <linux/printk.h>
+
+/***************************************************************************
+ * Adaptive Proportion Test
+ *
+ * This test complies with SP800-90B section 4.4.2.
+ ***************************************************************************/
+
+/*
+ * Reset the APT counter
+ *
+ * @ec [in] Reference to entropy collector
+ */
+static void jent_apt_reset(struct rand_data *ec, unsigned int delta_masked)
+{
+ /* Reset APT counter */
+ ec->apt_count = 0;
+ ec->apt_base = delta_masked;
+ ec->apt_observations = 0;
+}
+
+/*
+ * Insert a new entropy event into APT
+ *
+ * @ec [in] Reference to entropy collector
+ * @delta_masked [in] Masked time delta to process
+ */
+static void jent_apt_insert(struct rand_data *ec, unsigned int delta_masked)
+{
+ /* Initialize the base reference */
+ if (!ec->apt_base_set) {
+ ec->apt_base = delta_masked;
+ ec->apt_base_set = 1;
+ return;
+ }
+
+ if (delta_masked == ec->apt_base)
+ ec->apt_count++;
+
+ ec->apt_observations++;
+
+ if (ec->apt_observations >= JENT_APT_WINDOW_SIZE)
+ jent_apt_reset(ec, delta_masked);
+}
+
+/* APT health test failure detection */
+static int jent_apt_permanent_failure(struct rand_data *ec)
+{
+ return (ec->apt_count >= JENT_APT_CUTOFF_PERMANENT) ? 1 : 0;
+}
+
+static int jent_apt_failure(struct rand_data *ec)
+{
+ return (ec->apt_count >= JENT_APT_CUTOFF) ? 1 : 0;
+}
/***************************************************************************
- * Helper functions
+ * Stuck Test and its use as Repetition Count Test
+ *
+ * The Jitter RNG uses an enhanced version of the Repetition Count Test
+ * (RCT) specified in SP800-90B section 4.4.1. Instead of counting identical
+ * back-to-back values, the input to the RCT is the counting of the stuck
+ * values during the generation of one Jitter RNG output block.
+ *
+ * The RCT is applied with an alpha of 2^{-30} compliant to FIPS 140-2 IG 9.8.
+ *
+ * During the counting operation, the Jitter RNG always calculates the RCT
+ * cut-off value of C. If that value exceeds the allowed cut-off value,
+ * the Jitter RNG output block will be calculated completely but discarded at
+ * the end. The caller of the Jitter RNG is informed with an error code.
***************************************************************************/
-void jent_get_nstime(__u64 *out);
-void *jent_zalloc(unsigned int len);
-void jent_zfree(void *ptr);
-int jent_fips_enabled(void);
-void jent_panic(char *s);
-void jent_memcpy(void *dest, const void *src, unsigned int n);
+/*
+ * Repetition Count Test as defined in SP800-90B section 4.4.1
+ *
+ * @ec [in] Reference to entropy collector
+ * @stuck [in] Indicator whether the value is stuck
+ */
+static void jent_rct_insert(struct rand_data *ec, int stuck)
+{
+ if (stuck) {
+ ec->rct_count++;
+ } else {
+ /* Reset RCT */
+ ec->rct_count = 0;
+ }
+}
+
+static inline __u64 jent_delta(__u64 prev, __u64 next)
+{
+#define JENT_UINT64_MAX (__u64)(~((__u64) 0))
+ return (prev < next) ? (next - prev) :
+ (JENT_UINT64_MAX - prev + 1 + next);
+}
+
+/*
+ * Stuck test by checking the:
+ * 1st derivative of the jitter measurement (time delta)
+ * 2nd derivative of the jitter measurement (delta of time deltas)
+ * 3rd derivative of the jitter measurement (delta of delta of time deltas)
+ *
+ * All values must always be non-zero.
+ *
+ * @ec [in] Reference to entropy collector
+ * @current_delta [in] Jitter time delta
+ *
+ * @return
+ * 0 jitter measurement not stuck (good bit)
+ * 1 jitter measurement stuck (reject bit)
+ */
+static int jent_stuck(struct rand_data *ec, __u64 current_delta)
+{
+ __u64 delta2 = jent_delta(ec->last_delta, current_delta);
+ __u64 delta3 = jent_delta(ec->last_delta2, delta2);
+
+ ec->last_delta = current_delta;
+ ec->last_delta2 = delta2;
+
+ /*
+ * Insert the result of the comparison of two back-to-back time
+ * deltas.
+ */
+ jent_apt_insert(ec, current_delta);
+
+ if (!current_delta || !delta2 || !delta3) {
+ /* RCT with a stuck bit */
+ jent_rct_insert(ec, 1);
+ return 1;
+ }
+
+ /* RCT with a non-stuck bit */
+ jent_rct_insert(ec, 0);
+
+ return 0;
+}
+
+/* RCT health test failure detection */
+static int jent_rct_permanent_failure(struct rand_data *ec)
+{
+ return (ec->rct_count >= JENT_RCT_CUTOFF_PERMANENT) ? 1 : 0;
+}
+
+static int jent_rct_failure(struct rand_data *ec)
+{
+ return (ec->rct_count >= JENT_RCT_CUTOFF) ? 1 : 0;
+}
+
+/* Report of health test failures */
+static int jent_health_failure(struct rand_data *ec)
+{
+ return jent_rct_failure(ec) | jent_apt_failure(ec);
+}
+
+static int jent_permanent_health_failure(struct rand_data *ec)
+{
+ return jent_rct_permanent_failure(ec) | jent_apt_permanent_failure(ec);
+}
+
+/***************************************************************************
+ * Noise sources
+ ***************************************************************************/
-/**
+/*
* Update of the loop count used for the next round of
* an entropy collection.
*
@@ -153,11 +297,7 @@ static __u64 jent_loop_shuffle(struct rand_data *ec,
return (shuffle + (1<<min));
}
-/***************************************************************************
- * Noise sources
- ***************************************************************************/
-
-/**
+/*
* CPU Jitter noise source -- this is the noise source based on the CPU
* execution time jitter
*
@@ -171,18 +311,19 @@ static __u64 jent_loop_shuffle(struct rand_data *ec,
* the CPU execution time jitter. Any change to the loop in this function
* implies that careful retesting must be done.
*
- * Input:
- * @ec entropy collector struct -- may be NULL
- * @time time stamp to be injected
- * @loop_cnt if a value not equal to 0 is set, use the given value as number of
- * loops to perform the folding
+ * @ec [in] entropy collector struct
+ * @time [in] time stamp to be injected
+ * @loop_cnt [in] if a value not equal to 0 is set, use the given value as
+ * number of loops to perform the folding
+ * @stuck [in] Is the time stamp identified as stuck?
*
* Output:
* updated ec->data
*
* @return Number of loops the folding operation is performed
*/
-static __u64 jent_lfsr_time(struct rand_data *ec, __u64 time, __u64 loop_cnt)
+void jent_lfsr_time(struct rand_data *ec, __u64 time, __u64 loop_cnt,
+ int stuck)
{
unsigned int i;
__u64 j = 0;
@@ -225,12 +366,20 @@ static __u64 jent_lfsr_time(struct rand_data *ec, __u64 time, __u64 loop_cnt)
new ^= tmp;
}
}
- ec->data = new;
- return fold_loop_cnt;
+ /*
+ * If the time stamp is stuck, do not finally insert the value into
+ * the entropy pool. Although this operation should not do any harm
+ * even when the time stamp has no entropy, SP800-90B requires that
+ * any conditioning operation (SP800-90B considers the LFSR to be a
+ * conditioning operation) to have an identical amount of input
+ * data according to section 3.1.5.
+ */
+ if (!stuck)
+ ec->data = new;
}
-/**
+/*
* Memory Access noise source -- this is a noise source based on variations in
* memory access times
*
@@ -248,16 +397,13 @@ static __u64 jent_lfsr_time(struct rand_data *ec, __u64 time, __u64 loop_cnt)
* to reliably access either L3 or memory, the ec->mem memory must be quite
* large which is usually not desirable.
*
- * Input:
- * @ec Reference to the entropy collector with the memory access data -- if
- * the reference to the memory block to be accessed is NULL, this noise
- * source is disabled
- * @loop_cnt if a value not equal to 0 is set, use the given value as number of
- * loops to perform the folding
- *
- * @return Number of memory access operations
+ * @ec [in] Reference to the entropy collector with the memory access data -- if
+ * the reference to the memory block to be accessed is NULL, this noise
+ * source is disabled
+ * @loop_cnt [in] if a value not equal to 0 is set, use the given value
+ * number of loops to perform the LFSR
*/
-static unsigned int jent_memaccess(struct rand_data *ec, __u64 loop_cnt)
+static void jent_memaccess(struct rand_data *ec, __u64 loop_cnt)
{
unsigned int wrap = 0;
__u64 i = 0;
@@ -267,7 +413,7 @@ static unsigned int jent_memaccess(struct rand_data *ec, __u64 loop_cnt)
jent_loop_shuffle(ec, MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT);
if (NULL == ec || NULL == ec->mem)
- return 0;
+ return;
wrap = ec->memblocksize * ec->memblocks;
/*
@@ -293,44 +439,12 @@ static unsigned int jent_memaccess(struct rand_data *ec, __u64 loop_cnt)
ec->memlocation = ec->memlocation + ec->memblocksize - 1;
ec->memlocation = ec->memlocation % wrap;
}
- return i;
}
/***************************************************************************
* Start of entropy processing logic
***************************************************************************/
-
-/**
- * Stuck test by checking the:
- * 1st derivation of the jitter measurement (time delta)
- * 2nd derivation of the jitter measurement (delta of time deltas)
- * 3rd derivation of the jitter measurement (delta of delta of time deltas)
- *
- * All values must always be non-zero.
- *
- * Input:
- * @ec Reference to entropy collector
- * @current_delta Jitter time delta
- *
- * @return
- * 0 jitter measurement not stuck (good bit)
- * 1 jitter measurement stuck (reject bit)
- */
-static int jent_stuck(struct rand_data *ec, __u64 current_delta)
-{
- __s64 delta2 = ec->last_delta - current_delta;
- __s64 delta3 = delta2 - ec->last_delta2;
-
- ec->last_delta = current_delta;
- ec->last_delta2 = delta2;
-
- if (!current_delta || !delta2 || !delta3)
- return 1;
-
- return 0;
-}
-
-/**
+/*
* This is the heart of the entropy generation: calculate time deltas and
* use the CPU jitter in the time deltas. The jitter is injected into the
* entropy pool.
@@ -339,15 +453,15 @@ static int jent_stuck(struct rand_data *ec, __u64 current_delta)
* of this function! This can be done by calling this function
* and not using its result.
*
- * Input:
- * @entropy_collector Reference to entropy collector
+ * @ec [in] Reference to entropy collector
*
* @return result of stuck test
*/
-static int jent_measure_jitter(struct rand_data *ec)
+int jent_measure_jitter(struct rand_data *ec)
{
__u64 time = 0;
__u64 current_delta = 0;
+ int stuck;
/* Invoke one noise source before time measurement to add variations */
jent_memaccess(ec, 0);
@@ -357,31 +471,33 @@ static int jent_measure_jitter(struct rand_data *ec)
* invocation to measure the timing variations
*/
jent_get_nstime(&time);
- current_delta = time - ec->prev_time;
+ current_delta = jent_delta(ec->prev_time, time);
ec->prev_time = time;
+ /* Check whether we have a stuck measurement. */
+ stuck = jent_stuck(ec, current_delta);
/* Now call the next noise sources which also injects the data */
- jent_lfsr_time(ec, current_delta, 0);
-
- /* Check whether we have a stuck measurement. */
- return jent_stuck(ec, current_delta);
+ jent_lfsr_time(ec, current_delta, 0, stuck);
+ return stuck;
}
-/**
+/*
* Generator of one 64 bit random number
* Function fills rand_data->data
*
- * Input:
- * @ec Reference to entropy collector
+ * @ec [in] Reference to entropy collector
*/
static void jent_gen_entropy(struct rand_data *ec)
{
- unsigned int k = 0;
+ unsigned int k = 0, safety_factor = 0;
+
+ if (fips_enabled)
+ safety_factor = JENT_ENTROPY_SAFETY_FACTOR;
/* priming of the ->prev_time value */
jent_measure_jitter(ec);
- while (1) {
+ while (!jent_health_failure(ec)) {
/* If a stuck measurement is received, repeat measurement */
if (jent_measure_jitter(ec))
continue;
@@ -390,37 +506,12 @@ static void jent_gen_entropy(struct rand_data *ec)
* We multiply the loop value with ->osr to obtain the
* oversampling rate requested by the caller
*/
- if (++k >= (DATA_SIZE_BITS * ec->osr))
+ if (++k >= ((DATA_SIZE_BITS + safety_factor) * ec->osr))
break;
}
}
-/**
- * The continuous test required by FIPS 140-2 -- the function automatically
- * primes the test if needed.
- *
- * Return:
- * 0 if FIPS test passed
- * < 0 if FIPS test failed
- */
-static void jent_fips_test(struct rand_data *ec)
-{
- if (!jent_fips_enabled())
- return;
-
- /* prime the FIPS test */
- if (!ec->old_data) {
- ec->old_data = ec->data;
- jent_gen_entropy(ec);
- }
-
- if (ec->data == ec->old_data)
- jent_panic("jitterentropy: Duplicate output detected\n");
-
- ec->old_data = ec->data;
-}
-
-/**
+/*
* Entry function: Obtain entropy for the caller.
*
* This function invokes the entropy gathering logic as often to generate
@@ -430,42 +521,62 @@ static void jent_fips_test(struct rand_data *ec)
* This function truncates the last 64 bit entropy value output to the exact
* size specified by the caller.
*
- * Input:
- * @ec Reference to entropy collector
- * @data pointer to buffer for storing random data -- buffer must already
- * exist
- * @len size of the buffer, specifying also the requested number of random
- * in bytes
+ * @ec [in] Reference to entropy collector
+ * @data [in] 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 0 when request is fulfilled or an error
*
* The following error codes can occur:
* -1 entropy_collector is NULL
+ * -2 Intermittent health failure
+ * -3 Permanent health failure
*/
int jent_read_entropy(struct rand_data *ec, unsigned char *data,
unsigned int len)
{
unsigned char *p = data;
if (!ec)
return -1;
- while (0 < len) {
+ while (len > 0) {
unsigned int tocopy;
jent_gen_entropy(ec);
- jent_fips_test(ec);
+
+ if (jent_permanent_health_failure(ec)) {
+ /*
+ * At this point, the Jitter RNG instance is considered
+ * as a failed instance. There is no rerun of the
+ * startup test any more, because the caller
+ * is assumed to not further use this instance.
+ */
+ return -3;
+ } else if (jent_health_failure(ec)) {
+ /*
+ * Perform startup health tests and return permanent
+ * error if it fails.
+ */
+ if (jent_entropy_init())
+ return -3;
+
+ return -2;
+ }
+
if ((DATA_SIZE_BITS / 8) < len)
tocopy = (DATA_SIZE_BITS / 8);
else
tocopy = len;
jent_memcpy(p, &ec->data, tocopy);
len -= tocopy;
p += tocopy;
}
return 0;
}
/***************************************************************************
@@ -496,7 +609,7 @@ struct rand_data *jent_entropy_collector_alloc(unsigned int osr,
}
/* verify and set the oversampling rate */
- if (0 == osr)
+ if (osr == 0)
osr = 1; /* minimum sampling rate is 1 */
entropy_collector->osr = osr;
@@ -518,11 +631,15 @@ int jent_entropy_init(void)
int i;
__u64 delta_sum = 0;
__u64 old_delta = 0;
+ unsigned int nonstuck = 0;
int time_backwards = 0;
int count_mod = 0;
int count_stuck = 0;
struct rand_data ec = { 0 };
+ /* Required for RCT */
+ ec.osr = 1;
+
/* 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 and we produce
@@ -544,8 +661,10 @@ int jent_entropy_init(void)
/*
* TESTLOOPCOUNT needs some loops to identify edge systems. 100 is
* definitely too little.
+ *
+ * SP800-90B requires at least 1024 initial test cycles.
*/
-#define TESTLOOPCOUNT 300
+#define TESTLOOPCOUNT 1024
#define CLEARCACHE 100
for (i = 0; (TESTLOOPCOUNT + CLEARCACHE) > i; i++) {
__u64 time = 0;
@@ -557,13 +676,13 @@ int jent_entropy_init(void)
/* Invoke core entropy collection logic */
jent_get_nstime(&time);
ec.prev_time = time;
- jent_lfsr_time(&ec, time, 0);
+ jent_lfsr_time(&ec, time, 0, 0);
jent_get_nstime(&time2);
/* test whether timer works */
if (!time || !time2)
return JENT_ENOTIME;
- delta = time2 - time;
+ delta = jent_delta(time, time2);
/*
* test whether timer is fine grained enough to provide
* delta even when called shortly after each other -- this
@@ -581,11 +700,31 @@ int jent_entropy_init(void)
* etc. with the goal to clear it to get the worst case
* measurements.
*/
- if (CLEARCACHE > i)
+ if (i < CLEARCACHE)
continue;
if (stuck)
count_stuck++;
+ else {
+ nonstuck++;
+
+ /*
+ * Ensure that the APT succeeded.
+ *
+ * With the check below that count_stuck must be less
+ * than 10% of the overall generated raw entropy values
+ * it is guaranteed that the APT is invoked at
+ * floor((TESTLOOPCOUNT * 0.9) / 64) == 14 times.
+ */
+ if ((nonstuck % JENT_APT_WINDOW_SIZE) == 0) {
+ jent_apt_reset(&ec,
+ delta & JENT_APT_WORD_MASK);
+ }
+ }
+
+ /* Validate health test result */
+ if (jent_health_failure(&ec))
+ return JENT_EHEALTH;
/* test whether we have an increasing timer */
if (!(time2 > time))
@@ -616,7 +755,7 @@ int jent_entropy_init(void)
* should not fail. The value of 3 should cover the NTP case being
* performed during our test run.
*/
- if (3 < time_backwards)
+ if (time_backwards > 3)
return JENT_ENOMONOTONIC;
/*
diff --git a/crypto/jitterentropy.h b/crypto/jitterentropy.h
new file mode 100644
index 000000000..ee555f642
--- /dev/null
+++ b/crypto/jitterentropy.h
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#ifndef _JITTERENTROPY_H
+#define _JITTERENTROPY_H
+#include <linux/types.h>
+
+/* Flags that can be used to initialize the RNG */
+#define JENT_DISABLE_STIR (1<<0) /* Disable stirring the entropy pool */
+#define JENT_DISABLE_UNBIAS (1<<1) /* Disable the Von-Neuman Unbiaser */
+#define JENT_DISABLE_MEMORY_ACCESS (1<<2) /* Disable memory access for more
+ entropy, saves MEMORY_SIZE RAM for
+ entropy collector */
+#define DRIVER_NAME "jitterentropy"
+
+struct rand_data {
+ /* all data values that are vital to maintain the security
+ * of the RNG are marked as SENSITIVE. A user must not
+ * access that information while the RNG executes its loops to
+ * calculate the next random value. */
+ __u64 data; /* SENSITIVE Actual random number */
+ __u64 old_data; /* SENSITIVE Previous random number */
+ __u64 prev_time; /* SENSITIVE Previous time stamp */
+#define DATA_SIZE_BITS ((sizeof(__u64)) * 8)
+ __u64 last_delta; /* SENSITIVE stuck test */
+ __s64 last_delta2; /* SENSITIVE stuck test */
+ unsigned int osr; /* Oversample rate */
+#define JENT_MEMORY_BLOCKS 64
+#define JENT_MEMORY_BLOCKSIZE 32
+#define JENT_MEMORY_ACCESSLOOPS 128
+#define JENT_MEMORY_SIZE (JENT_MEMORY_BLOCKS*JENT_MEMORY_BLOCKSIZE)
+ unsigned char *mem; /* Memory access location with size of
+ * memblocks * memblocksize */
+ unsigned int memlocation; /* Pointer to byte in *mem */
+ unsigned int memblocks; /* Number of memory blocks in *mem */
+ unsigned int memblocksize; /* Size of one memory block in bytes */
+ unsigned int memaccessloops; /* Number of memory accesses per random
+ * bit generation */
+
+ /* Repetition Count Test */
+ unsigned int rct_count; /* Number of stuck values */
+
+ /* Intermittent health test failure threshold of 2^-30 */
+#define JENT_RCT_CUTOFF 30 /* Taken from SP800-90B sec 4.4.1 */
+#define JENT_APT_CUTOFF 325 /* Taken from SP800-90B sec 4.4.2 */
+ /* Permanent health test failure threshold of 2^-60 */
+#define JENT_RCT_CUTOFF_PERMANENT 60
+#define JENT_APT_CUTOFF_PERMANENT 355
+#define JENT_APT_WINDOW_SIZE 512 /* Data window size */
+ /* LSB of time stamp to process */
+#define JENT_APT_LSB 16
+#define JENT_APT_WORD_MASK (JENT_APT_LSB - 1)
+ unsigned int apt_observations; /* Number of collected observations */
+ unsigned int apt_count; /* APT counter */
+ unsigned int apt_base; /* APT base reference */
+ unsigned int apt_base_set:1; /* APT base reference set? */
+ unsigned int stir:1; /* Post-processing stirring */
+ unsigned int disable_unbias:1; /* Deactivate Von-Neuman unbias */
+};
+extern void *jent_zalloc(unsigned int len);
+extern void jent_zfree(void *ptr);
+extern void jent_memcpy(void *dest, const void *src, unsigned int n);
+extern void jent_get_nstime(__u64 *out);
+
+struct rand_data;
+extern int jent_entropy_init(void);
+extern int jent_read_entropy(struct rand_data *ec, unsigned char *data,
+ unsigned int len);
+
+extern struct rand_data *jent_entropy_collector_alloc(unsigned int osr,
+ unsigned int flags);
+extern void jent_entropy_collector_free(struct rand_data *entropy_collector);
+
+unsigned int jent_version(void);
+
+void jent_lfsr_time(struct rand_data *ec, __u64 time, __u64 loop_cnt, int stuck);
+
+int jent_measure_jitter(struct rand_data *ec);
+
+#endif /* _JITTERENTROPY_H */