chore(core/embed): add missing memzero to modtrezorcrypto
What changed, and why it matters
This commit adds secure cleanup (memzero) and fixes memory allocation ordering in Trezor's cryptocurrency module. It ensures that sensitive key material, such as BIP-32 and Cardano secrets, is wiped from memory even when an error occurs during key derivation. Without these changes, secret data could remain in memory longer than intended after a failure, increasing the risk of exposure if an attacker could read device memory. The commit is a defensive hardening fix and does not appear to be a complete exploit by itself.
Treat as a security-hardening fix and include it in the next firmware release. Review related derivation paths for consistent memzero usage. Consider static analysis or audit of all secret-handling code to ensure no other intermediate buffers are left uncleared on exception paths.
Security signals we found
Sensitive key material cleanup with memzero added to error and success paths
Memory allocation reordered to allow proper object deletion on failure
Intermediate Cardano derivation secrets are now explicitly zeroed
Local HDNode copies are zeroed after transfer to the managed object
Defensive hardening in cryptographic seed-to-node derivation code
Evidence from the diff
The patch modifies modtrezorcrypto-bip32.h and modtrezorcrypto-cardano.h. It moves allocation of the mp_obj_HDNode_t object before derivation so that cleanup can free it on failure, and adds memzero calls on local HDNode and secret buffers in both success and error paths. In bip32_from_seed, the HDNode is now zeroed after copying into the object and on failure. In cardano functions, intermediate ‘secret’ buffers and local HDNode copies are zeroed before raising exceptions. This reduces the window where key material lingers in stack or heap memory.
Changed components
core/embed/upymod/modtrezorcrypto/modtrezorcrypto-bip32.hcore/embed/upymod/modtrezorcrypto/modtrezorcrypto-cardano.hTrezor Core firmware BIP-32 derivationTrezor Core firmware Cardano (SLIP-23 and Ledger-style) derivationInspect captured patch +22 / −6
### core/embed/upymod/modtrezorcrypto/modtrezorcrypto-bip32.h
@@ -542,16 +542,19 @@ static mp_obj_t mod_trezorcrypto_bip32_from_seed(mp_obj_t seed,
mp_raise_ValueError(MP_ERROR_TEXT("Invalid curve name"));
}
+ mp_obj_HDNode_t *o = mp_obj_malloc_with_finaliser(
+ mp_obj_HDNode_t, &mod_trezorcrypto_HDNode_type);
HDNode hdnode = {0};
int res = hdnode_from_seed(seedb.buf, seedb.len, curveb.buf, &hdnode);
if (!res) {
+ memzero(&hdnode, sizeof(hdnode));
+ m_del_obj(mp_obj_HDNode_t, o);
mp_raise_ValueError(MP_ERROR_TEXT("Failed to derive the root node"));
}
- mp_obj_HDNode_t *o = mp_obj_malloc_with_finaliser(
- mp_obj_HDNode_t, &mod_trezorcrypto_HDNode_type);
o->hdnode = hdnode;
+ memzero(&hdnode, sizeof(hdnode));
o->fingerprint = 0;
return MP_OBJ_FROM_PTR(o);
}
### core/embed/upymod/modtrezorcrypto/modtrezorcrypto-cardano.h
@@ -108,6 +108,7 @@ static mp_obj_t mod_trezorcrypto_from_secret(mp_obj_t secret) {
mp_obj_HDNode_t, &mod_trezorcrypto_HDNode_type);
const int res = hdnode_from_secret_cardano(bufinfo.buf, &o->hdnode);
if (res != 1) {
+ memzero(&o->hdnode, sizeof(o->hdnode));
m_del_obj(mp_obj_HDNode_t, o);
mp_raise_msg(
&mp_type_RuntimeError,
@@ -131,25 +132,31 @@ static mp_obj_t mod_trezorcrypto_from_seed_slip23(mp_obj_t seed) {
mp_raise_ValueError(MP_ERROR_TEXT("Invalid seed"));
}
+ mp_obj_HDNode_t *o = mp_obj_malloc_with_finaliser(
+ mp_obj_HDNode_t, &mod_trezorcrypto_HDNode_type);
uint8_t secret[CARDANO_SECRET_LENGTH] = {0};
HDNode hdnode = {0};
int res = 0;
res = secret_from_seed_cardano_slip23(bufinfo.buf, bufinfo.len, secret);
if (res != 1) {
+ memzero(secret, sizeof(secret));
+ m_del_obj(mp_obj_HDNode_t, o);
mp_raise_msg(&mp_type_RuntimeError,
MP_ERROR_TEXT("Unexpected failure in SLIP-23 derivation."));
}
res = hdnode_from_secret_cardano(secret, &hdnode);
+ memzero(secret, sizeof(secret));
if (res != 1) {
+ memzero(&hdnode, sizeof(hdnode));
+ m_del_obj(mp_obj_HDNode_t, o);
mp_raise_msg(
&mp_type_RuntimeError,
MP_ERROR_TEXT("Unexpected failure in constructing Cardano node."));
}
- mp_obj_HDNode_t *o = mp_obj_malloc_with_finaliser(
- mp_obj_HDNode_t, &mod_trezorcrypto_HDNode_type);
o->hdnode = hdnode;
+ memzero(&hdnode, sizeof(hdnode));
o->fingerprint = hdnode_fingerprint(&o->hdnode);
return MP_OBJ_FROM_PTR(o);
}
@@ -168,25 +175,31 @@ static mp_obj_t mod_trezorcrypto_from_seed_ledger(mp_obj_t seed) {
mp_raise_ValueError(MP_ERROR_TEXT("Invalid seed"));
}
+ mp_obj_HDNode_t *o = mp_obj_malloc_with_finaliser(
+ mp_obj_HDNode_t, &mod_trezorcrypto_HDNode_type);
uint8_t secret[CARDANO_SECRET_LENGTH] = {0};
HDNode hdnode = {0};
int res = 0;
res = secret_from_seed_cardano_ledger(bufinfo.buf, bufinfo.len, secret);
if (res != 1) {
+ memzero(secret, sizeof(secret));
+ m_del_obj(mp_obj_HDNode_t, o);
mp_raise_msg(&mp_type_RuntimeError,
MP_ERROR_TEXT("Unexpected failure in Ledger derivation."));
}
res = hdnode_from_secret_cardano(secret, &hdnode);
+ memzero(secret, sizeof(secret));
if (res != 1) {
+ memzero(&hdnode, sizeof(hdnode));
+ m_del_obj(mp_obj_HDNode_t, o);
mp_raise_msg(
&mp_type_RuntimeError,
MP_ERROR_TEXT("Unexpected failure in constructing Cardano node."));
}
- mp_obj_HDNode_t *o = mp_obj_malloc_with_finaliser(
- mp_obj_HDNode_t, &mod_trezorcrypto_HDNode_type);
o->hdnode = hdnode;
+ memzero(&hdnode, sizeof(hdnode));
o->fingerprint = hdnode_fingerprint(&o->hdnode);
return MP_OBJ_FROM_PTR(o);
}Why this scored 44/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.