diff options
author | Chong Lu <Chong.Lu@windriver.com> | 2014-11-06 15:50:38 +0800 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2014-11-24 16:24:55 +0000 |
commit | db7f4f31c915a59c502cac4be905d23df5246b3d (patch) | |
tree | 9249881a0ae94b49c221a9eab35d310990d0e345 /meta/recipes-support | |
parent | 33e95afc83f244fe182a36b90affaf7d211bd6b6 (diff) | |
download | poky-db7f4f31c915a59c502cac4be905d23df5246b3d.tar.gz |
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>
Diffstat (limited to 'meta/recipes-support')
-rw-r--r-- | meta/recipes-support/nss/files/nss-CVE-2014-1568.patch | 670 | ||||
-rw-r--r-- | meta/recipes-support/nss/nss.inc | 1 |
2 files changed, 671 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 @@ | |||
1 | nss: CVE-2014-1568 | ||
2 | |||
3 | the patch comes from: | ||
4 | http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-1568 | ||
5 | https://bugzilla.mozilla.org/show_bug.cgi?id=1064636 | ||
6 | nss ng log: | ||
7 | ===== | ||
8 | changeset: 11252:ad411fb64046 | ||
9 | user: Kai Engert <kaie@kuix.de> | ||
10 | date: Tue Sep 23 19:28:34 2014 +0200 | ||
11 | summary: Fix bug 1064636, patch part 2, r=rrelyea | ||
12 | ===== | ||
13 | changeset: 11253:4e90910ad2f9 | ||
14 | user: Kai Engert <kaie@kuix.de> | ||
15 | date: Tue Sep 23 19:28:45 2014 +0200 | ||
16 | summary: Fix bug 1064636, patch part 3, r=rrelyea | ||
17 | ===== | ||
18 | changeset: 11254:fb7208e91ae8 | ||
19 | user: Kai Engert <kaie@kuix.de> | ||
20 | date: Tue Sep 23 19:28:52 2014 +0200 | ||
21 | summary: Fix bug 1064636, patch part 1, r=rrelyea | ||
22 | ===== | ||
23 | changeset: 11255:8dd6c6ac977d | ||
24 | user: Kai Engert <kaie@kuix.de> | ||
25 | date: Tue Sep 23 19:39:40 2014 +0200 | ||
26 | summary: Bug 1064636, follow up commit to fix Windows build bustage | ||
27 | |||
28 | Upstream-Status: Backport | ||
29 | Signed-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 | |||
41 | diff --git a/nss/lib/cryptohi/secvfy.c b/nss/lib/cryptohi/secvfy.c | ||
42 | index 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: | ||
329 | diff --git a/nss/lib/softoken/pkcs11c.c b/nss/lib/softoken/pkcs11c.c | ||
330 | index 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 | |||
424 | diff --git a/nss/lib/util/manifest.mn b/nss/lib/util/manifest.mn | ||
425 | index 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 \ | ||
444 | diff --git a/nss/lib/util/nssutil.def b/nss/lib/util/nssutil.def | ||
445 | index 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 | +;+}; | ||
458 | diff --git a/nss/lib/util/pkcs1sig.c b/nss/lib/util/pkcs1sig.c | ||
459 | new file mode 100644 | ||
460 | index 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 | +} | ||
633 | diff --git a/nss/lib/util/pkcs1sig.h b/nss/lib/util/pkcs1sig.h | ||
634 | new file mode 100644 | ||
635 | index 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 | -- | ||
670 | 1.7.9.5 | ||
diff --git a/meta/recipes-support/nss/nss.inc b/meta/recipes-support/nss/nss.inc index ce7bff4e5d..008bdad5c7 100644 --- a/meta/recipes-support/nss/nss.inc +++ b/meta/recipes-support/nss/nss.inc | |||
@@ -23,6 +23,7 @@ SRC_URI = "\ | |||
23 | file://nss-3.15.1-fix-CVE-2013-1739.patch \ | 23 | file://nss-3.15.1-fix-CVE-2013-1739.patch \ |
24 | file://nss-CVE-2013-5606.patch \ | 24 | file://nss-CVE-2013-5606.patch \ |
25 | file://nss-CVE-2014-1544.patch \ | 25 | file://nss-CVE-2014-1544.patch \ |
26 | file://nss-CVE-2014-1568.patch \ | ||
26 | " | 27 | " |
27 | SRC_URI_append = "\ | 28 | SRC_URI_append = "\ |
28 | file://nss.pc.in \ | 29 | file://nss.pc.in \ |