| 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 |