Skip to content

Commit cc0f943

Browse files
committed
tests: add ecdsa cross validation with software implementation
This also test hash truncation edge cases
1 parent 7eaba42 commit cc0f943

File tree

1 file changed

+257
-0
lines changed

1 file changed

+257
-0
lines changed

test/wh_test_crypto.c

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)