diff --git a/SOURCES/cve-2014-1568-nss-extra.patch b/SOURCES/cve-2014-1568-nss-extra.patch new file mode 100644 index 0000000..507198e --- /dev/null +++ b/SOURCES/cve-2014-1568-nss-extra.patch @@ -0,0 +1,32 @@ + +# HG changeset patch +# User Kai Engert +# Date 1411493980 -7200 +# Node ID 8dd6c6ac977d063dbd093f092ba46e50e9bcb80b +# Parent fb7208e91ae8e819b38a80480f816efb32fbfab3 +Bug 1064636, follow up commit to fix Windows build bustage + +diff --git a/lib/cryptohi/secvfy.c b/lib/cryptohi/secvfy.c +--- a/lib/cryptohi/secvfy.c ++++ b/lib/cryptohi/secvfy.c +@@ -595,18 +595,18 @@ VFY_EndWithSignature(VFYContext *cx, SEC + } + break; + case rsaKey: + { + SECItem digest; + digest.data = final; + digest.len = part; + if (sig) { ++ SECOidTag hashid; + PORT_Assert(cx->hashAlg != SEC_OID_UNKNOWN); +- SECOidTag hashid; + rv = recoverPKCS1DigestInfo(cx->hashAlg, &hashid, + &cx->pkcs1RSADigestInfo, + &cx->pkcs1RSADigestInfoLen, + cx->key, + sig, cx->wincx); + PORT_Assert(cx->hashAlg == hashid); + if (rv != SECSuccess) { + return SECFailure; + diff --git a/SOURCES/cve-2014-1568-nss.patch b/SOURCES/cve-2014-1568-nss.patch new file mode 100644 index 0000000..a97e863 --- /dev/null +++ b/SOURCES/cve-2014-1568-nss.patch @@ -0,0 +1,355 @@ + +# HG changeset patch +# User Kai Engert +# Date 1411493314 -7200 +# Node ID ad411fb64046d987272043f311ca477022c6fef4 +# Parent 70ae6afde27f9c977badc5271efa835c8a4ec4f0 +Fix bug 1064636, patch part 2, r=rrelyea + +diff --git a/lib/cryptohi/secvfy.c b/lib/cryptohi/secvfy.c +--- a/lib/cryptohi/secvfy.c ++++ b/lib/cryptohi/secvfy.c +@@ -7,121 +7,165 @@ + + #include + #include "cryptohi.h" + #include "sechash.h" + #include "keyhi.h" + #include "secasn1.h" + #include "secoid.h" + #include "pk11func.h" ++#include "pkcs1sig.h" + #include "secdig.h" + #include "secerr.h" + #include "keyi.h" + + /* +-** Decrypt signature block using public key +-** Store the hash algorithm oid tag in *tagp +-** Store the digest in the digest buffer +-** Store the digest length in *digestlen ++** Recover the DigestInfo from an RSA PKCS#1 signature. ++** ++** If givenDigestAlg != SEC_OID_UNKNOWN, copy givenDigestAlg to digestAlgOut. ++** Otherwise, parse the DigestInfo structure and store the decoded digest ++** algorithm into digestAlgOut. ++** ++** Store the encoded DigestInfo into digestInfo. ++** Store the DigestInfo length into digestInfoLen. ++** ++** This function does *not* verify that the AlgorithmIdentifier in the ++** DigestInfo identifies givenDigestAlg or that the DigestInfo is encoded ++** correctly; verifyPKCS1DigestInfo does that. ++** + ** XXX this is assuming that the signature algorithm has WITH_RSA_ENCRYPTION + */ + static SECStatus +-DecryptSigBlock(SECOidTag *tagp, unsigned char *digest, +- unsigned int *digestlen, unsigned int maxdigestlen, +- SECKEYPublicKey *key, const SECItem *sig, char *wincx) ++recoverPKCS1DigestInfo(SECOidTag givenDigestAlg, ++ /*out*/ SECOidTag* digestAlgOut, ++ /*out*/ unsigned char** digestInfo, ++ /*out*/ unsigned int* digestInfoLen, ++ SECKEYPublicKey* key, ++ const SECItem* sig, void* wincx) + { +- SGNDigestInfo *di = NULL; +- unsigned char *buf = NULL; +- SECStatus rv; +- SECOidTag tag; +- SECItem it; ++ SGNDigestInfo* di = NULL; ++ SECItem it; ++ PRBool rv = SECSuccess; + +- if (key == NULL) goto loser; ++ PORT_Assert(digestAlgOut); ++ PORT_Assert(digestInfo); ++ PORT_Assert(digestInfoLen); ++ PORT_Assert(key); ++ PORT_Assert(key->keyType == rsaKey); ++ PORT_Assert(sig); + ++ it.data = NULL; + it.len = SECKEY_PublicKeyStrength(key); +- if (!it.len) goto loser; +- it.data = buf = (unsigned char *)PORT_Alloc(it.len); +- if (!buf) goto loser; ++ if (it.len != 0) { ++ it.data = (unsigned char *)PORT_Alloc(it.len); ++ } ++ if (it.len == 0 || it.data == NULL ) { ++ rv = SECFailure; ++ } + +- /* decrypt the block */ +- rv = PK11_VerifyRecover(key, (SECItem *)sig, &it, wincx); +- if (rv != SECSuccess) goto loser; ++ if (rv == SECSuccess) { ++ /* decrypt the block */ ++ rv = PK11_VerifyRecover(key, sig, &it, wincx); ++ } ++ ++ if (rv == SECSuccess) { ++ if (givenDigestAlg != SEC_OID_UNKNOWN) { ++ /* We don't need to parse the DigestInfo if the caller gave us the ++ * digest algorithm to use. Later verifyPKCS1DigestInfo will verify ++ * that the DigestInfo identifies the given digest algorithm and ++ * that the DigestInfo is encoded absolutely correctly. ++ */ ++ *digestInfoLen = it.len; ++ *digestInfo = (unsigned char*)it.data; ++ *digestAlgOut = givenDigestAlg; ++ return SECSuccess; ++ } ++ } + +- di = SGN_DecodeDigestInfo(&it); +- if (di == NULL) goto sigloser; ++ if (rv == SECSuccess) { ++ /* The caller didn't specify a digest algorithm to use, so choose the ++ * digest algorithm by parsing the AlgorithmIdentifier within the ++ * DigestInfo. ++ */ ++ di = SGN_DecodeDigestInfo(&it); ++ if (!di) { ++ rv = SECFailure; ++ } ++ } + +- /* +- ** Finally we have the digest info; now we can extract the algorithm +- ** ID and the signature block +- */ +- tag = SECOID_GetAlgorithmTag(&di->digestAlgorithm); +- /* Check that tag is an appropriate algorithm */ +- if (tag == SEC_OID_UNKNOWN) { +- goto sigloser; ++ if (rv == SECSuccess) { ++ *digestAlgOut = SECOID_GetAlgorithmTag(&di->digestAlgorithm); ++ if (*digestAlgOut == SEC_OID_UNKNOWN) { ++ rv = SECFailure; ++ } + } +- /* make sure the "parameters" are not too bogus. */ +- if (di->digestAlgorithm.parameters.len > 2) { +- goto sigloser; ++ ++ if (di) { ++ SGN_DestroyDigestInfo(di); + } +- if (di->digest.len > maxdigestlen) { +- PORT_SetError(SEC_ERROR_OUTPUT_LEN); +- goto loser; ++ ++ if (rv == SECSuccess) { ++ *digestInfoLen = it.len; ++ *digestInfo = (unsigned char*)it.data; ++ } else { ++ if (it.data) { ++ PORT_Free(it.data); ++ } ++ *digestInfo = NULL; ++ *digestInfoLen = 0; ++ PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + } +- PORT_Memcpy(digest, di->digest.data, di->digest.len); +- *tagp = tag; +- *digestlen = di->digest.len; +- goto done; + +- sigloser: +- PORT_SetError(SEC_ERROR_BAD_SIGNATURE); +- +- loser: +- rv = SECFailure; +- +- done: +- if (di != NULL) SGN_DestroyDigestInfo(di); +- if (buf != NULL) PORT_Free(buf); +- + return rv; + } + +- + struct VFYContextStr { + SECOidTag hashAlg; /* the hash algorithm */ + SECKEYPublicKey *key; + /* + * This buffer holds either the digest or the full signature + * depending on the type of the signature (key->keyType). It is + * defined as a union to make sure it always has enough space. + * + * Use the "buffer" union member to reference the buffer. + * Note: do not take the size of the "buffer" union member. Take + * the size of the union or some other union member instead. + */ + union { + unsigned char buffer[1]; + +- /* the digest in the decrypted RSA signature */ +- unsigned char rsadigest[HASH_LENGTH_MAX]; + /* the full DSA signature... 40 bytes */ + unsigned char dsasig[DSA_MAX_SIGNATURE_LEN]; + /* the full ECDSA signature */ + unsigned char ecdsasig[2 * MAX_ECKEY_LEN]; + } u; +- unsigned int rsadigestlen; ++ unsigned int pkcs1RSADigestInfoLen; ++ /* the encoded DigestInfo from a RSA PKCS#1 signature */ ++ unsigned char *pkcs1RSADigestInfo; + void * wincx; + void *hashcx; + const SECHashObject *hashobj; + SECOidTag encAlg; /* enc alg */ + PRBool hasSignature; /* true if the signature was provided in the + * VFY_CreateContext call. If false, the + * signature must be provided with a + * VFY_EndWithSignature call. */ + }; + ++static SECStatus ++verifyPKCS1DigestInfo(const VFYContext* cx, const SECItem* digest) ++{ ++ SECItem pkcs1DigestInfo; ++ pkcs1DigestInfo.data = cx->pkcs1RSADigestInfo; ++ pkcs1DigestInfo.len = cx->pkcs1RSADigestInfoLen; ++ return _SGN_VerifyPKCS1DigestInfo( ++ cx->hashAlg, digest, &pkcs1DigestInfo, ++ PR_TRUE /*XXX: unsafeAllowMissingParameters*/); ++} ++ + /* + * decode the ECDSA or DSA signature from it's DER wrapping. + * The unwrapped/raw signature is placed in the buffer pointed + * to by dsig and has enough room for len bytes. + */ + static SECStatus + decodeECorDSASignature(SECOidTag algid, const SECItem *sig, unsigned char *dsig, + unsigned int len) { +@@ -371,26 +415,26 @@ vfy_CreateContext(const SECKEYPublicKey + goto loser; + } + + cx->wincx = wincx; + cx->hasSignature = (sig != NULL); + cx->encAlg = encAlg; + cx->hashAlg = hashAlg; + cx->key = SECKEY_CopyPublicKey(key); ++ cx->pkcs1RSADigestInfo = NULL; + rv = SECSuccess; + if (sig) { + switch (type) { + case rsaKey: +- rv = DecryptSigBlock(&cx->hashAlg, cx->u.buffer, &cx->rsadigestlen, +- HASH_LENGTH_MAX, cx->key, sig, (char*)wincx); +- if (cx->hashAlg != hashAlg && hashAlg != SEC_OID_UNKNOWN) { +- PORT_SetError(SEC_ERROR_BAD_SIGNATURE); +- rv = SECFailure; +- } ++ rv = recoverPKCS1DigestInfo(hashAlg, &cx->hashAlg, ++ &cx->pkcs1RSADigestInfo, ++ &cx->pkcs1RSADigestInfoLen, ++ cx->key, ++ sig, wincx); + break; + case dsaKey: + case ecKey: + sigLen = SECKEY_SignatureLen(key); + if (sigLen == 0) { + /* error set by SECKEY_SignatureLen */ + rv = SECFailure; + break; +@@ -464,16 +508,19 @@ VFY_DestroyContext(VFYContext *cx, PRBoo + if (cx) { + if (cx->hashcx != NULL) { + (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); + cx->hashcx = NULL; + } + if (cx->key) { + SECKEY_DestroyPublicKey(cx->key); + } ++ if (cx->pkcs1RSADigestInfo) { ++ PORT_Free(cx->pkcs1RSADigestInfo); ++ } + if (freeit) { + PORT_ZFree(cx, sizeof(VFYContext)); + } + } + } + + SECStatus + VFY_Begin(VFYContext *cx) +@@ -543,31 +590,35 @@ VFY_EndWithSignature(VFYContext *cx, SEC + hash.data = final; + hash.len = part; + if (PK11_Verify(cx->key,&dsasig,&hash,cx->wincx) != SECSuccess) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + return SECFailure; + } + break; + case rsaKey: ++ { ++ SECItem digest; ++ digest.data = final; ++ digest.len = part; + if (sig) { +- SECOidTag hashid = SEC_OID_UNKNOWN; +- rv = DecryptSigBlock(&hashid, cx->u.buffer, &cx->rsadigestlen, +- HASH_LENGTH_MAX, cx->key, sig, (char*)cx->wincx); +- if ((rv != SECSuccess) || (hashid != cx->hashAlg)) { +- PORT_SetError(SEC_ERROR_BAD_SIGNATURE); ++ PORT_Assert(cx->hashAlg != SEC_OID_UNKNOWN); ++ SECOidTag hashid; ++ rv = recoverPKCS1DigestInfo(cx->hashAlg, &hashid, ++ &cx->pkcs1RSADigestInfo, ++ &cx->pkcs1RSADigestInfoLen, ++ cx->key, ++ sig, cx->wincx); ++ PORT_Assert(cx->hashAlg == hashid); ++ if (rv != SECSuccess) { + return SECFailure; + } + } +- if ((part != cx->rsadigestlen) || +- PORT_Memcmp(final, cx->u.buffer, part)) { +- PORT_SetError(SEC_ERROR_BAD_SIGNATURE); +- return SECFailure; +- } +- break; ++ return verifyPKCS1DigestInfo(cx, &digest); ++ } + default: + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + return SECFailure; /* shouldn't happen */ + } + return SECSuccess; + } + + SECStatus +@@ -590,22 +641,17 @@ vfy_VerifyDigest(const SECItem *digest, + SECItem dsasig; /* also used for ECDSA */ + + rv = SECFailure; + + cx = vfy_CreateContext(key, sig, encAlg, hashAlg, NULL, wincx); + if (cx != NULL) { + switch (key->keyType) { + case rsaKey: +- if ((digest->len != cx->rsadigestlen) || +- PORT_Memcmp(digest->data, cx->u.buffer, digest->len)) { +- PORT_SetError(SEC_ERROR_BAD_SIGNATURE); +- } else { +- rv = SECSuccess; +- } ++ rv = verifyPKCS1DigestInfo(cx, digest); + break; + case dsaKey: + case ecKey: + dsasig.data = cx->u.buffer; + dsasig.len = SECKEY_SignatureLen(cx->key); + if (dsasig.len == 0) { + break; + } + diff --git a/SPECS/nss.spec b/SPECS/nss.spec index 8a03293..b462558 100644 --- a/SPECS/nss.spec +++ b/SPECS/nss.spec @@ -21,7 +21,7 @@ Summary: Network Security Services Name: nss Version: 3.16.2 -Release: 2%{?dist} +Release: 7%{?dist} License: MPLv2.0 URL: http://www.mozilla.org/projects/security/pki/nss/ Group: System Environment/Libraries @@ -102,6 +102,9 @@ Patch56: p-ignore-setpolicy.patch Patch62: dont-hold-issuer-cert-handles-in-crl-cache.patch # Upstream: https://bugzilla.mozilla.org/show_bug.cgi?id=1007126 Patch63: manfixes.patch +# Upstream: https://bugzilla.mozilla.org/show_bug.cgi?id=1064636 +Patch77: cve-2014-1568-nss.patch +Patch78: cve-2014-1568-nss-extra.patch %description Network Security Services (NSS) is a set of libraries designed to @@ -198,6 +201,8 @@ popd %patch62 -p0 -b .1034409 pushd nss %patch63 -p0 -b .missing_options +%patch77 -p1 -b cve-2014-1568-nss +%patch78 -p1 -b cve-2014-1568-nss-extra popd ######################################################### @@ -779,6 +784,13 @@ fi %changelog +* Wed Sep 24 2014 Elio Maldonado - 3.16.2-7 +- Resolves: Bug 1145433 - CVE-2014-1568 + +* Wed Sep 24 2014 Elio Maldonado - 3.16.2-6 +- Rolling back to commit e5fb6e476c179665976e906604496cbbb24f22a7 +- Related: Bug 1145433 + * Wed Aug 06 2014 Elio Maldonado - 3.16.2-2 - Restore missing options descriptions fix for certutil manpage - Document certutil options --dump-ext-val, --extGeneric, and --extSAN