feat(core/prodtest): introduce logging in `tropic_get_pubkey()` and `tropic_get_cert_chain_ptr()`
What changed, and why it matters
This commit only adds extra diagnostic log messages to two internal helper functions used during factory production testing of the Tropic secure chip. It does not change how keys or certificates are handled, and the new logging is compiled out of normal user firmware. There is no direct security vulnerability here; it is a minor debugging improvement.
No security action required. Treat as a normal feature/debugging commit. If desired, verify that `cli_trace()` output in prodtest is not captured in persistent factory logs that could leave the device.
Security signals we found
No change to cryptographic operations or trust boundaries
New code is guarded by `TREZOR_PRODTEST` and absent from production firmware
Logging output may expose verbose Tropic error strings, but only in a factory-prodtest CLI context
No buffer-size, pointer, or input-validation changes observed
Evidence from the diff
The change threads a cli_t* pointer through tropic_get_pubkey() and tropic_get_cert_chain_ptr() so that, when TREZOR_PRODTEST is defined, failure return codes from lt_get_info_cert_store() and lt_get_st_pub() can be printed via cli_trace(). In non-prodtest builds the parameter is unused and the behavior is unchanged. The commit does not alter certificate parsing, key derivation, session handling, or access-control logic.
Changed components
core/embed/sec/tropic/tropic.ccore/embed/sec/tropic/inc/sec/tropic.hcore/embed/projects/prodtest/cmd/prodtest_tropic.cInspect captured patch +21 / −11
diff --git a/core/embed/projects/prodtest/cmd/prodtest_tropic.c b/core/embed/projects/prodtest/cmd/prodtest_tropic.c
index 97eb2910..c7ccc3c3 100644
--- a/core/embed/projects/prodtest/cmd/prodtest_tropic.c
+++ b/core/embed/projects/prodtest/cmd/prodtest_tropic.c
@@ -552,7 +552,7 @@ static void prodtest_tropic_certtropic_read(cli_t* cli) {
const uint8_t* tropic_cert_chain = NULL;
size_t tropic_cert_chain_length = 0;
- if (!tropic_get_cert_chain_ptr(&tropic_cert_chain,
+ if (!tropic_get_cert_chain_ptr(cli, &tropic_cert_chain,
&tropic_cert_chain_length)) {
cli_error(cli, CLI_ERROR, "`tropic_get_cert_chain_ptr()` failed");
return;
@@ -777,7 +777,7 @@ static void prodtest_tropic_pair(cli_t* cli) {
// Get the Tropic01 public pairing key from the chip's certificate.
curve25519_key tropic_public = {0};
- if (!tropic_get_pubkey(tropic_public)) {
+ if (!tropic_get_pubkey(cli, tropic_public)) {
cli_error(cli, CLI_ERROR, "`tropic_get_tropic_pubkey()` failed");
goto cleanup;
}
@@ -877,7 +877,7 @@ static void prodtest_tropic_get_access_credential(cli_t* cli) {
}
curve25519_key tropic_public = {0};
- if (!tropic_get_pubkey(tropic_public)) {
+ if (!tropic_get_pubkey(cli, tropic_public)) {
cli_error(cli, CLI_ERROR, "`tropic_get_tropic_pubkey()` failed");
goto cleanup;
}
diff --git a/core/embed/sec/tropic/inc/sec/tropic.h b/core/embed/sec/tropic/inc/sec/tropic.h
index 9aab1f8b..30b5729a 100644
--- a/core/embed/sec/tropic/inc/sec/tropic.h
+++ b/core/embed/sec/tropic/inc/sec/tropic.h
@@ -82,9 +82,10 @@ lt_ret_t tropic_session_invalidate(void);
bool tropic_wait_for_ready(void);
-bool tropic_get_pubkey(curve25519_key pubkey);
+bool tropic_get_pubkey(cli_t* cli, curve25519_key pubkey);
-bool tropic_get_cert_chain_ptr(uint8_t const** cert_chain, size_t* length);
+bool tropic_get_cert_chain_ptr(cli_t* cli, uint8_t const** cert_chain,
+ size_t* length);
#endif
#endif
diff --git a/core/embed/sec/tropic/tropic.c b/core/embed/sec/tropic/tropic.c
index 9f02e055..bfff633a 100644
--- a/core/embed/sec/tropic/tropic.c
+++ b/core/embed/sec/tropic/tropic.c
@@ -128,7 +128,8 @@ static uint8_t tropic_cert_chain[LT_NUM_CERTIFICATES *
static size_t tropic_cert_chain_length = 0;
static curve25519_key tropic_public_cached = {0};
-static bool cache_tropic_cert_chain(void) {
+// If `TREZOR_PRODTEST` is not defined, the `cli` argument is ignored.
+static bool cache_tropic_cert_chain(cli_t *cli) {
if (tropic_cert_chain_length > 0) {
return true;
}
@@ -144,11 +145,19 @@ static bool cache_tropic_cert_chain(void) {
ret = lt_get_info_cert_store(&g_tropic_driver.handle, &cert_store);
if (ret != LT_OK) {
+#if TREZOR_PRODTEST
+ cli_trace(cli, "lt_get_info_cert_store() failed with error '%s'",
+ lt_ret_verbose(ret));
+#endif
return false;
}
ret = lt_get_st_pub(&cert_store, tropic_public_cached);
if (ret != LT_OK) {
+#if TREZOR_PRODTEST
+ cli_trace(cli, "lt_get_st_pub() failed with error '%s'",
+ lt_ret_verbose(ret));
+#endif
return false;
}
@@ -166,17 +175,17 @@ static bool cache_tropic_cert_chain(void) {
return true;
}
-bool tropic_get_pubkey(curve25519_key pubkey) {
- if (!cache_tropic_cert_chain()) {
+bool tropic_get_pubkey(cli_t *cli, curve25519_key pubkey) {
+ if (!cache_tropic_cert_chain(cli)) {
return false;
}
memcpy(pubkey, tropic_public_cached, sizeof(curve25519_key));
return true;
}
-bool tropic_get_cert_chain_ptr(uint8_t const **cert_chain,
+bool tropic_get_cert_chain_ptr(cli_t *cli, uint8_t const **cert_chain,
size_t *cert_chain_length) {
- if (!cache_tropic_cert_chain()) {
+ if (!cache_tropic_cert_chain(cli)) {
return false;
}
*cert_chain = tropic_cert_chain;
@@ -265,7 +274,7 @@ lt_ret_t tropic_custom_session_start(cli_t *cli,
if (secret_key_tropic_public(tropic_public) != sectrue) {
#if !PRODUCTION || defined(TREZOR_PRODTEST)
if (pairing_key_index != TROPIC_FACTORY_PAIRING_KEY_SLOT ||
- !tropic_get_pubkey(tropic_public))
+ !tropic_get_pubkey(cli, tropic_public))
#endif
{
#ifdef TREZOR_PRODTEST
Why this scored 19/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.