@@ -3171,3 +3171,101 @@ int test_dtls_set_session_min_downgrade(void)
31713171#endif
31723172 return EXPECT_RESULT ();
31733173}
3174+
3175+ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && defined(WOLFSSL_DTLS ) && \
3176+ defined(WOLFSSL_SESSION_EXPORT ) && defined(HAVE_ENCRYPT_THEN_MAC ) && \
3177+ !defined(WOLFSSL_AEAD_ONLY ) && !defined(WOLFSSL_NO_TLS12 ) && \
3178+ !defined(NO_RSA ) && !defined(NO_AES ) && defined(HAVE_AES_CBC ) && \
3179+ !defined(NO_SHA256 ) && defined(HAVE_ECC )
3180+ /* Dummy peer callbacks so the DTLS exporter/importer has peer information to
3181+ * work with (the library requires these unless built with
3182+ * WOLFSSL_SESSION_EXPORT_NOPEER). */
3183+ static int test_dtls_export_etm_get_peer (WOLFSSL * ssl , char * ip , int * ipSz ,
3184+ unsigned short * port , int * fam )
3185+ {
3186+ (void )ssl ;
3187+ ip [0 ] = -1 ;
3188+ * ipSz = 1 ;
3189+ * port = 1 ;
3190+ * fam = 2 ;
3191+ return 1 ;
3192+ }
3193+
3194+ static int test_dtls_export_etm_set_peer (WOLFSSL * ssl , char * ip , int ipSz ,
3195+ unsigned short port , int fam )
3196+ {
3197+ (void )ssl ;
3198+ if (ip [0 ] != -1 || ipSz != 1 || port != 1 || fam != 2 )
3199+ return 0 ;
3200+ return 1 ;
3201+ }
3202+ #endif
3203+
3204+ /* Regression test for DTLS session export/import dropping the Encrypt-Then-MAC
3205+ * options. Historically the ETM option fields were only serialized for TLS, so
3206+ * a re-imported DTLS session lost the negotiated ETM state and broke the record
3207+ * layer. Establish a DTLS 1.2 connection with a CBC cipher suite (where ETM
3208+ * applies), export the session, re-import it into a fresh WOLFSSL, and confirm
3209+ * the ETM option fields survive the round trip. */
3210+ int test_dtls12_export_import_etm (void )
3211+ {
3212+ EXPECT_DECLS ;
3213+ #if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && defined(WOLFSSL_DTLS ) && \
3214+ defined(WOLFSSL_SESSION_EXPORT ) && defined(HAVE_ENCRYPT_THEN_MAC ) && \
3215+ !defined(WOLFSSL_AEAD_ONLY ) && !defined(WOLFSSL_NO_TLS12 ) && \
3216+ !defined(NO_RSA ) && !defined(NO_AES ) && defined(HAVE_AES_CBC ) && \
3217+ !defined(NO_SHA256 ) && defined(HAVE_ECC )
3218+ /* TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - a CBC suite, where ETM applies. */
3219+ const char * cbcSuite = "ECDHE-RSA-AES128-SHA256" ;
3220+ WOLFSSL_CTX * ctx_c = NULL , * ctx_s = NULL ;
3221+ WOLFSSL * ssl_c = NULL , * ssl_s = NULL ;
3222+ WOLFSSL * ssl_imp = NULL ;
3223+ struct test_memio_ctx test_ctx ;
3224+ unsigned char * session = NULL ;
3225+ unsigned int sessionSz = 0 ;
3226+
3227+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
3228+ ExpectIntEQ (test_memio_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c , & ssl_s ,
3229+ wolfDTLSv1_2_client_method , wolfDTLSv1_2_server_method ), 0 );
3230+ ExpectIntEQ (wolfSSL_set_cipher_list (ssl_c , cbcSuite ), WOLFSSL_SUCCESS );
3231+ ExpectIntEQ (wolfSSL_set_cipher_list (ssl_s , cbcSuite ), WOLFSSL_SUCCESS );
3232+
3233+ /* The exporter/importer needs peer info callbacks. */
3234+ wolfSSL_CTX_SetIOGetPeer (ctx_s , test_dtls_export_etm_get_peer );
3235+ wolfSSL_CTX_SetIOSetPeer (ctx_s , test_dtls_export_etm_set_peer );
3236+
3237+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
3238+
3239+ /* Sanity: the handshake itself negotiated ETM on both sides. */
3240+ if (ssl_c != NULL )
3241+ ExpectIntEQ (ssl_c -> options .encThenMac , 1 );
3242+ if (ssl_s != NULL )
3243+ ExpectIntEQ (ssl_s -> options .encThenMac , 1 );
3244+
3245+ /* Export the server's DTLS session. */
3246+ ExpectIntGE (wolfSSL_dtls_export (ssl_s , NULL , & sessionSz ), 0 );
3247+ ExpectIntGT (sessionSz , 0 );
3248+ ExpectNotNull (session = (unsigned char * )XMALLOC (sessionSz , NULL ,
3249+ DYNAMIC_TYPE_TMP_BUFFER ));
3250+ ExpectIntGE (wolfSSL_dtls_export (ssl_s , session , & sessionSz ), 0 );
3251+
3252+ /* Import into a fresh WOLFSSL and confirm the ETM state survived. */
3253+ ExpectNotNull (ssl_imp = wolfSSL_new (ctx_s ));
3254+ ExpectIntGE (wolfSSL_dtls_import (ssl_imp , session , sessionSz ), 0 );
3255+ if (ssl_imp != NULL ) {
3256+ /* Regression check: pre-fix these were all reset to 0 for DTLS. */
3257+ ExpectIntEQ (ssl_imp -> options .encThenMac , 1 );
3258+ ExpectIntEQ (ssl_imp -> options .startedETMRead , 1 );
3259+ ExpectIntEQ (ssl_imp -> options .startedETMWrite , 1 );
3260+ ExpectIntEQ (ssl_imp -> options .disallowEncThenMac , 0 );
3261+ }
3262+
3263+ XFREE (session , NULL , DYNAMIC_TYPE_TMP_BUFFER );
3264+ wolfSSL_free (ssl_imp );
3265+ wolfSSL_free (ssl_c );
3266+ wolfSSL_free (ssl_s );
3267+ wolfSSL_CTX_free (ctx_c );
3268+ wolfSSL_CTX_free (ctx_s );
3269+ #endif
3270+ return EXPECT_RESULT ();
3271+ }
0 commit comments