Repository navigation
Reject certificates containing blocked eMudhra intermediate CA public keys - #481
Conversation
| def ssl_connect(hostname) | ||
| @ssl_socket.startHandshake | ||
| ssl_session = @ssl_socket.getSession | ||
| @config.check_peer_certificates(ssl_session.getPeerCertificates) |
There was a problem hiding this comment.
[P1] Include locally trusted intermediates in the denylist check
This checks the peer-supplied certificates, but not the locally selected trust anchor.
On JRuby, if a configured trust store contains a blocked intermediate and the server sends only an otherwise valid leaf signed by that intermediate, JSSE can validate the leaf against the local intermediate. The verification callback has the same gap: SystemTrustManager#checkServerTrusted passes the original input chain to the callback after validation. Neither check sees the blocked intermediate, so the connection can proceed to HTTP even with peer verification enabled.
Please apply the denylist to the actual validated certification path, including its trust anchor, and add a regression test where the blocked intermediate exists only in the local trust store and the server sends only the leaf. The test should assert rejection before any HTTP request is sent.
This finding is based on source/API analysis, supported by a separate JDK trust-manager check. I have not reproduced it end-to-end with JRuby/HTTPClient.
There was a problem hiding this comment.
In fact, httpclient treats MRI and JRuby completely differently while handling TLS/SSL sockets. While MRI implementation manages CA certificates utilizing cacert.pem bundled as a part of library, JRuby implementation is relying on CA certificates managed by the JVM runtime. I'd think that for the latter case, the general responsibility to maintain the certificate handling should be on the runtime, and not on a library application like httpclient. This PR is focusing on the former case which httpclient should be responsible for on TLS handshake to make it secure enough.
Although the behavior on JRuby is surely NOT identical with MRI, I've added some extra side notes in README to explicitly mentioning it. Hope it works for clarification.
|
My understanding is that the intended use case for this PR is: To prevent a successful validation using a compromised certificate—even after the client has removed it from the trust store due to a key leak—if that certificate is sent by the server. It does not anticipate a scenario where a compromised certificate is used due to an incorrect client-side configuration. Given this premise, I believe @takkanm 's point is not valid, I think. However, there is one caveat. While this is a possible change, it would not be advisable to implement it without documentation. |
…mudhra-keys # Conflicts: # CHANGELOG.md
|
That's a fair point. I should have been more cautious about changing the behavior w/o proper/explicit documentation of it. I'll figure out a way... |
|
I happened to notice CI is broken with |
Summary
Compromised eMudhra intermediate CA keys can remain trusted through cross-signed certificates even after related roots are removed. This adds a default safeguard to prevent HTTP data from being sent over connections presenting those keys.
Explicit verification overrides remain under the caller's control. The README, SSLConfig API documentation, and changelog explain the compatibility impact, including rejection of unused server-supplied certificates containing blocked keys.
On JRuby, this supplements JVM certificate validation and does not replace JVM security updates. Intermediates present only in local trust stores or obtained through JVM issuer retrieval may fall outside the check.
Testing
git diff --checkpassed. The Ruby HEAD CI failure is tracked separately in #483.References