Closed Bug 489714 Opened 16 years ago Closed 6 years ago

libPKIX erroneously detects cert chain loops when it finds untrusted roots

Categories

(NSS :: Libraries, defect, P1)

Tracking

(Not tracked)

RESOLVED WONTFIX
3.12.4

People

(Reporter: nelson, Assigned: alvolkov.bgs)

References

Details

(Whiteboard: PKIX)

Attachments

(1 file)

When function pkix_Build_VerifyCertificate comes to a self-signed root CA cert that is not trusted, it incorrectly determines that the chain has a loop. This apparently causes libPKIX to stop checking for other possible paths that might lead to other roots, and instead report that it cannot build a path. libPKIX has a function to determine if a cert is self-signed, but does not use it here. I think I can tackle this in Alexei's absence.
Sadly, pkix_IsCertSelfIssued() is wrong. It ignores key IDs.
So I went looking throughout libPKIX for a function that can test the SubjectKeyID extension in an issuer cert against the AuthorityKeyID extension in a subordinate cert, and found none. That's right, it appears there is NO code in libPKIX to properly test subject and authority key ID extensions against each other. I hope I'm wrong, but I really don't see it. Instead I found some silly code that compares two authority key IDs to each other as byte strings. Thankfully, that nonsense appears to be dead code, other than being tested in unit tests. We really should get rid of it.
The erroneous loop detection code is at http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/security/nss/lib/libpkix/pkix/top/pkix_build.c&rev=1.57&mark=897-921#889 The mere presence of a root in the chain does not constitute looping. To fix this, the code must CORRECTLY identify roots. That means that pkix_IsCertSelfIssued needs to be fixed before this bug can be fixed. Alexei, I'm giving this back to you. If you're bored ... :)
Assignee: nelson → alexei.volkov.bugs
Severity: normal → major
Priority: -- → P2
Whiteboard: PKIX
Priority: P2 → P1
I'm not sure if you have found this problem by review of a test. Would be great to have a test if you have one. But I'm quite convinced we have the problem but it is not related to pkix_IsCertSelfIssued. I think the function is correct(self-signed certs set is a subset of self-issued certs) and is used in proper places(when chain is already built), although we need test cases(see below). Consider the chain: CAI -> CAII -> CAII(Self-Issued) -> EE The problem that I see is inefficiency when dealing with self-issued certs in cases when chain CAI,CAII,EE is constructed and discarded due to failure to validate EE cert signature. I case when CAII(SI)->EE is built first, the libpkix traverses through all certs in the chain to detect a loop. pkix_pl_Cert_Equals function is used for this operation. It calls CERT_CompareCerts(plain cert DERs comparison) to compare the pair therefor will distinguish two cert of the same subject names(CAII and CAII(SI)). Here is some tasks for Slavo: we don't have even one test that would check that libpkix correctly handles Self-Issued(SI) certificates. There are a few areas where we need some testing: * Name Constraints/name validation should not be applied to SI certs(except the final cert). * Should be ignored when calculating any path lengths(cert path, Basic Constraints, explicit policy, policy mapping). It should also be ignored when calculating number of certs to be processed before inhibiting anyPolicy. * Signature checks for crls that do or don't have authKeyId extensions.
Alexei, I agree that pkix_IsCertSelfIssued is not part of the problem. Sadly, it is also not part of the solution. I was lamenting that fact.
In comment 3, I wrote: > That means that pkix_IsCertSelfIssued needs to be fixed before this bug > can be fixed. That was incorrect. I should have written that we need a new function, pkix_IsCertSelfSigned, and that the code that i cited above, which now erroneously calls pkix_IsCertSelfIssued should call pkix_IsCertSelfSigned instead.
> CAI -> CAII -> CAII(Self-Issued) -> EE Why do we need to support such chains? Under what situations should that chain verify but neither of the following chains should verify? CAII(Self-Issued) -> EE CAI -> CAII -> EE
Self Issued means only that the subject and issuer names are the same. It does not necessitate that the cert is self-signed. The self issued cert have have a different key, and keyID, than the cert of its issuer, even though the names are the same. Self-Issued CA certs are used as "rollover" certs, to facilitate a transition from an old CA public key to a new one. Imagine that CAII(2k) is a new cert for CAII, with a 2k-bit pub key. Imagine that CAII(1k) is a new cert for the old public key previously used by CAII, a key of only 1k bits. Imagine that EE is signed with a 1k bit pub key. Then the chain CAI(4k) -> CAII(2k) -> CAII(1k) -> EE should validate, but CAII(1k) -> EE does not because CAII(1k) is not a trust anchor, and CAI(4k) -> CAII(2k) -> EE does not because EE was signed with a 1k bit key.
Nelson, thank you for the excellent explanation. Is it true, then, that the old non-libpkix cert chain building code cannot handle these self-issued certificates correctly either? AFAICT, given a chain like CAI(4k) -> CAII(2k) -> CAII(1k) -> EE, the older code would try to build a chain like CAII(2k) -> EE if CAII(2k) is newer than CAII(1k) and that would fail. If my assumption is correct, we can remove this from the blocking "libpkix by default in Firefox" bug.
The old çode should handle self-issued certificates correctly provided that the certs all correctly use SubjectKeyID and AuthorityKeyID extensions correctly, regardless of date.
Would this function need to actually perform the signature validation, or is that handled elsewhere? i.e., does pkix_isCertSelfSigned need to check to see that it actually is self-signed, or only that it should be?
In the past I've been told: CERTCertificate.isRoot -> bool, tells whether or not a cert is self signed We use this check in PSM when we need to know. If I understand correctly, we simply need to change libpkix to check this bool?
(In reply to Nelson Bolyard (seldom reads bugmail) from comment #6) > In comment 3, I wrote: > > That means that pkix_IsCertSelfIssued needs to be fixed before this bug > > can be fixed. > > That was incorrect. I should have written that we need a new function, > pkix_IsCertSelfSigned, and that the code that i cited above, which now > erroneously calls pkix_IsCertSelfIssued should call pkix_IsCertSelfSigned > instead. But the code you had quoted in comment 3 doesn't call pkix_IsCertSelfIssued, so it's not clear which call should be replaced.
Sorry, but I don't understand this bug report. Nelson said: "When function pkix_Build_VerifyCertificate comes to a self-signed root CA cert that is not trusted, it incorrectly determines that the chain has a loop. " I cannot see such a check. The only loop decision that I can find in pkix_Build_VerifyCertificate happens, if a candidate cert is already found in the chain that was built so far, and hence, would now be used again. And the only check that involves calling IsCertSelfIssued is related to a decision to delay revocation checking.
Attached patch implement pkix_IsCertSelfSigned (deleted) — Splinter Review
just in case it's still needed, here is a proposed implementation of pkix_IsCertSelfSigned
Status: NEW → RESOLVED
Closed: 6 years ago
Resolution: --- → WONTFIX
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: