@@ -6189,3 +6189,212 @@ int test_tls13_cipher_fuzz_aes128_ccm_8_sha256(void)
61896189#endif
61906190 return EXPECT_RESULT ();
61916191}
6192+
6193+ /* Regression test for the AEAD record-protection limit constants in
6194+ * internal.h. The macros expand to w64From32(hi, lo). A prior version split
6195+ * the intended 32-bit constants into 16-bit halves and passed each half as
6196+ * a separate 32-bit argument, producing a 64-bit value many orders of
6197+ * magnitude larger than RFC 8446 / RFC 9147 require. That made
6198+ * CheckTLS13AEADSendLimit's key-update trigger effectively unreachable.
6199+ * Compare against the hard-coded spec values so a recurrence is caught even
6200+ * if the macro is reused on both sides of the comparison. */
6201+ int test_tls13_AEAD_limit_macros (void )
6202+ {
6203+ EXPECT_DECLS ;
6204+ #if defined(WOLFSSL_TLS13 ) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS )
6205+ w64wrapper limit ;
6206+
6207+ /* RFC 8446 5.5: 2^24.5 ~= 23726566 (0x016A09E6). */
6208+ limit = AEAD_AES_LIMIT ;
6209+ ExpectIntEQ (w64GetHigh32 (limit ), 0 );
6210+ ExpectIntEQ (w64GetLow32 (limit ), 0x016A09E6 );
6211+
6212+ #ifdef WOLFSSL_DTLS13
6213+ /* RFC 9147 (AES-CCM integrity): 2^23.5 ~= 11863283 (0x00B504F3). */
6214+ limit = DTLS_AEAD_AES_CCM_FAIL_LIMIT ;
6215+ ExpectIntEQ (w64GetHigh32 (limit ), 0 );
6216+ ExpectIntEQ (w64GetLow32 (limit ), 0x00B504F3 );
6217+
6218+ /* Key-update threshold is half the fail limit: 5931641 (0x005A8279). */
6219+ limit = DTLS_AEAD_AES_CCM_FAIL_KU_LIMIT ;
6220+ ExpectIntEQ (w64GetHigh32 (limit ), 0 );
6221+ ExpectIntEQ (w64GetLow32 (limit ), 0x005A8279 );
6222+ #endif
6223+ #endif
6224+ return EXPECT_RESULT ();
6225+ }
6226+
6227+ #if defined(WOLFSSL_TLS13 ) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS ) && \
6228+ !defined(NO_WOLFSSL_CLIENT ) && !defined(NO_WOLFSSL_SERVER ) && \
6229+ defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES )
6230+ /* Drive the client's encrypt sequence number towards the spec limit for
6231+ * `suite` and verify CheckTLS13AEADSendLimit's KeyUpdate trigger fires at
6232+ * exactly the right boundary.
6233+ *
6234+ * Two writes are exercised:
6235+ * 1. Counter set to limit - 2. After the write the counter must read
6236+ * limit - 1 (record incremented it by 1) and no KeyUpdate must have
6237+ * been emitted. CheckTLS13AEADSendLimit uses `seq >= limit`, so neither
6238+ * the pre-send check nor the trailing loop check (which runs once more
6239+ * after the last record before wolfSSL_write exits) is allowed to fire.
6240+ * 2. A second write follows with the counter already sitting at limit - 1
6241+ * from the previous record. The user record goes out at seq = limit-1,
6242+ * which bumps the counter to limit; the trailing limit check then
6243+ * fires SendTls13KeyUpdate. SetKeysSide zeroes the encrypt counter, so
6244+ * the post-write counter is 0.
6245+ *
6246+ * With the previous broken AEAD-limit macros the limit was unreachable, no
6247+ * KeyUpdate would ever fire, and the counter would simply advance to
6248+ * limit_lo + 1 in the second case instead of being reset.
6249+ *
6250+ * The AEAD nonce mixes in the record sequence number on both sides, so the
6251+ * server's decrypt counter has to be advanced in lockstep with the client's
6252+ * encrypt counter or the record fails the integrity check. */
6253+ static int test_tls13_AEAD_limit_triggers_KeyUpdate_cs (const char * suite ,
6254+ word32 limit_hi , word32 limit_lo , int expected_bulk_cipher )
6255+ {
6256+ EXPECT_DECLS ;
6257+ struct test_memio_ctx test_ctx ;
6258+ WOLFSSL_CTX * ctx_c = NULL , * ctx_s = NULL ;
6259+ WOLFSSL * ssl_c = NULL , * ssl_s = NULL ;
6260+ const char msg [] = "post-limit-record" ;
6261+ char buf [sizeof (msg )];
6262+ int written ;
6263+
6264+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
6265+ test_ctx .c_ciphers = suite ;
6266+ test_ctx .s_ciphers = suite ;
6267+
6268+ ExpectIntEQ (test_memio_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c , & ssl_s ,
6269+ wolfTLSv1_3_client_method , wolfTLSv1_3_server_method ), 0 );
6270+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
6271+
6272+ if (EXPECT_SUCCESS () && ssl_c != NULL && ssl_s != NULL ) {
6273+ /* Sanity check: the negotiated bulk cipher matches what the caller
6274+ * intends to exercise. If a build flag combination falls through to
6275+ * a different suite, the limit constant would be wrong. */
6276+ ExpectIntEQ (ssl_c -> specs .bulk_cipher_algorithm , expected_bulk_cipher );
6277+
6278+ /* Stage the counters two below the limit so the first write stays
6279+ * comfortably below the trigger threshold. */
6280+ ssl_c -> keys .sequence_number_hi = limit_hi ;
6281+ ssl_c -> keys .sequence_number_lo = limit_lo - 2 ;
6282+ ssl_s -> keys .peer_sequence_number_hi = limit_hi ;
6283+ ssl_s -> keys .peer_sequence_number_lo = limit_lo - 2 ;
6284+ }
6285+
6286+ /* First write: below the limit, no KeyUpdate expected. */
6287+ written = wolfSSL_write (ssl_c , msg , (int )sizeof (msg ));
6288+ ExpectIntEQ (written , (int )sizeof (msg ));
6289+
6290+ if (EXPECT_SUCCESS () && ssl_c != NULL ) {
6291+ /* The record bumped the counter from limit-2 to limit-1. A
6292+ * KeyUpdate would have zeroed it via SetKeysSide and bumped to 1. */
6293+ ExpectIntEQ ((int )ssl_c -> keys .sequence_number_hi , (int )limit_hi );
6294+ ExpectIntEQ (ssl_c -> keys .sequence_number_lo , limit_lo - 1 );
6295+ }
6296+
6297+ /* Server consumes the below-limit record with its existing keys. */
6298+ XMEMSET (buf , 0 , sizeof (buf ));
6299+ ExpectIntEQ (wolfSSL_read (ssl_s , buf , (int )sizeof (buf )), (int )sizeof (msg ));
6300+ ExpectIntEQ (XMEMCMP (buf , msg , sizeof (msg )), 0 );
6301+
6302+ /* Second write: the client's counter is now at limit-1. Sending this
6303+ * record will push it to limit, at which point the trailing check
6304+ * inside SendData's loop fires SendTls13KeyUpdate. No manual counter
6305+ * adjustment is needed -- the counter is allowed to "naturally" reach
6306+ * the limit through the previous send. */
6307+ written = wolfSSL_write (ssl_c , msg , (int )sizeof (msg ));
6308+ ExpectIntEQ (written , (int )sizeof (msg ));
6309+
6310+ if (EXPECT_SUCCESS () && ssl_c != NULL ) {
6311+ /* SendTls13KeyUpdate -> DeriveTls13Keys -> SetKeysSide zeroes the
6312+ * encrypt sequence number. The user record went out before the
6313+ * trigger fired, so no record was sent on the new keys. */
6314+ ExpectIntEQ ((int )ssl_c -> keys .sequence_number_hi , 0 );
6315+ ExpectIntEQ ((int )ssl_c -> keys .sequence_number_lo , 0 );
6316+ }
6317+
6318+ /* The server reads the user record (sent under the pre-update keys at
6319+ * seq = limit - 1) before it sees the KeyUpdate record. The KeyUpdate
6320+ * is consumed transparently on a subsequent read; for the test we just
6321+ * need to confirm the user data round-trips. */
6322+ XMEMSET (buf , 0 , sizeof (buf ));
6323+ {
6324+ int r = -1 , attempts ;
6325+ for (attempts = 0 ; attempts < 5 ; attempts ++ ) {
6326+ r = wolfSSL_read (ssl_s , buf , (int )sizeof (buf ));
6327+ if (r > 0 )
6328+ break ;
6329+ if (wolfSSL_get_error (ssl_s , r ) != WOLFSSL_ERROR_WANT_READ )
6330+ break ;
6331+ }
6332+ ExpectIntEQ (r , (int )sizeof (msg ));
6333+ }
6334+ ExpectIntEQ (XMEMCMP (buf , msg , sizeof (msg )), 0 );
6335+
6336+ wolfSSL_free (ssl_c );
6337+ wolfSSL_free (ssl_s );
6338+ wolfSSL_CTX_free (ctx_c );
6339+ wolfSSL_CTX_free (ctx_s );
6340+
6341+ return EXPECT_RESULT ();
6342+ }
6343+ #endif
6344+
6345+ int test_tls13_AEAD_limit_KU_aes128_gcm_sha256 (void )
6346+ {
6347+ EXPECT_DECLS ;
6348+ #if defined(WOLFSSL_TLS13 ) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS ) && \
6349+ !defined(NO_WOLFSSL_CLIENT ) && !defined(NO_WOLFSSL_SERVER ) && \
6350+ defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && \
6351+ defined(BUILD_TLS_AES_128_GCM_SHA256 )
6352+ ExpectIntEQ (test_tls13_AEAD_limit_triggers_KeyUpdate_cs (
6353+ "TLS13-AES128-GCM-SHA256" , 0 , 0x016A09E6 , wolfssl_aes_gcm ),
6354+ TEST_SUCCESS );
6355+ #endif
6356+ return EXPECT_RESULT ();
6357+ }
6358+
6359+ int test_tls13_AEAD_limit_KU_aes256_gcm_sha384 (void )
6360+ {
6361+ EXPECT_DECLS ;
6362+ #if defined(WOLFSSL_TLS13 ) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS ) && \
6363+ !defined(NO_WOLFSSL_CLIENT ) && !defined(NO_WOLFSSL_SERVER ) && \
6364+ defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && \
6365+ defined(BUILD_TLS_AES_256_GCM_SHA384 )
6366+ ExpectIntEQ (test_tls13_AEAD_limit_triggers_KeyUpdate_cs (
6367+ "TLS13-AES256-GCM-SHA384" , 0 , 0x016A09E6 , wolfssl_aes_gcm ),
6368+ TEST_SUCCESS );
6369+ #endif
6370+ return EXPECT_RESULT ();
6371+ }
6372+
6373+ int test_tls13_AEAD_limit_KU_aes128_ccm_sha256 (void )
6374+ {
6375+ EXPECT_DECLS ;
6376+ #if defined(WOLFSSL_TLS13 ) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS ) && \
6377+ !defined(NO_WOLFSSL_CLIENT ) && !defined(NO_WOLFSSL_SERVER ) && \
6378+ defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && \
6379+ defined(BUILD_TLS_AES_128_CCM_SHA256 )
6380+ ExpectIntEQ (test_tls13_AEAD_limit_triggers_KeyUpdate_cs (
6381+ "TLS13-AES128-CCM-SHA256" , 0 , 0x016A09E6 , wolfssl_aes_ccm ),
6382+ TEST_SUCCESS );
6383+ #endif
6384+ return EXPECT_RESULT ();
6385+ }
6386+
6387+ int test_tls13_AEAD_limit_KU_aes128_ccm_8_sha256 (void )
6388+ {
6389+ EXPECT_DECLS ;
6390+ #if defined(WOLFSSL_TLS13 ) && !defined(WOLFSSL_TLS13_IGNORE_AEAD_LIMITS ) && \
6391+ !defined(NO_WOLFSSL_CLIENT ) && !defined(NO_WOLFSSL_SERVER ) && \
6392+ defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && \
6393+ defined(BUILD_TLS_AES_128_CCM_8_SHA256 )
6394+ ExpectIntEQ (test_tls13_AEAD_limit_triggers_KeyUpdate_cs (
6395+ "TLS13-AES128-CCM-8-SHA256" , 0 , 0x016A09E6 , wolfssl_aes_ccm ),
6396+ TEST_SUCCESS );
6397+ #endif
6398+ return EXPECT_RESULT ();
6399+ }
6400+
0 commit comments