feat(core): Use correct pairing keys in Tropic handshake.
What changed, and why it matters
This commit fixes how a Trezor hardware wallet selects cryptographic pairing keys when establishing a secure session with the Tropic secure chip. Previously the code always used a single fixed key slot (likely a factory/unprivileged key). After the change, it tries to use a privileged pairing key if available, and falls back to an unprivileged key if not. It also adds a small delay to avoid a 'chip busy' error from the Tropic chip. The change is security-relevant because using the wrong pairing key could weaken the secure channel or cause it to rely on a less trusted factory key, but the commit itself does not describe an active vulnerability or attack.
Treat as a hardening/fix commit rather than a confirmed vulnerability. Review whether the previous hardcoded key slot could have led to use of a factory/unprivileged key in production devices, and verify that the fallback logic cannot be forced by an attacker to downgrade the pairing key. If a security advisory is issued, request a CVE and disclosure details from the vendor.
Security signals we found
Change in cryptographic key selection for secure-element handshake
Fallback from privileged to unprivileged pairing key
Addition of hardware timing delay to avoid busy-state error
Removal of hardcoded factory/unprivileged key slot constant
No explicit vulnerability description or CVE in commit message
Evidence from the diff
The patch modifies core/embed/sec/tropic/tropic.c, which implements the Tropic secure-element handshake. Before: PKEY_INDEX_BYTE was hardcoded to PAIRING_KEY_SLOT_INDEX_0 and only secret_key_tropic_pairing_privileged() was fetched. After: the code chooses TROPIC_PRIVILEGED_PAIRING_KEY_SLOT on real hardware (or TROPIC_FACTORY_PAIRING_KEY_SLOT in the emulator), attempts to load the privileged private key, and if that fails falls back to TROPIC_UNPRIVILEGED_PAIRING_KEY_SLOT plus secret_key_tropic_pairing_unprivileged(). It also adds a 100 ms hal_delay() before lt_session_start() to avoid LT_L1_CHIP_BUSY. The test file change is cosmetic whitespace only. The commit title and message frame this as a feature/fix (‘Use correct pairing keys’) but do not disclose a CVE or credit a reporter.
Changed components
core/embed/sec/tropic/tropic.cTropic secure-element session establishmentTrezor Core firmware secure channel initializationInspect captured patch +17 / −7
diff --git a/core/embed/sec/tropic/tropic.c b/core/embed/sec/tropic/tropic.c
index 33ad962d..f211d9da 100644
--- a/core/embed/sec/tropic/tropic.c
+++ b/core/embed/sec/tropic/tropic.c
@@ -24,6 +24,7 @@
#include <sec/secret_keys.h>
#include <sec/tropic.h>
+#include <sys/systick.h>
#include <libtropic.h>
@@ -36,8 +37,6 @@
#include "ed25519-donna/ed25519.h"
#include "memzero.h"
-#define PKEY_INDEX_BYTE PAIRING_KEY_SLOT_INDEX_0
-
typedef struct {
bool initialized;
bool sec_chan_established;
@@ -66,18 +65,30 @@ bool tropic_init(void) {
goto cleanup;
}
- curve25519_key tropic_pubkey = {0};
- curve25519_key trezor_privkey = {0};
+#ifdef TREZOR_EMULATOR
+ pkey_index_t pairing_key_slot = TROPIC_FACTORY_PAIRING_KEY_SLOT;
+#else
+ pkey_index_t pairing_key_slot = TROPIC_PRIVILEGED_PAIRING_KEY_SLOT;
+#endif
- secbool pubkey_ok = secret_key_tropic_public(tropic_pubkey);
+ curve25519_key trezor_privkey = {0};
secbool privkey_ok = secret_key_tropic_pairing_privileged(trezor_privkey);
+ if (privkey_ok != sectrue) {
+ pairing_key_slot = TROPIC_UNPRIVILEGED_PAIRING_KEY_SLOT;
+ privkey_ok = secret_key_tropic_pairing_unprivileged(trezor_privkey);
+ }
+ curve25519_key tropic_pubkey = {0};
+ secbool pubkey_ok = secret_key_tropic_public(tropic_pubkey);
if (pubkey_ok == sectrue && privkey_ok == sectrue) {
curve25519_key trezor_pubkey = {0};
curve25519_scalarmult_basepoint(trezor_pubkey, trezor_privkey);
+ // Note: Without the delay below Tropic01 may return LT_L1_CHIP_BUSY. The
+ // length was chosen arbitrarily. A shorter delay may be sufficient.
+ hal_delay(100);
lt_ret_t ret =
- lt_session_start(&drv->handle, tropic_pubkey, PKEY_INDEX_BYTE,
+ lt_session_start(&drv->handle, tropic_pubkey, pairing_key_slot,
trezor_privkey, trezor_pubkey);
drv->sec_chan_established = (ret == LT_OK);
diff --git a/core/tests/test_trezor.crypto.tropic.py b/core/tests/test_trezor.crypto.tropic.py
index 341abfe1..ff96875d 100644
--- a/core/tests/test_trezor.crypto.tropic.py
+++ b/core/tests/test_trezor.crypto.tropic.py
@@ -19,7 +19,6 @@ class TestCryptoTropic(unittest.TestCase):
# key is not generated yet
self.assertIn("lt_ecc_eddsa_sign failed", str(e).lower())
-
tropic.key_generate(0)
# signing should work now that we have a key
Why this scored 57/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.