File nss-CC-zeroize.patch of Package mozilla-nss.1743
# HG changeset patch
# Parent b09c13388473637047ba5363ec2d77cdddb10c5f
# Parent 12c829db838f9b243f9ca4a398c93291e5dcbe61
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, ¶ms->prime) );
SECITEM_TO_MPINT(key->prime, &p);
/* Set private key's g */
CHECK_SEC_OK( SECITEM_CopyItem(arena, &key->base, ¶ms->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