Bug 1064636 - Update NSS to version 3.16.2.1. r=rrelyea, a=bajaj default
authorKai Engert <kaie@kuix.de>
Tue, 23 Sep 2014 20:44:11 +0200
changeset 171624 b606d95b4011f75ecfaeb4323600eae13408b3b8
parent 171623 3a208c39bcb91162bde24669fc09d6cf1b82579a
push id601
push userryanvm@gmail.com
push dateThu, 09 Oct 2014 00:42:11 +0000
reviewersrrelyea, bajaj
bugs1064636
milestone28.0
Bug 1064636 - Update NSS to version 3.16.2.1. r=rrelyea, a=bajaj CLOSED TREE
configure.in
security/nss/TAG-INFO
security/nss/coreconf/coreconf.dep
security/nss/lib/cryptohi/secvfy.c
security/nss/lib/nss/nss.h
security/nss/lib/softoken/pkcs11c.c
security/nss/lib/softoken/softkver.h
security/nss/lib/util/manifest.mn
security/nss/lib/util/nssutil.def
security/nss/lib/util/nssutil.h
security/nss/lib/util/pkcs1sig.c
security/nss/lib/util/pkcs1sig.h
--- a/configure.in
+++ b/configure.in
@@ -3683,17 +3683,17 @@ dnl = If NSS was not detected in the sys
 dnl = use the one in the source tree (mozilla/security/nss)
 dnl ========================================================
 
 MOZ_ARG_WITH_BOOL(system-nss,
 [  --with-system-nss       Use system installed NSS],
     _USE_SYSTEM_NSS=1 )
 
 if test -n "$_USE_SYSTEM_NSS"; then
-    AM_PATH_NSS(3.16.2, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
+    AM_PATH_NSS(3.16.2.1, [MOZ_NATIVE_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
 fi
 
 if test -n "$MOZ_NATIVE_NSS"; then
    NSS_LIBS="$NSS_LIBS -lcrmf"
 else
    NSS_CFLAGS='-I$(LIBXUL_DIST)/include/nss'
 
    if test -z "$GNU_CC" -a "$OS_ARCH" = "WINNT" -o "$OS_ARCH" = "OS2"; then
--- a/security/nss/TAG-INFO
+++ b/security/nss/TAG-INFO
@@ -1,1 +1,1 @@
-NSS_3_16_2_RTM
+NSS_3_16_2_1_RTM
--- a/security/nss/coreconf/coreconf.dep
+++ b/security/nss/coreconf/coreconf.dep
@@ -5,9 +5,8 @@
 
 /*
  * A dummy header file that is a dependency for all the object files.
  * Used to force a full recompilation of NSS in Mozilla's Tinderbox
  * depend builds.  See comments in rules.mk.
  */
 
 #error "Do not include this header file."
-
--- a/security/nss/lib/cryptohi/secvfy.c
+++ b/security/nss/lib/cryptohi/secvfy.c
@@ -7,121 +7,165 @@
 
 #include <stdio.h>
 #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;
-
-    if (key == NULL) goto loser;
+    SGNDigestInfo* di = NULL;
+    SECItem it;
+    PRBool rv = SECSuccess;
 
-    it.len  = SECKEY_PublicKeyStrength(key);
-    if (!it.len) goto loser;
-    it.data = buf = (unsigned char *)PORT_Alloc(it.len);
-    if (!buf) goto loser;
+    PORT_Assert(digestAlgOut);
+    PORT_Assert(digestInfo);
+    PORT_Assert(digestInfoLen);
+    PORT_Assert(key);
+    PORT_Assert(key->keyType == rsaKey);
+    PORT_Assert(sig);
 
-    /* decrypt the block */
-    rv = PK11_VerifyRecover(key, (SECItem *)sig, &it, wincx);
-    if (rv != SECSuccess) goto loser;
-
-    di = SGN_DecodeDigestInfo(&it);
-    if (di == NULL) goto sigloser;
+    it.data = NULL;
+    it.len  = SECKEY_PublicKeyStrength(key);
+    if (it.len != 0) {
+        it.data = (unsigned char *)PORT_Alloc(it.len);
+    }
+    if (it.len == 0 || it.data == NULL ) {
+        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) {
+        /* decrypt the block */
+        rv = PK11_VerifyRecover(key, sig, &it, wincx);
     }
-    /* make sure the "parameters" are not too bogus. */
-    if (di->digestAlgorithm.parameters.len > 2) {
-	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;
+        }
     }
-    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;
+        }
+    }
+
+    if (di) {
+        SGN_DestroyDigestInfo(di);
+    }
 
-  loser:
-    rv = SECFailure;
+    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;
     /*
      * 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);
+	    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 */
     }
     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;
 	    }
--- a/security/nss/lib/nss/nss.h
+++ b/security/nss/lib/nss/nss.h
@@ -28,21 +28,21 @@
 
 /*
  * NSS's major version, minor version, patch level, build number, and whether
  * this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
  */
-#define NSS_VERSION  "3.16.2" _NSS_ECC_STRING _NSS_CUSTOMIZED
+#define NSS_VERSION  "3.16.2.1" _NSS_ECC_STRING _NSS_CUSTOMIZED
 #define NSS_VMAJOR   3
 #define NSS_VMINOR   16
 #define NSS_VPATCH   2
-#define NSS_VBUILD   0
+#define NSS_VBUILD   1
 #define NSS_BETA     PR_FALSE
 
 #ifndef RC_INVOKED
 
 #include "seccomon.h"
 
 typedef struct NSSInitParametersStr NSSInitParameters;
 
--- a/security/nss/lib/softoken/pkcs11c.c
+++ b/security/nss/lib/softoken/pkcs11c.c
@@ -18,16 +18,17 @@
  *   that created or generated them.
  */
 #include "seccomon.h"
 #include "secitem.h"
 #include "secport.h"
 #include "blapi.h"
 #include "pkcs11.h"
 #include "pkcs11i.h"
+#include "pkcs1sig.h"
 #include "lowkeyi.h"
 #include "secder.h"
 #include "secdig.h"
 #include "lowpbe.h"	/* We do PBE below */
 #include "pkcs11t.h"
 #include "secoid.h"
 #include "alghmac.h"
 #include "softoken.h"
@@ -2851,75 +2852,52 @@ sftk_hashCheckSign(SFTKHashVerifyInfo *i
         return SECFailure;
     }
 
     return RSA_HashCheckSign(info->hashOid, info->key, sig, sigLen, digest,
                              digestLen);
 }
 
 SECStatus
-RSA_HashCheckSign(SECOidTag hashOid, NSSLOWKEYPublicKey *key,
+RSA_HashCheckSign(SECOidTag digestOid, NSSLOWKEYPublicKey *key,
                   const unsigned char *sig, unsigned int sigLen,
-                  const unsigned char *hash, unsigned int hashLen)
+                  const unsigned char *digestData, unsigned int digestLen)
 {
-    SECItem it;
-    SGNDigestInfo *di = NULL;
-    SECStatus rv = SECSuccess;
-
-    it.data = NULL;
-    it.len = nsslowkey_PublicModulusLen(key);
-    if (!it.len) {
-        goto loser;
-    }
-
-    it.data = (unsigned char *)PORT_Alloc(it.len);
-    if (it.data == NULL) {
-        goto loser;
-    }
-
+    unsigned char *pkcs1DigestInfoData;
+    SECItem pkcs1DigestInfo;
+    SECItem digest;
+    unsigned int bufferSize;
+    SECStatus rv;
+
+    /* 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;
+    }
+
+    pkcs1DigestInfo.data = pkcs1DigestInfoData;
+    pkcs1DigestInfo.len = bufferSize;
+    
     /* decrypt the block */
-    rv = RSA_CheckSignRecover(&key->u.rsa, it.data, &it.len, it.len, sig,
-                              sigLen);
+    rv = RSA_CheckSignRecover(&key->u.rsa, pkcs1DigestInfo.data,
+                             &pkcs1DigestInfo.len, pkcs1DigestInfo.len,
+                             sig, sigLen);
     if (rv != SECSuccess) {
-        goto loser;
-    }
-
-    di = SGN_DecodeDigestInfo(&it);
-    if (di == NULL) {
-        goto loser;
-    }
-    if (di->digest.len != hashLen) {
-        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(hash, di->digest.data, di->digest.len) == 0) {
-        goto done;
-    }
-
-  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_SetError(SEC_ERROR_BAD_SIGNATURE);
+    } else {
+        digest.data = (PRUint8*) digestData;
+        digest.len = digestLen;
+        rv = _SGN_VerifyPKCS1DigestInfo(
+                digestOid, &digest, &pkcs1DigestInfo,
+                PR_TRUE /*XXX: unsafeAllowMissingParameters*/);
+    }
+
+    PORT_Free(pkcs1DigestInfoData);
     return rv;
 }
 
 static SECStatus
 sftk_RSACheckSign(NSSLOWKEYPublicKey *key, const unsigned char *sig,
                   unsigned int sigLen, const unsigned char *digest,
                   unsigned int digestLen)
 {
--- a/security/nss/lib/softoken/softkver.h
+++ b/security/nss/lib/softoken/softkver.h
@@ -20,16 +20,16 @@
 
 /*
  * Softoken's major version, minor version, patch level, build number,
  * and whether this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
  */
-#define SOFTOKEN_VERSION  "3.16.2" SOFTOKEN_ECC_STRING
+#define SOFTOKEN_VERSION  "3.16.2.1" SOFTOKEN_ECC_STRING
 #define SOFTOKEN_VMAJOR   3
 #define SOFTOKEN_VMINOR   16
 #define SOFTOKEN_VPATCH   2
-#define SOFTOKEN_VBUILD   0
+#define SOFTOKEN_VBUILD   1
 #define SOFTOKEN_BETA     PR_FALSE
 
 #endif /* _SOFTKVER_H_ */
--- a/security/nss/lib/util/manifest.mn
+++ b/security/nss/lib/util/manifest.mn
@@ -17,16 +17,17 @@ EXPORTS = \
 	nssrwlkt.h \
 	nssutil.h \
 	pkcs11.h \
 	pkcs11f.h \
 	pkcs11p.h \
 	pkcs11t.h \
 	pkcs11n.h \
 	pkcs11u.h \
+	pkcs1sig.h \
 	portreg.h \
 	secasn1.h \
 	secasn1t.h \
 	seccomon.h \
 	secder.h \
 	secdert.h \
 	secdig.h \
 	secdigt.h \
@@ -53,16 +54,17 @@ CSRCS = \
 	dersubr.c \
 	dertime.c \
 	errstrs.c \
 	nssb64d.c \
 	nssb64e.c \
 	nssrwlk.c \
 	nssilock.c \
 	oidstring.c \
+	pkcs1sig.c \
 	portreg.c \
 	secalgid.c \
 	secasn1d.c \
 	secasn1e.c \
 	secasn1u.c \
 	secitem.c \
 	secload.c \
 	secoid.c \
--- a/security/nss/lib/util/nssutil.def
+++ b/security/nss/lib/util/nssutil.def
@@ -266,8 +266,14 @@ NSSUTIL_QuoteSize;
 SECITEM_AllocArray;
 SECITEM_DupArray;
 SECITEM_FreeArray;
 SECITEM_ReallocItemV2;
 SECITEM_ZfreeArray;
 ;+    local:
 ;+       *;
 ;+};
+;+NSSUTIL_3.17.1 {         # NSS Utilities 3.17.1 release
+;+    global:
+_SGN_VerifyPKCS1DigestInfo;
+;+    local:
+;+       *;
+;+};
--- a/security/nss/lib/util/nssutil.h
+++ b/security/nss/lib/util/nssutil.h
@@ -14,21 +14,21 @@
 
 /*
  * NSS utilities's major version, minor version, patch level, build number,
  * and whether this is a beta release.
  *
  * The format of the version string should be
  *     "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]"
  */
-#define NSSUTIL_VERSION  "3.16.2"
+#define NSSUTIL_VERSION  "3.16.2.1"
 #define NSSUTIL_VMAJOR   3
 #define NSSUTIL_VMINOR   16
 #define NSSUTIL_VPATCH   2
-#define NSSUTIL_VBUILD   0
+#define NSSUTIL_VBUILD   1
 #define NSSUTIL_BETA     PR_FALSE
 
 SEC_BEGIN_PROTOS
 
 /*
  * Returns a const string of the UTIL library version.
  */
 extern const char *NSSUTIL_GetVersion(void);
new file mode 100644
--- /dev/null
+++ b/security/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;
+}
new file mode 100644
--- /dev/null
+++ b/security/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_ */