Skip to content

Add cache mechanism to certificate compression#13284

Draft
maskit wants to merge 7 commits into
apache:masterfrom
maskit:cert_compression_cache
Draft

Add cache mechanism to certificate compression#13284
maskit wants to merge 7 commits into
apache:masterfrom
maskit:cert_compression_cache

Conversation

@maskit

@maskit maskit commented Jun 16, 2026

Copy link
Copy Markdown
Member

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_certs pre-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.

  • Reads (the hot path) are lock-free: acquire-load the slot, memcpy.
  • Misses compare-exchange a fresh entry into the slot — only the first publisher in a thundering herd wins; the rest discard their work.
  • Invalidation runs on every OCSP refresh attempt, since the staple is part of what gets compressed. It swaps the slot to null and retires the previous entry for free on the next invalidation, so per-slot memory is bounded at two entries.

Operator-facing

  • proxy.config.ssl.server.cert_compression.cache (INT, default 1, 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

  • New autest tls_cert_comp_cache runs traffic through a mid-tier ATS with two full handshakes (session tickets disabled) and asserts the compress metric reaches 2 with caching on, and cache_hit stays at 0 with caching off.
  • New Catch2 microbench (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).

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.
@maskit maskit added this to the 11.0.0 milestone Jun 16, 2026
@maskit maskit self-assigned this Jun 16, 2026
Copilot AI review requested due to automatic review settings June 16, 2026 15:53
@maskit maskit added the TLS label Jun 16, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_hit metric.
  • 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.

Comment thread src/iocore/net/TLSCertCompression.cc
Comment thread tests/gold_tests/tls/tls_cert_comp_cache.test.py Outdated
@maskit maskit marked this pull request as draft June 16, 2026 17:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 22 out of 22 changed files in this pull request and generated 3 comments.

Comment thread tests/gold_tests/tls/tls_cert_comp_cache.test.py
Comment thread tests/gold_tests/tls/tls_cert_comp_cache.test.py
Comment thread src/iocore/net/unit_tests/benchmark_TLSCertCompression.cc

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 22 out of 22 changed files in this pull request and generated 4 comments.

Comment thread src/iocore/net/TLSCertCompression.cc
Comment thread src/iocore/net/TLSCertCompression_zlib.cc
Comment thread src/iocore/net/TLSCertCompression_brotli.cc
Comment thread src/iocore/net/TLSCertCompression_zstd.cc

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 cache parameter 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;
  }

Comment thread src/iocore/net/unit_tests/benchmark_TLSCertCompression.cc

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

  • cache is unused in the OpenSSL / no-cert-compression build branches of register_certificate_compression_preference(), which can trigger -Wunused-parameter warnings (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;
  }

Comment thread src/iocore/net/TLSCertCompression.h

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 22 out of 22 changed files in this pull request and generated no new comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants