This is an automated email from the ASF dual-hosted git repository.
bcall pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new fd02ff97ec Add server_group_list option to sni (#12223)
fd02ff97ec is described below
commit fd02ff97ecc06df9a48038169f7bc58f5381dfd1
Author: Jasmine Emanouel <[email protected]>
AuthorDate: Fri May 30 07:25:26 2025 +1000
Add server_group_list option to sni (#12223)
---
doc/admin-guide/files/sni.yaml.en.rst | 5 ++
include/iocore/net/TLSBasicSupport.h | 1 +
include/iocore/net/YamlSNIConfig.h | 2 +
src/iocore/net/SNIActionPerformer.cc | 19 +++++
src/iocore/net/SNIActionPerformer.h | 15 ++++
src/iocore/net/TLSBasicSupport.cc | 7 ++
src/iocore/net/YamlSNIConfig.cc | 8 ++-
tests/gold_tests/tls/tls_sni_groups.test.py | 104 ++++++++++++++++++++++++++++
8 files changed, 160 insertions(+), 1 deletion(-)
diff --git a/doc/admin-guide/files/sni.yaml.en.rst
b/doc/admin-guide/files/sni.yaml.en.rst
index 45f6a442aa..2a755580c9 100644
--- a/doc/admin-guide/files/sni.yaml.en.rst
+++ b/doc/admin-guide/files/sni.yaml.en.rst
@@ -167,6 +167,11 @@ server_TLSv1_3_cipher_suites Inbound
Specifies an override to the
documentation. Note that
this configures the cipher suite used for inbound TLSv1.3 and
above connections.
+server_group_list Inbound Specifies an override to
the global :ts:cv:`proxy.config.ssl.server.groups_list`
+ :file:`records.yaml`
configuration. See the
+ `OpenSSL
SSL_CTX_set_groups_list
<https://docs.openssl.org/3.5/man3/SSL_CTX_set1_curves/>`_
+ documentation.
+
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 799cda55c0..64ff16ea1a 100644
--- a/include/iocore/net/TLSBasicSupport.h
+++ b/include/iocore/net/TLSBasicSupport.h
@@ -63,6 +63,7 @@ public:
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);
+ bool set_groups_list(std::string const &groups_list);
/**
* 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 3a11dc5a57..c8396a76e7 100644
--- a/include/iocore/net/YamlSNIConfig.h
+++ b/include/iocore/net/YamlSNIConfig.h
@@ -58,6 +58,7 @@ TSDECL(client_key);
TSDECL(client_sni_policy);
TSDECL(server_cipher_suite);
TSDECL(server_TLSv1_3_cipher_suites);
+TSDECL(server_groups_list);
TSDECL(ip_allow);
TSDECL(valid_tls_versions_in);
TSDECL(valid_tls_version_min_in);
@@ -105,6 +106,7 @@ struct YamlSNIConfig {
std::string client_sni_policy;
std::string server_cipher_suite;
std::string server_TLSv1_3_cipher_suites;
+ std::string server_groups_list;
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 3a83a5772a..107a1552b3 100644
--- a/src/iocore/net/SNIActionPerformer.cc
+++ b/src/iocore/net/SNIActionPerformer.cc
@@ -493,3 +493,22 @@ ServerTLSv1_3CipherSuites::SNIAction(SSL &ssl, const
Context & /* ctx ATS_UNUSED
tbs->set_cipher_suite(server_TLSV1_3_cipher_suites);
return SSL_TLSEXT_ERR_OK;
}
+
+int
+ServerGroupsList::SNIAction(SSL &ssl, const Context & /* ctx ATS_UNUSED */)
const
+{
+ if (server_groups_list.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 groups list from server_groups_list to %s",
server_groups_list.c_str());
+
+ if (!tbs->set_groups_list(server_groups_list)) {
+ Error("Invalid server_groups_list: %s", server_groups_list.c_str());
+ return SSL_TLSEXT_ERR_ALERT_WARNING;
+ }
+ return SSL_TLSEXT_ERR_OK;
+}
diff --git a/src/iocore/net/SNIActionPerformer.h
b/src/iocore/net/SNIActionPerformer.h
index f2e8b60e26..c173caacaa 100644
--- a/src/iocore/net/SNIActionPerformer.h
+++ b/src/iocore/net/SNIActionPerformer.h
@@ -342,3 +342,18 @@ public:
private:
std::string const server_TLSV1_3_cipher_suites{};
};
+
+/**
+ Override proxy.config.ssl.server.groups_list by server_groups_list in
sni.yaml
+ */
+class ServerGroupsList : public ActionItem
+{
+public:
+ ServerGroupsList(std::string const &p) : server_groups_list(p) {}
+ ~ServerGroupsList() override {}
+
+ int SNIAction(SSL &ssl, const Context &ctx) const override;
+
+private:
+ std::string const server_groups_list{};
+};
diff --git a/src/iocore/net/TLSBasicSupport.cc
b/src/iocore/net/TLSBasicSupport.cc
index 0c3a5de50d..dc3a053657 100644
--- a/src/iocore/net/TLSBasicSupport.cc
+++ b/src/iocore/net/TLSBasicSupport.cc
@@ -188,6 +188,13 @@ TLSBasicSupport::set_cipher_suite([[maybe_unused]]
std::string const &cipher_sui
#endif
}
+bool
+TLSBasicSupport::set_groups_list(std::string const &groups_list)
+{
+ auto ssl = this->_get_ssl_object();
+ return SSL_set1_groups_list(ssl, groups_list.c_str());
+}
+
int
TLSBasicSupport::verify_certificate(X509_STORE_CTX *ctx)
{
diff --git a/src/iocore/net/YamlSNIConfig.cc b/src/iocore/net/YamlSNIConfig.cc
index c5dfd70c7d..bbc0eb4ace 100644
--- a/src/iocore/net/YamlSNIConfig.cc
+++ b/src/iocore/net/YamlSNIConfig.cc
@@ -161,6 +161,9 @@ YamlSNIConfig::Item::populate_sni_actions(action_vector_t
&actions)
if (!server_TLSv1_3_cipher_suites.empty()) {
actions.push_back(std::make_unique<ServerTLSv1_3CipherSuites>(server_TLSv1_3_cipher_suites));
}
+ if (!server_groups_list.empty()) {
+ actions.push_back(std::make_unique<ServerGroupsList>(server_groups_list));
+ }
if (http2_buffer_water_mark.has_value()) {
actions.push_back(std::make_unique<HTTP2BufferWaterMark>(http2_buffer_water_mark.value()));
}
@@ -226,6 +229,7 @@ std::set<std::string> valid_sni_config_keys = {TS_fqdn,
#if TS_USE_TLS_SET_CIPHERSUITES
TS_server_TLSv1_3_cipher_suites,
#endif
+ TS_server_groups_list,
TS_http2,
TS_http2_buffer_water_mark,
TS_http2_initial_window_size_in,
@@ -458,7 +462,9 @@ template <> struct convert<YamlSNIConfig::Item> {
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_server_groups_list]) {
+ item.server_groups_list = node[TS_server_groups_list].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_sni_groups.test.py
b/tests/gold_tests/tls/tls_sni_groups.test.py
new file mode 100644
index 0000000000..870f07de0e
--- /dev/null
+++ b/tests/gold_tests/tls/tls_sni_groups.test.py
@@ -0,0 +1,104 @@
+'''
+'''
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+Test.Summary = '''
+Test SNI configuration server_groups_list
+'''
+# The groups function was added in OpenSSL 1.1.1
+Test.SkipUnless(Condition.HasOpenSSLVersion("1.1.1"))
+
+# Define default ATS
+ts = Test.MakeATSProcess("ts", enable_tls=True)
+server = Test.MakeOriginServer("server", ssl=True)
+
+request_header = {"headers": "GET / HTTP/1.1\r\n\r\n", "timestamp":
"1469733493.993", "body": ""}
+response_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n",
"timestamp": "1469733493.993", "body": "foo ok"}
+server.addResponse("sessionlog.json", request_header, response_header)
+
+# add ssl materials like key, certificates for the server
+ts.addSSLfile("ssl/server.pem")
+ts.addSSLfile("ssl/server.key")
+
+# Need no remap rules. Everything should be processed by sni
+
+# 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')
+
+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.client.CA.cert.path':
'{0}'.format(ts.Variables.SSLDir),
+ 'proxy.config.diags.debug.enabled': 1,
+ 'proxy.config.diags.debug.tags': 'ssl_sni',
+ })
+
+ts.Disk.sni_yaml.AddLines(
+ [
+ 'sni:',
+ '- fqdn: aaa.com',
+ ' server_groups_list: X25519MLKEM768',
+ ' valid_tls_versions_in: [ TLSv1_3 ]',
+ ' server_TLSv1_3_cipher_suites: TLS_AES_256_GCM_SHA384',
+ '- fqdn: bbb.com',
+ ' server_groups_list: x25519',
+ ' valid_tls_versions_in: [ TLSv1_2 ]',
+ ' server_cipher_suite: ECDHE-RSA-AES256-GCM-SHA384',
+ '- fqdn: ccc.com',
+ ' server_groups_list: ABC123',
+ ' valid_tls_versions_in: [ TLSv1_2 ]',
+ ' server_cipher_suite: ECDHE-RSA-AES256-GCM-SHA384',
+ ])
+
+tr = Test.AddTestRun("Test 0: x25519")
+tr.Processes.Default.StartBefore(server)
+tr.Processes.Default.StartBefore(Test.Processes.ts)
+tr.MakeCurlCommand(
+ "-v --ciphers ECDHE-RSA-AES256-GCM-SHA384 --resolve
'bbb.com:{0}:127.0.0.1' -k https://bbb.com:{0}".format(
+ ts.Variables.ssl_port))
+tr.ReturnCode = 0
+tr.StillRunningAfter = ts
+ts.Disk.traffic_out.Content += Testers.ContainsExpression(
+ "Setting groups list from server_groups_list to x25519", "Should log
setting the server groups")
+tr.Processes.Default.Streams.all = Testers.IncludesExpression(
+ f"SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 / x25519",
"Curl should log using x25519 in the SSL connection")
+
+tr = Test.AddTestRun("Test 1: fail")
+tr.MakeCurlCommand(
+ "-v --ciphers ECDHE-RSA-AES256-GCM-SHA384 --resolve
'ccc.com:{0}:127.0.0.1' -k https://ccc.com:{0}".format(
+ ts.Variables.ssl_port))
+# The error code is 35, which indicates there was a ssl connection error
+tr.ReturnCode = 35
+tr.StillRunningAfter = ts
+tr.StillRunningAfter = server
+ts.Disk.diags_log.Content = Testers.ContainsExpression(
+ "ERROR: Invalid server_groups_list: ABC123", "Curl attempt should have
failed")
+
+# Hybrid ECDH PQ key exchange TLS groups were added in OpenSSL 3.5
+if Condition.HasOpenSSLVersion("3.5.0"):
+ tr = Test.AddTestRun("Test 2: X25519MLKEM768")
+ tr.MakeCurlCommand(
+ "-v --tls13-ciphers TLS_AES_256_GCM_SHA384 --resolve
'aaa.com:{0}:127.0.0.1' -k https://aaa.com:{0}".format(
+ ts.Variables.ssl_port))
+ tr.ReturnCode = 0
+ tr.StillRunningAfter = ts
+ ts.Disk.traffic_out.Content += Testers.ContainsExpression(
+ "Setting groups list from server_groups_list to X25519MLKEM768",
"Should log setting the server groups")
+ tr.Processes.Default.Streams.all = Testers.IncludesExpression(
+ f"SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 /
X25519MLKEM768",
+ f"Curl should log using X25519MLKEM768 in the SSL connection")