mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-26 09:28:13 +00:00
storage: Add STORAGE_UPGRADED_KEY to protect against fake storage upgrade attacks.
This commit is contained in:
parent
a168d661cf
commit
1deebf1065
@ -53,6 +53,9 @@
|
|||||||
// Norcow storage key of the wipe code data.
|
// Norcow storage key of the wipe code data.
|
||||||
#define WIPE_CODE_DATA_KEY ((APP_STORAGE << 8) | 0x06)
|
#define WIPE_CODE_DATA_KEY ((APP_STORAGE << 8) | 0x06)
|
||||||
|
|
||||||
|
// Norcow storage key of the storage upgrade flag.
|
||||||
|
#define STORAGE_UPGRADED_KEY ((APP_STORAGE << 8) | 0x07)
|
||||||
|
|
||||||
// The PIN value corresponding to an empty PIN.
|
// The PIN value corresponding to an empty PIN.
|
||||||
#define PIN_EMPTY 1
|
#define PIN_EMPTY 1
|
||||||
|
|
||||||
@ -150,6 +153,8 @@ static uint8_t hardware_salt[HARDWARE_SALT_SIZE] = {0};
|
|||||||
static uint32_t norcow_active_version = 0;
|
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 const uint32_t TRUE_WORD = 0xC35A69A5;
|
||||||
|
static const uint32_t FALSE_WORD = 0x3CA5965A;
|
||||||
|
|
||||||
static void __handle_fault(const char *msg, const char *file, int line,
|
static void __handle_fault(const char *msg, const char *file, int line,
|
||||||
const char *func);
|
const char *func);
|
||||||
@ -621,6 +626,8 @@ static void init_wiped_storage(void) {
|
|||||||
ensure(auth_init(), "set_storage_auth_tag failed");
|
ensure(auth_init(), "set_storage_auth_tag failed");
|
||||||
ensure(storage_set_encrypted(VERSION_KEY, &version, sizeof(version)),
|
ensure(storage_set_encrypted(VERSION_KEY, &version, sizeof(version)),
|
||||||
"set_storage_version failed");
|
"set_storage_version failed");
|
||||||
|
ensure(norcow_set(STORAGE_UPGRADED_KEY, &FALSE_WORD, sizeof(FALSE_WORD)),
|
||||||
|
"set_storage_not_upgraded failed");
|
||||||
ensure(pin_logs_init(0), "init_pin_logs failed");
|
ensure(pin_logs_init(0), "init_pin_logs failed");
|
||||||
ensure(set_wipe_code(WIPE_CODE_EMPTY), "set_wipe_code failed");
|
ensure(set_wipe_code(WIPE_CODE_EMPTY), "set_wipe_code failed");
|
||||||
|
|
||||||
@ -854,12 +861,36 @@ secbool check_storage_version(void) {
|
|||||||
handle_fault("storage version check");
|
handle_fault("storage version check");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
const void *storage_upgraded = NULL;
|
||||||
|
if (sectrue != norcow_get(STORAGE_UPGRADED_KEY, &storage_upgraded, &len) ||
|
||||||
|
len != sizeof(TRUE_WORD)) {
|
||||||
|
handle_fault("storage version check");
|
||||||
|
return secfalse;
|
||||||
|
}
|
||||||
if (version > norcow_active_version) {
|
if (version > norcow_active_version) {
|
||||||
|
// Attack: Storage was downgraded.
|
||||||
storage_wipe();
|
storage_wipe();
|
||||||
|
handle_fault("storage version check");
|
||||||
|
return secfalse;
|
||||||
} else if (version < norcow_active_version) {
|
} else if (version < norcow_active_version) {
|
||||||
|
// Storage was upgraded.
|
||||||
|
if (*(const uint32_t *)storage_upgraded != TRUE_WORD) {
|
||||||
|
// Attack: The upgrade process was bypassed.
|
||||||
|
storage_wipe();
|
||||||
|
handle_fault("storage version check");
|
||||||
|
return secfalse;
|
||||||
|
}
|
||||||
|
norcow_set(STORAGE_UPGRADED_KEY, &FALSE_WORD, sizeof(FALSE_WORD));
|
||||||
storage_set_encrypted(VERSION_KEY, &norcow_active_version,
|
storage_set_encrypted(VERSION_KEY, &norcow_active_version,
|
||||||
sizeof(norcow_active_version));
|
sizeof(norcow_active_version));
|
||||||
|
} else {
|
||||||
|
// Standard operation. The storage was neither upgraded nor downgraded.
|
||||||
|
if (*(const uint32_t *)storage_upgraded != FALSE_WORD) {
|
||||||
|
// Attack: The upgrade process was launched when it shouldn't have been.
|
||||||
|
storage_wipe();
|
||||||
|
handle_fault("storage version check");
|
||||||
|
return secfalse;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return sectrue;
|
return sectrue;
|
||||||
}
|
}
|
||||||
@ -900,7 +931,6 @@ static secbool decrypt_dek(const uint8_t *kek, const uint8_t *keiv) {
|
|||||||
memcpy(cached_keys, keys, sizeof(keys));
|
memcpy(cached_keys, keys, sizeof(keys));
|
||||||
memzero(keys, sizeof(keys));
|
memzero(keys, sizeof(keys));
|
||||||
memzero(tag, sizeof(tag));
|
memzero(tag, sizeof(tag));
|
||||||
|
|
||||||
// Check that the authenticated version number matches the norcow version.
|
// Check that the authenticated version number matches the norcow version.
|
||||||
// NOTE: This also initializes the authentication_sum by calling
|
// NOTE: This also initializes the authentication_sum by calling
|
||||||
// storage_get_encrypted() which calls auth_get().
|
// storage_get_encrypted() which calls auth_get().
|
||||||
@ -1464,6 +1494,11 @@ static secbool storage_upgrade(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sectrue !=
|
||||||
|
norcow_set(STORAGE_UPGRADED_KEY, &TRUE_WORD, sizeof(TRUE_WORD))) {
|
||||||
|
return secfalse;
|
||||||
|
}
|
||||||
|
|
||||||
norcow_active_version = NORCOW_VERSION;
|
norcow_active_version = NORCOW_VERSION;
|
||||||
return norcow_upgrade_finish();
|
return norcow_upgrade_finish();
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,9 @@ SAT_KEY = (PIN_APP_ID << 8) | 0x05
|
|||||||
# Norcow storage key of the wipe code data.
|
# Norcow storage key of the wipe code data.
|
||||||
WIPE_CODE_DATA_KEY = (PIN_APP_ID << 8) | 0x06
|
WIPE_CODE_DATA_KEY = (PIN_APP_ID << 8) | 0x06
|
||||||
|
|
||||||
|
# Norcow storage key of the storage upgrade flag.
|
||||||
|
STORAGE_UPGRADED_KEY = (PIN_APP_ID << 8) | 0x07
|
||||||
|
|
||||||
# The PIN value corresponding to an empty PIN.
|
# The PIN value corresponding to an empty PIN.
|
||||||
PIN_EMPTY = 1
|
PIN_EMPTY = 1
|
||||||
|
|
||||||
@ -102,6 +105,8 @@ WORD_SIZE = 4
|
|||||||
# Boolean values are stored as a simple 0/1 int.
|
# Boolean values are stored as a simple 0/1 int.
|
||||||
TRUE_BYTE = b"\x01"
|
TRUE_BYTE = b"\x01"
|
||||||
FALSE_BYTE = b"\x00"
|
FALSE_BYTE = b"\x00"
|
||||||
|
TRUE_WORD = b"\xA5\x69\x5A\xC3"
|
||||||
|
FALSE_WORD = b"\x5A\x96\xA5\x3C"
|
||||||
|
|
||||||
# ----- Crypto ----- #
|
# ----- Crypto ----- #
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ class Storage:
|
|||||||
|
|
||||||
self.nc.set(consts.SAT_KEY, crypto.init_hmacs(self.sak))
|
self.nc.set(consts.SAT_KEY, crypto.init_hmacs(self.sak))
|
||||||
self._set_encrypt(consts.VERSION_KEY, b"\x02\x00\x00\x00")
|
self._set_encrypt(consts.VERSION_KEY, b"\x02\x00\x00\x00")
|
||||||
|
self.nc.set(consts.STORAGE_UPGRADED_KEY, consts.FALSE_WORD)
|
||||||
self.pin_log.init()
|
self.pin_log.init()
|
||||||
self._set_wipe_code(consts.WIPE_CODE_EMPTY)
|
self._set_wipe_code(consts.WIPE_CODE_EMPTY)
|
||||||
self._set_pin(consts.PIN_EMPTY)
|
self._set_pin(consts.PIN_EMPTY)
|
||||||
|
Loading…
Reference in New Issue
Block a user