@@ -5340,3 +5340,101 @@ int test_dtls12_missing_finished(void)
53405340#endif
53415341 return EXPECT_RESULT ();
53425342}
5343+
5344+ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && defined(WOLFSSL_DTLS ) && \
5345+ defined(WOLFSSL_SESSION_EXPORT ) && defined(HAVE_ENCRYPT_THEN_MAC ) && \
5346+ !defined(WOLFSSL_AEAD_ONLY ) && !defined(WOLFSSL_NO_TLS12 ) && \
5347+ !defined(NO_RSA ) && !defined(NO_AES ) && defined(HAVE_AES_CBC ) && \
5348+ !defined(NO_SHA256 ) && defined(HAVE_ECC )
5349+ /* Dummy peer callbacks so the DTLS exporter/importer has peer information to
5350+ * work with (the library requires these unless built with
5351+ * WOLFSSL_SESSION_EXPORT_NOPEER). */
5352+ static int test_dtls_export_etm_get_peer (WOLFSSL * ssl , char * ip , int * ipSz ,
5353+ unsigned short * port , int * fam )
5354+ {
5355+ (void )ssl ;
5356+ ip [0 ] = -1 ;
5357+ * ipSz = 1 ;
5358+ * port = 1 ;
5359+ * fam = 2 ;
5360+ return 1 ;
5361+ }
5362+
5363+ static int test_dtls_export_etm_set_peer (WOLFSSL * ssl , char * ip , int ipSz ,
5364+ unsigned short port , int fam )
5365+ {
5366+ (void )ssl ;
5367+ if (ip [0 ] != -1 || ipSz != 1 || port != 1 || fam != 2 )
5368+ return 0 ;
5369+ return 1 ;
5370+ }
5371+ #endif
5372+
5373+ /* Regression test for DTLS session export/import dropping the Encrypt-Then-MAC
5374+ * options. Historically the ETM option fields were only serialized for TLS, so
5375+ * a re-imported DTLS session lost the negotiated ETM state and broke the record
5376+ * layer. Establish a DTLS 1.2 connection with a CBC cipher suite (where ETM
5377+ * applies), export the session, re-import it into a fresh WOLFSSL, and confirm
5378+ * the ETM option fields survive the round trip. */
5379+ int test_dtls12_export_import_etm (void )
5380+ {
5381+ EXPECT_DECLS ;
5382+ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && defined(WOLFSSL_DTLS ) && \
5383+ defined(WOLFSSL_SESSION_EXPORT ) && defined(HAVE_ENCRYPT_THEN_MAC ) && \
5384+ !defined(WOLFSSL_AEAD_ONLY ) && !defined(WOLFSSL_NO_TLS12 ) && \
5385+ !defined(NO_RSA ) && !defined(NO_AES ) && defined(HAVE_AES_CBC ) && \
5386+ !defined(NO_SHA256 ) && defined(HAVE_ECC )
5387+ /* TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - a CBC suite, where ETM applies. */
5388+ const char * cbcSuite = "ECDHE-RSA-AES128-SHA256" ;
5389+ WOLFSSL_CTX * ctx_c = NULL , * ctx_s = NULL ;
5390+ WOLFSSL * ssl_c = NULL , * ssl_s = NULL ;
5391+ WOLFSSL * ssl_imp = NULL ;
5392+ struct test_memio_ctx test_ctx ;
5393+ unsigned char * session = NULL ;
5394+ unsigned int sessionSz = 0 ;
5395+
5396+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
5397+ ExpectIntEQ (test_memio_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c , & ssl_s ,
5398+ wolfDTLSv1_2_client_method , wolfDTLSv1_2_server_method ), 0 );
5399+ ExpectIntEQ (wolfSSL_set_cipher_list (ssl_c , cbcSuite ), WOLFSSL_SUCCESS );
5400+ ExpectIntEQ (wolfSSL_set_cipher_list (ssl_s , cbcSuite ), WOLFSSL_SUCCESS );
5401+
5402+ /* The exporter/importer needs peer info callbacks. */
5403+ wolfSSL_CTX_SetIOGetPeer (ctx_s , test_dtls_export_etm_get_peer );
5404+ wolfSSL_CTX_SetIOSetPeer (ctx_s , test_dtls_export_etm_set_peer );
5405+
5406+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
5407+
5408+ /* Sanity: the handshake itself negotiated ETM on both sides. */
5409+ if (ssl_c != NULL )
5410+ ExpectIntEQ (ssl_c -> options .encThenMac , 1 );
5411+ if (ssl_s != NULL )
5412+ ExpectIntEQ (ssl_s -> options .encThenMac , 1 );
5413+
5414+ /* Export the server's DTLS session. */
5415+ ExpectIntGE (wolfSSL_dtls_export (ssl_s , NULL , & sessionSz ), 0 );
5416+ ExpectIntGT (sessionSz , 0 );
5417+ ExpectNotNull (session = (unsigned char * )XMALLOC (sessionSz , NULL ,
5418+ DYNAMIC_TYPE_TMP_BUFFER ));
5419+ ExpectIntGE (wolfSSL_dtls_export (ssl_s , session , & sessionSz ), 0 );
5420+
5421+ /* Import into a fresh WOLFSSL and confirm the ETM state survived. */
5422+ ExpectNotNull (ssl_imp = wolfSSL_new (ctx_s ));
5423+ ExpectIntGE (wolfSSL_dtls_import (ssl_imp , session , sessionSz ), 0 );
5424+ if (ssl_imp != NULL ) {
5425+ /* Regression check: pre-fix these were all reset to 0 for DTLS. */
5426+ ExpectIntEQ (ssl_imp -> options .encThenMac , 1 );
5427+ ExpectIntEQ (ssl_imp -> options .startedETMRead , 1 );
5428+ ExpectIntEQ (ssl_imp -> options .startedETMWrite , 1 );
5429+ ExpectIntEQ (ssl_imp -> options .disallowEncThenMac , 0 );
5430+ }
5431+
5432+ XFREE (session , NULL , DYNAMIC_TYPE_TMP_BUFFER );
5433+ wolfSSL_free (ssl_imp );
5434+ wolfSSL_free (ssl_c );
5435+ wolfSSL_free (ssl_s );
5436+ wolfSSL_CTX_free (ctx_c );
5437+ wolfSSL_CTX_free (ctx_s );
5438+ #endif
5439+ return EXPECT_RESULT ();
5440+ }
0 commit comments