summaryrefslogtreecommitdiff
path: root/nss/lib/freebl/drbg.c
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-01-04 14:24:24 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-01-04 14:24:24 +0000
commitdc1565216a5d20ae0d75872151523252309a1292 (patch)
treed57454ba9a40386552179eddf60d28bd1e8f3d54 /nss/lib/freebl/drbg.c
parent26c046fbc57d53136b4fb3b5e0d18298318125d4 (diff)
downloadnss-dc1565216a5d20ae0d75872151523252309a1292.tar.gz
nss-3.28.1nss-3.28.1
Diffstat (limited to 'nss/lib/freebl/drbg.c')
-rw-r--r--nss/lib/freebl/drbg.c1045
1 files changed, 539 insertions, 506 deletions
diff --git a/nss/lib/freebl/drbg.c b/nss/lib/freebl/drbg.c
index 391d456..658faa3 100644
--- a/nss/lib/freebl/drbg.c
+++ b/nss/lib/freebl/drbg.c
@@ -17,24 +17,28 @@
#include "secitem.h"
#include "sha_fast.h"
#include "sha256.h"
-#include "secrng.h" /* for RNG_SystemRNG() */
+#include "secrng.h" /* for RNG_SystemRNG() */
#include "secmpi.h"
-/* PRNG_SEEDLEN defined in NIST SP 800-90 section 10.1
+#ifdef UNSAFE_FUZZER_MODE
+#include "det_rng.h"
+#endif
+
+/* PRNG_SEEDLEN defined in NIST SP 800-90 section 10.1
* for SHA-1, SHA-224, and SHA-256 it's 440 bits.
* for SHA-384 and SHA-512 it's 888 bits */
-#define PRNG_SEEDLEN (440/PR_BITS_PER_BYTE)
+#define PRNG_SEEDLEN (440 / PR_BITS_PER_BYTE)
#define PRNG_MAX_ADDITIONAL_BYTES PR_INT64(0x100000000)
- /* 2^35 bits or 2^32 bytes */
-#define PRNG_MAX_REQUEST_SIZE 0x10000 /* 2^19 bits or 2^16 bytes */
-#define PRNG_ADDITONAL_DATA_CACHE_SIZE (8*1024) /* must be less than
- * PRNG_MAX_ADDITIONAL_BYTES
- */
+/* 2^35 bits or 2^32 bytes */
+#define PRNG_MAX_REQUEST_SIZE 0x10000 /* 2^19 bits or 2^16 bytes */
+#define PRNG_ADDITONAL_DATA_CACHE_SIZE (8 * 1024) /* must be less than \
+ * PRNG_MAX_ADDITIONAL_BYTES \
+ */
-/* RESEED_COUNT is how many calls to the prng before we need to reseed
+/* 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
* self-reseed with RNG_SystemRNG(). Count can be a large number. For code
- * simplicity, we specify count with 2 components: RESEED_BYTE (which is
+ * simplicity, we specify count with 2 components: RESEED_BYTE (which is
* the same as LOG256(RESEED_COUNT)) and RESEED_VALUE (which is the same as
* RESEED_COUNT / (256 ^ RESEED_BYTE)). Another way to look at this is
* RESEED_COUNT = RESEED_VALUE * (256 ^ RESEED_BYTE). For Hash based DRBG
@@ -43,67 +47,65 @@
#define RESEED_BYTE 6
#define RESEED_VALUE 1
-#define PRNG_RESET_RESEED_COUNT(rng) \
- PORT_Memset((rng)->reseed_counter, 0, sizeof (rng)->reseed_counter); \
- (rng)->reseed_counter[RESEED_BYTE] = 1;
-
+#define PRNG_RESET_RESEED_COUNT(rng) \
+ PORT_Memset((rng)->reseed_counter, 0, sizeof(rng)->reseed_counter); \
+ (rng)->reseed_counter[RESEED_BYTE] = 1;
/*
* The actual values of this enum are specified in SP 800-90, 10.1.1.*
- * The spec does not name the types, it only uses bare values
+ * The spec does not name the types, it only uses bare values
*/
typedef enum {
- prngCGenerateType = 0, /* used when creating a new 'C' */
- prngReseedType = 1, /* used in reseeding */
- prngAdditionalDataType = 2, /* used in mixing additional data */
- prngGenerateByteType = 3 /* used when mixing internal state while
- * generating bytes */
+ prngCGenerateType = 0, /* used when creating a new 'C' */
+ prngReseedType = 1, /* used in reseeding */
+ prngAdditionalDataType = 2, /* used in mixing additional data */
+ prngGenerateByteType = 3 /* used when mixing internal state while
+ * generating bytes */
} prngVTypes;
/*
* Global RNG context
- */
+ */
struct RNGContextStr {
- PZLock *lock; /* Lock to serialize access to global rng */
+ PZLock *lock; /* Lock to serialize access to global rng */
/*
- * NOTE, a number of steps in the drbg algorithm need to hash
- * V_type || V. The code, therefore, depends on the V array following
+ * NOTE, a number of steps in the drbg algorithm need to hash
+ * V_type || V. The code, therefore, depends on the V array following
* immediately after V_type to avoid extra copies. To accomplish this
* in a way that compiliers can't perturb, we declare V_type and V
* as a V_Data array and reference them by macros */
- PRUint8 V_Data[PRNG_SEEDLEN+1]; /* internal state variables */
-#define V_type V_Data[0]
-#define V(rng) (((rng)->V_Data)+1)
-#define VSize(rng) ((sizeof (rng)->V_Data) -1)
- PRUint8 C[PRNG_SEEDLEN]; /* internal state variables */
- PRUint8 oldV[PRNG_SEEDLEN]; /* for continuous rng checking */
+ PRUint8 V_Data[PRNG_SEEDLEN + 1]; /* internal state variables */
+#define V_type V_Data[0]
+#define V(rng) (((rng)->V_Data) + 1)
+#define VSize(rng) ((sizeof(rng)->V_Data) - 1)
+ PRUint8 C[PRNG_SEEDLEN]; /* internal state variables */
+ PRUint8 lastOutput[SHA256_LENGTH]; /* for continuous rng checking */
/* If we get calls for the PRNG to return less than the length of our
* hash, we extend the request for a full hash (since we'll be doing
* the full hash anyway). Future requests for random numbers are fulfilled
* from the remainder of the bytes we generated. Requests for bytes longer
* than the hash size are fulfilled directly from the HashGen function
* of the random number generator. */
- PRUint8 reseed_counter[RESEED_BYTE+1]; /* number of requests since the
- * last reseed. Need only be
- * big enough to hold the whole
- * reseed count */
- PRUint8 data[SHA256_LENGTH]; /* when we request less than a block
- * save the rest of the rng output for
- * another partial block */
- PRUint8 dataAvail; /* # bytes of output available in our cache,
- * [0...SHA256_LENGTH] */
+ PRUint8 reseed_counter[RESEED_BYTE + 1]; /* number of requests since the
+ * last reseed. Need only be
+ * big enough to hold the whole
+ * reseed count */
+ PRUint8 data[SHA256_LENGTH]; /* when we request less than a block
+ * save the rest of the rng output for
+ * another partial block */
+ PRUint8 dataAvail; /* # bytes of output available in our cache,
+ * [0...SHA256_LENGTH] */
/* store additional data that has been shovelled off to us by
* RNG_RandomUpdate. */
- PRUint8 additionalDataCache[PRNG_ADDITONAL_DATA_CACHE_SIZE];
+ PRUint8 additionalDataCache[PRNG_ADDITONAL_DATA_CACHE_SIZE];
PRUint32 additionalAvail;
- PRBool isValid; /* false if RNG reaches an invalid state */
+ PRBool isValid; /* false if RNG reaches an invalid state */
};
typedef struct RNGContextStr RNGContext;
static RNGContext *globalrng = NULL;
static RNGContext theGlobalRng;
-
/*
* The next several functions are derived from the NIST SP 800-90
* spec. In these functions, an attempt was made to use names consistent
@@ -113,41 +115,40 @@ static RNGContext theGlobalRng;
/*
* Hash Derive function defined in NISP SP 800-90 Section 10.4.1.
* This function is used in the Instantiate and Reseed functions.
- *
+ *
* NOTE: requested_bytes cannot overlap with input_string_1 or input_string_2.
- * input_string_1 and input_string_2 are logically concatentated.
+ * input_string_1 and input_string_2 are logically concatentated.
* input_string_1 must be supplied.
* if input_string_2 is not supplied, NULL should be passed for this parameter.
*/
static SECStatus
-prng_Hash_df(PRUint8 *requested_bytes, unsigned int no_of_bytes_to_return,
- const PRUint8 *input_string_1, unsigned int input_string_1_len,
- const PRUint8 *input_string_2, unsigned int input_string_2_len)
+prng_Hash_df(PRUint8 *requested_bytes, unsigned int no_of_bytes_to_return,
+ const PRUint8 *input_string_1, unsigned int input_string_1_len,
+ const PRUint8 *input_string_2, unsigned int input_string_2_len)
{
SHA256Context ctx;
PRUint32 tmp;
PRUint8 counter;
- tmp=SHA_HTONL(no_of_bytes_to_return*8);
-
- for (counter = 1 ; no_of_bytes_to_return > 0; counter++) {
- unsigned int hash_return_len;
- SHA256_Begin(&ctx);
- SHA256_Update(&ctx, &counter, 1);
- SHA256_Update(&ctx, (unsigned char *)&tmp, sizeof tmp);
- SHA256_Update(&ctx, input_string_1, input_string_1_len);
- if (input_string_2) {
- SHA256_Update(&ctx, input_string_2, input_string_2_len);
- }
- SHA256_End(&ctx, requested_bytes, &hash_return_len,
- no_of_bytes_to_return);
- requested_bytes += hash_return_len;
- no_of_bytes_to_return -= hash_return_len;
+ tmp = SHA_HTONL(no_of_bytes_to_return * 8);
+
+ for (counter = 1; no_of_bytes_to_return > 0; counter++) {
+ unsigned int hash_return_len;
+ SHA256_Begin(&ctx);
+ SHA256_Update(&ctx, &counter, 1);
+ SHA256_Update(&ctx, (unsigned char *)&tmp, sizeof tmp);
+ SHA256_Update(&ctx, input_string_1, input_string_1_len);
+ if (input_string_2) {
+ SHA256_Update(&ctx, input_string_2, input_string_2_len);
+ }
+ SHA256_End(&ctx, requested_bytes, &hash_return_len,
+ no_of_bytes_to_return);
+ requested_bytes += hash_return_len;
+ no_of_bytes_to_return -= hash_return_len;
}
return SECSuccess;
}
-
/*
* Hash_DRBG Instantiate NIST SP 800-80 10.1.1.2
*
@@ -158,18 +159,17 @@ static SECStatus
prng_instantiate(RNGContext *rng, const PRUint8 *bytes, unsigned int len)
{
if (len < PRNG_SEEDLEN) {
- /* if the seedlen is to small, it's probably because we failed to get
- * enough random data */
- PORT_SetError(SEC_ERROR_NEED_RANDOM);
- return SECFailure;
+ /* if the seedlen is to small, it's probably because we failed to get
+ * enough random data */
+ PORT_SetError(SEC_ERROR_NEED_RANDOM);
+ return SECFailure;
}
prng_Hash_df(V(rng), VSize(rng), bytes, len, NULL, 0);
rng->V_type = prngCGenerateType;
- prng_Hash_df(rng->C,sizeof rng->C,rng->V_Data,sizeof rng->V_Data,NULL,0);
+ prng_Hash_df(rng->C, sizeof rng->C, rng->V_Data, sizeof rng->V_Data, NULL, 0);
PRNG_RESET_RESEED_COUNT(rng)
return SECSuccess;
}
-
/*
* Update the global random number generator with more seeding
@@ -180,45 +180,45 @@ prng_instantiate(RNGContext *rng, const PRUint8 *bytes, unsigned int len)
*/
static SECStatus
prng_reseed(RNGContext *rng, const PRUint8 *entropy, unsigned int entropy_len,
- const PRUint8 *additional_input, unsigned int additional_input_len)
+ const PRUint8 *additional_input, unsigned int additional_input_len)
{
- PRUint8 noiseData[(sizeof rng->V_Data)+PRNG_SEEDLEN];
+ PRUint8 noiseData[(sizeof rng->V_Data) + PRNG_SEEDLEN];
PRUint8 *noise = &noiseData[0];
/* 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 = (unsigned int)RNG_SystemRNG(
+ &noiseData[sizeof rng->V_Data], PRNG_SEEDLEN);
} 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 */
- if (entropy_len > PRNG_SEEDLEN) {
- noise = PORT_Alloc(entropy_len + (sizeof rng->V_Data));
- if (noise == NULL) {
- return SECFailure;
- }
- }
- PORT_Memcpy(&noise[sizeof rng->V_Data],entropy, entropy_len);
+ /* NOTE: this code is only available for testing, not to applications */
+ /* if entropy was too big for the stack variable, get it from malloc */
+ if (entropy_len > PRNG_SEEDLEN) {
+ noise = PORT_Alloc(entropy_len + (sizeof rng->V_Data));
+ if (noise == NULL) {
+ return SECFailure;
+ }
+ }
+ PORT_Memcpy(&noise[sizeof rng->V_Data], entropy, entropy_len);
}
- if (entropy_len < 256/PR_BITS_PER_BYTE) {
- /* noise == &noiseData[0] at this point, so nothing to free */
- PORT_SetError(SEC_ERROR_NEED_RANDOM);
- return SECFailure;
+ if (entropy_len < 256 / PR_BITS_PER_BYTE) {
+ /* noise == &noiseData[0] at this point, so nothing to free */
+ PORT_SetError(SEC_ERROR_NEED_RANDOM);
+ return SECFailure;
}
rng->V_type = prngReseedType;
PORT_Memcpy(noise, rng->V_Data, sizeof rng->V_Data);
prng_Hash_df(V(rng), VSize(rng), noise, (sizeof rng->V_Data) + entropy_len,
- additional_input, additional_input_len);
+ additional_input, additional_input_len);
/* clear potential CSP */
- PORT_Memset(noise, 0, (sizeof rng->V_Data) + entropy_len);
+ PORT_Memset(noise, 0, (sizeof rng->V_Data) + entropy_len);
rng->V_type = prngCGenerateType;
- prng_Hash_df(rng->C,sizeof rng->C,rng->V_Data,sizeof rng->V_Data,NULL,0);
+ prng_Hash_df(rng->C, sizeof rng->C, rng->V_Data, sizeof rng->V_Data, NULL, 0);
PRNG_RESET_RESEED_COUNT(rng)
if (noise != &noiseData[0]) {
- PORT_Free(noise);
+ PORT_Free(noise);
}
return SECSuccess;
}
@@ -227,148 +227,165 @@ prng_reseed(RNGContext *rng, const PRUint8 *entropy, unsigned int entropy_len,
* SP 800-90 requires we rerun our health tests on reseed
*/
static SECStatus
-prng_reseed_test(RNGContext *rng, const PRUint8 *entropy,
- unsigned int entropy_len, const PRUint8 *additional_input,
- unsigned int additional_input_len)
+prng_reseed_test(RNGContext *rng, const PRUint8 *entropy,
+ unsigned int entropy_len, const PRUint8 *additional_input,
+ unsigned int additional_input_len)
{
SECStatus rv;
/* do health checks in FIPS mode */
rv = PRNGTEST_RunHealthTests();
if (rv != SECSuccess) {
- /* error set by PRNGTEST_RunHealTests() */
- rng->isValid = PR_FALSE;
- return SECFailure;
+ /* error set by PRNGTEST_RunHealTests() */
+ rng->isValid = PR_FALSE;
+ return SECFailure;
}
- return prng_reseed(rng, entropy, entropy_len,
- additional_input, additional_input_len);
+ return prng_reseed(rng, entropy, entropy_len,
+ additional_input, additional_input_len);
}
/*
* build some fast inline functions for adding.
*/
-#define PRNG_ADD_CARRY_ONLY(dest, start, carry) \
- { \
- int k1; \
+#define PRNG_ADD_CARRY_ONLY(dest, start, carry) \
+ { \
+ int k1; \
for (k1 = start; carry && k1 >= 0; k1--) { \
- carry = !(++dest[k1]); \
- } \
+ carry = !(++dest[k1]); \
+ } \
}
/*
* NOTE: dest must be an array for the following to work.
*/
-#define PRNG_ADD_BITS(dest, dest_len, add, len, carry) \
- carry = 0; \
- PORT_Assert((dest_len) >= (len)); \
- { \
- int k1, k2; \
+#define PRNG_ADD_BITS(dest, dest_len, add, len, carry) \
+ carry = 0; \
+ PORT_Assert((dest_len) >= (len)); \
+ { \
+ int k1, k2; \
for (k1 = dest_len - 1, k2 = len - 1; k2 >= 0; --k1, --k2) { \
- carry += dest[k1] + add[k2]; \
- dest[k1] = (PRUint8) carry; \
- carry >>= 8; \
- } \
+ carry += dest[k1] + add[k2]; \
+ dest[k1] = (PRUint8)carry; \
+ carry >>= 8; \
+ } \
}
#define PRNG_ADD_BITS_AND_CARRY(dest, dest_len, add, len, carry) \
- PRNG_ADD_BITS(dest, dest_len, add, len, carry) \
+ PRNG_ADD_BITS(dest, dest_len, add, len, carry) \
PRNG_ADD_CARRY_ONLY(dest, dest_len - len, carry)
/*
* This function expands the internal state of the prng to fulfill any number
* of bytes we need for this request. We only use this call if we need more
- * than can be supplied by a single call to SHA256_HashBuf.
+ * than can be supplied by a single call to SHA256_HashBuf.
*
* This function is specified in NIST SP 800-90 section 10.1.1.4, Hashgen
*/
static void
-prng_Hashgen(RNGContext *rng, PRUint8 *returned_bytes,
- unsigned int no_of_returned_bytes)
+prng_Hashgen(RNGContext *rng, PRUint8 *returned_bytes,
+ unsigned int no_of_returned_bytes)
{
PRUint8 data[VSize(rng)];
+ PRUint8 thisHash[SHA256_LENGTH];
+ PRUint8 *lastHash = rng->lastOutput;
PORT_Memcpy(data, V(rng), VSize(rng));
while (no_of_returned_bytes) {
- SHA256Context ctx;
- unsigned int len;
- unsigned int carry;
-
- SHA256_Begin(&ctx);
- SHA256_Update(&ctx, data, sizeof data);
- SHA256_End(&ctx, returned_bytes, &len, no_of_returned_bytes);
- returned_bytes += len;
- no_of_returned_bytes -= len;
- /* The carry parameter is a bool (increment or not).
- * This increments data if no_of_returned_bytes is not zero */
+ SHA256Context ctx;
+ unsigned int len;
+ unsigned int carry;
+
+ SHA256_Begin(&ctx);
+ SHA256_Update(&ctx, data, sizeof data);
+ SHA256_End(&ctx, thisHash, &len, SHA256_LENGTH);
+ if (PORT_Memcmp(lastHash, thisHash, len) == 0) {
+ rng->isValid = PR_FALSE;
+ break;
+ }
+ if (no_of_returned_bytes < SHA256_LENGTH) {
+ len = no_of_returned_bytes;
+ }
+ PORT_Memcpy(returned_bytes, thisHash, len);
+ lastHash = returned_bytes;
+ returned_bytes += len;
+ no_of_returned_bytes -= len;
+ /* The carry parameter is a bool (increment or not).
+ * This increments data if no_of_returned_bytes is not zero */
carry = no_of_returned_bytes;
- PRNG_ADD_CARRY_ONLY(data, (sizeof data)- 1, carry);
+ PRNG_ADD_CARRY_ONLY(data, (sizeof data) - 1, carry);
}
- PORT_Memset(data, 0, sizeof data);
+ PORT_Memcpy(rng->lastOutput, thisHash, SHA256_LENGTH);
+ PORT_Memset(data, 0, sizeof data);
+ PORT_Memset(thisHash, 0, sizeof thisHash);
}
-/*
- * Generates new random bytes and advances the internal prng state.
+/*
+ * Generates new random bytes and advances the internal prng state.
* additional bytes are only used in algorithm testing.
- *
+ *
* This function is specified in NIST SP 800-90 section 10.1.1.4
*/
static SECStatus
-prng_generateNewBytes(RNGContext *rng,
- PRUint8 *returned_bytes, unsigned int no_of_returned_bytes,
- const PRUint8 *additional_input,
- unsigned int additional_input_len)
+prng_generateNewBytes(RNGContext *rng,
+ PRUint8 *returned_bytes, unsigned int no_of_returned_bytes,
+ const PRUint8 *additional_input,
+ unsigned int additional_input_len)
{
- PRUint8 H[SHA256_LENGTH]; /* both H and w since they
- * aren't used concurrently */
+ PRUint8 H[SHA256_LENGTH]; /* both H and w since they
+ * aren't used concurrently */
unsigned int carry;
if (!rng->isValid) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
}
/* This code only triggers during tests, normal
* prng operation does not use additional_input */
- if (additional_input){
- SHA256Context ctx;
- /* NIST SP 800-90 defines two temporaries in their calculations,
- * w and H. These temporaries are the same lengths, and used
- * at different times, so we use the following macro to collapse
- * them to the same variable, but keeping their unique names for
- * easy comparison to the spec */
+ if (additional_input) {
+ SHA256Context ctx;
+/* NIST SP 800-90 defines two temporaries in their calculations,
+ * w and H. These temporaries are the same lengths, and used
+ * at different times, so we use the following macro to collapse
+ * them to the same variable, but keeping their unique names for
+ * easy comparison to the spec */
#define w H
- rng->V_type = prngAdditionalDataType;
- SHA256_Begin(&ctx);
- SHA256_Update(&ctx, rng->V_Data, sizeof rng->V_Data);
- SHA256_Update(&ctx, additional_input, additional_input_len);
- SHA256_End(&ctx, w, NULL, sizeof w);
- PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), w, sizeof w, carry)
- PORT_Memset(w, 0, sizeof w);
-#undef w
+ rng->V_type = prngAdditionalDataType;
+ SHA256_Begin(&ctx);
+ SHA256_Update(&ctx, rng->V_Data, sizeof rng->V_Data);
+ SHA256_Update(&ctx, additional_input, additional_input_len);
+ SHA256_End(&ctx, w, NULL, sizeof w);
+ PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), w, sizeof w, carry)
+ PORT_Memset(w, 0, sizeof w);
+#undef w
}
if (no_of_returned_bytes == SHA256_LENGTH) {
- /* short_cut to hashbuf and save a copy and a clear */
- SHA256_HashBuf(returned_bytes, V(rng), VSize(rng) );
+ /* short_cut to hashbuf and a couple of copies and clears */
+ SHA256_HashBuf(returned_bytes, V(rng), VSize(rng));
+ /* continuous rng check */
+ if (memcmp(rng->lastOutput, returned_bytes, SHA256_LENGTH) == 0) {
+ rng->isValid = PR_FALSE;
+ }
+ PORT_Memcpy(rng->lastOutput, returned_bytes, sizeof rng->lastOutput);
} else {
- prng_Hashgen(rng, returned_bytes, no_of_returned_bytes);
+ prng_Hashgen(rng, returned_bytes, no_of_returned_bytes);
}
/* advance our internal state... */
rng->V_type = prngGenerateByteType;
SHA256_HashBuf(H, rng->V_Data, sizeof rng->V_Data);
PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), H, sizeof H, carry)
PRNG_ADD_BITS(V(rng), VSize(rng), rng->C, sizeof rng->C, carry);
- PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), rng->reseed_counter,
- sizeof rng->reseed_counter, carry)
+ PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), rng->reseed_counter,
+ sizeof rng->reseed_counter, carry)
carry = 1;
- PRNG_ADD_CARRY_ONLY(rng->reseed_counter,(sizeof rng->reseed_counter)-1, carry);
+ PRNG_ADD_CARRY_ONLY(rng->reseed_counter, (sizeof rng->reseed_counter) - 1, carry);
- /* continuous rng check */
- if (memcmp(V(rng), rng->oldV, sizeof rng->oldV) == 0) {
- rng->isValid = PR_FALSE;
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
+ /* if the prng failed, don't return any output, signal softoken */
+ if (!rng->isValid) {
+ PORT_Memset(returned_bytes, 0, no_of_returned_bytes);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
}
- PORT_Memcpy(rng->oldV, V(rng), sizeof rng->oldV);
return SECSuccess;
}
@@ -377,59 +394,60 @@ prng_generateNewBytes(RNGContext *rng,
*/
static const PRCallOnceType pristineCallOnce;
static PRCallOnceType coRNGInit;
-static PRStatus rng_init(void)
+static PRStatus
+rng_init(void)
{
- PRUint8 bytes[PRNG_SEEDLEN*2]; /* entropy + nonce */
+ PRUint8 bytes[PRNG_SEEDLEN * 2]; /* entropy + nonce */
unsigned int numBytes;
SECStatus rv = SECSuccess;
if (globalrng == NULL) {
- /* bytes needs to have enough space to hold
- * a SHA256 hash value. Blow up at compile time if this isn't true */
- PR_STATIC_ASSERT(sizeof(bytes) >= SHA256_LENGTH);
- /* create a new global RNG context */
- globalrng = &theGlobalRng;
+ /* bytes needs to have enough space to hold
+ * a SHA256 hash value. Blow up at compile time if this isn't true */
+ PR_STATIC_ASSERT(sizeof(bytes) >= SHA256_LENGTH);
+ /* create a new global RNG context */
+ globalrng = &theGlobalRng;
PORT_Assert(NULL == globalrng->lock);
- /* create a lock for it */
- globalrng->lock = PZ_NewLock(nssILockOther);
- if (globalrng->lock == NULL) {
- globalrng = NULL;
- PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
- return PR_FAILURE;
- }
-
- /* 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) {
- /* 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);
- } else {
- rv = prng_reseed_test(globalrng, bytes, numBytes, NULL, 0);
- }
- memset(bytes, 0, numBytes);
- } else {
- PZ_DestroyLock(globalrng->lock);
- globalrng->lock = NULL;
- globalrng = NULL;
- return PR_FAILURE;
- }
-
- if (rv != SECSuccess) {
- return PR_FAILURE;
- }
- /* the RNG is in a valid state */
- globalrng->isValid = PR_TRUE;
-
- /* fetch one random value so that we can populate rng->oldV for our
- * continous random number test. */
- prng_generateNewBytes(globalrng, bytes, SHA256_LENGTH, NULL, 0);
-
- /* Fetch more entropy into the PRNG */
- RNG_SystemInfoForRNG();
+ /* create a lock for it */
+ globalrng->lock = PZ_NewLock(nssILockOther);
+ if (globalrng->lock == NULL) {
+ globalrng = NULL;
+ PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
+ return PR_FAILURE;
+ }
+
+ /* 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) {
+ /* 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);
+ } else {
+ rv = prng_reseed_test(globalrng, bytes, numBytes, NULL, 0);
+ }
+ memset(bytes, 0, numBytes);
+ } else {
+ PZ_DestroyLock(globalrng->lock);
+ globalrng->lock = NULL;
+ globalrng = NULL;
+ return PR_FAILURE;
+ }
+
+ if (rv != SECSuccess) {
+ return PR_FAILURE;
+ }
+ /* the RNG is in a valid state */
+ globalrng->isValid = PR_TRUE;
+
+ /* fetch one random value so that we can populate rng->oldV for our
+ * continous random number test. */
+ prng_generateNewBytes(globalrng, bytes, SHA256_LENGTH, NULL, 0);
+
+ /* Fetch more entropy into the PRNG */
+ RNG_SystemInfoForRNG();
}
return PR_SUCCESS;
}
@@ -446,12 +464,12 @@ prng_freeRNGContext(RNGContext *rng)
SKIP_AFTER_FORK(PZ_DestroyLock(globalrng->lock));
/* zero global RNG context except for C & V to preserve entropy */
- prng_Hash_df(inputhash, sizeof rng->C, rng->C, sizeof rng->C, NULL, 0);
- prng_Hash_df(&inputhash[sizeof rng->C], VSize(rng), V(rng), VSize(rng),
- NULL, 0);
+ prng_Hash_df(inputhash, sizeof rng->C, rng->C, sizeof rng->C, NULL, 0);
+ prng_Hash_df(&inputhash[sizeof rng->C], VSize(rng), V(rng), VSize(rng),
+ NULL, 0);
memset(rng, 0, sizeof *rng);
- memcpy(rng->C, inputhash, sizeof rng->C);
- memcpy(V(rng), &inputhash[sizeof rng->C], VSize(rng));
+ memcpy(rng->C, inputhash, sizeof rng->C);
+ memcpy(V(rng), &inputhash[sizeof rng->C], VSize(rng));
memset(inputhash, 0, sizeof inputhash);
}
@@ -469,7 +487,7 @@ prng_freeRNGContext(RNGContext *rng)
* provide the generator with additional entropy is to call
* RNG_SystemInfoForRNG(). Note that C_Initialize() does exactly that.
*/
-SECStatus
+SECStatus
RNG_RNGInit(void)
{
/* Allow only one call to initialize the context */
@@ -482,7 +500,7 @@ RNG_RNGInit(void)
** Update the global random number generator with more seeding
** material.
*/
-SECStatus
+SECStatus
RNG_RandomUpdate(const void *data, size_t bytes)
{
SECStatus rv;
@@ -501,23 +519,23 @@ RNG_RandomUpdate(const void *data, size_t bytes)
* greater than 32 bits if it is a 64 bit platform. The corner
* cases are handled with explicit defines NS_PTR_GT_32 and NS_PTR_LE_32.
*
- * In general, neither NS_PTR_GT_32 nor NS_PTR_LE_32 will need to be
+ * In general, neither NS_PTR_GT_32 nor NS_PTR_LE_32 will need to be
* defined. If you trip over the next two size ASSERTS at compile time,
* you will need to define them for your platform.
*
* if 'sizeof(size_t) > 4' is triggered it means that we were expecting
- * sizeof(size_t) to be greater than 4, but it wasn't. Setting
+ * sizeof(size_t) to be greater than 4, but it wasn't. Setting
* NS_PTR_LE_32 will correct that mistake.
*
* if 'sizeof(size_t) <= 4' is triggered, it means that we were expecting
- * sizeof(size_t) to be less than or equal to 4, but it wasn't. Setting
+ * sizeof(size_t) to be less than or equal to 4, but it wasn't. Setting
* NS_PTR_GT_32 will correct that mistake.
*/
PR_STATIC_ASSERT(sizeof(size_t) > 4);
if (bytes > (size_t)PRNG_MAX_ADDITIONAL_BYTES) {
- bytes = PRNG_MAX_ADDITIONAL_BYTES;
+ bytes = PRNG_MAX_ADDITIONAL_BYTES;
}
#else
PR_STATIC_ASSERT(sizeof(size_t) <= 4);
@@ -526,41 +544,38 @@ RNG_RandomUpdate(const void *data, size_t bytes)
PZ_Lock(globalrng->lock);
/* if we're passed more than our additionalDataCache, simply
* call reseed with that data */
- if (bytes > sizeof (globalrng->additionalDataCache)) {
- rv = prng_reseed_test(globalrng, NULL, 0, data, (unsigned int) bytes);
- /* if we aren't going to fill or overflow the buffer, just cache it */
- } else if (bytes < ((sizeof globalrng->additionalDataCache)
- - globalrng->additionalAvail)) {
- PORT_Memcpy(globalrng->additionalDataCache+globalrng->additionalAvail,
- data, bytes);
- globalrng->additionalAvail += (PRUint32) bytes;
- rv = SECSuccess;
+ if (bytes > sizeof(globalrng->additionalDataCache)) {
+ rv = prng_reseed_test(globalrng, NULL, 0, data, (unsigned int)bytes);
+ /* if we aren't going to fill or overflow the buffer, just cache it */
+ } else if (bytes < ((sizeof globalrng->additionalDataCache) - globalrng->additionalAvail)) {
+ PORT_Memcpy(globalrng->additionalDataCache + globalrng->additionalAvail,
+ data, bytes);
+ globalrng->additionalAvail += (PRUint32)bytes;
+ rv = SECSuccess;
} else {
- /* we are going to fill or overflow the buffer. In this case we will
- * fill the entropy buffer, reseed with it, start a new buffer with the
- * remainder. We know the remainder will fit in the buffer because
- * we already handled the case where bytes > the size of the buffer.
- */
- size_t bufRemain = (sizeof globalrng->additionalDataCache)
- - globalrng->additionalAvail;
- /* fill the rest of the buffer */
- if (bufRemain) {
- PORT_Memcpy(globalrng->additionalDataCache
- +globalrng->additionalAvail,
- data, bufRemain);
- data = ((unsigned char *)data) + bufRemain;
- bytes -= bufRemain;
- }
- /* reseed from buffer */
- rv = prng_reseed_test(globalrng, NULL, 0,
- globalrng->additionalDataCache,
- sizeof globalrng->additionalDataCache);
-
- /* copy the rest into the cache */
- PORT_Memcpy(globalrng->additionalDataCache, data, bytes);
- globalrng->additionalAvail = (PRUint32) bytes;
- }
-
+ /* we are going to fill or overflow the buffer. In this case we will
+ * fill the entropy buffer, reseed with it, start a new buffer with the
+ * remainder. We know the remainder will fit in the buffer because
+ * we already handled the case where bytes > the size of the buffer.
+ */
+ size_t bufRemain = (sizeof globalrng->additionalDataCache) - globalrng->additionalAvail;
+ /* fill the rest of the buffer */
+ if (bufRemain) {
+ PORT_Memcpy(globalrng->additionalDataCache + globalrng->additionalAvail,
+ data, bufRemain);
+ data = ((unsigned char *)data) + bufRemain;
+ bytes -= bufRemain;
+ }
+ /* reseed from buffer */
+ rv = prng_reseed_test(globalrng, NULL, 0,
+ globalrng->additionalDataCache,
+ sizeof globalrng->additionalDataCache);
+
+ /* copy the rest into the cache */
+ PORT_Memcpy(globalrng->additionalDataCache, data, bytes);
+ globalrng->additionalAvail = (PRUint32)bytes;
+ }
+
PZ_Unlock(globalrng->lock);
return rv;
}
@@ -569,7 +584,7 @@ RNG_RandomUpdate(const void *data, size_t bytes)
** Generate some random bytes, using the global random number generator
** object.
*/
-static SECStatus
+static SECStatus
prng_GenerateGlobalRandomBytes(RNGContext *rng,
void *dest, size_t len)
{
@@ -578,13 +593,13 @@ prng_GenerateGlobalRandomBytes(RNGContext *rng,
/* check for a valid global RNG context */
PORT_Assert(rng != NULL);
if (rng == NULL) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
}
/* FIPS limits the amount of entropy available in a single request */
if (len > PRNG_MAX_REQUEST_SIZE) {
- PORT_SetError(SEC_ERROR_INVALID_ARGS);
- return SECFailure;
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
}
/* --- LOCKED --- */
PZ_Lock(rng->lock);
@@ -592,40 +607,40 @@ prng_GenerateGlobalRandomBytes(RNGContext *rng,
* don't produce any data.
*/
if (rng->reseed_counter[0] >= RESEED_VALUE) {
- rv = prng_reseed_test(rng, NULL, 0, NULL, 0);
- PZ_Unlock(rng->lock);
- if (rv != SECSuccess) {
- return rv;
- }
- RNG_SystemInfoForRNG();
- PZ_Lock(rng->lock);
+ rv = prng_reseed_test(rng, NULL, 0, NULL, 0);
+ PZ_Unlock(rng->lock);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ RNG_SystemInfoForRNG();
+ PZ_Lock(rng->lock);
}
/*
* see if we have enough bytes to fulfill the request.
*/
if (len <= rng->dataAvail) {
- memcpy(output, rng->data + ((sizeof rng->data) - rng->dataAvail), len);
- memset(rng->data + ((sizeof rng->data) - rng->dataAvail), 0, len);
- rng->dataAvail -= len;
- rv = SECSuccess;
- /* if we are asking for a small number of bytes, cache the rest of
+ memcpy(output, rng->data + ((sizeof rng->data) - rng->dataAvail), len);
+ memset(rng->data + ((sizeof rng->data) - rng->dataAvail), 0, len);
+ rng->dataAvail -= len;
+ rv = SECSuccess;
+ /* if we are asking for a small number of bytes, cache the rest of
* the bytes */
} else if (len < sizeof rng->data) {
- rv = prng_generateNewBytes(rng, rng->data, sizeof rng->data,
- rng->additionalAvail ? rng->additionalDataCache : NULL,
- rng->additionalAvail);
- rng->additionalAvail = 0;
- if (rv == SECSuccess) {
- memcpy(output, rng->data, len);
- memset(rng->data, 0, len);
- rng->dataAvail = (sizeof rng->data) - len;
- }
- /* we are asking for lots of bytes, just ask the generator to pass them */
+ rv = prng_generateNewBytes(rng, rng->data, sizeof rng->data,
+ rng->additionalAvail ? rng->additionalDataCache : NULL,
+ rng->additionalAvail);
+ rng->additionalAvail = 0;
+ if (rv == SECSuccess) {
+ memcpy(output, rng->data, len);
+ memset(rng->data, 0, len);
+ rng->dataAvail = (sizeof rng->data) - len;
+ }
+ /* we are asking for lots of bytes, just ask the generator to pass them */
} else {
- rv = prng_generateNewBytes(rng, output, len,
- rng->additionalAvail ? rng->additionalDataCache : NULL,
- rng->additionalAvail);
- rng->additionalAvail = 0;
+ rv = prng_generateNewBytes(rng, output, len,
+ rng->additionalAvail ? rng->additionalDataCache : NULL,
+ rng->additionalAvail);
+ rng->additionalAvail = 0;
}
PZ_Unlock(rng->lock);
/* --- UNLOCKED --- */
@@ -636,10 +651,24 @@ prng_GenerateGlobalRandomBytes(RNGContext *rng,
** Generate some random bytes, using the global random number generator
** object.
*/
-SECStatus
+SECStatus
RNG_GenerateGlobalRandomBytes(void *dest, size_t len)
{
+#ifdef UNSAFE_FUZZER_MODE
+ return prng_GenerateDeterministicRandomBytes(globalrng->lock, dest, len);
+#else
return prng_GenerateGlobalRandomBytes(globalrng, dest, len);
+#endif
+}
+
+SECStatus
+RNG_ResetForFuzzing(void)
+{
+#ifdef UNSAFE_FUZZER_MODE
+ return prng_ResetForFuzzing(globalrng->lock);
+#else
+ return SECFailure;
+#endif
}
void
@@ -648,9 +677,9 @@ RNG_RNGShutdown(void)
/* check for a valid global RNG context */
PORT_Assert(globalrng != NULL);
if (globalrng == NULL) {
- /* Should set a "not initialized" error code. */
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return;
+ /* Should set a "not initialized" error code. */
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return;
}
/* clear */
prng_freeRNGContext(globalrng);
@@ -662,7 +691,7 @@ RNG_RNGShutdown(void)
/*
* Test case interface. used by fips testing and power on self test
*/
- /* make sure the test context is separate from the global context, This
+/* make sure the test context is separate from the global context, This
* allows us to test the internal random number generator without losing
* entropy we may have previously collected. */
RNGContext testContext;
@@ -672,249 +701,253 @@ RNGContext testContext;
* other NIST SP 800-90 algorithms may be used in the future.
*/
SECStatus
-PRNGTEST_Instantiate(const PRUint8 *entropy, unsigned int entropy_len,
- const PRUint8 *nonce, unsigned int nonce_len,
- const PRUint8 *personal_string, unsigned int ps_len)
+PRNGTEST_Instantiate(const PRUint8 *entropy, unsigned int entropy_len,
+ const PRUint8 *nonce, unsigned int nonce_len,
+ const PRUint8 *personal_string, unsigned int ps_len)
{
- int bytes_len = entropy_len + nonce_len + ps_len;
- PRUint8 *bytes = NULL;
- SECStatus rv;
-
- if (entropy_len < 256/PR_BITS_PER_BYTE) {
- PORT_SetError(SEC_ERROR_NEED_RANDOM);
- return SECFailure;
- }
-
- bytes = PORT_Alloc(bytes_len);
- if (bytes == NULL) {
- PORT_SetError(SEC_ERROR_NO_MEMORY);
- return SECFailure;
- }
- /* concatenate the various inputs, internally NSS only instantiates with
+ int bytes_len = entropy_len + nonce_len + ps_len;
+ PRUint8 *bytes = NULL;
+ SECStatus rv;
+
+ if (entropy_len < 256 / PR_BITS_PER_BYTE) {
+ PORT_SetError(SEC_ERROR_NEED_RANDOM);
+ return SECFailure;
+ }
+
+ bytes = PORT_Alloc(bytes_len);
+ if (bytes == NULL) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return SECFailure;
+ }
+ /* concatenate the various inputs, internally NSS only instantiates with
* a single long string */
- PORT_Memcpy(bytes, entropy, entropy_len);
- if (nonce) {
- PORT_Memcpy(&bytes[entropy_len], nonce, nonce_len);
- } else {
- PORT_Assert(nonce_len == 0);
- }
- if (personal_string) {
- PORT_Memcpy(&bytes[entropy_len+nonce_len], personal_string, ps_len);
- } else {
- PORT_Assert(ps_len == 0);
- }
- rv = prng_instantiate(&testContext, bytes, bytes_len);
- PORT_ZFree(bytes, bytes_len);
- if (rv == SECFailure) {
- return SECFailure;
- }
- testContext.isValid = PR_TRUE;
- return SECSuccess;
+ PORT_Memcpy(bytes, entropy, entropy_len);
+ if (nonce) {
+ PORT_Memcpy(&bytes[entropy_len], nonce, nonce_len);
+ } else {
+ PORT_Assert(nonce_len == 0);
+ }
+ if (personal_string) {
+ PORT_Memcpy(&bytes[entropy_len + nonce_len], personal_string, ps_len);
+ } else {
+ PORT_Assert(ps_len == 0);
+ }
+ rv = prng_instantiate(&testContext, bytes, bytes_len);
+ PORT_ZFree(bytes, bytes_len);
+ if (rv == SECFailure) {
+ return SECFailure;
+ }
+ testContext.isValid = PR_TRUE;
+ return SECSuccess;
}
SECStatus
-PRNGTEST_Reseed(const PRUint8 *entropy, unsigned int entropy_len,
- const PRUint8 *additional, unsigned int additional_len)
+PRNGTEST_Reseed(const PRUint8 *entropy, unsigned int entropy_len,
+ const PRUint8 *additional, unsigned int additional_len)
{
if (!testContext.isValid) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
}
- /* This magic input tells us to set the reseed count to it's max count,
- * so we can simulate PRNGTEST_Generate reaching max reseed count */
- if ((entropy == NULL) && (entropy_len == 0) &&
- (additional == NULL) && (additional_len == 0)) {
- testContext.reseed_counter[0] = RESEED_VALUE;
- return SECSuccess;
+ /* This magic input tells us to set the reseed count to it's max count,
+ * so we can simulate PRNGTEST_Generate reaching max reseed count */
+ if ((entropy == NULL) && (entropy_len == 0) &&
+ (additional == NULL) && (additional_len == 0)) {
+ testContext.reseed_counter[0] = RESEED_VALUE;
+ return SECSuccess;
}
return prng_reseed(&testContext, entropy, entropy_len, additional,
- additional_len);
-
+ additional_len);
}
SECStatus
-PRNGTEST_Generate(PRUint8 *bytes, unsigned int bytes_len,
- const PRUint8 *additional, unsigned int additional_len)
+PRNGTEST_Generate(PRUint8 *bytes, unsigned int bytes_len,
+ const PRUint8 *additional, unsigned int additional_len)
{
SECStatus rv;
if (!testContext.isValid) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
}
/* replicate reseed test from prng_GenerateGlobalRandomBytes */
if (testContext.reseed_counter[0] >= RESEED_VALUE) {
- rv = prng_reseed(&testContext, NULL, 0, NULL, 0);
- if (rv != SECSuccess) {
- return rv;
- }
+ rv = prng_reseed(&testContext, NULL, 0, NULL, 0);
+ if (rv != SECSuccess) {
+ return rv;
+ }
}
return prng_generateNewBytes(&testContext, bytes, bytes_len,
- additional, additional_len);
-
+ additional, additional_len);
}
SECStatus
PRNGTEST_Uninstantiate()
{
if (!testContext.isValid) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
}
- PORT_Memset(&testContext, 0, sizeof testContext);
- return SECSuccess;
+ PORT_Memset(&testContext, 0, sizeof testContext);
+ return SECSuccess;
}
SECStatus
PRNGTEST_RunHealthTests()
{
- static const PRUint8 entropy[] = {
- 0x8e,0x9c,0x0d,0x25,0x75,0x22,0x04,0xf9,
- 0xc5,0x79,0x10,0x8b,0x23,0x79,0x37,0x14,
- 0x9f,0x2c,0xc7,0x0b,0x39,0xf8,0xee,0xef,
- 0x95,0x0c,0x97,0x59,0xfc,0x0a,0x85,0x41,
- 0x76,0x9d,0x6d,0x67,0x00,0x4e,0x19,0x12,
- 0x02,0x16,0x53,0xea,0xf2,0x73,0xd7,0xd6,
- 0x7f,0x7e,0xc8,0xae,0x9c,0x09,0x99,0x7d,
- 0xbb,0x9e,0x48,0x7f,0xbb,0x96,0x46,0xb3,
- 0x03,0x75,0xf8,0xc8,0x69,0x45,0x3f,0x97,
- 0x5e,0x2e,0x48,0xe1,0x5d,0x58,0x97,0x4c };
- static const PRUint8 rng_known_result[] = {
- 0x16,0xe1,0x8c,0x57,0x21,0xd8,0xf1,0x7e,
- 0x5a,0xa0,0x16,0x0b,0x7e,0xa6,0x25,0xb4,
- 0x24,0x19,0xdb,0x54,0xfa,0x35,0x13,0x66,
- 0xbb,0xaa,0x2a,0x1b,0x22,0x33,0x2e,0x4a,
- 0x14,0x07,0x9d,0x52,0xfc,0x73,0x61,0x48,
- 0xac,0xc1,0x22,0xfc,0xa4,0xfc,0xac,0xa4,
- 0xdb,0xda,0x5b,0x27,0x33,0xc4,0xb3 };
- static const PRUint8 reseed_entropy[] = {
- 0xc6,0x0b,0x0a,0x30,0x67,0x07,0xf4,0xe2,
- 0x24,0xa7,0x51,0x6f,0x5f,0x85,0x3e,0x5d,
- 0x67,0x97,0xb8,0x3b,0x30,0x9c,0x7a,0xb1,
- 0x52,0xc6,0x1b,0xc9,0x46,0xa8,0x62,0x79 };
- static const PRUint8 additional_input[] = {
- 0x86,0x82,0x28,0x98,0xe7,0xcb,0x01,0x14,
- 0xae,0x87,0x4b,0x1d,0x99,0x1b,0xc7,0x41,
- 0x33,0xff,0x33,0x66,0x40,0x95,0x54,0xc6,
- 0x67,0x4d,0x40,0x2a,0x1f,0xf9,0xeb,0x65 };
- static const PRUint8 rng_reseed_result[] = {
- 0x02,0x0c,0xc6,0x17,0x86,0x49,0xba,0xc4,
- 0x7b,0x71,0x35,0x05,0xf0,0xdb,0x4a,0xc2,
- 0x2c,0x38,0xc1,0xa4,0x42,0xe5,0x46,0x4a,
- 0x7d,0xf0,0xbe,0x47,0x88,0xb8,0x0e,0xc6,
- 0x25,0x2b,0x1d,0x13,0xef,0xa6,0x87,0x96,
- 0xa3,0x7d,0x5b,0x80,0xc2,0x38,0x76,0x61,
- 0xc7,0x80,0x5d,0x0f,0x05,0x76,0x85 };
- static const PRUint8 rng_no_reseed_result[] = {
- 0xc4,0x40,0x41,0x8c,0xbf,0x2f,0x70,0x23,
- 0x88,0xf2,0x7b,0x30,0xc3,0xca,0x1e,0xf3,
- 0xef,0x53,0x81,0x5d,0x30,0xed,0x4c,0xf1,
- 0xff,0x89,0xa5,0xee,0x92,0xf8,0xc0,0x0f,
- 0x88,0x53,0xdf,0xb6,0x76,0xf0,0xaa,0xd3,
- 0x2e,0x1d,0x64,0x37,0x3e,0xe8,0x4a,0x02,
- 0xff,0x0a,0x7f,0xe5,0xe9,0x2b,0x6d };
-
- SECStatus rng_status = SECSuccess;
- PR_STATIC_ASSERT(sizeof(rng_known_result) >= sizeof(rng_reseed_result));
- PRUint8 result[sizeof(rng_known_result)];
-
- /********************************************/
- /* First test instantiate error path. */
- /* In this case we supply enough entropy, */
- /* but not enough seed. This will trigger */
- /* the code that checks for a entropy */
- /* source failure. */
- /********************************************/
- rng_status = PRNGTEST_Instantiate(entropy, 256/PR_BITS_PER_BYTE,
- NULL, 0, NULL, 0);
- if (rng_status == SECSuccess) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
- if (PORT_GetError() != SEC_ERROR_NEED_RANDOM) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
- /* we failed with the proper error code, we can continue */
-
- /********************************************/
- /* Generate random bytes with a known seed. */
- /********************************************/
- rng_status = PRNGTEST_Instantiate(entropy, sizeof entropy,
- NULL, 0, NULL, 0);
- if (rng_status != SECSuccess) {
- /* Error set by PRNGTEST_Instantiate */
- return SECFailure;
- }
- rng_status = PRNGTEST_Generate(result, sizeof rng_known_result, NULL, 0);
- if ( ( rng_status != SECSuccess) ||
- ( PORT_Memcmp( result, rng_known_result,
- sizeof rng_known_result ) != 0 ) ) {
- PRNGTEST_Uninstantiate();
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
- rng_status = PRNGTEST_Reseed(reseed_entropy, sizeof reseed_entropy,
- additional_input, sizeof additional_input);
- if (rng_status != SECSuccess) {
- /* Error set by PRNG_Reseed */
- PRNGTEST_Uninstantiate();
- return SECFailure;
- }
- rng_status = PRNGTEST_Generate(result, sizeof rng_reseed_result, NULL, 0);
- if ( ( rng_status != SECSuccess) ||
- ( PORT_Memcmp( result, rng_reseed_result,
- sizeof rng_reseed_result ) != 0 ) ) {
- PRNGTEST_Uninstantiate();
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
- /* This magic forces the reseed count to it's max count, so we can see if
- * PRNGTEST_Generate will actually when it reaches it's count */
- rng_status = PRNGTEST_Reseed(NULL, 0, NULL, 0);
- if (rng_status != SECSuccess) {
- PRNGTEST_Uninstantiate();
- /* Error set by PRNG_Reseed */
- return SECFailure;
- }
- /* This generate should now reseed */
- rng_status = PRNGTEST_Generate(result, sizeof rng_reseed_result, NULL, 0);
- if ( ( rng_status != SECSuccess) ||
- /* NOTE we fail if the result is equal to the no_reseed_result.
+ static const PRUint8 entropy[] = {
+ 0x8e, 0x9c, 0x0d, 0x25, 0x75, 0x22, 0x04, 0xf9,
+ 0xc5, 0x79, 0x10, 0x8b, 0x23, 0x79, 0x37, 0x14,
+ 0x9f, 0x2c, 0xc7, 0x0b, 0x39, 0xf8, 0xee, 0xef,
+ 0x95, 0x0c, 0x97, 0x59, 0xfc, 0x0a, 0x85, 0x41,
+ 0x76, 0x9d, 0x6d, 0x67, 0x00, 0x4e, 0x19, 0x12,
+ 0x02, 0x16, 0x53, 0xea, 0xf2, 0x73, 0xd7, 0xd6,
+ 0x7f, 0x7e, 0xc8, 0xae, 0x9c, 0x09, 0x99, 0x7d,
+ 0xbb, 0x9e, 0x48, 0x7f, 0xbb, 0x96, 0x46, 0xb3,
+ 0x03, 0x75, 0xf8, 0xc8, 0x69, 0x45, 0x3f, 0x97,
+ 0x5e, 0x2e, 0x48, 0xe1, 0x5d, 0x58, 0x97, 0x4c
+ };
+ static const PRUint8 rng_known_result[] = {
+ 0x16, 0xe1, 0x8c, 0x57, 0x21, 0xd8, 0xf1, 0x7e,
+ 0x5a, 0xa0, 0x16, 0x0b, 0x7e, 0xa6, 0x25, 0xb4,
+ 0x24, 0x19, 0xdb, 0x54, 0xfa, 0x35, 0x13, 0x66,
+ 0xbb, 0xaa, 0x2a, 0x1b, 0x22, 0x33, 0x2e, 0x4a,
+ 0x14, 0x07, 0x9d, 0x52, 0xfc, 0x73, 0x61, 0x48,
+ 0xac, 0xc1, 0x22, 0xfc, 0xa4, 0xfc, 0xac, 0xa4,
+ 0xdb, 0xda, 0x5b, 0x27, 0x33, 0xc4, 0xb3
+ };
+ static const PRUint8 reseed_entropy[] = {
+ 0xc6, 0x0b, 0x0a, 0x30, 0x67, 0x07, 0xf4, 0xe2,
+ 0x24, 0xa7, 0x51, 0x6f, 0x5f, 0x85, 0x3e, 0x5d,
+ 0x67, 0x97, 0xb8, 0x3b, 0x30, 0x9c, 0x7a, 0xb1,
+ 0x52, 0xc6, 0x1b, 0xc9, 0x46, 0xa8, 0x62, 0x79
+ };
+ static const PRUint8 additional_input[] = {
+ 0x86, 0x82, 0x28, 0x98, 0xe7, 0xcb, 0x01, 0x14,
+ 0xae, 0x87, 0x4b, 0x1d, 0x99, 0x1b, 0xc7, 0x41,
+ 0x33, 0xff, 0x33, 0x66, 0x40, 0x95, 0x54, 0xc6,
+ 0x67, 0x4d, 0x40, 0x2a, 0x1f, 0xf9, 0xeb, 0x65
+ };
+ static const PRUint8 rng_reseed_result[] = {
+ 0x02, 0x0c, 0xc6, 0x17, 0x86, 0x49, 0xba, 0xc4,
+ 0x7b, 0x71, 0x35, 0x05, 0xf0, 0xdb, 0x4a, 0xc2,
+ 0x2c, 0x38, 0xc1, 0xa4, 0x42, 0xe5, 0x46, 0x4a,
+ 0x7d, 0xf0, 0xbe, 0x47, 0x88, 0xb8, 0x0e, 0xc6,
+ 0x25, 0x2b, 0x1d, 0x13, 0xef, 0xa6, 0x87, 0x96,
+ 0xa3, 0x7d, 0x5b, 0x80, 0xc2, 0x38, 0x76, 0x61,
+ 0xc7, 0x80, 0x5d, 0x0f, 0x05, 0x76, 0x85
+ };
+ static const PRUint8 rng_no_reseed_result[] = {
+ 0xc4, 0x40, 0x41, 0x8c, 0xbf, 0x2f, 0x70, 0x23,
+ 0x88, 0xf2, 0x7b, 0x30, 0xc3, 0xca, 0x1e, 0xf3,
+ 0xef, 0x53, 0x81, 0x5d, 0x30, 0xed, 0x4c, 0xf1,
+ 0xff, 0x89, 0xa5, 0xee, 0x92, 0xf8, 0xc0, 0x0f,
+ 0x88, 0x53, 0xdf, 0xb6, 0x76, 0xf0, 0xaa, 0xd3,
+ 0x2e, 0x1d, 0x64, 0x37, 0x3e, 0xe8, 0x4a, 0x02,
+ 0xff, 0x0a, 0x7f, 0xe5, 0xe9, 0x2b, 0x6d
+ };
+
+ SECStatus rng_status = SECSuccess;
+ PR_STATIC_ASSERT(sizeof(rng_known_result) >= sizeof(rng_reseed_result));
+ PRUint8 result[sizeof(rng_known_result)];
+
+ /********************************************/
+ /* First test instantiate error path. */
+ /* In this case we supply enough entropy, */
+ /* but not enough seed. This will trigger */
+ /* the code that checks for a entropy */
+ /* source failure. */
+ /********************************************/
+ rng_status = PRNGTEST_Instantiate(entropy, 256 / PR_BITS_PER_BYTE,
+ NULL, 0, NULL, 0);
+ if (rng_status == SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ if (PORT_GetError() != SEC_ERROR_NEED_RANDOM) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ /* we failed with the proper error code, we can continue */
+
+ /********************************************/
+ /* Generate random bytes with a known seed. */
+ /********************************************/
+ rng_status = PRNGTEST_Instantiate(entropy, sizeof entropy,
+ NULL, 0, NULL, 0);
+ if (rng_status != SECSuccess) {
+ /* Error set by PRNGTEST_Instantiate */
+ return SECFailure;
+ }
+ rng_status = PRNGTEST_Generate(result, sizeof rng_known_result, NULL, 0);
+ if ((rng_status != SECSuccess) ||
+ (PORT_Memcmp(result, rng_known_result,
+ sizeof rng_known_result) != 0)) {
+ PRNGTEST_Uninstantiate();
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ rng_status = PRNGTEST_Reseed(reseed_entropy, sizeof reseed_entropy,
+ additional_input, sizeof additional_input);
+ if (rng_status != SECSuccess) {
+ /* Error set by PRNG_Reseed */
+ PRNGTEST_Uninstantiate();
+ return SECFailure;
+ }
+ rng_status = PRNGTEST_Generate(result, sizeof rng_reseed_result, NULL, 0);
+ if ((rng_status != SECSuccess) ||
+ (PORT_Memcmp(result, rng_reseed_result,
+ sizeof rng_reseed_result) != 0)) {
+ PRNGTEST_Uninstantiate();
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ /* This magic forces the reseed count to it's max count, so we can see if
+ * PRNGTEST_Generate will actually when it reaches it's count */
+ rng_status = PRNGTEST_Reseed(NULL, 0, NULL, 0);
+ if (rng_status != SECSuccess) {
+ PRNGTEST_Uninstantiate();
+ /* Error set by PRNG_Reseed */
+ return SECFailure;
+ }
+ /* This generate should now reseed */
+ rng_status = PRNGTEST_Generate(result, sizeof rng_reseed_result, NULL, 0);
+ if ((rng_status != SECSuccess) ||
+ /* NOTE we fail if the result is equal to the no_reseed_result.
* no_reseed_result is the value we would have gotten if we didn't
- * do an automatic reseed in PRNGTEST_Generate */
- ( PORT_Memcmp( result, rng_no_reseed_result,
- sizeof rng_no_reseed_result ) == 0 ) ) {
- PRNGTEST_Uninstantiate();
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
- /* make sure reseed fails when we don't supply enough entropy */
- rng_status = PRNGTEST_Reseed(reseed_entropy, 4, NULL, 0);
- if (rng_status == SECSuccess) {
- PRNGTEST_Uninstantiate();
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
- if (PORT_GetError() != SEC_ERROR_NEED_RANDOM) {
- PRNGTEST_Uninstantiate();
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
- rng_status = PRNGTEST_Uninstantiate();
- if (rng_status != SECSuccess) {
- /* Error set by PRNG_Uninstantiate */
- return rng_status;
- }
- /* make sure uninstantiate fails if the contest is not initiated (also tests
- * if the context was cleared in the previous Uninstantiate) */
- rng_status = PRNGTEST_Uninstantiate();
- if (rng_status == SECSuccess) {
- PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
- return SECFailure;
- }
- if (PORT_GetError() != SEC_ERROR_LIBRARY_FAILURE) {
- return rng_status;
- }
-
- return SECSuccess;
+ * do an automatic reseed in PRNGTEST_Generate */
+ (PORT_Memcmp(result, rng_no_reseed_result,
+ sizeof rng_no_reseed_result) == 0)) {
+ PRNGTEST_Uninstantiate();
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ /* make sure reseed fails when we don't supply enough entropy */
+ rng_status = PRNGTEST_Reseed(reseed_entropy, 4, NULL, 0);
+ if (rng_status == SECSuccess) {
+ PRNGTEST_Uninstantiate();
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ if (PORT_GetError() != SEC_ERROR_NEED_RANDOM) {
+ PRNGTEST_Uninstantiate();
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ rng_status = PRNGTEST_Uninstantiate();
+ if (rng_status != SECSuccess) {
+ /* Error set by PRNG_Uninstantiate */
+ return rng_status;
+ }
+ /* make sure uninstantiate fails if the contest is not initiated (also tests
+ * if the context was cleared in the previous Uninstantiate) */
+ rng_status = PRNGTEST_Uninstantiate();
+ if (rng_status == SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ if (PORT_GetError() != SEC_ERROR_LIBRARY_FAILURE) {
+ return rng_status;
+ }
+
+ return SECSuccess;
}