summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/freebl/drbg.c
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@wolfbeast.com>2020-01-02 21:06:40 +0100
committerwolfbeast <mcwerewolf@wolfbeast.com>2020-01-02 21:06:40 +0100
commitf4a12fc67689a830e9da1c87fd11afe5bc09deb3 (patch)
tree211ae0cd022a6c11b0026ecc7761a550c584583c /security/nss/lib/freebl/drbg.c
parentf7d30133221896638f7bf4f66c504255c4b14f48 (diff)
downloadUXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar
UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar.gz
UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar.lz
UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.tar.xz
UXP-f4a12fc67689a830e9da1c87fd11afe5bc09deb3.zip
Issue #1338 - Part 2: Update NSS to 3.48-RTM
Diffstat (limited to 'security/nss/lib/freebl/drbg.c')
-rw-r--r--security/nss/lib/freebl/drbg.c99
1 files changed, 90 insertions, 9 deletions
diff --git a/security/nss/lib/freebl/drbg.c b/security/nss/lib/freebl/drbg.c
index 70ae2618e..85e9e61b6 100644
--- a/security/nss/lib/freebl/drbg.c
+++ b/security/nss/lib/freebl/drbg.c
@@ -30,6 +30,7 @@
#define PRNG_ADDITONAL_DATA_CACHE_SIZE (8 * 1024) /* must be less than \
* PRNG_MAX_ADDITIONAL_BYTES \
*/
+#define PRNG_ENTROPY_BLOCK_SIZE SHA256_LENGTH
/* RESEED_COUNT is how many calls to the prng before we need to reseed
* under normal NIST rules, you must return an error. In the NSS case, we
@@ -96,6 +97,8 @@ struct RNGContextStr {
PRUint32 additionalAvail;
PRBool isValid; /* false if RNG reaches an invalid state */
PRBool isKatTest; /* true if running NIST PRNG KAT tests */
+ /* for continuous entropy check */
+ PRUint8 previousEntropyHash[SHA256_LENGTH];
};
typedef struct RNGContextStr RNGContext;
@@ -169,6 +172,82 @@ prng_instantiate(RNGContext *rng, const PRUint8 *bytes, unsigned int len)
return SECSuccess;
}
+static PRCallOnceType coRNGInitEntropy;
+
+static PRStatus
+prng_initEntropy(void)
+{
+ size_t length;
+ PRUint8 block[PRNG_ENTROPY_BLOCK_SIZE];
+ SHA256Context ctx;
+
+ /* For FIPS 140-2 4.9.2 continuous random number generator test,
+ * fetch the initial entropy from the system RNG and keep it for
+ * later comparison. */
+ length = RNG_SystemRNG(block, sizeof(block));
+ if (length == 0) {
+ return PR_FAILURE; /* error is already set */
+ }
+ PORT_Assert(length == sizeof(block));
+
+ /* Store the hash of the entropy block rather than the block
+ * itself for backward secrecy. */
+ SHA256_Begin(&ctx);
+ SHA256_Update(&ctx, block, sizeof(block));
+ SHA256_End(&ctx, globalrng->previousEntropyHash, NULL,
+ sizeof(globalrng->previousEntropyHash));
+ PORT_Memset(block, 0, sizeof(block));
+ return PR_SUCCESS;
+}
+
+static SECStatus
+prng_getEntropy(PRUint8 *buffer, size_t requestLength)
+{
+ size_t total = 0;
+ PRUint8 block[PRNG_ENTROPY_BLOCK_SIZE];
+ PRUint8 hash[SHA256_LENGTH];
+ SHA256Context ctx;
+ SECStatus rv = SECSuccess;
+
+ if (PR_CallOnce(&coRNGInitEntropy, prng_initEntropy) != PR_SUCCESS) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ /* For FIPS 140-2 4.9.2 continuous random generator test,
+ * iteratively fetch fixed sized blocks from the system and
+ * compare consecutive blocks. */
+ while (total < requestLength) {
+ size_t length = RNG_SystemRNG(block, sizeof(block));
+ if (length == 0) {
+ rv = SECFailure; /* error is already set */
+ goto out;
+ }
+ PORT_Assert(length == sizeof(block));
+
+ /* Store the hash of the entropy block rather than the block
+ * itself for backward secrecy. */
+ SHA256_Begin(&ctx);
+ SHA256_Update(&ctx, block, sizeof(block));
+ SHA256_End(&ctx, hash, NULL, sizeof(hash));
+
+ if (PORT_Memcmp(globalrng->previousEntropyHash, hash, sizeof(hash)) == 0) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ rv = SECFailure;
+ goto out;
+ }
+ PORT_Memcpy(globalrng->previousEntropyHash, hash, sizeof(hash));
+ length = PR_MIN(requestLength - total, sizeof(block));
+ PORT_Memcpy(buffer, block, length);
+ total += length;
+ buffer += length;
+ }
+
+out:
+ PORT_Memset(block, 0, sizeof block);
+ return rv;
+}
+
/*
* Update the global random number generator with more seeding
* material. Use the Hash_DRBG reseed algorithm from NIST SP-800-90
@@ -182,11 +261,15 @@ prng_reseed(RNGContext *rng, const PRUint8 *entropy, unsigned int entropy_len,
{
PRUint8 noiseData[(sizeof rng->V_Data) + PRNG_SEEDLEN];
PRUint8 *noise = &noiseData[0];
+ SECStatus rv;
/* if entropy wasn't supplied, fetch it. (normal operation case) */
if (entropy == NULL) {
- entropy_len = (unsigned int)RNG_SystemRNG(
- &noiseData[sizeof rng->V_Data], PRNG_SEEDLEN);
+ entropy_len = PRNG_SEEDLEN;
+ rv = prng_getEntropy(&noiseData[sizeof rng->V_Data], entropy_len);
+ if (rv != SECSuccess) {
+ return SECFailure; /* error is already set */
+ }
} else {
/* NOTE: this code is only available for testing, not to applications */
/* if entropy was too big for the stack variable, get it from malloc */
@@ -384,7 +467,6 @@ static PRStatus
rng_init(void)
{
PRUint8 bytes[PRNG_SEEDLEN * 2]; /* entropy + nonce */
- unsigned int numBytes;
SECStatus rv = SECSuccess;
if (globalrng == NULL) {
@@ -403,18 +485,17 @@ rng_init(void)
}
/* Try to get some seed data for the RNG */
- numBytes = (unsigned int)RNG_SystemRNG(bytes, sizeof bytes);
- PORT_Assert(numBytes == 0 || numBytes == sizeof bytes);
- if (numBytes != 0) {
+ rv = prng_getEntropy(bytes, sizeof bytes);
+ if (rv == SECSuccess) {
/* if this is our first call, instantiate, otherwise reseed
* prng_instantiate gets a new clean state, we want to mix
* any previous entropy we may have collected */
if (V(globalrng)[0] == 0) {
- rv = prng_instantiate(globalrng, bytes, numBytes);
+ rv = prng_instantiate(globalrng, bytes, sizeof bytes);
} else {
- rv = prng_reseed_test(globalrng, bytes, numBytes, NULL, 0);
+ rv = prng_reseed_test(globalrng, bytes, sizeof bytes, NULL, 0);
}
- memset(bytes, 0, numBytes);
+ memset(bytes, 0, sizeof bytes);
} else {
PZ_DestroyLock(globalrng->lock);
globalrng->lock = NULL;