Skip to content

Commit f3a5676

Browse files
committed
Fix ECC validation regression
1 parent fa9f24f commit f3a5676

File tree

3 files changed

+69
-1
lines changed

3 files changed

+69
-1
lines changed

tests/api/test_ecc.c

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

tests/api/test_ecc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ int test_wc_ecc_shared_secret(void);
3939
int test_wc_ecc_export_x963(void);
4040
int test_wc_ecc_export_x963_ex(void);
4141
int test_wc_ecc_import_x963(void);
42+
int test_wc_ecc_import_x963_off_curve(void);
4243
int test_wc_ecc_import_private_key(void);
4344
int test_wc_ecc_export_private_only(void);
4445
int test_wc_ecc_rs_to_sig(void);
@@ -76,6 +77,7 @@ int test_wc_EccPrivateKeyToDer(void);
7677
TEST_DECL_GROUP("ecc", test_wc_ecc_export_x963), \
7778
TEST_DECL_GROUP("ecc", test_wc_ecc_export_x963_ex), \
7879
TEST_DECL_GROUP("ecc", test_wc_ecc_import_x963), \
80+
TEST_DECL_GROUP("ecc", test_wc_ecc_import_x963_off_curve), \
7981
TEST_DECL_GROUP("ecc", test_wc_ecc_import_private_key), \
8082
TEST_DECL_GROUP("ecc", test_wc_ecc_export_private_only), \
8183
TEST_DECL_GROUP("ecc", test_wc_ecc_rs_to_sig), \

wolfcrypt/src/ecc.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11217,7 +11217,8 @@ int wc_ecc_import_x963_ex2(const byte* in, word32 inLen, ecc_key* key,
1121711217
int wc_ecc_import_x963_ex(const byte* in, word32 inLen, ecc_key* key,
1121811218
int curve_id)
1121911219
{
11220-
return wc_ecc_import_x963_ex2(in, inLen, key, curve_id, 0);
11220+
/* treat as untrusted: validate the point is on the curve */
11221+
return wc_ecc_import_x963_ex2(in, inLen, key, curve_id, 1);
1122111222
}
1122211223

1122311224
WOLFSSL_ABI

0 commit comments

Comments
 (0)