@@ -690,6 +690,258 @@ 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+ int i ;
728+
729+ /* Use non-repeating pattern to detect hash truncation bugs */
730+ for (i = 0 ; i < WH_TEST_ECC_HASH_SIZE ; i ++ ) {
731+ hash [i ] = (uint8_t )i ;
732+ }
733+
734+ WH_TEST_PRINT (" Testing %s curve...\n" , name );
735+
736+ pubXLen = keySize ;
737+ pubYLen = keySize ;
738+
739+ /* Test 1: HSM sign + Software verify */
740+ ret = wc_ecc_init_ex (hsmKey , NULL , WH_DEV_ID );
741+ if (ret != 0 ) {
742+ WH_ERROR_PRINT ("%s: Failed to init HSM key: %d\n" , name , ret );
743+ }
744+ else {
745+ hsmKeyInit = 1 ;
746+ }
747+ if (ret == 0 ) {
748+ ret = wc_ecc_make_key (rng , keySize , hsmKey );
749+ if (ret != 0 ) {
750+ WH_ERROR_PRINT ("%s: Failed to generate HSM key: %d\n" , name , ret );
751+ }
752+ }
753+ if (ret == 0 ) {
754+ /* Export public key from HSM */
755+ ret = wc_ecc_export_public_raw (hsmKey , pubX , & pubXLen , pubY , & pubYLen );
756+ if (ret != 0 ) {
757+ WH_ERROR_PRINT ("%s: Failed to export HSM public key: %d\n" , name ,
758+ ret );
759+ }
760+ }
761+ if (ret == 0 ) {
762+ /* Sign with HSM */
763+ sigLen = sizeof (sig );
764+ ret = wc_ecc_sign_hash (hash , sizeof (hash ), sig , & sigLen , rng , hsmKey );
765+ if (ret != 0 ) {
766+ WH_ERROR_PRINT ("%s: HSM sign failed: %d\n" , name , ret );
767+ }
768+ }
769+ if (ret == 0 ) {
770+ /* Import public key into software key for verification */
771+ ret = wc_ecc_init_ex (swKey , NULL , INVALID_DEVID );
772+ if (ret != 0 ) {
773+ WH_ERROR_PRINT ("%s: Failed to init SW key: %d\n" , name , ret );
774+ }
775+ else {
776+ swKeyInit = 1 ;
777+ }
778+ }
779+ if (ret == 0 ) {
780+ ret = wc_ecc_import_unsigned (swKey , pubX , pubY , NULL , curveId );
781+ if (ret != 0 ) {
782+ WH_ERROR_PRINT ("%s: Failed to import public to SW: %d\n" , name ,
783+ ret );
784+ }
785+ }
786+ if (ret == 0 ) {
787+ /* Verify with software */
788+ res = 0 ;
789+ ret = wc_ecc_verify_hash (sig , sigLen , hash , sizeof (hash ), & res , swKey );
790+ if (ret != 0 ) {
791+ WH_ERROR_PRINT ("%s: SW verify failed: %d\n" , name , ret );
792+ }
793+ else if (res != 1 ) {
794+ WH_ERROR_PRINT ("%s: HSM sign + SW verify: signature invalid\n" ,
795+ name );
796+ ret = -1 ;
797+ }
798+ else {
799+ WH_TEST_PRINT (" HSM sign + SW verify: PASS\n" );
800+ }
801+ }
802+ /* Cleanup Test 1 keys */
803+ if (swKeyInit ) {
804+ wc_ecc_free (swKey );
805+ swKeyInit = 0 ;
806+ }
807+ if (hsmKeyInit ) {
808+ if (wh_Client_EccGetKeyId (hsmKey , & keyId ) == 0 &&
809+ !WH_KEYID_ISERASED (keyId )) {
810+ (void )wh_Client_KeyEvict (ctx , keyId );
811+ }
812+ wc_ecc_free (hsmKey );
813+ hsmKeyInit = 0 ;
814+ }
815+
816+ /* Test 2: Software sign + HSM verify */
817+ if (ret == 0 ) {
818+ memset (sig , 0 , sizeof (sig ));
819+ memset (pubX , 0 , sizeof (pubX ));
820+ memset (pubY , 0 , sizeof (pubY ));
821+ pubXLen = keySize ;
822+ pubYLen = keySize ;
823+ keyId = WH_KEYID_ERASED ;
824+
825+ ret = wc_ecc_init_ex (swKey , NULL , INVALID_DEVID );
826+ if (ret != 0 ) {
827+ WH_ERROR_PRINT ("%s: Failed to init SW key: %d\n" , name , ret );
828+ }
829+ else {
830+ swKeyInit = 1 ;
831+ }
832+ }
833+ if (ret == 0 ) {
834+ ret = wc_ecc_make_key (rng , keySize , swKey );
835+ if (ret != 0 ) {
836+ WH_ERROR_PRINT ("%s: Failed to generate SW key: %d\n" , name , ret );
837+ }
838+ }
839+ if (ret == 0 ) {
840+ /* Export public key from software */
841+ ret = wc_ecc_export_public_raw (swKey , pubX , & pubXLen , pubY , & pubYLen );
842+ if (ret != 0 ) {
843+ WH_ERROR_PRINT ("%s: Failed to export SW public key: %d\n" , name ,
844+ ret );
845+ }
846+ }
847+ if (ret == 0 ) {
848+ /* Sign with software */
849+ sigLen = sizeof (sig );
850+ ret = wc_ecc_sign_hash (hash , sizeof (hash ), sig , & sigLen , rng , swKey );
851+ if (ret != 0 ) {
852+ WH_ERROR_PRINT ("%s: SW sign failed: %d\n" , name , ret );
853+ }
854+ }
855+ if (ret == 0 ) {
856+ /* Import public key into HSM key for verification */
857+ ret = wc_ecc_init_ex (hsmKey , NULL , WH_DEV_ID );
858+ if (ret != 0 ) {
859+ WH_ERROR_PRINT ("%s: Failed to init HSM key: %d\n" , name , ret );
860+ }
861+ else {
862+ hsmKeyInit = 1 ;
863+ }
864+ }
865+ if (ret == 0 ) {
866+ ret = wc_ecc_import_unsigned (hsmKey , pubX , pubY , NULL , curveId );
867+ if (ret != 0 ) {
868+ WH_ERROR_PRINT ("%s: Failed to import public to HSM: %d\n" , name ,
869+ ret );
870+ }
871+ }
872+ if (ret == 0 ) {
873+ /* Verify with HSM */
874+ res = 0 ;
875+ ret = wc_ecc_verify_hash (sig , sigLen , hash , sizeof (hash ), & res , hsmKey );
876+ if (ret != 0 ) {
877+ WH_ERROR_PRINT ("%s: HSM verify failed: %d\n" , name , ret );
878+ }
879+ else if (res != 1 ) {
880+ WH_ERROR_PRINT ("%s: SW sign + HSM verify: signature invalid\n" ,
881+ name );
882+ ret = -1 ;
883+ }
884+ else {
885+ WH_TEST_PRINT (" SW sign + HSM verify: PASS\n" );
886+ }
887+ }
888+ /* Cleanup Test 2 keys */
889+ if (hsmKeyInit ) {
890+ if (wh_Client_EccGetKeyId (hsmKey , & keyId ) == 0 &&
891+ !WH_KEYID_ISERASED (keyId )) {
892+ (void )wh_Client_KeyEvict (ctx , keyId );
893+ }
894+ wc_ecc_free (hsmKey );
895+ }
896+ if (swKeyInit ) {
897+ wc_ecc_free (swKey );
898+ }
899+
900+ return ret ;
901+ }
902+
903+ /**
904+ * Test ECDSA cross-verification between HSM and software implementations.
905+ * This detects bugged hardware that might verify its own bad signatures.
906+ *
907+ * Tests two scenarios per curve:
908+ * 1. HSM sign + Software verify
909+ * 2. Software sign + HSM verify
910+ */
911+ static int whTest_CryptoEccCrossVerify (whClientContext * ctx , WC_RNG * rng )
912+ {
913+ int ret = WH_ERROR_OK ;
914+
915+ WH_TEST_PRINT ("Testing ECDSA cross-verification (HSM<->SW)...\n" );
916+
917+ #if !defined(NO_ECC256 )
918+ if (ret == 0 ) {
919+ ret = whTest_CryptoEccCrossVerify_OneCurve (
920+ ctx , rng , WH_TEST_ECC_P256_KEY_SIZE , ECC_SECP256R1 , "P-256" );
921+ }
922+ #endif
923+
924+ #if (defined(HAVE_ECC384 ) || defined(HAVE_ALL_CURVES )) && ECC_MIN_KEY_SZ <= 384
925+ if (ret == 0 ) {
926+ ret = whTest_CryptoEccCrossVerify_OneCurve (
927+ ctx , rng , WH_TEST_ECC_P384_KEY_SIZE , ECC_SECP384R1 , "P-384" );
928+ }
929+ #endif
930+
931+ #if (defined(HAVE_ECC521 ) || defined(HAVE_ALL_CURVES )) && ECC_MIN_KEY_SZ <= 521
932+ if (ret == 0 ) {
933+ ret = whTest_CryptoEccCrossVerify_OneCurve (
934+ ctx , rng , WH_TEST_ECC_P521_KEY_SIZE , ECC_SECP521R1 , "P-521" );
935+ }
936+ #endif
937+
938+ if (ret == 0 ) {
939+ WH_TEST_PRINT ("ECDSA cross-verification SUCCESS\n" );
940+ }
941+
942+ return ret ;
943+ }
944+ #endif /* HAVE_ECC_SIGN && HAVE_ECC_VERIFY && !WOLF_CRYPTO_CB_ONLY_ECC */
693945#endif /* HAVE_ECC */
694946
695947#ifdef HAVE_ED25519
@@ -5146,6 +5398,12 @@ int whTest_CryptoClientConfig(whClientConfig* config)
51465398 if (ret == 0 ) {
51475399 ret = whTest_CryptoEccCacheDuplicate (client );
51485400 }
5401+ #if defined(HAVE_ECC_SIGN ) && defined(HAVE_ECC_VERIFY ) && \
5402+ !defined(WOLF_CRYPTO_CB_ONLY_ECC )
5403+ if (ret == 0 ) {
5404+ ret = whTest_CryptoEccCrossVerify (client , rng );
5405+ }
5406+ #endif
51495407#endif /* HAVE_ECC */
51505408
51515409#ifdef HAVE_ED25519
0 commit comments