From 84ccbd800206db97f2334704b3d0e01be82c49fb Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 10 Mar 2025 14:16:46 +0100 Subject: [PATCH] Simulate closing the connection mid-message Simulate the server closing the connection after a partial handshake message. These test cases don't send a close_notify alert. The test cases "insert alert record" exercise what happens if the server sends an alert. Signed-off-by: Gilles Peskine --- tests/suites/test_suite_ssl.function | 47 ++++++++++++++++++++++++ tests/suites/test_suite_ssl.records.data | 8 ++++ 2 files changed, 55 insertions(+) diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function index 52e887af6d..3081257cb8 100644 --- a/tests/suites/test_suite_ssl.function +++ b/tests/suites/test_suite_ssl.function @@ -109,6 +109,7 @@ static void resize_buffers(int mfl, int renegotiation, int legacy_renegotiation, typedef enum { RECOMBINE_NOMINAL, /* param: ignored */ RECOMBINE_SPLIT_FIRST, /* param: offset of split (<=0 means from end) */ + RECOMBINE_TRUNCATE_FIRST, /* param: offset of truncation (<=0 means from end) */ RECOMBINE_INSERT_EMPTY, /* param: offset (<0 means from end) */ RECOMBINE_INSERT_RECORD, /* param: record type */ RECOMBINE_COALESCE, /* param: min number of records */ @@ -160,6 +161,39 @@ exit: return -1; } +/* Truncate the first record, keeping only the first offset bytes. + * If offset is zero or negative, count from the end of the record. + * Remove the subsequent records. + */ +static int recombine_truncate_first_record(mbedtls_test_ssl_buffer *buf, + int offset) +{ + const size_t header_length = 5; + TEST_LE_U(header_length, buf->content_length); + size_t record_length = MBEDTLS_GET_UINT16_BE(buf->buffer, header_length - 2); + + if (offset > 0) { + TEST_LE_S(offset, record_length); + } else { + TEST_LE_S(-offset, record_length); + offset = record_length + offset; + } + + /* Adjust the length of the first record */ + MBEDTLS_PUT_UINT16_BE(offset, buf->buffer, header_length - 2); + + /* Wipe the rest */ + size_t truncated_end = header_length + offset; + memset(buf->buffer + truncated_end, '!', + buf->content_length - truncated_end); + buf->content_length = truncated_end; + + return 0; + +exit: + return -1; +} + /* Insert an empty record at the given offset. If offset is negative, * count from the end of the first record. */ static int recombine_insert_record(mbedtls_test_ssl_buffer *buf, @@ -307,6 +341,11 @@ static int recombine_records(mbedtls_test_ssl_endpoint *server, TEST_LE_S(0, ret); break; + case RECOMBINE_TRUNCATE_FIRST: + ret = recombine_truncate_first_record(buf, param); + TEST_LE_S(0, ret); + break; + case RECOMBINE_INSERT_EMPTY: /* Insert an empty handshake record. */ ret = recombine_insert_record(buf, param, MBEDTLS_SSL_MSG_HANDSHAKE); @@ -3204,6 +3243,14 @@ void recombine_server_first_flight(int version, /* Server: parse the first flight from the client * and emit the second flight from the server */ + if (instruction == RECOMBINE_TRUNCATE_FIRST) { + /* Close without a notification. The case of closing with a + * notification is tested via RECOMBINE_INSERT_RECORD to insert + * an alert record (which we reject, making the client SSL + * context become invalid). */ + mbedtls_test_mock_socket_close(&server.socket); + goto goal_reached; + } while (ret == 0 && !mbedtls_ssl_is_handshake_over(&server.ssl)) { mbedtls_test_set_step(1000 + server.ssl.state); ret = mbedtls_ssl_handshake_step(&server.ssl); diff --git a/tests/suites/test_suite_ssl.records.data b/tests/suites/test_suite_ssl.records.data index 2acbbe9f4f..e94f554c69 100644 --- a/tests/suites/test_suite_ssl.records.data +++ b/tests/suites/test_suite_ssl.records.data @@ -67,6 +67,14 @@ Recombine server flight 1: TLS 1.3, split first at 1 (bad) depends_on:MBEDTLS_SSL_PROTO_TLS1_3 recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_3:RECOMBINE_SPLIT_FIRST:1:"handshake message too short\: 1":"":MBEDTLS_SSL_SERVER_HELLO:MBEDTLS_ERR_SSL_INVALID_RECORD +Recombine server flight 1: TLS 1.2, truncate at 4 (bad) +depends_on:MBEDTLS_SSL_PROTO_TLS1_2 +recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_2:RECOMBINE_TRUNCATE_FIRST:4:"initial handshake fragment\: 4, 0..4 of":"":MBEDTLS_SSL_SERVER_HELLO:MBEDTLS_ERR_SSL_WANT_READ + +Recombine server flight 1: TLS 1.3, truncate at 4 (bad) +depends_on:MBEDTLS_SSL_PROTO_TLS1_3 +recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_3:RECOMBINE_TRUNCATE_FIRST:4:"initial handshake fragment\: 4, 0..4 of":"":MBEDTLS_SSL_SERVER_HELLO:MBEDTLS_ERR_SSL_WANT_READ + Recombine server flight 1: TLS 1.2, insert empty record after first (bad) depends_on:MBEDTLS_SSL_PROTO_TLS1_2 recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_2:RECOMBINE_SPLIT_FIRST:0:"rejecting empty record":"":MBEDTLS_SSL_SERVER_CERTIFICATE:MBEDTLS_ERR_SSL_INVALID_RECORD