Blob Blame History Raw
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_ */