@@ -2955,23 +2955,21 @@ int test_dtls13_no_session_id_echo(void)
29552955{
29562956 EXPECT_DECLS ;
29572957#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && defined(WOLFSSL_DTLS13 ) && \
2958- defined(HAVE_SESSION_TICKET )
2958+ defined(HAVE_SESSION_TICKET ) && defined(HAVE_ECC ) && \
2959+ !defined(WOLFSSL_DTLS13_5_9_0_COMPAT )
29592960 struct test_memio_ctx test_ctx ;
29602961 WOLFSSL_CTX * ctx_c = NULL , * ctx_s = NULL ;
29612962 WOLFSSL * ssl_c = NULL , * ssl_s = NULL ;
29622963 WOLFSSL_SESSION * sess = NULL ;
29632964 char readBuf [1 ];
2964- /* Use traditional groups to avoid HRR from PQ key share mismatch */
2965- int groups [] = {
2966- WOLFSSL_ECC_SECP256R1 ,
2967- WOLFSSL_ECC_SECP384R1 ,
2968- };
2965+ /* Pin to SECP256R1 to avoid a PQ-induced key-share HRR */
2966+ int groups [] = { WOLFSSL_ECC_SECP256R1 };
29692967
29702968 /* First connection: complete a DTLS 1.3 handshake to get a session */
29712969 XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
29722970 ExpectIntEQ (test_memio_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c , & ssl_s ,
29732971 wolfDTLSv1_3_client_method , wolfDTLSv1_3_server_method ), 0 );
2974- ExpectIntEQ (wolfSSL_set_groups (ssl_c , groups , 2 ), WOLFSSL_SUCCESS );
2972+ ExpectIntEQ (wolfSSL_set_groups (ssl_c , groups , 1 ), WOLFSSL_SUCCESS );
29752973 ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
29762974
29772975 /* Read to process any NewSessionTicket */
@@ -3000,8 +2998,7 @@ int test_dtls13_no_session_id_echo(void)
30002998 ExpectIntEQ (test_memio_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c , & ssl_s ,
30012999 wolfDTLSv1_3_client_method , wolfDTLSv1_3_server_method ), 0 );
30023000 ExpectIntEQ (wolfSSL_set_session (ssl_c , sess ), WOLFSSL_SUCCESS );
3003- /* Use traditional groups to avoid HRR from key share mismatch */
3004- ExpectIntEQ (wolfSSL_set_groups (ssl_c , groups , 2 ), WOLFSSL_SUCCESS );
3001+ ExpectIntEQ (wolfSSL_set_groups (ssl_c , groups , 1 ), WOLFSSL_SUCCESS );
30053002 /* Disable HRR cookie so the server directly sends a ServerHello */
30063003 ExpectIntEQ (wolfSSL_disable_hrr_cookie (ssl_s ), WOLFSSL_SUCCESS );
30073004
@@ -3035,6 +3032,132 @@ int test_dtls13_no_session_id_echo(void)
30353032 return EXPECT_RESULT ();
30363033}
30373034
3035+ /* Test that a server built with WOLFSSL_DTLS13_5_9_0_COMPAT echoes the
3036+ * client's legacy_session_id in both the direct ServerHello path and the
3037+ * stateless HRR path (which also exercises RestartHandshakeHashWithCookie). */
3038+ int test_dtls13_5_9_0_compat (void )
3039+ {
3040+ EXPECT_DECLS ;
3041+ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && defined(WOLFSSL_DTLS13 ) && \
3042+ defined(HAVE_SESSION_TICKET ) && defined(WOLFSSL_DTLS13_5_9_0_COMPAT ) && \
3043+ defined(HAVE_ECC )
3044+ struct test_memio_ctx test_ctx ;
3045+ WOLFSSL_CTX * ctx_c = NULL , * ctx_s = NULL ;
3046+ WOLFSSL * ssl_c = NULL , * ssl_s = NULL ;
3047+ WOLFSSL_SESSION * sess = NULL ;
3048+ char readBuf [1 ];
3049+ /* Pin to SECP256R1 to avoid a PQ-induced key-share HRR */
3050+ int groups [] = { WOLFSSL_ECC_SECP256R1 };
3051+ /* RFC 8446 Section 4.1.3: an HRR is a ServerHello carrying this magic
3052+ * random. Used to assert sub-test 1 is a real ServerHello, not an HRR. */
3053+ static const byte hrrRandom [RAN_LEN ] = {
3054+ 0xCF , 0x21 , 0xAD , 0x74 , 0xE5 , 0x9A , 0x61 , 0x11 ,
3055+ 0xBE , 0x1D , 0x8C , 0x02 , 0x1E , 0x65 , 0xB8 , 0x91 ,
3056+ 0xC2 , 0xA2 , 0x11 , 0x16 , 0x7A , 0xBB , 0x8C , 0x5E ,
3057+ 0x07 , 0x9E , 0x09 , 0xE2 , 0xC8 , 0xA8 , 0x33 , 0x9C
3058+ };
3059+
3060+ /* --- initial connection: get a real session to carry the session ID --- */
3061+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
3062+ ExpectIntEQ (test_memio_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c , & ssl_s ,
3063+ wolfDTLSv1_3_client_method , wolfDTLSv1_3_server_method ), 0 );
3064+ ExpectIntEQ (wolfSSL_set_groups (ssl_c , groups , 1 ), WOLFSSL_SUCCESS );
3065+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
3066+
3067+ /* drain any NewSessionTicket before calling get1_session */
3068+ ExpectIntEQ (wolfSSL_read (ssl_c , readBuf , sizeof (readBuf )), -1 );
3069+ ExpectIntEQ (wolfSSL_get_error (ssl_c , -1 ), WOLFSSL_ERROR_WANT_READ );
3070+
3071+ ExpectNotNull (sess = wolfSSL_get1_session (ssl_c ));
3072+
3073+ /* Force a non-zero session ID — simulates a wolfSSL <=v5.9.0 client that
3074+ * mistakenly sends 32 bytes as legacy_session_id in DTLS 1.3. */
3075+ if (sess != NULL && sess -> sessionIDSz == 0 ) {
3076+ sess -> sessionIDSz = ID_LEN ;
3077+ XMEMSET (sess -> sessionID , 0x42 , ID_LEN );
3078+ }
3079+
3080+ wolfSSL_free (ssl_c ); ssl_c = NULL ;
3081+ wolfSSL_free (ssl_s ); ssl_s = NULL ;
3082+ wolfSSL_CTX_free (ctx_c ); ctx_c = NULL ;
3083+ wolfSSL_CTX_free (ctx_s ); ctx_s = NULL ;
3084+
3085+ /* --- sub-test 1: direct ServerHello (HRR cookie disabled) ---
3086+ * Exercises DoTls13ClientHello (change 1) and
3087+ * SendTls13ServerHello (change 2). */
3088+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
3089+ ExpectIntEQ (test_memio_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c , & ssl_s ,
3090+ wolfDTLSv1_3_client_method , wolfDTLSv1_3_server_method ), 0 );
3091+ ExpectIntEQ (wolfSSL_set_session (ssl_c , sess ), WOLFSSL_SUCCESS );
3092+ ExpectIntEQ (wolfSSL_set_groups (ssl_c , groups , 1 ), WOLFSSL_SUCCESS );
3093+ ExpectIntEQ (wolfSSL_disable_hrr_cookie (ssl_s ), WOLFSSL_SUCCESS );
3094+
3095+ /* Client sends CH1 with non-empty legacy_session_id */
3096+ ExpectIntEQ (wolfSSL_negotiate (ssl_c ), -1 );
3097+ ExpectIntEQ (wolfSSL_get_error (ssl_c , -1 ), WOLFSSL_ERROR_WANT_READ );
3098+
3099+ /* Server processes CH1 and sends ServerHello */
3100+ ExpectIntEQ (wolfSSL_negotiate (ssl_s ), -1 );
3101+ ExpectIntEQ (wolfSSL_get_error (ssl_s , -1 ), WOLFSSL_ERROR_WANT_READ );
3102+
3103+ /* Verify that the ServerHello on the wire echoes the session ID.
3104+ * Layout: DTLS Record Header (13) + DTLS Handshake Header (12) +
3105+ * ProtocolVersion (2) + Random (32) = byte 59 for
3106+ * legacy_session_id_echo length. */
3107+ ExpectIntGE (test_ctx .c_len , 60 );
3108+ ExpectIntEQ (test_ctx .c_buff [0 ], handshake );
3109+ ExpectIntEQ (test_ctx .c_buff [DTLS_RECORD_HEADER_SZ ], server_hello );
3110+ /* Confirm it is a real ServerHello, not an HRR (also encoded as a
3111+ * ServerHello but bearing the HelloRetryRequest magic random). */
3112+ ExpectIntNE (XMEMCMP (& test_ctx .c_buff [DTLS_RECORD_HEADER_SZ +
3113+ DTLS_HANDSHAKE_HEADER_SZ + OPAQUE16_LEN ], hrrRandom , RAN_LEN ), 0 );
3114+ ExpectIntEQ (test_ctx .c_buff [DTLS_RECORD_HEADER_SZ +
3115+ DTLS_HANDSHAKE_HEADER_SZ + OPAQUE16_LEN + RAN_LEN ], ID_LEN );
3116+
3117+ /* Complete the handshake — Finished MAC validates the transcript */
3118+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
3119+
3120+ wolfSSL_free (ssl_c ); ssl_c = NULL ;
3121+ wolfSSL_free (ssl_s ); ssl_s = NULL ;
3122+ wolfSSL_CTX_free (ctx_c ); ctx_c = NULL ;
3123+ wolfSSL_CTX_free (ctx_s ); ctx_s = NULL ;
3124+
3125+ /* --- sub-test 2: stateless HRR (HRR cookie enabled by default) ---
3126+ * Exercises SendStatelessReplyDtls13 (change 4) and
3127+ * RestartHandshakeHashWithCookie (change 3). */
3128+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
3129+ ExpectIntEQ (test_memio_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c , & ssl_s ,
3130+ wolfDTLSv1_3_client_method , wolfDTLSv1_3_server_method ), 0 );
3131+ ExpectIntEQ (wolfSSL_set_session (ssl_c , sess ), WOLFSSL_SUCCESS );
3132+ ExpectIntEQ (wolfSSL_set_groups (ssl_c , groups , 1 ), WOLFSSL_SUCCESS );
3133+
3134+ /* Client sends CH1 */
3135+ ExpectIntEQ (wolfSSL_negotiate (ssl_c ), -1 );
3136+ ExpectIntEQ (wolfSSL_get_error (ssl_c , -1 ), WOLFSSL_ERROR_WANT_READ );
3137+
3138+ /* Server sends stateless HRR (SendStatelessReplyDtls13) */
3139+ ExpectIntEQ (wolfSSL_negotiate (ssl_s ), -1 );
3140+ ExpectIntEQ (wolfSSL_get_error (ssl_s , -1 ), WOLFSSL_ERROR_WANT_READ );
3141+
3142+ /* Verify the HRR echoes the session ID at the same wire offset */
3143+ ExpectIntGE (test_ctx .c_len , 60 );
3144+ ExpectIntEQ (test_ctx .c_buff [0 ], handshake );
3145+ ExpectIntEQ (test_ctx .c_buff [DTLS_RECORD_HEADER_SZ ], server_hello );
3146+ ExpectIntEQ (test_ctx .c_buff [DTLS_RECORD_HEADER_SZ +
3147+ DTLS_HANDSHAKE_HEADER_SZ + OPAQUE16_LEN + RAN_LEN ], ID_LEN );
3148+
3149+ /* Complete the handshake — Finished MAC validates RestartHandshakeHashWithCookie */
3150+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
3151+
3152+ wolfSSL_SESSION_free (sess );
3153+ wolfSSL_free (ssl_c );
3154+ wolfSSL_free (ssl_s );
3155+ wolfSSL_CTX_free (ctx_c );
3156+ wolfSSL_CTX_free (ctx_s );
3157+ #endif
3158+ return EXPECT_RESULT ();
3159+ }
3160+
30383161/* Test that a DTLS 1.3 handshake with an oversized certificate chain does
30393162 * not crash or cause out-of-bounds access in SendTls13Certificate. */
30403163int test_dtls13_oversized_cert_chain (void )
0 commit comments