Skip to content

Commit eb168f2

Browse files
jouholrstewart
andauthored
fix: Fix a bug in tls1.3 code path (#4513)
* fix a bug in tls1.3 code path with unit test to verify the change * modify comment on if block * fix formatting to clang-format compatible * reformat if() block to avoid unnecessarry computation * free memory used for test * add a check if tls1.3 is supported before running the test * change s2n_config_is_encrypt_decrypt_key_available() return type to S2N_RESULT * add null checks and reformat if() block for readability * better comments and variable naming * style fixes and add tls 1.3 verification * use shorter function name * modify test to fail on HS type assersion instead of during the HS * use shorter variable name Co-authored-by: Lindsay Stewart <[email protected]> * address readability * use shorter variable names * address PR comment * Update tests/unit/s2n_session_ticket_test.c Co-authored-by: Lindsay Stewart <[email protected]> * bail with proper error code * fix err code --------- Co-authored-by: Lindsay Stewart <[email protected]>
1 parent 3d125a5 commit eb168f2

File tree

5 files changed

+86
-17
lines changed

5 files changed

+86
-17
lines changed

tests/unit/s2n_session_ticket_test.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,6 +1348,74 @@ int main(int argc, char **argv)
13481348
EXPECT_SUCCESS(s2n_config_free(config));
13491349
}
13501350

1351+
/* Test: TLS1.3 resumption is successful when key used to encrypt ticket is in decrypt-only state */
1352+
if (s2n_is_tls13_fully_supported()) {
1353+
DEFER_CLEANUP(struct s2n_config *client_configuration = s2n_config_new(),
1354+
s2n_config_ptr_free);
1355+
EXPECT_NOT_NULL(client_configuration);
1356+
EXPECT_SUCCESS(s2n_config_set_session_tickets_onoff(client_configuration, 1));
1357+
EXPECT_SUCCESS(s2n_config_set_cipher_preferences(client_configuration, "default_tls13"));
1358+
EXPECT_SUCCESS(s2n_config_set_unsafe_for_testing(client_configuration));
1359+
1360+
DEFER_CLEANUP(struct s2n_config *server_configuration = s2n_config_new(),
1361+
s2n_config_ptr_free);
1362+
EXPECT_NOT_NULL(server_configuration);
1363+
EXPECT_SUCCESS(s2n_config_set_session_tickets_onoff(server_configuration, 1));
1364+
EXPECT_SUCCESS(s2n_config_set_cipher_preferences(server_configuration, "default_tls13"));
1365+
EXPECT_SUCCESS(s2n_config_set_unsafe_for_testing(server_configuration));
1366+
EXPECT_SUCCESS(s2n_config_add_cert_chain_and_key_to_store(server_configuration,
1367+
chain_and_key));
1368+
1369+
/* Add the key that encrypted the session ticket so that the server will be able to decrypt
1370+
* the ticket successfully.
1371+
*/
1372+
EXPECT_SUCCESS(s2n_config_add_ticket_crypto_key(server_configuration, ticket_key_name1,
1373+
s2n_array_len(ticket_key_name1), ticket_key1, s2n_array_len(ticket_key1), 0));
1374+
1375+
/* Add a mock delay such that key 1 moves to decrypt-only state */
1376+
uint64_t mock_delay = server_configuration->encrypt_decrypt_key_lifetime_in_nanos;
1377+
EXPECT_SUCCESS(s2n_config_set_wall_clock(server_configuration, mock_nanoseconds_since_epoch,
1378+
&mock_delay));
1379+
1380+
/* Add one session ticket key with an intro time in the past so that the key is immediately valid */
1381+
POSIX_GUARD(server_configuration->wall_clock(server_configuration->sys_clock_ctx, &now));
1382+
uint64_t key_intro_time = (now / ONE_SEC_IN_NANOS) - ONE_SEC_DELAY;
1383+
EXPECT_SUCCESS(s2n_config_add_ticket_crypto_key(server_configuration, ticket_key_name2,
1384+
s2n_array_len(ticket_key_name2), ticket_key2, s2n_array_len(ticket_key2), key_intro_time));
1385+
1386+
DEFER_CLEANUP(struct s2n_connection *client = s2n_connection_new(S2N_CLIENT),
1387+
s2n_connection_ptr_free);
1388+
EXPECT_NOT_NULL(client);
1389+
EXPECT_SUCCESS(s2n_connection_set_session(client, tls13_serialized_session_state.blob.data,
1390+
s2n_stuffer_data_available(&tls13_serialized_session_state)));
1391+
EXPECT_SUCCESS(s2n_connection_set_config(client, client_configuration));
1392+
1393+
DEFER_CLEANUP(struct s2n_connection *server = s2n_connection_new(S2N_SERVER),
1394+
s2n_connection_ptr_free);
1395+
EXPECT_NOT_NULL(server);
1396+
EXPECT_SUCCESS(s2n_connection_set_config(server, server_configuration));
1397+
1398+
/* Create nonblocking pipes */
1399+
DEFER_CLEANUP(struct s2n_test_io_stuffer_pair test_io = { 0 },
1400+
s2n_io_stuffer_pair_free);
1401+
EXPECT_OK(s2n_io_stuffer_pair_init(&test_io));
1402+
EXPECT_OK(s2n_connections_set_io_stuffer_pair(client, server, &test_io));
1403+
1404+
EXPECT_SUCCESS(s2n_negotiate_test_server_and_client(server, client));
1405+
1406+
/* Verify that TLS1.3 was negotiated */
1407+
EXPECT_EQUAL(client->actual_protocol_version, S2N_TLS13);
1408+
EXPECT_EQUAL(server->actual_protocol_version, S2N_TLS13);
1409+
1410+
/* Expect a resumption handshake because the session ticket is valid.
1411+
* If a full handshake is performed instead, then the session ticket is incorrectly
1412+
* being evaluated as invalid. This was previously known to happen with a decrypt-only
1413+
* key because we'd incorrectly try to set a TLS1.2-only handshake type flag,
1414+
* triggering an error while decrypting the session ticket.
1415+
*/
1416+
EXPECT_TRUE(IS_RESUMPTION_HANDSHAKE(server));
1417+
}
1418+
13511419
EXPECT_SUCCESS(s2n_io_pair_close(&io_pair));
13521420
EXPECT_SUCCESS(s2n_cert_chain_and_key_free(chain_and_key));
13531421
EXPECT_SUCCESS(s2n_cert_chain_and_key_free(ecdsa_chain_and_key));

tls/extensions/s2n_client_session_ticket.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ static int s2n_client_session_ticket_recv(struct s2n_connection *conn, struct s2
6363
if (s2n_stuffer_data_available(extension) == S2N_TLS12_TICKET_SIZE_IN_BYTES) {
6464
conn->session_ticket_status = S2N_DECRYPT_TICKET;
6565
POSIX_GUARD(s2n_stuffer_copy(extension, &conn->client_ticket_to_decrypt, S2N_TLS12_TICKET_SIZE_IN_BYTES));
66-
} else if (s2n_config_is_encrypt_decrypt_key_available(conn->config) == 1) {
66+
} else if (s2n_result_is_ok(s2n_config_is_encrypt_key_available(conn->config))) {
6767
conn->session_ticket_status = S2N_NEW_TICKET;
6868
}
6969

tls/s2n_handshake_io.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1053,7 +1053,7 @@ int s2n_conn_set_handshake_type(struct s2n_connection *conn)
10531053
POSIX_GUARD_RESULT(s2n_validate_ems_status(conn));
10541054

10551055
/* Set up the handshake to send a session ticket since a valid ticket was not provided */
1056-
if (s2n_config_is_encrypt_decrypt_key_available(conn->config) == 1) {
1056+
if (s2n_result_is_ok(s2n_config_is_encrypt_key_available(conn->config))) {
10571057
conn->session_ticket_status = S2N_NEW_TICKET;
10581058
POSIX_GUARD_RESULT(s2n_handshake_type_set_tls12_flag(conn, WITH_SESSION_TICKET));
10591059
}

tls/s2n_resume.c

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -610,28 +610,30 @@ int s2n_connection_is_ocsp_stapled(struct s2n_connection *conn)
610610
}
611611
}
612612

613-
int s2n_config_is_encrypt_decrypt_key_available(struct s2n_config *config)
613+
S2N_RESULT s2n_config_is_encrypt_key_available(struct s2n_config *config)
614614
{
615+
RESULT_ENSURE_REF(config);
616+
615617
uint64_t now = 0;
616618
struct s2n_ticket_key *ticket_key = NULL;
617-
POSIX_GUARD_RESULT(s2n_config_wall_clock(config, &now));
618-
POSIX_ENSURE_REF(config->ticket_keys);
619+
RESULT_GUARD(s2n_config_wall_clock(config, &now));
620+
RESULT_ENSURE_REF(config->ticket_keys);
619621

620622
uint32_t ticket_keys_len = 0;
621-
POSIX_GUARD_RESULT(s2n_set_len(config->ticket_keys, &ticket_keys_len));
623+
RESULT_GUARD(s2n_set_len(config->ticket_keys, &ticket_keys_len));
622624

623625
for (uint32_t i = ticket_keys_len; i > 0; i--) {
624626
uint32_t idx = i - 1;
625-
POSIX_GUARD_RESULT(s2n_set_get(config->ticket_keys, idx, (void **) &ticket_key));
627+
RESULT_GUARD(s2n_set_get(config->ticket_keys, idx, (void **) &ticket_key));
626628
uint64_t key_intro_time = ticket_key->intro_timestamp;
627629

628630
if (key_intro_time < now
629631
&& now < key_intro_time + config->encrypt_decrypt_key_lifetime_in_nanos) {
630-
return 1;
632+
return S2N_RESULT_OK;
631633
}
632634
}
633635

634-
return 0;
636+
RESULT_BAIL(S2N_ERR_NO_TICKET_ENCRYPT_DECRYPT_KEY);
635637
}
636638

637639
/* This function is used in s2n_get_ticket_encrypt_decrypt_key to compute the weight
@@ -868,18 +870,17 @@ int s2n_decrypt_session_ticket(struct s2n_connection *conn, struct s2n_stuffer *
868870
POSIX_GUARD(s2n_stuffer_skip_write(&state_stuffer, state_blob_size));
869871
POSIX_GUARD_RESULT(s2n_deserialize_resumption_state(conn, &from->blob, &state_stuffer));
870872

873+
if (s2n_connection_get_protocol_version(conn) >= S2N_TLS13) {
874+
return S2N_SUCCESS;
875+
}
876+
877+
/* A new key is assigned for the ticket if the key used to encrypt current ticket is expired */
871878
uint64_t now = 0;
872879
POSIX_GUARD_RESULT(s2n_config_wall_clock(conn->config, &now));
873-
874-
/* If the key is in decrypt-only state, then a new key is assigned
875-
* for the ticket.
876-
*/
877880
if (now >= key->intro_timestamp + conn->config->encrypt_decrypt_key_lifetime_in_nanos) {
878-
/* Check if a key in encrypt-decrypt state is available */
879-
if (s2n_config_is_encrypt_decrypt_key_available(conn->config) == 1) {
881+
if (s2n_result_is_ok(s2n_config_is_encrypt_key_available(conn->config))) {
880882
conn->session_ticket_status = S2N_NEW_TICKET;
881883
POSIX_GUARD_RESULT(s2n_handshake_type_set_tls12_flag(conn, WITH_SESSION_TICKET));
882-
return S2N_SUCCESS;
883884
}
884885
}
885886
return S2N_SUCCESS;

tls/s2n_resume.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ int s2n_encrypt_session_ticket(struct s2n_connection *conn, struct s2n_stuffer *
7575
int s2n_decrypt_session_ticket(struct s2n_connection *conn, struct s2n_stuffer *from);
7676
int s2n_encrypt_session_cache(struct s2n_connection *conn, struct s2n_stuffer *to);
7777
int s2n_decrypt_session_cache(struct s2n_connection *conn, struct s2n_stuffer *from);
78-
int s2n_config_is_encrypt_decrypt_key_available(struct s2n_config *config);
78+
S2N_RESULT s2n_config_is_encrypt_key_available(struct s2n_config *config);
7979
int s2n_verify_unique_ticket_key(struct s2n_config *config, uint8_t *hash, uint16_t *insert_index);
8080
int s2n_config_wipe_expired_ticket_crypto_keys(struct s2n_config *config, int8_t expired_key_index);
8181
int s2n_config_store_ticket_key(struct s2n_config *config, struct s2n_ticket_key *key);

0 commit comments

Comments
 (0)