Skip to content

Commit 9fa5f6e

Browse files
jmayclinlrstewart
andauthored
test: add sslv2 client hello test w/ jvm (#5019)
Co-authored-by: Lindsay Stewart <[email protected]>
1 parent 4342e8a commit 9fa5f6e

File tree

5 files changed

+96
-10
lines changed

5 files changed

+96
-10
lines changed

codebuild/spec/buildspec_ubuntu_integrationv2.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ batch:
3636
- openssl-1.1.1_gcc9
3737
- openssl-3.0
3838
INTEGV2_TEST:
39-
- "test_dynamic_record_sizes test_sslyze"
39+
- "test_dynamic_record_sizes test_sslyze test_sslv2_client_hello"
4040

4141
env:
4242
variables:

tests/integrationv2/bin/SSLSocketClient.java

+13-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import java.security.cert.CertificateFactory;
22
import java.security.cert.X509Certificate;
3+
import java.util.Arrays;
34
import java.security.KeyStore;
45
import java.io.FileInputStream;
56
import java.io.OutputStream;
@@ -18,14 +19,18 @@ public class SSLSocketClient {
1819
public static void main(String[] args) throws Exception {
1920
int port = Integer.parseInt(args[0]);
2021
String certificatePath = args[1];
21-
String protocol = sslProtocols(args[2]);
22-
String[] protocolList = new String[] {protocol};
23-
String[] cipher = new String[] {args[3]};
22+
String[] cipher = new String[] {args[2]};
23+
// We assume that args[3] is the intended protocol to negotiate, like "TLS1.3"
24+
// or "TLS1.2". args[4] is optional, and if included its value must be "SSLv2Hello".
25+
String[] protocolList = Arrays.copyOfRange(args, 3, args.length);
26+
for (int i = 0; i < protocolList.length; i++) {
27+
protocolList[i] = sslProtocols(protocolList[i]);
28+
}
2429

2530
String host = "localhost";
2631
byte[] buffer = new byte[100];
2732

28-
SSLSocketFactory socketFactory = createSocketFactory(certificatePath, protocol);
33+
SSLSocketFactory socketFactory = createSocketFactory(certificatePath, protocolList[0]);
2934

3035
try (
3136
SSLSocket socket = (SSLSocket)socketFactory.createSocket(host, port);
@@ -92,8 +97,11 @@ public static String sslProtocols(String s2nProtocol) {
9297
return "TLSv1.1";
9398
case "TLS1.0":
9499
return "TLSv1.0";
100+
// This "protocol" forces the ClientHello message to use SSLv2 format.
101+
case "SSLv2Hello":
102+
return "SSLv2Hello";
95103
}
96104

97-
return null;
105+
throw new RuntimeException("unrecognized protocol version:" + s2nProtocol);
98106
}
99107
}

tests/integrationv2/common.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ class Protocols(object):
217217
TLS11 = Protocol("TLS1.1", 32)
218218
TLS10 = Protocol("TLS1.0", 31)
219219
SSLv3 = Protocol("SSLv3", 30)
220+
SSLv2 = Protocol("SSLv2", 20)
220221

221222

222223
class Cipher(object):
@@ -567,7 +568,7 @@ def __init__(
567568
# Boolean whether to use a resumption ticket
568569
self.use_session_ticket = use_session_ticket
569570

570-
# Boolean whether to allow insecure certificates
571+
# Boolean whether to disable x509 verification
571572
self.insecure = insecure
572573

573574
# Which protocol to use with this provider

tests/integrationv2/providers.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -600,12 +600,15 @@ def setup_client(self):
600600
cmd_line.extend([self.options.trust_store])
601601
elif self.options.cert:
602602
cmd_line.extend([self.options.cert])
603+
if self.options.cipher.iana_standard_name is not None:
604+
cmd_line.extend([self.options.cipher.iana_standard_name])
603605

604606
if self.options.protocol is not None:
605607
cmd_line.extend([self.options.protocol.name])
606-
607-
if self.options.cipher.iana_standard_name is not None:
608-
cmd_line.extend([self.options.cipher.iana_standard_name])
608+
# SSLv2ClientHello is a "protocol" for Java TLS, so we append it next to
609+
# the existing protocol.
610+
if self.options.extra_flags is not None:
611+
cmd_line.extend(self.options.extra_flags)
609612

610613
# Clients are always ready to connect
611614
self.set_provider_ready()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
import copy
4+
5+
from configuration import available_ports
6+
from common import Certificates, Ciphers, Protocols, ProviderOptions, data_bytes
7+
from fixtures import managed_process # lgtm [py/unused-import]
8+
from providers import Provider, S2N, JavaSSL
9+
from utils import (
10+
to_bytes,
11+
)
12+
13+
14+
def test_s2n_server_sslv2_client_hello(managed_process):
15+
# TLS 1.3: not supported by SSLv2 ClientHellos
16+
# TLS 1.2: supported
17+
# TLS 1.0 - TLS 1.1: not supported by Java
18+
TEST_PROTOCOL = Protocols.TLS12
19+
20+
port = next(available_ports)
21+
22+
# s2nd can receive large amounts of data because all the data is
23+
# echo'd to stdout unmodified. This lets us compare received to
24+
# expected easily.
25+
# We purposefully send a non block aligned number to make sure
26+
# nothing blocks waiting for more data.
27+
random_bytes = data_bytes(65519)
28+
29+
certificate = Certificates.RSA_2048_SHA256
30+
31+
client_options = ProviderOptions(
32+
mode=Provider.ClientMode,
33+
port=port,
34+
# The cipher must use RSA key exchange. ECDHE is not supported with
35+
# SSLv2 formatted client hellos.
36+
cipher=Ciphers.AES256_SHA256,
37+
cert=certificate.cert,
38+
data_to_send=random_bytes,
39+
insecure=True,
40+
protocol=TEST_PROTOCOL,
41+
extra_flags=["SSLv2Hello"],
42+
)
43+
44+
server_options = copy.copy(client_options)
45+
server_options.mode = Provider.ServerMode
46+
server_options.data_to_send = None
47+
server_options.key = certificate.key
48+
server_options.cert = certificate.cert
49+
server_options.extra_flags = None
50+
51+
# Passing the type of client and server as a parameter will
52+
# allow us to use a fixture to enumerate all possibilities.
53+
server = managed_process(S2N, server_options, timeout=5)
54+
client = managed_process(JavaSSL, client_options, timeout=5)
55+
56+
# The client will be one of all supported providers. We
57+
# just want to make sure there was no exception and that
58+
# the client exited cleanly.
59+
for client_results in client.get_results():
60+
client_results.assert_success()
61+
62+
# The server is always S2N in this test, so we can examine
63+
# the stdout reliably.
64+
for server_results in server.get_results():
65+
server_results.assert_success()
66+
assert (
67+
to_bytes(f"Client hello version: {Protocols.SSLv2.value}")
68+
in server_results.stdout
69+
)
70+
assert (
71+
to_bytes(f"Actual protocol version: {TEST_PROTOCOL.value}")
72+
in server_results.stdout
73+
)
74+
assert random_bytes in server_results.stdout

0 commit comments

Comments
 (0)