nss: CVE-2014-1568
authorChong Lu <Chong.Lu@windriver.com>
Thu, 6 Nov 2014 07:50:38 +0000 (15:50 +0800)
committerPatrick Ohly <patrick.ohly@intel.com>
Fri, 9 Jan 2015 17:18:41 +0000 (09:18 -0800)
the patch comes from:
http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-1568
https://bugzilla.mozilla.org/show_bug.cgi?id=1064636
nss ng log:
=====
changeset:   11252:ad411fb64046
user:        Kai Engert <kaie@kuix.de>
date:        Tue Sep 23 19:28:34 2014 +0200
summary:     Fix bug 1064636, patch part 2, r=rrelyea
=====
changeset:   11253:4e90910ad2f9
user:        Kai Engert <kaie@kuix.de>
date:        Tue Sep 23 19:28:45 2014 +0200
summary:     Fix bug    1064636, patch part 3, r=rrelyea
=====
changeset:   11254:fb7208e91ae8
user:        Kai Engert <kaie@kuix.de>
date:        Tue Sep 23 19:28:52 2014 +0200
summary:     Fix bug    1064636, patch part 1, r=rrelyea
=====
changeset:   11255:8dd6c6ac977d
user:        Kai Engert <kaie@kuix.de>
date:        Tue Sep 23 19:39:40 2014 +0200
summary:     Bug 1064636, follow up commit to fix Windows build bustage

(From OE-Core rev: 0ed9070619f959b802dcc4ee8399d252d0349583)

Signed-off-by: Li Wang <li.wang@windriver.com>
Signed-off-by: Chong Lu <Chong.Lu@windriver.com>
Signed-off-by: Armin Kuster <akuster808@gmail.com>
Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
meta/recipes-support/nss/files/nss-CVE-2014-1568.patch [new file with mode: 0644]
meta/recipes-support/nss/nss.inc

diff --git a/meta/recipes-support/nss/files/nss-CVE-2014-1568.patch b/meta/recipes-support/nss/files/nss-CVE-2014-1568.patch
new file mode 100644 (file)
index 0000000..dbdb00c
--- /dev/null
@@ -0,0 +1,670 @@
+nss: CVE-2014-1568
+
+the patch comes from:
+http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-1568
+https://bugzilla.mozilla.org/show_bug.cgi?id=1064636
+nss ng log:
+=====
+changeset:   11252:ad411fb64046
+user:        Kai Engert <kaie@kuix.de>
+date:        Tue Sep 23 19:28:34 2014 +0200
+summary:     Fix bug 1064636, patch part 2, r=rrelyea
+=====
+changeset:   11253:4e90910ad2f9
+user:        Kai Engert <kaie@kuix.de>
+date:        Tue Sep 23 19:28:45 2014 +0200
+summary:     Fix bug    1064636, patch part 3, r=rrelyea
+=====
+changeset:   11254:fb7208e91ae8
+user:        Kai Engert <kaie@kuix.de>
+date:        Tue Sep 23 19:28:52 2014 +0200
+summary:     Fix bug    1064636, patch part 1, r=rrelyea
+=====
+changeset:   11255:8dd6c6ac977d
+user:        Kai Engert <kaie@kuix.de>
+date:        Tue Sep 23 19:39:40 2014 +0200
+summary:     Bug 1064636, follow up commit to fix Windows build bustage
+
+Upstream-Status: Backport
+Signed-off-by: Li Wang <li.wang@windriver.com>
+---
+ nss/lib/cryptohi/secvfy.c  |  202 +++++++++++++++++++++++++++-----------------
+ nss/lib/softoken/pkcs11c.c |   69 +++++++--------
+ nss/lib/util/manifest.mn   |    2 +
+ nss/lib/util/nssutil.def   |    6 ++
+ nss/lib/util/pkcs1sig.c    |  169 ++++++++++++++++++++++++++++++++++++
+ nss/lib/util/pkcs1sig.h    |   30 +++++++
+ 6 files changed, 360 insertions(+), 118 deletions(-)
+ create mode 100644 nss/lib/util/pkcs1sig.c
+ create mode 100644 nss/lib/util/pkcs1sig.h
+
+diff --git a/nss/lib/cryptohi/secvfy.c b/nss/lib/cryptohi/secvfy.c
+index c1ac39b..0a20672 100644
+--- a/nss/lib/cryptohi/secvfy.c
++++ b/nss/lib/cryptohi/secvfy.c
+@@ -12,78 +12,111 @@
+ #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;
+-
+-    if (key == NULL) goto loser;
+-
++    SGNDigestInfo* di = NULL;
++    SECItem it;
++    PRBool rv = SECSuccess;
++
++    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);
++    }
+-    di = SGN_DecodeDigestInfo(&it);
+-    if (di == NULL) goto sigloser;
++    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;
++        }
++    }
+-    /*
+-    ** 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;
+-    }
+-    /* make sure the "parameters" are not too bogus. */
+-    if (di->digestAlgorithm.parameters.len > 2) {
+-      goto sigloser;
+-    }
+-    if (di->digest.len > maxdigestlen) {
+-      PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+-      goto loser;
++    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;
++        }
+     }
+-    PORT_Memcpy(digest, di->digest.data, di->digest.len);
+-    *tagp = tag;
+-    *digestlen = di->digest.len;
+-    goto done;
+-  sigloser:
+-    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
++    if (rv == SECSuccess) {
++        *digestAlgOut = SECOID_GetAlgorithmTag(&di->digestAlgorithm);
++        if (*digestAlgOut == SEC_OID_UNKNOWN) {
++            rv = SECFailure;
++        }
++    }
+-  loser:
+-    rv = SECFailure;
++    if (di) {
++        SGN_DestroyDigestInfo(di);
++    }
++
++    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);
++    }
+-  done:
+-    if (di   != NULL) SGN_DestroyDigestInfo(di);
+-    if (buf  != NULL) PORT_Free(buf);
+-    
+     return rv;
+ }
+-
+ struct VFYContextStr {
+     SECOidTag hashAlg;  /* the hash algorithm */
+     SECKEYPublicKey *key;
+@@ -99,14 +132,14 @@ struct VFYContextStr {
+     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;
+@@ -117,6 +150,17 @@ struct VFYContextStr {
+                            * 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
+@@ -376,16 +420,16 @@ vfy_CreateContext(const SECKEYPublicKey *key, const SECItem *sig,
+     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:
+@@ -469,6 +513,9 @@ VFY_DestroyContext(VFYContext *cx, PRBool freeit)
+       if (cx->key) {
+           SECKEY_DestroyPublicKey(cx->key);
+       }
++        if (cx->pkcs1RSADigestInfo) {
++            PORT_Free(cx->pkcs1RSADigestInfo);
++        }
+       if (freeit) {
+           PORT_ZFree(cx, sizeof(VFYContext));
+       }
+@@ -548,21 +595,25 @@ VFY_EndWithSignature(VFYContext *cx, SECItem *sig)
+       }
+       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);
++            SECOidTag hashid;
++            PORT_Assert(cx->hashAlg != SEC_OID_UNKNOWN);
++            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 */
+@@ -595,12 +646,7 @@ vfy_VerifyDigest(const SECItem *digest, const SECKEYPublicKey *key,
+     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:
+diff --git a/nss/lib/softoken/pkcs11c.c b/nss/lib/softoken/pkcs11c.c
+index 89b5bd8..ba6dcfa 100644
+--- a/nss/lib/softoken/pkcs11c.c
++++ b/nss/lib/softoken/pkcs11c.c
+@@ -23,6 +23,7 @@
+ #include "blapi.h"
+ #include "pkcs11.h"
+ #include "pkcs11i.h"
++#include "pkcs1sig.h"
+ #include "lowkeyi.h"
+ #include "secder.h"
+ #include "secdig.h"
+@@ -2580,54 +2581,42 @@ sftk_hashCheckSign(SFTKHashVerifyInfo *info, unsigned char *sig,
+ }
+ SECStatus
+-RSA_HashCheckSign(SECOidTag hashOid, NSSLOWKEYPublicKey *key,
++RSA_HashCheckSign(SECOidTag digestOid, NSSLOWKEYPublicKey *key,
+       unsigned char *sig, unsigned int sigLen,
+-      unsigned char *digest, unsigned int digestLen)
++        unsigned char *digestData, unsigned int digestLen)
+ {
++    unsigned char *pkcs1DigestInfoData;
++    SECItem pkcs1DigestInfo;
++    SECItem digest;
++    unsigned int bufferSize;
++    SECStatus rv;
+-    SECItem it;
+-    SGNDigestInfo *di = NULL;
+-    SECStatus rv = SECSuccess;
+-    
+-    it.data = NULL;
+-
+-    if (key == NULL) goto loser;
+-
+-    it.len = nsslowkey_PublicModulusLen(key); 
+-    if (!it.len) goto loser;
++    /* pkcs1DigestInfo.data must be less than key->u.rsa.modulus.len */
++    bufferSize = key->u.rsa.modulus.len;
++    pkcs1DigestInfoData = PORT_ZAlloc(bufferSize);
++    if (!pkcs1DigestInfoData) {
++        PORT_SetError(SEC_ERROR_NO_MEMORY);
++        return SECFailure;
++    }
+-    it.data = (unsigned char *) PORT_Alloc(it.len);
+-    if (it.data == NULL) goto loser;
++    pkcs1DigestInfo.data = pkcs1DigestInfoData;
++    pkcs1DigestInfo.len = bufferSize;
+     /* decrypt the block */
+-    rv = RSA_CheckSignRecover(key, it.data, &it.len, it.len, sig, sigLen);
+-    if (rv != SECSuccess) goto loser;
+-
+-    di = SGN_DecodeDigestInfo(&it);
+-    if (di == NULL) goto loser;
+-    if (di->digest.len != digestLen)  goto loser; 
+-
+-    /* make sure the tag is OK */
+-    if (SECOID_GetAlgorithmTag(&di->digestAlgorithm) != hashOid) {
+-      goto loser;
+-    }
+-    /* make sure the "parameters" are not too bogus. */
+-    if (di->digestAlgorithm.parameters.len > 2) {
+-      goto loser;
+-    }
+-    /* Now check the signature */
+-    if (PORT_Memcmp(digest, di->digest.data, di->digest.len) == 0) {
+-      goto done;
++    rv = RSA_CheckSignRecover(key, pkcs1DigestInfo.data,
++                              &pkcs1DigestInfo.len, pkcs1DigestInfo.len,
++                              sig, sigLen);
++    if (rv != SECSuccess) {
++        PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
++    } else {
++        digest.data = (PRUint8*) digestData;
++        digest.len = digestLen;
++        rv = _SGN_VerifyPKCS1DigestInfo(
++                digestOid, &digest, &pkcs1DigestInfo,
++                PR_TRUE /*XXX: unsafeAllowMissingParameters*/);
+     }
+-  loser:
+-    PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+-    rv = SECFailure;
+-
+-  done:
+-    if (it.data != NULL) PORT_Free(it.data);
+-    if (di != NULL) SGN_DestroyDigestInfo(di);
+-    
++    PORT_Free(pkcs1DigestInfoData);
+     return rv;
+ }
+diff --git a/nss/lib/util/manifest.mn b/nss/lib/util/manifest.mn
+index ed54a16..9ff3758 100644
+--- a/nss/lib/util/manifest.mn
++++ b/nss/lib/util/manifest.mn
+@@ -22,6 +22,7 @@ EXPORTS = \
+       pkcs11t.h \
+       pkcs11n.h \
+       pkcs11u.h \
++      pkcs1sig.h \
+       portreg.h \
+       secasn1.h \
+       secasn1t.h \
+@@ -58,6 +59,7 @@ CSRCS = \
+       nssrwlk.c \
+       nssilock.c \
+       oidstring.c \
++      pkcs1sig.c \
+       portreg.c \
+       secalgid.c \
+       secasn1d.c \
+diff --git a/nss/lib/util/nssutil.def b/nss/lib/util/nssutil.def
+index 86a0ad7..9d98df2 100644
+--- a/nss/lib/util/nssutil.def
++++ b/nss/lib/util/nssutil.def
+@@ -271,3 +271,9 @@ SECITEM_ZfreeArray;
+ ;+    local:
+ ;+       *;
+ ;+};
++;+NSSUTIL_3.17.1 {         # NSS Utilities 3.17.1 release
++;+    global:
++_SGN_VerifyPKCS1DigestInfo;
++;+    local:
++;+       *;
++;+};
+diff --git a/nss/lib/util/pkcs1sig.c b/nss/lib/util/pkcs1sig.c
+new file mode 100644
+index 0000000..03b16f5
+--- /dev/null
++++ b/nss/lib/util/pkcs1sig.c
+@@ -0,0 +1,169 @@
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
++ */
++
++#include "pkcs1sig.h"
++#include "hasht.h"
++#include "secerr.h"
++#include "secasn1t.h"
++#include "secoid.h"
++
++typedef struct pkcs1PrefixStr pkcs1Prefix;
++struct pkcs1PrefixStr {
++    unsigned int len;
++    PRUint8 *data;
++};
++
++typedef struct pkcs1PrefixesStr pkcs1Prefixes;
++struct pkcs1PrefixesStr {
++    unsigned int digestLen;
++    pkcs1Prefix prefixWithParams;
++    pkcs1Prefix prefixWithoutParams;
++};
++
++/* The value for SGN_PKCS1_DIGESTINFO_MAX_PREFIX_LEN_EXCLUDING_OID is based on
++ * the possible prefix encodings as explained below.
++ */
++#define MAX_PREFIX_LEN_EXCLUDING_OID 10
++
++static SECStatus
++encodePrefix(const SECOidData *hashOid, unsigned int digestLen,
++             pkcs1Prefix *prefix, PRBool withParams)
++{
++    /* with params coding is:
++     *  Sequence (2 bytes) {
++     *      Sequence (2 bytes) {
++     *               Oid (2 bytes)  {
++     *                   Oid value (derOid->oid.len)
++     *               }
++     *               NULL (2 bytes)
++     *      }
++     *      OCTECT (2 bytes);
++     *
++     * without params coding is:
++     *  Sequence (2 bytes) {
++     *      Sequence (2 bytes) {
++     *               Oid (2 bytes)  {
++     *                   Oid value (derOid->oid.len)
++     *               }
++     *      }
++     *      OCTECT (2 bytes);
++     */
++
++    unsigned int innerSeqLen = 2 + hashOid->oid.len;
++    unsigned int outerSeqLen = 2 + innerSeqLen + 2 + digestLen;
++    unsigned int extra = 0;
++
++    if (withParams) {
++        innerSeqLen += 2;
++        outerSeqLen += 2;
++        extra = 2;
++    }
++
++    if (innerSeqLen >= 128 ||
++        outerSeqLen >= 128 ||
++        (outerSeqLen + 2 - digestLen) >
++            (MAX_PREFIX_LEN_EXCLUDING_OID + hashOid->oid.len)) {
++        /* this is actually a library failure, It shouldn't happen */
++        PORT_SetError(SEC_ERROR_INVALID_ARGS);
++        return SECFailure;
++    }
++
++    prefix->len = 6 + hashOid->oid.len + extra + 2;
++    prefix->data = PORT_Alloc(prefix->len);
++    if (!prefix->data) {
++        PORT_SetError(SEC_ERROR_NO_MEMORY);
++        return SECFailure;
++    }
++
++    prefix->data[0] = SEC_ASN1_SEQUENCE|SEC_ASN1_CONSTRUCTED;
++    prefix->data[1] = outerSeqLen;
++    prefix->data[2] = SEC_ASN1_SEQUENCE|SEC_ASN1_CONSTRUCTED;
++    prefix->data[3] = innerSeqLen;
++    prefix->data[4] = SEC_ASN1_OBJECT_ID;
++    prefix->data[5] = hashOid->oid.len;
++    PORT_Memcpy(&prefix->data[6], hashOid->oid.data, hashOid->oid.len);
++    if (withParams) {
++        prefix->data[6 + hashOid->oid.len] = SEC_ASN1_NULL;
++        prefix->data[6 + hashOid->oid.len + 1] = 0;
++    }
++    prefix->data[6 + hashOid->oid.len + extra] = SEC_ASN1_OCTET_STRING;
++    prefix->data[6 + hashOid->oid.len + extra + 1] = digestLen;
++
++    return SECSuccess;
++}
++
++SECStatus
++_SGN_VerifyPKCS1DigestInfo(SECOidTag digestAlg,
++                           const SECItem* digest,
++                           const SECItem* dataRecoveredFromSignature,
++                           PRBool unsafeAllowMissingParameters)
++{
++    SECOidData *hashOid;
++    pkcs1Prefixes pp;
++    const pkcs1Prefix* expectedPrefix;
++    SECStatus rv, rv2, rv3;
++
++    if (!digest || !digest->data ||
++        !dataRecoveredFromSignature || !dataRecoveredFromSignature->data) {
++        PORT_SetError(SEC_ERROR_INVALID_ARGS);
++        return SECFailure;
++    }
++
++    hashOid = SECOID_FindOIDByTag(digestAlg);
++    if (hashOid == NULL) {
++        PORT_SetError(SEC_ERROR_INVALID_ARGS);
++        return SECFailure;
++    }
++
++    pp.digestLen = digest->len;
++    pp.prefixWithParams.data = NULL;
++    pp.prefixWithoutParams.data = NULL;
++
++    rv2 = encodePrefix(hashOid, pp.digestLen, &pp.prefixWithParams, PR_TRUE);
++    rv3 = encodePrefix(hashOid, pp.digestLen, &pp.prefixWithoutParams, PR_FALSE);
++
++    rv = SECSuccess;
++    if (rv2 != SECSuccess || rv3 != SECSuccess) {
++        rv = SECFailure;
++    }
++
++    if (rv == SECSuccess) {
++        /* We don't attempt to avoid timing attacks on these comparisons because
++         * signature verification is a public key operation, not a private key
++         * operation.
++         */
++
++        if (dataRecoveredFromSignature->len ==
++                pp.prefixWithParams.len + pp.digestLen) {
++            expectedPrefix = &pp.prefixWithParams;
++        } else if (unsafeAllowMissingParameters &&
++                   dataRecoveredFromSignature->len ==
++                      pp.prefixWithoutParams.len + pp.digestLen) {
++            expectedPrefix = &pp.prefixWithoutParams;
++        } else {
++            PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
++            rv = SECFailure;
++        }
++    }
++
++    if (rv == SECSuccess) {
++        if (memcmp(dataRecoveredFromSignature->data, expectedPrefix->data,
++                   expectedPrefix->len) ||
++            memcmp(dataRecoveredFromSignature->data + expectedPrefix->len,
++                   digest->data, digest->len)) {
++            PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
++            rv = SECFailure;
++        }
++    }
++
++    if (pp.prefixWithParams.data) {
++        PORT_Free(pp.prefixWithParams.data);
++    }
++    if (pp.prefixWithoutParams.data) {
++        PORT_Free(pp.prefixWithoutParams.data);
++    }
++
++    return rv;
++}
+diff --git a/nss/lib/util/pkcs1sig.h b/nss/lib/util/pkcs1sig.h
+new file mode 100644
+index 0000000..7c52b15
+--- /dev/null
++++ b/nss/lib/util/pkcs1sig.h
+@@ -0,0 +1,30 @@
++/* This Source Code Form is subject to the terms of the Mozilla Public
++ * License, v. 2.0. If a copy of the MPL was not distributed with this
++ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
++ */
++
++#ifndef _PKCS1SIG_H_
++#define _PKCS1SIG_H_
++
++#include "hasht.h"
++#include "seccomon.h"
++#include "secoidt.h"
++
++/* SGN_VerifyPKCS1DigestInfo verifies that the length of the digest is correct
++ * for the given algorithm, then verifies that the recovered data from the
++ * PKCS#1 signature is a properly-formatted DigestInfo that identifies the
++ * given digest algorithm, then verifies that the digest in the DigestInfo
++ * matches the given digest.
++ *
++ * dataRecoveredFromSignature must be the result of calling PK11_VerifyRecover
++ * or equivalent.
++ *
++ * If unsafeAllowMissingParameters is true (not recommended), then a DigestInfo
++ * without the mandatory ASN.1 NULL parameter will also be accepted.
++ */
++SECStatus _SGN_VerifyPKCS1DigestInfo(SECOidTag digestAlg,
++                                     const SECItem* digest,
++                                     const SECItem* dataRecoveredFromSignature,
++                                     PRBool unsafeAllowMissingParameters);
++
++#endif /* _PKCS1SIG_H_ */
+-- 
+1.7.9.5
index ce7bff4..008bdad 100644 (file)
@@ -23,6 +23,7 @@ SRC_URI = "\
     file://nss-3.15.1-fix-CVE-2013-1739.patch \
     file://nss-CVE-2013-5606.patch \
     file://nss-CVE-2014-1544.patch \
+    file://nss-CVE-2014-1568.patch \
 "
 SRC_URI_append = "\
     file://nss.pc.in \