OLD | NEW |
1 /* This Source Code Form is subject to the terms of the Mozilla Public | 1 /* This Source Code Form is subject to the terms of the Mozilla Public |
2 * License, v. 2.0. If a copy of the MPL was not distributed with this | 2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 /* $Id: drbg.c,v 1.11 2012/06/28 17:55:05 rrelyea%redhat.com Exp $ */ | 4 /* $Id: drbg.c,v 1.11 2012/06/28 17:55:05 rrelyea%redhat.com Exp $ */ |
5 | 5 |
6 #ifdef FREEBL_NO_DEPEND | 6 #ifdef FREEBL_NO_DEPEND |
7 #include "stubs.h" | 7 #include "stubs.h" |
8 #endif | 8 #endif |
9 | 9 |
10 #include "prerror.h" | 10 #include "prerror.h" |
(...skipping 14 matching lines...) Expand all Loading... |
25 * for SHA-1, SHA-224, and SHA-256 it's 440 bits. | 25 * for SHA-1, SHA-224, and SHA-256 it's 440 bits. |
26 * for SHA-384 and SHA-512 it's 888 bits */ | 26 * for SHA-384 and SHA-512 it's 888 bits */ |
27 #define PRNG_SEEDLEN (440/PR_BITS_PER_BYTE) | 27 #define PRNG_SEEDLEN (440/PR_BITS_PER_BYTE) |
28 static const PRInt64 PRNG_MAX_ADDITIONAL_BYTES = LL_INIT(0x1, 0x0); | 28 static const PRInt64 PRNG_MAX_ADDITIONAL_BYTES = LL_INIT(0x1, 0x0); |
29 /* 2^35 bits or 2^32 bytes */ | 29 /* 2^35 bits or 2^32 bytes */ |
30 #define PRNG_MAX_REQUEST_SIZE 0x10000 /* 2^19 bits or 2^16 bytes */ | 30 #define PRNG_MAX_REQUEST_SIZE 0x10000 /* 2^19 bits or 2^16 bytes */ |
31 #define PRNG_ADDITONAL_DATA_CACHE_SIZE (8*1024) /* must be less than | 31 #define PRNG_ADDITONAL_DATA_CACHE_SIZE (8*1024) /* must be less than |
32 * PRNG_MAX_ADDITIONAL_BYTES | 32 * PRNG_MAX_ADDITIONAL_BYTES |
33 */ | 33 */ |
34 | 34 |
35 | |
36 /* RESEED_COUNT is how many calls to the prng before we need to reseed | 35 /* RESEED_COUNT is how many calls to the prng before we need to reseed |
37 * under normal NIST rules, you must return an error. In the NSS case, we | 36 * under normal NIST rules, you must return an error. In the NSS case, we |
38 * self-reseed with RNG_SystemRNG(). Count can be a large number. For code | 37 * self-reseed with RNG_SystemRNG(). Count can be a large number. For code |
39 * simplicity, we specify count with 2 components: RESEED_BYTE (which is | 38 * simplicity, we specify count with 2 components: RESEED_BYTE (which is |
40 * the same as LOG256(RESEED_COUNT)) and RESEED_VALUE (which is the same as | 39 * the same as LOG256(RESEED_COUNT)) and RESEED_VALUE (which is the same as |
41 * RESEED_COUNT / (256 ^ RESEED_BYTE)). Another way to look at this is | 40 * RESEED_COUNT / (256 ^ RESEED_BYTE)). Another way to look at this is |
42 * RESEED_COUNT = RESEED_VALUE * (256 ^ RESEED_BYTE). For Hash based DRBG | 41 * RESEED_COUNT = RESEED_VALUE * (256 ^ RESEED_BYTE). For Hash based DRBG |
43 * we use the maximum count value, 2^48, or RESEED_BYTE=6 and RESEED_VALUE=1 | 42 * we use the maximum count value, 2^48, or RESEED_BYTE=6 and RESEED_VALUE=1 |
44 */ | 43 */ |
45 #define RESEED_BYTE 6 | 44 #define RESEED_BYTE 6 |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
150 } | 149 } |
151 | 150 |
152 | 151 |
153 /* | 152 /* |
154 * Hash_DRBG Instantiate NIST SP 800-80 10.1.1.2 | 153 * Hash_DRBG Instantiate NIST SP 800-80 10.1.1.2 |
155 * | 154 * |
156 * NOTE: bytes & len are entropy || nonce || personalization_string. In | 155 * NOTE: bytes & len are entropy || nonce || personalization_string. In |
157 * normal operation, NSS calculates them all together in a single call. | 156 * normal operation, NSS calculates them all together in a single call. |
158 */ | 157 */ |
159 static SECStatus | 158 static SECStatus |
160 prng_instantiate(RNGContext *rng, PRUint8 *bytes, unsigned int len) | 159 prng_instantiate(RNGContext *rng, const PRUint8 *bytes, unsigned int len) |
161 { | 160 { |
| 161 if (len < PRNG_SEEDLEN) { |
| 162 /* if the seedlen is to small, it's probably because we failed to get |
| 163 * enough random data */ |
| 164 PORT_SetError(SEC_ERROR_NEED_RANDOM); |
| 165 return SECFailure; |
| 166 } |
162 prng_Hash_df(V(rng), VSize(rng), bytes, len, NULL, 0); | 167 prng_Hash_df(V(rng), VSize(rng), bytes, len, NULL, 0); |
163 rng->V_type = prngCGenerateType; | 168 rng->V_type = prngCGenerateType; |
164 prng_Hash_df(rng->C,sizeof rng->C,rng->V_Data,sizeof rng->V_Data,NULL,0); | 169 prng_Hash_df(rng->C,sizeof rng->C,rng->V_Data,sizeof rng->V_Data,NULL,0); |
165 PRNG_RESET_RESEED_COUNT(rng) | 170 PRNG_RESET_RESEED_COUNT(rng) |
166 return SECSuccess; | 171 return SECSuccess; |
167 } | 172 } |
168 | 173 |
169 | 174 |
170 /* | 175 /* |
171 * Update the global random number generator with more seeding | 176 * Update the global random number generator with more seeding |
172 * material. Use the Hash_DRBG reseed algorithm from NIST SP-800-90 | 177 * material. Use the Hash_DRBG reseed algorithm from NIST SP-800-90 |
173 * section 10.1.1.3 | 178 * section 10.1.1.3 |
174 * | 179 * |
175 * If entropy is NULL, it is fetched from the noise generator. | 180 * If entropy is NULL, it is fetched from the noise generator. |
176 */ | 181 */ |
177 static | 182 static SECStatus |
178 SECStatus | |
179 prng_reseed(RNGContext *rng, const PRUint8 *entropy, unsigned int entropy_len, | 183 prng_reseed(RNGContext *rng, const PRUint8 *entropy, unsigned int entropy_len, |
180 const PRUint8 *additional_input, unsigned int additional_input_len) | 184 const PRUint8 *additional_input, unsigned int additional_input_len) |
181 { | 185 { |
182 PRUint8 noiseData[(sizeof rng->V_Data)+PRNG_SEEDLEN]; | 186 PRUint8 noiseData[(sizeof rng->V_Data)+PRNG_SEEDLEN]; |
183 PRUint8 *noise = &noiseData[0]; | 187 PRUint8 *noise = &noiseData[0]; |
184 | 188 |
185 /* if entropy wasn't supplied, fetch it. (normal operation case) */ | 189 /* if entropy wasn't supplied, fetch it. (normal operation case) */ |
186 if (entropy == NULL) { | 190 if (entropy == NULL) { |
187 entropy_len = (unsigned int) RNG_SystemRNG( | 191 entropy_len = (unsigned int) RNG_SystemRNG( |
188 &noiseData[sizeof rng->V_Data], PRNG_SEEDLEN); | 192 &noiseData[sizeof rng->V_Data], PRNG_SEEDLEN); |
189 } else { | 193 } else { |
190 /* NOTE: this code is only available for testing, not to applications */ | 194 /* NOTE: this code is only available for testing, not to applications */ |
191 /* if entropy was too big for the stack variable, get it from malloc */ | 195 /* if entropy was too big for the stack variable, get it from malloc */ |
192 if (entropy_len > PRNG_SEEDLEN) { | 196 if (entropy_len > PRNG_SEEDLEN) { |
193 noise = PORT_Alloc(entropy_len + (sizeof rng->V_Data)); | 197 noise = PORT_Alloc(entropy_len + (sizeof rng->V_Data)); |
194 if (noise == NULL) { | 198 if (noise == NULL) { |
195 return SECFailure; | 199 return SECFailure; |
196 } | 200 } |
197 } | 201 } |
198 PORT_Memcpy(&noise[sizeof rng->V_Data],entropy, entropy_len); | 202 PORT_Memcpy(&noise[sizeof rng->V_Data],entropy, entropy_len); |
199 } | 203 } |
200 | 204 |
| 205 if (entropy_len < 256/PR_BITS_PER_BYTE) { |
| 206 /* noise == &noiseData[0] at this point, so nothing to free */ |
| 207 PORT_SetError(SEC_ERROR_NEED_RANDOM); |
| 208 return SECFailure; |
| 209 } |
| 210 |
201 rng->V_type = prngReseedType; | 211 rng->V_type = prngReseedType; |
202 PORT_Memcpy(noise, rng->V_Data, sizeof rng->V_Data); | 212 PORT_Memcpy(noise, rng->V_Data, sizeof rng->V_Data); |
203 prng_Hash_df(V(rng), VSize(rng), noise, (sizeof rng->V_Data) + entropy_len, | 213 prng_Hash_df(V(rng), VSize(rng), noise, (sizeof rng->V_Data) + entropy_len, |
204 additional_input, additional_input_len); | 214 additional_input, additional_input_len); |
205 /* clear potential CSP */ | 215 /* clear potential CSP */ |
206 PORT_Memset(noise, 0, (sizeof rng->V_Data) + entropy_len); | 216 PORT_Memset(noise, 0, (sizeof rng->V_Data) + entropy_len); |
207 rng->V_type = prngCGenerateType; | 217 rng->V_type = prngCGenerateType; |
208 prng_Hash_df(rng->C,sizeof rng->C,rng->V_Data,sizeof rng->V_Data,NULL,0); | 218 prng_Hash_df(rng->C,sizeof rng->C,rng->V_Data,sizeof rng->V_Data,NULL,0); |
209 PRNG_RESET_RESEED_COUNT(rng) | 219 PRNG_RESET_RESEED_COUNT(rng) |
210 | 220 |
211 if (noise != &noiseData[0]) { | 221 if (noise != &noiseData[0]) { |
212 PORT_Free(noise); | 222 PORT_Free(noise); |
213 } | 223 } |
214 return SECSuccess; | 224 return SECSuccess; |
215 } | 225 } |
216 | 226 |
217 /* | 227 /* |
| 228 * SP 800-90 requires we rerun our health tests on reseed |
| 229 */ |
| 230 static SECStatus |
| 231 prng_reseed_test(RNGContext *rng, const PRUint8 *entropy, |
| 232 unsigned int entropy_len, const PRUint8 *additional_input, |
| 233 unsigned int additional_input_len) |
| 234 { |
| 235 SECStatus rv; |
| 236 |
| 237 /* do health checks in FIPS mode */ |
| 238 rv = PRNGTEST_RunHealthTests(); |
| 239 if (rv != SECSuccess) { |
| 240 /* error set by PRNGTEST_RunHealTests() */ |
| 241 rng->isValid = PR_FALSE; |
| 242 return SECFailure; |
| 243 } |
| 244 return prng_reseed(rng, entropy, entropy_len, |
| 245 additional_input, additional_input_len); |
| 246 } |
| 247 |
| 248 /* |
218 * build some fast inline functions for adding. | 249 * build some fast inline functions for adding. |
219 */ | 250 */ |
220 #define PRNG_ADD_CARRY_ONLY(dest, start, cy) \ | 251 #define PRNG_ADD_CARRY_ONLY(dest, start, cy) \ |
221 carry = cy; \ | 252 carry = cy; \ |
222 for (k1=start; carry && k1 >=0 ; k1--) { \ | 253 for (k1=start; carry && k1 >=0 ; k1--) { \ |
223 carry = !(++dest[k1]); \ | 254 carry = !(++dest[k1]); \ |
224 } | 255 } |
225 | 256 |
226 /* | 257 /* |
227 * NOTE: dest must be an array for the following to work. | 258 * NOTE: dest must be an array for the following to work. |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
338 | 369 |
339 /* Use NSPR to prevent RNG_RNGInit from being called from separate | 370 /* Use NSPR to prevent RNG_RNGInit from being called from separate |
340 * threads, creating a race condition. | 371 * threads, creating a race condition. |
341 */ | 372 */ |
342 static const PRCallOnceType pristineCallOnce; | 373 static const PRCallOnceType pristineCallOnce; |
343 static PRCallOnceType coRNGInit; | 374 static PRCallOnceType coRNGInit; |
344 static PRStatus rng_init(void) | 375 static PRStatus rng_init(void) |
345 { | 376 { |
346 PRUint8 bytes[PRNG_SEEDLEN*2]; /* entropy + nonce */ | 377 PRUint8 bytes[PRNG_SEEDLEN*2]; /* entropy + nonce */ |
347 unsigned int numBytes; | 378 unsigned int numBytes; |
| 379 SECStatus rv = SECSuccess; |
| 380 |
348 if (globalrng == NULL) { | 381 if (globalrng == NULL) { |
349 /* bytes needs to have enough space to hold | 382 /* bytes needs to have enough space to hold |
350 * a SHA256 hash value. Blow up at compile time if this isn't true */ | 383 * a SHA256 hash value. Blow up at compile time if this isn't true */ |
351 PR_STATIC_ASSERT(sizeof(bytes) >= SHA256_LENGTH); | 384 PR_STATIC_ASSERT(sizeof(bytes) >= SHA256_LENGTH); |
352 /* create a new global RNG context */ | 385 /* create a new global RNG context */ |
353 globalrng = &theGlobalRng; | 386 globalrng = &theGlobalRng; |
354 PORT_Assert(NULL == globalrng->lock); | 387 PORT_Assert(NULL == globalrng->lock); |
355 /* create a lock for it */ | 388 /* create a lock for it */ |
356 globalrng->lock = PZ_NewLock(nssILockOther); | 389 globalrng->lock = PZ_NewLock(nssILockOther); |
357 if (globalrng->lock == NULL) { | 390 if (globalrng->lock == NULL) { |
358 globalrng = NULL; | 391 globalrng = NULL; |
359 PORT_SetError(PR_OUT_OF_MEMORY_ERROR); | 392 PORT_SetError(PR_OUT_OF_MEMORY_ERROR); |
360 return PR_FAILURE; | 393 return PR_FAILURE; |
361 } | 394 } |
362 | 395 |
363 /* Try to get some seed data for the RNG */ | 396 /* Try to get some seed data for the RNG */ |
364 numBytes = (unsigned int) RNG_SystemRNG(bytes, sizeof bytes); | 397 numBytes = (unsigned int) RNG_SystemRNG(bytes, sizeof bytes); |
365 PORT_Assert(numBytes == 0 || numBytes == sizeof bytes); | 398 PORT_Assert(numBytes == 0 || numBytes == sizeof bytes); |
366 if (numBytes != 0) { | 399 if (numBytes != 0) { |
367 /* if this is our first call, instantiate, otherwise reseed | 400 /* if this is our first call, instantiate, otherwise reseed |
368 * prng_instantiate gets a new clean state, we want to mix | 401 * prng_instantiate gets a new clean state, we want to mix |
369 * any previous entropy we may have collected */ | 402 * any previous entropy we may have collected */ |
370 if (V(globalrng)[0] == 0) { | 403 if (V(globalrng)[0] == 0) { |
371 » » prng_instantiate(globalrng, bytes, numBytes); | 404 » » rv = prng_instantiate(globalrng, bytes, numBytes); |
372 } else { | 405 } else { |
373 » » prng_reseed(globalrng, bytes, numBytes, NULL, 0); | 406 » » rv = prng_reseed_test(globalrng, bytes, numBytes, NULL, 0); |
374 } | 407 } |
375 memset(bytes, 0, numBytes); | 408 memset(bytes, 0, numBytes); |
376 } else { | 409 } else { |
377 PZ_DestroyLock(globalrng->lock); | 410 PZ_DestroyLock(globalrng->lock); |
378 globalrng->lock = NULL; | 411 globalrng->lock = NULL; |
379 globalrng = NULL; | 412 globalrng = NULL; |
380 return PR_FAILURE; | 413 return PR_FAILURE; |
381 } | 414 } |
| 415 |
| 416 if (rv != SECSuccess) { |
| 417 return PR_FAILURE; |
| 418 } |
382 /* the RNG is in a valid state */ | 419 /* the RNG is in a valid state */ |
383 globalrng->isValid = PR_TRUE; | 420 globalrng->isValid = PR_TRUE; |
384 | 421 |
385 /* fetch one random value so that we can populate rng->oldV for our | 422 /* fetch one random value so that we can populate rng->oldV for our |
386 * continous random number test. */ | 423 * continous random number test. */ |
387 prng_generateNewBytes(globalrng, bytes, SHA256_LENGTH, NULL, 0); | 424 prng_generateNewBytes(globalrng, bytes, SHA256_LENGTH, NULL, 0); |
388 | 425 |
389 /* Fetch more entropy into the PRNG */ | 426 /* Fetch more entropy into the PRNG */ |
390 RNG_SystemInfoForRNG(); | 427 RNG_SystemInfoForRNG(); |
391 } | 428 } |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
478 bytes = PRNG_MAX_ADDITIONAL_BYTES; | 515 bytes = PRNG_MAX_ADDITIONAL_BYTES; |
479 } | 516 } |
480 #else | 517 #else |
481 PR_STATIC_ASSERT(sizeof(size_t) <= 4); | 518 PR_STATIC_ASSERT(sizeof(size_t) <= 4); |
482 #endif | 519 #endif |
483 | 520 |
484 PZ_Lock(globalrng->lock); | 521 PZ_Lock(globalrng->lock); |
485 /* if we're passed more than our additionalDataCache, simply | 522 /* if we're passed more than our additionalDataCache, simply |
486 * call reseed with that data */ | 523 * call reseed with that data */ |
487 if (bytes > sizeof (globalrng->additionalDataCache)) { | 524 if (bytes > sizeof (globalrng->additionalDataCache)) { |
488 » rv = prng_reseed(globalrng, NULL, 0, data, (unsigned int) bytes); | 525 » rv = prng_reseed_test(globalrng, NULL, 0, data, (unsigned int) bytes); |
489 /* if we aren't going to fill or overflow the buffer, just cache it */ | 526 /* if we aren't going to fill or overflow the buffer, just cache it */ |
490 } else if (bytes < ((sizeof globalrng->additionalDataCache) | 527 } else if (bytes < ((sizeof globalrng->additionalDataCache) |
491 - globalrng->additionalAvail)) { | 528 - globalrng->additionalAvail)) { |
492 PORT_Memcpy(globalrng->additionalDataCache+globalrng->additionalAvail, | 529 PORT_Memcpy(globalrng->additionalDataCache+globalrng->additionalAvail, |
493 data, bytes); | 530 data, bytes); |
494 globalrng->additionalAvail += (PRUint32) bytes; | 531 globalrng->additionalAvail += (PRUint32) bytes; |
495 rv = SECSuccess; | 532 rv = SECSuccess; |
496 } else { | 533 } else { |
497 /* we are going to fill or overflow the buffer. In this case we will | 534 /* we are going to fill or overflow the buffer. In this case we will |
498 * fill the entropy buffer, reseed with it, start a new buffer with the | 535 * fill the entropy buffer, reseed with it, start a new buffer with the |
499 * remainder. We know the remainder will fit in the buffer because | 536 * remainder. We know the remainder will fit in the buffer because |
500 * we already handled the case where bytes > the size of the buffer. | 537 * we already handled the case where bytes > the size of the buffer. |
501 */ | 538 */ |
502 size_t bufRemain = (sizeof globalrng->additionalDataCache) | 539 size_t bufRemain = (sizeof globalrng->additionalDataCache) |
503 - globalrng->additionalAvail; | 540 - globalrng->additionalAvail; |
504 /* fill the rest of the buffer */ | 541 /* fill the rest of the buffer */ |
505 if (bufRemain) { | 542 if (bufRemain) { |
506 PORT_Memcpy(globalrng->additionalDataCache | 543 PORT_Memcpy(globalrng->additionalDataCache |
507 +globalrng->additionalAvail, | 544 +globalrng->additionalAvail, |
508 data, bufRemain); | 545 data, bufRemain); |
509 data = ((unsigned char *)data) + bufRemain; | 546 data = ((unsigned char *)data) + bufRemain; |
510 bytes -= bufRemain; | 547 bytes -= bufRemain; |
511 } | 548 } |
512 /* reseed from buffer */ | 549 /* reseed from buffer */ |
513 » rv = prng_reseed(globalrng, NULL, 0, globalrng->additionalDataCache, | 550 » rv = prng_reseed_test(globalrng, NULL, 0, |
| 551 » » » » globalrng->additionalDataCache, |
514 sizeof globalrng->additionalDataCache); | 552 sizeof globalrng->additionalDataCache); |
515 | 553 |
516 /* copy the rest into the cache */ | 554 /* copy the rest into the cache */ |
517 PORT_Memcpy(globalrng->additionalDataCache, data, bytes); | 555 PORT_Memcpy(globalrng->additionalDataCache, data, bytes); |
518 globalrng->additionalAvail = (PRUint32) bytes; | 556 globalrng->additionalAvail = (PRUint32) bytes; |
519 } | 557 } |
520 | 558 |
521 PZ_Unlock(globalrng->lock); | 559 PZ_Unlock(globalrng->lock); |
522 return rv; | 560 return rv; |
523 } | 561 } |
(...skipping 18 matching lines...) Expand all Loading... |
542 if (len > PRNG_MAX_REQUEST_SIZE) { | 580 if (len > PRNG_MAX_REQUEST_SIZE) { |
543 PORT_SetError(SEC_ERROR_INVALID_ARGS); | 581 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
544 return SECFailure; | 582 return SECFailure; |
545 } | 583 } |
546 /* --- LOCKED --- */ | 584 /* --- LOCKED --- */ |
547 PZ_Lock(rng->lock); | 585 PZ_Lock(rng->lock); |
548 /* Check the amount of seed data in the generator. If not enough, | 586 /* Check the amount of seed data in the generator. If not enough, |
549 * don't produce any data. | 587 * don't produce any data. |
550 */ | 588 */ |
551 if (rng->reseed_counter[0] >= RESEED_VALUE) { | 589 if (rng->reseed_counter[0] >= RESEED_VALUE) { |
552 » rv = prng_reseed(rng, NULL, 0, NULL, 0); | 590 » rv = prng_reseed_test(rng, NULL, 0, NULL, 0); |
553 PZ_Unlock(rng->lock); | 591 PZ_Unlock(rng->lock); |
554 if (rv != SECSuccess) { | 592 if (rv != SECSuccess) { |
555 return rv; | 593 return rv; |
556 } | 594 } |
557 RNG_SystemInfoForRNG(); | 595 RNG_SystemInfoForRNG(); |
558 PZ_Lock(rng->lock); | 596 PZ_Lock(rng->lock); |
559 } | 597 } |
560 /* | 598 /* |
561 * see if we have enough bytes to fulfill the request. | 599 * see if we have enough bytes to fulfill the request. |
562 */ | 600 */ |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
599 return prng_GenerateGlobalRandomBytes(globalrng, dest, len); | 637 return prng_GenerateGlobalRandomBytes(globalrng, dest, len); |
600 } | 638 } |
601 | 639 |
602 void | 640 void |
603 RNG_RNGShutdown(void) | 641 RNG_RNGShutdown(void) |
604 { | 642 { |
605 /* check for a valid global RNG context */ | 643 /* check for a valid global RNG context */ |
606 PORT_Assert(globalrng != NULL); | 644 PORT_Assert(globalrng != NULL); |
607 if (globalrng == NULL) { | 645 if (globalrng == NULL) { |
608 /* Should set a "not initialized" error code. */ | 646 /* Should set a "not initialized" error code. */ |
609 » PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | 647 » PORT_SetError(SEC_ERROR_NO_MEMORY); |
610 return; | 648 return; |
611 } | 649 } |
612 /* clear */ | 650 /* clear */ |
613 prng_freeRNGContext(globalrng); | 651 prng_freeRNGContext(globalrng); |
614 globalrng = NULL; | 652 globalrng = NULL; |
615 /* reset the callonce struct to allow a new call to RNG_RNGInit() */ | 653 /* reset the callonce struct to allow a new call to RNG_RNGInit() */ |
616 coRNGInit = pristineCallOnce; | 654 coRNGInit = pristineCallOnce; |
617 } | 655 } |
618 | 656 |
619 /* | 657 /* |
620 * Test case interface. used by fips testing and power on self test | 658 * Test case interface. used by fips testing and power on self test |
621 */ | 659 */ |
622 /* make sure the test context is separate from the global context, This | 660 /* make sure the test context is separate from the global context, This |
623 * allows us to test the internal random number generator without losing | 661 * allows us to test the internal random number generator without losing |
624 * entropy we may have previously collected. */ | 662 * entropy we may have previously collected. */ |
625 RNGContext testContext; | 663 RNGContext testContext; |
626 | 664 |
627 /* | 665 /* |
628 * Test vector API. Use NIST SP 800-90 general interface so one of the | 666 * Test vector API. Use NIST SP 800-90 general interface so one of the |
629 * other NIST SP 800-90 algorithms may be used in the future. | 667 * other NIST SP 800-90 algorithms may be used in the future. |
630 */ | 668 */ |
631 SECStatus | 669 SECStatus |
632 PRNGTEST_Instantiate(const PRUint8 *entropy, unsigned int entropy_len, | 670 PRNGTEST_Instantiate(const PRUint8 *entropy, unsigned int entropy_len, |
633 const PRUint8 *nonce, unsigned int nonce_len, | 671 const PRUint8 *nonce, unsigned int nonce_len, |
634 const PRUint8 *personal_string, unsigned int ps_len) | 672 const PRUint8 *personal_string, unsigned int ps_len) |
635 { | 673 { |
636 int bytes_len = entropy_len + nonce_len + ps_len; | 674 int bytes_len = entropy_len + nonce_len + ps_len; |
637 PRUint8 *bytes = PORT_Alloc(bytes_len); | 675 PRUint8 *bytes = NULL; |
| 676 SECStatus rv; |
638 | 677 |
| 678 if (entropy_len < 256/PR_BITS_PER_BYTE) { |
| 679 PORT_SetError(SEC_ERROR_NEED_RANDOM); |
| 680 return SECFailure; |
| 681 } |
| 682 |
| 683 bytes = PORT_Alloc(bytes_len); |
639 if (bytes == NULL) { | 684 if (bytes == NULL) { |
| 685 PORT_SetError(SEC_ERROR_NO_MEMORY); |
640 return SECFailure; | 686 return SECFailure; |
641 } | 687 } |
642 /* concatenate the various inputs, internally NSS only instantiates with | 688 /* concatenate the various inputs, internally NSS only instantiates with |
643 * a single long string */ | 689 * a single long string */ |
644 PORT_Memcpy(bytes, entropy, entropy_len); | 690 PORT_Memcpy(bytes, entropy, entropy_len); |
645 if (nonce) { | 691 if (nonce) { |
646 PORT_Memcpy(&bytes[entropy_len], nonce, nonce_len); | 692 PORT_Memcpy(&bytes[entropy_len], nonce, nonce_len); |
647 } else { | 693 } else { |
648 PORT_Assert(nonce_len == 0); | 694 PORT_Assert(nonce_len == 0); |
649 } | 695 } |
650 if (personal_string) { | 696 if (personal_string) { |
651 PORT_Memcpy(&bytes[entropy_len+nonce_len], personal_string, ps_len); | 697 PORT_Memcpy(&bytes[entropy_len+nonce_len], personal_string, ps_len); |
652 } else { | 698 } else { |
653 PORT_Assert(ps_len == 0); | 699 PORT_Assert(ps_len == 0); |
654 } | 700 } |
655 prng_instantiate(&testContext, bytes, bytes_len); | 701 rv = prng_instantiate(&testContext, bytes, bytes_len); |
| 702 PORT_ZFree(bytes, bytes_len); |
| 703 if (rv == SECFailure) { |
| 704 » return SECFailure; |
| 705 } |
656 testContext.isValid = PR_TRUE; | 706 testContext.isValid = PR_TRUE; |
657 PORT_ZFree(bytes, bytes_len); | |
658 return SECSuccess; | 707 return SECSuccess; |
659 } | 708 } |
660 | 709 |
661 SECStatus | 710 SECStatus |
662 PRNGTEST_Reseed(const PRUint8 *entropy, unsigned int entropy_len, | 711 PRNGTEST_Reseed(const PRUint8 *entropy, unsigned int entropy_len, |
663 const PRUint8 *additional, unsigned int additional_len) | 712 const PRUint8 *additional, unsigned int additional_len) |
664 { | 713 { |
665 if (!testContext.isValid) { | 714 if (!testContext.isValid) { |
666 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | 715 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
667 return SECFailure; | 716 return SECFailure; |
668 } | 717 } |
| 718 /* This magic input tells us to set the reseed count to it's max count, |
| 719 * so we can simulate PRNGTEST_Generate reaching max reseed count */ |
| 720 if ((entropy == NULL) && (entropy_len == 0) && |
| 721 (additional == NULL) && (additional_len == 0)) { |
| 722 testContext.reseed_counter[0] = RESEED_VALUE; |
| 723 return SECSuccess; |
| 724 } |
669 return prng_reseed(&testContext, entropy, entropy_len, additional, | 725 return prng_reseed(&testContext, entropy, entropy_len, additional, |
670 additional_len); | 726 additional_len); |
671 | 727 |
672 } | 728 } |
673 | 729 |
674 SECStatus | 730 SECStatus |
675 PRNGTEST_Generate(PRUint8 *bytes, unsigned int bytes_len, | 731 PRNGTEST_Generate(PRUint8 *bytes, unsigned int bytes_len, |
676 const PRUint8 *additional, unsigned int additional_len) | 732 const PRUint8 *additional, unsigned int additional_len) |
677 { | 733 { |
| 734 SECStatus rv; |
678 if (!testContext.isValid) { | 735 if (!testContext.isValid) { |
679 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | 736 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
680 return SECFailure; | 737 return SECFailure; |
681 } | 738 } |
| 739 /* replicate reseed test from prng_GenerateGlobalRandomBytes */ |
| 740 if (testContext.reseed_counter[0] >= RESEED_VALUE) { |
| 741 rv = prng_reseed(&testContext, NULL, 0, NULL, 0); |
| 742 if (rv != SECSuccess) { |
| 743 return rv; |
| 744 } |
| 745 } |
682 return prng_generateNewBytes(&testContext, bytes, bytes_len, | 746 return prng_generateNewBytes(&testContext, bytes, bytes_len, |
683 additional, additional_len); | 747 additional, additional_len); |
684 | 748 |
685 } | 749 } |
686 | 750 |
687 SECStatus | 751 SECStatus |
688 PRNGTEST_Uninstantiate() | 752 PRNGTEST_Uninstantiate() |
689 { | 753 { |
| 754 if (!testContext.isValid) { |
| 755 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
| 756 return SECFailure; |
| 757 } |
690 PORT_Memset(&testContext, 0, sizeof testContext); | 758 PORT_Memset(&testContext, 0, sizeof testContext); |
691 return SECSuccess; | 759 return SECSuccess; |
692 } | 760 } |
693 | 761 |
| 762 SECStatus |
| 763 PRNGTEST_RunHealthTests() |
| 764 { |
| 765 static const PRUint8 entropy[] = { |
| 766 0x8e,0x9c,0x0d,0x25,0x75,0x22,0x04,0xf9, |
| 767 0xc5,0x79,0x10,0x8b,0x23,0x79,0x37,0x14, |
| 768 0x9f,0x2c,0xc7,0x0b,0x39,0xf8,0xee,0xef, |
| 769 0x95,0x0c,0x97,0x59,0xfc,0x0a,0x85,0x41, |
| 770 0x76,0x9d,0x6d,0x67,0x00,0x4e,0x19,0x12, |
| 771 0x02,0x16,0x53,0xea,0xf2,0x73,0xd7,0xd6, |
| 772 0x7f,0x7e,0xc8,0xae,0x9c,0x09,0x99,0x7d, |
| 773 0xbb,0x9e,0x48,0x7f,0xbb,0x96,0x46,0xb3, |
| 774 0x03,0x75,0xf8,0xc8,0x69,0x45,0x3f,0x97, |
| 775 0x5e,0x2e,0x48,0xe1,0x5d,0x58,0x97,0x4c }; |
| 776 static const PRUint8 rng_known_result[] = { |
| 777 0x16,0xe1,0x8c,0x57,0x21,0xd8,0xf1,0x7e, |
| 778 0x5a,0xa0,0x16,0x0b,0x7e,0xa6,0x25,0xb4, |
| 779 0x24,0x19,0xdb,0x54,0xfa,0x35,0x13,0x66, |
| 780 0xbb,0xaa,0x2a,0x1b,0x22,0x33,0x2e,0x4a, |
| 781 0x14,0x07,0x9d,0x52,0xfc,0x73,0x61,0x48, |
| 782 0xac,0xc1,0x22,0xfc,0xa4,0xfc,0xac,0xa4, |
| 783 0xdb,0xda,0x5b,0x27,0x33,0xc4,0xb3 }; |
| 784 static const PRUint8 reseed_entropy[] = { |
| 785 0xc6,0x0b,0x0a,0x30,0x67,0x07,0xf4,0xe2, |
| 786 0x24,0xa7,0x51,0x6f,0x5f,0x85,0x3e,0x5d, |
| 787 0x67,0x97,0xb8,0x3b,0x30,0x9c,0x7a,0xb1, |
| 788 0x52,0xc6,0x1b,0xc9,0x46,0xa8,0x62,0x79 }; |
| 789 static const PRUint8 additional_input[] = { |
| 790 0x86,0x82,0x28,0x98,0xe7,0xcb,0x01,0x14, |
| 791 0xae,0x87,0x4b,0x1d,0x99,0x1b,0xc7,0x41, |
| 792 0x33,0xff,0x33,0x66,0x40,0x95,0x54,0xc6, |
| 793 0x67,0x4d,0x40,0x2a,0x1f,0xf9,0xeb,0x65 }; |
| 794 static const PRUint8 rng_reseed_result[] = { |
| 795 0x02,0x0c,0xc6,0x17,0x86,0x49,0xba,0xc4, |
| 796 0x7b,0x71,0x35,0x05,0xf0,0xdb,0x4a,0xc2, |
| 797 0x2c,0x38,0xc1,0xa4,0x42,0xe5,0x46,0x4a, |
| 798 0x7d,0xf0,0xbe,0x47,0x88,0xb8,0x0e,0xc6, |
| 799 0x25,0x2b,0x1d,0x13,0xef,0xa6,0x87,0x96, |
| 800 0xa3,0x7d,0x5b,0x80,0xc2,0x38,0x76,0x61, |
| 801 0xc7,0x80,0x5d,0x0f,0x05,0x76,0x85 }; |
| 802 static const PRUint8 rng_no_reseed_result[] = { |
| 803 0xc4,0x40,0x41,0x8c,0xbf,0x2f,0x70,0x23, |
| 804 0x88,0xf2,0x7b,0x30,0xc3,0xca,0x1e,0xf3, |
| 805 0xef,0x53,0x81,0x5d,0x30,0xed,0x4c,0xf1, |
| 806 0xff,0x89,0xa5,0xee,0x92,0xf8,0xc0,0x0f, |
| 807 0x88,0x53,0xdf,0xb6,0x76,0xf0,0xaa,0xd3, |
| 808 0x2e,0x1d,0x64,0x37,0x3e,0xe8,0x4a,0x02, |
| 809 0xff,0x0a,0x7f,0xe5,0xe9,0x2b,0x6d }; |
694 | 810 |
| 811 SECStatus rng_status = SECSuccess; |
| 812 PR_STATIC_ASSERT(sizeof(rng_known_result) >= sizeof(rng_reseed_result)); |
| 813 PRUint8 result[sizeof(rng_known_result)]; |
| 814 |
| 815 /********************************************/ |
| 816 /* First test instantiate error path. */ |
| 817 /* In this case we supply enough entropy, */ |
| 818 /* but not enough seed. This will trigger */ |
| 819 /* the code that checks for a entropy */ |
| 820 /* source failure. */ |
| 821 /********************************************/ |
| 822 rng_status = PRNGTEST_Instantiate(entropy, 256/PR_BITS_PER_BYTE, |
| 823 NULL, 0, NULL, 0); |
| 824 if (rng_status == SECSuccess) { |
| 825 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
| 826 return SECFailure; |
| 827 } |
| 828 if (PORT_GetError() != SEC_ERROR_NEED_RANDOM) { |
| 829 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
| 830 return SECFailure; |
| 831 } |
| 832 /* we failed with the proper error code, we can continue */ |
| 833 |
| 834 /********************************************/ |
| 835 /* Generate random bytes with a known seed. */ |
| 836 /********************************************/ |
| 837 rng_status = PRNGTEST_Instantiate(entropy, sizeof entropy, |
| 838 NULL, 0, NULL, 0); |
| 839 if (rng_status != SECSuccess) { |
| 840 /* Error set by PRNGTEST_Instantiate */ |
| 841 return SECFailure; |
| 842 } |
| 843 rng_status = PRNGTEST_Generate(result, sizeof rng_known_result, NULL, 0); |
| 844 if ( ( rng_status != SECSuccess) || |
| 845 ( PORT_Memcmp( result, rng_known_result, |
| 846 sizeof rng_known_result ) != 0 ) ) { |
| 847 PRNGTEST_Uninstantiate(); |
| 848 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
| 849 return SECFailure; |
| 850 } |
| 851 rng_status = PRNGTEST_Reseed(reseed_entropy, sizeof reseed_entropy, |
| 852 additional_input, sizeof additional_input); |
| 853 if (rng_status != SECSuccess) { |
| 854 /* Error set by PRNG_Reseed */ |
| 855 PRNGTEST_Uninstantiate(); |
| 856 return SECFailure; |
| 857 } |
| 858 rng_status = PRNGTEST_Generate(result, sizeof rng_reseed_result, NULL, 0); |
| 859 if ( ( rng_status != SECSuccess) || |
| 860 ( PORT_Memcmp( result, rng_reseed_result, |
| 861 sizeof rng_reseed_result ) != 0 ) ) { |
| 862 PRNGTEST_Uninstantiate(); |
| 863 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
| 864 return SECFailure; |
| 865 } |
| 866 /* This magic forces the reseed count to it's max count, so we can see if |
| 867 * PRNGTEST_Generate will actually when it reaches it's count */ |
| 868 rng_status = PRNGTEST_Reseed(NULL, 0, NULL, 0); |
| 869 if (rng_status != SECSuccess) { |
| 870 PRNGTEST_Uninstantiate(); |
| 871 /* Error set by PRNG_Reseed */ |
| 872 return SECFailure; |
| 873 } |
| 874 /* This generate should now reseed */ |
| 875 rng_status = PRNGTEST_Generate(result, sizeof rng_reseed_result, NULL, 0); |
| 876 if ( ( rng_status != SECSuccess) || |
| 877 /* NOTE we fail if the result is equal to the no_reseed_result. |
| 878 * no_reseed_result is the value we would have gotten if we didn't |
| 879 * do an automatic reseed in PRNGTEST_Generate */ |
| 880 ( PORT_Memcmp( result, rng_no_reseed_result, |
| 881 sizeof rng_no_reseed_result ) == 0 ) ) { |
| 882 PRNGTEST_Uninstantiate(); |
| 883 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
| 884 return SECFailure; |
| 885 } |
| 886 /* make sure reseed fails when we don't supply enough entropy */ |
| 887 rng_status = PRNGTEST_Reseed(reseed_entropy, 4, NULL, 0); |
| 888 if (rng_status == SECSuccess) { |
| 889 PRNGTEST_Uninstantiate(); |
| 890 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
| 891 return SECFailure; |
| 892 } |
| 893 if (PORT_GetError() != SEC_ERROR_NEED_RANDOM) { |
| 894 PRNGTEST_Uninstantiate(); |
| 895 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
| 896 return SECFailure; |
| 897 } |
| 898 rng_status = PRNGTEST_Uninstantiate(); |
| 899 if (rng_status != SECSuccess) { |
| 900 /* Error set by PRNG_Uninstantiate */ |
| 901 return rng_status; |
| 902 } |
| 903 /* make sure uninstantiate fails if the contest is not initiated (also tests |
| 904 * if the context was cleared in the previous Uninstantiate) */ |
| 905 rng_status = PRNGTEST_Uninstantiate(); |
| 906 if (rng_status == SECSuccess) { |
| 907 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
| 908 return SECFailure; |
| 909 } |
| 910 if (PORT_GetError() != SEC_ERROR_LIBRARY_FAILURE) { |
| 911 return rng_status; |
| 912 } |
| 913 |
| 914 return SECSuccess; |
| 915 } |
OLD | NEW |