feat(storage,core/embed): support multiple stretched pins in optiga
What changed, and why it matters
This commit rewrites how the Trezor hardware wallet stores and verifies PINs when the Optiga secure chip is present. It replaces a single 'stretched PIN' slot with a chain of up to 10 slots (currently configured to 1, so behavior is unchanged for users). The goal is to make future brute-force and side-channel attacks against the PIN harder by adding more authorization steps and by separating the HMAC counter reset key from the main unlock path. Because the new code is complex and touches the PIN verification flow, any bug here could affect device security, but the commit itself is a defensive hardening feature rather than a fix for a known vulnerability.
Treat as a high-risk hardening change requiring careful review of the new authorization chain, state clearing, counter-reset logic, and fallback paths. Verify that STRETCHED_PIN_COUNT=1 preserves exact legacy behavior and that enabling values >1 does not introduce bypasses, race conditions, or counter-exhaustion bugs. Run formal/spec-based tests on PIN set/verify/change and firmware downgrade/upgrade scenarios before release.
Security signals we found
Refactor of PIN verification and key-derivation path in secure-element code
Introduction of chained authorization metadata across multiple Optiga OIDs
New encrypted storage key (OPTIGA_HMAC_RESET_KEY) for HMAC counter reset
Changes to counter reset values and timing estimates for PIN operations
Addition of mpu_reconfig(MPU_MODE_STORAGE) moved earlier in unlock/change_pin entry points
No changelog entry and no linked advisory or CVE
Evidence from the diff
The change refactors optiga_pin_set/optiga_pin_verify to support STRETCHED_PIN_COUNT chained stretched-PIN data objects (OIDs). It introduces optiga_pin_init, optiga_pin_stretch_cmac_ecdh, and optiga_pin_reset_hmac_counter, and changes metadata so each OID authorizes the next in the chain. A new OPTIGA_HMAC_RESET_KEY is stored encrypted in storage and used to reset the HMAC counter after a successful unlock when more than one slot exists. The current header still defines STRETCHED_PIN_COUNT as 1, so the multi-slot logic is compiled in but not active yet. The patch is large, adds several new authorization/clear-state sequences, and changes timing estimates and counter reset values.
Changed components
core/embed/sec/optiga/optiga.ccore/embed/sec/optiga/inc/sec/optiga.hcore/embed/sec/optiga/unix/optiga.cstorage/storage.cstorage/storage.hInspect captured patch +434 / −150
diff --git a/core/embed/sec/optiga/inc/sec/optiga.h b/core/embed/sec/optiga/inc/sec/optiga.h
index 2f7f71125..a4a3e188b 100644
--- a/core/embed/sec/optiga/inc/sec/optiga.h
+++ b/core/embed/sec/optiga/inc/sec/optiga.h
@@ -62,13 +62,25 @@ void optiga_set_sec_max(void);
bool __wur optiga_random_buffer(uint8_t *dest, size_t size);
-bool __wur optiga_pin_set(optiga_ui_progress_t ui_progress,
- uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]);
+bool __wur optiga_pin_init(optiga_ui_progress_t ui_progress);
-uint32_t optiga_estimate_time_ms(storage_pin_op_t op);
+bool optiga_pin_stretch_cmac_ecdh(
+ optiga_ui_progress_t ui_progress,
+ uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]);
+
+bool __wur optiga_pin_set(
+ optiga_ui_progress_t ui_progress,
+ uint8_t stretched_pins[STRETCHED_PIN_COUNT][OPTIGA_PIN_SECRET_SIZE],
+ uint8_t hmac_reset_key[OPTIGA_PIN_SECRET_SIZE]);
+
+bool __wur
+optiga_pin_reset_hmac_counter(optiga_ui_progress_t ui_progress,
+ const uint8_t reset_key[OPTIGA_PIN_SECRET_SIZE]);
+
+uint32_t optiga_estimate_time_ms(storage_pin_op_t op, uint8_t slot_index);
optiga_pin_result __wur
-optiga_pin_verify(optiga_ui_progress_t ui_progress,
+optiga_pin_verify(optiga_ui_progress_t ui_progress, uint8_t index,
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]);
optiga_pin_result __wur
diff --git a/core/embed/sec/optiga/optiga.c b/core/embed/sec/optiga/optiga.c
index 7cda0c021..e211ef5e3 100644
--- a/core/embed/sec/optiga/optiga.c
+++ b/core/embed/sec/optiga/optiga.c
@@ -17,6 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "sec/optiga_common.h"
#ifdef SECURE_MODE
#include <trezor_rtl.h>
@@ -37,13 +38,10 @@
// 0xF1D0).
#define OID_PIN_SECRET (OPTIGA_OID_DATA + 0)
-// Digest of the stretched PIN (OID 0xF1D4).
-#define OID_STRETCHED_PIN (OPTIGA_OID_DATA + 4)
-
// Counter-protected key for HMAC-SHA256 PIN stretching step (OID 0xF1D8).
#define OID_PIN_HMAC (OPTIGA_OID_DATA + 8)
-// Counter which limits the guesses at OID_STRETCHED_PIN (OID 0xE120).
+// Counter which limits the guesses at OID_STRETCHED_PINS (OID 0xE120).
#define OID_STRETCHED_PIN_CTR (OPTIGA_OID_COUNTER + 0)
// Counter which limits the use of OID_PIN_HMAC (OID 0xE122).
@@ -69,6 +67,20 @@
// The throttling delay when the security event counter is at its maximum.
#define OPTIGA_T_MAX_MS 5000
+// Stretched PINs
+// The first stretched PIN is OPTIGA_OID_DATA + 4 to preserve compatiblity with
+// Trezors without Tropics.
+// OPTIGA_OID_DATA + 0 and OPTIGA_OID_DATA + 8 are not used since they are
+// occupied by the PIN secret and PIN HMAC secret.
+static const uint16_t OID_STRETCHED_PINS[] = {
+ OPTIGA_OID_DATA + 4, OPTIGA_OID_DATA + 1, OPTIGA_OID_DATA + 2,
+ OPTIGA_OID_DATA + 3, OPTIGA_OID_DATA + 5, OPTIGA_OID_DATA + 6,
+ OPTIGA_OID_DATA + 7, OPTIGA_OID_DATA + 9, OPTIGA_OID_DATA + 10,
+ OPTIGA_OID_DATA + 11};
+_Static_assert(sizeof(OID_STRETCHED_PINS) / sizeof(OID_STRETCHED_PINS[0]) >=
+ STRETCHED_PIN_COUNT,
+ "STRETCHED_PIN_COUNT too large");
+
// Initial value of the counter which limits the total number of PIN stretching
// operations. The limit is 600000 stretching operations, which equates to
// 300000 / PIN_STRETCH_ITERATIONS unlock operations over the lifetime of the
@@ -79,8 +91,11 @@ static const optiga_metadata_item TYPE_AUTOREF =
OPTIGA_META_VALUE(OPTIGA_DATA_TYPE_AUTOREF);
static const optiga_metadata_item TYPE_PRESSEC =
OPTIGA_META_VALUE(OPTIGA_DATA_TYPE_PRESSEC);
-static const optiga_metadata_item ACCESS_STRETCHED_PIN =
- OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_AUTO, OID_STRETCHED_PIN);
+static const optiga_metadata_item ACCESS_FIRST_STRETCHED_PIN =
+ OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_AUTO, OID_STRETCHED_PINS[0]);
+static const optiga_metadata_item ACCESS_LAST_STRETCHED_PIN =
+ OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_AUTO,
+ OID_STRETCHED_PINS[STRETCHED_PIN_COUNT - 1]);
static const optiga_metadata_item ACCESS_PIN_SECRET =
OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_AUTO, OID_PIN_SECRET);
static const optiga_metadata_item ACCESS_STRETCHED_PIN_CTR =
@@ -233,7 +248,8 @@ void optiga_set_sec_max(void) {
sizeof(invalid_point), buffer, sizeof(buffer), &size);
}
-uint32_t optiga_estimate_time_ms(storage_pin_op_t op) {
+// slot_index is only used if op == STORAGE_PIN_OP_VERIFY
+uint32_t optiga_estimate_time_ms(storage_pin_op_t op, uint8_t pin_index) {
uint8_t sec = 0;
if (!optiga_read_sec(&sec)) {
return UINT32_MAX;
@@ -252,13 +268,46 @@ uint32_t optiga_estimate_time_ms(storage_pin_op_t op) {
// To estimate the overall time of the PIN operation we multiply the
// throttling delay by the number of protected Optiga commands and add the
// time required to execute all Optiga commands without throttling delays.
+
+ // Time: (STRETCHED_PIN_COUNT + 7) * 15 ms + 295 ms
+ const int init_time = (STRETCHED_PIN_COUNT + 7) * 15 + 295;
+ const int init_protected_command_count = 0;
+
+ const int stretch_cmac_ecdh_time = PIN_STRETCH_ITERATIONS * 275;
+ const int stretch_cmac_ecdh_protected_command_count =
+ PIN_STRETCH_ITERATIONS * 2;
+
+ const int set_time = STRETCHED_PIN_COUNT * 180 + 400;
+ const int set_protected_command_count = 2 * (STRETCHED_PIN_COUNT + 1);
+
+ const int verify_time = (STRETCHED_PIN_COUNT - pin_index - 1) * 170 + 470;
+ const int verify_protected_command_count =
+ 1 + 2 * (STRETCHED_PIN_COUNT - pin_index + 1);
+
+ const int reset_hmac_counter_time = 170;
+ const int reset_hmac_counter_protected_command_count = 2;
+
+ const int pin_set_time =
+ throttling_delay * (init_protected_command_count +
+ stretch_cmac_ecdh_protected_command_count +
+ set_protected_command_count) +
+ init_time + stretch_cmac_ecdh_time + set_time;
+ const int pin_verify_time =
+ throttling_delay * (stretch_cmac_ecdh_protected_command_count +
+ verify_protected_command_count) +
+ stretch_cmac_ecdh_time + verify_time +
+ (pin_index == 0
+ ? 0
+ : (reset_hmac_counter_time +
+ throttling_delay * reset_hmac_counter_protected_command_count));
+
switch (op) {
case STORAGE_PIN_OP_SET:
- return throttling_delay * 6 + 1300;
+ return pin_set_time;
case STORAGE_PIN_OP_VERIFY:
- return throttling_delay * 7 + 1000;
+ return pin_verify_time;
case STORAGE_PIN_OP_CHANGE:
- return throttling_delay * 13 + 2300;
+ return pin_set_time + pin_verify_time;
default:
return 0;
}
@@ -350,32 +399,71 @@ bool optiga_set_metadata(uint16_t oid, const optiga_metadata *metadata) {
return true;
}
-static bool optiga_pin_init_metadata(void) {
+static bool optiga_pin_init_metadata() {
optiga_metadata metadata = {0};
// Set metadata for counter-protected PIN secret.
memzero(&metadata, sizeof(metadata));
metadata.change = OPTIGA_META_ACCESS_ALWAYS;
- metadata.read = ACCESS_STRETCHED_PIN;
+ metadata.read = ACCESS_LAST_STRETCHED_PIN;
metadata.execute = OPTIGA_META_ACCESS_ALWAYS;
metadata.data_type = TYPE_AUTOREF;
if (!optiga_set_metadata(OID_PIN_SECRET, &metadata)) {
return false;
}
- // Set metadata for stretched PIN.
+#if STRETCHED_PIN_COUNT == 1
+ // Set metadata for the stretched PIN.
memzero(&metadata, sizeof(metadata));
metadata.change = ACCESS_PIN_SECRET;
metadata.read = OPTIGA_META_ACCESS_NEVER;
metadata.execute = ACCESS_STRETCHED_PIN_CTR;
metadata.data_type = TYPE_AUTOREF;
- if (!optiga_set_metadata(OID_STRETCHED_PIN, &metadata)) {
+ if (!optiga_set_metadata(OID_STRETCHED_PINS[0], &metadata)) {
+ return false;
+ }
+#else
+ // Set metadata for the first stretched PIN.
+ memzero(&metadata, sizeof(metadata));
+ metadata.change =
+ OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_AUTO, OID_STRETCHED_PINS[1]);
+ metadata.read = OPTIGA_META_ACCESS_NEVER;
+ metadata.execute = ACCESS_STRETCHED_PIN_CTR;
+ metadata.data_type = TYPE_AUTOREF;
+ if (!optiga_set_metadata(OID_STRETCHED_PINS[0], &metadata)) {
+ return false;
+ }
+
+ // Set metadata for the rest of the stretched PINs.
+ for (int i = 1; i < STRETCHED_PIN_COUNT - 1; i++) {
+ memzero(&metadata, sizeof(metadata));
+ metadata.change = OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_AUTO,
+ OID_STRETCHED_PINS[i + 1]);
+ metadata.read = OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_AUTO,
+ OID_STRETCHED_PINS[i - 1]);
+ metadata.execute = ACCESS_STRETCHED_PIN_CTR;
+ metadata.data_type = TYPE_AUTOREF;
+ if (!optiga_set_metadata(OID_STRETCHED_PINS[i], &metadata)) {
+ return false;
+ }
+ }
+
+ // Set metadata for the last stretched PIN.
+ memzero(&metadata, sizeof(metadata));
+ metadata.change = ACCESS_PIN_SECRET;
+ metadata.read = OPTIGA_ACCESS_CONDITION(
+ OPTIGA_ACCESS_COND_AUTO, OID_STRETCHED_PINS[STRETCHED_PIN_COUNT - 2]);
+ metadata.execute = ACCESS_STRETCHED_PIN_CTR;
+ metadata.data_type = TYPE_AUTOREF;
+ if (!optiga_set_metadata(OID_STRETCHED_PINS[STRETCHED_PIN_COUNT - 1],
+ &metadata)) {
return false;
}
+#endif
// Set metadata for HMAC-SHA256 PIN stretching secret.
memzero(&metadata, sizeof(metadata));
- metadata.change = ACCESS_STRETCHED_PIN;
+ metadata.change = ACCESS_FIRST_STRETCHED_PIN;
metadata.read = OPTIGA_META_ACCESS_NEVER;
metadata.execute = ACCESS_PIN_HMAC_CTR;
metadata.data_type = TYPE_PRESSEC;
@@ -383,7 +471,7 @@ static bool optiga_pin_init_metadata(void) {
return false;
}
- // Set metadata for the counter of guesses at OID_STRETCHED_PIN.
+ // Set metadata for the counter of guesses at OID_STRETCHED_PINS.
memzero(&metadata, sizeof(metadata));
metadata.change = ACCESS_PIN_SECRET;
metadata.read = OPTIGA_META_ACCESS_ALWAYS;
@@ -394,7 +482,7 @@ static bool optiga_pin_init_metadata(void) {
// Set metadata for the counter of OID_PIN_HMAC uses.
memzero(&metadata, sizeof(metadata));
- metadata.change = ACCESS_STRETCHED_PIN;
+ metadata.change = ACCESS_FIRST_STRETCHED_PIN;
metadata.read = OPTIGA_META_ACCESS_ALWAYS;
metadata.execute = OPTIGA_META_ACCESS_ALWAYS;
if (!optiga_set_metadata(OID_PIN_HMAC_CTR, &metadata)) {
@@ -447,7 +535,7 @@ static bool optiga_pin_init_metadata(void) {
return true;
}
-static bool optiga_pin_init_stretch(void) {
+static bool optiga_pin_init_stretch() {
// Generate a new key in OID_PIN_CMAC.
if (optiga_gen_sym_key(OPTIGA_AES_256, OPTIGA_KEY_USAGE_ENC, OID_PIN_CMAC) !=
OPTIGA_SUCCESS) {
@@ -457,14 +545,16 @@ static bool optiga_pin_init_stretch(void) {
// Generate a new key in OID_PIN_ECDH.
uint8_t public_key[6 + 65] = {0};
size_t size = 0;
- return optiga_gen_key_pair(OPTIGA_CURVE_P256, OPTIGA_KEY_USAGE_KEYAGREE,
- OID_PIN_ECDH, public_key, sizeof(public_key),
- &size) == OPTIGA_SUCCESS;
+ optiga_result res =
+ optiga_gen_key_pair(OPTIGA_CURVE_P256, OPTIGA_KEY_USAGE_KEYAGREE,
+ OID_PIN_ECDH, public_key, sizeof(public_key), &size);
+
+ return res == OPTIGA_SUCCESS;
}
static bool optiga_pin_stretch_common(
- optiga_ui_progress_t ui_progress, HMAC_SHA256_CTX *ctx,
- const uint8_t input[OPTIGA_PIN_SECRET_SIZE], bool version4) {
+ HMAC_SHA256_CTX *ctx, const uint8_t input[OPTIGA_PIN_SECRET_SIZE],
+ bool version4) {
// Implements the functionality that is common to
// optiga_pin_stretch_cmac_ecdh() and the legacy function
// optiga_pin_stretch_secret_v4().
@@ -509,8 +599,6 @@ static bool optiga_pin_stretch_common(
goto end;
}
- ui_progress();
-
hmac_sha256_Update(ctx, buffer, size);
end:
@@ -520,7 +608,7 @@ end:
}
static bool optiga_pin_stretch_secret_v4(
- optiga_ui_progress_t ui_progress, uint8_t secret[OPTIGA_PIN_SECRET_SIZE]) {
+ uint8_t secret[OPTIGA_PIN_SECRET_SIZE]) {
// Legacy PIN verification method used in storage versions 3 and 4.
// This step hardens the PIN verification process in case an attacker is able
@@ -541,7 +629,7 @@ static bool optiga_pin_stretch_secret_v4(
HMAC_SHA256_CTX ctx = {0};
hmac_sha256_Init(&ctx, secret, OPTIGA_PIN_SECRET_SIZE);
- bool ret = optiga_pin_stretch_common(ui_progress, &ctx, secret, true);
+ bool ret = optiga_pin_stretch_common(&ctx, secret, true);
if (ret) {
hmac_sha256_Final(&ctx, secret);
}
@@ -550,9 +638,13 @@ static bool optiga_pin_stretch_secret_v4(
return ret;
}
-static bool optiga_pin_stretch_cmac_ecdh(
+bool optiga_pin_stretch_cmac_ecdh(
optiga_ui_progress_t ui_progress,
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
+ // Protected commands: PIN_STRETCH_ITERATIONS * 2
+ // Time: PIN_STRETCH_ITERATIONS * 275 ms
+
+ optiga_set_ui_progress(ui_progress);
// This step hardens the PIN verification process in case an attacker is able
// to extract the secret value of a data object in Optiga that has a
// particular configuration, but does not allow secret extraction for other
@@ -581,7 +673,7 @@ static bool optiga_pin_stretch_cmac_ecdh(
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, NULL, 0, digest);
hmac_sha256_Init(&ctx, stretched_pin, OPTIGA_PIN_SECRET_SIZE);
- if (!optiga_pin_stretch_common(ui_progress, &ctx, digest, false)) {
+ if (!optiga_pin_stretch_common(&ctx, digest, false)) {
ret = false;
goto end;
}
@@ -592,28 +684,66 @@ static bool optiga_pin_stretch_cmac_ecdh(
end:
memzero(digest, sizeof(digest));
memzero(&ctx, sizeof(ctx));
+ optiga_set_ui_progress(NULL);
return ret;
}
-bool optiga_pin_set(optiga_ui_progress_t ui_progress,
- uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
+bool optiga_pin_init(optiga_ui_progress_t ui_progress) {
+ // Time: (STRETCHED_PIN_COUNT + 7) * 15 ms + 295 ms
+ // Protected commands: 0
+ optiga_set_ui_progress(ui_progress);
+ bool ret = optiga_pin_init_metadata() && optiga_pin_init_stretch();
+ optiga_set_ui_progress(NULL);
+ return ret;
+}
+
+static void optiga_pin_stretch_hmac_offline(
+ const uint8_t hmac_stretching_secret[OPTIGA_PIN_SECRET_SIZE],
+ uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
+ uint8_t hmac_buffer[ENCRYPT_SYM_PREFIX_SIZE + OPTIGA_PIN_SECRET_SIZE] = {
+ 0x61, 0x00, 0x20};
+ uint8_t digest[OPTIGA_PIN_SECRET_SIZE] = {0};
+
+ // Process the stretched PIN using a one-way function before using it in the
+ // operation that will be executed in Optiga during verification. This
+ // ensures that in the unlikely case of an attacker recording communication
+ // between the MCU and Optiga, they will not gain knowledge of the stretched
+ // PIN.
+ hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, NULL, 0, digest);
+
+ // Compute the operation that will be executed in Optiga during
+ // verification.
+ hmac_sha256(hmac_stretching_secret, OPTIGA_PIN_SECRET_SIZE, digest,
+ sizeof(digest), &hmac_buffer[ENCRYPT_SYM_PREFIX_SIZE]);
+
+ // Stretch the PIN with the result.
+ hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, hmac_buffer,
+ sizeof(hmac_buffer), stretched_pin);
+
+ memzero(digest, sizeof(digest));
+ memzero(hmac_buffer, sizeof(hmac_buffer));
+}
+
+bool optiga_pin_set(
+ optiga_ui_progress_t ui_progress,
+ uint8_t stretched_pins[STRETCHED_PIN_COUNT][OPTIGA_PIN_SECRET_SIZE],
+ uint8_t hmac_reset_key[OPTIGA_PIN_SECRET_SIZE]) {
+ // Protected commands: 2 * (STRETCHED_PIN_COUNT + 1)
+ // Time: STRETCHED_PIN_COUNT * 180 ms + 400 ms
+
optiga_set_ui_progress(ui_progress);
bool ret = true;
- if (!optiga_pin_init_metadata() || !optiga_pin_init_stretch()) {
+
+ uint8_t hmac_stretching_secret[OPTIGA_PIN_SECRET_SIZE] = {0};
+ if (!rng_fill_buffer_strong(hmac_stretching_secret,
+ sizeof(hmac_stretching_secret))) {
ret = false;
goto end;
}
- ui_progress();
-
- // Stretch the PIN more with stretching secrets from the Optiga. This step
- // ensures that if an attacker extracts the value of OID_STRETCHED_PIN or
- // OID_PIN_SECRET, then it cannot be used to conduct an offline brute-force
- // search for the PIN.
- if (!optiga_pin_stretch_cmac_ecdh(ui_progress, stretched_pin)) {
- ret = false;
- goto end;
+ for (int i = 0; i < STRETCHED_PIN_COUNT; i++) {
+ optiga_pin_stretch_hmac_offline(hmac_stretching_secret, stretched_pins[i]);
}
// Generate and store the counter-protected PIN secret.
@@ -629,72 +759,70 @@ bool optiga_pin_set(optiga_ui_progress_t ui_progress,
goto end;
}
- // Generate the key for the HMAC-SHA256 PIN stretching step.
- uint8_t pin_hmac[OPTIGA_PIN_SECRET_SIZE] = {0};
- if (!rng_fill_buffer_strong(pin_hmac, sizeof(pin_hmac))) {
+ // Authorise using OID_PIN_SECRET so that we can write to the last stretched
+ // PIN and to OID_STRETCHED_PIN_CTR.
+ if (optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_PIN_SECRET, pin_secret,
+ sizeof(pin_secret)) != OPTIGA_SUCCESS) {
ret = false;
goto end;
}
- // Authorise using OID_PIN_SECRET so that we can write to OID_STRETCHED_PIN
- // and OID_STRETCHED_PIN_CTR.
- if (optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_PIN_SECRET, pin_secret,
- sizeof(pin_secret)) != OPTIGA_SUCCESS) {
+ // Initialize the counter that limits the guesses at OID_STRETCHED_PINS with
+ // OPTIGA_STRETCHED_PINS_COUNT + PIN_MAX_TRIES, of which
+ // OPTIGA_STRETCHED_PINS_COUNT will be used when setting stretched PINs.
+ if (optiga_reset_counter(OID_STRETCHED_PIN_CTR,
+ STRETCHED_PIN_COUNT + PIN_MAX_TRIES) !=
+ OPTIGA_SUCCESS) {
ret = false;
goto end;
}
- // Process the stretched PIN using a one-way function before using it in the
- // operation that will be executed in Optiga during verification. This ensures
- // that in the unlikely case of an attacker recording communication between
- // the MCU and Optiga, they will not gain knowledge of the stretched PIN.
uint8_t digest[OPTIGA_PIN_SECRET_SIZE] = {0};
- hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, NULL, 0, digest);
- // Compute the operation that will be executed in Optiga during verification.
- uint8_t hmac_buffer[ENCRYPT_SYM_PREFIX_SIZE + OPTIGA_PIN_SECRET_SIZE] = {
- 0x61, 0x00, 0x20};
- hmac_sha256(pin_hmac, sizeof(pin_hmac), digest, sizeof(digest),
- &hmac_buffer[ENCRYPT_SYM_PREFIX_SIZE]);
-
- // Stretch the PIN with the result.
- hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, hmac_buffer,
- sizeof(hmac_buffer), stretched_pin);
+ for (int i = STRETCHED_PIN_COUNT - 1; i >= 0; i--) {
+ // Time: 180 ms
- // Process the stretched PIN using a one-way function before sending it to the
- // Optiga. This ensures that in the unlikely case of an attacker recording
- // communication between the MCU and Optiga, they will not gain knowledge of
- // the stretched PIN.
- hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, NULL, 0, digest);
-
- // Store the digest of the stretched PIN in OID_STRETCHED_PIN.
- if (optiga_set_data_object(OID_STRETCHED_PIN, false, digest,
- sizeof(digest)) != OPTIGA_SUCCESS) {
- ret = false;
- goto end;
- }
+ // Process the stretched PIN using a one-way function before sending it to
+ // the Optiga. This ensures that in the unlikely case of an attacker
+ // recording communication between the MCU and Optiga, they will not gain
+ // knowledge of the stretched PIN.
+ hmac_sha256(stretched_pins[i], OPTIGA_PIN_SECRET_SIZE, NULL, 0, digest);
- // Initialize the counter which limits the guesses at OID_STRETCHED_PIN with
- // one extra attempt that we will use up in the next step.
- if (optiga_reset_counter(OID_STRETCHED_PIN_CTR, PIN_MAX_TRIES + 1) !=
- OPTIGA_SUCCESS) {
- ret = false;
- goto end;
- }
+ if (i == 0) {
+ // The first stretched PIN is used to reset the HMAC counter.
+ memcpy(hmac_reset_key, digest, sizeof(digest));
+ }
- ui_progress();
+ // Store the digest of the stretched PIN in OID_STRETCHED_PINS[i].
+ if (optiga_set_data_object(OID_STRETCHED_PINS[i], false, digest,
+ sizeof(digest)) != OPTIGA_SUCCESS) {
+ ret = false;
+ goto end;
+ }
- // Authorise using OID_STRETCHED_PIN so that we can write to OID_PIN_HMAC and
- // OID_PIN_HMAC_CTR.
- if (optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_STRETCHED_PIN, digest,
- sizeof(digest)) != OPTIGA_SUCCESS) {
- ret = false;
- goto end;
+ optiga_clear_all_auto_states();
+
+ // Stretch the PIN more with the counter-protected PIN secret. This method
+ // ensures that if the user chooses a high-entropy PIN, then even if the
+ // Optiga and its communication link is completely compromised, it will not
+ // reduce the security of their device any more than if the Optiga was not
+ // integrated into the device in the first place.
+ hmac_sha256(stretched_pins[i], OPTIGA_PIN_SECRET_SIZE, pin_secret,
+ sizeof(pin_secret), stretched_pins[i]);
+
+ // Authorise using OID_STRETCHED_PINS[i] so that we can write to
+ // * OID_STRETCHED_PINS[i - 1], if i > 0;
+ // * OID_PIN_HMAC and OID_PIN_HMAC_CTR, if i == 0.
+ if (optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_STRETCHED_PINS[i],
+ digest, sizeof(digest)) != OPTIGA_SUCCESS) {
+ ret = false;
+ goto end;
+ }
}
// Initialize the key for HMAC-SHA256 PIN stretching.
- if (optiga_set_data_object(OID_PIN_HMAC, false, pin_hmac, sizeof(pin_hmac)) !=
- OPTIGA_SUCCESS) {
+ if (optiga_set_data_object(OID_PIN_HMAC, false, hmac_stretching_secret,
+ OPTIGA_PIN_SECRET_SIZE) != OPTIGA_SUCCESS) {
ret = false;
goto end;
}
@@ -705,19 +833,7 @@ bool optiga_pin_set(optiga_ui_progress_t ui_progress,
goto end;
}
- ui_progress();
-
- // Stretch the PIN more with the counter-protected PIN secret. This method
- // ensures that if the user chooses a high-entropy PIN, then even if the
- // Optiga and its communication link is completely compromised, it will not
- // reduce the security of their device any more than if the Optiga was not
- // integrated into the device in the first place.
- hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, pin_secret,
- sizeof(pin_secret), stretched_pin);
-
end:
- memzero(hmac_buffer, sizeof(hmac_buffer));
- memzero(pin_hmac, sizeof(pin_hmac));
memzero(pin_secret, sizeof(pin_secret));
memzero(digest, sizeof(digest));
optiga_clear_all_auto_states();
@@ -740,14 +856,15 @@ optiga_pin_result optiga_pin_verify_v4(
hmac_sha256(pin_secret, OPTIGA_PIN_SECRET_SIZE, NULL, 0, stretched_pin);
// Combine the result with stretching secrets from the Optiga.
- if (!optiga_pin_stretch_secret_v4(ui_progress, stretched_pin)) {
+ if (!optiga_pin_stretch_secret_v4(stretched_pin)) {
ret = OPTIGA_PIN_ERROR;
goto end;
}
- // Authorise using OID_STRETCHED_PIN so that we can read from OID_PIN_SECRET.
+ // Authorise using OID_STRETCHED_PINS[0] so that we can read from
+ // OID_PIN_SECRET.
optiga_result res =
- optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_STRETCHED_PIN,
+ optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_STRETCHED_PINS[0],
stretched_pin, sizeof(stretched_pin));
if (res != OPTIGA_SUCCESS) {
uint8_t error_code = 0;
@@ -779,8 +896,6 @@ optiga_pin_result optiga_pin_verify_v4(
goto end;
}
- ui_progress();
-
// Authorise using OID_PIN_SECRET so that we can write to
// OID_STRETCHED_PIN_CTR.
if (optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_PIN_SECRET, out_secret,
@@ -789,13 +904,11 @@ optiga_pin_result optiga_pin_verify_v4(
goto end;
}
- ui_progress();
-
// Combine the value of OID_PIN_SECRET with the PIN-derived secret and
// stretching secrets from the Optiga.
hmac_sha256(pin_secret, OPTIGA_PIN_SECRET_SIZE, out_secret,
OPTIGA_PIN_SECRET_SIZE, out_secret);
- if (!optiga_pin_stretch_secret_v4(ui_progress, out_secret)) {
+ if (!optiga_pin_stretch_secret_v4(out_secret)) {
ret = OPTIGA_PIN_ERROR;
goto end;
}
@@ -814,6 +927,9 @@ end:
static optiga_pin_result optiga_pin_stretch_hmac(
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
+ // Protected commands: 1
+ // Time: 120 ms
+
optiga_pin_result ret = OPTIGA_PIN_SUCCESS;
// Process the stretched PIN using a one-way function before sending it to the
@@ -850,13 +966,15 @@ end:
}
optiga_pin_result optiga_pin_verify(
- optiga_ui_progress_t ui_progress,
+ optiga_ui_progress_t ui_progress, uint8_t pin_index,
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
+ // Protected commands: 1 + 2 * (STRETCHED_PIN_COUNT - pin_index + 1)
+ // Time: (STRETCHED_PIN_COUNT - pin_index - 1) * 170 ms + 470 ms
+
optiga_set_ui_progress(ui_progress);
optiga_pin_result ret = OPTIGA_PIN_SUCCESS;
- // Stretch the PIN more with stretching secrets from the Optiga.
- if (!optiga_pin_stretch_cmac_ecdh(ui_progress, stretched_pin)) {
+ if (pin_index >= STRETCHED_PIN_COUNT) {
ret = OPTIGA_PIN_ERROR;
goto end;
}
@@ -871,10 +989,11 @@ optiga_pin_result optiga_pin_verify(
uint8_t digest[OPTIGA_PIN_SECRET_SIZE] = {0};
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, NULL, 0, digest);
- // Authorise using OID_STRETCHED_PIN so that we can read from OID_PIN_SECRET
- // and reset OID_PIN_HMAC_CTR.
- optiga_result res = optiga_set_auto_state(
- OPTIGA_OID_SESSION_CTX, OID_STRETCHED_PIN, digest, sizeof(digest));
+ // Authorise using OID_STRETCHED_PINS[pin_index] so that we can read from
+ // OID_STRETCHED_PINS[pin_index + 1] and eventually from OID_PIN_SECRET.
+ optiga_result res = optiga_set_auto_state(OPTIGA_OID_SESSION_CTX,
+ OID_STRETCHED_PINS[pin_index],
+ digest, sizeof(digest));
if (res != OPTIGA_SUCCESS) {
uint8_t error_code = 0;
if (res != OPTIGA_ERR_CMD ||
@@ -896,12 +1015,40 @@ optiga_pin_result optiga_pin_verify(
goto end;
}
- ui_progress();
+ uint8_t stretched_pin_ctr_limit = PIN_MAX_TRIES;
+ if (pin_index == 0) {
+ // If this is the first PIN attempt or there is only one stretched PIN
+ // slot, the HMAC counter can be reset immediately. Otherwise, the counter
+ // is reset in optiga_pin_reset_hmac_counter().
+ if (optiga_reset_counter(OID_PIN_HMAC_CTR, PIN_MAX_TRIES) !=
+ OPTIGA_SUCCESS) {
+ ret = OPTIGA_PIN_ERROR;
+ goto end;
+ }
+ } else {
+ // An extra attempt will be needed to authorize using OID_STRETCHED_PIN[0]
+ // in optiga_pin_reset_hmac_counter().
+ stretched_pin_ctr_limit += 1;
+ }
+
+ for (int i = pin_index + 1; i < STRETCHED_PIN_COUNT; i++) {
+ // Time: 170 ms
- // Reset the counter which limits the use of OID_PIN_HMAC.
- if (optiga_reset_counter(OID_PIN_HMAC_CTR, PIN_MAX_TRIES) != OPTIGA_SUCCESS) {
- ret = OPTIGA_PIN_ERROR;
- goto end;
+ size_t size = 0;
+ if (optiga_get_data_object(OID_STRETCHED_PINS[i], false, digest,
+ OPTIGA_PIN_SECRET_SIZE,
+ &size) != OPTIGA_SUCCESS) {
+ ret = OPTIGA_PIN_ERROR;
+ goto end;
+ }
+
+ optiga_clear_all_auto_states();
+
+ if (optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_STRETCHED_PINS[i],
+ digest, sizeof(digest)) != OPTIGA_SUCCESS) {
+ ret = OPTIGA_PIN_ERROR;
+ goto end;
+ }
}
// Read the counter-protected PIN secret from OID_PIN_SECRET.
@@ -913,6 +1060,8 @@ optiga_pin_result optiga_pin_verify(
goto end;
}
+ optiga_clear_all_auto_states();
+
// Stretch the PIN more with the counter-protected PIN secret.
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, pin_secret, size,
stretched_pin);
@@ -924,15 +1073,12 @@ optiga_pin_result optiga_pin_verify(
goto end;
}
- // Reset the counter which limits the guesses at OID_STRETCHED_PIN.
- if (optiga_reset_counter(OID_STRETCHED_PIN_CTR, PIN_MAX_TRIES) !=
+ if (optiga_reset_counter(OID_STRETCHED_PIN_CTR, stretched_pin_ctr_limit) !=
OPTIGA_SUCCESS) {
ret = OPTIGA_PIN_ERROR;
goto end;
}
- ui_progress();
-
end:
memzero(pin_secret, sizeof(pin_secret));
memzero(digest, sizeof(digest));
@@ -941,6 +1087,36 @@ end:
return ret;
}
+bool optiga_pin_reset_hmac_counter(
+ optiga_ui_progress_t ui_progress,
+ const uint8_t hmac_reset_key[OPTIGA_PIN_SECRET_SIZE]) {
+ // Protected commands: 2
+ // Time: 170 ms
+
+ optiga_set_ui_progress(ui_progress);
+
+ bool res = false;
+
+ // Authorize using the first stretched PIN.
+ if (optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_STRETCHED_PINS[0],
+ hmac_reset_key,
+ OPTIGA_PIN_SECRET_SIZE) != OPTIGA_SUCCESS) {
+ goto cleanup;
+ }
+
+ // Reset the counter.
+ if (optiga_reset_counter(OID_PIN_HMAC_CTR, PIN_MAX_TRIES) != OPTIGA_SUCCESS) {
+ goto cleanup;
+ }
+
+ res = true;
+
+cleanup:
+ optiga_clear_all_auto_states();
+ optiga_set_ui_progress(NULL);
+ return res;
+}
+
static uint32_t uint32_from_be(uint8_t buf[4]) {
uint32_t i = buf[0];
i = (i << 8) + buf[1];
diff --git a/core/embed/sec/optiga/unix/optiga.c b/core/embed/sec/optiga/unix/optiga.c
index 8d361ce52..63de7ed30 100644
--- a/core/embed/sec/optiga/unix/optiga.c
+++ b/core/embed/sec/optiga/unix/optiga.c
@@ -99,15 +99,27 @@ bool optiga_read_sec(uint8_t *sec) {
void optiga_set_sec_max(void) {}
-uint32_t optiga_estimate_time_ms(storage_pin_op_t op) { return 0; }
+bool optiga_pin_init(optiga_ui_progress_t ui_progress) { return true; }
+
+bool optiga_pin_stretch_cmac_ecdh(
+ optiga_ui_progress_t ui_progress,
+ uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
+ return true;
+}
+
+uint32_t optiga_estimate_time_ms(storage_pin_op_t op, uint8_t slot_index) {
+ return 0;
+}
bool optiga_random_buffer(uint8_t *dest, size_t size) {
rng_fill_buffer(dest, size);
return true;
}
-bool optiga_pin_set(optiga_ui_progress_t ui_progress,
- uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
+bool optiga_pin_set(
+ optiga_ui_progress_t ui_progress,
+ uint8_t stretched_pins[STRETCHED_PIN_COUNT][OPTIGA_PIN_SECRET_SIZE],
+ uint8_t hmac_reset_key[OPTIGA_PIN_SECRET_SIZE]) {
return true;
}
@@ -120,11 +132,17 @@ optiga_pin_result optiga_pin_verify_v4(
}
optiga_pin_result optiga_pin_verify(
- optiga_ui_progress_t ui_progress,
+ optiga_ui_progress_t ui_progress, uint8_t pin_index,
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
return OPTIGA_PIN_SUCCESS;
}
+bool optiga_pin_reset_hmac_counter(
+ optiga_ui_progress_t ui_progress,
+ const uint8_t hmac_reset_key[OPTIGA_PIN_SECRET_SIZE]) {
+ return true;
+}
+
bool optiga_pin_get_rem_v4(uint32_t *ctr) {
*ctr = PIN_MAX_TRIES;
return true;
diff --git a/storage/storage.c b/storage/storage.c
index 7745bfa2a..163d9bbad 100644
--- a/storage/storage.c
+++ b/storage/storage.c
@@ -18,6 +18,8 @@
*/
#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
#include <string.h>
#include <sec/rng.h>
@@ -74,6 +76,12 @@
// NOTE: This should always equal the value in VERSION_KEY.
#define UNAUTH_VERSION_KEY ((APP_STORAGE << 8) | 0x08)
+#if USE_OPTIGA && STRETCHED_PIN_COUNT > 1
+// Key that is used to reset the HMAC counter in Optiga after successfull
+// unlock.
+#define OPTIGA_HMAC_RESET_KEY ((APP_STORAGE << 8) | 0x0A)
+#endif
+
// The PIN value corresponding to an empty PIN.
const uint8_t *PIN_EMPTY = (const uint8_t *)"";
@@ -457,7 +465,15 @@ static secbool is_not_wipe_code(const uint8_t *pin, size_t pin_len) {
static uint32_t ui_estimate_time_ms(storage_pin_op_t op) {
uint32_t time_ms = 0;
#if USE_OPTIGA
- time_ms += optiga_estimate_time_ms(op);
+ uint32_t pin_index = 0;
+#if STRETCHED_PIN_COUNT > 1
+ if (sectrue != pin_get_fails(&pin_index)) {
+ return 0;
+ }
+#endif
+#endif
+#if USE_OPTIGA
+ time_ms += optiga_estimate_time_ms(op, pin_index);
#endif
uint32_t pbkdf2_ms = time_estimate_pbkdf2_ms(PIN_ITER_COUNT);
@@ -663,17 +679,46 @@ static void derive_kek_optiga_v4(
#endif
#endif
-static secbool __wur derive_kek_set(
- const uint8_t *pin, size_t pin_len, const uint8_t *storage_salt,
- const uint8_t *ext_salt, uint8_t stretched_pin[SHA256_DIGEST_LENGTH]) {
- mcu_pin_stretch(pin, pin_len, storage_salt, ext_salt, stretched_pin, sectrue);
+static secbool __wur derive_kek_set(const uint8_t *pin, size_t pin_len,
+ const uint8_t *storage_salt,
+ const uint8_t *ext_salt,
+ uint8_t kek[SHA256_DIGEST_LENGTH]) {
+ secbool ret = secfalse;
+ uint8_t stretched_pins[STRETCHED_PIN_COUNT][SHA256_DIGEST_LENGTH] = {0};
+ mcu_pin_stretch(pin, pin_len, storage_salt, ext_salt, stretched_pins[0],
+ sectrue);
#if USE_OPTIGA
- if (!optiga_pin_set(ui_progress, stretched_pin)) {
- memzero(stretched_pin, SHA256_DIGEST_LENGTH);
- return secfalse;
+ if (!optiga_pin_init(ui_progress)) {
+ goto cleanup;
+ }
+ if (!optiga_pin_stretch_cmac_ecdh(ui_progress, stretched_pins[0])) {
+ goto cleanup;
+ }
+#if STRETCHED_PIN_COUNT > 1
+ for (int i = 1; i < STRETCHED_PIN_COUNT; i++) {
+ memcpy(stretched_pins[i], stretched_pins[0], SHA256_DIGEST_LENGTH);
}
#endif
- return sectrue;
+ _Static_assert(SHA256_DIGEST_LENGTH == OPTIGA_PIN_SECRET_SIZE);
+ uint8_t optiga_hmac_reset_key[SHA256_DIGEST_LENGTH] = {0};
+ if (!optiga_pin_set(ui_progress, stretched_pins, optiga_hmac_reset_key)) {
+ goto cleanup;
+ }
+#if STRETCHED_PIN_COUNT > 1
+ if (storage_set_encrypted(OPTIGA_HMAC_RESET_KEY, optiga_hmac_reset_key,
+ sizeof(optiga_hmac_reset_key)) != sectrue) {
+ goto cleanup;
+ }
+#endif
+#endif
+ memcpy(kek, stretched_pins[0], SHA256_DIGEST_LENGTH);
+ ret = sectrue;
+#if USE_OPTIGA
+cleanup:
+ memzero(optiga_hmac_reset_key, sizeof(optiga_hmac_reset_key));
+#endif
+ memzero(stretched_pins, sizeof(stretched_pins));
+ return ret;
}
#if NORCOW_MIN_VERSION <= 4
@@ -718,16 +763,27 @@ static secbool __wur derive_kek_unlock(
mcu_pin_stretch(pin, pin_len, storage_salt, ext_salt, stretched_pin,
privileged_bhk);
#if USE_OPTIGA
- optiga_pin_result ret = optiga_pin_verify(ui_progress, stretched_pin);
- if (ret != OPTIGA_PIN_SUCCESS) {
+ uint32_t pin_index = 0;
+#if STRETCHED_PIN_COUNT > 1
+ uint32_t pin_fails = 0;
+ ensure(pin_get_fails(&pin_fails), "pin_get_fails failed");
+ pin_index = pin_fails - 1; // The counter has already been incremented
+#endif
+#endif
+#if USE_OPTIGA
+ ensure(optiga_pin_stretch_cmac_ecdh(ui_progress, stretched_pin) * sectrue,
+ "optiga_pin_stretch_cmac_ecdh failed");
+ optiga_pin_result optiga_ret =
+ optiga_pin_verify(ui_progress, pin_index, stretched_pin);
+ if (optiga_ret != OPTIGA_PIN_SUCCESS) {
memzero(stretched_pin, SHA256_DIGEST_LENGTH);
- if (ret == OPTIGA_PIN_COUNTER_EXCEEDED) {
+ if (optiga_ret == OPTIGA_PIN_COUNTER_EXCEEDED) {
// Unreachable code. Wipe should have already been triggered in unlock().
storage_wipe();
show_pin_too_many_screen();
}
- ensure(ret == OPTIGA_PIN_INVALID ? sectrue : secfalse,
+ ensure(optiga_ret == OPTIGA_PIN_INVALID ? sectrue : secfalse,
"optiga_pin_verify failed");
return secfalse;
}
@@ -1111,6 +1167,24 @@ static secbool unlock(const uint8_t *pin, size_t pin_len,
unlocked = sectrue;
+#if USE_OPTIGA && STRETCHED_PIN_COUNT > 1
+ if (ctr != 0) {
+ uint8_t optiga_hmac_reset_key[SHA256_DIGEST_LENGTH] = {0};
+ uint16_t optiga_hmac_reset_key_len = 0;
+ if (storage_get_encrypted(OPTIGA_HMAC_RESET_KEY, &optiga_hmac_reset_key,
+ sizeof(optiga_hmac_reset_key),
+ &optiga_hmac_reset_key_len) != sectrue ||
+ optiga_hmac_reset_key_len != SHA256_DIGEST_LENGTH) {
+ return secfalse;
+ }
+ if (!optiga_pin_reset_hmac_counter(ui_progress, optiga_hmac_reset_key)) {
+ memzero(optiga_hmac_reset_key, sizeof(optiga_hmac_reset_key));
+ return secfalse;
+ }
+ memzero(optiga_hmac_reset_key, sizeof(optiga_hmac_reset_key));
+ }
+#endif
+
// Finally set the counter to 0 to indicate success.
return pin_fails_reset();
}
@@ -1121,6 +1195,8 @@ secbool storage_unlock(const uint8_t *pin, size_t pin_len,
return secfalse;
}
+ mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_STORAGE);
+
ui_progress_init(STORAGE_PIN_OP_VERIFY);
if (pin_len == 0) {
if (ui_message == NO_MSG) {
@@ -1132,7 +1208,6 @@ secbool storage_unlock(const uint8_t *pin, size_t pin_len,
ui_message = VERIFYING_PIN_MSG;
}
- mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_STORAGE);
secbool ret = unlock(pin, pin_len, ext_salt);
mpu_restore(mpu_mode);
@@ -1462,12 +1537,12 @@ secbool storage_change_pin(const uint8_t *oldpin, size_t oldpin_len,
return secfalse;
}
+ mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_STORAGE);
+
ui_progress_init(STORAGE_PIN_OP_CHANGE);
ui_message =
(oldpin_len != 0 && newpin_len == 0) ? VERIFYING_PIN_MSG : PROCESSING_MSG;
- mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_STORAGE);
-
secbool ret = unlock(oldpin, oldpin_len, old_ext_salt);
if (sectrue != ret) {
goto end;
diff --git a/storage/storage.h b/storage/storage.h
index 2f956c6ef..919b599af 100644
--- a/storage/storage.h
+++ b/storage/storage.h
@@ -46,6 +46,9 @@ extern const uint8_t *PIN_EMPTY;
// to 16.
#define PIN_MAX_TRIES 16
+// The number of slots configured as stretched PINs.
+#define STRETCHED_PIN_COUNT 1
+
// The length of the random salt in bytes.
#if USE_OPTIGA
#define STORAGE_SALT_SIZE 32
Why this scored 35/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.