@@ -3294,3 +3294,101 @@ int test_dtls_set_session_min_downgrade(void)
32943294#endif
32953295 return EXPECT_RESULT ();
32963296}
3297+
3298+ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && defined(WOLFSSL_DTLS ) && \
3299+ defined(WOLFSSL_SESSION_EXPORT ) && defined(HAVE_ENCRYPT_THEN_MAC ) && \
3300+ !defined(WOLFSSL_AEAD_ONLY ) && !defined(WOLFSSL_NO_TLS12 ) && \
3301+ !defined(NO_RSA ) && !defined(NO_AES ) && defined(HAVE_AES_CBC ) && \
3302+ !defined(NO_SHA256 ) && defined(HAVE_ECC )
3303+ /* Dummy peer callbacks so the DTLS exporter/importer has peer information to
3304+ * work with (the library requires these unless built with
3305+ * WOLFSSL_SESSION_EXPORT_NOPEER). */
3306+ static int test_dtls_export_etm_get_peer (WOLFSSL * ssl , char * ip , int * ipSz ,
3307+ unsigned short * port , int * fam )
3308+ {
3309+ (void )ssl ;
3310+ ip [0 ] = -1 ;
3311+ * ipSz = 1 ;
3312+ * port = 1 ;
3313+ * fam = 2 ;
3314+ return 1 ;
3315+ }
3316+
3317+ static int test_dtls_export_etm_set_peer (WOLFSSL * ssl , char * ip , int ipSz ,
3318+ unsigned short port , int fam )
3319+ {
3320+ (void )ssl ;
3321+ if (ip [0 ] != -1 || ipSz != 1 || port != 1 || fam != 2 )
3322+ return 0 ;
3323+ return 1 ;
3324+ }
3325+ #endif
3326+
3327+ /* Regression test for DTLS session export/import dropping the Encrypt-Then-MAC
3328+ * options. Historically the ETM option fields were only serialized for TLS, so
3329+ * a re-imported DTLS session lost the negotiated ETM state and broke the record
3330+ * layer. Establish a DTLS 1.2 connection with a CBC cipher suite (where ETM
3331+ * applies), export the session, re-import it into a fresh WOLFSSL, and confirm
3332+ * the ETM option fields survive the round trip. */
3333+ int test_dtls12_export_import_etm (void )
3334+ {
3335+ EXPECT_DECLS ;
3336+ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && defined(WOLFSSL_DTLS ) && \
3337+ defined(WOLFSSL_SESSION_EXPORT ) && defined(HAVE_ENCRYPT_THEN_MAC ) && \
3338+ !defined(WOLFSSL_AEAD_ONLY ) && !defined(WOLFSSL_NO_TLS12 ) && \
3339+ !defined(NO_RSA ) && !defined(NO_AES ) && defined(HAVE_AES_CBC ) && \
3340+ !defined(NO_SHA256 ) && defined(HAVE_ECC )
3341+ /* TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - a CBC suite, where ETM applies. */
3342+ const char * cbcSuite = "ECDHE-RSA-AES128-SHA256" ;
3343+ WOLFSSL_CTX * ctx_c = NULL , * ctx_s = NULL ;
3344+ WOLFSSL * ssl_c = NULL , * ssl_s = NULL ;
3345+ WOLFSSL * ssl_imp = NULL ;
3346+ struct test_memio_ctx test_ctx ;
3347+ unsigned char * session = NULL ;
3348+ unsigned int sessionSz = 0 ;
3349+
3350+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
3351+ ExpectIntEQ (test_memio_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c , & ssl_s ,
3352+ wolfDTLSv1_2_client_method , wolfDTLSv1_2_server_method ), 0 );
3353+ ExpectIntEQ (wolfSSL_set_cipher_list (ssl_c , cbcSuite ), WOLFSSL_SUCCESS );
3354+ ExpectIntEQ (wolfSSL_set_cipher_list (ssl_s , cbcSuite ), WOLFSSL_SUCCESS );
3355+
3356+ /* The exporter/importer needs peer info callbacks. */
3357+ wolfSSL_CTX_SetIOGetPeer (ctx_s , test_dtls_export_etm_get_peer );
3358+ wolfSSL_CTX_SetIOSetPeer (ctx_s , test_dtls_export_etm_set_peer );
3359+
3360+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
3361+
3362+ /* Sanity: the handshake itself negotiated ETM on both sides. */
3363+ if (ssl_c != NULL )
3364+ ExpectIntEQ (ssl_c -> options .encThenMac , 1 );
3365+ if (ssl_s != NULL )
3366+ ExpectIntEQ (ssl_s -> options .encThenMac , 1 );
3367+
3368+ /* Export the server's DTLS session. */
3369+ ExpectIntGE (wolfSSL_dtls_export (ssl_s , NULL , & sessionSz ), 0 );
3370+ ExpectIntGT (sessionSz , 0 );
3371+ ExpectNotNull (session = (unsigned char * )XMALLOC (sessionSz , NULL ,
3372+ DYNAMIC_TYPE_TMP_BUFFER ));
3373+ ExpectIntGE (wolfSSL_dtls_export (ssl_s , session , & sessionSz ), 0 );
3374+
3375+ /* Import into a fresh WOLFSSL and confirm the ETM state survived. */
3376+ ExpectNotNull (ssl_imp = wolfSSL_new (ctx_s ));
3377+ ExpectIntGE (wolfSSL_dtls_import (ssl_imp , session , sessionSz ), 0 );
3378+ if (ssl_imp != NULL ) {
3379+ /* Regression check: pre-fix these were all reset to 0 for DTLS. */
3380+ ExpectIntEQ (ssl_imp -> options .encThenMac , 1 );
3381+ ExpectIntEQ (ssl_imp -> options .startedETMRead , 1 );
3382+ ExpectIntEQ (ssl_imp -> options .startedETMWrite , 1 );
3383+ ExpectIntEQ (ssl_imp -> options .disallowEncThenMac , 0 );
3384+ }
3385+
3386+ XFREE (session , NULL , DYNAMIC_TYPE_TMP_BUFFER );
3387+ wolfSSL_free (ssl_imp );
3388+ wolfSSL_free (ssl_c );
3389+ wolfSSL_free (ssl_s );
3390+ wolfSSL_CTX_free (ctx_c );
3391+ wolfSSL_CTX_free (ctx_s );
3392+ #endif
3393+ return EXPECT_RESULT ();
3394+ }
0 commit comments