-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Handle more basic constraints chain statuses. #35347
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
macOS can return additional chain status strings for a certificate that was issued by a certificate that violated its basic constraints. If a leaf certificate is issued from a certificate with CA:FALSE, the strings BasicConstraintsCA and BasicConstraintsPathLen are reported. We map these the same for BasicConstraints.
| *pStatus |= PAL_X509ChainUntrustedRoot; | ||
| else if (CFEqual(keyString, CFSTR("BasicConstraints"))) | ||
| else if (CFEqual(keyString, CFSTR("BasicConstraints")) || CFEqual(keyString, CFSTR("BasicConstraintsCA")) || | ||
| CFEqual(keyString, CFSTR("BasicConstraintsPathLen"))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Presumably this means that we need more tests for this status code. Can you add them in DynamicChainTests along with this PR?
|
@bartonjs done. Confirmed that without the fix, test fails with: [stuff elided]
ib/src/System/Runtime/CompilerServices/AsyncMethodBuilderCore.cs:line 42
at Xunit.Sdk.ExceptionAggregator.RunAsync[T](Func`1 code)
at Xunit.Sdk.TestInvoker`1.RunAsync() in C:\Dev\xunit\xunit\src\xunit.execution\Sdk\Frameworks\Runners\TestInvoker.cs:line 189
at Xunit.Sdk.XunitTestRunner.InvokeTestMethodAsync(ExceptionAggregator aggregator) in C:\Dev\xunit\xunit\src\xunit.execution\Sdk\Frameworks\Runners\XunitTestRunner.cs:line 84
Unknown Chain Status: BasicConstraintsCA
at Xunit.Sdk.XunitTestRunner.InvokeTestAsync(ExceptionAggregator aggregator) in C:\Dev\xunit\xunit\src\xunit.execution\Sdk\Frameworks\Runners\XunitTestRunner.cs:line 67
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine) in /Users/kjones/Projects/runtime/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncMethodBuilderCore.cs:line 42
[stuff elided]
|
|
@bartonjs once this is green / merged, is this backport worthy? If so I can prepare PRs for current LTS release branches. (My current feeling is "no", but, couldn't hurt to ask) |
|
For what it's worth, I saw the test fail on 10.15.4. I don't know if this test passes for the right reason in CI if it is using an older version of macOS. It would appear that at some point a "BasicConstraints" status was split out to "BasicConstraintsCA" and "BasicConstraintsPathLen" on macOS. So perhaps that test I wrote is just exercising the "BasicConstraints" path and would pass anyway in CI. |
| { | ||
| byte[] serialNumber = new byte[9]; | ||
| RandomNumberGenerator.Fill(serialNumber); | ||
| serialNumber[0] &= 0b01111111; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
99% sure CertificateRequest handles this already, by inserting an 0x00 if the high bit was set.
| } | ||
| } | ||
|
|
||
| Assert.True(verifiedIntermediate, "verify leaf certificate"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| Assert.True(verifiedIntermediate, "verify leaf certificate"); | |
| Assert.True(verifiedIntermediate, "Verified intermediate certificate"); |
| } | ||
|
|
||
| Assert.True(verifiedIntermediate, "verify leaf certificate"); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we already have a test for pathLen exceeded? I feel like the easy overload on CertificateRequest will check that and block it, but if you use the X509SignatureGenerator version (where it can't see the parent cert) then it obviously won't.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Really the question here is is there an extra extra error that appears for pathlen exceeded)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really the question here is is there an extra extra error that appears for pathlen exceeded
Yeah, It's reported as BasicConstraintsPathLen which this test handled both since Apple reports both in this case (It's a CA:FALSE and has a path length violation) - I will split this in to two separate tests.
X509SignatureGenerator
Oh that's much better than the weird intermediate swap-out I did. I completely missed Create.
Yeah, the API claims it handles a bad basic constraints extension; it throwing "something went wrong" when it happens is bad UX... and is presumably caused by an OS update somewhere along the way... so it's probably something we should take. |
Test CA:FALSE and path length violations independently.
|
Looks like Linux isn't reporting the invalid constraints on pathLen 0 test. Either we (I) mis-mapped a code somewhere or OpenSSL thinks that CA + pathLen 0 is "obviously they meant null"; and it needs to be
Maybe? Or maybe there's some other nuance, like it only bothers reporting it for trusted chains (the tests could use the new contextual roots feature if that's the case). |
|
@bartonjs I think the issue is that it is always reporting PartialChain. I fixed linux using the CustomTrustStore, but now I broke OSX. Working on trying to make everyone happy. |
That makes way more sense, I misunderstood how it works from a test. I assume you meant "extra instead of custom" since the intermediates should not at all be considered trust anchors? |
Yep. All of our underlying engines support doing arbitrary anchors (e.g. pin to one of these issuing CA), but we chose not to support it with the initial custom trust store. We could at some point add things like PinnedIssuer (directly issued by something in the store) or AnyAncestor (like CustomRoot but allows intermediates to function as anchors); which merely changes the way that we interpret the custom collection. So it's just nice to represent the intent correctly :) |
|
:-( Looking at Windows... path length seems to be excessively platform-specific behavior... |
|
@bartonjs the path length case has a few interesting behaviors from platform to platform, but I think I've found a case where they all agree. The current fails appear unrelated. |
|
I agree the failure looks unrelated, but trying one more re-run just to feel better about myself. (I don't like when the failure is in a downstream component... even though the only source change is in macOS and the test failure was in Windows) |
I've managed to shake out a few more of these... (#35463, #35492, #35533) and might find a few more. Should I hold off opening a PR to the LTS branches in case you think any of these should go in to the same PR as well? (35492 seems to be a similar criteria as this one) |
|
Yeah, we should try to get a bunch into one change as simply improving reliability around those cases. Nice work on burning down the delta, BTW. |
|
Multiple PRs in master with one PR to each of 3.1 and 2.1 is what I had in mind. |
macOS can return additional chain status strings for a certificate that
was issued by a certificate that violated its basic constraints.
If a leaf certificate is issued from a certificate with CA:FALSE,
the strings BasicConstraintsCA and BasicConstraintsPathLen are
reported. We map these the same for BasicConstraints.
Relates to #35238.