Skip to content

Commit

Permalink
test: add sslv2 client hello test w/ jvm (aws#5019)
Browse files Browse the repository at this point in the history
Co-authored-by: Lindsay Stewart <stewart.r.lindsay@gmail.com>
  • Loading branch information
2 people authored and johubertj committed Feb 13, 2025
1 parent 81b7e67 commit d554d8c
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 10 deletions.
2 changes: 1 addition & 1 deletion codebuild/spec/buildspec_ubuntu_integrationv2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ batch:
- openssl-1.1.1_gcc9
- openssl-3.0
INTEGV2_TEST:
- "test_dynamic_record_sizes test_sslyze"
- "test_dynamic_record_sizes test_sslyze test_sslv2_client_hello"

env:
variables:
Expand Down
18 changes: 13 additions & 5 deletions tests/integrationv2/bin/SSLSocketClient.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.security.KeyStore;
import java.io.FileInputStream;
import java.io.OutputStream;
Expand All @@ -18,14 +19,18 @@ public class SSLSocketClient {
public static void main(String[] args) throws Exception {
int port = Integer.parseInt(args[0]);
String certificatePath = args[1];
String protocol = sslProtocols(args[2]);
String[] protocolList = new String[] {protocol};
String[] cipher = new String[] {args[3]};
String[] cipher = new String[] {args[2]};
// We assume that args[3] is the intended protocol to negotiate, like "TLS1.3"
// or "TLS1.2". args[4] is optional, and if included its value must be "SSLv2Hello".
String[] protocolList = Arrays.copyOfRange(args, 3, args.length);
for (int i = 0; i < protocolList.length; i++) {
protocolList[i] = sslProtocols(protocolList[i]);
}

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

SSLSocketFactory socketFactory = createSocketFactory(certificatePath, protocol);
SSLSocketFactory socketFactory = createSocketFactory(certificatePath, protocolList[0]);

try (
SSLSocket socket = (SSLSocket)socketFactory.createSocket(host, port);
Expand Down Expand Up @@ -92,8 +97,11 @@ public static String sslProtocols(String s2nProtocol) {
return "TLSv1.1";
case "TLS1.0":
return "TLSv1.0";
// This "protocol" forces the ClientHello message to use SSLv2 format.
case "SSLv2Hello":
return "SSLv2Hello";
}

return null;
throw new RuntimeException("unrecognized protocol version:" + s2nProtocol);
}
}
3 changes: 2 additions & 1 deletion tests/integrationv2/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ class Protocols(object):
TLS11 = Protocol("TLS1.1", 32)
TLS10 = Protocol("TLS1.0", 31)
SSLv3 = Protocol("SSLv3", 30)
SSLv2 = Protocol("SSLv2", 20)


class Cipher(object):
Expand Down Expand Up @@ -567,7 +568,7 @@ def __init__(
# Boolean whether to use a resumption ticket
self.use_session_ticket = use_session_ticket

# Boolean whether to allow insecure certificates
# Boolean whether to disable x509 verification
self.insecure = insecure

# Which protocol to use with this provider
Expand Down
9 changes: 6 additions & 3 deletions tests/integrationv2/providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -619,12 +619,15 @@ def setup_client(self):
cmd_line.extend([self.options.trust_store])
elif self.options.cert:
cmd_line.extend([self.options.cert])
if self.options.cipher.iana_standard_name is not None:
cmd_line.extend([self.options.cipher.iana_standard_name])

if self.options.protocol is not None:
cmd_line.extend([self.options.protocol.name])

if self.options.cipher.iana_standard_name is not None:
cmd_line.extend([self.options.cipher.iana_standard_name])
# SSLv2ClientHello is a "protocol" for Java TLS, so we append it next to
# the existing protocol.
if self.options.extra_flags is not None:
cmd_line.extend(self.options.extra_flags)

# Clients are always ready to connect
self.set_provider_ready()
Expand Down
74 changes: 74 additions & 0 deletions tests/integrationv2/test_sslv2_client_hello.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
import copy

from configuration import available_ports
from common import Certificates, Ciphers, Protocols, ProviderOptions, data_bytes
from fixtures import managed_process # lgtm [py/unused-import]
from providers import Provider, S2N, JavaSSL
from utils import (
to_bytes,
)


def test_s2n_server_sslv2_client_hello(managed_process):
# TLS 1.3: not supported by SSLv2 ClientHellos
# TLS 1.2: supported
# TLS 1.0 - TLS 1.1: not supported by Java
TEST_PROTOCOL = Protocols.TLS12

port = next(available_ports)

# s2nd can receive large amounts of data because all the data is
# echo'd to stdout unmodified. This lets us compare received to
# expected easily.
# We purposefully send a non block aligned number to make sure
# nothing blocks waiting for more data.
random_bytes = data_bytes(65519)

certificate = Certificates.RSA_2048_SHA256

client_options = ProviderOptions(
mode=Provider.ClientMode,
port=port,
# The cipher must use RSA key exchange. ECDHE is not supported with
# SSLv2 formatted client hellos.
cipher=Ciphers.AES256_SHA256,
cert=certificate.cert,
data_to_send=random_bytes,
insecure=True,
protocol=TEST_PROTOCOL,
extra_flags=["SSLv2Hello"],
)

server_options = copy.copy(client_options)
server_options.mode = Provider.ServerMode
server_options.data_to_send = None
server_options.key = certificate.key
server_options.cert = certificate.cert
server_options.extra_flags = None

# Passing the type of client and server as a parameter will
# allow us to use a fixture to enumerate all possibilities.
server = managed_process(S2N, server_options, timeout=5)
client = managed_process(JavaSSL, client_options, timeout=5)

# The client will be one of all supported providers. We
# just want to make sure there was no exception and that
# the client exited cleanly.
for client_results in client.get_results():
client_results.assert_success()

# The server is always S2N in this test, so we can examine
# the stdout reliably.
for server_results in server.get_results():
server_results.assert_success()
assert (
to_bytes(f"Client hello version: {Protocols.SSLv2.value}")
in server_results.stdout
)
assert (
to_bytes(f"Actual protocol version: {TEST_PROTOCOL.value}")
in server_results.stdout
)
assert random_bytes in server_results.stdout

0 comments on commit d554d8c

Please sign in to comment.