Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,8 @@ check_symbol_exists(SSL_error_description "openssl/ssl.h" HAVE_SSL_ERROR_DESCRIP
check_symbol_exists(SSL_CTX_set_ciphersuites "openssl/ssl.h" TS_USE_TLS_SET_CIPHERSUITES)
check_symbol_exists(SSL_CTX_set_keylog_callback "openssl/ssl.h" TS_HAS_TLS_KEYLOGGING)
check_symbol_exists(SSL_CTX_set_tlsext_ticket_key_cb "openssl/ssl.h" HAVE_SSL_CTX_SET_TLSEXT_TICKET_KEY_CB)
check_symbol_exists(SSL_CTX_add_cert_compression_alg "openssl/ssl.h" HAVE_SSL_CTX_ADD_CERT_COMPRESSION_ALG)
check_symbol_exists(SSL_CTX_set1_cert_comp_preference "openssl/ssl.h" HAVE_SSL_CTX_SET1_CERT_COMP_PREFERENCE)
check_symbol_exists(SSL_get_all_async_fds openssl/ssl.h TS_USE_TLS_ASYNC)
check_symbol_exists(OSSL_PARAM_construct_end "openssl/params.h" HAVE_OSSL_PARAM_CONSTRUCT_END)
check_symbol_exists(TLS1_3_VERSION "openssl/ssl.h" TS_USE_TLS13)
Expand Down
15 changes: 13 additions & 2 deletions cmake/Findbrotli.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,28 @@
#
# brotli_FOUND
# brotlicommon_LIBRARY
# brotlidec_LIBRARY
# brotlienc_LIBRARY
# brotli_INCLUDE_DIRS
#
# and the following imported targets
#
# brotli::brotlicommon
# brotli::brotlidec
# brotli::brotlienc
#

find_library(brotlicommon_LIBRARY NAMES brotlicommon)
find_library(brotlidec_LIBRARY NAMES brotlidec)
find_library(brotlienc_LIBRARY NAMES brotlienc)
find_path(brotli_INCLUDE_DIR NAMES brotli/encode.h)

mark_as_advanced(brotli_FOUND brotlicommon_LIBRARY brotlienc_LIBRARY brotli_INCLUDE_DIR)
mark_as_advanced(brotli_FOUND brotlicommon_LIBRARY brotlidec_LIBRARY brotlienc_LIBRARY brotli_INCLUDE_DIR)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(brotli REQUIRED_VARS brotlicommon_LIBRARY brotlienc_LIBRARY brotli_INCLUDE_DIR)
find_package_handle_standard_args(
brotli REQUIRED_VARS brotlicommon_LIBRARY brotlidec_LIBRARY brotlienc_LIBRARY brotli_INCLUDE_DIR
)

if(brotli_FOUND)
set(brotli_INCLUDE_DIRS "${brotli_INCLUDE_DIR}")
Expand All @@ -49,6 +54,12 @@ if(brotli_FOUND AND NOT TARGET brotli::brotlicommon)
target_link_libraries(brotli::brotlicommon INTERFACE "${brotlicommon_LIBRARY}")
endif()

if(brotli_FOUND AND NOT TARGET brotli::brotlidec)
add_library(brotli::brotlidec INTERFACE IMPORTED)
target_include_directories(brotli::brotlidec INTERFACE ${brotli_INCLUDE_DIRS})
target_link_libraries(brotli::brotlidec INTERFACE brotli::brotlicommon "${brotlidec_LIBRARY}")
endif()

if(brotli_FOUND AND NOT TARGET brotli::brotlienc)
add_library(brotli::brotlienc INTERFACE IMPORTED)
target_include_directories(brotli::brotlienc INTERFACE ${brotli_INCLUDE_DIRS})
Expand Down
34 changes: 34 additions & 0 deletions doc/admin-guide/files/records.yaml.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4268,6 +4268,40 @@ SSL Termination
``1`` Enables the use of Kernel TLS..
===== ======================================================================

.. ts:cv:: CONFIG proxy.config.ssl.server.cert_compression.algorithms STRING
:reloadable:

A comma-separated list of compression algorithms that |TS| is willing to
use for TLS Certificate Compression
(`RFC 8879 <https://datatracker.ietf.org/doc/html/rfc8879>`_) when |TS|
acts as a TLS server (i.e. accepting connections from clients). When a
connecting client advertises support for one of these algorithms, |TS| will
send its certificate in compressed form, reducing handshake size.

Supported values: ``zlib``, ``brotli``, ``zstd``. The order determines the
server's preference. An empty value (the default) disables certificate
compression.

``brotli`` and ``zstd`` are only available when |TS| is compiled with the
corresponding libraries.

Example::

proxy.config.ssl.server.cert_compression.algorithms: zlib,brotli

.. ts:cv:: CONFIG proxy.config.ssl.client.cert_compression.algorithms STRING
:reloadable:

A comma-separated list of compression algorithms that |TS| advertises for
TLS Certificate Compression
(`RFC 8879 <https://datatracker.ietf.org/doc/html/rfc8879>`_) when |TS|
acts as a TLS client (i.e. connecting to origin servers). When the origin
supports one of these algorithms, |TS| will accept and decompress the
certificate.

Supported values: ``zlib``, ``brotli``, ``zstd``. An empty value (the
default) disables certificate compression.

Client-Related Configuration
----------------------------

Expand Down
66 changes: 66 additions & 0 deletions doc/admin-guide/monitoring/statistics/core/ssl.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -389,3 +389,69 @@ Stats for Pre-warming TLS Tunnel is registered dynamically. The ``POOL`` in belo
:type: counter

Represents the total number of pre-warming retry.

.. ts:stat:: global proxy.process.ssl.cert_compress.zlib integer
:type: counter

The number of times a server certificate was compressed with zlib during a
TLS handshake.

.. ts:stat:: global proxy.process.ssl.cert_compress.zlib_failure integer
:type: counter

Comment thread
maskit marked this conversation as resolved.
The number of times zlib compression of a server certificate failed.

.. ts:stat:: global proxy.process.ssl.cert_decompress.zlib integer
:type: counter

The number of times a certificate received from an origin server was
decompressed with zlib.

.. ts:stat:: global proxy.process.ssl.cert_decompress.zlib_failure integer
:type: counter

The number of times zlib decompression of a certificate failed.

.. ts:stat:: global proxy.process.ssl.cert_compress.brotli integer
:type: counter

The number of times a server certificate was compressed with Brotli during a
TLS handshake.

.. ts:stat:: global proxy.process.ssl.cert_compress.brotli_failure integer
:type: counter

The number of times Brotli compression of a server certificate failed.

.. ts:stat:: global proxy.process.ssl.cert_decompress.brotli integer
:type: counter

The number of times a certificate received from an origin server was
decompressed with Brotli.

.. ts:stat:: global proxy.process.ssl.cert_decompress.brotli_failure integer
:type: counter

The number of times Brotli decompression of a certificate failed.

.. ts:stat:: global proxy.process.ssl.cert_compress.zstd integer
:type: counter

The number of times a server certificate was compressed with zstd during a
TLS handshake.

.. ts:stat:: global proxy.process.ssl.cert_compress.zstd_failure integer
:type: counter

The number of times zstd compression of a server certificate failed.

.. ts:stat:: global proxy.process.ssl.cert_decompress.zstd integer
:type: counter

The number of times a certificate received from an origin server was
decompressed with zstd.

.. ts:stat:: global proxy.process.ssl.cert_decompress.zstd_failure integer
:type: counter

The number of times zstd decompression of a certificate failed.
1 change: 1 addition & 0 deletions include/iocore/net/SSLMultiCertConfigLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ class SSLMultiCertConfigLoader
virtual bool _set_npn_callback(SSL_CTX *ctx);
virtual bool _set_alpn_callback(SSL_CTX *ctx);
virtual bool _set_keylog_callback(SSL_CTX *ctx);
virtual bool _enable_cert_compression(SSL_CTX *ctx);
virtual bool _enable_ktls(SSL_CTX *ctx);
virtual bool _enable_early_data(SSL_CTX *ctx);
};
2 changes: 2 additions & 0 deletions include/tscore/ink_config.h.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ const int DEFAULT_STACKSIZE = @DEFAULT_STACK_SIZE@;
#cmakedefine01 HAVE_SSL_ERROR_DESCRIPTION
#cmakedefine01 HAVE_OSSL_PARAM_CONSTRUCT_END
#cmakedefine01 TS_USE_TLS_SET_CIPHERSUITES
#cmakedefine01 HAVE_SSL_CTX_ADD_CERT_COMPRESSION_ALG
#cmakedefine01 HAVE_SSL_CTX_SET1_CERT_COMP_PREFERENCE

#define TS_BUILD_CANONICAL_HOST "@CMAKE_HOST@"

Expand Down
16 changes: 16 additions & 0 deletions src/iocore/net/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ add_library(
TLSSessionResumptionSupport.cc
TLSSNISupport.cc
TLSTunnelSupport.cc
TLSCertCompression.cc
UDPEventIO.cc
UDPIOEvent.cc
UnixConnection.cc
Expand Down Expand Up @@ -116,6 +117,21 @@ if(TS_USE_LINUX_IO_URING)
target_link_libraries(inknet PUBLIC ts::inkuring)
endif()

# Link cert compression libraries after OpenSSL so that OpenSSL include
# directories appear first in the search order, preventing broad system
# include paths (e.g. from Homebrew's zstd) from shadowing them.
if(HAVE_SSL_CTX_ADD_CERT_COMPRESSION_ALG)
target_sources(inknet PRIVATE TLSCertCompression_zlib.cc)
if(HAVE_BROTLI_ENCODE_H)
target_sources(inknet PRIVATE TLSCertCompression_brotli.cc)
target_link_libraries(inknet PRIVATE brotli::brotlienc brotli::brotlidec)
endif()
if(HAVE_ZSTD_H)
target_sources(inknet PRIVATE TLSCertCompression_zstd.cc)
target_link_libraries(inknet PRIVATE zstd::zstd)
endif()
endif()

if(BUILD_TESTING)
# libinknet_stub.cc is need because GNU ld is sensitive to the order of static libraries on the command line, and we have a cyclic dependency between inknet and proxy
add_executable(
Expand Down
3 changes: 3 additions & 0 deletions src/iocore/net/P_SSLConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ struct SSLConfigParams : public ConfigInfo {
unsigned char alpn_protocols_array[MAX_ALPN_STRING];
int alpn_protocols_array_size = 0;

char *server_cert_compression_algorithms;
char *client_cert_compression_algorithms;

char *server_tls13_cipher_suites;
char *client_tls13_cipher_suites;
char *server_groups_list;
Expand Down
14 changes: 14 additions & 0 deletions src/iocore/net/SSLClientUtils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@
#include "P_SSLNetVConnection.h"
#include "P_TLSKeyLogger.h"
#include "SSLSessionCache.h"
#include "TLSCertCompression.h"
#include "iocore/net/YamlSNIConfig.h"
#include "iocore/net/SSLDiags.h"
#include "tscore/ink_config.h"
#include "tscore/SimpleTokenizer.h"
#include "tscore/Filenames.h"
#include "tscore/X509HostnameValidator.h"

Expand Down Expand Up @@ -247,6 +249,18 @@ SSLInitClientContext(const SSLConfigParams *params)
}
#endif

if (params->client_cert_compression_algorithms) {
std::vector<std::string> algs;
SimpleTokenizer tok(params->client_cert_compression_algorithms, ',');
for (const char *token = tok.getNext(); token; token = tok.getNext()) {
algs.emplace_back(token);
Comment thread
maskit marked this conversation as resolved.
}
if (register_certificate_compression_preference(client_ctx, algs) != 1) {
SSLError("invalid client certificate compression algorithm list in %s", ts::filename::RECORDS);
goto fail;
}
}

SSL_CTX_set_verify_depth(client_ctx, params->client_verify_depth);
if (SSLConfigParams::init_ssl_ctx_cb) {
SSLConfigParams::init_ssl_ctx_cb(client_ctx, false);
Expand Down
21 changes: 16 additions & 5 deletions src/iocore/net/SSLConfig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ SSLConfigParams::reset()
clientKeyPath = clientCACertFilename = clientCACertPath = cipherSuite = client_cipherSuite = dhparamsFile = serverKeyPathOnly =
clientKeyPathOnly = clientCertPathOnly = nullptr;
ssl_ocsp_response_path_only = nullptr;
server_cert_compression_algorithms = nullptr;
client_cert_compression_algorithms = nullptr;
server_tls13_cipher_suites = nullptr;
client_tls13_cipher_suites = nullptr;
server_groups_list = nullptr;
Expand Down Expand Up @@ -151,11 +153,13 @@ SSLConfigParams::cleanup()

ssl_ocsp_response_path_only = static_cast<char *>(ats_free_null(ssl_ocsp_response_path_only));

server_tls13_cipher_suites = static_cast<char *>(ats_free_null(server_tls13_cipher_suites));
client_tls13_cipher_suites = static_cast<char *>(ats_free_null(client_tls13_cipher_suites));
server_groups_list = static_cast<char *>(ats_free_null(server_groups_list));
client_groups_list = static_cast<char *>(ats_free_null(client_groups_list));
keylog_file = static_cast<char *>(ats_free_null(keylog_file));
server_cert_compression_algorithms = static_cast<char *>(ats_free_null(server_cert_compression_algorithms));
client_cert_compression_algorithms = static_cast<char *>(ats_free_null(client_cert_compression_algorithms));
server_tls13_cipher_suites = static_cast<char *>(ats_free_null(server_tls13_cipher_suites));
client_tls13_cipher_suites = static_cast<char *>(ats_free_null(client_tls13_cipher_suites));
server_groups_list = static_cast<char *>(ats_free_null(server_groups_list));
client_groups_list = static_cast<char *>(ats_free_null(client_groups_list));
keylog_file = static_cast<char *>(ats_free_null(keylog_file));

cleanupCTXTable();
reset();
Expand Down Expand Up @@ -494,6 +498,13 @@ SSLConfigParams::initialize()
server_groups_list = ats_stringdup(rec_str);
}

if (auto rec_str{RecGetRecordStringAlloc("proxy.config.ssl.server.cert_compression.algorithms")}; rec_str) {
server_cert_compression_algorithms = ats_stringdup(rec_str);
}
if (auto rec_str{RecGetRecordStringAlloc("proxy.config.ssl.client.cert_compression.algorithms")}; rec_str) {
client_cert_compression_algorithms = ats_stringdup(rec_str);
}

// ++++++++++++++++++++++++ Client part ++++++++++++++++++++
client_verify_depth = 7;

Expand Down
12 changes: 12 additions & 0 deletions src/iocore/net/SSLStats.cc
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,18 @@ SSLInitializeStatistics()
// For now, register with the librecords global sync.
RecRegNewSyncStatSync(SSLPeriodicMetricsUpdate);

ssl_rsb.cert_compress_zlib = Metrics::Counter::createPtr("proxy.process.ssl.cert_compress.zlib");
ssl_rsb.cert_compress_zlib_failure = Metrics::Counter::createPtr("proxy.process.ssl.cert_compress.zlib_failure");
ssl_rsb.cert_decompress_zlib = Metrics::Counter::createPtr("proxy.process.ssl.cert_decompress.zlib");
ssl_rsb.cert_decompress_zlib_failure = Metrics::Counter::createPtr("proxy.process.ssl.cert_decompress.zlib_failure");
ssl_rsb.cert_compress_brotli = Metrics::Counter::createPtr("proxy.process.ssl.cert_compress.brotli");
ssl_rsb.cert_compress_brotli_failure = Metrics::Counter::createPtr("proxy.process.ssl.cert_compress.brotli_failure");
ssl_rsb.cert_decompress_brotli = Metrics::Counter::createPtr("proxy.process.ssl.cert_decompress.brotli");
ssl_rsb.cert_decompress_brotli_failure = Metrics::Counter::createPtr("proxy.process.ssl.cert_decompress.brotli_failure");
ssl_rsb.cert_compress_zstd = Metrics::Counter::createPtr("proxy.process.ssl.cert_compress.zstd");
ssl_rsb.cert_compress_zstd_failure = Metrics::Counter::createPtr("proxy.process.ssl.cert_compress.zstd_failure");
ssl_rsb.cert_decompress_zstd = Metrics::Counter::createPtr("proxy.process.ssl.cert_decompress.zstd");
ssl_rsb.cert_decompress_zstd_failure = Metrics::Counter::createPtr("proxy.process.ssl.cert_decompress.zstd_failure");
ssl_rsb.early_data_received_count = Metrics::Counter::createPtr("proxy.process.ssl.early_data_received");
ssl_rsb.error_async = Metrics::Counter::createPtr("proxy.process.ssl.ssl_error_async");
ssl_rsb.error_ssl = Metrics::Counter::createPtr("proxy.process.ssl.ssl_error_ssl");
Expand Down
12 changes: 12 additions & 0 deletions src/iocore/net/SSLStats.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@ using ts::Metrics;
// for ssl_rsb.total_ticket_keys_renewed needs this initialization, but lets be
// consistent at least.
struct SSLStatsBlock {
Metrics::Counter::AtomicType *cert_compress_zlib = nullptr;
Metrics::Counter::AtomicType *cert_compress_zlib_failure = nullptr;
Metrics::Counter::AtomicType *cert_decompress_zlib = nullptr;
Metrics::Counter::AtomicType *cert_decompress_zlib_failure = nullptr;
Metrics::Counter::AtomicType *cert_compress_brotli = nullptr;
Metrics::Counter::AtomicType *cert_compress_brotli_failure = nullptr;
Metrics::Counter::AtomicType *cert_decompress_brotli = nullptr;
Metrics::Counter::AtomicType *cert_decompress_brotli_failure = nullptr;
Metrics::Counter::AtomicType *cert_compress_zstd = nullptr;
Metrics::Counter::AtomicType *cert_compress_zstd_failure = nullptr;
Metrics::Counter::AtomicType *cert_decompress_zstd = nullptr;
Metrics::Counter::AtomicType *cert_decompress_zstd_failure = nullptr;
Metrics::Counter::AtomicType *early_data_received_count = nullptr;
Metrics::Counter::AtomicType *error_async = nullptr;
Metrics::Counter::AtomicType *error_ssl = nullptr;
Expand Down
25 changes: 25 additions & 0 deletions src/iocore/net/SSLUtils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "SSLSessionCache.h"
#include "SSLSessionTicket.h"
#include "SSLDynlock.h" // IWYU pragma: keep - for ssl_dyn_*
#include "TLSCertCompression.h"

#include "iocore/net/SSLMultiCertConfigLoader.h"
#include "config/ssl_multicert.h"
Expand Down Expand Up @@ -435,6 +436,26 @@ DH_get_2048_256()
}
#endif

bool
SSLMultiCertConfigLoader::_enable_cert_compression(SSL_CTX *ctx)
{
std::vector<std::string> algs;

if (this->_params->server_cert_compression_algorithms) {
SimpleTokenizer tok(this->_params->server_cert_compression_algorithms, ',');
for (const char *token = tok.getNext(); token; token = tok.getNext()) {
algs.emplace_back(token);
Comment thread
maskit marked this conversation as resolved.
}
}

if (register_certificate_compression_preference(ctx, algs) == 1) {
return true;
} else {
SSLError("Failed to enable certificate compression");
return false;
}
}

bool
SSLMultiCertConfigLoader::_enable_ktls([[maybe_unused]] SSL_CTX *ctx)
{
Expand Down Expand Up @@ -1272,6 +1293,10 @@ SSLMultiCertConfigLoader::init_server_ssl_ctx(CertLoadData const &data, const SS
goto fail;
}

if (!this->_enable_cert_compression(ctx)) {
goto fail;
}

if (!this->_enable_ktls(ctx)) {
goto fail;
}
Expand Down
Loading