diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 7940679aeb..e6fa306e06 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -4761,6 +4761,78 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out, return ECC_BAD_ARG_E; } +#if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \ + !defined(WOLFSSL_CRYPTOCELL) && !defined(WOLFSSL_SILABS_SE_ACCEL) && \ + !defined(WOLFSSL_KCAPI_ECC) && !defined(WOLFSSL_SE050) && \ + !defined(WOLF_CRYPTO_CB_ONLY_ECC) + /* Defense-in-depth: verify peer public key lies on the intended curve + * regardless of how the key was imported. Catches any import path that + * skipped the on-curve check (e.g. trusted-flag set, + * WOLFSSL_VALIDATE_ECC_IMPORT not defined, or future callers using + * wc_ecc_import_x963_ex2 directly). */ + if (public_key->idx != ECC_CUSTOM_IDX) { + #ifdef WOLFSSL_HAVE_SP_ECC + /* Use compact SP check functions for supported curves to avoid the + * mp_int stack cost of wc_ecc_point_is_on_curve on embedded targets. */ + #ifndef WOLFSSL_SP_NO_256 + if (ecc_sets[public_key->idx].id == ECC_SECP256R1) { + err = sp_ecc_check_key_256(public_key->pubkey.x, + public_key->pubkey.y, + NULL, public_key->heap); + #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SP_SM2) + if (err == MP_VAL) { + /* Retry with SM2 check when SP-256 returns invalid. + * This is required as in some cases, the SM2 curve is + * not recognized correctly while parsing the encoded + * input. In this case, SM2 keys are invalidly identified + * as SECP256R1 keys. */ + err = sp_ecc_check_key_sm2_256(public_key->pubkey.x, + public_key->pubkey.y, + NULL, public_key->heap); + } + #endif + } + else + #endif + #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SP_SM2) + if (ecc_sets[public_key->idx].id == ECC_SM2P256V1) { + err = sp_ecc_check_key_sm2_256(public_key->pubkey.x, + public_key->pubkey.y, + NULL, public_key->heap); + } + else + #endif + #ifdef WOLFSSL_SP_384 + if (ecc_sets[public_key->idx].id == ECC_SECP384R1) { + err = sp_ecc_check_key_384(public_key->pubkey.x, + public_key->pubkey.y, + NULL, public_key->heap); + } + else + #endif + #ifdef WOLFSSL_SP_521 + if (ecc_sets[public_key->idx].id == ECC_SECP521R1) { + err = sp_ecc_check_key_521(public_key->pubkey.x, + public_key->pubkey.y, + NULL, public_key->heap); + } + else + #endif + { + err = wc_ecc_point_is_on_curve(&public_key->pubkey, + public_key->idx); + } + #else + err = wc_ecc_point_is_on_curve(&public_key->pubkey, public_key->idx); + #endif /* WOLFSSL_HAVE_SP_ECC */ + + if (err != MP_OKAY) { + WOLFSSL_MSG("wc_ecc_shared_secret: peer public key not on curve"); + return ECC_BAD_ARG_E; + } + } +#endif + #if defined(WOLFSSL_ATECC508A) || defined(WOLFSSL_ATECC608A) /* For SECP256R1 use hardware */ if (private_key->dp->id == ECC_SECP256R1) { @@ -11011,16 +11083,89 @@ int wc_ecc_import_x963_ex2(const byte* in, word32 inLen, ecc_key* key, !defined(WOLFSSL_CRYPTOCELL) && \ (!defined(WOLF_CRYPTO_CB_ONLY_ECC) || defined(WOLFSSL_QNX_CAAM) || \ defined(WOLFSSL_IMXRT1170_CAAM)) - if (untrusted) { - /* Only do quick checks. */ + if ((err == MP_OKAY) && untrusted) { + #ifdef WOLFSSL_HAVE_SP_ECC + /* For SP-supported curves sp_ecc_check_key_NNN validates infinity, + * coordinate range, on-curve equation, and point*order=infinity using + * compact sp_digit arrays - no mp_int stack cost. */ + if (key->idx != ECC_CUSTOM_IDX) { + #ifndef WOLFSSL_SP_NO_256 + if (ecc_sets[key->idx].id == ECC_SECP256R1) { + err = sp_ecc_check_key_256(key->pubkey.x, key->pubkey.y, + NULL, key->heap); + #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SP_SM2) + if (err == MP_VAL) { + /* Retry with SM2 check when SP-256 returns invalid. + * This is required as in some cases, the SM2 curve is + * not recognized correctly while parsing the encoded + * input. In this case, SM2 keys are invalidly identified + * as SECP256R1 keys. */ + err = sp_ecc_check_key_sm2_256(key->pubkey.x, + key->pubkey.y, NULL, + key->heap); + } + #endif + } + else + #endif + #if defined(WOLFSSL_SM2) && defined(WOLFSSL_SP_SM2) + if (ecc_sets[key->idx].id == ECC_SM2P256V1) { + /* Native SM2 curve: always use SM2 check. */ + err = sp_ecc_check_key_sm2_256(key->pubkey.x, key->pubkey.y, + NULL, key->heap); + } + else + #endif + #ifdef WOLFSSL_SP_384 + if (ecc_sets[key->idx].id == ECC_SECP384R1) { + err = sp_ecc_check_key_384(key->pubkey.x, key->pubkey.y, + NULL, key->heap); + } + else + #endif + #ifdef WOLFSSL_SP_521 + if (ecc_sets[key->idx].id == ECC_SECP521R1) { + err = sp_ecc_check_key_521(key->pubkey.x, key->pubkey.y, + NULL, key->heap); + } + else + #endif + { + /* Non-SP curve: fall back to generic checks */ + if ((err == MP_OKAY) && + wc_ecc_point_is_at_infinity(&key->pubkey)) { + err = ECC_INF_E; + } + if (err == MP_OKAY) { + err = wc_ecc_point_is_on_curve(&key->pubkey, key->idx); + } + } + } + #else + /* Generic checks for all curves */ if ((err == MP_OKAY) && wc_ecc_point_is_at_infinity(&key->pubkey)) { err = ECC_INF_E; } #ifdef USE_ECC_B_PARAM - if ((err == MP_OKAY) && (key->idx != ECC_CUSTOM_IDX)) { + if ((err == MP_OKAY) && (key->idx != ECC_CUSTOM_IDX)) { err = wc_ecc_point_is_on_curve(&key->pubkey, key->idx); + #if defined(WOLFSSL_SM2) + if (err != MP_OKAY && curve_id < 0) { + /* Retry with SM2 check when default identified curve returns + * invalid. This is required as in some cases, the SM2 curve is + * not recognized correctly while parsing the encoded + * input. In this case, SM2 keys are invalidly identified + * as SECP256R1 keys. */ + err = wc_ecc_set_curve(key, WOLFSSL_SM2_KEY_BITS / 8, + ECC_SM2P256V1); + if (err == MP_OKAY) { + err = wc_ecc_point_is_on_curve(&key->pubkey, key->idx); + } + } + #endif } #endif /* USE_ECC_B_PARAM */ + #endif /* WOLFSSL_HAVE_SP_ECC */ } #endif (void)untrusted; @@ -11047,7 +11192,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 diff --git a/wolfssl/wolfcrypt/ecc.h b/wolfssl/wolfcrypt/ecc.h index e5a6839d56..11ea02b152 100644 --- a/wolfssl/wolfcrypt/ecc.h +++ b/wolfssl/wolfcrypt/ecc.h @@ -84,11 +84,12 @@ WOLFSSL_LOCAL int wolfCrypt_FIPS_ECC_sanity(void); #endif -/* Enable curve B parameter if needed */ -#if defined(HAVE_COMP_KEY) || defined(ECC_CACHE_CURVE) - #ifndef USE_ECC_B_PARAM /* Allow someone to force enable */ - #define USE_ECC_B_PARAM - #endif +/* Enable curve B parameter for on-curve point validation. + * The b coefficient is present in every compiled-in ecc_set_type entry; + * making it always available lets wc_ecc_point_is_on_curve() run in all + * builds and closes the invalid-curve attack surface. */ +#ifndef USE_ECC_B_PARAM + #define USE_ECC_B_PARAM #endif