@@ -1740,6 +1740,19 @@ int test_dtls13_no_session_id_echo(void)
17401740 return EXPECT_RESULT ();
17411741}
17421742
1743+ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && defined(WOLFSSL_DTLS13 ) && \
1744+ defined(HAVE_SESSION_TICKET ) && defined(WOLFSSL_DTLS13_ECHO_LEGACY_SESSION_ID ) && \
1745+ defined(HAVE_ECC )
1746+ /* RFC 8446 Section 4.1.3: an HRR is a ServerHello carrying this magic random.
1747+ * Used to assert a real ServerHello was captured, not an HRR. */
1748+ static const byte hrrRandom [RAN_LEN ] = {
1749+ 0xCF , 0x21 , 0xAD , 0x74 , 0xE5 , 0x9A , 0x61 , 0x11 ,
1750+ 0xBE , 0x1D , 0x8C , 0x02 , 0x1E , 0x65 , 0xB8 , 0x91 ,
1751+ 0xC2 , 0xA2 , 0x11 , 0x16 , 0x7A , 0xBB , 0x8C , 0x5E ,
1752+ 0x07 , 0x9E , 0x09 , 0xE2 , 0xC8 , 0xA8 , 0x33 , 0x9C
1753+ };
1754+ #endif
1755+
17431756/*-- 5_9_0_compat (test_dtls.c lines 3049,3170) ---*/
17441757int test_dtls13_5_9_0_compat (void )
17451758{
@@ -1754,14 +1767,6 @@ int test_dtls13_5_9_0_compat(void)
17541767 char readBuf [1 ];
17551768 /* Pin to SECP256R1 to avoid a PQ-induced key-share HRR */
17561769 int groups [] = { WOLFSSL_ECC_SECP256R1 };
1757- /* RFC 8446 Section 4.1.3: an HRR is a ServerHello carrying this magic
1758- * random. Used to assert sub-test 1 is a real ServerHello, not an HRR. */
1759- static const byte hrrRandom [RAN_LEN ] = {
1760- 0xCF , 0x21 , 0xAD , 0x74 , 0xE5 , 0x9A , 0x61 , 0x11 ,
1761- 0xBE , 0x1D , 0x8C , 0x02 , 0x1E , 0x65 , 0xB8 , 0x91 ,
1762- 0xC2 , 0xA2 , 0x11 , 0x16 , 0x7A , 0xBB , 0x8C , 0x5E ,
1763- 0x07 , 0x9E , 0x09 , 0xE2 , 0xC8 , 0xA8 , 0x33 , 0x9C
1764- };
17651770
17661771 /* --- initial connection: get a real session to carry the session ID --- */
17671772 XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
@@ -1863,3 +1868,159 @@ int test_dtls13_5_9_0_compat(void)
18631868#endif
18641869 return EXPECT_RESULT ();
18651870}
1871+
1872+ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && defined(WOLFSSL_DTLS13 ) && \
1873+ defined(HAVE_SESSION_TICKET ) && defined(WOLFSSL_DTLS13_ECHO_LEGACY_SESSION_ID ) && \
1874+ defined(HAVE_ECC )
1875+ /* Drive a compat-build resumption up to the point where the server's
1876+ * ServerHello is sitting in the client's inbound buffer, echoing the session
1877+ * ID the client sent. Returns 0 on success. */
1878+ static int compat_echo_setup (struct test_memio_ctx * test_ctx ,
1879+ WOLFSSL_CTX * * ctx_c , WOLFSSL_CTX * * ctx_s , WOLFSSL * * ssl_c , WOLFSSL * * ssl_s ,
1880+ WOLFSSL_SESSION * * sess )
1881+ {
1882+ EXPECT_DECLS ;
1883+ char readBuf [1 ];
1884+ int groups [] = { WOLFSSL_ECC_SECP256R1 };
1885+ int echoIdx = DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ +
1886+ OPAQUE16_LEN + RAN_LEN ;
1887+
1888+ XMEMSET (test_ctx , 0 , sizeof (* test_ctx ));
1889+ ExpectIntEQ (test_memio_setup (test_ctx , ctx_c , ctx_s , ssl_c , ssl_s ,
1890+ wolfDTLSv1_3_client_method , wolfDTLSv1_3_server_method ), 0 );
1891+ ExpectIntEQ (wolfSSL_set_groups (* ssl_c , groups , 1 ), WOLFSSL_SUCCESS );
1892+ ExpectIntEQ (test_memio_do_handshake (* ssl_c , * ssl_s , 10 , NULL ), 0 );
1893+
1894+ ExpectIntEQ (wolfSSL_read (* ssl_c , readBuf , sizeof (readBuf )), -1 );
1895+ ExpectIntEQ (wolfSSL_get_error (* ssl_c , -1 ), WOLFSSL_ERROR_WANT_READ );
1896+ ExpectNotNull (* sess = wolfSSL_get1_session (* ssl_c ));
1897+
1898+ /* A DTLS 1.3 client carries a ticket-derived session ID (SetTicket), so
1899+ * the ClientHello legacy_session_id is non-empty. */
1900+ ExpectIntEQ ((* sess )-> sessionIDSz , ID_LEN );
1901+
1902+ wolfSSL_free (* ssl_c ); * ssl_c = NULL ;
1903+ wolfSSL_free (* ssl_s ); * ssl_s = NULL ;
1904+ wolfSSL_CTX_free (* ctx_c ); * ctx_c = NULL ;
1905+ wolfSSL_CTX_free (* ctx_s ); * ctx_s = NULL ;
1906+
1907+ XMEMSET (test_ctx , 0 , sizeof (* test_ctx ));
1908+ ExpectIntEQ (test_memio_setup (test_ctx , ctx_c , ctx_s , ssl_c , ssl_s ,
1909+ wolfDTLSv1_3_client_method , wolfDTLSv1_3_server_method ), 0 );
1910+ ExpectIntEQ (wolfSSL_set_session (* ssl_c , * sess ), WOLFSSL_SUCCESS );
1911+ ExpectIntEQ (wolfSSL_set_groups (* ssl_c , groups , 1 ), WOLFSSL_SUCCESS );
1912+ ExpectIntEQ (wolfSSL_disable_hrr_cookie (* ssl_s ), WOLFSSL_SUCCESS );
1913+
1914+ ExpectIntEQ (wolfSSL_negotiate (* ssl_c ), -1 );
1915+ ExpectIntEQ (wolfSSL_get_error (* ssl_c , -1 ), WOLFSSL_ERROR_WANT_READ );
1916+ ExpectIntEQ (wolfSSL_negotiate (* ssl_s ), -1 );
1917+ ExpectIntEQ (wolfSSL_get_error (* ssl_s , -1 ), WOLFSSL_ERROR_WANT_READ );
1918+
1919+ /* A real ServerHello (not an HRR) echoing the client's session ID. */
1920+ ExpectIntGE (test_ctx -> c_len , echoIdx + 1 + ID_LEN );
1921+ ExpectIntEQ (test_ctx -> c_buff [DTLS_RECORD_HEADER_SZ ], server_hello );
1922+ ExpectIntNE (XMEMCMP (& test_ctx -> c_buff [DTLS_RECORD_HEADER_SZ +
1923+ DTLS_HANDSHAKE_HEADER_SZ + OPAQUE16_LEN ], hrrRandom , RAN_LEN ), 0 );
1924+ ExpectIntEQ (test_ctx -> c_buff [echoIdx ], ID_LEN );
1925+
1926+ return EXPECT_RESULT () == TEST_SUCCESS ? 0 : -1 ;
1927+ }
1928+ #endif
1929+
1930+ /* The 5.9.0 compat path accepts an echoed legacy_session_id, but RFC 8446
1931+ * Section 4.1.3 still requires the echo to be the value the client sent, so a
1932+ * server echoing something else must be rejected. */
1933+ int test_dtls13_5_9_0_compat_bad_echo (void )
1934+ {
1935+ EXPECT_DECLS ;
1936+ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && defined(WOLFSSL_DTLS13 ) && \
1937+ defined(HAVE_SESSION_TICKET ) && defined(WOLFSSL_DTLS13_ECHO_LEGACY_SESSION_ID ) && \
1938+ defined(HAVE_ECC )
1939+ struct test_memio_ctx test_ctx ;
1940+ WOLFSSL_CTX * ctx_c = NULL , * ctx_s = NULL ;
1941+ WOLFSSL * ssl_c = NULL , * ssl_s = NULL ;
1942+ WOLFSSL_SESSION * sess = NULL ;
1943+ int echoIdx = DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ +
1944+ OPAQUE16_LEN + RAN_LEN ;
1945+
1946+ ExpectIntEQ (compat_echo_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c , & ssl_s ,
1947+ & sess ), 0 );
1948+
1949+ /* Corrupt the echo so it no longer matches what the client sent. */
1950+ if (EXPECT_SUCCESS ())
1951+ test_ctx .c_buff [echoIdx + 1 ] ^= 0xFF ;
1952+
1953+ ExpectIntEQ (wolfSSL_negotiate (ssl_c ), -1 );
1954+ ExpectIntEQ (wolfSSL_get_error (ssl_c , -1 ),
1955+ WC_NO_ERR_TRACE (INVALID_PARAMETER ));
1956+
1957+ wolfSSL_SESSION_free (sess );
1958+ wolfSSL_free (ssl_c );
1959+ wolfSSL_free (ssl_s );
1960+ wolfSSL_CTX_free (ctx_c );
1961+ wolfSSL_CTX_free (ctx_s );
1962+ #endif
1963+ return EXPECT_RESULT ();
1964+ }
1965+
1966+ /* A compat-enabled client must still interoperate with an RFC 9147 compliant
1967+ * server, which omits the echo entirely. Rewrite the ServerHello to carry an
1968+ * empty legacy_session_id_echo and confirm the client does not reject it. */
1969+ int test_dtls13_5_9_0_compat_empty_echo (void )
1970+ {
1971+ EXPECT_DECLS ;
1972+ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && defined(WOLFSSL_DTLS13 ) && \
1973+ defined(HAVE_SESSION_TICKET ) && defined(WOLFSSL_DTLS13_ECHO_LEGACY_SESSION_ID ) && \
1974+ defined(HAVE_ECC )
1975+ struct test_memio_ctx test_ctx ;
1976+ WOLFSSL_CTX * ctx_c = NULL , * ctx_s = NULL ;
1977+ WOLFSSL * ssl_c = NULL , * ssl_s = NULL ;
1978+ WOLFSSL_SESSION * sess = NULL ;
1979+ int echoIdx = DTLS_RECORD_HEADER_SZ + DTLS_HANDSHAKE_HEADER_SZ +
1980+ OPAQUE16_LEN + RAN_LEN ;
1981+ /* DTLS record header: ... | length(2) at the end. */
1982+ int recLenIdx = DTLS_RECORD_HEADER_SZ - OPAQUE16_LEN ;
1983+ /* DtlsHandShakeHeader: type(1) | length(3) | seq(2) | fragOff(3) |
1984+ * fragLen(3). */
1985+ int hsLenIdx = DTLS_RECORD_HEADER_SZ + OPAQUE8_LEN ;
1986+ int fragLenIdx = hsLenIdx + OPAQUE24_LEN + OPAQUE16_LEN + OPAQUE24_LEN ;
1987+ word32 hsLen , fragLen ;
1988+ word16 recLen ;
1989+
1990+ ExpectIntEQ (compat_echo_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c , & ssl_s ,
1991+ & sess ), 0 );
1992+
1993+ if (EXPECT_SUCCESS ()) {
1994+ byte * b = test_ctx .c_buff ;
1995+
1996+ /* Drop the ID_LEN echo bytes and shrink the three enclosing lengths:
1997+ * DTLS record length, handshake length, fragment length. */
1998+ XMEMMOVE (& b [echoIdx + 1 ], & b [echoIdx + 1 + ID_LEN ],
1999+ (size_t )test_ctx .c_len - (size_t )(echoIdx + 1 + ID_LEN ));
2000+ b [echoIdx ] = 0 ;
2001+ test_ctx .c_len -= ID_LEN ;
2002+
2003+ ato16 (& b [recLenIdx ], & recLen );
2004+ c16toa ((word16 )(recLen - ID_LEN ), & b [recLenIdx ]);
2005+
2006+ ato24 (& b [hsLenIdx ], & hsLen );
2007+ c32to24 (hsLen - ID_LEN , & b [hsLenIdx ]);
2008+
2009+ ato24 (& b [fragLenIdx ], & fragLen );
2010+ c32to24 (fragLen - ID_LEN , & b [fragLenIdx ]);
2011+ }
2012+
2013+ /* The rewrite breaks the transcript, so the handshake still fails - but it
2014+ * must not fail by rejecting the empty echo. */
2015+ ExpectIntEQ (wolfSSL_negotiate (ssl_c ), -1 );
2016+ ExpectIntNE (wolfSSL_get_error (ssl_c , -1 ),
2017+ WC_NO_ERR_TRACE (INVALID_PARAMETER ));
2018+
2019+ wolfSSL_SESSION_free (sess );
2020+ wolfSSL_free (ssl_c );
2021+ wolfSSL_free (ssl_s );
2022+ wolfSSL_CTX_free (ctx_c );
2023+ wolfSSL_CTX_free (ctx_s );
2024+ #endif
2025+ return EXPECT_RESULT ();
2026+ }
0 commit comments