-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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
crypto/x509: NameConstraintsWithoutSANs when checking signing certificate #24151
Comments
If there are no SANs in the certificate, then how are you assigning names to the leafs? crypto/x509 is intended to implement the WebPKI and, there, using common names as hostnames has been deprecated for years and support is being dropped in major clients. |
The name is specified in the Subject. For the example test certificate it is:
As mentioned, these are personal signing certificates (nonRepudiation/contentCommitment; specifically, signing certificates of the Estonian national ID-card) and not server certificates, so the Common Name is not used as a hostname, but just to identify the signing person. I understand that the primary use case is TLS and WebPKI, but before this change, the package could also be successfully used for other RFC-compliant X.509 certificates. |
Do the in-use Estonian ID cards also have this property, or is this just a test CA? |
This is fairly dodgy by the Estonian ID system: they're setting DNS constraints but expecting those constraints not to apply to the CN (where DNS names historically went) and yet are also not including the SAN extension to signal that the certificate is new enough to know not to wedge DNS names into the CN. A workaround for this would look like ignoring name constraints when no SANs exist if no |DNSName| is requested in the |
Would this break the explicit goal set by Go 1.10?
As I understand, the idea is that now I can do |
Yes, that's a good point—it would break that. We could add a flag on the Certificate to indicate that the CN shouldn't be used by a later Unless someone has a clever suggestion, it's not clear to me that we should change anything here. |
@agl Nowhere in https://golang.org/pkg/crypto/x509/ does it read that this package is (solely) about WebPKI. Might want to clarify that in the docs? |
@agl What about moving the We do not do any Name Constraints validation in This would also work if only EDIT: After reading the RFC in more detail, the following requirement should be kept in mind if considering my proposed solution:
The Estonian ID system does not set any constraints on the email, but this could affect some other CAs. |
VerifyHostname takes only a leaf certificate, but the property of whether or not constraints apply is a property of the validation chain. (I.e. the root certificate can trigger it.) My best idea for this is to allow constraints without SANs if the CN doesn't parse as a valid DNS name, and have VerifyHostname ignore the CN if it doesn't parse. |
Ah, of course. For some reason I thought that the new *DNSDomains fields would include data from the entire chain, but it makes much more sense that they only reflect the extensions on the certificate itself. Maybe set some (unexported?) flag on the leaf Certificate showing if there were any Name Constraints in the chain? Otherwise checking the CN would seem to work. Could consulting the Extended Key Usage for Server Authentication help in some way? |
@agl Any updates on this? |
I believe the fix for this is scheduled for 1.10.1. |
@agl @FiloSottile can you dupe this into the 1.10.1 fix? |
AFAICT this one doesn't have a fix yet, and it still doesn't work on tip. |
Sorry, when I said above that "I believe the fix for this is scheduled for 1.10.1", I was confusing this with #23995 and didn't notice until Filippo just said that we didn't have a fix. I don't think we've actually decided whether we want to do something here. |
OK. Then this is outside the 1.10.1 window. Moving to 1.11 for now. |
Should we consider dropping support for hostnames in CN altogether? The browsers managed to. |
So far we have seen three potential solutions to this. a) Drop support for hostnames in CN altogether. b) Allow for NameConstraints without SANs in Certificate.isValid. Instead set a flag in the leaf Certificate struct noting that there were NameConstraints in the chain. Later, when calling Certificate.VerifyHostName (either directly or via Certificate.Verify with a DNSName) on the leaf, return NameConstraintsWithoutSANs if the flag is set and there are no SANs. This works because Certificate.VerifyHostname is never called for signing certificates. c) Allow for NameConstraints without SANs in Certificate.isValid ONLY IF the CN of the leaf Certificate does not parse as a valid DNS name. Otherwise return NameConstraintsWithoutSANs. Later, when calling Certificate.VerifyHostname, ignore the CN if it does not parse. This works because signing certificates usually do not have names that parse as DNS names. From the perspective of current issue all these solutions are equally good. Is there a reason not to implement one of those for go 1.11? |
@agl, can you assume that if CA uses DNS constraints then the certificates issued by that CA are new enough to know not to wedge DNS names into the CN? Would such assumption lead to much simpler fix? |
Change https://golang.org/cl/103868 mentions this issue: |
That would be nice. However, 1.10 has been overly "exciting" w.r.t. certificate validation so I'm dialing towards being more conservative at the moment. I think of all the options enumerated by @svenheiberg, I like (c) the most. However, the example certificate in given above has a CN of So, if the REDACTED part always contains a space then it would happen to work. I guess we could also ban commas, but it feels like we're really crafting a special case for these Estonian certificates in that case. Thus I'm wondering about an option (d): require SANs for DNS name constraints only. (I think @user8547 might have been suggesting this just above.) The point of the error is to ensure that we don't have a gap between https://go-review.googlesource.com/c/go/+/103868 to do that. |
Your certificates are correct.
The problem is that name constraints don't apply to CN, but Go currently considers CN a hostname. We are trying to fix that in Go 1.15 but a lot of things put hostnames in CN. |
If one of the names fails name constraints, is only that name invalid or the whole certificate? If an intermediate certificate has an invalid (because of constraints) alternative name, does that invalidate the leaf certificate even if all its names are valid? If a certificate contains an alternative name of unknown type, and there is a constraint of that type, should the certificate be rejected altogether? |
The dominant model, which Go follows (now), is that a certificate is verified in the abstract, not in the context of a specific name. Thus the whole certificate should be invalid.
Intermediates generally shouldn't have SANs. I don't think they should invalidate a chain if they do even if they don't match constraints. But you're getting into areas where I bet different libraries disagree.
If a parent certificate has constraints of an unknown type, and the extension is critical, then that's a parse error. If not critical, then the constraint is ignored. |
DirectoryName constraint does apply to subject DN. Also, like with DNS name and CN, rfc822Name constraint applies to emailAddress in DN in the absence of SAN. |
Change https://golang.org/cl/243221 mentions this issue: |
The interaction of constraints and CN is a historical problem because of the legacy of repurposing the CN as a DNS name. Once that is eliminated, DNS constraints should only apply to DNS SANs in the same way that email constraints only apply to email SANs. (There is some historical practice of putting email addresses in a special type in a DN, but that's ignorable now and Go does ignore it.) |
I did some tests for DNS and email constraints applied to SAN and dirname constraints applied to subject. Most implementations reject all certificates, including intermediates, that have any failing name. One exception is Wget, who doesn't check subjects and intermediate certificates. Go 1.15 beta 1 doesn't check intermediates, and it doesn't support dirname constraints. |
According to the spec, the name constraints from issuers apply to all certificates, including intermediates, issued by it, transitively.
That is the right thing to do.
If true, that seems wrong. |
Updates #39568 Updates #37419 Updates #24151 Change-Id: I44c940e09e26a039076396bbfecb2b1574197cf7 Reviewed-on: https://go-review.googlesource.com/c/go/+/243221 Reviewed-by: Kevin Burke <kev@inburke.com>
The change (almost surprisingly) landed in Go 1.15, but I know of a few large companies using the opt-out while they transition. Let's keep it around until Go 1.17, and announce it will be removed in the Go 1.16 release notes. |
Change https://golang.org/cl/266539 mentions this issue: |
For #40700 Updates #24151 Change-Id: Id63dcaad238f7534bfce8902b8cb3efd8db5942d Reviewed-on: https://go-review.googlesource.com/c/go/+/266539 Trust: Filippo Valsorda <filippo@golang.org> Trust: Katie Hockman <katie@golang.org> Reviewed-by: Katie Hockman <katie@golang.org>
@FiloSottile in #24151 (comment) you mentioned that we should document removal in Go1.16 release notes, then keep this issue around/open for Go1.17. With that I am going to move this milestone forward to Go1.17, but please feel free to revert or close if you need to. cc-ing @toothrot for release tracking/visibility. |
Is something supposed to change for 1.17? |
Yeah, we are removing the GODEBUG flag. |
Change https://golang.org/cl/315209 mentions this issue: |
What did you do?
A CA which issues personal signing certificates has specified X.509 Name Constraints to exclude any DNS names and IP addresses:
This is good practice to protect against misissued certificates.
Attempt to verify a test certificate issued by that CA: https://play.golang.org/p/y4l1JJqDQPs
What did you expect to see?
I expected the verification to succeed as it did in go 1.9 and earlier.
What did you see instead?
Starting from go 1.10, verification fails with
NameConstraintsWithoutSANs
:It is true that the signing certificates do not contain SAN extensions, because they have no need for one. This error did not trigger before, because when verifying a signing certificate, no DNS name is specified. But as stated in the change log for go 1.10:
I believe this is a bug, because RFC 5280 Section 4.2.1.10 regarding Name Constraints states:
I understand this behavior is there for cases where we encounter a legacy TLS server certificate which relies on the Common Name as the hostname, but other certificates are now also hit by this. Maybe
Certificate.Verify
should distinguish between TLS server certificates and other X.509 certificates and haveNameConstraintsWithoutSANs
only trigger for the first ones?Does this issue reproduce with the latest release (go1.10)?
Yes, go 1.10 is where it was introduced.
System details
The text was updated successfully, but these errors were encountered: