feat(core/prodtest): use traces instead of errors in `tropic_is_paired()`
What changed, and why it matters
This commit changes how a production-test tool reports problems when checking whether a Tropic secure chip is paired. Previously, the check function itself printed error messages; now it only records diagnostic traces, and the calling commands decide whether to report an error. It also fixes two callers that were passing a dummy/NULL context so they now pass the real command-line interface, meaning their 'pairing required' error messages will actually be shown. This is a code-quality and diagnostics change in a factory/testing tool, not a fix for an exploitable security flaw in end-user firmware.
No security action required. Treat as normal code-quality/diagnostics improvement. If reviewing, verify that `cli_trace()` output is still captured in production-test logs so failures remain auditable.
Security signals we found
Error-vs-trace reporting refactor in factory diagnostic code
NULL cli context replaced with real cli context in two callers, restoring error visibility
No change to cryptographic logic, pairing state machine, or access control
No buffer, memory, authentication, or authorization changes
Evidence from the diff
In core/embed/projects/prodtest/cmd/prodtest_tropic.c, tropic_is_paired() is refactored to use cli_trace() instead of cli_error() when session-start or pairing-key-read operations return non-success codes. The function still returns a boolean result; callers now handle failure explicitly. Additionally, prodtest_tropic_handshake() and prodtest_tropic_lock() are updated to pass the real cli_t* to tropic_is_paired() instead of NULL, restoring proper error output. prodtest_tropic_pair() now emits its own error if pairing verification fails. The change is confined to the prodtest (manufacturing test) build target and the Tropic subsystem.
Changed components
core/embed/projects/prodtest/cmd/prodtest_tropic.cprodtest_tropic_handshake commandprodtest_tropic_lock commandprodtest_tropic_pair commandTropic secure-element pairing verification helperInspect captured patch +24 / −29
diff --git a/core/embed/projects/prodtest/cmd/prodtest_tropic.c b/core/embed/projects/prodtest/cmd/prodtest_tropic.c
index b2a70322d..08ae42936 100644
--- a/core/embed/projects/prodtest/cmd/prodtest_tropic.c
+++ b/core/embed/projects/prodtest/cmd/prodtest_tropic.c
@@ -688,25 +688,21 @@ static bool tropic_is_paired(cli_t* cli) {
// Try to establish a session using the unprivileged key pair.
ret = tropic_custom_session_start(cli, TROPIC_UNPRIVILEGED_PAIRING_KEY_SLOT);
if (ret != LT_OK) {
- if (cli != NULL) {
- cli_error(
- cli, CLI_ERROR,
- "`tropic_custom_session_start()` for unprivileged key failed with "
- "error '%s'",
- lt_ret_verbose(ret));
- }
+ cli_trace(
+ cli,
+ "`tropic_custom_session_start()` for unprivileged key failed with "
+ "error '%s'",
+ lt_ret_verbose(ret));
goto cleanup;
}
// Try to establish a session using the privileged key pair.
ret = tropic_custom_session_start(cli, TROPIC_PRIVILEGED_PAIRING_KEY_SLOT);
if (ret != LT_OK) {
- if (cli != NULL) {
- cli_error(cli, CLI_ERROR,
- "`tropic_custom_session_start()` for privileged key failed "
- "with error '%s'",
- lt_ret_verbose(ret));
- }
+ cli_trace(cli,
+ "`tropic_custom_session_start()` for privileged key failed "
+ "with error '%s'",
+ lt_ret_verbose(ret));
goto cleanup;
}
@@ -715,12 +711,10 @@ static bool tropic_is_paired(cli_t* cli) {
ret = lt_pairing_key_read(tropic_handle, public_read,
TROPIC_FACTORY_PAIRING_KEY_SLOT);
if (ret != LT_L3_SLOT_INVALID) {
- if (cli != NULL) {
- cli_error(cli, CLI_ERROR,
- "`lt_pairing_key_read()` for factory pairing key failed with "
- "error '%s'",
- lt_ret_verbose(ret));
- }
+ cli_trace(cli,
+ "`lt_pairing_key_read()` for factory pairing key failed with "
+ "error '%s'",
+ lt_ret_verbose(ret));
goto cleanup;
}
@@ -728,12 +722,10 @@ static bool tropic_is_paired(cli_t* cli) {
ret = lt_pairing_key_read(tropic_handle, public_read,
TR01_PAIRING_KEY_SLOT_INDEX_3);
if (ret != LT_L3_SLOT_EMPTY) {
- if (cli != NULL) {
- cli_error(cli, CLI_ERROR,
- "`lt_pairing_key_read()` for pairing key slot 3 failed with "
- "error '%s'",
- lt_ret_verbose(ret));
- }
+ cli_trace(cli,
+ "`lt_pairing_key_read()` for pairing key slot 3 failed with "
+ "error '%s'",
+ lt_ret_verbose(ret));
goto cleanup;
}
@@ -870,10 +862,13 @@ static void prodtest_tropic_pair(cli_t* cli) {
}
}
- if (tropic_is_paired(cli)) {
- cli_ok(cli, "");
+ if (!tropic_is_paired(cli)) {
+ cli_error(cli, CLI_ERROR, "`tropic_is_paired()` failed.");
+ goto cleanup;
}
+ cli_ok(cli, "");
+
cleanup:
memzero(privileged_private, sizeof(privileged_private));
memzero(unprivileged_private, sizeof(unprivileged_private));
@@ -990,7 +985,7 @@ static void prodtest_tropic_handshake(cli_t* cli) {
return;
}
- if (!tropic_is_paired(NULL)) {
+ if (!tropic_is_paired(cli)) {
cli_error(cli, CLI_ERROR, "`tropic-pair` must be called first.");
return;
}
@@ -1172,7 +1167,7 @@ static void prodtest_tropic_lock(cli_t* cli) {
return;
}
- if (!tropic_is_paired(NULL)) {
+ if (!tropic_is_paired(cli)) {
cli_error(cli, CLI_ERROR, "`tropic-pair` must be called first.");
return;
}
Why this scored 18/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.