node:https: forward crl, sessionTimeout, ecdhCurve, sigalgs and honorCipherOrder to the TLS listener - #41641
node:https: forward crl, sessionTimeout, ecdhCurve, sigalgs and honorCipherOrder to the TLS listener#41641robobun wants to merge 4 commits into
Conversation
…CipherOrder to the TLS listener https.Server built its Bun.serve tls object from a fixed list of keys. Every other tls.createServer option was dropped with no error, so a client certificate revoked by the configured crl completed mTLS and was served with req.socket.authorized === true. Forward crl, sessionTimeout, ecdhCurve, sigalgs, honorCipherOrder and allowPartialTrustChain, and run the same secure-context validation that tls.createServer runs. The validator moves to internal/tls so both modules share it.
|
Warning Review limit reached
On-demand reviews are free for the next 14 days. After that, they cost $0.25 per reviewed file. Or wait 4 minutes for your next included review. View limit detailsLimit details: You’ve used all 10 included reviews currently available. Review configuration: ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Essentials Run ID: 📒 Files selected for processing (4)
Comment |
There was a problem hiding this comment.
Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.
Beyond the inline finding, I diffed the moved validateSecureContextOptions against its original in node/tls.ts — the body is byte-identical apart from lazy-requiring validateString/validateBuffer inside the function, so the refactor preserves behavior. Also checked that StringPrototypeSplit and validateBuffer still have live callers in node/tls.ts after the move, so the flagged import is the only newly-dead symbol there.
Extended reasoning...
The change forwards TLS secure-context options through https.createServer and moves a validator into shared internal code. I verified the moved function is behavior-preserving (identical checks, same error codes, same ordering; only the validator imports moved from module-top-level to a lazy require inside the function body) and confirmed the other symbols the original relied on (StringPrototypeSplit, validateBuffer) remain live in node/tls.ts. Because this is a security-relevant TLS path (CRL enforcement, honorCipherOrder default, cipher/curve negotiation) and a verified finding beyond the posted nit was withheld from this run, deferring rather than approving.
|
Status: ready for review. Reproduced with the node fixtures in The fix and 6 tests are in this PR. All 6 fail on stock bun and pass with the change. The lanes that run the changed code are green on 2e0899f. The remaining red jobs are unrelated to this diff: |
…tted tls.Server reads tls.DEFAULT_ECDH_CURVE when no ecdhCurve is given. Do the same on the https path so both servers negotiate the same groups.
Problem
https.createServer({ crl, requestCert: true, rejectUnauthorized: true })serves a client certificate that the CRL revokes, withreq.socket.authorized === true. Node refuses it withCERT_REVOKED. Bun'stls.createServer,Bun.serveandBun.listenrefuse it too.src/js/node/_http_server.ts:356. The https Server builds itsBun.servetls object from a fixed list of keys.crl,sessionTimeout,ecdhCurve,sigalgs,honorCipherOrderandallowPartialTrustChainnever reach the native config, and no error says so.Fix
crl,sessionTimeout,ecdhCurve(with thetls.DEFAULT_ECDH_CURVEfallback thattls.Serveruses),sigalgsandallowPartialTrustChainto the tls object. FoldhonorCipherOrderintosecureOptionsasSSL_OP_CIPHER_SERVER_PREFERENCE, default true liketls.Server(tls.ts:1276) and Node.validateSecureContextOptionsthattls.createServerruns, so a badecdhCurve,sigalgsorsessionTimeoutthrows from the constructor. The validator moves fromnode/tls.tstointernal/tls.tsso both modules share one copy.SSLConfig(src/runtime/socket/SSLConfig.bindv2.ts) already accepts every one of these keys.Bun.serveapplies them throughas_usockets. Only the https allowlist dropped them.test/js/node/tls/node-tls-server.test.ts(6 new tests, all fail on stock bun). Alsonode-tls-context,node-tls-ecdh-curve,node-tls-connect,ssl-ctx-cache,node-http.test.tsand thetest-https-*node parallel tests. Self-reviewed: 3 concerns raised, 2 addressed (see Notes).Background
https.Serverin Bun ishttp.Serverwith a tls object.listen()passes that object toBun.serve({ tls }). So every TLS option a user gives must be copied into that object by hand.tls.createServergoes throughnewNativeSecureContext, which hands the whole options object to native. That is why the same options work there.crldoes.Notes
Manual checks with
openssl s_clientagainst the debug build, https server:sessionTimeout: 1, TLS 1.2 session resumed after 2.5 s:Reusedbefore,Newafter (node:New).sessionTimeoutcovers TLS 1.2 sessions only. The native site callsSSL_CTX_set_timeout(packages/bun-usockets/src/crypto/openssl.c:1494), which BoringSSL scopes to TLS 1.2 and below. A TLS 1.3 ticket keeps the 172800 s lifetime hint and is stillReusedafter 2.5 s (measured ontls.createServer, which shares that site; node: hint 1,New). tls: apply sessionTimeout to TLS 1.3 sessions too #38145 fixes that natively for every TLS server. It is independent of this PR.ciphers: "AES256:AES128", client prefers AES128: server picked AES128 before, AES256 after (honorCipherOrder default).crlwith the revoked agent3 fixture: served before,ECONNRESETafter.Self-review concerns:
tls.DEFAULT_ECDH_CURVEwhiletls.Serverhonors it. Addressed in 2e0899f, with a test.honorCipherOrderdefault true is a behaviour change for existing https servers that setciphers. Kept: it matches Node and Bun's owntls.Server, andhonorCipherOrder: falseopts out. Called out in the Fix section above.tls.Server's translation. Not addressed here. node:https: apply the full TLS option set when creating a Server #33054 (open, conflicting) moves the same validator intointernal/tls.tsand forwardsciphers/minVersion/maxVersion, which have since landed on main. It does not forwardcrlor the other keys in this PR. A follow-up that makes both servers call one translation helper ininternal/tls.tswould remove the remaining drift (stripTls13CipherNames,setDefaultCACertificates).Not forwarded, because
Bun.serve's tls config has no equivalent:ticketKeys,dhparam(native takes a file path only),SNICallback,ALPNProtocols, thekeylogevent. Those stay as separate items.crlwithoutkey/certis ignored, as the https server is plaintext in that case today.The
SNICallback runs even when the requested servername matches the bind hostnametest in the same file fails in this container with and without the change (localhostresolves to::1here, the client connects to127.0.0.1). It passes in CI.