From 45e45eb1f3f2007b13fc68f34f65217c1f24ec49 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Fri, 6 Nov 2026 13:34:15 -0800 Subject: [PATCH 1/2] Test that a coalesced app data record is returned before the next --- tests/api/test_ssl_rw.c | 46 +++++++++++++++++++++++++++++++++++++++++ tests/api/test_ssl_rw.h | 2 ++ 2 files changed, 48 insertions(+) diff --git a/tests/api/test_ssl_rw.c b/tests/api/test_ssl_rw.c index 4c992da4f74..67ff0f92786 100644 --- a/tests/api/test_ssl_rw.c +++ b/tests/api/test_ssl_rw.c @@ -717,6 +717,52 @@ int test_wolfSSL_inject_app_data_ready(void) return EXPECT_RESULT(); } +/* Deliver a buffered application record before reading the next record. */ +int test_wolfSSL_inject_coalesced_read(void) +{ + EXPECT_DECLS; +#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && !defined(NO_TLS) && \ + !defined(WOLFSSL_NO_TLS12) + WOLFSSL_CTX* ctx_c = NULL; + WOLFSSL_CTX* ctx_s = NULL; + WOLFSSL* ssl_c = NULL; + WOLFSSL* ssl_s = NULL; + struct test_memio_ctx test_ctx; + byte first[32]; + byte second[4096]; + byte received[sizeof(first)]; + int firstRecordSz; + + XMEMSET(first, 0x41, sizeof(first)); + XMEMSET(second, 0x42, sizeof(second)); + XMEMSET(&test_ctx, 0, sizeof(test_ctx)); + ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s, + wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0); + ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0); + test_memio_clear_buffer(&test_ctx, 1); + + ExpectIntEQ(wolfSSL_write(ssl_s, first, sizeof(first)), sizeof(first)); + ExpectIntEQ(wolfSSL_write(ssl_s, second, sizeof(second)), sizeof(second)); + firstRecordSz = RECORD_HEADER_SZ + + ((int)test_ctx.c_buff[3] << 8) + (int)test_ctx.c_buff[4]; + ExpectIntGT(test_ctx.c_len, firstRecordSz + RECORD_HEADER_SZ); + if (test_ctx.c_len > firstRecordSz + RECORD_HEADER_SZ) { + ExpectIntEQ(wolfSSL_inject(ssl_c, test_ctx.c_buff, + firstRecordSz + RECORD_HEADER_SZ), WOLFSSL_SUCCESS); + test_memio_clear_buffer(&test_ctx, 1); + ExpectIntEQ(wolfSSL_read(ssl_c, received, sizeof(received)), + sizeof(received)); + ExpectBufEQ(received, first, sizeof(first)); + } + + wolfSSL_free(ssl_c); + wolfSSL_free(ssl_s); + wolfSSL_CTX_free(ctx_c); + wolfSSL_CTX_free(ctx_s); +#endif + return EXPECT_RESULT(); +} + /* Test that application data decrypted from an injected record is returned * before a partial record queued behind it is processed. * diff --git a/tests/api/test_ssl_rw.h b/tests/api/test_ssl_rw.h index 822863c4515..53dae056487 100644 --- a/tests/api/test_ssl_rw.h +++ b/tests/api/test_ssl_rw.h @@ -33,6 +33,7 @@ int test_wolfSSL_rw_bad_args(void); int test_wolfSSL_rw_info_callback(void); int test_wolfSSL_write_ex_partial(void); int test_wolfSSL_inject_app_data_ready(void); +int test_wolfSSL_inject_coalesced_read(void); int test_wolfSSL_inject_app_data_partial_record(void); int test_wolfSSL_clear_app_data_pending(void); int test_wolfSSL_rehandshake_app_data_pending(void); @@ -62,6 +63,7 @@ int test_wolfSSL_write_dup_max_fragment(void); TEST_DECL_GROUP("ssl_rw", test_wolfSSL_rw_info_callback), \ TEST_DECL_GROUP("ssl_rw", test_wolfSSL_write_ex_partial), \ TEST_DECL_GROUP("ssl_rw", test_wolfSSL_inject_app_data_ready), \ + TEST_DECL_GROUP("ssl_rw", test_wolfSSL_inject_coalesced_read), \ TEST_DECL_GROUP("ssl_rw", \ test_wolfSSL_inject_app_data_partial_record), \ TEST_DECL_GROUP("ssl_rw", test_wolfSSL_clear_app_data_pending), \ From 859994b4d7865ce7607bd52c18716cbad4072dc3 Mon Sep 17 00:00:00 2001 From: Aidan Garske Date: Fri, 6 Nov 2026 13:34:15 -0800 Subject: [PATCH 2/2] Make coalesced record test fail safely --- tests/api/test_ssl_rw.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/tests/api/test_ssl_rw.c b/tests/api/test_ssl_rw.c index 67ff0f92786..3d3dd56ed8f 100644 --- a/tests/api/test_ssl_rw.c +++ b/tests/api/test_ssl_rw.c @@ -743,18 +743,24 @@ int test_wolfSSL_inject_coalesced_read(void) ExpectIntEQ(wolfSSL_write(ssl_s, first, sizeof(first)), sizeof(first)); ExpectIntEQ(wolfSSL_write(ssl_s, second, sizeof(second)), sizeof(second)); + ExpectIntGT(test_ctx.c_len, RECORD_HEADER_SZ); + if (test_ctx.c_len <= RECORD_HEADER_SZ) + goto cleanup; + /* The record length occupies the final two header bytes. */ firstRecordSz = RECORD_HEADER_SZ + - ((int)test_ctx.c_buff[3] << 8) + (int)test_ctx.c_buff[4]; + ((int)test_ctx.c_buff[RECORD_HEADER_SZ - 2] << 8) + + (int)test_ctx.c_buff[RECORD_HEADER_SZ - 1]; ExpectIntGT(test_ctx.c_len, firstRecordSz + RECORD_HEADER_SZ); - if (test_ctx.c_len > firstRecordSz + RECORD_HEADER_SZ) { - ExpectIntEQ(wolfSSL_inject(ssl_c, test_ctx.c_buff, - firstRecordSz + RECORD_HEADER_SZ), WOLFSSL_SUCCESS); - test_memio_clear_buffer(&test_ctx, 1); - ExpectIntEQ(wolfSSL_read(ssl_c, received, sizeof(received)), - sizeof(received)); - ExpectBufEQ(received, first, sizeof(first)); - } + if (test_ctx.c_len <= firstRecordSz + RECORD_HEADER_SZ) + goto cleanup; + ExpectIntEQ(wolfSSL_inject(ssl_c, test_ctx.c_buff, + firstRecordSz + RECORD_HEADER_SZ), WOLFSSL_SUCCESS); + test_memio_clear_buffer(&test_ctx, 1); + ExpectIntEQ(wolfSSL_read(ssl_c, received, sizeof(received)), + sizeof(received)); + ExpectBufEQ(received, first, sizeof(first)); +cleanup: wolfSSL_free(ssl_c); wolfSSL_free(ssl_s); wolfSSL_CTX_free(ctx_c);