diff -up ./nss/lib/freebl/ctr.c.fips ./nss/lib/freebl/ctr.c --- ./nss/lib/freebl/ctr.c.fips 2014-06-24 13:45:27.000000000 -0700 +++ ./nss/lib/freebl/ctr.c 2014-09-22 11:03:48.410869823 -0700 @@ -30,6 +30,7 @@ CTR_InitContext(CTRContext *ctr, void *c } /* Invariant: 0 < ctr->bufPtr <= blocksize */ + ctr->checkWrap = PR_FALSE; ctr->bufPtr = blocksize; /* no unused data in the buffer */ ctr->cipher = cipher; ctr->context = context; @@ -40,6 +41,10 @@ CTR_InitContext(CTRContext *ctr, void *c return SECFailure; } PORT_Memcpy(ctr->counter, ctrParams->cb, blocksize); + if (ctr->counterBits < 64) { + PORT_Memcpy(ctr->counterFirst, ctr->counter, blocksize); + ctr->checkWrap = PR_TRUE; + } return SECSuccess; } @@ -147,6 +152,12 @@ CTR_Update(CTRContext *ctr, unsigned cha rv = (*ctr->cipher)(ctr->context, ctr->buffer, &tmp, blocksize, ctr->counter, blocksize, blocksize); ctr_GetNextCtr(ctr->counter, ctr->counterBits, blocksize); + if (ctr->checkWrap) { + if (PORT_Memcmp(ctr->counter, ctr->counterFirst, blocksize) == 0) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + } if (rv != SECSuccess) { return SECFailure; } @@ -162,6 +173,12 @@ CTR_Update(CTRContext *ctr, unsigned cha rv = (*ctr->cipher)(ctr->context, ctr->buffer, &tmp, blocksize, ctr->counter, blocksize, blocksize); ctr_GetNextCtr(ctr->counter, ctr->counterBits, blocksize); + if (ctr->checkWrap) { + if (PORT_Memcmp(ctr->counter, ctr->counterFirst, blocksize) == 0) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + } if (rv != SECSuccess) { return SECFailure; } diff -up ./nss/lib/freebl/ctr.h.fips ./nss/lib/freebl/ctr.h --- ./nss/lib/freebl/ctr.h.fips 2014-06-24 13:45:27.000000000 -0700 +++ ./nss/lib/freebl/ctr.h 2014-09-22 11:03:48.411869840 -0700 @@ -14,6 +14,8 @@ struct CTRContextStr { void *context; unsigned char counter[MAX_BLOCK_SIZE]; unsigned char buffer[MAX_BLOCK_SIZE]; + unsigned char counterFirst[MAX_BLOCK_SIZE]; /* counter overlfow value */ + PRBool checkWrap; /*check for counter overflow*/ unsigned long counterBits; unsigned int bufPtr; }; diff -up ./nss/lib/freebl/cts.c.fips ./nss/lib/freebl/cts.c --- ./nss/lib/freebl/cts.c.fips 2014-06-24 13:45:27.000000000 -0700 +++ ./nss/lib/freebl/cts.c 2014-09-22 11:03:48.411869840 -0700 @@ -97,6 +97,7 @@ CTS_EncryptUpdate(CTSContext *cts, unsig unsigned int tmp; int fullblocks; int written; + char *saveout = outbuf; SECStatus rv; if (inlen < blocksize) { @@ -141,6 +142,8 @@ CTS_EncryptUpdate(CTSContext *cts, unsig PORT_Memset(lastBlock, 0, blocksize); if (rv == SECSuccess) { *outlen = written + blocksize; + } else { + PORT_Memset(saveout, 0, written+blocksize); } return rv; } @@ -184,6 +187,7 @@ CTS_DecryptUpdate(CTSContext *cts, unsig unsigned char Cn[MAX_BLOCK_SIZE]; /* block Cn */ unsigned char lastBlock[MAX_BLOCK_SIZE]; const unsigned char *tmp; + char *saveout = outbuf; unsigned int tmpLen; int fullblocks, pad; unsigned int i; @@ -281,6 +285,8 @@ CTS_DecryptUpdate(CTSContext *cts, unsig rv = (*cts->cipher)(cts->context, Pn, &tmpLen, blocksize, lastBlock, blocksize, blocksize); if (rv != SECSuccess) { + PORT_Memset(lastBlock, 0, blocksize); + PORT_Memset(saveout, 0, *outlen); return SECFailure; } /* make up for the out of order CBC decryption */ diff -up ./nss/lib/freebl/dh.c.fips ./nss/lib/freebl/dh.c --- ./nss/lib/freebl/dh.c.fips 2014-06-24 13:45:27.000000000 -0700 +++ ./nss/lib/freebl/dh.c 2014-09-22 11:03:48.412869857 -0700 @@ -173,8 +173,8 @@ DH_NewKey(DHParams *params, DHPrivateKey /* Generate private key xa */ SECITEM_AllocItem(arena, &key->privateValue, dh_GetSecretKeyLen(params->prime.len)); - RNG_GenerateGlobalRandomBytes(key->privateValue.data, - key->privateValue.len); + CHECK_SEC_OK(RNG_GenerateGlobalRandomBytes(key->privateValue.data, + key->privateValue.len)); SECITEM_TO_MPINT( key->privateValue, &xa ); /* xa < p */ CHECK_MPI_OK( mp_mod(&xa, &p, &xa) ); @@ -191,8 +191,10 @@ cleanup: MP_TO_SEC_ERROR(err); rv = SECFailure; } - if (rv) + if (rv) { + *privKey = NULL; PORT_FreeArena(arena, PR_TRUE); + } return rv; } @@ -254,6 +256,10 @@ DH_Derive(SECItem *publicValue, } /* allocate a buffer which can hold the entire derived secret. */ secret = PORT_Alloc(len); + if (secret == NULL) { + err = MP_MEM; + goto cleanup; + } /* grab the derived secret */ err = mp_to_unsigned_octets(&ZZ, secret, len); if (err >= 0) err = MP_OKAY; @@ -267,7 +273,10 @@ DH_Derive(SECItem *publicValue, nb = outBytes; else nb = len; - SECITEM_AllocItem(NULL, derivedSecret, nb); + if (SECITEM_AllocItem(NULL, derivedSecret, nb) == NULL) { + err = MP_MEM; + goto cleanup; + } if (len < nb) { unsigned int offset = nb - len; memset(derivedSecret->data, 0, offset); @@ -342,11 +351,19 @@ KEA_Derive(SECItem *prime, /* allocate a buffer for the full derived secret */ len = mp_unsigned_octet_size(&w); secret = PORT_Alloc(len); + if (secret == NULL) { + err = MP_MEM; + goto cleanup; + } /* grab the secret */ err = mp_to_unsigned_octets(&w, secret, len); if (err > 0) err = MP_OKAY; /* allocate output buffer */ - SECITEM_AllocItem(NULL, derivedSecret, KEA_DERIVED_SECRET_LEN); + if (SECITEM_AllocItem(NULL, derivedSecret, KEA_DERIVED_SECRET_LEN) + == NULL) { + err = MP_MEM; + goto cleanup; + } memset(derivedSecret->data, 0, derivedSecret->len); /* copy in the 128 lsb of the secret */ if (len >= KEA_DERIVED_SECRET_LEN) { @@ -369,6 +386,8 @@ cleanup: PORT_ZFree(secret, len); if (err) { MP_TO_SEC_ERROR(err); + if (derivedSecret->data) + PORT_ZFree(derivedSecret->data, derivedSecret->len); return SECFailure; } return SECSuccess; diff -up ./nss/lib/freebl/drbg.c.fips ./nss/lib/freebl/drbg.c --- ./nss/lib/freebl/drbg.c.fips 2014-06-24 13:45:27.000000000 -0700 +++ ./nss/lib/freebl/drbg.c 2014-09-22 11:03:48.413869874 -0700 @@ -76,7 +76,7 @@ struct RNGContextStr { #define V(rng) (((rng)->V_Data)+1) #define VSize(rng) ((sizeof (rng)->V_Data) -1) PRUint8 C[PRNG_SEEDLEN]; /* internal state variables */ - PRUint8 oldV[PRNG_SEEDLEN]; /* for continuous rng checking */ + PRUint8 lastOutput[SHA256_LENGTH]; /* for continuous rng checking */ /* If we get calls for the PRNG to return less than the length of our * hash, we extend the request for a full hash (since we'll be doing * the full hash anyway). Future requests for random numbers are fulfilled @@ -280,6 +280,8 @@ prng_Hashgen(RNGContext *rng, PRUint8 *r unsigned int no_of_returned_bytes) { PRUint8 data[VSize(rng)]; + PRUint8 thisHash[SHA256_LENGTH]; + PRUint8 *lastHash = rng->lastOutput; PORT_Memcpy(data, V(rng), VSize(rng)); while (no_of_returned_bytes) { @@ -290,14 +292,25 @@ prng_Hashgen(RNGContext *rng, PRUint8 *r SHA256_Begin(&ctx); SHA256_Update(&ctx, data, sizeof data); - SHA256_End(&ctx, returned_bytes, &len, no_of_returned_bytes); + SHA256_End(&ctx, thisHash, &len, SHA256_LENGTH); + if (PORT_Memcmp(lastHash, thisHash, len) == 0) { + rng->isValid = PR_FALSE; + break; + } + if (no_of_returned_bytes < SHA256_LENGTH) { + len = no_of_returned_bytes; + } + PORT_Memcpy(returned_bytes, thisHash, len); + lastHash = returned_bytes; returned_bytes += len; no_of_returned_bytes -= len; /* The carry parameter is a bool (increment or not). * This increments data if no_of_returned_bytes is not zero */ PRNG_ADD_CARRY_ONLY(data, (sizeof data)- 1, no_of_returned_bytes); } + PORT_Memcpy(rng->lastOutput, thisHash, SHA256_LENGTH); PORT_Memset(data, 0, sizeof data); + PORT_Memset(thisHash, 0, sizeof thisHash); } /* @@ -342,8 +355,13 @@ prng_generateNewBytes(RNGContext *rng, } if (no_of_returned_bytes == SHA256_LENGTH) { - /* short_cut to hashbuf and save a copy and a clear */ + /* short_cut to hashbuf and a couple of copies and clears */ SHA256_HashBuf(returned_bytes, V(rng), VSize(rng) ); + /* continuous rng check */ + if (memcmp(rng->lastOutput, returned_bytes, SHA256_LENGTH) == 0) { + rng->isValid = PR_FALSE; + } + PORT_Memcpy(rng->lastOutput, returned_bytes, sizeof rng->lastOutput); } else { prng_Hashgen(rng, returned_bytes, no_of_returned_bytes); } @@ -356,13 +374,12 @@ prng_generateNewBytes(RNGContext *rng, sizeof rng->reseed_counter) PRNG_ADD_CARRY_ONLY(rng->reseed_counter,(sizeof rng->reseed_counter)-1, 1); - /* continuous rng check */ - if (memcmp(V(rng), rng->oldV, sizeof rng->oldV) == 0) { - rng->isValid = PR_FALSE; + /* if the prng failed, don't return any output, signal softoken */ + if (!rng->isValid) { + PORT_Memset(returned_bytes, 0, no_of_returned_bytes); PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - PORT_Memcpy(rng->oldV, V(rng), sizeof rng->oldV); return SECSuccess; } diff -up ./nss/lib/freebl/ec.c.fips ./nss/lib/freebl/ec.c --- ./nss/lib/freebl/ec.c.fips 2014-06-24 13:45:27.000000000 -0700 +++ ./nss/lib/freebl/ec.c 2014-09-22 11:03:48.413869874 -0700 @@ -376,7 +376,7 @@ cleanup: rv = SECFailure; } if (rv != SECSuccess && privKeyBytes) { - PORT_Free(privKeyBytes); + PORT_ZFree(privKeyBytes,2*len); privKeyBytes = NULL; } return privKeyBytes; @@ -1061,7 +1061,7 @@ cleanup: mp_clear(&v); mp_clear(&n); - if (pointC.data) SECITEM_FreeItem(&pointC, PR_FALSE); + if (pointC.data) SECITEM_ZfreeItem(&pointC, PR_FALSE); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; diff -up ./nss/lib/freebl/gcm.c.fips ./nss/lib/freebl/gcm.c --- ./nss/lib/freebl/gcm.c.fips 2014-06-24 13:45:27.000000000 -0700 +++ ./nss/lib/freebl/gcm.c 2014-09-22 11:03:48.414869890 -0700 @@ -192,9 +192,7 @@ gcmHash_DestroyContext(gcmHashContext *g mp_clear(&ghash->H); mp_clear(&ghash->X); mp_clear(&ghash->C_i); - MP_DIGITS(&ghash->H) = 0; - MP_DIGITS(&ghash->X) = 0; - MP_DIGITS(&ghash->C_i) = 0; + PORT_Memset(ghash, 0, sizeof(gcmHashContext)); if (freeit) { PORT_Free(ghash); } @@ -267,6 +265,7 @@ gcm_HashMult(gcmHashContext *ghash, cons } rv = SECSuccess; cleanup: + PORT_Memset(tmp_buf, 0, sizeof(tmp_buf)); if (rv != SECSuccess) { MP_TO_SEC_ERROR(err); } @@ -366,6 +365,7 @@ cleanup: static void gcmHash_DestroyContext(gcmHashContext *ghash, PRBool freeit) { + PORT_Memset(ghash, 0, sizeof(gcmHashContext)); if (freeit) { PORT_Free(ghash); } @@ -423,6 +423,7 @@ gcm_HashMult(gcmHashContext *ghash, cons } GCM_TRACE_X(ghash, "X%d = ") } + PORT_Memset(C_i, 0, sizeof(C_i)); return SECSuccess; } @@ -538,26 +539,30 @@ gcmHash_Final(gcmHashContext *ghash, uns rv = gcmHash_Sync(ghash, blocksize); if (rv != SECSuccess) { - return SECFailure; + goto cleanup; } rv = gcm_HashMult(ghash, ghash->counterBuf, (GCM_HASH_LEN_LEN*2)/blocksize, blocksize); if (rv != SECSuccess) { - return SECFailure; + goto cleanup; } GCM_TRACE_X(ghash, "GHASH(H,A,C) = ") rv = gcm_getX(ghash, T, blocksize); if (rv != SECSuccess) { - return SECFailure; + goto cleanup; } if (maxout > blocksize) maxout = blocksize; PORT_Memcpy(outbuf, T, maxout); *outlen = maxout; - return SECSuccess; + rv = SECSuccess; + +cleanup: + PORT_Memset(T, 0, sizeof(T)); + return rv; } SECStatus @@ -695,6 +700,8 @@ GCM_DestroyContext(GCMContext *gcm, PRBo * allocated data (like mp_int's) */ CTR_DestroyContext(&gcm->ctr_context, PR_FALSE); gcmHash_DestroyContext(&gcm->ghash_context, PR_FALSE); + PORT_Memset(&gcm->tagBits, 0, sizeof(gcm->tagBits)); + PORT_Memset(gcm->tagKey, 0, sizeof(gcm->tagKey)); if (freeit) { PORT_Free(gcm); } @@ -838,8 +845,10 @@ GCM_DecryptUpdate(GCMContext *gcm, unsig if (NSS_SecureMemcmp(tag, intag, tagBytes) != 0) { /* force a CKR_ENCRYPTED_DATA_INVALID error at in softoken */ PORT_SetError(SEC_ERROR_BAD_DATA); + PORT_Memset(tag, 0, sizeof(tag)); return SECFailure; } + PORT_Memset(tag, 0, sizeof(tag)); /* finish the decryption */ return CTR_Update(&gcm->ctr_context, outbuf, outlen, maxout, inbuf, inlen, blocksize); diff -up ./nss/lib/freebl/pqg.c.fips ./nss/lib/freebl/pqg.c --- ./nss/lib/freebl/pqg.c.fips 2014-06-24 13:45:27.000000000 -0700 +++ ./nss/lib/freebl/pqg.c 2014-09-22 11:03:48.414869890 -0700 @@ -701,6 +701,7 @@ cleanup: mp_clear(&a); mp_clear(&z); mp_clear(&two_length_minus_1); + PORT_Memset(x, 0, sizeof(x)); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; @@ -856,6 +857,7 @@ cleanup: mp_clear(&c); mp_clear(&c0); mp_clear(&one); + PORT_Memset(x, 0, sizeof(x)); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; diff -up ./nss/lib/freebl/rijndael.c.fips ./nss/lib/freebl/rijndael.c --- ./nss/lib/freebl/rijndael.c.fips 2014-06-24 13:45:27.000000000 -0700 +++ ./nss/lib/freebl/rijndael.c 2014-09-22 11:03:48.415869907 -0700 @@ -1164,6 +1164,7 @@ AES_InitContext(AESContext *cx, const un AES_DestroyContext(cx, PR_FALSE); return rv; } + cx->mode = mode; /* finally, set up any mode specific contexts */ switch (mode) { @@ -1287,6 +1288,23 @@ AES_Encrypt(AESContext *cx, unsigned cha return SECFailure; } *outputLen = inputLen; +#if UINT_MAX > MP_32BIT_MAX + /* + * we can guarentee that GSM won't overlfow if we limit the input to + * 2^36 bytes. For simplicity, we are limiting it to 2^32 for now. + * + * We do it here to cover both hardware and software GCM operations. + */ + PR_STATIC_ASSERT(sizeof(unsigned int) > 4); + if ((cx->mode == NSS_AES_GCM) && (inputLen > MP_32_BIT_MAX)) { + PORT_SetError(SEC_ERROR_OUTPUT_LEN); + return SECFailure; + } +#else + /* if we can't pass in a 32_bit number, then no such check needed */ + PR_STATIC_ASSERT(sizeof(unsigned int) <= 4); +#endif + return (*cx->worker)(cx->worker_cx, output, outputLen, maxOutputLen, input, inputLen, blocksize); } diff -up ./nss/lib/freebl/rijndael.h.fips ./nss/lib/freebl/rijndael.h --- ./nss/lib/freebl/rijndael.h.fips 2014-06-24 13:45:27.000000000 -0700 +++ ./nss/lib/freebl/rijndael.h 2014-09-22 11:03:48.415869907 -0700 @@ -62,6 +62,7 @@ struct AESContextStr freeblDestroyFunc destroy; void *worker_cx; PRBool isBlock; + int mode; }; #endif /* _RIJNDAEL_H_ */