diff --git a/tests/unit/s2n_ktls_test.c b/tests/unit/s2n_ktls_test.c new file mode 100644 index 00000000000..7417e13da4c --- /dev/null +++ b/tests/unit/s2n_ktls_test.c @@ -0,0 +1,202 @@ +/* + * 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 + +#include "api/s2n.h" +#include "crypto/s2n_fips.h" +#include "s2n_test.h" +#include "testlib/s2n_testlib.h" +#include "tls/s2n_config.h" +#include "tls/s2n_connection.h" +#include "tls/s2n_record.h" +#include "tls/s2n_security_policies.h" +#include "tls/s2n_tls13.h" + +int main(int argc, char **argv) +{ + BEGIN_TEST(); + EXPECT_SUCCESS(s2n_disable_tls13_in_test()); + + const struct s2n_security_policy *default_security_policy, *tls13_security_policy, *fips_security_policy; + EXPECT_SUCCESS(s2n_find_security_policy_from_version("default_tls13", &tls13_security_policy)); + EXPECT_SUCCESS(s2n_find_security_policy_from_version("default_fips", &fips_security_policy)); + EXPECT_SUCCESS(s2n_find_security_policy_from_version("default", &default_security_policy)); + + char cert[S2N_MAX_TEST_PEM_SIZE] = { 0 }; + EXPECT_SUCCESS(s2n_read_test_pem(S2N_DEFAULT_TEST_CERT_CHAIN, cert, S2N_MAX_TEST_PEM_SIZE)); + char key[S2N_MAX_TEST_PEM_SIZE] = { 0 }; + EXPECT_SUCCESS(s2n_read_test_pem(S2N_DEFAULT_TEST_PRIVATE_KEY, key, S2N_MAX_TEST_PEM_SIZE)); + + /* config default kTLS mode */ + { + DEFER_CLEANUP(struct s2n_config *config = s2n_config_new(), s2n_config_ptr_free); + EXPECT_NOT_NULL(config); + EXPECT_EQUAL(config->ktls_mode_requested, S2N_KTLS_MODE_DISABLED); + EXPECT_TRUE(s2n_config_is_ktls_requested(config, S2N_KTLS_MODE_DISABLED)); + EXPECT_FALSE(s2n_config_is_ktls_requested(config, S2N_KTLS_MODE_TX)); + EXPECT_FALSE(s2n_config_is_ktls_requested(config, S2N_KTLS_MODE_RX)); + EXPECT_FALSE(s2n_config_is_ktls_requested(config, S2N_KTLS_MODE_DUPLEX)); + }; + + /* request config kTLS mode + * + * Enabling TX and RX modes is additive and equals Duplex + */ + { + DEFER_CLEANUP(struct s2n_config *config = s2n_config_new(), s2n_config_ptr_free); + EXPECT_NOT_NULL(config); + + EXPECT_SUCCESS(s2n_config_ktls_enable(config, S2N_KTLS_MODE_TX)); + EXPECT_FALSE(s2n_config_is_ktls_requested(config, S2N_KTLS_MODE_DISABLED)); + EXPECT_TRUE(s2n_config_is_ktls_requested(config, S2N_KTLS_MODE_TX)); + EXPECT_FALSE(s2n_config_is_ktls_requested(config, S2N_KTLS_MODE_RX)); + EXPECT_FALSE(s2n_config_is_ktls_requested(config, S2N_KTLS_MODE_DUPLEX)); + + EXPECT_SUCCESS(s2n_config_ktls_enable(config, S2N_KTLS_MODE_RX)); + EXPECT_FALSE(s2n_config_is_ktls_requested(config, S2N_KTLS_MODE_DISABLED)); + EXPECT_TRUE(s2n_config_is_ktls_requested(config, S2N_KTLS_MODE_TX)); + EXPECT_TRUE(s2n_config_is_ktls_requested(config, S2N_KTLS_MODE_RX)); + EXPECT_TRUE(s2n_config_is_ktls_requested(config, S2N_KTLS_MODE_DUPLEX)); + }; + + /* disallow kTLS disable requested + * + * kTLS cannot be disabled once it has been enabled + */ + { + DEFER_CLEANUP(struct s2n_config *config = s2n_config_new(), s2n_config_ptr_free); + EXPECT_NOT_NULL(config); + + EXPECT_SUCCESS(s2n_config_ktls_enable(config, S2N_KTLS_MODE_DUPLEX)); + EXPECT_FALSE(s2n_config_is_ktls_requested(config, S2N_KTLS_MODE_DISABLED)); + EXPECT_TRUE(s2n_config_is_ktls_requested(config, S2N_KTLS_MODE_TX)); + EXPECT_TRUE(s2n_config_is_ktls_requested(config, S2N_KTLS_MODE_RX)); + EXPECT_TRUE(s2n_config_is_ktls_requested(config, S2N_KTLS_MODE_DUPLEX)); + + EXPECT_SUCCESS(s2n_config_ktls_enable(config, S2N_KTLS_MODE_DISABLED)); + EXPECT_FALSE(s2n_config_is_ktls_requested(config, S2N_KTLS_MODE_DISABLED)); + EXPECT_TRUE(s2n_config_is_ktls_requested(config, S2N_KTLS_MODE_TX)); + EXPECT_TRUE(s2n_config_is_ktls_requested(config, S2N_KTLS_MODE_RX)); + EXPECT_TRUE(s2n_config_is_ktls_requested(config, S2N_KTLS_MODE_DUPLEX)); + }; + + /* connection default kTLS mode */ + { + DEFER_CLEANUP(struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT), + s2n_connection_ptr_free); + EXPECT_NOT_NULL(conn); + DEFER_CLEANUP(struct s2n_test_io_pair io_pair = { 0 }, s2n_io_pair_close); + EXPECT_SUCCESS(s2n_io_pair_init_non_blocking(&io_pair)); + EXPECT_SUCCESS(s2n_connection_set_io_pair(conn, &io_pair)); + EXPECT_TRUE(conn->managed_send_io); + EXPECT_TRUE(conn->managed_recv_io); + + EXPECT_EQUAL(conn->ktls_mode_enabled, S2N_KTLS_MODE_DISABLED); + EXPECT_TRUE(s2n_connection_is_ktls_enabled(conn, S2N_KTLS_MODE_DISABLED)); + EXPECT_FALSE(s2n_connection_is_ktls_enabled(conn, S2N_KTLS_MODE_TX)); + EXPECT_FALSE(s2n_connection_is_ktls_enabled(conn, S2N_KTLS_MODE_RX)); + EXPECT_FALSE(s2n_connection_is_ktls_enabled(conn, S2N_KTLS_MODE_DUPLEX)); + }; + + /* enable kTLS modes + * + * Enabling TX and RX modes is additive and equals Duplex + */ + { + DEFER_CLEANUP(struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT), + s2n_connection_ptr_free); + EXPECT_NOT_NULL(conn); + DEFER_CLEANUP(struct s2n_test_io_pair io_pair = { 0 }, s2n_io_pair_close); + EXPECT_SUCCESS(s2n_io_pair_init_non_blocking(&io_pair)); + EXPECT_SUCCESS(s2n_connection_set_io_pair(conn, &io_pair)); + EXPECT_TRUE(conn->managed_send_io); + EXPECT_TRUE(conn->managed_recv_io); + + DEFER_CLEANUP(struct s2n_config *config = s2n_config_new(), s2n_config_ptr_free); + EXPECT_NOT_NULL(config); + EXPECT_SUCCESS(s2n_config_ktls_enable(config, S2N_KTLS_MODE_DUPLEX)); + EXPECT_SUCCESS(s2n_connection_set_config(conn, config)); + + EXPECT_EQUAL(conn->ktls_mode_enabled, S2N_KTLS_MODE_DISABLED); + + EXPECT_OK(s2n_connection_mark_ktls_enabled(conn, S2N_KTLS_MODE_TX)); + EXPECT_FALSE(s2n_connection_is_ktls_enabled(conn, S2N_KTLS_MODE_DISABLED)); + EXPECT_TRUE(s2n_connection_is_ktls_enabled(conn, S2N_KTLS_MODE_TX)); + EXPECT_FALSE(s2n_connection_is_ktls_enabled(conn, S2N_KTLS_MODE_RX)); + EXPECT_FALSE(s2n_connection_is_ktls_enabled(conn, S2N_KTLS_MODE_DUPLEX)); + + EXPECT_OK(s2n_connection_mark_ktls_enabled(conn, S2N_KTLS_MODE_RX)); + EXPECT_FALSE(s2n_connection_is_ktls_enabled(conn, S2N_KTLS_MODE_DISABLED)); + EXPECT_TRUE(s2n_connection_is_ktls_enabled(conn, S2N_KTLS_MODE_TX)); + EXPECT_TRUE(s2n_connection_is_ktls_enabled(conn, S2N_KTLS_MODE_RX)); + EXPECT_TRUE(s2n_connection_is_ktls_enabled(conn, S2N_KTLS_MODE_DUPLEX)); + }; + + /* enable kTLS duplex */ + { + DEFER_CLEANUP(struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT), + s2n_connection_ptr_free); + EXPECT_NOT_NULL(conn); + DEFER_CLEANUP(struct s2n_test_io_pair io_pair = { 0 }, s2n_io_pair_close); + EXPECT_SUCCESS(s2n_io_pair_init_non_blocking(&io_pair)); + EXPECT_SUCCESS(s2n_connection_set_io_pair(conn, &io_pair)); + EXPECT_TRUE(conn->managed_send_io); + EXPECT_TRUE(conn->managed_recv_io); + + DEFER_CLEANUP(struct s2n_config *config = s2n_config_new(), s2n_config_ptr_free); + EXPECT_NOT_NULL(config); + EXPECT_SUCCESS(s2n_config_ktls_enable(config, S2N_KTLS_MODE_DUPLEX)); + EXPECT_SUCCESS(s2n_connection_set_config(conn, config)); + + EXPECT_EQUAL(conn->ktls_mode_enabled, S2N_KTLS_MODE_DISABLED); + + EXPECT_OK(s2n_connection_mark_ktls_enabled(conn, S2N_KTLS_MODE_DUPLEX)); + EXPECT_FALSE(s2n_connection_is_ktls_enabled(conn, S2N_KTLS_MODE_DISABLED)); + EXPECT_TRUE(s2n_connection_is_ktls_enabled(conn, S2N_KTLS_MODE_TX)); + EXPECT_TRUE(s2n_connection_is_ktls_enabled(conn, S2N_KTLS_MODE_RX)); + EXPECT_TRUE(s2n_connection_is_ktls_enabled(conn, S2N_KTLS_MODE_DUPLEX)); + }; + + /* disabling kTLS, once enabled is not supported so confirm this returns an error + * + * Note: This behavior might change if we introduce a kernel patch which + * support user space fallback from kTLS. + */ + { + DEFER_CLEANUP(struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT), + s2n_connection_ptr_free); + EXPECT_NOT_NULL(conn); + DEFER_CLEANUP(struct s2n_test_io_pair io_pair = { 0 }, s2n_io_pair_close); + EXPECT_SUCCESS(s2n_io_pair_init_non_blocking(&io_pair)); + EXPECT_SUCCESS(s2n_connection_set_io_pair(conn, &io_pair)); + EXPECT_TRUE(conn->managed_send_io); + EXPECT_TRUE(conn->managed_recv_io); + + DEFER_CLEANUP(struct s2n_config *config = s2n_config_new(), s2n_config_ptr_free); + EXPECT_NOT_NULL(config); + EXPECT_SUCCESS(s2n_config_ktls_enable(config, S2N_KTLS_MODE_DUPLEX)); + EXPECT_SUCCESS(s2n_connection_set_config(conn, config)); + + EXPECT_EQUAL(conn->ktls_mode_enabled, S2N_KTLS_MODE_DISABLED); + + EXPECT_ERROR(s2n_connection_mark_ktls_enabled(conn, S2N_KTLS_MODE_DISABLED)); + EXPECT_FALSE(s2n_connection_is_ktls_enabled(conn, S2N_KTLS_MODE_TX)); + EXPECT_FALSE(s2n_connection_is_ktls_enabled(conn, S2N_KTLS_MODE_RX)); + EXPECT_FALSE(s2n_connection_is_ktls_enabled(conn, S2N_KTLS_MODE_DUPLEX)); + }; + + END_TEST(); +} diff --git a/tls/s2n_config.c b/tls/s2n_config.c index 6d6d2c1b4f1..6109ffcd705 100644 --- a/tls/s2n_config.c +++ b/tls/s2n_config.c @@ -13,6 +13,8 @@ * permissions and limitations under the License. */ +#include "tls/s2n_config.h" + #include #include @@ -1067,3 +1069,18 @@ int s2n_config_set_recv_multi_record(struct s2n_config *config, bool enabled) return S2N_SUCCESS; } + +int s2n_config_ktls_enable(struct s2n_config *config, s2n_ktls_mode mode) +{ + POSIX_ENSURE_REF(config); + + config->ktls_mode_requested |= mode; + return S2N_SUCCESS; +} + +bool s2n_config_is_ktls_requested(struct s2n_config *config, s2n_ktls_mode ktls_mode) +{ + POSIX_ENSURE_REF(config); + + return s2n_ktls_is_ktls_mode_eq(config->ktls_mode_requested, ktls_mode); +} diff --git a/tls/s2n_config.h b/tls/s2n_config.h index 96969be9710..75014bcb72f 100644 --- a/tls/s2n_config.h +++ b/tls/s2n_config.h @@ -19,6 +19,7 @@ #include "crypto/s2n_certificate.h" #include "crypto/s2n_dhe.h" #include "tls/s2n_crl.h" +#include "tls/s2n_ktls.h" #include "tls/s2n_psk.h" #include "tls/s2n_renegotiate.h" #include "tls/s2n_resume.h" @@ -175,6 +176,11 @@ struct s2n_config { void *renegotiate_request_ctx; s2n_renegotiate_request_cb renegotiate_request_cb; + + /* Depending on OS and configuration it is possible to use kTLS. + * + * This option indicates if connections should attempt to use kTLS. */ + s2n_ktls_mode ktls_mode_requested; }; S2N_CLEANUP_RESULT s2n_config_ptr_free(struct s2n_config **config); @@ -190,3 +196,4 @@ void s2n_wipe_static_configs(void); extern struct s2n_cert_chain_and_key *s2n_config_get_single_default_cert(struct s2n_config *config); int s2n_config_get_num_default_certs(struct s2n_config *config); S2N_RESULT s2n_config_wall_clock(struct s2n_config *config, uint64_t *output); +bool s2n_config_is_ktls_requested(struct s2n_config *config, s2n_ktls_mode ktls_mode); diff --git a/tls/s2n_connection.c b/tls/s2n_connection.c index d599be86597..9015c68a710 100644 --- a/tls/s2n_connection.c +++ b/tls/s2n_connection.c @@ -37,6 +37,7 @@ #include "tls/s2n_handshake.h" #include "tls/s2n_internal.h" #include "tls/s2n_kem.h" +#include "tls/s2n_ktls.h" #include "tls/s2n_prf.h" #include "tls/s2n_record.h" #include "tls/s2n_resume.h" @@ -1517,3 +1518,22 @@ S2N_RESULT s2n_connection_dynamic_free_in_buffer(struct s2n_connection *conn) return S2N_RESULT_OK; } + +S2N_RESULT s2n_connection_mark_ktls_enabled(struct s2n_connection *conn, s2n_ktls_mode ktls_mode) +{ + RESULT_ENSURE_REF(conn); + + /* perform sanity check. */ + RESULT_GUARD(s2n_ktls_validate(conn, ktls_mode)); + + conn->ktls_mode_enabled |= ktls_mode; + + return S2N_RESULT_OK; +} + +bool s2n_connection_is_ktls_enabled(struct s2n_connection *conn, s2n_ktls_mode ktls_mode) +{ + POSIX_ENSURE_REF(conn); + + return s2n_ktls_is_ktls_mode_eq(conn->ktls_mode_enabled, ktls_mode); +} diff --git a/tls/s2n_connection.h b/tls/s2n_connection.h index 555efe0af51..ed034b3a36a 100644 --- a/tls/s2n_connection.h +++ b/tls/s2n_connection.h @@ -282,8 +282,8 @@ struct s2n_connection { */ uint16_t max_outgoing_fragment_length; - /* The number of bytes to send before changing the record size. - * If this value > 0 then dynamic TLS record size is enabled. Otherwise, the feature is disabled (default). + /* The number of bytes to send before changing the record size. + * If this value > 0 then dynamic TLS record size is enabled. Otherwise, the feature is disabled (default). */ uint32_t dynamic_record_resize_threshold; @@ -385,6 +385,9 @@ struct s2n_connection { uint32_t server_keying_material_lifetime; struct s2n_post_handshake post_handshake; + + /* Marks if kTLS has been enabled for this connection. */ + s2n_ktls_mode ktls_mode_enabled; }; S2N_CLEANUP_RESULT s2n_connection_ptr_free(struct s2n_connection **s2n_connection); @@ -417,3 +420,4 @@ int s2n_connection_get_client_cert_chain(struct s2n_connection *conn, uint8_t ** int s2n_connection_get_peer_cert_chain(const struct s2n_connection *conn, struct s2n_cert_chain_and_key *cert_chain_and_key); uint8_t s2n_connection_get_protocol_version(const struct s2n_connection *conn); S2N_RESULT s2n_connection_set_max_fragment_length(struct s2n_connection *conn, uint16_t length); +S2N_RESULT s2n_connection_mark_ktls_enabled(struct s2n_connection *conn, s2n_ktls_mode mode); diff --git a/tls/s2n_ktls.c b/tls/s2n_ktls.c new file mode 100644 index 00000000000..7b0e0b0f7cb --- /dev/null +++ b/tls/s2n_ktls.c @@ -0,0 +1,166 @@ +/* + * 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 "tls/s2n_ktls.h" + +#include +#include +#include + +#include "error/s2n_errno.h" +#include "tls/s2n_config.h" +#include "tls/s2n_connection.h" +#include "tls/s2n_crypto.h" +#include "utils/s2n_result.h" +#include "utils/s2n_safety_macros.h" +#include "utils/s2n_socket.h" + +#define TLS_ULP "tls" +#define TLS_ULP_SIZE sizeof(TLS_ULP) +/* value declared in netinet/tcp.h */ +#define SOL_TCP 6 /* TCP level */ + +/* + * Compares s2n_ktls_mode to see if they are equal. + */ +bool s2n_ktls_is_ktls_mode_eq(s2n_ktls_mode a, s2n_ktls_mode b) +{ + if (b == S2N_KTLS_MODE_DUPLEX) { + return a == S2N_KTLS_MODE_DUPLEX; + } + if (b == S2N_KTLS_MODE_DISABLED) { + return a == S2N_KTLS_MODE_DISABLED; + } + return a & b; +} + +S2N_RESULT s2n_ktls_set_crypto_info( + s2n_ktls_mode ktls_mode, + int fd, + uint8_t implicit_iv[S2N_TLS_MAX_IV_LEN], + uint8_t sequence_number[S2N_TLS_SEQUENCE_NUM_LEN]) +{ + uint8_t key[16] = { 0 }; + + struct tls12_crypto_info_aes_gcm_128 crypto_info; + + /* AES_GCM_128 specific configuration */ + crypto_info.info.cipher_type = TLS_CIPHER_AES_GCM_128; + RESULT_CHECKED_MEMCPY(crypto_info.salt, implicit_iv, TLS_CIPHER_AES_GCM_128_SALT_SIZE); + RESULT_CHECKED_MEMCPY(crypto_info.rec_seq, sequence_number, TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE); + RESULT_CHECKED_MEMCPY(crypto_info.key, key, TLS_CIPHER_AES_GCM_128_KEY_SIZE); + + /* TLS1.2 specific configuration */ + crypto_info.info.version = TLS_1_2_VERSION; + RESULT_CHECKED_MEMCPY(crypto_info.iv, implicit_iv, TLS_CIPHER_AES_GCM_128_IV_SIZE); + + int tls_mode; + /* configure socket and enable kTLS */ + if (s2n_ktls_is_ktls_mode_eq(ktls_mode, S2N_KTLS_MODE_RX)) { + tls_mode = TLS_RX; + } else if (s2n_ktls_is_ktls_mode_eq(ktls_mode, S2N_KTLS_MODE_TX)) { + tls_mode = TLS_RX; + } else { + /* unreachable */ + return S2N_RESULT_ERROR; + } + + RESULT_GUARD_POSIX(setsockopt(fd, SOL_TLS, tls_mode, &crypto_info, sizeof(crypto_info))); + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_ktls_enable_impl(struct s2n_connection *conn, s2n_ktls_mode ktls_mode, int fd) +{ + RESULT_ENSURE_REF(conn); + RESULT_ENSURE(ktls_mode == S2N_KTLS_MODE_RX || ktls_mode == S2N_KTLS_MODE_TX, S2N_ERR_SAFETY); + + /* register the tls ULP */ + RESULT_GUARD_POSIX(setsockopt(fd, SOL_TCP, TCP_ULP, TLS_ULP, TLS_ULP_SIZE)); + + /* set crypto info and enable kTLS on the socket */ + struct s2n_crypto_parameters *crypto_param; + if (conn->mode == S2N_SERVER) { + crypto_param = conn->server; + } else { + crypto_param = conn->client; + } + RESULT_GUARD(s2n_ktls_set_crypto_info(ktls_mode, fd, crypto_param->server_implicit_iv, crypto_param->server_sequence_number)); + + /* Note: kTLS has been enabled on the socket. Errors must be handled appropriately and + * are likely to be fatal. */ + + /* TODO configure kTLS specific I/O callback and context. */ + + /* mark kTLS enabled on the connection */ + RESULT_GUARD(s2n_connection_mark_ktls_enabled(conn, ktls_mode)); + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_ktls_validate(struct s2n_connection *conn, s2n_ktls_mode ktls_mode) +{ + RESULT_ENSURE_REF(conn); + + /* TODO support TLS1.3 + * + * TLS1.3 support requires sending the KeyUpdate message when the cryptographic + * KeyLimits are met. However, this is currently only possible by applying a + * kernel patch to support this functionality. + */ + RESULT_ENSURE_EQ(conn->actual_protocol_version, S2N_TLS12); + + /* TODO Add validation for cipher suites */ + + /* confirm that the application requested ktls */ + RESULT_ENSURE(s2n_config_is_ktls_requested(conn->config, ktls_mode), S2N_ERR_SAFETY); + + /* kTLS I/O functionality is managed by s2n-tls. kTLS cannot be enabled + * if the application sets custom I/O. + */ + if (s2n_ktls_is_ktls_mode_eq(ktls_mode, S2N_KTLS_MODE_TX) && !conn->managed_send_io) { + return S2N_RESULT_ERROR; + } + if (s2n_ktls_is_ktls_mode_eq(ktls_mode, S2N_KTLS_MODE_RX) && !conn->managed_recv_io) { + return S2N_RESULT_ERROR; + } + + /* confim kTLS isn't enabled already */ + RESULT_ENSURE_EQ(s2n_connection_is_ktls_enabled(conn, ktls_mode), false); + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_ktls_enable(struct s2n_connection *conn, s2n_ktls_mode ktls_mode) +{ + RESULT_ENSURE_REF(conn); + RESULT_GUARD(s2n_ktls_validate(conn, ktls_mode)); + + if (s2n_ktls_is_ktls_mode_eq(ktls_mode, S2N_KTLS_MODE_RX)) { + /* retrieve the recv fd */ + const struct s2n_socket_write_io_context *peer_socket_ctx = conn->recv_io_context; + int fd = peer_socket_ctx->fd; + RESULT_GUARD(s2n_ktls_enable_impl(conn, S2N_KTLS_MODE_RX, fd)); + } + + if (s2n_ktls_is_ktls_mode_eq(ktls_mode, S2N_KTLS_MODE_TX)) { + /* retrieve the send fd */ + const struct s2n_socket_write_io_context *peer_socket_ctx = conn->send_io_context; + int fd = peer_socket_ctx->fd; + RESULT_GUARD(s2n_ktls_enable_impl(conn, S2N_KTLS_MODE_TX, fd)); + } + + return S2N_RESULT_OK; +} diff --git a/tls/s2n_ktls.h b/tls/s2n_ktls.h new file mode 100644 index 00000000000..97e154e22bf --- /dev/null +++ b/tls/s2n_ktls.h @@ -0,0 +1,49 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include "utils/s2n_result.h" + +struct s2n_config; +struct s2n_connection; + +/* --- unstable API --- + * + * These will eventually be moved to unstable/ktls.h once kTLS is implemented + */ + +typedef enum { + /** Enable kTLS for both rx and tx socket. */ + S2N_KTLS_MODE_DISABLED = 0, + /** Enable kTLS for the tx socket. */ + S2N_KTLS_MODE_TX = 1 << 0, + /** Enable kTLS for the rx socket. */ + S2N_KTLS_MODE_RX = 1 << 1, + /** Enable kTLS for both rx and tx socket. */ + S2N_KTLS_MODE_DUPLEX = S2N_KTLS_MODE_RX | S2N_KTLS_MODE_TX, +} s2n_ktls_mode; + +int s2n_config_ktls_enable(struct s2n_config *config, s2n_ktls_mode mode); + +bool s2n_connection_is_ktls_enabled(struct s2n_connection *conn, s2n_ktls_mode mode); + +/* --- unstable API --- */ + +bool s2n_ktls_is_ktls_mode_eq(s2n_ktls_mode a, s2n_ktls_mode b); +S2N_RESULT s2n_ktls_enable(struct s2n_connection *conn, s2n_ktls_mode ktls_mode); +S2N_RESULT s2n_ktls_validate(struct s2n_connection *conn, s2n_ktls_mode ktls_mode);