# HG changeset patch
# Parent b09c13388473637047ba5363ec2d77cdddb10c5f
# Parent  5b45fd899b93bdcc200932e45786a6d6cfa1ae16
Zeroizations of internal states that could leak outside via heap or stack.

diff --git a/lib/freebl/aeskeywrap.c b/lib/freebl/aeskeywrap.c
--- a/lib/freebl/aeskeywrap.c
+++ b/lib/freebl/aeskeywrap.c
@@ -88,16 +88,17 @@ AESKeyWrap_CreateContext(const unsigned 
 **	"cx" the context
 **	"freeit" if PR_TRUE then free the object as well as its sub-objects
 */
 extern void 
 AESKeyWrap_DestroyContext(AESKeyWrapContext *cx, PRBool freeit)
 {
     if (cx) {
 	AES_DestroyContext(&cx->aescx, PR_FALSE);
+	memset(cx->iv, 0, sizeof (cx->iv));
 /*	memset(cx, 0, sizeof *cx); */
 	if (freeit)
 	    PORT_Free(cx);
     }
 }
 
 #if !BIG_ENDIAN_WITH_64_BIT_REGISTERS
 
diff --git a/lib/freebl/cts.c b/lib/freebl/cts.c
--- a/lib/freebl/cts.c
+++ b/lib/freebl/cts.c
@@ -36,16 +36,17 @@ CTS_CreateContext(void *context, freeblC
     cts->cipher = cipher;
     cts->context = context;
     return cts;
 }
 
 void
 CTS_DestroyContext(CTSContext *cts, PRBool freeit)
 {
+    PORT_Memset(cts, 0, sizeof(CTSContext));
     if (freeit) {
 	PORT_Free(cts);
     }
 }
 	
 /*
  * See addemdum to NIST SP 800-38A
  * Generically handle cipher text stealing. Basically this is doing CBC
@@ -133,17 +134,17 @@ CTS_EncryptUpdate(CTSContext *cts, unsig
      * (Cn-1**) in our buffer. This allows us to have input data == output
      * data since Cn contains enough information to reconver Cn-1** when
      * we decrypt (at the cost of some complexity as you can see in decrypt
      * below */
     PORT_Memcpy(lastBlock, inbuf, inlen);
     PORT_Memset(lastBlock + inlen, 0, blocksize - inlen);
     rv = (*cts->cipher)(cts->context, outbuf, &tmp, maxout, lastBlock,
 			blocksize, blocksize);
-    PORT_Memset(lastBlock, 0, blocksize);
+    PORT_Memset(lastBlock, 0, MAX_BLOCK_SIZE);
     if (rv == SECSuccess) {
 	*outlen = written + blocksize;
     }
     return rv;
 }
 
 
 #define XOR_BLOCK(x,y,count) for(i=0; i < count; i++) x[i] = x[i] ^ y[i]
@@ -225,23 +226,25 @@ CTS_DecryptUpdate(CTSContext *cts, unsig
      * chaining */
     tmp =  (fullblocks < blocksize*2) ? cts->iv :
 			inbuf+fullblocks-blocksize*2;
     PORT_Memcpy(Cn_2, tmp, blocksize);
     PORT_Memcpy(Cn, inbuf+fullblocks-blocksize, blocksize);
     rv = (*cts->cipher)(cts->context, outbuf, outlen, maxout, inbuf,
 	 fullblocks, blocksize);
     if (rv != SECSuccess) {
-	return SECFailure;
+	rv = SECFailure;
+	goto cleanup;
     }
     *outlen = fullblocks; /* AES low level doesn't set outlen */
     inbuf += fullblocks;
     inlen -= fullblocks;
     if (inlen == 0) {
-	return SECSuccess;
+	rv = SECSuccess;
+	goto cleanup;
     }
     outbuf += fullblocks;
 
     /* recover the stolen text */
     PORT_Memset(lastBlock, 0, blocksize);
     PORT_Memcpy(lastBlock, inbuf, inlen);
     PORT_Memcpy(Cn_1, inbuf, inlen);
     Pn = outbuf-blocksize;
@@ -275,27 +278,26 @@ CTS_DecryptUpdate(CTSContext *cts, unsig
     /* copy Cn-1* into last buf to recover Cn-1 */
     PORT_Memcpy(lastBlock, Cn_1, inlen);
     /* note: because Cn and Cn-1 were out of order, our pointer to Pn also
      * points to where Pn-1 needs to reside. From here on out read Pn in
      * the code as really Pn-1. */
     rv = (*cts->cipher)(cts->context, Pn, &tmpLen, blocksize, lastBlock,
 	 blocksize, blocksize);
     if (rv != SECSuccess) {
-	return SECFailure;
+        rv = SECFailure;
+        goto cleanup;
     }
     /* make up for the out of order CBC decryption */
     XOR_BLOCK(Pn, Cn_2, blocksize);
     XOR_BLOCK(Pn, Cn, blocksize);
     /* reset iv to Cn  */
     PORT_Memcpy(cts->iv, Cn, blocksize);
     /* This makes Cn the last block for the next decrypt operation, which
      * matches the encrypt. We don't care about the contexts of last block,
      * only the side effect of setting the internal IV */
     (void) (*cts->cipher)(cts->context, lastBlock, &tmpLen, blocksize, Cn,
 		blocksize, blocksize);
-    /* clear last block. At this point last block contains Pn xor Cn_1 xor
-     * Cn_2, both of with an attacker would know, so we need to clear this
-     * buffer out */
-    PORT_Memset(lastBlock, 0, blocksize);
+cleanup:
+    PORT_Memset(lastBlock, 0, MAX_BLOCK_SIZE);
     /* Cn, Cn_1, and Cn_2 have encrypted data, so no need to clear them */
-    return SECSuccess;
+    return rv;
 }
diff --git a/lib/freebl/dh.c b/lib/freebl/dh.c
--- a/lib/freebl/dh.c
+++ b/lib/freebl/dh.c
@@ -168,36 +168,41 @@ DH_NewKey(DHParams *params, DHPrivateKey
     CHECK_SEC_OK( SECITEM_CopyItem(arena, &key->prime, &params->prime) );
     SECITEM_TO_MPINT(key->prime, &p);
     /* Set private key's g */
     CHECK_SEC_OK( SECITEM_CopyItem(arena, &key->base, &params->base) );
     SECITEM_TO_MPINT(key->base, &g);
     /* 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) );
     /* Compute public key Ya = g ** xa mod p */
     CHECK_MPI_OK( mp_exptmod(&g, &xa, &p, &Ya) );
     MPINT_TO_SECITEM(&Ya, &key->publicValue, key->arena);
     *privKey = key;
 cleanup:
     mp_clear(&g);
     mp_clear(&xa);
     mp_clear(&p);
     mp_clear(&Ya);
     if (err) {
 	MP_TO_SEC_ERROR(err);
 	rv = SECFailure;
     }
-    if (rv)
+    if (rv) {
+	SECITEM_ZfreeItem(&key->prime, PR_FALSE);
+	SECITEM_ZfreeItem(&key->base, PR_FALSE);
+	SECITEM_ZfreeItem(&key->publicValue, PR_FALSE);
+	SECITEM_ZfreeItem(&key->privateValue, PR_FALSE);
 	PORT_FreeArena(arena, PR_TRUE);
+    }
     return rv;
 }
 
 SECStatus 
 DH_Derive(SECItem *publicValue, 
           SECItem *prime, 
           SECItem *privateValue, 
           SECItem *derivedSecret, 
diff --git a/lib/freebl/ec.c b/lib/freebl/ec.c
--- a/lib/freebl/ec.c
+++ b/lib/freebl/ec.c
@@ -367,22 +367,22 @@ ec_GenerateRandomPrivateKey(const unsign
     CHECK_MPI_OK( mp_add(&privKeyVal, &one, &privKeyVal) );
     CHECK_MPI_OK( mp_to_fixlen_octets(&privKeyVal, privKeyBytes, len) );
     memset(privKeyBytes+len, 0, len);
 cleanup:
     mp_clear(&privKeyVal);
     mp_clear(&order_1);
     mp_clear(&one);
     if (err < MP_OKAY) {
-	MP_TO_SEC_ERROR(err);
-	rv = SECFailure;
-    }
-    if (rv != SECSuccess && privKeyBytes) {
-	PORT_Free(privKeyBytes);
-	privKeyBytes = NULL;
+        MP_TO_SEC_ERROR(err);
+        if (privKeyBytes) {
+            memset(privKeyBytes, 0, 2*len);
+            PORT_Free(privKeyBytes);
+            privKeyBytes = NULL;
+        }
     }
     return privKeyBytes;
 }
 #endif /* NSS_DISABLE_ECC */
 
 /* Generates a new EC key pair. The private key is a random value and
  * the public key is the result of performing a scalar point multiplication
  * of that value with the curve's base point.
@@ -1061,17 +1061,20 @@ cleanup:
     mp_clear(&s_);
     mp_clear(&c);
     mp_clear(&u1);
     mp_clear(&u2);
     mp_clear(&x1);
     mp_clear(&v);
     mp_clear(&n);
 
-    if (pointC.data) SECITEM_FreeItem(&pointC, PR_FALSE);
+    if (pointC.data) {
+        PORT_Memset(pointC.data, 0, 2*flen + 1);
+        SECITEM_FreeItem(&pointC, PR_FALSE);
+    }
     if (err) {
 	MP_TO_SEC_ERROR(err);
 	rv = SECFailure;
     }
 
 #if EC_DEBUG
     printf("ECDSA verification %s\n",
 	(rv == SECSuccess) ? "succeeded" : "failed");
diff --git a/lib/freebl/gcm.c b/lib/freebl/gcm.c
--- a/lib/freebl/gcm.c
+++ b/lib/freebl/gcm.c
@@ -196,18 +196,23 @@ static void
 gcmHash_DestroyContext(gcmHashContext *ghash, PRBool freeit)
 {
     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->buffer, 0, sizeof(ghash->buffer));
+    ghash->bufLen = 0;
+    ghash->m = 0;
+    PORT_Memset(ghash->counterBuf, 0, sizeof(ghash->counterBuf));
+    ghash->cLen = 0;
     if (freeit) {
-	PORT_Free(ghash);
+        PORT_Free(ghash);
     }
 }
 
 static SECStatus
 gcm_getX(gcmHashContext *ghash, unsigned char *T, unsigned int blocksize)
 {
     int len;
     mp_err err;
@@ -268,32 +273,35 @@ gcm_HashMult(gcmHashContext *ghash, cons
 	 * the builtin bmulmod from mpi
 	 */
         CHECK_MPI_OK(mp_bmulmod(&ghash->C_i, &ghash->H,
 					ghash->poly, &ghash->X));
 	GCM_TRACE_X(ghash, "X%d = ")
     }
     rv = SECSuccess;
 cleanup:
+    mp_zero(&ghash->C_i);
+    PORT_Memset(tmp_buf, 0, sizeof(tmp_buf));
     if (rv != SECSuccess) {
 	MP_TO_SEC_ERROR(err);
     }
     return rv;
 }
 
 static void
 gcm_zeroX(gcmHashContext *ghash)
 {
     mp_zero(&ghash->X);
     ghash->m = 0;
 }
 
 #endif
 
-#ifdef GCM_USE_ALGORITHM_1
+#if 0
+//#ifdef GCM_USE_ALGORITHM_1
 /* use algorithm 1 of McGrew & Viega "The Galois/Counter Mode of Operation" */
 
 #define GCM_ARRAY_SIZE (MAX_BLOCK_SIZE/sizeof(unsigned long))
 
 struct gcmHashContextStr {
      unsigned long H[GCM_ARRAY_SIZE];
      unsigned long X[GCM_ARRAY_SIZE];
      unsigned long R;
@@ -696,18 +704,20 @@ loser:
 void
 GCM_DestroyContext(GCMContext *gcm, PRBool freeit)
 {
     /* these two are statically allocated and will be freed when we free
      * gcm. call their destroy functions to free up any locally
      * allocated data (like mp_int's) */
     CTR_DestroyContext(&gcm->ctr_context, PR_FALSE);
     gcmHash_DestroyContext(&gcm->ghash_context, PR_FALSE);
+    gcm->tagBits = 0;
+    PORT_Memset(gcm->tagKey, 0, sizeof(gcm->tagKey));
     if (freeit) {
-	PORT_Free(gcm);
+        PORT_Free(gcm);
     }
 }
 
 static SECStatus
 gcm_GetTag(GCMContext *gcm, unsigned char *outbuf,
 	unsigned int *outlen, unsigned int maxout,
 	unsigned int blocksize)
 {
@@ -827,26 +837,39 @@ GCM_DecryptUpdate(GCMContext *gcm, unsig
     }
 
     inlen -= tagBytes;
     intag = inbuf + inlen;
 
     /* verify the block */
     rv = gcmHash_Update(&gcm->ghash_context, inbuf, inlen, blocksize);
     if (rv != SECSuccess) {
-	return SECFailure;
+        rv = SECFailure;
+        goto cleanup;
     }
     rv = gcm_GetTag(gcm, tag, &len, blocksize, blocksize);
     if (rv != SECSuccess) {
-	return SECFailure;
+        rv = SECFailure;
+        goto cleanup;
     }
     /* Don't decrypt if we can't authenticate the encrypted data!
      * This assumes that if tagBits is not a multiple of 8, intag will
      * preserve the masked off missing bits.  */
     if (NSS_SecureMemcmp(tag, intag, tagBytes) != 0) {
-	/* force a CKR_ENCRYPTED_DATA_INVALID error at in softoken */
-	PORT_SetError(SEC_ERROR_BAD_DATA);
-	return SECFailure;
+        /* force a CKR_ENCRYPTED_DATA_INVALID error at in softoken */
+        PORT_SetError(SEC_ERROR_BAD_DATA);
+        rv = SECFailure;
     }
+
+cleanup:
+    /* stack cleanup */
+    tagBytes = 0;
+    PORT_Memset(tag, 0, sizeof(tag));
+    intag = NULL;
+    len = 0;
+    
     /* finish the decryption */
+    if (rv != SECSuccess) {
+        return rv;
+    }
     return CTR_Update(&gcm->ctr_context, outbuf, outlen, maxout,
 			  inbuf, inlen, blocksize);
 }
diff --git a/lib/freebl/pqg.c b/lib/freebl/pqg.c
--- a/lib/freebl/pqg.c
+++ b/lib/freebl/pqg.c
@@ -707,16 +707,17 @@ cleanup:
     }
     if (rv == SECFailure) {
 	mp_zero(prime);
 	if (prime_seed->data) {
 	    SECITEM_FreeItem(prime_seed, PR_FALSE);
 	}
 	*prime_gen_counter = 0;
     }
+    PORT_Memset(x, 0, sizeof(x));
     return rv;
 }
 
 /*
 **  Perform steps from  FIPS 186-3, Appendix C.6
 **
 **  This generates a provable prime from a seed
 */
@@ -862,16 +863,17 @@ cleanup:
     }
     if (rv == SECFailure) {
 	mp_zero(prime);
 	if (prime_seed->data) {
 	    SECITEM_FreeItem(prime_seed, PR_FALSE);
 	}
 	*prime_gen_counter = 0;
     }
+    PORT_Memset(x, 0, sizeof(x));
     return rv;
 }
 
 
 /*
  * Find a Q and algorithm from Seed.
  */
 static SECStatus
