From 9f75d342a4872a9544b0ec36493bf3e9de5454fc Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 28 Dec 2018 16:54:25 +0100 Subject: [PATCH 01/38] Add trezor-storage submodule. Update modtrezorconfig to work with the new storage_get() interface. Update tests to expect None instead of bytes(), when the value is not found in the storage. --- .gitmodules | 3 + SConscript.firmware | 7 +- SConscript.unix | 7 +- .../extmod/modtrezorconfig/modtrezorconfig.c | 34 +- embed/extmod/modtrezorconfig/norcow.c | 305 ------------------ embed/extmod/modtrezorconfig/norcow.h | 58 ---- embed/extmod/modtrezorconfig/norcow_config.h | 43 --- embed/extmod/modtrezorconfig/storage.c | 238 -------------- embed/extmod/modtrezorconfig/storage.h | 38 --- src/apps/common/storage.py | 10 +- tests/test_trezor.config.py | 12 +- vendor/trezor-storage | 1 + 12 files changed, 55 insertions(+), 701 deletions(-) delete mode 100644 embed/extmod/modtrezorconfig/norcow.c delete mode 100644 embed/extmod/modtrezorconfig/norcow.h delete mode 100644 embed/extmod/modtrezorconfig/norcow_config.h delete mode 100644 embed/extmod/modtrezorconfig/storage.c delete mode 100644 embed/extmod/modtrezorconfig/storage.h create mode 160000 vendor/trezor-storage diff --git a/.gitmodules b/.gitmodules index eca08288a..67995f4c5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,6 @@ [submodule "vendor/nanopb"] path = vendor/nanopb url = https://github.com/nanopb/nanopb.git +[submodule "vendor/trezor-storage"] + path = vendor/trezor-storage + url = git@github.com:satoshilabs/trezor-storage.git diff --git a/SConscript.firmware b/SConscript.firmware index f75681b41..679992640 100644 --- a/SConscript.firmware +++ b/SConscript.firmware @@ -10,10 +10,13 @@ SOURCE_MOD = [] PYOPT = '1' # modtrezorconfig +CPPPATH_MOD += [ + 'vendor/trezor-storage/c', +] SOURCE_MOD += [ 'embed/extmod/modtrezorconfig/modtrezorconfig.c', - 'embed/extmod/modtrezorconfig/norcow.c', - 'embed/extmod/modtrezorconfig/storage.c', + 'vendor/trezor-storage/c/norcow.c', + 'vendor/trezor-storage/c/storage.c', ] # modtrezorcrypto diff --git a/SConscript.unix b/SConscript.unix index 7fadbb87e..9609c7d32 100644 --- a/SConscript.unix +++ b/SConscript.unix @@ -9,10 +9,13 @@ SOURCE_MOD = [] LIBS_MOD = [] # modtrezorconfig +CPPPATH_MOD += [ + 'vendor/trezor-storage/c', +] SOURCE_MOD += [ 'embed/extmod/modtrezorconfig/modtrezorconfig.c', - 'embed/extmod/modtrezorconfig/norcow.c', - 'embed/extmod/modtrezorconfig/storage.c', + 'vendor/trezor-storage/c/norcow.c', + 'vendor/trezor-storage/c/storage.c', ] # modtrezorcrypto diff --git a/embed/extmod/modtrezorconfig/modtrezorconfig.c b/embed/extmod/modtrezorconfig/modtrezorconfig.c index 8de2c5a7b..f492adb85 100644 --- a/embed/extmod/modtrezorconfig/modtrezorconfig.c +++ b/embed/extmod/modtrezorconfig/modtrezorconfig.c @@ -41,11 +41,12 @@ STATIC void wrapped_ui_wait_callback(uint32_t wait, uint32_t progress) { /// called from this module! /// ''' STATIC mp_obj_t mod_trezorconfig_init(size_t n_args, const mp_obj_t *args) { + // TODO: Add salt. if (n_args > 0) { ui_wait_callback = args[0]; - storage_init(wrapped_ui_wait_callback); + storage_init(wrapped_ui_wait_callback, (const uint8_t*)"", 0); } else { - storage_init(NULL); + storage_init(NULL, (const uint8_t*)"", 0); } return mp_const_none; } @@ -57,7 +58,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_init_obj, 0, 1, mod_ /// ''' STATIC mp_obj_t mod_trezorconfig_check_pin(mp_obj_t pin) { uint32_t pin_i = trezor_obj_get_uint(pin); - if (sectrue != storage_check_pin(pin_i)) { + if (sectrue != storage_unlock(pin_i)) { return mp_const_false; } return mp_const_true; @@ -90,6 +91,15 @@ STATIC mp_obj_t mod_trezorconfig_has_pin(void) { } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorconfig_has_pin_obj, mod_trezorconfig_has_pin); +/// def get_pin_rem() -> int: +/// ''' +/// Returns the number of remaining PIN entry attempts. +/// ''' +STATIC mp_obj_t mod_trezorconfig_get_pin_rem(void) { + return mp_obj_new_int_from_uint(storage_get_pin_rem()); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorconfig_get_pin_rem_obj, mod_trezorconfig_get_pin_rem); + /// def change_pin(pin: int, newpin: int) -> bool: /// ''' /// Change PIN. Returns True on success, False on failure. @@ -106,7 +116,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorconfig_change_pin_obj, mod_trezorconf /// def get(app: int, key: int, public: bool=False) -> bytes: /// ''' -/// Gets a value of given key for given app (or empty bytes if not set). +/// Gets the value of the given key for the given app (or None if not set). +/// Raises a RuntimeError if decryption or authentication of the stored value fails. /// ''' STATIC mp_obj_t mod_trezorconfig_get(size_t n_args, const mp_obj_t *args) { uint8_t app = trezor_obj_get_uint8(args[0]) & 0x7F; @@ -116,11 +127,19 @@ STATIC mp_obj_t mod_trezorconfig_get(size_t n_args, const mp_obj_t *args) { } uint16_t appkey = (app << 8) | key; uint16_t len = 0; - const void *val; - if (sectrue != storage_get(appkey, &val, &len) || len == 0) { + if (sectrue != storage_get(appkey, NULL, 0, &len)) { + return mp_const_none; + } + if (len == 0) { return mp_const_empty_bytes; } - return mp_obj_new_bytes(val, len); + vstr_t vstr; + vstr_init_len(&vstr, len); + if (sectrue != storage_get(appkey, vstr.buf, vstr.len, &len)) { + vstr_clear(&vstr); + mp_raise_msg(&mp_type_RuntimeError, "Failed to get value from storage."); + } + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_get_obj, 2, 3, mod_trezorconfig_get); @@ -160,6 +179,7 @@ STATIC const mp_rom_map_elem_t mp_module_trezorconfig_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_check_pin), MP_ROM_PTR(&mod_trezorconfig_check_pin_obj) }, { MP_ROM_QSTR(MP_QSTR_unlock), MP_ROM_PTR(&mod_trezorconfig_unlock_obj) }, { MP_ROM_QSTR(MP_QSTR_has_pin), MP_ROM_PTR(&mod_trezorconfig_has_pin_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_pin_rem), MP_ROM_PTR(&mod_trezorconfig_get_pin_rem_obj) }, { MP_ROM_QSTR(MP_QSTR_change_pin), MP_ROM_PTR(&mod_trezorconfig_change_pin_obj) }, { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&mod_trezorconfig_get_obj) }, { MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&mod_trezorconfig_set_obj) }, diff --git a/embed/extmod/modtrezorconfig/norcow.c b/embed/extmod/modtrezorconfig/norcow.c deleted file mode 100644 index ed54be3b2..000000000 --- a/embed/extmod/modtrezorconfig/norcow.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (c) SatoshiLabs - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - -#include "norcow.h" -#include "flash.h" -#include "common.h" - -// NRCW = 4e524357 -#define NORCOW_MAGIC ((uint32_t)0x5743524e) -#define NORCOW_MAGIC_LEN (sizeof(uint32_t)) - -static const uint8_t norcow_sectors[NORCOW_SECTOR_COUNT] = NORCOW_SECTORS; -static uint8_t norcow_active_sector = 0; -static uint32_t norcow_active_offset = NORCOW_MAGIC_LEN; - -/* - * Returns pointer to sector, starting with offset - * Fails when there is not enough space for data of given size - */ -static const void *norcow_ptr(uint8_t sector, uint32_t offset, uint32_t size) -{ - ensure(sectrue * (sector <= NORCOW_SECTOR_COUNT), "invalid sector"); - return flash_get_address(norcow_sectors[sector], offset, size); -} - -/* - * Writes data to given sector, starting from offset - */ -static secbool norcow_write(uint8_t sector, uint32_t offset, uint32_t prefix, const uint8_t *data, uint16_t len) -{ - if (sector >= NORCOW_SECTOR_COUNT) { - return secfalse; - } - ensure(flash_unlock(), NULL); - - // write prefix - ensure(flash_write_word(norcow_sectors[sector], offset, prefix), NULL); - - if (len > 0) { - offset += sizeof(uint32_t); - // write data - for (uint16_t i = 0; i < len; i++, offset++) { - ensure(flash_write_byte(norcow_sectors[sector], offset, data[i]), NULL); - } - // pad with zeroes - for (; offset % 4; offset++) { - ensure(flash_write_byte(norcow_sectors[sector], offset, 0x00), NULL); - } - } - ensure(flash_lock(), NULL); - return sectrue; -} - -/* - * Erases sector (and sets a magic) - */ -static void norcow_erase(uint8_t sector, secbool set_magic) -{ - ensure(sectrue * (sector <= NORCOW_SECTOR_COUNT), "invalid sector"); - ensure(flash_erase_sector(norcow_sectors[sector]), "erase failed"); - if (sectrue == set_magic) { - ensure(norcow_write(sector, 0, NORCOW_MAGIC, NULL, 0), "set magic failed"); - } -} - -#define ALIGN4(X) (X) = ((X) + 3) & ~3 - -/* - * Reads one item starting from offset - */ -static secbool read_item(uint8_t sector, uint32_t offset, uint16_t *key, const void **val, uint16_t *len, uint32_t *pos) -{ - *pos = offset; - - const void *k = norcow_ptr(sector, *pos, 2); - if (k == NULL) return secfalse; - *pos += 2; - memcpy(key, k, sizeof(uint16_t)); - if (*key == 0xFFFF) { - return secfalse; - } - - const void *l = norcow_ptr(sector, *pos, 2); - if (l == NULL) return secfalse; - *pos += 2; - memcpy(len, l, sizeof(uint16_t)); - - *val = norcow_ptr(sector, *pos, *len); - if (*val == NULL) return secfalse; - *pos += *len; - ALIGN4(*pos); - return sectrue; -} - -/* - * Writes one item starting from offset - */ -static secbool write_item(uint8_t sector, uint32_t offset, uint16_t key, const void *val, uint16_t len, uint32_t *pos) -{ - uint32_t prefix = (len << 16) | key; - *pos = offset + sizeof(uint32_t) + len; - ALIGN4(*pos); - return norcow_write(sector, offset, prefix, val, len); -} - -/* - * Finds item in given sector - */ -static secbool find_item(uint8_t sector, uint16_t key, const void **val, uint16_t *len) -{ - *val = 0; - *len = 0; - uint32_t offset = NORCOW_MAGIC_LEN; - for (;;) { - uint16_t k, l; - const void *v; - uint32_t pos; - if (sectrue != read_item(sector, offset, &k, &v, &l, &pos)) { - break; - } - if (key == k) { - *val = v; - *len = l; - } - offset = pos; - } - return sectrue * (*val != NULL); -} - -/* - * Finds first unused offset in given sector - */ -static uint32_t find_free_offset(uint8_t sector) -{ - uint32_t offset = NORCOW_MAGIC_LEN; - for (;;) { - uint16_t key, len; - const void *val; - uint32_t pos; - if (sectrue != read_item(sector, offset, &key, &val, &len, &pos)) { - break; - } - offset = pos; - } - return offset; -} - -/* - * Compacts active sector and sets new active sector - */ -static void compact() -{ - uint8_t norcow_next_sector = (norcow_active_sector + 1) % NORCOW_SECTOR_COUNT; - norcow_erase(norcow_next_sector, sectrue); - - uint32_t offset = NORCOW_MAGIC_LEN, offsetw = NORCOW_MAGIC_LEN; - - for (;;) { - // read item - uint16_t k, l; - const void *v; - uint32_t pos; - secbool r = read_item(norcow_active_sector, offset, &k, &v, &l, &pos); - if (sectrue != r) { - break; - } - offset = pos; - - // check if not already saved - const void *v2; - uint16_t l2; - r = find_item(norcow_next_sector, k, &v2, &l2); - if (sectrue == r) { - continue; - } - - // scan for latest instance - uint32_t offsetr = offset; - for (;;) { - uint16_t k2; - uint32_t posr; - r = read_item(norcow_active_sector, offsetr, &k2, &v2, &l2, &posr); - if (sectrue != r) { - break; - } - if (k == k2) { - v = v2; - l = l2; - } - offsetr = posr; - } - - // copy the last item - uint32_t posw; - ensure(write_item(norcow_next_sector, offsetw, k, v, l, &posw), "compaction write failed"); - offsetw = posw; - } - - norcow_erase(norcow_active_sector, secfalse); - norcow_active_sector = norcow_next_sector; - norcow_active_offset = find_free_offset(norcow_active_sector); -} - -/* - * Initializes storage - */ -void norcow_init(void) -{ - flash_init(); - secbool found = secfalse; - // detect active sector - starts with magic - for (uint8_t i = 0; i < NORCOW_SECTOR_COUNT; i++) { - const uint32_t *magic = norcow_ptr(i, 0, NORCOW_MAGIC_LEN); - if (magic != NULL && *magic == NORCOW_MAGIC) { - found = sectrue; - norcow_active_sector = i; - break; - } - } - // no active sectors found - let's erase - if (sectrue == found) { - norcow_active_offset = find_free_offset(norcow_active_sector); - } else { - norcow_wipe(); - } -} - -/* - * Wipe the storage - */ -void norcow_wipe(void) -{ - norcow_erase(0, sectrue); - for (uint8_t i = 1; i < NORCOW_SECTOR_COUNT; i++) { - norcow_erase(i, secfalse); - } - norcow_active_sector = 0; - norcow_active_offset = NORCOW_MAGIC_LEN; -} - -/* - * Looks for the given key, returns status of the operation - */ -secbool norcow_get(uint16_t key, const void **val, uint16_t *len) -{ - return find_item(norcow_active_sector, key, val, len); -} - -/* - * Sets the given key, returns status of the operation - */ -secbool norcow_set(uint16_t key, const void *val, uint16_t len) -{ - // check whether there is enough free space - // and compact if full - if (norcow_active_offset + sizeof(uint32_t) + len > NORCOW_SECTOR_SIZE) { - compact(); - } - // write item - uint32_t pos; - secbool r = write_item(norcow_active_sector, norcow_active_offset, key, val, len, &pos); - if (sectrue == r) { - norcow_active_offset = pos; - } - return r; -} - -/* - * Update a word in flash at the given pointer. The pointer must point - * into the NORCOW area. - */ -secbool norcow_update(uint16_t key, uint16_t offset, uint32_t value) -{ - const void *ptr; - uint16_t len; - if (sectrue != find_item(norcow_active_sector, key, &ptr, &len)) { - return secfalse; - } - if ((offset & 3) != 0 || offset >= len) { - return secfalse; - } - uint32_t sector_offset = (const uint8_t*) ptr - (const uint8_t *)norcow_ptr(norcow_active_sector, 0, NORCOW_SECTOR_SIZE) + offset; - ensure(flash_unlock(), NULL); - ensure(flash_write_word(norcow_sectors[norcow_active_sector], sector_offset, value), NULL); - ensure(flash_lock(), NULL); - return sectrue; -} diff --git a/embed/extmod/modtrezorconfig/norcow.h b/embed/extmod/modtrezorconfig/norcow.h deleted file mode 100644 index 00bab4d0a..000000000 --- a/embed/extmod/modtrezorconfig/norcow.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (c) SatoshiLabs - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __NORCOW_H__ -#define __NORCOW_H__ - -#include -#include "secbool.h" - -/* - * Storage parameters - */ - -#include "norcow_config.h" - -/* - * Initialize storage - */ -void norcow_init(void); - -/* - * Wipe the storage - */ -void norcow_wipe(void); - -/* - * Looks for the given key, returns status of the operation - */ -secbool norcow_get(uint16_t key, const void **val, uint16_t *len); - -/* - * Sets the given key, returns status of the operation - */ -secbool norcow_set(uint16_t key, const void *val, uint16_t len); - -/* - * Update a word in flash in the given key at the given offset. - * Note that you can only change bits from 1 to 0. - */ -secbool norcow_update(uint16_t key, uint16_t offset, uint32_t value); - -#endif diff --git a/embed/extmod/modtrezorconfig/norcow_config.h b/embed/extmod/modtrezorconfig/norcow_config.h deleted file mode 100644 index d792776d5..000000000 --- a/embed/extmod/modtrezorconfig/norcow_config.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (c) SatoshiLabs - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __NORCOW_CONFIG_H__ -#define __NORCOW_CONFIG_H__ - -#include "flash.h" - -#define NORCOW_SECTOR_COUNT 2 - -#if TREZOR_MODEL == T - -#define NORCOW_SECTOR_SIZE (64*1024) -#define NORCOW_SECTORS {FLASH_SECTOR_STORAGE_1, FLASH_SECTOR_STORAGE_2} - -#elif TREZOR_MODEL == 1 - -#define NORCOW_SECTOR_SIZE (16*1024) -#define NORCOW_SECTORS {2, 3} - -#else - -#error Unknown TREZOR Model - -#endif - -#endif diff --git a/embed/extmod/modtrezorconfig/storage.c b/embed/extmod/modtrezorconfig/storage.c deleted file mode 100644 index 5e0f8343b..000000000 --- a/embed/extmod/modtrezorconfig/storage.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (c) SatoshiLabs - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include - -#include "common.h" -#include "norcow.h" -#include "storage.h" - -// Norcow storage key of configured PIN. -#define PIN_KEY 0x0000 - -// Maximum PIN length. -#define PIN_MAXLEN 32 - -// Byte-length of flash section containing fail counters. -#define PIN_FAIL_KEY 0x0001 -#define PIN_FAIL_SECTOR_SIZE 32 - -// Maximum number of failed unlock attempts. -#define PIN_MAX_TRIES 15 - -static secbool initialized = secfalse; -static secbool unlocked = secfalse; -static PIN_UI_WAIT_CALLBACK ui_callback = NULL; - -void storage_init(PIN_UI_WAIT_CALLBACK callback) -{ - initialized = secfalse; - unlocked = secfalse; - norcow_init(); - initialized = sectrue; - ui_callback = callback; -} - -static secbool pin_fails_reset(uint16_t ofs) -{ - return norcow_update(PIN_FAIL_KEY, ofs, 0); -} - -static secbool pin_fails_increase(const uint32_t *ptr, uint16_t ofs) -{ - uint32_t ctr = *ptr; - ctr = ctr << 1; - - if (sectrue != norcow_update(PIN_FAIL_KEY, ofs, ctr)) { - return secfalse; - } - - uint32_t check = *ptr; - if (ctr != check) { - return secfalse; - } - return sectrue; -} - -static void pin_fails_check_max(uint32_t ctr) -{ - if (~ctr >= (1 << PIN_MAX_TRIES)) { - norcow_wipe(); - ensure(secfalse, "pin_fails_check_max"); - } -} - -static secbool pin_cmp(const uint32_t pin) -{ - const void *spin = NULL; - uint16_t spinlen = 0; - norcow_get(PIN_KEY, &spin, &spinlen); - if (NULL != spin && spinlen == sizeof(uint32_t)) { - return sectrue * (pin == *(const uint32_t*)spin); - } else { - return sectrue * (1 == pin); - } -} - -static secbool pin_get_fails(const uint32_t **pinfail, uint32_t *pofs) -{ - const void *vpinfail; - uint16_t pinfaillen; - unsigned int ofs; - // The PIN_FAIL_KEY points to an area of words, initialized to - // 0xffffffff (meaning no pin failures). The first non-zero word - // in this area is the current pin failure counter. If PIN_FAIL_KEY - // has no configuration or is empty, the pin failure counter is 0. - // We rely on the fact that flash allows to clear bits and we clear one - // bit to indicate pin failure. On success, the word is set to 0, - // indicating that the next word is the pin failure counter. - - // Find the current pin failure counter - if (secfalse != norcow_get(PIN_FAIL_KEY, &vpinfail, &pinfaillen)) { - *pinfail = vpinfail; - for (ofs = 0; ofs < pinfaillen / sizeof(uint32_t); ofs++) { - if (((const uint32_t *) vpinfail)[ofs]) { - *pinfail = vpinfail; - *pofs = ofs; - return sectrue; - } - } - } - - // No pin failure section, or all entries used -> create a new one. - uint32_t pinarea[PIN_FAIL_SECTOR_SIZE]; - memset(pinarea, 0xff, sizeof(pinarea)); - if (sectrue != norcow_set(PIN_FAIL_KEY, pinarea, sizeof(pinarea))) { - return secfalse; - } - if (sectrue != norcow_get(PIN_FAIL_KEY, &vpinfail, &pinfaillen)) { - return secfalse; - } - *pinfail = vpinfail; - *pofs = 0; - return sectrue; -} - -secbool storage_check_pin(const uint32_t pin) -{ - const uint32_t *pinfail = NULL; - uint32_t ofs; - uint32_t ctr; - - // Get the pin failure counter - if (pin_get_fails(&pinfail, &ofs) != sectrue) { - return secfalse; - } - - // Read current failure counter - ctr = pinfail[ofs]; - // Wipe storage if too many failures - pin_fails_check_max(ctr); - - // Sleep for ~ctr seconds before checking the PIN. - uint32_t progress; - for (uint32_t wait = ~ctr; wait > 0; wait--) { - for (int i = 0; i < 10; i++) { - if (ui_callback) { - if ((~ctr) > 1000000) { // precise enough - progress = (~ctr - wait) / ((~ctr) / 1000); - } else { - progress = ((~ctr - wait) * 10 + i) * 100 / (~ctr); - } - ui_callback(wait, progress); - } - hal_delay(100); - } - } - // Show last frame if we were waiting - if ((~ctr > 0) && ui_callback) { - ui_callback(0, 1000); - } - - // First, we increase PIN fail counter in storage, even before checking the - // PIN. If the PIN is correct, we reset the counter afterwards. If not, we - // check if this is the last allowed attempt. - if (sectrue != pin_fails_increase(pinfail + ofs, ofs * sizeof(uint32_t))) { - return secfalse; - } - if (sectrue != pin_cmp(pin)) { - // Wipe storage if too many failures - pin_fails_check_max(ctr << 1); - return secfalse; - } - // Finally set the counter to 0 to indicate success. - return pin_fails_reset(ofs * sizeof(uint32_t)); -} - -secbool storage_unlock(const uint32_t pin) -{ - unlocked = secfalse; - if (sectrue == initialized && sectrue == storage_check_pin(pin)) { - unlocked = sectrue; - } - return unlocked; -} - -secbool storage_get(const uint16_t key, const void **val, uint16_t *len) -{ - const uint8_t app = key >> 8; - // APP == 0 is reserved for PIN related values - if (sectrue != initialized || app == 0) { - return secfalse; - } - // top bit of APP set indicates the value can be read from unlocked device - if (sectrue != unlocked && ((app & 0x80) == 0)) { - return secfalse; - } - return norcow_get(key, val, len); -} - -secbool storage_set(const uint16_t key, const void *val, uint16_t len) -{ - const uint8_t app = key >> 8; - // APP == 0 is reserved for PIN related values - if (sectrue != initialized || sectrue != unlocked || app == 0) { - return secfalse; - } - return norcow_set(key, val, len); -} - -secbool storage_has_pin(void) -{ - if (sectrue != initialized) { - return secfalse; - } - return sectrue == pin_cmp(1) ? secfalse : sectrue; -} - -secbool storage_change_pin(const uint32_t oldpin, const uint32_t newpin) -{ - if (sectrue != initialized || sectrue != unlocked) { - return secfalse; - } - if (sectrue != storage_check_pin(oldpin)) { - return secfalse; - } - return norcow_set(PIN_KEY, &newpin, sizeof(uint32_t)); -} - -void storage_wipe(void) -{ - norcow_wipe(); -} diff --git a/embed/extmod/modtrezorconfig/storage.h b/embed/extmod/modtrezorconfig/storage.h deleted file mode 100644 index 797528175..000000000 --- a/embed/extmod/modtrezorconfig/storage.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (c) SatoshiLabs - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __STORAGE_H__ -#define __STORAGE_H__ - -#include -#include -#include "secbool.h" - -typedef void (*PIN_UI_WAIT_CALLBACK)(uint32_t wait, uint32_t progress); - -void storage_init(PIN_UI_WAIT_CALLBACK callback); -void storage_wipe(void); -secbool storage_check_pin(const uint32_t pin); -secbool storage_unlock(const uint32_t pin); -secbool storage_has_pin(void); -secbool storage_change_pin(const uint32_t oldpin, const uint32_t newpin); -secbool storage_get(const uint16_t key, const void **val, uint16_t *len); -secbool storage_set(const uint16_t key, const void *val, uint16_t len); - -#endif diff --git a/src/apps/common/storage.py b/src/apps/common/storage.py index d1be98c2a..b16d8be57 100644 --- a/src/apps/common/storage.py +++ b/src/apps/common/storage.py @@ -46,11 +46,17 @@ def is_initialized() -> bool: def get_label() -> str: - return config.get(_APP, _LABEL, True).decode() # public + label = config.get(_APP, _LABEL, True) # public + if label is None: + return None + return label.decode() def get_mnemonic() -> str: - return config.get(_APP, _MNEMONIC).decode() + mnemonic = config.get(_APP, _MNEMONIC) + if mnemonic is None: + return None + return mnemonic.decode() def has_passphrase() -> bool: diff --git a/tests/test_trezor.config.py b/tests/test_trezor.config.py index 68ee5ac60..4bba499da 100644 --- a/tests/test_trezor.config.py +++ b/tests/test_trezor.config.py @@ -37,8 +37,8 @@ class TestConfig(unittest.TestCase): config.wipe() v0 = config.get(1, 1) v1 = config.get(1, 2) - self.assertEqual(v0, bytes()) - self.assertEqual(v1, bytes()) + self.assertEqual(v0, None) + self.assertEqual(v1, None) def test_lock(self): for _ in range(128): @@ -49,7 +49,7 @@ class TestConfig(unittest.TestCase): value = random.bytes(16) config.set(appid, key, value) config.init() - self.assertEqual(config.get(appid, key), bytes()) + self.assertEqual(config.get(appid, key), None) with self.assertRaises(RuntimeError): config.set(appid, key, bytes()) config.init() @@ -79,7 +79,7 @@ class TestConfig(unittest.TestCase): v1 = config.get(appid, key) v2 = config.get(appid, key, True) self.assertNotEqual(v1, v2) - self.assertEqual(v1, bytes()) + self.assertEqual(v1, None) self.assertEqual(v2, value16) def test_change_pin(self): @@ -90,7 +90,7 @@ class TestConfig(unittest.TestCase): config.set(PINAPP, PINKEY, b'value') self.assertEqual(config.change_pin(pin_to_int('000'), pin_to_int('666')), False) self.assertEqual(config.change_pin(pin_to_int(''), pin_to_int('000')), True) - self.assertEqual(config.get(PINAPP, PINKEY), bytes()) + self.assertEqual(config.get(PINAPP, PINKEY), None) config.set(1, 1, b'value') config.init() self.assertEqual(config.unlock(pin_to_int('000')), True) @@ -129,7 +129,7 @@ class TestConfig(unittest.TestCase): for _ in range(128): appid, key = random_entry() value = config.get(appid, key) - self.assertEqual(value, bytes()) + self.assertEqual(value, None) if __name__ == '__main__': diff --git a/vendor/trezor-storage b/vendor/trezor-storage new file mode 160000 index 000000000..639bea4ea --- /dev/null +++ b/vendor/trezor-storage @@ -0,0 +1 @@ +Subproject commit 639bea4ea8a56e4a2f30b39e25a363c462a70e2d From 3517018f30ea29527d60934d9cd9151d521bac9b Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 28 Dec 2018 17:10:16 +0100 Subject: [PATCH 02/38] Display the number of PIN entry attempts remaining. --- src/apps/common/request_pin.py | 10 ++++++++-- src/apps/common/storage.py | 8 ++++---- src/apps/management/change_pin.py | 2 +- src/boot.py | 2 +- src/trezor/ui/pin.py | 9 +++++++-- 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/apps/common/request_pin.py b/src/apps/common/request_pin.py index 1c9d0e04f..24f2d90da 100644 --- a/src/apps/common/request_pin.py +++ b/src/apps/common/request_pin.py @@ -11,7 +11,7 @@ class PinCancelled(Exception): @ui.layout -async def request_pin(label=None, cancellable: bool = True) -> str: +async def request_pin(label=None, attempts_remaining=None, cancellable: bool = True) -> str: def onchange(): c = dialog.cancel if matrix.pin: @@ -36,7 +36,13 @@ async def request_pin(label=None, cancellable: bool = True) -> str: if label is None: label = "Enter your PIN" - matrix = PinMatrix(label) + sublabel = None + if attempts_remaining: + if attempts_remaining == 1: + sublabel = "This is your last attempt" + else: + sublabel = "{} attempts remaining".format(attempts_remaining) + matrix = PinMatrix(label, sublabel) matrix.onchange = onchange dialog = ConfirmDialog(matrix) dialog.cancel.area = ui.grid(12) diff --git a/src/apps/common/storage.py b/src/apps/common/storage.py index b16d8be57..7954c015a 100644 --- a/src/apps/common/storage.py +++ b/src/apps/common/storage.py @@ -34,11 +34,11 @@ def _new_device_id() -> str: def get_device_id() -> str: - dev_id = config.get(_APP, _DEVICE_ID, True).decode() # public + dev_id = config.get(_APP, _DEVICE_ID, True) # public if not dev_id: - dev_id = _new_device_id() - config.set(_APP, _DEVICE_ID, dev_id.encode(), True) # public - return dev_id + dev_id = _new_device_id().encode() + config.set(_APP, _DEVICE_ID, dev_id, True) # public + return dev_id.decode() def is_initialized() -> bool: diff --git a/src/apps/management/change_pin.py b/src/apps/management/change_pin.py index 2c554b8fb..71f01ed0c 100644 --- a/src/apps/management/change_pin.py +++ b/src/apps/management/change_pin.py @@ -16,7 +16,7 @@ async def change_pin(ctx, msg): # get current pin, return failure if invalid if config.has_pin(): - curpin = await request_pin_ack(ctx) + curpin = await request_pin_ack(ctx, "Enter old PIN", config.get_pin_rem()) if not config.check_pin(pin_to_int(curpin)): raise wire.PinInvalid("PIN invalid") else: diff --git a/src/boot.py b/src/boot.py index 622562152..cec662cdb 100644 --- a/src/boot.py +++ b/src/boot.py @@ -13,7 +13,7 @@ async def bootscreen(): await lockscreen() label = None while True: - pin = await request_pin(label) + pin = await request_pin(label, config.get_pin_rem()) if config.unlock(pin_to_int(pin)): return else: diff --git a/src/trezor/ui/pin.py b/src/trezor/ui/pin.py index 00bf61029..5ae89f663 100644 --- a/src/trezor/ui/pin.py +++ b/src/trezor/ui/pin.py @@ -19,8 +19,9 @@ def generate_digits(): class PinMatrix(ui.Widget): - def __init__(self, label, pin="", maxlength=9): + def __init__(self, label, sublabel, pin="", maxlength=9): self.label = label + self.sublabel = sublabel self.pin = pin self.maxlength = maxlength self.digits = generate_digits() @@ -48,7 +49,7 @@ class PinMatrix(ui.Widget): return # clear canvas under input line - display.bar(0, 0, ui.WIDTH, 45, ui.BG) + display.bar(0, 0, ui.WIDTH, 52, ui.BG) if self.pin: # input line with pin @@ -60,6 +61,10 @@ class PinMatrix(ui.Widget): x = (box_w - l * padding) // 2 for i in range(0, l): ui.display.bar_radius(x + i * padding, y, size, size, ui.GREY, ui.BG, 4) + elif self.sublabel: + # input line with header label and sublabel + display.text_center(ui.WIDTH // 2, 20, self.label, ui.BOLD, ui.GREY, ui.BG) + display.text_center(ui.WIDTH // 2, 46, self.sublabel, ui.NORMAL, ui.GREY, ui.BG) else: # input line with header label display.text_center(ui.WIDTH // 2, 36, self.label, ui.BOLD, ui.GREY, ui.BG) From efe8a7f06598a3a6d1badcbf223c53ff3f0ed305 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 28 Dec 2018 17:19:11 +0100 Subject: [PATCH 03/38] Improve messages in the Enable PIN dialog and Change PIN dialog. --- src/apps/management/change_pin.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/apps/management/change_pin.py b/src/apps/management/change_pin.py index 71f01ed0c..b85a7e033 100644 --- a/src/apps/management/change_pin.py +++ b/src/apps/management/change_pin.py @@ -44,19 +44,19 @@ def require_confirm_change_pin(ctx, msg): if msg.remove and has_pin: # removing pin text = Text("Remove PIN", ui.ICON_CONFIG) text.normal("Do you really want to") - text.bold("remove current PIN?") + text.bold("disable PIN protection?") return require_confirm(ctx, text) if not msg.remove and has_pin: # changing pin - text = Text("Remove PIN", ui.ICON_CONFIG) + text = Text("Change PIN", ui.ICON_CONFIG) text.normal("Do you really want to") - text.bold("change current PIN?") + text.bold("change the current PIN?") return require_confirm(ctx, text) if not msg.remove and not has_pin: # setting new pin - text = Text("Remove PIN", ui.ICON_CONFIG) + text = Text("Enable PIN", ui.ICON_CONFIG) text.normal("Do you really want to") - text.bold("set new PIN?") + text.bold("enable PIN protection?") return require_confirm(ctx, text) From 11ba0b424e145d621887379e1c75d73204da56e3 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 28 Dec 2018 17:48:19 +0100 Subject: [PATCH 04/38] Improve messages in the seed recovery dialog to better match the terminology used in Trezor wallet. --- src/apps/management/recovery_device.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/apps/management/recovery_device.py b/src/apps/management/recovery_device.py index 4d3ca7ac5..702aec6d5 100644 --- a/src/apps/management/recovery_device.py +++ b/src/apps/management/recovery_device.py @@ -32,8 +32,12 @@ async def recovery_device(ctx, msg): if not msg.dry_run and storage.is_initialized(): raise wire.UnexpectedMessage("Already initialized") - text = Text("Device recovery", ui.ICON_RECOVERY) - text.normal("Do you really want to", "recover the device?", "") + if msg.dry_run: + text = Text("Check recovery seed", ui.ICON_RECOVERY) + text.normal("Do you really want to", "check your recovery", "seed?") + else: + text = Text("Recover wallet", ui.ICON_RECOVERY) + text.normal("Do you really want to", "restore a wallet from", "your backup?") await require_confirm(ctx, text, code=ProtectCall) @@ -77,7 +81,7 @@ async def recovery_device(ctx, msg): async def request_wordcount(ctx): await ctx.call(ButtonRequest(code=MnemonicWordCount), ButtonAck) - text = Text("Device recovery", ui.ICON_RECOVERY) + text = Text("Recovery seed", ui.ICON_RECOVERY) text.normal("Number of words?") count = await ctx.wait(WordSelector(text)) From 7f7a8a2ca6142c800b7abc23021ecfd4cd5ba179 Mon Sep 17 00:00:00 2001 From: andrew Date: Sat, 29 Dec 2018 18:48:30 +0100 Subject: [PATCH 05/38] Store boolean values as '0x00' and '0x01' instead of '' and '0x01'. --- src/apps/common/storage.py | 41 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/apps/common/storage.py b/src/apps/common/storage.py index 7954c015a..0d1c3fd81 100644 --- a/src/apps/common/storage.py +++ b/src/apps/common/storage.py @@ -9,6 +9,8 @@ from apps.common import cache HOMESCREEN_MAXSIZE = 16384 _STORAGE_VERSION = b"\x01" +_FALSE_BYTE = b"\x00" +_TRUE_BYTE = b"\x01" # fmt: off _APP = const(0x01) # app namespace @@ -28,6 +30,16 @@ _AUTOLOCK_DELAY_MS = const(0x0C) # int _NO_BACKUP = const(0x0D) # bool (0x01 or empty) # fmt: on +def _set_bool(app: int, key: int, value: bool, public: bool = False) -> None: + if value: + config.set(app, key, _TRUE_BYTE, public) + else: + config.set(app, key, _FALSE_BYTE, public) + + +def _get_bool(app: int, key: int, public: bool = False) -> bool: + return config.get(app, key, public) == _TRUE_BYTE + def _new_device_id() -> str: return hexlify(random.bytes(12)).decode().upper() @@ -60,7 +72,7 @@ def get_mnemonic() -> str: def has_passphrase() -> bool: - return bool(config.get(_APP, _USE_PASSPHRASE)) + return _get_bool(_APP, _USE_PASSPHRASE) def get_homescreen() -> bytes: @@ -70,18 +82,13 @@ def get_homescreen() -> bytes: def load_mnemonic(mnemonic: str, needs_backup: bool, no_backup: bool) -> None: config.set(_APP, _MNEMONIC, mnemonic.encode()) config.set(_APP, _VERSION, _STORAGE_VERSION) - if no_backup: - config.set(_APP, _NO_BACKUP, b"\x01") - else: - config.set(_APP, _NO_BACKUP, b"") - if needs_backup: - config.set(_APP, _NEEDS_BACKUP, b"\x01") - else: - config.set(_APP, _NEEDS_BACKUP, b"") + _set_bool(_APP, _NO_BACKUP, no_backup) + if not no_backup: + _set_bool(_APP, _NEEDS_BACKUP, needs_backup) def needs_backup() -> bool: - return bool(config.get(_APP, _NEEDS_BACKUP)) + return _get_bool(_APP, _NEEDS_BACKUP) def set_backed_up() -> None: @@ -89,18 +96,15 @@ def set_backed_up() -> None: def unfinished_backup() -> bool: - return bool(config.get(_APP, _UNFINISHED_BACKUP)) + return _get_bool(_APP, _UNFINISHED_BACKUP) def set_unfinished_backup(state: bool) -> None: - if state: - config.set(_APP, _UNFINISHED_BACKUP, b"\x01") - else: - config.set(_APP, _UNFINISHED_BACKUP, b"") + _set_bool(_APP, _UNFINISHED_BACKUP, state) def no_backup() -> bool: - return bool(config.get(_APP, _NO_BACKUP)) + return _get_bool(_APP, _NO_BACKUP) def get_passphrase_source() -> int: @@ -121,10 +125,7 @@ def load_settings( ) -> None: if label is not None: config.set(_APP, _LABEL, label.encode(), True) # public - if use_passphrase is True: - config.set(_APP, _USE_PASSPHRASE, b"\x01") - if use_passphrase is False: - config.set(_APP, _USE_PASSPHRASE, b"") + _set_bool(_APP, _USE_PASSPHRASE, use_passphrase) if homescreen is not None: if homescreen[:8] == b"TOIf\x90\x00\x90\x00": if len(homescreen) <= HOMESCREEN_MAXSIZE: From 4cea4d2a4a9a5005aea06301e4d800ec84560ce4 Mon Sep 17 00:00:00 2001 From: andrew Date: Sat, 29 Dec 2018 22:33:19 +0100 Subject: [PATCH 06/38] Implement efficient counter in storage.py. --- src/apps/common/storage.py | 57 ++++++++++++++++++++++++------- tests/test_apps.common.storage.py | 21 ++++++++++++ 2 files changed, 66 insertions(+), 12 deletions(-) create mode 100644 tests/test_apps.common.storage.py diff --git a/src/apps/common/storage.py b/src/apps/common/storage.py index 0d1c3fd81..7692d9741 100644 --- a/src/apps/common/storage.py +++ b/src/apps/common/storage.py @@ -11,6 +11,8 @@ HOMESCREEN_MAXSIZE = 16384 _STORAGE_VERSION = b"\x01" _FALSE_BYTE = b"\x00" _TRUE_BYTE = b"\x01" +_COUNTER_HEAD_LEN = 4 +_COUNTER_TAIL_LEN = 8 # fmt: off _APP = const(0x01) # app namespace @@ -41,6 +43,46 @@ def _get_bool(app: int, key: int, public: bool = False) -> bool: return config.get(app, key, public) == _TRUE_BYTE +def _set_counter(app: int, key: int, count: int, public: bool = False) -> None: + value = count.to_bytes(_COUNTER_HEAD_LEN, "big") + if public: + value += _COUNTER_TAIL_LEN * b"\xff" + config.set(app, key, value, public) + + +def _next_counter(app: int, key: int, public: bool = False) -> int: +# If the counter value is public, then it is stored as a four byte integer in +# big endian byte order, called the "head", followed an eight byte "tail". The +# counter value is equal to the integer value of the head plus the number of +# zero bits in the tail. The counter value 0 is stored as 00000000FFFFFFFFFFFFFFFF. +# With each increment the tail is shifted to the right by one bit. Thus after +# three increments the stored value is 000000001FFFFFFFFFFFFFFF. Once all the +# bits in the tail are set to zero, the next counter value is stored as +# 00000021FFFFFFFFFFFFFFFF. + + value = config.get(app, key, public) + if value is None: + _set_counter(app, key, 0, public) + return 0 + + head = value[: _COUNTER_HEAD_LEN] + tail = value[_COUNTER_HEAD_LEN :] + i = tail.rfind(b"\x00") + 1 + count = int.from_bytes(head, "big") + 1 + 8*i + if i == len(tail): + _set_counter(app, key, count, public) + return count + + zero_count = 0 + while (tail[i] << zero_count) < 128: + zero_count += 1 + count += zero_count + + tail = tail[:i] + bytes([tail[i] >> 1]) + tail[i+1:] + config.set(app, key, head + tail, public) + return count + + def _new_device_id() -> str: return hexlify(random.bytes(12)).decode().upper() @@ -171,20 +213,11 @@ def set_autolock_delay_ms(delay_ms: int) -> None: def next_u2f_counter() -> int: - b = config.get(_APP, _U2F_COUNTER) - if not b: - b = 0 - else: - b = int.from_bytes(b, "big") + 1 - set_u2f_counter(b) - return b + return _next_counter(_APP, _U2F_COUNTER) -def set_u2f_counter(cntr: int): - if cntr: - config.set(_APP, _U2F_COUNTER, cntr.to_bytes(4, "big")) - else: - config.set(_APP, _U2F_COUNTER, b"") +def set_u2f_counter(cntr: int) -> None: + _set_counter(_APP, _U2F_COUNTER, cntr) def wipe(): diff --git a/tests/test_apps.common.storage.py b/tests/test_apps.common.storage.py new file mode 100644 index 000000000..f530c0b1c --- /dev/null +++ b/tests/test_apps.common.storage.py @@ -0,0 +1,21 @@ +from common import * +from trezor.pin import pin_to_int +from trezor import config +from apps.common import storage + + +class TestConfig(unittest.TestCase): + + def test_counter(self): + config.init() + config.wipe() + self.assertEqual(config.unlock(pin_to_int('')), True) + for i in range(150): + self.assertEqual(storage.next_u2f_counter(), i) + storage.set_u2f_counter(350) + for i in range(351, 500): + self.assertEqual(storage.next_u2f_counter(), i) + + +if __name__ == '__main__': + unittest.main() From 5f94b6a6d2bb042e5c3136881919245afbf9bf77 Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 2 Jan 2019 16:14:12 +0100 Subject: [PATCH 07/38] Add CPUID, flash size and unique device ID as salt to storage_init(). --- SConscript.firmware | 1 + SConscript.unix | 1 + .../extmod/modtrezorconfig/modtrezorconfig.c | 13 +++- embed/trezorhal/utils.c | 62 +++++++++++++++++++ embed/trezorhal/utils.h | 31 ++++++++++ embed/unix/utils.c | 60 ++++++++++++++++++ embed/unix/utils.h | 31 ++++++++++ 7 files changed, 196 insertions(+), 3 deletions(-) create mode 100644 embed/trezorhal/utils.c create mode 100644 embed/trezorhal/utils.h create mode 100644 embed/unix/utils.c create mode 100644 embed/unix/utils.h diff --git a/SConscript.firmware b/SConscript.firmware index 679992640..67682baa9 100644 --- a/SConscript.firmware +++ b/SConscript.firmware @@ -278,6 +278,7 @@ SOURCE_TREZORHAL = [ 'embed/trezorhal/usbd_core.c', 'embed/trezorhal/usbd_ctlreq.c', 'embed/trezorhal/usbd_ioreq.c', + 'embed/trezorhal/utils.c', 'embed/trezorhal/util.s', 'embed/trezorhal/vectortable.s', ] diff --git a/SConscript.unix b/SConscript.unix index 9609c7d32..d1f4c7010 100644 --- a/SConscript.unix +++ b/SConscript.unix @@ -257,6 +257,7 @@ SOURCE_UNIX = [ 'embed/unix/sbu.c', 'embed/unix/touch.c', 'embed/unix/usb.c', + 'embed/unix/utils.c', ] SOURCE_QSTR = SOURCE_MOD + SOURCE_MICROPYTHON + SOURCE_UNIX diff --git a/embed/extmod/modtrezorconfig/modtrezorconfig.c b/embed/extmod/modtrezorconfig/modtrezorconfig.c index f492adb85..4b368ac71 100644 --- a/embed/extmod/modtrezorconfig/modtrezorconfig.c +++ b/embed/extmod/modtrezorconfig/modtrezorconfig.c @@ -26,6 +26,7 @@ #include "embed/extmod/trezorobj.h" #include "storage.h" +#include "utils.h" STATIC mp_obj_t ui_wait_callback = mp_const_none; @@ -41,12 +42,18 @@ STATIC void wrapped_ui_wait_callback(uint32_t wait, uint32_t progress) { /// called from this module! /// ''' STATIC mp_obj_t mod_trezorconfig_init(size_t n_args, const mp_obj_t *args) { - // TODO: Add salt. + uint32_t salt[] = { + utils_get_cpu_id(), + utils_get_flash_size(), + utils_get_uid_word0(), + utils_get_uid_word1(), + utils_get_uid_word2() + }; if (n_args > 0) { ui_wait_callback = args[0]; - storage_init(wrapped_ui_wait_callback, (const uint8_t*)"", 0); + storage_init(wrapped_ui_wait_callback, (const uint8_t*)salt, sizeof(salt)); } else { - storage_init(NULL, (const uint8_t*)"", 0); + storage_init(NULL, (const uint8_t*)salt, sizeof(salt)); } return mp_const_none; } diff --git a/embed/trezorhal/utils.c b/embed/trezorhal/utils.c new file mode 100644 index 000000000..01761a4b6 --- /dev/null +++ b/embed/trezorhal/utils.c @@ -0,0 +1,62 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "utils.h" +#include STM32_HAL_H +#include "stm32l4xx_ll_utils.h" + +/* + * Returns the CPUID Base Register of the System Control Block. + */ +uint32_t utils_get_cpu_id() +{ + return SCB->CPUID; +} + +/* + * Returns the size of the device flash memory expressed in kilobytes, e.g. 0x040 corresponds to 64 kB. + */ +uint32_t utils_get_flash_size() +{ + return LL_GetFlashSize(); +} + +/* + * Returns word 0 of the unique device identifier. + */ +uint32_t utils_get_uid_word0() +{ + return LL_GetUID_Word0(); +} + +/* + * Returns word 1 of the unique device identifier. + */ +uint32_t utils_get_uid_word1() +{ + return LL_GetUID_Word1(); +} + +/* + * Returns word 2 of the unique device identifier. + */ +uint32_t utils_get_uid_word2() +{ + return LL_GetUID_Word2(); +} diff --git a/embed/trezorhal/utils.h b/embed/trezorhal/utils.h new file mode 100644 index 000000000..3e3cbcb6a --- /dev/null +++ b/embed/trezorhal/utils.h @@ -0,0 +1,31 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __TREZORHAL_UTILS_H__ +#define __TREZORHAL_UTILS_H__ + +#include + +uint32_t utils_get_cpu_id(); +uint32_t utils_get_flash_size(); +uint32_t utils_get_uid_word0(); +uint32_t utils_get_uid_word1(); +uint32_t utils_get_uid_word2(); + +#endif diff --git a/embed/unix/utils.c b/embed/unix/utils.c new file mode 100644 index 000000000..04867c0ba --- /dev/null +++ b/embed/unix/utils.c @@ -0,0 +1,60 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "utils.h" + +/* + * Returns the CPUID Base Register of the System Control Block. + */ +uint32_t utils_get_cpu_id() +{ + return 0; +} + +/* + * Returns the size of the device flash memory expressed in kilobytes, e.g. 0x040 corresponds to 64 kB. + */ +uint32_t utils_get_flash_size() +{ + return 0; +} + +/* + * Returns word 0 of the unique device identifier. + */ +uint32_t utils_get_uid_word0() +{ + return 0; +} + +/* + * Returns word 1 of the unique device identifier. + */ +uint32_t utils_get_uid_word1() +{ + return 0; +} + +/* + * Returns word 2 of the unique device identifier. + */ +uint32_t utils_get_uid_word2() +{ + return 0; +} diff --git a/embed/unix/utils.h b/embed/unix/utils.h new file mode 100644 index 000000000..3e3cbcb6a --- /dev/null +++ b/embed/unix/utils.h @@ -0,0 +1,31 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __TREZORHAL_UTILS_H__ +#define __TREZORHAL_UTILS_H__ + +#include + +uint32_t utils_get_cpu_id(); +uint32_t utils_get_flash_size(); +uint32_t utils_get_uid_word0(); +uint32_t utils_get_uid_word1(); +uint32_t utils_get_uid_word2(); + +#endif From 4a194e48c62efd9531297341caa5f2b6d0bbbc25 Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 3 Jan 2019 15:17:32 +0100 Subject: [PATCH 08/38] Update trezor-storage submodule. --- vendor/trezor-storage | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 639bea4ea..5dfafc3b8 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 639bea4ea8a56e4a2f30b39e25a363c462a70e2d +Subproject commit 5dfafc3b8785f30b58f6665a21f5c9126e1d9642 From fa339bbe0652c97758865da9c161304248f04cd7 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Jan 2019 16:17:57 +0100 Subject: [PATCH 09/38] Add config.delete(key) method. --- .../extmod/modtrezorconfig/modtrezorconfig.c | 19 +++++++++++++++++++ vendor/trezor-storage | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/embed/extmod/modtrezorconfig/modtrezorconfig.c b/embed/extmod/modtrezorconfig/modtrezorconfig.c index 4b368ac71..0c7c7746b 100644 --- a/embed/extmod/modtrezorconfig/modtrezorconfig.c +++ b/embed/extmod/modtrezorconfig/modtrezorconfig.c @@ -170,6 +170,24 @@ STATIC mp_obj_t mod_trezorconfig_set(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_set_obj, 3, 4, mod_trezorconfig_set); +/// def delete(app: int, key: int, public: bool=False) -> bool: +/// ''' +/// Deletes the given key of the given app. +/// ''' +STATIC mp_obj_t mod_trezorconfig_delete(size_t n_args, const mp_obj_t *args) { + uint8_t app = trezor_obj_get_uint8(args[0]) & 0x7F; + uint8_t key = trezor_obj_get_uint8(args[1]); + if (n_args > 2 && args[2] == mp_const_true) { + app |= 0x80; + } + uint16_t appkey = (app << 8) | key; + if (sectrue != storage_delete(appkey)) { + return mp_const_false; + } + return mp_const_true; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_delete_obj, 3, 4, mod_trezorconfig_delete); + /// def wipe() -> None: /// ''' /// Erases the whole config. Use with caution! @@ -190,6 +208,7 @@ STATIC const mp_rom_map_elem_t mp_module_trezorconfig_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_change_pin), MP_ROM_PTR(&mod_trezorconfig_change_pin_obj) }, { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&mod_trezorconfig_get_obj) }, { MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&mod_trezorconfig_set_obj) }, + { MP_ROM_QSTR(MP_QSTR_delete), MP_ROM_PTR(&mod_trezorconfig_delete_obj) }, { MP_ROM_QSTR(MP_QSTR_wipe), MP_ROM_PTR(&mod_trezorconfig_wipe_obj) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_trezorconfig_globals, mp_module_trezorconfig_globals_table); diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 5dfafc3b8..52a3a46db 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 5dfafc3b8785f30b58f6665a21f5c9126e1d9642 +Subproject commit 52a3a46db0ed93848a49597f7582523386db5e74 From 8be38960389380a89a01cd45a0f3f45eb6f4966a Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 4 Jan 2019 16:23:14 +0100 Subject: [PATCH 10/38] Convert U2F counter from private to public to take advantage of the more efficient implementation. --- src/apps/common/storage.py | 14 +++++++++++++- src/boot.py | 5 +++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/apps/common/storage.py b/src/apps/common/storage.py index 7692d9741..894668201 100644 --- a/src/apps/common/storage.py +++ b/src/apps/common/storage.py @@ -8,7 +8,7 @@ from apps.common import cache HOMESCREEN_MAXSIZE = 16384 -_STORAGE_VERSION = b"\x01" +_STORAGE_VERSION = b"\x02" _FALSE_BYTE = b"\x00" _TRUE_BYTE = b"\x01" _COUNTER_HEAD_LEN = 4 @@ -223,3 +223,15 @@ def set_u2f_counter(cntr: int) -> None: def wipe(): config.wipe() cache.clear() + + +def init_unlocked(): + # Check for storage version upgrade. + version = config.get(_APP, _VERSION) + if version == b"\x01": + # Make the U2F counter public. + counter = config.get(_APP, _U2F_COUNTER) + if counter is not None: + _set_counter(_APP, _U2F_COUNTER, counter, True) + config.delete(_APP, _U2F_COUNTER) + config.set(_APP, _VERSION, _STORAGE_VERSION) diff --git a/src/boot.py b/src/boot.py index cec662cdb..c47b566a2 100644 --- a/src/boot.py +++ b/src/boot.py @@ -2,6 +2,7 @@ from trezor import config, log, loop, res, ui from trezor.pin import pin_to_int, show_pin_timeout from apps.common.request_pin import request_pin +from apps.common import storage async def bootscreen(): @@ -9,12 +10,14 @@ async def bootscreen(): try: if not config.has_pin(): config.unlock(pin_to_int("")) + storage.init_unlocked() return await lockscreen() label = None while True: pin = await request_pin(label, config.get_pin_rem()) if config.unlock(pin_to_int(pin)): + storage.init_unlocked() return else: label = "Wrong PIN, enter again" @@ -24,8 +27,6 @@ async def bootscreen(): async def lockscreen(): - from apps.common import storage - label = storage.get_label() image = storage.get_homescreen() if not label: From 97a4cdb68e03b6fd3949ae5e0fafdd971a8d8ad2 Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 9 Jan 2019 12:04:48 +0100 Subject: [PATCH 11/38] Use only unique device ID as salt to storage_init(). Update storage submodule. --- embed/extmod/modtrezorconfig/modtrezorconfig.c | 2 -- vendor/trezor-storage | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/embed/extmod/modtrezorconfig/modtrezorconfig.c b/embed/extmod/modtrezorconfig/modtrezorconfig.c index 0c7c7746b..75ea8e4b3 100644 --- a/embed/extmod/modtrezorconfig/modtrezorconfig.c +++ b/embed/extmod/modtrezorconfig/modtrezorconfig.c @@ -43,8 +43,6 @@ STATIC void wrapped_ui_wait_callback(uint32_t wait, uint32_t progress) { /// ''' STATIC mp_obj_t mod_trezorconfig_init(size_t n_args, const mp_obj_t *args) { uint32_t salt[] = { - utils_get_cpu_id(), - utils_get_flash_size(), utils_get_uid_word0(), utils_get_uid_word1(), utils_get_uid_word2() diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 52a3a46db..e5641c12f 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 52a3a46db0ed93848a49597f7582523386db5e74 +Subproject commit e5641c12f7cef6b686c34336a1cd20b613083e56 From fa7b496a9a6c77fd8c82dbaa8208b4c8fecbd7e5 Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 9 Jan 2019 12:11:41 +0100 Subject: [PATCH 12/38] Revert changes to seed recovery dialog, to avoid tests failing. These changes were moved to the branch andrewkozlik/pin-messages. --- src/apps/management/recovery_device.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/apps/management/recovery_device.py b/src/apps/management/recovery_device.py index 702aec6d5..4d3ca7ac5 100644 --- a/src/apps/management/recovery_device.py +++ b/src/apps/management/recovery_device.py @@ -32,12 +32,8 @@ async def recovery_device(ctx, msg): if not msg.dry_run and storage.is_initialized(): raise wire.UnexpectedMessage("Already initialized") - if msg.dry_run: - text = Text("Check recovery seed", ui.ICON_RECOVERY) - text.normal("Do you really want to", "check your recovery", "seed?") - else: - text = Text("Recover wallet", ui.ICON_RECOVERY) - text.normal("Do you really want to", "restore a wallet from", "your backup?") + text = Text("Device recovery", ui.ICON_RECOVERY) + text.normal("Do you really want to", "recover the device?", "") await require_confirm(ctx, text, code=ProtectCall) @@ -81,7 +77,7 @@ async def recovery_device(ctx, msg): async def request_wordcount(ctx): await ctx.call(ButtonRequest(code=MnemonicWordCount), ButtonAck) - text = Text("Recovery seed", ui.ICON_RECOVERY) + text = Text("Device recovery", ui.ICON_RECOVERY) text.normal("Number of words?") count = await ctx.wait(WordSelector(text)) From d41072b0cebb71bbec2c9d54589eecf83ef2b7da Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 9 Jan 2019 17:40:29 +0100 Subject: [PATCH 13/38] Update origin for trezor-storage submodule. --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 67995f4c5..61bd4d265 100644 --- a/.gitmodules +++ b/.gitmodules @@ -15,4 +15,4 @@ url = https://github.com/nanopb/nanopb.git [submodule "vendor/trezor-storage"] path = vendor/trezor-storage - url = git@github.com:satoshilabs/trezor-storage.git + url = https://github.com/trezor/trezor-storage.git From 1c0946f5626f4552026244813d184849af0fb722 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 11 Jan 2019 19:40:55 +0100 Subject: [PATCH 14/38] Fix typo in include. --- embed/trezorhal/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embed/trezorhal/utils.c b/embed/trezorhal/utils.c index 01761a4b6..5d48ae7da 100644 --- a/embed/trezorhal/utils.c +++ b/embed/trezorhal/utils.c @@ -19,7 +19,7 @@ #include "utils.h" #include STM32_HAL_H -#include "stm32l4xx_ll_utils.h" +#include "stm32f4xx_ll_utils.h" /* * Returns the CPUID Base Register of the System Control Block. From bddb72d76ae04a4cd981433fc40e1e1546659ae7 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 11 Jan 2019 20:40:40 +0100 Subject: [PATCH 15/38] Include trezor-storage before micropython. --- SConscript.firmware | 4 +--- SConscript.unix | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/SConscript.firmware b/SConscript.firmware index 67682baa9..03e3af463 100644 --- a/SConscript.firmware +++ b/SConscript.firmware @@ -10,9 +10,6 @@ SOURCE_MOD = [] PYOPT = '1' # modtrezorconfig -CPPPATH_MOD += [ - 'vendor/trezor-storage/c', -] SOURCE_MOD += [ 'embed/extmod/modtrezorconfig/modtrezorconfig.c', 'vendor/trezor-storage/c/norcow.c', @@ -330,6 +327,7 @@ env.Replace( 'embed/firmware', 'embed/trezorhal', 'embed/extmod/modtrezorui', + 'vendor/trezor-storage/c', 'vendor/micropython', 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Inc', 'vendor/micropython/lib/stm32lib/CMSIS/STM32F4xx/Include', diff --git a/SConscript.unix b/SConscript.unix index d1f4c7010..4770d1c39 100644 --- a/SConscript.unix +++ b/SConscript.unix @@ -9,9 +9,6 @@ SOURCE_MOD = [] LIBS_MOD = [] # modtrezorconfig -CPPPATH_MOD += [ - 'vendor/trezor-storage/c', -] SOURCE_MOD += [ 'embed/extmod/modtrezorconfig/modtrezorconfig.c', 'vendor/trezor-storage/c/norcow.c', @@ -299,6 +296,7 @@ env.Replace( '.', 'embed/unix', 'embed/extmod/modtrezorui', + 'vendor/trezor-storage/c', 'vendor/micropython', 'vendor/micropython/ports/unix', 'vendor/micropython/lib/mp-readline', From e3ab0dfbcb9f24517d00431e9cb2bce1f02da731 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 11 Jan 2019 20:57:12 +0100 Subject: [PATCH 16/38] Reformat Python files using black, isort and flake8. --- src/apps/common/request_pin.py | 4 +++- src/apps/common/storage.py | 29 +++++++++++++++-------------- src/boot.py | 2 +- src/trezor/ui/pin.py | 4 +++- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/apps/common/request_pin.py b/src/apps/common/request_pin.py index 24f2d90da..82eb3eb77 100644 --- a/src/apps/common/request_pin.py +++ b/src/apps/common/request_pin.py @@ -11,7 +11,9 @@ class PinCancelled(Exception): @ui.layout -async def request_pin(label=None, attempts_remaining=None, cancellable: bool = True) -> str: +async def request_pin( + label=None, attempts_remaining=None, cancellable: bool = True +) -> str: def onchange(): c = dialog.cancel if matrix.pin: diff --git a/src/apps/common/storage.py b/src/apps/common/storage.py index 894668201..0fcced626 100644 --- a/src/apps/common/storage.py +++ b/src/apps/common/storage.py @@ -32,6 +32,7 @@ _AUTOLOCK_DELAY_MS = const(0x0C) # int _NO_BACKUP = const(0x0D) # bool (0x01 or empty) # fmt: on + def _set_bool(app: int, key: int, value: bool, public: bool = False) -> None: if value: config.set(app, key, _TRUE_BYTE, public) @@ -48,27 +49,27 @@ def _set_counter(app: int, key: int, count: int, public: bool = False) -> None: if public: value += _COUNTER_TAIL_LEN * b"\xff" config.set(app, key, value, public) - + def _next_counter(app: int, key: int, public: bool = False) -> int: -# If the counter value is public, then it is stored as a four byte integer in -# big endian byte order, called the "head", followed an eight byte "tail". The -# counter value is equal to the integer value of the head plus the number of -# zero bits in the tail. The counter value 0 is stored as 00000000FFFFFFFFFFFFFFFF. -# With each increment the tail is shifted to the right by one bit. Thus after -# three increments the stored value is 000000001FFFFFFFFFFFFFFF. Once all the -# bits in the tail are set to zero, the next counter value is stored as -# 00000021FFFFFFFFFFFFFFFF. + # If the counter value is public, then it is stored as a four byte integer in + # big endian byte order, called the "head", followed an eight byte "tail". The + # counter value is equal to the integer value of the head plus the number of + # zero bits in the tail. The counter value 0 is stored as 00000000FFFFFFFFFFFFFFFF. + # With each increment the tail is shifted to the right by one bit. Thus after + # three increments the stored value is 000000001FFFFFFFFFFFFFFF. Once all the + # bits in the tail are set to zero, the next counter value is stored as + # 00000021FFFFFFFFFFFFFFFF. value = config.get(app, key, public) if value is None: _set_counter(app, key, 0, public) return 0 - head = value[: _COUNTER_HEAD_LEN] - tail = value[_COUNTER_HEAD_LEN :] + head = value[:_COUNTER_HEAD_LEN] + tail = value[_COUNTER_HEAD_LEN:] i = tail.rfind(b"\x00") + 1 - count = int.from_bytes(head, "big") + 1 + 8*i + count = int.from_bytes(head, "big") + 1 + 8 * i if i == len(tail): _set_counter(app, key, count, public) return count @@ -78,7 +79,7 @@ def _next_counter(app: int, key: int, public: bool = False) -> int: zero_count += 1 count += zero_count - tail = tail[:i] + bytes([tail[i] >> 1]) + tail[i+1:] + tail = tail[:i] + bytes([tail[i] >> 1]) + tail[i + 1 :] config.set(app, key, head + tail, public) return count @@ -100,7 +101,7 @@ def is_initialized() -> bool: def get_label() -> str: - label = config.get(_APP, _LABEL, True) # public + label = config.get(_APP, _LABEL, True) # public if label is None: return None return label.decode() diff --git a/src/boot.py b/src/boot.py index c47b566a2..7ef86c092 100644 --- a/src/boot.py +++ b/src/boot.py @@ -1,8 +1,8 @@ from trezor import config, log, loop, res, ui from trezor.pin import pin_to_int, show_pin_timeout -from apps.common.request_pin import request_pin from apps.common import storage +from apps.common.request_pin import request_pin async def bootscreen(): diff --git a/src/trezor/ui/pin.py b/src/trezor/ui/pin.py index 5ae89f663..be4c739b1 100644 --- a/src/trezor/ui/pin.py +++ b/src/trezor/ui/pin.py @@ -64,7 +64,9 @@ class PinMatrix(ui.Widget): elif self.sublabel: # input line with header label and sublabel display.text_center(ui.WIDTH // 2, 20, self.label, ui.BOLD, ui.GREY, ui.BG) - display.text_center(ui.WIDTH // 2, 46, self.sublabel, ui.NORMAL, ui.GREY, ui.BG) + display.text_center( + ui.WIDTH // 2, 46, self.sublabel, ui.NORMAL, ui.GREY, ui.BG + ) else: # input line with header label display.text_center(ui.WIDTH // 2, 36, self.label, ui.BOLD, ui.GREY, ui.BG) From 4246d7f6cdf761b2bd6140b54880d32644868cec Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 15 Jan 2019 13:41:18 +0100 Subject: [PATCH 17/38] Update trezor-storage submodule (do not automatically lock the storage after wipe). --- vendor/trezor-storage | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-storage b/vendor/trezor-storage index e5641c12f..884480205 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit e5641c12f7cef6b686c34336a1cd20b613083e56 +Subproject commit 884480205dba3be6f4cb422bf6f58fa9783e7708 From a19446fabd638dea8725479be7cd959d73fa6633 Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 15 Jan 2019 15:13:51 +0100 Subject: [PATCH 18/38] Fix use_passphrase setting in storage.py. --- src/apps/common/storage.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/apps/common/storage.py b/src/apps/common/storage.py index 0fcced626..ab8624071 100644 --- a/src/apps/common/storage.py +++ b/src/apps/common/storage.py @@ -168,7 +168,8 @@ def load_settings( ) -> None: if label is not None: config.set(_APP, _LABEL, label.encode(), True) # public - _set_bool(_APP, _USE_PASSPHRASE, use_passphrase) + if use_passphrase is not None: + _set_bool(_APP, _USE_PASSPHRASE, use_passphrase) if homescreen is not None: if homescreen[:8] == b"TOIf\x90\x00\x90\x00": if len(homescreen) <= HOMESCREEN_MAXSIZE: From 32c80e98899c67d8bcbe97f774a6ece55ca1ce3f Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 15 Jan 2019 17:55:28 +0100 Subject: [PATCH 19/38] Make U2F counter public. --- src/apps/common/storage.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/apps/common/storage.py b/src/apps/common/storage.py index ab8624071..3eb651dc8 100644 --- a/src/apps/common/storage.py +++ b/src/apps/common/storage.py @@ -215,11 +215,11 @@ def set_autolock_delay_ms(delay_ms: int) -> None: def next_u2f_counter() -> int: - return _next_counter(_APP, _U2F_COUNTER) + return _next_counter(_APP, _U2F_COUNTER, True) # public def set_u2f_counter(cntr: int) -> None: - _set_counter(_APP, _U2F_COUNTER, cntr) + _set_counter(_APP, _U2F_COUNTER, cntr, True) # public def wipe(): @@ -234,6 +234,6 @@ def init_unlocked(): # Make the U2F counter public. counter = config.get(_APP, _U2F_COUNTER) if counter is not None: - _set_counter(_APP, _U2F_COUNTER, counter, True) + _set_counter(_APP, _U2F_COUNTER, counter, True) # public config.delete(_APP, _U2F_COUNTER) config.set(_APP, _VERSION, _STORAGE_VERSION) From 92faa9f958a1144a5d67c2bbaaeb888d6beadd36 Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 15 Jan 2019 18:25:00 +0100 Subject: [PATCH 20/38] Fix parameter count for config.delete(). --- embed/extmod/modtrezorconfig/modtrezorconfig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embed/extmod/modtrezorconfig/modtrezorconfig.c b/embed/extmod/modtrezorconfig/modtrezorconfig.c index 75ea8e4b3..2344c3a6e 100644 --- a/embed/extmod/modtrezorconfig/modtrezorconfig.c +++ b/embed/extmod/modtrezorconfig/modtrezorconfig.c @@ -184,7 +184,7 @@ STATIC mp_obj_t mod_trezorconfig_delete(size_t n_args, const mp_obj_t *args) { } return mp_const_true; } -STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_delete_obj, 3, 4, mod_trezorconfig_delete); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_delete_obj, 2, 3, mod_trezorconfig_delete); /// def wipe() -> None: /// ''' From 1d43f9bea23b79733a4aaecfdcfd3ecd9ce3b4dc Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 15 Jan 2019 18:26:11 +0100 Subject: [PATCH 21/38] Delete the U2F counter if it's set to None. --- src/apps/common/storage.py | 4 ++++ tests/test_apps.common.storage.py | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/apps/common/storage.py b/src/apps/common/storage.py index 3eb651dc8..91737c80c 100644 --- a/src/apps/common/storage.py +++ b/src/apps/common/storage.py @@ -45,6 +45,10 @@ def _get_bool(app: int, key: int, public: bool = False) -> bool: def _set_counter(app: int, key: int, count: int, public: bool = False) -> None: + if count is None: + config.delete(app, key, public) + return + value = count.to_bytes(_COUNTER_HEAD_LEN, "big") if public: value += _COUNTER_TAIL_LEN * b"\xff" diff --git a/tests/test_apps.common.storage.py b/tests/test_apps.common.storage.py index f530c0b1c..075a9a4fd 100644 --- a/tests/test_apps.common.storage.py +++ b/tests/test_apps.common.storage.py @@ -15,6 +15,10 @@ class TestConfig(unittest.TestCase): storage.set_u2f_counter(350) for i in range(351, 500): self.assertEqual(storage.next_u2f_counter(), i) + storage.set_u2f_counter(0) + self.assertEqual(storage.next_u2f_counter(), 1) + storage.set_u2f_counter(None) + self.assertEqual(storage.next_u2f_counter(), 0) if __name__ == '__main__': From 0309e9e520e37ad7967d91c8ce3039cc071ed138 Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 23 Jan 2019 17:33:05 +0100 Subject: [PATCH 22/38] Update trezor-storage submodule. --- vendor/trezor-storage | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 884480205..8970e2bde 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 884480205dba3be6f4cb422bf6f58fa9783e7708 +Subproject commit 8970e2bdebb3334ddd0bacf41c66be79e78880f8 From 434a9c208491a12fdf5605fc2ac29024b2096ad4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Thu, 24 Jan 2019 16:17:37 +0100 Subject: [PATCH 23/38] storage: add norcow_config.h, reorganize storage sources in SConscript files --- SConscript.firmware | 11 +++-- SConscript.unix | 9 ++-- embed/extmod/modtrezorconfig/norcow_config.h | 49 ++++++++++++++++++++ 3 files changed, 62 insertions(+), 7 deletions(-) create mode 100644 embed/extmod/modtrezorconfig/norcow_config.h diff --git a/SConscript.firmware b/SConscript.firmware index 03e3af463..7f810a036 100644 --- a/SConscript.firmware +++ b/SConscript.firmware @@ -10,10 +10,14 @@ SOURCE_MOD = [] PYOPT = '1' # modtrezorconfig +CPPPATH_MOD += [ + 'embed/extmod/modtrezorconfig', + 'vendor/trezor-storage', +] SOURCE_MOD += [ 'embed/extmod/modtrezorconfig/modtrezorconfig.c', - 'vendor/trezor-storage/c/norcow.c', - 'vendor/trezor-storage/c/storage.c', + 'vendor/trezor-storage/norcow.c', + 'vendor/trezor-storage/storage.c', ] # modtrezorcrypto @@ -275,8 +279,8 @@ SOURCE_TREZORHAL = [ 'embed/trezorhal/usbd_core.c', 'embed/trezorhal/usbd_ctlreq.c', 'embed/trezorhal/usbd_ioreq.c', - 'embed/trezorhal/utils.c', 'embed/trezorhal/util.s', + 'embed/trezorhal/utils.c', 'embed/trezorhal/vectortable.s', ] @@ -327,7 +331,6 @@ env.Replace( 'embed/firmware', 'embed/trezorhal', 'embed/extmod/modtrezorui', - 'vendor/trezor-storage/c', 'vendor/micropython', 'vendor/micropython/lib/stm32lib/STM32F4xx_HAL_Driver/Inc', 'vendor/micropython/lib/stm32lib/CMSIS/STM32F4xx/Include', diff --git a/SConscript.unix b/SConscript.unix index 4770d1c39..ac8cdf35e 100644 --- a/SConscript.unix +++ b/SConscript.unix @@ -9,10 +9,14 @@ SOURCE_MOD = [] LIBS_MOD = [] # modtrezorconfig +CPPPATH_MOD += [ + 'embed/extmod/modtrezorconfig', + 'vendor/trezor-storage', +] SOURCE_MOD += [ 'embed/extmod/modtrezorconfig/modtrezorconfig.c', - 'vendor/trezor-storage/c/norcow.c', - 'vendor/trezor-storage/c/storage.c', + 'vendor/trezor-storage/norcow.c', + 'vendor/trezor-storage/storage.c', ] # modtrezorcrypto @@ -296,7 +300,6 @@ env.Replace( '.', 'embed/unix', 'embed/extmod/modtrezorui', - 'vendor/trezor-storage/c', 'vendor/micropython', 'vendor/micropython/ports/unix', 'vendor/micropython/lib/mp-readline', diff --git a/embed/extmod/modtrezorconfig/norcow_config.h b/embed/extmod/modtrezorconfig/norcow_config.h new file mode 100644 index 000000000..1faafd79f --- /dev/null +++ b/embed/extmod/modtrezorconfig/norcow_config.h @@ -0,0 +1,49 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __NORCOW_CONFIG_H__ +#define __NORCOW_CONFIG_H__ + +#include "flash.h" + +#define NORCOW_HEADER_LEN 0 +#define NORCOW_SECTOR_COUNT 2 + +#if TREZOR_MODEL == T + +#define NORCOW_SECTOR_SIZE (64*1024) +#define NORCOW_SECTORS {FLASH_SECTOR_STORAGE_1, FLASH_SECTOR_STORAGE_2} + +#elif TREZOR_MODEL == 1 + +#define NORCOW_SECTOR_SIZE (16*1024) +#define NORCOW_SECTORS {2, 3} + +#else + +#error Unknown TREZOR Model + +#endif + +/* + * Current storage version. + */ +#define NORCOW_VERSION ((uint32_t)0x00000001) + +#endif From 8541c4265bd299bd08e7e02eede980838ef62f97 Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 24 Jan 2019 15:56:05 +0100 Subject: [PATCH 24/38] Fix comment in _next_counter(). --- src/apps/common/storage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apps/common/storage.py b/src/apps/common/storage.py index 91737c80c..4c16f6978 100644 --- a/src/apps/common/storage.py +++ b/src/apps/common/storage.py @@ -63,7 +63,7 @@ def _next_counter(app: int, key: int, public: bool = False) -> int: # With each increment the tail is shifted to the right by one bit. Thus after # three increments the stored value is 000000001FFFFFFFFFFFFFFF. Once all the # bits in the tail are set to zero, the next counter value is stored as - # 00000021FFFFFFFFFFFFFFFF. + # 00000041FFFFFFFFFFFFFFFF. value = config.get(app, key, public) if value is None: From 40325f40697c9850c9245bcdd5c5cc12ecb00df9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 25 Jan 2019 15:59:21 +0100 Subject: [PATCH 25/38] makefile: add debugging targets for reading/erasing storage sectors --- Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Makefile b/Makefile index c043c74e5..8940e4705 100644 --- a/Makefile +++ b/Makefile @@ -175,6 +175,12 @@ flash_combine: $(PRODTEST_BUILD_DIR)/combined.bin ## flash combined using OpenOC flash_erase: ## erase all sectors in flash bank 0 $(OPENOCD) -c "init; reset halt; flash info 0; flash erase_sector 0 0 last; flash erase_check 0; exit" +flash_read_storage: ## read storage sectors from flash + $(OPENOCD) -c "init; flash read_bank 0 storage1.data 0x10000 65536; flash read_bank 0 storage2.data 0x110000 65536; exit" + +flash_erase_storage: ## erase storage sectors from flash + $(OPENOCD) -c "init; flash erase_sector 0 4 4; flash erase_sector 0 16 16; exit" + ## openocd debug commands: openocd: ## start openocd which connects to the device From c0317e1afff6ce0678a17267be8f3f96f5da85b9 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 25 Jan 2019 16:00:10 +0100 Subject: [PATCH 26/38] embed/trezorhal: add more checks to flash write functions --- embed/trezorhal/flash.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/embed/trezorhal/flash.c b/embed/trezorhal/flash.c index f6f971930..5496677d5 100644 --- a/embed/trezorhal/flash.c +++ b/embed/trezorhal/flash.c @@ -123,7 +123,16 @@ secbool flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data) if (address == 0) { return secfalse; } - return sectrue * (HAL_OK == HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, address, data)); + if (data != (data & *((const uint8_t *)address))) { + return secfalse; + } + if (HAL_OK != HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, address, data)) { + return secfalse; + } + if (data != *((const uint8_t *)address)) { + return secfalse; + } + return sectrue; } secbool flash_write_word(uint8_t sector, uint32_t offset, uint32_t data) @@ -135,7 +144,17 @@ secbool flash_write_word(uint8_t sector, uint32_t offset, uint32_t data) if (offset % 4 != 0) { return secfalse; } - return sectrue * (HAL_OK == HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, data)); + if (data != (data & *((const uint32_t *)address))) { + return secfalse; + } + if (HAL_OK != HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, data)) { + return secfalse; + + } + if (data != *((const uint32_t *)address)) { + return secfalse; + } + return sectrue; } #define FLASH_OTP_LOCK_BASE 0x1FFF7A00U From b754ee8cf676b044285eda042c2d3c73b221be74 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 25 Jan 2019 18:33:25 +0100 Subject: [PATCH 27/38] embed/trezorhal: collect HW entropy before MPU kicks in --- SConscript.firmware | 1 - SConscript.unix | 1 - .../extmod/modtrezorconfig/modtrezorconfig.c | 11 +--- embed/firmware/main.c | 2 + embed/trezorhal/common.c | 16 +++++ embed/trezorhal/common.h | 4 ++ embed/trezorhal/utils.c | 62 ------------------- embed/trezorhal/utils.h | 31 ---------- embed/unix/common.c | 8 +++ embed/unix/common.h | 4 ++ embed/unix/main.c | 4 ++ embed/unix/utils.c | 60 ------------------ embed/unix/utils.h | 31 ---------- 13 files changed, 41 insertions(+), 194 deletions(-) delete mode 100644 embed/trezorhal/utils.c delete mode 100644 embed/trezorhal/utils.h delete mode 100644 embed/unix/utils.c delete mode 100644 embed/unix/utils.h diff --git a/SConscript.firmware b/SConscript.firmware index 7f810a036..6c32f5771 100644 --- a/SConscript.firmware +++ b/SConscript.firmware @@ -280,7 +280,6 @@ SOURCE_TREZORHAL = [ 'embed/trezorhal/usbd_ctlreq.c', 'embed/trezorhal/usbd_ioreq.c', 'embed/trezorhal/util.s', - 'embed/trezorhal/utils.c', 'embed/trezorhal/vectortable.s', ] diff --git a/SConscript.unix b/SConscript.unix index ac8cdf35e..a09a96196 100644 --- a/SConscript.unix +++ b/SConscript.unix @@ -258,7 +258,6 @@ SOURCE_UNIX = [ 'embed/unix/sbu.c', 'embed/unix/touch.c', 'embed/unix/usb.c', - 'embed/unix/utils.c', ] SOURCE_QSTR = SOURCE_MOD + SOURCE_MICROPYTHON + SOURCE_UNIX diff --git a/embed/extmod/modtrezorconfig/modtrezorconfig.c b/embed/extmod/modtrezorconfig/modtrezorconfig.c index 2344c3a6e..70d306e67 100644 --- a/embed/extmod/modtrezorconfig/modtrezorconfig.c +++ b/embed/extmod/modtrezorconfig/modtrezorconfig.c @@ -26,7 +26,7 @@ #include "embed/extmod/trezorobj.h" #include "storage.h" -#include "utils.h" +#include "common.h" STATIC mp_obj_t ui_wait_callback = mp_const_none; @@ -42,16 +42,11 @@ STATIC void wrapped_ui_wait_callback(uint32_t wait, uint32_t progress) { /// called from this module! /// ''' STATIC mp_obj_t mod_trezorconfig_init(size_t n_args, const mp_obj_t *args) { - uint32_t salt[] = { - utils_get_uid_word0(), - utils_get_uid_word1(), - utils_get_uid_word2() - }; if (n_args > 0) { ui_wait_callback = args[0]; - storage_init(wrapped_ui_wait_callback, (const uint8_t*)salt, sizeof(salt)); + storage_init(wrapped_ui_wait_callback, HW_ENTROPY_DATA, HW_ENTROPY_LEN); } else { - storage_init(NULL, (const uint8_t*)salt, sizeof(salt)); + storage_init(NULL, HW_ENTROPY_DATA, HW_ENTROPY_LEN); } return mp_const_none; } diff --git a/embed/firmware/main.c b/embed/firmware/main.c index 62cceda90..5b203ccc6 100644 --- a/embed/firmware/main.c +++ b/embed/firmware/main.c @@ -48,6 +48,8 @@ int main(void) HAL_Init(); #endif + collect_hw_entropy(); + #if TREZOR_MODEL == T // Enable MPU mpu_config(); diff --git a/embed/trezorhal/common.c b/embed/trezorhal/common.c index a01ae2ad5..f7cdbcc76 100644 --- a/embed/trezorhal/common.c +++ b/embed/trezorhal/common.c @@ -19,10 +19,14 @@ #include STM32_HAL_H +#include + #include "common.h" #include "display.h" #include "rng.h" +#include "stm32f4xx_ll_utils.h" + void shutdown(void); #define COLOR_FATAL_ERROR RGB16(0x7F, 0x00, 0x00) @@ -80,3 +84,15 @@ void __attribute__((noreturn)) __stack_chk_fail(void) { ensure(secfalse, "Stack smashing detected"); } + +uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; + +void collect_hw_entropy(void) +{ + uint32_t w = LL_GetUID_Word0(); + memcpy(HW_ENTROPY_DATA, &w, 4); + w = LL_GetUID_Word1(); + memcpy(HW_ENTROPY_DATA + 4, &w, 4); + w = LL_GetUID_Word2(); + memcpy(HW_ENTROPY_DATA + 8, &w, 4); +} diff --git a/embed/trezorhal/common.h b/embed/trezorhal/common.h index 9b6ebca91..1b8c8a3b4 100644 --- a/embed/trezorhal/common.h +++ b/embed/trezorhal/common.h @@ -43,6 +43,10 @@ void clear_otg_hs_memory(void); extern uint32_t __stack_chk_guard; +void collect_hw_entropy(void); +#define HW_ENTROPY_LEN 12 +extern uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; + // the following functions are defined in util.s void memset_reg(volatile void *start, volatile void *stop, uint32_t val); diff --git a/embed/trezorhal/utils.c b/embed/trezorhal/utils.c deleted file mode 100644 index 5d48ae7da..000000000 --- a/embed/trezorhal/utils.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (c) SatoshiLabs - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "utils.h" -#include STM32_HAL_H -#include "stm32f4xx_ll_utils.h" - -/* - * Returns the CPUID Base Register of the System Control Block. - */ -uint32_t utils_get_cpu_id() -{ - return SCB->CPUID; -} - -/* - * Returns the size of the device flash memory expressed in kilobytes, e.g. 0x040 corresponds to 64 kB. - */ -uint32_t utils_get_flash_size() -{ - return LL_GetFlashSize(); -} - -/* - * Returns word 0 of the unique device identifier. - */ -uint32_t utils_get_uid_word0() -{ - return LL_GetUID_Word0(); -} - -/* - * Returns word 1 of the unique device identifier. - */ -uint32_t utils_get_uid_word1() -{ - return LL_GetUID_Word1(); -} - -/* - * Returns word 2 of the unique device identifier. - */ -uint32_t utils_get_uid_word2() -{ - return LL_GetUID_Word2(); -} diff --git a/embed/trezorhal/utils.h b/embed/trezorhal/utils.h deleted file mode 100644 index 3e3cbcb6a..000000000 --- a/embed/trezorhal/utils.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (c) SatoshiLabs - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __TREZORHAL_UTILS_H__ -#define __TREZORHAL_UTILS_H__ - -#include - -uint32_t utils_get_cpu_id(); -uint32_t utils_get_flash_size(); -uint32_t utils_get_uid_word0(); -uint32_t utils_get_uid_word1(); -uint32_t utils_get_uid_word2(); - -#endif diff --git a/embed/unix/common.c b/embed/unix/common.c index 62a6686bb..c591e66e5 100644 --- a/embed/unix/common.c +++ b/embed/unix/common.c @@ -23,6 +23,7 @@ #include "common.h" #include "display.h" +#include "memzero.h" void __shutdown(void) { @@ -68,3 +69,10 @@ void hal_delay(uint32_t ms) { usleep(1000 * ms); } + +uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; + +void collect_hw_entropy(void) +{ + memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); +} diff --git a/embed/unix/common.h b/embed/unix/common.h index 4ff96dcff..af73c80ff 100644 --- a/embed/unix/common.h +++ b/embed/unix/common.h @@ -39,4 +39,8 @@ void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, void hal_delay(uint32_t ms); +void collect_hw_entropy(void); +#define HW_ENTROPY_LEN 12 +extern uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; + #endif diff --git a/embed/unix/main.c b/embed/unix/main.c index 12c3823d5..aef92a8cc 100644 --- a/embed/unix/main.c +++ b/embed/unix/main.c @@ -50,6 +50,8 @@ #include "input.h" #include "profile.h" +#include "common.h" + // Command line options, with their defaults STATIC bool compile_only = false; STATIC uint emit_opt = MP_EMIT_OPT_NONE; @@ -409,6 +411,8 @@ int main(int argc, char **argv) { // Through TREZOR_PROFILE you can set the directory for trezor.flash file. profile_init(); + collect_hw_entropy(); + #if MICROPY_PY_THREAD mp_thread_init(); #endif diff --git a/embed/unix/utils.c b/embed/unix/utils.c deleted file mode 100644 index 04867c0ba..000000000 --- a/embed/unix/utils.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (c) SatoshiLabs - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "utils.h" - -/* - * Returns the CPUID Base Register of the System Control Block. - */ -uint32_t utils_get_cpu_id() -{ - return 0; -} - -/* - * Returns the size of the device flash memory expressed in kilobytes, e.g. 0x040 corresponds to 64 kB. - */ -uint32_t utils_get_flash_size() -{ - return 0; -} - -/* - * Returns word 0 of the unique device identifier. - */ -uint32_t utils_get_uid_word0() -{ - return 0; -} - -/* - * Returns word 1 of the unique device identifier. - */ -uint32_t utils_get_uid_word1() -{ - return 0; -} - -/* - * Returns word 2 of the unique device identifier. - */ -uint32_t utils_get_uid_word2() -{ - return 0; -} diff --git a/embed/unix/utils.h b/embed/unix/utils.h deleted file mode 100644 index 3e3cbcb6a..000000000 --- a/embed/unix/utils.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (c) SatoshiLabs - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __TREZORHAL_UTILS_H__ -#define __TREZORHAL_UTILS_H__ - -#include - -uint32_t utils_get_cpu_id(); -uint32_t utils_get_flash_size(); -uint32_t utils_get_uid_word0(); -uint32_t utils_get_uid_word1(); -uint32_t utils_get_uid_word2(); - -#endif From 8832c6e63b6b099f8333b7b7f97695160696547f Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 29 Jan 2019 15:51:15 +0100 Subject: [PATCH 28/38] embed/trezorhal: rename flash functions flash_erase_sector -> flash_erase flash_lock -> flash_lock_write flash_unlock -> flash_unlock_write --- embed/boardloader/main.c | 4 ++-- embed/bootloader/messages.c | 4 ++-- embed/prodtest/main.c | 4 ++-- embed/reflash/main.c | 4 ++-- embed/trezorhal/flash.c | 20 ++++++++++---------- embed/trezorhal/flash.h | 6 +++--- embed/unix/flash.c | 4 ++-- vendor/trezor-storage | 2 +- 8 files changed, 24 insertions(+), 24 deletions(-) diff --git a/embed/boardloader/main.c b/embed/boardloader/main.c index 1d32a3ce0..d5ff4a499 100644 --- a/embed/boardloader/main.c +++ b/embed/boardloader/main.c @@ -133,7 +133,7 @@ static secbool copy_sdcard(void) } display_printf(" done\n\n"); - ensure(flash_unlock(), NULL); + ensure(flash_unlock_write(), NULL); // copy bootloader from SD card to Flash display_printf("copying new bootloader from SD card\n\n"); @@ -149,7 +149,7 @@ static secbool copy_sdcard(void) } sdcard_power_off(); - ensure(flash_lock(), NULL); + ensure(flash_lock_write(), NULL); display_printf("\ndone\n\n"); display_printf("Unplug the device and remove the SD card\n"); diff --git a/embed/bootloader/messages.c b/embed/bootloader/messages.c index 28949c43e..269215fe0 100644 --- a/embed/bootloader/messages.c +++ b/embed/bootloader/messages.c @@ -517,14 +517,14 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, uint8_t *bu return -6; } - ensure(flash_unlock(), NULL); + ensure(flash_unlock_write(), NULL); const uint32_t * const src = (const uint32_t * const)chunk_buffer; for (int i = 0; i < chunk_size / sizeof(uint32_t); i++) { ensure(flash_write_word(firmware_sectors[firmware_block], i * sizeof(uint32_t), src[i]), NULL); } - ensure(flash_lock(), NULL); + ensure(flash_lock_write(), NULL); firmware_remaining -= chunk_requested; firmware_block++; diff --git a/embed/prodtest/main.c b/embed/prodtest/main.c index 8f3ca2fd2..5a663c531 100644 --- a/embed/prodtest/main.c +++ b/embed/prodtest/main.c @@ -305,11 +305,11 @@ power_off: static void test_wipe(void) { // erase start of the firmware (metadata) -> invalidate FW - ensure(flash_unlock(), NULL); + ensure(flash_unlock_write(), NULL); for (int i = 0; i < 1024 / sizeof(uint32_t); i++) { ensure(flash_write_word(FLASH_SECTOR_FIRMWARE_START, i * sizeof(uint32_t), 0x00000000), NULL); } - ensure(flash_lock(), NULL); + ensure(flash_lock_write(), NULL); display_clear(); display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY / 2 + 10, "WIPED", -1, FONT_BOLD, COLOR_WHITE, COLOR_BLACK); display_refresh(); diff --git a/embed/reflash/main.c b/embed/reflash/main.c index 3013f4b4a..236f4779a 100644 --- a/embed/reflash/main.c +++ b/embed/reflash/main.c @@ -88,7 +88,7 @@ int main(void) display_printf("\n"); display_printf("erased\n"); - ensure(flash_unlock(), NULL); + ensure(flash_unlock_write(), NULL); ensure(sdcard_power_on(), NULL); @@ -103,7 +103,7 @@ int main(void) display_printf("done\n"); sdcard_power_off(); - ensure(flash_lock(), NULL); + ensure(flash_lock_write(), NULL); return 0; } diff --git a/embed/trezorhal/flash.c b/embed/trezorhal/flash.c index 5496677d5..1f468e91f 100644 --- a/embed/trezorhal/flash.c +++ b/embed/trezorhal/flash.c @@ -58,14 +58,14 @@ void flash_init(void) { } -secbool flash_unlock(void) +secbool flash_unlock_write(void) { HAL_FLASH_Unlock(); FLASH->SR |= FLASH_STATUS_ALL_FLAGS; // clear all status flags return sectrue; } -secbool flash_lock(void) +secbool flash_lock_write(void) { HAL_FLASH_Lock(); return sectrue; @@ -86,7 +86,7 @@ const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size) secbool flash_erase_sectors(const uint8_t *sectors, int len, void (*progress)(int pos, int len)) { - ensure(flash_unlock(), NULL); + ensure(flash_unlock_write(), NULL); FLASH_EraseInitTypeDef EraseInitStruct; EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS; EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3; @@ -98,14 +98,14 @@ secbool flash_erase_sectors(const uint8_t *sectors, int len, void (*progress)(in EraseInitStruct.Sector = sectors[i]; uint32_t SectorError; if (HAL_FLASHEx_Erase(&EraseInitStruct, &SectorError) != HAL_OK) { - ensure(flash_lock(), NULL); + ensure(flash_lock_write(), NULL); return secfalse; } // check whether the sector was really deleted (contains only 0xFF) const uint32_t addr_start = FLASH_SECTOR_TABLE[sectors[i]], addr_end = FLASH_SECTOR_TABLE[sectors[i] + 1]; for (uint32_t addr = addr_start; addr < addr_end; addr += 4) { if (*((const uint32_t *)addr) != 0xFFFFFFFF) { - ensure(flash_lock(), NULL); + ensure(flash_lock_write(), NULL); return secfalse; } } @@ -113,7 +113,7 @@ secbool flash_erase_sectors(const uint8_t *sectors, int len, void (*progress)(in progress(i + 1, len); } } - ensure(flash_lock(), NULL); + ensure(flash_lock_write(), NULL); return sectrue; } @@ -175,12 +175,12 @@ secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data, uint if (block >= FLASH_OTP_NUM_BLOCKS || offset + datalen > FLASH_OTP_BLOCK_SIZE) { return secfalse; } - ensure(flash_unlock(), NULL); + ensure(flash_unlock_write(), NULL); for (uint8_t i = 0; i < datalen; i++) { uint32_t address = FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i; ensure(sectrue * (HAL_OK == HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, address, data[i])), NULL); } - ensure(flash_lock(), NULL); + ensure(flash_lock_write(), NULL); return sectrue; } @@ -189,9 +189,9 @@ secbool flash_otp_lock(uint8_t block) if (block >= FLASH_OTP_NUM_BLOCKS) { return secfalse; } - ensure(flash_unlock(), NULL); + ensure(flash_unlock_write(), NULL); HAL_StatusTypeDef ret = HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, FLASH_OTP_LOCK_BASE + block, 0x00); - ensure(flash_lock(), NULL); + ensure(flash_lock_write(), NULL); return sectrue * (ret == HAL_OK); } diff --git a/embed/trezorhal/flash.h b/embed/trezorhal/flash.h index a13c35176..2548571a4 100644 --- a/embed/trezorhal/flash.h +++ b/embed/trezorhal/flash.h @@ -69,13 +69,13 @@ void flash_init(void); -secbool __wur flash_unlock(void); -secbool __wur flash_lock(void); +secbool __wur flash_unlock_write(void); +secbool __wur flash_lock_write(void); const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size); secbool __wur flash_erase_sectors(const uint8_t *sectors, int len, void (*progress)(int pos, int len)); -static inline secbool flash_erase_sector(uint8_t sector) { return flash_erase_sectors(§or, 1, NULL); } +static inline secbool flash_erase(uint8_t sector) { return flash_erase_sectors(§or, 1, NULL); } secbool __wur flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data); secbool __wur flash_write_word(uint8_t sector, uint32_t offset, uint32_t data); diff --git a/embed/unix/flash.c b/embed/unix/flash.c index 52ec0ed74..a76e6f2e4 100644 --- a/embed/unix/flash.c +++ b/embed/unix/flash.c @@ -103,12 +103,12 @@ void flash_init(void) atexit(flash_exit); } -secbool flash_unlock(void) +secbool flash_unlock_write(void) { return sectrue; } -secbool flash_lock(void) +secbool flash_lock_write(void) { return sectrue; } diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 8970e2bde..fc29df6f8 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 8970e2bdebb3334ddd0bacf41c66be79e78880f8 +Subproject commit fc29df6f874efa649bc3520c247b2169ffb563bf From 55e030dbaeb7bc1f7ea7a72d2c0105a9c3e49d1c Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 1 Feb 2019 19:18:43 +0100 Subject: [PATCH 29/38] Add config.lock(). --- embed/extmod/modtrezorconfig/modtrezorconfig.c | 11 +++++++++++ vendor/trezor-storage | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/embed/extmod/modtrezorconfig/modtrezorconfig.c b/embed/extmod/modtrezorconfig/modtrezorconfig.c index 70d306e67..fc446cc68 100644 --- a/embed/extmod/modtrezorconfig/modtrezorconfig.c +++ b/embed/extmod/modtrezorconfig/modtrezorconfig.c @@ -79,6 +79,16 @@ STATIC mp_obj_t mod_trezorconfig_unlock(mp_obj_t pin) { } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorconfig_unlock_obj, mod_trezorconfig_unlock); +/// def lock() -> None: +/// ''' +/// Locks the storage. +/// ''' +STATIC mp_obj_t mod_trezorconfig_lock(void) { + storage_lock(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorconfig_lock_obj, mod_trezorconfig_lock); + /// def has_pin() -> bool: /// ''' /// Returns True if storage has a configured PIN, False otherwise. @@ -196,6 +206,7 @@ STATIC const mp_rom_map_elem_t mp_module_trezorconfig_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&mod_trezorconfig_init_obj) }, { MP_ROM_QSTR(MP_QSTR_check_pin), MP_ROM_PTR(&mod_trezorconfig_check_pin_obj) }, { MP_ROM_QSTR(MP_QSTR_unlock), MP_ROM_PTR(&mod_trezorconfig_unlock_obj) }, + { MP_ROM_QSTR(MP_QSTR_lock), MP_ROM_PTR(&mod_trezorconfig_lock_obj) }, { MP_ROM_QSTR(MP_QSTR_has_pin), MP_ROM_PTR(&mod_trezorconfig_has_pin_obj) }, { MP_ROM_QSTR(MP_QSTR_get_pin_rem), MP_ROM_PTR(&mod_trezorconfig_get_pin_rem_obj) }, { MP_ROM_QSTR(MP_QSTR_change_pin), MP_ROM_PTR(&mod_trezorconfig_change_pin_obj) }, diff --git a/vendor/trezor-storage b/vendor/trezor-storage index fc29df6f8..2888c1109 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit fc29df6f874efa649bc3520c247b2169ffb563bf +Subproject commit 2888c1109563f32febb2eda9aed1130c07c6672b From c106e81a052e615313a409733500ecd588bb6d2a Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 4 Feb 2019 15:49:16 +0100 Subject: [PATCH 30/38] Update trezor-storage. --- vendor/trezor-storage | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 2888c1109..8fc03a5a9 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 2888c1109563f32febb2eda9aed1130c07c6672b +Subproject commit 8fc03a5a95d3b75b29909a9f030fd74b294bf63b From 36f354714d7f2e2cd73d82549e2afe37cdf3f614 Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 7 Feb 2019 12:01:08 +0100 Subject: [PATCH 31/38] modtrezorconfig: Chenge ui_wait_callback() to return secbool. --- embed/extmod/modtrezorconfig/modtrezorconfig.c | 7 +++++-- src/trezor/pin.py | 3 ++- vendor/trezor-storage | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/embed/extmod/modtrezorconfig/modtrezorconfig.c b/embed/extmod/modtrezorconfig/modtrezorconfig.c index fc446cc68..0e9822f16 100644 --- a/embed/extmod/modtrezorconfig/modtrezorconfig.c +++ b/embed/extmod/modtrezorconfig/modtrezorconfig.c @@ -30,10 +30,13 @@ STATIC mp_obj_t ui_wait_callback = mp_const_none; -STATIC void wrapped_ui_wait_callback(uint32_t wait, uint32_t progress) { +STATIC secbool wrapped_ui_wait_callback(uint32_t wait, uint32_t progress) { if (mp_obj_is_callable(ui_wait_callback)) { - mp_call_function_2(ui_wait_callback, mp_obj_new_int(wait), mp_obj_new_int(progress)); + if (mp_call_function_2(ui_wait_callback, mp_obj_new_int(wait), mp_obj_new_int(progress)) == mp_const_true) { + return sectrue; + } } + return secfalse; } /// def init(ui_wait_callback: (int, int -> None)=None) -> None: diff --git a/src/trezor/pin.py b/src/trezor/pin.py index 983df9a00..eb4faa96d 100644 --- a/src/trezor/pin.py +++ b/src/trezor/pin.py @@ -5,7 +5,7 @@ def pin_to_int(pin: str) -> int: return int("1" + pin) -def show_pin_timeout(seconds: int, progress: int): +def show_pin_timeout(seconds: int, progress: int) -> bool: if progress == 0: ui.display.bar(0, 0, ui.WIDTH, ui.HEIGHT, ui.BG) ui.display.text_center( @@ -37,3 +37,4 @@ def show_pin_timeout(seconds: int, progress: int): ui.WIDTH, ) ui.display.refresh() + return False diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 8fc03a5a9..4429888b9 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 8fc03a5a95d3b75b29909a9f030fd74b294bf63b +Subproject commit 4429888b9325d200b699a90f7a0e1a07d08f09c0 From 8b78e6710ac545a0ea6551d6494648bbf9f85a62 Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 7 Feb 2019 12:02:41 +0100 Subject: [PATCH 32/38] common.c: Add error_shutdown(). Upon fatal error display 'Contact TREZOR support'. --- embed/trezorhal/common.c | 47 ++++++++++++++++++++++++++++++++++++++++ embed/trezorhal/common.h | 1 + embed/unix/common.c | 36 ++++++++++++++++++++++++++++++ embed/unix/common.h | 1 + 4 files changed, 85 insertions(+) diff --git a/embed/trezorhal/common.c b/embed/trezorhal/common.c index f7cdbcc76..67b68ebc4 100644 --- a/embed/trezorhal/common.c +++ b/embed/trezorhal/common.c @@ -51,6 +51,53 @@ void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, #ifdef GITREV display_printf("rev : %s\n", XSTR(GITREV)); #endif + display_printf("\nPlease contact TREZOR support.\n"); + shutdown(); + for (;;); +} + +void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4) +{ + display_orientation(0); +#ifdef TREZOR_FONT_NORMAL_ENABLE + display_clear(); + display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_FATAL_ERROR); + int y = 32; + if (line1) { + display_text(8, y, line1, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); + y += 32; + } + if (line2) { + display_text(8, y, line2, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); + y += 32; + } + if (line3) { + display_text(8, y, line3, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); + y += 32; + } + if (line4) { + display_text(8, y, line4, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); + y += 32; + } + y += 32; + display_text(8, y, "Please unplug the device.", -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); +#else + display_print_color(COLOR_WHITE, COLOR_FATAL_ERROR); + if (line1) { + display_printf("%s\n", line1); + } + if (line2) { + display_printf("%s\n", line2); + } + if (line3) { + display_printf("%s\n", line3); + } + if (line4) { + display_printf("%s\n", line4); + } + display_printf("\nPlease unplug the device.\n"); +#endif + display_backlight(255); shutdown(); for (;;); } diff --git a/embed/trezorhal/common.h b/embed/trezorhal/common.h index 1b8c8a3b4..7f147956d 100644 --- a/embed/trezorhal/common.h +++ b/embed/trezorhal/common.h @@ -34,6 +34,7 @@ #endif void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line, const char *func); +void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4); #define ensure(expr, msg) (((expr) == sectrue) ? (void)0 : __fatal_error(#expr, msg, __FILE__, __LINE__, __func__)) diff --git a/embed/unix/common.c b/embed/unix/common.c index c591e66e5..73047d40e 100644 --- a/embed/unix/common.c +++ b/embed/unix/common.c @@ -60,11 +60,47 @@ void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, display_printf("rev : %s\n", XSTR(GITREV)); printf("rev : %s\n", XSTR(GITREV)); #endif + display_printf("\nPlease contact TREZOR support.\n"); + printf("\nPlease contact TREZOR support.\n"); hal_delay(3000); __shutdown(); for (;;); } +void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4) +{ + display_clear(); + display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_FATAL_ERROR); + int y = 32; + if (line1) { + display_text(8, y, line1, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); + printf("%s\n", line1); + y += 32; + } + if (line2) { + display_text(8, y, line2, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); + printf("%s\n", line2); + y += 32; + } + if (line3) { + display_text(8, y, line3, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); + printf("%s\n", line3); + y += 32; + } + if (line4) { + display_text(8, y, line4, -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); + printf("%s\n", line4); + y += 32; + } + y += 32; + display_text(8, y, "Please unplug the device.", -1, FONT_NORMAL, COLOR_WHITE, COLOR_FATAL_ERROR); + printf("\nPlease unplug the device.\n"); + display_backlight(255); + hal_delay(5000); + __shutdown(); + for (;;); +} + void hal_delay(uint32_t ms) { usleep(1000 * ms); diff --git a/embed/unix/common.h b/embed/unix/common.h index af73c80ff..022fbacda 100644 --- a/embed/unix/common.h +++ b/embed/unix/common.h @@ -34,6 +34,7 @@ #endif void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line, const char *func); +void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4); #define ensure(expr, msg) (((expr) == sectrue) ? (void)0 : __fatal_error(#expr, msg, __FILE__, __LINE__, __func__)) From 52c7f0eb93d721ec74e4a2bade744fd007cb85ae Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 11 Feb 2019 14:38:37 +0100 Subject: [PATCH 33/38] config: Use efficient implementation of U2F counter from trezor-storage. --- .../extmod/modtrezorconfig/modtrezorconfig.c | 56 ++++++++++++++++++- src/apps/common/storage.py | 50 +---------------- vendor/trezor-storage | 2 +- 3 files changed, 57 insertions(+), 51 deletions(-) diff --git a/embed/extmod/modtrezorconfig/modtrezorconfig.c b/embed/extmod/modtrezorconfig/modtrezorconfig.c index 0e9822f16..09730bd35 100644 --- a/embed/extmod/modtrezorconfig/modtrezorconfig.c +++ b/embed/extmod/modtrezorconfig/modtrezorconfig.c @@ -133,7 +133,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorconfig_change_pin_obj, mod_trezorconf /// Raises a RuntimeError if decryption or authentication of the stored value fails. /// ''' STATIC mp_obj_t mod_trezorconfig_get(size_t n_args, const mp_obj_t *args) { - uint8_t app = trezor_obj_get_uint8(args[0]) & 0x7F; + uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F; uint8_t key = trezor_obj_get_uint8(args[1]); if (n_args > 2 && args[2] == mp_const_true) { app |= 0x80; @@ -161,7 +161,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_get_obj, 2, 3, mod_t /// Sets a value of given key for given app. /// ''' STATIC mp_obj_t mod_trezorconfig_set(size_t n_args, const mp_obj_t *args) { - uint8_t app = trezor_obj_get_uint8(args[0]) & 0x7F; + uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F; uint8_t key = trezor_obj_get_uint8(args[1]); if (n_args > 3 && args[3] == mp_const_true) { app |= 0x80; @@ -181,7 +181,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_set_obj, 3, 4, mod_t /// Deletes the given key of the given app. /// ''' STATIC mp_obj_t mod_trezorconfig_delete(size_t n_args, const mp_obj_t *args) { - uint8_t app = trezor_obj_get_uint8(args[0]) & 0x7F; + uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F; uint8_t key = trezor_obj_get_uint8(args[1]); if (n_args > 2 && args[2] == mp_const_true) { app |= 0x80; @@ -194,6 +194,54 @@ STATIC mp_obj_t mod_trezorconfig_delete(size_t n_args, const mp_obj_t *args) { } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_delete_obj, 2, 3, mod_trezorconfig_delete); +/// def set_counter(app: int, key: int, count: int, writable_locked: bool=False) -> bool: +/// ''' +/// Sets the given key of the given app as a counter with the given value. +/// ''' +STATIC mp_obj_t mod_trezorconfig_set_counter(size_t n_args, const mp_obj_t *args) { + uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F; + uint8_t key = trezor_obj_get_uint8(args[1]); + if (n_args > 3 && args[3] == mp_const_true) { + app |= 0xC0; + } else { + app |= 0x80; + } + uint16_t appkey = (app << 8) | key; + if (args[2] == mp_const_none) { + if (sectrue != storage_delete(appkey)) { + return mp_const_false; + } + } else { + uint32_t count = trezor_obj_get_uint(args[2]); + if (sectrue != storage_set_counter(appkey, count)) { + return mp_const_false; + } + } + return mp_const_true; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_set_counter_obj, 3, 4, mod_trezorconfig_set_counter); + +/// def next_counter(app: int, key: int, writable_locked: bool=False) -> bool: +/// ''' +/// Increments the counter stored under the given key of the given app and returns the new value. +/// ''' +STATIC mp_obj_t mod_trezorconfig_next_counter(size_t n_args, const mp_obj_t *args) { + uint8_t app = trezor_obj_get_uint8(args[0]) & 0x3F; + uint8_t key = trezor_obj_get_uint8(args[1]); + if (n_args > 2 && args[2] == mp_const_true) { + app |= 0xC0; + } else { + app |= 0x80; + } + uint16_t appkey = (app << 8) | key; + uint32_t count = 0; + if (sectrue != storage_next_counter(appkey, &count)) { + return mp_const_none; + } + return mp_obj_new_int_from_uint(count); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_next_counter_obj, 2, 3, mod_trezorconfig_next_counter); + /// def wipe() -> None: /// ''' /// Erases the whole config. Use with caution! @@ -216,6 +264,8 @@ STATIC const mp_rom_map_elem_t mp_module_trezorconfig_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&mod_trezorconfig_get_obj) }, { MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&mod_trezorconfig_set_obj) }, { MP_ROM_QSTR(MP_QSTR_delete), MP_ROM_PTR(&mod_trezorconfig_delete_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_counter), MP_ROM_PTR(&mod_trezorconfig_set_counter_obj) }, + { MP_ROM_QSTR(MP_QSTR_next_counter), MP_ROM_PTR(&mod_trezorconfig_next_counter_obj) }, { MP_ROM_QSTR(MP_QSTR_wipe), MP_ROM_PTR(&mod_trezorconfig_wipe_obj) }, }; STATIC MP_DEFINE_CONST_DICT(mp_module_trezorconfig_globals, mp_module_trezorconfig_globals_table); diff --git a/src/apps/common/storage.py b/src/apps/common/storage.py index 4c16f6978..85780797d 100644 --- a/src/apps/common/storage.py +++ b/src/apps/common/storage.py @@ -44,50 +44,6 @@ def _get_bool(app: int, key: int, public: bool = False) -> bool: return config.get(app, key, public) == _TRUE_BYTE -def _set_counter(app: int, key: int, count: int, public: bool = False) -> None: - if count is None: - config.delete(app, key, public) - return - - value = count.to_bytes(_COUNTER_HEAD_LEN, "big") - if public: - value += _COUNTER_TAIL_LEN * b"\xff" - config.set(app, key, value, public) - - -def _next_counter(app: int, key: int, public: bool = False) -> int: - # If the counter value is public, then it is stored as a four byte integer in - # big endian byte order, called the "head", followed an eight byte "tail". The - # counter value is equal to the integer value of the head plus the number of - # zero bits in the tail. The counter value 0 is stored as 00000000FFFFFFFFFFFFFFFF. - # With each increment the tail is shifted to the right by one bit. Thus after - # three increments the stored value is 000000001FFFFFFFFFFFFFFF. Once all the - # bits in the tail are set to zero, the next counter value is stored as - # 00000041FFFFFFFFFFFFFFFF. - - value = config.get(app, key, public) - if value is None: - _set_counter(app, key, 0, public) - return 0 - - head = value[:_COUNTER_HEAD_LEN] - tail = value[_COUNTER_HEAD_LEN:] - i = tail.rfind(b"\x00") + 1 - count = int.from_bytes(head, "big") + 1 + 8 * i - if i == len(tail): - _set_counter(app, key, count, public) - return count - - zero_count = 0 - while (tail[i] << zero_count) < 128: - zero_count += 1 - count += zero_count - - tail = tail[:i] + bytes([tail[i] >> 1]) + tail[i + 1 :] - config.set(app, key, head + tail, public) - return count - - def _new_device_id() -> str: return hexlify(random.bytes(12)).decode().upper() @@ -219,11 +175,11 @@ def set_autolock_delay_ms(delay_ms: int) -> None: def next_u2f_counter() -> int: - return _next_counter(_APP, _U2F_COUNTER, True) # public + return config.next_counter(_APP, _U2F_COUNTER) def set_u2f_counter(cntr: int) -> None: - _set_counter(_APP, _U2F_COUNTER, cntr, True) # public + config.set_counter(_APP, _U2F_COUNTER, cntr) def wipe(): @@ -238,6 +194,6 @@ def init_unlocked(): # Make the U2F counter public. counter = config.get(_APP, _U2F_COUNTER) if counter is not None: - _set_counter(_APP, _U2F_COUNTER, counter, True) # public + config.set_counter(_APP, _U2F_COUNTER, counter) config.delete(_APP, _U2F_COUNTER) config.set(_APP, _VERSION, _STORAGE_VERSION) diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 4429888b9..5c2765740 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 4429888b9325d200b699a90f7a0e1a07d08f09c0 +Subproject commit 5c2765740db064c99fe54cbae79f74a3d767973c From 6afd9b1d09b812d0170cc2f00bacc0d3cb7fbc0e Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Mon, 11 Feb 2019 15:52:26 +0100 Subject: [PATCH 34/38] tests: Do not require storage to be unlocked prior to calling storage_change_pin(). The function checks the old PIN anyway. --- tests/test_trezor.config.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_trezor.config.py b/tests/test_trezor.config.py index 4bba499da..eaecda838 100644 --- a/tests/test_trezor.config.py +++ b/tests/test_trezor.config.py @@ -54,7 +54,6 @@ class TestConfig(unittest.TestCase): config.set(appid, key, bytes()) config.init() config.wipe() - self.assertEqual(config.change_pin(pin_to_int(''), pin_to_int('000')), False) def test_public(self): config.init() From fd6eb333a681bd3c8bbda83250f57ff2341d54b5 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Mon, 11 Feb 2019 16:07:34 +0100 Subject: [PATCH 35/38] src/apps/common/storage: allow U2F counter to be written even when storage is locked --- src/apps/common/storage.py | 10 ++++++---- tests/test_apps.common.storage.py | 1 - 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/apps/common/storage.py b/src/apps/common/storage.py index 85780797d..92c2a0d13 100644 --- a/src/apps/common/storage.py +++ b/src/apps/common/storage.py @@ -175,11 +175,11 @@ def set_autolock_delay_ms(delay_ms: int) -> None: def next_u2f_counter() -> int: - return config.next_counter(_APP, _U2F_COUNTER) + return config.next_counter(_APP, _U2F_COUNTER, True) # writable when locked def set_u2f_counter(cntr: int) -> None: - config.set_counter(_APP, _U2F_COUNTER, cntr) + config.set_counter(_APP, _U2F_COUNTER, cntr, True) # writable when locked def wipe(): @@ -191,9 +191,11 @@ def init_unlocked(): # Check for storage version upgrade. version = config.get(_APP, _VERSION) if version == b"\x01": - # Make the U2F counter public. + # Make the U2F counter public and writable even when storage is locked. counter = config.get(_APP, _U2F_COUNTER) if counter is not None: - config.set_counter(_APP, _U2F_COUNTER, counter) + config.set_counter( + _APP, _U2F_COUNTER, counter, True + ) # writable when locked config.delete(_APP, _U2F_COUNTER) config.set(_APP, _VERSION, _STORAGE_VERSION) diff --git a/tests/test_apps.common.storage.py b/tests/test_apps.common.storage.py index 075a9a4fd..e3630a920 100644 --- a/tests/test_apps.common.storage.py +++ b/tests/test_apps.common.storage.py @@ -9,7 +9,6 @@ class TestConfig(unittest.TestCase): def test_counter(self): config.init() config.wipe() - self.assertEqual(config.unlock(pin_to_int('')), True) for i in range(150): self.assertEqual(storage.next_u2f_counter(), i) storage.set_u2f_counter(350) From 06ef27a718da94d1975bc618553f601fcfc1c0d5 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Mon, 11 Feb 2019 16:15:25 +0100 Subject: [PATCH 36/38] config: Erase HW_ENTROPY_DATA when no longer needed. This assumes that config.init() is called only once in production. For the emulator tests config.init() can be called repeatedly, since HW_ENTROPY_DATA is null-initialized to begin with. --- embed/extmod/modtrezorconfig/modtrezorconfig.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/embed/extmod/modtrezorconfig/modtrezorconfig.c b/embed/extmod/modtrezorconfig/modtrezorconfig.c index 09730bd35..5d84d655b 100644 --- a/embed/extmod/modtrezorconfig/modtrezorconfig.c +++ b/embed/extmod/modtrezorconfig/modtrezorconfig.c @@ -27,6 +27,7 @@ #include "storage.h" #include "common.h" +#include "memzero.h" STATIC mp_obj_t ui_wait_callback = mp_const_none; @@ -51,6 +52,7 @@ STATIC mp_obj_t mod_trezorconfig_init(size_t n_args, const mp_obj_t *args) { } else { storage_init(NULL, HW_ENTROPY_DATA, HW_ENTROPY_LEN); } + memzero(HW_ENTROPY_DATA, sizeof(HW_ENTROPY_DATA)); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorconfig_init_obj, 0, 1, mod_trezorconfig_init); From bc46892ba0fa21c1f3a779e73c61fb38f2bd33a6 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Mon, 11 Feb 2019 17:55:09 +0100 Subject: [PATCH 37/38] vendor: update trezor-storage --- vendor/trezor-storage | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 5c2765740..13b256ab2 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 5c2765740db064c99fe54cbae79f74a3d767973c +Subproject commit 13b256ab2c11791e0c13696a8c507787a374884f From 69efeac015e3c05be05ca98c734cd66a1d5e43be Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Tue, 12 Feb 2019 18:21:23 +0100 Subject: [PATCH 38/38] tests: Limit the APP values in test_trezor.config to 1, ..., 63 to account for the fact that the top two bits are being used as permissions flags. --- tests/test_trezor.config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_trezor.config.py b/tests/test_trezor.config.py index eaecda838..416ec3059 100644 --- a/tests/test_trezor.config.py +++ b/tests/test_trezor.config.py @@ -11,7 +11,7 @@ PINKEY = 0x00 def random_entry(): while True: - appid, key = 1 + random.uniform(127), random.uniform(256) + appid, key = 1 + random.uniform(63), random.uniform(256) if appid != PINAPP or key != PINKEY: break return appid, key