1
0
mirror of https://github.com/Mbed-TLS/mbedtls.git synced 2025-07-30 22:43:08 +03:00

Test split, coalesced-split and empty handshake records

Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
This commit is contained in:
Gilles Peskine
2025-03-07 20:48:01 +01:00
committed by Manuel Pégourié-Gonnard
parent 92122edf4b
commit 7c1dbeff49
3 changed files with 211 additions and 0 deletions

View File

@ -3699,6 +3699,7 @@ static int ssl_parse_record_header(mbedtls_ssl_context const *ssl,
rec->buf_len = rec->data_offset + rec->data_len; rec->buf_len = rec->data_offset + rec->data_len;
if (rec->data_len == 0) { if (rec->data_len == 0) {
MBEDTLS_SSL_DEBUG_MSG(1, ("rejecting empty record"));
return MBEDTLS_ERR_SSL_INVALID_RECORD; return MBEDTLS_ERR_SSL_INVALID_RECORD;
} }

View File

@ -108,9 +108,100 @@ static void resize_buffers(int mfl, int renegotiation, int legacy_renegotiation,
typedef enum { typedef enum {
RECOMBINE_NOMINAL, /* param: ignored */ RECOMBINE_NOMINAL, /* param: ignored */
RECOMBINE_SPLIT_FIRST, /* param: offset of split (<=0 means from end) */
RECOMBINE_INSERT_EMPTY, /* param: offset (<0 means from end) */
RECOMBINE_COALESCE, /* param: min number of records */ RECOMBINE_COALESCE, /* param: min number of records */
RECOMBINE_COALESCE_SPLIT_ONCE, /* param: offset of split (<=0 means from end) */
RECOMBINE_COALESCE_SPLIT_ENDS, /* the hairiest one? param: offset, must be >0 */
} recombine_records_instruction_t; } recombine_records_instruction_t;
/* Split the first record into two pieces of lengths offset and
* record_length-offset. If offset is zero or negative, count from the end of
* the record. */
static int recombine_split_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;
}
/* Check that we have room to insert a record header */
TEST_LE_U(buf->content_length + header_length, buf->capacity);
/* Make room for a record header */
size_t new_record_start = header_length + offset;
size_t new_content_start = new_record_start + header_length;
memmove(buf->buffer + new_content_start,
buf->buffer + new_record_start,
buf->content_length - new_record_start);
buf->content_length += header_length;
/* Construct a header for the new record based on the existing one */
memcpy(buf->buffer + new_record_start, buf->buffer, header_length);
MBEDTLS_PUT_UINT16_BE(record_length - offset,
buf->buffer, new_content_start - 2);
/* Adjust the length of the first record */
MBEDTLS_PUT_UINT16_BE(offset, buf->buffer, header_length - 2);
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_empty_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;
}
/* Check that we have room to insert two record headers */
TEST_LE_U(buf->content_length + 2 * header_length, buf->capacity);
/* Make room for an empty record and a record header */
size_t empty_record_start = header_length + offset;
size_t empty_content_start = empty_record_start + header_length;
size_t tail_record_start = empty_content_start;
size_t tail_content_start = tail_record_start + header_length;
memmove(buf->buffer + tail_content_start,
buf->buffer + tail_record_start,
buf->content_length - tail_record_start);
buf->content_length += 2 * header_length;
/* Construct headers for the new records based on the existing one */
memcpy(buf->buffer + empty_record_start, buf->buffer, header_length);
MBEDTLS_PUT_UINT16_BE(0, buf->buffer, empty_content_start - 2);
memcpy(buf->buffer + tail_record_start, buf->buffer, header_length);
MBEDTLS_PUT_UINT16_BE(record_length - offset,
buf->buffer, tail_content_start - 2);
/* Adjust the length of the first record */
MBEDTLS_PUT_UINT16_BE(offset, buf->buffer, header_length - 2);
return 0;
exit:
return -1;
}
/* Coalesce TLS handshake records. /* Coalesce TLS handshake records.
* DTLS is not supported. * DTLS is not supported.
* Encrypted or authenticated handshake records are not supported. * Encrypted or authenticated handshake records are not supported.
@ -179,6 +270,16 @@ static int recombine_records(mbedtls_test_ssl_endpoint *server,
case RECOMBINE_NOMINAL: case RECOMBINE_NOMINAL:
break; break;
case RECOMBINE_SPLIT_FIRST:
ret = recombine_split_first_record(buf, param);
TEST_LE_S(0, ret);
break;
case RECOMBINE_INSERT_EMPTY:
ret = recombine_insert_empty_record(buf, param);
TEST_LE_S(0, ret);
break;
case RECOMBINE_COALESCE: case RECOMBINE_COALESCE:
ret = recombine_coalesce_handshake_records(buf, param); ret = recombine_coalesce_handshake_records(buf, param);
if (param == INT_MAX) { if (param == INT_MAX) {
@ -188,6 +289,27 @@ static int recombine_records(mbedtls_test_ssl_endpoint *server,
} }
break; break;
case RECOMBINE_COALESCE_SPLIT_ONCE:
ret = recombine_coalesce_handshake_records(buf, INT_MAX);
/* Require at least two coalesced records, otherwise this
* doesn't lead to a meaningful test (use
* RECOMBINE_SPLIT_FIRST instead). */
TEST_LE_S(2, ret);
ret = recombine_split_first_record(buf, param);
TEST_LE_S(0, ret);
break;
case RECOMBINE_COALESCE_SPLIT_ENDS:
ret = recombine_coalesce_handshake_records(buf, INT_MAX);
/* Accept a single record, which will be split at both ends */
TEST_LE_S(1, ret);
TEST_LE_S(1, param);
ret = recombine_split_first_record(buf, -param);
TEST_LE_S(0, ret);
ret = recombine_split_first_record(buf, param);
TEST_LE_S(0, ret);
break;
default: default:
TEST_FAIL("Instructions not understood"); TEST_FAIL("Instructions not understood");
} }

View File

@ -24,3 +24,91 @@ recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_2:RECOMBINE_COALESCE:INT_
Recombine server flight 1: TLS 1.3, coalesce all Recombine server flight 1: TLS 1.3, coalesce all
depends_on:MBEDTLS_SSL_PROTO_TLS1_3 depends_on:MBEDTLS_SSL_PROTO_TLS1_3
recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_3:RECOMBINE_COALESCE:INT_MAX:"<= handshake wrapup":"<= handshake wrapup":MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET_FLUSH:0 recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_3:RECOMBINE_COALESCE:INT_MAX:"<= handshake wrapup":"<= handshake wrapup":MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET_FLUSH:0
Recombine server flight 1: TLS 1.2, split first at 4
depends_on:MBEDTLS_SSL_PROTO_TLS1_2
recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_2:RECOMBINE_SPLIT_FIRST:4:"initial handshake fragment\: 4, 0..4 of":"<= handshake wrapup":MBEDTLS_SSL_HANDSHAKE_OVER:0
Recombine server flight 1: TLS 1.3, split first at 4
depends_on:MBEDTLS_SSL_PROTO_TLS1_3
recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_3:RECOMBINE_SPLIT_FIRST:4:"initial handshake fragment\: 4, 0..4 of":"<= handshake wrapup":MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET_FLUSH:0
Recombine server flight 1: TLS 1.2, split first at end-1
depends_on:MBEDTLS_SSL_PROTO_TLS1_2
recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_2:RECOMBINE_SPLIT_FIRST:-1:"subsequent handshake fragment\: 1,":"<= handshake wrapup":MBEDTLS_SSL_HANDSHAKE_OVER:0
Recombine server flight 1: TLS 1.3, split first at end-1
depends_on:MBEDTLS_SSL_PROTO_TLS1_3
recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_3:RECOMBINE_SPLIT_FIRST:-1:"subsequent handshake fragment\: 1,":"<= handshake wrapup":MBEDTLS_SSL_TLS1_3_NEW_SESSION_TICKET_FLUSH:0
# The library doesn't support an initial handshake fragment that doesn't
# contain the full 4-byte handshake header.
Recombine server flight 1: TLS 1.2, split first at 3 (bad)
depends_on:MBEDTLS_SSL_PROTO_TLS1_2
recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_2:RECOMBINE_SPLIT_FIRST:3:"handshake message too short\: 3":"":MBEDTLS_SSL_SERVER_HELLO:MBEDTLS_ERR_SSL_INVALID_RECORD
Recombine server flight 1: TLS 1.3, split first at 3 (bad)
depends_on:MBEDTLS_SSL_PROTO_TLS1_3
recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_3:RECOMBINE_SPLIT_FIRST:3:"handshake message too short\: 3":"":MBEDTLS_SSL_SERVER_HELLO:MBEDTLS_ERR_SSL_INVALID_RECORD
Recombine server flight 1: TLS 1.2, split first at 2 (bad)
depends_on:MBEDTLS_SSL_PROTO_TLS1_2
recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_2:RECOMBINE_SPLIT_FIRST:2:"handshake message too short\: 2":"":MBEDTLS_SSL_SERVER_HELLO:MBEDTLS_ERR_SSL_INVALID_RECORD
Recombine server flight 1: TLS 1.3, split first at 2 (bad)
depends_on:MBEDTLS_SSL_PROTO_TLS1_3
recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_3:RECOMBINE_SPLIT_FIRST:2:"handshake message too short\: 2":"":MBEDTLS_SSL_SERVER_HELLO:MBEDTLS_ERR_SSL_INVALID_RECORD
Recombine server flight 1: TLS 1.2, split first at 1 (bad)
depends_on:MBEDTLS_SSL_PROTO_TLS1_2
recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_2:RECOMBINE_SPLIT_FIRST:1:"handshake message too short\: 1":"":MBEDTLS_SSL_SERVER_HELLO:MBEDTLS_ERR_SSL_INVALID_RECORD
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, 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
Recombine server flight 1: TLS 1.3, insert empty record after first (bad)
depends_on:MBEDTLS_SSL_PROTO_TLS1_3
recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_3:RECOMBINE_SPLIT_FIRST:0:"rejecting empty record":"":MBEDTLS_SSL_ENCRYPTED_EXTENSIONS:MBEDTLS_ERR_SSL_INVALID_RECORD
Recombine server flight 1: TLS 1.2, insert empty record at start (bad)
depends_on:MBEDTLS_SSL_PROTO_TLS1_2
recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_2:RECOMBINE_INSERT_EMPTY:0:"rejecting empty record":"":MBEDTLS_SSL_SERVER_HELLO:MBEDTLS_ERR_SSL_INVALID_RECORD
Recombine server flight 1: TLS 1.3, insert empty record at start (bad)
depends_on:MBEDTLS_SSL_PROTO_TLS1_3
recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_3:RECOMBINE_INSERT_EMPTY:0:"rejecting empty record":"":MBEDTLS_SSL_SERVER_HELLO:MBEDTLS_ERR_SSL_INVALID_RECORD
Recombine server flight 1: TLS 1.2, insert empty record at 42 (bad)
depends_on:MBEDTLS_SSL_PROTO_TLS1_2
recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_2:RECOMBINE_INSERT_EMPTY:42:"rejecting empty record":"":MBEDTLS_SSL_SERVER_HELLO:MBEDTLS_ERR_SSL_INVALID_RECORD
Recombine server flight 1: TLS 1.3, insert empty record at 42 (bad)
depends_on:MBEDTLS_SSL_PROTO_TLS1_3
recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_3:RECOMBINE_INSERT_EMPTY:42:"rejecting empty record":"":MBEDTLS_SSL_SERVER_HELLO:MBEDTLS_ERR_SSL_INVALID_RECORD
# Since there is a single unencrypted handshake message in the first flight
# from the server, and the test code that recombines handshake records can only
# handle plaintext records, we can't have TLS 1.3 tests with coalesced
# handshake messages. Hence most coalesce-and-split test cases are 1.2-only.
Recombine server flight 1: TLS 1.2, coalesce and split at 4
depends_on:MBEDTLS_SSL_PROTO_TLS1_2
recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_2:RECOMBINE_COALESCE_SPLIT_ONCE:4:"initial handshake fragment\: 4, 0..4 of":"<= handshake wrapup":MBEDTLS_SSL_HANDSHAKE_OVER:0
# The last message of the first flight from the server is ServerHelloDone,
# which is an empty handshake message, i.e. of length 4. The library doesn't
# support fragmentation of a handshake message, so the last place where we
# can split the flight is 4+1 = 5 bytes before it ends, with 1 byte in the
# previous handshake message and 4 bytes of ServerHelloDone including header.
Recombine server flight 1: TLS 1.2, coalesce and split at end-5
depends_on:MBEDTLS_SSL_PROTO_TLS1_2
recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_2:RECOMBINE_COALESCE_SPLIT_ONCE:-5:"subsequent handshake fragment\: 5,":"<= handshake wrapup":MBEDTLS_SSL_HANDSHAKE_OVER:0
Recombine server flight 1: TLS 1.2, coalesce and split at both ends
depends_on:MBEDTLS_SSL_PROTO_TLS1_2
recombine_server_first_flight:MBEDTLS_SSL_VERSION_TLS1_2:RECOMBINE_COALESCE_SPLIT_ENDS:5:"subsequent handshake fragment\: 5,":"<= handshake wrapup":MBEDTLS_SSL_HANDSHAKE_OVER:0