summaryrefslogtreecommitdiffstats
path: root/meta/recipes-support/nss/files/nss-CVE-2014-1568.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-support/nss/files/nss-CVE-2014-1568.patch')
-rw-r--r--meta/recipes-support/nss/files/nss-CVE-2014-1568.patch670
1 files changed, 670 insertions, 0 deletions
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
index 0000000000..dbdb00ce2b
--- /dev/null
+++ b/meta/recipes-support/nss/files/nss-CVE-2014-1568.patch
@@ -0,0 +1,670 @@
1nss: CVE-2014-1568
2
3the patch comes from:
4http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-1568
5https://bugzilla.mozilla.org/show_bug.cgi?id=1064636
6nss ng log:
7=====
8changeset: 11252:ad411fb64046
9user: Kai Engert <kaie@kuix.de>
10date: Tue Sep 23 19:28:34 2014 +0200
11summary: Fix bug 1064636, patch part 2, r=rrelyea
12=====
13changeset: 11253:4e90910ad2f9
14user: Kai Engert <kaie@kuix.de>
15date: Tue Sep 23 19:28:45 2014 +0200
16summary: Fix bug 1064636, patch part 3, r=rrelyea
17=====
18changeset: 11254:fb7208e91ae8
19user: Kai Engert <kaie@kuix.de>
20date: Tue Sep 23 19:28:52 2014 +0200
21summary: Fix bug 1064636, patch part 1, r=rrelyea
22=====
23changeset: 11255:8dd6c6ac977d
24user: Kai Engert <kaie@kuix.de>
25date: Tue Sep 23 19:39:40 2014 +0200
26summary: Bug 1064636, follow up commit to fix Windows build bustage
27
28Upstream-Status: Backport
29Signed-off-by: Li Wang <li.wang@windriver.com>
30---
31 nss/lib/cryptohi/secvfy.c | 202 +++++++++++++++++++++++++++-----------------
32 nss/lib/softoken/pkcs11c.c | 69 +++++++--------
33 nss/lib/util/manifest.mn | 2 +
34 nss/lib/util/nssutil.def | 6 ++
35 nss/lib/util/pkcs1sig.c | 169 ++++++++++++++++++++++++++++++++++++
36 nss/lib/util/pkcs1sig.h | 30 +++++++
37 6 files changed, 360 insertions(+), 118 deletions(-)
38 create mode 100644 nss/lib/util/pkcs1sig.c
39 create mode 100644 nss/lib/util/pkcs1sig.h
40
41diff --git a/nss/lib/cryptohi/secvfy.c b/nss/lib/cryptohi/secvfy.c
42index c1ac39b..0a20672 100644
43--- a/nss/lib/cryptohi/secvfy.c
44+++ b/nss/lib/cryptohi/secvfy.c
45@@ -12,78 +12,111 @@
46 #include "secasn1.h"
47 #include "secoid.h"
48 #include "pk11func.h"
49+#include "pkcs1sig.h"
50 #include "secdig.h"
51 #include "secerr.h"
52 #include "keyi.h"
53
54 /*
55-** Decrypt signature block using public key
56-** Store the hash algorithm oid tag in *tagp
57-** Store the digest in the digest buffer
58-** Store the digest length in *digestlen
59+** Recover the DigestInfo from an RSA PKCS#1 signature.
60+**
61+** If givenDigestAlg != SEC_OID_UNKNOWN, copy givenDigestAlg to digestAlgOut.
62+** Otherwise, parse the DigestInfo structure and store the decoded digest
63+** algorithm into digestAlgOut.
64+**
65+** Store the encoded DigestInfo into digestInfo.
66+** Store the DigestInfo length into digestInfoLen.
67+**
68+** This function does *not* verify that the AlgorithmIdentifier in the
69+** DigestInfo identifies givenDigestAlg or that the DigestInfo is encoded
70+** correctly; verifyPKCS1DigestInfo does that.
71+**
72 ** XXX this is assuming that the signature algorithm has WITH_RSA_ENCRYPTION
73 */
74 static SECStatus
75-DecryptSigBlock(SECOidTag *tagp, unsigned char *digest,
76- unsigned int *digestlen, unsigned int maxdigestlen,
77- SECKEYPublicKey *key, const SECItem *sig, char *wincx)
78+recoverPKCS1DigestInfo(SECOidTag givenDigestAlg,
79+ /*out*/ SECOidTag* digestAlgOut,
80+ /*out*/ unsigned char** digestInfo,
81+ /*out*/ unsigned int* digestInfoLen,
82+ SECKEYPublicKey* key,
83+ const SECItem* sig, void* wincx)
84 {
85- SGNDigestInfo *di = NULL;
86- unsigned char *buf = NULL;
87- SECStatus rv;
88- SECOidTag tag;
89- SECItem it;
90-
91- if (key == NULL) goto loser;
92-
93+ SGNDigestInfo* di = NULL;
94+ SECItem it;
95+ PRBool rv = SECSuccess;
96+
97+ PORT_Assert(digestAlgOut);
98+ PORT_Assert(digestInfo);
99+ PORT_Assert(digestInfoLen);
100+ PORT_Assert(key);
101+ PORT_Assert(key->keyType == rsaKey);
102+ PORT_Assert(sig);
103+
104+ it.data = NULL;
105 it.len = SECKEY_PublicKeyStrength(key);
106- if (!it.len) goto loser;
107- it.data = buf = (unsigned char *)PORT_Alloc(it.len);
108- if (!buf) goto loser;
109+ if (it.len != 0) {
110+ it.data = (unsigned char *)PORT_Alloc(it.len);
111+ }
112+ if (it.len == 0 || it.data == NULL ) {
113+ rv = SECFailure;
114+ }
115
116- /* decrypt the block */
117- rv = PK11_VerifyRecover(key, (SECItem *)sig, &it, wincx);
118- if (rv != SECSuccess) goto loser;
119+ if (rv == SECSuccess) {
120+ /* decrypt the block */
121+ rv = PK11_VerifyRecover(key, sig, &it, wincx);
122+ }
123
124- di = SGN_DecodeDigestInfo(&it);
125- if (di == NULL) goto sigloser;
126+ if (rv == SECSuccess) {
127+ if (givenDigestAlg != SEC_OID_UNKNOWN) {
128+ /* We don't need to parse the DigestInfo if the caller gave us the
129+ * digest algorithm to use. Later verifyPKCS1DigestInfo will verify
130+ * that the DigestInfo identifies the given digest algorithm and
131+ * that the DigestInfo is encoded absolutely correctly.
132+ */
133+ *digestInfoLen = it.len;
134+ *digestInfo = (unsigned char*)it.data;
135+ *digestAlgOut = givenDigestAlg;
136+ return SECSuccess;
137+ }
138+ }
139
140- /*
141- ** Finally we have the digest info; now we can extract the algorithm
142- ** ID and the signature block
143- */
144- tag = SECOID_GetAlgorithmTag(&di->digestAlgorithm);
145- /* Check that tag is an appropriate algorithm */
146- if (tag == SEC_OID_UNKNOWN) {
147- goto sigloser;
148- }
149- /* make sure the "parameters" are not too bogus. */
150- if (di->digestAlgorithm.parameters.len > 2) {
151- goto sigloser;
152- }
153- if (di->digest.len > maxdigestlen) {
154- PORT_SetError(SEC_ERROR_OUTPUT_LEN);
155- goto loser;
156+ if (rv == SECSuccess) {
157+ /* The caller didn't specify a digest algorithm to use, so choose the
158+ * digest algorithm by parsing the AlgorithmIdentifier within the
159+ * DigestInfo.
160+ */
161+ di = SGN_DecodeDigestInfo(&it);
162+ if (!di) {
163+ rv = SECFailure;
164+ }
165 }
166- PORT_Memcpy(digest, di->digest.data, di->digest.len);
167- *tagp = tag;
168- *digestlen = di->digest.len;
169- goto done;
170
171- sigloser:
172- PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
173+ if (rv == SECSuccess) {
174+ *digestAlgOut = SECOID_GetAlgorithmTag(&di->digestAlgorithm);
175+ if (*digestAlgOut == SEC_OID_UNKNOWN) {
176+ rv = SECFailure;
177+ }
178+ }
179
180- loser:
181- rv = SECFailure;
182+ if (di) {
183+ SGN_DestroyDigestInfo(di);
184+ }
185+
186+ if (rv == SECSuccess) {
187+ *digestInfoLen = it.len;
188+ *digestInfo = (unsigned char*)it.data;
189+ } else {
190+ if (it.data) {
191+ PORT_Free(it.data);
192+ }
193+ *digestInfo = NULL;
194+ *digestInfoLen = 0;
195+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
196+ }
197
198- done:
199- if (di != NULL) SGN_DestroyDigestInfo(di);
200- if (buf != NULL) PORT_Free(buf);
201-
202 return rv;
203 }
204
205-
206 struct VFYContextStr {
207 SECOidTag hashAlg; /* the hash algorithm */
208 SECKEYPublicKey *key;
209@@ -99,14 +132,14 @@ struct VFYContextStr {
210 union {
211 unsigned char buffer[1];
212
213- /* the digest in the decrypted RSA signature */
214- unsigned char rsadigest[HASH_LENGTH_MAX];
215 /* the full DSA signature... 40 bytes */
216 unsigned char dsasig[DSA_MAX_SIGNATURE_LEN];
217 /* the full ECDSA signature */
218 unsigned char ecdsasig[2 * MAX_ECKEY_LEN];
219 } u;
220- unsigned int rsadigestlen;
221+ unsigned int pkcs1RSADigestInfoLen;
222+ /* the encoded DigestInfo from a RSA PKCS#1 signature */
223+ unsigned char *pkcs1RSADigestInfo;
224 void * wincx;
225 void *hashcx;
226 const SECHashObject *hashobj;
227@@ -117,6 +150,17 @@ struct VFYContextStr {
228 * VFY_EndWithSignature call. */
229 };
230
231+static SECStatus
232+verifyPKCS1DigestInfo(const VFYContext* cx, const SECItem* digest)
233+{
234+ SECItem pkcs1DigestInfo;
235+ pkcs1DigestInfo.data = cx->pkcs1RSADigestInfo;
236+ pkcs1DigestInfo.len = cx->pkcs1RSADigestInfoLen;
237+ return _SGN_VerifyPKCS1DigestInfo(
238+ cx->hashAlg, digest, &pkcs1DigestInfo,
239+ PR_TRUE /*XXX: unsafeAllowMissingParameters*/);
240+}
241+
242 /*
243 * decode the ECDSA or DSA signature from it's DER wrapping.
244 * The unwrapped/raw signature is placed in the buffer pointed
245@@ -376,16 +420,16 @@ vfy_CreateContext(const SECKEYPublicKey *key, const SECItem *sig,
246 cx->encAlg = encAlg;
247 cx->hashAlg = hashAlg;
248 cx->key = SECKEY_CopyPublicKey(key);
249+ cx->pkcs1RSADigestInfo = NULL;
250 rv = SECSuccess;
251 if (sig) {
252 switch (type) {
253 case rsaKey:
254- rv = DecryptSigBlock(&cx->hashAlg, cx->u.buffer, &cx->rsadigestlen,
255- HASH_LENGTH_MAX, cx->key, sig, (char*)wincx);
256- if (cx->hashAlg != hashAlg && hashAlg != SEC_OID_UNKNOWN) {
257- PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
258- rv = SECFailure;
259- }
260+ rv = recoverPKCS1DigestInfo(hashAlg, &cx->hashAlg,
261+ &cx->pkcs1RSADigestInfo,
262+ &cx->pkcs1RSADigestInfoLen,
263+ cx->key,
264+ sig, wincx);
265 break;
266 case dsaKey:
267 case ecKey:
268@@ -469,6 +513,9 @@ VFY_DestroyContext(VFYContext *cx, PRBool freeit)
269 if (cx->key) {
270 SECKEY_DestroyPublicKey(cx->key);
271 }
272+ if (cx->pkcs1RSADigestInfo) {
273+ PORT_Free(cx->pkcs1RSADigestInfo);
274+ }
275 if (freeit) {
276 PORT_ZFree(cx, sizeof(VFYContext));
277 }
278@@ -548,21 +595,25 @@ VFY_EndWithSignature(VFYContext *cx, SECItem *sig)
279 }
280 break;
281 case rsaKey:
282+ {
283+ SECItem digest;
284+ digest.data = final;
285+ digest.len = part;
286 if (sig) {
287- SECOidTag hashid = SEC_OID_UNKNOWN;
288- rv = DecryptSigBlock(&hashid, cx->u.buffer, &cx->rsadigestlen,
289- HASH_LENGTH_MAX, cx->key, sig, (char*)cx->wincx);
290- if ((rv != SECSuccess) || (hashid != cx->hashAlg)) {
291- PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
292+ SECOidTag hashid;
293+ PORT_Assert(cx->hashAlg != SEC_OID_UNKNOWN);
294+ rv = recoverPKCS1DigestInfo(cx->hashAlg, &hashid,
295+ &cx->pkcs1RSADigestInfo,
296+ &cx->pkcs1RSADigestInfoLen,
297+ cx->key,
298+ sig, cx->wincx);
299+ PORT_Assert(cx->hashAlg == hashid);
300+ if (rv != SECSuccess) {
301 return SECFailure;
302 }
303 }
304- if ((part != cx->rsadigestlen) ||
305- PORT_Memcmp(final, cx->u.buffer, part)) {
306- PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
307- return SECFailure;
308- }
309- break;
310+ return verifyPKCS1DigestInfo(cx, &digest);
311+ }
312 default:
313 PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
314 return SECFailure; /* shouldn't happen */
315@@ -595,12 +646,7 @@ vfy_VerifyDigest(const SECItem *digest, const SECKEYPublicKey *key,
316 if (cx != NULL) {
317 switch (key->keyType) {
318 case rsaKey:
319- if ((digest->len != cx->rsadigestlen) ||
320- PORT_Memcmp(digest->data, cx->u.buffer, digest->len)) {
321- PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
322- } else {
323- rv = SECSuccess;
324- }
325+ rv = verifyPKCS1DigestInfo(cx, digest);
326 break;
327 case dsaKey:
328 case ecKey:
329diff --git a/nss/lib/softoken/pkcs11c.c b/nss/lib/softoken/pkcs11c.c
330index 89b5bd8..ba6dcfa 100644
331--- a/nss/lib/softoken/pkcs11c.c
332+++ b/nss/lib/softoken/pkcs11c.c
333@@ -23,6 +23,7 @@
334 #include "blapi.h"
335 #include "pkcs11.h"
336 #include "pkcs11i.h"
337+#include "pkcs1sig.h"
338 #include "lowkeyi.h"
339 #include "secder.h"
340 #include "secdig.h"
341@@ -2580,54 +2581,42 @@ sftk_hashCheckSign(SFTKHashVerifyInfo *info, unsigned char *sig,
342 }
343
344 SECStatus
345-RSA_HashCheckSign(SECOidTag hashOid, NSSLOWKEYPublicKey *key,
346+RSA_HashCheckSign(SECOidTag digestOid, NSSLOWKEYPublicKey *key,
347 unsigned char *sig, unsigned int sigLen,
348- unsigned char *digest, unsigned int digestLen)
349+ unsigned char *digestData, unsigned int digestLen)
350 {
351+ unsigned char *pkcs1DigestInfoData;
352+ SECItem pkcs1DigestInfo;
353+ SECItem digest;
354+ unsigned int bufferSize;
355+ SECStatus rv;
356
357- SECItem it;
358- SGNDigestInfo *di = NULL;
359- SECStatus rv = SECSuccess;
360-
361- it.data = NULL;
362-
363- if (key == NULL) goto loser;
364-
365- it.len = nsslowkey_PublicModulusLen(key);
366- if (!it.len) goto loser;
367+ /* pkcs1DigestInfo.data must be less than key->u.rsa.modulus.len */
368+ bufferSize = key->u.rsa.modulus.len;
369+ pkcs1DigestInfoData = PORT_ZAlloc(bufferSize);
370+ if (!pkcs1DigestInfoData) {
371+ PORT_SetError(SEC_ERROR_NO_MEMORY);
372+ return SECFailure;
373+ }
374
375- it.data = (unsigned char *) PORT_Alloc(it.len);
376- if (it.data == NULL) goto loser;
377+ pkcs1DigestInfo.data = pkcs1DigestInfoData;
378+ pkcs1DigestInfo.len = bufferSize;
379
380 /* decrypt the block */
381- rv = RSA_CheckSignRecover(key, it.data, &it.len, it.len, sig, sigLen);
382- if (rv != SECSuccess) goto loser;
383-
384- di = SGN_DecodeDigestInfo(&it);
385- if (di == NULL) goto loser;
386- if (di->digest.len != digestLen) goto loser;
387-
388- /* make sure the tag is OK */
389- if (SECOID_GetAlgorithmTag(&di->digestAlgorithm) != hashOid) {
390- goto loser;
391- }
392- /* make sure the "parameters" are not too bogus. */
393- if (di->digestAlgorithm.parameters.len > 2) {
394- goto loser;
395- }
396- /* Now check the signature */
397- if (PORT_Memcmp(digest, di->digest.data, di->digest.len) == 0) {
398- goto done;
399+ rv = RSA_CheckSignRecover(key, pkcs1DigestInfo.data,
400+ &pkcs1DigestInfo.len, pkcs1DigestInfo.len,
401+ sig, sigLen);
402+ if (rv != SECSuccess) {
403+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
404+ } else {
405+ digest.data = (PRUint8*) digestData;
406+ digest.len = digestLen;
407+ rv = _SGN_VerifyPKCS1DigestInfo(
408+ digestOid, &digest, &pkcs1DigestInfo,
409+ PR_TRUE /*XXX: unsafeAllowMissingParameters*/);
410 }
411
412- loser:
413- PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
414- rv = SECFailure;
415-
416- done:
417- if (it.data != NULL) PORT_Free(it.data);
418- if (di != NULL) SGN_DestroyDigestInfo(di);
419-
420+ PORT_Free(pkcs1DigestInfoData);
421 return rv;
422 }
423
424diff --git a/nss/lib/util/manifest.mn b/nss/lib/util/manifest.mn
425index ed54a16..9ff3758 100644
426--- a/nss/lib/util/manifest.mn
427+++ b/nss/lib/util/manifest.mn
428@@ -22,6 +22,7 @@ EXPORTS = \
429 pkcs11t.h \
430 pkcs11n.h \
431 pkcs11u.h \
432+ pkcs1sig.h \
433 portreg.h \
434 secasn1.h \
435 secasn1t.h \
436@@ -58,6 +59,7 @@ CSRCS = \
437 nssrwlk.c \
438 nssilock.c \
439 oidstring.c \
440+ pkcs1sig.c \
441 portreg.c \
442 secalgid.c \
443 secasn1d.c \
444diff --git a/nss/lib/util/nssutil.def b/nss/lib/util/nssutil.def
445index 86a0ad7..9d98df2 100644
446--- a/nss/lib/util/nssutil.def
447+++ b/nss/lib/util/nssutil.def
448@@ -271,3 +271,9 @@ SECITEM_ZfreeArray;
449 ;+ local:
450 ;+ *;
451 ;+};
452+;+NSSUTIL_3.17.1 { # NSS Utilities 3.17.1 release
453+;+ global:
454+_SGN_VerifyPKCS1DigestInfo;
455+;+ local:
456+;+ *;
457+;+};
458diff --git a/nss/lib/util/pkcs1sig.c b/nss/lib/util/pkcs1sig.c
459new file mode 100644
460index 0000000..03b16f5
461--- /dev/null
462+++ b/nss/lib/util/pkcs1sig.c
463@@ -0,0 +1,169 @@
464+/* This Source Code Form is subject to the terms of the Mozilla Public
465+ * License, v. 2.0. If a copy of the MPL was not distributed with this
466+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
467+ */
468+
469+#include "pkcs1sig.h"
470+#include "hasht.h"
471+#include "secerr.h"
472+#include "secasn1t.h"
473+#include "secoid.h"
474+
475+typedef struct pkcs1PrefixStr pkcs1Prefix;
476+struct pkcs1PrefixStr {
477+ unsigned int len;
478+ PRUint8 *data;
479+};
480+
481+typedef struct pkcs1PrefixesStr pkcs1Prefixes;
482+struct pkcs1PrefixesStr {
483+ unsigned int digestLen;
484+ pkcs1Prefix prefixWithParams;
485+ pkcs1Prefix prefixWithoutParams;
486+};
487+
488+/* The value for SGN_PKCS1_DIGESTINFO_MAX_PREFIX_LEN_EXCLUDING_OID is based on
489+ * the possible prefix encodings as explained below.
490+ */
491+#define MAX_PREFIX_LEN_EXCLUDING_OID 10
492+
493+static SECStatus
494+encodePrefix(const SECOidData *hashOid, unsigned int digestLen,
495+ pkcs1Prefix *prefix, PRBool withParams)
496+{
497+ /* with params coding is:
498+ * Sequence (2 bytes) {
499+ * Sequence (2 bytes) {
500+ * Oid (2 bytes) {
501+ * Oid value (derOid->oid.len)
502+ * }
503+ * NULL (2 bytes)
504+ * }
505+ * OCTECT (2 bytes);
506+ *
507+ * without params coding is:
508+ * Sequence (2 bytes) {
509+ * Sequence (2 bytes) {
510+ * Oid (2 bytes) {
511+ * Oid value (derOid->oid.len)
512+ * }
513+ * }
514+ * OCTECT (2 bytes);
515+ */
516+
517+ unsigned int innerSeqLen = 2 + hashOid->oid.len;
518+ unsigned int outerSeqLen = 2 + innerSeqLen + 2 + digestLen;
519+ unsigned int extra = 0;
520+
521+ if (withParams) {
522+ innerSeqLen += 2;
523+ outerSeqLen += 2;
524+ extra = 2;
525+ }
526+
527+ if (innerSeqLen >= 128 ||
528+ outerSeqLen >= 128 ||
529+ (outerSeqLen + 2 - digestLen) >
530+ (MAX_PREFIX_LEN_EXCLUDING_OID + hashOid->oid.len)) {
531+ /* this is actually a library failure, It shouldn't happen */
532+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
533+ return SECFailure;
534+ }
535+
536+ prefix->len = 6 + hashOid->oid.len + extra + 2;
537+ prefix->data = PORT_Alloc(prefix->len);
538+ if (!prefix->data) {
539+ PORT_SetError(SEC_ERROR_NO_MEMORY);
540+ return SECFailure;
541+ }
542+
543+ prefix->data[0] = SEC_ASN1_SEQUENCE|SEC_ASN1_CONSTRUCTED;
544+ prefix->data[1] = outerSeqLen;
545+ prefix->data[2] = SEC_ASN1_SEQUENCE|SEC_ASN1_CONSTRUCTED;
546+ prefix->data[3] = innerSeqLen;
547+ prefix->data[4] = SEC_ASN1_OBJECT_ID;
548+ prefix->data[5] = hashOid->oid.len;
549+ PORT_Memcpy(&prefix->data[6], hashOid->oid.data, hashOid->oid.len);
550+ if (withParams) {
551+ prefix->data[6 + hashOid->oid.len] = SEC_ASN1_NULL;
552+ prefix->data[6 + hashOid->oid.len + 1] = 0;
553+ }
554+ prefix->data[6 + hashOid->oid.len + extra] = SEC_ASN1_OCTET_STRING;
555+ prefix->data[6 + hashOid->oid.len + extra + 1] = digestLen;
556+
557+ return SECSuccess;
558+}
559+
560+SECStatus
561+_SGN_VerifyPKCS1DigestInfo(SECOidTag digestAlg,
562+ const SECItem* digest,
563+ const SECItem* dataRecoveredFromSignature,
564+ PRBool unsafeAllowMissingParameters)
565+{
566+ SECOidData *hashOid;
567+ pkcs1Prefixes pp;
568+ const pkcs1Prefix* expectedPrefix;
569+ SECStatus rv, rv2, rv3;
570+
571+ if (!digest || !digest->data ||
572+ !dataRecoveredFromSignature || !dataRecoveredFromSignature->data) {
573+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
574+ return SECFailure;
575+ }
576+
577+ hashOid = SECOID_FindOIDByTag(digestAlg);
578+ if (hashOid == NULL) {
579+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
580+ return SECFailure;
581+ }
582+
583+ pp.digestLen = digest->len;
584+ pp.prefixWithParams.data = NULL;
585+ pp.prefixWithoutParams.data = NULL;
586+
587+ rv2 = encodePrefix(hashOid, pp.digestLen, &pp.prefixWithParams, PR_TRUE);
588+ rv3 = encodePrefix(hashOid, pp.digestLen, &pp.prefixWithoutParams, PR_FALSE);
589+
590+ rv = SECSuccess;
591+ if (rv2 != SECSuccess || rv3 != SECSuccess) {
592+ rv = SECFailure;
593+ }
594+
595+ if (rv == SECSuccess) {
596+ /* We don't attempt to avoid timing attacks on these comparisons because
597+ * signature verification is a public key operation, not a private key
598+ * operation.
599+ */
600+
601+ if (dataRecoveredFromSignature->len ==
602+ pp.prefixWithParams.len + pp.digestLen) {
603+ expectedPrefix = &pp.prefixWithParams;
604+ } else if (unsafeAllowMissingParameters &&
605+ dataRecoveredFromSignature->len ==
606+ pp.prefixWithoutParams.len + pp.digestLen) {
607+ expectedPrefix = &pp.prefixWithoutParams;
608+ } else {
609+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
610+ rv = SECFailure;
611+ }
612+ }
613+
614+ if (rv == SECSuccess) {
615+ if (memcmp(dataRecoveredFromSignature->data, expectedPrefix->data,
616+ expectedPrefix->len) ||
617+ memcmp(dataRecoveredFromSignature->data + expectedPrefix->len,
618+ digest->data, digest->len)) {
619+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
620+ rv = SECFailure;
621+ }
622+ }
623+
624+ if (pp.prefixWithParams.data) {
625+ PORT_Free(pp.prefixWithParams.data);
626+ }
627+ if (pp.prefixWithoutParams.data) {
628+ PORT_Free(pp.prefixWithoutParams.data);
629+ }
630+
631+ return rv;
632+}
633diff --git a/nss/lib/util/pkcs1sig.h b/nss/lib/util/pkcs1sig.h
634new file mode 100644
635index 0000000..7c52b15
636--- /dev/null
637+++ b/nss/lib/util/pkcs1sig.h
638@@ -0,0 +1,30 @@
639+/* This Source Code Form is subject to the terms of the Mozilla Public
640+ * License, v. 2.0. If a copy of the MPL was not distributed with this
641+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
642+ */
643+
644+#ifndef _PKCS1SIG_H_
645+#define _PKCS1SIG_H_
646+
647+#include "hasht.h"
648+#include "seccomon.h"
649+#include "secoidt.h"
650+
651+/* SGN_VerifyPKCS1DigestInfo verifies that the length of the digest is correct
652+ * for the given algorithm, then verifies that the recovered data from the
653+ * PKCS#1 signature is a properly-formatted DigestInfo that identifies the
654+ * given digest algorithm, then verifies that the digest in the DigestInfo
655+ * matches the given digest.
656+ *
657+ * dataRecoveredFromSignature must be the result of calling PK11_VerifyRecover
658+ * or equivalent.
659+ *
660+ * If unsafeAllowMissingParameters is true (not recommended), then a DigestInfo
661+ * without the mandatory ASN.1 NULL parameter will also be accepted.
662+ */
663+SECStatus _SGN_VerifyPKCS1DigestInfo(SECOidTag digestAlg,
664+ const SECItem* digest,
665+ const SECItem* dataRecoveredFromSignature,
666+ PRBool unsafeAllowMissingParameters);
667+
668+#endif /* _PKCS1SIG_H_ */
669--
6701.7.9.5