feat(core/embed): introduce tropic progress in `lt_port_delay()`
What changed, and why it matters
This commit is a user-interface improvement for the Tropic secure chip integration. It moves progress-bar updates so they happen automatically during built-in hardware delays, rather than being sprinkled manually around cryptographic operations. There is no security vulnerability here; it is a code-quality and UX refactor.
No security action required. Treat as normal UX/refactor code review.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch refactors how ui_progress() callbacks are invoked during Tropic operations. Previously each high-level function in tropic.c called ui_progress() manually between lt_* operations. Now a global callback is registered via tropic_set_ui_progress() and invoked from lt_port_delay() inside the STM32 HAL, so progress updates occur during hardware-enforced delays. The Unix emulator stub also implements the setter. Error handling is improved with centralized cleanup labels that clear the callback and sensitive buffers. No cryptographic logic, trust boundaries, or access controls are changed.
Changed components
core/embed/sec/tropic/stm32/tropic01.ccore/embed/sec/tropic/tropic.ccore/embed/sec/tropic/unix/tropic01.cInspect captured patch +79 / −61
diff --git a/core/embed/sec/tropic/stm32/tropic01.c b/core/embed/sec/tropic/stm32/tropic01.c
index 1aef0e413..d273e6236 100644
--- a/core/embed/sec/tropic/stm32/tropic01.c
+++ b/core/embed/sec/tropic/stm32/tropic01.c
@@ -34,6 +34,10 @@ typedef struct {
static tropic01_hal_driver_t g_tropic01_hal_driver = {.initialized = false};
+static tropic_ui_progress_t ui_progress = NULL;
+
+void tropic_set_ui_progress(tropic_ui_progress_t f) { ui_progress = f; }
+
void tropic01_reset(void) {
HAL_GPIO_WritePin(TROPIC01_PWR_PORT, TROPIC01_PWR_PIN, GPIO_PIN_SET);
systick_delay_ms(10);
@@ -182,6 +186,10 @@ lt_ret_t lt_port_delay(lt_l2_state_t *s2, uint32_t ms) {
systick_delay_ms(ms);
+ if (ui_progress != NULL) {
+ ui_progress();
+ }
+
return LT_OK;
}
diff --git a/core/embed/sec/tropic/tropic.c b/core/embed/sec/tropic/tropic.c
index f710c835e..f2fdaa9bd 100644
--- a/core/embed/sec/tropic/tropic.c
+++ b/core/embed/sec/tropic/tropic.c
@@ -367,6 +367,9 @@ void tropic_random_buffer_time(uint32_t *time_ms) {
#ifdef USE_STORAGE
+// Defined in tropic01.c
+void tropic_set_ui_progress(tropic_ui_progress_t f);
+
static mac_and_destroy_slot_t get_first_mac_and_destroy_slot(
tropic_driver_t *drv) {
return drv->pairing_key_index == TROPIC_UNPRIVILEGED_PAIRING_KEY_SLOT
@@ -401,9 +404,12 @@ bool tropic_pin_stretch(tropic_ui_progress_t ui_progress, uint16_t pin_index,
}
tropic_driver_t *drv = &g_tropic_driver;
+ bool ret = false;
+
+ tropic_set_ui_progress(ui_progress);
if (!tropic_session_start()) {
- return false;
+ goto cleanup;
}
mac_and_destroy_slot_t first_slot_index = get_first_mac_and_destroy_slot(drv);
@@ -412,18 +418,20 @@ bool tropic_pin_stretch(tropic_ui_progress_t ui_progress, uint16_t pin_index,
hmac_sha256(stretched_pin, TROPIC_MAC_AND_DESTROY_SIZE, NULL, 0, digest);
- ui_progress();
-
- lt_ret_t res = lt_mac_and_destroy(&drv->handle, first_slot_index + pin_index,
- digest, digest);
-
- ui_progress();
+ if (lt_mac_and_destroy(&drv->handle, first_slot_index + pin_index, digest,
+ digest) != LT_OK) {
+ goto cleanup;
+ }
hmac_sha256(stretched_pin, TROPIC_MAC_AND_DESTROY_SIZE, digest,
sizeof(digest), stretched_pin);
+ ret = true;
+
+cleanup:
memzero(digest, sizeof(digest));
- return res == LT_OK;
+ tropic_set_ui_progress(NULL);
+ return ret;
}
void tropic_pin_stretch_time(uint32_t *time_ms) {
@@ -438,32 +446,32 @@ bool tropic_pin_reset_slots(
}
tropic_driver_t *drv = &g_tropic_driver;
+ bool ret = false;
+
+ tropic_set_ui_progress(ui_progress);
if (!tropic_session_start()) {
- return false;
+ goto cleanup;
}
- lt_ret_t res = LT_FAIL;
uint8_t output[TROPIC_MAC_AND_DESTROY_SIZE] = {0};
mac_and_destroy_slot_t first_slot_index = get_first_mac_and_destroy_slot(drv);
- ui_progress();
-
for (int i = 0; i <= pin_index; i++) {
- res = lt_mac_and_destroy(&drv->handle, first_slot_index + i, reset_key,
- output);
- if (res != LT_OK) {
+ if (lt_mac_and_destroy(&drv->handle, first_slot_index + i, reset_key,
+ output) != LT_OK) {
goto cleanup;
}
-
- ui_progress();
}
+ ret = true;
+
cleanup:
memzero(output, sizeof(output));
+ tropic_set_ui_progress(NULL);
- return res == LT_OK;
+ return ret;
}
void tropic_pin_reset_slots_time(uint32_t *time_ms, uint16_t pin_index) {
@@ -477,60 +485,54 @@ bool tropic_pin_set(
uint8_t stretched_pins[PIN_MAX_TRIES][TROPIC_MAC_AND_DESTROY_SIZE],
uint8_t reset_key[TROPIC_MAC_AND_DESTROY_SIZE]) {
tropic_driver_t *drv = &g_tropic_driver;
+ bool ret = false;
+
+ tropic_set_ui_progress(ui_progress);
if (!tropic_session_start()) {
- return false;
+ goto cleanup;
}
if (!rng_fill_buffer_strong(reset_key, TROPIC_MAC_AND_DESTROY_SIZE)) {
- return false;
+ goto cleanup;
}
- lt_ret_t res = LT_FAIL;
uint8_t output[TROPIC_MAC_AND_DESTROY_SIZE] = {0};
uint8_t digest[TROPIC_MAC_AND_DESTROY_SIZE] = {0};
mac_and_destroy_slot_t first_slot_index = get_first_mac_and_destroy_slot(drv);
- ui_progress();
-
for (int i = 0; i < PIN_MAX_TRIES; i++) {
- res = lt_mac_and_destroy(&drv->handle, first_slot_index + i, reset_key,
- output);
- if (res != LT_OK) {
+ if (lt_mac_and_destroy(&drv->handle, first_slot_index + i, reset_key,
+ output) != LT_OK) {
goto cleanup;
}
hmac_sha256(stretched_pins[i], TROPIC_MAC_AND_DESTROY_SIZE, NULL, 0,
digest);
- ui_progress();
-
- res =
- lt_mac_and_destroy(&drv->handle, first_slot_index + i, digest, digest);
- if (res != LT_OK) {
+ if (lt_mac_and_destroy(&drv->handle, first_slot_index + i, digest,
+ digest) != LT_OK) {
goto cleanup;
}
- ui_progress();
-
hmac_sha256(stretched_pins[i], TROPIC_MAC_AND_DESTROY_SIZE, digest,
sizeof(digest), stretched_pins[i]);
- res = lt_mac_and_destroy(&drv->handle, first_slot_index + i, reset_key,
- output);
- if (res != LT_OK) {
+ if (lt_mac_and_destroy(&drv->handle, first_slot_index + i, reset_key,
+ output) != LT_OK) {
goto cleanup;
}
-
- ui_progress();
}
+ ret = true;
+
cleanup:
memzero(output, sizeof(output));
memzero(digest, sizeof(digest));
+ tropic_set_ui_progress(NULL);
- return res == LT_OK;
+ return ret;
}
void tropic_pin_set_time(uint32_t *time_ms) {
@@ -547,13 +549,14 @@ bool tropic_pin_set_kek_masks(
const uint8_t kek[TROPIC_MAC_AND_DESTROY_SIZE],
const uint8_t stretched_pins[PIN_MAX_TRIES][TROPIC_MAC_AND_DESTROY_SIZE]) {
tropic_driver_t *drv = &g_tropic_driver;
+ bool ret = false;
+
+ tropic_set_ui_progress(ui_progress);
if (!tropic_session_start()) {
- return false;
+ goto cleanup;
}
- lt_ret_t ret = LT_FAIL;
-
uint8_t masks[PIN_MAX_TRIES * TROPIC_MAC_AND_DESTROY_SIZE] = {0};
for (int i = 0; i < PIN_MAX_TRIES; i++) {
for (int j = 0; j < TROPIC_MAC_AND_DESTROY_SIZE; j++) {
@@ -562,29 +565,24 @@ bool tropic_pin_set_kek_masks(
}
}
- ui_progress();
-
uint16_t masked_kek_slot = get_kek_masks_slot(drv);
- ret = lt_r_mem_data_erase(&drv->handle, masked_kek_slot);
- if (ret != LT_OK) {
+ if (lt_r_mem_data_erase(&drv->handle, masked_kek_slot) != LT_OK) {
goto cleanup;
}
- ui_progress();
-
- ret =
- lt_r_mem_data_write(&drv->handle, masked_kek_slot, masks, sizeof(masks));
- if (ret != LT_OK) {
+ if (lt_r_mem_data_write(&drv->handle, masked_kek_slot, masks,
+ sizeof(masks)) != LT_OK) {
goto cleanup;
}
- ui_progress();
+ ret = true;
cleanup:
memzero(masks, sizeof(masks));
+ tropic_set_ui_progress(NULL);
- return ret == LT_OK;
+ return ret;
}
void tropic_pin_set_kek_masks_time(uint32_t *time_ms) {
@@ -598,8 +596,11 @@ bool tropic_pin_unmask_kek(
uint8_t kek[TROPIC_MAC_AND_DESTROY_SIZE]) {
tropic_driver_t *drv = &g_tropic_driver;
+ tropic_set_ui_progress(ui_progress);
+ bool ret = false;
+
if (!tropic_session_start()) {
- return false;
+ goto cleanup;
}
uint8_t masks[R_MEM_DATA_SIZE_MAX] = {0};
@@ -610,24 +611,25 @@ bool tropic_pin_unmask_kek(
uint16_t masked_kek_slot = get_kek_masks_slot(drv);
- ui_progress();
-
if (lt_r_mem_data_read(&drv->handle, masked_kek_slot, masks, &length) !=
LT_OK) {
- return false;
+ goto cleanup;
}
if (length != PIN_MAX_TRIES * TROPIC_MAC_AND_DESTROY_SIZE) {
- return false;
+ goto cleanup;
}
- ui_progress();
-
for (int i = 0; i < TROPIC_MAC_AND_DESTROY_SIZE; i++) {
kek[i] =
masks[pin_index * TROPIC_MAC_AND_DESTROY_SIZE + i] ^ stretched_pin[i];
}
- return true;
+
+ ret = true;
+
+cleanup:
+ tropic_set_ui_progress(NULL);
+ return ret;
}
void tropic_pin_unmask_kek_time(uint32_t *time_ms) {
diff --git a/core/embed/sec/tropic/unix/tropic01.c b/core/embed/sec/tropic/unix/tropic01.c
index 3e345df05..d68fb893b 100644
--- a/core/embed/sec/tropic/unix/tropic01.c
+++ b/core/embed/sec/tropic/unix/tropic01.c
@@ -20,8 +20,16 @@
#include <trezor_rtl.h>
+#include <sec/tropic.h>
+
bool tropic_hal_init(void) { return true; }
void tropic_hal_deinit(void) {}
+void tropic_set_ui_progress(tropic_ui_progress_t ui_progress) {
+ if (ui_progress != NULL) {
+ ui_progress();
+ }
+}
+
#endif
Why this scored 15/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.