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 | |
| 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>
| -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 \ |
