From 669142d3c8fb523ddc9fd13cc027afe889bda314 Mon Sep 17 00:00:00 2001 From: Justin Zhang <76919968+tinzh@users.noreply.github.com> Date: Fri, 16 Jun 2023 15:10:13 -0700 Subject: [PATCH] s2n-tls handshake benchmark (#4053) --- bindings/rust/Cargo.toml | 3 +- bindings/rust/bench/Cargo.toml | 16 ++ bindings/rust/bench/benches/handshake.rs | 23 +++ bindings/rust/bench/certs/ca-cert.pem | 22 +++ bindings/rust/bench/certs/client-cert.pem | 22 +++ bindings/rust/bench/certs/client-key.pem | 6 + bindings/rust/bench/certs/config/ca.cnf | 13 ++ bindings/rust/bench/certs/config/client.cnf | 24 +++ bindings/rust/bench/certs/config/server.cnf | 24 +++ bindings/rust/bench/certs/fullchain.pem | 44 +++++ bindings/rust/bench/certs/generate_certs.sh | 35 ++++ bindings/rust/bench/certs/server-cert.pem | 22 +++ bindings/rust/bench/certs/server-key.pem | 6 + bindings/rust/bench/rust-toolchain | 1 + bindings/rust/bench/src/harness.rs | 25 +++ bindings/rust/bench/src/lib.rs | 22 +++ bindings/rust/bench/src/s2n_tls.rs | 208 ++++++++++++++++++++ 17 files changed, 515 insertions(+), 1 deletion(-) create mode 100644 bindings/rust/bench/Cargo.toml create mode 100644 bindings/rust/bench/benches/handshake.rs create mode 100644 bindings/rust/bench/certs/ca-cert.pem create mode 100644 bindings/rust/bench/certs/client-cert.pem create mode 100644 bindings/rust/bench/certs/client-key.pem create mode 100644 bindings/rust/bench/certs/config/ca.cnf create mode 100644 bindings/rust/bench/certs/config/client.cnf create mode 100644 bindings/rust/bench/certs/config/server.cnf create mode 100644 bindings/rust/bench/certs/fullchain.pem create mode 100755 bindings/rust/bench/certs/generate_certs.sh create mode 100644 bindings/rust/bench/certs/server-cert.pem create mode 100644 bindings/rust/bench/certs/server-key.pem create mode 100644 bindings/rust/bench/rust-toolchain create mode 100644 bindings/rust/bench/src/harness.rs create mode 100644 bindings/rust/bench/src/lib.rs create mode 100644 bindings/rust/bench/src/s2n_tls.rs diff --git a/bindings/rust/Cargo.toml b/bindings/rust/Cargo.toml index 34b4bc40d9f..5b82a43e898 100644 --- a/bindings/rust/Cargo.toml +++ b/bindings/rust/Cargo.toml @@ -9,7 +9,8 @@ members = [ # s2n-tls-sys/Cargo.toml (part of the workspace) is generated by # generate/main.rs exclude = [ - "generate" + "generate", + "bench" ] [profile.release] diff --git a/bindings/rust/bench/Cargo.toml b/bindings/rust/bench/Cargo.toml new file mode 100644 index 00000000000..9e16a4469fa --- /dev/null +++ b/bindings/rust/bench/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "bench" +version = "0.1.0" +edition = "2021" + +[dependencies] +s2n-tls = { path = "../s2n-tls" } +errno = "0.3" +libc = "0.2" +criterion = "0.3" +# release_max_level_off feature removes logging statements in the release build +log = { version = "0.4", features = [ "release_max_level_off", "max_level_debug" ] } + +[[bench]] +name = "handshake" +harness = false diff --git a/bindings/rust/bench/benches/handshake.rs b/bindings/rust/bench/benches/handshake.rs new file mode 100644 index 00000000000..d03f0e38f72 --- /dev/null +++ b/bindings/rust/bench/benches/handshake.rs @@ -0,0 +1,23 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use bench::{S2NHarness, TlsBenchHarness}; +use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; + +pub fn criterion_benchmark(c: &mut Criterion) { + let mut group = c.benchmark_group("handshake"); + + group.bench_function("s2n-tls", |b| { + // generate all inputs (s2n-tls objects) before benchmarking handshakes + b.iter_batched_ref( + || S2NHarness::new(), + |s2n_tls| { + s2n_tls.handshake().unwrap(); + }, + BatchSize::SmallInput, + ) + }); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/bindings/rust/bench/certs/ca-cert.pem b/bindings/rust/bench/certs/ca-cert.pem new file mode 100644 index 00000000000..636079e433b --- /dev/null +++ b/bindings/rust/bench/certs/ca-cert.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDnTCCAoUCFHd1xnhLaVEsJVDIz0PHH1mclbPuMA0GCSqGSIb3DQEBCwUAMIGJ +MQswCQYDVQQGEwJKUDEOMAwGA1UECAwFQ2hpYmExEzARBgNVBAcMCkNoaWJhIENp +dHkxGDAWBgNVBAoMD1Rlc3NpZXItQXNocG9vbDEYMBYGA1UEAwwPZGV2ZWxvcC5s +b2NhbGNhMSEwHwYJKoZIhvcNAQkBFhJjYUBkZXZlbG9wLmxvY2FsY2EwIBcNMjMw +NjA5MTcyNTAyWhgPMjIwMjExMTQxNzI1MDJaMIGJMQswCQYDVQQGEwJKUDEOMAwG +A1UECAwFQ2hpYmExEzARBgNVBAcMCkNoaWJhIENpdHkxGDAWBgNVBAoMD1Rlc3Np +ZXItQXNocG9vbDEYMBYGA1UEAwwPZGV2ZWxvcC5sb2NhbGNhMSEwHwYJKoZIhvcN +AQkBFhJjYUBkZXZlbG9wLmxvY2FsY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDII4MvapIuBLmDoIn/jeu9xeHqw8vUiPZecg4azweLv6B/QKKQSAXF +bQA2JVCSHF7gxjHDvOFG3+Kx/RV74hKjHlp2yVMskW1r4e6WCC+duIBgR2y7xfaM +7C5XKt6DuSexHECmUiU9cG2ZRP8lx8Wclvet9Ob+iP+sx3xQJ8Y0NtLjeo5UCV5X +CAAVBUHLTypRNSsU6LFxkRjs2JxdjGLG98+ih4VNfc5lUXBJzcrCSLErnaIhvxcz +X6myHd57eCYsWEsukuGcY+59rgPkxDofK+G/PwMOMVjYeQ1HoR/Ms9+mgN88Udcm +d9IXCKZh1dmqbBZMOXZi5fjaViO8xhe1AgMBAAEwDQYJKoZIhvcNAQELBQADggEB +AKA3FgjF97cFyT0EfZfJag3g5sSq1NLqGuAvmtgaUhdqRT2vo5Uuaj+ZqxmFvEll +tb9zeQgaPksyW+wZ+Lg46qYHhwuInycqke6Sa4FKlQrydThoF9tM1zQtnJqzdX1s +gcm731nR2O3lYsrfNRasOeB11rk4a14cJRwWk57d8qt/nLwmPMt9dc4IsCmqQw6l +s0f49lX/PmEenAaO5hfVI7XcasT260L4/NlFA2HzrbGdO+o2aCrSfA5+Qt0PMsjZ +H2P+1/JefgRyMDG8hk0ev2aoqkGBvZrSJyCI/+EZoJRuS1qPI3S+kHGXkJ3tF4i+ +IeTBeNaFh9ayc/UoUPyved0= +-----END CERTIFICATE----- diff --git a/bindings/rust/bench/certs/client-cert.pem b/bindings/rust/bench/certs/client-cert.pem new file mode 100644 index 00000000000..0975dfc4e54 --- /dev/null +++ b/bindings/rust/bench/certs/client-cert.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIUNCurbgaG3FFx/oedAfC+QM7PJI4wDQYJKoZIhvcNAQEL +BQAwgYkxCzAJBgNVBAYTAkpQMQ4wDAYDVQQIDAVDaGliYTETMBEGA1UEBwwKQ2hp +YmEgQ2l0eTEYMBYGA1UECgwPVGVzc2llci1Bc2hwb29sMRgwFgYDVQQDDA9kZXZl +bG9wLmxvY2FsY2ExITAfBgkqhkiG9w0BCQEWEmNhQGRldmVsb3AubG9jYWxjYTAg +Fw0yMzA2MDkxNzI1MDJaGA8yMjAyMTExNDE3MjUwMlowYDELMAkGA1UEBhMCVVMx +EzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxDzANBgNVBAoM +BmNsaWVudDEZMBcGA1UEAwwQY2xpZW50LmxvY2FsaG9zdDB2MBAGByqGSM49AgEG +BSuBBAAiA2IABPCBEz2mGh83HkcxVHCZeKnQnl4RcJI4kznhAMSGRrFl9yEkbypf +wrOCTwytVQDn9ZLFR8BRWAlOQvaC7lYN0nVtA0dHpLJEATilvRzf3a4QUznh8Rbp +svRRUvOXoXWTM6OB7jCB6zAUBgNVHREEDTALgglsb2NhbGhvc3QwHQYDVR0OBBYE +FAEG/BipFATRiCJUrQTLvrrsxwHMMIGzBgNVHSMEgaswgaihgY+kgYwwgYkxCzAJ +BgNVBAYTAkpQMQ4wDAYDVQQIDAVDaGliYTETMBEGA1UEBwwKQ2hpYmEgQ2l0eTEY +MBYGA1UECgwPVGVzc2llci1Bc2hwb29sMRgwFgYDVQQDDA9kZXZlbG9wLmxvY2Fs +Y2ExITAfBgkqhkiG9w0BCQEWEmNhQGRldmVsb3AubG9jYWxjYYIUd3XGeEtpUSwl +UMjPQ8cfWZyVs+4wDQYJKoZIhvcNAQELBQADggEBAKsuZKK0mBcop0ZakO5tS8pm +5BLqymrC3yhEoEKTS6Tf6ek+Fr/++3bIiFeU1+X84Pd6/cfHRZp1RHykDPiLZy5S +xNZr+wsg1Dkx3GT521c/wievUTrqZ0G5/CK5On2jC5ytFHuARF9XNqYM/WhvSHN0 +q/ZLUBqyOOGUsQ5BHatgPuEKXp3n7Qp0yW4Wy/s16f3jRi4KCbGAQC+Q64OXzBzr +rFMNGrLHJrusv4TIKQ/UR5A4JLuRChk1UdxlErowyID4UOOyzHroK73dFmwg/jGu +65miqd2SX8KcKC2Jiq+YCAnzIpuigiyz0EgFAV/pdUZB1qP3hEwb4hJItz3vyAo= +-----END CERTIFICATE----- diff --git a/bindings/rust/bench/certs/client-key.pem b/bindings/rust/bench/certs/client-key.pem new file mode 100644 index 00000000000..775648870fc --- /dev/null +++ b/bindings/rust/bench/certs/client-key.pem @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBuxa4+TKypIlwZT2N3 +G3pMGDTJgrxTCfuc9QX917hf5ulXz915VIJkUcRFe+AXVkOhZANiAATwgRM9phof +Nx5HMVRwmXip0J5eEXCSOJM54QDEhkaxZfchJG8qX8Kzgk8MrVUA5/WSxUfAUVgJ +TkL2gu5WDdJ1bQNHR6SyRAE4pb0c392uEFM54fEW6bL0UVLzl6F1kzM= +-----END PRIVATE KEY----- diff --git a/bindings/rust/bench/certs/config/ca.cnf b/bindings/rust/bench/certs/config/ca.cnf new file mode 100644 index 00000000000..66447a71611 --- /dev/null +++ b/bindings/rust/bench/certs/config/ca.cnf @@ -0,0 +1,13 @@ +[ req ] +prompt = no +distinguished_name = ca_distinguished_name + +[ ca_distinguished_name ] +# country name +C = JP +# state or province +ST = Chiba +L = Chiba City +O = Tessier-Ashpool +CN = develop.localca +emailAddress = ca@develop.localca diff --git a/bindings/rust/bench/certs/config/client.cnf b/bindings/rust/bench/certs/config/client.cnf new file mode 100644 index 00000000000..2018077e6c3 --- /dev/null +++ b/bindings/rust/bench/certs/config/client.cnf @@ -0,0 +1,24 @@ +[req] +distinguished_name = client_distinguished_name +prompt = no + +# these fields are used to force x509 to v3 certificates +# rustls will complain otherwise +x509_extensions = v3_req +req_extensions = req_ext + +[client_distinguished_name] +countryName = US +stateOrProvinceName = Washington +localityName = Seattle +organizationName = client +commonName = client.localhost + +[v3_req] +subjectAltName = @alt_names + +[req_ext] +subjectAltName = @alt_names + +[alt_names] +DNS = localhost diff --git a/bindings/rust/bench/certs/config/server.cnf b/bindings/rust/bench/certs/config/server.cnf new file mode 100644 index 00000000000..403932d8fcf --- /dev/null +++ b/bindings/rust/bench/certs/config/server.cnf @@ -0,0 +1,24 @@ +[req] +distinguished_name = server_distinguished_name +prompt = no + +# these fields are used to force x509 to v3 certificates +# rustls will complain otherwise +x509_extensions = v3_req +req_extensions = req_ext + +[server_distinguished_name] +countryName = US +stateOrProvinceName = Washington +localityName = Seattle +organizationName = server +commonName = server.localhost + +[v3_req] +subjectAltName = @alt_names + +[req_ext] +subjectAltName = @alt_names + +[alt_names] +DNS = localhost diff --git a/bindings/rust/bench/certs/fullchain.pem b/bindings/rust/bench/certs/fullchain.pem new file mode 100644 index 00000000000..ab5694c0383 --- /dev/null +++ b/bindings/rust/bench/certs/fullchain.pem @@ -0,0 +1,44 @@ +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIUNDIVTXmgX5RATAJujllJQucIu74wDQYJKoZIhvcNAQEL +BQAwgYkxCzAJBgNVBAYTAkpQMQ4wDAYDVQQIDAVDaGliYTETMBEGA1UEBwwKQ2hp +YmEgQ2l0eTEYMBYGA1UECgwPVGVzc2llci1Bc2hwb29sMRgwFgYDVQQDDA9kZXZl +bG9wLmxvY2FsY2ExITAfBgkqhkiG9w0BCQEWEmNhQGRldmVsb3AubG9jYWxjYTAg +Fw0yMzA2MDkxNzI1MDJaGA8yMjAyMTExNDE3MjUwMlowYDELMAkGA1UEBhMCVVMx +EzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxDzANBgNVBAoM +BnNlcnZlcjEZMBcGA1UEAwwQc2VydmVyLmxvY2FsaG9zdDB2MBAGByqGSM49AgEG +BSuBBAAiA2IABJD8tMww7UbaLR4YF2nR4zIJuYPBvo+4ur334MfX5RSVNSheX0x8 +t6CDzSxQQhURuBZuEPgsxhKKjj9+OAq/jTX2tS/hVfeMUoCyaqoKlNCUDu0EhunH +51FINWa/ejbQw6OB7jCB6zAUBgNVHREEDTALgglsb2NhbGhvc3QwHQYDVR0OBBYE +FPxzHMcaw/HlTkUsoljncbhHxRXxMIGzBgNVHSMEgaswgaihgY+kgYwwgYkxCzAJ +BgNVBAYTAkpQMQ4wDAYDVQQIDAVDaGliYTETMBEGA1UEBwwKQ2hpYmEgQ2l0eTEY +MBYGA1UECgwPVGVzc2llci1Bc2hwb29sMRgwFgYDVQQDDA9kZXZlbG9wLmxvY2Fs +Y2ExITAfBgkqhkiG9w0BCQEWEmNhQGRldmVsb3AubG9jYWxjYYIUd3XGeEtpUSwl +UMjPQ8cfWZyVs+4wDQYJKoZIhvcNAQELBQADggEBAAejR6XomhNxTtvKNGA7SgDh +yeoz9ZQUipu2s4Dfy7Sf3s6NGRF8pL+3RByk5yB87I8YpdfWI0pjSZK1EWVXpwe4 +26E8EwncNVpaXJeI3z4L33IWSMYE+Q1MmduN8EvBtpMRSt06vLHZ+Y+uOZbsdaOq +ioT4AP6AK7ZJ74STJWJIVMS6pNy9Do6HSAa9RX5+5fkn3gpho+Qtdhq0dRF/8RV6 +c7P79o6Q0SoK99G9WJOzwOkmXR9ytLAKq5GxS7JaxEjShWXc+v0VqEC/94iktXaM +Bh9ndJPw6NMAhWZONpNqzQIzKKsNXtGqGWzN3Ed6bNnNFQohcZnyu5AT8kf3iQA= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDnTCCAoUCFHd1xnhLaVEsJVDIz0PHH1mclbPuMA0GCSqGSIb3DQEBCwUAMIGJ +MQswCQYDVQQGEwJKUDEOMAwGA1UECAwFQ2hpYmExEzARBgNVBAcMCkNoaWJhIENp +dHkxGDAWBgNVBAoMD1Rlc3NpZXItQXNocG9vbDEYMBYGA1UEAwwPZGV2ZWxvcC5s +b2NhbGNhMSEwHwYJKoZIhvcNAQkBFhJjYUBkZXZlbG9wLmxvY2FsY2EwIBcNMjMw +NjA5MTcyNTAyWhgPMjIwMjExMTQxNzI1MDJaMIGJMQswCQYDVQQGEwJKUDEOMAwG +A1UECAwFQ2hpYmExEzARBgNVBAcMCkNoaWJhIENpdHkxGDAWBgNVBAoMD1Rlc3Np +ZXItQXNocG9vbDEYMBYGA1UEAwwPZGV2ZWxvcC5sb2NhbGNhMSEwHwYJKoZIhvcN +AQkBFhJjYUBkZXZlbG9wLmxvY2FsY2EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDII4MvapIuBLmDoIn/jeu9xeHqw8vUiPZecg4azweLv6B/QKKQSAXF +bQA2JVCSHF7gxjHDvOFG3+Kx/RV74hKjHlp2yVMskW1r4e6WCC+duIBgR2y7xfaM +7C5XKt6DuSexHECmUiU9cG2ZRP8lx8Wclvet9Ob+iP+sx3xQJ8Y0NtLjeo5UCV5X +CAAVBUHLTypRNSsU6LFxkRjs2JxdjGLG98+ih4VNfc5lUXBJzcrCSLErnaIhvxcz +X6myHd57eCYsWEsukuGcY+59rgPkxDofK+G/PwMOMVjYeQ1HoR/Ms9+mgN88Udcm +d9IXCKZh1dmqbBZMOXZi5fjaViO8xhe1AgMBAAEwDQYJKoZIhvcNAQELBQADggEB +AKA3FgjF97cFyT0EfZfJag3g5sSq1NLqGuAvmtgaUhdqRT2vo5Uuaj+ZqxmFvEll +tb9zeQgaPksyW+wZ+Lg46qYHhwuInycqke6Sa4FKlQrydThoF9tM1zQtnJqzdX1s +gcm731nR2O3lYsrfNRasOeB11rk4a14cJRwWk57d8qt/nLwmPMt9dc4IsCmqQw6l +s0f49lX/PmEenAaO5hfVI7XcasT260L4/NlFA2HzrbGdO+o2aCrSfA5+Qt0PMsjZ +H2P+1/JefgRyMDG8hk0ev2aoqkGBvZrSJyCI/+EZoJRuS1qPI3S+kHGXkJ3tF4i+ +IeTBeNaFh9ayc/UoUPyved0= +-----END CERTIFICATE----- diff --git a/bindings/rust/bench/certs/generate_certs.sh b/bindings/rust/bench/certs/generate_certs.sh new file mode 100755 index 00000000000..ce68dbbed4d --- /dev/null +++ b/bindings/rust/bench/certs/generate_certs.sh @@ -0,0 +1,35 @@ +# immediately bail if any command fails +set -e + +pushd "$(dirname "$0")" + +echo "generating CA private key and certificate" +openssl req -nodes -new -x509 -keyout ca-key.pem -out ca-cert.pem -days 65536 -config config/ca.cnf + +# secp384r1 is an arbitrarily chosen curve that is supported by the default +# security policy in s2n-tls. +# https://github.com/aws/s2n-tls/blob/main/docs/USAGE-GUIDE.md#chart-security-policy-version-to-supported-curvesgroups +echo "generating server private key and CSR" +openssl req -new -nodes -newkey ec -pkeyopt ec_paramgen_curve:secp384r1 -keyout server-key.pem -out server.csr -config config/server.cnf + +echo "generating client private key and CSR" +openssl req -new -nodes -newkey ec -pkeyopt ec_paramgen_curve:secp384r1 -keyout client-key.pem -out client.csr -config config/client.cnf + +echo "generating server certificate and signing it" +openssl x509 -days 65536 -req -in server.csr -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extensions req_ext -extfile config/server.cnf + +echo "generating client certificate and signing it" +openssl x509 -days 65536 -req -in client.csr -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -extensions req_ext -extfile config/client.cnf + +echo "verifying generated certificates" +openssl verify -CAfile ca-cert.pem server-cert.pem +openssl verify -CAfile ca-cert.pem client-cert.pem + +cat server-cert.pem ca-cert.pem > fullchain.pem + +echo "cleaning up temporary files" +rm server.csr +rm client.csr +rm ca-key.pem + +popd diff --git a/bindings/rust/bench/certs/server-cert.pem b/bindings/rust/bench/certs/server-cert.pem new file mode 100644 index 00000000000..b3d4d0ed3ba --- /dev/null +++ b/bindings/rust/bench/certs/server-cert.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIUNDIVTXmgX5RATAJujllJQucIu74wDQYJKoZIhvcNAQEL +BQAwgYkxCzAJBgNVBAYTAkpQMQ4wDAYDVQQIDAVDaGliYTETMBEGA1UEBwwKQ2hp +YmEgQ2l0eTEYMBYGA1UECgwPVGVzc2llci1Bc2hwb29sMRgwFgYDVQQDDA9kZXZl +bG9wLmxvY2FsY2ExITAfBgkqhkiG9w0BCQEWEmNhQGRldmVsb3AubG9jYWxjYTAg +Fw0yMzA2MDkxNzI1MDJaGA8yMjAyMTExNDE3MjUwMlowYDELMAkGA1UEBhMCVVMx +EzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxDzANBgNVBAoM +BnNlcnZlcjEZMBcGA1UEAwwQc2VydmVyLmxvY2FsaG9zdDB2MBAGByqGSM49AgEG +BSuBBAAiA2IABJD8tMww7UbaLR4YF2nR4zIJuYPBvo+4ur334MfX5RSVNSheX0x8 +t6CDzSxQQhURuBZuEPgsxhKKjj9+OAq/jTX2tS/hVfeMUoCyaqoKlNCUDu0EhunH +51FINWa/ejbQw6OB7jCB6zAUBgNVHREEDTALgglsb2NhbGhvc3QwHQYDVR0OBBYE +FPxzHMcaw/HlTkUsoljncbhHxRXxMIGzBgNVHSMEgaswgaihgY+kgYwwgYkxCzAJ +BgNVBAYTAkpQMQ4wDAYDVQQIDAVDaGliYTETMBEGA1UEBwwKQ2hpYmEgQ2l0eTEY +MBYGA1UECgwPVGVzc2llci1Bc2hwb29sMRgwFgYDVQQDDA9kZXZlbG9wLmxvY2Fs +Y2ExITAfBgkqhkiG9w0BCQEWEmNhQGRldmVsb3AubG9jYWxjYYIUd3XGeEtpUSwl +UMjPQ8cfWZyVs+4wDQYJKoZIhvcNAQELBQADggEBAAejR6XomhNxTtvKNGA7SgDh +yeoz9ZQUipu2s4Dfy7Sf3s6NGRF8pL+3RByk5yB87I8YpdfWI0pjSZK1EWVXpwe4 +26E8EwncNVpaXJeI3z4L33IWSMYE+Q1MmduN8EvBtpMRSt06vLHZ+Y+uOZbsdaOq +ioT4AP6AK7ZJ74STJWJIVMS6pNy9Do6HSAa9RX5+5fkn3gpho+Qtdhq0dRF/8RV6 +c7P79o6Q0SoK99G9WJOzwOkmXR9ytLAKq5GxS7JaxEjShWXc+v0VqEC/94iktXaM +Bh9ndJPw6NMAhWZONpNqzQIzKKsNXtGqGWzN3Ed6bNnNFQohcZnyu5AT8kf3iQA= +-----END CERTIFICATE----- diff --git a/bindings/rust/bench/certs/server-key.pem b/bindings/rust/bench/certs/server-key.pem new file mode 100644 index 00000000000..20083acc9ce --- /dev/null +++ b/bindings/rust/bench/certs/server-key.pem @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCSl0T2qNjybO7rcLvx +++vXvjPk98d+YXxGKH+voS+VynS8eOyjcVjJVRYCetXZAlihZANiAASQ/LTMMO1G +2i0eGBdp0eMyCbmDwb6PuLq99+DH1+UUlTUoXl9MfLegg80sUEIVEbgWbhD4LMYS +io4/fjgKv4019rUv4VX3jFKAsmqqCpTQlA7tBIbpx+dRSDVmv3o20MM= +-----END PRIVATE KEY----- diff --git a/bindings/rust/bench/rust-toolchain b/bindings/rust/bench/rust-toolchain new file mode 100644 index 00000000000..2bf5ad0447d --- /dev/null +++ b/bindings/rust/bench/rust-toolchain @@ -0,0 +1 @@ +stable diff --git a/bindings/rust/bench/src/harness.rs b/bindings/rust/bench/src/harness.rs new file mode 100644 index 00000000000..f8dcfe98c0f --- /dev/null +++ b/bindings/rust/bench/src/harness.rs @@ -0,0 +1,25 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use std::fs::read_to_string; + +pub fn read_to_bytes(path: &str) -> Vec { + read_to_string(path).unwrap().into_bytes() +} + +pub enum Mode { + Client, + Server, +} + +pub trait TlsBenchHarness { + /// Initialize buffers, configs, and connections (pre-handshake) + fn new() -> Self; + + /// Run handshake on initialized connection + /// Returns error if handshake already happened + fn handshake(&mut self) -> Result<(), &str>; + + /// Checks if handshake is finished for both client and server + fn handshake_completed(&self) -> bool; +} diff --git a/bindings/rust/bench/src/lib.rs b/bindings/rust/bench/src/lib.rs new file mode 100644 index 00000000000..a7e1eaa9f6b --- /dev/null +++ b/bindings/rust/bench/src/lib.rs @@ -0,0 +1,22 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +pub mod harness; +pub mod s2n_tls; +pub use crate::{harness::TlsBenchHarness, s2n_tls::S2NHarness}; + +const SERVER_KEY_PATH: &str = "certs/server-key.pem"; +const SERVER_CERT_CHAIN_PATH: &str = "certs/fullchain.pem"; +const CA_CERT_PATH: &str = "certs/ca-cert.pem"; + +#[cfg(test)] +mod tests { + use std::path::Path; + + #[test] + fn cert_paths_valid() { + assert!(Path::new(crate::SERVER_KEY_PATH).exists()); + assert!(Path::new(crate::SERVER_CERT_CHAIN_PATH).exists()); + assert!(Path::new(crate::CA_CERT_PATH).exists()); + } +} diff --git a/bindings/rust/bench/src/s2n_tls.rs b/bindings/rust/bench/src/s2n_tls.rs new file mode 100644 index 00000000000..8ee84ddf681 --- /dev/null +++ b/bindings/rust/bench/src/s2n_tls.rs @@ -0,0 +1,208 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use crate::{ + harness::{read_to_bytes, Mode, TlsBenchHarness}, + CA_CERT_PATH, SERVER_CERT_CHAIN_PATH, SERVER_KEY_PATH, +}; +use log::debug; +use s2n_tls::{ + callbacks::VerifyHostNameCallback, + config::{Builder, Config}, + connection::Connection, + enums::Blinding, + security::DEFAULT_TLS13, +}; +use std::{ + cell::UnsafeCell, + collections::VecDeque, + ffi::c_void, + io::{Read, Write}, + os::raw::c_int, + pin::Pin, + task::Poll::Ready, +}; + +pub struct S2NHarness { + // UnsafeCell is needed b/c client and server share *mut to IO buffers + // Pin> is to ensure long-term *mut to IO buffers remain valid + client_to_server_buf: Pin>>>, + server_to_client_buf: Pin>>>, + client_config: Config, + server_config: Config, + client_conn: Connection, + server_conn: Connection, + client_handshake_completed: bool, + server_handshake_completed: bool, +} + +/// Custom callback for verifying hostnames. Rustls requires checking hostnames, +/// so this is to make a fair comparison +struct HostNameHandler<'a> { + expected_server_name: &'a str, +} +impl VerifyHostNameCallback for HostNameHandler<'_> { + fn verify_host_name(&self, hostname: &str) -> bool { + self.expected_server_name == hostname + } +} + +impl S2NHarness { + /// Unsafe callback for custom IO C API + /// + /// s2n-tls IO is usually used with file descriptors to a TCP socket, but we + /// reduce overhead and outside noise with a local buffer for benchmarking + unsafe extern "C" fn send_cb(context: *mut c_void, data: *const u8, len: u32) -> c_int { + let context = &mut *(context as *mut VecDeque); + let data = core::slice::from_raw_parts(data, len as _); + context.write(data).unwrap() as _ + } + + /// Unsafe callback for custom IO C API + unsafe extern "C" fn recv_cb(context: *mut c_void, data: *mut u8, len: u32) -> c_int { + let context = &mut *(context as *mut VecDeque); + let data = core::slice::from_raw_parts_mut(data, len as _); + context.flush().unwrap(); + let len = context.read(data).unwrap(); + if len == 0 { + debug!("\t[blocking]"); + errno::set_errno(errno::Errno(libc::EWOULDBLOCK)); + -1 + } else { + debug!("\t- received {len}"); + len as _ + } + } + + fn create_config(mode: Mode) -> Config { + let mut builder = Builder::new(); + builder.set_security_policy(&DEFAULT_TLS13).unwrap(); + + match mode { + Mode::Server => builder + .load_pem( + read_to_bytes(SERVER_CERT_CHAIN_PATH).as_slice(), + read_to_bytes(SERVER_KEY_PATH).as_slice(), + ) + .unwrap(), + Mode::Client => builder + .trust_pem(read_to_bytes(CA_CERT_PATH).as_slice()) + .unwrap() + .set_verify_host_callback(HostNameHandler { + expected_server_name: "localhost", + }) + .unwrap(), + }; + + builder.build().unwrap() + } + + /// Set up connections with config and custom IO + fn init_conn(&mut self, mode: Mode) -> Result<(), s2n_tls::error::Error> { + let client_to_server_ptr = self.client_to_server_buf.get() as *mut c_void; + let server_to_client_ptr = self.server_to_client_buf.get() as *mut c_void; + let (read_ptr, write_ptr, config, conn) = match mode { + Mode::Client => ( + server_to_client_ptr, + client_to_server_ptr, + &self.client_config, + &mut self.client_conn, + ), + Mode::Server => ( + client_to_server_ptr, + server_to_client_ptr, + &self.server_config, + &mut self.server_conn, + ), + }; + + conn.set_blinding(Blinding::SelfService)? + .set_config(config.clone())? + .set_send_callback(Some(Self::send_cb))? + .set_receive_callback(Some(Self::recv_cb))?; + unsafe { + conn.set_send_context(write_ptr)? + .set_receive_context(read_ptr)?; + } + + Ok(()) + } + + /// Handshake step for one connection + fn handshake_conn(&mut self, mode: Mode) { + let (conn, handshake_completed) = match mode { + Mode::Client => { + debug!("Client: "); + (&mut self.client_conn, &mut self.client_handshake_completed) + } + Mode::Server => { + debug!("Server: "); + (&mut self.server_conn, &mut self.server_handshake_completed) + } + }; + + if let Ready(res) = conn.poll_negotiate() { + res.unwrap(); + *handshake_completed = true; + } else { + *handshake_completed = false; + } + } +} + +impl TlsBenchHarness for S2NHarness { + fn new() -> Self { + debug!("----- constructing new s2n-tls harness -----"); + let mut harness = S2NHarness { + client_to_server_buf: Box::pin(UnsafeCell::new(VecDeque::new())), + server_to_client_buf: Box::pin(UnsafeCell::new(VecDeque::new())), + client_config: Self::create_config(Mode::Client), + server_config: Self::create_config(Mode::Server), + client_conn: Connection::new_client(), + server_conn: Connection::new_server(), + client_handshake_completed: false, + server_handshake_completed: false, + }; + harness.init_conn(Mode::Client).unwrap(); + harness.init_conn(Mode::Server).unwrap(); + harness + } + + fn handshake(&mut self) -> Result<(), &str> { + if self.handshake_completed() { + return Err("Already completed handshake"); + } + debug!("HANDSHAKE"); + let mut round_trips = 2; // expect two round trips, second for server to see Finished message + while round_trips > 0 { + self.handshake_conn(Mode::Client); + self.handshake_conn(Mode::Server); + round_trips -= 1; + } + debug!("HANDSHAKE DONE\n"); + Ok(()) + } + + fn handshake_completed(&self) -> bool { + self.client_handshake_completed && self.server_handshake_completed + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn s2n_tls_create_object() { + S2NHarness::new(); + } + + #[test] + fn s2n_tls_handshake_successful() { + let mut s2n_tls_harness = S2NHarness::new(); + assert!(!s2n_tls_harness.handshake_completed()); + assert!(s2n_tls_harness.handshake().is_ok()); + assert!(s2n_tls_harness.handshake_completed()); + assert!(s2n_tls_harness.handshake().is_err()); // make sure doesn't panic + } +}