feat(core): Use randomness from Tropic to generate secrets.
What changed, and why it matters
This commit changes how secret keys are generated during Trezor device production testing. Previously, randomness came from the device's own RNG and (on some models) an Infineon OPTIGA chip. The patch adds support for also mixing in randomness from a new 'Tropic' secure chip, and ensures a factory secure session with Tropic is started before secrets are generated. This is a feature addition, not a vulnerability fix. It improves entropy quality but introduces a new hardware dependency and a TODO-removal that should be reviewed for correctness.
Review the new Tropic integration for correctness: confirm `lt_random_value_get` and `prodtest_tropic_factory_session_start` error handling, verify the factory pairing key lifecycle matches the provisioning stage, and ensure the shared `buffer` cannot leak partial randomness if one branch fails before `memzero`. Consider whether this change warrants a changelog entry despite the [no changelog] tag, because it affects production secret generation.
Security signals we found
New hardware RNG source integrated into secret generation
Removal of a TODO placeholder for Tropic randomness
Addition of factory secure-session precondition before secret generation
Shared buffer reuse between OPTIGA and Tropic branches (non-overlapping macros, but same variable name)
Potential failure mode: if Tropic session start or randomness read fails, secret generation aborts
Evidence from the diff
In core/embed/projects/prodtest/cmd/prodtest_secrets.c, generate_random_secret() is refactored. A shared local buffer is now used to receive random bytes from either OPTIGA (optiga_random_buffer) or Tropic (lt_random_value_get), which are then XORed into the secret. The old OPTIGA-specific optiga_secret buffer is removed. A new block in prodtest_secrets_init() calls prodtest_tropic_factory_session_start() before secret generation when USE_TROPIC is defined, with a comment explaining that the factory pairing key must still be valid at this provisioning stage. The previous Tropic code was a TODO; it is now implemented.
Changed components
core/embed/projects/prodtest/cmd/prodtest_secrets.cTropic secure chip integration (USE_TROPIC)OPTIGA secure chip integration (USE_OPTIGA)Production-test / provisioning flowInspect captured patch +31 / −8
diff --git a/core/embed/projects/prodtest/cmd/prodtest_secrets.c b/core/embed/projects/prodtest/cmd/prodtest_secrets.c
index e929ebe7d..289b4abaa 100644
--- a/core/embed/projects/prodtest/cmd/prodtest_secrets.c
+++ b/core/embed/projects/prodtest/cmd/prodtest_secrets.c
@@ -22,9 +22,6 @@
#include <string.h>
#include <rtl/cli.h>
-#ifdef USE_OPTIGA
-#include <sec/optiga_commands.h>
-#endif
#include <sec/secret.h>
#include <sec/secret_keys.h>
@@ -34,6 +31,16 @@
#include "secbool.h"
#include "secure_channel.h"
+#ifdef USE_OPTIGA
+#include <sec/optiga.h>
+#endif
+
+#ifdef USE_TROPIC
+#include <libtropic.h>
+#include <sec/tropic.h>
+#include "prodtest_tropic.h"
+#endif
+
#ifndef TREZOR_EMULATOR
#include <trezor_model.h>
#endif
@@ -43,21 +50,26 @@
secbool generate_random_secret(uint8_t* secret, size_t length) {
random_buffer(secret, length);
+ uint8_t buffer[length];
#ifdef USE_OPTIGA
- uint8_t optiga_secret[length];
- if (OPTIGA_SUCCESS != optiga_get_random(optiga_secret, length)) {
+ if (!optiga_random_buffer(buffer, length)) {
return secfalse;
}
for (size_t i = 0; i < length; i++) {
- secret[i] ^= optiga_secret[i];
+ secret[i] ^= buffer[i];
}
- memzero(optiga_secret, sizeof(optiga_secret));
#endif
#ifdef USE_TROPIC
- // TODO: Generate randomness using tropic and xor it with `secret`.
+ if (LT_OK != lt_random_value_get(tropic_get_handle(), buffer, length)) {
+ return secfalse;
+ }
+ for (size_t i = 0; i < length; i++) {
+ secret[i] ^= buffer[i];
+ }
#endif
+ memzero(buffer, sizeof(buffer));
return sectrue;
}
@@ -104,6 +116,17 @@ static void prodtest_secrets_init(cli_t* cli) {
return;
}
+#ifdef USE_TROPIC
+ // Ensure that a session with Tropic is established so that we can include
+ // randomness from the chip when generating the secrets. At this point in
+ // provisioning the factory pairing key should still be valid.
+ if (!prodtest_tropic_factory_session_start(tropic_get_handle())) {
+ cli_error(cli, CLI_ERROR,
+ "`prodtest_tropic_factory_session_start` failed.");
+ return;
+ }
+#endif
+
#ifdef SECRET_PRIVILEGED_MASTER_KEY_SLOT
if (set_random_secret(SECRET_PRIVILEGED_MASTER_KEY_SLOT,
SECRET_MASTER_KEY_SLOT_SIZE) != sectrue) {
Why this scored 32/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.