Skip to content

Commit

Permalink
Add PQ integration tests between s2n and AWS-LC's libssl (#4267)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexw91 authored Jan 2, 2024
1 parent 2392bb9 commit 458a29d
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 3 deletions.
1 change: 1 addition & 0 deletions codebuild/bin/install_default_dependencies.sh
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ fi
if [[ "$S2N_LIBCRYPTO" == "awslc" && ! -d "$AWSLC_INSTALL_DIR" ]]; then
codebuild/bin/install_awslc.sh "$(mktemp -d)" "$AWSLC_INSTALL_DIR" "0" > /dev/null ;
fi

if [[ "$S2N_LIBCRYPTO" == "awslc-fips" && ! -d "$AWSLC_FIPS_INSTALL_DIR" ]]; then
codebuild/bin/install_awslc.sh "$(mktemp -d)" "$AWSLC_FIPS_INSTALL_DIR" "1" > /dev/null ;
fi
Expand Down
17 changes: 17 additions & 0 deletions tests/integrationv2/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,21 @@ class Curves(object):
P256 = Curve("P-256")
P384 = Curve("P-384")
P521 = Curve("P-521")
SecP256r1Kyber768Draft00 = Curve("SecP256r1Kyber768Draft00")
X25519Kyber768Draft00 = Curve("X25519Kyber768Draft00")

@staticmethod
def from_name(name):
curves = [
curve for attr in vars(Curves)
if not callable(curve := getattr(Curves, attr))
and not attr.startswith("_")
and curve.name
]
return {
curve.name: curve
for curve in curves
}.get(name)


class KemGroup(object):
Expand All @@ -369,6 +384,8 @@ class KemGroups(object):
P256_KYBER512R3 = KemGroup("p256_kyber512")
P384_KYBER768R3 = KemGroup("p384_kyber768")
P521_KYBER1024R3 = KemGroup("p521_kyber1024")
SecP256r1Kyber768Draft00 = KemGroup("SecP256r1Kyber768Draft00")
X25519Kyber768Draft00 = KemGroup("X25519Kyber768Draft00")


class Signature(object):
Expand Down
33 changes: 32 additions & 1 deletion tests/integrationv2/providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -677,7 +677,31 @@ def get_send_marker(cls):
return 'Cert issuer:'

def setup_server(self):
pytest.skip('BoringSSL does not support server mode at this time')
cmd_line = ['bssl', 's_server']
cmd_line.extend(['-accept', self.options.port])
if self.options.cert is not None:
cmd_line.extend(['-cert', self.options.cert])
if self.options.key is not None:
cmd_line.extend(['-key', self.options.key])
if self.options.curve is not None:
if self.options.curve == Curves.P256:
cmd_line.extend(['-curves', 'P-256'])
elif self.options.curve == Curves.P384:
cmd_line.extend(['-curves', 'P-384'])
elif self.options.curve == Curves.P521:
cmd_line.extend(['-curves', 'P-521'])
elif self.options.curve == Curves.SecP256r1Kyber768Draft00:
cmd_line.extend(['-curves', 'SecP256r1Kyber768Draft00'])
elif self.options.curve == Curves.X25519Kyber768Draft00:
cmd_line.extend(['-curves', 'X25519Kyber768Draft00'])
elif self.options.curve == Curves.X25519:
pytest.skip('BoringSSL does not support curve {}'.format(
self.options.curve))

if self.options.extra_flags is not None:
cmd_line.extend(self.options.extra_flags)

return cmd_line

def setup_client(self):
cmd_line = ['bssl', 's_client']
Expand All @@ -704,10 +728,17 @@ def setup_client(self):
cmd_line.extend(['-curves', 'P-384'])
elif self.options.curve == Curves.P521:
cmd_line.extend(['-curves', 'P-521'])
elif self.options.curve == Curves.SecP256r1Kyber768Draft00:
cmd_line.extend(['-curves', 'SecP256r1Kyber768Draft00'])
elif self.options.curve == Curves.X25519Kyber768Draft00:
cmd_line.extend(['-curves', 'X25519Kyber768Draft00'])
elif self.options.curve == Curves.X25519:
pytest.skip('BoringSSL does not support curve {}'.format(
self.options.curve))

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
105 changes: 103 additions & 2 deletions tests/integrationv2/test_pq_handshake.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
import os

from configuration import available_ports
from common import Ciphers, ProviderOptions, Protocols, KemGroups, Certificates, pq_enabled
from common import Ciphers, Curves, ProviderOptions, Protocols, KemGroups, Certificates, pq_enabled
from fixtures import managed_process # lgtm [py/unused-import]
from providers import Provider, S2N, OpenSSL
from providers import Provider, S2N, OpenSSL, BoringSSL
from utils import invalid_test_parameters, get_parameter_name, to_bytes
from global_flags import get_flag, S2N_PROVIDER_VERSION

Expand Down Expand Up @@ -138,6 +138,14 @@
(KemGroups.P521_KYBER1024R3, Ciphers.PQ_TLS_1_3_2023_06_01):
{"cipher": "AES256_GCM_SHA384", "kem": "NONE",
"kem_group": "secp521r1_kyber-1024-r3"},
(Ciphers.PQ_TLS_1_3_2023_06_01, KemGroups.X25519Kyber768Draft00):
{"cipher": "TLS_AES_256_GCM_SHA384",
"kem": "NONE",
"kem_group": "X25519Kyber768Draft00"},
(Ciphers.PQ_TLS_1_3_2023_06_01, KemGroups.SecP256r1Kyber768Draft00):
{"cipher": "TLS_AES_256_GCM_SHA384",
"kem": "NONE",
"kem_group": "SecP256r1Kyber768Draft00"},
}

"""
Expand Down Expand Up @@ -180,6 +188,13 @@ def assert_s2n_negotiation_parameters(s2n_results, expected_result):
assert to_bytes(expected_result['kem_group']) in s2n_results.stdout


def assert_awslc_negotiation_parameters(awslc_results, expected_result):
assert expected_result is not None
assert awslc_results.exit_code is 0
assert to_bytes(("group: " + expected_result['kem_group'])) in awslc_results.stderr
assert to_bytes(("Cipher: " + expected_result['cipher'])) in awslc_results.stderr


def test_nothing():
"""
Sometimes the pq handshake test parameters in combination with the s2n libcrypto
Expand Down Expand Up @@ -253,6 +268,92 @@ def test_s2nc_to_s2nd_pq_handshake(managed_process, protocol, certificate, clien
assert_s2n_negotiation_parameters(results, expected_result)


@pytest.mark.parametrize("s2n_client_policy", [Ciphers.PQ_TLS_1_3_2023_06_01], ids=get_parameter_name)
@pytest.mark.parametrize("awslc_server_group", [KemGroups.SecP256r1Kyber768Draft00, KemGroups.X25519Kyber768Draft00], ids=get_parameter_name)
def test_s2nc_to_awslc_pq_handshake(managed_process, s2n_client_policy, awslc_server_group):

if not pq_enabled():
pytest.skip("PQ not enabled")

if "awslc" not in get_flag(S2N_PROVIDER_VERSION):
pytest.skip("s2n must be compiled with awslc libcrypto in order to test PQ TLS compatibility")

if "fips" in get_flag(S2N_PROVIDER_VERSION):
pytest.skip("No FIPS validated version of AWS-LC has support for negotiating Hybrid PQ TLS yet")

port = next(available_ports)

awslc_env_vars = dict()
awslc_env_vars["PATH"] = os.path.abspath("../../test-deps/awslc/bin")

s2nc_client_options = ProviderOptions(
mode=Provider.ClientMode,
port=port,
insecure=True,
cipher=s2n_client_policy,
protocol=Protocols.TLS13)

awslc_server_options = ProviderOptions(
mode=Provider.ServerMode,
port=port,
protocol=Protocols.TLS13,
env_overrides=awslc_env_vars,
curve=Curves.from_name(awslc_server_group.oqs_name))

awslc_server = managed_process(BoringSSL, awslc_server_options, timeout=5)
s2n_client = managed_process(S2N, s2nc_client_options, timeout=5)
expected_result = EXPECTED_RESULTS.get((s2n_client_policy, awslc_server_group), None)

awslc_result = next(awslc_server.get_results())
assert_awslc_negotiation_parameters(awslc_result, expected_result)

s2nd_result = next(s2n_client.get_results())
assert_s2n_negotiation_parameters(s2nd_result, expected_result)


@pytest.mark.parametrize("s2n_server_policy", [Ciphers.PQ_TLS_1_3_2023_06_01], ids=get_parameter_name)
@pytest.mark.parametrize("awslc_client_group", [KemGroups.SecP256r1Kyber768Draft00, KemGroups.X25519Kyber768Draft00], ids=get_parameter_name)
def test_s2nd_to_awslc_pq_handshake(managed_process, s2n_server_policy, awslc_client_group):

if not pq_enabled():
pytest.skip("PQ not enabled")

if "awslc" not in get_flag(S2N_PROVIDER_VERSION):
pytest.skip("s2n must be compiled with awslc libcrypto in order to test PQ TLS compatibility")

if "fips" in get_flag(S2N_PROVIDER_VERSION):
pytest.skip("No FIPS validated version of AWS-LC has support for negotiating Hybrid PQ TLS yet")

port = next(available_ports)

awslc_env_vars = dict()
awslc_env_vars["PATH"] = os.path.abspath("../../test-deps/awslc/bin")

s2nd_server_options = ProviderOptions(
mode=Provider.ServerMode,
port=port,
insecure=True,
cipher=s2n_server_policy,
protocol=Protocols.TLS13)

awslc_client_options = ProviderOptions(
mode=Provider.ClientMode,
port=port,
protocol=Protocols.TLS13,
env_overrides=awslc_env_vars,
curve=Curves.from_name(awslc_client_group.oqs_name))

s2nd_server = managed_process(S2N, s2nd_server_options, timeout=5)
awslc_client = managed_process(BoringSSL, awslc_client_options, timeout=5)
expected_result = EXPECTED_RESULTS.get((s2n_server_policy, awslc_client_group), None)

awslc_result = next(awslc_client.get_results())
assert_awslc_negotiation_parameters(awslc_result, expected_result)

s2nd_result = next(s2nd_server.get_results())
assert_s2n_negotiation_parameters(s2nd_result, expected_result)


@pytest.mark.uncollect_if(func=invalid_test_parameters)
@pytest.mark.parametrize("protocol", [Protocols.TLS13], ids=get_parameter_name)
@pytest.mark.parametrize("cipher", [Ciphers.PQ_TLS_1_0_2020_12], ids=get_parameter_name)
Expand Down

0 comments on commit 458a29d

Please sign in to comment.