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 | |
| 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>
| -rw-r--r-- | crypto/internal.h | 7 | ||||
| -rw-r--r-- | drivers/char/random.c | 14 | ||||
| -rw-r--r-- | include/linux/fips.h | 10 |
3 files changed, 25 insertions, 6 deletions
diff --git a/crypto/internal.h b/crypto/internal.h index 113579a82dff..95baaea21fbc 100644 --- a/crypto/internal.h +++ b/crypto/internal.h | |||
| @@ -25,12 +25,7 @@ | |||
| 25 | #include <linux/notifier.h> | 25 | #include <linux/notifier.h> |
| 26 | #include <linux/rwsem.h> | 26 | #include <linux/rwsem.h> |
| 27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
| 28 | 28 | #include <linux/fips.h> | |
| 29 | #ifdef CONFIG_CRYPTO_FIPS | ||
| 30 | extern int fips_enabled; | ||
| 31 | #else | ||
| 32 | #define fips_enabled 0 | ||
| 33 | #endif | ||
| 34 | 29 | ||
| 35 | /* Crypto notification events. */ | 30 | /* Crypto notification events. */ |
| 36 | enum { | 31 | enum { |
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) |
diff --git a/include/linux/fips.h b/include/linux/fips.h new file mode 100644 index 000000000000..f8fb07b0b6b8 --- /dev/null +++ b/include/linux/fips.h | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | #ifndef _FIPS_H | ||
| 2 | #define _FIPS_H | ||
| 3 | |||
| 4 | #ifdef CONFIG_CRYPTO_FIPS | ||
| 5 | extern int fips_enabled; | ||
| 6 | #else | ||
| 7 | #define fips_enabled 0 | ||
| 8 | #endif | ||
| 9 | |||
| 10 | #endif | ||
