Skip to content

Commit fd02ff9

Browse files
Add server_group_list option to sni (#12223)
1 parent 90e7283 commit fd02ff9

8 files changed

Lines changed: 160 additions & 1 deletion

File tree

doc/admin-guide/files/sni.yaml.en.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,11 @@ server_TLSv1_3_cipher_suites Inbound Specifies an override to the
167167
documentation. Note that this configures the cipher suite used for inbound TLSv1.3 and
168168
above connections.
169169

170+
server_group_list Inbound Specifies an override to the global :ts:cv:`proxy.config.ssl.server.groups_list`
171+
:file:`records.yaml` configuration. See the
172+
`OpenSSL SSL_CTX_set_groups_list <https://docs.openssl.org/3.5/man3/SSL_CTX_set1_curves/>`_
173+
documentation.
174+
170175
host_sni_policy Inbound One of the values :code:`DISABLED`, :code:`PERMISSIVE`, or :code:`ENFORCED`.
171176

172177
If not specified, the value of :ts:cv:`proxy.config.http.host_sni_policy` is used.

include/iocore/net/TLSBasicSupport.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class TLSBasicSupport
6363
void set_valid_tls_protocols(unsigned long proto_mask, unsigned long max_mask);
6464
void set_legacy_cipher_suite(std::string const &cipher_suite);
6565
void set_cipher_suite(std::string const &cipher_suite);
66+
bool set_groups_list(std::string const &groups_list);
6667

6768
/**
6869
* Give the plugin access to the data structure passed in during the underlying

include/iocore/net/YamlSNIConfig.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ TSDECL(client_key);
5858
TSDECL(client_sni_policy);
5959
TSDECL(server_cipher_suite);
6060
TSDECL(server_TLSv1_3_cipher_suites);
61+
TSDECL(server_groups_list);
6162
TSDECL(ip_allow);
6263
TSDECL(valid_tls_versions_in);
6364
TSDECL(valid_tls_version_min_in);
@@ -105,6 +106,7 @@ struct YamlSNIConfig {
105106
std::string client_sni_policy;
106107
std::string server_cipher_suite;
107108
std::string server_TLSv1_3_cipher_suites;
109+
std::string server_groups_list;
108110
std::string ip_allow;
109111
bool protocol_unset = true;
110112
unsigned long protocol_mask;

src/iocore/net/SNIActionPerformer.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,3 +493,22 @@ ServerTLSv1_3CipherSuites::SNIAction(SSL &ssl, const Context & /* ctx ATS_UNUSED
493493
tbs->set_cipher_suite(server_TLSV1_3_cipher_suites);
494494
return SSL_TLSEXT_ERR_OK;
495495
}
496+
497+
int
498+
ServerGroupsList::SNIAction(SSL &ssl, const Context & /* ctx ATS_UNUSED */) const
499+
{
500+
if (server_groups_list.empty()) {
501+
return SSL_TLSEXT_ERR_OK;
502+
}
503+
auto tbs = TLSBasicSupport::getInstance(&ssl);
504+
if (tbs == nullptr) {
505+
return SSL_TLSEXT_ERR_OK;
506+
}
507+
Dbg(dbg_ctl_ssl_sni, "Setting groups list from server_groups_list to %s", server_groups_list.c_str());
508+
509+
if (!tbs->set_groups_list(server_groups_list)) {
510+
Error("Invalid server_groups_list: %s", server_groups_list.c_str());
511+
return SSL_TLSEXT_ERR_ALERT_WARNING;
512+
}
513+
return SSL_TLSEXT_ERR_OK;
514+
}

src/iocore/net/SNIActionPerformer.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,3 +342,18 @@ class ServerTLSv1_3CipherSuites : public ActionItem
342342
private:
343343
std::string const server_TLSV1_3_cipher_suites{};
344344
};
345+
346+
/**
347+
Override proxy.config.ssl.server.groups_list by server_groups_list in sni.yaml
348+
*/
349+
class ServerGroupsList : public ActionItem
350+
{
351+
public:
352+
ServerGroupsList(std::string const &p) : server_groups_list(p) {}
353+
~ServerGroupsList() override {}
354+
355+
int SNIAction(SSL &ssl, const Context &ctx) const override;
356+
357+
private:
358+
std::string const server_groups_list{};
359+
};

src/iocore/net/TLSBasicSupport.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,13 @@ TLSBasicSupport::set_cipher_suite([[maybe_unused]] std::string const &cipher_sui
188188
#endif
189189
}
190190

191+
bool
192+
TLSBasicSupport::set_groups_list(std::string const &groups_list)
193+
{
194+
auto ssl = this->_get_ssl_object();
195+
return SSL_set1_groups_list(ssl, groups_list.c_str());
196+
}
197+
191198
int
192199
TLSBasicSupport::verify_certificate(X509_STORE_CTX *ctx)
193200
{

src/iocore/net/YamlSNIConfig.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,9 @@ YamlSNIConfig::Item::populate_sni_actions(action_vector_t &actions)
161161
if (!server_TLSv1_3_cipher_suites.empty()) {
162162
actions.push_back(std::make_unique<ServerTLSv1_3CipherSuites>(server_TLSv1_3_cipher_suites));
163163
}
164+
if (!server_groups_list.empty()) {
165+
actions.push_back(std::make_unique<ServerGroupsList>(server_groups_list));
166+
}
164167
if (http2_buffer_water_mark.has_value()) {
165168
actions.push_back(std::make_unique<HTTP2BufferWaterMark>(http2_buffer_water_mark.value()));
166169
}
@@ -226,6 +229,7 @@ std::set<std::string> valid_sni_config_keys = {TS_fqdn,
226229
#if TS_USE_TLS_SET_CIPHERSUITES
227230
TS_server_TLSv1_3_cipher_suites,
228231
#endif
232+
TS_server_groups_list,
229233
TS_http2,
230234
TS_http2_buffer_water_mark,
231235
TS_http2_initial_window_size_in,
@@ -458,7 +462,9 @@ template <> struct convert<YamlSNIConfig::Item> {
458462
if (node[TS_server_TLSv1_3_cipher_suites]) {
459463
item.server_TLSv1_3_cipher_suites = node[TS_server_TLSv1_3_cipher_suites].as<std::string>();
460464
}
461-
465+
if (node[TS_server_groups_list]) {
466+
item.server_groups_list = node[TS_server_groups_list].as<std::string>();
467+
}
462468
if (node[TS_ip_allow]) {
463469
item.ip_allow = node[TS_ip_allow].as<std::string>();
464470
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
'''
2+
'''
3+
# Licensed to the Apache Software Foundation (ASF) under one
4+
# or more contributor license agreements. See the NOTICE file
5+
# distributed with this work for additional information
6+
# regarding copyright ownership. The ASF licenses this file
7+
# to you under the Apache License, Version 2.0 (the
8+
# "License"); you may not use this file except in compliance
9+
# with the License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS,
15+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
# See the License for the specific language governing permissions and
17+
# limitations under the License.
18+
19+
Test.Summary = '''
20+
Test SNI configuration server_groups_list
21+
'''
22+
# The groups function was added in OpenSSL 1.1.1
23+
Test.SkipUnless(Condition.HasOpenSSLVersion("1.1.1"))
24+
25+
# Define default ATS
26+
ts = Test.MakeATSProcess("ts", enable_tls=True)
27+
server = Test.MakeOriginServer("server", ssl=True)
28+
29+
request_header = {"headers": "GET / HTTP/1.1\r\n\r\n", "timestamp": "1469733493.993", "body": ""}
30+
response_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", "timestamp": "1469733493.993", "body": "foo ok"}
31+
server.addResponse("sessionlog.json", request_header, response_header)
32+
33+
# add ssl materials like key, certificates for the server
34+
ts.addSSLfile("ssl/server.pem")
35+
ts.addSSLfile("ssl/server.key")
36+
37+
# Need no remap rules. Everything should be processed by sni
38+
39+
# Make sure the TS server certs are different from the origin certs
40+
ts.Disk.ssl_multicert_config.AddLine('dest_ip=* ssl_cert_name=server.pem ssl_key_name=server.key')
41+
42+
ts.Disk.records_config.update(
43+
{
44+
'proxy.config.ssl.server.cert.path': '{0}'.format(ts.Variables.SSLDir),
45+
'proxy.config.ssl.server.private_key.path': '{0}'.format(ts.Variables.SSLDir),
46+
'proxy.config.ssl.client.CA.cert.path': '{0}'.format(ts.Variables.SSLDir),
47+
'proxy.config.diags.debug.enabled': 1,
48+
'proxy.config.diags.debug.tags': 'ssl_sni',
49+
})
50+
51+
ts.Disk.sni_yaml.AddLines(
52+
[
53+
'sni:',
54+
'- fqdn: aaa.com',
55+
' server_groups_list: X25519MLKEM768',
56+
' valid_tls_versions_in: [ TLSv1_3 ]',
57+
' server_TLSv1_3_cipher_suites: TLS_AES_256_GCM_SHA384',
58+
'- fqdn: bbb.com',
59+
' server_groups_list: x25519',
60+
' valid_tls_versions_in: [ TLSv1_2 ]',
61+
' server_cipher_suite: ECDHE-RSA-AES256-GCM-SHA384',
62+
'- fqdn: ccc.com',
63+
' server_groups_list: ABC123',
64+
' valid_tls_versions_in: [ TLSv1_2 ]',
65+
' server_cipher_suite: ECDHE-RSA-AES256-GCM-SHA384',
66+
])
67+
68+
tr = Test.AddTestRun("Test 0: x25519")
69+
tr.Processes.Default.StartBefore(server)
70+
tr.Processes.Default.StartBefore(Test.Processes.ts)
71+
tr.MakeCurlCommand(
72+
"-v --ciphers ECDHE-RSA-AES256-GCM-SHA384 --resolve 'bbb.com:{0}:127.0.0.1' -k https://bbb.com:{0}".format(
73+
ts.Variables.ssl_port))
74+
tr.ReturnCode = 0
75+
tr.StillRunningAfter = ts
76+
ts.Disk.traffic_out.Content += Testers.ContainsExpression(
77+
"Setting groups list from server_groups_list to x25519", "Should log setting the server groups")
78+
tr.Processes.Default.Streams.all = Testers.IncludesExpression(
79+
f"SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384 / x25519", "Curl should log using x25519 in the SSL connection")
80+
81+
tr = Test.AddTestRun("Test 1: fail")
82+
tr.MakeCurlCommand(
83+
"-v --ciphers ECDHE-RSA-AES256-GCM-SHA384 --resolve 'ccc.com:{0}:127.0.0.1' -k https://ccc.com:{0}".format(
84+
ts.Variables.ssl_port))
85+
# The error code is 35, which indicates there was a ssl connection error
86+
tr.ReturnCode = 35
87+
tr.StillRunningAfter = ts
88+
tr.StillRunningAfter = server
89+
ts.Disk.diags_log.Content = Testers.ContainsExpression(
90+
"ERROR: Invalid server_groups_list: ABC123", "Curl attempt should have failed")
91+
92+
# Hybrid ECDH PQ key exchange TLS groups were added in OpenSSL 3.5
93+
if Condition.HasOpenSSLVersion("3.5.0"):
94+
tr = Test.AddTestRun("Test 2: X25519MLKEM768")
95+
tr.MakeCurlCommand(
96+
"-v --tls13-ciphers TLS_AES_256_GCM_SHA384 --resolve 'aaa.com:{0}:127.0.0.1' -k https://aaa.com:{0}".format(
97+
ts.Variables.ssl_port))
98+
tr.ReturnCode = 0
99+
tr.StillRunningAfter = ts
100+
ts.Disk.traffic_out.Content += Testers.ContainsExpression(
101+
"Setting groups list from server_groups_list to X25519MLKEM768", "Should log setting the server groups")
102+
tr.Processes.Default.Streams.all = Testers.IncludesExpression(
103+
f"SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519MLKEM768",
104+
f"Curl should log using X25519MLKEM768 in the SSL connection")

0 commit comments

Comments
 (0)