Skip to content

Commit

Permalink
ktls: config socket ULP
Browse files Browse the repository at this point in the history
  • Loading branch information
toidiu committed Jul 11, 2023
1 parent e0fd532 commit 0c5ccb9
Show file tree
Hide file tree
Showing 10 changed files with 478 additions and 16 deletions.
7 changes: 7 additions & 0 deletions error/s2n_errno.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,13 @@ static const char *no_such_error = "Internal s2n error";
ERR_ENTRY(S2N_ERR_INTERNAL_LIBCRYPTO_ERROR, "An internal error has occurred in the libcrypto API") \
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") \
ERR_ENTRY(S2N_ERR_KTLS_ALREADY_ENABLED, "kTLS is already enabled on the socket") \
ERR_ENTRY(S2N_ERR_KTLS_MANAGED_IO, "kTLS cannot be enabled while custom I/O is configured for the connection") \
ERR_ENTRY(S2N_ERR_KTLS_HANDSHAKE_NOT_COMPLETE, "kTLS can only be enabled once the handshake is completed") \
ERR_ENTRY(S2N_ERR_KTLS_UNSUPPORTED_PLATFORM, "kTLS is unsupported on this platform") \
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_DISABLED_FOR_TEST, "Some kTLS operations have been disabled for testing") \
ERR_ENTRY(S2N_ERR_ATOMIC, "Atomic operations in this environment would require locking") \
/* clang-format on */

Expand Down
7 changes: 7 additions & 0 deletions error/s2n_errno.h
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,13 @@ typedef enum {
S2N_ERR_SECRET_SCHEDULE_STATE,
S2N_ERR_CERT_OWNERSHIP,
S2N_ERR_INTERNAL_LIBCRYPTO_ERROR,
S2N_ERR_KTLS_ALREADY_ENABLED,
S2N_ERR_KTLS_MANAGED_IO,
S2N_ERR_KTLS_HANDSHAKE_NOT_COMPLETE,
S2N_ERR_KTLS_UNSUPPORTED_PLATFORM,
S2N_ERR_KTLS_UNSUPPORTED_CONN,
S2N_ERR_KTLS_ULP,
S2N_ERR_KTLS_DISABLED_FOR_TEST,
S2N_ERR_ATOMIC,
S2N_ERR_T_USAGE_END,
} s2n_error;
Expand Down
9 changes: 9 additions & 0 deletions tests/testlib/s2n_connection_test_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -332,3 +332,12 @@ S2N_RESULT s2n_set_all_mutually_supported_groups(struct s2n_connection *conn)

return S2N_RESULT_OK;
}

S2N_RESULT s2n_skip_handshake(struct s2n_connection *conn)
{
conn->handshake.handshake_type = NEGOTIATED | FULL_HANDSHAKE;
while (!s2n_handshake_is_complete(conn)) {
conn->handshake.message_number++;
}
return S2N_RESULT_OK;
}
1 change: 1 addition & 0 deletions tests/testlib/s2n_testlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ int s2n_connection_allow_response_extension(struct s2n_connection *conn, uint16_
int s2n_connection_allow_all_response_extensions(struct s2n_connection *conn);
int s2n_connection_set_all_protocol_versions(struct s2n_connection *conn, uint8_t version);
S2N_RESULT s2n_set_all_mutually_supported_groups(struct s2n_connection *conn);
S2N_RESULT s2n_skip_handshake(struct s2n_connection *conn);

S2N_RESULT s2n_connection_set_secrets(struct s2n_connection *conn);

Expand Down
216 changes: 215 additions & 1 deletion tests/unit/s2n_ktls_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,53 @@
* permissions and limitations under the License.
*/

#include "crypto/s2n_cipher.h"
#include "tls/s2n_ktls.h"

#include "s2n_test.h"
#include "testlib/s2n_testlib.h"

S2N_RESULT s2n_ktls_retrieve_file_descriptor(struct s2n_connection *conn, s2n_ktls_mode ktls_mode, int *fd);
S2N_RESULT s2n_disable_ktls_socket_config_for_testing(void);

/* set kTLS supported cipher */
struct s2n_cipher ktls_temp_supported_cipher = {
.ktls_supported = true,
};
struct s2n_record_algorithm ktls_temp_supported_record_alg = {
.cipher = &ktls_temp_supported_cipher,
};
struct s2n_cipher_suite ktls_temp_supported_cipher_suite = {
.record_alg = &ktls_temp_supported_record_alg,
};

S2N_RESULT s2n_test_configure_mock_ktls_connection(struct s2n_connection *conn, int fd, bool complete_handshake)
{
RESULT_ENSURE_REF(conn);

/* config I/O */
RESULT_GUARD_POSIX(s2n_connection_set_write_fd(conn, fd));
RESULT_GUARD_POSIX(s2n_connection_set_read_fd(conn, fd));
conn->managed_send_io = true;
conn->managed_recv_io = true;
conn->ktls_send_enabled = false;
conn->ktls_recv_enabled = false;

/* configure connection so that the handshake is complete */
conn->secure->cipher_suite = &ktls_temp_supported_cipher_suite;
conn->actual_protocol_version = S2N_TLS12;
if (complete_handshake) {
RESULT_GUARD(s2n_skip_handshake(conn));
}

return S2N_RESULT_OK;
}

int main(int argc, char **argv)
{
BEGIN_TEST();

EXPECT_OK(s2n_disable_ktls_socket_config_for_testing());

/* ktls_supported ciphers */
{
struct s2n_cipher cipher = s2n_aes128_gcm;
Expand All @@ -38,5 +78,179 @@ int main(int argc, char **argv)
EXPECT_FALSE(cipher.ktls_supported);
};

if (!s2n_ktls_is_supported_on_platform()) {
DEFER_CLEANUP(struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER),
s2n_connection_ptr_free);
int fd = 1;
EXPECT_OK(s2n_test_configure_mock_ktls_connection(server_conn, fd, true));

EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_send(server_conn), S2N_ERR_KTLS_UNSUPPORTED_PLATFORM);
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_recv(server_conn), S2N_ERR_KTLS_UNSUPPORTED_PLATFORM);
} else {
/* ktls handshake must be complete */
{
DEFER_CLEANUP(struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER),
s2n_connection_ptr_free);
int fd = 1;
EXPECT_OK(s2n_test_configure_mock_ktls_connection(server_conn, fd, false));

EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_send(server_conn), S2N_ERR_KTLS_HANDSHAKE_NOT_COMPLETE);
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_recv(server_conn), S2N_ERR_KTLS_HANDSHAKE_NOT_COMPLETE);
};

/* s2n_connection_ktls_enable */
{
DEFER_CLEANUP(struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER),
s2n_connection_ptr_free);
int fd = 1;
EXPECT_OK(s2n_test_configure_mock_ktls_connection(server_conn, fd, true));

EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_send(server_conn), S2N_ERR_KTLS_DISABLED_FOR_TEST);

EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_recv(server_conn), S2N_ERR_KTLS_DISABLED_FOR_TEST);
};

/* ktls already enabled */
{
DEFER_CLEANUP(struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER),
s2n_connection_ptr_free);
int fd = 1;
EXPECT_OK(s2n_test_configure_mock_ktls_connection(server_conn, fd, true));

server_conn->ktls_send_enabled = true;
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_send(server_conn), S2N_ERR_KTLS_ALREADY_ENABLED);

server_conn->ktls_recv_enabled = true;
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_recv(server_conn), S2N_ERR_KTLS_ALREADY_ENABLED);
};

/* unsupported protocols */
{
DEFER_CLEANUP(struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER),
s2n_connection_ptr_free);
int fd = 1;
EXPECT_OK(s2n_test_configure_mock_ktls_connection(server_conn, fd, true));

server_conn->actual_protocol_version = S2N_TLS13;
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_send(server_conn), S2N_ERR_KTLS_UNSUPPORTED_CONN);

server_conn->actual_protocol_version = S2N_TLS11;
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_send(server_conn), S2N_ERR_KTLS_UNSUPPORTED_CONN);
};

/* unsupported ciphers */
{
/* set kTLS un-supported cipher */
struct s2n_cipher ktls_temp_unsupported_cipher = {
.ktls_supported = false,
};
struct s2n_record_algorithm ktls_temp_unsupported_record_alg = {
.cipher = &ktls_temp_unsupported_cipher,
};
struct s2n_cipher_suite ktls_temp_unsupported_cipher_suite = {
.record_alg = &ktls_temp_unsupported_record_alg,
};

DEFER_CLEANUP(struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER),
s2n_connection_ptr_free);
int fd = 1;
EXPECT_OK(s2n_test_configure_mock_ktls_connection(server_conn, fd, true));

/* base case */
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_send(server_conn), S2N_ERR_KTLS_DISABLED_FOR_TEST);

server_conn->ktls_send_enabled = false; /* reset ktls enable connection */
server_conn->secure->cipher_suite = &ktls_temp_unsupported_cipher_suite;
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_send(server_conn), S2N_ERR_KTLS_UNSUPPORTED_CONN);
};

/* drain buffer prior to enabling kTLS */
{
DEFER_CLEANUP(struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER),
s2n_connection_ptr_free);
int fd = 1;
EXPECT_OK(s2n_test_configure_mock_ktls_connection(server_conn, fd, true));

/* base case */
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_send(server_conn), S2N_ERR_KTLS_DISABLED_FOR_TEST);
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_recv(server_conn), S2N_ERR_KTLS_DISABLED_FOR_TEST);

uint8_t write_byte = 8;
uint8_t read_byte = 0;
/* write to conn->out buffer and assert error */
EXPECT_SUCCESS(s2n_stuffer_write_bytes(&server_conn->out, &write_byte, 1));
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_send(server_conn), S2N_ERR_RECORD_STUFFER_NEEDS_DRAINING);
/* drain conn->out buffer and assert base case */
EXPECT_SUCCESS(s2n_stuffer_read_bytes(&server_conn->out, &read_byte, 1));
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_send(server_conn), S2N_ERR_KTLS_DISABLED_FOR_TEST);

/* write to conn->in buffer and assert error */
EXPECT_SUCCESS(s2n_stuffer_write_bytes(&server_conn->in, &write_byte, 1));
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_recv(server_conn), S2N_ERR_RECORD_STUFFER_NEEDS_DRAINING);
/* drain conn->in buffer and assert base case */
EXPECT_SUCCESS(s2n_stuffer_read_bytes(&server_conn->in, &read_byte, 1));
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_recv(server_conn), S2N_ERR_KTLS_DISABLED_FOR_TEST);
};

/* managed_send_io */
{
DEFER_CLEANUP(struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER),
s2n_connection_ptr_free);
int fd = 1;
EXPECT_OK(s2n_test_configure_mock_ktls_connection(server_conn, fd, true));

/* base case */
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_send(server_conn), S2N_ERR_KTLS_DISABLED_FOR_TEST);

server_conn->ktls_send_enabled = false; /* reset ktls enable connection */
/* expect failure if connection is using custom IO */
server_conn->managed_send_io = false;
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_send(server_conn), S2N_ERR_KTLS_MANAGED_IO);

server_conn->ktls_send_enabled = false; /* reset ktls enable connection */
/* expect success if connection is NOT using custom IO */
server_conn->managed_send_io = true;
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_send(server_conn), S2N_ERR_KTLS_DISABLED_FOR_TEST);
};

/* managed_recv_io */
{
DEFER_CLEANUP(struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER),
s2n_connection_ptr_free);
int fd = 1;
EXPECT_OK(s2n_test_configure_mock_ktls_connection(server_conn, fd, true));

/* base case */
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_recv(server_conn), S2N_ERR_KTLS_DISABLED_FOR_TEST);

server_conn->ktls_recv_enabled = false; /* reset ktls enable connection */
/* recv managed io */
server_conn->managed_recv_io = false;
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_recv(server_conn), S2N_ERR_KTLS_MANAGED_IO);

server_conn->ktls_recv_enabled = false; /* reset ktls enable connection */
/* expect success if connection is NOT using custom IO */
server_conn->managed_recv_io = true;
EXPECT_FAILURE_WITH_ERRNO(s2n_connection_ktls_enable_recv(server_conn), S2N_ERR_KTLS_DISABLED_FOR_TEST);
};

/* s2n_ktls_retrieve_file_descriptor */
{
DEFER_CLEANUP(struct s2n_connection *server_conn = s2n_connection_new(S2N_SERVER),
s2n_connection_ptr_free);
int write_fd_orig = 1;
int read_fd_orig = 2;
int fd_ret = 0;

EXPECT_SUCCESS(s2n_connection_set_write_fd(server_conn, write_fd_orig));
EXPECT_OK(s2n_ktls_retrieve_file_descriptor(server_conn, S2N_KTLS_MODE_SEND, &fd_ret));
EXPECT_EQUAL(write_fd_orig, fd_ret);

EXPECT_SUCCESS(s2n_connection_set_read_fd(server_conn, read_fd_orig));
EXPECT_OK(s2n_ktls_retrieve_file_descriptor(server_conn, S2N_KTLS_MODE_RECV, &fd_ret));
EXPECT_EQUAL(read_fd_orig, fd_ret);
};
}

END_TEST();
}
9 changes: 0 additions & 9 deletions tests/unit/s2n_shutdown_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,6 @@

#define ALERT_LEN (sizeof(uint16_t))

static S2N_RESULT s2n_skip_handshake(struct s2n_connection *conn)
{
conn->handshake.handshake_type = NEGOTIATED | FULL_HANDSHAKE;
while (!s2n_handshake_is_complete(conn)) {
conn->handshake.message_number++;
}
return S2N_RESULT_OK;
}

int main(int argc, char **argv)
{
BEGIN_TEST();
Expand Down
Loading

0 comments on commit 0c5ccb9

Please sign in to comment.