@@ -5873,3 +5873,275 @@ int test_tls13_clear_preserves_psk_dhe(void)
58735873#endif
58745874 return EXPECT_RESULT ();
58755875}
5876+
5877+ #if defined(WOLFSSL_TLS13 ) && \
5878+ defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && \
5879+ !defined(NO_WOLFSSL_CLIENT ) && !defined(NO_WOLFSSL_SERVER ) && \
5880+ (defined(BUILD_TLS_AES_128_GCM_SHA256 ) || \
5881+ defined(BUILD_TLS_AES_256_GCM_SHA384 ) || \
5882+ defined(BUILD_TLS_CHACHA20_POLY1305_SHA256 ) || \
5883+ defined(BUILD_TLS_AES_128_CCM_SHA256 ) || \
5884+ defined(BUILD_TLS_AES_128_CCM_8_SHA256 ))
5885+ /* One iteration of the AEAD fuzz test: run a fresh handshake
5886+ * up to the point where the first AEAD-protected record from the side under
5887+ * test sits in the receiver's input buffer, flip one random byte of the
5888+ * encrypted payload to a random non-zero value, and confirm the receiver
5889+ * fails with VERIFY_MAC_ERROR. side==0 fuzzes the server's first encrypted
5890+ * record (EncryptedExtensions, read by the client). side==1 fuzzes the
5891+ * client's first encrypted record (Finished, read by the server). */
5892+ static int test_tls13_cipher_fuzz_once (WC_RNG * rng ,
5893+ const char * cipher , int side )
5894+ {
5895+ EXPECT_DECLS ;
5896+ WOLFSSL_CTX * ctx_c = NULL ;
5897+ WOLFSSL_CTX * ctx_s = NULL ;
5898+ WOLFSSL * ssl_c = NULL ;
5899+ WOLFSSL * ssl_s = NULL ;
5900+ struct test_memio_ctx test_ctx ;
5901+ byte * buf = NULL ;
5902+ int buf_len = 0 ;
5903+ int rec_off = 0 ;
5904+ int rec_len = 0 ;
5905+ int fuzz_off ;
5906+ byte fuzz_xor ;
5907+ word32 rand32 ;
5908+ int ret ;
5909+ int err ;
5910+
5911+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
5912+ test_ctx .c_ciphers = cipher ;
5913+ test_ctx .s_ciphers = cipher ;
5914+ ExpectIntEQ (test_memio_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c , & ssl_s ,
5915+ wolfTLSv1_3_client_method , wolfTLSv1_3_server_method ), 0 );
5916+
5917+ /* Drive the handshake forward until the side being fuzzed has written
5918+ * its first AEAD-encrypted record into the peer's read buffer. The
5919+ * server's first encrypted record is queued after its first
5920+ * wolfSSL_accept() (EncryptedExtensions, immediately following
5921+ * ServerHello). The client's first encrypted record is queued once
5922+ * wolfSSL_connect() returns success and the client has sent its
5923+ * Finished. */
5924+ ExpectIntNE (wolfSSL_connect (ssl_c ), WOLFSSL_SUCCESS );
5925+ ExpectIntEQ (wolfSSL_get_error (ssl_c , -1 ), WOLFSSL_ERROR_WANT_READ );
5926+ ExpectIntNE (wolfSSL_accept (ssl_s ), WOLFSSL_SUCCESS );
5927+ ExpectIntEQ (wolfSSL_get_error (ssl_s , -1 ), WOLFSSL_ERROR_WANT_READ );
5928+ if (side == 1 ) {
5929+ ExpectIntEQ (wolfSSL_connect (ssl_c ), WOLFSSL_SUCCESS );
5930+ buf = test_ctx .s_buff ;
5931+ buf_len = test_ctx .s_len ;
5932+ }
5933+ else {
5934+ buf = test_ctx .c_buff ;
5935+ buf_len = test_ctx .c_len ;
5936+ }
5937+
5938+ /* Walk the TLS records in the target buffer and locate the first
5939+ * application_data record (content type 0x17), which holds the first
5940+ * encrypted handshake message. Plaintext records (ServerHello,
5941+ * ChangeCipherSpec for middlebox compatibility) precede it and must be
5942+ * skipped over. */
5943+ if (EXPECT_SUCCESS ()) {
5944+ int off = 0 ;
5945+ while (off + 5 <= buf_len ) {
5946+ int this_len = ((int )buf [off + 3 ] << 8 ) | (int )buf [off + 4 ];
5947+ if (buf [off ] == 0x17 ) {
5948+ rec_off = off ;
5949+ rec_len = this_len ;
5950+ break ;
5951+ }
5952+ off += 5 + this_len ;
5953+ }
5954+ }
5955+ ExpectIntGT (rec_len , 0 );
5956+ ExpectIntLE (rec_off + 5 + rec_len , buf_len );
5957+
5958+ /* Pick a random offset within the encrypted payload (skipping the
5959+ * 5-byte record header) and XOR it with a non-zero value so the byte
5960+ * is guaranteed to change. */
5961+ if (EXPECT_SUCCESS ()) {
5962+ rand32 = 0 ;
5963+ fuzz_off = 0 ;
5964+ ExpectIntEQ (wc_RNG_GenerateBlock (rng , (byte * )& rand32 ,
5965+ sizeof (rand32 )), 0 );
5966+ if (EXPECT_SUCCESS ()) {
5967+ fuzz_off = rec_off + 5 + (int )(rand32 % (word32 )rec_len );
5968+ }
5969+ do {
5970+ ExpectIntEQ (wc_RNG_GenerateByte (rng , & fuzz_xor ), 0 );
5971+ } while (EXPECT_SUCCESS () && fuzz_xor == 0 );
5972+ if (EXPECT_SUCCESS ()) {
5973+ buf [fuzz_off ] ^= fuzz_xor ;
5974+ }
5975+ }
5976+
5977+ /* Drive the receiving side. It must report VERIFY_MAC_ERROR - the
5978+ * corrupted cipher text or tag must surface as a hard error. */
5979+ if (EXPECT_SUCCESS ()) {
5980+ if (side == 1 ) {
5981+ ret = wolfSSL_accept (ssl_s );
5982+ err = wolfSSL_get_error (ssl_s , ret );
5983+ }
5984+ else {
5985+ ret = wolfSSL_connect (ssl_c );
5986+ err = wolfSSL_get_error (ssl_c , ret );
5987+ }
5988+ ExpectIntEQ (ret , WOLFSSL_FATAL_ERROR );
5989+ ExpectTrue ((err == WC_NO_ERR_TRACE (VERIFY_MAC_ERROR )) ||
5990+ (err == WC_NO_ERR_TRACE (AES_GCM_AUTH_E )) ||
5991+ (err == WC_NO_ERR_TRACE (AES_CCM_AUTH_E )));
5992+ }
5993+
5994+ wolfSSL_free (ssl_c );
5995+ wolfSSL_CTX_free (ctx_c );
5996+ wolfSSL_free (ssl_s );
5997+ wolfSSL_CTX_free (ctx_s );
5998+ return EXPECT_RESULT ();
5999+ }
6000+
6001+ /* Run 5 fuzz iterations per side for a single cipher suite. */
6002+ static int test_tls13_cipher_fuzz_cs (WC_RNG * rng , const char * cipher )
6003+ {
6004+ EXPECT_DECLS ;
6005+ int side ;
6006+ int iter ;
6007+
6008+ for (side = 0 ; side < 2 && EXPECT_SUCCESS (); side ++ ) {
6009+ for (iter = 0 ; iter < 5 && EXPECT_SUCCESS (); iter ++ ) {
6010+ int _r = test_tls13_cipher_fuzz_once (rng , cipher , side );
6011+ if (_r != TEST_SUCCESS ) {
6012+ fprintf (stderr , "FAIL cipher=%s side=%d iter=%d\n" ,
6013+ cipher , side , iter );
6014+ }
6015+ ExpectIntEQ (_r , TEST_SUCCESS );
6016+ }
6017+ }
6018+ return EXPECT_RESULT ();
6019+ }
6020+ #endif
6021+
6022+ /* Each per-cipher-suite test below runs the fuzz body (test_tls13_cipher_fuzz_cs)
6023+ * against a single AEAD cipher: it flips a random byte of the first encrypted
6024+ * record on each side of a TLS 1.3 handshake and expects the receiver to fail
6025+ * authentication. AEAD authentication makes it cryptographically infeasible
6026+ * for any single-byte change in the ciphertext or tag to leave authentication
6027+ * intact, so the receiver must report a hard auth error. */
6028+
6029+ int test_tls13_cipher_fuzz_aes128_gcm_sha256 (void )
6030+ {
6031+ EXPECT_DECLS ;
6032+ #if defined(WOLFSSL_TLS13 ) && \
6033+ defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && \
6034+ !defined(NO_WOLFSSL_CLIENT ) && !defined(NO_WOLFSSL_SERVER ) && \
6035+ defined(BUILD_TLS_AES_128_GCM_SHA256 )
6036+ WC_RNG rng ;
6037+ int rngInit = 0 ;
6038+
6039+ XMEMSET (& rng , 0 , sizeof (rng ));
6040+ ExpectIntEQ (wc_InitRng (& rng ), 0 );
6041+ if (EXPECT_SUCCESS ())
6042+ rngInit = 1 ;
6043+
6044+ ExpectIntEQ (test_tls13_cipher_fuzz_cs (& rng , "TLS13-AES128-GCM-SHA256" ),
6045+ TEST_SUCCESS );
6046+
6047+ if (rngInit )
6048+ wc_FreeRng (& rng );
6049+ #endif
6050+ return EXPECT_RESULT ();
6051+ }
6052+
6053+ int test_tls13_cipher_fuzz_aes256_gcm_sha384 (void )
6054+ {
6055+ EXPECT_DECLS ;
6056+ #if defined(WOLFSSL_TLS13 ) && \
6057+ defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && \
6058+ !defined(NO_WOLFSSL_CLIENT ) && !defined(NO_WOLFSSL_SERVER ) && \
6059+ defined(BUILD_TLS_AES_256_GCM_SHA384 )
6060+ WC_RNG rng ;
6061+ int rngInit = 0 ;
6062+
6063+ XMEMSET (& rng , 0 , sizeof (rng ));
6064+ ExpectIntEQ (wc_InitRng (& rng ), 0 );
6065+ if (EXPECT_SUCCESS ())
6066+ rngInit = 1 ;
6067+
6068+ ExpectIntEQ (test_tls13_cipher_fuzz_cs (& rng , "TLS13-AES256-GCM-SHA384" ),
6069+ TEST_SUCCESS );
6070+
6071+ if (rngInit )
6072+ wc_FreeRng (& rng );
6073+ #endif
6074+ return EXPECT_RESULT ();
6075+ }
6076+
6077+ int test_tls13_cipher_fuzz_chacha20_poly1305_sha256 (void )
6078+ {
6079+ EXPECT_DECLS ;
6080+ #if defined(WOLFSSL_TLS13 ) && \
6081+ defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && \
6082+ !defined(NO_WOLFSSL_CLIENT ) && !defined(NO_WOLFSSL_SERVER ) && \
6083+ defined(BUILD_TLS_CHACHA20_POLY1305_SHA256 )
6084+ WC_RNG rng ;
6085+ int rngInit = 0 ;
6086+
6087+ XMEMSET (& rng , 0 , sizeof (rng ));
6088+ ExpectIntEQ (wc_InitRng (& rng ), 0 );
6089+ if (EXPECT_SUCCESS ())
6090+ rngInit = 1 ;
6091+
6092+ ExpectIntEQ (test_tls13_cipher_fuzz_cs (& rng ,
6093+ "TLS13-CHACHA20-POLY1305-SHA256" ), TEST_SUCCESS );
6094+
6095+ if (rngInit )
6096+ wc_FreeRng (& rng );
6097+ #endif
6098+ return EXPECT_RESULT ();
6099+ }
6100+
6101+ int test_tls13_cipher_fuzz_aes128_ccm_sha256 (void )
6102+ {
6103+ EXPECT_DECLS ;
6104+ #if defined(WOLFSSL_TLS13 ) && \
6105+ defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && \
6106+ !defined(NO_WOLFSSL_CLIENT ) && !defined(NO_WOLFSSL_SERVER ) && \
6107+ defined(BUILD_TLS_AES_128_CCM_SHA256 )
6108+ WC_RNG rng ;
6109+ int rngInit = 0 ;
6110+
6111+ XMEMSET (& rng , 0 , sizeof (rng ));
6112+ ExpectIntEQ (wc_InitRng (& rng ), 0 );
6113+ if (EXPECT_SUCCESS ())
6114+ rngInit = 1 ;
6115+
6116+ ExpectIntEQ (test_tls13_cipher_fuzz_cs (& rng , "TLS13-AES128-CCM-SHA256" ),
6117+ TEST_SUCCESS );
6118+
6119+ if (rngInit )
6120+ wc_FreeRng (& rng );
6121+ #endif
6122+ return EXPECT_RESULT ();
6123+ }
6124+
6125+ int test_tls13_cipher_fuzz_aes128_ccm_8_sha256 (void )
6126+ {
6127+ EXPECT_DECLS ;
6128+ #if defined(WOLFSSL_TLS13 ) && \
6129+ defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && \
6130+ !defined(NO_WOLFSSL_CLIENT ) && !defined(NO_WOLFSSL_SERVER ) && \
6131+ defined(BUILD_TLS_AES_128_CCM_8_SHA256 )
6132+ WC_RNG rng ;
6133+ int rngInit = 0 ;
6134+
6135+ XMEMSET (& rng , 0 , sizeof (rng ));
6136+ ExpectIntEQ (wc_InitRng (& rng ), 0 );
6137+ if (EXPECT_SUCCESS ())
6138+ rngInit = 1 ;
6139+
6140+ ExpectIntEQ (test_tls13_cipher_fuzz_cs (& rng , "TLS13-AES128-CCM-8-SHA256" ),
6141+ TEST_SUCCESS );
6142+
6143+ if (rngInit )
6144+ wc_FreeRng (& rng );
6145+ #endif
6146+ return EXPECT_RESULT ();
6147+ }
0 commit comments