Bugzilla Bug 355297: changed the way we reseed the RNG so that we modify NSS_3_11_BRANCH NSS_3_11_4_BETA1
authorwtchang%redhat.com
Fri, 13 Oct 2006 17:02:58 +0000
branchNSS_3_11_BRANCH
changeset 7506 c420e3e44ebb380b5af476a0eafc3ed79599880e
parent 7505 a08807003389dcb5e1b8d2ef5decbfdca572445f
child 7528 f17078807602a93f432baf2e71447e02ca76d8b4
push idunknown
push userunknown
push dateunknown
bugs355297
Bugzilla Bug 355297: changed the way we reseed the RNG so that we modify all the 256 bits of XKEY. Define struct SHA256ContextStr in the new header sha256.h so that prng_fips1861.c can use it. r=nelsonb,jpierre. Modified files: manifest.mn prng_fips1861.c sha512.c Added file: sha256.h Tag: NSS_3_11_BRANCH
security/nss/lib/freebl/manifest.mn
security/nss/lib/freebl/prng_fips1861.c
security/nss/lib/freebl/sha512.c
--- a/security/nss/lib/freebl/manifest.mn
+++ b/security/nss/lib/freebl/manifest.mn
@@ -155,16 +155,17 @@ ALL_HDRS =  \
 	blapit.h \
 	des.h \
 	ec.h \
 	loader.h \
 	rijndael.h \
 	secmpi.h \
 	sha.h \
 	sha_fast.h \
+	sha256.h \
 	shsign.h \
 	vis_proto.h \
 	$(NULL)
 
 
 ifdef NSS_ENABLE_ECC
 DEFINES += -DNSS_ENABLE_ECC
 endif
--- a/security/nss/lib/freebl/prng_fips1861.c
+++ b/security/nss/lib/freebl/prng_fips1861.c
@@ -41,16 +41,17 @@
 #include "secerr.h"
 
 #include "prtypes.h"
 #include "prinit.h"
 #include "blapi.h"
 #include "nssilock.h"
 #include "secitem.h"
 #include "sha_fast.h"
+#include "sha256.h"
 #include "secrng.h"	/* for RNG_GetNoise() */
 #include "secmpi.h"
 
 /*
  * The minimum amount of seed data required before the generator will
  * provide data.
  * Note that this is a measure of the number of bytes sent to
  * RNG_RandomUpdate, not the actual amount of entropy present in the
@@ -69,18 +70,20 @@
 
 /*
  * According to FIPS 186-2, 160 <= b <= 512.
  * For our purposes, we will assume b == 160,
  * 256, or 512 (the output size of SHA-1,
  * SHA-256, or SHA-512).
  */
 #define FIPS_B     256
-#define B_HASH_BUF SHA256_HashBuf
 #define BSIZE      (FIPS_B / PR_BITS_PER_BYTE)
+#if BSIZE != SHA256_LENGTH
+#error "this file requires that BSIZE and SHA256_LENGTH be equal"
+#endif
 
 /* Output size of the G function */
 #define FIPS_G     160
 #define GSIZE      (FIPS_G / PR_BITS_PER_BYTE)
 
 /*
  * Add two b-bit numbers represented as arrays of BSIZE bytes.
  * The numbers are big-endian, MSB first, so addition is done
@@ -179,17 +182,17 @@ freeRNGContext()
 {
     unsigned char inputhash[BSIZE];
     SECStatus rv;
 
     /* destroy context lock */
     PZ_DestroyLock(globalrng->lock);
 
     /* zero global RNG context except for XKEY to preserve entropy */
-    rv = B_HASH_BUF(inputhash, globalrng->XKEY, BSIZE);
+    rv = SHA256_HashBuf(inputhash, globalrng->XKEY, BSIZE);
     PORT_Assert(SECSuccess == rv);
     memset(globalrng, 0, sizeof(*globalrng));
     memcpy(globalrng->XKEY, inputhash, BSIZE);
 
     globalrng = NULL;
 }
 
 /*
@@ -357,29 +360,17 @@ static PRStatus rng_init(void)
 	globalrng->lock = PZ_NewLock(nssILockOther);
 	if (globalrng->lock == NULL) {
 	    globalrng = NULL;
 	    PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
 	    return PR_FAILURE;
 	}
 	/* the RNG is in a valid state */
 	globalrng->isValid = PR_TRUE;
-	/*
-	 * Try to get some seed data for the RNG.
-	 *
-	 * The very first RNG_RandomUpdate call initializes all FIPS_B
-	 * bits of the RNG's seed-key.  Subsequent RNG_RandomUpdate calls
-	 * only modify the low FIPS_G bits of the seed-key.  So it's
-	 * important to pass high entropy to the first RNG_RandomUpdate
-	 * call.
-	 *
-	 * RNG_GetNoise only reads the high-resolution clocks, which
-	 * have low entropy.  So if RNG_SystemRNG fails, the RNG will
-	 * have at most slightly more than FIPS_G bits of entropy.
-	 */
+	/* Try to get some seed data for the RNG */
 	numBytes = RNG_SystemRNG(bytes, sizeof bytes);
 	PORT_Assert(numBytes == 0 || numBytes == sizeof bytes);
 	if (numBytes != 0) {
 	    RNG_RandomUpdate(bytes, numBytes);
 	    memset(bytes, 0, numBytes);
 	} else if (PORT_GetError() != PR_NOT_IMPLEMENTED_ERROR) {
 	    PZ_DestroyLock(globalrng->lock);
 	    globalrng->lock = NULL;
@@ -414,78 +405,74 @@ RNG_RNGInit(void)
 /*
 ** Update the global random number generator with more seeding
 ** material
 */
 static SECStatus 
 prng_RandomUpdate(RNGContext *rng, const void *data, size_t bytes)
 {
     SECStatus rv = SECSuccess;
-    unsigned char inputhash[BSIZE];
     /* check for a valid global RNG context */
     PORT_Assert(rng != NULL);
     if (rng == NULL) {
 	PORT_SetError(SEC_ERROR_INVALID_ARGS);
 	return SECFailure;
     }
     /* RNG_SystemInfoForRNG() sometimes does this, not really an error */
     if (bytes == 0)
 	return SECSuccess;
-    /* If received 20 bytes of input, use it, else hash the input before 
-     * locking.
-     */
-    if (bytes == BSIZE)
-	memcpy(inputhash, data, BSIZE);
-    else
-	rv = B_HASH_BUF(inputhash, data, bytes);
-    if (rv != SECSuccess) {
-	/* B_HASH_BUF set error */
-	return SECFailure;
-    }
     /* --- LOCKED --- */
     PZ_Lock(rng->lock);
     /*
      * Random information is initially supplied by a call to
      * RNG_SystemInfoForRNG().  That function collects entropy from
      * the system and calls RNG_RandomUpdate() to seed the generator.
      * Algorithm 1 of FIPS 186-2 Change Notice 1, step 1 specifies that
      * a secret value for the seed-key must be chosen before the
      * generator can begin.  The size of XKEY is b bits, so fill it
-     * with the first b bits sent to RNG_RandomUpdate().
+     * with the b-bit hash of the input to the first RNG_RandomUpdate()
+     * call.
      */
     if (rng->seedCount == 0) {
 	/* This is the first call to RandomUpdate().  Use a hash
-	 * of the input to set the seed, XKEY.
+	 * of the input to set the seed-key, XKEY.
 	 *
-	 * <Step 1> copy seed bytes into context's XKEY
+	 * <Step 1> copy hash of seed bytes into context's XKEY
 	 */
-	memcpy(rng->XKEY, inputhash, BSIZE);
-	/* 
-	 * Now continue with algorithm.  Since the input was used to
-	 * initialize XKEY, the "optional user input" at this stage
-	 * will be a pad of zeros, XSEEDj = 0.
-	 */
+	SHA256_HashBuf(rng->XKEY, data, bytes);
+	/* Now continue with algorithm. */
 	rv = alg_fips186_2_cn_1(rng, NULL);
 	/* As per FIPS 140-2 continuous RNG test requirement, the first
 	 * iteration of output is discarded.  So here there is really
 	 * no output available.  This forces another execution of alg_cn_1()
 	 * before any bytes can be extracted from the generator.
 	 */
 	rng->avail = 0;
+    } else if (bytes == BSIZE && memcmp(rng->XKEY, data, BSIZE) == 0) {
+	/* Should we add the error code SEC_ERROR_BAD_RNG_SEED? */
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	rv = SECFailure;
     } else {
-	/* Execute the algorithm from FIPS 186-2 Change Notice 1 */
-	rv = alg_fips186_2_cn_1(rng, inputhash);
+	/*
+	 * FIPS 186-2 does not specify how to reseed the RNG.  We retrofit
+	 * our RNG with a reseed function from NIST SP 800-90.
+	 *
+	 * Use a hash of the seed-key and the input to reseed the RNG.
+	 */
+	SHA256Context ctx;
+	SHA256_Begin(&ctx);
+	SHA256_Update(&ctx, rng->XKEY, BSIZE);
+	SHA256_Update(&ctx, data, bytes);
+	SHA256_End(&ctx, rng->XKEY, NULL, BSIZE);
     }
     /* If got this far, have added bytes of seed data. */
     if (rv == SECSuccess)
 	rng->seedCount += bytes;
     PZ_Unlock(rng->lock);
     /* --- UNLOCKED --- */
-    /* housekeeping */
-    memset(inputhash, 0, BSIZE);
     return rv;
 }
 
 /*
 ** Update the global random number generator with more seeding
 ** material.
 */
 SECStatus 
@@ -493,17 +480,17 @@ RNG_RandomUpdate(const void *data, size_
 {
     return prng_RandomUpdate(globalrng, data, bytes);
 }
 
 /*
 ** Generate some random bytes, using the global random number generator
 ** object.
 */
-SECStatus 
+static SECStatus 
 prng_GenerateGlobalRandomBytes(RNGContext *rng,
                                void *dest, size_t len)
 {
     PRUint8 num;
     SECStatus rv = SECSuccess;
     unsigned char *output = dest;
     /* check for a valid global RNG context */
     PORT_Assert(rng != NULL);
--- a/security/nss/lib/freebl/sha512.c
+++ b/security/nss/lib/freebl/sha512.c
@@ -40,16 +40,17 @@
 #include "prcpucfg.h"
 #if defined(_X86_) || defined(SHA_NO_LONG_LONG)
 #define NOUNROLL512 1
 #undef HAVE_LONG_LONG
 #endif
 #include "prtypes.h"	/* for PRUintXX */
 #include "secport.h"	/* for PORT_XXX */
 #include "blapi.h"
+#include "sha256.h"	/* for struct SHA256ContextStr */
 
 /* ============= Common constants and defines ======================= */
 
 #define W ctx->u.w
 #define B ctx->u.b
 #define H ctx->h
 
 #define SHR(x,n) (x >> n)
@@ -87,25 +88,16 @@ static const PRUint32 K256[64] = {
 };
 
 /* SHA-256 initial hash values */
 static const PRUint32 H256[8] = {
     0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 
     0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
 };
 
-struct SHA256ContextStr {
-    union {
-	PRUint32 w[64];	    /* message schedule, input buffer, plus 48 words */
-	PRUint8  b[256];
-    } u;
-    PRUint32 h[8];		/* 8 state variables */
-    PRUint32 sizeHi,sizeLo;	/* 64-bit count of hashed bytes. */
-};
-
 #if defined(_MSC_VER) && defined(_X86_)
 #ifndef FORCEINLINE
 #if (MSC_VER >= 1200)
 #define FORCEINLINE __forceinline
 #else
 #define FORCEINLINE __inline
 #endif
 #endif