Skip to content

Commit 8def184

Browse files
authored
Check Curl support for TLS 1.0 and 1.1 (#12887)
Skip TLSv1/TLSv1.1 subtests when curl cannot negotiate those protocols. Adds a curl-based capability probe alongside the existing OpenSSL check.
1 parent 6112a78 commit 8def184

3 files changed

Lines changed: 105 additions & 35 deletions

File tree

tests/gold_tests/autest-site/conditions.test.ext

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,67 @@ def HasCurlOption(self, option):
146146
return self.CheckOutput(['curl', '--help', 'all'], default, "Curl needs to support option: {option}".format(option=option))
147147

148148

149+
def HasCurlTLSVersionSupport(self, tls_version):
150+
"""Check whether curl can attempt a given TLS version.
151+
152+
This probes curl directly because OpenSSL capability checks do not always
153+
reflect curl runtime policy behavior on hardened systems.
154+
"""
155+
156+
def check_curl_tls_support():
157+
# Map semantic versions used by tests to curl flags.
158+
version_map = {
159+
"1.0": ("--tlsv1", "1.0"),
160+
"1.1": ("--tlsv1.1", "1.1"),
161+
"1.2": ("--tlsv1.2", "1.2"),
162+
"1.3": ("--tlsv1.3", "1.3"),
163+
}
164+
if tls_version not in version_map:
165+
return False
166+
167+
tls_flag, tls_max = version_map[tls_version]
168+
try:
169+
# Connect to localhost closed port to avoid network dependencies.
170+
# "connection refused" means curl accepted the TLS flags and tried.
171+
result = subprocess.run(
172+
[
173+
"curl",
174+
"-svk",
175+
"--connect-timeout",
176+
"2",
177+
"--max-time",
178+
"3",
179+
tls_flag,
180+
"--tls-max",
181+
tls_max,
182+
"https://127.0.0.1:1",
183+
],
184+
capture_output=True,
185+
text=True,
186+
timeout=5,
187+
)
188+
output = (result.stdout + result.stderr).lower()
189+
unsupported_markers = [
190+
"unsupported protocol",
191+
"no protocols available",
192+
"option --tlsv",
193+
"unknown option",
194+
"is unknown",
195+
]
196+
if any(marker in output for marker in unsupported_markers):
197+
return False
198+
199+
# Any attempt to connect implies curl accepted the TLS setting.
200+
return True
201+
except subprocess.TimeoutExpired:
202+
return False
203+
except Exception:
204+
return False
205+
206+
return self.Condition(
207+
check_curl_tls_support, "Curl does not support TLSv{version} in this environment".format(version=tls_version))
208+
209+
149210
def HasATSFeature(self, feature):
150211

151212
val = self.Variables.get(feature, None)
@@ -175,5 +236,6 @@ ExtendCondition(HasATSFeature)
175236
ExtendCondition(HasCurlVersion)
176237
ExtendCondition(HasCurlFeature)
177238
ExtendCondition(HasCurlOption)
239+
ExtendCondition(HasCurlTLSVersionSupport)
178240
ExtendCondition(PluginExists)
179241
ExtendCondition(CurlUsingUnixDomainSocket)

tests/gold_tests/tls/tls_client_versions.test.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
Test.SkipUnless(Condition.HasOpenSSLVersion("1.1.1"))
2727
Test.SkipUnless(Condition.HasLegacyTLSSupport())
28+
has_curl_tlsv1 = Condition.HasCurlTLSVersionSupport("1.0")
2829

2930
# Define default ATS
3031
ts = Test.MakeATSProcess("ts", enable_tls=True)
@@ -85,22 +86,24 @@
8586
tr.StillRunningAfter = ts
8687

8788
# Target foo.com for TLSv1. Should succeed
88-
tr = Test.AddTestRun("foo.com TLSv1")
89-
tr.MakeCurlCommand(
90-
"-v --ciphers DEFAULT@SECLEVEL=0 --tls-max 1.0 --tlsv1 --resolve 'foo.com:{0}:127.0.0.1' -k https://foo.com:{0}".format(
91-
ts.Variables.ssl_port),
92-
ts=ts)
93-
tr.ReturnCode = 0
94-
tr.StillRunningAfter = ts
89+
if has_curl_tlsv1:
90+
tr = Test.AddTestRun("foo.com TLSv1")
91+
tr.MakeCurlCommand(
92+
"-v --ciphers DEFAULT@SECLEVEL=0 --tls-max 1.0 --tlsv1 --resolve 'foo.com:{0}:127.0.0.1' -k https://foo.com:{0}".format(
93+
ts.Variables.ssl_port),
94+
ts=ts)
95+
tr.ReturnCode = 0
96+
tr.StillRunningAfter = ts
9597

9698
# Target bar.com for TLSv1. Should fail
97-
tr = Test.AddTestRun("bar.com TLSv1")
98-
tr.MakeCurlCommand(
99-
"-v --ciphers DEFAULT@SECLEVEL=0 --tls-max 1.0 --tlsv1 --resolve 'bar.com:{0}:127.0.0.1' -k https://bar.com:{0}".format(
100-
ts.Variables.ssl_port),
101-
ts=ts)
102-
tr.ReturnCode = 35
103-
tr.StillRunningAfter = ts
99+
if has_curl_tlsv1:
100+
tr = Test.AddTestRun("bar.com TLSv1")
101+
tr.MakeCurlCommand(
102+
"-v --ciphers DEFAULT@SECLEVEL=0 --tls-max 1.0 --tlsv1 --resolve 'bar.com:{0}:127.0.0.1' -k https://bar.com:{0}".format(
103+
ts.Variables.ssl_port),
104+
ts=ts)
105+
tr.ReturnCode = 35
106+
tr.StillRunningAfter = ts
104107

105108
# Target bar.com for TLSv1_2. Should succeed
106109
tr = Test.AddTestRun("bar.com TLSv1_2")

tests/gold_tests/tls/tls_client_versions_minmax.test.py

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525

2626
Test.SkipUnless(Condition.HasOpenSSLVersion("1.1.1"))
2727
Test.SkipUnless(Condition.HasLegacyTLSSupport())
28+
has_curl_tlsv1 = Condition.HasCurlTLSVersionSupport("1.0")
29+
has_curl_tlsv1_1 = Condition.HasCurlTLSVersionSupport("1.1")
2830

2931
# Define default ATS
3032
ts = Test.MakeATSProcess("ts", enable_tls=True)
@@ -90,31 +92,34 @@
9092
tr.StillRunningAfter = ts
9193

9294
# Target foo.com for TLSv1. Should succeed
93-
tr = Test.AddTestRun("foo.com TLSv1")
94-
tr.MakeCurlCommand(
95-
"-v --ciphers DEFAULT@SECLEVEL=0 --tls-max 1.0 --tlsv1 --resolve 'foo.com:{0}:127.0.0.1' -k https://foo.com:{0}".format(
96-
ts.Variables.ssl_port),
97-
ts=ts)
98-
tr.ReturnCode = 0
99-
tr.StillRunningAfter = ts
95+
if has_curl_tlsv1:
96+
tr = Test.AddTestRun("foo.com TLSv1")
97+
tr.MakeCurlCommand(
98+
"-v --ciphers DEFAULT@SECLEVEL=0 --tls-max 1.0 --tlsv1 --resolve 'foo.com:{0}:127.0.0.1' -k https://foo.com:{0}".format(
99+
ts.Variables.ssl_port),
100+
ts=ts)
101+
tr.ReturnCode = 0
102+
tr.StillRunningAfter = ts
100103

101104
# Target foo.com for TLSv1_1. Should succeed
102-
tr = Test.AddTestRun("foo.com TLSv1_1")
103-
tr.MakeCurlCommand(
104-
"-v --ciphers DEFAULT@SECLEVEL=0 --tls-max 1.1 --tlsv1.1 --resolve 'foo.com:{0}:127.0.0.1' -k https://foo.com:{0}".format(
105-
ts.Variables.ssl_port),
106-
ts=ts)
107-
tr.ReturnCode = 0
108-
tr.StillRunningAfter = ts
105+
if has_curl_tlsv1_1:
106+
tr = Test.AddTestRun("foo.com TLSv1_1")
107+
tr.MakeCurlCommand(
108+
"-v --ciphers DEFAULT@SECLEVEL=0 --tls-max 1.1 --tlsv1.1 --resolve 'foo.com:{0}:127.0.0.1' -k https://foo.com:{0}".format(
109+
ts.Variables.ssl_port),
110+
ts=ts)
111+
tr.ReturnCode = 0
112+
tr.StillRunningAfter = ts
109113

110114
# Target bar.com for TLSv1. Should fail
111-
tr = Test.AddTestRun("bar.com TLSv1")
112-
tr.MakeCurlCommand(
113-
"-v --ciphers DEFAULT@SECLEVEL=0 --tls-max 1.0 --tlsv1 --resolve 'bar.com:{0}:127.0.0.1' -k https://bar.com:{0}".format(
114-
ts.Variables.ssl_port),
115-
ts=ts)
116-
tr.ReturnCode = 35
117-
tr.StillRunningAfter = ts
115+
if has_curl_tlsv1:
116+
tr = Test.AddTestRun("bar.com TLSv1")
117+
tr.MakeCurlCommand(
118+
"-v --ciphers DEFAULT@SECLEVEL=0 --tls-max 1.0 --tlsv1 --resolve 'bar.com:{0}:127.0.0.1' -k https://bar.com:{0}".format(
119+
ts.Variables.ssl_port),
120+
ts=ts)
121+
tr.ReturnCode = 35
122+
tr.StillRunningAfter = ts
118123

119124
# Target bar.com for TLSv1_2. Should succeed
120125
tr = Test.AddTestRun("bar.com TLSv1_2")

0 commit comments

Comments
 (0)