diff --git a/bindings/rust/bench/README.md b/bindings/rust/bench/README.md index 27ccc15b372..98926ebbbca 100644 --- a/bindings/rust/bench/README.md +++ b/bindings/rust/bench/README.md @@ -45,7 +45,7 @@ To generate flamegraphs, run `cargo bench --bench handshake --bench throughput - ## Memory benchmarks -To run all memory benchmarks, run `memory/bench-memory.sh`. Graphs of memory usage will be generated in `images/`. +To run all memory benchmarks, run `scripts/bench-memory.sh`. Graphs of memory usage will be generated in `images/`. Memory benchmark data is generated using the `memory` binary. Command line arguments can be given to `cargo run` or to the built executable located at `target/release/memory`. The usage is as follows: @@ -88,7 +88,7 @@ Notes: - Two sets of parameters for the handshake couldn't be benched before 1.3.40, since security policies that negotiated those policies as their top choice did not exist before then. - There is no data from 1.3.30 to 1.3.37 because those versions have a dependency issue that cause the Rust bindings not to build. However, there is data before and after that period, so the performance for those versions can be inferred via interpolation. - The improvement in throughput in 1.3.28 was most likely caused by the addition of LTO to the default Rust bindings build. -- Since the benches are run over a long time, noise on the machine can cause variability, as seen in the throughput graph. +- Since the benches are run over a long time, noise on the machine can cause variability, and background processes can cause spikes. - The variability can be seen with throughput especially because it is calculated as the inverse of time taken. ![historical-perf-handshake](images/historical-perf-handshake.svg) diff --git a/bindings/rust/bench/images/historical-perf-handshake.svg b/bindings/rust/bench/images/historical-perf-handshake.svg index 79ac67a2507..06f65b30056 100644 --- a/bindings/rust/bench/images/historical-perf-handshake.svg +++ b/bindings/rust/bench/images/historical-perf-handshake.svg @@ -4,421 +4,944 @@ Performance of handshake by version since Jun 2022 - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - + + + + + + - - - - + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + Time Version - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - + + + + + 0 ms - + 2 ms - - + + 4 ms - - + + 6 ms - + + +8 ms + + - + 1.3.16 - - + + 1.3.18 - - + + 1.3.20 - - + + 1.3.22 - - + + 1.3.24 - - + + 1.3.26 - - + + 1.3.28 - - + + 1.3.30 - - + + 1.3.32 - - + + 1.3.34 - - + + 1.3.36 - - + + 1.3.38 - - + + 1.3.40 - - + + 1.3.42 - - + + 1.3.44 - - + + 1.3.46 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -handshake-MutualAuth-SECP256R1 - - -handshake-ServerAuth-X25519 - - -handshake-MutualAuth-X25519 - - -handshake-ServerAuth-SECP256R1 - - - - - + + +1.3.48 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +handshake-x25519 + + +handshake-no-mTLS + + +handshake-rsa2048 + + +handshake-rsa4096 + + +handshake-rsa3072 + + +handshake-secp256r1 + + +handshake-mTLS + + +handshake-ecdsa384 + + + + + + + + + diff --git a/bindings/rust/bench/images/historical-perf-throughput.svg b/bindings/rust/bench/images/historical-perf-throughput.svg index 46aeb36c475..a27ad4e054c 100644 --- a/bindings/rust/bench/images/historical-perf-throughput.svg +++ b/bindings/rust/bench/images/historical-perf-throughput.svg @@ -1,341 +1,383 @@ -Performance of throughput by version since Jun 2022 +Performance of round trip throughput by version since Jun 2022 - - - - - - + + + + + + + + + + + - - + + + + - - - + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + Throughput Version - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - + + + + + 0 GB/s - -0.5 GB/s + +0.2 GB/s - - -1 GB/s + + +0.4 GB/s - + + +0.6 GB/s + + + +0.8 GB/s + + - + 1.3.16 - - + + 1.3.18 - - + + 1.3.20 - - + + 1.3.22 - - + + 1.3.24 - - + + 1.3.26 - - + + 1.3.28 - - + + 1.3.30 - - + + 1.3.32 - - + + 1.3.34 - - + + 1.3.36 - - + + 1.3.38 - - + + 1.3.40 - - + + 1.3.42 - - + + 1.3.44 - - + + 1.3.46 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + +1.3.48 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + throughput-AES_128_GCM_SHA256 - + throughput-AES_256_GCM_SHA384 - - + + diff --git a/bindings/rust/s2n-tls-sys/templates/Cargo.template b/bindings/rust/s2n-tls-sys/templates/Cargo.template index 55f8cfef955..ae6cd88427c 100644 --- a/bindings/rust/s2n-tls-sys/templates/Cargo.template +++ b/bindings/rust/s2n-tls-sys/templates/Cargo.template @@ -1,7 +1,7 @@ [package] name = "s2n-tls-sys" description = "A C99 implementation of the TLS/SSL protocols" -version = "0.0.35" +version = "0.0.36" authors = ["AWS s2n"] edition = "2021" rust-version = "1.63.0" diff --git a/bindings/rust/s2n-tls-tokio/Cargo.toml b/bindings/rust/s2n-tls-tokio/Cargo.toml index 145e6a05de6..4418291b9a3 100644 --- a/bindings/rust/s2n-tls-tokio/Cargo.toml +++ b/bindings/rust/s2n-tls-tokio/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "s2n-tls-tokio" description = "An implementation of TLS streams for Tokio built on top of s2n-tls" -version = "0.0.35" +version = "0.0.36" authors = ["AWS s2n"] edition = "2021" rust-version = "1.63.0" @@ -15,7 +15,7 @@ default = [] errno = { version = "0.3" } libc = { version = "0.2" } pin-project-lite = { version = "0.2" } -s2n-tls = { version = "=0.0.35", path = "../s2n-tls" } +s2n-tls = { version = "=0.0.36", path = "../s2n-tls" } tokio = { version = "1", features = ["net", "time"] } [dev-dependencies] diff --git a/bindings/rust/s2n-tls/Cargo.toml b/bindings/rust/s2n-tls/Cargo.toml index 45bd4f574c9..956a0d4c914 100644 --- a/bindings/rust/s2n-tls/Cargo.toml +++ b/bindings/rust/s2n-tls/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "s2n-tls" description = "A C99 implementation of the TLS/SSL protocols" -version = "0.0.35" +version = "0.0.36" authors = ["AWS s2n"] edition = "2021" rust-version = "1.63.0" @@ -19,7 +19,7 @@ testing = ["bytes"] bytes = { version = "1", optional = true } errno = { version = "0.3" } libc = "0.2" -s2n-tls-sys = { version = "=0.0.35", path = "../s2n-tls-sys", features = ["internal"] } +s2n-tls-sys = { version = "=0.0.36", path = "../s2n-tls-sys", features = ["internal"] } pin-project-lite = "0.2" hex = "0.4" diff --git a/bindings/rust/s2n-tls/src/config.rs b/bindings/rust/s2n-tls/src/config.rs index 05c1078e101..b3c2c767ea8 100644 --- a/bindings/rust/s2n-tls/src/config.rs +++ b/bindings/rust/s2n-tls/src/config.rs @@ -660,6 +660,7 @@ impl Builder { if key_len < 16 { return Err(Error::INVALID_INPUT); } + self.enable_session_tickets(true)?; unsafe { s2n_config_add_ticket_crypto_key( self.as_mut_ptr(), @@ -672,7 +673,6 @@ impl Builder { ) .into_result() }?; - self.enable_session_tickets(true)?; Ok(self) } diff --git a/bindings/rust/s2n-tls/src/testing/resumption.rs b/bindings/rust/s2n-tls/src/testing/resumption.rs index c07ffe117ef..f8eb8c0d10c 100644 --- a/bindings/rust/s2n-tls/src/testing/resumption.rs +++ b/bindings/rust/s2n-tls/src/testing/resumption.rs @@ -43,7 +43,6 @@ mod tests { // Initialize config for server with a ticket key let mut server_config_builder = Builder::new(); server_config_builder - .enable_session_tickets(true)? .add_session_ticket_key(&KEYNAME, &KEY, SystemTime::now())? .load_pem(keypair.cert(), keypair.key())?; let server_config = server_config_builder.build()?; @@ -123,7 +122,6 @@ mod tests { // Initialize config for server with a ticket key let mut server_config_builder = Builder::new(); server_config_builder - .enable_session_tickets(true)? .add_session_ticket_key(&KEYNAME, &KEY, SystemTime::now())? .load_pem(keypair.cert(), keypair.key())? .set_security_policy(&security::DEFAULT_TLS13)?; diff --git a/error/s2n_errno.c b/error/s2n_errno.c index 2fed1cb7eec..fa20836c54d 100644 --- a/error/s2n_errno.c +++ b/error/s2n_errno.c @@ -296,6 +296,7 @@ static const char *no_such_error = "Internal s2n error"; ERR_ENTRY(S2N_ERR_KTLS_UNSUPPORTED_CONN, "kTLS is unsupported for this connection") \ ERR_ENTRY(S2N_ERR_KTLS_ULP, "An error occurred when attempting to configure the socket for kTLS. Ensure the 'tls' kernel module is enabled.") \ ERR_ENTRY(S2N_ERR_KTLS_ENABLE_CRYPTO, "An error occurred when attempting to enable kTLS on socket.") \ + ERR_ENTRY(S2N_ERR_KTLS_BAD_CMSG, "Error handling cmsghdr.") \ ERR_ENTRY(S2N_ERR_ATOMIC, "Atomic operations in this environment would require locking") \ /* clang-format on */ diff --git a/error/s2n_errno.h b/error/s2n_errno.h index 8558729248c..71e032eaa09 100644 --- a/error/s2n_errno.h +++ b/error/s2n_errno.h @@ -312,6 +312,7 @@ typedef enum { S2N_ERR_KTLS_UNSUPPORTED_CONN, S2N_ERR_KTLS_ULP, S2N_ERR_KTLS_ENABLE_CRYPTO, + S2N_ERR_KTLS_BAD_CMSG, S2N_ERR_ATOMIC, S2N_ERR_T_USAGE_END, } s2n_error; diff --git a/nix/shell.sh b/nix/shell.sh index b828a482f89..14acd88a4aa 100644 --- a/nix/shell.sh +++ b/nix/shell.sh @@ -62,7 +62,7 @@ function integ { ctest --test-dir ./build -L integrationv2 --no-tests=error --output-on-failure -R "$test" --verbose if [ "$?" -ne 0 ]; then echo "Test failed, stopping execution" - exit 1 + return 1 fi done fi diff --git a/tests/features/S2N_KTLS_SUPPORTED.c b/tests/features/S2N_KTLS_SUPPORTED.c index 6cb2789d134..b779a832dbc 100644 --- a/tests/features/S2N_KTLS_SUPPORTED.c +++ b/tests/features/S2N_KTLS_SUPPORTED.c @@ -26,5 +26,8 @@ int main() struct tls12_crypto_info_aes_gcm_128 aes_crypto_info; struct tls_crypto_info crypto_info; + int get_record_type = TLS_GET_RECORD_TYPE; + int set_record_type = TLS_SET_RECORD_TYPE; + return 0; } diff --git a/tests/testlib/s2n_ktls_test_utils.c b/tests/testlib/s2n_ktls_test_utils.c index 2b2a523f841..6df323e4c27 100644 --- a/tests/testlib/s2n_ktls_test_utils.c +++ b/tests/testlib/s2n_ktls_test_utils.c @@ -15,9 +15,14 @@ #include "testlib/s2n_ktls_test_utils.h" +S2N_RESULT s2n_ktls_set_control_data(struct msghdr *msg, char *buf, size_t buf_size, + int cmsg_type, uint8_t record_type); +S2N_RESULT s2n_ktls_get_control_data(struct msghdr *msg, int cmsg_type, uint8_t *record_type); + /* Since it is possible to read partial data, we need a way to update the length * of the previous record for the mock stuffer IO implementation. */ -static S2N_RESULT s2n_test_ktls_update_prev_header_len(struct s2n_test_ktls_io_stuffer *io_ctx, uint16_t remaining_len) +static S2N_RESULT s2n_test_ktls_update_prev_header_len(struct s2n_test_ktls_io_stuffer *io_ctx, + uint16_t remaining_len) { RESULT_ENSURE_REF(io_ctx); RESULT_ENSURE(remaining_len > 0, S2N_ERR_IO); @@ -38,19 +43,17 @@ static S2N_RESULT s2n_test_ktls_update_prev_header_len(struct s2n_test_ktls_io_s ssize_t s2n_test_ktls_sendmsg_io_stuffer(void *io_context, const struct msghdr *msg) { - POSIX_ENSURE_REF(io_context); POSIX_ENSURE_REF(msg); POSIX_ENSURE_REF(msg->msg_iov); - /* Assuming msg_control is uint8_t is a simplification and will not work when we - * attempt to test the production s2n_ktls_send implementation. However, setting/parsing - * cmsg is critical code and will be added in a separate PR. */ - uint8_t *record_type = (uint8_t *) msg->msg_control; - POSIX_ENSURE_REF(record_type); struct s2n_test_ktls_io_stuffer *io_ctx = (struct s2n_test_ktls_io_stuffer *) io_context; POSIX_ENSURE_REF(io_ctx); io_ctx->sendmsg_invoked_count++; + uint8_t record_type = 0; + struct msghdr msg_to_parse = *msg; + POSIX_GUARD_RESULT(s2n_ktls_get_control_data(&msg_to_parse, S2N_TLS_SET_RECORD_TYPE, &record_type)); + size_t total_len = 0; for (size_t count = 0; count < msg->msg_iovlen; count++) { uint8_t *buf = msg->msg_iov[count].iov_base; @@ -73,7 +76,7 @@ ssize_t s2n_test_ktls_sendmsg_io_stuffer(void *io_context, const struct msghdr * } if (total_len) { /* write record_type and len after some data was written successfully */ - POSIX_GUARD(s2n_stuffer_write_uint8(&io_ctx->ancillary_buffer, *record_type)); + POSIX_GUARD(s2n_stuffer_write_uint8(&io_ctx->ancillary_buffer, record_type)); POSIX_GUARD(s2n_stuffer_write_uint16(&io_ctx->ancillary_buffer, total_len)); } @@ -87,18 +90,13 @@ ssize_t s2n_test_ktls_sendmsg_io_stuffer(void *io_context, const struct msghdr * * are of the same type. */ ssize_t s2n_test_ktls_recvmsg_io_stuffer(void *io_context, struct msghdr *msg) { - POSIX_ENSURE_REF(io_context); POSIX_ENSURE_REF(msg); POSIX_ENSURE_REF(msg->msg_iov); - /* Assuming msg_control is uint8_t is a simplification and will not work when we - * attempt to test the production s2n_ktls_recv implementation. However, setting/parsing - * cmsg is critical code and will be added in a separate PR. */ - uint8_t *record_type = (uint8_t *) msg->msg_control; - POSIX_ENSURE_REF(record_type); struct s2n_test_ktls_io_stuffer *io_ctx = (struct s2n_test_ktls_io_stuffer *) io_context; POSIX_ENSURE_REF(io_ctx); io_ctx->recvmsg_invoked_count++; + uint8_t *buf = msg->msg_iov->iov_base; POSIX_ENSURE_REF(buf); @@ -112,10 +110,13 @@ ssize_t s2n_test_ktls_recvmsg_io_stuffer(void *io_context, struct msghdr *msg) POSIX_ENSURE_EQ(msg->msg_iovlen, 1); size_t size = msg->msg_iov->iov_len; + uint8_t record_type = 0; + POSIX_GUARD(s2n_stuffer_read_uint8(&io_ctx->ancillary_buffer, &record_type)); + POSIX_GUARD_RESULT(s2n_ktls_set_control_data(msg, msg->msg_control, msg->msg_controllen, + S2N_TLS_GET_RECORD_TYPE, record_type)); + ssize_t bytes_read = 0; while (bytes_read < size) { - /* read record_type and number of bytes available in the next record */ - POSIX_GUARD(s2n_stuffer_read_uint8(&io_ctx->ancillary_buffer, record_type)); uint16_t n_avail = 0; POSIX_GUARD(s2n_stuffer_read_uint16(&io_ctx->ancillary_buffer, &n_avail)); @@ -129,6 +130,7 @@ ssize_t s2n_test_ktls_recvmsg_io_stuffer(void *io_context, struct msghdr *msg) ssize_t remaining_len = n_avail - n_read; if (remaining_len) { POSIX_GUARD_RESULT(s2n_test_ktls_update_prev_header_len(io_ctx, remaining_len)); + break; } /* attempt to read multiple records (must be of the same type) */ @@ -138,17 +140,20 @@ ssize_t s2n_test_ktls_recvmsg_io_stuffer(void *io_context, struct msghdr *msg) if (no_more_records) { break; } - bool next_record_different_type = next_record_type != *record_type; + + bool next_record_different_type = next_record_type != record_type; if (next_record_different_type) { break; } + + POSIX_GUARD(s2n_stuffer_skip_read(&io_ctx->ancillary_buffer, sizeof(record_type))); } return bytes_read; } -S2N_RESULT s2n_test_init_ktls_io_stuffer(struct s2n_connection *server, struct s2n_connection *client, - struct s2n_test_ktls_io_stuffer_pair *io_pair) +S2N_RESULT s2n_test_init_ktls_io_stuffer(struct s2n_connection *server, + struct s2n_connection *client, struct s2n_test_ktls_io_stuffer_pair *io_pair) { RESULT_ENSURE_REF(server); RESULT_ENSURE_REF(client); diff --git a/tests/testlib/s2n_ktls_test_utils.h b/tests/testlib/s2n_ktls_test_utils.h index d20f1268696..b06373eda1c 100644 --- a/tests/testlib/s2n_ktls_test_utils.h +++ b/tests/testlib/s2n_ktls_test_utils.h @@ -62,6 +62,6 @@ struct s2n_test_ktls_io_stuffer_pair { ssize_t s2n_test_ktls_sendmsg_io_stuffer(void *io_context, const struct msghdr *msg); ssize_t s2n_test_ktls_recvmsg_io_stuffer(void *io_context, struct msghdr *msg); -S2N_RESULT s2n_test_init_ktls_io_stuffer(struct s2n_connection *server, struct s2n_connection *client, - struct s2n_test_ktls_io_stuffer_pair *io_pair); +S2N_RESULT s2n_test_init_ktls_io_stuffer(struct s2n_connection *server, + struct s2n_connection *client, struct s2n_test_ktls_io_stuffer_pair *io_pair); S2N_CLEANUP_RESULT s2n_ktls_io_stuffer_pair_free(struct s2n_test_ktls_io_stuffer_pair *pair); diff --git a/tests/unit/s2n_ktls_io_test.c b/tests/unit/s2n_ktls_io_test.c new file mode 100644 index 00000000000..c8ba335e0a8 --- /dev/null +++ b/tests/unit/s2n_ktls_io_test.c @@ -0,0 +1,78 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +#include "s2n_test.h" +#include "testlib/s2n_testlib.h" +#include "tls/s2n_ktls.h" + +S2N_RESULT s2n_ktls_set_control_data(struct msghdr *msg, char *buf, size_t buf_size, + int cmsg_type, uint8_t record_type); +S2N_RESULT s2n_ktls_get_control_data(struct msghdr *msg, int cmsg_type, uint8_t *record_type); + +int main(int argc, char **argv) +{ + BEGIN_TEST(); + + /* Test s2n_ktls_set_control_data and s2n_ktls_get_control_data */ + { + /* Test: Safety */ + { + struct msghdr msg = { 0 }; + char buf[100] = { 0 }; + EXPECT_ERROR_WITH_ERRNO(s2n_ktls_set_control_data(NULL, buf, sizeof(buf), 0, 0), + S2N_ERR_NULL); + EXPECT_ERROR_WITH_ERRNO(s2n_ktls_set_control_data(&msg, NULL, sizeof(buf), 0, 0), + S2N_ERR_NULL); + EXPECT_ERROR_WITH_ERRNO(s2n_ktls_set_control_data(&msg, buf, 0, 0, 0), + S2N_ERR_NULL); + + uint8_t record_type = 0; + EXPECT_ERROR_WITH_ERRNO(s2n_ktls_get_control_data(NULL, 0, &record_type), + S2N_ERR_NULL); + EXPECT_ERROR_WITH_ERRNO(s2n_ktls_get_control_data(&msg, 0, NULL), + S2N_ERR_NULL); + }; + + /* Test: s2n_ktls_set_control_data msg is parseable by s2n_ktls_get_control_data */ + { + const uint8_t set_record_type = 5; + struct msghdr msg = { 0 }; + const int cmsg_type = 11; + char buf[100] = { 0 }; + EXPECT_OK(s2n_ktls_set_control_data(&msg, buf, sizeof(buf), cmsg_type, set_record_type)); + + uint8_t get_record_type = 0; + EXPECT_OK(s2n_ktls_get_control_data(&msg, cmsg_type, &get_record_type)); + + EXPECT_EQUAL(set_record_type, get_record_type); + }; + + /* Test: s2n_ktls_get_control_data fails with unexpected cmsg_type */ + { + const uint8_t set_record_type = 5; + struct msghdr msg = { 0 }; + const int cmsg_type = 11; + char buf[100] = { 0 }; + EXPECT_OK(s2n_ktls_set_control_data(&msg, buf, sizeof(buf), cmsg_type, set_record_type)); + + const int bad_cmsg_type = 99; + uint8_t get_record_type = 0; + EXPECT_ERROR_WITH_ERRNO(s2n_ktls_get_control_data(&msg, bad_cmsg_type, &get_record_type), + S2N_ERR_KTLS_BAD_CMSG); + }; + }; + + END_TEST(); +} diff --git a/tests/unit/s2n_ktls_test_utils_test.c b/tests/unit/s2n_ktls_test_utils_test.c index d3fa32da215..6be94a37608 100644 --- a/tests/unit/s2n_ktls_test_utils_test.c +++ b/tests/unit/s2n_ktls_test_utils_test.c @@ -19,7 +19,13 @@ #include "testlib/s2n_testlib.h" #include "utils/s2n_random.h" -#define S2N_TEST_TO_SEND 10 +#define S2N_TEST_TO_SEND 10 +#define S2N_CONTROL_BUF_SIZE 100 +#define S2N_TEST_MSG_IOVLEN 5 + +S2N_RESULT s2n_ktls_set_control_data(struct msghdr *msg, char *buf, size_t buf_size, + int cmsg_type, uint8_t record_type); +S2N_RESULT s2n_ktls_get_control_data(struct msghdr *msg, int cmsg_type, uint8_t *record_type); S2N_RESULT s2n_test_validate_data(struct s2n_test_ktls_io_stuffer *ktls_io, uint8_t *expected_data, uint16_t expected_len) { @@ -74,8 +80,10 @@ int main(int argc, char **argv) EXPECT_OK(s2n_test_init_ktls_io_stuffer(server, client, &io_pair)); struct iovec send_msg_iov = { .iov_base = test_data, .iov_len = S2N_TEST_TO_SEND }; - struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1, .msg_control = &test_record_type }; - /* sendmsg */ + struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1 }; + char control_buf[S2N_CONTROL_BUF_SIZE] = { 0 }; + EXPECT_OK(s2n_ktls_set_control_data(&send_msg, control_buf, sizeof(control_buf), + S2N_TLS_SET_RECORD_TYPE, test_record_type)); ssize_t bytes_written = s2n_test_ktls_sendmsg_io_stuffer(server->send_io_context, &send_msg); EXPECT_EQUAL(bytes_written, S2N_TEST_TO_SEND); @@ -98,8 +106,10 @@ int main(int argc, char **argv) EXPECT_OK(s2n_test_init_ktls_io_stuffer(server, client, &io_pair)); struct iovec send_msg_iov = { .iov_base = test_data, .iov_len = S2N_TEST_TO_SEND }; - struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1, .msg_control = &test_record_type }; - /* sendmsg */ + struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1 }; + char control_buf[S2N_CONTROL_BUF_SIZE] = { 0 }; + EXPECT_OK(s2n_ktls_set_control_data(&send_msg, control_buf, sizeof(control_buf), + S2N_TLS_SET_RECORD_TYPE, test_record_type)); ssize_t bytes_written = s2n_test_ktls_sendmsg_io_stuffer(client->send_io_context, &send_msg); EXPECT_EQUAL(bytes_written, S2N_TEST_TO_SEND); @@ -123,8 +133,10 @@ int main(int argc, char **argv) size_t send_zero = 0; struct iovec send_msg_iov = { .iov_base = test_data, .iov_len = send_zero }; - struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1, .msg_control = &test_record_type }; - /* sendmsg */ + struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1 }; + char control_buf[S2N_CONTROL_BUF_SIZE] = { 0 }; + EXPECT_OK(s2n_ktls_set_control_data(&send_msg, control_buf, sizeof(control_buf), + S2N_TLS_SET_RECORD_TYPE, test_record_type)); ssize_t bytes_written = s2n_test_ktls_sendmsg_io_stuffer(server->send_io_context, &send_msg); EXPECT_EQUAL(bytes_written, send_zero); @@ -134,7 +146,7 @@ int main(int argc, char **argv) EXPECT_EQUAL(io_pair.client_in.sendmsg_invoked_count, 1); }; - /* Send iov_len > 1 */ + /* Send msg_iovlen > 1 */ { DEFER_CLEANUP(struct s2n_connection *server = s2n_connection_new(S2N_SERVER), s2n_connection_ptr_free); @@ -144,19 +156,18 @@ int main(int argc, char **argv) s2n_ktls_io_stuffer_pair_free); EXPECT_OK(s2n_test_init_ktls_io_stuffer(server, client, &io_pair)); - uint8_t count = 5; size_t total_sent = 0; - struct iovec *send_msg_iov = NULL; - send_msg_iov = malloc(sizeof(*send_msg_iov) * count); - for (size_t i = 0; i < count; i++) { + struct iovec send_msg_iov[sizeof(struct iovec) * S2N_TEST_MSG_IOVLEN] = { 0 }; + for (size_t i = 0; i < S2N_TEST_MSG_IOVLEN; i++) { send_msg_iov[i].iov_base = test_data + total_sent; send_msg_iov[i].iov_len = S2N_TEST_TO_SEND; total_sent += S2N_TEST_TO_SEND; } - struct msghdr send_msg = { .msg_iov = send_msg_iov, .msg_iovlen = count, .msg_control = &test_record_type }; - - /* sendmsg */ + struct msghdr send_msg = { .msg_iov = send_msg_iov, .msg_iovlen = S2N_TEST_MSG_IOVLEN }; + char control_buf[S2N_CONTROL_BUF_SIZE] = { 0 }; + EXPECT_OK(s2n_ktls_set_control_data(&send_msg, control_buf, sizeof(control_buf), + S2N_TLS_SET_RECORD_TYPE, test_record_type)); ssize_t bytes_written = s2n_test_ktls_sendmsg_io_stuffer(server->send_io_context, &send_msg); EXPECT_EQUAL(bytes_written, total_sent); @@ -166,8 +177,6 @@ int main(int argc, char **argv) /* validate only 1 record was sent */ EXPECT_EQUAL(s2n_stuffer_data_available(&io_pair.client_in.ancillary_buffer), S2N_TEST_KTLS_MOCK_HEADER_SIZE); EXPECT_EQUAL(io_pair.client_in.sendmsg_invoked_count, 1); - - free(send_msg_iov); }; /* Send multiple records of same type */ @@ -182,13 +191,16 @@ int main(int argc, char **argv) size_t records_to_send = 5; struct iovec send_msg_iov = { .iov_len = S2N_TEST_TO_SEND }; - struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1, .msg_control = &test_record_type }; + struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1 }; + char control_buf[S2N_CONTROL_BUF_SIZE] = { 0 }; + size_t total_sent = 0; for (size_t i = 0; i < records_to_send; i++) { /* increment test data ptr */ send_msg_iov.iov_base = test_data + total_sent; - /* sendmsg */ + EXPECT_OK(s2n_ktls_set_control_data(&send_msg, control_buf, sizeof(control_buf), + S2N_TLS_SET_RECORD_TYPE, test_record_type)); ssize_t bytes_written = s2n_test_ktls_sendmsg_io_stuffer(server->send_io_context, &send_msg); EXPECT_EQUAL(bytes_written, S2N_TEST_TO_SEND); total_sent += bytes_written; @@ -221,13 +233,15 @@ int main(int argc, char **argv) size_t records_to_send = 5; struct iovec send_msg_iov = { .iov_len = S2N_TEST_TO_SEND }; struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1 }; + char control_buf[S2N_CONTROL_BUF_SIZE] = { 0 }; + size_t total_sent = 0; for (size_t i = 0; i < records_to_send; i++) { /* increment test data ptr */ send_msg_iov.iov_base = test_data + total_sent; - send_msg.msg_control = &i; - /* sendmsg */ + EXPECT_OK(s2n_ktls_set_control_data(&send_msg, control_buf, sizeof(control_buf), + S2N_TLS_SET_RECORD_TYPE, i)); ssize_t bytes_written = s2n_test_ktls_sendmsg_io_stuffer(server->send_io_context, &send_msg); EXPECT_EQUAL(bytes_written, S2N_TEST_TO_SEND); total_sent += bytes_written; @@ -261,9 +275,14 @@ int main(int argc, char **argv) size_t to_send = 1; struct iovec send_msg_iov = { .iov_base = test_data, .iov_len = to_send }; - struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1, .msg_control = &test_record_type }; + struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1 }; + char control_buf[S2N_CONTROL_BUF_SIZE] = { 0 }; + /* attempt sendmsg and expect EAGAIN */ - for (size_t i = 0; i < 5; i++) { + size_t blocked_invoked_count = 5; + for (size_t i = 0; i < blocked_invoked_count; i++) { + EXPECT_OK(s2n_ktls_set_control_data(&send_msg, control_buf, sizeof(control_buf), + S2N_TLS_SET_RECORD_TYPE, test_record_type)); EXPECT_EQUAL(s2n_test_ktls_sendmsg_io_stuffer(server->send_io_context, &send_msg), S2N_FAILURE); EXPECT_EQUAL(errno, EAGAIN); } @@ -281,7 +300,7 @@ int main(int argc, char **argv) /* validate only 1 record was sent */ EXPECT_EQUAL(s2n_stuffer_data_available(&io_pair.client_in.ancillary_buffer), S2N_TEST_KTLS_MOCK_HEADER_SIZE); - EXPECT_EQUAL(io_pair.client_in.sendmsg_invoked_count, 6); + EXPECT_EQUAL(io_pair.client_in.sendmsg_invoked_count, blocked_invoked_count + 1); }; /* Attempt partial write with iov_len > 1 and expect error */ @@ -297,25 +316,23 @@ int main(int argc, char **argv) io_pair.client_in.data_buffer.growable = false; EXPECT_SUCCESS(s2n_stuffer_alloc(&io_pair.client_in.data_buffer, S2N_TEST_TO_SEND)); - uint8_t count = 2; - struct iovec *send_msg_iov = NULL; - send_msg_iov = malloc(sizeof(*send_msg_iov) * count); uint8_t *test_data_ptr = test_data; - for (size_t i = 0; i < count; i++) { + struct iovec send_msg_iov[sizeof(struct iovec) * S2N_TEST_MSG_IOVLEN] = { 0 }; + for (size_t i = 0; i < S2N_TEST_MSG_IOVLEN; i++) { send_msg_iov[i].iov_base = (void *) test_data_ptr; send_msg_iov[i].iov_len = S2N_TEST_TO_SEND; test_data_ptr += S2N_TEST_TO_SEND; } - struct msghdr send_msg = { .msg_iov = send_msg_iov, .msg_iovlen = count, .msg_control = &test_record_type }; - - /* sendmsg */ + struct msghdr send_msg = { .msg_iov = send_msg_iov, .msg_iovlen = S2N_TEST_MSG_IOVLEN }; + char control_buf[S2N_CONTROL_BUF_SIZE] = { 0 }; + EXPECT_OK(s2n_ktls_set_control_data(&send_msg, control_buf, sizeof(control_buf), + S2N_TLS_SET_RECORD_TYPE, test_record_type)); EXPECT_FAILURE_WITH_ERRNO(s2n_test_ktls_sendmsg_io_stuffer(server->send_io_context, &send_msg), S2N_ERR_SAFETY); /* validate no record were sent */ EXPECT_EQUAL(s2n_stuffer_data_available(&io_pair.client_in.ancillary_buffer), 0); EXPECT_EQUAL(io_pair.client_in.sendmsg_invoked_count, 1); - free(send_msg_iov); }; }; @@ -332,20 +349,28 @@ int main(int argc, char **argv) EXPECT_OK(s2n_test_init_ktls_io_stuffer(server, client, &io_pair)); struct iovec send_msg_iov = { .iov_base = test_data, .iov_len = to_send }; - struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1, .msg_control = &test_record_type }; - /* sendmsg */ + struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1 }; + char send_ctrl_buf[S2N_CONTROL_BUF_SIZE] = { 0 }; + EXPECT_OK(s2n_ktls_set_control_data(&send_msg, send_ctrl_buf, sizeof(send_ctrl_buf), + S2N_TLS_SET_RECORD_TYPE, test_record_type)); ssize_t bytes_written = s2n_test_ktls_sendmsg_io_stuffer(server->send_io_context, &send_msg); EXPECT_EQUAL(bytes_written, to_send); uint8_t recv_buffer[S2N_TLS_MAXIMUM_FRAGMENT_LENGTH] = { 0 }; - uint8_t recv_record_type = 0; + char recv_ctrl_buf[S2N_CONTROL_BUF_SIZE] = { 0 }; struct iovec recv_msg_iov = { .iov_base = recv_buffer, .iov_len = to_send }; - struct msghdr recv_msg = { .msg_iov = &recv_msg_iov, .msg_iovlen = 1, .msg_control = &recv_record_type }; - /* recvmsg */ + struct msghdr recv_msg = { + .msg_iov = &recv_msg_iov, + .msg_iovlen = 1, + .msg_control = recv_ctrl_buf, + .msg_controllen = sizeof(recv_ctrl_buf), + }; ssize_t bytes_read = s2n_test_ktls_recvmsg_io_stuffer(client->recv_io_context, &recv_msg); EXPECT_EQUAL(bytes_read, to_send); /* confirm read data */ EXPECT_BYTEARRAY_EQUAL(test_data, recv_buffer, to_send); + uint8_t recv_record_type = 0; + EXPECT_OK(s2n_ktls_get_control_data(&recv_msg, S2N_TLS_GET_RECORD_TYPE, &recv_record_type)); EXPECT_EQUAL(recv_record_type, test_record_type); EXPECT_EQUAL(io_pair.client_in.sendmsg_invoked_count, 1); @@ -364,16 +389,23 @@ int main(int argc, char **argv) size_t to_send = 1; uint8_t recv_buffer[S2N_TLS_MAXIMUM_FRAGMENT_LENGTH] = { 0 }; - uint8_t recv_record_type = 0; struct iovec recv_msg_iov = { .iov_base = recv_buffer, .iov_len = to_send }; - struct msghdr recv_msg = { .msg_iov = &recv_msg_iov, .msg_iovlen = 1, .msg_control = &recv_record_type }; + char recv_ctrl_buf[S2N_CONTROL_BUF_SIZE] = { 0 }; + struct msghdr recv_msg = { + .msg_iov = &recv_msg_iov, + .msg_iovlen = 1, + .msg_control = recv_ctrl_buf, + .msg_controllen = sizeof(recv_ctrl_buf), + }; /* attempting to recv data when nothing has been sent blocks */ EXPECT_EQUAL(s2n_test_ktls_recvmsg_io_stuffer(client->recv_io_context, &recv_msg), S2N_FAILURE); EXPECT_EQUAL(errno, EAGAIN); struct iovec send_msg_iov = { .iov_base = test_data, .iov_len = to_send }; - struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1, .msg_control = &test_record_type }; - /* sendmsg */ + struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1 }; + char send_ctrl_buf[S2N_CONTROL_BUF_SIZE] = { 0 }; + EXPECT_OK(s2n_ktls_set_control_data(&send_msg, send_ctrl_buf, sizeof(send_ctrl_buf), + S2N_TLS_SET_RECORD_TYPE, test_record_type)); ssize_t bytes_written = s2n_test_ktls_sendmsg_io_stuffer(server->send_io_context, &send_msg); EXPECT_EQUAL(bytes_written, to_send); @@ -383,16 +415,19 @@ int main(int argc, char **argv) EXPECT_EQUAL(bytes_read, to_send); /* confirm read data */ EXPECT_BYTEARRAY_EQUAL(test_data, recv_buffer, to_send); + uint8_t recv_record_type = 0; + EXPECT_OK(s2n_ktls_get_control_data(&recv_msg, S2N_TLS_GET_RECORD_TYPE, &recv_record_type)); EXPECT_EQUAL(recv_record_type, test_record_type); - for (size_t i = 0; i < 5; i++) { + size_t blocked_invoked_count = 5; + for (size_t i = 0; i < blocked_invoked_count; i++) { /* attempting to recv more data blocks */ EXPECT_EQUAL(s2n_test_ktls_recvmsg_io_stuffer(client->recv_io_context, &recv_msg), S2N_FAILURE); EXPECT_EQUAL(errno, EAGAIN); } EXPECT_EQUAL(io_pair.client_in.sendmsg_invoked_count, 1); - EXPECT_EQUAL(io_pair.client_in.recvmsg_invoked_count, 7); + EXPECT_EQUAL(io_pair.client_in.recvmsg_invoked_count, blocked_invoked_count + 2); }; /* Read partial data: request < total sent */ @@ -410,21 +445,29 @@ int main(int argc, char **argv) size_t remaining_len = to_send - to_recv; struct iovec send_msg_iov = { .iov_base = test_data, .iov_len = to_send }; - struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1, .msg_control = &test_record_type }; - /* sendmsg */ + struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1 }; + char send_ctrl_buf[S2N_CONTROL_BUF_SIZE] = { 0 }; + EXPECT_OK(s2n_ktls_set_control_data(&send_msg, send_ctrl_buf, sizeof(send_ctrl_buf), + S2N_TLS_SET_RECORD_TYPE, test_record_type)); ssize_t bytes_written = s2n_test_ktls_sendmsg_io_stuffer(server->send_io_context, &send_msg); EXPECT_EQUAL(bytes_written, to_send); uint8_t recv_buffer[S2N_TLS_MAXIMUM_FRAGMENT_LENGTH] = { 0 }; - uint8_t recv_record_type = 0; + char recv_ctrl_buf[S2N_CONTROL_BUF_SIZE] = { 0 }; struct iovec recv_msg_iov = { .iov_base = recv_buffer, .iov_len = to_recv }; - struct msghdr recv_msg = { .msg_iov = &recv_msg_iov, .msg_iovlen = 1, .msg_control = &recv_record_type }; - /* recvmsg */ + struct msghdr recv_msg = { + .msg_iov = &recv_msg_iov, + .msg_iovlen = 1, + .msg_control = recv_ctrl_buf, + .msg_controllen = sizeof(recv_ctrl_buf), + }; ssize_t bytes_read = s2n_test_ktls_recvmsg_io_stuffer(client->recv_io_context, &recv_msg); EXPECT_EQUAL(bytes_read, to_recv); /* confirm read data */ EXPECT_BYTEARRAY_EQUAL(test_data, recv_buffer, to_recv); - EXPECT_EQUAL(recv_record_type, test_record_type); + uint8_t recv_record_type_1 = 0; + EXPECT_OK(s2n_ktls_get_control_data(&recv_msg, S2N_TLS_GET_RECORD_TYPE, &recv_record_type_1)); + EXPECT_EQUAL(recv_record_type_1, test_record_type); /* confirm that a single records still exists; data len is updated on partial reads */ EXPECT_EQUAL(s2n_stuffer_data_available(&io_pair.client_in.ancillary_buffer), S2N_TEST_KTLS_MOCK_HEADER_SIZE); @@ -434,7 +477,10 @@ int main(int argc, char **argv) recv_msg_iov.iov_len = remaining_len; bytes_read = s2n_test_ktls_recvmsg_io_stuffer(client->recv_io_context, &recv_msg); EXPECT_EQUAL(bytes_read, remaining_len); - EXPECT_EQUAL(recv_record_type, test_record_type); + /* confirm read data */ + uint8_t recv_record_type_2 = 0; + EXPECT_OK(s2n_ktls_get_control_data(&recv_msg, S2N_TLS_GET_RECORD_TYPE, &recv_record_type_2)); + EXPECT_EQUAL(recv_record_type_2, test_record_type); /* validate all sent/recv data */ EXPECT_BYTEARRAY_EQUAL(test_data, recv_buffer, to_send); @@ -459,21 +505,29 @@ int main(int argc, char **argv) size_t to_recv = 15; struct iovec send_msg_iov = { .iov_base = test_data, .iov_len = to_send }; - struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1, .msg_control = &test_record_type }; - /* sendmsg */ + struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1 }; + char send_ctrl_buf[S2N_CONTROL_BUF_SIZE] = { 0 }; + EXPECT_OK(s2n_ktls_set_control_data(&send_msg, send_ctrl_buf, sizeof(send_ctrl_buf), + S2N_TLS_SET_RECORD_TYPE, test_record_type)); ssize_t bytes_written = s2n_test_ktls_sendmsg_io_stuffer(server->send_io_context, &send_msg); EXPECT_EQUAL(bytes_written, to_send); uint8_t recv_buffer[S2N_TLS_MAXIMUM_FRAGMENT_LENGTH] = { 0 }; - uint8_t recv_record_type = 0; struct iovec recv_msg_iov = { .iov_base = recv_buffer, .iov_len = to_recv }; - struct msghdr recv_msg = { .msg_iov = &recv_msg_iov, .msg_iovlen = 1, .msg_control = &recv_record_type }; - /* recvmsg */ + char recv_ctrl_buf[S2N_CONTROL_BUF_SIZE] = { 0 }; + struct msghdr recv_msg = { + .msg_iov = &recv_msg_iov, + .msg_iovlen = 1, + .msg_control = recv_ctrl_buf, + .msg_controllen = sizeof(recv_ctrl_buf), + }; ssize_t bytes_read = s2n_test_ktls_recvmsg_io_stuffer(client->recv_io_context, &recv_msg); /* confirm read data: minimum of sent and requested (to_send) */ EXPECT_EQUAL(bytes_read, to_send); EXPECT_BYTEARRAY_EQUAL(test_data, recv_buffer, to_send); + uint8_t recv_record_type = 0; + EXPECT_OK(s2n_ktls_get_control_data(&recv_msg, S2N_TLS_GET_RECORD_TYPE, &recv_record_type)); EXPECT_EQUAL(recv_record_type, test_record_type); EXPECT_EQUAL(io_pair.client_in.sendmsg_invoked_count, 1); @@ -496,25 +550,33 @@ int main(int argc, char **argv) size_t to_recv = 10; struct iovec send_msg_iov = { .iov_base = test_data, .iov_len = to_send }; - struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1, .msg_control = &test_record_type }; + struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1 }; + char send_ctrl_buf[S2N_CONTROL_BUF_SIZE] = { 0 }; + EXPECT_OK(s2n_ktls_set_control_data(&send_msg, send_ctrl_buf, sizeof(send_ctrl_buf), + S2N_TLS_SET_RECORD_TYPE, test_record_type)); size_t total_sent = 0; for (size_t i = 0; i < records_to_send; i++) { /* increment test data ptr */ send_msg_iov.iov_base = test_data + total_sent; - /* sendmsg */ ssize_t bytes_written = s2n_test_ktls_sendmsg_io_stuffer(server->send_io_context, &send_msg); EXPECT_EQUAL(bytes_written, to_send); total_sent += bytes_written; } uint8_t recv_buffer[S2N_TLS_MAXIMUM_FRAGMENT_LENGTH] = { 0 }; - uint8_t recv_record_type = 0; + char recv_ctrl_buf[S2N_CONTROL_BUF_SIZE] = { 0 }; struct iovec recv_msg_iov = { .iov_base = recv_buffer, .iov_len = to_recv }; - struct msghdr recv_msg = { .msg_iov = &recv_msg_iov, .msg_iovlen = 1, .msg_control = &recv_record_type }; - /* recvmsg */ + struct msghdr recv_msg = { + .msg_iov = &recv_msg_iov, + .msg_iovlen = 1, + .msg_control = recv_ctrl_buf, + .msg_controllen = sizeof(recv_ctrl_buf), + }; ssize_t bytes_read = s2n_test_ktls_recvmsg_io_stuffer(client->recv_io_context, &recv_msg); EXPECT_EQUAL(bytes_read, to_recv); + uint8_t recv_record_type = 0; + EXPECT_OK(s2n_ktls_get_control_data(&recv_msg, S2N_TLS_GET_RECORD_TYPE, &recv_record_type)); EXPECT_EQUAL(recv_record_type, test_record_type); /* validate all data was received */ @@ -545,32 +607,44 @@ int main(int argc, char **argv) struct iovec send_msg_iov = { .iov_base = test_data, .iov_len = to_send }; struct msghdr send_msg = { .msg_iov = &send_msg_iov, .msg_iovlen = 1 }; + char send_ctrl_buf[S2N_CONTROL_BUF_SIZE] = { 0 }; /* sendmsg record_type_1 */ - send_msg.msg_control = &record_type_1; + EXPECT_OK(s2n_ktls_set_control_data(&send_msg, send_ctrl_buf, sizeof(send_ctrl_buf), + S2N_TLS_SET_RECORD_TYPE, record_type_1)); ssize_t bytes_written = s2n_test_ktls_sendmsg_io_stuffer(server->send_io_context, &send_msg); EXPECT_EQUAL(bytes_written, to_send); total_sent += bytes_written; /* sendmsg record_type_2 */ - send_msg.msg_control = &record_type_2; + EXPECT_OK(s2n_ktls_set_control_data(&send_msg, send_ctrl_buf, sizeof(send_ctrl_buf), + S2N_TLS_SET_RECORD_TYPE, record_type_2)); send_msg_iov.iov_base = test_data + total_sent; bytes_written = s2n_test_ktls_sendmsg_io_stuffer(server->send_io_context, &send_msg); EXPECT_EQUAL(bytes_written, to_send); total_sent += bytes_written; uint8_t recv_buffer[S2N_TLS_MAXIMUM_FRAGMENT_LENGTH] = { 0 }; - uint8_t recv_record_type = 0; + char recv_ctrl_buf[S2N_CONTROL_BUF_SIZE] = { 0 }; struct iovec recv_msg_iov = { .iov_base = recv_buffer, .iov_len = to_recv }; - struct msghdr recv_msg = { .msg_iov = &recv_msg_iov, .msg_iovlen = 1, .msg_control = &recv_record_type }; + struct msghdr recv_msg = { + .msg_iov = &recv_msg_iov, + .msg_iovlen = 1, + .msg_control = recv_ctrl_buf, + .msg_controllen = sizeof(recv_ctrl_buf), + }; /* only recv record_type_1 even though we request more data */ ssize_t bytes_read = s2n_test_ktls_recvmsg_io_stuffer(client->recv_io_context, &recv_msg); EXPECT_EQUAL(bytes_read, to_send); - EXPECT_EQUAL(recv_record_type, record_type_1); + uint8_t recv_record_type_1 = 0; + EXPECT_OK(s2n_ktls_get_control_data(&recv_msg, S2N_TLS_GET_RECORD_TYPE, &recv_record_type_1)); + EXPECT_EQUAL(recv_record_type_1, record_type_1); total_recv += bytes_read; /* only recv record_type_2; which is all that remains */ recv_msg_iov.iov_base = recv_buffer + bytes_read; bytes_read = s2n_test_ktls_recvmsg_io_stuffer(client->recv_io_context, &recv_msg); EXPECT_EQUAL(bytes_read, to_send); - EXPECT_EQUAL(recv_record_type, record_type_2); + uint8_t recv_record_type_2 = 0; + EXPECT_OK(s2n_ktls_get_control_data(&recv_msg, S2N_TLS_GET_RECORD_TYPE, &recv_record_type_2)); + EXPECT_EQUAL(recv_record_type_2, record_type_2); total_recv += bytes_read; /* validate all data was received (we offset the test_data/recv_buffer so the diff --git a/tests/unit/s2n_self_talk_tls13_test.c b/tests/unit/s2n_self_talk_tls13_test.c index 9a311f82fe3..94e8e3b1b75 100644 --- a/tests/unit/s2n_self_talk_tls13_test.c +++ b/tests/unit/s2n_self_talk_tls13_test.c @@ -138,6 +138,7 @@ int main(int argc, char **argv) /* Negotiate the handshake. */ EXPECT_SUCCESS(s2n_negotiate(conn, &blocked)); + EXPECT_NOT_NULL(s2n_connection_get_client_hello(conn)); EXPECT_EQUAL(conn->actual_protocol_version, s2n_get_highest_fully_supported_tls_version()); char buffer[0xffff]; diff --git a/tests/unit/s2n_server_hello_retry_test.c b/tests/unit/s2n_server_hello_retry_test.c index 0df4264dff3..ae44a31104c 100644 --- a/tests/unit/s2n_server_hello_retry_test.c +++ b/tests/unit/s2n_server_hello_retry_test.c @@ -507,6 +507,7 @@ int main(int argc, char **argv) EXPECT_TRUE(server_conn->handshake.handshake_type & HELLO_RETRY_REQUEST); EXPECT_EQUAL(client_hello_ctx.invocations, 1); + EXPECT_NOT_NULL(s2n_connection_get_client_hello(server_conn)); EXPECT_TRUE(IS_HELLO_RETRY_HANDSHAKE(client_conn)); EXPECT_TRUE(IS_HELLO_RETRY_HANDSHAKE(server_conn)); diff --git a/tls/s2n_client_hello.c b/tls/s2n_client_hello.c index a2391027db1..dacfc0b9d88 100644 --- a/tls/s2n_client_hello.c +++ b/tls/s2n_client_hello.c @@ -43,7 +43,7 @@ struct s2n_client_hello *s2n_connection_get_client_hello(struct s2n_connection *conn) { - if (conn->client_hello.callback_invoked != 1) { + if (conn->client_hello.parsed != 1) { return NULL; } @@ -638,6 +638,7 @@ int s2n_client_hello_recv(struct s2n_connection *conn) /* Only parse the ClientHello once */ if (!conn->client_hello.parsed) { POSIX_GUARD(s2n_parse_client_hello(conn)); + /* Mark the collected client hello as available when parsing is done and before the client hello callback */ conn->client_hello.parsed = true; } @@ -647,7 +648,7 @@ int s2n_client_hello_recv(struct s2n_connection *conn) * callback state may have been cleared while parsing the second ClientHello. */ if (!conn->client_hello.callback_invoked && !IS_HELLO_RETRY_HANDSHAKE(conn)) { - /* Mark the collected client hello as available when parsing is done and before the client hello callback */ + /* Mark the client hello callback as invoked to avoid calling it again. */ conn->client_hello.callback_invoked = true; /* Call client_hello_cb if exists, letting application to modify s2n_connection or swap s2n_config */ diff --git a/tls/s2n_ktls.h b/tls/s2n_ktls.h index 3e4b7809adb..e8d092433d4 100644 --- a/tls/s2n_ktls.h +++ b/tls/s2n_ktls.h @@ -36,20 +36,21 @@ typedef enum { S2N_KTLS_MODE_RECV, } s2n_ktls_mode; -/* Used for overriding setsockopt calls in testing */ -typedef int (*s2n_setsockopt_fn)(int socket, int level, int option_name, - const void *option_value, socklen_t option_len); -S2N_RESULT s2n_ktls_set_setsockopt_cb(s2n_setsockopt_fn cb); - bool s2n_ktls_is_supported_on_platform(); -S2N_RESULT s2n_ktls_get_file_descriptor(struct s2n_connection *conn, s2n_ktls_mode ktls_mode, int *fd); +S2N_RESULT s2n_ktls_get_file_descriptor(struct s2n_connection *conn, s2n_ktls_mode ktls_mode, + int *fd); /* These functions will be part of the public API. */ int s2n_connection_ktls_enable_send(struct s2n_connection *conn); int s2n_connection_ktls_enable_recv(struct s2n_connection *conn); /* Testing */ +typedef int (*s2n_setsockopt_fn)(int socket, int level, int option_name, const void *option_value, + socklen_t option_len); +S2N_RESULT s2n_ktls_set_setsockopt_cb(s2n_setsockopt_fn cb); typedef ssize_t (*s2n_ktls_sendmsg_fn)(void *io_context, const struct msghdr *msg); typedef ssize_t (*s2n_ktls_recvmsg_fn)(void *io_context, struct msghdr *msg); -S2N_RESULT s2n_ktls_set_sendmsg_cb(struct s2n_connection *conn, s2n_ktls_sendmsg_fn send_cb, void *send_ctx); -S2N_RESULT s2n_ktls_set_recvmsg_cb(struct s2n_connection *conn, s2n_ktls_recvmsg_fn recv_cb, void *recv_ctx); +S2N_RESULT s2n_ktls_set_sendmsg_cb(struct s2n_connection *conn, s2n_ktls_sendmsg_fn send_cb, + void *send_ctx); +S2N_RESULT s2n_ktls_set_recvmsg_cb(struct s2n_connection *conn, s2n_ktls_recvmsg_fn recv_cb, + void *recv_ctx); diff --git a/tls/s2n_ktls_io.c b/tls/s2n_ktls_io.c index 16ef4ee7edb..c4b02a88e7a 100644 --- a/tls/s2n_ktls_io.c +++ b/tls/s2n_ktls_io.c @@ -13,16 +13,35 @@ * permissions and limitations under the License. */ +#if defined(__FreeBSD__) || defined(__APPLE__) + /* https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html + * The POSIX standard does not define the CMSG_LEN and CMSG_SPACE macros. FreeBSD + * and APPLE check and disable these macros if the _POSIX_C_SOURCE flag is set. + * + * Since s2n-tls already unsets the _POSIX_C_SOURCE in other files and is not + * POSIX compliant, we continue the pattern here. + */ + #undef _POSIX_C_SOURCE +#endif +#include + +#include "error/s2n_errno.h" #include "tls/s2n_ktls.h" +#include "utils/s2n_result.h" +#include "utils/s2n_safety.h" #include "utils/s2n_socket.h" +/* record_type is of type uint8_t */ +#define S2N_KTLS_RECORD_TYPE_SIZE (sizeof(uint8_t)) + /* Used to override sendmsg and recvmsg for testing. */ static ssize_t s2n_ktls_default_sendmsg(void *io_context, const struct msghdr *msg); static ssize_t s2n_ktls_default_recvmsg(void *io_context, struct msghdr *msg); s2n_ktls_sendmsg_fn s2n_sendmsg_fn = s2n_ktls_default_sendmsg; s2n_ktls_recvmsg_fn s2n_recvmsg_fn = s2n_ktls_default_recvmsg; -S2N_RESULT s2n_ktls_set_sendmsg_cb(struct s2n_connection *conn, s2n_ktls_sendmsg_fn send_cb, void *send_ctx) +S2N_RESULT s2n_ktls_set_sendmsg_cb(struct s2n_connection *conn, s2n_ktls_sendmsg_fn send_cb, + void *send_ctx) { RESULT_ENSURE_REF(conn); RESULT_ENSURE_REF(send_ctx); @@ -32,7 +51,8 @@ S2N_RESULT s2n_ktls_set_sendmsg_cb(struct s2n_connection *conn, s2n_ktls_sendmsg return S2N_RESULT_OK; } -S2N_RESULT s2n_ktls_set_recvmsg_cb(struct s2n_connection *conn, s2n_ktls_recvmsg_fn recv_cb, void *recv_ctx) +S2N_RESULT s2n_ktls_set_recvmsg_cb(struct s2n_connection *conn, s2n_ktls_recvmsg_fn recv_cb, + void *recv_ctx) { RESULT_ENSURE_REF(conn); RESULT_ENSURE_REF(recv_ctx); @@ -65,3 +85,92 @@ static ssize_t s2n_ktls_default_sendmsg(void *io_context, const struct msghdr *m return sendmsg(fd, msg, 0); } + +S2N_RESULT s2n_ktls_set_control_data(struct msghdr *msg, char *buf, size_t buf_size, + int cmsg_type, uint8_t record_type) +{ + RESULT_ENSURE_REF(msg); + RESULT_ENSURE_REF(buf); + + /* + * https://man7.org/linux/man-pages/man3/cmsg.3.html + * To create ancillary data, first initialize the msg_controllen + * member of the msghdr with the length of the control message + * buffer. + */ + msg->msg_control = buf; + msg->msg_controllen = buf_size; + + /* + * https://man7.org/linux/man-pages/man3/cmsg.3.html + * Use CMSG_FIRSTHDR() on the msghdr to get the first + * control message and CMSG_NXTHDR() to get all subsequent ones. + */ + struct cmsghdr *hdr = CMSG_FIRSTHDR(msg); + RESULT_ENSURE_REF(hdr); + + /* + * https://man7.org/linux/man-pages/man3/cmsg.3.html + * In each control message, initialize cmsg_len (with CMSG_LEN()), the + * other cmsghdr header fields, and the data portion using + * CMSG_DATA(). + */ + hdr->cmsg_len = CMSG_LEN(S2N_KTLS_RECORD_TYPE_SIZE); + hdr->cmsg_level = S2N_SOL_TLS; + hdr->cmsg_type = cmsg_type; + *CMSG_DATA(hdr) = record_type; + + /* + * https://man7.org/linux/man-pages/man3/cmsg.3.html + * Finally, the msg_controllen field of the msghdr + * should be set to the sum of the CMSG_SPACE() of the length of all + * control messages in the buffer + */ + RESULT_ENSURE_GTE(msg->msg_controllen, CMSG_SPACE(S2N_KTLS_RECORD_TYPE_SIZE)); + msg->msg_controllen = CMSG_SPACE(S2N_KTLS_RECORD_TYPE_SIZE); + + return S2N_RESULT_OK; +} + +/* Expect to receive a single cmsghdr containing the TLS record_type. + * + * s2n-tls allocates enough space to receive a single cmsghdr. Since this is + * used to get the record_type when receiving over kTLS (enabled via + * `s2n_connection_ktls_enable_recv`), the application should not configure + * the socket to receive additional control messages. In the event s2n-tls + * can not retrieve the record_type, it is safer to drop the record. + */ +S2N_RESULT s2n_ktls_get_control_data(struct msghdr *msg, int cmsg_type, uint8_t *record_type) +{ + RESULT_ENSURE_REF(msg); + RESULT_ENSURE_REF(record_type); + + /* + * https://man7.org/linux/man-pages/man3/cmsg.3.html + * To create ancillary data, first initialize the msg_controllen + * member of the msghdr with the length of the control message + * buffer. + */ + RESULT_ENSURE(msg->msg_control, S2N_ERR_SAFETY); + RESULT_ENSURE(msg->msg_controllen >= CMSG_SPACE(S2N_KTLS_RECORD_TYPE_SIZE), S2N_ERR_SAFETY); + + /* https://man7.org/linux/man-pages/man3/cmsg.3.html + * Use CMSG_FIRSTHDR() on the msghdr to get the first + * control message and CMSG_NXTHDR() to get all subsequent ones. + */ + struct cmsghdr *hdr = CMSG_FIRSTHDR(msg); + RESULT_ENSURE(hdr, S2N_ERR_KTLS_BAD_CMSG); + + /* + * https://man7.org/linux/man-pages/man3/cmsg.3.html + * In each control message, initialize cmsg_len (with CMSG_LEN()), the + * other cmsghdr header fields, and the data portion using + * CMSG_DATA(). + */ + RESULT_ENSURE(hdr->cmsg_level == S2N_SOL_TLS, S2N_ERR_KTLS_BAD_CMSG); + RESULT_ENSURE(hdr->cmsg_type == cmsg_type, S2N_ERR_KTLS_BAD_CMSG); + RESULT_ENSURE(hdr->cmsg_len == CMSG_LEN(S2N_KTLS_RECORD_TYPE_SIZE), S2N_ERR_KTLS_BAD_CMSG); + *record_type = *CMSG_DATA(hdr); + + return S2N_RESULT_OK; +} diff --git a/tls/s2n_ktls_parameters.h b/tls/s2n_ktls_parameters.h index 0137467c242..c3f1482c4fb 100644 --- a/tls/s2n_ktls_parameters.h +++ b/tls/s2n_ktls_parameters.h @@ -41,6 +41,8 @@ #define S2N_TLS_TX 1 #define S2N_TLS_RX 2 + #define S2N_TLS_SET_RECORD_TYPE TLS_SET_RECORD_TYPE + #define S2N_TLS_GET_RECORD_TYPE TLS_GET_RECORD_TYPE #else /* For unsupported platforms 0-init (array of size 1) all values. */ @@ -51,6 +53,9 @@ #define S2N_TLS_TX 0 #define S2N_TLS_RX 0 + + #define S2N_TLS_SET_RECORD_TYPE 0 + #define S2N_TLS_GET_RECORD_TYPE 0 #endif /* Common */