Torsten Duwe 2f8971
From 0c8b22399c344807517f3bf5cdd0a582acaf6d68 Mon Sep 17 00:00:00 2001
Torsten Duwe 2f8971
From: Stephan Mueller <smueller@chronox.de>
Torsten Duwe 2f8971
Date: Tue, 27 Dec 2016 23:29:59 +0100
Torsten Duwe 2f8971
Subject: [PATCH 8/8] random: move FIPS continuous test to output functions
Torsten Duwe 2f8971
Patch-mainline: Never, handled differently
Torsten Duwe 2f8971
References: bsc#1155334
Torsten Duwe 2f8971
Torsten Duwe 2f8971
The current location of the FIPS continuous self test covers the
Torsten Duwe 2f8971
input_pool only. However, the FIPS continuous self test shall cover the
Torsten Duwe 2f8971
output of the random number generator, i.e. the blocking pool and the
Torsten Duwe 2f8971
ChaCha20 DRNG.
Torsten Duwe 2f8971
Torsten Duwe 2f8971
This patch therefore moves the continuous test to the output function
Torsten Duwe 2f8971
used for /dev/random. In addition, it adds the continuous test to the
Torsten Duwe 2f8971
ChaCha20 output function.
Torsten Duwe 2f8971
Torsten Duwe 2f8971
Signed-off-by: Stephan Mueller <smueller@chronox.de>
Torsten Duwe 2f8971
Acked-by: Torsten Duwe <duwe@suse.de>
Torsten Duwe 2f8971
---
Torsten Duwe 2f8971
 drivers/char/random.c | 71 +++++++++++++++++++++++++++++++--------------------
Torsten Duwe 2f8971
 1 file changed, 43 insertions(+), 28 deletions(-)
Torsten Duwe 2f8971
Torsten Duwe 2f8971
--- a/drivers/char/random.c
Torsten Duwe 2f8971
+++ b/drivers/char/random.c
Torsten Duwe 2f8971
@@ -415,6 +415,8 @@ struct crng_state {
Torsten Duwe 2f8971
 	__u32		state[16];
Torsten Duwe 2f8971
 	unsigned long	init_time;
Torsten Duwe 2f8971
 	spinlock_t	lock;
Torsten Duwe 2f8971
+	unsigned int last_data_init:1;
Torsten Duwe 2f8971
+	__u8 last_data[CHACHA20_BLOCK_SIZE];
Torsten Duwe 2f8971
 };
Torsten Duwe 2f8971
 
Torsten Duwe 2f8971
 struct crng_state primary_crng = {
Torsten Duwe 2f8971
@@ -481,7 +483,7 @@ struct entropy_store {
Torsten Duwe 2f8971
 static ssize_t extract_entropy(struct entropy_store *r, void *buf,
Torsten Duwe 2f8971
 			       size_t nbytes, int min, int rsvd);
Torsten Duwe 2f8971
 static ssize_t _extract_entropy(struct entropy_store *r, void *buf,
Torsten Duwe 2f8971
-				size_t nbytes, int fips);
Torsten Duwe 2f8971
+				size_t nbytes);
Torsten Duwe 2f8971
 
Torsten Duwe 2f8971
 static void crng_reseed(struct crng_state *crng, struct entropy_store *r);
Torsten Duwe 2f8971
 static void push_to_pool(struct work_struct *work);
Torsten Duwe 2f8971
@@ -787,7 +789,7 @@ static void crng_initialize(struct crng_
Torsten Duwe 2f8971
 	memcpy(&crng->state[0], "expand 32-byte k", 16);
Torsten Duwe 2f8971
 	if (crng == &primary_crng)
Torsten Duwe 2f8971
 		_extract_entropy(&input_pool, &crng->state[4],
Torsten Duwe 2f8971
-				 sizeof(__u32) * 12, 0);
Torsten Duwe 2f8971
+				 sizeof(__u32) * 12);
Torsten Duwe 2f8971
 	else
Torsten Duwe 2f8971
 		get_random_bytes(&crng->state[4], sizeof(__u32) * 12);
Torsten Duwe 2f8971
 	for (i = 4; i < 16; i++) {
Torsten Duwe 2f8971
@@ -968,11 +970,25 @@ static void _extract_crng(struct crng_st
Torsten Duwe 2f8971
 	     time_after(jiffies, crng->init_time + CRNG_RESEED_INTERVAL)))
Torsten Duwe 2f8971
 		crng_reseed(crng, crng == &primary_crng ? &input_pool : NULL);
Torsten Duwe 2f8971
 	spin_lock_irqsave(&crng->lock, flags);
Torsten Duwe 2f8971
+
Torsten Duwe 2f8971
+	if (fips_enabled && !crng->last_data_init) {
Torsten Duwe 2f8971
+		crng->last_data_init = 1;
Torsten Duwe 2f8971
+		chacha20_block(&crng->state[0], out);
Torsten Duwe 2f8971
+		memcpy(crng->last_data, out, CHACHA20_BLOCK_SIZE);
Torsten Duwe 2f8971
+	}
Torsten Duwe 2f8971
+
Torsten Duwe 2f8971
 	if (arch_get_random_long(&v))
Torsten Duwe 2f8971
 		crng->state[14] ^= v;
Torsten Duwe 2f8971
 	chacha20_block(&crng->state[0], out);
Torsten Duwe 2f8971
 	if (crng->state[12] == 0)
Torsten Duwe 2f8971
 		crng->state[13]++;
Torsten Duwe 2f8971
+
Torsten Duwe 2f8971
+	if (fips_enabled) {
Torsten Duwe 2f8971
+		if (!memcmp(out, crng->last_data, CHACHA20_BLOCK_SIZE))
Torsten Duwe 2f8971
+			panic("ChaCha20 RNG duplicated output!\n");
Torsten Duwe 2f8971
+		memcpy(crng->last_data, out, CHACHA20_BLOCK_SIZE);
Torsten Duwe 2f8971
+	}
Torsten Duwe 2f8971
+
Torsten Duwe 2f8971
 	spin_unlock_irqrestore(&crng->lock, flags);
Torsten Duwe 2f8971
 }
Torsten Duwe 2f8971
 
Torsten Duwe 2f8971
@@ -1468,22 +1484,14 @@ static void extract_buf(struct entropy_s
Torsten Duwe 2f8971
 }
Torsten Duwe 2f8971
 
Torsten Duwe 2f8971
 static ssize_t _extract_entropy(struct entropy_store *r, void *buf,
Torsten Duwe 2f8971
-				size_t nbytes, int fips)
Torsten Duwe 2f8971
+				size_t nbytes)
Torsten Duwe 2f8971
 {
Torsten Duwe 2f8971
 	ssize_t ret = 0, i;
Torsten Duwe 2f8971
 	__u8 tmp[EXTRACT_SIZE];
Torsten Duwe 2f8971
-	unsigned long flags;
Torsten Duwe 2f8971
 
Torsten Duwe 2f8971
 	while (nbytes) {
Torsten Duwe 2f8971
 		extract_buf(r, tmp);
Torsten Duwe 2f8971
 
Torsten Duwe 2f8971
-		if (fips) {
Torsten Duwe 2f8971
-			spin_lock_irqsave(&r->lock, flags);
Torsten Duwe 2f8971
-			if (!memcmp(tmp, r->last_data, EXTRACT_SIZE))
Torsten Duwe 2f8971
-				panic("Hardware RNG duplicated output!\n");
Torsten Duwe 2f8971
-			memcpy(r->last_data, tmp, EXTRACT_SIZE);
Torsten Duwe 2f8971
-			spin_unlock_irqrestore(&r->lock, flags);
Torsten Duwe 2f8971
-		}
Torsten Duwe 2f8971
 		i = min_t(int, nbytes, EXTRACT_SIZE);
Torsten Duwe 2f8971
 		memcpy(buf, tmp, i);
Torsten Duwe 2f8971
 		nbytes -= i;
Torsten Duwe 2f8971
@@ -1509,7 +1517,22 @@ static ssize_t _extract_entropy(struct e
Torsten Duwe 2f8971
 static ssize_t extract_entropy(struct entropy_store *r, void *buf,
Torsten Duwe 2f8971
 				 size_t nbytes, int min, int reserved)
Torsten Duwe 2f8971
 {
Torsten Duwe 2f8971
+	trace_extract_entropy(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_);
Torsten Duwe 2f8971
+	nbytes = account(r, nbytes, min, reserved);
Torsten Duwe 2f8971
+
Torsten Duwe 2f8971
+	return _extract_entropy(r, buf, nbytes);
Torsten Duwe 2f8971
+}
Torsten Duwe 2f8971
+
Torsten Duwe 2f8971
+/*
Torsten Duwe 2f8971
+ * This function extracts randomness from the "entropy pool", and
Torsten Duwe 2f8971
+ * returns it in a userspace buffer.
Torsten Duwe 2f8971
+ */
Torsten Duwe 2f8971
+static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf,
Torsten Duwe 2f8971
+				    size_t nbytes)
Torsten Duwe 2f8971
+{
Torsten Duwe 2f8971
+	ssize_t ret = 0, i;
Torsten Duwe 2f8971
 	__u8 tmp[EXTRACT_SIZE];
Torsten Duwe 2f8971
+	int large_request = (nbytes > 256);
Torsten Duwe 2f8971
 	unsigned long flags;
Torsten Duwe 2f8971
 
Torsten Duwe 2f8971
 	/* if last_data isn't primed, we need EXTRACT_SIZE extra bytes */
Torsten Duwe 2f8971
@@ -1528,24 +1551,6 @@ static ssize_t extract_entropy(struct en
Torsten Duwe 2f8971
 		spin_unlock_irqrestore(&r->lock, flags);
Torsten Duwe 2f8971
 	}
Torsten Duwe 2f8971
 
Torsten Duwe 2f8971
-	trace_extract_entropy(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_);
Torsten Duwe 2f8971
-	xfer_secondary_pool(r, nbytes);
Torsten Duwe 2f8971
-	nbytes = account(r, nbytes, min, reserved);
Torsten Duwe 2f8971
-
Torsten Duwe 2f8971
-	return _extract_entropy(r, buf, nbytes, fips_enabled);
Torsten Duwe 2f8971
-}
Torsten Duwe 2f8971
-
Torsten Duwe 2f8971
-/*
Torsten Duwe 2f8971
- * This function extracts randomness from the "entropy pool", and
Torsten Duwe 2f8971
- * returns it in a userspace buffer.
Torsten Duwe 2f8971
- */
Torsten Duwe 2f8971
-static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf,
Torsten Duwe 2f8971
-				    size_t nbytes)
Torsten Duwe 2f8971
-{
Torsten Duwe 2f8971
-	ssize_t ret = 0, i;
Torsten Duwe 2f8971
-	__u8 tmp[EXTRACT_SIZE];
Torsten Duwe 2f8971
-	int large_request = (nbytes > 256);
Torsten Duwe 2f8971
-
Torsten Duwe 2f8971
 	trace_extract_entropy_user(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_);
Torsten Duwe 2f8971
 	xfer_secondary_pool(r, nbytes);
Torsten Duwe 2f8971
 	nbytes = account(r, nbytes, 0, 0);
Torsten Duwe 2f8971
@@ -1561,6 +1566,15 @@ static ssize_t extract_entropy_user(stru
Torsten Duwe 2f8971
 		}
Torsten Duwe 2f8971
 
Torsten Duwe 2f8971
 		extract_buf(r, tmp);
Torsten Duwe 2f8971
+
Torsten Duwe 2f8971
+		if (fips_enabled) {
Torsten Duwe 2f8971
+			spin_lock_irqsave(&r->lock, flags);
Torsten Duwe 2f8971
+			if (!memcmp(tmp, r->last_data, EXTRACT_SIZE))
Torsten Duwe 2f8971
+				panic("Hardware RNG duplicated output!\n");
Torsten Duwe 2f8971
+			memcpy(r->last_data, tmp, EXTRACT_SIZE);
Torsten Duwe 2f8971
+			spin_unlock_irqrestore(&r->lock, flags);
Torsten Duwe 2f8971
+		}
Torsten Duwe 2f8971
+
Torsten Duwe 2f8971
 		i = min_t(int, nbytes, EXTRACT_SIZE);
Torsten Duwe 2f8971
 		if (copy_to_user(buf, tmp, i)) {
Torsten Duwe 2f8971
 			ret = -EFAULT;