Module Name:    src
Committed By:   tls
Date:           Sat Jan 26 16:05:34 UTC 2013

Modified Files:
        src/sys/kern: subr_cprng.c

Log Message:
Fix a security issue: when we are reseeding a PRNG seeded early in boot
before we had ever had any entropy, if something else has consumed the
entropy that triggered the immediate reseed, we can reseed with as little
as sizeof(int) bytes of entropy.


To generate a diff of this commit:
cvs rdiff -u -r1.14 -r1.15 src/sys/kern/subr_cprng.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/subr_cprng.c
diff -u src/sys/kern/subr_cprng.c:1.14 src/sys/kern/subr_cprng.c:1.15
--- src/sys/kern/subr_cprng.c:1.14	Tue Nov 20 11:06:27 2012
+++ src/sys/kern/subr_cprng.c	Sat Jan 26 16:05:34 2013
@@ -1,4 +1,4 @@
-/*	$NetBSD: subr_cprng.c,v 1.14 2012/11/20 11:06:27 msaitoh Exp $ */
+/*	$NetBSD: subr_cprng.c,v 1.15 2013/01/26 16:05:34 tls Exp $ */
 
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -46,7 +46,7 @@
 
 #include <sys/cprng.h>
 
-__KERNEL_RCSID(0, "$NetBSD: subr_cprng.c,v 1.14 2012/11/20 11:06:27 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_cprng.c,v 1.15 2013/01/26 16:05:34 tls Exp $");
 
 void
 cprng_init(void)
@@ -84,6 +84,8 @@ cprng_strong_doreseed(cprng_strong_t *co
 				 &cc, sizeof(cc))) {
 		panic("cprng %s: nist_ctr_drbg_reseed failed.", c->name);
 	}
+	memset(c->reseed.data, 0, c->reseed.len);
+
 #ifdef RND_VERBOSE
 	printf("cprng %s: reseeded with rnd_filled = %d\n", c->name,
 							    rnd_filled);
@@ -154,6 +156,17 @@ cprng_strong_reseed(void *const arg)
 	mutex_exit(&c->mtx);
 }
 
+static size_t
+cprng_entropy_try(uint8_t *key, size_t keylen, int hard)
+{
+	int r;
+	r = rnd_extract_data(key, keylen, RND_EXTRACT_GOOD);
+	if (r != keylen && !hard) {
+		rnd_extract_data(key + r, keylen - r, RND_EXTRACT_ANY);
+	}
+	return r;
+}
+
 cprng_strong_t *
 cprng_strong_create(const char *const name, int ipl, int flags)
 {
@@ -183,15 +196,13 @@ cprng_strong_create(const char *const na
 
 	selinit(&c->selq);
 
-	r = rnd_extract_data(key, sizeof(key), RND_EXTRACT_GOOD);
+	r = cprng_entropy_try(key, sizeof(key), c->flags & CPRNG_INIT_ANY);
 	if (r != sizeof(key)) {
 		if (c->flags & CPRNG_INIT_ANY) {
 #ifdef DEBUG
 			printf("cprng %s: WARNING insufficient "
 			       "entropy at creation.\n", name);
 #endif
-			rnd_extract_data(key + r, sizeof(key - r),
-					 RND_EXTRACT_ANY);
 		} else {
 			hard++;
 		}
@@ -240,15 +251,18 @@ rekeyany:
 		if (c->flags & CPRNG_REKEY_ANY) {
 			uint8_t key[NIST_BLOCK_KEYLEN_BYTES];
 
- 			printf("cprng %s: WARNING pseudorandom rekeying.\n",
-			       c->name);
-                        rnd_extract_data(key, sizeof(key), RND_EXTRACT_ANY);
+			if (cprng_entropy_try(key, sizeof(key), 0) !=
+			    sizeof(key)) {
+ 				printf("cprng %s: WARNING "
+				       "pseudorandom rekeying.\n", c->name);
+			}
 			cc = cprng_counter();
 			if (nist_ctr_drbg_reseed(&c->drbg, key, sizeof(key),
 			    &cc, sizeof(cc))) {
 				panic("cprng %s: nist_ctr_drbg_reseed "
 				      "failed.", c->name);
 			}
+			memset(key, 0, sizeof(key));
 		} else {
 			int wr;
 

Reply via email to