Add cache mechanism to certificate compression#13284
Conversation
Current implementation recompressed the cert chain on every TLS handshake. Now cached on the first handshake per certificatees. Cash gets invalidated when the OCSP staple refreshes. New setting: proxy.config.ssl.server.cert_compression.cache (default 1). BoringSSL only -- OpenSSL caches internally with no opt-out, so the flag has no effect there.
There was a problem hiding this comment.
Pull request overview
This PR adds a per-SSL_CTX cache for TLS Certificate Compression on BoringSSL builds so the compressed certificate chain can be reused across handshakes, reducing repeated compression CPU overhead. It also wires cache invalidation into OCSP stapling refresh, adds a new reloadable config record, and introduces new tests/benchmarks to validate and measure the change.
Changes:
- Implement per-certificate, per-algorithm compressed-bytes caching (BoringSSL callback path) plus a
cache_hitmetric. - Add
proxy.config.ssl.server.cert_compression.cache(reloadable) and document it; plumb config into SSL context setup. - Add an autest for cache behavior and a Catch2 microbenchmark; invalidate cache on OCSP refresh attempts.
Reviewed changes
Copilot reviewed 22 out of 22 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/gold_tests/tls/tls_cert_comp.test.py | Disables the new cache in the existing cert compression gold test for determinism. |
| tests/gold_tests/tls/tls_cert_comp_cache.test.py | New gold test to validate caching enabled/disabled behavior and metrics. |
| tests/gold_tests/tls/replay/tls_cert_compression_cache.replay.yaml | Replay file with two sessions to drive two TLS handshakes. |
| src/records/RecordsConfig.cc | Adds the new reloadable proxy.config.ssl.server.cert_compression.cache record. |
| src/iocore/net/unit_tests/benchmark_TLSCertCompression.cc | New Catch2 microbenchmark exercising cold/warm/disabled cache paths and scaling. |
| src/iocore/net/TLSCertCompression.h | Extends API to accept cache flag and declares cache structures/helpers (BoringSSL path). |
| src/iocore/net/TLSCertCompression.cc | Implements cache attach/get/publish/invalidate, calls invalidate/recompress from common helper, and precompresses on OpenSSL path. |
| src/iocore/net/TLSCertCompression_zlib.h | Defines RFC 8879 zlib algorithm ID constant. |
| src/iocore/net/TLSCertCompression_zlib.cc | Adds hot-path cache lookup + publish-on-miss for zlib compression callback. |
| src/iocore/net/TLSCertCompression_brotli.h | Defines RFC 8879 brotli algorithm ID constant. |
| src/iocore/net/TLSCertCompression_brotli.cc | Adds hot-path cache lookup + publish-on-miss for brotli compression callback. |
| src/iocore/net/TLSCertCompression_zstd.h | Defines RFC 8879 zstd algorithm ID constant. |
| src/iocore/net/TLSCertCompression_zstd.cc | Adds hot-path cache lookup + publish-on-miss for zstd compression callback. |
| src/iocore/net/SSLUtils.cc | Passes config flag into cert compression registration; initializes cache index during SSL library init (BoringSSL path). |
| src/iocore/net/SSLStats.h | Adds cert_compress_cache_hit counter to the stats block. |
| src/iocore/net/SSLStats.cc | Creates the proxy.process.ssl.cert_compress.cache_hit metric. |
| src/iocore/net/SSLConfig.cc | Reads the new proxy.config.ssl.server.cert_compression.cache record into params. |
| src/iocore/net/SSLClientUtils.cc | Updates registration call signature for client context. |
| src/iocore/net/P_SSLConfig.h | Adds server_cert_compression_cache to SSL config params. |
| src/iocore/net/OCSPStapling.cc | Invalidates/recompresses cert compression artifacts on OCSP refresh attempts. |
| src/iocore/net/CMakeLists.txt | Adds the new benchmark source to the test_net executable. |
| doc/admin-guide/files/records.yaml.en.rst | Documents proxy.config.ssl.server.cert_compression.cache behavior and OpenSSL no-op note. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 22 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
src/iocore/net/TLSCertCompression.cc:233
- In OpenSSL builds (HAVE_SSL_CTX_SET1_CERT_COMP_PREFERENCE), the
cacheparameter is unused, which can trigger -Wunused-parameter warnings depending on compiler flags. Add an explicit(void)cache;in that branch (or mark it[[maybe_unused]]) to keep builds warning-clean across SSL backends.
#elif HAVE_SSL_CTX_SET1_CERT_COMP_PREFERENCE
if (specified_algs.size() > N_ALGORITHMS) {
return 0;
}
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 22 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
src/iocore/net/TLSCertCompression.cc:206
cacheis unused in the OpenSSL / no-cert-compression build branches ofregister_certificate_compression_preference(), which can trigger-Wunused-parameterwarnings (often treated as errors). Please explicitly mark it unused (or conditionally compile it) so OpenSSL builds stay warning-free.
int
register_certificate_compression_preference(SSL_CTX *ctx, const std::vector<std::string> &specified_algs, bool cache)
{
ink_assert(ctx != nullptr);
if (specified_algs.empty()) {
return 1;
}
Summary
Cache compressed certificate bytes so the cert chain is compressed once per certificate, not on every TLS handshake.
Why
BoringSSL has no internal cache for cert compression — each handshake re-runs the compression callback on the same static cert chain. Wasted CPU.
(OpenSSL builds aren't affected:
SSL_CTX_compress_certspre-compresses the chain and caches internally.)Approach
A per-certificate cache attached to the SSL_CTX. Each algorithm has a slot holding an atomic pointer to an immutable compressed-bytes entry.
Operator-facing
proxy.config.ssl.server.cert_compression.cache(INT, default1, reloadable). Disabling forces recompression on every handshake. No-op on OpenSSL builds (documented in records.yaml).proxy.process.ssl.cert_compress.cache_hit(counter). Aggregated across algorithms — hit rate is identical per algorithm by construction.Validation
tls_cert_comp_cacheruns traffic through a mid-tier ATS with two full handshakes (session tickets disabled) and asserts the compress metric reaches 2 with caching on, andcache_hitstays at 0 with caching off.test_net "[!benchmark]") drives the production callbacks at cold / warm / disabled and at thread fan-out of 1, 2, 4, 8, 16, 32. Single-thread warm hit is ~125 ns regardless of algorithm. Throughput scales positively with threads (zlib: 7.5M → 21.7M ops/sec at 1 → 8 threads on an 18-core box).