Skip to content

Commit 63ede0d

Browse files
committed
Add test for minimum TLS version
1 parent 300e8b4 commit 63ede0d

File tree

4 files changed

+112
-26
lines changed

4 files changed

+112
-26
lines changed
Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
"""
2-
Setup local TLS server for tests
2+
Setup local TLS servers for tests
33
"""
44

55
import Builder
66

7-
import os
7+
from pathlib import Path
88
import sys
99
import subprocess
1010
import atexit
11-
import time
1211

1312

1413
class TlsServerSetup(Builder.Action):
@@ -18,26 +17,47 @@ class TlsServerSetup(Builder.Action):
1817
This action should be run in the 'pre_build_steps' or 'build_steps' stage.
1918
"""
2019

20+
@staticmethod
21+
def cleanup_tls_server(tls_server_process):
22+
tls_server_process.terminate()
23+
out, err = tls_server_process.communicate()
24+
print("TLS server stdout:")
25+
for line in out.splitlines():
26+
print(f" = {line.decode('utf-8')}")
27+
print("TLS server stderr:")
28+
for line in err.splitlines():
29+
print(f" = {line.decode('utf-8')}")
30+
2131
def run(self, env):
2232
if not env.project.needs_tests(env):
2333
print("Skipping TLS server setup because tests disabled for project")
2434
return
2535

2636
self.env = env
2737

28-
base_dir = os.path.dirname(os.path.realpath(__file__))
29-
dir = os.path.join(base_dir, "..", "..", "tests", "tls_server")
38+
root_dir = Path(__file__).resolve().parent / '..' / '..'
39+
tls_server_dir = root_dir / 'tests' / 'tls_server'
40+
resource_dir = root_dir / 'tests' / 'resources'
3041

31-
print("Running openssl TLS server")
42+
print("Running TLS servers")
3243

3344
python_path = sys.executable
34-
p = subprocess.Popen([python_path, "tls_server.py",
35-
], cwd=dir, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
45+
46+
tls12_server_process = subprocess.Popen(
47+
[python_path, tls_server_dir / 'tls_server.py', '--port', '58443', '--resource-dir', resource_dir,
48+
'--min-tls', '1.2',
49+
'--max-tls', '1.2'],
50+
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
51+
52+
tls13_server_process = subprocess.Popen(
53+
[python_path, tls_server_dir / 'tls_server.py', '--port', '59443', '--resource-dir', resource_dir,
54+
'--min-tls', '1.3',
55+
'--max-tls', '1.3'],
56+
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
3657

3758
@atexit.register
38-
def close_tls_server():
39-
print("Terminating openssl TLS server")
40-
p.terminate()
41-
out, err = p.communicate()
42-
print("TLS server stdout:\n{}".format(out))
43-
print("TLS server stderr:\n{}".format(err))
59+
def close_tls_servers():
60+
print('Terminating TLS 1.2 server')
61+
TlsServerSetup.cleanup_tls_server(tls12_server_process)
62+
print('Terminating TLS 1.3 server')
63+
TlsServerSetup.cleanup_tls_server(tls13_server_process)

tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ if(NOT BYO_CRYPTO)
230230
add_net_test_case(tls_client_channel_negotiation_error_broken_crypto_dh480)
231231
add_net_test_case(tls_client_channel_negotiation_error_broken_crypto_dh512)
232232
add_net_test_case(tls_client_channel_negotiation_error_broken_crypto_null)
233+
add_net_test_case(tls_client_channel_negotiation_error_tls1_3_to_tls1_2_server)
233234

234235
# Badssl - Legacy crypto suite, includes both negative and positive tests, with override checks where appropriate
235236
# Our current baseline/default is platform-specific, whereas badssl expects a baseline of 1.2

tests/tls_handler_test.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,10 @@ static void s_raise_tls_version_to_12(struct aws_tls_ctx_options *options) {
12251225
aws_tls_ctx_options_set_minimum_tls_version(options, AWS_IO_TLSv1_2);
12261226
}
12271227

1228+
static void s_raise_tls_version_to_13(struct aws_tls_ctx_options *options) {
1229+
aws_tls_ctx_options_set_minimum_tls_version(options, AWS_IO_TLSv1_3);
1230+
}
1231+
12281232
static int s_tls_client_channel_negotiation_error_override_legacy_crypto_tls11_fn(
12291233
struct aws_allocator *allocator,
12301234
void *ctx) {
@@ -1334,6 +1338,21 @@ AWS_TEST_CASE(
13341338
tls_client_channel_negotiation_error_socket_closed,
13351339
s_tls_client_channel_negotiation_error_socket_closed_fn);
13361340

1341+
AWS_STATIC_STRING_FROM_LITERAL(s_aws_local_tls_server_host_name, "127.0.0.1");
1342+
1343+
static int s_tls_client_channel_negotiation_error_tls1_3_to_tls1_2_server_fn(
1344+
struct aws_allocator *allocator,
1345+
void *ctx) {
1346+
(void)ctx;
1347+
uint32_t server_tls1_2_port = 58443;
1348+
return s_verify_negotiation_fails(
1349+
allocator, s_aws_local_tls_server_host_name, server_tls1_2_port, &s_raise_tls_version_to_13);
1350+
}
1351+
1352+
AWS_TEST_CASE(
1353+
tls_client_channel_negotiation_error_tls1_3_to_tls1_2_server,
1354+
s_tls_client_channel_negotiation_error_tls1_3_to_tls1_2_server_fn)
1355+
13371356
static int s_verify_good_host(
13381357
struct aws_allocator *allocator,
13391358
const struct aws_string *host_name,
@@ -1623,14 +1642,12 @@ AWS_TEST_CASE(
16231642
s_tls_client_channel_negotiation_success_ecc384_SCHANNEL_CREDS_fn)
16241643
# endif
16251644

1626-
static void s_raise_tls_version_to_13(struct aws_tls_ctx_options *options) {
1627-
aws_tls_ctx_options_set_minimum_tls_version(options, AWS_IO_TLSv1_3);
1628-
}
1629-
16301645
AWS_STATIC_STRING_FROM_LITERAL(s_aws_ecc384_host_name, "127.0.0.1");
16311646
static int s_tls_client_channel_negotiation_success_mtls_tls1_3_fn(struct aws_allocator *allocator, void *ctx) {
16321647
(void)ctx;
1633-
return s_verify_good_host_mqtt_connect(allocator, s_aws_ecc384_host_name, 59443, s_raise_tls_version_to_13);
1648+
uint32_t server_tls1_3_port = 59443;
1649+
return s_verify_good_host_mqtt_connect(
1650+
allocator, s_aws_ecc384_host_name, server_tls1_3_port, s_raise_tls_version_to_13);
16341651
}
16351652

16361653
AWS_TEST_CASE(

tests/tls_server/tls_server.py

Lines changed: 55 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,71 @@
11
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
# SPDX-License-Identifier: Apache-2.0.
33

4+
import argparse
5+
import pathlib
6+
import signal
47
import socket
58
import ssl
9+
import sys
10+
11+
12+
def parse_tls(tls_str):
13+
if tls_str == '1.1':
14+
return ssl.TLSVersion.TLSv1_1
15+
elif tls_str == '1.2':
16+
return ssl.TLSVersion.TLSv1_2
17+
elif tls_str == '1.3':
18+
return ssl.TLSVersion.TLSv1_3
19+
raise ValueError('Unknown TLS version')
20+
21+
22+
print(f"Starting TLS server")
23+
24+
parser = argparse.ArgumentParser(
25+
description="TLS test server",
26+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
27+
)
28+
29+
optional = parser.add_argument_group("optional arguments")
30+
31+
optional.add_argument("--host", dest="host", default="127.0.0.1", help="Listening host")
32+
optional.add_argument("--port", type=int, dest="port", default=59443, help="Listening port")
33+
optional.add_argument("--min-tls", choices=['1.1', '1.2', '1.3'], dest="min_tls", default='1.2',
34+
help="Minimum acceptable TLS version")
35+
optional.add_argument("--max-tls", choices=['1.1', '1.2', '1.3'], dest="max_tls", default='1.3',
36+
help="Maximum acceptable TLS version")
37+
optional.add_argument("--resource-dir", type=pathlib.Path, dest="resource_dir", default='./tests/resources/',
38+
help="Path to keys and certificates")
39+
40+
args = parser.parse_args()
641

742
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
8-
context.minimum_version = ssl.TLSVersion.TLSv1_3
9-
context.maximum_version = ssl.TLSVersion.TLSv1_3
10-
context.load_cert_chain('../resources/tls13_server.pem.crt', '../resources/tls13_server.key')
11-
context.load_verify_locations('../resources/tls13_device_root_ca.pem.crt')
43+
context.minimum_version = parse_tls(args.min_tls)
44+
context.maximum_version = parse_tls(args.max_tls)
45+
context.load_cert_chain(args.resource_dir / 'tls13_server.pem.crt', args.resource_dir / 'tls13_server.key')
46+
context.load_verify_locations(args.resource_dir / 'tls13_device_root_ca.pem.crt')
1247
context.verify_mode = ssl.CERT_REQUIRED
1348

49+
50+
def signal_handler(signum, frame):
51+
sys.stdout.flush()
52+
sys.exit(0)
53+
54+
55+
signal.signal(signal.SIGTERM, signal_handler)
56+
57+
print(f"Running TLS server on {args.host}:{args.port}")
58+
print(f"Minimum TLS version: {context.minimum_version.name}")
59+
print(f"Maximum TLS version: {context.maximum_version.name}")
60+
1461
with socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) as sock:
15-
sock.bind(('127.0.0.1', 59443))
62+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
63+
sock.bind((args.host, args.port))
1664
sock.listen(1)
1765
with context.wrap_socket(sock, server_side=True) as ssock:
1866
while True:
1967
try:
2068
conn, addr = ssock.accept()
21-
print("accepted new connection: {}".format(addr))
69+
print("Accepted new connection: {}".format(addr))
2270
except Exception as e:
23-
print("accept failed: {}".format(e))
71+
print(f"Accept failed: {e}")

0 commit comments

Comments
 (0)