@@ -772,6 +772,71 @@ int test_wc_ecc_import_x963(void)
772772 return EXPECT_RESULT ();
773773} /* END wc_ecc_import_x963 */
774774
775+ /*
776+ * testing wc_ecc_import_x963() rejects an off-curve public point.
777+ *
778+ * Regression coverage for the invalid-curve attack: the legacy wrapper
779+ * wc_ecc_import_x963_ex must pass untrusted=1 to wc_ecc_import_x963_ex2
780+ * so that ECIES, PKCS#7 KARI, and EVP ECDH callers validate that the
781+ * imported point actually lies on the curve. Without that, an attacker
782+ * can feed a point from a weak twist and leak the victim's private
783+ * scalar modulo small primes (Biehl-Meyer-Müller).
784+ */
785+ int test_wc_ecc_import_x963_off_curve (void )
786+ {
787+ EXPECT_DECLS ;
788+ #if defined(HAVE_ECC ) && defined(HAVE_ECC_KEY_IMPORT ) && \
789+ defined(HAVE_ECC_KEY_EXPORT ) && !defined(WC_NO_RNG ) && \
790+ !defined(NO_ECC256 ) && !defined(NO_ECC_SECP )
791+ ecc_key key ;
792+ ecc_key pubKey ;
793+ WC_RNG rng ;
794+ byte x963 [ECC_ASN963_MAX_BUF_SZ ];
795+ word32 x963Len = (word32 )sizeof (x963 );
796+ int ret ;
797+
798+ XMEMSET (& key , 0 , sizeof (ecc_key ));
799+ XMEMSET (& pubKey , 0 , sizeof (ecc_key ));
800+ XMEMSET (& rng , 0 , sizeof (WC_RNG ));
801+ XMEMSET (x963 , 0 , x963Len );
802+
803+ ExpectIntEQ (wc_ecc_init (& key ), 0 );
804+ ExpectIntEQ (wc_ecc_init (& pubKey ), 0 );
805+ ExpectIntEQ (wc_InitRng (& rng ), 0 );
806+
807+ /* Generate a valid P-256 key pair and export in X9.63 format. */
808+ ret = wc_ecc_make_key_ex (& rng , 32 , & key , ECC_SECP256R1 );
809+ #if defined(WOLFSSL_ASYNC_CRYPT )
810+ ret = wc_AsyncWait (ret , & key .asyncDev , WC_ASYNC_FLAG_NONE );
811+ #endif
812+ ExpectIntEQ (ret , 0 );
813+
814+ PRIVATE_KEY_UNLOCK ();
815+ ExpectIntEQ (wc_ecc_export_x963 (& key , x963 , & x963Len ), 0 );
816+ PRIVATE_KEY_LOCK ();
817+
818+ /* X9.63 uncompressed form is 0x04 || X || Y. Flipping a single bit
819+ * in Y yields a point that is no longer on the curve with
820+ * overwhelming probability. */
821+ ExpectIntEQ (x963Len , 1 + 2 * 32 );
822+ if (x963Len == 1 + 2 * 32 ) {
823+ x963 [x963Len - 1 ] ^= 0x01 ;
824+ }
825+
826+ /* Importing an off-curve point must fail. */
827+ ExpectIntNE (wc_ecc_import_x963 (x963 , x963Len , & pubKey ), 0 );
828+
829+ DoExpectIntEQ (wc_FreeRng (& rng ), 0 );
830+ wc_ecc_free (& pubKey );
831+ wc_ecc_free (& key );
832+
833+ #ifdef FP_ECC
834+ wc_ecc_fp_free ();
835+ #endif
836+ #endif
837+ return EXPECT_RESULT ();
838+ } /* END test_wc_ecc_import_x963_off_curve */
839+
775840/*
776841 * testing wc_ecc_import_private_key()
777842 */
0 commit comments