Reject RSA private key encoding without public exponent

Add a check to fail RSA private key encoding when e is missing or zero, and add an SDV test for
  n+d only keys

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

Signed-off-by: Dongjianwei001 <dongjianwei1@huawei.com>
This commit is contained in:
jchx
2026-06-13 02:43:31 +00:00
committed by Dongjianwei001
parent 06dfcb1002
commit 5e44d5881a
3 changed files with 126 additions and 0 deletions
@@ -1417,6 +1417,19 @@ static void SetRsaPrv2Arr(const CRYPT_EAL_PkeyPrv *rsaPrv, BSL_ASN1_Buffer *asn1
asn1[CRYPT_RSA_PRV_QINV_IDX].tag = BSL_ASN1_TAG_INTEGER;
}
static bool RsaPrvPubExpIsZero(const CRYPT_RsaPrv *rsaPrv)
{
if (rsaPrv->e == NULL || rsaPrv->eLen == 0) {
return true;
}
for (uint32_t i = 0; i < rsaPrv->eLen; i++) {
if (rsaPrv->e[i] != 0) {
return false;
}
}
return true;
}
int32_t EncodeRsaPrikeyAsn1Buff(CRYPT_EAL_PkeyCtx *ealPriKey, BSL_Buffer *encode)
{
BSL_ASN1_Buffer asn1[CRYPT_RSA_PRV_OTHER_PRIME_IDX + 1] = {0};
@@ -1433,6 +1446,11 @@ int32_t EncodeRsaPrikeyAsn1Buff(CRYPT_EAL_PkeyCtx *ealPriKey, BSL_Buffer *encode
BSL_ERR_PUSH_ERROR(ret);
return ret;
}
if (RsaPrvPubExpIsZero(&rsaPrv.key.rsaPrv)) {
CRYPT_EAL_DeinitRsaPrv(&rsaPrv);
BSL_ERR_PUSH_ERROR(CRYPT_RSA_ERR_INPUT_VALUE);
return CRYPT_RSA_ERR_INPUT_VALUE;
}
SetRsaPrv2Arr(&rsaPrv, asn1);
uint8_t version = 0;
asn1[CRYPT_RSA_PRV_VERSION_IDX].buff = (uint8_t *)&version;
@@ -485,6 +485,68 @@ EXIT:
return ret;
}
static int32_t GenerateRsaNdOnlyKey(CRYPT_EAL_PkeyCtx **ndKey)
{
CRYPT_EAL_PkeyCtx *fullKey = NULL;
CRYPT_EAL_PkeyCtx *tmpKey = NULL;
uint8_t *keyBuf = NULL;
uint32_t keyLen = 0;
int32_t ret = CRYPT_SUCCESS;
CRYPT_EAL_PkeyPara para = {0};
para.id = CRYPT_PKEY_RSA;
para.para.rsaPara.e = g_rsaNoCrtPubExp;
para.para.rsaPara.eLen = sizeof(g_rsaNoCrtPubExp);
para.para.rsaPara.bits = 1024;
fullKey = CRYPT_EAL_PkeyNewCtx(CRYPT_PKEY_RSA);
tmpKey = CRYPT_EAL_PkeyNewCtx(CRYPT_PKEY_RSA);
if (fullKey == NULL || tmpKey == NULL) {
ret = CRYPT_MEM_ALLOC_FAIL;
goto EXIT;
}
ret = CRYPT_EAL_PkeySetPara(fullKey, &para);
if (ret != CRYPT_SUCCESS) {
goto EXIT;
}
ret = CRYPT_EAL_PkeyGen(fullKey);
if (ret != CRYPT_SUCCESS) {
goto EXIT;
}
keyLen = CRYPT_EAL_PkeyGetKeyLen(fullKey);
keyBuf = BSL_SAL_Malloc(keyLen * 2); // n and d
if (keyBuf == NULL) {
ret = CRYPT_MEM_ALLOC_FAIL;
goto EXIT;
}
CRYPT_EAL_PkeyPrv prv = {0};
prv.id = CRYPT_PKEY_RSA;
prv.key.rsaPrv.n = keyBuf;
prv.key.rsaPrv.nLen = keyLen;
prv.key.rsaPrv.d = keyBuf + keyLen;
prv.key.rsaPrv.dLen = keyLen;
ret = CRYPT_EAL_PkeyGetPrv(fullKey, &prv);
if (ret != CRYPT_SUCCESS) {
goto EXIT;
}
ret = CRYPT_EAL_PkeySetPrv(tmpKey, &prv);
if (ret != CRYPT_SUCCESS) {
goto EXIT;
}
*ndKey = tmpKey;
tmpKey = NULL;
ret = CRYPT_SUCCESS;
EXIT:
CRYPT_EAL_PkeyFreeCtx(fullKey);
CRYPT_EAL_PkeyFreeCtx(tmpKey);
BSL_SAL_ClearFree(keyBuf, keyBuf == NULL ? 0 : keyLen * 2);
return ret;
}
static void RsaNoCrtEncDec(CRYPT_EAL_PkeyCtx *noCrtKey, int isProvider, int keyType, const char *keyTypeStr,
const CRYPT_EncodeParam *encodeParam, uint8_t *pwd, uint32_t pwdLen)
{
@@ -674,6 +736,49 @@ EXIT:
}
/* END_CASE */
/**
* @test SDV_CRYPT_EAL_RSA_ND_PRIKEY_ENCODE_REJECT_TC001
* @title RSA private key encoding rejects n/d only keys
*/
/* BEGIN_CASE */
void SDV_CRYPT_EAL_RSA_ND_PRIKEY_ENCODE_REJECT_TC001(void)
{
#if defined(HITLS_CRYPTO_RSA) && defined(HITLS_CRYPTO_KEY_ENCODE) && defined(HITLS_CRYPTO_KEY_DECODE)
CRYPT_EAL_PkeyCtx *ndKey = NULL;
BSL_Buffer encode = {0};
uint8_t pwd[] = {0x31, 0x32, 0x33, 0x34};
CRYPT_Pbkdf2Param param = {
.pbesId = BSL_CID_PBES2,
.pbkdfId = BSL_CID_PBKDF2,
.hmacId = CRYPT_MAC_HMAC_SHA256,
.symId = CRYPT_CIPHER_AES256_CBC,
.saltLen = 16,
.pwd = pwd,
.pwdLen = sizeof(pwd),
.itCnt = 2048
};
CRYPT_EncodeParam paramEx = {CRYPT_DERIVE_PBKDF2, &param};
ASSERT_EQ(TestRandInit(), CRYPT_SUCCESS);
ASSERT_EQ(GenerateRsaNdOnlyKey(&ndKey), CRYPT_SUCCESS);
ASSERT_EQ(CRYPT_EAL_EncodeBuffKey(ndKey, NULL, BSL_FORMAT_ASN1, CRYPT_PRIKEY_RSA, &encode),
CRYPT_RSA_ERR_INPUT_VALUE);
ASSERT_EQ(CRYPT_EAL_EncodeBuffKey(ndKey, NULL, BSL_FORMAT_ASN1, CRYPT_PRIKEY_PKCS8_UNENCRYPT, &encode),
CRYPT_RSA_ERR_INPUT_VALUE);
#if defined(HITLS_CRYPTO_KEY_EPKI)
ASSERT_EQ(CRYPT_EAL_EncodeBuffKey(ndKey, &paramEx, BSL_FORMAT_ASN1, CRYPT_PRIKEY_PKCS8_ENCRYPT, &encode),
CRYPT_RSA_ERR_INPUT_VALUE);
#endif
EXIT:
CRYPT_EAL_PkeyFreeCtx(ndKey);
TestRandDeInit();
#else
SKIP_TEST();
#endif
}
/* END_CASE */
/* sign and optional compare in a reusable subroutine */
static int32_t PrikeySign(CRYPT_EAL_PkeyCtx *pkeyCtx, int mdId, int fileType, char *fileTypeStr, Hex *msg, Hex *sign)
{
@@ -811,6 +811,9 @@ SDV_CRYPT_EAL_RSA_NO_CRT_PRIKEY_ENCDEC_TC001:0
SDV_CRYPT_EAL_RSA_NO_CRT_PRIKEY_ENCDEC_TC001 provider decoder
SDV_CRYPT_EAL_RSA_NO_CRT_PRIKEY_ENCDEC_TC001:1
SDV_CRYPT_EAL_RSA_ND_PRIKEY_ENCODE_REJECT_TC001
SDV_CRYPT_EAL_RSA_ND_PRIKEY_ENCODE_REJECT_TC001:
SDV_CRYPT_EAL_PROVIDER_DECODE_BUFF_KEY_ALGID_TC001 Test RSA key with mismatched SM2 algId
SDV_CRYPT_EAL_PROVIDER_DECODE_BUFF_KEY_ALGID_TC001:"../testdata/cert/asn1/rsa2048key_pkcs8.der":"ASN1":"PRIKEY_PKCS8_UNENCRYPT":CRYPT_PKEY_SM2:CRYPT_PKEY_RSA