This is an automated email from the ASF dual-hosted git repository. cmcfarlen pushed a commit to branch 10.1.x in repository https://gitbox.apache.org/repos/asf/trafficserver.git
commit af1d5e97d4e52505e06bd8fc485b5b50fa976966 Author: Brian Neradt <[email protected]> AuthorDate: Thu Mar 20 10:55:30 2025 -0500 Add server_cipher_suite to sni.yaml (#12110) Allow the override of records.yaml configurations: * proxy.config.ssl.server.cipher_suite * proxy.config.ssl.server.TLSv1_3.cipher_suites By the following new sni.yaml configurations: * server_cipher_suite * server_TLSv1_3_cipher_suites. (cherry picked from commit 13b94b94175b184025ee4f08f8b8641d2b62496b) --- doc/admin-guide/files/sni.yaml.en.rst | 12 +++++++++ include/iocore/net/TLSBasicSupport.h | 4 +++ include/iocore/net/YamlSNIConfig.h | 4 +++ src/iocore/net/SNIActionPerformer.cc | 31 ++++++++++++++++++++++ src/iocore/net/SNIActionPerformer.h | 31 ++++++++++++++++++++++ src/iocore/net/TLSBasicSupport.cc | 16 +++++++++++ src/iocore/net/YamlSNIConfig.cc | 16 +++++++++++ .../tls/tls_client_versions_minmax.test.py | 11 ++++---- 8 files changed, 119 insertions(+), 6 deletions(-) diff --git a/doc/admin-guide/files/sni.yaml.en.rst b/doc/admin-guide/files/sni.yaml.en.rst index 14f04ddeea..2640f2f3e8 100644 --- a/doc/admin-guide/files/sni.yaml.en.rst +++ b/doc/admin-guide/files/sni.yaml.en.rst @@ -155,6 +155,18 @@ verify_client_ca_certs Both Specifies an alternate set of ``verify_client_ca_certs`` can only be used with capabilities provided by OpenSSL 1.0.2 or later. +server_cipher_suite Inbound Specifies an override to the global :ts:cv:`proxy.config.ssl.server.cipher_suite` + :file:`records.yaml` configuration. See the + `OpenSSL SSL_CTX_set_cipher_list <https://docs.openssl.org/3.1/man3/SSL_CTX_set_cipher_list/>`_ + documentation. Note that this configures the cipher suite used for inbound TLS + (version 1.2 and below) connections. + +server_TLSv1_3_cipher_suites Inbound Specifies an override to the global :ts:cv:`proxy.config.ssl.server.TLSv1_3.cipher_suites` + :file:`records.yaml` configuration. See the + `OpenSSL SSL_set_ciphersuites <https://docs.openssl.org/3.1/man3/SSL_set_ciphersuites/>`_ + documentation. Note that this configures the cipher suite used for inbound TLSv1.3 and + above connections. + host_sni_policy Inbound One of the values :code:`DISABLED`, :code:`PERMISSIVE`, or :code:`ENFORCED`. If not specified, the value of :ts:cv:`proxy.config.http.host_sni_policy` is used. diff --git a/include/iocore/net/TLSBasicSupport.h b/include/iocore/net/TLSBasicSupport.h index c814357ca4..799cda55c0 100644 --- a/include/iocore/net/TLSBasicSupport.h +++ b/include/iocore/net/TLSBasicSupport.h @@ -24,6 +24,8 @@ #pragma once +#include <string> + #include <openssl/ssl.h> #include "tscore/ink_hrtime.h" @@ -59,6 +61,8 @@ public: void set_valid_tls_version_min(int min); void set_valid_tls_version_max(int max); void set_valid_tls_protocols(unsigned long proto_mask, unsigned long max_mask); + void set_legacy_cipher_suite(std::string const &cipher_suite); + void set_cipher_suite(std::string const &cipher_suite); /** * Give the plugin access to the data structure passed in during the underlying diff --git a/include/iocore/net/YamlSNIConfig.h b/include/iocore/net/YamlSNIConfig.h index ea7c67377d..3a11dc5a57 100644 --- a/include/iocore/net/YamlSNIConfig.h +++ b/include/iocore/net/YamlSNIConfig.h @@ -56,6 +56,8 @@ TSDECL(verify_origin_server); TSDECL(client_cert); TSDECL(client_key); TSDECL(client_sni_policy); +TSDECL(server_cipher_suite); +TSDECL(server_TLSv1_3_cipher_suites); TSDECL(ip_allow); TSDECL(valid_tls_versions_in); TSDECL(valid_tls_version_min_in); @@ -101,6 +103,8 @@ struct YamlSNIConfig { std::string client_cert; std::string client_key; std::string client_sni_policy; + std::string server_cipher_suite; + std::string server_TLSv1_3_cipher_suites; std::string ip_allow; bool protocol_unset = true; unsigned long protocol_mask; diff --git a/src/iocore/net/SNIActionPerformer.cc b/src/iocore/net/SNIActionPerformer.cc index c34cb652ee..3a83a5772a 100644 --- a/src/iocore/net/SNIActionPerformer.cc +++ b/src/iocore/net/SNIActionPerformer.cc @@ -462,3 +462,34 @@ ServerMaxEarlyData::SNIAction([[maybe_unused]] SSL &ssl, const Context & /* ctx #endif return SSL_TLSEXT_ERR_OK; } + +int +ServerCipherSuite::SNIAction(SSL &ssl, const Context & /* ctx ATS_UNUSED */) const +{ + if (server_cipher_suite.empty()) { + return SSL_TLSEXT_ERR_OK; + } + auto tbs = TLSBasicSupport::getInstance(&ssl); + if (tbs == nullptr) { + return SSL_TLSEXT_ERR_OK; + } + Dbg(dbg_ctl_ssl_sni, "Setting pre TLSv1.3 cipher suite from server_cipher_suite to %s", server_cipher_suite.c_str()); + tbs->set_legacy_cipher_suite(server_cipher_suite); + return SSL_TLSEXT_ERR_OK; +} + +int +ServerTLSv1_3CipherSuites::SNIAction(SSL &ssl, const Context & /* ctx ATS_UNUSED */) const +{ + if (server_TLSV1_3_cipher_suites.empty()) { + return SSL_TLSEXT_ERR_OK; + } + auto tbs = TLSBasicSupport::getInstance(&ssl); + if (tbs == nullptr) { + return SSL_TLSEXT_ERR_OK; + } + Dbg(dbg_ctl_ssl_sni, "Setting TLSv1.3 or later cipher suites from server_TLSv1_3_cipher_suites to %s", + server_TLSV1_3_cipher_suites.c_str()); + tbs->set_cipher_suite(server_TLSV1_3_cipher_suites); + return SSL_TLSEXT_ERR_OK; +} diff --git a/src/iocore/net/SNIActionPerformer.h b/src/iocore/net/SNIActionPerformer.h index 09236eaf73..f2e8b60e26 100644 --- a/src/iocore/net/SNIActionPerformer.h +++ b/src/iocore/net/SNIActionPerformer.h @@ -28,6 +28,7 @@ #include "iocore/net/YamlSNIConfig.h" #include "tscore/ink_inet.h" +#include <string> #include "swoc/TextView.h" #include <vector> @@ -311,3 +312,33 @@ private: uint32_t server_max_early_data = 0; #endif }; + +/** + Override proxy.config.ssl.server.cipher_suite by server_cipher_suite in sni.yaml + */ +class ServerCipherSuite : public ActionItem +{ +public: + ServerCipherSuite(std::string const &p) : server_cipher_suite(p) {} + ~ServerCipherSuite() override {} + + int SNIAction(SSL &ssl, const Context &ctx) const override; + +private: + std::string const server_cipher_suite{}; +}; + +/** + Override proxy.config.ssl.server.TLSv1_3.cipher_suites by server_TLSv1_3_cipher_suites in sni.yaml + */ +class ServerTLSv1_3CipherSuites : public ActionItem +{ +public: + ServerTLSv1_3CipherSuites(std::string const &p) : server_TLSV1_3_cipher_suites(p) {} + ~ServerTLSv1_3CipherSuites() override {} + + int SNIAction(SSL &ssl, const Context &ctx) const override; + +private: + std::string const server_TLSV1_3_cipher_suites{}; +}; diff --git a/src/iocore/net/TLSBasicSupport.cc b/src/iocore/net/TLSBasicSupport.cc index ab97412ea4..0c3a5de50d 100644 --- a/src/iocore/net/TLSBasicSupport.cc +++ b/src/iocore/net/TLSBasicSupport.cc @@ -172,6 +172,22 @@ TLSBasicSupport::set_valid_tls_version_max(int max) SSL_set_max_proto_version(ssl, ver); } +void +TLSBasicSupport::set_legacy_cipher_suite(std::string const &cipher_suite) +{ + auto ssl = this->_get_ssl_object(); + SSL_set_cipher_list(ssl, cipher_suite.c_str()); +} + +void +TLSBasicSupport::set_cipher_suite([[maybe_unused]] std::string const &cipher_suite) +{ +#if TS_USE_TLS_SET_CIPHERSUITES + auto ssl = this->_get_ssl_object(); + SSL_set_ciphersuites(ssl, cipher_suite.c_str()); +#endif +} + int TLSBasicSupport::verify_certificate(X509_STORE_CTX *ctx) { diff --git a/src/iocore/net/YamlSNIConfig.cc b/src/iocore/net/YamlSNIConfig.cc index df53e7f363..c5dfd70c7d 100644 --- a/src/iocore/net/YamlSNIConfig.cc +++ b/src/iocore/net/YamlSNIConfig.cc @@ -155,6 +155,12 @@ YamlSNIConfig::Item::populate_sni_actions(action_vector_t &actions) if (!client_sni_policy.empty()) { actions.push_back(std::make_unique<OutboundSNIPolicy>(client_sni_policy)); } + if (!server_cipher_suite.empty()) { + actions.push_back(std::make_unique<ServerCipherSuite>(server_cipher_suite)); + } + if (!server_TLSv1_3_cipher_suites.empty()) { + actions.push_back(std::make_unique<ServerTLSv1_3CipherSuites>(server_TLSv1_3_cipher_suites)); + } if (http2_buffer_water_mark.has_value()) { actions.push_back(std::make_unique<HTTP2BufferWaterMark>(http2_buffer_water_mark.value())); } @@ -216,6 +222,10 @@ std::set<std::string> valid_sni_config_keys = {TS_fqdn, TS_client_cert, TS_client_key, TS_client_sni_policy, + TS_server_cipher_suite, +#if TS_USE_TLS_SET_CIPHERSUITES + TS_server_TLSv1_3_cipher_suites, +#endif TS_http2, TS_http2_buffer_water_mark, TS_http2_initial_window_size_in, @@ -442,6 +452,12 @@ template <> struct convert<YamlSNIConfig::Item> { if (node[TS_client_sni_policy]) { item.client_sni_policy = node[TS_client_sni_policy].as<std::string>(); } + if (node[TS_server_cipher_suite]) { + item.server_cipher_suite = node[TS_server_cipher_suite].as<std::string>(); + } + if (node[TS_server_TLSv1_3_cipher_suites]) { + item.server_TLSv1_3_cipher_suites = node[TS_server_TLSv1_3_cipher_suites].as<std::string>(); + } if (node[TS_ip_allow]) { item.ip_allow = node[TS_ip_allow].as<std::string>(); diff --git a/tests/gold_tests/tls/tls_client_versions_minmax.test.py b/tests/gold_tests/tls/tls_client_versions_minmax.test.py index 70641c21e1..7076cb9d1b 100644 --- a/tests/gold_tests/tls/tls_client_versions_minmax.test.py +++ b/tests/gold_tests/tls/tls_client_versions_minmax.test.py @@ -42,16 +42,10 @@ ts.addSSLfile("ssl/server.key") # Make sure the TS server certs are different from the origin certs ts.Disk.ssl_multicert_config.AddLine('dest_ip=* ssl_cert_name=server.pem ssl_key_name=server.key') -cipher_suite = 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:RC4-SHA:RC4-MD5:AES128-SHA:AES256-SHA:DES-CBC3-SHA!SRP:!DSS:!PSK:!aNULL:!eNULL:!SSLv2' - -if Condition.HasOpenSSLVersion("3.0.0"): - cipher_suite += ":@SECLEVEL=0" - ts.Disk.records_config.update( { 'proxy.config.ssl.server.cert.path': '{0}'.format(ts.Variables.SSLDir), 'proxy.config.ssl.server.private_key.path': '{0}'.format(ts.Variables.SSLDir), - 'proxy.config.ssl.server.cipher_suite': cipher_suite, 'proxy.config.ssl.client.CA.cert.path': '{0}'.format(ts.Variables.SSLDir), 'proxy.config.url_remap.pristine_host_hdr': 1, 'proxy.config.ssl.server.version.min': 2, @@ -62,6 +56,10 @@ ts.Disk.records_config.update( 'proxy.config.diags.debug.tags': 'ssl', }) +cipher_suite = 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:RC4-SHA:RC4-MD5:AES128-SHA:AES256-SHA:DES-CBC3-SHA!SRP:!DSS:!PSK:!aNULL:!eNULL:!SSLv2' +if Condition.HasOpenSSLVersion("3.0.0"): + cipher_suite += ":@SECLEVEL=0" + # foo.com should only offer the older TLS protocols # bar.com should terminate. # empty SNI should tunnel to server_bar @@ -72,6 +70,7 @@ ts.Disk.sni_yaml.AddLines( ' valid_tls_versions_in: [ TLSv1_2 ]', # This setting should be ignored in favor of a version range setting ' valid_tls_version_min_in: TLSv1', ' valid_tls_version_max_in: TLSv1_1', + f' server_cipher_suite: {cipher_suite}', ]) # Target foo.com for TLSv1_2. Should fail
