fix(ext/node): allow tls.Server SecureContext without cert/key for SNICallback#33715
Conversation
…ICallback Enables tests/node_compat/runner/suite/test/parallel/test-tls-empty-sni-context.js Co-authored-by: Divy Srivastava <[email protected]>
The previous fix returned -1 from initServerTls when cert/key were absent, surfacing as "unsupported protocol" / ERR_SSL_UNSUPPORTED_PROTOCOL. The new fix lets rustls drive the handshake and the cert resolver returns None, surfacing as "no suitable signature algorithm" — switch the test to a real TLS client so it exercises that path. Co-authored-by: Divy Srivastava <[email protected]>
fibibot
left a comment
There was a problem hiding this comment.
Substance is right and well-thought-out. Walking through:
- Both
certandkeymade optional — theno_server_cert = cert_str.is_none() && key_str.is_none()short-circuit lets atls.createSecureContext({})placeholder or an SNICallback-only server pass through. ✓ NoCertResolverinstalled when no cert — theOption<Arc<CertifiedKey>>::Nonereturn fromresolve()is what triggers rustls'sError::General("no server certificate chain resolved")+AccessDeniedfatal alert. The PR mirrors Node/OpenSSL by mapping that error toERR_SSL_NO_SUITABLE_SIGNATURE_ALGORITHMserver-side. The matching client-sideERR_SSL_SSLV3_ALERT_HANDSHAKE_FAILUREis already covered by the catch-all_arm inrustls_error_to_node_error. ✓- Existing "key was provided but malformed" path preserved:
rustls_pemfile::private_key(...).ok().flatten()?still propagatesNoneup tobuild_server_config's caller via?, so a half-configured (cert without key, or key without cert) call still bails with the same behavior as before. ✓ E::General(msg) if msg == "no server certificate chain resolved"— string match on rustls's error message is fragile (rustls could change the wording), but there isn't a structured variant for "resolver returned None". A// keep in sync with rustls upstream wordingTODO comment would help future-proof this; non-blocking.
Test enrollment placement is wrong
tests/node_compat/config.jsonc puts the new entry after test-tls-set-encoding:
"parallel/test-tls-set-encoding.js": {},
+ "parallel/test-tls-empty-sni-context.js": {},
"parallel/test-tls-snicallback-error.js": {},But e-mpty < s-et alphabetically. The entry should sort with the test-tls-e* cluster, not between set-encoding and snicallback-error. Worth fixing for the next person who's grepping for test-tls-empty-*.
CI
94 success, 1 substantive failure (test node_compat (3/3) debug windows-x86_64) + a few pending. Same single-shard windows-x86_64-debug flake we've been seeing across today's TLS / lazy-load PRs; the matching release windows-x86_64 (3/3) and other windows-x86_64 debug shards (1/3, 2/3) all pass.
Holding to COMMENT until the alphabetical placement is fixed and the windows-x86_64 (3/3) shard is confirmed flake on rerun. Substance is good; happy to flip to APPROVE with those two cleanups.
Enables tests/node_compat/runner/suite/test/parallel/test-tls-empty-sni-context.js Co-authored-by: Divy Srivastava <[email protected]>
Per review feedback (denoland#33715): the entry was inserted between test-tls-set-encoding and test-tls-snicallback-error, but alphabetically "empty" sorts with the other test-tls-e* entries, before test-tls-enable-*. Co-authored-by: Divy Srivastava <[email protected]>
Enables tests/node_compat/runner/suite/test/parallel/test-tls-empty-sni-context.js Co-authored-by: Divy Srivastava <[email protected]>
Per review feedback (denoland#33715, non-blocking): the `Error::General` arm matches on rustls's literal "no server certificate chain resolved" message. Add a NOTE so future readers know to keep it in sync with rustls upstream. Co-authored-by: Divy Srivastava <[email protected]>
fibibot
left a comment
There was a problem hiding this comment.
LGTM on the delta. Both prior non-blocking notes addressed:
- Test enrollment moved to the correct alphabetical position: now slotted between
test-tls-econnresetandtest-tls-enable-trace-cliin thetest-tls-e*cluster (was misplaced afterset-encoding). ✓ - Sync-comment added for the rustls error-string match:
Future-proofs the brittle string match. ✓
// NOTE: keep this string in sync with rustls upstream — there is no // structured `Error` variant for "resolver returned None".
Substance unchanged from my prior review — cert/key both optional in build_server_config, NoCertResolver triggers rustls's Error::General("no server certificate chain resolved") + AccessDenied fatal alert, which rustls_error_to_node_error translates back to Node's ERR_SSL_NO_SUITABLE_SIGNATURE_ALGORITHM.
CI: 90 SUCCESS, 0 FAILURE, 23 still pending. No regressions on the relevant test node_compat and test unit_node shards.
| // both ends so existing Node code (and upstream tests) match. | ||
| // NOTE: keep this string in sync with rustls upstream — there is no | ||
| // structured `Error` variant for "resolver returned None". | ||
| E::General(msg) if msg == "no server certificate chain resolved" => ( |
There was a problem hiding this comment.
I'm not a fan of this one since it's matching string, but I don't have a better idea for now. Hopefully the tests catch the regression if this error message ever changes
Summary
Enables
test-tls-empty-sni-contextin node_compat suite.Test plan
cargo test --test node_compat -- test-tls-empty-sni-context