diff options
author | Neil Horman <nhorman@tuxdriver.com> | 2009-06-18 07:50:21 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2009-06-18 07:50:21 -0400 |
commit | 5b739ef8a4e8cf5201d21abff897e292c232477b (patch) | |
tree | 6301126016ad869997b4ef31973999e16049dfeb /drivers/char/random.c | |
parent | b6f34d44cb341ad32f08717d1a2c418e6053a031 (diff) |
random: Add optional continuous repetition test to entropy store based rngs
FIPS-140 requires that all random number generators implement continuous self
tests in which each extracted block of data is compared against the last block
for repetition. The ansi_cprng implements such a test, but it would be nice if
the hw rng's did the same thing. Obviously its not something thats always
needed, but it seems like it would be a nice feature to have on occasion. I've
written the below patch which allows individual entropy stores to be flagged as
desiring a continuous test to be run on them as is extracted. By default this
option is off, but is enabled in the event that fips mode is selected during
bootup.
Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
Acked-by: Matt Mackall <mpm@selenic.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'drivers/char/random.c')
-rw-r--r-- | drivers/char/random.c | 14 |
1 files changed, 14 insertions, 0 deletions
diff --git a/drivers/char/random.c b/drivers/char/random.c index 8c7444857a4b..d8a9255e1a3f 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c | |||
@@ -240,6 +240,7 @@ | |||
240 | #include <linux/spinlock.h> | 240 | #include <linux/spinlock.h> |
241 | #include <linux/percpu.h> | 241 | #include <linux/percpu.h> |
242 | #include <linux/cryptohash.h> | 242 | #include <linux/cryptohash.h> |
243 | #include <linux/fips.h> | ||
243 | 244 | ||
244 | #ifdef CONFIG_GENERIC_HARDIRQS | 245 | #ifdef CONFIG_GENERIC_HARDIRQS |
245 | # include <linux/irq.h> | 246 | # include <linux/irq.h> |
@@ -413,6 +414,7 @@ struct entropy_store { | |||
413 | unsigned add_ptr; | 414 | unsigned add_ptr; |
414 | int entropy_count; | 415 | int entropy_count; |
415 | int input_rotate; | 416 | int input_rotate; |
417 | __u8 *last_data; | ||
416 | }; | 418 | }; |
417 | 419 | ||
418 | static __u32 input_pool_data[INPUT_POOL_WORDS]; | 420 | static __u32 input_pool_data[INPUT_POOL_WORDS]; |
@@ -852,12 +854,21 @@ static ssize_t extract_entropy(struct entropy_store *r, void *buf, | |||
852 | { | 854 | { |
853 | ssize_t ret = 0, i; | 855 | ssize_t ret = 0, i; |
854 | __u8 tmp[EXTRACT_SIZE]; | 856 | __u8 tmp[EXTRACT_SIZE]; |
857 | unsigned long flags; | ||
855 | 858 | ||
856 | xfer_secondary_pool(r, nbytes); | 859 | xfer_secondary_pool(r, nbytes); |
857 | nbytes = account(r, nbytes, min, reserved); | 860 | nbytes = account(r, nbytes, min, reserved); |
858 | 861 | ||
859 | while (nbytes) { | 862 | while (nbytes) { |
860 | extract_buf(r, tmp); | 863 | extract_buf(r, tmp); |
864 | |||
865 | if (r->last_data) { | ||
866 | spin_lock_irqsave(&r->lock, flags); | ||
867 | if (!memcmp(tmp, r->last_data, EXTRACT_SIZE)) | ||
868 | panic("Hardware RNG duplicated output!\n"); | ||
869 | memcpy(r->last_data, tmp, EXTRACT_SIZE); | ||
870 | spin_unlock_irqrestore(&r->lock, flags); | ||
871 | } | ||
861 | i = min_t(int, nbytes, EXTRACT_SIZE); | 872 | i = min_t(int, nbytes, EXTRACT_SIZE); |
862 | memcpy(buf, tmp, i); | 873 | memcpy(buf, tmp, i); |
863 | nbytes -= i; | 874 | nbytes -= i; |
@@ -940,6 +951,9 @@ static void init_std_data(struct entropy_store *r) | |||
940 | now = ktime_get_real(); | 951 | now = ktime_get_real(); |
941 | mix_pool_bytes(r, &now, sizeof(now)); | 952 | mix_pool_bytes(r, &now, sizeof(now)); |
942 | mix_pool_bytes(r, utsname(), sizeof(*(utsname()))); | 953 | mix_pool_bytes(r, utsname(), sizeof(*(utsname()))); |
954 | /* Enable continuous test in fips mode */ | ||
955 | if (fips_enabled) | ||
956 | r->last_data = kmalloc(EXTRACT_SIZE, GFP_KERNEL); | ||
943 | } | 957 | } |
944 | 958 | ||
945 | static int rand_initialize(void) | 959 | static int rand_initialize(void) |