Closed Bug 351848 Opened 18 years ago Closed 18 years ago

DecryptSigBlock does not check the message digest's length is correct

Categories

(NSS :: Libraries, defect, P1)

3.11.2
defect

Tracking

(Not tracked)

RESOLVED FIXED
3.11.3

People

(Reporter: wtc, Assigned: nelson)

Details

(Keywords: verified1.8.0.7, verified1.8.1, Whiteboard: [sg:high])

Attachments

(4 files, 5 obsolete files)

The callers of DecryptSigBlock pass a buffer of size HASH_LENGTH_MAX to ensure it is large enough to hold any message digest. But DecryptSigBlock only checks that the message digest can fit in the buffer. It doesn't check that the message digest's length is correct for the message digest algorithm, and it doesn't return the length to the callers, so the callers can't check that, either. So for MD5, one can append up to 48 bytes of arbitrary data after the MD5 hash, and for SHA-1, up to 44 bytes. However, the length octet in the ASN.1 encoding of the hash must match the length. Because of the smaller number of bytes to play with and the constraint on the length octet, it may be impossible to implement an attack similar to bug 350640.
This form of forgery is one of the 9 test cases attached to bug 351079.
It's e) garbage appended to the hash, inside the DER encoding that is: header, DER(Algorithm OID, algorithm parameters, hash+garbage)
oh, wait, are you suggesting something like this: header, DER(Algorithm OID, algorithm parameters, hash, garbage) where the garbage is inside the sequence that includes the hash, but comes after the hash?
It is header, DER(Algorithm OID, algorithm parameters, hash+garbage) NSS 3.11.3 release candidate has this bug. I also tried header, DER(Algorithm OID, algorithm parameters, hash, garbage) Thunderbird says the signature is invalid. I believe it fails in the decoding of DigestInfo but didn't verify it in a debugger or with printf statements.
We have a forged cert for that test case. 3.11.3 has been tested against it (certutil -V and vfychain) and detects it. So I conclude that one of these must be true: a) test forgery is defective. (I will investigate that) b) you're testing a different code path than I have been testing (I've been testing CERT_VerifyCert).
I tested email signature verification in Thunderbird. This is the code path (the line numbers may be slightly off because of the printf statements and other changes I added): 1. Decoding of DigestInfo: DecryptSigBlock(int * 0x0309fdfc, unsigned char * 0x027862ac, unsigned int 64, SECKEYPublicKeyStr * 0x0389ef00, const SECItemStr * 0x03759eb0, char * 0x0373dfa0) line 107 vfy_CreateContextPrivate(const SECKEYPublicKeyStr * 0x02d361d0, const SECItemStr * 0x03759eb0, int 20, const SECItemStr * 0x00000000, void * 0x0373dfa0) line 354 + 33 bytes vfy_VerifyDataPrivate(const unsigned char * 0x038a17f8, int 461, const SECKEYPublicKeyStr * 0x02d361d0, const SECItemStr * 0x03759eb0, int 20, const SECItemStr * 0x00000000, void * 0x0373dfa0) line 602 + 25 bytes VFY_VerifyData(unsigned char * 0x038a17f8, int 461, SECKEYPublicKeyStr * 0x02d361d0, SECItemStr * 0x03759eb0, int 20, void * 0x0373dfa0) line 621 + 31 bytes NSS_CMSSignerInfo_Verify(NSSCMSSignerInfoStr * 0x03759e68, SECItemStr * 0x0375a4b8, SECItemStr * 0x00303894) line 469 + 38 bytes NSS_CMSSignedData_VerifySignerInfo(NSSCMSSignedDataStr * 0x0276a228, int 0, NSSTrustDomainStr * 0x027452e0, int 4) line 699 + 17 bytes THUNDERBIRD! 007ec136() THUNDERBIRD! 007ec03a() THUNDERBIRD! 007ef870() THUNDERBIRD! 007ef9d6() 25e814ec() 2. PORT_Memcmp call that compares the decrypted hash with the alleged hash: VFY_EndWithSignature(VFYContextStr * 0x027862a0, SECItemStr * 0x00000000) line 521 VFY_End(VFYContextStr * 0x027862a0) line 536 + 11 bytes vfy_VerifyDataPrivate(const unsigned char * 0x038a17f8, int 461, const SECKEYPublicKeyStr * 0x02d361d0, const SECItemStr * 0x03759eb0, int 20, const SECItemStr * 0x00000000, void * 0x0373dfa0) line 610 + 9 bytes VFY_VerifyData(unsigned char * 0x038a17f8, int 461, SECKEYPublicKeyStr * 0x02d361d0, SECItemStr * 0x03759eb0, int 20, void * 0x0373dfa0) line 621 + 31 bytes NSS_CMSSignerInfo_Verify(NSSCMSSignerInfoStr * 0x03759e68, SECItemStr * 0x0375a4b8, SECItemStr * 0x00303894) line 469 + 38 bytes NSS_CMSSignedData_VerifySignerInfo(NSSCMSSignedDataStr * 0x0276a228, int 0, NSSTrustDomainStr * 0x027452e0, int 4) line 699 + 17 bytes THUNDERBIRD! 007ec136() THUNDERBIRD! 007ec03a() THUNDERBIRD! 007ef870() THUNDERBIRD! 007ef9d6() 25e814ec()
Please assign this to a real owner (wtc? nelson?) I'm confused by comment 4, NSS is vulnerable but Thunderbird is not?
Flags: blocking1.8.1?
Flags: blocking1.8.0.8?
Flags: blocking1.8.0.7?
Whiteboard: [sg:investigate]
This is one way to fix it. I won't be able to work on this bug this week. Feel free to use this patch or write your own patch. If you use this patch, feel free to change identifier names and indentation, etc. I didn't have time to work on coding style.
Also, someone should examine VFY_VerifyDigest because of the XXX comment in front of it.
Assignee: nobody → nelson
This bug, together with bug 350640 and bug 351079, are all vulnerabilities to malformed PKCS#1 v1.5 RSA signatures. There are several code paths through NSS that check these signatures. One of them was fixed for bug 351079. This bug reports another path that is vulnerable to one of the same cases as shown in that bug. It appears that the difference is that this path is used to verify signatures on things other than certificates, whereas the other path was used to verify signatures on certificates. I consider this to be part of the same vulnerability. If NSS accepts the malformed signature, NSS is vulnerable to it, regardless of what kind of data (cert or other) is being signed. Perhaps we should reopen bug 351079 and make this bug a dup of that one.
Severity: normal → blocker
Priority: -- → P1
Whiteboard: [sg:investigate] → [sg:high]
Target Milestone: --- → 3.11.3
Comment on attachment 237388 [details] [diff] [review] Patch for NSS_3_11_BRANCH (Checked in) r=nelsonb. Bob please SR. There is one minor (nit) change I would make to this patch, but in the interest of time, I will refrain from changing it. In the patch segment below, instead of the 3 "+" lines, I would have coded this "*" line: > if (sig) { > SECOidTag hashid = SEC_OID_UNKNOWN; >- rv = DecryptSigBlock(&hashid, cx->u.buffer, >+ unsigned int digestlen = 0; >+ rv = DecryptSigBlock(&hashid, cx->u.buffer, &digestlen, >* rv = DecryptSigBlock(&hashid, cx->u.buffer, &cx->rsadigestlen, > HASH_LENGTH_MAX, cx->key, sig, (char*)wincx); > cx->alg = hashid; >+ cx->rsadigestlen = digestlen; > } else {
Attachment #237388 - Flags: superreview?(rrelyea)
Attachment #237388 - Flags: review+
Comment on attachment 237388 [details] [diff] [review] Patch for NSS_3_11_BRANCH (Checked in) r+=relyea The u.buffer data really calls out to be a secitem which points to the u.buffer space. That should also simplify the DSA and ECDSA verification code.
Attachment #237388 - Flags: superreview?(rrelyea) → superreview+
I believe the issue here is that the forged signature case uses more data than the biggest HASH we support, so it is being detected. The reduced size means that it will likely be harder to construct a perfect cube in the space we allow, but 40 bytes is enough to make me worried. Especially if one starts trying to attack 1024 bit keys (which may need less 'garbage' than 2048 or 3072 bit keys). Anyway I concur this should be fixed as part of the other signing issues. bob
Severity: blocker → normal
Priority: P1 → --
Target Milestone: 3.11.3 → ---
Flags: blocking1.8.1? → blocking1.8.1+
Comment on attachment 237388 [details] [diff] [review] Patch for NSS_3_11_BRANCH (Checked in) > if (sig) { > SECOidTag hashid = SEC_OID_UNKNOWN; >- rv = DecryptSigBlock(&hashid, cx->u.buffer, >+ unsigned int digestlen = 0; >+ rv = DecryptSigBlock(&hashid, cx->u.buffer, &digestlen, > HASH_LENGTH_MAX, cx->key, sig, (char*)wincx); > cx->alg = hashid; >+ cx->rsadigestlen = digestlen; > } else { The use of the local variable 'digestlen' is intended to bring your attention to the similar use of 'hashid' in the original code. Feel free to eliminate 'digestlen' and pass &cx->rsadigestlen directly, but please also eliminate 'hashid' and pass &cx->alg directly.
Flags: blocking1.8.0.8?
Flags: blocking1.8.0.7?
Flags: blocking1.8.0.7+
Comment on attachment 237388 [details] [diff] [review] Patch for NSS_3_11_BRANCH (Checked in) approved for the 1.8.0 branch, a=dveditz for drivers
Attachment #237388 - Flags: approval1.8.0.7+
Checked in on NSS_3_11_BRANCH
Severity: normal → critical
Status: NEW → ASSIGNED
Priority: -- → P1
Target Milestone: --- → 3.11.3
Comment on attachment 237388 [details] [diff] [review] Patch for NSS_3_11_BRANCH (Checked in) Now the owners of the mozilla branches need to port this to their branches. lib/cryptohi/secvfy.c; new revision: 1.16.2.4; previous revision: 1.16.2.3 I will work on preparing a patch for the trunk next. This file is VERY different on the trunk.
Attachment #237388 - Attachment description: Patch → Patch for NSS_3_11_BRANCH (Checked in)
Attached patch Patch for trunk (obsolete) — Splinter Review
Since this file is already SO different between trunk and branch, this patch for the trunk differs significantly from the branch patch. I took the liberty of renaming one variable to avoid ambiguity, and I also took Wan-Teh's suggestion about the hashid variable. This patch is not blocking any other mozilla branches.
Attachment #237443 - Flags: superreview?(wtchang)
Attachment #237443 - Flags: review?(rrelyea)
I renamed a function parameter and added a comment. There is no real change.
Attachment #237388 - Attachment is obsolete: true
Comment on attachment 237536 [details] [diff] [review] Patch for NSS_3_11_BRANCH v2 (Checked in) groovy.
Attachment #237536 - Flags: review+
Comment on attachment 237443 [details] [diff] [review] Patch for trunk r+ = rrelyea. The patch explains why hashid was separate, and handles the new semantic correctly. bob
Attachment #237443 - Flags: review?(rrelyea) → review+
Attached patch merged to client 1.8.0 branch (obsolete) — Splinter Review
Nelson, please give this a once-over to make sure the merge is OK.
Attachment #237546 - Flags: review?
Attachment #237546 - Flags: approval1.8.0.7+
Attachment #237546 - Flags: review?(wtchang)
Attachment #237546 - Flags: review?(nelson)
Attachment #237546 - Flags: review?
Attachment #237388 - Flags: approval1.8.0.7+
Comment on attachment 237388 [details] [diff] [review] Patch for NSS_3_11_BRANCH (Checked in) This one works for the 1.8 branch.
Attachment #237388 - Flags: approval1.8.1?
Comment on attachment 237536 [details] [diff] [review] Patch for NSS_3_11_BRANCH v2 (Checked in) ought to take this too just in case we have to merge something else in here later on.
Attachment #237536 - Flags: approval1.8.1?
Comment on attachment 237546 [details] [diff] [review] merged to client 1.8.0 branch I'm giving this a qualified r+ for the 1.8.0 branch. I believe this patch accurately carries the change from the NSS_3_11_BRANCH back to this older branch. However, because there are other preceeding changes from the NSS_3_11_BRANCH that have not been carried back I cannot state with any certainty that, with this patch applied, the 1.8.0 branch will be as free of vulnerabilities as the 3_11_BRANCH is now.
Attachment #237546 - Flags: review?(nelson) → review+
Attachment #237388 - Flags: approval1.8.1?
Dan, your patch is correct. I renamed the rsadigestlen field of VFYContext because 'digestlen' looks nicer on the MOZILLA_1_8_0_BRANCH (and NSS_3_10_BRANCH).
Attachment #237546 - Attachment is obsolete: true
Attachment #237546 - Flags: review?(wtchang)
Comment on attachment 237536 [details] [diff] [review] Patch for NSS_3_11_BRANCH v2 (Checked in) a=schrep
Attachment #237536 - Flags: approval1.8.1? → approval1.8.1+
Checked in attachment 237536 [details] [diff] [review] to the 1.8 branch for 1.8.1
Keywords: fixed1.8.1
Verified with Thunderbird 1.5.0.7 rc6 (compared with 1.5.0.5, which has the bug). Verified with Thunderbird 2 alpha 1 20060911 (compared with build 20060910, which has the bug).
Attached patch Patch for trunk v2 (obsolete) — Splinter Review
I added my new comment for digestlen and renamed the 'len' parameter of DecryptSigBlock. You missed the change to one PORT_Memcmp call. If it's intentional, please remove that change from this patch.
Attachment #237443 - Attachment is obsolete: true
Attachment #237443 - Flags: superreview?(wtchang)
Attachment #237879 - Flags: review?(julien.pierre.bugs)
Attachment #237879 - Flags: review?(julien.pierre.bugs) → review+
Comment on attachment 237878 [details] [diff] [review] Patch for trunk v2 r=nelson
Attachment #237878 - Flags: superreview?(rrelyea)
Attachment #237878 - Flags: review+
Comment on attachment 237878 [details] [diff] [review] Patch for trunk v2 sigh, good catch wan-teh. r=relyea
Attachment #237878 - Flags: superreview?(rrelyea) → superreview+
I made two additional changes to vfy_CreateContext. 1. I removed a break statement that's no longer necessary. 2. I fixed a leak of 'cx' on an error return. Coverity should be able to catch this leak, but Coverity was only run on some NSS branch used by Mozilla, and this code is new on the trunk only. Please review these two changes. I've checked in this patch on the NSS trunk for NSS 3.12. Checking in secvfy.c; /cvsroot/mozilla/security/nss/lib/cryptohi/secvfy.c,v <-- secvfy.c new revision: 1.20; previous revision: 1.19 done
Attachment #237878 - Attachment is obsolete: true
Attachment #238003 - Flags: review+
This revision fixes a problem due to the added declaration of QuickDER coming from a different revision than the source to QuickDER. The MSVC compiler didn't complain, but Sun's compiler rightly called it an error.
Attachment #237879 - Attachment is obsolete: true
Attachment #238134 - Flags: superreview?(julien.pierre.bugs)
Attachment #238134 - Flags: review?(christophe.ravel.bugs)
The build is passing on Solaris now. I am going to run some tests with all.sh.
Comment on attachment 238134 [details] [diff] [review] patch for NSS_3_3_4_1_BRANCH, v2 Build and tests are passing on Solaris with this patch.
Attachment #238134 - Flags: review?(christophe.ravel.bugs) → review+
Attachment #238134 - Flags: superreview?(julien.pierre.bugs) → superreview+
Comment on attachment 238134 [details] [diff] [review] patch for NSS_3_3_4_1_BRANCH, v2 Fix committed on the NSS_3_3_4_1_BRANCH. cmd/lib/SECerrs.h; new : 1.1.148.1; previous : 1.1 lib/cryptohi/secvfy.c; new : 1.5.54.1; previous : 1.5 lib/softoken/pkcs11c.c; new : 1.13.2.2.2.2; previous : 1.13.2.2.2.1 lib/util/manifest.mn; new : 1.4.108.1; previous : 1.4 lib/util/quickder.c; new : 1.23.20.1; previous : (added) lib/util/secasn1.h; new : 1.4.56.1; previous : 1.4 lib/util/secasn1t.h; new : 1.4.48.1.46.2; previous : 1.4.48.1.46.1 lib/util/seccomon.h; new : 1.2.118.1; previous : 1.2 lib/util/secdig.c; new : 1.2.200.1; previous : 1.2 lib/util/secerr.h; new : 1.3.64.1; previous : 1.3 tests/qa_stat; new : 1.21.50.1; previous : 1.21 tests/cipher/cipher.sh; new : 1.5.124.1; previous : 1.5 tests/cipher/performance.sh; new : 1.2.220.1; previous : 1.2 tests/ssl/ssl.sh; new : 1.38.52.2; previous : 1.38.52.1 Is this bug ready to be marked resolved/fixed?
Status: ASSIGNED → RESOLVED
Closed: 18 years ago
Resolution: --- → FIXED
Group: security
Related to or inspired by CVE-2006-4340 : unchecked garbage in PKCS v1.5 blocks
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: