Skip to content

Commit 9347c89

Browse files
authored
Merge pull request #10133 from Frauschi/ecc_curve_validation
Improved ECC curve validation
2 parents ede15b4 + e32e926 commit 9347c89

File tree

7 files changed

+103
-97
lines changed

7 files changed

+103
-97
lines changed

src/pk_ec.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1532,7 +1532,7 @@ int wolfSSL_ECPoint_d2i(const unsigned char *in, unsigned int len,
15321532
ret = 0;
15331533
}
15341534

1535-
/* wolfSSL_EC_POINT_set_affine_coordinates_GFp check that the point is
1535+
/* wolfSSL_EC_POINT_set_affine_coordinates_GFp checks that the point is
15361536
* on the curve. */
15371537
if (ret == 1 && wolfSSL_EC_POINT_set_affine_coordinates_GFp(group,
15381538
point, x, y, NULL) != 1) {
@@ -1544,6 +1544,18 @@ int wolfSSL_ECPoint_d2i(const unsigned char *in, unsigned int len,
15441544
"operations later on.");
15451545
#endif
15461546
}
1547+
#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
1548+
/* Validate that the imported point lies on the curve. The Z!=1 path
1549+
* above validates via set_affine_coordinates_GFp, but for affine
1550+
* imports (Z==1), the common case for uncompressed points, that
1551+
* block is skipped. Check unconditionally so no import path can
1552+
* bypass validation. */
1553+
if (ret == 1 && wolfSSL_EC_POINT_is_on_curve(group,
1554+
(WOLFSSL_EC_POINT *)point, NULL) != 1) {
1555+
WOLFSSL_MSG("wolfSSL_ECPoint_d2i: point not on curve");
1556+
ret = 0;
1557+
}
1558+
#endif
15471559

15481560
if (ret == 1) {
15491561
/* Dump new point. */
@@ -1750,8 +1762,7 @@ WOLFSSL_BIGNUM *wolfSSL_EC_POINT_point2bn(const WOLFSSL_EC_GROUP* group,
17501762
return ret;
17511763
}
17521764

1753-
#if defined(USE_ECC_B_PARAM) && !defined(HAVE_SELFTEST) && \
1754-
(!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
1765+
#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
17551766
/* Check if EC point is on the the curve defined by the EC group.
17561767
*
17571768
* @param [in] group EC group defining curve.
@@ -1792,7 +1803,7 @@ int wolfSSL_EC_POINT_is_on_curve(const WOLFSSL_EC_GROUP *group,
17921803
/* Return boolean of on curve. No error means on curve. */
17931804
return !err;
17941805
}
1795-
#endif /* USE_ECC_B_PARAM && !HAVE_SELFTEST && !(FIPS_VERSION <= 2) */
1806+
#endif /* !HAVE_SELFTEST && !(HAVE_FIPS && FIPS_VERSION <= 2) */
17961807

17971808
#if !defined(WOLFSSL_SP_MATH) && !defined(WOLF_CRYPTO_CB_ONLY_ECC)
17981809
/* Convert Jacobian ordinates to affine.
@@ -1985,8 +1996,7 @@ int wolfSSL_EC_POINT_set_affine_coordinates_GFp(const WOLFSSL_EC_GROUP* group,
19851996
ret = 0;
19861997
}
19871998

1988-
#if defined(USE_ECC_B_PARAM) && !defined(HAVE_SELFTEST) && \
1989-
(!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
1999+
#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
19902000
/* Check that the point is valid. */
19912001
if ((ret == 1) && (wolfSSL_EC_POINT_is_on_curve(group,
19922002
(WOLFSSL_EC_POINT *)point, ctx) != 1)) {

tests/api/test_ecc.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,6 +1314,7 @@ int test_wc_ecc_encryptDecrypt(void)
13141314

13151315
#ifdef WOLFSSL_ECIES_OLD
13161316
tmpKey.dp = cliKey.dp;
1317+
tmpKey.idx = cliKey.idx;
13171318
ExpectIntEQ(wc_ecc_copy_point(&cliKey.pubkey, &tmpKey.pubkey), 0);
13181319
#endif
13191320

@@ -1445,15 +1446,13 @@ int test_wc_ecc_pointFns(void)
14451446

14461447
#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || \
14471448
(defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)))
1448-
#ifdef USE_ECC_B_PARAM
14491449
/* On curve if ret == 0 */
14501450
ExpectIntEQ(wc_ecc_point_is_on_curve(point, idx), 0);
14511451
/* Test bad args. */
14521452
ExpectIntEQ(wc_ecc_point_is_on_curve(NULL, idx),
14531453
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
14541454
ExpectIntEQ(wc_ecc_point_is_on_curve(point, 1000),
14551455
WC_NO_ERR_TRACE(ECC_BAD_ARG_E));
1456-
#endif /* USE_ECC_B_PARAM */
14571456
#endif /* !HAVE_SELFTEST && (!HAVE_FIPS || HAVE_FIPS_VERSION > 2) */
14581457

14591458
/* Free */

tests/api/test_ossl_ec.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -476,8 +476,7 @@ int test_wolfSSL_EC_POINT(void)
476476
/* check if point X coordinate is zero */
477477
ExpectIntEQ(BN_is_zero(new_point->X), 0);
478478

479-
#if defined(USE_ECC_B_PARAM) && !defined(HAVE_SELFTEST) && \
480-
(!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
479+
#if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || FIPS_VERSION_GT(2,0))
481480
ExpectIntEQ(EC_POINT_is_on_curve(group, new_point, ctx), 1);
482481
#endif
483482

wolfcrypt/src/ecc.c

Lines changed: 76 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ Possible ECC enable options:
5050
* SECP160K1 and SECP224K1. These do not work with scalars
5151
* that are the length of the order when the order is
5252
* longer than the prime. Use wc_ecc_fp_free to free cache.
53-
* USE_ECC_B_PARAM: Enable ECC curve B param default: off
54-
* (on for HAVE_COMP_KEY)
5553
* WOLFSSL_ECC_CURVE_STATIC: default off (on for windows)
5654
* For the ECC curve parameters `ecc_set_type` use fixed
5755
* array for hex string
@@ -1519,19 +1517,15 @@ typedef struct ecc_curve_spec {
15191517

15201518
mp_int* prime;
15211519
mp_int* Af;
1522-
#ifdef USE_ECC_B_PARAM
1523-
mp_int* Bf;
1524-
#endif
1520+
mp_int* Bf;
15251521
mp_int* order;
15261522
mp_int* Gx;
15271523
mp_int* Gy;
15281524

15291525
#ifdef ECC_CACHE_CURVE
15301526
mp_int prime_lcl;
15311527
mp_int Af_lcl;
1532-
#ifdef USE_ECC_B_PARAM
1533-
mp_int Bf_lcl;
1534-
#endif
1528+
mp_int Bf_lcl;
15351529
mp_int order_lcl;
15361530
mp_int Gx_lcl;
15371531
mp_int Gy_lcl;
@@ -1551,19 +1545,12 @@ typedef struct ecc_curve_spec {
15511545
#define ECC_CURVE_FIELD_NONE 0x00
15521546
#define ECC_CURVE_FIELD_PRIME 0x01
15531547
#define ECC_CURVE_FIELD_AF 0x02
1554-
#ifdef USE_ECC_B_PARAM
15551548
#define ECC_CURVE_FIELD_BF 0x04
1556-
#endif
15571549
#define ECC_CURVE_FIELD_ORDER 0x08
15581550
#define ECC_CURVE_FIELD_GX 0x10
15591551
#define ECC_CURVE_FIELD_GY 0x20
1560-
#ifdef USE_ECC_B_PARAM
15611552
#define ECC_CURVE_FIELD_ALL 0x3F
15621553
#define ECC_CURVE_FIELD_COUNT 6
1563-
#else
1564-
#define ECC_CURVE_FIELD_ALL 0x3B
1565-
#define ECC_CURVE_FIELD_COUNT 5
1566-
#endif
15671554

15681555
#if defined(WOLFSSL_XILINX_CRYPT_VERSAL)
15691556
static const u32 xil_curve_type[ECC_CURVE_MAX] = {
@@ -1707,10 +1694,8 @@ static void wc_ecc_curve_cache_free_spec(ecc_curve_spec* curve)
17071694
wc_ecc_curve_cache_free_spec_item(curve, curve->prime, ECC_CURVE_FIELD_PRIME);
17081695
if (curve->load_mask & ECC_CURVE_FIELD_AF)
17091696
wc_ecc_curve_cache_free_spec_item(curve, curve->Af, ECC_CURVE_FIELD_AF);
1710-
#ifdef USE_ECC_B_PARAM
17111697
if (curve->load_mask & ECC_CURVE_FIELD_BF)
17121698
wc_ecc_curve_cache_free_spec_item(curve, curve->Bf, ECC_CURVE_FIELD_BF);
1713-
#endif
17141699
if (curve->load_mask & ECC_CURVE_FIELD_ORDER)
17151700
wc_ecc_curve_cache_free_spec_item(curve, curve->order, ECC_CURVE_FIELD_ORDER);
17161701
if (curve->load_mask & ECC_CURVE_FIELD_GX)
@@ -1844,9 +1829,7 @@ static int wc_ecc_curve_load(const ecc_set_type* dp, ecc_curve_spec** pCurve,
18441829
#ifdef ECC_CACHE_CURVE
18451830
curve->prime = &curve->prime_lcl;
18461831
curve->Af = &curve->Af_lcl;
1847-
#ifdef USE_ECC_B_PARAM
1848-
curve->Bf = &curve->Bf_lcl;
1849-
#endif
1832+
curve->Bf = &curve->Bf_lcl;
18501833
curve->order = &curve->order_lcl;
18511834
curve->Gx = &curve->Gx_lcl;
18521835
curve->Gy = &curve->Gy_lcl;
@@ -1865,11 +1848,9 @@ static int wc_ecc_curve_load(const ecc_set_type* dp, ecc_curve_spec** pCurve,
18651848
if (load_items & ECC_CURVE_FIELD_AF)
18661849
ret += wc_ecc_curve_cache_load_item(curve, dp->Af, &curve->Af,
18671850
ECC_CURVE_FIELD_AF);
1868-
#ifdef USE_ECC_B_PARAM
18691851
if (load_items & ECC_CURVE_FIELD_BF)
18701852
ret += wc_ecc_curve_cache_load_item(curve, dp->Bf, &curve->Bf,
18711853
ECC_CURVE_FIELD_BF);
1872-
#endif
18731854
if (load_items & ECC_CURVE_FIELD_ORDER)
18741855
ret += wc_ecc_curve_cache_load_item(curve, dp->order, &curve->order,
18751856
ECC_CURVE_FIELD_ORDER);
@@ -4759,6 +4740,7 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out,
47594740
return ECC_BAD_ARG_E;
47604741
}
47614742

4743+
47624744
#if defined(WOLFSSL_ATECC508A) || defined(WOLFSSL_ATECC608A)
47634745
/* For SECP256R1 use hardware */
47644746
if (private_key->dp->id == ECC_SECP256R1) {
@@ -5271,7 +5253,6 @@ int wc_ecc_shared_secret_ex(ecc_key* private_key, ecc_point* point,
52715253
#endif /* !WOLFSSL_ATECC508A && !WOLFSSL_CRYPTOCELL && !WOLFSSL_KCAPI_ECC */
52725254
#endif /* HAVE_ECC_DHE */
52735255

5274-
#ifdef USE_ECC_B_PARAM
52755256
/* Checks if a point p lies on the curve with index curve_idx */
52765257
int wc_ecc_point_is_on_curve(ecc_point *p, int curve_idx)
52775258
{
@@ -5306,7 +5287,6 @@ int wc_ecc_point_is_on_curve(ecc_point *p, int curve_idx)
53065287

53075288
return err;
53085289
}
5309-
#endif /* USE_ECC_B_PARAM */
53105290

53115291
#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \
53125292
!defined(WOLFSSL_CRYPTOCELL) && \
@@ -9982,8 +9962,6 @@ int wc_ecc_export_x963_ex(ecc_key* key, byte* out, word32* outLen,
99829962
#endif /* HAVE_ECC_KEY_EXPORT */
99839963

99849964

9985-
#ifdef HAVE_ECC_CHECK_PUBKEY_ORDER
9986-
99879965
/* is ecc point on curve described by dp ? */
99889966
static int _ecc_is_point(ecc_point* ecp, mp_int* a, mp_int* b, mp_int* prime)
99899967
{
@@ -10160,6 +10138,8 @@ int wc_ecc_is_point(ecc_point* ecp, mp_int* a, mp_int* b, mp_int* prime)
1016010138
return err;
1016110139
}
1016210140

10141+
#ifdef HAVE_ECC_CHECK_PUBKEY_ORDER
10142+
1016310143
#if (FIPS_VERSION_GE(5,0) || defined(WOLFSSL_VALIDATE_ECC_KEYGEN) || \
1016410144
(defined(WOLFSSL_VALIDATE_ECC_IMPORT) && !defined(WOLFSSL_SP_MATH))) && \
1016510145
!defined(WOLFSSL_KCAPI_ECC) || defined(WOLFSSL_CAAM)
@@ -10527,14 +10507,7 @@ static int _ecc_validate_public_key(ecc_key* key, int partial, int priv)
1052710507
int err = MP_OKAY;
1052810508
#if defined(HAVE_ECC_CHECK_PUBKEY_ORDER) && !defined(WOLFSSL_SP_MATH)
1052910509
mp_int* b = NULL;
10530-
#ifdef USE_ECC_B_PARAM
10531-
DECLARE_CURVE_SPECS(4);
10532-
#else
10533-
#ifndef WOLFSSL_SMALL_STACK
10534-
mp_int b_lcl;
10535-
#endif
10536-
DECLARE_CURVE_SPECS(3);
10537-
#endif /* USE_ECC_B_PARAM */
10510+
DECLARE_CURVE_SPECS(4);
1053810511
#endif
1053910512

1054010513
ASSERT_SAVED_VECTOR_REGISTERS();
@@ -10586,21 +10559,7 @@ static int _ecc_validate_public_key(ecc_key* key, int partial, int priv)
1058610559
#endif
1058710560

1058810561
#ifndef WOLFSSL_SP_MATH
10589-
#ifdef USE_ECC_B_PARAM
10590-
ALLOC_CURVE_SPECS(4, err);
10591-
#else
10592-
ALLOC_CURVE_SPECS(3, err);
10593-
#ifndef WOLFSSL_SMALL_STACK
10594-
b = &b_lcl;
10595-
#else
10596-
b = (mp_int*)XMALLOC(sizeof(mp_int), key->heap, DYNAMIC_TYPE_ECC);
10597-
if (b == NULL) {
10598-
FREE_CURVE_SPECS();
10599-
return MEMORY_E;
10600-
}
10601-
#endif
10602-
XMEMSET(b, 0, sizeof(mp_int));
10603-
#endif
10562+
ALLOC_CURVE_SPECS(4, err);
1060410563

1060510564
#ifdef WOLFSSL_CAAM
1060610565
/* keys can be black encrypted ones which can not be checked like plain text
@@ -10625,22 +10584,10 @@ static int _ecc_validate_public_key(ecc_key* key, int partial, int priv)
1062510584
/* load curve info */
1062610585
if (err == MP_OKAY)
1062710586
err = wc_ecc_curve_load(key->dp, &curve, (ECC_CURVE_FIELD_PRIME |
10628-
ECC_CURVE_FIELD_AF | ECC_CURVE_FIELD_ORDER
10629-
#ifdef USE_ECC_B_PARAM
10630-
| ECC_CURVE_FIELD_BF
10631-
#endif
10632-
));
10587+
ECC_CURVE_FIELD_AF | ECC_CURVE_FIELD_ORDER | ECC_CURVE_FIELD_BF));
1063310588

10634-
#ifndef USE_ECC_B_PARAM
10635-
/* load curve b parameter */
10636-
if (err == MP_OKAY)
10637-
err = mp_init(b);
10638-
if (err == MP_OKAY)
10639-
err = mp_read_radix(b, key->dp->Bf, MP_RADIX_HEX);
10640-
#else
1064110589
if (err == MP_OKAY)
1064210590
b = curve->Bf;
10643-
#endif
1064410591

1064510592
/* SP 800-56Ar3, section 5.6.2.3.3, process step 2 */
1064610593
/* SP 800-56Ar3, section 5.6.2.3.4, process step 2 */
@@ -10697,11 +10644,6 @@ static int _ecc_validate_public_key(ecc_key* key, int partial, int priv)
1069710644

1069810645
wc_ecc_curve_free(curve);
1069910646

10700-
#ifndef USE_ECC_B_PARAM
10701-
mp_clear(b);
10702-
WC_FREE_VAR_EX(b, key->heap, DYNAMIC_TYPE_ECC);
10703-
#endif
10704-
1070510647
FREE_CURVE_SPECS();
1070610648

1070710649
#else
@@ -11025,16 +10967,75 @@ int wc_ecc_import_x963_ex2(const byte* in, word32 inLen, ecc_key* key,
1102510967
!defined(WOLFSSL_CRYPTOCELL) && \
1102610968
(!defined(WOLF_CRYPTO_CB_ONLY_ECC) || defined(WOLFSSL_QNX_CAAM) || \
1102710969
defined(WOLFSSL_IMXRT1170_CAAM))
11028-
if (untrusted) {
11029-
/* Only do quick checks. */
11030-
if ((err == MP_OKAY) && wc_ecc_point_is_at_infinity(&key->pubkey)) {
10970+
if ((err == MP_OKAY) && untrusted) {
10971+
/* Reject point at infinity. */
10972+
if (wc_ecc_point_is_at_infinity(&key->pubkey)) {
1103110973
err = ECC_INF_E;
1103210974
}
11033-
#ifdef USE_ECC_B_PARAM
11034-
if ((err == MP_OKAY) && (key->idx != ECC_CUSTOM_IDX)) {
10975+
/* Verify the point lies on the curve (y^2 = x^3 + ax + b mod p) */
10976+
if ((err == MP_OKAY) && (key->idx != ECC_CUSTOM_IDX)) {
10977+
#ifdef WOLFSSL_HAVE_SP_ECC
10978+
#ifndef WOLFSSL_SP_NO_256
10979+
if (ecc_sets[key->idx].id == ECC_SECP256R1) {
10980+
err = sp_ecc_is_point_256(key->pubkey.x, key->pubkey.y);
10981+
#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SP_SM2)
10982+
if (err != MP_OKAY && curve_id < 0) {
10983+
/* Retry with SM2 curve when P-256 returns invalid.
10984+
* Only when no explicit curve was requested (curve_id < 0).
10985+
* Needed because SM2 keys can be mis-identified as
10986+
* SECP256R1 during parsing. */
10987+
err = sp_ecc_is_point_sm2_256(key->pubkey.x,
10988+
key->pubkey.y);
10989+
if (err == MP_OKAY) {
10990+
err = wc_ecc_set_curve(key, key->dp->size,
10991+
ECC_SM2P256V1);
10992+
}
10993+
}
10994+
#endif
10995+
}
10996+
else
10997+
#endif
10998+
#if defined(WOLFSSL_SM2) && defined(WOLFSSL_SP_SM2)
10999+
if (ecc_sets[key->idx].id == ECC_SM2P256V1) {
11000+
err = sp_ecc_is_point_sm2_256(key->pubkey.x, key->pubkey.y);
11001+
}
11002+
else
11003+
#endif
11004+
#ifdef WOLFSSL_SP_384
11005+
if (ecc_sets[key->idx].id == ECC_SECP384R1) {
11006+
err = sp_ecc_is_point_384(key->pubkey.x, key->pubkey.y);
11007+
}
11008+
else
11009+
#endif
11010+
#ifdef WOLFSSL_SP_521
11011+
if (ecc_sets[key->idx].id == ECC_SECP521R1) {
11012+
err = sp_ecc_is_point_521(key->pubkey.x, key->pubkey.y);
11013+
}
11014+
else
11015+
#endif
11016+
{
11017+
err = wc_ecc_point_is_on_curve(&key->pubkey, key->idx);
11018+
}
11019+
#else
1103511020
err = wc_ecc_point_is_on_curve(&key->pubkey, key->idx);
11021+
#if defined(WOLFSSL_SM2)
11022+
if (err != MP_OKAY && curve_id < 0) {
11023+
/* Retry with SM2 curve when P-256 returns invalid.
11024+
* Only when no explicit curve was requested (curve_id < 0).
11025+
* Needed because SM2 keys can be mis-identified as
11026+
* SECP256R1 during parsing. */
11027+
int sm2_idx = wc_ecc_get_curve_idx(ECC_SM2P256V1);
11028+
if (sm2_idx != ECC_CURVE_INVALID) {
11029+
err = wc_ecc_point_is_on_curve(&key->pubkey, sm2_idx);
11030+
if (err == MP_OKAY) {
11031+
err = wc_ecc_set_curve(key, WOLFSSL_SM2_KEY_BITS / 8,
11032+
ECC_SM2P256V1);
11033+
}
11034+
}
11035+
}
11036+
#endif
11037+
#endif /* WOLFSSL_HAVE_SP_ECC */
1103611038
}
11037-
#endif /* USE_ECC_B_PARAM */
1103811039
}
1103911040
#endif
1104011041
(void)untrusted;
@@ -11061,7 +11062,8 @@ int wc_ecc_import_x963_ex2(const byte* in, word32 inLen, ecc_key* key,
1106111062
int wc_ecc_import_x963_ex(const byte* in, word32 inLen, ecc_key* key,
1106211063
int curve_id)
1106311064
{
11064-
return wc_ecc_import_x963_ex2(in, inLen, key, curve_id, 0);
11065+
/* treat as untrusted: validate the point is on the curve */
11066+
return wc_ecc_import_x963_ex2(in, inLen, key, curve_id, 1);
1106511067
}
1106611068

1106711069
WOLFSSL_ABI

wolfcrypt/test/test.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38346,6 +38346,7 @@ static wc_test_ret_t ecc_encrypt_e2e_test(WC_RNG* rng, ecc_key* userA, ecc_key*
3834638346

3834738347
#ifdef WOLFSSL_ECIES_OLD
3834838348
tmpKey->dp = userA->dp;
38349+
tmpKey->idx = userA->idx;
3834938350
ret = wc_ecc_copy_point(&userA->pubkey, &tmpKey->pubkey);
3835038351
if (ret != 0) {
3835138352
ret = WC_TEST_RET_ENC_EC(ret); goto done;

0 commit comments

Comments
 (0)