mirror of
https://git.yoctoproject.org/poky
synced 2026-04-26 00:32:12 +02:00
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 (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: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
670
meta/recipes-support/nss/files/nss-CVE-2014-1568.patch
Normal file
670
meta/recipes-support/nss/files/nss-CVE-2014-1568.patch
Normal file
@@ -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
|
||||
@@ -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 \
|
||||
|
||||
Reference in New Issue
Block a user