@@ -323,6 +323,138 @@ static int certificate_authorities_server_cb(WOLFSSL *ssl, void *_arg) {
323323}
324324#endif
325325
326+ #if defined(HAVE_TRUSTED_CA ) && !defined(NO_SHA ) && \
327+ defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && \
328+ !defined(NO_WOLFSSL_SERVER ) && !defined(NO_WOLFSSL_CLIENT )
329+ /* Walk the TLSX list to find an extension by type. Avoids calling the
330+ * WOLFSSL_LOCAL TLSX_Find which is not available in shared library builds. */
331+ static TLSX * test_TLSX_find_ext (TLSX * list , TLSX_Type type )
332+ {
333+ while (list ) {
334+ if (list -> type == type )
335+ return list ;
336+ list = list -> next ;
337+ }
338+ return NULL ;
339+ }
340+ #endif
341+
342+ int test_TLSX_TCA_Find (void )
343+ {
344+ EXPECT_DECLS ;
345+ #if defined(HAVE_TRUSTED_CA ) && !defined(NO_SHA ) && \
346+ defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES ) && \
347+ !defined(NO_WOLFSSL_SERVER ) && !defined(NO_WOLFSSL_CLIENT )
348+ /* Two different 20-byte SHA1 ids */
349+ byte id_A [WC_SHA_DIGEST_SIZE ];
350+ byte id_B [WC_SHA_DIGEST_SIZE ];
351+ TLSX * ext ;
352+
353+ XMEMSET (id_A , 0xAA , sizeof (id_A ));
354+ XMEMSET (id_B , 0xBB , sizeof (id_B ));
355+
356+ /* Test 1: Exact match - same type and same id should match */
357+ {
358+ struct test_memio_ctx test_ctx ;
359+ WOLFSSL_CTX * ctx_c = NULL , * ctx_s = NULL ;
360+ WOLFSSL * ssl_c = NULL , * ssl_s = NULL ;
361+
362+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
363+ ExpectIntEQ (test_memio_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c ,
364+ & ssl_s , wolfTLSv1_2_client_method , wolfTLSv1_2_server_method ), 0 );
365+
366+ /* Server has KEY_SHA1 with id_A */
367+ ExpectIntEQ (wolfSSL_UseTrustedCA (ssl_s , WOLFSSL_TRUSTED_CA_KEY_SHA1 ,
368+ id_A , sizeof (id_A )), WOLFSSL_SUCCESS );
369+ /* Client sends KEY_SHA1 with id_A (same) */
370+ ExpectIntEQ (wolfSSL_UseTrustedCA (ssl_c , WOLFSSL_TRUSTED_CA_KEY_SHA1 ,
371+ id_A , sizeof (id_A )), WOLFSSL_SUCCESS );
372+
373+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
374+
375+ /* Server should have found a match and responded */
376+ ext = test_TLSX_find_ext (ssl_c ? ssl_c -> extensions : NULL ,
377+ TLSX_TRUSTED_CA_KEYS );
378+ ExpectNotNull (ext );
379+ if (EXPECT_SUCCESS ())
380+ ExpectIntEQ (ext -> resp , 1 );
381+
382+ wolfSSL_free (ssl_c );
383+ wolfSSL_free (ssl_s );
384+ wolfSSL_CTX_free (ctx_c );
385+ wolfSSL_CTX_free (ctx_s );
386+ }
387+
388+ /* Test 2: Same type, different id - should NOT match.
389+ * This is the key test that exposes the logic bug in TLSX_TCA_Find
390+ * where matching on type alone (without checking id content) causes
391+ * a false positive. */
392+ {
393+ struct test_memio_ctx test_ctx ;
394+ WOLFSSL_CTX * ctx_c = NULL , * ctx_s = NULL ;
395+ WOLFSSL * ssl_c = NULL , * ssl_s = NULL ;
396+
397+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
398+ ExpectIntEQ (test_memio_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c ,
399+ & ssl_s , wolfTLSv1_2_client_method , wolfTLSv1_2_server_method ), 0 );
400+
401+ /* Server has KEY_SHA1 with id_A */
402+ ExpectIntEQ (wolfSSL_UseTrustedCA (ssl_s , WOLFSSL_TRUSTED_CA_KEY_SHA1 ,
403+ id_A , sizeof (id_A )), WOLFSSL_SUCCESS );
404+ /* Client sends KEY_SHA1 with id_B (different!) */
405+ ExpectIntEQ (wolfSSL_UseTrustedCA (ssl_c , WOLFSSL_TRUSTED_CA_KEY_SHA1 ,
406+ id_B , sizeof (id_B )), WOLFSSL_SUCCESS );
407+
408+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
409+
410+ /* Server should NOT have found a match - ids differ */
411+ ext = test_TLSX_find_ext (ssl_c ? ssl_c -> extensions : NULL ,
412+ TLSX_TRUSTED_CA_KEYS );
413+ ExpectNotNull (ext );
414+ if (EXPECT_SUCCESS ())
415+ ExpectIntEQ (ext -> resp , 0 );
416+
417+ wolfSSL_free (ssl_c );
418+ wolfSSL_free (ssl_s );
419+ wolfSSL_CTX_free (ctx_c );
420+ wolfSSL_CTX_free (ctx_s );
421+ }
422+
423+ /* Test 3: PRE_AGREED should match any server entry */
424+ {
425+ struct test_memio_ctx test_ctx ;
426+ WOLFSSL_CTX * ctx_c = NULL , * ctx_s = NULL ;
427+ WOLFSSL * ssl_c = NULL , * ssl_s = NULL ;
428+
429+ XMEMSET (& test_ctx , 0 , sizeof (test_ctx ));
430+ ExpectIntEQ (test_memio_setup (& test_ctx , & ctx_c , & ctx_s , & ssl_c ,
431+ & ssl_s , wolfTLSv1_2_client_method , wolfTLSv1_2_server_method ), 0 );
432+
433+ /* Server has KEY_SHA1 with id_A */
434+ ExpectIntEQ (wolfSSL_UseTrustedCA (ssl_s , WOLFSSL_TRUSTED_CA_KEY_SHA1 ,
435+ id_A , sizeof (id_A )), WOLFSSL_SUCCESS );
436+ /* Client sends PRE_AGREED (no id needed) */
437+ ExpectIntEQ (wolfSSL_UseTrustedCA (ssl_c , WOLFSSL_TRUSTED_CA_PRE_AGREED ,
438+ NULL , 0 ), WOLFSSL_SUCCESS );
439+
440+ ExpectIntEQ (test_memio_do_handshake (ssl_c , ssl_s , 10 , NULL ), 0 );
441+
442+ /* Server should have matched (PRE_AGREED matches anything) */
443+ ext = test_TLSX_find_ext (ssl_c ? ssl_c -> extensions : NULL ,
444+ TLSX_TRUSTED_CA_KEYS );
445+ ExpectNotNull (ext );
446+ if (EXPECT_SUCCESS ())
447+ ExpectIntEQ (ext -> resp , 1 );
448+
449+ wolfSSL_free (ssl_c );
450+ wolfSSL_free (ssl_s );
451+ wolfSSL_CTX_free (ctx_c );
452+ wolfSSL_CTX_free (ctx_s );
453+ }
454+ #endif
455+ return EXPECT_RESULT ();
456+ }
457+
326458int test_certificate_authorities_client_hello (void ) {
327459 EXPECT_DECLS ;
328460#if !defined(NO_WOLFSSL_CLIENT ) && !defined(NO_WOLFSSL_SERVER ) && \
0 commit comments