Repository navigation
feat(tls): certificate hot reload without listener restart - #417
Merged
Merged
Conversation
Add hot certificate reload for live HTTPS (TCP) and HTTPS/3 (QUIC) listeners via cwist_app_reload_tls(), cwist_https_reload_context(), and cwist_http3_reload_context(): - Build and validate the new SSL_CTX before swapping it under a reader-writer lock (ctx_lock / ssl_ctx_lock). In-flight handshakes and established connections keep their own BoringSSL SSL_CTX reference and finish on the previous certificate; new handshakes present the new one. - Preserve the shared session-ticket key (STEK) across reloads so TLS 1.3 and QUIC session resumption survive a certificate swap without a full-handshake cliff (documented in docs/decisions/0002-tls-hot-reload-stek.md). - Join the HTTP/3 UDP listener thread and close the UDP socket on app_listen_serve() shutdown so cwist_app_destroy() cannot race with an exiting QUIC loop thread. - Add tests/test_tls_hot_reload.c covering mid-traffic HTTPS swap, HTTP/3 CA-verified swap, rollback on invalid cert/key, context-level APIs, and a 200/1000-iteration fd/ASan leak check.
Member
Author
|
Some functions are deleted. But I don't think we can decide to delete those functions so easily. |
# Conflicts: # docs/README.md # docs/api/v4.0-api-baseline.txt
- https_hs_shard.running is read lock-free by the shepherd loop while start/stop write it from other threads; make it _Atomic bool. - cwist_shutdown_request() now only claims the UDP fd instead of closing it: the HTTP/3 loop thread can be inside recvmmsg() on it, and closing under it raced with the read and could later close a reused descriptor number. The loop exits on g_cwist_running within its poll timeout and the owning server path closes the fd after joining the thread. - cwist_multiport_h3_stop_group() now joins the listener thread before closing its udp_fd, same race.
…ls-hot-reload # Conflicts: # docs/README.md # docs/api/v4.0-api-baseline.txt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds hot TLS certificate + private-key reload for live HTTPS (TCP) and HTTPS/3 (QUIC) listeners without restarting the listener or dropping in-flight connections (closes #404).
Scope & Design
cwist_app_reload_tls(app, cert_path, key_path): reloads the application's HTTPS context and, when HTTPS/3 is enabled, its HTTP/3 QUIC context, then updatesapp->cert_path/app->key_path.cwist_https_reload_context(ctx, cert_path, key_path, app): builds and validates a newSSL_CTXviacwist_https_build_ssl_ctx(), carries over the shared STEK and ALPN callback, and swapsctx->ctxunderctx_lock. Readers hold the read lock only across the pointer load +SSL_new()(which takes BoringSSL's ownSSL_CTXreference).cwist_http3_reload_context(ctx, cert_path, key_path): builds and validates a new QUICSSL_CTX, carries over the wrapper-owned STEK, and swapsctx->ssl_ctxunderssl_ctx_lock.ssl_ctx_handoutpins theSSL_CTXreturned from lsquic'sea_get_ssl_ctxcallback across the window before lsquic callsSSL_new().docs/decisions/0002-tls-hot-reload-stek.md(and indexed indocs/README.md). Certificate reload keeps the existing STEK so session resumption (and QUIC 0-RTT) continues seamlessly across a cert swap.app_listen_serve()now joins the HTTP/3 listener thread and closesudp_fdafter clearingapp->h3_ctx->running, preventing a shutdown use-after-free whencwist_app_destroy()runs immediately aftercwist_app_listen_ex()returns.Verification
tests/test_tls_hot_reload.c(wired intomake test):CWIST_TLS_RELOAD_ITERS=1000) alternating reloads and asserts zero fd drift and zero ASan/LSan leaks.make SANITIZE=address,undefined WERROR=1 test_tls_hot_reload+CWIST_TLS_RELOAD_ITERS=1000passes cleanly.make api-check,make env-check,check_api_test_coverage.py,check_test_wiring.py, andmalloc_lint.shall pass.Closes #404