node:https: apply the full TLS option set when creating a Server

JA
4mo ago
+833-588

What

https.createServer(options) (and new https.Server) only forwarded key, cert, ca, passphrase, secureOptions, requestCert and rejectUnauthorized to the underlying TLS listener. Every other secure-context option Node accepts there was silently dropped, and a pfx- or secureContext-only configuration was treated as plain HTTP.

This change makes the node:http/node:https Server constructor reuse the same option translation node:tls.Server already uses:

  • minVersion / maxVersion / secureProtocol are translated to the protocol-version range the native context applies (defaulting to tls.DEFAULT_MIN_VERSION / tls.DEFAULT_MAX_VERSION, including the --tls-min-v* / --tls-max-v* flags).
  • ciphers is validated and applied.
  • pfx is parsed (key/cert/embedded CA) and now produces a TLS listener.
  • A secureContext-only config now produces a TLS listener that refuses plaintext (matching Node's observable behavior) instead of serving plaintext.
  • Invalid options (ciphers, minVersion/maxVersion, secureProtocol, dhparam: "auto", bad ticketKeys, ...) throw synchronously from createServer with the same error codes as Node (ERR_SSL_NO_CIPHER_MATCH, ERR_TLS_INVALID_PROTOCOL_VERSION, ERR_TLS_INVALID_PROTOCOL_METHOD, ...).

To keep one source of truth, the option-translation helpers (validateSecureContextOptions, validateCiphers, the protocol-version translation, processPfxOptions, convertALPNProtocols, and the mutable DEFAULT_MIN_VERSION/DEFAULT_MAX_VERSION state) moved from node/tls.ts into the existing internal/tls module; node:tls re-imports them, so its behavior is unchanged.

What is intentionally not changed

  • Plain http.createServer keeps ignoring TLS-only options (Node parity; there's a test for it).
  • ALPNProtocols, honorCipherOrder, ecdhCurve, inline dhparam, sigalgs, ticketKeys, sessionIdContext are validated but not enforced for https.Server, exactly like node:tls.Server in Bun today: the native server context (Bun.serve's SSLConfig -> uSockets context options) has no fields for them. ALPN in particular needs native plumbing (uSockets server contexts never register an ALPN select callback), so it is left for a follow-up that would also benefit tls.Server.
  • The Bun-specific server.listen({ tls }) extension is untouched.

Behavior notes

  • A pfx/secureContext-only https.Server is now actually HTTPS (it used to answer plaintext HTTP).
  • TLS options that were previously ignored are now honored/validated, so code passing invalid values to https.createServer will now throw the same errors Node throws.
  • tls.DEFAULT_MIN_VERSION / DEFAULT_MAX_VERSION (and --tls-min-v* / --tls-max-v*) now apply to https servers, as in Node.

Verification

  • Behavior compared against Node v26.3.0 with the same fixture for every case above (minVersion enforcement, secureProtocol pinning, cipher selection, synchronous validation error codes, pfx, secureContext-only, plain-http parity); the new tests assert the Node-verified semantics and each one (except the plain-http parity negative) fails on the previous behavior.
  • bun bd test test/js/node/http/node-http.test.ts and the whole test/js/node/tls/ suite pass (the one pre-existing failure there, tls.connect should ignore invalid NODE_EXTRA_CA_CERTS, is a debug-build startup-time timeout unrelated to this change).