@@ -690,6 +690,257 @@ static int whTest_CryptoEccCacheDuplicate(whClientContext* client)
690690
691691 return ret ;
692692}
693+
694+ #if defined(HAVE_ECC_SIGN ) && defined(HAVE_ECC_VERIFY ) && \
695+ !defined(WOLF_CRYPTO_CB_ONLY_ECC )
696+
697+ /* Key sizes in bytes for each curve */
698+ #define WH_TEST_ECC_P256_KEY_SIZE 32
699+ #define WH_TEST_ECC_P384_KEY_SIZE 48
700+ #define WH_TEST_ECC_P521_KEY_SIZE 66
701+
702+ /* Use maximum digest size for all curves to test hash truncation edge cases.
703+ * ECDSA implementations must properly truncate hashes larger than the curve
704+ * order. */
705+ #define WH_TEST_ECC_HASH_SIZE WC_MAX_DIGEST_SIZE
706+
707+ static int whTest_CryptoEccCrossVerify_OneCurve (whClientContext * ctx ,
708+ WC_RNG * rng ,
709+ int keySize ,
710+ int curveId ,
711+ const char * name )
712+ {
713+ ecc_key hsmKey [1 ] = {0 };
714+ ecc_key swKey [1 ] = {0 };
715+ uint8_t hash [WH_TEST_ECC_HASH_SIZE ] = {0 };
716+ uint8_t sig [ECC_MAX_SIG_SIZE ] = {0 };
717+ uint8_t pubX [ECC_MAXSIZE ] = {0 };
718+ uint8_t pubY [ECC_MAXSIZE ] = {0 };
719+ word32 pubXLen = 0 ;
720+ word32 pubYLen = 0 ;
721+ word32 sigLen = 0 ;
722+ int res = 0 ;
723+ whKeyId keyId = WH_KEYID_ERASED ;
724+ int hsmKeyInit = 0 ;
725+ int swKeyInit = 0 ;
726+ int ret = WH_ERROR_OK ;
727+
728+ /* Use non-repeating pattern to detect hash truncation bugs */
729+ for (int i = 0 ; i < WH_TEST_ECC_HASH_SIZE ; i ++ ) {
730+ hash [i ] = (uint8_t )i ;
731+ }
732+
733+ WH_TEST_PRINT (" Testing %s curve...\n" , name );
734+
735+ pubXLen = keySize ;
736+ pubYLen = keySize ;
737+
738+ /* Test 1: HSM sign + Software verify */
739+ ret = wc_ecc_init_ex (hsmKey , NULL , WH_DEV_ID );
740+ if (ret != 0 ) {
741+ WH_ERROR_PRINT ("%s: Failed to init HSM key: %d\n" , name , ret );
742+ }
743+ else {
744+ hsmKeyInit = 1 ;
745+ }
746+ if (ret == 0 ) {
747+ ret = wc_ecc_make_key (rng , keySize , hsmKey );
748+ if (ret != 0 ) {
749+ WH_ERROR_PRINT ("%s: Failed to generate HSM key: %d\n" , name , ret );
750+ }
751+ }
752+ if (ret == 0 ) {
753+ /* Export public key from HSM */
754+ ret = wc_ecc_export_public_raw (hsmKey , pubX , & pubXLen , pubY , & pubYLen );
755+ if (ret != 0 ) {
756+ WH_ERROR_PRINT ("%s: Failed to export HSM public key: %d\n" , name ,
757+ ret );
758+ }
759+ }
760+ if (ret == 0 ) {
761+ /* Sign with HSM */
762+ sigLen = sizeof (sig );
763+ ret = wc_ecc_sign_hash (hash , sizeof (hash ), sig , & sigLen , rng , hsmKey );
764+ if (ret != 0 ) {
765+ WH_ERROR_PRINT ("%s: HSM sign failed: %d\n" , name , ret );
766+ }
767+ }
768+ if (ret == 0 ) {
769+ /* Import public key into software key for verification */
770+ ret = wc_ecc_init_ex (swKey , NULL , INVALID_DEVID );
771+ if (ret != 0 ) {
772+ WH_ERROR_PRINT ("%s: Failed to init SW key: %d\n" , name , ret );
773+ }
774+ else {
775+ swKeyInit = 1 ;
776+ }
777+ }
778+ if (ret == 0 ) {
779+ ret = wc_ecc_import_unsigned (swKey , pubX , pubY , NULL , curveId );
780+ if (ret != 0 ) {
781+ WH_ERROR_PRINT ("%s: Failed to import public to SW: %d\n" , name ,
782+ ret );
783+ }
784+ }
785+ if (ret == 0 ) {
786+ /* Verify with software */
787+ res = 0 ;
788+ ret = wc_ecc_verify_hash (sig , sigLen , hash , sizeof (hash ), & res , swKey );
789+ if (ret != 0 ) {
790+ WH_ERROR_PRINT ("%s: SW verify failed: %d\n" , name , ret );
791+ }
792+ else if (res != 1 ) {
793+ WH_ERROR_PRINT ("%s: HSM sign + SW verify: signature invalid\n" ,
794+ name );
795+ ret = -1 ;
796+ }
797+ else {
798+ WH_TEST_PRINT (" HSM sign + SW verify: PASS\n" );
799+ }
800+ }
801+ /* Cleanup Test 1 keys */
802+ if (swKeyInit ) {
803+ wc_ecc_free (swKey );
804+ swKeyInit = 0 ;
805+ }
806+ if (hsmKeyInit ) {
807+ if (wh_Client_EccGetKeyId (hsmKey , & keyId ) == 0 &&
808+ !WH_KEYID_ISERASED (keyId )) {
809+ (void )wh_Client_KeyEvict (ctx , keyId );
810+ }
811+ wc_ecc_free (hsmKey );
812+ hsmKeyInit = 0 ;
813+ }
814+
815+ /* Test 2: Software sign + HSM verify */
816+ if (ret == 0 ) {
817+ memset (sig , 0 , sizeof (sig ));
818+ memset (pubX , 0 , sizeof (pubX ));
819+ memset (pubY , 0 , sizeof (pubY ));
820+ pubXLen = keySize ;
821+ pubYLen = keySize ;
822+ keyId = WH_KEYID_ERASED ;
823+
824+ ret = wc_ecc_init_ex (swKey , NULL , INVALID_DEVID );
825+ if (ret != 0 ) {
826+ WH_ERROR_PRINT ("%s: Failed to init SW key: %d\n" , name , ret );
827+ }
828+ else {
829+ swKeyInit = 1 ;
830+ }
831+ }
832+ if (ret == 0 ) {
833+ ret = wc_ecc_make_key (rng , keySize , swKey );
834+ if (ret != 0 ) {
835+ WH_ERROR_PRINT ("%s: Failed to generate SW key: %d\n" , name , ret );
836+ }
837+ }
838+ if (ret == 0 ) {
839+ /* Export public key from software */
840+ ret = wc_ecc_export_public_raw (swKey , pubX , & pubXLen , pubY , & pubYLen );
841+ if (ret != 0 ) {
842+ WH_ERROR_PRINT ("%s: Failed to export SW public key: %d\n" , name ,
843+ ret );
844+ }
845+ }
846+ if (ret == 0 ) {
847+ /* Sign with software */
848+ sigLen = sizeof (sig );
849+ ret = wc_ecc_sign_hash (hash , sizeof (hash ), sig , & sigLen , rng , swKey );
850+ if (ret != 0 ) {
851+ WH_ERROR_PRINT ("%s: SW sign failed: %d\n" , name , ret );
852+ }
853+ }
854+ if (ret == 0 ) {
855+ /* Import public key into HSM key for verification */
856+ ret = wc_ecc_init_ex (hsmKey , NULL , WH_DEV_ID );
857+ if (ret != 0 ) {
858+ WH_ERROR_PRINT ("%s: Failed to init HSM key: %d\n" , name , ret );
859+ }
860+ else {
861+ hsmKeyInit = 1 ;
862+ }
863+ }
864+ if (ret == 0 ) {
865+ ret = wc_ecc_import_unsigned (hsmKey , pubX , pubY , NULL , curveId );
866+ if (ret != 0 ) {
867+ WH_ERROR_PRINT ("%s: Failed to import public to HSM: %d\n" , name ,
868+ ret );
869+ }
870+ }
871+ if (ret == 0 ) {
872+ /* Verify with HSM */
873+ res = 0 ;
874+ ret = wc_ecc_verify_hash (sig , sigLen , hash , sizeof (hash ), & res , hsmKey );
875+ if (ret != 0 ) {
876+ WH_ERROR_PRINT ("%s: HSM verify failed: %d\n" , name , ret );
877+ }
878+ else if (res != 1 ) {
879+ WH_ERROR_PRINT ("%s: SW sign + HSM verify: signature invalid\n" ,
880+ name );
881+ ret = -1 ;
882+ }
883+ else {
884+ WH_TEST_PRINT (" SW sign + HSM verify: PASS\n" );
885+ }
886+ }
887+ /* Cleanup Test 2 keys */
888+ if (hsmKeyInit ) {
889+ if (wh_Client_EccGetKeyId (hsmKey , & keyId ) == 0 &&
890+ !WH_KEYID_ISERASED (keyId )) {
891+ (void )wh_Client_KeyEvict (ctx , keyId );
892+ }
893+ wc_ecc_free (hsmKey );
894+ }
895+ if (swKeyInit ) {
896+ wc_ecc_free (swKey );
897+ }
898+
899+ return ret ;
900+ }
901+
902+ /**
903+ * Test ECDSA cross-verification between HSM and software implementations.
904+ * This detects bugged hardware that might verify its own bad signatures.
905+ *
906+ * Tests two scenarios per curve:
907+ * 1. HSM sign + Software verify
908+ * 2. Software sign + HSM verify
909+ */
910+ static int whTest_CryptoEccCrossVerify (whClientContext * ctx , WC_RNG * rng )
911+ {
912+ int ret = WH_ERROR_OK ;
913+
914+ WH_TEST_PRINT ("Testing ECDSA cross-verification (HSM<->SW)...\n" );
915+
916+ #if !defined(NO_ECC256 )
917+ if (ret == 0 ) {
918+ ret = whTest_CryptoEccCrossVerify_OneCurve (
919+ ctx , rng , WH_TEST_ECC_P256_KEY_SIZE , ECC_SECP256R1 , "P-256" );
920+ }
921+ #endif
922+
923+ #if (defined(HAVE_ECC384 ) || defined(HAVE_ALL_CURVES )) && ECC_MIN_KEY_SZ <= 384
924+ if (ret == 0 ) {
925+ ret = whTest_CryptoEccCrossVerify_OneCurve (
926+ ctx , rng , WH_TEST_ECC_P384_KEY_SIZE , ECC_SECP384R1 , "P-384" );
927+ }
928+ #endif
929+
930+ #if (defined(HAVE_ECC521 ) || defined(HAVE_ALL_CURVES )) && ECC_MIN_KEY_SZ <= 521
931+ if (ret == 0 ) {
932+ ret = whTest_CryptoEccCrossVerify_OneCurve (
933+ ctx , rng , WH_TEST_ECC_P521_KEY_SIZE , ECC_SECP521R1 , "P-521" );
934+ }
935+ #endif
936+
937+ if (ret == 0 ) {
938+ WH_TEST_PRINT ("ECDSA cross-verification SUCCESS\n" );
939+ }
940+
941+ return ret ;
942+ }
943+ #endif /* HAVE_ECC_SIGN && HAVE_ECC_VERIFY && !WOLF_CRYPTO_CB_ONLY_ECC */
693944#endif /* HAVE_ECC */
694945
695946#ifdef HAVE_ED25519
@@ -5146,6 +5397,12 @@ int whTest_CryptoClientConfig(whClientConfig* config)
51465397 if (ret == 0 ) {
51475398 ret = whTest_CryptoEccCacheDuplicate (client );
51485399 }
5400+ #if defined(HAVE_ECC_SIGN ) && defined(HAVE_ECC_VERIFY ) && \
5401+ !defined(WOLF_CRYPTO_CB_ONLY_ECC )
5402+ if (ret == 0 ) {
5403+ ret = whTest_CryptoEccCrossVerify (client , rng );
5404+ }
5405+ #endif
51495406#endif /* HAVE_ECC */
51505407
51515408#ifdef HAVE_ED25519
0 commit comments