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_ */