security/nss/lib/freebl/drbg.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #ifdef FREEBL_NO_DEPEND
michael@0 6 #include "stubs.h"
michael@0 7 #endif
michael@0 8
michael@0 9 #include "prerror.h"
michael@0 10 #include "secerr.h"
michael@0 11
michael@0 12 #include "prtypes.h"
michael@0 13 #include "prinit.h"
michael@0 14 #include "blapi.h"
michael@0 15 #include "blapii.h"
michael@0 16 #include "nssilock.h"
michael@0 17 #include "secitem.h"
michael@0 18 #include "sha_fast.h"
michael@0 19 #include "sha256.h"
michael@0 20 #include "secrng.h" /* for RNG_SystemRNG() */
michael@0 21 #include "secmpi.h"
michael@0 22
michael@0 23 /* PRNG_SEEDLEN defined in NIST SP 800-90 section 10.1
michael@0 24 * for SHA-1, SHA-224, and SHA-256 it's 440 bits.
michael@0 25 * for SHA-384 and SHA-512 it's 888 bits */
michael@0 26 #define PRNG_SEEDLEN (440/PR_BITS_PER_BYTE)
michael@0 27 static const PRInt64 PRNG_MAX_ADDITIONAL_BYTES = LL_INIT(0x1, 0x0);
michael@0 28 /* 2^35 bits or 2^32 bytes */
michael@0 29 #define PRNG_MAX_REQUEST_SIZE 0x10000 /* 2^19 bits or 2^16 bytes */
michael@0 30 #define PRNG_ADDITONAL_DATA_CACHE_SIZE (8*1024) /* must be less than
michael@0 31 * PRNG_MAX_ADDITIONAL_BYTES
michael@0 32 */
michael@0 33
michael@0 34 /* RESEED_COUNT is how many calls to the prng before we need to reseed
michael@0 35 * under normal NIST rules, you must return an error. In the NSS case, we
michael@0 36 * self-reseed with RNG_SystemRNG(). Count can be a large number. For code
michael@0 37 * simplicity, we specify count with 2 components: RESEED_BYTE (which is
michael@0 38 * the same as LOG256(RESEED_COUNT)) and RESEED_VALUE (which is the same as
michael@0 39 * RESEED_COUNT / (256 ^ RESEED_BYTE)). Another way to look at this is
michael@0 40 * RESEED_COUNT = RESEED_VALUE * (256 ^ RESEED_BYTE). For Hash based DRBG
michael@0 41 * we use the maximum count value, 2^48, or RESEED_BYTE=6 and RESEED_VALUE=1
michael@0 42 */
michael@0 43 #define RESEED_BYTE 6
michael@0 44 #define RESEED_VALUE 1
michael@0 45
michael@0 46 #define PRNG_RESET_RESEED_COUNT(rng) \
michael@0 47 PORT_Memset((rng)->reseed_counter, 0, sizeof (rng)->reseed_counter); \
michael@0 48 (rng)->reseed_counter[RESEED_BYTE] = 1;
michael@0 49
michael@0 50
michael@0 51 /*
michael@0 52 * The actual values of this enum are specified in SP 800-90, 10.1.1.*
michael@0 53 * The spec does not name the types, it only uses bare values
michael@0 54 */
michael@0 55 typedef enum {
michael@0 56 prngCGenerateType = 0, /* used when creating a new 'C' */
michael@0 57 prngReseedType = 1, /* used in reseeding */
michael@0 58 prngAdditionalDataType = 2, /* used in mixing additional data */
michael@0 59 prngGenerateByteType = 3 /* used when mixing internal state while
michael@0 60 * generating bytes */
michael@0 61 } prngVTypes;
michael@0 62
michael@0 63 /*
michael@0 64 * Global RNG context
michael@0 65 */
michael@0 66 struct RNGContextStr {
michael@0 67 PZLock *lock; /* Lock to serialize access to global rng */
michael@0 68 /*
michael@0 69 * NOTE, a number of steps in the drbg algorithm need to hash
michael@0 70 * V_type || V. The code, therefore, depends on the V array following
michael@0 71 * immediately after V_type to avoid extra copies. To accomplish this
michael@0 72 * in a way that compiliers can't perturb, we declare V_type and V
michael@0 73 * as a V_Data array and reference them by macros */
michael@0 74 PRUint8 V_Data[PRNG_SEEDLEN+1]; /* internal state variables */
michael@0 75 #define V_type V_Data[0]
michael@0 76 #define V(rng) (((rng)->V_Data)+1)
michael@0 77 #define VSize(rng) ((sizeof (rng)->V_Data) -1)
michael@0 78 PRUint8 C[PRNG_SEEDLEN]; /* internal state variables */
michael@0 79 PRUint8 oldV[PRNG_SEEDLEN]; /* for continuous rng checking */
michael@0 80 /* If we get calls for the PRNG to return less than the length of our
michael@0 81 * hash, we extend the request for a full hash (since we'll be doing
michael@0 82 * the full hash anyway). Future requests for random numbers are fulfilled
michael@0 83 * from the remainder of the bytes we generated. Requests for bytes longer
michael@0 84 * than the hash size are fulfilled directly from the HashGen function
michael@0 85 * of the random number generator. */
michael@0 86 PRUint8 reseed_counter[RESEED_BYTE+1]; /* number of requests since the
michael@0 87 * last reseed. Need only be
michael@0 88 * big enough to hold the whole
michael@0 89 * reseed count */
michael@0 90 PRUint8 data[SHA256_LENGTH]; /* when we request less than a block
michael@0 91 * save the rest of the rng output for
michael@0 92 * another partial block */
michael@0 93 PRUint8 dataAvail; /* # bytes of output available in our cache,
michael@0 94 * [0...SHA256_LENGTH] */
michael@0 95 /* store additional data that has been shovelled off to us by
michael@0 96 * RNG_RandomUpdate. */
michael@0 97 PRUint8 additionalDataCache[PRNG_ADDITONAL_DATA_CACHE_SIZE];
michael@0 98 PRUint32 additionalAvail;
michael@0 99 PRBool isValid; /* false if RNG reaches an invalid state */
michael@0 100 };
michael@0 101
michael@0 102 typedef struct RNGContextStr RNGContext;
michael@0 103 static RNGContext *globalrng = NULL;
michael@0 104 static RNGContext theGlobalRng;
michael@0 105
michael@0 106
michael@0 107 /*
michael@0 108 * The next several functions are derived from the NIST SP 800-90
michael@0 109 * spec. In these functions, an attempt was made to use names consistent
michael@0 110 * with the names in the spec, even if they differ from normal NSS usage.
michael@0 111 */
michael@0 112
michael@0 113 /*
michael@0 114 * Hash Derive function defined in NISP SP 800-90 Section 10.4.1.
michael@0 115 * This function is used in the Instantiate and Reseed functions.
michael@0 116 *
michael@0 117 * NOTE: requested_bytes cannot overlap with input_string_1 or input_string_2.
michael@0 118 * input_string_1 and input_string_2 are logically concatentated.
michael@0 119 * input_string_1 must be supplied.
michael@0 120 * if input_string_2 is not supplied, NULL should be passed for this parameter.
michael@0 121 */
michael@0 122 static SECStatus
michael@0 123 prng_Hash_df(PRUint8 *requested_bytes, unsigned int no_of_bytes_to_return,
michael@0 124 const PRUint8 *input_string_1, unsigned int input_string_1_len,
michael@0 125 const PRUint8 *input_string_2, unsigned int input_string_2_len)
michael@0 126 {
michael@0 127 SHA256Context ctx;
michael@0 128 PRUint32 tmp;
michael@0 129 PRUint8 counter;
michael@0 130
michael@0 131 tmp=SHA_HTONL(no_of_bytes_to_return*8);
michael@0 132
michael@0 133 for (counter = 1 ; no_of_bytes_to_return > 0; counter++) {
michael@0 134 unsigned int hash_return_len;
michael@0 135 SHA256_Begin(&ctx);
michael@0 136 SHA256_Update(&ctx, &counter, 1);
michael@0 137 SHA256_Update(&ctx, (unsigned char *)&tmp, sizeof tmp);
michael@0 138 SHA256_Update(&ctx, input_string_1, input_string_1_len);
michael@0 139 if (input_string_2) {
michael@0 140 SHA256_Update(&ctx, input_string_2, input_string_2_len);
michael@0 141 }
michael@0 142 SHA256_End(&ctx, requested_bytes, &hash_return_len,
michael@0 143 no_of_bytes_to_return);
michael@0 144 requested_bytes += hash_return_len;
michael@0 145 no_of_bytes_to_return -= hash_return_len;
michael@0 146 }
michael@0 147 return SECSuccess;
michael@0 148 }
michael@0 149
michael@0 150
michael@0 151 /*
michael@0 152 * Hash_DRBG Instantiate NIST SP 800-80 10.1.1.2
michael@0 153 *
michael@0 154 * NOTE: bytes & len are entropy || nonce || personalization_string. In
michael@0 155 * normal operation, NSS calculates them all together in a single call.
michael@0 156 */
michael@0 157 static SECStatus
michael@0 158 prng_instantiate(RNGContext *rng, const PRUint8 *bytes, unsigned int len)
michael@0 159 {
michael@0 160 if (len < PRNG_SEEDLEN) {
michael@0 161 /* if the seedlen is to small, it's probably because we failed to get
michael@0 162 * enough random data */
michael@0 163 PORT_SetError(SEC_ERROR_NEED_RANDOM);
michael@0 164 return SECFailure;
michael@0 165 }
michael@0 166 prng_Hash_df(V(rng), VSize(rng), bytes, len, NULL, 0);
michael@0 167 rng->V_type = prngCGenerateType;
michael@0 168 prng_Hash_df(rng->C,sizeof rng->C,rng->V_Data,sizeof rng->V_Data,NULL,0);
michael@0 169 PRNG_RESET_RESEED_COUNT(rng)
michael@0 170 return SECSuccess;
michael@0 171 }
michael@0 172
michael@0 173
michael@0 174 /*
michael@0 175 * Update the global random number generator with more seeding
michael@0 176 * material. Use the Hash_DRBG reseed algorithm from NIST SP-800-90
michael@0 177 * section 10.1.1.3
michael@0 178 *
michael@0 179 * If entropy is NULL, it is fetched from the noise generator.
michael@0 180 */
michael@0 181 static SECStatus
michael@0 182 prng_reseed(RNGContext *rng, const PRUint8 *entropy, unsigned int entropy_len,
michael@0 183 const PRUint8 *additional_input, unsigned int additional_input_len)
michael@0 184 {
michael@0 185 PRUint8 noiseData[(sizeof rng->V_Data)+PRNG_SEEDLEN];
michael@0 186 PRUint8 *noise = &noiseData[0];
michael@0 187
michael@0 188 /* if entropy wasn't supplied, fetch it. (normal operation case) */
michael@0 189 if (entropy == NULL) {
michael@0 190 entropy_len = (unsigned int) RNG_SystemRNG(
michael@0 191 &noiseData[sizeof rng->V_Data], PRNG_SEEDLEN);
michael@0 192 } else {
michael@0 193 /* NOTE: this code is only available for testing, not to applications */
michael@0 194 /* if entropy was too big for the stack variable, get it from malloc */
michael@0 195 if (entropy_len > PRNG_SEEDLEN) {
michael@0 196 noise = PORT_Alloc(entropy_len + (sizeof rng->V_Data));
michael@0 197 if (noise == NULL) {
michael@0 198 return SECFailure;
michael@0 199 }
michael@0 200 }
michael@0 201 PORT_Memcpy(&noise[sizeof rng->V_Data],entropy, entropy_len);
michael@0 202 }
michael@0 203
michael@0 204 if (entropy_len < 256/PR_BITS_PER_BYTE) {
michael@0 205 /* noise == &noiseData[0] at this point, so nothing to free */
michael@0 206 PORT_SetError(SEC_ERROR_NEED_RANDOM);
michael@0 207 return SECFailure;
michael@0 208 }
michael@0 209
michael@0 210 rng->V_type = prngReseedType;
michael@0 211 PORT_Memcpy(noise, rng->V_Data, sizeof rng->V_Data);
michael@0 212 prng_Hash_df(V(rng), VSize(rng), noise, (sizeof rng->V_Data) + entropy_len,
michael@0 213 additional_input, additional_input_len);
michael@0 214 /* clear potential CSP */
michael@0 215 PORT_Memset(noise, 0, (sizeof rng->V_Data) + entropy_len);
michael@0 216 rng->V_type = prngCGenerateType;
michael@0 217 prng_Hash_df(rng->C,sizeof rng->C,rng->V_Data,sizeof rng->V_Data,NULL,0);
michael@0 218 PRNG_RESET_RESEED_COUNT(rng)
michael@0 219
michael@0 220 if (noise != &noiseData[0]) {
michael@0 221 PORT_Free(noise);
michael@0 222 }
michael@0 223 return SECSuccess;
michael@0 224 }
michael@0 225
michael@0 226 /*
michael@0 227 * SP 800-90 requires we rerun our health tests on reseed
michael@0 228 */
michael@0 229 static SECStatus
michael@0 230 prng_reseed_test(RNGContext *rng, const PRUint8 *entropy,
michael@0 231 unsigned int entropy_len, const PRUint8 *additional_input,
michael@0 232 unsigned int additional_input_len)
michael@0 233 {
michael@0 234 SECStatus rv;
michael@0 235
michael@0 236 /* do health checks in FIPS mode */
michael@0 237 rv = PRNGTEST_RunHealthTests();
michael@0 238 if (rv != SECSuccess) {
michael@0 239 /* error set by PRNGTEST_RunHealTests() */
michael@0 240 rng->isValid = PR_FALSE;
michael@0 241 return SECFailure;
michael@0 242 }
michael@0 243 return prng_reseed(rng, entropy, entropy_len,
michael@0 244 additional_input, additional_input_len);
michael@0 245 }
michael@0 246
michael@0 247 /*
michael@0 248 * build some fast inline functions for adding.
michael@0 249 */
michael@0 250 #define PRNG_ADD_CARRY_ONLY(dest, start, cy) \
michael@0 251 carry = cy; \
michael@0 252 for (k1=start; carry && k1 >=0 ; k1--) { \
michael@0 253 carry = !(++dest[k1]); \
michael@0 254 }
michael@0 255
michael@0 256 /*
michael@0 257 * NOTE: dest must be an array for the following to work.
michael@0 258 */
michael@0 259 #define PRNG_ADD_BITS(dest, dest_len, add, len) \
michael@0 260 carry = 0; \
michael@0 261 for (k1=dest_len -1, k2=len-1; k2 >= 0; --k1, --k2) { \
michael@0 262 carry += dest[k1]+ add[k2]; \
michael@0 263 dest[k1] = (PRUint8) carry; \
michael@0 264 carry >>= 8; \
michael@0 265 }
michael@0 266
michael@0 267 #define PRNG_ADD_BITS_AND_CARRY(dest, dest_len, add, len) \
michael@0 268 PRNG_ADD_BITS(dest, dest_len, add, len) \
michael@0 269 PRNG_ADD_CARRY_ONLY(dest, k1, carry)
michael@0 270
michael@0 271 /*
michael@0 272 * This function expands the internal state of the prng to fulfill any number
michael@0 273 * of bytes we need for this request. We only use this call if we need more
michael@0 274 * than can be supplied by a single call to SHA256_HashBuf.
michael@0 275 *
michael@0 276 * This function is specified in NIST SP 800-90 section 10.1.1.4, Hashgen
michael@0 277 */
michael@0 278 static void
michael@0 279 prng_Hashgen(RNGContext *rng, PRUint8 *returned_bytes,
michael@0 280 unsigned int no_of_returned_bytes)
michael@0 281 {
michael@0 282 PRUint8 data[VSize(rng)];
michael@0 283
michael@0 284 PORT_Memcpy(data, V(rng), VSize(rng));
michael@0 285 while (no_of_returned_bytes) {
michael@0 286 SHA256Context ctx;
michael@0 287 unsigned int len;
michael@0 288 unsigned int carry;
michael@0 289 int k1;
michael@0 290
michael@0 291 SHA256_Begin(&ctx);
michael@0 292 SHA256_Update(&ctx, data, sizeof data);
michael@0 293 SHA256_End(&ctx, returned_bytes, &len, no_of_returned_bytes);
michael@0 294 returned_bytes += len;
michael@0 295 no_of_returned_bytes -= len;
michael@0 296 /* The carry parameter is a bool (increment or not).
michael@0 297 * This increments data if no_of_returned_bytes is not zero */
michael@0 298 PRNG_ADD_CARRY_ONLY(data, (sizeof data)- 1, no_of_returned_bytes);
michael@0 299 }
michael@0 300 PORT_Memset(data, 0, sizeof data);
michael@0 301 }
michael@0 302
michael@0 303 /*
michael@0 304 * Generates new random bytes and advances the internal prng state.
michael@0 305 * additional bytes are only used in algorithm testing.
michael@0 306 *
michael@0 307 * This function is specified in NIST SP 800-90 section 10.1.1.4
michael@0 308 */
michael@0 309 static SECStatus
michael@0 310 prng_generateNewBytes(RNGContext *rng,
michael@0 311 PRUint8 *returned_bytes, unsigned int no_of_returned_bytes,
michael@0 312 const PRUint8 *additional_input,
michael@0 313 unsigned int additional_input_len)
michael@0 314 {
michael@0 315 PRUint8 H[SHA256_LENGTH]; /* both H and w since they
michael@0 316 * aren't used concurrently */
michael@0 317 unsigned int carry;
michael@0 318 int k1, k2;
michael@0 319
michael@0 320 if (!rng->isValid) {
michael@0 321 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
michael@0 322 return SECFailure;
michael@0 323 }
michael@0 324 /* This code only triggers during tests, normal
michael@0 325 * prng operation does not use additional_input */
michael@0 326 if (additional_input){
michael@0 327 SHA256Context ctx;
michael@0 328 /* NIST SP 800-90 defines two temporaries in their calculations,
michael@0 329 * w and H. These temporaries are the same lengths, and used
michael@0 330 * at different times, so we use the following macro to collapse
michael@0 331 * them to the same variable, but keeping their unique names for
michael@0 332 * easy comparison to the spec */
michael@0 333 #define w H
michael@0 334 rng->V_type = prngAdditionalDataType;
michael@0 335 SHA256_Begin(&ctx);
michael@0 336 SHA256_Update(&ctx, rng->V_Data, sizeof rng->V_Data);
michael@0 337 SHA256_Update(&ctx, additional_input, additional_input_len);
michael@0 338 SHA256_End(&ctx, w, NULL, sizeof w);
michael@0 339 PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), w, sizeof w)
michael@0 340 PORT_Memset(w, 0, sizeof w);
michael@0 341 #undef w
michael@0 342 }
michael@0 343
michael@0 344 if (no_of_returned_bytes == SHA256_LENGTH) {
michael@0 345 /* short_cut to hashbuf and save a copy and a clear */
michael@0 346 SHA256_HashBuf(returned_bytes, V(rng), VSize(rng) );
michael@0 347 } else {
michael@0 348 prng_Hashgen(rng, returned_bytes, no_of_returned_bytes);
michael@0 349 }
michael@0 350 /* advance our internal state... */
michael@0 351 rng->V_type = prngGenerateByteType;
michael@0 352 SHA256_HashBuf(H, rng->V_Data, sizeof rng->V_Data);
michael@0 353 PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), H, sizeof H)
michael@0 354 PRNG_ADD_BITS(V(rng), VSize(rng), rng->C, sizeof rng->C);
michael@0 355 PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), rng->reseed_counter,
michael@0 356 sizeof rng->reseed_counter)
michael@0 357 PRNG_ADD_CARRY_ONLY(rng->reseed_counter,(sizeof rng->reseed_counter)-1, 1);
michael@0 358
michael@0 359 /* continuous rng check */
michael@0 360 if (memcmp(V(rng), rng->oldV, sizeof rng->oldV) == 0) {
michael@0 361 rng->isValid = PR_FALSE;
michael@0 362 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
michael@0 363 return SECFailure;
michael@0 364 }
michael@0 365 PORT_Memcpy(rng->oldV, V(rng), sizeof rng->oldV);
michael@0 366 return SECSuccess;
michael@0 367 }
michael@0 368
michael@0 369 /* Use NSPR to prevent RNG_RNGInit from being called from separate
michael@0 370 * threads, creating a race condition.
michael@0 371 */
michael@0 372 static const PRCallOnceType pristineCallOnce;
michael@0 373 static PRCallOnceType coRNGInit;
michael@0 374 static PRStatus rng_init(void)
michael@0 375 {
michael@0 376 PRUint8 bytes[PRNG_SEEDLEN*2]; /* entropy + nonce */
michael@0 377 unsigned int numBytes;
michael@0 378 SECStatus rv = SECSuccess;
michael@0 379
michael@0 380 if (globalrng == NULL) {
michael@0 381 /* bytes needs to have enough space to hold
michael@0 382 * a SHA256 hash value. Blow up at compile time if this isn't true */
michael@0 383 PR_STATIC_ASSERT(sizeof(bytes) >= SHA256_LENGTH);
michael@0 384 /* create a new global RNG context */
michael@0 385 globalrng = &theGlobalRng;
michael@0 386 PORT_Assert(NULL == globalrng->lock);
michael@0 387 /* create a lock for it */
michael@0 388 globalrng->lock = PZ_NewLock(nssILockOther);
michael@0 389 if (globalrng->lock == NULL) {
michael@0 390 globalrng = NULL;
michael@0 391 PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
michael@0 392 return PR_FAILURE;
michael@0 393 }
michael@0 394
michael@0 395 /* Try to get some seed data for the RNG */
michael@0 396 numBytes = (unsigned int) RNG_SystemRNG(bytes, sizeof bytes);
michael@0 397 PORT_Assert(numBytes == 0 || numBytes == sizeof bytes);
michael@0 398 if (numBytes != 0) {
michael@0 399 /* if this is our first call, instantiate, otherwise reseed
michael@0 400 * prng_instantiate gets a new clean state, we want to mix
michael@0 401 * any previous entropy we may have collected */
michael@0 402 if (V(globalrng)[0] == 0) {
michael@0 403 rv = prng_instantiate(globalrng, bytes, numBytes);
michael@0 404 } else {
michael@0 405 rv = prng_reseed_test(globalrng, bytes, numBytes, NULL, 0);
michael@0 406 }
michael@0 407 memset(bytes, 0, numBytes);
michael@0 408 } else {
michael@0 409 PZ_DestroyLock(globalrng->lock);
michael@0 410 globalrng->lock = NULL;
michael@0 411 globalrng = NULL;
michael@0 412 return PR_FAILURE;
michael@0 413 }
michael@0 414
michael@0 415 if (rv != SECSuccess) {
michael@0 416 return PR_FAILURE;
michael@0 417 }
michael@0 418 /* the RNG is in a valid state */
michael@0 419 globalrng->isValid = PR_TRUE;
michael@0 420
michael@0 421 /* fetch one random value so that we can populate rng->oldV for our
michael@0 422 * continous random number test. */
michael@0 423 prng_generateNewBytes(globalrng, bytes, SHA256_LENGTH, NULL, 0);
michael@0 424
michael@0 425 /* Fetch more entropy into the PRNG */
michael@0 426 RNG_SystemInfoForRNG();
michael@0 427 }
michael@0 428 return PR_SUCCESS;
michael@0 429 }
michael@0 430
michael@0 431 /*
michael@0 432 * Clean up the global RNG context
michael@0 433 */
michael@0 434 static void
michael@0 435 prng_freeRNGContext(RNGContext *rng)
michael@0 436 {
michael@0 437 PRUint8 inputhash[VSize(rng) + (sizeof rng->C)];
michael@0 438
michael@0 439 /* destroy context lock */
michael@0 440 SKIP_AFTER_FORK(PZ_DestroyLock(globalrng->lock));
michael@0 441
michael@0 442 /* zero global RNG context except for C & V to preserve entropy */
michael@0 443 prng_Hash_df(inputhash, sizeof rng->C, rng->C, sizeof rng->C, NULL, 0);
michael@0 444 prng_Hash_df(&inputhash[sizeof rng->C], VSize(rng), V(rng), VSize(rng),
michael@0 445 NULL, 0);
michael@0 446 memset(rng, 0, sizeof *rng);
michael@0 447 memcpy(rng->C, inputhash, sizeof rng->C);
michael@0 448 memcpy(V(rng), &inputhash[sizeof rng->C], VSize(rng));
michael@0 449
michael@0 450 memset(inputhash, 0, sizeof inputhash);
michael@0 451 }
michael@0 452
michael@0 453 /*
michael@0 454 * Public functions
michael@0 455 */
michael@0 456
michael@0 457 /*
michael@0 458 * Initialize the global RNG context and give it some seed input taken
michael@0 459 * from the system. This function is thread-safe and will only allow
michael@0 460 * the global context to be initialized once. The seed input is likely
michael@0 461 * small, so it is imperative that RNG_RandomUpdate() be called with
michael@0 462 * additional seed data before the generator is used. A good way to
michael@0 463 * provide the generator with additional entropy is to call
michael@0 464 * RNG_SystemInfoForRNG(). Note that C_Initialize() does exactly that.
michael@0 465 */
michael@0 466 SECStatus
michael@0 467 RNG_RNGInit(void)
michael@0 468 {
michael@0 469 /* Allow only one call to initialize the context */
michael@0 470 PR_CallOnce(&coRNGInit, rng_init);
michael@0 471 /* Make sure there is a context */
michael@0 472 return (globalrng != NULL) ? SECSuccess : SECFailure;
michael@0 473 }
michael@0 474
michael@0 475 /*
michael@0 476 ** Update the global random number generator with more seeding
michael@0 477 ** material.
michael@0 478 */
michael@0 479 SECStatus
michael@0 480 RNG_RandomUpdate(const void *data, size_t bytes)
michael@0 481 {
michael@0 482 SECStatus rv;
michael@0 483
michael@0 484 /* Make sure our assumption that size_t is unsigned is true */
michael@0 485 PR_STATIC_ASSERT(((size_t)-1) > (size_t)1);
michael@0 486
michael@0 487 #if defined(NS_PTR_GT_32) || (defined(NSS_USE_64) && !defined(NS_PTR_LE_32))
michael@0 488 /*
michael@0 489 * NIST 800-90 requires us to verify our inputs. This value can
michael@0 490 * come from the application, so we need to make sure it's within the
michael@0 491 * spec. The spec says it must be less than 2^32 bytes (2^35 bits).
michael@0 492 * This can only happen if size_t is greater than 32 bits (i.e. on
michael@0 493 * most 64 bit platforms). The 90% case (perhaps 100% case), size_t
michael@0 494 * is less than or equal to 32 bits if the platform is not 64 bits, and
michael@0 495 * greater than 32 bits if it is a 64 bit platform. The corner
michael@0 496 * cases are handled with explicit defines NS_PTR_GT_32 and NS_PTR_LE_32.
michael@0 497 *
michael@0 498 * In general, neither NS_PTR_GT_32 nor NS_PTR_LE_32 will need to be
michael@0 499 * defined. If you trip over the next two size ASSERTS at compile time,
michael@0 500 * you will need to define them for your platform.
michael@0 501 *
michael@0 502 * if 'sizeof(size_t) > 4' is triggered it means that we were expecting
michael@0 503 * sizeof(size_t) to be greater than 4, but it wasn't. Setting
michael@0 504 * NS_PTR_LE_32 will correct that mistake.
michael@0 505 *
michael@0 506 * if 'sizeof(size_t) <= 4' is triggered, it means that we were expecting
michael@0 507 * sizeof(size_t) to be less than or equal to 4, but it wasn't. Setting
michael@0 508 * NS_PTR_GT_32 will correct that mistake.
michael@0 509 */
michael@0 510
michael@0 511 PR_STATIC_ASSERT(sizeof(size_t) > 4);
michael@0 512
michael@0 513 if (bytes > PRNG_MAX_ADDITIONAL_BYTES) {
michael@0 514 bytes = PRNG_MAX_ADDITIONAL_BYTES;
michael@0 515 }
michael@0 516 #else
michael@0 517 PR_STATIC_ASSERT(sizeof(size_t) <= 4);
michael@0 518 #endif
michael@0 519
michael@0 520 PZ_Lock(globalrng->lock);
michael@0 521 /* if we're passed more than our additionalDataCache, simply
michael@0 522 * call reseed with that data */
michael@0 523 if (bytes > sizeof (globalrng->additionalDataCache)) {
michael@0 524 rv = prng_reseed_test(globalrng, NULL, 0, data, (unsigned int) bytes);
michael@0 525 /* if we aren't going to fill or overflow the buffer, just cache it */
michael@0 526 } else if (bytes < ((sizeof globalrng->additionalDataCache)
michael@0 527 - globalrng->additionalAvail)) {
michael@0 528 PORT_Memcpy(globalrng->additionalDataCache+globalrng->additionalAvail,
michael@0 529 data, bytes);
michael@0 530 globalrng->additionalAvail += (PRUint32) bytes;
michael@0 531 rv = SECSuccess;
michael@0 532 } else {
michael@0 533 /* we are going to fill or overflow the buffer. In this case we will
michael@0 534 * fill the entropy buffer, reseed with it, start a new buffer with the
michael@0 535 * remainder. We know the remainder will fit in the buffer because
michael@0 536 * we already handled the case where bytes > the size of the buffer.
michael@0 537 */
michael@0 538 size_t bufRemain = (sizeof globalrng->additionalDataCache)
michael@0 539 - globalrng->additionalAvail;
michael@0 540 /* fill the rest of the buffer */
michael@0 541 if (bufRemain) {
michael@0 542 PORT_Memcpy(globalrng->additionalDataCache
michael@0 543 +globalrng->additionalAvail,
michael@0 544 data, bufRemain);
michael@0 545 data = ((unsigned char *)data) + bufRemain;
michael@0 546 bytes -= bufRemain;
michael@0 547 }
michael@0 548 /* reseed from buffer */
michael@0 549 rv = prng_reseed_test(globalrng, NULL, 0,
michael@0 550 globalrng->additionalDataCache,
michael@0 551 sizeof globalrng->additionalDataCache);
michael@0 552
michael@0 553 /* copy the rest into the cache */
michael@0 554 PORT_Memcpy(globalrng->additionalDataCache, data, bytes);
michael@0 555 globalrng->additionalAvail = (PRUint32) bytes;
michael@0 556 }
michael@0 557
michael@0 558 PZ_Unlock(globalrng->lock);
michael@0 559 return rv;
michael@0 560 }
michael@0 561
michael@0 562 /*
michael@0 563 ** Generate some random bytes, using the global random number generator
michael@0 564 ** object.
michael@0 565 */
michael@0 566 static SECStatus
michael@0 567 prng_GenerateGlobalRandomBytes(RNGContext *rng,
michael@0 568 void *dest, size_t len)
michael@0 569 {
michael@0 570 SECStatus rv = SECSuccess;
michael@0 571 PRUint8 *output = dest;
michael@0 572 /* check for a valid global RNG context */
michael@0 573 PORT_Assert(rng != NULL);
michael@0 574 if (rng == NULL) {
michael@0 575 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 576 return SECFailure;
michael@0 577 }
michael@0 578 /* FIPS limits the amount of entropy available in a single request */
michael@0 579 if (len > PRNG_MAX_REQUEST_SIZE) {
michael@0 580 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 581 return SECFailure;
michael@0 582 }
michael@0 583 /* --- LOCKED --- */
michael@0 584 PZ_Lock(rng->lock);
michael@0 585 /* Check the amount of seed data in the generator. If not enough,
michael@0 586 * don't produce any data.
michael@0 587 */
michael@0 588 if (rng->reseed_counter[0] >= RESEED_VALUE) {
michael@0 589 rv = prng_reseed_test(rng, NULL, 0, NULL, 0);
michael@0 590 PZ_Unlock(rng->lock);
michael@0 591 if (rv != SECSuccess) {
michael@0 592 return rv;
michael@0 593 }
michael@0 594 RNG_SystemInfoForRNG();
michael@0 595 PZ_Lock(rng->lock);
michael@0 596 }
michael@0 597 /*
michael@0 598 * see if we have enough bytes to fulfill the request.
michael@0 599 */
michael@0 600 if (len <= rng->dataAvail) {
michael@0 601 memcpy(output, rng->data + ((sizeof rng->data) - rng->dataAvail), len);
michael@0 602 memset(rng->data + ((sizeof rng->data) - rng->dataAvail), 0, len);
michael@0 603 rng->dataAvail -= len;
michael@0 604 rv = SECSuccess;
michael@0 605 /* if we are asking for a small number of bytes, cache the rest of
michael@0 606 * the bytes */
michael@0 607 } else if (len < sizeof rng->data) {
michael@0 608 rv = prng_generateNewBytes(rng, rng->data, sizeof rng->data,
michael@0 609 rng->additionalAvail ? rng->additionalDataCache : NULL,
michael@0 610 rng->additionalAvail);
michael@0 611 rng->additionalAvail = 0;
michael@0 612 if (rv == SECSuccess) {
michael@0 613 memcpy(output, rng->data, len);
michael@0 614 memset(rng->data, 0, len);
michael@0 615 rng->dataAvail = (sizeof rng->data) - len;
michael@0 616 }
michael@0 617 /* we are asking for lots of bytes, just ask the generator to pass them */
michael@0 618 } else {
michael@0 619 rv = prng_generateNewBytes(rng, output, len,
michael@0 620 rng->additionalAvail ? rng->additionalDataCache : NULL,
michael@0 621 rng->additionalAvail);
michael@0 622 rng->additionalAvail = 0;
michael@0 623 }
michael@0 624 PZ_Unlock(rng->lock);
michael@0 625 /* --- UNLOCKED --- */
michael@0 626 return rv;
michael@0 627 }
michael@0 628
michael@0 629 /*
michael@0 630 ** Generate some random bytes, using the global random number generator
michael@0 631 ** object.
michael@0 632 */
michael@0 633 SECStatus
michael@0 634 RNG_GenerateGlobalRandomBytes(void *dest, size_t len)
michael@0 635 {
michael@0 636 return prng_GenerateGlobalRandomBytes(globalrng, dest, len);
michael@0 637 }
michael@0 638
michael@0 639 void
michael@0 640 RNG_RNGShutdown(void)
michael@0 641 {
michael@0 642 /* check for a valid global RNG context */
michael@0 643 PORT_Assert(globalrng != NULL);
michael@0 644 if (globalrng == NULL) {
michael@0 645 /* Should set a "not initialized" error code. */
michael@0 646 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 647 return;
michael@0 648 }
michael@0 649 /* clear */
michael@0 650 prng_freeRNGContext(globalrng);
michael@0 651 globalrng = NULL;
michael@0 652 /* reset the callonce struct to allow a new call to RNG_RNGInit() */
michael@0 653 coRNGInit = pristineCallOnce;
michael@0 654 }
michael@0 655
michael@0 656 /*
michael@0 657 * Test case interface. used by fips testing and power on self test
michael@0 658 */
michael@0 659 /* make sure the test context is separate from the global context, This
michael@0 660 * allows us to test the internal random number generator without losing
michael@0 661 * entropy we may have previously collected. */
michael@0 662 RNGContext testContext;
michael@0 663
michael@0 664 /*
michael@0 665 * Test vector API. Use NIST SP 800-90 general interface so one of the
michael@0 666 * other NIST SP 800-90 algorithms may be used in the future.
michael@0 667 */
michael@0 668 SECStatus
michael@0 669 PRNGTEST_Instantiate(const PRUint8 *entropy, unsigned int entropy_len,
michael@0 670 const PRUint8 *nonce, unsigned int nonce_len,
michael@0 671 const PRUint8 *personal_string, unsigned int ps_len)
michael@0 672 {
michael@0 673 int bytes_len = entropy_len + nonce_len + ps_len;
michael@0 674 PRUint8 *bytes = NULL;
michael@0 675 SECStatus rv;
michael@0 676
michael@0 677 if (entropy_len < 256/PR_BITS_PER_BYTE) {
michael@0 678 PORT_SetError(SEC_ERROR_NEED_RANDOM);
michael@0 679 return SECFailure;
michael@0 680 }
michael@0 681
michael@0 682 bytes = PORT_Alloc(bytes_len);
michael@0 683 if (bytes == NULL) {
michael@0 684 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 685 return SECFailure;
michael@0 686 }
michael@0 687 /* concatenate the various inputs, internally NSS only instantiates with
michael@0 688 * a single long string */
michael@0 689 PORT_Memcpy(bytes, entropy, entropy_len);
michael@0 690 if (nonce) {
michael@0 691 PORT_Memcpy(&bytes[entropy_len], nonce, nonce_len);
michael@0 692 } else {
michael@0 693 PORT_Assert(nonce_len == 0);
michael@0 694 }
michael@0 695 if (personal_string) {
michael@0 696 PORT_Memcpy(&bytes[entropy_len+nonce_len], personal_string, ps_len);
michael@0 697 } else {
michael@0 698 PORT_Assert(ps_len == 0);
michael@0 699 }
michael@0 700 rv = prng_instantiate(&testContext, bytes, bytes_len);
michael@0 701 PORT_ZFree(bytes, bytes_len);
michael@0 702 if (rv == SECFailure) {
michael@0 703 return SECFailure;
michael@0 704 }
michael@0 705 testContext.isValid = PR_TRUE;
michael@0 706 return SECSuccess;
michael@0 707 }
michael@0 708
michael@0 709 SECStatus
michael@0 710 PRNGTEST_Reseed(const PRUint8 *entropy, unsigned int entropy_len,
michael@0 711 const PRUint8 *additional, unsigned int additional_len)
michael@0 712 {
michael@0 713 if (!testContext.isValid) {
michael@0 714 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
michael@0 715 return SECFailure;
michael@0 716 }
michael@0 717 /* This magic input tells us to set the reseed count to it's max count,
michael@0 718 * so we can simulate PRNGTEST_Generate reaching max reseed count */
michael@0 719 if ((entropy == NULL) && (entropy_len == 0) &&
michael@0 720 (additional == NULL) && (additional_len == 0)) {
michael@0 721 testContext.reseed_counter[0] = RESEED_VALUE;
michael@0 722 return SECSuccess;
michael@0 723 }
michael@0 724 return prng_reseed(&testContext, entropy, entropy_len, additional,
michael@0 725 additional_len);
michael@0 726
michael@0 727 }
michael@0 728
michael@0 729 SECStatus
michael@0 730 PRNGTEST_Generate(PRUint8 *bytes, unsigned int bytes_len,
michael@0 731 const PRUint8 *additional, unsigned int additional_len)
michael@0 732 {
michael@0 733 SECStatus rv;
michael@0 734 if (!testContext.isValid) {
michael@0 735 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
michael@0 736 return SECFailure;
michael@0 737 }
michael@0 738 /* replicate reseed test from prng_GenerateGlobalRandomBytes */
michael@0 739 if (testContext.reseed_counter[0] >= RESEED_VALUE) {
michael@0 740 rv = prng_reseed(&testContext, NULL, 0, NULL, 0);
michael@0 741 if (rv != SECSuccess) {
michael@0 742 return rv;
michael@0 743 }
michael@0 744 }
michael@0 745 return prng_generateNewBytes(&testContext, bytes, bytes_len,
michael@0 746 additional, additional_len);
michael@0 747
michael@0 748 }
michael@0 749
michael@0 750 SECStatus
michael@0 751 PRNGTEST_Uninstantiate()
michael@0 752 {
michael@0 753 if (!testContext.isValid) {
michael@0 754 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
michael@0 755 return SECFailure;
michael@0 756 }
michael@0 757 PORT_Memset(&testContext, 0, sizeof testContext);
michael@0 758 return SECSuccess;
michael@0 759 }
michael@0 760
michael@0 761 SECStatus
michael@0 762 PRNGTEST_RunHealthTests()
michael@0 763 {
michael@0 764 static const PRUint8 entropy[] = {
michael@0 765 0x8e,0x9c,0x0d,0x25,0x75,0x22,0x04,0xf9,
michael@0 766 0xc5,0x79,0x10,0x8b,0x23,0x79,0x37,0x14,
michael@0 767 0x9f,0x2c,0xc7,0x0b,0x39,0xf8,0xee,0xef,
michael@0 768 0x95,0x0c,0x97,0x59,0xfc,0x0a,0x85,0x41,
michael@0 769 0x76,0x9d,0x6d,0x67,0x00,0x4e,0x19,0x12,
michael@0 770 0x02,0x16,0x53,0xea,0xf2,0x73,0xd7,0xd6,
michael@0 771 0x7f,0x7e,0xc8,0xae,0x9c,0x09,0x99,0x7d,
michael@0 772 0xbb,0x9e,0x48,0x7f,0xbb,0x96,0x46,0xb3,
michael@0 773 0x03,0x75,0xf8,0xc8,0x69,0x45,0x3f,0x97,
michael@0 774 0x5e,0x2e,0x48,0xe1,0x5d,0x58,0x97,0x4c };
michael@0 775 static const PRUint8 rng_known_result[] = {
michael@0 776 0x16,0xe1,0x8c,0x57,0x21,0xd8,0xf1,0x7e,
michael@0 777 0x5a,0xa0,0x16,0x0b,0x7e,0xa6,0x25,0xb4,
michael@0 778 0x24,0x19,0xdb,0x54,0xfa,0x35,0x13,0x66,
michael@0 779 0xbb,0xaa,0x2a,0x1b,0x22,0x33,0x2e,0x4a,
michael@0 780 0x14,0x07,0x9d,0x52,0xfc,0x73,0x61,0x48,
michael@0 781 0xac,0xc1,0x22,0xfc,0xa4,0xfc,0xac,0xa4,
michael@0 782 0xdb,0xda,0x5b,0x27,0x33,0xc4,0xb3 };
michael@0 783 static const PRUint8 reseed_entropy[] = {
michael@0 784 0xc6,0x0b,0x0a,0x30,0x67,0x07,0xf4,0xe2,
michael@0 785 0x24,0xa7,0x51,0x6f,0x5f,0x85,0x3e,0x5d,
michael@0 786 0x67,0x97,0xb8,0x3b,0x30,0x9c,0x7a,0xb1,
michael@0 787 0x52,0xc6,0x1b,0xc9,0x46,0xa8,0x62,0x79 };
michael@0 788 static const PRUint8 additional_input[] = {
michael@0 789 0x86,0x82,0x28,0x98,0xe7,0xcb,0x01,0x14,
michael@0 790 0xae,0x87,0x4b,0x1d,0x99,0x1b,0xc7,0x41,
michael@0 791 0x33,0xff,0x33,0x66,0x40,0x95,0x54,0xc6,
michael@0 792 0x67,0x4d,0x40,0x2a,0x1f,0xf9,0xeb,0x65 };
michael@0 793 static const PRUint8 rng_reseed_result[] = {
michael@0 794 0x02,0x0c,0xc6,0x17,0x86,0x49,0xba,0xc4,
michael@0 795 0x7b,0x71,0x35,0x05,0xf0,0xdb,0x4a,0xc2,
michael@0 796 0x2c,0x38,0xc1,0xa4,0x42,0xe5,0x46,0x4a,
michael@0 797 0x7d,0xf0,0xbe,0x47,0x88,0xb8,0x0e,0xc6,
michael@0 798 0x25,0x2b,0x1d,0x13,0xef,0xa6,0x87,0x96,
michael@0 799 0xa3,0x7d,0x5b,0x80,0xc2,0x38,0x76,0x61,
michael@0 800 0xc7,0x80,0x5d,0x0f,0x05,0x76,0x85 };
michael@0 801 static const PRUint8 rng_no_reseed_result[] = {
michael@0 802 0xc4,0x40,0x41,0x8c,0xbf,0x2f,0x70,0x23,
michael@0 803 0x88,0xf2,0x7b,0x30,0xc3,0xca,0x1e,0xf3,
michael@0 804 0xef,0x53,0x81,0x5d,0x30,0xed,0x4c,0xf1,
michael@0 805 0xff,0x89,0xa5,0xee,0x92,0xf8,0xc0,0x0f,
michael@0 806 0x88,0x53,0xdf,0xb6,0x76,0xf0,0xaa,0xd3,
michael@0 807 0x2e,0x1d,0x64,0x37,0x3e,0xe8,0x4a,0x02,
michael@0 808 0xff,0x0a,0x7f,0xe5,0xe9,0x2b,0x6d };
michael@0 809
michael@0 810 SECStatus rng_status = SECSuccess;
michael@0 811 PR_STATIC_ASSERT(sizeof(rng_known_result) >= sizeof(rng_reseed_result));
michael@0 812 PRUint8 result[sizeof(rng_known_result)];
michael@0 813
michael@0 814 /********************************************/
michael@0 815 /* First test instantiate error path. */
michael@0 816 /* In this case we supply enough entropy, */
michael@0 817 /* but not enough seed. This will trigger */
michael@0 818 /* the code that checks for a entropy */
michael@0 819 /* source failure. */
michael@0 820 /********************************************/
michael@0 821 rng_status = PRNGTEST_Instantiate(entropy, 256/PR_BITS_PER_BYTE,
michael@0 822 NULL, 0, NULL, 0);
michael@0 823 if (rng_status == SECSuccess) {
michael@0 824 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
michael@0 825 return SECFailure;
michael@0 826 }
michael@0 827 if (PORT_GetError() != SEC_ERROR_NEED_RANDOM) {
michael@0 828 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
michael@0 829 return SECFailure;
michael@0 830 }
michael@0 831 /* we failed with the proper error code, we can continue */
michael@0 832
michael@0 833 /********************************************/
michael@0 834 /* Generate random bytes with a known seed. */
michael@0 835 /********************************************/
michael@0 836 rng_status = PRNGTEST_Instantiate(entropy, sizeof entropy,
michael@0 837 NULL, 0, NULL, 0);
michael@0 838 if (rng_status != SECSuccess) {
michael@0 839 /* Error set by PRNGTEST_Instantiate */
michael@0 840 return SECFailure;
michael@0 841 }
michael@0 842 rng_status = PRNGTEST_Generate(result, sizeof rng_known_result, NULL, 0);
michael@0 843 if ( ( rng_status != SECSuccess) ||
michael@0 844 ( PORT_Memcmp( result, rng_known_result,
michael@0 845 sizeof rng_known_result ) != 0 ) ) {
michael@0 846 PRNGTEST_Uninstantiate();
michael@0 847 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
michael@0 848 return SECFailure;
michael@0 849 }
michael@0 850 rng_status = PRNGTEST_Reseed(reseed_entropy, sizeof reseed_entropy,
michael@0 851 additional_input, sizeof additional_input);
michael@0 852 if (rng_status != SECSuccess) {
michael@0 853 /* Error set by PRNG_Reseed */
michael@0 854 PRNGTEST_Uninstantiate();
michael@0 855 return SECFailure;
michael@0 856 }
michael@0 857 rng_status = PRNGTEST_Generate(result, sizeof rng_reseed_result, NULL, 0);
michael@0 858 if ( ( rng_status != SECSuccess) ||
michael@0 859 ( PORT_Memcmp( result, rng_reseed_result,
michael@0 860 sizeof rng_reseed_result ) != 0 ) ) {
michael@0 861 PRNGTEST_Uninstantiate();
michael@0 862 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
michael@0 863 return SECFailure;
michael@0 864 }
michael@0 865 /* This magic forces the reseed count to it's max count, so we can see if
michael@0 866 * PRNGTEST_Generate will actually when it reaches it's count */
michael@0 867 rng_status = PRNGTEST_Reseed(NULL, 0, NULL, 0);
michael@0 868 if (rng_status != SECSuccess) {
michael@0 869 PRNGTEST_Uninstantiate();
michael@0 870 /* Error set by PRNG_Reseed */
michael@0 871 return SECFailure;
michael@0 872 }
michael@0 873 /* This generate should now reseed */
michael@0 874 rng_status = PRNGTEST_Generate(result, sizeof rng_reseed_result, NULL, 0);
michael@0 875 if ( ( rng_status != SECSuccess) ||
michael@0 876 /* NOTE we fail if the result is equal to the no_reseed_result.
michael@0 877 * no_reseed_result is the value we would have gotten if we didn't
michael@0 878 * do an automatic reseed in PRNGTEST_Generate */
michael@0 879 ( PORT_Memcmp( result, rng_no_reseed_result,
michael@0 880 sizeof rng_no_reseed_result ) == 0 ) ) {
michael@0 881 PRNGTEST_Uninstantiate();
michael@0 882 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
michael@0 883 return SECFailure;
michael@0 884 }
michael@0 885 /* make sure reseed fails when we don't supply enough entropy */
michael@0 886 rng_status = PRNGTEST_Reseed(reseed_entropy, 4, NULL, 0);
michael@0 887 if (rng_status == SECSuccess) {
michael@0 888 PRNGTEST_Uninstantiate();
michael@0 889 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
michael@0 890 return SECFailure;
michael@0 891 }
michael@0 892 if (PORT_GetError() != SEC_ERROR_NEED_RANDOM) {
michael@0 893 PRNGTEST_Uninstantiate();
michael@0 894 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
michael@0 895 return SECFailure;
michael@0 896 }
michael@0 897 rng_status = PRNGTEST_Uninstantiate();
michael@0 898 if (rng_status != SECSuccess) {
michael@0 899 /* Error set by PRNG_Uninstantiate */
michael@0 900 return rng_status;
michael@0 901 }
michael@0 902 /* make sure uninstantiate fails if the contest is not initiated (also tests
michael@0 903 * if the context was cleared in the previous Uninstantiate) */
michael@0 904 rng_status = PRNGTEST_Uninstantiate();
michael@0 905 if (rng_status == SECSuccess) {
michael@0 906 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
michael@0 907 return SECFailure;
michael@0 908 }
michael@0 909 if (PORT_GetError() != SEC_ERROR_LIBRARY_FAILURE) {
michael@0 910 return rng_status;
michael@0 911 }
michael@0 912
michael@0 913 return SECSuccess;
michael@0 914 }

mercurial