Fix ARMv7 SM2 infinite loop, concurrency issues, and API safety annotations

- Fix ECP_Sm2FpInv/ECP_Sm2FnInv infinite loop when q==0 or q==modulus
- Fix ECP_Sm2PointToAffineCore missing infinity point check before FpInv
- Fix ECP_Sm2OrderInv missing a==N check
- Fix ECP_SM2FpPut pointer comparison bug breaking BN size calculation
- Fix ECP_Sm2PointMulCore static buffers not thread-safe
- Add safety annotations for SM4-XTS key setters, CRYPT_CTRL_SET_SM2_K,
  CRYPT_CTRL_GET_SM2_RANDOM, and CRYPT_EAL_ProviderUnload
- Add 5 ARMv7-specific test cases for edge case coverage

Cherry-picked from: https://gitcode.com/openHiTLS/openhitls/merge_requests/1415

Signed-off-by: Dongjianwei001 <dongjianwei1@huawei.com>
This commit is contained in:
dumb
2026-05-15 06:00:19 +00:00
committed by Dongjianwei001
parent 3ac94d7f4e
commit e4d0872138
8 changed files with 280 additions and 16 deletions
+4
View File
@@ -402,6 +402,10 @@ int32_t ECP_Sm2OrderInv(const ECC_Para *para, BN_BigNum *r, const BN_BigNum *a)
BSL_ERR_PUSH_ERROR(CRYPT_BN_ERR_DIVISOR_ZERO);
return CRYPT_BN_ERR_DIVISOR_ZERO;
}
if (BN_Cmp(para->n, a) == 0) {
BSL_ERR_PUSH_ERROR(CRYPT_BN_ERR_NO_INVERSE);
return CRYPT_BN_ERR_NO_INVERSE;
}
int32_t ret = BN_Extend(r, SM2_LIMBS);
if (ret != CRYPT_SUCCESS) {
BSL_ERR_PUSH_ERROR(ret);
+25 -6
View File
@@ -183,7 +183,12 @@ static int ECP_Sm2FpEqu(const Sm2Fp a, const Sm2Fp b) {
* @ref "Guide to Elliptic Curve Cryptography" by Hankerson, Menezes and Vanstone, Algorithm 2.22
*/
static void ECP_Sm2FpInv(Sm2Fp r, const Sm2Fp q) {
Sm2Fp u, v = {0xFFFFFFFFU, 0xFFFFFFFFU, 0x00000000U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFEU}, a = {1}, c = {0};
Sm2Fp v = {0xFFFFFFFFU, 0xFFFFFFFFU, 0x00000000U, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFEU};
if (ECP_Sm2FpIsZero(q) || ECP_Sm2FpEqu(q, v)) {
ECP_Sm2FpSet(r, g_Sm2Zero);
return;
}
Sm2Fp u, a = {1}, c = {0};
ECP_Sm2FpSet(u, q);
while (ECP_Sm2FpIsOne(u) == 0 && ECP_Sm2FpIsOne(v) == 0) {
while (ECP_Sm2FpIsEven(u)) {
@@ -217,7 +222,12 @@ static void ECP_Sm2FpInv(Sm2Fp r, const Sm2Fp q) {
* @ref "Guide to Elliptic Curve Cryptography" by Hankerson, Menezes and Vanstone, Algorithm 2.22
*/
static void ECP_Sm2FnInv(Sm2Fp r, const Sm2Fp q) {
Sm2Fp u, v = {0x39D54123U, 0x53BBF409U, 0x21C6052BU, 0x7203DF6BU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFEU}, a = {1}, c = {0};
Sm2Fp v = {0x39D54123U, 0x53BBF409U, 0x21C6052BU, 0x7203DF6BU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFFU, 0xFFFFFFFEU};
if (ECP_Sm2FpIsZero(q) || ECP_Sm2FpEqu(q, v)) {
ECP_Sm2FpSet(r, g_Sm2Zero);
return;
}
Sm2Fp u, a = {1}, c = {0};
ECP_Sm2FpSet(u, q);
while (ECP_Sm2FpIsOne(u) == 0 && ECP_Sm2FpIsOne(v) == 0) {
while (ECP_Sm2FpIsEven(u)) {
@@ -308,6 +318,10 @@ static int ECP_Sm2PointAtInfinity(const Sm2Point *r){
* @param [out] r Pointer to the resulting affine point.
*/
void ECP_Sm2PointToAffineCore(const Sm2Point *a, Sm2Point *r) {
if (ECP_Sm2PointAtInfinity(a)) {
ECP_Sm2PointSetInfinity(r);
return;
}
Sm2Fp t1, t2;
ECP_Sm2FpInv(t1, a->z);
ECP_Sm2FpSqr(t2, t1);
@@ -543,11 +557,10 @@ static void ECP_Sm2PointMultDoubleCore(Sm2Point *r, uint32_t m, const Sm2Point *
static void ECP_Sm2PointMulCore(Sm2Point *r, const Sm2Fp k, const Sm2Point *g) {
// compute the sm2_naf of k, The optimal parameter (window width) w = 4 is used here.
static Sm2Naf K;
Sm2Naf K;
ECP_Sm2FpNaf(K, 4, k);
// compute the table of point g: {g, 3g, 5g, 7g, 9g, 11g, 13g, 15g}, a total of 2^{w-1} - 1 points.
static Sm2Point upt[8];
Sm2Point upt[8];
upt[0] = *g;
ECP_Sm2PointDouCore(r, g);
for (uint32_t i = 1; i < 8; i++) {
@@ -629,7 +642,9 @@ static int32_t ECP_SM2FpPut(const Sm2Fp src, BN_BigNum *dst)
BN_Zeroize(dst);
for (uint32_t i = 0; i < SM2_LIMBS; i++) {
dst->data[i] = src[i];
dst->size += dst->data != 0;
if (dst->data[i] != 0) {
dst->size = i + 1;
}
}
return CRYPT_SUCCESS;
@@ -735,6 +750,10 @@ int32_t ECP_Sm2OrderInv(const ECC_Para *para, BN_BigNum *r, const BN_BigNum *a)
BSL_ERR_PUSH_ERROR(CRYPT_BN_ERR_DIVISOR_ZERO);
return CRYPT_BN_ERR_DIVISOR_ZERO;
}
if (BN_Cmp(para->n, a) == 0) {
BSL_ERR_PUSH_ERROR(CRYPT_BN_ERR_NO_INVERSE);
return CRYPT_BN_ERR_NO_INVERSE;
}
int32_t ret = CRYPT_SUCCESS;
Sm2Fp n;
GOTO_ERR_IF(ECP_SM2FpGet(n, a), ret);
+7 -7
View File
@@ -82,26 +82,26 @@ void CRYPT_SM4_Clean(CRYPT_SM4_Ctx *ctx);
#ifdef HITLS_CRYPTO_XTS
/**
* @brief SM4 Set the encryption key.
* @brief SM4 XTS set the encryption key. Internal use only, input validation is performed
* by the upper-level modes wrapper (SM4_XTS_InitCtx).
*
* @param ctx [IN] sm4 Context
* @param key [IN] Key. The first 16 bytes are data_key, and the last 16 bytes are tweak_key.
* @param keyLen [IN] Key length
*
* @retval #CRYPT_SUCCESS succeeded.
* @retval #CRYPT_NULL_INPUT ctx or key is NULL.
* @retval #CRYPT_SM4_ERR_KEY_LEN The key length is not equal to 32.
*/
int32_t CRYPT_SM4_XTS_SetEncryptKey(CRYPT_SM4_Ctx *ctx, const uint8_t *key, uint32_t len);
/**
* @brief SM4 Set the decryption key.
* @brief SM4 XTS set the decryption key. Internal use only, input validation is performed
* by the upper-level modes wrapper (SM4_XTS_InitCtx).
*
* @param ctx [IN] sm4 Context
* @param key [IN] Key
* @param key [IN] Key. The first 16 bytes are data_key, and the last 16 bytes are tweak_key.
* @param keyLen [IN] Key length
* @return Success: CRYPT_SUCCESS
* Other error codes are returned if the operation fails.
*
* @retval #CRYPT_SUCCESS succeeded.
*/
int32_t CRYPT_SM4_XTS_SetDecryptKey(CRYPT_SM4_Ctx *ctx, const uint8_t *key, uint32_t len);
+6
View File
@@ -134,6 +134,12 @@ int32_t CRYPT_EAL_ProviderGetCaps(CRYPT_EAL_ProvMgrCtx *ctx, int32_t cmd, CRYPT_
* @ingroup crypt_eal_provider
* @brief Provider unload interface
*
* @warning All crypto contexts (cipher, digest, sign, etc.) created from this
* provider must be freed before calling this function. Unloading a
* provider with active contexts will invalidate the function pointers
* held by those contexts, causing crash or use-after-free on any
* subsequent operation performed through them.
*
* @param libCtx [IN] Library context
* @param cmd [IN] Command specifying the conversion format for the provider library name.
* This parameter is used to determine how the provider library name should be
+6 -2
View File
@@ -685,7 +685,9 @@ typedef enum {
CRYPT_CTRL_SET_SM2_R, /* SM2 set the R value. */
CRYPT_CTRL_SET_SM2_RANDOM, /* SM2 set the r value. */
CRYPT_CTRL_SET_SM2_PKG, /* SM2 uses the PKG process. */
CRYPT_CTRL_SET_SM2_K, /* SM2 set the K value. */
CRYPT_CTRL_SET_SM2_K, /**< SM2 encryption: set the ephemeral scalar k. Only available when
* HITLS_CRYPTO_ACVP_TESTS is enabled. For test vector verification
* only, must not be used in production. */
CRYPT_CTRL_SET_ECC_POINT_FORMAT, /**< ECC PKEY set the point format. For the point format,
see CRYPT_PKEY_PointFormat. */
@@ -703,7 +705,9 @@ typedef enum {
CRYPT_CTRL_GET_ECC_ORDER_BITS, /**< Get the number of bits in the group order. */
CRYPT_CTRL_GET_ECC_NAME, /**< Obtain the name of the ECC curve. */
CRYPT_CTRL_GEN_X25519_PUBLICKEY, /**< Use prikey genarate x25519 pubkey. */
CRYPT_CTRL_GET_SM2_RANDOM, /**< SM2 get the r value. */
CRYPT_CTRL_GET_SM2_RANDOM, /**< SM2 key exchange: get the ephemeral scalar r for special users
* (e.g. ACVP test vector verification). Caller must ensure r is kept
* confidential and securely erased after use. */
CRYPT_CTRL_GET_FLAG, /**< Get ECC pkey flags. */
CRYPT_CTRL_SET_FLAG, /**< Set ECC pkey flags (OR with existing). */
CRYPT_CTRL_CLR_FLAG, /**< Clear ECC pkey flags (AND NOT). */
@@ -1054,3 +1054,219 @@ EXIT:
TestRandDeInit();
}
/* END_CASE */
/**
* @test SDV_CRYPTO_ECC_MODORDERINV_EQUAL_ORDER_TC001
* @brief ECC_ModOrderInv with input equal to the curve order N; verify ECP_Sm2OrderInv detects a==N and returns error.
* @expect Returns CRYPT_BN_ERR_NO_INVERSE (no inverse exists for N mod N == 0).
*/
/* BEGIN_CASE */
void SDV_CRYPTO_ECC_MODORDERINV_EQUAL_ORDER_TC001(int paraId)
{
if (IsCurveDisabled(paraId) && paraId != CRYPT_ECC_SM2) {
SKIP_TEST();
}
TestMemInit();
ASSERT_EQ(TestRandInit(), CRYPT_SUCCESS);
ECC_Para *para = ECC_NewPara(paraId);
ASSERT_TRUE(para != NULL);
BN_BigNum *N = ECC_GetParaN(para);
ASSERT_TRUE(N != NULL);
BN_BigNum *r = BN_Create(0);
ASSERT_TRUE(r != NULL);
ASSERT_EQ(BN_Copy(r, N), CRYPT_SUCCESS);
int32_t ret = ECC_ModOrderInv(para, r, N);
ASSERT_EQ(ret, CRYPT_BN_ERR_NO_INVERSE);
EXIT:
ECC_FreePara(para);
BN_Destroy(N);
BN_Destroy(r);
TestRandDeInit();
}
/* END_CASE */
/**
* @test SDV_CRYPTO_ECC_MUL_INFINITY_POINT_TC001
* @brief Compute 0*G to produce the point at infinity, then verify point operations do not hang.
* @expect 0*G is at infinity; ECC_GetPoint returns CRYPT_ECC_POINT_AT_INFINITY without hanging.
*/
/* BEGIN_CASE */
void SDV_CRYPTO_ECC_MUL_INFINITY_POINT_TC001(int paraId)
{
if (IsCurveDisabled(paraId) && paraId != CRYPT_ECC_SM2) {
SKIP_TEST();
}
TestMemInit();
ASSERT_EQ(TestRandInit(), CRYPT_SUCCESS);
ECC_Para *para = ECC_NewPara(paraId);
ASSERT_TRUE(para != NULL);
BN_BigNum *zero = BN_Create(0);
ASSERT_TRUE(zero != NULL);
ECC_Point *inf = ECC_NewPoint(para);
ASSERT_TRUE(inf != NULL);
ASSERT_EQ(ECC_PointMul(para, inf, zero, NULL), CRYPT_SUCCESS);
ASSERT_EQ(ECP_PointAtInfinity(para, inf), CRYPT_ECC_POINT_AT_INFINITY);
CRYPT_Data x = {0};
CRYPT_Data y = {0};
uint8_t xBuf[ECC_MAX_BIT_LEN / 8 + 1];
uint8_t yBuf[ECC_MAX_BIT_LEN / 8 + 1];
x.data = xBuf;
x.len = sizeof(xBuf);
y.data = yBuf;
y.len = sizeof(yBuf);
ASSERT_EQ(ECC_GetPoint(para, inf, &x, &y), CRYPT_ECC_POINT_AT_INFINITY);
EXIT:
ECC_FreePara(para);
ECC_FreePoint(inf);
BN_Destroy(zero);
TestRandDeInit();
}
/* END_CASE */
/**
* @test SDV_CRYPTO_ECC_MULADD_INFINITY_POINT_TC001
* @brief ECC_PointMulAdd with k2=0 produces infinity; verify ECC_GetPoint does not hang.
* @expect k1*G + 0*pt = k1*G is a valid point (not infinity).
*/
/* BEGIN_CASE */
void SDV_CRYPTO_ECC_MULADD_INFINITY_POINT_TC001(int paraId)
{
if (IsCurveDisabled(paraId) && paraId != CRYPT_ECC_SM2) {
SKIP_TEST();
}
TestMemInit();
ASSERT_EQ(TestRandInit(), CRYPT_SUCCESS);
ECC_Para *para = ECC_NewPara(paraId);
ASSERT_TRUE(para != NULL);
BN_BigNum *N = ECC_GetParaN(para);
ASSERT_TRUE(N != NULL);
ECC_Point *G = ECC_GetGFromPara(para);
ASSERT_TRUE(G != NULL);
BN_BigNum *k1 = BN_Create(0);
BN_BigNum *k2 = BN_Create(0);
ASSERT_TRUE(k1 != NULL);
ASSERT_TRUE(k2 != NULL);
ASSERT_EQ(BN_Bin2Bn(k1, (const uint8_t *)"\x02", 1), CRYPT_SUCCESS);
ASSERT_EQ(BN_Zeroize(k2), CRYPT_SUCCESS);
ECC_Point *r = ECC_NewPoint(para);
ASSERT_TRUE(r != NULL);
ASSERT_EQ(ECC_PointMulAdd(para, r, k1, k2, G), CRYPT_SUCCESS);
CRYPT_Data x = {0};
CRYPT_Data y = {0};
uint8_t xBuf[ECC_MAX_BIT_LEN / 8 + 1];
uint8_t yBuf[ECC_MAX_BIT_LEN / 8 + 1];
x.data = xBuf;
x.len = sizeof(xBuf);
y.data = yBuf;
y.len = sizeof(yBuf);
ASSERT_EQ(ECC_GetPoint(para, r, &x, &y), CRYPT_SUCCESS);
EXIT:
ECC_FreePara(para);
ECC_FreePoint(G);
ECC_FreePoint(r);
BN_Destroy(k1);
BN_Destroy(k2);
BN_Destroy(N);
TestRandDeInit();
}
/* END_CASE */
/**
* @test SDV_CRYPTO_ECC_POINTADD_INFINITY_POINT_TC001
* @brief ECC_PointAddAffine with an infinity input point returns the other point without hanging.
* @expect Adding infinity to a valid point returns the valid point.
*/
/* BEGIN_CASE */
void SDV_CRYPTO_ECC_POINTADD_INFINITY_POINT_TC001(int paraId)
{
if (IsCurveDisabled(paraId) && paraId != CRYPT_ECC_SM2) {
SKIP_TEST();
}
TestMemInit();
ASSERT_EQ(TestRandInit(), CRYPT_SUCCESS);
ECC_Para *para = ECC_NewPara(paraId);
ASSERT_TRUE(para != NULL);
BN_BigNum *zero = BN_Create(0);
BN_BigNum *k = BN_Create(0);
ASSERT_TRUE(zero != NULL);
ASSERT_TRUE(k != NULL);
ASSERT_EQ(BN_Bin2Bn(k, (const uint8_t *)"\x02", 1), CRYPT_SUCCESS);
ECC_Point *P = ECC_NewPoint(para);
ECC_Point *inf = ECC_NewPoint(para);
ECC_Point *result = ECC_NewPoint(para);
ASSERT_TRUE(P != NULL);
ASSERT_TRUE(inf != NULL);
ASSERT_TRUE(result != NULL);
ASSERT_EQ(ECC_PointMul(para, P, k, NULL), CRYPT_SUCCESS);
ASSERT_EQ(ECC_PointMul(para, inf, zero, NULL), CRYPT_SUCCESS);
ASSERT_EQ(ECP_PointAtInfinity(para, inf), CRYPT_ECC_POINT_AT_INFINITY);
ASSERT_EQ(ECC_PointAddAffine(para, result, inf, P), CRYPT_SUCCESS);
ASSERT_EQ(ECP_PointAtInfinity(para, result), CRYPT_SUCCESS);
EXIT:
ECC_FreePara(para);
ECC_FreePoint(P);
ECC_FreePoint(inf);
ECC_FreePoint(result);
BN_Destroy(zero);
BN_Destroy(k);
TestRandDeInit();
}
/* END_CASE */
/**
* @test SDV_CRYPTO_ECC_MULADD_INFINITY_RESULT_TC001
* @brief ECC_PointMulAdd with k1=1, k2=N-1, pt=G produces infinity (z=0); verify PointToAffineCore handles infinity without hang.
* @expect ECC_PointMulAdd returns CRYPT_SUCCESS.
*/
/* BEGIN_CASE */
void SDV_CRYPTO_ECC_MULADD_INFINITY_RESULT_TC001(int paraId)
{
if (IsCurveDisabled(paraId) && paraId != CRYPT_ECC_SM2) {
SKIP_TEST();
}
TestMemInit();
ASSERT_EQ(TestRandInit(), CRYPT_SUCCESS);
ECC_Para *para = ECC_NewPara(paraId);
ASSERT_TRUE(para != NULL);
BN_BigNum *N = ECC_GetParaN(para);
ASSERT_TRUE(N != NULL);
ECC_Point *G = ECC_GetGFromPara(para);
ASSERT_TRUE(G != NULL);
BN_BigNum *k1 = BN_Create(0);
BN_BigNum *k2 = BN_Create(0);
BN_BigNum *one = BN_Create(0);
ASSERT_TRUE(k1 != NULL);
ASSERT_TRUE(k2 != NULL);
ASSERT_TRUE(one != NULL);
ASSERT_EQ(BN_Bin2Bn(k1, (const uint8_t *)"\x01", 1), CRYPT_SUCCESS);
ASSERT_EQ(BN_Bin2Bn(one, (const uint8_t *)"\x01", 1), CRYPT_SUCCESS);
ASSERT_EQ(BN_Copy(k2, N), CRYPT_SUCCESS);
ASSERT_EQ(BN_Sub(k2, k2, one), CRYPT_SUCCESS);
ECC_Point *r = ECC_NewPoint(para);
ASSERT_TRUE(r != NULL);
ASSERT_EQ(ECC_PointMulAdd(para, r, k1, k2, G), CRYPT_SUCCESS);
EXIT:
ECC_FreePara(para);
ECC_FreePoint(G);
ECC_FreePoint(r);
BN_Destroy(N);
BN_Destroy(k1);
BN_Destroy(k2);
BN_Destroy(one);
TestRandDeInit();
}
/* END_CASE */
@@ -642,3 +642,18 @@ SDV_CRYPTO_ECC_POINTMUL_ZERO_K_TC001:CRYPT_ECC_BRAINPOOLP512R1
SDV_CRYPTO_ECC_POINTMUL_ZERO_K_TC001
SDV_CRYPTO_ECC_POINTMUL_ZERO_K_TC001:CRYPT_ECC_SM2
SDV_CRYPTO_ECC_MODORDERINV_EQUAL_ORDER_TC001
SDV_CRYPTO_ECC_MODORDERINV_EQUAL_ORDER_TC001:CRYPT_ECC_SM2
SDV_CRYPTO_ECC_MUL_INFINITY_POINT_TC001
SDV_CRYPTO_ECC_MUL_INFINITY_POINT_TC001:CRYPT_ECC_SM2
SDV_CRYPTO_ECC_MULADD_INFINITY_POINT_TC001
SDV_CRYPTO_ECC_MULADD_INFINITY_POINT_TC001:CRYPT_ECC_SM2
SDV_CRYPTO_ECC_POINTADD_INFINITY_POINT_TC001
SDV_CRYPTO_ECC_POINTADD_INFINITY_POINT_TC001:CRYPT_ECC_SM2
SDV_CRYPTO_ECC_MULADD_INFINITY_RESULT_TC001
SDV_CRYPTO_ECC_MULADD_INFINITY_RESULT_TC001:CRYPT_ECC_SM2