cryptocb: always run software cleanup in key Free functions

The WOLF_CRYPTO_CB_FREE path in wc_MlKemKey_Free, wc_dilithium_free,
and wc_ecc_free returned early when the crypto callback succeeded,
skipping local cleanup: ForceZero on private key material, PRF/hash
object frees (ML-KEM), SHAKE free and cached vector frees (ML-DSA),
and mp_forcezero on the private scalar and all hardware port frees
(ECC).

Any non-PKCS#11 callback returning 0 would silently leave key material
in memory. The PKCS#11 backend worked around this by returning
CRYPTOCB_UNAVAILABLE on success to force the fallthrough — a fragile
contract that is not part of the documented callback interface.

Fix by always continuing to software cleanup after invoking the
callback.

Remove the CRYPTOCB_UNAVAILABLE workaround from the three PKCS#11 free
dispatchers (ECC, ML-DSA, ML-KEM); they now return the real result of
C_DestroyObject.
This commit is contained in:
Tobias Frauenschläger
2026-03-26 15:08:33 +01:00
parent 21f1587c26
commit 85dd923355
4 changed files with 16 additions and 49 deletions
+2 -9
View File
@@ -10963,22 +10963,15 @@ int wc_dilithium_get_level(dilithium_key* key, byte* level)
*/
void wc_dilithium_free(dilithium_key* key)
{
#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE)
int ret = 0;
#endif
if (key != NULL) {
#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE)
if (key->devId != INVALID_DEVID) {
ret = wc_CryptoCb_Free(key->devId, WC_ALGO_TYPE_PK,
(void)wc_CryptoCb_Free(key->devId, WC_ALGO_TYPE_PK,
WC_PK_TYPE_PQC_SIG_KEYGEN,
WC_PQC_SIG_TYPE_DILITHIUM,
(void*)key);
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
return;
/* fall-through to software cleanup */
/* always continue to software cleanup */
}
(void)ret;
#endif
#ifdef WOLFSSL_WC_DILITHIUM
#ifndef WC_DILITHIUM_FIXED_ARRAY
+9 -10
View File
@@ -7930,23 +7930,19 @@ void wc_ecc_free_curve(ecc_set_type* curve, void* heap)
WOLFSSL_ABI
int wc_ecc_free(ecc_key* key)
{
#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE)
int ret = 0;
#endif
if (key == NULL) {
return 0;
}
#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE)
if (key->devId != INVALID_DEVID) {
ret = wc_CryptoCb_Free(key->devId, WC_ALGO_TYPE_PK,
/* Best-effort HSM resource release; errors are intentionally discarded
* so that software cleanup always runs and wc_ecc_free() retains its
* ABI guarantee of returning 0 on success. */
(void)wc_CryptoCb_Free(key->devId, WC_ALGO_TYPE_PK,
WC_PK_TYPE_EC_KEYGEN, 0, key);
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE))
return ret;
/* fall-through to software cleanup */
/* always continue to software cleanup */
}
(void)ret;
#endif
#if defined(WOLFSSL_ECDSA_SET_K) || defined(WOLFSSL_ECDSA_SET_K_ONE_LOOP) || \
@@ -7960,6 +7956,7 @@ int wc_ecc_free(ecc_key* key)
mp_free(key->sign_k);
#ifndef WOLFSSL_NO_MALLOC
XFREE(key->sign_k, key->heap, DYNAMIC_TYPE_ECC);
key->sign_k = NULL;
#endif
}
#endif
@@ -8025,8 +8022,10 @@ int wc_ecc_free(ecc_key* key)
#endif
#ifdef WOLFSSL_CUSTOM_CURVES
if (key->deallocSet && key->dp != NULL)
if (key->deallocSet && key->dp != NULL) {
wc_ecc_free_curve((ecc_set_type *)(wc_ptr_t)key->dp, key->heap);
key->dp = NULL;
}
#endif
#ifdef WOLFSSL_CHECK_MEM_ZERO
+5 -11
View File
@@ -391,21 +391,15 @@ int wc_MlKemKey_Init_Label(MlKemKey* key, int type, const char* label,
*/
int wc_MlKemKey_Free(MlKemKey* key)
{
#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE)
int ret = 0;
#endif
if (key != NULL) {
#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE)
if (key->devId != INVALID_DEVID) {
ret = wc_CryptoCb_Free(key->devId, WC_ALGO_TYPE_PK,
WC_PK_TYPE_PQC_KEM_KEYGEN, WC_PQC_KEM_TYPE_KYBER, (void*)key);
if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) {
return ret;
}
/* fall-through to software cleanup */
(void)wc_CryptoCb_Free(key->devId, WC_ALGO_TYPE_PK,
WC_PK_TYPE_PQC_KEM_KEYGEN,
WC_PQC_KEM_TYPE_KYBER,
(void*)key);
/* always continue to software cleanup */
}
(void)ret;
#endif
/* Dispose of PRF object. */
mlkem_prf_free(&key->prf);
-19
View File
@@ -6582,12 +6582,6 @@ int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx)
(ecc_key*)info->free.obj);
Pkcs11CloseSession(token, &session);
}
/* Return CRYPTOCB_UNAVAILABLE so wc_ecc_free() still
* performs software cleanup. This callback only releases
* the HSM object. Conditional because wc_ecc_free returns
* int and can propagate an HSM error to the caller. */
if (ret == 0)
ret = CRYPTOCB_UNAVAILABLE;
}
else
#endif
@@ -6601,11 +6595,6 @@ int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx)
(MlDsaKey*)info->free.obj);
Pkcs11CloseSession(token, &session);
}
/* Always return CRYPTOCB_UNAVAILABLE so wc_dilithium_free()
* performs software cleanup. This callback only releases
* the HSM object. Unconditional because wc_dilithium_free
* returns void and cannot propagate an error. */
ret = CRYPTOCB_UNAVAILABLE;
}
else
#endif
@@ -6619,14 +6608,6 @@ int wc_Pkcs11_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx)
(MlKemKey*)info->free.obj);
Pkcs11CloseSession(token, &session);
}
/* Return CRYPTOCB_UNAVAILABLE so wc_MlKemKey_Free() still
* performs software cleanup. This callback only releases
* the HSM object. Conditional because wc_MlKemKey_Free
* returns int and can propagate an HSM error to the caller.
*/
if (ret == 0) {
ret = CRYPTOCB_UNAVAILABLE;
}
}
else
#endif