mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 19:00:49 +02:00
Fix SE050 RSA-PSS signing, key cleanup, and mutex leaks
RSA-PSS fix: Skip SE050 hardware path for RSA-PSS sign and verify operations in RsaPublicEncryptEx() and RsaPrivateDecryptEx(). The SE050's PSS sign API (Se05x_API_RSASign) is a hash-then-sign operation, which double-hashes when wolfSSL passes a pre-computed digest (as done during TLS CertificateVerify). PSS operations now fall through to the software RSA path. PKCS#1 v1.5 signing continues to use SE050 hardware. Key object leak fix: Add se050_rsa_free_key() called from wc_FreeRsaKey() to erase wolfSSL-allocated RSA key objects from SE050 persistent storage on free. Without this, persistent key slots on the SE050 are never reclaimed and eventually exhaust secure storage. Add matching sss_key_store_erase_key() calls to se050_ecc_free_key(), se050_ed25519_free_key(), and se050_curve25519_free_key(). Only keys with keyId >= SE050_KEYID_START are erased (pre-provisioned keys are left intact). Mutex leak fix: Add missing wolfSSL_CryptHwMutexUnLock() calls before early returns in se050_rsa_sign(), se050_rsa_verify(), se050_rsa_public_encrypt(), and se050_rsa_private_decrypt() when the algorithm lookup fails after the mutex has already been acquired. ZD 21212
This commit is contained in:
@@ -1017,8 +1017,59 @@ int wc_se050_rsa_insert_public_key(word32 keyId, const byte* rsaDer,
|
||||
}
|
||||
|
||||
/**
|
||||
* Return sss_algorithm_t type for RSA sign/verify based on wolfCrypt pad type,
|
||||
* hash value, and mask generation function (mgf).
|
||||
* Free an RSA key object from the SE050. Erases key from persistent storage
|
||||
* if it was allocated by wolfSSL (not pre-provisioned).
|
||||
*
|
||||
* key Pointer to initialized RsaKey structure
|
||||
*/
|
||||
void se050_rsa_free_key(struct RsaKey* key)
|
||||
{
|
||||
sss_status_t status = kStatus_SSS_Success;
|
||||
sss_object_t keyObject;
|
||||
sss_key_store_t host_keystore;
|
||||
|
||||
#ifdef SE050_DEBUG
|
||||
printf("se050_rsa_free_key: key %p, keyId %d\n", key, key->keyId);
|
||||
#endif
|
||||
|
||||
if (cfg_se050_i2c_pi == NULL) {
|
||||
return;
|
||||
}
|
||||
if (key->keyIdSet == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (wolfSSL_CryptHwMutexLock() != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
status = sss_key_store_context_init(&host_keystore, cfg_se050_i2c_pi);
|
||||
if (status == kStatus_SSS_Success) {
|
||||
status = sss_key_store_allocate(&host_keystore, SE050_KEYSTOREID_RSA);
|
||||
}
|
||||
if (status == kStatus_SSS_Success) {
|
||||
status = sss_key_object_init(&keyObject, &host_keystore);
|
||||
}
|
||||
if (status == kStatus_SSS_Success) {
|
||||
status = sss_key_object_get_handle(&keyObject, key->keyId);
|
||||
}
|
||||
|
||||
if (status == kStatus_SSS_Success) {
|
||||
/* Erase key from SE050 persistent storage if it was allocated
|
||||
* by wolfSSL (not a pre-provisioned key). Without this, persistent
|
||||
* key objects leak on the SE050 and can exhaust secure storage. */
|
||||
if (key->keyId >= SE050_KEYID_START) {
|
||||
sss_key_store_erase_key(&host_keystore, &keyObject);
|
||||
}
|
||||
sss_key_object_free(&keyObject);
|
||||
key->keyId = 0;
|
||||
key->keyIdSet = 0;
|
||||
}
|
||||
wolfSSL_CryptHwMutexUnLock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get SSS algorithm type for RSA signature operations.
|
||||
*
|
||||
* padType padding type
|
||||
* hash hash function
|
||||
@@ -1172,15 +1223,29 @@ int se050_rsa_sign(const byte* in, word32 inLen, byte* out,
|
||||
algorithm = se050_get_rsa_signature_type(pad_type, hash, mgf);
|
||||
if (algorithm == kAlgorithm_None) {
|
||||
WOLFSSL_MSG("Unsupported padding/hash/mgf combination for SE050");
|
||||
wolfSSL_CryptHwMutexUnLock();
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
#ifdef SE050_DEBUG
|
||||
printf("se050_rsa_sign: algorithm = %d, keySz = %d, keyIdSet = %d\n",
|
||||
algorithm, keySz, key->keyIdSet);
|
||||
#endif
|
||||
|
||||
status = sss_key_store_context_init(&host_keystore, cfg_se050_i2c_pi);
|
||||
#ifdef SE050_DEBUG
|
||||
printf("se050_rsa_sign: sss_key_store_context_init status = %d\n", status);
|
||||
#endif
|
||||
if (status == kStatus_SSS_Success) {
|
||||
status = sss_key_store_allocate(&host_keystore, SE050_KEYSTOREID_RSA);
|
||||
#ifdef SE050_DEBUG
|
||||
printf("se050_rsa_sign: sss_key_store_allocate status = %d\n", status);
|
||||
#endif
|
||||
}
|
||||
if (status == kStatus_SSS_Success) {
|
||||
status = sss_key_object_init(&newKey, &host_keystore);
|
||||
#ifdef SE050_DEBUG
|
||||
printf("se050_rsa_sign: sss_key_object_init status = %d\n", status);
|
||||
#endif
|
||||
}
|
||||
if (status == kStatus_SSS_Success) {
|
||||
keyId = key->keyId;
|
||||
@@ -1188,6 +1253,9 @@ int se050_rsa_sign(const byte* in, word32 inLen, byte* out,
|
||||
/* key was not generated in SE050, export RsaKey to DER
|
||||
* and use that to store into SE050 keystore */
|
||||
derSz = wc_RsaKeyToDer(key, NULL, 0);
|
||||
#ifdef SE050_DEBUG
|
||||
printf("se050_rsa_sign: wc_RsaKeyToDer size query = %d\n", derSz);
|
||||
#endif
|
||||
if (derSz < 0) {
|
||||
status = kStatus_SSS_Fail;
|
||||
ret = derSz;
|
||||
@@ -1203,6 +1271,9 @@ int se050_rsa_sign(const byte* in, word32 inLen, byte* out,
|
||||
}
|
||||
if (status == kStatus_SSS_Success) {
|
||||
derSz = wc_RsaKeyToDer(key, derBuf, derSz);
|
||||
#ifdef SE050_DEBUG
|
||||
printf("se050_rsa_sign: wc_RsaKeyToDer export = %d\n", derSz);
|
||||
#endif
|
||||
if (derSz < 0) {
|
||||
status = kStatus_SSS_Fail;
|
||||
ret = derSz;
|
||||
@@ -1213,31 +1284,60 @@ int se050_rsa_sign(const byte* in, word32 inLen, byte* out,
|
||||
status = sss_key_object_allocate_handle(&newKey, keyId,
|
||||
kSSS_KeyPart_Pair, kSSS_CipherType_RSA, keySz,
|
||||
kKeyObject_Mode_Persistent);
|
||||
#ifdef SE050_DEBUG
|
||||
printf("se050_rsa_sign: sss_key_object_allocate_handle "
|
||||
"status = %d, keyId = %d\n", status, keyId);
|
||||
#endif
|
||||
}
|
||||
if (status == kStatus_SSS_Success) {
|
||||
/* Try to delete existing key first, ignore return since will
|
||||
* fail if no key exists yet */
|
||||
sss_key_store_erase_key(&host_keystore, &newKey);
|
||||
status = sss_key_store_erase_key(&host_keystore, &newKey);
|
||||
#ifdef SE050_DEBUG
|
||||
printf("se050_rsa_sign: sss_key_store_erase_key "
|
||||
"status = %d\n", status);
|
||||
#endif
|
||||
/* Reset status - erase failing is expected if key doesn't
|
||||
* exist yet */
|
||||
status = kStatus_SSS_Success;
|
||||
|
||||
keyCreated = 1;
|
||||
status = sss_key_store_set_key(&host_keystore, &newKey, derBuf,
|
||||
derSz, (keySz * 8), NULL, 0);
|
||||
#ifdef SE050_DEBUG
|
||||
printf("se050_rsa_sign: sss_key_store_set_key "
|
||||
"status = %d, derSz = %d, keyBits = %d\n",
|
||||
status, derSz, (keySz * 8));
|
||||
#endif
|
||||
}
|
||||
|
||||
XFREE(derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
}
|
||||
else {
|
||||
status = sss_key_object_get_handle(&newKey, keyId);
|
||||
#ifdef SE050_DEBUG
|
||||
printf("se050_rsa_sign: sss_key_object_get_handle "
|
||||
"status = %d, keyId = %d\n", status, keyId);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (status == kStatus_SSS_Success) {
|
||||
status = sss_asymmetric_context_init(&ctx_asymm, cfg_se050_i2c_pi,
|
||||
&newKey, algorithm, kMode_SSS_Sign);
|
||||
#ifdef SE050_DEBUG
|
||||
printf("se050_rsa_sign: sss_asymmetric_context_init "
|
||||
"status = %d, algorithm = %d\n", status, algorithm);
|
||||
#endif
|
||||
if (status == kStatus_SSS_Success) {
|
||||
sigSz = outLen;
|
||||
status = sss_asymmetric_sign_digest(&ctx_asymm, (uint8_t*)in, inLen,
|
||||
out, &sigSz);
|
||||
status = sss_asymmetric_sign_digest(&ctx_asymm, (uint8_t*)in,
|
||||
inLen, out, &sigSz);
|
||||
#ifdef SE050_DEBUG
|
||||
printf("se050_rsa_sign: sss_asymmetric_sign_digest "
|
||||
"status = %d, inLen = %d, sigSz = %d\n",
|
||||
status, inLen, (int)sigSz);
|
||||
#endif
|
||||
}
|
||||
sss_asymmetric_context_free(&ctx_asymm);
|
||||
}
|
||||
@@ -1327,6 +1427,7 @@ int se050_rsa_verify(const byte* in, word32 inLen, byte* out, word32 outLen,
|
||||
algorithm = se050_get_rsa_signature_type(pad_type, hash, mgf);
|
||||
if (algorithm == kAlgorithm_None) {
|
||||
WOLFSSL_MSG("Unsupported padding/hash/mgf combination for SE050");
|
||||
wolfSSL_CryptHwMutexUnLock();
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
@@ -1515,6 +1616,7 @@ int se050_rsa_public_encrypt(const byte* in, word32 inLen, byte* out,
|
||||
algorithm = se050_get_rsa_encrypt_type(pad_type, hash);
|
||||
if (algorithm == kAlgorithm_None) {
|
||||
WOLFSSL_MSG("Unsupported padding/hash/mgf combination for SE050");
|
||||
wolfSSL_CryptHwMutexUnLock();
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
@@ -1673,6 +1775,7 @@ int se050_rsa_private_decrypt(const byte* in, word32 inLen, byte* out,
|
||||
algorithm = se050_get_rsa_encrypt_type(pad_type, hash);
|
||||
if (algorithm == kAlgorithm_None) {
|
||||
WOLFSSL_MSG("Unsupported padding/hash/mgf combination for SE050");
|
||||
wolfSSL_CryptHwMutexUnLock();
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
@@ -2334,6 +2437,12 @@ void se050_ecc_free_key(struct ecc_key* key)
|
||||
}
|
||||
|
||||
if (status == kStatus_SSS_Success) {
|
||||
/* Erase key from SE050 persistent storage if it was allocated
|
||||
* by wolfSSL (not a pre-provisioned key). Without this, persistent
|
||||
* key objects leak on the SE050 and can exhaust secure storage. */
|
||||
if (key->keyId >= SE050_KEYID_START) {
|
||||
sss_key_store_erase_key(&host_keystore, &keyObject);
|
||||
}
|
||||
sss_key_object_free(&keyObject);
|
||||
key->keyId = 0;
|
||||
key->keyIdSet = 0;
|
||||
@@ -2795,6 +2904,9 @@ void se050_ed25519_free_key(ed25519_key* key)
|
||||
status = sss_key_object_get_handle(&newKey, key->keyId);
|
||||
}
|
||||
if (status == kStatus_SSS_Success) {
|
||||
if (key->keyId >= SE050_KEYID_START) {
|
||||
sss_key_store_erase_key(&host_keystore, &newKey);
|
||||
}
|
||||
sss_key_object_free(&newKey);
|
||||
key->keyId = 0;
|
||||
key->keyIdSet = 0;
|
||||
@@ -3268,6 +3380,9 @@ void se050_curve25519_free_key(struct curve25519_key* key)
|
||||
status = sss_key_object_get_handle(&newKey, key->keyId);
|
||||
}
|
||||
if (status == kStatus_SSS_Success) {
|
||||
if (key->keyId >= SE050_KEYID_START) {
|
||||
sss_key_store_erase_key(&host_keystore, &newKey);
|
||||
}
|
||||
sss_key_object_free(&newKey);
|
||||
key->keyId = 0;
|
||||
key->keyIdSet = 0;
|
||||
|
||||
+16
-2
@@ -557,6 +557,10 @@ int wc_FreeRsaKey(RsaKey* key)
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
#if defined(WOLFSSL_SE050) && !defined(WOLFSSL_SE050_NO_RSA)
|
||||
se050_rsa_free_key(key);
|
||||
#endif
|
||||
|
||||
wc_RsaCleanup(key);
|
||||
|
||||
#if defined(WOLFSSL_ASYNC_CRYPT) && defined(WC_ASYNC_ENABLE_RSA)
|
||||
@@ -3389,7 +3393,12 @@ static int RsaPublicEncryptEx(const byte* in, word32 inLen, byte* out,
|
||||
mgf, label, labelSz, sz);
|
||||
}
|
||||
else if (rsa_type == RSA_PRIVATE_ENCRYPT &&
|
||||
pad_value == RSA_BLOCK_TYPE_1) {
|
||||
pad_value == RSA_BLOCK_TYPE_1 &&
|
||||
pad_type != WC_RSA_PSS_PAD) {
|
||||
/* SE050 handles PKCS#1 v1.5 signing directly. PSS signing falls
|
||||
* through to software path because the SE050 PSS sign API
|
||||
* (Se05x_API_RSASign) is hash-then-sign and does not support
|
||||
* signing a pre-computed digest without double-hashing. */
|
||||
return se050_rsa_sign(in, inLen, out, outLen, key, rsa_type,
|
||||
pad_value, pad_type, hash, mgf, label,
|
||||
labelSz, sz);
|
||||
@@ -3555,7 +3564,12 @@ static int RsaPrivateDecryptEx(const byte* in, word32 inLen, byte* out,
|
||||
return ret;
|
||||
}
|
||||
else if (rsa_type == RSA_PUBLIC_DECRYPT &&
|
||||
pad_value == RSA_BLOCK_TYPE_1) {
|
||||
pad_value == RSA_BLOCK_TYPE_1 &&
|
||||
pad_type != WC_RSA_PSS_PAD) {
|
||||
/* SE050 handles PKCS#1 v1.5 verification directly. PSS
|
||||
* verification falls through to software path to match the
|
||||
* software PSS signing path (SE050 PSS sign uses hash-then-sign
|
||||
* which double-hashes a pre-computed digest). */
|
||||
ret = se050_rsa_verify(in, inLen, out, outLen, key, rsa_type,
|
||||
pad_value, pad_type, hash, mgf, label,
|
||||
labelSz);
|
||||
|
||||
Reference in New Issue
Block a user