Skip to content

Commit

Permalink
pr comments
Browse files Browse the repository at this point in the history
  • Loading branch information
toidiu committed Feb 9, 2023
1 parent ec9d38d commit 0fcad1d
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 20 deletions.
2 changes: 1 addition & 1 deletion error/s2n_errno.c
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ static const char *no_such_error = "Internal s2n error";
ERR_ENTRY(S2N_ERR_OSSL_PROVIDER, "Failed to load or unload an openssl provider") \
ERR_ENTRY(S2N_ERR_CERT_OWNERSHIP, "The ownership of the certificate chain is incompatible with the operation") \
ERR_ENTRY(S2N_ERR_INTERNAL_LIBCRYPTO_ERROR, "An internal error has occurred in the libcrypto API") \
ERR_ENTRY(S2N_ERR_KTLS, "An internal error while enabling kTLS") \
ERR_ENTRY(S2N_ERR_KTLS, "An internal error has occurred while enabling kTLS") \
ERR_ENTRY(S2N_ERR_NO_RENEGOTIATION, "Only secure, server-initiated renegotiation is supported") \
ERR_ENTRY(S2N_ERR_APP_DATA_BLOCKED, "Blocked on application data during handshake") \
/* clang-format on */
Expand Down
2 changes: 1 addition & 1 deletion s2n.mk
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ ifeq ($(TRY_COMPILE_CLONE), 0)
endif

# Determine if kTLS is available
TRY_COMPILE_KTLS := $(call try_run,$(S2N_ROOT)/tests/features/ktls.c)
TRY_COMPILE_KTLS := $(call try_compile,$(S2N_ROOT)/tests/features/ktls.c)
ifeq ($(TRY_COMPILE_KTLS), 0)
DEFAULT_CFLAGS += -DS2N_PLATFORM_SUPPORTS_KTLS
endif
Expand Down
124 changes: 123 additions & 1 deletion tests/unit/s2n_ktls_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,19 @@
* permissions and limitations under the License.
*/

#include "tls/s2n_ktls.h"

#include <sys/socket.h>

#include "crypto/s2n_cipher.h"
#include "s2n_test.h"
#include "testlib/s2n_testlib.h"
#include "tls/s2n_handshake_type.h"
#include "utils/s2n_safety.h"

S2N_RESULT s2n_ktls_validate(struct s2n_connection *conn);
S2N_RESULT s2n_ktls_validate_socket_mode(struct s2n_connection *conn, s2n_ktls_mode ktls_mode);
S2N_RESULT s2n_ktls_retrieve_file_descriptor(struct s2n_connection *conn, s2n_ktls_mode ktls_mode, int *fd);

int main(int argc, char **argv)
{
Expand All @@ -36,7 +47,118 @@ int main(int argc, char **argv)

cipher = s2n_chacha20_poly1305;
EXPECT_FALSE(cipher.ktls_supported);
};
}

/* s2n_ktls_validate TLS 1.2 */
{
DEFER_CLEANUP(struct s2n_cert_chain_and_key *chain_and_key = NULL, s2n_cert_chain_and_key_ptr_free);
EXPECT_SUCCESS(s2n_test_cert_chain_and_key_new(&chain_and_key,
S2N_DEFAULT_TEST_CERT_CHAIN, S2N_DEFAULT_TEST_PRIVATE_KEY));

DEFER_CLEANUP(struct s2n_config *config = s2n_config_new(), s2n_config_ptr_free);
EXPECT_NOT_NULL(config);
EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(config, chain_and_key));
EXPECT_SUCCESS(s2n_config_disable_x509_verification(config));
EXPECT_SUCCESS(s2n_config_set_cipher_preferences(config, "default"));

DEFER_CLEANUP(struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER),
s2n_connection_ptr_free);
DEFER_CLEANUP(struct s2n_connection *client_conn = s2n_connection_new(S2N_CLIENT),
s2n_connection_ptr_free);

EXPECT_SUCCESS(s2n_connection_set_config(client_conn, config));
EXPECT_SUCCESS(s2n_connection_set_config(server_conn, config));

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(client_conn, &io_pair));
EXPECT_SUCCESS(s2n_connection_set_io_pair(server_conn, &io_pair));

EXPECT_SUCCESS(s2n_negotiate_test_server_and_client(server_conn, client_conn));

EXPECT_EQUAL(server_conn->actual_protocol_version, S2N_TLS12);
uint8_t key_size = server_conn->secure->cipher_suite->record_alg->cipher->key_material_size;
EXPECT_EQUAL(key_size, S2N_TLS_AES_128_GCM_KEY_LEN);

EXPECT_OK(s2n_ktls_validate(server_conn));
}

/* s2n_ktls_validate TLS 1.3 */
{
DEFER_CLEANUP(struct s2n_cert_chain_and_key *chain_and_key = NULL, s2n_cert_chain_and_key_ptr_free);
EXPECT_SUCCESS(s2n_test_cert_chain_and_key_new(&chain_and_key,
S2N_DEFAULT_TEST_CERT_CHAIN, S2N_DEFAULT_TEST_PRIVATE_KEY));

DEFER_CLEANUP(struct s2n_config *config = s2n_config_new(), s2n_config_ptr_free);
EXPECT_NOT_NULL(config);
EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(config, chain_and_key));
EXPECT_SUCCESS(s2n_config_disable_x509_verification(config));
EXPECT_SUCCESS(s2n_config_set_cipher_preferences(config, "default_tls13"));

DEFER_CLEANUP(struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER),
s2n_connection_ptr_free);
DEFER_CLEANUP(struct s2n_connection *client_conn = s2n_connection_new(S2N_CLIENT),
s2n_connection_ptr_free);

EXPECT_SUCCESS(s2n_connection_set_config(client_conn, config));
EXPECT_SUCCESS(s2n_connection_set_config(server_conn, config));

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(client_conn, &io_pair));
EXPECT_SUCCESS(s2n_connection_set_io_pair(server_conn, &io_pair));

EXPECT_SUCCESS(s2n_negotiate_test_server_and_client(server_conn, client_conn));

EXPECT_EQUAL(server_conn->actual_protocol_version, S2N_TLS13);
uint8_t key_size = server_conn->secure->cipher_suite->record_alg->cipher->key_material_size;
EXPECT_EQUAL(key_size, S2N_TLS_AES_128_GCM_KEY_LEN);

EXPECT_ERROR(s2n_ktls_validate(server_conn));
}

/* s2n_ktls_validate_socket_mode */
{
DEFER_CLEANUP(struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER),
s2n_connection_ptr_free);
int fd = 1;
EXPECT_SUCCESS(s2n_connection_set_write_fd(server_conn, fd));
EXPECT_SUCCESS(s2n_connection_set_read_fd(server_conn, fd));
server_conn->managed_recv_io = false;

/* base case */
server_conn->managed_send_io = false;
server_conn->ktls_send_enabled = false;
EXPECT_OK(s2n_ktls_validate_socket_mode(server_conn, S2N_KTLS_MODE_RECV));
EXPECT_OK(s2n_ktls_validate_socket_mode(server_conn, S2N_KTLS_MODE_SEND));

/* managed io */
server_conn->managed_send_io = true;
server_conn->ktls_send_enabled = false;
EXPECT_OK(s2n_ktls_validate_socket_mode(server_conn, S2N_KTLS_MODE_RECV));
EXPECT_ERROR(s2n_ktls_validate_socket_mode(server_conn, S2N_KTLS_MODE_SEND));

/* ktls enabled */
server_conn->managed_send_io = false;
server_conn->ktls_send_enabled = true;
EXPECT_OK(s2n_ktls_validate_socket_mode(server_conn, S2N_KTLS_MODE_RECV));
EXPECT_ERROR(s2n_ktls_validate_socket_mode(server_conn, S2N_KTLS_MODE_SEND));
}

/* s2n_ktls_retrieve_file_descriptor */
{
DEFER_CLEANUP(struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER),
s2n_connection_ptr_free);
int fd = 1;
EXPECT_SUCCESS(s2n_connection_set_write_fd(server_conn, fd));
EXPECT_SUCCESS(s2n_connection_set_read_fd(server_conn, fd));
server_conn->managed_recv_io = false;
server_conn->managed_send_io = false;

int fd_ret = 0;
EXPECT_OK(s2n_ktls_retrieve_file_descriptor(server_conn, S2N_KTLS_MODE_SEND, &fd_ret));
EXPECT_EQUAL(fd, fd_ret);
}

END_TEST();
}
60 changes: 43 additions & 17 deletions tls/s2n_ktls.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,16 @@

#include "error/s2n_errno.h"
#include "tls/s2n_connection.h"
#include "tls/s2n_ktls.h"
#include "utils/s2n_result.h"
#include "utils/s2n_socket.h"

#define S2N_TLS_ULP_NAME "tls"
#define S2N_TLS_ULP_NAME_SIZE sizeof(S2N_TLS_ULP_NAME)
#endif

#include "tls/s2n_ktls.h"
#include "utils/s2n_safety.h"
#include "utils/s2n_socket.h"

#ifdef S2N_PLATFORM_SUPPORTS_KTLS
S2N_RESULT s2n_ktls_validate(struct s2n_connection *conn)
{
RESULT_ENSURE_REF(conn);
Expand Down Expand Up @@ -74,27 +73,30 @@ S2N_RESULT s2n_ktls_validate(struct s2n_connection *conn)
S2N_RESULT s2n_ktls_validate_socket_mode(struct s2n_connection *conn, s2n_ktls_mode ktls_mode)
{
RESULT_ENSURE_REF(conn);
RESULT_ENSURE(ktls_mode == S2N_KTLS_MODE_RECV || ktls_mode == S2N_KTLS_MODE_SEND, S2N_ERR_T_INTERNAL);
RESULT_ENSURE(ktls_mode == S2N_KTLS_MODE_RECV || ktls_mode == S2N_KTLS_MODE_SEND, S2N_ERR_SAFETY);

/* kTLS I/O functionality is managed by s2n-tls. kTLS cannot be enabled if the
* application sets custom I/O (managed_send_io == false means application has
* set custom I/O).
*
* - Confirm application is has not using custom I/O
* - Safety checks
* - Confirm application is not using custom I/O
* - Confirm kTLS isn't enabled already
*/
switch (ktls_mode) {
case S2N_KTLS_MODE_SEND:
RESULT_ENSURE_REF(conn->send_io_context);
RESULT_ENSURE(!conn->managed_send_io, S2N_ERR_KTLS);
RESULT_ENSURE(!conn->ktls_send_enabled, S2N_ERR_KTLS);
break;
case S2N_KTLS_MODE_RECV:
RESULT_ENSURE_REF(conn->recv_io_context);
RESULT_ENSURE(!conn->managed_recv_io, S2N_ERR_KTLS);
RESULT_ENSURE(!conn->ktls_recv_enabled, S2N_ERR_KTLS);
break;
case S2N_KTLS_MODE_DISABLED:
case S2N_KTLS_MODE_DUPLEX:
RESULT_BAIL(S2N_ERR_T_INTERNAL);
RESULT_BAIL(S2N_ERR_SAFETY);
break;
}

Expand All @@ -104,6 +106,7 @@ S2N_RESULT s2n_ktls_validate_socket_mode(struct s2n_connection *conn, s2n_ktls_m
S2N_RESULT s2n_ktls_retrieve_file_descriptor(struct s2n_connection *conn, s2n_ktls_mode ktls_mode, int *fd)
{
RESULT_GUARD(s2n_ktls_validate_socket_mode(conn, ktls_mode));
RESULT_ENSURE_REF(fd);

if (ktls_mode == S2N_KTLS_MODE_RECV) {
/* retrieve the receive fd */
Expand All @@ -118,12 +121,14 @@ S2N_RESULT s2n_ktls_retrieve_file_descriptor(struct s2n_connection *conn, s2n_kt
return S2N_RESULT_OK;
}

#ifdef S2N_PLATFORM_SUPPORTS_KTLS

S2N_RESULT s2n_ktls_configure_socket(struct s2n_connection *conn, s2n_ktls_mode ktls_mode)
{
RESULT_GUARD(s2n_ktls_validate_socket_mode(conn, ktls_mode));

/* register the tls ULP */
int fd;
int fd = 0;
RESULT_GUARD(s2n_ktls_retrieve_file_descriptor(conn, ktls_mode, &fd));
RESULT_GUARD_POSIX(setsockopt(fd, SOL_TCP, TCP_ULP, S2N_TLS_ULP_NAME, S2N_TLS_ULP_NAME_SIZE));

Expand All @@ -145,29 +150,50 @@ S2N_RESULT s2n_ktls_configure_connection(struct s2n_connection *conn, s2n_ktls_m
return S2N_RESULT_OK;
}

S2N_RESULT s2n_ktls_enable(struct s2n_connection *conn)
/*
* Since kTLS is an optimization, it is possible to continue operation
* by using userspace TLS if kTLS is not supported. Upon successfully
* enabling kTLS, we set connection->ktls_send_enabled (and recv) to true.
*
* For this reason we categorize kTLS errors into recoverable and
* un-recoverable and handle them appropriately:
*
* - Errors related to the socket configuration are considered recoverable
* since kTLS related `setsockopt` operations are non-destructive.
*
* - Errors related to connection configuration are considered
* un-recoverable since we attempt to modify s2n_connection state.
*/
int s2n_ktls_enable(struct s2n_connection *conn, s2n_ktls_mode ktls_mode)
{
if (s2n_result_is_error(s2n_ktls_validate(conn))) {
return S2N_RESULT_OK;
return S2N_SUCCESS;
}

if (s2n_result_is_ok(s2n_ktls_configure_socket(conn, S2N_KTLS_MODE_RECV))) {
RESULT_ENSURE_OK(s2n_ktls_configure_connection(conn, S2N_KTLS_MODE_RECV), S2N_ERR_KTLS);
if (ktls_mode == S2N_KTLS_MODE_RECV || ktls_mode == S2N_KTLS_MODE_DUPLEX) {
if (s2n_result_is_ok(s2n_ktls_configure_socket(conn, S2N_KTLS_MODE_RECV))) {
POSIX_GUARD_RESULT(s2n_ktls_configure_connection(conn, S2N_KTLS_MODE_RECV));
}
}

if (s2n_result_is_ok(s2n_ktls_configure_socket(conn, S2N_KTLS_MODE_SEND))) {
RESULT_ENSURE_OK(s2n_ktls_configure_connection(conn, S2N_KTLS_MODE_SEND), S2N_ERR_KTLS);
if (ktls_mode == S2N_KTLS_MODE_SEND || ktls_mode == S2N_KTLS_MODE_DUPLEX) {
if (s2n_result_is_ok(s2n_ktls_configure_socket(conn, S2N_KTLS_MODE_SEND))) {
POSIX_GUARD_RESULT(s2n_ktls_configure_connection(conn, S2N_KTLS_MODE_SEND));
}
}

return S2N_RESULT_OK;
return S2N_SUCCESS;
}

#else

S2N_RESULT s2n_ktls_enable(struct s2n_connection *conn)
/*
* kTLS feature is not supported on this platform. We return success
* and continue to operate in userspace TLS mode.
*/
int s2n_ktls_enable(struct s2n_connection *conn, s2n_ktls_mode ktls_mode)
{
/* kTLS feature is not supported on this platform */
return S2N_RESULT_OK;
return S2N_SUCCESS;
}

#endif

0 comments on commit 0fcad1d

Please sign in to comment.