mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-01-30 09:11:07 +00:00
Display more information when handle_fault() is invoked to help diagnose bugs. We might want to remove this in the next release.
This commit is contained in:
parent
4429888b93
commit
0497802014
58
storage.c
58
storage.c
@ -117,7 +117,9 @@ static uint32_t norcow_active_version = 0;
|
|||||||
static const uint8_t TRUE_BYTE = 0x01;
|
static const uint8_t TRUE_BYTE = 0x01;
|
||||||
static const uint8_t FALSE_BYTE = 0x00;
|
static const uint8_t FALSE_BYTE = 0x00;
|
||||||
|
|
||||||
static void handle_fault(void);
|
static void __handle_fault(const char *msg, const char *file, int line, const char *func);
|
||||||
|
#define handle_fault(msg) (__handle_fault(msg, __FILE__, __LINE__, __func__))
|
||||||
|
|
||||||
static secbool storage_upgrade(void);
|
static secbool storage_upgrade(void);
|
||||||
static secbool storage_set_encrypted(const uint16_t key, const void *val, const uint16_t len);
|
static secbool storage_set_encrypted(const uint16_t key, const void *val, const uint16_t len);
|
||||||
static secbool storage_get_encrypted(const uint16_t key, void *val_dest, const uint16_t max_len, uint16_t *len);
|
static secbool storage_get_encrypted(const uint16_t key, void *val_dest, const uint16_t max_len, uint16_t *len);
|
||||||
@ -135,7 +137,7 @@ static secbool secequal(const void* ptr1, const void* ptr2, size_t n) {
|
|||||||
|
|
||||||
// Check loop completion in case of a fault injection attack.
|
// Check loop completion in case of a fault injection attack.
|
||||||
if (i != n) {
|
if (i != n) {
|
||||||
handle_fault();
|
handle_fault("loop completion check");
|
||||||
}
|
}
|
||||||
|
|
||||||
return diff ? secfalse : sectrue;
|
return diff ? secfalse : sectrue;
|
||||||
@ -258,7 +260,7 @@ static secbool auth_get(uint16_t key, const void **val, uint16_t *len)
|
|||||||
|
|
||||||
// Check loop completion in case of a fault injection attack.
|
// Check loop completion in case of a fault injection attack.
|
||||||
if (secfalse != norcow_get_next(&offset, &k, &v, &l)) {
|
if (secfalse != norcow_get_next(&offset, &k, &v, &l)) {
|
||||||
handle_fault();
|
handle_fault("loop completion check");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check storage authentication tag.
|
// Check storage authentication tag.
|
||||||
@ -268,13 +270,13 @@ static secbool auth_get(uint16_t key, const void **val, uint16_t *len)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (tag_val == NULL || tag_len != STORAGE_TAG_SIZE || sectrue != secequal(h, tag_val, STORAGE_TAG_SIZE)) {
|
if (tag_val == NULL || tag_len != STORAGE_TAG_SIZE || sectrue != secequal(h, tag_val, STORAGE_TAG_SIZE)) {
|
||||||
handle_fault();
|
handle_fault("storage tag check");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*val == NULL) {
|
if (*val == NULL) {
|
||||||
// Check for fault injection.
|
// Check for fault injection.
|
||||||
if (other_count != entry_count) {
|
if (other_count != entry_count) {
|
||||||
handle_fault();
|
handle_fault("sanity check");
|
||||||
}
|
}
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
@ -292,7 +294,7 @@ static void wait_random(void)
|
|||||||
volatile int j = wait;
|
volatile int j = wait;
|
||||||
while (i < wait) {
|
while (i < wait) {
|
||||||
if (i + j != wait) {
|
if (i + j != wait) {
|
||||||
handle_fault();
|
handle_fault("sanity check");
|
||||||
}
|
}
|
||||||
++i;
|
++i;
|
||||||
--j;
|
--j;
|
||||||
@ -300,7 +302,7 @@ static void wait_random(void)
|
|||||||
|
|
||||||
// Double-check loop completion.
|
// Double-check loop completion.
|
||||||
if (i != wait) {
|
if (i != wait) {
|
||||||
handle_fault();
|
handle_fault("loop completion check");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -404,7 +406,7 @@ static uint32_t generate_guard_key(void)
|
|||||||
static secbool expand_guard_key(const uint32_t guard_key, uint32_t *guard_mask, uint32_t *guard)
|
static secbool expand_guard_key(const uint32_t guard_key, uint32_t *guard_mask, uint32_t *guard)
|
||||||
{
|
{
|
||||||
if (sectrue != check_guard_key(guard_key)) {
|
if (sectrue != check_guard_key(guard_key)) {
|
||||||
handle_fault();
|
handle_fault("guard key check");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
*guard_mask = ((guard_key & LOW_MASK) << 1) | ((~guard_key) & LOW_MASK);
|
*guard_mask = ((guard_key & LOW_MASK) << 1) | ((~guard_key) & LOW_MASK);
|
||||||
@ -532,7 +534,7 @@ secbool storage_pin_fails_increase(void)
|
|||||||
|
|
||||||
wait_random();
|
wait_random();
|
||||||
if (sectrue != norcow_get(PIN_LOGS_KEY, &logs, &len) || len != WORD_SIZE*(GUARD_KEY_WORDS + 2*PIN_LOG_WORDS)) {
|
if (sectrue != norcow_get(PIN_LOGS_KEY, &logs, &len) || len != WORD_SIZE*(GUARD_KEY_WORDS + 2*PIN_LOG_WORDS)) {
|
||||||
handle_fault();
|
handle_fault("no PIN logs");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -540,7 +542,7 @@ secbool storage_pin_fails_increase(void)
|
|||||||
uint32_t guard;
|
uint32_t guard;
|
||||||
wait_random();
|
wait_random();
|
||||||
if (sectrue != expand_guard_key(*(const uint32_t*)logs, &guard_mask, &guard)) {
|
if (sectrue != expand_guard_key(*(const uint32_t*)logs, &guard_mask, &guard)) {
|
||||||
handle_fault();
|
handle_fault("guard key expansion");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -548,7 +550,7 @@ secbool storage_pin_fails_increase(void)
|
|||||||
for (size_t i = 0; i < PIN_LOG_WORDS; ++i) {
|
for (size_t i = 0; i < PIN_LOG_WORDS; ++i) {
|
||||||
wait_random();
|
wait_random();
|
||||||
if ((entry_log[i] & guard_mask) != guard) {
|
if ((entry_log[i] & guard_mask) != guard) {
|
||||||
handle_fault();
|
handle_fault("guard bits check");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
if (entry_log[i] != guard) {
|
if (entry_log[i] != guard) {
|
||||||
@ -559,14 +561,14 @@ secbool storage_pin_fails_increase(void)
|
|||||||
|
|
||||||
wait_random();
|
wait_random();
|
||||||
if (sectrue != norcow_update_word(PIN_LOGS_KEY, sizeof(uint32_t)*(i + GUARD_KEY_WORDS + PIN_LOG_WORDS), (word & ~guard_mask) | guard)) {
|
if (sectrue != norcow_update_word(PIN_LOGS_KEY, sizeof(uint32_t)*(i + GUARD_KEY_WORDS + PIN_LOG_WORDS), (word & ~guard_mask) | guard)) {
|
||||||
handle_fault();
|
handle_fault("PIN logs update");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
return sectrue;
|
return sectrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
handle_fault();
|
handle_fault("PIN log exhausted");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -588,7 +590,7 @@ static secbool pin_get_fails(uint32_t *ctr)
|
|||||||
uint16_t len = 0;
|
uint16_t len = 0;
|
||||||
wait_random();
|
wait_random();
|
||||||
if (sectrue != norcow_get(PIN_LOGS_KEY, &logs, &len) || len != WORD_SIZE*(GUARD_KEY_WORDS + 2*PIN_LOG_WORDS)) {
|
if (sectrue != norcow_get(PIN_LOGS_KEY, &logs, &len) || len != WORD_SIZE*(GUARD_KEY_WORDS + 2*PIN_LOG_WORDS)) {
|
||||||
handle_fault();
|
handle_fault("no PIN logs");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -596,7 +598,7 @@ static secbool pin_get_fails(uint32_t *ctr)
|
|||||||
uint32_t guard;
|
uint32_t guard;
|
||||||
wait_random();
|
wait_random();
|
||||||
if (sectrue != expand_guard_key(*(const uint32_t*)logs, &guard_mask, &guard)) {
|
if (sectrue != expand_guard_key(*(const uint32_t*)logs, &guard_mask, &guard)) {
|
||||||
handle_fault();
|
handle_fault("guard key expansion");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
const uint32_t unused = guard | ~guard_mask;
|
const uint32_t unused = guard | ~guard_mask;
|
||||||
@ -607,7 +609,7 @@ static secbool pin_get_fails(uint32_t *ctr)
|
|||||||
volatile size_t i;
|
volatile size_t i;
|
||||||
for (i = 0; i < PIN_LOG_WORDS; ++i) {
|
for (i = 0; i < PIN_LOG_WORDS; ++i) {
|
||||||
if ((entry_log[i] & guard_mask) != guard || (success_log[i] & guard_mask) != guard || (entry_log[i] & success_log[i]) != entry_log[i]) {
|
if ((entry_log[i] & guard_mask) != guard || (success_log[i] & guard_mask) != guard || (entry_log[i] & success_log[i]) != entry_log[i]) {
|
||||||
handle_fault();
|
handle_fault("PIN logs format check");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -617,14 +619,14 @@ static secbool pin_get_fails(uint32_t *ctr)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (entry_log[i] != unused) {
|
if (entry_log[i] != unused) {
|
||||||
handle_fault();
|
handle_fault("PIN entry log format check");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current < 0 || current >= PIN_LOG_WORDS || i != PIN_LOG_WORDS) {
|
if (current < 0 || current >= PIN_LOG_WORDS || i != PIN_LOG_WORDS) {
|
||||||
handle_fault();
|
handle_fault("PIN log exhausted");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -635,7 +637,7 @@ static secbool pin_get_fails(uint32_t *ctr)
|
|||||||
word = word | (word << 1);
|
word = word | (word << 1);
|
||||||
// Verify that the entry word has form 0*1*.
|
// Verify that the entry word has form 0*1*.
|
||||||
if ((word & (word + 1)) != 0) {
|
if ((word & (word + 1)) != 0) {
|
||||||
handle_fault();
|
handle_fault("PIN entry log format check");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -706,7 +708,7 @@ static secbool unlock(uint32_t pin)
|
|||||||
// NOTE: storage_get_encrypted() calls auth_get(), which initializes the authentication_sum.
|
// NOTE: storage_get_encrypted() calls auth_get(), which initializes the authentication_sum.
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
if (sectrue != storage_get_encrypted(VERSION_KEY, &version, sizeof(version), &len) || len != sizeof(version) || version != norcow_active_version) {
|
if (sectrue != storage_get_encrypted(VERSION_KEY, &version, sizeof(version), &len) || len != sizeof(version) || version != norcow_active_version) {
|
||||||
handle_fault();
|
handle_fault("storage version check");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -770,7 +772,7 @@ secbool storage_unlock(uint32_t pin)
|
|||||||
// Check that the PIN fail counter was incremented.
|
// Check that the PIN fail counter was incremented.
|
||||||
uint32_t ctr_ck;
|
uint32_t ctr_ck;
|
||||||
if (sectrue != pin_get_fails(&ctr_ck) || ctr + 1 != ctr_ck) {
|
if (sectrue != pin_get_fails(&ctr_ck) || ctr + 1 != ctr_ck) {
|
||||||
handle_fault();
|
handle_fault("PIN counter increment");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -804,7 +806,7 @@ static secbool storage_get_encrypted(const uint16_t key, void *val_dest, const u
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (*len < CHACHA20_IV_SIZE + POLY1305_TAG_SIZE) {
|
if (*len < CHACHA20_IV_SIZE + POLY1305_TAG_SIZE) {
|
||||||
handle_fault();
|
handle_fault("ciphertext length check");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
*len -= CHACHA20_IV_SIZE + POLY1305_TAG_SIZE;
|
*len -= CHACHA20_IV_SIZE + POLY1305_TAG_SIZE;
|
||||||
@ -832,7 +834,7 @@ static secbool storage_get_encrypted(const uint16_t key, void *val_dest, const u
|
|||||||
if (secequal(tag_computed, tag_stored, POLY1305_TAG_SIZE) != sectrue) {
|
if (secequal(tag_computed, tag_stored, POLY1305_TAG_SIZE) != sectrue) {
|
||||||
memzero(val_dest, max_len);
|
memzero(val_dest, max_len);
|
||||||
memzero(tag_computed, sizeof(tag_computed));
|
memzero(tag_computed, sizeof(tag_computed));
|
||||||
handle_fault();
|
handle_fault("authentication tag check");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1003,14 +1005,14 @@ void storage_wipe(void)
|
|||||||
init_wiped_storage();
|
init_wiped_storage();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_fault(void)
|
static void __handle_fault(const char *msg, const char *file, int line, const char *func)
|
||||||
{
|
{
|
||||||
static secbool in_progress = secfalse;
|
static secbool in_progress = secfalse;
|
||||||
|
|
||||||
// If fault handling is already in progress, then we are probably facing a fault injection attack, so wipe.
|
// If fault handling is already in progress, then we are probably facing a fault injection attack, so wipe.
|
||||||
if (secfalse != in_progress) {
|
if (secfalse != in_progress) {
|
||||||
storage_wipe();
|
storage_wipe();
|
||||||
ensure(secfalse, "fault detected");
|
__fatal_error("Fault detected", msg, file, line, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We use the PIN fail counter as a fault counter. Increment the counter, check that it was incremented and halt.
|
// We use the PIN fail counter as a fault counter. Increment the counter, check that it was incremented and halt.
|
||||||
@ -1018,19 +1020,19 @@ static void handle_fault(void)
|
|||||||
uint32_t ctr;
|
uint32_t ctr;
|
||||||
if (sectrue != pin_get_fails(&ctr)) {
|
if (sectrue != pin_get_fails(&ctr)) {
|
||||||
storage_wipe();
|
storage_wipe();
|
||||||
ensure(secfalse, "fault detected");
|
__fatal_error("Fault detected", msg, file, line, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sectrue != storage_pin_fails_increase()) {
|
if (sectrue != storage_pin_fails_increase()) {
|
||||||
storage_wipe();
|
storage_wipe();
|
||||||
ensure(secfalse, "fault detected");
|
__fatal_error("Fault detected", msg, file, line, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ctr_new;
|
uint32_t ctr_new;
|
||||||
if (sectrue != pin_get_fails(&ctr_new) || ctr + 1 != ctr_new) {
|
if (sectrue != pin_get_fails(&ctr_new) || ctr + 1 != ctr_new) {
|
||||||
storage_wipe();
|
storage_wipe();
|
||||||
}
|
}
|
||||||
ensure(secfalse, "fault detected");
|
__fatal_error("Fault detected", msg, file, line, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user