mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-01-28 16:21:03 +00:00
Added storage area for u2f counter.
To prevent flashing for every u2f operation just clear one bit in the u2f area to indicate an increased counter.
This commit is contained in:
parent
8e7896456a
commit
e093371129
@ -48,13 +48,15 @@ char storage_uuid_str[25];
|
||||
/*
|
||||
storage layout:
|
||||
|
||||
offset | type/length | description
|
||||
--------+-------------+-------------------------------
|
||||
0x0000 | 4 bytes | magic = 'stor'
|
||||
0x0004 | 12 bytes | uuid
|
||||
0x0010 | ? | Storage structure
|
||||
0x4000 | 4 kbytes | area for pin failures
|
||||
0x5000 | 12 kbytes | reserved
|
||||
offset | type/length | description
|
||||
--------+--------------+-------------------------------
|
||||
0x0000 | 4 bytes | magic = 'stor'
|
||||
0x0004 | 12 bytes | uuid
|
||||
0x0010 | ? bytes | Storage structure
|
||||
--------+--------------+-------------------------------
|
||||
0x4000 | 4 kbytes | area for pin failures
|
||||
0x5000 | 256 bytes | area for u2f counter updates
|
||||
0x5100 | 11.75 kbytes | reserved
|
||||
|
||||
The area for pin failures looks like this:
|
||||
0 ... 0 pinfail 0xffffffff .. 0xffffffff
|
||||
@ -63,15 +65,28 @@ the number of zeros is the number of pin failures.
|
||||
This layout is used because we can only clear bits without
|
||||
erasing the flash.
|
||||
|
||||
The area for u2f counter updates is just a sequence of zero-bits
|
||||
followed by a sequence of one-bits. The bits in a byte are numbered
|
||||
from LSB to MSB. The number of zero bits is the offset that should
|
||||
be added to the storage u2f_counter to get the real counter value.
|
||||
|
||||
*/
|
||||
|
||||
#define FLASH_STORAGE_PINAREA (FLASH_META_START + 0x4000)
|
||||
#define FLASH_STORAGE_PINAREA_LEN (0x1000)
|
||||
#define FLASH_STORAGE_U2FAREA (FLASH_STORAGE_PINAREA + FLASH_STORAGE_PINAREA_LEN)
|
||||
#define FLASH_STORAGE_U2FAREA_LEN (0x100)
|
||||
#define FLASH_STORAGE_REALLEN (4 + sizeof(storage_uuid) + sizeof(Storage))
|
||||
_Static_assert(FLASH_STORAGE_START + FLASH_STORAGE_REALLEN <= FLASH_STORAGE_PINAREA, "Storage struct is too large for TREZOR flash");
|
||||
_Static_assert((sizeof(storage_uuid) & 3) == 0, "storage uuid unaligned");
|
||||
_Static_assert((sizeof(storage) & 3) == 0, "storage unaligned");
|
||||
|
||||
/* Current u2f offset, i.e. u2f counter is
|
||||
* storage.u2f_counter + storage_u2f_offset.
|
||||
* This corresponds to the number of cleared bits in the U2FAREA.
|
||||
*/
|
||||
static uint32_t storage_u2f_offset;
|
||||
|
||||
static bool sessionSeedCached, sessionSeedUsesPassphrase;
|
||||
|
||||
static uint8_t sessionSeed[64];
|
||||
@ -132,6 +147,15 @@ bool storage_from_flash(void)
|
||||
storage.has_pin_failed_attempts = false;
|
||||
storage.pin_failed_attempts = 0;
|
||||
}
|
||||
uint32_t *u2fptr = (uint32_t*) FLASH_STORAGE_U2FAREA;
|
||||
while (*u2fptr == 0)
|
||||
u2fptr++;
|
||||
storage_u2f_offset = 32 * (u2fptr - (uint32_t*) FLASH_STORAGE_U2FAREA);
|
||||
uint32_t u2fword = *u2fptr;
|
||||
while ((u2fword & 1) == 0) {
|
||||
storage_u2f_offset++;
|
||||
u2fword >>= 1;
|
||||
}
|
||||
// upgrade storage version
|
||||
if (version != STORAGE_VERSION) {
|
||||
storage.version = STORAGE_VERSION;
|
||||
@ -185,15 +209,13 @@ static uint32_t storage_flash_words(uint32_t addr, uint32_t *src, int nwords) {
|
||||
return addr;
|
||||
}
|
||||
|
||||
void storage_commit(void)
|
||||
static void storage_commit_locked(void)
|
||||
{
|
||||
uint8_t meta_backup[FLASH_META_DESC_LEN];
|
||||
|
||||
// backup meta
|
||||
memcpy(meta_backup, (uint8_t*)FLASH_META_START, FLASH_META_DESC_LEN);
|
||||
|
||||
flash_clear_status_flags();
|
||||
flash_unlock();
|
||||
// erase storage
|
||||
flash_erase_sector(FLASH_META_SECTOR_FIRST, FLASH_CR_PROGRAM_X32);
|
||||
// copy meta
|
||||
@ -209,6 +231,13 @@ void storage_commit(void)
|
||||
flash_program_word(flash, 0);
|
||||
flash += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void storage_commit(void)
|
||||
{
|
||||
flash_clear_status_flags();
|
||||
flash_unlock();
|
||||
storage_commit_locked();
|
||||
flash_lock();
|
||||
storage_check_flash_errors();
|
||||
}
|
||||
@ -429,23 +458,38 @@ bool session_isPinCached(void)
|
||||
return sessionPinCached;
|
||||
}
|
||||
|
||||
void storage_clearPinArea()
|
||||
void storage_clearPinArea(void)
|
||||
{
|
||||
flash_clear_status_flags();
|
||||
flash_unlock();
|
||||
flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32);
|
||||
flash_lock();
|
||||
storage_check_flash_errors();
|
||||
storage_u2f_offset = 0;
|
||||
}
|
||||
|
||||
// called when u2f area or pin area overflows
|
||||
static void storage_area_recycle(uint32_t new_pinfails)
|
||||
{
|
||||
// erase storage sector
|
||||
flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32);
|
||||
flash_program_word(FLASH_STORAGE_PINAREA, new_pinfails);
|
||||
if (storage_u2f_offset > 0) {
|
||||
storage.has_u2f_counter = true;
|
||||
storage.u2f_counter += storage_u2f_offset;
|
||||
storage_commit_locked();
|
||||
storage_u2f_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void storage_resetPinFails(uint32_t *pinfailsptr)
|
||||
{
|
||||
flash_clear_status_flags();
|
||||
flash_unlock();
|
||||
if ((uint32_t) (pinfailsptr + 1) - FLASH_STORAGE_PINAREA
|
||||
>= FLASH_STORAGE_PINAREA_LEN) {
|
||||
// erase extra storage sector
|
||||
flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32);
|
||||
if ((uint32_t) (pinfailsptr + 1)
|
||||
>= FLASH_STORAGE_PINAREA + FLASH_STORAGE_PINAREA_LEN) {
|
||||
// recycle extra storage sector
|
||||
storage_area_recycle(0xffffffff);
|
||||
} else {
|
||||
flash_program_word((uint32_t) pinfailsptr, 0);
|
||||
}
|
||||
@ -483,14 +527,24 @@ bool storage_isInitialized(void)
|
||||
return storage.has_node || storage.has_mnemonic;
|
||||
}
|
||||
|
||||
uint32_t storage_getU2FCounter(void)
|
||||
{
|
||||
return storage.u2f_counter + storage_u2f_offset;
|
||||
}
|
||||
|
||||
uint32_t storage_nextU2FCounter(void)
|
||||
{
|
||||
if(!storage.has_u2f_counter) {
|
||||
storage.has_u2f_counter = true;
|
||||
storage.u2f_counter = 1;
|
||||
} else {
|
||||
storage.u2f_counter++;
|
||||
uint32_t *ptr = ((uint32_t *) FLASH_STORAGE_U2FAREA) + (storage_u2f_offset / 32);
|
||||
uint32_t newval = 0xfffffffe << (storage_u2f_offset & 31);
|
||||
|
||||
flash_clear_status_flags();
|
||||
flash_unlock();
|
||||
flash_program_word((uint32_t) ptr, newval);
|
||||
storage_u2f_offset++;
|
||||
if (storage_u2f_offset >= 8 * FLASH_STORAGE_U2FAREA_LEN) {
|
||||
storage_area_recycle(*storage_getPinFailsPtr());
|
||||
}
|
||||
storage_commit();
|
||||
return storage.u2f_counter;
|
||||
flash_lock();
|
||||
storage_check_flash_errors();
|
||||
return storage.u2f_counter + storage_u2f_offset;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user