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/tls: Client authentication fails for certificates that don't specify an extended key usage #11087
Comments
I think that the requirement that client-auth certificates be explicitly marked for client-auth is a reasonable default. Most people don't know about EKUs and this might save them from a nasty security bug where they didn't think about what other certificates a given CA might be issuing. For cases where one wants to override this, there's already an option for bypassing automatic verification and then you can do whatever you want. I'm not seeing a convincing case for changing things here. |
Thanks for your comment... @agl by this logic you should not allow server certificates that don't specify ExtKeyUsageServerAuth. This isn't about people knowing or not knowing about EKUs. If an EKU isn't there you aren't required to check for this... But you are. This is incompatible with the standard and is breaking existing client certs. You're not really saving people from security bugs, it's perfectly fine/secure to use a cert without any specified key usages as a client auth certificate. I agree that if EKU is in the cert you should enforce it. I'd appreciate it if you could point me to how I could bypass automatic verification in the context of a TLS HTTP server application. I haven't been able to find a clean way to do that. I'm using both client and sever authentication. |
We don't. Although, as a retreat at the hands of practicality, we accept no EKUs to mean "all" in that case. (And we accept the Netscape EKU.)
Just set RequestClientCert or RequireAnyClientCert (http://golang.org/pkg/crypto/tls/#ClientAuthType) and then http://golang.org/pkg/crypto/tls/#Conn.ConnectionState to get the chain that the client provided. That can can be passed to Verify with whatever options you wish. See http://golang.org/src/crypto/tls/handshake_server.go#L605 |
I see the situation as symmetric between client and server. I think your client implementation is standard compliant (no EKU means all) and your server implementation not compliant (no EKU means none). Since client authentication isn't very commonly used there aren't too many people who care about this... Not sure if there's something else I can say to convince you here that isn't simply a matter of opinion. I can do a little more research and see if I come up with something. In situation where I've seen client certs used EKU wasn't typically set (hence the original report and the similar SO question). If I set RequireAnyClientCert (which I tried) it seems the only place I can verify the cert is in the context of my handler functions. I'm using persistent connections and I don't want to need to re-verify this for every HTTP request. It's not clear where I can hook the server to only verify on the initial incoming connection. Also I wouldn't be able to fail the TLS negotiation at this point, it would need to be an HTTP error. Is there a better way of doing this? |
@agl Maybe relevant and last attempt to re-iterate on this :) https://www.ietf.org/mail-archive/web/pkix/current/msg05179.html
http://lists.shmoo.com/pipermail/hostap/2014-February/029519.html
|
Having slept on it, I think that I'm convinced that this isn't a battle worth fighting: https://go-review.googlesource.com/#/c/10806/ |
CL https://golang.org/cl/10806 mentions this issue. |
Previously we enforced both that the extended key usages of a client certificate chain allowed for client authentication, and that the client-auth EKU was in the leaf certificate. This change removes the latter requirement. It's still the case that the chain must be compatible with the client-auth EKU (i.e. that a parent certificate isn't limited to another usage, like S/MIME), but we'll now accept a leaf certificate with no EKUs for client-auth. While it would be nice if all client certificates were explicit in their intended purpose, I no longer feel that this battle is worthwhile. Fixes golang#11087. Change-Id: I777e695101cbeba069b730163533e2977f4dc1fc Reviewed-on: https://go-review.googlesource.com/10806 Reviewed-by: Andrew Gerrand <adg@golang.org> Run-TryBot: Adam Langley <agl@golang.org>
Previously we enforced both that the extended key usages of a client certificate chain allowed for client authentication, and that the client-auth EKU was in the leaf certificate. This change removes the latter requirement. It's still the case that the chain must be compatible with the client-auth EKU (i.e. that a parent certificate isn't limited to another usage, like S/MIME), but we'll now accept a leaf certificate with no EKUs for client-auth. While it would be nice if all client certificates were explicit in their intended purpose, I no longer feel that this battle is worthwhile. Fixes golang#11087. Change-Id: I777e695101cbeba069b730163533e2977f4dc1fc Reviewed-on: https://go-review.googlesource.com/10806 Reviewed-by: Andrew Gerrand <adg@golang.org> Run-TryBot: Adam Langley <agl@golang.org>
go version go1.4.2 linux/amd64
Expecting: client cert to be verified and connection proceeds.
Getting: "tls: client's certificate's extended key usage doesn't permit it to be used for client authentication"
Also see: #7423
This is basically the same issue reposted. At the time the issue was posted people who hit this issue generated new certs with EKU to get around the problem. However the behaviour for certs without EKU is IMO still incorrect.
I am using Go in an existing system where there are an existing set of certs that are already used for client authentication. Because of live upgrade considerations generating new certs is difficult and the existing certs do not specify EKU. From my reading of the standard the way we are currently using the certificates is compliant. One option I have to fit within this system is to patch the libraries which I'd rather not do. Trying to override the default verification appears to be complicated and error prone.
From RFC3280 (emphasis mine):
From RFC5280:
If I'm reading it correctly, the existing code (ftls/handshake_server.go) appears to treat a missing EKU the same as if the EKU is specified without the client auth usage but as far I can tell there's no real justification in the standard for doing this?
Contrast this with the way server certificates are treated here (x509/verify.go):
(if the same requirement for EKU was applied to server certs that would probably break everyone's applications... client authentication is not very common which is why only a few people seem to have hit this...)
Further reference:
http://tools.ietf.org/html/rfc5280#section-4.2.1.12
http://blogs.msdn.com/b/kaushal/archive/2012/02/18/client-certificates-v-s-server-certificates.aspx
http://security.stackexchange.com/questions/68491/recommended-key-usage-for-a-client-certificate
http://stackoverflow.com/questions/20875626/tls-clientauth-requires-extkeyusageclientauth-through-whole-certificate-chain
I'd be happy to propose a patch if there's agreement there is an issue. Either changing the default behaviour or providing some way of overriding could solve my problem. Any other suggestions would be appreciated. (The proper way is probably to pass the client auth usage to the verify function which already seems to do the right thing rather than doing the extra verification in the server handshake code)
The text was updated successfully, but these errors were encountered: