Repository navigation
Reject options that ask for both the default and the trust-all SSL context - #1639
Conversation
…ntext One SSL context serves every server of a connection. When the options asked for both, secure() with opentls(), both properties true, or a bootstrap list with an opentls:// server next to a tls:// or wss:// server, the trust-all context won, so the certificate verification the other side asked for was silently removed. Options.build() now throws IllegalStateException for any of those. One explicit choice is unchanged: opentls() or secure() with any mix of schemes builds as before, a supplied sslContext(ctx) is used whatever the flags and schemes are, and plain nats:// servers still mix with either. docs/TLS_CONFIGURATION.md explains how the context is chosen, what opentls does and does not protect against, and this rule; the README points to it in one line. Tests: OptionsTests.testSslContextIsProvided covers the rejected combinations, the accepted single-scheme and nats:// mixes, and the explicit choices.
|
Claude finished @scottf's task in 2m 25s —— View job Reviewing PR #1639
ReviewTraced the new check in
Tests look sound: Minor, non-blocking: the No correctness, security, or thread-safety issues found. |
One SSL context serves every server of a connection. When the options asked for both the default context and the trust-all context, the trust-all context won, so the certificate verification the other side asked for was silently removed. That happened for
secure()together withopentls(), for thesecureandopentlsproperties both true, and for a bootstrap list with anopentls://server next to atls://orwss://server, where oneopentls://entry made the whole connection, discovered servers included, trust all certificates.Why a trust-all context matters
opentlswithout a context builds anSSLContextwhose trust manager accepts any server certificate: self-signed, expired, revoked, issued by anyone, for any name. Supplying that context by hand, withsslContext(SSLUtils.createTrustAllTlsContext()),sslContext(SSLUtils.createOpenTLSContext()), or any trust manager that does not throw, is the same thing; the client cannot tell the difference and does not warn.TLS gives encryption and proof of who is at the other end. The proof comes entirely from checking the certificate against something the client already trusts. A trust-all context keeps the encryption and discards the proof: the connection is encrypted to whoever answered. Anything on the path that can answer the TCP connection, a compromised host on the same network, a wrong proxy, a wrong DNS answer, a pod that took over an address, presents its own certificate and the client completes the handshake. The CONNECT then hands it the credentials: a password or token outright; for NKey and credentials-file authentication, a relaying impersonator passes the real server's nonce through and forwards the signature, so signed authentication does not prevent it either. From then on it reads everything the client publishes, delivers anything to the client's subscriptions, and can relay to the real server so nothing looks wrong. No error, event or log line is raised. Every client has this switch, and Go's documentation says
InsecureSkipVerify"should NOT be used in a production setting"; it is for development and tests only.This PR does not remove
opentls. It stops the case where a configuration asked for verification and got trust-all anyway, and it documents the rest.Change
Options.build()throwsIllegalStateExceptionwhen both contexts are asked for, by builder, by properties, or by a server list that mixes the schemes. The message names both sources and says to choose one or provide anSSLContext.opentls()orsecure()with any mix of schemes builds as before, because an explicit flag stops the schemes from being consulted;sslContext(ctx)is used whatever the flags and schemes are; plainnats://servers still mix with either secure scheme.Documentation
docs/TLS_CONFIGURATION.md: how the context is chosen and in what order; what the default context trusts; the trust-all context,opentlsor hand-supplied, what it removes, what an impersonated server can do with it, when it is acceptable and what to use otherwise; this rule with the exact error text; client certificates; TLS-first; the server-side checks.Tests
OptionsTests.testSslContextIsProvided: rejected fortls+opentls,opentls+tls,wss+opentls, a three-entry list withnats,tlsandopentls,secure()withopentls(), and both properties true; accepted fornats+opentls, twoopentlsentries,opentls()withtlsurls,secure()withopentlsurls,opentls()over a mixed list, and a provided context over a mixed list. 69 of 69 pass.