Skip to content

fix(connection): Make set_config validator replacement transactional#5847

Open
alexw91 wants to merge 2 commits into
aws:mainfrom
alexw91:fix-set-config-transactional-validator
Open

fix(connection): Make set_config validator replacement transactional#5847
alexw91 wants to merge 2 commits into
aws:mainfrom
alexw91:fix-set-config-transactional-validator

Conversation

@alexw91

@alexw91 alexw91 commented Apr 23, 2026

Copy link
Copy Markdown
Contributor

Goal

Make the x509 validator replacement in s2n_connection_set_config transactional, so a failed init does not leave the connection with a wiped validator.

Why

s2n_connection_set_config wiped the connection's x509_validator before initializing a replacement from the incoming config. If the replacement initialization failed (e.g. X509_STORE_CTX_new returning NULL under OOM, or s2n_x509_validator_set_max_chain_depth rejecting an invalid depth), the function returned an error with the validator already wiped to UNINIT state while conn->config still referenced the previous config. A subsequent handshake attempt on that connection would fail in cert validation.

How

The new validator is built into a stack-local struct s2n_x509_validator. Each fallible step (s2n_x509_validator_init, s2n_x509_validator_set_max_chain_depth) is checked individually. On failure, the local is wiped to avoid leaking any partially-initialized OpenSSL objects, and the error is propagated. The connection's existing validator is untouched. Only after the local is fully initialized is the old validator wiped and replaced via struct assignment.

Callouts

  • The verify_host_fn assignment remains inside the else block in the same position relative to the other operations as in the original code. It is not part of the validator and does not need rollback.
  • s2n_x509_validator_init can partially populate the struct (e.g. set trust_store, allocate cert_chain_from_wire via sk_X509_new_null()) before failing on X509_STORE_CTX_new. The explicit s2n_x509_validator_wipe(&new_validator) on the init failure path prevents leaking those objects.
  • s2n_x509_validator_init_no_x509_validation cannot currently fail (it only does assignments and sk_X509_new_null), but the POSIX_GUARD is retained as a defensive measure.

Testing

Added a regression test in s2n_config_test.c that:

  1. Creates a connection with a valid config and verifies the validator is in INIT state.
  2. Creates a second config with max_verify_cert_chain_depth set to 0 (invalid) and max_verify_cert_chain_depth_set enabled, which causes s2n_x509_validator_set_max_chain_depth to fail with S2N_ERR_INVALID_ARGUMENT.
  3. Calls s2n_connection_set_config with the bad config and asserts it fails.
  4. Verifies conn->config still points to the original config.
  5. Verifies conn->x509_validator.state is still INIT (not UNINIT).

Related

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@alexw91 alexw91 force-pushed the fix-set-config-transactional-validator branch from 59c8459 to a5ac431 Compare April 23, 2026 23:06
@alexw91 alexw91 requested review from jmayclin and maddeleine April 24, 2026 14:18
s2n_connection_set_config wiped the connection's x509_validator
before initializing a replacement from the new config. If the
replacement init failed (e.g. X509_STORE_CTX_new returning NULL
under OOM, or an invalid max chain depth), the connection was left
with a wiped validator while conn->config still referenced the old
config. A subsequent handshake would fail in cert validation.

Stage the new validator into a stack-local struct. If any init step
fails, wipe the local and propagate the error, leaving the
connection's existing validator intact. Only swap on full success.
Add a regression test that triggers a validator init failure via an
invalid max chain depth and verifies the old validator is preserved.
@alexw91 alexw91 force-pushed the fix-set-config-transactional-validator branch from a5ac431 to c86f5d3 Compare April 24, 2026 14:24
@alexw91 alexw91 enabled auto-merge April 29, 2026 02:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants