-
Notifications
You must be signed in to change notification settings - Fork 81
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
pshtt may not be handling client cert authentication properly #153
Comments
The reference example is So, thinking about this a bit more...
Stepping back and looking at it from a policy intent perspective: M-15-13 and BOD 18-01 ask that agencies deprecate insecure traffic and take all available measures to instruct clients to initiate secure connections (and to support those connections once clients make them). Pshtt evaluates support for secure connections for traditional (server certificate) TLS by making sure port 443 is open and ensuring that the certificate is unexpired and for the intended hostname. The former check is relevant for client authentication, but the latter are not -- so even if we could detect endpoints that expect client certificates, pshtt would not be able to use the same logic path to evaluate the strength of the connection. But when the client provides the certificate, the client is the one that is ensuring authenticity, and so we shouldn't be evaluating the server's obligations there anyway. That's all to say that pshtt can't really have anything interesting to say about client certificate connections. If they're available at all, then the server's meeting its policy obligations to support them by definition whether or not we scan it, because opening the port is all we could evaluate. So, we could look into something novel like retrying HTTPS connections another time with a client cert in the specific case of an HTTP redirect that appears to redirect directly to a @PaulSD: How viable is it to drop the port 80->443 redirect for this hostname? Is it ever expected that that would be used? Dropping port 80 would at least patch the problem, because the domain would be seen as entirely inaccessible over HTTP. This may also be be compatible with policy intent as a general solution: 80->443 is only allowed for compatibility reasons, so that old links, and the common user behavior of manual link entry, can still be supported even before an HSTS policy takes effect. But these may not be very relevant for the highly specialized (and rare) cases of client-certificate-enabled services, and so it may be acceptable to ask service owners to remove that compatibility redirect. |
Another thought: even if we essentially ignore client cert connections from a That would be a I'd defer to @h-m-f-t and @jsf9k as to whether they think it's worth looking into the possibility of instrumenting |
Yet another thought: I'm not an expert at TLS connections using client certificates, and thinking about it more, I may be wrong about the server not having obligations to present a valid unexpired certificate during the connection, if the connection is trying to establish mutual authentication. But I also don't know whether we could realistically present a certificate that would get us far enough to evaluate the presented server certificate, if we presented an invalid certificate to the server. |
Sorry, port 443 on The way TLS works with client certificates is:
So, for the purposes here, client certificate authentication does not technically prevent checking the server SSL/TLS version, the configured cipher suites, or the server's certificate. Whether or not libcurl or sslyze can return those without completing the handshake is a different question, but it is technically possible to get them. The only thing client cert auth prevents is checking the HSTS header returned in the HTTPS response after the connection is established. However, in this particular case, the base domain is HSTS preloaded, so does it actually matter that you can't check the HSTS header returned after the connection is established? In this particular case, I could drop the port 80->443 redirect because users never actually type this URL in manually ... However, there are other cases in my environment where client certs are required and the port 80->443 redirect is needed, for example on a domain that unconditionally requires PIV authentication. So that wouldn't be a generic solution. Another monkey wrench here: This particular URL is actually only used by a specific client-side desktop application that uses its own embedded trust store, so we created an internal CA for it that is only trusted by that client app. So, even after we get past the client cert auth issue, we're still going to run into cert validation issues. However, I think the discussion 18F/pulse#760 may cover that issue. |
Ah, okay, this helps -- now it looks like it's a Running
Some quick efforts to generate a fake PEM to use as a client certificate and pass in as the
Though I think even if I could figure it out, most of what I said still applies. If killing the port 80 redirect isn't a generic option, this may be tough. Hmm...
For Pulse's case, and in DHS' scans, this won't be an issue, because preloading a domain automatically grants HSTS compliance for each individual hostname in the domain. (
Yeah, you should be fine here as well - it's not required to use a trusted CA, just that it's unexpired and valid for that hostname. |
A fake cert isn't actually going to help ... Assuming the server is properly validating the client cert, it will simply reject your fake cert and terminate the handshake in the same way as it does when you don't provide a cert. A quick test using curl on the command line returns -- Re-reading your earlier comments, this stands out at me as as an indicator of some sort of misunderstanding:
When client auth is not enabled, the server provides the client a cert, and the client ensures the authenticity of the server cert. When client auth is enabled, the server provides the client a cert, and the client ensures the authenticity of the server's cert, and also the client provides the server a cert, and the server ensures the authenticity of the client's cert. So, if pshtt needs to ensure that the server's certificate is unexpired and for the intended hostname, then it needs to do this regardless of whether or not client auth is enabled. Note that in the TLS exchange described above, the server sends its certificate to the client near the beginning of the handshake. The client should always be validating the server's certificate before reaching the point in handshake processing where client cert auth is relevant. If the server's certificate is invalid, libcurl should fail with an error about that before it fails with any error related to client cert auth. So, if we can get enough info out of curl to determine that the failure is definitely because of client cert auth ( |
Hmm... To make things more complicated, it looks like different servers behave slightly differently and cause different curl errors. Some servers terminate the connection without terminating the handshake resulting in |
And when I try hitting it via
The full command and stack trace is:
This looks like a toughie... |
@PaulSD can you share another hostname which demonstrates different behavior via cURL from sdv.max.gov |
Ok, for testing: |
It looks to me like something is hosed in your sslyze. Here's what I get:
|
Hmm, you're right that the It looks like this is going to be tough given pshtt's current code structure, since the SSLyze-based checks only happen after we've already ruled out various TLS handshake errors (we only proceed to the SSLyze section if the connection failed with So we could change the logic to run all TLS handshake errors (where it's something more interesting than "port 443 isn't open") through SSLyze as well and try to determine error conditions there. That would require adjusting a decent amount of logic, but might have other benefits in detecting other novel situations (and in just detecting all cases where port 443 is open but not responding in expected ways, which agencies may be interested whether or not certain kinds of configurations are compliant with policies, etc). Since it'd be a non-trivial change, with the possibility of regressions, I'd love to hear any thoughts from @h-m-f-t or @jsf9k before I take a whack at it. |
@konklone I think you're right. As long as port 443 is open we should run the host through |
We are seeing this same issue with https://vhs.services.nesdis.noaa.gov which is Citrix NetScaler Access Gateway with Client Certificate Authentication set to mandatory. |
We are seeing this same issue with trident.fisheries.noaa.gov and trident-test.fisheries.noaa.gov. Both have Client Certificate set to mandatory and when scanned return saying that TLS/SSL is not enabled let alone being able to detect an HSTS header. |
We have a pseudo workaround for our netscaler, allowing it to be scanned and show complaint without lowering our security posture too much. Be happy to share configurations @jonathanosullivan @rickminer . |
Client cert issues should be resolved by #179. |
See 18F/pulse#758 for the details, but it looks like
pshtt
may choke when client certs are required and mark it as non-compliant. If this is true, I think we should look into ways to prevent this.cc @PaulSD
The text was updated successfully, but these errors were encountered: