Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

crypto: jitter - add interface for gathering of raw entropy

The test interface allows a privileged process to capture the raw
unconditioned noise that is collected by the Jitter RNG for statistical
analysis. Such testing allows the analysis how much entropy
the Jitter RNG noise source provides on a given platform. The obtained
data is the time stamp sampled by the Jitter RNG. Considering that
the Jitter RNG inserts the delta of this time stamp compared to the
immediately preceding time stamp, the obtained data needs to be
post-processed accordingly to obtain the data the Jitter RNG inserts
into its entropy pool.

The raw entropy collection is provided to obtain the raw unmodified
time stamps that are about to be added to the Jitter RNG entropy pool
and are credited with entropy. Thus, this patch adds an interface
which renders the Jitter RNG insecure. This patch is NOT INTENDED
FOR PRODUCTION SYSTEMS, but solely for development/test systems to
verify the available entropy rate.

Access to the data is given through the jent_raw_hires debugfs file.
The data buffer should be multiples of sizeof(u32) to fill the entire
buffer. Using the option jitterentropy_testing.boot_raw_hires_test=1
the raw noise of the first 1000 entropy events since boot can be
sampled.

This test interface allows generating the data required for
analysis whether the Jitter RNG is in compliance with SP800-90B
sections 3.1.3 and 3.1.4.

If the test interface is not compiled, its code is a noop which has no
impact on the performance.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

authored by

Stephan Müller and committed by
Herbert Xu
69f1c387 bb897c55

+333 -1
+20
crypto/Kconfig
··· 1288 1288 1289 1289 See https://www.chronox.de/jent.html 1290 1290 1291 + config CRYPTO_JITTERENTROPY_TESTINTERFACE 1292 + bool "CPU Jitter RNG Test Interface" 1293 + depends on CRYPTO_JITTERENTROPY 1294 + help 1295 + The test interface allows a privileged process to capture 1296 + the raw unconditioned high resolution time stamp noise that 1297 + is collected by the Jitter RNG for statistical analysis. As 1298 + this data is used at the same time to generate random bits, 1299 + the Jitter RNG operates in an insecure mode as long as the 1300 + recording is enabled. This interface therefore is only 1301 + intended for testing purposes and is not suitable for 1302 + production systems. 1303 + 1304 + The raw noise data can be obtained using the jent_raw_hires 1305 + debugfs file. Using the option 1306 + jitterentropy_testing.boot_raw_hires_test=1 the raw noise of 1307 + the first 1000 entropy events since boot can be sampled. 1308 + 1309 + If unsure, select N. 1310 + 1291 1311 config CRYPTO_KDF800108_CTR 1292 1312 tristate 1293 1313 select CRYPTO_HMAC
+1
crypto/Makefile
··· 171 171 KASAN_SANITIZE_jitterentropy.o = n 172 172 UBSAN_SANITIZE_jitterentropy.o = n 173 173 jitterentropy_rng-y := jitterentropy.o jitterentropy-kcapi.o 174 + obj-$(CONFIG_CRYPTO_JITTERENTROPY_TESTINTERFACE) += jitterentropy-testing.o 174 175 obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o 175 176 obj-$(CONFIG_CRYPTO_GHASH) += ghash-generic.o 176 177 obj-$(CONFIG_CRYPTO_POLYVAL) += polyval-generic.o
+8 -1
crypto/jitterentropy-kcapi.c
··· 88 88 tmp = ktime_get_ns(); 89 89 90 90 *out = tmp; 91 + jent_raw_hires_entropy_store(tmp); 91 92 } 92 93 93 94 int jent_hash_time(void *hash_state, __u64 time, u8 *addtl, ··· 324 323 struct crypto_shash *tfm; 325 324 int ret = 0; 326 325 326 + jent_testing_init(); 327 + 327 328 tfm = crypto_alloc_shash(JENT_CONDITIONING_HASH, 0, 0); 328 - if (IS_ERR(tfm)) 329 + if (IS_ERR(tfm)) { 330 + jent_testing_exit(); 329 331 return PTR_ERR(tfm); 332 + } 330 333 331 334 desc->tfm = tfm; 332 335 crypto_shash_init(desc); ··· 342 337 if (fips_enabled) 343 338 panic("jitterentropy: Initialization failed with host not compliant with requirements: %d\n", ret); 344 339 340 + jent_testing_exit(); 345 341 pr_info("jitterentropy: Initialization failed with host not compliant with requirements: %d\n", ret); 346 342 return -EFAULT; 347 343 } ··· 351 345 352 346 static void __exit jent_mod_exit(void) 353 347 { 348 + jent_testing_exit(); 354 349 crypto_unregister_rng(&jent_alg); 355 350 } 356 351
+294
crypto/jitterentropy-testing.c
··· 1 + /* SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause */ 2 + /* 3 + * Test interface for Jitter RNG. 4 + * 5 + * Copyright (C) 2023, Stephan Mueller <smueller@chronox.de> 6 + */ 7 + 8 + #include <linux/debugfs.h> 9 + #include <linux/module.h> 10 + #include <linux/uaccess.h> 11 + 12 + #include "jitterentropy.h" 13 + 14 + #define JENT_TEST_RINGBUFFER_SIZE (1<<10) 15 + #define JENT_TEST_RINGBUFFER_MASK (JENT_TEST_RINGBUFFER_SIZE - 1) 16 + 17 + struct jent_testing { 18 + u32 jent_testing_rb[JENT_TEST_RINGBUFFER_SIZE]; 19 + u32 rb_reader; 20 + atomic_t rb_writer; 21 + atomic_t jent_testing_enabled; 22 + spinlock_t lock; 23 + wait_queue_head_t read_wait; 24 + }; 25 + 26 + static struct dentry *jent_raw_debugfs_root = NULL; 27 + 28 + /*************************** Generic Data Handling ****************************/ 29 + 30 + /* 31 + * boot variable: 32 + * 0 ==> No boot test, gathering of runtime data allowed 33 + * 1 ==> Boot test enabled and ready for collecting data, gathering runtime 34 + * data is disabled 35 + * 2 ==> Boot test completed and disabled, gathering of runtime data is 36 + * disabled 37 + */ 38 + 39 + static void jent_testing_reset(struct jent_testing *data) 40 + { 41 + unsigned long flags; 42 + 43 + spin_lock_irqsave(&data->lock, flags); 44 + data->rb_reader = 0; 45 + atomic_set(&data->rb_writer, 0); 46 + spin_unlock_irqrestore(&data->lock, flags); 47 + } 48 + 49 + static void jent_testing_data_init(struct jent_testing *data, u32 boot) 50 + { 51 + /* 52 + * The boot time testing implies we have a running test. If the 53 + * caller wants to clear it, he has to unset the boot_test flag 54 + * at runtime via sysfs to enable regular runtime testing 55 + */ 56 + if (boot) 57 + return; 58 + 59 + jent_testing_reset(data); 60 + atomic_set(&data->jent_testing_enabled, 1); 61 + pr_warn("Enabling data collection\n"); 62 + } 63 + 64 + static void jent_testing_fini(struct jent_testing *data, u32 boot) 65 + { 66 + /* If we have boot data, we do not reset yet to allow data to be read */ 67 + if (boot) 68 + return; 69 + 70 + atomic_set(&data->jent_testing_enabled, 0); 71 + jent_testing_reset(data); 72 + pr_warn("Disabling data collection\n"); 73 + } 74 + 75 + static bool jent_testing_store(struct jent_testing *data, u32 value, 76 + u32 *boot) 77 + { 78 + unsigned long flags; 79 + 80 + if (!atomic_read(&data->jent_testing_enabled) && (*boot != 1)) 81 + return false; 82 + 83 + spin_lock_irqsave(&data->lock, flags); 84 + 85 + /* 86 + * Disable entropy testing for boot time testing after ring buffer 87 + * is filled. 88 + */ 89 + if (*boot) { 90 + if (((u32)atomic_read(&data->rb_writer)) > 91 + JENT_TEST_RINGBUFFER_SIZE) { 92 + *boot = 2; 93 + pr_warn_once("One time data collection test disabled\n"); 94 + spin_unlock_irqrestore(&data->lock, flags); 95 + return false; 96 + } 97 + 98 + if (atomic_read(&data->rb_writer) == 1) 99 + pr_warn("One time data collection test enabled\n"); 100 + } 101 + 102 + data->jent_testing_rb[((u32)atomic_read(&data->rb_writer)) & 103 + JENT_TEST_RINGBUFFER_MASK] = value; 104 + atomic_inc(&data->rb_writer); 105 + 106 + spin_unlock_irqrestore(&data->lock, flags); 107 + 108 + if (wq_has_sleeper(&data->read_wait)) 109 + wake_up_interruptible(&data->read_wait); 110 + 111 + return true; 112 + } 113 + 114 + static bool jent_testing_have_data(struct jent_testing *data) 115 + { 116 + return ((((u32)atomic_read(&data->rb_writer)) & 117 + JENT_TEST_RINGBUFFER_MASK) != 118 + (data->rb_reader & JENT_TEST_RINGBUFFER_MASK)); 119 + } 120 + 121 + static int jent_testing_reader(struct jent_testing *data, u32 *boot, 122 + u8 *outbuf, u32 outbuflen) 123 + { 124 + unsigned long flags; 125 + int collected_data = 0; 126 + 127 + jent_testing_data_init(data, *boot); 128 + 129 + while (outbuflen) { 130 + u32 writer = (u32)atomic_read(&data->rb_writer); 131 + 132 + spin_lock_irqsave(&data->lock, flags); 133 + 134 + /* We have no data or reached the writer. */ 135 + if (!writer || (writer == data->rb_reader)) { 136 + 137 + spin_unlock_irqrestore(&data->lock, flags); 138 + 139 + /* 140 + * Now we gathered all boot data, enable regular data 141 + * collection. 142 + */ 143 + if (*boot) { 144 + *boot = 0; 145 + goto out; 146 + } 147 + 148 + wait_event_interruptible(data->read_wait, 149 + jent_testing_have_data(data)); 150 + if (signal_pending(current)) { 151 + collected_data = -ERESTARTSYS; 152 + goto out; 153 + } 154 + 155 + continue; 156 + } 157 + 158 + /* We copy out word-wise */ 159 + if (outbuflen < sizeof(u32)) { 160 + spin_unlock_irqrestore(&data->lock, flags); 161 + goto out; 162 + } 163 + 164 + memcpy(outbuf, &data->jent_testing_rb[data->rb_reader], 165 + sizeof(u32)); 166 + data->rb_reader++; 167 + 168 + spin_unlock_irqrestore(&data->lock, flags); 169 + 170 + outbuf += sizeof(u32); 171 + outbuflen -= sizeof(u32); 172 + collected_data += sizeof(u32); 173 + } 174 + 175 + out: 176 + jent_testing_fini(data, *boot); 177 + return collected_data; 178 + } 179 + 180 + static int jent_testing_extract_user(struct file *file, char __user *buf, 181 + size_t nbytes, loff_t *ppos, 182 + int (*reader)(u8 *outbuf, u32 outbuflen)) 183 + { 184 + u8 *tmp, *tmp_aligned; 185 + int ret = 0, large_request = (nbytes > 256); 186 + 187 + if (!nbytes) 188 + return 0; 189 + 190 + /* 191 + * The intention of this interface is for collecting at least 192 + * 1000 samples due to the SP800-90B requirements. So, we make no 193 + * effort in avoiding allocating more memory that actually needed 194 + * by the user. Hence, we allocate sufficient memory to always hold 195 + * that amount of data. 196 + */ 197 + tmp = kmalloc(JENT_TEST_RINGBUFFER_SIZE + sizeof(u32), GFP_KERNEL); 198 + if (!tmp) 199 + return -ENOMEM; 200 + 201 + tmp_aligned = PTR_ALIGN(tmp, sizeof(u32)); 202 + 203 + while (nbytes) { 204 + int i; 205 + 206 + if (large_request && need_resched()) { 207 + if (signal_pending(current)) { 208 + if (ret == 0) 209 + ret = -ERESTARTSYS; 210 + break; 211 + } 212 + schedule(); 213 + } 214 + 215 + i = min_t(int, nbytes, JENT_TEST_RINGBUFFER_SIZE); 216 + i = reader(tmp_aligned, i); 217 + if (i <= 0) { 218 + if (i < 0) 219 + ret = i; 220 + break; 221 + } 222 + if (copy_to_user(buf, tmp_aligned, i)) { 223 + ret = -EFAULT; 224 + break; 225 + } 226 + 227 + nbytes -= i; 228 + buf += i; 229 + ret += i; 230 + } 231 + 232 + kfree_sensitive(tmp); 233 + 234 + if (ret > 0) 235 + *ppos += ret; 236 + 237 + return ret; 238 + } 239 + 240 + /************** Raw High-Resolution Timer Entropy Data Handling **************/ 241 + 242 + static u32 boot_raw_hires_test = 0; 243 + module_param(boot_raw_hires_test, uint, 0644); 244 + MODULE_PARM_DESC(boot_raw_hires_test, 245 + "Enable gathering boot time high resolution timer entropy of the first Jitter RNG entropy events"); 246 + 247 + static struct jent_testing jent_raw_hires = { 248 + .rb_reader = 0, 249 + .rb_writer = ATOMIC_INIT(0), 250 + .lock = __SPIN_LOCK_UNLOCKED(jent_raw_hires.lock), 251 + .read_wait = __WAIT_QUEUE_HEAD_INITIALIZER(jent_raw_hires.read_wait) 252 + }; 253 + 254 + int jent_raw_hires_entropy_store(__u32 value) 255 + { 256 + return jent_testing_store(&jent_raw_hires, value, &boot_raw_hires_test); 257 + } 258 + EXPORT_SYMBOL(jent_raw_hires_entropy_store); 259 + 260 + static int jent_raw_hires_entropy_reader(u8 *outbuf, u32 outbuflen) 261 + { 262 + return jent_testing_reader(&jent_raw_hires, &boot_raw_hires_test, 263 + outbuf, outbuflen); 264 + } 265 + 266 + static ssize_t jent_raw_hires_read(struct file *file, char __user *to, 267 + size_t count, loff_t *ppos) 268 + { 269 + return jent_testing_extract_user(file, to, count, ppos, 270 + jent_raw_hires_entropy_reader); 271 + } 272 + 273 + static const struct file_operations jent_raw_hires_fops = { 274 + .owner = THIS_MODULE, 275 + .read = jent_raw_hires_read, 276 + }; 277 + 278 + /******************************* Initialization *******************************/ 279 + 280 + void jent_testing_init(void) 281 + { 282 + jent_raw_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); 283 + 284 + debugfs_create_file_unsafe("jent_raw_hires", 0400, 285 + jent_raw_debugfs_root, NULL, 286 + &jent_raw_hires_fops); 287 + } 288 + EXPORT_SYMBOL(jent_testing_init); 289 + 290 + void jent_testing_exit(void) 291 + { 292 + debugfs_remove_recursive(jent_raw_debugfs_root); 293 + } 294 + EXPORT_SYMBOL(jent_testing_exit);
+10
crypto/jitterentropy.h
··· 17 17 unsigned int flags, 18 18 void *hash_state); 19 19 extern void jent_entropy_collector_free(struct rand_data *entropy_collector); 20 + 21 + #ifdef CONFIG_CRYPTO_JITTERENTROPY_TESTINTERFACE 22 + int jent_raw_hires_entropy_store(__u32 value); 23 + void jent_testing_init(void); 24 + void jent_testing_exit(void); 25 + #else /* CONFIG_CRYPTO_JITTERENTROPY_TESTINTERFACE */ 26 + static inline int jent_raw_hires_entropy_store(__u32 value) { return 0; } 27 + static inline void jent_testing_init(void) { } 28 + static inline void jent_testing_exit(void) { } 29 + #endif /* CONFIG_CRYPTO_JITTERENTROPY_TESTINTERFACE */