Skip to content

Commit

Permalink
ktls: send and recv cmsg
Browse files Browse the repository at this point in the history
  • Loading branch information
toidiu committed Jun 24, 2023
1 parent e954ee5 commit b25bf7f
Show file tree
Hide file tree
Showing 6 changed files with 499 additions and 1 deletion.
193 changes: 193 additions & 0 deletions tests/unit/s2n_ktls_cmsg_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
/*
* 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 <sys/socket.h>

#include "error/s2n_errno.h"
#include "s2n.h"
#include "s2n_test.h"
#include "testlib/s2n_testlib.h"
#include "tls/s2n_ktls.h"

S2N_RESULT s2n_ktls_send_msg_impl(int sock, struct msghdr *msg,
const struct iovec *msg_iov, s2n_blocked_status *blocked, ssize_t *result);
S2N_RESULT s2n_ktls_recv_msg_impl(int sock, struct msghdr *msg,
struct iovec *msg_iov, s2n_blocked_status *blocked, ssize_t *result);
S2N_RESULT s2n_ktls_send_control_msg(int sock, struct msghdr *msg,
uint8_t record_type, s2n_blocked_status *blocked, ssize_t *result);
S2N_RESULT s2n_ktls_recv_control_msg(int sock, struct msghdr *msg,
uint8_t *record_type, s2n_blocked_status *blocked, ssize_t *result);

#define MAX_DATA_LEN 20000

S2N_RESULT helper_generate_test_data(struct s2n_blob *test_data)
{
struct s2n_stuffer test_data_stuffer = { 0 };
RESULT_GUARD_POSIX(s2n_stuffer_init(&test_data_stuffer, test_data));
for (int i = 1; i < MAX_DATA_LEN; i++) {
RESULT_GUARD_POSIX(s2n_stuffer_write_uint8(&test_data_stuffer, i));
}
return S2N_RESULT_OK;
}

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

uint8_t test_data[MAX_DATA_LEN] = { 0 };
struct s2n_blob test_data_blob = { 0 };
EXPECT_SUCCESS(s2n_blob_init(&test_data_blob, test_data, sizeof(test_data)));
EXPECT_OK(helper_generate_test_data(&test_data_blob));

struct msghdr msg = { 0 };
struct iovec msg_iov = { 0 };

#if defined(S2N_KTLS_SUPPORTED)
/* ctrl_msg send and recv data */
for (size_t to_send = 1; to_send < MAX_DATA_LEN; to_send += 500) {
/* Create a pipe */
struct s2n_test_io_pair io_pair;
EXPECT_SUCCESS(s2n_io_pair_init_non_blocking(&io_pair));
s2n_blocked_status blocked = S2N_NOT_BLOCKED;

{
msg_iov.iov_base = (void *) (uintptr_t) test_data;
msg_iov.iov_len = to_send;

ssize_t sent_len = 0;
EXPECT_OK(s2n_ktls_send_msg_impl(io_pair.client, &msg, &msg_iov, &blocked, &sent_len));
EXPECT_EQUAL(sent_len, to_send);
}

uint8_t recv_buffer[MAX_DATA_LEN] = { 0 };
/* confirm test_data and recv_buffer dont match */
EXPECT_NOT_EQUAL(memcmp(test_data, recv_buffer, to_send), 0);
{
msg_iov.iov_base = recv_buffer;
msg_iov.iov_len = to_send;

ssize_t recv_len = 0;
EXPECT_OK(s2n_ktls_recv_msg_impl(io_pair.server, &msg, &msg_iov, &blocked, &recv_len));
EXPECT_EQUAL(recv_len, to_send);
EXPECT_EQUAL(memcmp(test_data, recv_buffer, recv_len), 0);
}
}

/* test blocked data and partial reads */
{
/* Create a pipe */
struct s2n_test_io_pair io_pair;
EXPECT_SUCCESS(s2n_io_pair_init_non_blocking(&io_pair));
s2n_blocked_status blocked = S2N_NOT_BLOCKED;

/* only read half the total data sent to simulate multiple reads */
size_t to_send = 10;
size_t to_recv = 5;

uint8_t recv_buffer[MAX_DATA_LEN] = { 0 };
/* confirm test_data and recv_buffer dont match */
EXPECT_NOT_EQUAL(memcmp(test_data, recv_buffer, to_send), 0);

/* calling recv when nothing has been sent blocks */
{
msg_iov.iov_base = recv_buffer;
msg_iov.iov_len = to_recv;

ssize_t recv_len = 0;
EXPECT_ERROR_WITH_ERRNO(s2n_ktls_recv_msg_impl(io_pair.server, &msg, &msg_iov, &blocked, &recv_len), S2N_ERR_IO_BLOCKED);
EXPECT_EQUAL(blocked, S2N_BLOCKED_ON_READ);
}

/* send data */
{
msg_iov.iov_base = (void *) (uintptr_t) test_data;
msg_iov.iov_len = to_send;

ssize_t sent_len = 0;
EXPECT_OK(s2n_ktls_send_msg_impl(io_pair.client, &msg, &msg_iov, &blocked, &sent_len));
EXPECT_EQUAL(sent_len, to_send);
}

/* only read half the amount of data sent */
{
msg_iov.iov_base = recv_buffer;
msg_iov.iov_len = to_recv;

ssize_t recv_len = 0;
EXPECT_OK(s2n_ktls_recv_msg_impl(io_pair.server, &msg, &msg_iov, &blocked, &recv_len));
EXPECT_EQUAL(recv_len, to_recv);
EXPECT_EQUAL(memcmp(test_data, recv_buffer, to_recv), 0);
}

/* read the other half of data sent */
{
/* offset the read buffer by the amount already read */
msg_iov.iov_base = recv_buffer + to_recv;
msg_iov.iov_len = to_recv;

ssize_t recv_len = 0;
EXPECT_OK(s2n_ktls_recv_msg_impl(io_pair.server, &msg, &msg_iov, &blocked, &recv_len));
EXPECT_EQUAL(recv_len, to_recv);
}

/* confirm that all data was read and matches sent data of length `to_send` */
EXPECT_EQUAL(memcmp(test_data, recv_buffer, to_send), 0);
}

/* cmsg send and recv ancillary data */
{
uint8_t send_record_type = 10;
int fd = 0;
s2n_blocked_status blocked = S2N_NOT_BLOCKED;
ssize_t result = 0;
union {
char buf[CMSG_SPACE(sizeof(send_record_type))];
/* Space large enough to hold a ucred structure */
struct cmsghdr align;
} control_msg;

/* Init msghdr */
struct msghdr s_msg = { 0 };
s_msg.msg_name = NULL;
s_msg.msg_namelen = 0;
s_msg.msg_control = control_msg.buf;
s_msg.msg_controllen = sizeof(control_msg.buf);

/* create the control_msg */
EXPECT_OK(s2n_ktls_send_control_msg(fd, &s_msg, send_record_type, &blocked, &result));

/* modify control_msg for the recv side
*
* cmsg_type is converted to GET on the recv side if record type is not TLS_APPLICATION_DATA
*/
struct cmsghdr *hdr = CMSG_FIRSTHDR(&s_msg);
hdr->cmsg_type = S2N_TLS_GET_RECORD_TYPE;

/* assert that we can parse the same record_type */
uint8_t recv_record_type = 0;
EXPECT_OK(s2n_ktls_recv_control_msg(fd, &s_msg, &recv_record_type, &blocked, &result));
EXPECT_EQUAL(recv_record_type, send_record_type);

/* record_type should default to TLS_APPLICATION_DATA */
hdr->cmsg_type = 0;
hdr->cmsg_level = 0;
recv_record_type = 0;
EXPECT_OK(s2n_ktls_recv_control_msg(fd, &s_msg, &recv_record_type, &blocked, &result));
EXPECT_EQUAL(recv_record_type, TLS_APPLICATION_DATA);
}
#endif

END_TEST();
}
2 changes: 1 addition & 1 deletion tls/s2n_ktls.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

bool s2n_ktls_is_supported_on_platform()
{
#if defined(__linux__)
#if defined(S2N_KTLS_SUPPORTED)
return true;
#else
return false;
Expand Down
12 changes: 12 additions & 0 deletions tls/s2n_ktls.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@

#include "tls/s2n_config.h"

/* Enable kTLS on tested platforms.
*
* Define headers needed to enable and use kTLS.
*/
#if defined(__linux__)
#define S2N_KTLS_SUPPORTED true
#include "tls/s2n_ktls_linux.h"
#else
#undef S2N_KTLS_SUPPORTED
#include "tls/s2n_ktls_unsupported.h"
#endif

/* A set of kTLS configurations representing the combination of sending
* and receiving.
*/
Expand Down
Loading

0 comments on commit b25bf7f

Please sign in to comment.