From 5a3e3f9696ee22182d4210e9ce03e0833759f201 Mon Sep 17 00:00:00 2001 From: bneradt Date: Fri, 22 May 2026 08:32:30 -0500 Subject: [PATCH] Update cert compression reporting Some OpenSSL 3.2+ builds expose the certificate-compression preference API while compiling out the built-in compression algorithms. The newly updated tools/build_openssl_h3_tools.sh builds an OpenSSL functions like this: it has the compression API without the algorithms for it. Before this patch, ATS reported cert compression support based only on API availability, which caused it to report a feature that is functionally not available if the appropriate compression libraries weren't baked in. This gates certificate-compression feature reporting and algorithm setup on the callbacks and algorithms ATS can actually use. --- src/iocore/net/TLSCertCompression.cc | 57 ++++++++++++++++------ src/traffic_layout/info.cc | 44 +++++++++++++++-- tests/gold_tests/tls/tls_cert_comp.test.py | 2 +- 3 files changed, 83 insertions(+), 20 deletions(-) diff --git a/src/iocore/net/TLSCertCompression.cc b/src/iocore/net/TLSCertCompression.cc index 3b31d3e1be3..7931b8dc669 100644 --- a/src/iocore/net/TLSCertCompression.cc +++ b/src/iocore/net/TLSCertCompression.cc @@ -31,8 +31,6 @@ namespace DbgCtl dbg_ctl_ssl_cert_compress{"ssl_cert_compress"}; } -constexpr unsigned int N_ALGORITHMS = 3; - #if HAVE_SSL_CTX_ADD_CERT_COMPRESSION_ALG #include "TLSCertCompression_zlib.h" @@ -48,25 +46,41 @@ constexpr unsigned int N_ALGORITHMS = 3; struct alg_info { const char *name; int32_t number; + bool available; #if HAVE_SSL_CTX_ADD_CERT_COMPRESSION_ALG ssl_cert_compression_func_t compress_func; ssl_cert_decompression_func_t decompress_func; #endif } supported_algs[] = { {"zlib", 1, +#if HAVE_SSL_CTX_ADD_CERT_COMPRESSION_ALG || !defined(OPENSSL_NO_ZLIB) + true, +#else + false, +#endif #if HAVE_SSL_CTX_ADD_CERT_COMPRESSION_ALG compression_func_zlib, decompression_func_zlib #endif }, -#if HAVE_BROTLI_ENCODE_H +#if HAVE_BROTLI_ENCODE_H || !HAVE_SSL_CTX_ADD_CERT_COMPRESSION_ALG {"brotli", 2, +#if HAVE_SSL_CTX_ADD_CERT_COMPRESSION_ALG || !defined(OPENSSL_NO_BROTLI) + true, +#else + false, +#endif #if HAVE_SSL_CTX_ADD_CERT_COMPRESSION_ALG compression_func_brotli, decompression_func_brotli #endif }, #endif -#if HAVE_ZSTD_H +#if HAVE_ZSTD_H || !HAVE_SSL_CTX_ADD_CERT_COMPRESSION_ALG {"zstd", 3, +#if HAVE_SSL_CTX_ADD_CERT_COMPRESSION_ALG || !defined(OPENSSL_NO_ZSTD) + true, +#else + false, +#endif #if HAVE_SSL_CTX_ADD_CERT_COMPRESSION_ALG compression_func_zstd, decompression_func_zstd #endif @@ -78,7 +92,7 @@ int register_certificate_compression_preference(SSL_CTX *ctx, const std::vector &specified_algs) { ink_assert(ctx != nullptr); - if (specified_algs.size() > N_ALGORITHMS) { + if (specified_algs.size() > countof(supported_algs)) { return 0; } @@ -95,28 +109,43 @@ register_certificate_compression_preference(SSL_CTX *ctx, const std::vectornumber, info->compress_func, info->decompress_func) == 0) { - return 0; - } - Dbg(dbg_ctl_ssl_cert_compress, "Enabled %s", info->name); - } else { + if (info == nullptr) { Dbg(dbg_ctl_ssl_cert_compress, "Unrecognized algorithm: %s", alg.c_str()); return 0; } + if (!info->available) { + Dbg(dbg_ctl_ssl_cert_compress, "Algorithm disabled by OpenSSL build: %s", alg.c_str()); + return 0; + } + if (SSL_CTX_add_cert_compression_alg(ctx, info->number, info->compress_func, info->decompress_func) == 0) { + return 0; + } + Dbg(dbg_ctl_ssl_cert_compress, "Enabled %s", info->name); } return 1; #elif HAVE_SSL_CTX_SET1_CERT_COMP_PREFERENCE - int algs[N_ALGORITHMS]; + int algs[countof(supported_algs)]; int n = 0; for (unsigned int i = 0; i < specified_algs.size(); ++i) { + struct alg_info *info = nullptr; + for (unsigned int j = 0; j < countof(supported_algs); ++j) { if (strcmp(specified_algs[i].c_str(), supported_algs[j].name) == 0) { - algs[n++] = supported_algs[j].number; - Dbg(dbg_ctl_ssl_cert_compress, "Enabled %s", supported_algs[j].name); + info = &supported_algs[j]; + break; } } + if (info == nullptr) { + Dbg(dbg_ctl_ssl_cert_compress, "Unrecognized algorithm: %s", specified_algs[i].c_str()); + return 0; + } + if (!info->available) { + Dbg(dbg_ctl_ssl_cert_compress, "Algorithm disabled by OpenSSL build: %s", specified_algs[i].c_str()); + return 0; + } + algs[n++] = info->number; + Dbg(dbg_ctl_ssl_cert_compress, "Enabled %s", info->name); } return SSL_CTX_set1_cert_comp_preference(ctx, algs, n); #else diff --git a/src/traffic_layout/info.cc b/src/traffic_layout/info.cc index dfdbc6915a0..692cdad418b 100644 --- a/src/traffic_layout/info.cc +++ b/src/traffic_layout/info.cc @@ -23,6 +23,7 @@ #include #include +#include #include #include #include "tscore/Layout.h" @@ -53,6 +54,39 @@ #include #endif +#if HAVE_SSL_CTX_ADD_CERT_COMPRESSION_ALG +static constexpr int ts_has_cert_compression_callbacks = 1; +#else +static constexpr int ts_has_cert_compression_callbacks = 0; +#endif + +#if HAVE_SSL_CTX_ADD_CERT_COMPRESSION_ALG +static constexpr int ts_has_cert_compression_zlib = 1; +#elif HAVE_SSL_CTX_SET1_CERT_COMP_PREFERENCE && !defined(OPENSSL_NO_ZLIB) +static constexpr int ts_has_cert_compression_zlib = 1; +#else +static constexpr int ts_has_cert_compression_zlib = 0; +#endif + +#if HAVE_SSL_CTX_ADD_CERT_COMPRESSION_ALG && HAVE_BROTLI_ENCODE_H +static constexpr int ts_has_cert_compression_brotli = 1; +#elif !HAVE_SSL_CTX_ADD_CERT_COMPRESSION_ALG && HAVE_SSL_CTX_SET1_CERT_COMP_PREFERENCE && !defined(OPENSSL_NO_BROTLI) +static constexpr int ts_has_cert_compression_brotli = 1; +#else +static constexpr int ts_has_cert_compression_brotli = 0; +#endif + +#if HAVE_SSL_CTX_ADD_CERT_COMPRESSION_ALG && HAVE_ZSTD_H +static constexpr int ts_has_cert_compression_zstd = 1; +#elif !HAVE_SSL_CTX_ADD_CERT_COMPRESSION_ALG && HAVE_SSL_CTX_SET1_CERT_COMP_PREFERENCE && !defined(OPENSSL_NO_ZSTD) +static constexpr int ts_has_cert_compression_zstd = 1; +#else +static constexpr int ts_has_cert_compression_zstd = 0; +#endif + +static constexpr int ts_has_cert_compression = + ts_has_cert_compression_zlib | ts_has_cert_compression_brotli | ts_has_cert_compression_zstd; + // Produce output about compile time features, useful for checking how things were built static void print_feature(std::string_view name, int value, bool json, bool last = false) @@ -100,11 +134,11 @@ produce_features(bool json) #else print_feature("TS_HAS_ZSTD", 0, json); #endif -#if HAVE_SSL_CTX_ADD_CERT_COMPRESSION_ALG || HAVE_SSL_CTX_SET1_CERT_COMP_PREFERENCE - print_feature("TS_HAS_CERT_COMPRESSION", 1, json); -#else - print_feature("TS_HAS_CERT_COMPRESSION", 0, json); -#endif + print_feature("TS_HAS_CERT_COMPRESSION", ts_has_cert_compression, json); + print_feature("TS_HAS_CERT_COMPRESSION_CALLBACKS", ts_has_cert_compression_callbacks, json); + print_feature("TS_HAS_CERT_COMPRESSION_ZLIB", ts_has_cert_compression_zlib, json); + print_feature("TS_HAS_CERT_COMPRESSION_BROTLI", ts_has_cert_compression_brotli, json); + print_feature("TS_HAS_CERT_COMPRESSION_ZSTD", ts_has_cert_compression_zstd, json); #ifdef F_GETPIPE_SZ print_feature("TS_HAS_PIPE_BUFFER_SIZE_CONFIG", 1, json); #else diff --git a/tests/gold_tests/tls/tls_cert_comp.test.py b/tests/gold_tests/tls/tls_cert_comp.test.py index 53d87c670b1..0bb17e90951 100644 --- a/tests/gold_tests/tls/tls_cert_comp.test.py +++ b/tests/gold_tests/tls/tls_cert_comp.test.py @@ -24,7 +24,7 @@ decompression succeed by checking the ssl cert compression metrics. ''' -Test.SkipUnless(Condition.HasATSFeature('TS_HAS_CERT_COMPRESSION')) +Test.SkipUnless(Condition.HasATSFeature('TS_HAS_CERT_COMPRESSION_CALLBACKS')) REPLAY_FILE = 'replay/tls_cert_compression.replay.yaml'