diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-01-04 14:24:24 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-01-04 14:24:24 +0000 |
commit | dc1565216a5d20ae0d75872151523252309a1292 (patch) | |
tree | d57454ba9a40386552179eddf60d28bd1e8f3d54 /nss/lib/freebl/drbg.c | |
parent | 26c046fbc57d53136b4fb3b5e0d18298318125d4 (diff) | |
download | nss-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.c | 1045 |
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; } |