Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 | } |