Skip to content

Commit 30f40f2

Browse files
feat: Add key update to ktls feature (#5484)
Co-authored-by: Lindsay Stewart <stewart.r.lindsay@gmail.com>
1 parent fa93e58 commit 30f40f2

File tree

11 files changed

+362
-95
lines changed

11 files changed

+362
-95
lines changed

codebuild/spec/buildspec_ktls_keyupdate.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ env:
2525
NIX_CACHE_BUCKET: "s3://s2n-tls-nixcachebucket-x86-64?region=us-west-2"
2626
NIX_INSTALLER: "https://nixos.org/nix/install"
2727
S2N_KTLS_TESTING_EXPECTED: 1
28+
S2N_KTLS_KEYUPDATE_TESTING_EXPECTED: 1
2829
phases:
2930
pre_build:
3031
commands:

error/s2n_errno.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ static const char *no_such_error = "Internal s2n error";
309309
ERR_ENTRY(S2N_ERR_KTLS_RENEG, "kTLS does not support secure renegotiation") \
310310
ERR_ENTRY(S2N_ERR_KTLS_KEYUPDATE, "Received KeyUpdate from peer, but kernel does not support updating tls keys") \
311311
ERR_ENTRY(S2N_ERR_KTLS_KEY_LIMIT, "Reached key encryption limit, but kernel does not support updating tls keys") \
312+
ERR_ENTRY(S2N_ERR_KTLS_SOCKOPT, "A call to sockopt failed when attempting to update the keys in the kernel") \
312313
ERR_ENTRY(S2N_ERR_UNEXPECTED_CERT_REQUEST, "Client forbids mutual authentication, but server requested a cert") \
313314
ERR_ENTRY(S2N_ERR_MISSING_CERT_REQUEST, "Client requires mutual authentication, but server did not request a cert") \
314315
ERR_ENTRY(S2N_ERR_MISSING_CLIENT_CERT, "Server requires client certificate") \

error/s2n_errno.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ typedef enum {
328328
S2N_ERR_KTLS_ENABLE,
329329
S2N_ERR_KTLS_BAD_CMSG,
330330
S2N_ERR_KTLS_RENEG,
331+
S2N_ERR_KTLS_SOCKOPT,
331332
S2N_ERR_ATOMIC,
332333
S2N_ERR_KTLS_KEY_LIMIT,
333334
S2N_ERR_SECURITY_POLICY_INCOMPATIBLE_CERT,

tests/unit/s2n_key_update_test.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ int main(int argc, char **argv)
148148
EXPECT_SUCCESS(s2n_connection_free(conn));
149149
};
150150

151-
/* Key update messages not allowed with ktls */
151+
/* Key update messages not allowed with ktls by default */
152152
{
153153
DEFER_CLEANUP(struct s2n_stuffer input, s2n_stuffer_free);
154154
EXPECT_SUCCESS(s2n_stuffer_growable_alloc(&input, 0));
@@ -175,8 +175,10 @@ int main(int argc, char **argv)
175175
conn->ktls_send_enabled = true;
176176
conn->ktls_recv_enabled = false;
177177
EXPECT_SUCCESS(s2n_stuffer_write_uint8(&input, S2N_KEY_UPDATE_REQUESTED));
178-
EXPECT_FAILURE_WITH_ERRNO(s2n_key_update_recv(conn, &input), S2N_ERR_KTLS_KEYUPDATE);
178+
EXPECT_SUCCESS(s2n_key_update_recv(conn, &input));
179179
EXPECT_EQUAL(s2n_stuffer_data_available(&input), 0);
180+
s2n_blocked_status blocked = S2N_NOT_BLOCKED;
181+
EXPECT_FAILURE_WITH_ERRNO(s2n_key_update_send(conn, &blocked), S2N_ERR_KTLS_KEYUPDATE);
180182

181183
/* Succeeds if only sending with ktls and no update requested:
182184
* No kernel key update would be required.
@@ -527,7 +529,7 @@ int main(int argc, char **argv)
527529
/* Fails if KeyUpdate required */
528530
EXPECT_FAILURE_WITH_ERRNO(
529531
s2n_key_update_send(conn, &blocked),
530-
S2N_ERR_KTLS_KEY_LIMIT);
532+
S2N_ERR_KTLS_KEYUPDATE);
531533
EXPECT_TRUE(s2n_atomic_flag_test(&conn->key_update_pending));
532534
};
533535
};

tests/unit/s2n_ktls_test.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,5 +639,76 @@ int main(int argc, char **argv)
639639
EXPECT_TRUE(config->ktls_tls13_enabled);
640640
};
641641

642+
/* Test: s2n_ktls_check_estimated_record_limit sets key_update_pending flag */
643+
{
644+
/* Create a cipher suite with an artificially lowered encryption limit */
645+
const size_t test_encryption_limit = 3;
646+
struct s2n_record_algorithm test_record_alg = *s2n_tls13_aes_128_gcm_sha256.record_alg;
647+
test_record_alg.encryption_limit = test_encryption_limit;
648+
struct s2n_cipher_suite test_cipher_suite = s2n_tls13_aes_128_gcm_sha256;
649+
test_cipher_suite.record_alg = &test_record_alg;
650+
651+
DEFER_CLEANUP(struct s2n_connection *conn = s2n_connection_new(S2N_CLIENT),
652+
s2n_connection_ptr_free);
653+
EXPECT_NOT_NULL(conn);
654+
DEFER_CLEANUP(struct s2n_config *config = s2n_config_new(), s2n_config_ptr_free);
655+
EXPECT_SUCCESS(s2n_config_ktls_enable_unsafe_tls13(config));
656+
EXPECT_SUCCESS(s2n_connection_set_config(conn, config));
657+
658+
EXPECT_NOT_NULL(conn->secure);
659+
conn->secure->cipher_suite = &test_cipher_suite;
660+
conn->actual_protocol_version = S2N_TLS13;
661+
662+
/* Test: 0 records sent so far */
663+
{
664+
/* Requested bytes exactly hit encryption limit */
665+
size_t bytes_requested = S2N_TLS_MAXIMUM_FRAGMENT_LENGTH * test_encryption_limit;
666+
EXPECT_OK(s2n_ktls_check_estimated_record_limit(conn, bytes_requested));
667+
EXPECT_FALSE(s2n_atomic_flag_test(&conn->key_update_pending));
668+
669+
/* Requested bytes go over the encryption limit */
670+
bytes_requested = (S2N_TLS_MAXIMUM_FRAGMENT_LENGTH * test_encryption_limit) + 1;
671+
EXPECT_ERROR_WITH_ERRNO(s2n_ktls_check_estimated_record_limit(conn, bytes_requested), S2N_ERR_INVALID_ARGUMENT);
672+
EXPECT_FALSE(s2n_atomic_flag_test(&conn->key_update_pending));
673+
}
674+
675+
/* Test: 2 records sent so far */
676+
{
677+
EXPECT_OK(s2n_ktls_set_estimated_sequence_number(conn, S2N_TLS_MAXIMUM_FRAGMENT_LENGTH * 2));
678+
679+
/* Requested bytes exactly hit encryption limit */
680+
size_t bytes_requested = S2N_TLS_MAXIMUM_FRAGMENT_LENGTH;
681+
EXPECT_OK(s2n_ktls_check_estimated_record_limit(conn, bytes_requested));
682+
EXPECT_FALSE(s2n_atomic_flag_test(&conn->key_update_pending));
683+
684+
/* Requested bytes go over the encryption limit */
685+
bytes_requested = S2N_TLS_MAXIMUM_FRAGMENT_LENGTH + 1;
686+
EXPECT_OK(s2n_ktls_check_estimated_record_limit(conn, bytes_requested));
687+
EXPECT_TRUE(s2n_atomic_flag_test(&conn->key_update_pending));
688+
s2n_atomic_flag_clear(&conn->key_update_pending);
689+
690+
/* Requested bytes go over the encryption limit twice */
691+
bytes_requested = (S2N_TLS_MAXIMUM_FRAGMENT_LENGTH * test_encryption_limit) + 1;
692+
EXPECT_ERROR_WITH_ERRNO(s2n_ktls_check_estimated_record_limit(conn, bytes_requested), S2N_ERR_INVALID_ARGUMENT);
693+
EXPECT_FALSE(s2n_atomic_flag_test(&conn->key_update_pending));
694+
}
695+
696+
/* Test: 3 records sent so far (exactly at encryption limit) */
697+
{
698+
EXPECT_OK(s2n_ktls_set_estimated_sequence_number(conn, S2N_TLS_MAXIMUM_FRAGMENT_LENGTH * 3));
699+
700+
/* Requested bytes go over the encryption limit */
701+
size_t bytes_requested = 1;
702+
EXPECT_OK(s2n_ktls_check_estimated_record_limit(conn, bytes_requested));
703+
EXPECT_TRUE(s2n_atomic_flag_test(&conn->key_update_pending));
704+
s2n_atomic_flag_clear(&conn->key_update_pending);
705+
706+
/* Requested bytes go over the encryption limit twice */
707+
bytes_requested = (S2N_TLS_MAXIMUM_FRAGMENT_LENGTH * test_encryption_limit) + 1;
708+
EXPECT_ERROR_WITH_ERRNO(s2n_ktls_check_estimated_record_limit(conn, bytes_requested), S2N_ERR_INVALID_ARGUMENT);
709+
EXPECT_FALSE(s2n_atomic_flag_test(&conn->key_update_pending));
710+
}
711+
}
712+
642713
END_TEST();
643714
}

tests/unit/s2n_self_talk_ktls_test.c

Lines changed: 120 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ int main(int argc, char **argv)
9797
* where we think we're testing it.
9898
*/
9999
const bool ktls_expected = (getenv("S2N_KTLS_TESTING_EXPECTED") != NULL);
100+
const bool ktls_keyupdate_expected = (getenv("S2N_KTLS_KEYUPDATE_TESTING_EXPECTED") != NULL);
100101

101102
if (!s2n_ktls_is_supported_on_platform() && !ktls_expected) {
102103
END_TEST();
@@ -460,22 +461,6 @@ int main(int argc, char **argv)
460461
EXPECT_BYTEARRAY_EQUAL(test_data, buffer, read);
461462
}
462463
};
463-
464-
/* Test: receiving KeyUpdate message */
465-
{
466-
EXPECT_SUCCESS(s2n_connection_set_blinding(reader, S2N_SELF_SERVICE_BLINDING));
467-
468-
/* Write KeyUpdate message */
469-
s2n_atomic_flag_set(&writer->key_update_pending);
470-
int written = s2n_send(writer, test_data, sizeof(test_data), &blocked);
471-
EXPECT_EQUAL(written, sizeof(test_data));
472-
473-
/* Read KeyUpdate message */
474-
uint8_t buffer[sizeof(test_data)] = { 0 };
475-
EXPECT_FAILURE_WITH_ERRNO(
476-
s2n_recv(reader, buffer, sizeof(buffer), &blocked),
477-
S2N_ERR_KTLS_KEYUPDATE);
478-
};
479464
};
480465

481466
/* Test: s2n_shutdown
@@ -698,5 +683,124 @@ int main(int argc, char **argv)
698683
}
699684
}
700685

686+
/* Test: Keyupdates with KTLS */
687+
if (ktls_keyupdate_expected) {
688+
/* Cipher suite with an artificially lowered encryption limit */
689+
const size_t test_encryption_limit = 1;
690+
struct s2n_record_algorithm test_record_alg = *s2n_tls13_aes_128_gcm_sha256.record_alg;
691+
test_record_alg.encryption_limit = test_encryption_limit;
692+
struct s2n_cipher_suite test_cipher_suite = s2n_tls13_aes_128_gcm_sha256;
693+
test_cipher_suite.record_alg = &test_record_alg;
694+
695+
/* Test: Sending key update with KTLS */
696+
if (ktls_send_supported) {
697+
/* Test: Multiple key updates are allowed as long as they can be sent over multiple
698+
* s2n_send calls with ktls. */
699+
{
700+
DEFER_CLEANUP(struct s2n_connection *client = s2n_connection_new(S2N_CLIENT),
701+
s2n_connection_ptr_free);
702+
EXPECT_NOT_NULL(client);
703+
EXPECT_SUCCESS(s2n_connection_set_config(client, config));
704+
EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(client, "default_tls13"));
705+
EXPECT_SUCCESS(s2n_connection_set_blinding(client, S2N_SELF_SERVICE_BLINDING));
706+
707+
DEFER_CLEANUP(struct s2n_connection *server = s2n_connection_new(S2N_SERVER),
708+
s2n_connection_ptr_free);
709+
EXPECT_NOT_NULL(server);
710+
EXPECT_SUCCESS(s2n_connection_set_config(server, config));
711+
EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(server, "default_tls13"));
712+
EXPECT_SUCCESS(s2n_connection_set_blinding(server, S2N_SELF_SERVICE_BLINDING));
713+
714+
DEFER_CLEANUP(struct s2n_test_io_pair io_pair = { 0 }, s2n_io_pair_close);
715+
EXPECT_OK(s2n_new_inet_socket_pair(&io_pair));
716+
EXPECT_OK(s2n_setup_connections(server, client, &io_pair));
717+
718+
EXPECT_SUCCESS(s2n_connection_ktls_enable_send(server));
719+
720+
/* Reset server cipher suite to trigger a key update after sending one record */
721+
EXPECT_NOT_NULL(server->secure);
722+
EXPECT_EQUAL(server->secure->cipher_suite, &s2n_tls13_aes_128_gcm_sha256);
723+
server->secure->cipher_suite = &test_cipher_suite;
724+
725+
/* This will require a keyupdate mid-send, which is not allowed with ktls */
726+
uint8_t exceeds_record_limit[S2N_TLS_MAXIMUM_FRAGMENT_LENGTH * 2] = { 0 };
727+
s2n_blocked_status blocked = S2N_NOT_BLOCKED;
728+
EXPECT_FAILURE_WITH_ERRNO(s2n_send(server, exceeds_record_limit, sizeof(exceeds_record_limit),
729+
&blocked),
730+
S2N_ERR_INVALID_ARGUMENT);
731+
732+
uint8_t large_test_data[S2N_TLS_MAXIMUM_FRAGMENT_LENGTH] = { "Hello there" };
733+
/* Each send call will include one key update */
734+
for (int i = 0; i < 10; i++) {
735+
int written = s2n_send(server, large_test_data, sizeof(large_test_data), &blocked);
736+
EXPECT_EQUAL(written, sizeof(large_test_data));
737+
EXPECT_EQUAL(blocked, S2N_NOT_BLOCKED);
738+
}
739+
EXPECT_EQUAL(server->recv_key_updated, 0);
740+
EXPECT_EQUAL(server->send_key_updated, 9);
741+
742+
/* We only get one record per s2n_recv call, so we call it ten times */
743+
for (size_t i = 0; i < 10; i++) {
744+
uint8_t buffer[sizeof(large_test_data)] = { 1 };
745+
int read = s2n_recv(client, buffer, sizeof(buffer), &blocked);
746+
EXPECT_EQUAL(read, sizeof(large_test_data));
747+
EXPECT_BYTEARRAY_EQUAL(large_test_data, buffer, read);
748+
}
749+
750+
EXPECT_EQUAL(client->recv_key_updated, 9);
751+
EXPECT_EQUAL(client->send_key_updated, 0);
752+
}
753+
};
754+
755+
/* Test: Receiving key update with KTLS */
756+
if (ktls_recv_supported) {
757+
DEFER_CLEANUP(struct s2n_connection *client = s2n_connection_new(S2N_CLIENT),
758+
s2n_connection_ptr_free);
759+
EXPECT_NOT_NULL(client);
760+
EXPECT_SUCCESS(s2n_connection_set_config(client, config));
761+
EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(client, "default_tls13"));
762+
EXPECT_SUCCESS(s2n_connection_set_blinding(client, S2N_SELF_SERVICE_BLINDING));
763+
764+
DEFER_CLEANUP(struct s2n_connection *server = s2n_connection_new(S2N_SERVER),
765+
s2n_connection_ptr_free);
766+
EXPECT_NOT_NULL(server);
767+
EXPECT_SUCCESS(s2n_connection_set_config(server, config));
768+
EXPECT_SUCCESS(s2n_connection_set_cipher_preferences(server, "default_tls13"));
769+
EXPECT_SUCCESS(s2n_connection_set_blinding(server, S2N_SELF_SERVICE_BLINDING));
770+
771+
DEFER_CLEANUP(struct s2n_test_io_pair io_pair = { 0 }, s2n_io_pair_close);
772+
EXPECT_OK(s2n_new_inet_socket_pair(&io_pair));
773+
EXPECT_OK(s2n_setup_connections(server, client, &io_pair));
774+
775+
EXPECT_SUCCESS(s2n_connection_ktls_enable_recv(client));
776+
777+
/* Reset server cipher suite to trigger a key update after sending one record */
778+
EXPECT_NOT_NULL(server->secure);
779+
EXPECT_EQUAL(server->secure->cipher_suite, &s2n_tls13_aes_128_gcm_sha256);
780+
server->secure->cipher_suite = &test_cipher_suite;
781+
782+
uint8_t large_test_data[S2N_DEFAULT_FRAGMENT_LENGTH * 10] = { "Hello there" };
783+
s2n_blocked_status blocked = S2N_NOT_BLOCKED;
784+
int written = s2n_send(server, large_test_data, sizeof(large_test_data), &blocked);
785+
EXPECT_EQUAL(written, sizeof(large_test_data));
786+
EXPECT_EQUAL(blocked, S2N_NOT_BLOCKED);
787+
788+
/* Sent 10 records and the encryption limit is 1 record so the send key will be updated
789+
* 9 times. */
790+
EXPECT_EQUAL(server->recv_key_updated, 0);
791+
EXPECT_EQUAL(server->send_key_updated, 9);
792+
793+
/* We only get one record per s2n_recv call, so we call it ten times */
794+
for (size_t i = 0; i < 10; i++) {
795+
uint8_t buffer[sizeof(large_test_data) / 10] = { 1 };
796+
int read = s2n_recv(client, buffer, sizeof(buffer), &blocked);
797+
EXPECT_EQUAL(read, sizeof(large_test_data) / 10);
798+
EXPECT_BYTEARRAY_EQUAL(buffer, large_test_data + (i * S2N_DEFAULT_FRAGMENT_LENGTH), read);
799+
}
800+
801+
EXPECT_EQUAL(client->recv_key_updated, 9);
802+
EXPECT_EQUAL(client->send_key_updated, 0);
803+
};
804+
}
701805
END_TEST();
702806
}

tls/s2n_key_update.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "crypto/s2n_sequence.h"
1919
#include "error/s2n_errno.h"
2020
#include "tls/s2n_connection.h"
21+
#include "tls/s2n_ktls.h"
2122
#include "tls/s2n_record.h"
2223
#include "tls/s2n_tls.h"
2324
#include "tls/s2n_tls13_handshake.h"
@@ -39,14 +40,13 @@ S2N_RESULT s2n_set_key_update_request_for_testing(s2n_peer_key_update request)
3940
int s2n_key_update_recv(struct s2n_connection *conn, struct s2n_stuffer *request)
4041
{
4142
POSIX_ENSURE_REF(conn);
43+
POSIX_ENSURE_REF(conn->config);
4244
POSIX_ENSURE(conn->actual_protocol_version >= S2N_TLS13, S2N_ERR_BAD_MESSAGE);
4345
POSIX_ENSURE(!s2n_connection_is_quic_enabled(conn), S2N_ERR_BAD_MESSAGE);
44-
POSIX_ENSURE(!conn->ktls_recv_enabled, S2N_ERR_KTLS_KEYUPDATE);
4546

4647
uint8_t key_update_request = 0;
4748
POSIX_GUARD(s2n_stuffer_read_uint8(request, &key_update_request));
4849
if (key_update_request == S2N_KEY_UPDATE_REQUESTED) {
49-
POSIX_ENSURE(!conn->ktls_send_enabled, S2N_ERR_KTLS_KEYUPDATE);
5050
s2n_atomic_flag_set(&conn->key_update_pending);
5151
} else {
5252
POSIX_ENSURE(key_update_request == S2N_KEY_UPDATE_NOT_REQUESTED, S2N_ERR_BAD_MESSAGE);
@@ -59,6 +59,11 @@ int s2n_key_update_recv(struct s2n_connection *conn, struct s2n_stuffer *request
5959
POSIX_GUARD(s2n_update_application_traffic_keys(conn, S2N_CLIENT, RECEIVING));
6060
}
6161

62+
/* We need to update the socket with the new keys in the case of ktls */
63+
if (conn->ktls_recv_enabled) {
64+
POSIX_GUARD_RESULT(s2n_ktls_key_update_process(conn));
65+
}
66+
6267
return S2N_SUCCESS;
6368
}
6469

@@ -73,7 +78,7 @@ int s2n_key_update_send(struct s2n_connection *conn, s2n_blocked_status *blocked
7378
POSIX_GUARD(s2n_check_record_limit(conn, &sequence_number));
7479

7580
if (s2n_atomic_flag_test(&conn->key_update_pending)) {
76-
POSIX_ENSURE(!conn->ktls_send_enabled, S2N_ERR_KTLS_KEY_LIMIT);
81+
POSIX_ENSURE(!conn->ktls_send_enabled, S2N_ERR_KTLS_KEYUPDATE);
7782

7883
/* Flush any buffered records to ensure an empty output buffer.
7984
*

tls/s2n_key_update.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@ typedef enum {
2727

2828
int s2n_key_update_recv(struct s2n_connection *conn, struct s2n_stuffer *request);
2929
int s2n_key_update_send(struct s2n_connection *conn, s2n_blocked_status *blocked);
30+
int s2n_key_update_write(struct s2n_blob *out);

0 commit comments

Comments
 (0)