fix(crypto): add missing memzero to `cardano.c`
What changed, and why it matters
This commit fixes a bug in the Cardano cryptocurrency key derivation code for Trezor hardware wallets. Previously, if a certain error path was hit during key derivation, the function would return early without wiping sensitive intermediate values from memory. The fix ensures those temporary secrets are always cleared, even when the function fails partway through. It also adds cleanup for a couple of additional temporary buffers that were not being wiped before.
Treat as a security hardening fix and include in release notes. Users running Cardano operations on affected firmware versions should update once a release containing this commit is available. No immediate external incident response is indicated by the diff alone.
Security signals we found
Missing secure wipe (memzero) on early-return error path
Addition of centralized cleanup label to guarantee wiping of confidential stack buffers
Use of LOCAL_CONFIDENTIAL annotation indicating these buffers hold sensitive material
Additional wiping of previously unzeroed temporaries `zl8` and `ctx`
Evidence from the diff
In hdnode_private_ckd_cardano() in crypto/cardano.c, the function previously returned 0 directly when hdnode_fill_public_key() failed during public derivation. Because the function returned early, the LOCAL_CONFIDENTIAL stack buffers data, z, priv_key, and res_key were not zeroized. The patch introduces a ret variable and a cleanup: label so that all sensitive intermediates are memzero()-ed before returning, and additionally zeroizes zl8 and ctx which were previously left unwiped on the normal success path. The change is defensive hardening against possible leakage of private key material or chain code fragments from stack memory.
Changed components
crypto/cardano.chdnode_private_ckd_cardano()Cardano key derivationInspect captured patch +7 / −2
diff --git a/crypto/cardano.c b/crypto/cardano.c
index 116c3e2d..a9c5668e 100644
--- a/crypto/cardano.c
+++ b/crypto/cardano.c
@@ -89,6 +89,7 @@ int hdnode_private_ckd_cardano(HDNode *inout, uint32_t index) {
keysize = 64;
}
+ int ret = 0;
LOCAL_CONFIDENTIAL uint8_t data[1 + 64 + 4];
LOCAL_CONFIDENTIAL uint8_t z[32 + 32];
LOCAL_CONFIDENTIAL uint8_t priv_key[64];
@@ -105,7 +106,7 @@ int hdnode_private_ckd_cardano(HDNode *inout, uint32_t index) {
memcpy(data + 1 + 32, inout->private_key_extension, 32);
} else { // public derivation
if (hdnode_fill_public_key(inout) != 0) {
- return 0;
+ goto cleanup;
}
data[0] = 2;
memcpy(data + 1, inout->public_key + 1, 32);
@@ -144,13 +145,17 @@ int hdnode_private_ckd_cardano(HDNode *inout, uint32_t index) {
inout->child_num = index;
memzero(inout->public_key, sizeof(inout->public_key));
inout->is_public_key_set = false;
+ ret = 1;
+cleanup:
// making sure to wipe our memory
memzero(z, sizeof(z));
memzero(data, sizeof(data));
memzero(priv_key, sizeof(priv_key));
memzero(res_key, sizeof(res_key));
- return 1;
+ memzero(zl8, sizeof(zl8));
+ memzero(&ctx, sizeof(ctx));
+ return ret;
}
int hdnode_from_secret_cardano(const uint8_t secret[CARDANO_SECRET_LENGTH],
Why this scored 59/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.