Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions tests/api/test_ecc.c
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,58 @@ int test_wc_ecc_import_x963(void)
return EXPECT_RESULT();
} /* END wc_ecc_import_x963 */

/*
* testing wc_ecc_import_x963() rejects an off-curve public point.
*
* Regression coverage for the invalid-curve attack: the legacy wrapper
* wc_ecc_import_x963_ex (called by wc_ecc_import_x963()) must pass untrusted=1
* to wc_ecc_import_x963_ex2 so that ECIES, PKCS#7 KARI, and EVP ECDH callers
* validate that the imported point actually lies on the curve. Without that,
* an attacker can feed a point from a weak twist and leak the victim's private
* scalar modulo small primes (Biehl-Meyer-Mueller).
Comment thread
Frauschi marked this conversation as resolved.
*/
int test_wc_ecc_import_x963_off_curve(void)
{
EXPECT_DECLS;
#if defined(HAVE_ECC) && defined(HAVE_ECC_KEY_IMPORT) && \
!defined(NO_ECC256) && !defined(NO_ECC_SECP) && \
(!defined(HAVE_FIPS) || FIPS_VERSION_GE(7,0)) && !defined(HAVE_SELFTEST)
ecc_key pubKey;
/* Uncompressed X9.63 P-256 point: 0x04 || Gx || Gy with the last byte
* of Gy flipped by 1. Gx/Gy are the NIST P-256 generator coordinates;
* modifying a single bit of Gy produces a point that is not on the
* curve, so wc_ecc_import_x963 must reject it. */
static const byte offCurveX963[] = {
0x04,
0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47,
0xF8, 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40, 0xF2,
0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0,
0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, 0x96,
0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B,
0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16,
0x2B, 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, 0xCE,
0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF4
};

XMEMSET(&pubKey, 0, sizeof(ecc_key));

ExpectIntEQ(wc_ecc_init(&pubKey), 0);

/* Importing an off-curve point must fail. wc_ecc_import_x963() calls
* wc_ecc_import_x963_ex() which ultimately calls wc_ecc_import_x963_ex2()
* with the required untrusted=1 flag. */
ExpectIntNE(wc_ecc_import_x963(offCurveX963, (word32)sizeof(offCurveX963),
&pubKey), 0);
Comment thread
Frauschi marked this conversation as resolved.

wc_ecc_free(&pubKey);

#ifdef FP_ECC
wc_ecc_fp_free();
#endif
#endif
return EXPECT_RESULT();
} /* END test_wc_ecc_import_x963_off_curve */

/*
* testing wc_ecc_import_private_key()
*/
Expand Down
2 changes: 2 additions & 0 deletions tests/api/test_ecc.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ int test_wc_ecc_shared_secret(void);
int test_wc_ecc_export_x963(void);
int test_wc_ecc_export_x963_ex(void);
int test_wc_ecc_import_x963(void);
int test_wc_ecc_import_x963_off_curve(void);
int test_wc_ecc_import_private_key(void);
int test_wc_ecc_export_private_only(void);
int test_wc_ecc_rs_to_sig(void);
Expand Down Expand Up @@ -76,6 +77,7 @@ int test_wc_EccPrivateKeyToDer(void);
TEST_DECL_GROUP("ecc", test_wc_ecc_export_x963), \
TEST_DECL_GROUP("ecc", test_wc_ecc_export_x963_ex), \
TEST_DECL_GROUP("ecc", test_wc_ecc_import_x963), \
TEST_DECL_GROUP("ecc", test_wc_ecc_import_x963_off_curve), \
TEST_DECL_GROUP("ecc", test_wc_ecc_import_private_key), \
TEST_DECL_GROUP("ecc", test_wc_ecc_export_private_only), \
TEST_DECL_GROUP("ecc", test_wc_ecc_rs_to_sig), \
Expand Down
3 changes: 2 additions & 1 deletion wolfcrypt/src/ecc.c
Original file line number Diff line number Diff line change
Expand Up @@ -11226,7 +11226,8 @@ int wc_ecc_import_x963_ex2(const byte* in, word32 inLen, ecc_key* key,
int wc_ecc_import_x963_ex(const byte* in, word32 inLen, ecc_key* key,
int curve_id)
{
return wc_ecc_import_x963_ex2(in, inLen, key, curve_id, 0);
/* treat as untrusted: validate the point is on the curve */
return wc_ecc_import_x963_ex2(in, inLen, key, curve_id, 1);
}

WOLFSSL_ABI
Expand Down
Loading