@@ -1928,6 +1928,133 @@ int test_dtls13_ch2_rtx_no_ch1(void)
19281928 return EXPECT_RESULT ();
19291929}
19301930
1931+ int test_dtls13_frag_ch2_with_ch1_rtx (void )
1932+ {
1933+ EXPECT_DECLS ;
1934+ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && \
1935+ defined(WOLFSSL_DTLS13 ) && defined(WOLFSSL_DTLS ) && \
1936+ defined(WOLFSSL_DTLS_MTU ) && defined(WOLFSSL_DTLS_CH_FRAG )
1937+ WOLFSSL_CTX * ctx_c = NULL , * ctx_s = NULL ;
1938+ WOLFSSL * ssl_c = NULL , * ssl_s = NULL ;
1939+ struct test_memio_ctx test_ctx ;
1940+ char hrr [TEST_MEMIO_BUF_SZ ];
1941+ int hrrSz = (int )sizeof (hrr );
1942+ char ch1Rtx [TEST_MEMIO_BUF_SZ ];
1943+ int ch1RtxSz = (int )sizeof (ch1Rtx );
1944+ char ch2 [TEST_MEMIO_BUF_SZ ];
1945+ int ch2Sz = 0 ;
1946+ int ch2MsgCount = 0 ;
1947+ int ch2MsgSizes [TEST_MEMIO_MAX_MSGS ] = {0 };
1948+ /* The DTLS record sequence number occupies the last 8 bytes of the
1949+ * record header. */
1950+ int recordSeqOff = DTLS_RECORD_HEADER_SZ - 8 ;
1951+ int ch2Seq = 0 ;
1952+ int ch1RtxSeq = 0 ;
1953+ int off ;
1954+ int i ;
1955+
1956+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
1957+
1958+ ExpectIntEQ (test_memio_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c , & ssl_s ,
1959+ wolfDTLSv1_3_client_method , wolfDTLSv1_3_server_method ),
1960+ 0 );
1961+
1962+ /* To force HRR */
1963+ ExpectIntEQ (wolfSSL_NoKeyShares (ssl_c ), WOLFSSL_SUCCESS );
1964+ ExpectIntEQ (wolfSSL_dtls13_allow_ch_frag (ssl_s , 1 ), WOLFSSL_SUCCESS );
1965+
1966+ /* CH1 */
1967+ ExpectIntEQ (wolfSSL_connect (ssl_c ), -1 );
1968+ ExpectIntEQ (wolfSSL_get_error (ssl_c , -1 ), WOLFSSL_ERROR_WANT_READ );
1969+
1970+ /* HRR */
1971+ ExpectIntEQ (wolfSSL_accept (ssl_s ), -1 );
1972+ ExpectIntEQ (wolfSSL_get_error (ssl_s , -1 ), WOLFSSL_ERROR_WANT_READ );
1973+ ExpectIntEQ (test_memio_copy_message (& test_ctx , 1 , hrr , & hrrSz , 0 ), 0 );
1974+
1975+ /* Drop HRR, trigger CH1 retransmission, copy and drop it */
1976+ test_memio_clear_buffer (& test_ctx , 1 );
1977+ if (wolfSSL_dtls13_use_quick_timeout (ssl_c ))
1978+ ExpectIntEQ (wolfSSL_dtls_got_timeout (ssl_c ), WOLFSSL_SUCCESS );
1979+ ExpectIntEQ (wolfSSL_dtls_got_timeout (ssl_c ), WOLFSSL_SUCCESS );
1980+ ExpectIntEQ (test_memio_copy_message (& test_ctx , 0 , ch1Rtx , & ch1RtxSz , 0 ), 0 );
1981+ test_memio_clear_buffer (& test_ctx , 0 );
1982+
1983+ /* Force CH2 fragmentation. MTU must be small enough to fragment but large
1984+ * enough that the cookie extension lands in the first fragment, otherwise
1985+ * the server can't validate it statelessly and the test scenario (server
1986+ * stateful after frag 1) does not hold. With --enable-all (PQ groups in
1987+ * supported_groups), the cookie extension can sit ~400 bytes into CH2; 600
1988+ * gives margin while still producing multiple fragments (CH2 is ~2KB). */
1989+ ExpectIntEQ (wolfSSL_dtls_set_mtu (ssl_c , 600 ), WOLFSSL_SUCCESS );
1990+
1991+ /* Forward HRR and let the client create fragmented CH2 */
1992+ ExpectIntEQ (test_memio_inject_message (& test_ctx , 1 , hrr , hrrSz ), 0 );
1993+ ExpectIntEQ (wolfSSL_connect (ssl_c ), -1 );
1994+ ExpectIntEQ (wolfSSL_get_error (ssl_c , -1 ), WOLFSSL_ERROR_WANT_READ );
1995+
1996+ ExpectIntGT (test_ctx .s_msg_count , 1 );
1997+ ExpectIntLE (test_ctx .s_msg_count , TEST_MEMIO_MAX_MSGS );
1998+ ExpectIntLE (test_ctx .s_len , (int )sizeof (ch2 ));
1999+ if (EXPECT_SUCCESS ()) {
2000+ ch2Sz = test_ctx .s_len ;
2001+ ch2MsgCount = test_ctx .s_msg_count ;
2002+ XMEMCPY (ch2 , test_ctx .s_buff , ch2Sz );
2003+ XMEMCPY (ch2MsgSizes , test_ctx .s_msg_sizes ,
2004+ sizeof (ch2MsgSizes [0 ]) * (size_t )ch2MsgCount );
2005+
2006+ ch2Seq = ((byte )ch2 [recordSeqOff + 4 ] << 8 ) |
2007+ (byte )ch2 [recordSeqOff + 5 ];
2008+ ch1RtxSeq = ch2Seq + ch2MsgCount ;
2009+
2010+ /* Synthesize a CH1 retransmission that can pass the replay window after
2011+ * the first CH2 fragment makes the server stateful. The handshake
2012+ * message_seq remains the original CH1 value; only the DTLS record
2013+ * sequence is moved past the fragmented CH2 flight */
2014+ ch1Rtx [recordSeqOff + 0 ] = 0 ;
2015+ ch1Rtx [recordSeqOff + 1 ] = 0 ;
2016+ ch1Rtx [recordSeqOff + 2 ] = 0 ;
2017+ ch1Rtx [recordSeqOff + 3 ] = 0 ;
2018+ ch1Rtx [recordSeqOff + 4 ] = (byte )(ch1RtxSeq >> 8 );
2019+ ch1Rtx [recordSeqOff + 5 ] = (byte )ch1RtxSeq ;
2020+ }
2021+
2022+ test_memio_clear_buffer (& test_ctx , 0 );
2023+
2024+ /* Deliver CH2 first fragment only. Now server is stateful */
2025+ ExpectIntEQ (test_memio_inject_message (& test_ctx , 0 , ch2 , ch2MsgSizes [0 ]), 0 );
2026+ ExpectIntEQ (wolfSSL_accept (ssl_s ), -1 );
2027+ ExpectIntEQ (wolfSSL_get_error (ssl_s , -1 ), WOLFSSL_ERROR_WANT_READ );
2028+
2029+ /* Deliver the retransmitted CH1 between CH2 fragments, it should be
2030+ * discarded as rtx */
2031+ ExpectIntEQ (test_memio_inject_message (& test_ctx , 0 , ch1Rtx , ch1RtxSz ), 0 );
2032+ ExpectIntEQ (wolfSSL_accept (ssl_s ), -1 );
2033+ ExpectIntEQ (wolfSSL_get_error (ssl_s , -1 ), WOLFSSL_ERROR_WANT_READ );
2034+ test_memio_clear_buffer (& test_ctx , 1 );
2035+
2036+ /* Deliver the rest of CH2 */
2037+ off = ch2MsgSizes [0 ];
2038+ for (i = 1 ; i < ch2MsgCount && EXPECT_SUCCESS (); i ++ ) {
2039+ ExpectIntEQ (test_memio_inject_message (& test_ctx , 0 , ch2 + off ,
2040+ ch2MsgSizes [i ]), 0 );
2041+ off += ch2MsgSizes [i ];
2042+ }
2043+
2044+ /* Restore MTU so the client's input buffer can hold the full server
2045+ * flight (e.g. an SH carrying a hybrid PQC key share). */
2046+ ExpectIntEQ (wolfSSL_dtls_set_mtu (ssl_c , 1500 ), WOLFSSL_SUCCESS );
2047+
2048+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
2049+
2050+ wolfSSL_free (ssl_c );
2051+ wolfSSL_CTX_free (ctx_c );
2052+ wolfSSL_free (ssl_s );
2053+ wolfSSL_CTX_free (ctx_s );
2054+ #endif
2055+ return EXPECT_RESULT ();
2056+ }
2057+
19312058int test_dtls_drop_client_ack (void )
19322059{
19332060 EXPECT_DECLS ;
0 commit comments