From 4f32cb508383ec0e65843d037f6ac6473a668359 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 25 Jan 2019 11:58:23 +0100 Subject: [PATCH 01/31] firmware: integrate trezor-storage --- .gitmodules | 3 + Makefile | 2 + Makefile.include | 3 +- common.c | 65 +++ common.h | 43 ++ firmware/Makefile | 10 +- firmware/config.c | 854 ++++++++++++++++++++++++++++ firmware/{storage.h => config.h} | 105 ++-- firmware/fsm.c | 9 +- firmware/fsm_msg_common.h | 79 ++- firmware/fsm_msg_debug.h | 14 +- firmware/layout2.c | 21 +- firmware/protect.c | 157 +++--- firmware/protect.h | 3 +- firmware/recovery.c | 27 +- firmware/reset.c | 51 +- firmware/reset.h | 2 +- firmware/stellar.c | 4 +- firmware/storage.c | 936 ------------------------------- firmware/trezor.c | 8 +- firmware/u2f.c | 10 +- firmware/usb.c | 4 +- flash.c | 137 +++++ flash.h | 47 ++ norcow_config.h | 39 ++ secbool.h | 33 ++ vendor/trezor-storage | 1 + 27 files changed, 1484 insertions(+), 1183 deletions(-) create mode 100644 common.c create mode 100644 common.h create mode 100644 firmware/config.c rename firmware/{storage.h => config.h} (53%) delete mode 100644 firmware/storage.c create mode 100644 flash.c create mode 100644 flash.h create mode 100644 norcow_config.h create mode 100644 secbool.h create mode 160000 vendor/trezor-storage diff --git a/.gitmodules b/.gitmodules index 920894a059..ff5aff640d 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 = https://github.com/trezor/trezor-storage.git diff --git a/Makefile b/Makefile index 140c3faf54..fce0a317c5 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,8 @@ OBJS += startup.o endif OBJS += buttons.o +OBJS += common.o +OBJS += flash.o OBJS += layout.o OBJS += oled.o OBJS += rng.o diff --git a/Makefile.include b/Makefile.include index 1f175f0e28..11e922652f 100644 --- a/Makefile.include +++ b/Makefile.include @@ -72,7 +72,8 @@ CFLAGS += $(OPTFLAGS) \ -I$(TOP_DIR) \ -I$(TOP_DIR)gen \ -I$(TOP_DIR)vendor/trezor-crypto \ - -I$(TOP_DIR)vendor/trezor-qrenc + -I$(TOP_DIR)vendor/trezor-qrenc \ + -I$(TOP_DIR)vendor/trezor-storage LDFLAGS += -L$(TOP_DIR) \ $(DBGFLAGS) \ diff --git a/common.c b/common.c new file mode 100644 index 0000000000..5a8c0c1cc5 --- /dev/null +++ b/common.c @@ -0,0 +1,65 @@ +/* + * 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 "rng.h" +#include "layout.h" +#include "firmware/usb.h" + +void shutdown(void); + +void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line_num, const char *func) { + char line[4][128] = {{0}}; + int i = 0; + if (expr != NULL) { + snprintf(line[i], sizeof(line[0]), "Expr: %s", expr); + i++; + } + if (msg != NULL) { + snprintf(line[i], sizeof(line[0]), "Msg: %s", msg); + i++; + } + if (file != NULL) { + snprintf(line[i], sizeof(line[0]), "File: %s:%d", file, line_num); + i++; + } + if (func != NULL) { + snprintf(line[i], sizeof(line[0]), "Func: %s", func); + i++; + } + error_shutdown("FATAL ERROR:", NULL, line[0], line[1], line[2], line[3]); +} + +void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) { + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, line2, line3, line4, line5, line6); + shutdown(); + for (;;); +} + +#ifndef NDEBUG +void __assert_func(const char *file, int line, const char *func, const char *expr) { + __fatal_error(expr, "assert failed", file, line, func); +} +#endif + +void hal_delay(uint32_t ms) +{ + usbSleep(ms); +} diff --git a/common.h b/common.h new file mode 100644 index 0000000000..b89547a378 --- /dev/null +++ b/common.h @@ -0,0 +1,43 @@ +/* + * 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_COMMON_H__ +#define __TREZORHAL_COMMON_H__ + +#include +#include "secbool.h" + +#define XSTR(s) STR(s) +#define STR(s) #s + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#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, const char *line5, const char *line6); + +#define ensure(expr, msg) (((expr) == sectrue) ? (void)0 : __fatal_error(#expr, msg, __FILE__, __LINE__, __func__)) + +void hal_delay(uint32_t ms); + +#endif diff --git a/firmware/Makefile b/firmware/Makefile index c8095160ce..90e136324d 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -11,7 +11,7 @@ endif OBJS += u2f.o OBJS += messages.o -OBJS += storage.o +OBJS += config.o OBJS += trezor.o OBJS += pinmatrix.o OBJS += fsm.o @@ -75,10 +75,18 @@ OBJS += ../vendor/trezor-crypto/aes/aeskey.o OBJS += ../vendor/trezor-crypto/aes/aestab.o OBJS += ../vendor/trezor-crypto/aes/aes_modes.o +OBJS += ../vendor/trezor-crypto/chacha20poly1305/chacha20poly1305.o +OBJS += ../vendor/trezor-crypto/chacha20poly1305/chacha_merged.o +OBJS += ../vendor/trezor-crypto/chacha20poly1305/poly1305-donna.o +OBJS += ../vendor/trezor-crypto/chacha20poly1305/rfc7539.o + OBJS += ../vendor/trezor-crypto/nem.o OBJS += ../vendor/trezor-qrenc/qr_encode.o +OBJS += ../vendor/trezor-storage/storage.o +OBJS += ../vendor/trezor-storage/norcow.o + OBJS += ../vendor/nanopb/pb_common.o OBJS += ../vendor/nanopb/pb_decode.o OBJS += ../vendor/nanopb/pb_encode.o diff --git a/firmware/config.c b/firmware/config.c new file mode 100644 index 0000000000..7799f1ff81 --- /dev/null +++ b/firmware/config.c @@ -0,0 +1,854 @@ +/* + * This file is part of the TREZOR project, https://trezor.io/ + * + * Copyright (C) 2014 Pavol Rusnak + * + * This library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library. If not, see . + */ + +#include +#include +#include + +#include "messages.pb.h" + +#include "trezor.h" +#include "sha2.h" +#include "aes/aes.h" +#include "pbkdf2.h" +#include "hmac.h" +#include "bip32.h" +#include "bip39.h" +#include "curves.h" +#include "util.h" +#include "memory.h" +#include "rng.h" +#include "config.h" +#include "debug.h" +#include "protect.h" +#include "layout2.h" +#include "usb.h" +#include "gettext.h" +#include "u2f.h" +#include "memzero.h" +#include "supervise.h" +#include "storage.h" + +/* Magic constant to check validity of storage block for storage versions 1 to 10. */ +static const uint32_t CONFIG_MAGIC_V10 = 0x726f7473; // 'stor' as uint32_t + +#define APP 0x0100 +#define FLAG_PUBLIC 0x8000 + +static const uint16_t KEY_UUID = 0 | APP | FLAG_PUBLIC; // bytes(12) +static const uint16_t KEY_VERSION = 1 | APP; // uint32 +static const uint16_t KEY_NODE = 2 | APP; // node +static const uint16_t KEY_MNEMONIC = 3 | APP; // string(241) +static const uint16_t KEY_PASSPHRASE_PROTECTION = 4 | APP; // bool +static const uint16_t KEY_LANGUAGE = 5 | APP | FLAG_PUBLIC; // string(17) +static const uint16_t KEY_LABEL = 6 | APP | FLAG_PUBLIC; // string(33) +static const uint16_t KEY_IMPORTED = 7 | APP; // bool +static const uint16_t KEY_HOMESCREEN = 8 | APP | FLAG_PUBLIC; // bytes(1024) +static const uint16_t KEY_U2F_COUNTER = 9 | APP | FLAG_PUBLIC; // uint32 +static const uint16_t KEY_NEEDS_BACKUP = 10 | APP; // bool +static const uint16_t KEY_FLAGS = 11 | APP; // uint32 +static const uint16_t KEY_U2F_ROOT = 12 | APP; // node +static const uint16_t KEY_UNFINISHED_BACKUP = 13 | APP; // bool +static const uint16_t KEY_AUTO_LOCK_DELAY_MS = 14 | APP; // uint32 +static const uint16_t KEY_NO_BACKUP = 15 | APP; // bool + +// The PIN value corresponding to an empty PIN. +static const uint32_t PIN_EMPTY = 1; + +static uint32_t config_uuid[UUID_SIZE / sizeof(uint32_t)]; +_Static_assert(sizeof(config_uuid) == UUID_SIZE, "config_uuid has wrong size"); + +char config_uuid_str[2*UUID_SIZE + 1]; + +/* + Old storage layout: + + offset | type/length | description +--------+--------------+------------------------------- + 0x0000 | 4 bytes | magic = 'stor' + 0x0004 | 12 bytes | uuid + 0x0010 | ? bytes | Storage structure +--------+--------------+------------------------------- + 0x4000 | 4 kbytes | area for pin failures + 0x5000 | 256 bytes | area for u2f counter updates + 0x5100 | 11.75 kbytes | reserved + +The area for pin failures looks like this: +0 ... 0 pinfail 0xffffffff .. 0xffffffff +The pinfail is a binary number of the form 1...10...0, +the number of zeros is the number of pin failures. +This layout is used because we can only clear bits without +erasing the flash. + +The area for u2f counter updates is just a sequence of zero-bits +followed by a sequence of one-bits. The bits in a byte are numbered +from LSB to MSB. The number of zero bits is the offset that should +be added to the storage u2f_counter to get the real counter value. + + */ + +/* Current u2f offset, i.e. u2f counter is + * storage.u2f_counter + config_u2f_offset. + * This corresponds to the number of cleared bits in the U2FAREA. + */ +static bool sessionSeedCached, sessionSeedUsesPassphrase; + +static uint8_t CONFIDENTIAL sessionSeed[64]; + +static bool sessionPassphraseCached = false; +static char CONFIDENTIAL sessionPassphrase[51]; + +static const uint32_t CONFIG_VERSION = 10; + +static const uint8_t FALSE_BYTE = '\x00'; +static const uint8_t TRUE_BYTE = '\x01'; + +static uint32_t pin_to_int(const char *pin) +{ + uint32_t val = 1; + size_t i = 0; + for (i = 0; i < MAX_PIN_LEN && pin[i] != '\0'; ++i) { + if (pin[i] < '0' || pin[i] > '9') { + return 0; + } + val = 10*val + pin[i] - '0'; + } + + if (pin[i] != '\0') { + return 0; + } + + return val; +} + +static bool config_set_bool(uint16_t key, bool value) +{ + if (value) { + return (sectrue == storage_set(key, &TRUE_BYTE, sizeof(TRUE_BYTE))); + } else { + return (sectrue == storage_set(key, &FALSE_BYTE, sizeof(FALSE_BYTE))); + } +} + +static bool config_get_bool(uint16_t key) +{ + uint8_t value = 0; + uint16_t len = 0; + secbool ret = storage_get(key, &value, sizeof(value), &len); + return (sectrue == ret && len == 1 && value == TRUE_BYTE); +} + +static bool config_has_key(uint16_t key) +{ + uint16_t len = 0; + return sectrue == storage_get(key, NULL, 0, &len); +} + +static bool config_get_string(uint16_t key, char *dest, uint16_t dest_size) { + dest[0] = '\0'; + uint16_t len = 0; + if (sectrue != storage_get(key, dest, dest_size - 1, &len)) { + return false; + } + dest[len] = '\0'; + return true; +} + +static uint32_t config_get_uint32(uint16_t key) { + uint32_t value = 0; + uint16_t len = 0; + if (sectrue != storage_get(key, &value, sizeof(value), &len) || len != sizeof(value)) { + return 0; + } + return value; +} + +void config_show_error(void) +{ + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Storage failure"), _("detected."), NULL, _("Please unplug"), _("the device."), NULL); + shutdown(); +} + +static bool config_upgrade_v10(void) +{ +#define OLD_STORAGE_SIZE(last_member) (((offsetof(Storage, last_member) + pb_membersize(Storage, last_member)) + 3) & ~3) + + if (memcmp(FLASH_PTR(FLASH_STORAGE_START), &CONFIG_MAGIC_V10, sizeof(CONFIG_MAGIC_V10)) != 0) { + // wrong magic + return false; + } + + Storage config __attribute__((aligned(4))); + _Static_assert((sizeof(config) & 3) == 0, "storage unaligned"); + + memcpy(config_uuid, FLASH_PTR(FLASH_STORAGE_START + sizeof(CONFIG_MAGIC_V10)), sizeof(config_uuid)); + memcpy(&config, FLASH_PTR(FLASH_STORAGE_START + sizeof(CONFIG_MAGIC_V10) + sizeof(config_uuid)), sizeof(config)); + + // version 1: since 1.0.0 + // version 2: since 1.2.1 + // version 3: since 1.3.1 + // version 4: since 1.3.2 + // version 5: since 1.3.3 + // version 6: since 1.3.6 + // version 7: since 1.5.1 + // version 8: since 1.5.2 + // version 9: since 1.6.1 + // version 10: since 1.7.2 + if (config.version > CONFIG_VERSION) { + // downgrade -> clear storage + config_wipe(); + return false; + } + + size_t old_config_size = 0; + if (config.version == 0) { + } else if (config.version <= 2) { + old_config_size = OLD_STORAGE_SIZE(imported); + } else if (config.version <= 5) { + // added homescreen + old_config_size = OLD_STORAGE_SIZE(homescreen); + } else if (config.version <= 7) { + // added u2fcounter + old_config_size = OLD_STORAGE_SIZE(u2f_counter); + } else if (config.version <= 8) { + // added flags and needsBackup + old_config_size = OLD_STORAGE_SIZE(flags); + } else if (config.version <= 9) { + // added u2froot, unfinished_backup and auto_lock_delay_ms + old_config_size = OLD_STORAGE_SIZE(auto_lock_delay_ms); + } else if (config.version <= 10) { + // added no_backup + old_config_size = OLD_STORAGE_SIZE(no_backup); + } + + // Erase newly added fields. + if (old_config_size != sizeof(Storage)) { + memzero(&config + old_config_size, sizeof(Storage) - old_config_size); + } + + const uint32_t FLASH_STORAGE_PINAREA = FLASH_META_START + 0x4000; + uint32_t pin_wait = 0; + if (config.version <= 5) { + // Get PIN failure counter from version 5 format. + uint32_t pinctr = config.has_pin_failed_attempts ? config.pin_failed_attempts : 0; + if (pinctr > 31) { + pinctr = 31; + } + + pin_wait = (1 << pinctr) - 1; + } else { + // Get PIN failure counter from version 10 format. + uint32_t flash_pinfails = FLASH_STORAGE_PINAREA; + while (*(const uint32_t*)FLASH_PTR(flash_pinfails) == 0) { + flash_pinfails += sizeof(uint32_t); + } + pin_wait = ~*(const uint32_t*)FLASH_PTR(flash_pinfails); + } + + uint32_t u2f_offset = 0; + if (config.has_u2f_counter) { + const uint32_t FLASH_STORAGE_U2FAREA = FLASH_STORAGE_PINAREA + 0x1000; + const uint32_t *u2fptr = (const uint32_t*) FLASH_PTR(FLASH_STORAGE_U2FAREA); + while (*u2fptr == 0) { + u2fptr++; + } + u2f_offset = 32 * (u2fptr - (const uint32_t*) FLASH_PTR(FLASH_STORAGE_U2FAREA)); + uint32_t u2fword = *u2fptr; + while ((u2fword & 1) == 0) { + u2f_offset++; + u2fword >>= 1; + } + } + + // TODO Add salt. + storage_init(NULL, (const uint8_t*)"", 0); + storage_unlock(PIN_EMPTY); + if (config.has_pin) { + storage_change_pin(PIN_EMPTY, pin_to_int(config.pin)); + } + while (pin_wait != 0) { + storage_pin_fails_increase(); + pin_wait >>= 1; + } + + storage_set(KEY_UUID, config_uuid, sizeof(config_uuid)); + storage_set(KEY_VERSION, &CONFIG_VERSION, sizeof(CONFIG_VERSION)); + if (config.has_node) { + storage_set(KEY_NODE, &config.node, sizeof(config.node)); + } + if (config.has_mnemonic) { + config_setMnemonic(config.mnemonic); + } + if (config.has_passphrase_protection) { + config_setPassphraseProtection(config.passphrase_protection); + } + if (config.has_language) { + config_setLanguage(config.language); + } + if (config.has_label) { + config_setLabel(config.label); + } + if (config.has_imported) { + config_setImported(config.imported); + } + if (config.has_homescreen) { + config_setHomescreen(config.homescreen.bytes, config.homescreen.size); + } + if (config.has_u2f_counter) { + config_setU2FCounter(config.u2f_counter + u2f_offset); + } + if (config.has_needs_backup) { + config_setNeedsBackup(config.needs_backup); + } + if (config.has_flags) { + config_applyFlags(config.flags); + } + if (config.has_unfinished_backup) { + config_setUnfinishedBackup(config.unfinished_backup); + } + if (config.has_auto_lock_delay_ms) { + config_setAutoLockDelayMs(config.auto_lock_delay_ms); + } + if (config.has_no_backup && config.no_backup) { + config_setNoBackup(); + } + memzero(&config, sizeof(config)); + + session_clear(true); + + return true; +} + +void config_init(void) +{ + config_upgrade_v10(); + + // TODO Add salt. + storage_init(&protectPinUiCallback, (const uint8_t*)"", 0); + + uint16_t len = 0; + if (sectrue == storage_get(KEY_UUID, config_uuid, sizeof(config_uuid), &len) && len == sizeof(config_uuid)) { + data2hex(config_uuid, sizeof(config_uuid), config_uuid_str); + } else { + config_wipe(); + } +} + +void session_clear(bool lock) +{ + sessionSeedCached = false; + memzero(&sessionSeed, sizeof(sessionSeed)); + sessionPassphraseCached = false; + memzero(&sessionPassphrase, sizeof(sessionPassphrase)); + if (lock) { + storage_lock(); + } +} + +static void get_u2froot_callback(uint32_t iter, uint32_t total) +{ + layoutProgress(_("Updating"), 1000 * iter / total); +} + +static void config_compute_u2froot(const char* mnemonic, StorageHDNode *u2froot) { + static CONFIDENTIAL HDNode node; + char oldTiny = usbTiny(1); + mnemonic_to_seed(mnemonic, "", sessionSeed, get_u2froot_callback); // BIP-0039 + usbTiny(oldTiny); + hdnode_from_seed(sessionSeed, 64, NIST256P1_NAME, &node); + hdnode_private_ckd(&node, U2F_KEY_PATH); + u2froot->depth = node.depth; + u2froot->child_num = U2F_KEY_PATH; + u2froot->chain_code.size = sizeof(node.chain_code); + memcpy(u2froot->chain_code.bytes, node.chain_code, sizeof(node.chain_code)); + u2froot->has_private_key = true; + u2froot->private_key.size = sizeof(node.private_key); + memcpy(u2froot->private_key.bytes, node.private_key, sizeof(node.private_key)); + memzero(&node, sizeof(node)); + session_clear(false); // invalidate seed cache +} + +static void config_setNode(const HDNodeType *node) { + StorageHDNode storageHDNode; + memzero(&storageHDNode, sizeof(storageHDNode)); + + storageHDNode.depth = node->depth; + storageHDNode.fingerprint = node->fingerprint; + storageHDNode.child_num = node->child_num; + storageHDNode.chain_code.size = 32; + memcpy(storageHDNode.chain_code.bytes, node->chain_code.bytes, 32); + + if (node->has_private_key) { + storageHDNode.has_private_key = true; + storageHDNode.private_key.size = 32; + memcpy(storageHDNode.private_key.bytes, node->private_key.bytes, 32); + } + storage_set(KEY_NODE, &storageHDNode, sizeof(storageHDNode)); +} + +#if DEBUG_LINK +void config_dumpNode(HDNodeType *node) +{ + memzero(node, sizeof(HDNodeType)); + + StorageHDNode storageNode; + uint16_t len = 0; + if (sectrue != storage_get(KEY_NODE, &storageNode, sizeof(storageNode), &len) || len != sizeof(StorageHDNode)) { + return; + } + + node->depth = storageNode.depth; + node->fingerprint = storageNode.fingerprint; + node->child_num = storageNode.child_num; + + node->chain_code.size = 32; + memcpy(node->chain_code.bytes, storageNode.chain_code.bytes, 32); + + if (storageNode.has_private_key) { + node->has_private_key = true; + node->private_key.size = 32; + memcpy(node->private_key.bytes, storageNode.private_key.bytes, 32); + } + + memzero(&storageNode, sizeof(storageNode)); +} +#endif + +void config_loadDevice(const LoadDevice *msg) +{ + session_clear(true); + // TODO We can't set anything with the storage locked. Shouldn't we wipe? + + config_set_bool(KEY_IMPORTED, true); + config_setPassphraseProtection(msg->has_passphrase_protection && msg->passphrase_protection); + + if (msg->has_pin) { + config_changePin("", msg->pin); + } + + if (msg->has_node) { + storage_delete(KEY_MNEMONIC); + config_setNode(&(msg->node)); + } else if (msg->has_mnemonic) { + storage_delete(KEY_NODE); + config_setMnemonic(msg->mnemonic); + } + + if (msg->has_language) { + config_setLanguage(msg->language); + } + + config_setLabel(msg->has_label ? msg->label : ""); + + if (msg->has_u2f_counter) { + config_setU2FCounter(msg->u2f_counter); + } +} + +void config_setLabel(const char *label) +{ + if (label == NULL || label[0] == '\0') { + storage_delete(KEY_LABEL); + } else { + storage_set(KEY_LABEL, label, strnlen(label, MAX_LABEL_LEN)); + } +} + +void config_setLanguage(const char *lang) +{ + if (lang == NULL) { + return; + } + + // Sanity check. + if (strcmp(lang, "english") != 0) { + return; + } + storage_set(KEY_LABEL, lang, strnlen(lang, MAX_LANGUAGE_LEN)); +} + +void config_setPassphraseProtection(bool passphrase_protection) +{ + sessionSeedCached = false; + sessionPassphraseCached = false; + config_set_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection); +} + +bool config_hasPassphraseProtection(void) +{ + return config_get_bool(KEY_PASSPHRASE_PROTECTION); +} + +void config_setHomescreen(const uint8_t *data, uint32_t size) +{ + if (data != NULL && size == HOMESCREEN_SIZE) { + storage_set(KEY_HOMESCREEN, data, size); + } else { + storage_delete(KEY_HOMESCREEN); + } +} + +static void get_root_node_callback(uint32_t iter, uint32_t total) +{ + usbSleep(1); + layoutProgress(_("Waking up"), 1000 * iter / total); +} + +const uint8_t *config_getSeed(bool usePassphrase) +{ + // root node is properly cached + if (usePassphrase == sessionSeedUsesPassphrase + && sessionSeedCached) { + return sessionSeed; + } + + // if storage has mnemonic, convert it to node and use it + char mnemonic[MAX_MNEMONIC_LEN + 1]; + if (config_getMnemonic(mnemonic, sizeof(mnemonic))) { + if (usePassphrase && !protectPassphrase()) { + memzero(mnemonic, sizeof(mnemonic)); + return NULL; + } + // if storage was not imported (i.e. it was properly generated or recovered) + if (!config_get_bool(KEY_IMPORTED)) { + // test whether mnemonic is a valid BIP-0039 mnemonic + if (!mnemonic_check(mnemonic)) { + // and if not then halt the device + config_show_error(); + } + } + char oldTiny = usbTiny(1); + mnemonic_to_seed(mnemonic, usePassphrase ? sessionPassphrase : "", sessionSeed, get_root_node_callback); // BIP-0039 + memzero(mnemonic, sizeof(mnemonic)); + usbTiny(oldTiny); + sessionSeedCached = true; + sessionSeedUsesPassphrase = usePassphrase; + return sessionSeed; + } + + return NULL; +} + +static bool config_loadNode(const StorageHDNode *node, const char *curve, HDNode *out) { + return hdnode_from_xprv(node->depth, node->child_num, node->chain_code.bytes, node->private_key.bytes, curve, out); +} + +bool config_getU2FRoot(HDNode *node) +{ + StorageHDNode u2fNode; + uint16_t len = 0; + if (sectrue != storage_get(KEY_U2F_ROOT, &u2fNode, sizeof(u2fNode), &len) || len != sizeof(StorageHDNode)) { + memzero(&u2fNode, sizeof(u2fNode)); + return false; + } + bool ret = config_loadNode(&u2fNode, NIST256P1_NAME, node); + memzero(&u2fNode, sizeof(u2fNode)); + return ret; +} + +bool config_getRootNode(HDNode *node, const char *curve, bool usePassphrase) +{ + // if storage has node, decrypt and use it + StorageHDNode storageHDNode; + uint16_t len = 0; + if (strcmp(curve, SECP256K1_NAME) == 0 && sectrue == storage_get(KEY_NODE, &storageHDNode, sizeof(storageHDNode), &len) && len == sizeof(StorageHDNode)) { + if (!protectPassphrase()) { + memzero(&storageHDNode, sizeof(storageHDNode)); + return false; + } + if (!config_loadNode(&storageHDNode, curve, node)) { + memzero(&storageHDNode, sizeof(storageHDNode)); + return false; + } + if (config_hasPassphraseProtection() && sessionPassphraseCached && sessionPassphrase[0] != '\0') { + // decrypt hd node + uint8_t secret[64]; + PBKDF2_HMAC_SHA512_CTX pctx; + char oldTiny = usbTiny(1); + pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), (const uint8_t *)"TREZORHD", 8, 1); + get_root_node_callback(0, BIP39_PBKDF2_ROUNDS); + for (int i = 0; i < 8; i++) { + pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 8); + get_root_node_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 8, BIP39_PBKDF2_ROUNDS); + } + pbkdf2_hmac_sha512_Final(&pctx, secret); + usbTiny(oldTiny); + aes_decrypt_ctx ctx; + aes_decrypt_key256(secret, &ctx); + aes_cbc_decrypt(node->chain_code, node->chain_code, 32, secret + 32, &ctx); + aes_cbc_decrypt(node->private_key, node->private_key, 32, secret + 32, &ctx); + } + return true; + } + memzero(&storageHDNode, sizeof(storageHDNode)); + + const uint8_t *seed = config_getSeed(usePassphrase); + if (seed == NULL) { + return false; + } + + return hdnode_from_seed(seed, 64, curve, node); +} + +bool config_getLabel(char *dest, uint16_t dest_size) +{ + return config_get_string(KEY_LABEL, dest, dest_size); +} + +bool config_getLanguage(char *dest, uint16_t dest_size) +{ + return config_get_string(KEY_LANGUAGE, dest, dest_size); +} + +bool config_getHomescreen(uint8_t *dest, uint16_t dest_size) +{ + uint16_t len = 0; + secbool ret = storage_get(KEY_HOMESCREEN, dest, dest_size, &len); + if (sectrue != ret || len != HOMESCREEN_SIZE) { + return false; + } + return true; +} + +void config_setMnemonic(const char *mnemonic) +{ + if (mnemonic == NULL) { + return; + } + + if (sectrue != storage_set(KEY_MNEMONIC, mnemonic, strnlen(mnemonic, MAX_MNEMONIC_LEN))) { + return; + } + + StorageHDNode u2fNode; + memzero(&u2fNode, sizeof(u2fNode)); + config_compute_u2froot(mnemonic, &u2fNode); + storage_set(KEY_U2F_ROOT, &u2fNode, sizeof(u2fNode)); + memzero(&u2fNode, sizeof(u2fNode)); +} + +bool config_hasNode(void) +{ + return config_has_key(KEY_NODE); +} + +bool config_hasMnemonic(void) +{ + return config_has_key(KEY_MNEMONIC); +} + +bool config_getMnemonic(char *dest, uint16_t dest_size) +{ + return config_get_string(KEY_MNEMONIC, dest, dest_size); +} + +/* Check whether mnemonic matches storage. The mnemonic must be + * a null-terminated string. + */ +bool config_containsMnemonic(const char *mnemonic) +{ + uint16_t len = 0; + uint8_t stored_mnemonic[MAX_MNEMONIC_LEN + 1]; + if (sectrue != storage_get(KEY_MNEMONIC, stored_mnemonic, MAX_MNEMONIC_LEN, &len)) { + return false; + } + stored_mnemonic[len] = '\0'; + + /* The execution time of the following code only depends on the + * (public) input. This avoids timing attacks. + */ + char diff = 0; + uint32_t i = 0; + for (; mnemonic[i]; i++) { + diff |= (stored_mnemonic[i] - mnemonic[i]); + } + diff |= stored_mnemonic[i]; + memzero(stored_mnemonic, sizeof(stored_mnemonic)); + return diff == 0; +} + +/* Check whether pin matches storage. The pin must be + * a null-terminated string with at most 9 characters. + */ +bool config_containsPin(const char *pin) +{ + return sectrue == storage_unlock(pin_to_int(pin)); +} + +bool config_hasPin(void) +{ + return storage_has_pin(); +} + +bool config_changePin(const char *old_pin, const char *new_pin) +{ + uint32_t new_pin_int = pin_to_int(new_pin); + if (new_pin_int == 0) { + return false; + } + + if (sectrue == storage_change_pin(pin_to_int(old_pin), new_pin_int)) { + return true; + } + return false; +} + +void session_cachePassphrase(const char *passphrase) +{ + strlcpy(sessionPassphrase, passphrase, sizeof(sessionPassphrase)); + sessionPassphraseCached = true; +} + +bool session_isPassphraseCached(void) +{ + return sessionPassphraseCached; +} + +bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphrase) +{ + if (!passphrase && !sessionPassphraseCached) { + return false; + } else { + passphrase = sessionPassphrase; + } + if (!salt) { + // if salt is not provided fill the first half of the state with random data + random_buffer(state, 32); + } else { + // if salt is provided fill the first half of the state with salt + memcpy(state, salt, 32); + } + // state[0:32] = salt + // state[32:64] = HMAC(passphrase, salt || device_id) + HMAC_SHA256_CTX ctx; + hmac_sha256_Init(&ctx, (const uint8_t *)passphrase, strlen(passphrase)); + hmac_sha256_Update(&ctx, state, 32); + hmac_sha256_Update(&ctx, (const uint8_t *)config_uuid, sizeof(config_uuid)); + hmac_sha256_Final(&ctx, state + 32); + + memzero(&ctx, sizeof(ctx)); + + return true; +} + +bool session_isPinCached(void) +{ + return storage_is_unlocked(); +} + +bool config_isInitialized(void) +{ + return config_has_key(KEY_NODE) || config_has_key(KEY_MNEMONIC); +} + +bool config_isImported(void) +{ + return config_get_bool(KEY_IMPORTED); +} + +void config_setImported(bool imported) +{ + config_set_bool(KEY_IMPORTED, imported); +} + +bool config_needsBackup(void) +{ + return config_get_bool(KEY_NEEDS_BACKUP); +} + +void config_setNeedsBackup(bool needs_backup) +{ + config_set_bool(KEY_NEEDS_BACKUP, needs_backup); +} + +bool config_unfinishedBackup(void) +{ + return config_get_bool(KEY_UNFINISHED_BACKUP); +} + +void config_setUnfinishedBackup(bool unfinished_backup) +{ + config_set_bool(KEY_UNFINISHED_BACKUP, unfinished_backup); +} + +bool config_noBackup(void) +{ + return config_get_bool(KEY_NO_BACKUP); +} + +void config_setNoBackup(void) +{ + config_set_bool(KEY_NO_BACKUP, true); +} + +void config_applyFlags(uint32_t flags) +{ + uint32_t old_flags = config_get_uint32(KEY_FLAGS); + flags |= old_flags; + if (flags == old_flags) { + return; // no new flags + } + storage_set(KEY_FLAGS, &flags, sizeof(flags)); +} + +uint32_t config_getFlags(void) +{ + return config_get_uint32(KEY_FLAGS); +} + +uint32_t config_nextU2FCounter(void) +{ + // TODO Implement efficient version. + uint32_t counter = 0; + uint16_t len = 0; + storage_get(KEY_U2F_COUNTER, &counter, sizeof(counter), &len); + counter++; + storage_set(KEY_U2F_COUNTER, &counter, sizeof(counter)); + return counter; +} + +void config_setU2FCounter(uint32_t u2fcounter) +{ + storage_set(KEY_U2F_COUNTER, &u2fcounter, sizeof(u2fcounter)); +} + +uint32_t config_getAutoLockDelayMs() +{ + const uint32_t default_delay_ms = 10 * 60 * 1000U; // 10 minutes + uint32_t delay_ms = config_get_uint32(KEY_AUTO_LOCK_DELAY_MS); + return (delay_ms != 0) ? delay_ms : default_delay_ms; +} + +void config_setAutoLockDelayMs(uint32_t auto_lock_delay_ms) +{ + const uint32_t min_delay_ms = 10 * 1000U; // 10 seconds + auto_lock_delay_ms = MAX(auto_lock_delay_ms, min_delay_ms); + storage_set(KEY_AUTO_LOCK_DELAY_MS, &auto_lock_delay_ms, sizeof(auto_lock_delay_ms)); +} + +void config_wipe(void) +{ + storage_wipe(); + storage_unlock(PIN_EMPTY); + random_buffer((uint8_t *)config_uuid, sizeof(config_uuid)); + data2hex(config_uuid, sizeof(config_uuid), config_uuid_str); + storage_set(KEY_UUID, config_uuid, sizeof(config_uuid)); + storage_set(KEY_VERSION, &CONFIG_VERSION, sizeof(CONFIG_VERSION)); + session_clear(true); +} diff --git a/firmware/storage.h b/firmware/config.h similarity index 53% rename from firmware/storage.h rename to firmware/config.h index 3004e89901..8bde314da0 100644 --- a/firmware/storage.h +++ b/firmware/config.h @@ -17,8 +17,8 @@ * along with this library. If not, see . */ -#ifndef __STORAGE_H__ -#define __STORAGE_H__ +#ifndef __CONFIG_H__ +#define __CONFIG_H__ #include "bip32.h" #include "messages-management.pb.h" @@ -76,85 +76,82 @@ typedef struct _Storage { STORAGE_BOOL (no_backup) } Storage; -extern Storage storageUpdate; +extern Storage configUpdate; -void storage_init(void); -void storage_generate_uuid(void); -void storage_clear_update(void); -void storage_update(void); -void session_clear(bool clear_pin); +#define MAX_PIN_LEN 9 +#define MAX_LABEL_LEN 32 +#define MAX_LANGUAGE_LEN 16 +#define MAX_MNEMONIC_LEN 240 +#define HOMESCREEN_SIZE 1024 +#define UUID_SIZE 12 -void storage_loadDevice(const LoadDevice *msg); +void config_init(void); +void session_clear(bool lock); -const uint8_t *storage_getSeed(bool usePassphrase); +void config_loadDevice(const LoadDevice *msg); -bool storage_getU2FRoot(HDNode *node); -bool storage_getRootNode(HDNode *node, const char *curve, bool usePassphrase); +const uint8_t *config_getSeed(bool usePassphrase); -const char *storage_getLabel(void); -void storage_setLabel(const char *label); +bool config_getU2FRoot(HDNode *node); +bool config_getRootNode(HDNode *node, const char *curve, bool usePassphrase); -const char *storage_getLanguage(void); -void storage_setLanguage(const char *lang); +bool config_getLabel(char *dest, uint16_t dest_size); +void config_setLabel(const char *label); -void storage_setPassphraseProtection(bool passphrase_protection); -bool storage_hasPassphraseProtection(void); +bool config_getLanguage(char *dest, uint16_t dest_size); +void config_setLanguage(const char *lang); -const uint8_t *storage_getHomescreen(void); -void storage_setHomescreen(const uint8_t *data, uint32_t size); +void config_setPassphraseProtection(bool passphrase_protection); +bool config_hasPassphraseProtection(void); + +bool config_getHomescreen(uint8_t *dest, uint16_t dest_size); +void config_setHomescreen(const uint8_t *data, uint32_t size); void session_cachePassphrase(const char *passphrase); bool session_isPassphraseCached(void); bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphrase); -void storage_setMnemonic(const char *mnemonic); -bool storage_containsMnemonic(const char *mnemonic); -bool storage_hasMnemonic(void); -const char *storage_getMnemonic(void); +void config_setMnemonic(const char *mnemonic); +bool config_containsMnemonic(const char *mnemonic); +bool config_hasMnemonic(void); +bool config_getMnemonic(char *dest, uint16_t dest_size); -bool storage_hasNode(void); +bool config_hasNode(void); #if DEBUG_LINK -void storage_dumpNode(HDNodeType *node); +void config_dumpNode(HDNodeType *node); #endif -bool storage_containsPin(const char *pin); -bool storage_hasPin(void); -const char *storage_getPin(void); -void storage_setPin(const char *pin); -void session_cachePin(void); -void session_uncachePin(void); +bool config_containsPin(const char *pin); +bool config_hasPin(void); +void config_setPin(const char *pin); +bool config_changePin(const char *old_pin, const char *new_pin); bool session_isPinCached(void); -void storage_clearPinArea(void); -void storage_resetPinFails(uint32_t flash_pinfails); -bool storage_increasePinFails(uint32_t flash_pinfails); -uint32_t storage_getPinWait(uint32_t flash_pinfails); -uint32_t storage_getPinFailsOffset(void); -uint32_t storage_nextU2FCounter(void); -void storage_setU2FCounter(uint32_t u2fcounter); +uint32_t config_nextU2FCounter(void); +void config_setU2FCounter(uint32_t u2fcounter); -bool storage_isInitialized(void); +bool config_isInitialized(void); -bool storage_isImported(void); -void storage_setImported(bool imported); +bool config_isImported(void); +void config_setImported(bool imported); -bool storage_needsBackup(void); -void storage_setNeedsBackup(bool needs_backup); +bool config_needsBackup(void); +void config_setNeedsBackup(bool needs_backup); -bool storage_unfinishedBackup(void); -void storage_setUnfinishedBackup(bool unfinished_backup); +bool config_unfinishedBackup(void); +void config_setUnfinishedBackup(bool unfinished_backup); -bool storage_noBackup(void); -void storage_setNoBackup(void); +bool config_noBackup(void); +void config_setNoBackup(void); -void storage_applyFlags(uint32_t flags); -uint32_t storage_getFlags(void); +void config_applyFlags(uint32_t flags); +uint32_t config_getFlags(void); -uint32_t storage_getAutoLockDelayMs(void); -void storage_setAutoLockDelayMs(uint32_t auto_lock_delay_ms); +uint32_t config_getAutoLockDelayMs(void); +void config_setAutoLockDelayMs(uint32_t auto_lock_delay_ms); -void storage_wipe(void); +void config_wipe(void); -extern char storage_uuid_str[25]; +extern char config_uuid_str[2*UUID_SIZE + 1]; #endif diff --git a/firmware/fsm.c b/firmware/fsm.c index 50fd0fc45c..ce0732fa15 100644 --- a/firmware/fsm.c +++ b/firmware/fsm.c @@ -23,12 +23,11 @@ #include "fsm.h" #include "messages.h" #include "bip32.h" -#include "storage.h" +#include "config.h" #include "coins.h" #include "debug.h" #include "transaction.h" #include "rng.h" -#include "storage.h" #include "oled.h" #include "protect.h" #include "pinmatrix.h" @@ -70,13 +69,13 @@ static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned)); memzero(resp, sizeof(TYPE)); #define CHECK_INITIALIZED \ - if (!storage_isInitialized()) { \ + if (!config_isInitialized()) { \ fsm_sendFailure(FailureType_Failure_NotInitialized, NULL); \ return; \ } #define CHECK_NOT_INITIALIZED \ - if (storage_isInitialized()) { \ + if (config_isInitialized()) { \ fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Device is already initialized. Use Wipe first.")); \ return; \ } @@ -207,7 +206,7 @@ static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, if (fingerprint) { *fingerprint = 0; } - if (!storage_getRootNode(&node, curve, true)) { + if (!config_getRootNode(&node, curve, true)) { fsm_sendFailure(FailureType_Failure_NotInitialized, _("Device not initialized or passphrase request cancelled or unsupported curve")); layoutHome(); return 0; diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index 524d12b114..25fef38382 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -45,31 +45,31 @@ void fsm_msgGetFeatures(const GetFeatures *msg) resp->has_major_version = true; resp->major_version = VERSION_MAJOR; resp->has_minor_version = true; resp->minor_version = VERSION_MINOR; resp->has_patch_version = true; resp->patch_version = VERSION_PATCH; - resp->has_device_id = true; strlcpy(resp->device_id, storage_uuid_str, sizeof(resp->device_id)); - resp->has_pin_protection = true; resp->pin_protection = storage_hasPin(); - resp->has_passphrase_protection = true; resp->passphrase_protection = storage_hasPassphraseProtection(); + resp->has_device_id = true; strlcpy(resp->device_id, config_uuid_str, sizeof(resp->device_id)); + resp->has_pin_protection = true; resp->pin_protection = config_hasPin(); + resp->has_passphrase_protection = true; resp->passphrase_protection = config_hasPassphraseProtection(); #ifdef SCM_REVISION int len = sizeof(SCM_REVISION) - 1; resp->has_revision = true; memcpy(resp->revision.bytes, SCM_REVISION, len); resp->revision.size = len; #endif resp->has_bootloader_hash = true; resp->bootloader_hash.size = memory_bootloader_hash(resp->bootloader_hash.bytes); - if (storage_getLanguage()) { - resp->has_language = true; - strlcpy(resp->language, storage_getLanguage(), sizeof(resp->language)); - } - if (storage_getLabel()) { + + if (config_getLanguage(resp->language, sizeof(resp->language))) { + resp->has_language = true; + } + + if (config_getLabel(resp->label, sizeof(resp->label))) { resp->has_label = true; - strlcpy(resp->label, storage_getLabel(), sizeof(resp->label)); } - resp->has_initialized = true; resp->initialized = storage_isInitialized(); - resp->has_imported = true; resp->imported = storage_isImported(); + resp->has_initialized = true; resp->initialized = config_isInitialized(); + resp->has_imported = true; resp->imported = config_isImported(); resp->has_pin_cached = true; resp->pin_cached = session_isPinCached(); resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); - resp->has_needs_backup = true; resp->needs_backup = storage_needsBackup(); - resp->has_unfinished_backup = true; resp->unfinished_backup = storage_unfinishedBackup(); - resp->has_no_backup = true; resp->no_backup = storage_noBackup(); - resp->has_flags = true; resp->flags = storage_getFlags(); + resp->has_needs_backup = true; resp->needs_backup = config_needsBackup(); + resp->has_unfinished_backup = true; resp->unfinished_backup = config_unfinishedBackup(); + resp->has_no_backup = true; resp->no_backup = config_noBackup(); + resp->has_flags = true; resp->flags = config_getFlags(); resp->has_model = true; strlcpy(resp->model, "1", sizeof(resp->model)); msg_write(MessageType_MessageType_Features, resp); @@ -111,14 +111,14 @@ void fsm_msgChangePin(const ChangePin *msg) { bool removal = msg->has_remove && msg->remove; if (removal) { - if (storage_hasPin()) { + if (config_hasPin()) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("remove current PIN?"), NULL, NULL, NULL, NULL); } else { fsm_sendSuccess(_("PIN removed")); return; } } else { - if (storage_hasPin()) { + if (config_hasPin()) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change current PIN?"), NULL, NULL, NULL, NULL); } else { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("set new PIN?"), NULL, NULL, NULL, NULL); @@ -130,19 +130,14 @@ void fsm_msgChangePin(const ChangePin *msg) return; } - CHECK_PIN_UNCACHED + if (protectChangePin(removal)) { + if (removal) { + fsm_sendSuccess(_("PIN removed")); + } else { + fsm_sendSuccess(_("PIN changed")); + } + } - if (removal) { - storage_setPin(""); - storage_update(); - fsm_sendSuccess(_("PIN removed")); - } else { - if (protectChangePin()) { - fsm_sendSuccess(_("PIN changed")); - } else { - fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); - } - } layoutHome(); } @@ -155,7 +150,7 @@ void fsm_msgWipeDevice(const WipeDevice *msg) layoutHome(); return; } - storage_wipe(); + config_wipe(); // the following does not work on Mac anyway :-/ Linux/Windows are fine, so it is not needed // usbReconnect(); // force re-enumeration because of the serial number change fsm_sendSuccess(_("Device wiped")); @@ -202,7 +197,7 @@ void fsm_msgLoadDevice(const LoadDevice *msg) } } - storage_loadDevice(msg); + config_loadDevice(msg); fsm_sendSuccess(_("Device loaded")); layoutHome(); } @@ -242,7 +237,11 @@ void fsm_msgBackupDevice(const BackupDevice *msg) CHECK_PIN_UNCACHED (void)msg; - reset_backup(true); + char mnemonic[MAX_MNEMONIC_LEN + 1]; + if (config_getMnemonic(mnemonic, sizeof(mnemonic))) { + reset_backup(true, mnemonic); + } + memzero(mnemonic, sizeof(mnemonic)); } void fsm_msgCancel(const Cancel *msg) @@ -312,21 +311,20 @@ void fsm_msgApplySettings(const ApplySettings *msg) } if (msg->has_label) { - storage_setLabel(msg->label); + config_setLabel(msg->label); } if (msg->has_language) { - storage_setLanguage(msg->language); + config_setLanguage(msg->language); } if (msg->has_use_passphrase) { - storage_setPassphraseProtection(msg->use_passphrase); + config_setPassphraseProtection(msg->use_passphrase); } if (msg->has_homescreen) { - storage_setHomescreen(msg->homescreen.bytes, msg->homescreen.size); + config_setHomescreen(msg->homescreen.bytes, msg->homescreen.size); } if (msg->has_auto_lock_delay_ms) { - storage_setAutoLockDelayMs(msg->auto_lock_delay_ms); + config_setAutoLockDelayMs(msg->auto_lock_delay_ms); } - storage_update(); fsm_sendSuccess(_("Settings applied")); layoutHome(); } @@ -334,7 +332,7 @@ void fsm_msgApplySettings(const ApplySettings *msg) void fsm_msgApplyFlags(const ApplyFlags *msg) { if (msg->has_flags) { - storage_applyFlags(msg->flags); + config_applyFlags(msg->flags); } fsm_sendSuccess(_("Flags applied")); } @@ -376,8 +374,7 @@ void fsm_msgSetU2FCounter(const SetU2FCounter *msg) layoutHome(); return; } - storage_setU2FCounter(msg->u2f_counter); - storage_update(); + config_setU2FCounter(msg->u2f_counter); fsm_sendSuccess(_("U2F counter set")); layoutHome(); } diff --git a/firmware/fsm_msg_debug.h b/firmware/fsm_msg_debug.h index 2ac38d4727..788bb5fb8d 100644 --- a/firmware/fsm_msg_debug.h +++ b/firmware/fsm_msg_debug.h @@ -32,9 +32,9 @@ void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) resp.layout.size = OLED_BUFSIZE; memcpy(resp.layout.bytes, oledGetBuffer(), OLED_BUFSIZE); - if (storage_hasPin()) { + if (config_hasPin()) { resp.has_pin = true; - strlcpy(resp.pin, storage_getPin(), sizeof(resp.pin)); + strlcpy(resp.pin, "1", sizeof(resp.pin)); } resp.has_matrix = true; @@ -52,18 +52,18 @@ void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) resp.has_recovery_word_pos = true; resp.recovery_word_pos = recovery_get_word_pos(); - if (storage_hasMnemonic()) { + if (config_hasMnemonic()) { resp.has_mnemonic = true; - strlcpy(resp.mnemonic, storage_getMnemonic(), sizeof(resp.mnemonic)); + strlcpy(resp.mnemonic, config_getMnemonic(), sizeof(resp.mnemonic)); } - if (storage_hasNode()) { + if (config_hasNode()) { resp.has_node = true; - storage_dumpNode(&(resp.node)); + config_dumpNode(&(resp.node)); } resp.has_passphrase_protection = true; - resp.passphrase_protection = storage_hasPassphraseProtection(); + resp.passphrase_protection = config_hasPassphraseProtection(); msg_debug_write(MessageType_MessageType_DebugLinkState, &resp); } diff --git a/firmware/layout2.c b/firmware/layout2.c index 15bc7ef41c..98474de615 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -22,7 +22,7 @@ #include #include "layout2.h" -#include "storage.h" +#include "config.h" #include "oled.h" #include "bitmaps.h" #include "string.h" @@ -235,31 +235,36 @@ void layoutHome(void) layoutSwipe(); } layoutLast = layoutHome; - const char *label = storage_isInitialized() ? storage_getLabel() : _("Go to trezor.io/start"); - const uint8_t *homescreen = storage_getHomescreen(); - if (homescreen) { + + char label[MAX_LABEL_LEN + 1] = _("Go to trezor.io/start"); + if (config_isInitialized()) { + config_getLabel(label, sizeof(label)); + } + + uint8_t homescreen[HOMESCREEN_SIZE]; + if (config_getHomescreen(homescreen, sizeof(homescreen))) { BITMAP b; b.width = 128; b.height = 64; b.data = homescreen; oledDrawBitmap(0, 0, &b); } else { - if (label && strlen(label) > 0) { + if (label[0] != '\0') { oledDrawBitmap(44, 4, &bmp_logo48); oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 8, label, FONT_STANDARD); } else { oledDrawBitmap(40, 0, &bmp_logo64); } } - if (storage_noBackup()) { + if (config_noBackup()) { oledBox(0, 0, 127, 8, false); oledDrawStringCenter(OLED_WIDTH / 2, 0, "SEEDLESS", FONT_STANDARD); } else - if (storage_unfinishedBackup()) { + if (config_unfinishedBackup()) { oledBox(0, 0, 127, 8, false); oledDrawStringCenter(OLED_WIDTH / 2, 0, "BACKUP FAILED!", FONT_STANDARD); } else - if (storage_needsBackup()) { + if (config_needsBackup()) { oledBox(0, 0, 127, 8, false); oledDrawStringCenter(OLED_WIDTH / 2, 0, "NEEDS BACKUP!", FONT_STANDARD); } diff --git a/firmware/protect.c b/firmware/protect.c index 4a1d12c7ed..43acf4ea87 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -18,7 +18,7 @@ */ #include "protect.h" -#include "storage.h" +#include "config.h" #include "memory.h" #include "messages.h" #include "usb.h" @@ -147,102 +147,115 @@ const char *requestPin(PinMatrixRequestType type, const char *text) } } -static void protectCheckMaxTry(uint32_t wait) { - if (wait < (1 << MAX_WRONG_PINS)) - return; +void protectPinUiCallback(uint32_t wait, uint32_t progress) +{ + (void) progress; - storage_wipe(); - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Too many wrong PIN"), _("attempts. Storage has"), _("been wiped."), NULL, _("Please unplug"), _("the device.")); - for (;;) {} // loop forever + // Convert wait to secstr string. + char secstrbuf[] = _("________0 seconds"); + char *secstr = secstrbuf + 9; + uint32_t secs = wait; + while (secs > 0 && secstr >= secstrbuf) { + secstr--; + *secstr = (secs % 10) + '0'; + secs /= 10; + } + if (wait == 1) { + // Change "seconds" to "second". + secstrbuf[16] = 0; + } + layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Wrong PIN entered"), NULL, _("Please wait"), secstr, _("to continue ..."), NULL); + + /* TODO + if (msg_tiny_id == MessageType_MessageType_Initialize) { + protectAbortedByCancel = false; + protectAbortedByInitialize = true; + msg_tiny_id = 0xFFFF; + usbTiny(0); + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } + */ } bool protectPin(bool use_cached) { - if (!storage_hasPin() || (use_cached && session_isPinCached())) { + if (!config_hasPin() || (use_cached && session_isPinCached())) { return true; } - uint32_t fails = storage_getPinFailsOffset(); - uint32_t wait = storage_getPinWait(fails); - protectCheckMaxTry(wait); - usbTiny(1); - while (wait > 0) { - // convert wait to secstr string - char secstrbuf[20]; - strlcpy(secstrbuf, _("________0 seconds"), sizeof(secstrbuf)); - char *secstr = secstrbuf + 9; - uint32_t secs = wait; - while (secs > 0 && secstr >= secstrbuf) { - secstr--; - *secstr = (secs % 10) + '0'; - secs /= 10; - } - if (wait == 1) { - secstrbuf[16] = 0; - } - layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Wrong PIN entered"), NULL, _("Please wait"), secstr, _("to continue ..."), NULL); - // wait one second - usbSleep(1000); - if (msg_tiny_id == MessageType_MessageType_Initialize) { - protectAbortedByCancel = false; - protectAbortedByInitialize = true; - msg_tiny_id = 0xFFFF; - usbTiny(0); - fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); - return false; - } - wait--; - } - usbTiny(0); - const char *pin; - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); + + // TODO If maximum number of PIN attempts: + // error_shutdown("Too many wrong PIN", "attempts. Storage has", "been wiped.", NULL, "Please unplug", "the device."); + + const char *pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); if (!pin) { fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); return false; } - if (!storage_increasePinFails(fails)) { + + usbTiny(1); + bool ret = config_containsPin(pin); + usbTiny(0); + if (!ret) { fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); - return false; - } - if (storage_containsPin(pin)) { - session_cachePin(); - storage_resetPinFails(fails); - return true; - } else { - protectCheckMaxTry(storage_getPinWait(fails)); - fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); - return false; } + return ret; } -bool protectChangePin(void) +bool protectChangePin(bool removal) { - static CONFIDENTIAL char pin_compare[17]; + static CONFIDENTIAL char old_pin[MAX_PIN_LEN + 1] = ""; + static CONFIDENTIAL char new_pin[MAX_PIN_LEN + 1] = ""; + const char* pin = NULL; - const char *pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst, _("Please enter new PIN:")); + if (config_hasPin()) { + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); + if (pin == NULL) { + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } + strlcpy(old_pin, pin, sizeof(old_pin)); + } - if (!pin) { - return false; - } + if (!removal) { + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst, _("Please enter new PIN:")); + if (pin == NULL) { + memzero(old_pin, sizeof(old_pin)); + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } + strlcpy(new_pin, pin, sizeof(new_pin)); - strlcpy(pin_compare, pin, sizeof(pin_compare)); + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewSecond, _("Please re-enter new PIN:")); + if (pin == NULL) { + memzero(old_pin, sizeof(old_pin)); + memzero(new_pin, sizeof(new_pin)); + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewSecond, _("Please re-enter new PIN:")); + if (strncmp(new_pin, pin, sizeof(new_pin)) != 0) { + memzero(old_pin, sizeof(old_pin)); + memzero(new_pin, sizeof(new_pin)); + fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); + return false; + } + } - const bool result = pin && (strncmp(pin_compare, pin, sizeof(pin_compare)) == 0); - - if (result) { - storage_setPin(pin_compare); - storage_update(); - } - - memzero(pin_compare, sizeof(pin_compare)); - - return result; + usbTiny(1); + bool ret = config_changePin(old_pin, new_pin); + usbTiny(0); + memzero(old_pin, sizeof(old_pin)); + memzero(new_pin, sizeof(new_pin)); + if (ret == false) { + fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); + } + return ret; } bool protectPassphrase(void) { - if (!storage_hasPassphraseProtection() || session_isPassphraseCached()) { + if (!config_hasPassphraseProtection() || session_isPassphraseCached()) { return true; } diff --git a/firmware/protect.h b/firmware/protect.h index 8a3af45108..eaf1782762 100644 --- a/firmware/protect.h +++ b/firmware/protect.h @@ -24,8 +24,9 @@ #include "messages-common.pb.h" bool protectButton(ButtonRequestType type, bool confirm_only); +void protectPinUiCallback(uint32_t wait, uint32_t progress); bool protectPin(bool use_cached); -bool protectChangePin(void); +bool protectChangePin(bool removal); bool protectPassphrase(void); extern bool protectAbortedByCancel; diff --git a/firmware/recovery.c b/firmware/recovery.c index f67af3bcdc..d5c7acd088 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -21,7 +21,7 @@ #include #include "recovery.h" #include "fsm.h" -#include "storage.h" +#include "config.h" #include "layout2.h" #include "protect.h" #include "messages.h" @@ -44,7 +44,7 @@ static uint32_t word_count; */ static int awaiting_word = 0; -/* True if we should not write anything back to storage +/* True if we should not write anything back to config * (can be used for testing seed for correctness). */ static bool dry_run; @@ -163,18 +163,17 @@ static void recovery_done(void) { if (!enforce_wordlist || mnemonic_check(new_mnemonic)) { // New mnemonic is valid. if (!dry_run) { - // Update mnemonic on storage. - storage_setMnemonic(new_mnemonic); + // Update mnemonic on config. + config_setMnemonic(new_mnemonic); memzero(new_mnemonic, sizeof(new_mnemonic)); if (!enforce_wordlist) { - // not enforcing => mark storage as imported - storage_setImported(true); + // not enforcing => mark config as imported + config_setImported(true); } - storage_update(); fsm_sendSuccess(_("Device recovered")); } else { // Inform the user about new mnemonic correctness (as well as whether it is the same as the current one). - bool match = (storage_isInitialized() && storage_containsMnemonic(new_mnemonic)); + bool match = (config_isInitialized() && config_containsMnemonic(new_mnemonic)); memzero(new_mnemonic, sizeof(new_mnemonic)); if (match) { layoutDialog(&bmp_icon_ok, NULL, _("Confirm"), NULL, @@ -466,17 +465,15 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr } if (!dry_run) { - if (pin_protection && !protectChangePin()) { - fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); + if (pin_protection && !protectChangePin(false)) { layoutHome(); return; } - storage_setPassphraseProtection(passphrase_protection); - storage_setLanguage(language); - storage_setLabel(label); - storage_setU2FCounter(u2f_counter); - storage_update(); + config_setPassphraseProtection(passphrase_protection); + config_setLanguage(language); + config_setLabel(label); + config_setU2FCounter(u2f_counter); } if ((type & RecoveryDeviceType_RecoveryDeviceType_Matrix) != 0) { diff --git a/firmware/reset.c b/firmware/reset.c index dd7fe102bf..df6bc83612 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -18,7 +18,7 @@ */ #include "reset.h" -#include "storage.h" +#include "config.h" #include "rng.h" #include "sha2.h" #include "messages.h" @@ -75,17 +75,15 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect } } - if (pin_protection && !protectChangePin()) { - fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); + if (pin_protection && !protectChangePin(false)) { layoutHome(); return; } - storage_setPassphraseProtection(passphrase_protection); - storage_setLanguage(language); - storage_setLabel(label); - storage_setU2FCounter(u2f_counter); - storage_update(); + config_setPassphraseProtection(passphrase_protection); + config_setLanguage(language); + config_setLabel(label); + config_setU2FCounter(u2f_counter); EntropyRequest resp; memzero(&resp, sizeof(EntropyRequest)); @@ -104,45 +102,41 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) sha256_Update(&ctx, int_entropy, 32); sha256_Update(&ctx, ext_entropy, len); sha256_Final(&ctx, int_entropy); - if (no_backup) { - storage_setNoBackup(); - } else { - storage_setNeedsBackup(true); - } - storage_setMnemonic(mnemonic_from_data(int_entropy, strength / 8)); - mnemonic_clear(); + const char* mnemonic = mnemonic_from_data(int_entropy, strength / 8); memzero(int_entropy, 32); awaiting_entropy = false; + if (skip_backup || no_backup) { - storage_update(); + if (no_backup) { + config_setNoBackup(); + } else { + config_setNeedsBackup(true); + } + config_setMnemonic(mnemonic); fsm_sendSuccess(_("Device successfully initialized")); layoutHome(); } else { - reset_backup(false); + reset_backup(false, mnemonic); } - + mnemonic_clear(); } static char current_word[10]; // separated == true if called as a separate workflow via BackupMessage -void reset_backup(bool separated) +void reset_backup(bool separated, const char* mnemonic) { - if (!storage_needsBackup()) { + if (!config_needsBackup()) { fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); return; } - storage_setUnfinishedBackup(true); - storage_setNeedsBackup(false); - if (separated) { - storage_update(); + config_setUnfinishedBackup(true); + config_setNeedsBackup(false); } - const char *mnemonic = storage_getMnemonic(); - for (int pass = 0; pass < 2; pass++) { int i = 0, word_pos = 1; while (mnemonic[i] != 0) { @@ -159,7 +153,6 @@ void reset_backup(bool separated) layoutResetWord(current_word, pass, word_pos, mnemonic[i] == 0); if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) { if (!separated) { - storage_clear_update(); session_clear(true); } layoutHome(); @@ -170,12 +163,14 @@ void reset_backup(bool separated) } } - storage_setUnfinishedBackup(false); + config_setUnfinishedBackup(false); storage_update(); if (separated) { fsm_sendSuccess(_("Seed successfully backed up")); } else { + config_setNeedsBackup(false); + config_setMnemonic(mnemonic); fsm_sendSuccess(_("Device successfully initialized")); } layoutHome(); diff --git a/firmware/reset.h b/firmware/reset.h index f4638ac36f..3ceea7533b 100644 --- a/firmware/reset.h +++ b/firmware/reset.h @@ -25,7 +25,7 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, uint32_t u2f_counter, bool _skip_backup, bool _no_backup); void reset_entropy(const uint8_t *ext_entropy, uint32_t len); -void reset_backup(bool separated); +void reset_backup(bool separated, const char* mnemonic); uint32_t reset_get_int_entropy(uint8_t *entropy); const char *reset_get_word(void); diff --git a/firmware/stellar.c b/firmware/stellar.c index 662cd5922b..5ee64d8574 100644 --- a/firmware/stellar.c +++ b/firmware/stellar.c @@ -38,7 +38,7 @@ #include "bignum.h" #include "oled.h" #include "base32.h" -#include "storage.h" +#include "config.h" #include "fsm.h" #include "protect.h" #include "util.h" @@ -1514,7 +1514,7 @@ const HDNode *stellar_deriveNode(const uint32_t *address_n, size_t address_n_cou const char *curve = "ed25519"; // Device not initialized, passphrase request cancelled, or unsupported curve - if (!storage_getRootNode(&node, curve, true)) { + if (!config_getRootNode(&node, curve, true)) { return 0; } // Failed to derive private key diff --git a/firmware/storage.c b/firmware/storage.c deleted file mode 100644 index 6e7f66db32..0000000000 --- a/firmware/storage.c +++ /dev/null @@ -1,936 +0,0 @@ -/* - * This file is part of the TREZOR project, https://trezor.io/ - * - * Copyright (C) 2014 Pavol Rusnak - * - * This library is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This library 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see . - */ - -#include -#include - -#include - -#include "messages.pb.h" - -#include "trezor.h" -#include "sha2.h" -#include "aes/aes.h" -#include "pbkdf2.h" -#include "hmac.h" -#include "bip32.h" -#include "bip39.h" -#include "curves.h" -#include "util.h" -#include "memory.h" -#include "rng.h" -#include "storage.h" -#include "debug.h" -#include "protect.h" -#include "layout2.h" -#include "usb.h" -#include "gettext.h" -#include "u2f.h" -#include "memzero.h" -#include "supervise.h" - -/* magic constant to check validity of storage block */ -static const uint32_t storage_magic = 0x726f7473; // 'stor' as uint32_t - -static uint32_t storage_uuid[12 / sizeof(uint32_t)]; -_Static_assert(sizeof(storage_uuid) == 12, "storage_uuid has wrong size"); - -Storage CONFIDENTIAL storageUpdate __attribute__((aligned(4))); -_Static_assert((sizeof(storageUpdate) & 3) == 0, "storage unaligned"); - -#define FLASH_STORAGE (FLASH_STORAGE_START + sizeof(storage_magic) + sizeof(storage_uuid)) -#define storageRom ((const Storage *) FLASH_PTR(FLASH_STORAGE)) - -char storage_uuid_str[25]; - -/* - storage layout: - - offset | type/length | description ---------+--------------+------------------------------- - 0x0000 | 4 bytes | magic = 'stor' - 0x0004 | 12 bytes | uuid - 0x0010 | ? bytes | Storage structure ---------+--------------+------------------------------- - 0x4000 | 4 kbytes | area for pin failures - 0x5000 | 256 bytes | area for u2f counter updates - 0x5100 | 11.75 kbytes | reserved - -The area for pin failures looks like this: -0 ... 0 pinfail 0xffffffff .. 0xffffffff -The pinfail is a binary number of the form 1...10...0, -the number of zeros is the number of pin failures. -This layout is used because we can only clear bits without -erasing the flash. - -The area for u2f counter updates is just a sequence of zero-bits -followed by a sequence of one-bits. The bits in a byte are numbered -from LSB to MSB. The number of zero bits is the offset that should -be added to the storage u2f_counter to get the real counter value. - - */ - -#define FLASH_STORAGE_PINAREA (FLASH_META_START + 0x4000) -#define FLASH_STORAGE_PINAREA_LEN (0x1000) -#define FLASH_STORAGE_U2FAREA (FLASH_STORAGE_PINAREA + FLASH_STORAGE_PINAREA_LEN) -#define FLASH_STORAGE_U2FAREA_LEN (0x100) -#define FLASH_STORAGE_REALLEN (sizeof(storage_magic) + sizeof(storage_uuid) + sizeof(Storage)) - -#if !EMULATOR -// TODO: Fix this for emulator -_Static_assert(FLASH_STORAGE_START + FLASH_STORAGE_REALLEN <= FLASH_STORAGE_PINAREA, "Storage struct is too large for TREZOR flash"); -#endif - -/* Current u2f offset, i.e. u2f counter is - * storage.u2f_counter + storage_u2f_offset. - * This corresponds to the number of cleared bits in the U2FAREA. - */ -static uint32_t storage_u2f_offset; - -static bool sessionSeedCached, sessionSeedUsesPassphrase; - -static uint8_t CONFIDENTIAL sessionSeed[64]; - -static bool sessionPinCached = false; - -static bool sessionPassphraseCached = false; -static char CONFIDENTIAL sessionPassphrase[51]; - -#define STORAGE_VERSION 10 - -void storage_show_error(void) -{ - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Storage failure"), _("detected."), NULL, _("Please unplug"), _("the device."), NULL); - shutdown(); -} - -void storage_check_flash_errors(uint32_t status) -{ - // flash operation failed - if (status & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) { - storage_show_error(); - } -} - -bool storage_from_flash(void) -{ - storage_clear_update(); - if (memcmp(FLASH_PTR(FLASH_STORAGE_START), &storage_magic, sizeof(storage_magic)) != 0) { - // wrong magic - return false; - } - - const uint32_t version = storageRom->version; - // version 1: since 1.0.0 - // version 2: since 1.2.1 - // version 3: since 1.3.1 - // version 4: since 1.3.2 - // version 5: since 1.3.3 - // version 6: since 1.3.6 - // version 7: since 1.5.1 - // version 8: since 1.5.2 - // version 9: since 1.6.1 - // version 10: since 1.7.2 - if (version > STORAGE_VERSION) { - // downgrade -> clear storage - return false; - } - - // load uuid - memcpy(storage_uuid, FLASH_PTR(FLASH_STORAGE_START + sizeof(storage_magic)), sizeof(storage_uuid)); - data2hex(storage_uuid, sizeof(storage_uuid), storage_uuid_str); - -#define OLD_STORAGE_SIZE(last_member) (((offsetof(Storage, last_member) + pb_membersize(Storage, last_member)) + 3) & ~3) - - // copy storage - size_t old_storage_size = 0; - - if (version == 0) { - } else if (version <= 2) { - old_storage_size = OLD_STORAGE_SIZE(imported); - } else if (version <= 5) { - // added homescreen - old_storage_size = OLD_STORAGE_SIZE(homescreen); - } else if (version <= 7) { - // added u2fcounter - old_storage_size = OLD_STORAGE_SIZE(u2f_counter); - } else if (version <= 8) { - // added flags and needsBackup - old_storage_size = OLD_STORAGE_SIZE(flags); - } else if (version <= 9) { - // added u2froot, unfinished_backup and auto_lock_delay_ms - old_storage_size = OLD_STORAGE_SIZE(auto_lock_delay_ms); - } else if (version <= 10) { - // added no_backup - old_storage_size = OLD_STORAGE_SIZE(no_backup); - } - - // erase newly added fields - if (old_storage_size != sizeof(Storage)) { - svc_flash_unlock(); - svc_flash_program(FLASH_CR_PROGRAM_X32); - for (uint32_t offset = old_storage_size; offset < sizeof(Storage); offset += sizeof(uint32_t)) { - flash_write32(FLASH_STORAGE_START + sizeof(storage_magic) + sizeof(storage_uuid) + offset, 0); - } - storage_check_flash_errors(svc_flash_lock()); - } - - if (version <= 5) { - // convert PIN failure counter from version 5 format - uint32_t pinctr = storageRom->has_pin_failed_attempts ? storageRom->pin_failed_attempts : 0; - if (pinctr > 31) { - pinctr = 31; - } - svc_flash_unlock(); - // erase extra storage sector - svc_flash_erase_sector(FLASH_META_SECTOR_LAST); - svc_flash_program(FLASH_CR_PROGRAM_X32); - flash_write32(FLASH_STORAGE_PINAREA, 0xffffffff << pinctr); - // storageRom.has_pin_failed_attempts and storageRom.pin_failed_attempts - // are erased by storage_update below - storage_check_flash_errors(svc_flash_lock()); - } - const uint32_t *u2fptr = (const uint32_t*) FLASH_PTR(FLASH_STORAGE_U2FAREA); - while (*u2fptr == 0) { - u2fptr++; - } - storage_u2f_offset = 32 * (u2fptr - (const uint32_t*) FLASH_PTR(FLASH_STORAGE_U2FAREA)); - uint32_t u2fword = *u2fptr; - while ((u2fword & 1) == 0) { - storage_u2f_offset++; - u2fword >>= 1; - } - // force recomputing u2f root for storage version < 9. - // this is done by re-setting the mnemonic, which triggers the computation - if (version < 9) { - storageUpdate.has_mnemonic = storageRom->has_mnemonic; - strlcpy(storageUpdate.mnemonic, storageRom->mnemonic, sizeof(storageUpdate.mnemonic)); - } - // update storage version on flash - if (version != STORAGE_VERSION) { - storage_update(); - } - return true; -} - -void storage_init(void) -{ - if (!storage_from_flash()) { - storage_wipe(); - } -} - -void storage_generate_uuid(void) -{ - // set random uuid - random_buffer((uint8_t *)storage_uuid, sizeof(storage_uuid)); - data2hex(storage_uuid, sizeof(storage_uuid), storage_uuid_str); -} - -void session_clear(bool clear_pin) -{ - sessionSeedCached = false; - memzero(&sessionSeed, sizeof(sessionSeed)); - sessionPassphraseCached = false; - memzero(&sessionPassphrase, sizeof(sessionPassphrase)); - if (clear_pin) { - session_uncachePin(); - } -} - -static uint32_t storage_flash_words(uint32_t addr, const uint32_t *src, int nwords) { - for (int i = 0; i < nwords; i++) { - flash_write32(addr, *src++); - addr += sizeof(uint32_t); - } - return addr; -} - -static void get_u2froot_callback(uint32_t iter, uint32_t total) -{ - layoutProgress(_("Updating"), 1000 * iter / total); -} - -static void storage_compute_u2froot(const char* mnemonic, StorageHDNode *u2froot) { - static CONFIDENTIAL HDNode node; - char oldTiny = usbTiny(1); - mnemonic_to_seed(mnemonic, "", sessionSeed, get_u2froot_callback); // BIP-0039 - usbTiny(oldTiny); - hdnode_from_seed(sessionSeed, 64, NIST256P1_NAME, &node); - hdnode_private_ckd(&node, U2F_KEY_PATH); - u2froot->depth = node.depth; - u2froot->child_num = U2F_KEY_PATH; - u2froot->chain_code.size = sizeof(node.chain_code); - memcpy(u2froot->chain_code.bytes, node.chain_code, sizeof(node.chain_code)); - u2froot->has_private_key = true; - u2froot->private_key.size = sizeof(node.private_key); - memcpy(u2froot->private_key.bytes, node.private_key, sizeof(node.private_key)); - memzero(&node, sizeof(node)); - session_clear(false); // invalidate seed cache -} - -// if storage is filled in - update fields that has has_field set to true -// if storage is NULL - do not backup original content - essentialy a wipe -static void storage_commit_locked(bool update) -{ - if (update) { - if (storageUpdate.has_passphrase_protection) { - sessionSeedCached = false; - sessionPassphraseCached = false; - } - - storageUpdate.version = STORAGE_VERSION; - if (!storageUpdate.has_node && !storageUpdate.has_mnemonic) { - storageUpdate.has_node = storageRom->has_node; - memcpy(&storageUpdate.node, &storageRom->node, sizeof(StorageHDNode)); - storageUpdate.has_mnemonic = storageRom->has_mnemonic; - strlcpy(storageUpdate.mnemonic, storageRom->mnemonic, sizeof(storageUpdate.mnemonic)); - storageUpdate.has_u2froot = storageRom->has_u2froot; - memcpy(&storageUpdate.u2froot, &storageRom->u2froot, sizeof(StorageHDNode)); - } else if (storageUpdate.has_mnemonic) { - storageUpdate.has_u2froot = true; - storage_compute_u2froot(storageUpdate.mnemonic, &storageUpdate.u2froot); - } - if (!storageUpdate.has_passphrase_protection) { - storageUpdate.has_passphrase_protection = storageRom->has_passphrase_protection; - storageUpdate.passphrase_protection = storageRom->passphrase_protection; - } - if (!storageUpdate.has_pin) { - storageUpdate.has_pin = storageRom->has_pin; - strlcpy(storageUpdate.pin, storageRom->pin, sizeof(storageUpdate.pin)); - } else if (!storageUpdate.pin[0]) { - storageUpdate.has_pin = false; - } - if (!storageUpdate.has_language) { - storageUpdate.has_language = storageRom->has_language; - strlcpy(storageUpdate.language, storageRom->language, sizeof(storageUpdate.language)); - } - if (!storageUpdate.has_label) { - storageUpdate.has_label = storageRom->has_label; - strlcpy(storageUpdate.label, storageRom->label, sizeof(storageUpdate.label)); - } else if (!storageUpdate.label[0]) { - storageUpdate.has_label = false; - } - if (!storageUpdate.has_imported) { - storageUpdate.has_imported = storageRom->has_imported; - storageUpdate.imported = storageRom->imported; - } - if (!storageUpdate.has_homescreen) { - storageUpdate.has_homescreen = storageRom->has_homescreen; - memcpy(&storageUpdate.homescreen, &storageRom->homescreen, sizeof(storageUpdate.homescreen)); - } else if (storageUpdate.homescreen.size == 0) { - storageUpdate.has_homescreen = false; - } - if (!storageUpdate.has_u2f_counter) { - storageUpdate.has_u2f_counter = storageRom->has_u2f_counter; - storageUpdate.u2f_counter = storageRom->u2f_counter; - } - if (!storageUpdate.has_needs_backup) { - storageUpdate.has_needs_backup = storageRom->has_needs_backup; - storageUpdate.needs_backup = storageRom->needs_backup; - } - if (!storageUpdate.has_unfinished_backup) { - storageUpdate.has_unfinished_backup = storageRom->has_unfinished_backup; - storageUpdate.unfinished_backup = storageRom->unfinished_backup; - } - if (!storageUpdate.has_no_backup) { - storageUpdate.has_no_backup = storageRom->has_no_backup; - storageUpdate.no_backup = storageRom->no_backup; - } - if (!storageUpdate.has_flags) { - storageUpdate.has_flags = storageRom->has_flags; - storageUpdate.flags = storageRom->flags; - } - } - - // backup meta - uint32_t meta_backup[FLASH_META_DESC_LEN / sizeof(uint32_t)]; - memcpy(meta_backup, FLASH_PTR(FLASH_META_START), FLASH_META_DESC_LEN); - - // erase storage - svc_flash_erase_sector(FLASH_META_SECTOR_FIRST); - svc_flash_program(FLASH_CR_PROGRAM_X32); - - // copy meta back - uint32_t flash = FLASH_META_START; - flash = storage_flash_words(flash, meta_backup, FLASH_META_DESC_LEN / sizeof(uint32_t)); - - // copy storage - flash = storage_flash_words(flash, &storage_magic, sizeof(storage_magic) / sizeof(uint32_t)); - flash = storage_flash_words(flash, storage_uuid, sizeof(storage_uuid) / sizeof(uint32_t)); - - if (update) { - flash = storage_flash_words(flash, (const uint32_t *)&storageUpdate, sizeof(storageUpdate) / sizeof(uint32_t)); - } - storage_clear_update(); - - // fill remainder with zero for future extensions - while (flash < FLASH_STORAGE_PINAREA) { - flash_write32(flash, 0); - flash += sizeof(uint32_t); - } -} - -void storage_clear_update(void) -{ - memzero(&storageUpdate, sizeof(storageUpdate)); -} - -void storage_update(void) -{ - svc_flash_unlock(); - storage_commit_locked(true); - storage_check_flash_errors(svc_flash_lock()); -} - -static void storage_setNode(const HDNodeType *node) { - storageUpdate.node.depth = node->depth; - storageUpdate.node.fingerprint = node->fingerprint; - storageUpdate.node.child_num = node->child_num; - - storageUpdate.node.chain_code.size = 32; - memcpy(storageUpdate.node.chain_code.bytes, node->chain_code.bytes, 32); - - if (node->has_private_key) { - storageUpdate.node.has_private_key = true; - storageUpdate.node.private_key.size = 32; - memcpy(storageUpdate.node.private_key.bytes, node->private_key.bytes, 32); - } -} - -#if DEBUG_LINK -void storage_dumpNode(HDNodeType *node) { - node->depth = storageRom->node.depth; - node->fingerprint = storageRom->node.fingerprint; - node->child_num = storageRom->node.child_num; - - node->chain_code.size = 32; - memcpy(node->chain_code.bytes, storageRom->node.chain_code.bytes, 32); - - if (storageRom->node.has_private_key) { - node->has_private_key = true; - node->private_key.size = 32; - memcpy(node->private_key.bytes, storageRom->node.private_key.bytes, 32); - } -} -#endif - -void storage_loadDevice(const LoadDevice *msg) -{ - session_clear(true); - - storageUpdate.has_imported = true; - storageUpdate.imported = true; - - storage_setPin(msg->has_pin ? msg->pin : ""); - storage_setPassphraseProtection(msg->has_passphrase_protection && msg->passphrase_protection); - - if (msg->has_node) { - storageUpdate.has_node = true; - storageUpdate.has_mnemonic = false; - storage_setNode(&(msg->node)); - sessionSeedCached = false; - memzero(&sessionSeed, sizeof(sessionSeed)); - } else if (msg->has_mnemonic) { - storageUpdate.has_mnemonic = true; - storageUpdate.has_node = false; - strlcpy(storageUpdate.mnemonic, msg->mnemonic, sizeof(storageUpdate.mnemonic)); - sessionSeedCached = false; - memzero(&sessionSeed, sizeof(sessionSeed)); - } - - if (msg->has_language) { - storageUpdate.has_language = true; - strlcpy(storageUpdate.language, msg->language, sizeof(storageUpdate.language)); - } - - storage_setLabel(msg->has_label ? msg->label : ""); - - if (msg->has_u2f_counter) { - storageUpdate.has_u2f_counter = true; - storageUpdate.u2f_counter = msg->u2f_counter - storage_u2f_offset; - } - - storage_update(); -} - -void storage_setLabel(const char *label) -{ - storageUpdate.has_label = true; - if (!label) return; - strlcpy(storageUpdate.label, label, sizeof(storageUpdate.label)); -} - -void storage_setLanguage(const char *lang) -{ - if (!lang) return; - // sanity check - if (strcmp(lang, "english") == 0) { - storageUpdate.has_language = true; - strlcpy(storageUpdate.language, lang, sizeof(storageUpdate.language)); - } -} - -void storage_setPassphraseProtection(bool passphrase_protection) -{ - sessionSeedCached = false; - sessionPassphraseCached = false; - - storageUpdate.has_passphrase_protection = true; - storageUpdate.passphrase_protection = passphrase_protection; -} - -bool storage_hasPassphraseProtection(void) -{ - return storageRom->has_passphrase_protection && storageRom->passphrase_protection; -} - -void storage_setHomescreen(const uint8_t *data, uint32_t size) -{ - storageUpdate.has_homescreen = true; - if (data && size == 1024) { - memcpy(storageUpdate.homescreen.bytes, data, size); - storageUpdate.homescreen.size = size; - } else { - memzero(storageUpdate.homescreen.bytes, sizeof(storageUpdate.homescreen.bytes)); - storageUpdate.homescreen.size = 0; - } -} - -static void get_root_node_callback(uint32_t iter, uint32_t total) -{ - usbSleep(1); - layoutProgress(_("Waking up"), 1000 * iter / total); -} - -const uint8_t *storage_getSeed(bool usePassphrase) -{ - // root node is properly cached - if (usePassphrase == sessionSeedUsesPassphrase - && sessionSeedCached) { - return sessionSeed; - } - - // if storage has mnemonic, convert it to node and use it - if (storageRom->has_mnemonic) { - if (usePassphrase && !protectPassphrase()) { - return NULL; - } - // if storage was not imported (i.e. it was properly generated or recovered) - if (!storageRom->has_imported || !storageRom->imported) { - // test whether mnemonic is a valid BIP-0039 mnemonic - if (!mnemonic_check(storageRom->mnemonic)) { - // and if not then halt the device - storage_show_error(); - } - } - char oldTiny = usbTiny(1); - mnemonic_to_seed(storageRom->mnemonic, usePassphrase ? sessionPassphrase : "", sessionSeed, get_root_node_callback); // BIP-0039 - usbTiny(oldTiny); - sessionSeedCached = true; - sessionSeedUsesPassphrase = usePassphrase; - return sessionSeed; - } - - return NULL; -} - -static bool storage_loadNode(const StorageHDNode *node, const char *curve, HDNode *out) { - return hdnode_from_xprv(node->depth, node->child_num, node->chain_code.bytes, node->private_key.bytes, curve, out); -} - -bool storage_getU2FRoot(HDNode *node) -{ - return storageRom->has_u2froot && storage_loadNode(&storageRom->u2froot, NIST256P1_NAME, node); -} - -bool storage_getRootNode(HDNode *node, const char *curve, bool usePassphrase) -{ - // if storage has node, decrypt and use it - if (storageRom->has_node && strcmp(curve, SECP256K1_NAME) == 0) { - if (!protectPassphrase()) { - return false; - } - if (!storage_loadNode(&storageRom->node, curve, node)) { - return false; - } - if (storageRom->has_passphrase_protection && storageRom->passphrase_protection && sessionPassphraseCached && strlen(sessionPassphrase) > 0) { - // decrypt hd node - uint8_t secret[64]; - PBKDF2_HMAC_SHA512_CTX pctx; - char oldTiny = usbTiny(1); - pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), (const uint8_t *)"TREZORHD", 8, 1); - get_root_node_callback(0, BIP39_PBKDF2_ROUNDS); - for (int i = 0; i < 8; i++) { - pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 8); - get_root_node_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 8, BIP39_PBKDF2_ROUNDS); - } - pbkdf2_hmac_sha512_Final(&pctx, secret); - usbTiny(oldTiny); - aes_decrypt_ctx ctx; - aes_decrypt_key256(secret, &ctx); - aes_cbc_decrypt(node->chain_code, node->chain_code, 32, secret + 32, &ctx); - aes_cbc_decrypt(node->private_key, node->private_key, 32, secret + 32, &ctx); - } - return true; - } - - const uint8_t *seed = storage_getSeed(usePassphrase); - if (seed == NULL) { - return false; - } - - return hdnode_from_seed(seed, 64, curve, node); -} - -const char *storage_getLabel(void) -{ - return storageRom->has_label ? storageRom->label : 0; -} - -const char *storage_getLanguage(void) -{ - return storageRom->has_language ? storageRom->language : 0; -} - -const uint8_t *storage_getHomescreen(void) -{ - return (storageRom->has_homescreen && storageRom->homescreen.size == 1024) ? storageRom->homescreen.bytes : 0; -} - -void storage_setMnemonic(const char *mnemonic) -{ - storageUpdate.has_mnemonic = true; - strlcpy(storageUpdate.mnemonic, mnemonic, sizeof(storageUpdate.mnemonic)); -} - -bool storage_hasNode(void) -{ - return storageRom->has_node; -} - -bool storage_hasMnemonic(void) -{ - return storageRom->has_mnemonic; -} - -const char *storage_getMnemonic(void) -{ - return storageUpdate.has_mnemonic ? storageUpdate.mnemonic - : storageRom->has_mnemonic ? storageRom->mnemonic : 0; -} - -/* Check whether mnemonic matches storage. The mnemonic must be - * a null-terminated string. - */ -bool storage_containsMnemonic(const char *mnemonic) { - /* The execution time of the following code only depends on the - * (public) input. This avoids timing attacks. - */ - char diff = 0; - uint32_t i = 0; - for (; mnemonic[i]; i++) { - diff |= (storageRom->mnemonic[i] - mnemonic[i]); - } - diff |= storageRom->mnemonic[i]; - return diff == 0; -} - -/* Check whether pin matches storage. The pin must be - * a null-terminated string with at most 9 characters. - */ -bool storage_containsPin(const char *pin) -{ - /* The execution time of the following code only depends on the - * (public) input. This avoids timing attacks. - */ - char diff = 0; - uint32_t i = 0; - while (pin[i]) { - diff |= storageRom->pin[i] - pin[i]; - i++; - } - diff |= storageRom->pin[i]; - return diff == 0; -} - -bool storage_hasPin(void) -{ - return storageRom->has_pin && storageRom->pin[0] != 0; -} - -void storage_setPin(const char *pin) -{ - storageUpdate.has_pin = true; - strlcpy(storageUpdate.pin, pin, sizeof(storageUpdate.pin)); - session_cachePin(); -} - -const char *storage_getPin(void) -{ - return storageRom->has_pin ? storageRom->pin : 0; -} - -void session_cachePassphrase(const char *passphrase) -{ - strlcpy(sessionPassphrase, passphrase, sizeof(sessionPassphrase)); - sessionPassphraseCached = true; -} - -bool session_isPassphraseCached(void) -{ - return sessionPassphraseCached; -} - -bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphrase) -{ - if (!passphrase && !sessionPassphraseCached) { - return false; - } else { - passphrase = sessionPassphrase; - } - if (!salt) { - // if salt is not provided fill the first half of the state with random data - random_buffer(state, 32); - } else { - // if salt is provided fill the first half of the state with salt - memcpy(state, salt, 32); - } - // state[0:32] = salt - // state[32:64] = HMAC(passphrase, salt || device_id) - HMAC_SHA256_CTX ctx; - hmac_sha256_Init(&ctx, (const uint8_t *)passphrase, strlen(passphrase)); - hmac_sha256_Update(&ctx, state, 32); - hmac_sha256_Update(&ctx, (const uint8_t *)storage_uuid, sizeof(storage_uuid)); - hmac_sha256_Final(&ctx, state + 32); - - memzero(&ctx, sizeof(ctx)); - - return true; -} - -void session_cachePin(void) -{ - sessionPinCached = true; -} - -void session_uncachePin(void) -{ - sessionPinCached = false; -} - -bool session_isPinCached(void) -{ - return sessionPinCached; -} - -void storage_clearPinArea(void) -{ - svc_flash_unlock(); - svc_flash_erase_sector(FLASH_META_SECTOR_LAST); - storage_check_flash_errors(svc_flash_lock()); - storage_u2f_offset = 0; -} - -// called when u2f area or pin area overflows -static void storage_area_recycle(uint32_t new_pinfails) -{ - // first clear storage marker. In case of a failure below it is better - // to clear the storage than to allow restarting with zero PIN failures - svc_flash_program(FLASH_CR_PROGRAM_X32); - flash_write32(FLASH_STORAGE_START, 0); - if (*(const uint32_t *)FLASH_PTR(FLASH_STORAGE_START) != 0) { - storage_show_error(); - } - - // erase pinarea/u2f sector - svc_flash_erase_sector(FLASH_META_SECTOR_LAST); - flash_write32(FLASH_STORAGE_PINAREA, new_pinfails); - if (*(const volatile uint32_t *)FLASH_PTR(FLASH_STORAGE_PINAREA) != new_pinfails) { - storage_show_error(); - } - - // restore storage sector - storageUpdate.has_u2f_counter = true; - storageUpdate.u2f_counter += storage_u2f_offset; - storage_u2f_offset = 0; - storage_commit_locked(true); -} - -void storage_resetPinFails(uint32_t flash_pinfails) -{ - svc_flash_unlock(); - if (flash_pinfails + sizeof(uint32_t) - >= FLASH_STORAGE_PINAREA + FLASH_STORAGE_PINAREA_LEN) { - // recycle extra storage sector - storage_area_recycle(0xffffffff); - } else { - svc_flash_program(FLASH_CR_PROGRAM_X32); - flash_write32(flash_pinfails, 0); - } - storage_check_flash_errors(svc_flash_lock()); -} - -bool storage_increasePinFails(uint32_t flash_pinfails) -{ - uint32_t newctr = *(const uint32_t*)FLASH_PTR(flash_pinfails) << 1; - // counter already at maximum, we do not increase it any more - // return success so that a good pin is accepted - if (!newctr) - return true; - - svc_flash_unlock(); - svc_flash_program(FLASH_CR_PROGRAM_X32); - flash_write32(flash_pinfails, newctr); - storage_check_flash_errors(svc_flash_lock()); - - return *(const uint32_t*)FLASH_PTR(flash_pinfails) == newctr; -} - -uint32_t storage_getPinWait(uint32_t flash_pinfails) -{ - // The pin failure word is the inverted wait time in seconds. - // It's inverted because flash allows changing 1 to 0 but not vice versa. - return ~*(const uint32_t*)FLASH_PTR(flash_pinfails); -} - -uint32_t storage_getPinFailsOffset(void) -{ - uint32_t flash_pinfails = FLASH_STORAGE_PINAREA; - while (*(const uint32_t*)FLASH_PTR(flash_pinfails) == 0) - flash_pinfails += sizeof(uint32_t); - return flash_pinfails; -} - -bool storage_isInitialized(void) -{ - return storageRom->has_node || storageRom->has_mnemonic; -} - -bool storage_isImported(void) -{ - return storageRom->has_imported && storageRom->imported; -} - -void storage_setImported(bool imported) -{ - storageUpdate.has_imported = true; - storageUpdate.imported = imported; -} - -bool storage_needsBackup(void) -{ - return storageUpdate.has_needs_backup ? storageUpdate.needs_backup - : storageRom->has_needs_backup && storageRom->needs_backup; -} - -void storage_setNeedsBackup(bool needs_backup) -{ - storageUpdate.has_needs_backup = true; - storageUpdate.needs_backup = needs_backup; -} - -bool storage_unfinishedBackup(void) -{ - return storageUpdate.has_unfinished_backup ? storageUpdate.unfinished_backup - : storageRom->has_unfinished_backup && storageRom->unfinished_backup; -} - -void storage_setUnfinishedBackup(bool unfinished_backup) -{ - storageUpdate.has_unfinished_backup = true; - storageUpdate.unfinished_backup = unfinished_backup; -} - -bool storage_noBackup(void) -{ - return storageUpdate.has_no_backup ? storageUpdate.no_backup - : storageRom->has_no_backup && storageRom->no_backup; -} - -void storage_setNoBackup(void) -{ - storageUpdate.has_no_backup = true; - storageUpdate.no_backup = true; -} - -void storage_applyFlags(uint32_t flags) -{ - if ((storageRom->flags | flags) == storageRom->flags) { - return; // no new flags - } - storageUpdate.has_flags = true; - storageUpdate.flags |= flags; - storage_update(); -} - -uint32_t storage_getFlags(void) -{ - return storageRom->has_flags ? storageRom->flags : 0; -} - -uint32_t storage_nextU2FCounter(void) -{ - uint32_t flash_u2f_offset = FLASH_STORAGE_U2FAREA + - sizeof(uint32_t) * (storage_u2f_offset / 32); - uint32_t newval = 0xfffffffe << (storage_u2f_offset & 31); - - svc_flash_unlock(); - svc_flash_program(FLASH_CR_PROGRAM_X32); - flash_write32(flash_u2f_offset, newval); - storage_u2f_offset++; - if (storage_u2f_offset >= 8 * FLASH_STORAGE_U2FAREA_LEN) { - storage_area_recycle(*(const uint32_t*) - FLASH_PTR(storage_getPinFailsOffset())); - } - storage_check_flash_errors(svc_flash_lock()); - return storageRom->u2f_counter + storage_u2f_offset; -} - -void storage_setU2FCounter(uint32_t u2fcounter) -{ - storageUpdate.has_u2f_counter = true; - storageUpdate.u2f_counter = u2fcounter - storage_u2f_offset; -} - -uint32_t storage_getAutoLockDelayMs() -{ - const uint32_t default_delay_ms = 10 * 60 * 1000U; // 10 minutes - return storageRom->has_auto_lock_delay_ms ? storageRom->auto_lock_delay_ms : default_delay_ms; -} - -void storage_setAutoLockDelayMs(uint32_t auto_lock_delay_ms) -{ - const uint32_t min_delay_ms = 10 * 1000U; // 10 seconds - auto_lock_delay_ms = MAX(auto_lock_delay_ms, min_delay_ms); - storageUpdate.has_auto_lock_delay_ms = true; - storageUpdate.auto_lock_delay_ms = auto_lock_delay_ms; -} - -void storage_wipe(void) -{ - session_clear(true); - storage_generate_uuid(); - - svc_flash_unlock(); - storage_commit_locked(false); - storage_check_flash_errors(svc_flash_lock()); - - storage_clearPinArea(); -} diff --git a/firmware/trezor.c b/firmware/trezor.c index 4d256eaece..30a9e3746d 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -23,7 +23,7 @@ #include "util.h" #include "usb.h" #include "setup.h" -#include "storage.h" +#include "config.h" #include "layout.h" #include "layout2.h" #include "rng.h" @@ -76,7 +76,7 @@ void check_lock_screen(void) // if homescreen is shown for too long if (layoutLast == layoutHome) { - if ((timer_ms() - system_millis_lock_start) >= storage_getAutoLockDelayMs()) { + if ((timer_ms() - system_millis_lock_start) >= config_getAutoLockDelayMs()) { // lock the screen session_clear(true); layoutScreensaver(); @@ -108,13 +108,13 @@ int main(void) #if DEBUG_LINK oledSetDebugLink(1); - storage_wipe(); + config_wipe(); #endif oledDrawBitmap(40, 0, &bmp_logo64); oledRefresh(); - storage_init(); + config_init(); layoutHome(); usbInit(); for (;;) { diff --git a/firmware/u2f.c b/firmware/u2f.c index 456ca3f147..048b52a15f 100644 --- a/firmware/u2f.c +++ b/firmware/u2f.c @@ -21,7 +21,7 @@ #include #include "debug.h" -#include "storage.h" +#include "config.h" #include "bip32.h" #include "layout2.h" #include "usb.h" @@ -460,7 +460,7 @@ static void getReadableAppId(const uint8_t appid[U2F_APPID_SIZE], const char **a static const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count) { static CONFIDENTIAL HDNode node; - if (!storage_getU2FRoot(&node)) { + if (!config_getU2FRoot(&node)) { layoutHome(); debugLog(0, "", "ERR: Device not init"); return 0; @@ -546,7 +546,7 @@ void u2f_register(const APDU *a) static U2F_REGISTER_REQ last_req; const U2F_REGISTER_REQ *req = (U2F_REGISTER_REQ *)a->data; - if (!storage_isInitialized()) { + if (!config_isInitialized()) { send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); return; } @@ -654,7 +654,7 @@ void u2f_authenticate(const APDU *a) const U2F_AUTHENTICATE_REQ *req = (U2F_AUTHENTICATE_REQ *)a->data; static U2F_AUTHENTICATE_REQ last_req; - if (!storage_isInitialized()) { + if (!config_isInitialized()) { send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED); return; } @@ -727,7 +727,7 @@ void u2f_authenticate(const APDU *a) U2F_AUTHENTICATE_RESP *resp = (U2F_AUTHENTICATE_RESP *)&buf; - const uint32_t ctr = storage_nextU2FCounter(); + const uint32_t ctr = config_nextU2FCounter(); resp->flags = U2F_AUTH_FLAG_TUP; resp->ctr[0] = ctr >> 24 & 0xff; resp->ctr[1] = ctr >> 16 & 0xff; diff --git a/firmware/usb.c b/firmware/usb.c index a40ce122b2..9da00ea913 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -25,7 +25,7 @@ #include "debug.h" #include "messages.h" #include "u2f.h" -#include "storage.h" +#include "config.h" #include "util.h" #include "timer.h" @@ -56,7 +56,7 @@ #define USB_STRINGS \ X(MANUFACTURER, "SatoshiLabs") \ X(PRODUCT, "TREZOR") \ - X(SERIAL_NUMBER, storage_uuid_str) \ + X(SERIAL_NUMBER, config_uuid_str) \ X(INTERFACE_MAIN, "TREZOR Interface") \ X(INTERFACE_DEBUG, "TREZOR Debug Link Interface") \ X(INTERFACE_U2F, "TREZOR U2F Interface") \ diff --git a/flash.c b/flash.c new file mode 100644 index 0000000000..9b9482550b --- /dev/null +++ b/flash.c @@ -0,0 +1,137 @@ +/* + * 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 + +#include "common.h" +#include "flash.h" +#include "memory.h" +#include "supervise.h" + +static const uint32_t FLASH_SECTOR_TABLE[FLASH_SECTOR_COUNT + 1] = { + [ 0] = 0x08000000, // - 0x08003FFF | 16 KiB + [ 1] = 0x08004000, // - 0x08007FFF | 16 KiB + [ 2] = 0x08008000, // - 0x0800BFFF | 16 KiB + [ 3] = 0x0800C000, // - 0x0800FFFF | 16 KiB + [ 4] = 0x08010000, // - 0x0801FFFF | 64 KiB + [ 5] = 0x08020000, // - 0x0803FFFF | 128 KiB + [ 6] = 0x08040000, // - 0x0805FFFF | 128 KiB + [ 7] = 0x08060000, // - 0x0807FFFF | 128 KiB + [ 8] = 0x08080000, // - 0x0809FFFF | 128 KiB + [ 9] = 0x080A0000, // - 0x080BFFFF | 128 KiB + [10] = 0x080C0000, // - 0x080DFFFF | 128 KiB + [11] = 0x080E0000, // - 0x080FFFFF | 128 KiB + [12] = 0x08100000, // last element - not a valid sector +}; + +static secbool flash_check_success(uint32_t status) +{ + return (status & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) ? secfalse : sectrue; +} + +void flash_init(void) +{ +} + +secbool flash_unlock_write(void) +{ + svc_flash_unlock(); + return sectrue; +} + +secbool flash_lock_write(void) +{ + return flash_check_success(svc_flash_lock()); +} + +const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size) +{ + if (sector >= FLASH_SECTOR_COUNT) { + return NULL; + } + const uint32_t addr = FLASH_SECTOR_TABLE[sector] + offset; + const uint32_t next = FLASH_SECTOR_TABLE[sector + 1]; + if (addr + size > next) { + return NULL; + } + return (const void *)addr; +} + +secbool flash_erase(uint8_t sector) +{ + ensure(flash_unlock_write(), NULL); + svc_flash_erase_sector(sector); + ensure(flash_lock_write(), NULL); + + // Check whether the sector was really deleted (contains only 0xFF). + const uint32_t addr_start = FLASH_SECTOR_TABLE[sector], addr_end = FLASH_SECTOR_TABLE[sector + 1]; + for (uint32_t addr = addr_start; addr < addr_end; addr += 4) { + if (*((const uint32_t *)addr) != 0xFFFFFFFF) { + return secfalse; + } + } + return sectrue; +} + +secbool flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data) +{ + uint32_t address = (uint32_t)flash_get_address(sector, offset, 1); + if (address == 0) { + return secfalse; + } + + if ((*((uint8_t*)address) & data) != data) { + return secfalse; + } + + svc_flash_program(FLASH_CR_PROGRAM_X8); + flash_write8(address, data); + + if (*((uint8_t*)address) != data) { + return secfalse; + } + + return sectrue; +} + +secbool flash_write_word(uint8_t sector, uint32_t offset, uint32_t data) +{ + uint32_t address = (uint32_t)flash_get_address(sector, offset, 4); + if (address == 0) { + return secfalse; + } + + if (offset % 4 != 0) { + return secfalse; + } + + if ((*((uint32_t*)address) & data) != data) { + return secfalse; + } + + svc_flash_program(FLASH_CR_PROGRAM_X32); + flash_write32(address, data); + + if (*((uint32_t*)address) != data) { + return secfalse; + } + + return sectrue; +} diff --git a/flash.h b/flash.h new file mode 100644 index 0000000000..f67ea88239 --- /dev/null +++ b/flash.h @@ -0,0 +1,47 @@ +/* + * 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_FLASH_H +#define TREZORHAL_FLASH_H + +#include +#include +#include "secbool.h" + +#define FLASH_SECTOR_COUNT 24 + +// note: FLASH_SR_RDERR is STM32F42xxx and STM32F43xxx specific (STM32F427) (reference RM0090 section 3.7.5) +#ifndef STM32F427xx +#define FLASH_SR_RDERR 0 +#endif + +#define FLASH_STATUS_ALL_FLAGS (FLASH_SR_RDERR | FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR | FLASH_SR_WRPERR | FLASH_SR_SOP | FLASH_SR_EOP) + +void flash_init(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(uint8_t sector); +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); + +#endif // TREZORHAL_FLASH_H diff --git a/norcow_config.h b/norcow_config.h new file mode 100644 index 0000000000..ba57dfb4b2 --- /dev/null +++ b/norcow_config.h @@ -0,0 +1,39 @@ +/* + * 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 +#define NORCOW_SECTOR_SIZE (16*1024) +#define NORCOW_SECTORS {2, 3} + +/* + * The length of the sector header in bytes. The header is preserved between sector erasures. + */ +#define NORCOW_HEADER_LEN (0x100) + +/* + * Current storage version. + */ +#define NORCOW_VERSION ((uint32_t)0x00000001) + +#endif diff --git a/secbool.h b/secbool.h new file mode 100644 index 0000000000..76dfb38dc1 --- /dev/null +++ b/secbool.h @@ -0,0 +1,33 @@ +/* + * 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_SECBOOL_H +#define TREZORHAL_SECBOOL_H + +#include + +typedef uint32_t secbool; +#define sectrue 0xAAAAAAAAU +#define secfalse 0x00000000U + +#ifndef __wur +#define __wur __attribute__ ((warn_unused_result)) +#endif + +#endif diff --git a/vendor/trezor-storage b/vendor/trezor-storage new file mode 160000 index 0000000000..840f7461ee --- /dev/null +++ b/vendor/trezor-storage @@ -0,0 +1 @@ +Subproject commit 840f7461ee6f0c5cb0db75c46018615dbd5b0256 From d970597ddd41f41fa7cb0e68c76b260f2cf70e3e Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 31 Jan 2019 17:33:32 +0100 Subject: [PATCH 02/31] Fix emulator memory access. --- emulator/Makefile | 2 +- emulator/{flash.c => memory.c} | 0 flash.c | 24 ++++++++++++------------ flash.h | 6 +++--- 4 files changed, 16 insertions(+), 16 deletions(-) rename emulator/{flash.c => memory.c} (100%) diff --git a/emulator/Makefile b/emulator/Makefile index 1f2976dd01..1243a7fe54 100644 --- a/emulator/Makefile +++ b/emulator/Makefile @@ -3,7 +3,7 @@ EMULATOR := 1 OBJS += setup.o OBJS += buttons.o -OBJS += flash.o +OBJS += memory.o OBJS += oled.o OBJS += rng.o OBJS += timer.o diff --git a/emulator/flash.c b/emulator/memory.c similarity index 100% rename from emulator/flash.c rename to emulator/memory.c diff --git a/flash.c b/flash.c index 9b9482550b..998219c0b0 100644 --- a/flash.c +++ b/flash.c @@ -71,7 +71,7 @@ const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size) if (addr + size > next) { return NULL; } - return (const void *)addr; + return (const void *) FLASH_PTR(addr); } secbool flash_erase(uint8_t sector) @@ -83,7 +83,7 @@ secbool flash_erase(uint8_t sector) // Check whether the sector was really deleted (contains only 0xFF). const uint32_t addr_start = FLASH_SECTOR_TABLE[sector], addr_end = FLASH_SECTOR_TABLE[sector + 1]; for (uint32_t addr = addr_start; addr < addr_end; addr += 4) { - if (*((const uint32_t *)addr) != 0xFFFFFFFF) { + if (*((const uint32_t *)FLASH_PTR(addr)) != 0xFFFFFFFF) { return secfalse; } } @@ -92,19 +92,19 @@ secbool flash_erase(uint8_t sector) secbool flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data) { - uint32_t address = (uint32_t)flash_get_address(sector, offset, 1); - if (address == 0) { + uint8_t *address = (uint8_t *) flash_get_address(sector, offset, 1); + if (address == NULL) { return secfalse; } - if ((*((uint8_t*)address) & data) != data) { + if ((*address & data) != data) { return secfalse; } svc_flash_program(FLASH_CR_PROGRAM_X8); - flash_write8(address, data); + *(volatile uint8_t *) address = data; - if (*((uint8_t*)address) != data) { + if (*address != data) { return secfalse; } @@ -113,8 +113,8 @@ secbool flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data) secbool flash_write_word(uint8_t sector, uint32_t offset, uint32_t data) { - uint32_t address = (uint32_t)flash_get_address(sector, offset, 4); - if (address == 0) { + uint32_t *address = (uint32_t *) flash_get_address(sector, offset, 4); + if (address == NULL) { return secfalse; } @@ -122,14 +122,14 @@ secbool flash_write_word(uint8_t sector, uint32_t offset, uint32_t data) return secfalse; } - if ((*((uint32_t*)address) & data) != data) { + if ((*address & data) != data) { return secfalse; } svc_flash_program(FLASH_CR_PROGRAM_X32); - flash_write32(address, data); + *(volatile uint32_t *) address = data; - if (*((uint32_t*)address) != data) { + if (*address != data) { return secfalse; } diff --git a/flash.h b/flash.h index f67ea88239..24e1a3ad64 100644 --- a/flash.h +++ b/flash.h @@ -17,8 +17,8 @@ * along with this program. If not, see . */ -#ifndef TREZORHAL_FLASH_H -#define TREZORHAL_FLASH_H +#ifndef FLASH_H +#define FLASH_H #include #include @@ -44,4 +44,4 @@ secbool __wur flash_erase(uint8_t sector); 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); -#endif // TREZORHAL_FLASH_H +#endif // FLASH_H From b8932205cec416d6fa3ee2a1a5b911b47d0ed939 Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 31 Jan 2019 17:55:20 +0100 Subject: [PATCH 03/31] 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 840f7461ee..2888c11095 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 840f7461ee6f0c5cb0db75c46018615dbd5b0256 +Subproject commit 2888c1109563f32febb2eda9aed1130c07c6672b From 681137c2eff61fdce56b95714e5ca26b702d5a19 Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 31 Jan 2019 18:31:10 +0100 Subject: [PATCH 04/31] Unlock for testing. --- firmware/config.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 7799f1ff81..4af3e381af 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -342,6 +342,8 @@ void config_init(void) // TODO Add salt. storage_init(&protectPinUiCallback, (const uint8_t*)"", 0); + storage_unlock(1); + uint16_t len = 0; if (sectrue == storage_get(KEY_UUID, config_uuid, sizeof(config_uuid), &len) && len == sizeof(config_uuid)) { data2hex(config_uuid, sizeof(config_uuid), config_uuid_str); @@ -432,9 +434,6 @@ void config_dumpNode(HDNodeType *node) void config_loadDevice(const LoadDevice *msg) { - session_clear(true); - // TODO We can't set anything with the storage locked. Shouldn't we wipe? - config_set_bool(KEY_IMPORTED, true); config_setPassphraseProtection(msg->has_passphrase_protection && msg->passphrase_protection); @@ -459,6 +458,8 @@ void config_loadDevice(const LoadDevice *msg) if (msg->has_u2f_counter) { config_setU2FCounter(msg->u2f_counter); } + + session_clear(true); } void config_setLabel(const char *label) From 679174ea7a26243765b3e795088866183e965de7 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 1 Feb 2019 15:47:52 +0100 Subject: [PATCH 05/31] Fix separated backup. Fix forgotten config_getMnemonic() in DEBUG_LINK build. --- firmware/fsm_msg_debug.h | 2 +- firmware/reset.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/firmware/fsm_msg_debug.h b/firmware/fsm_msg_debug.h index 788bb5fb8d..307066a3d0 100644 --- a/firmware/fsm_msg_debug.h +++ b/firmware/fsm_msg_debug.h @@ -54,7 +54,7 @@ void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) if (config_hasMnemonic()) { resp.has_mnemonic = true; - strlcpy(resp.mnemonic, config_getMnemonic(), sizeof(resp.mnemonic)); + config_getMnemonic(resp.mnemonic, sizeof(resp.mnemonic)); } if (config_hasNode()) { diff --git a/firmware/reset.c b/firmware/reset.c index df6bc83612..0765fe595f 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -106,7 +106,6 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) memzero(int_entropy, 32); awaiting_entropy = false; - if (skip_backup || no_backup) { if (no_backup) { config_setNoBackup(); @@ -127,7 +126,7 @@ static char current_word[10]; // separated == true if called as a separate workflow via BackupMessage void reset_backup(bool separated, const char* mnemonic) { - if (!config_needsBackup()) { + if (separated && !config_needsBackup()) { fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); return; } From a7fcf9b036f648e30fcd71e88187e98986794458 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 1 Feb 2019 21:02:43 +0100 Subject: [PATCH 06/31] Fix key constant in config_setLanguage(). Update trezor-storage. --- firmware/config.c | 2 +- vendor/trezor-storage | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 4af3e381af..4259938a4b 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -481,7 +481,7 @@ void config_setLanguage(const char *lang) if (strcmp(lang, "english") != 0) { return; } - storage_set(KEY_LABEL, lang, strnlen(lang, MAX_LANGUAGE_LEN)); + storage_set(KEY_LANGUAGE, lang, strnlen(lang, MAX_LANGUAGE_LEN)); } void config_setPassphraseProtection(bool passphrase_protection) diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 2888c11095..8fc03a5a95 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 2888c1109563f32febb2eda9aed1130c07c6672b +Subproject commit 8fc03a5a95d3b75b29909a9f030fd74b294bf63b From d433401311807305fde7a1fdf4aa6787e99941c8 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 4 Feb 2019 17:57:53 +0100 Subject: [PATCH 07/31] 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 8fc03a5a95..6d9a4962a4 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 8fc03a5a95d3b75b29909a9f030fd74b294bf63b +Subproject commit 6d9a4962a427717100517d59a4dcc1012199f0f5 From 247337c63d587b7bc08490d0ce6227e0f8dc9539 Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 5 Feb 2019 11:57:19 +0100 Subject: [PATCH 08/31] Do not lock after wipe. Fix protectPinUiCallback() to correctly display '0 seconds' when wait is 0. --- firmware/config.c | 3 ++- firmware/protect.c | 4 ++-- firmware/recovery.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 4259938a4b..520effd2a0 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -342,6 +342,7 @@ void config_init(void) // TODO Add salt. storage_init(&protectPinUiCallback, (const uint8_t*)"", 0); + // TODO Remove storage_unlock(1); uint16_t len = 0; @@ -851,5 +852,5 @@ void config_wipe(void) data2hex(config_uuid, sizeof(config_uuid), config_uuid_str); storage_set(KEY_UUID, config_uuid, sizeof(config_uuid)); storage_set(KEY_VERSION, &CONFIG_VERSION, sizeof(CONFIG_VERSION)); - session_clear(true); + session_clear(false); } diff --git a/firmware/protect.c b/firmware/protect.c index 43acf4ea87..0d416c41ec 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -155,11 +155,11 @@ void protectPinUiCallback(uint32_t wait, uint32_t progress) char secstrbuf[] = _("________0 seconds"); char *secstr = secstrbuf + 9; uint32_t secs = wait; - while (secs > 0 && secstr >= secstrbuf) { + do { secstr--; *secstr = (secs % 10) + '0'; secs /= 10; - } + } while (secs > 0 && secstr >= secstrbuf); if (wait == 1) { // Change "seconds" to "second". secstrbuf[16] = 0; diff --git a/firmware/recovery.c b/firmware/recovery.c index d5c7acd088..c12dda3afa 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -153,7 +153,7 @@ static void recovery_request(void) { * Check mnemonic and send success/failure. */ static void recovery_done(void) { - char new_mnemonic[241] = {0}; // TODO: remove constant + char new_mnemonic[MAX_MNEMONIC_LEN + 1] = {0}; strlcpy(new_mnemonic, words[0], sizeof(new_mnemonic)); for (uint32_t i = 1; i < word_count; i++) { From e49e84ea5a95b4801b6211c37cbdabca09ff1019 Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 5 Feb 2019 20:40:58 +0100 Subject: [PATCH 09/31] Reorder storage keys in config.c to correspond with trezor-core and add KEY_INITIALIZED. Add CHECK_PIN to fsm_msgApplyFlags() and to other fsm_msg functions in order to unlock storage. Improve error handling in reset.c and recovery.c. --- firmware/config.c | 57 +++++++++++++++++++++++++-------------- firmware/config.h | 2 +- firmware/fsm_msg_common.h | 14 +++++++--- firmware/protect.c | 13 +++++---- firmware/recovery.c | 15 ++++++----- firmware/reset.c | 17 ++++++++---- 6 files changed, 77 insertions(+), 41 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 520effd2a0..980d130585 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -53,20 +53,21 @@ static const uint32_t CONFIG_MAGIC_V10 = 0x726f7473; // 'stor' as uint32_t static const uint16_t KEY_UUID = 0 | APP | FLAG_PUBLIC; // bytes(12) static const uint16_t KEY_VERSION = 1 | APP; // uint32 -static const uint16_t KEY_NODE = 2 | APP; // node -static const uint16_t KEY_MNEMONIC = 3 | APP; // string(241) -static const uint16_t KEY_PASSPHRASE_PROTECTION = 4 | APP; // bool -static const uint16_t KEY_LANGUAGE = 5 | APP | FLAG_PUBLIC; // string(17) -static const uint16_t KEY_LABEL = 6 | APP | FLAG_PUBLIC; // string(33) -static const uint16_t KEY_IMPORTED = 7 | APP; // bool -static const uint16_t KEY_HOMESCREEN = 8 | APP | FLAG_PUBLIC; // bytes(1024) +static const uint16_t KEY_MNEMONIC = 2 | APP; // string(241) +static const uint16_t KEY_LANGUAGE = 3 | APP | FLAG_PUBLIC; // string(17) +static const uint16_t KEY_LABEL = 4 | APP | FLAG_PUBLIC; // string(33) +static const uint16_t KEY_PASSPHRASE_PROTECTION = 5 | APP; // bool +static const uint16_t KEY_HOMESCREEN = 6 | APP | FLAG_PUBLIC; // bytes(1024) +static const uint16_t KEY_NEEDS_BACKUP = 7 | APP; // bool +static const uint16_t KEY_FLAGS = 8 | APP; // uint32 static const uint16_t KEY_U2F_COUNTER = 9 | APP | FLAG_PUBLIC; // uint32 -static const uint16_t KEY_NEEDS_BACKUP = 10 | APP; // bool -static const uint16_t KEY_FLAGS = 11 | APP; // uint32 -static const uint16_t KEY_U2F_ROOT = 12 | APP; // node -static const uint16_t KEY_UNFINISHED_BACKUP = 13 | APP; // bool -static const uint16_t KEY_AUTO_LOCK_DELAY_MS = 14 | APP; // uint32 -static const uint16_t KEY_NO_BACKUP = 15 | APP; // bool +static const uint16_t KEY_UNFINISHED_BACKUP = 11 | APP; // bool +static const uint16_t KEY_AUTO_LOCK_DELAY_MS = 12 | APP; // uint32 +static const uint16_t KEY_NO_BACKUP = 13 | APP; // bool +static const uint16_t KEY_INITIALIZED = 14 | APP | FLAG_PUBLIC; // uint32 +static const uint16_t KEY_NODE = 15 | APP; // node +static const uint16_t KEY_IMPORTED = 16 | APP; // bool +static const uint16_t KEY_U2F_ROOT = 17 | APP | FLAG_PUBLIC; // node // The PIN value corresponding to an empty PIN. static const uint32_t PIN_EMPTY = 1; @@ -290,7 +291,9 @@ static bool config_upgrade_v10(void) storage_set(KEY_UUID, config_uuid, sizeof(config_uuid)); storage_set(KEY_VERSION, &CONFIG_VERSION, sizeof(CONFIG_VERSION)); if (config.has_node) { - storage_set(KEY_NODE, &config.node, sizeof(config.node)); + if (sectrue == storage_set(KEY_NODE, &config.node, sizeof(config.node))) { + config_set_bool(KEY_INITIALIZED, true); + } } if (config.has_mnemonic) { config_setMnemonic(config.mnemonic); @@ -402,7 +405,9 @@ static void config_setNode(const HDNodeType *node) { storageHDNode.private_key.size = 32; memcpy(storageHDNode.private_key.bytes, node->private_key.bytes, 32); } - storage_set(KEY_NODE, &storageHDNode, sizeof(storageHDNode)); + if (sectrue == storage_set(KEY_NODE, &storageHDNode, sizeof(storageHDNode))) { + config_set_bool(KEY_INITIALIZED, true); + } } #if DEBUG_LINK @@ -628,21 +633,33 @@ bool config_getHomescreen(uint8_t *dest, uint16_t dest_size) return true; } -void config_setMnemonic(const char *mnemonic) +bool config_setMnemonic(const char *mnemonic) { if (mnemonic == NULL) { - return; + return false; } if (sectrue != storage_set(KEY_MNEMONIC, mnemonic, strnlen(mnemonic, MAX_MNEMONIC_LEN))) { - return; + return false; + } + + if (sectrue != config_set_bool(KEY_INITIALIZED, true)) { + storage_delete(KEY_MNEMONIC); + return false; } StorageHDNode u2fNode; memzero(&u2fNode, sizeof(u2fNode)); config_compute_u2froot(mnemonic, &u2fNode); - storage_set(KEY_U2F_ROOT, &u2fNode, sizeof(u2fNode)); + secbool ret = storage_set(KEY_U2F_ROOT, &u2fNode, sizeof(u2fNode)); memzero(&u2fNode, sizeof(u2fNode)); + + if (sectrue != ret) { + storage_delete(KEY_MNEMONIC); + storage_delete(KEY_INITIALIZED); + return false; + } + return true; } bool config_hasNode(void) @@ -756,7 +773,7 @@ bool session_isPinCached(void) bool config_isInitialized(void) { - return config_has_key(KEY_NODE) || config_has_key(KEY_MNEMONIC); + return config_get_bool(KEY_INITIALIZED); } bool config_isImported(void) diff --git a/firmware/config.h b/firmware/config.h index 8bde314da0..a44b6f29f3 100644 --- a/firmware/config.h +++ b/firmware/config.h @@ -111,7 +111,7 @@ void session_cachePassphrase(const char *passphrase); bool session_isPassphraseCached(void); bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphrase); -void config_setMnemonic(const char *mnemonic); +bool config_setMnemonic(const char *mnemonic); bool config_containsMnemonic(const char *mnemonic); bool config_hasMnemonic(void); bool config_getMnemonic(char *dest, uint16_t dest_size); diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index 25fef38382..93e2d8abcd 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -63,7 +63,7 @@ void fsm_msgGetFeatures(const GetFeatures *msg) } resp->has_initialized = true; resp->initialized = config_isInitialized(); - resp->has_imported = true; resp->imported = config_isImported(); + resp->has_imported = config_hasKey(KEY_IMPORTED); resp->imported = config_isImported(); resp->has_pin_cached = true; resp->pin_cached = session_isPinCached(); resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); resp->has_needs_backup = true; resp->needs_backup = config_needsBackup(); @@ -180,6 +180,8 @@ void fsm_msgGetEntropy(const GetEntropy *msg) void fsm_msgLoadDevice(const LoadDevice *msg) { + CHECK_PIN + CHECK_NOT_INITIALIZED layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("I take the risk"), NULL, _("Loading private seed"), _("is not recommended."), _("Continue only if you"), _("know what you are"), _("doing!"), NULL); @@ -204,6 +206,8 @@ void fsm_msgLoadDevice(const LoadDevice *msg) void fsm_msgResetDevice(const ResetDevice *msg) { + CHECK_PIN + CHECK_NOT_INITIALIZED CHECK_PARAM(!msg->has_strength || msg->strength == 128 || msg->strength == 192 || msg->strength == 256, _("Invalid seed strength")); @@ -331,6 +335,8 @@ void fsm_msgApplySettings(const ApplySettings *msg) void fsm_msgApplyFlags(const ApplyFlags *msg) { + CHECK_PIN + if (msg->has_flags) { config_applyFlags(msg->flags); } @@ -339,10 +345,10 @@ void fsm_msgApplyFlags(const ApplyFlags *msg) void fsm_msgRecoveryDevice(const RecoveryDevice *msg) { + CHECK_PIN + const bool dry_run = msg->has_dry_run ? msg->dry_run : false; - if (dry_run) { - CHECK_PIN - } else { + if (!dry_run) { CHECK_NOT_INITIALIZED } diff --git a/firmware/protect.c b/firmware/protect.c index 0d416c41ec..423c2fd985 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -180,17 +180,20 @@ void protectPinUiCallback(uint32_t wait, uint32_t progress) bool protectPin(bool use_cached) { - if (!config_hasPin() || (use_cached && session_isPinCached())) { + if (use_cached && session_isPinCached()) { return true; } // TODO If maximum number of PIN attempts: // error_shutdown("Too many wrong PIN", "attempts. Storage has", "been wiped.", NULL, "Please unplug", "the device."); - const char *pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); - if (!pin) { - fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); - return false; + const char *pin = ""; + if (config_hasPin()) { + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); + if (!pin) { + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } } usbTiny(1); diff --git a/firmware/recovery.c b/firmware/recovery.c index c12dda3afa..f7e5460fc8 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -164,13 +164,16 @@ static void recovery_done(void) { // New mnemonic is valid. if (!dry_run) { // Update mnemonic on config. - config_setMnemonic(new_mnemonic); - memzero(new_mnemonic, sizeof(new_mnemonic)); - if (!enforce_wordlist) { - // not enforcing => mark config as imported - config_setImported(true); + if (config_setMnemonic(new_mnemonic)) { + if (!enforce_wordlist) { + // not enforcing => mark config as imported + config_setImported(true); + } + fsm_sendSuccess(_("Device recovered")); + } else { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); } - fsm_sendSuccess(_("Device recovered")); + memzero(new_mnemonic, sizeof(new_mnemonic)); } else { // Inform the user about new mnemonic correctness (as well as whether it is the same as the current one). bool match = (config_isInitialized() && config_containsMnemonic(new_mnemonic)); diff --git a/firmware/reset.c b/firmware/reset.c index 0765fe595f..58479ab2ee 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -97,6 +97,8 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Reset mode")); return; } + awaiting_entropy = false; + SHA256_CTX ctx; sha256_Init(&ctx); sha256_Update(&ctx, int_entropy, 32); @@ -104,7 +106,6 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) sha256_Final(&ctx, int_entropy); const char* mnemonic = mnemonic_from_data(int_entropy, strength / 8); memzero(int_entropy, 32); - awaiting_entropy = false; if (skip_backup || no_backup) { if (no_backup) { @@ -112,8 +113,11 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) } else { config_setNeedsBackup(true); } - config_setMnemonic(mnemonic); - fsm_sendSuccess(_("Device successfully initialized")); + if (config_setMnemonic(mnemonic)) { + fsm_sendSuccess(_("Device successfully initialized")); + } else { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); + } layoutHome(); } else { reset_backup(false, mnemonic); @@ -169,8 +173,11 @@ void reset_backup(bool separated, const char* mnemonic) fsm_sendSuccess(_("Seed successfully backed up")); } else { config_setNeedsBackup(false); - config_setMnemonic(mnemonic); - fsm_sendSuccess(_("Device successfully initialized")); + if (config_setMnemonic(mnemonic)) { + fsm_sendSuccess(_("Device successfully initialized")); + } else { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); + } } layoutHome(); } From 03e9ea4f5cd7f216e2c27da3e3acb6b0947a2e35 Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 6 Feb 2019 19:01:06 +0100 Subject: [PATCH 10/31] Support interruption of the PIN wait dialog by Cancel and Initialize messages. --- firmware/config.c | 5 +---- firmware/protect.c | 15 ++++++++------- firmware/protect.h | 3 ++- vendor/trezor-storage | 2 +- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 980d130585..0ba7ab7816 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -345,9 +345,6 @@ void config_init(void) // TODO Add salt. storage_init(&protectPinUiCallback, (const uint8_t*)"", 0); - // TODO Remove - storage_unlock(1); - uint16_t len = 0; if (sectrue == storage_get(KEY_UUID, config_uuid, sizeof(config_uuid), &len) && len == sizeof(config_uuid)) { data2hex(config_uuid, sizeof(config_uuid), config_uuid_str); @@ -643,7 +640,7 @@ bool config_setMnemonic(const char *mnemonic) return false; } - if (sectrue != config_set_bool(KEY_INITIALIZED, true)) { + if (!config_set_bool(KEY_INITIALIZED, true)) { storage_delete(KEY_MNEMONIC); return false; } diff --git a/firmware/protect.c b/firmware/protect.c index 423c2fd985..e322c3fe6d 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -147,7 +147,7 @@ const char *requestPin(PinMatrixRequestType type, const char *text) } } -void protectPinUiCallback(uint32_t wait, uint32_t progress) +secbool protectPinUiCallback(uint32_t wait, uint32_t progress) { (void) progress; @@ -166,16 +166,17 @@ void protectPinUiCallback(uint32_t wait, uint32_t progress) } layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Wrong PIN entered"), NULL, _("Please wait"), secstr, _("to continue ..."), NULL); - /* TODO - if (msg_tiny_id == MessageType_MessageType_Initialize) { - protectAbortedByCancel = false; - protectAbortedByInitialize = true; + // Check for Cancel / Initialize. + protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); + protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); + if (protectAbortedByCancel || protectAbortedByInitialize) { msg_tiny_id = 0xFFFF; usbTiny(0); fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); - return false; + return sectrue; } - */ + + return secfalse; } bool protectPin(bool use_cached) diff --git a/firmware/protect.h b/firmware/protect.h index eaf1782762..bcabdac674 100644 --- a/firmware/protect.h +++ b/firmware/protect.h @@ -22,9 +22,10 @@ #include #include "messages-common.pb.h" +#include "secbool.h" bool protectButton(ButtonRequestType type, bool confirm_only); -void protectPinUiCallback(uint32_t wait, uint32_t progress); +secbool protectPinUiCallback(uint32_t wait, uint32_t progress); bool protectPin(bool use_cached); bool protectChangePin(bool removal); bool protectPassphrase(void); diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 6d9a4962a4..4429888b93 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 6d9a4962a427717100517d59a4dcc1012199f0f5 +Subproject commit 4429888b9325d200b699a90f7a0e1a07d08f09c0 From 5d4fb5556196c688713b49e69d9791a819663985 Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 6 Feb 2019 19:02:51 +0100 Subject: [PATCH 11/31] Improve __fatal_error() layout. --- common.c | 65 +++++++++++++++++++++++++++++++++++--------------------- common.h | 2 +- 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/common.c b/common.c index 5a8c0c1cc5..8489e02b8c 100644 --- a/common.c +++ b/common.c @@ -21,34 +21,51 @@ #include "common.h" #include "rng.h" #include "layout.h" +#include "oled.h" #include "firmware/usb.h" -void shutdown(void); - -void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line_num, const char *func) { - char line[4][128] = {{0}}; - int i = 0; - if (expr != NULL) { - snprintf(line[i], sizeof(line[0]), "Expr: %s", expr); - i++; - } - if (msg != NULL) { - snprintf(line[i], sizeof(line[0]), "Msg: %s", msg); - i++; - } - if (file != NULL) { - snprintf(line[i], sizeof(line[0]), "File: %s:%d", file, line_num); - i++; - } - if (func != NULL) { - snprintf(line[i], sizeof(line[0]), "Func: %s", func); - i++; - } - error_shutdown("FATAL ERROR:", NULL, line[0], line[1], line[2], line[3]); +static void __attribute__((noreturn)) shutdown(void) +{ + for (;;); } -void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) { - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, line2, line3, line4, line5, line6); +void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line_num, const char *func) { + const BITMAP *icon = &bmp_icon_error; + char line[128] = {0}; + int y = icon->height + 3; + oledClear(); + + oledDrawBitmap(0, 0, icon); + oledDrawStringCenter((icon->height - FONT_HEIGHT)/2 + 1, "FATAL ERROR", FONT_STANDARD); + + snprintf(line, sizeof(line), "Expr: %s", expr ? expr : "(null)"); + oledDrawString(0, y, line, FONT_STANDARD); + y += FONT_HEIGHT + 1; + + snprintf(line, sizeof(line), "Msg: %s", msg ? msg : "(null)"); + oledDrawString(0, y, line, FONT_STANDARD); + y += FONT_HEIGHT + 1; + + const char *label = "File: "; + snprintf(line, sizeof(line), "%s:%d", file ? file : "(null)", line_num); + oledDrawStringRight(OLED_WIDTH - 1, y, line, FONT_STANDARD); + oledBox(0, y, oledStringWidth(label, FONT_STANDARD), y + FONT_HEIGHT, false); + oledDrawString(0, y, label, FONT_STANDARD); + y += FONT_HEIGHT + 1; + + snprintf(line, sizeof(line), "Func: %s", func ? func : "(null)"); + oledDrawString(0, y, line, FONT_STANDARD); + y += FONT_HEIGHT + 1; + + oledDrawString(0, y, "Please unplug the device.", FONT_STANDARD); + oledRefresh(); + + shutdown(); + for (;;); +} + +void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4) { + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, line2, line3, line4, "Please unplug", "the device."); shutdown(); for (;;); } diff --git a/common.h b/common.h index b89547a378..9ac0a13c1c 100644 --- a/common.h +++ b/common.h @@ -34,7 +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, const char *line5, const char *line6); +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 7b0f5e031d7344ebc27448a58613e4ee745c4764 Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 7 Feb 2019 16:06:07 +0100 Subject: [PATCH 12/31] config: Change config_get*() functions to return status of the get operation. --- common.h | 10 ----- firmware/config.c | 84 ++++++++++++++++++++++----------------- firmware/config.h | 12 +++--- firmware/fsm_msg_common.h | 22 ++++------ firmware/fsm_msg_debug.h | 8 +--- firmware/layout2.c | 15 ++++--- firmware/protect.c | 4 +- firmware/reset.c | 12 +++--- norcow_config.h | 2 +- vendor/trezor-storage | 2 +- 10 files changed, 86 insertions(+), 85 deletions(-) diff --git a/common.h b/common.h index 9ac0a13c1c..9a40d000f7 100644 --- a/common.h +++ b/common.h @@ -23,16 +23,6 @@ #include #include "secbool.h" -#define XSTR(s) STR(s) -#define STR(s) #s - -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif -#ifndef MAX -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#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); diff --git a/firmware/config.c b/firmware/config.c index 0ba7ab7816..aeda096afb 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -23,6 +23,7 @@ #include "messages.pb.h" +#include "common.h" #include "trezor.h" #include "sha2.h" #include "aes/aes.h" @@ -147,12 +148,17 @@ static bool config_set_bool(uint16_t key, bool value) } } -static bool config_get_bool(uint16_t key) +static bool config_get_bool(uint16_t key, bool *value) { - uint8_t value = 0; + uint8_t val = 0; uint16_t len = 0; - secbool ret = storage_get(key, &value, sizeof(value), &len); - return (sectrue == ret && len == 1 && value == TRUE_BYTE); + if (sectrue == storage_get(key, &val, sizeof(val), &len) && len == sizeof(TRUE_BYTE)) { + *value = (val == TRUE_BYTE); + return true; + } else { + *value = false; + return false; + } } static bool config_has_key(uint16_t key) @@ -161,7 +167,8 @@ static bool config_has_key(uint16_t key) return sectrue == storage_get(key, NULL, 0, &len); } -static bool config_get_string(uint16_t key, char *dest, uint16_t dest_size) { +static bool config_get_string(uint16_t key, char *dest, uint16_t dest_size) +{ dest[0] = '\0'; uint16_t len = 0; if (sectrue != storage_get(key, dest, dest_size - 1, &len)) { @@ -171,19 +178,14 @@ static bool config_get_string(uint16_t key, char *dest, uint16_t dest_size) { return true; } -static uint32_t config_get_uint32(uint16_t key) { - uint32_t value = 0; - uint16_t len = 0; - if (sectrue != storage_get(key, &value, sizeof(value), &len) || len != sizeof(value)) { - return 0; - } - return value; -} - -void config_show_error(void) +static bool config_get_uint32(uint16_t key, uint32_t *value) { - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Storage failure"), _("detected."), NULL, _("Please unplug"), _("the device."), NULL); - shutdown(); + uint16_t len = 0; + if (sectrue != storage_get(key, value, sizeof(uint32_t), &len) || len != sizeof(uint32_t)) { + *value = 0; + return false; + } + return true; } static bool config_upgrade_v10(void) @@ -494,9 +496,9 @@ void config_setPassphraseProtection(bool passphrase_protection) config_set_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection); } -bool config_hasPassphraseProtection(void) +bool config_getPassphraseProtection(bool *passphrase_protection) { - return config_get_bool(KEY_PASSPHRASE_PROTECTION); + return config_get_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection); } void config_setHomescreen(const uint8_t *data, uint32_t size) @@ -530,11 +532,13 @@ const uint8_t *config_getSeed(bool usePassphrase) return NULL; } // if storage was not imported (i.e. it was properly generated or recovered) - if (!config_get_bool(KEY_IMPORTED)) { + bool imported = false; + config_get_bool(KEY_IMPORTED, &imported); + if (!imported) { // test whether mnemonic is a valid BIP-0039 mnemonic if (!mnemonic_check(mnemonic)) { // and if not then halt the device - config_show_error(); + error_shutdown(_("Storage failure"), _("detected."), NULL, NULL); } } char oldTiny = usbTiny(1); @@ -580,7 +584,9 @@ bool config_getRootNode(HDNode *node, const char *curve, bool usePassphrase) memzero(&storageHDNode, sizeof(storageHDNode)); return false; } - if (config_hasPassphraseProtection() && sessionPassphraseCached && sessionPassphrase[0] != '\0') { + bool passphrase_protection = false; + config_getPassphraseProtection(&passphrase_protection); + if (passphrase_protection && sessionPassphraseCached && sessionPassphrase[0] != '\0') { // decrypt hd node uint8_t secret[64]; PBKDF2_HMAC_SHA512_CTX pctx; @@ -770,12 +776,14 @@ bool session_isPinCached(void) bool config_isInitialized(void) { - return config_get_bool(KEY_INITIALIZED); + bool initialized = false; + config_get_bool(KEY_INITIALIZED, &initialized); + return initialized; } -bool config_isImported(void) +bool config_getImported(bool* imported) { - return config_get_bool(KEY_IMPORTED); + return config_get_bool(KEY_IMPORTED, imported); } void config_setImported(bool imported) @@ -783,9 +791,9 @@ void config_setImported(bool imported) config_set_bool(KEY_IMPORTED, imported); } -bool config_needsBackup(void) +bool config_getNeedsBackup(bool *needs_backup) { - return config_get_bool(KEY_NEEDS_BACKUP); + return config_get_bool(KEY_NEEDS_BACKUP, needs_backup); } void config_setNeedsBackup(bool needs_backup) @@ -793,9 +801,9 @@ void config_setNeedsBackup(bool needs_backup) config_set_bool(KEY_NEEDS_BACKUP, needs_backup); } -bool config_unfinishedBackup(void) +bool config_getUnfinishedBackup(bool *unfinished_backup) { - return config_get_bool(KEY_UNFINISHED_BACKUP); + return config_get_bool(KEY_UNFINISHED_BACKUP, unfinished_backup); } void config_setUnfinishedBackup(bool unfinished_backup) @@ -803,9 +811,9 @@ void config_setUnfinishedBackup(bool unfinished_backup) config_set_bool(KEY_UNFINISHED_BACKUP, unfinished_backup); } -bool config_noBackup(void) +bool config_getNoBackup(bool *no_backup) { - return config_get_bool(KEY_NO_BACKUP); + return config_get_bool(KEY_NO_BACKUP, no_backup); } void config_setNoBackup(void) @@ -815,7 +823,8 @@ void config_setNoBackup(void) void config_applyFlags(uint32_t flags) { - uint32_t old_flags = config_get_uint32(KEY_FLAGS); + uint32_t old_flags = 0; + config_get_uint32(KEY_FLAGS, &old_flags); flags |= old_flags; if (flags == old_flags) { return; // no new flags @@ -823,9 +832,9 @@ void config_applyFlags(uint32_t flags) storage_set(KEY_FLAGS, &flags, sizeof(flags)); } -uint32_t config_getFlags(void) +bool config_getFlags(uint32_t *flags) { - return config_get_uint32(KEY_FLAGS); + return config_get_uint32(KEY_FLAGS, flags); } uint32_t config_nextU2FCounter(void) @@ -847,8 +856,11 @@ void config_setU2FCounter(uint32_t u2fcounter) uint32_t config_getAutoLockDelayMs() { const uint32_t default_delay_ms = 10 * 60 * 1000U; // 10 minutes - uint32_t delay_ms = config_get_uint32(KEY_AUTO_LOCK_DELAY_MS); - return (delay_ms != 0) ? delay_ms : default_delay_ms; + uint32_t delay_ms = 0; + if (config_get_uint32(KEY_AUTO_LOCK_DELAY_MS, &delay_ms)) { + return delay_ms; + } + return default_delay_ms; } void config_setAutoLockDelayMs(uint32_t auto_lock_delay_ms) diff --git a/firmware/config.h b/firmware/config.h index a44b6f29f3..b015ca78f9 100644 --- a/firmware/config.h +++ b/firmware/config.h @@ -102,7 +102,7 @@ bool config_getLanguage(char *dest, uint16_t dest_size); void config_setLanguage(const char *lang); void config_setPassphraseProtection(bool passphrase_protection); -bool config_hasPassphraseProtection(void); +bool config_getPassphraseProtection(bool *passphrase_protection); bool config_getHomescreen(uint8_t *dest, uint16_t dest_size); void config_setHomescreen(const uint8_t *data, uint32_t size); @@ -132,20 +132,20 @@ void config_setU2FCounter(uint32_t u2fcounter); bool config_isInitialized(void); -bool config_isImported(void); +bool config_getImported(bool *imported); void config_setImported(bool imported); -bool config_needsBackup(void); +bool config_getNeedsBackup(bool *needs_backup); void config_setNeedsBackup(bool needs_backup); -bool config_unfinishedBackup(void); +bool config_getUnfinishedBackup(bool *unfinished_backup); void config_setUnfinishedBackup(bool unfinished_backup); -bool config_noBackup(void); +bool config_getNoBackup(bool *no_backup); void config_setNoBackup(void); void config_applyFlags(uint32_t flags); -uint32_t config_getFlags(void); +bool config_getFlags(uint32_t *flags); uint32_t config_getAutoLockDelayMs(void); void config_setAutoLockDelayMs(uint32_t auto_lock_delay_ms); diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index 93e2d8abcd..aa906423f7 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -47,29 +47,23 @@ void fsm_msgGetFeatures(const GetFeatures *msg) resp->has_patch_version = true; resp->patch_version = VERSION_PATCH; resp->has_device_id = true; strlcpy(resp->device_id, config_uuid_str, sizeof(resp->device_id)); resp->has_pin_protection = true; resp->pin_protection = config_hasPin(); - resp->has_passphrase_protection = true; resp->passphrase_protection = config_hasPassphraseProtection(); + resp->has_passphrase_protection = config_getPassphraseProtection(&(resp->passphrase_protection)); #ifdef SCM_REVISION int len = sizeof(SCM_REVISION) - 1; resp->has_revision = true; memcpy(resp->revision.bytes, SCM_REVISION, len); resp->revision.size = len; #endif resp->has_bootloader_hash = true; resp->bootloader_hash.size = memory_bootloader_hash(resp->bootloader_hash.bytes); - if (config_getLanguage(resp->language, sizeof(resp->language))) { - resp->has_language = true; - } - - if (config_getLabel(resp->label, sizeof(resp->label))) { - resp->has_label = true; - } - + resp->has_language = config_getLanguage(resp->language, sizeof(resp->language)); + resp->has_label = config_getLabel(resp->label, sizeof(resp->label)); resp->has_initialized = true; resp->initialized = config_isInitialized(); - resp->has_imported = config_hasKey(KEY_IMPORTED); resp->imported = config_isImported(); + resp->has_imported = config_getImported(&(resp->imported)); resp->has_pin_cached = true; resp->pin_cached = session_isPinCached(); resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); - resp->has_needs_backup = true; resp->needs_backup = config_needsBackup(); - resp->has_unfinished_backup = true; resp->unfinished_backup = config_unfinishedBackup(); - resp->has_no_backup = true; resp->no_backup = config_noBackup(); - resp->has_flags = true; resp->flags = config_getFlags(); + resp->has_needs_backup = config_getNeedsBackup(&(resp->needs_backup)); + resp->has_unfinished_backup = config_getUnfinishedBackup(&(resp->unfinished_backup)); + resp->has_no_backup = config_getNoBackup(&(resp->no_backup)); + resp->has_flags = config_getFlags(&(resp->flags)); resp->has_model = true; strlcpy(resp->model, "1", sizeof(resp->model)); msg_write(MessageType_MessageType_Features, resp); diff --git a/firmware/fsm_msg_debug.h b/firmware/fsm_msg_debug.h index 307066a3d0..0ef38279f6 100644 --- a/firmware/fsm_msg_debug.h +++ b/firmware/fsm_msg_debug.h @@ -52,18 +52,14 @@ void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) resp.has_recovery_word_pos = true; resp.recovery_word_pos = recovery_get_word_pos(); - if (config_hasMnemonic()) { - resp.has_mnemonic = true; - config_getMnemonic(resp.mnemonic, sizeof(resp.mnemonic)); - } + resp.has_mnemonic = config_getMnemonic(resp.mnemonic, sizeof(resp.mnemonic)); if (config_hasNode()) { resp.has_node = true; config_dumpNode(&(resp.node)); } - resp.has_passphrase_protection = true; - resp.passphrase_protection = config_hasPassphraseProtection(); + resp.has_passphrase_protection = config_getPassphraseProtection(&(resp.passphrase_protection)); msg_debug_write(MessageType_MessageType_DebugLinkState, &resp); } diff --git a/firmware/layout2.c b/firmware/layout2.c index 98474de615..36e02829f5 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -256,15 +256,20 @@ void layoutHome(void) oledDrawBitmap(40, 0, &bmp_logo64); } } - if (config_noBackup()) { + + bool no_backup = false; + bool unfinished_backup = false; + bool needs_backup = false; + config_getNoBackup(&no_backup); + config_getUnfinishedBackup(&unfinished_backup); + config_getNeedsBackup(&needs_backup); + if (no_backup) { oledBox(0, 0, 127, 8, false); oledDrawStringCenter(OLED_WIDTH / 2, 0, "SEEDLESS", FONT_STANDARD); - } else - if (config_unfinishedBackup()) { + } else if (unfinished_backup) { oledBox(0, 0, 127, 8, false); oledDrawStringCenter(OLED_WIDTH / 2, 0, "BACKUP FAILED!", FONT_STANDARD); - } else - if (config_needsBackup()) { + } else if (needs_backup) { oledBox(0, 0, 127, 8, false); oledDrawStringCenter(OLED_WIDTH / 2, 0, "NEEDS BACKUP!", FONT_STANDARD); } diff --git a/firmware/protect.c b/firmware/protect.c index e322c3fe6d..f048eb45a5 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -259,7 +259,9 @@ bool protectChangePin(bool removal) bool protectPassphrase(void) { - if (!config_hasPassphraseProtection() || session_isPassphraseCached()) { + bool passphrase_protection = false; + config_getPassphraseProtection(&passphrase_protection); + if (!passphrase_protection || session_isPassphraseCached()) { return true; } diff --git a/firmware/reset.c b/firmware/reset.c index 58479ab2ee..8fa650c443 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -130,12 +130,14 @@ static char current_word[10]; // separated == true if called as a separate workflow via BackupMessage void reset_backup(bool separated, const char* mnemonic) { - if (separated && !config_needsBackup()) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); - return; - } - if (separated) { + bool needs_backup = false; + config_getNeedsBackup(&needs_backup); + if (!needs_backup) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); + return; + } + config_setUnfinishedBackup(true); config_setNeedsBackup(false); } diff --git a/norcow_config.h b/norcow_config.h index ba57dfb4b2..d78f0749e5 100644 --- a/norcow_config.h +++ b/norcow_config.h @@ -29,7 +29,7 @@ /* * The length of the sector header in bytes. The header is preserved between sector erasures. */ -#define NORCOW_HEADER_LEN (0x100) +#define NORCOW_HEADER_LEN (0x000) /* * Current storage version. diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 4429888b93..0497802014 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 4429888b9325d200b699a90f7a0e1a07d08f09c0 +Subproject commit 0497802014edf03cdcce8cb70889d5a6e0bd3361 From c592a09459050281cbf9e30c57488cfed92b8f05 Mon Sep 17 00:00:00 2001 From: andrew Date: Thu, 7 Feb 2019 16:27:03 +0100 Subject: [PATCH 13/31] protect.c: Display 'Verifying PIN' instead of 'Wrong PIN entered' in the PIN_UI_WAIT_CALLBACK. --- firmware/protect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/protect.c b/firmware/protect.c index f048eb45a5..2f961bb8c0 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -164,7 +164,7 @@ secbool protectPinUiCallback(uint32_t wait, uint32_t progress) // Change "seconds" to "second". secstrbuf[16] = 0; } - layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Wrong PIN entered"), NULL, _("Please wait"), secstr, _("to continue ..."), NULL); + layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Verifying PIN"), NULL, _("Please wait"), secstr, _("to continue ..."), NULL); // Check for Cancel / Initialize. protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); From 66ffa4c7dc1010392fdeabee7c22234016e82abe Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 8 Feb 2019 00:46:16 +0100 Subject: [PATCH 14/31] config: Add hardware entropy to storage_init(). --- common.c | 2 ++ common.h | 3 +++ firmware/config.c | 6 ++---- firmware/trezor.c | 10 ++++++++++ 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/common.c b/common.c index 8489e02b8c..7d019ec310 100644 --- a/common.c +++ b/common.c @@ -24,6 +24,8 @@ #include "oled.h" #include "firmware/usb.h" +uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; + static void __attribute__((noreturn)) shutdown(void) { for (;;); diff --git a/common.h b/common.h index 9a40d000f7..912f73c54d 100644 --- a/common.h +++ b/common.h @@ -23,6 +23,9 @@ #include #include "secbool.h" +#define HW_ENTROPY_LEN 12 +extern uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; + 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); diff --git a/firmware/config.c b/firmware/config.c index aeda096afb..af55fccf15 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -279,8 +279,7 @@ static bool config_upgrade_v10(void) } } - // TODO Add salt. - storage_init(NULL, (const uint8_t*)"", 0); + storage_init(NULL, HW_ENTROPY_DATA, HW_ENTROPY_LEN); storage_unlock(PIN_EMPTY); if (config.has_pin) { storage_change_pin(PIN_EMPTY, pin_to_int(config.pin)); @@ -344,8 +343,7 @@ void config_init(void) { config_upgrade_v10(); - // TODO Add salt. - storage_init(&protectPinUiCallback, (const uint8_t*)"", 0); + storage_init(&protectPinUiCallback, HW_ENTROPY_DATA, HW_ENTROPY_LEN); uint16_t len = 0; if (sectrue == storage_get(KEY_UUID, config_uuid, sizeof(config_uuid), &len) && len == sizeof(config_uuid)) { diff --git a/firmware/trezor.c b/firmware/trezor.c index 30a9e3746d..fd59578025 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -17,6 +17,7 @@ * along with this library. If not, see . */ +#include "common.h" #include "trezor.h" #include "oled.h" #include "bitmaps.h" @@ -31,6 +32,8 @@ #include "buttons.h" #include "gettext.h" #include "bl_check.h" +#include "memzero.h" +#include /* Screen timeout */ uint32_t system_millis_lock_start; @@ -86,6 +89,13 @@ void check_lock_screen(void) int main(void) { +#if EMULATOR + memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); + HW_ENTROPY_DATA[0] = 1; +#else + desig_get_unique_id((uint32_t*)HW_ENTROPY_DATA); +#endif + #ifndef APPVER setup(); __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks From ae48b528a9497f6b5e877720ae5f68438bd1dfaf Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 8 Feb 2019 16:08:55 +0100 Subject: [PATCH 15/31] config: Rename session_isPinCached() to session_isUnlocked(). Change GetFeatures to always return pin_cached=false if PIN is not set, in order to maintain the same behavior as before. --- firmware/config.c | 2 +- firmware/config.h | 2 +- firmware/fsm_msg_common.h | 2 +- firmware/protect.c | 5 +---- firmware/trezor.c | 1 - 5 files changed, 4 insertions(+), 8 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index af55fccf15..8e52a29183 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -767,7 +767,7 @@ bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphras return true; } -bool session_isPinCached(void) +bool session_isUnlocked(void) { return storage_is_unlocked(); } diff --git a/firmware/config.h b/firmware/config.h index b015ca78f9..df7bd58f55 100644 --- a/firmware/config.h +++ b/firmware/config.h @@ -125,7 +125,7 @@ bool config_containsPin(const char *pin); bool config_hasPin(void); void config_setPin(const char *pin); bool config_changePin(const char *old_pin, const char *new_pin); -bool session_isPinCached(void); +bool session_isUnlocked(void); uint32_t config_nextU2FCounter(void); void config_setU2FCounter(uint32_t u2fcounter); diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index aa906423f7..9cafd4d302 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -58,7 +58,7 @@ void fsm_msgGetFeatures(const GetFeatures *msg) resp->has_label = config_getLabel(resp->label, sizeof(resp->label)); resp->has_initialized = true; resp->initialized = config_isInitialized(); resp->has_imported = config_getImported(&(resp->imported)); - resp->has_pin_cached = true; resp->pin_cached = session_isPinCached(); + resp->has_pin_cached = true; resp->pin_cached = session_isUnlocked() && config_hasPin(); resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); resp->has_needs_backup = config_getNeedsBackup(&(resp->needs_backup)); resp->has_unfinished_backup = config_getUnfinishedBackup(&(resp->unfinished_backup)); diff --git a/firmware/protect.c b/firmware/protect.c index 2f961bb8c0..796997d1fc 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -181,13 +181,10 @@ secbool protectPinUiCallback(uint32_t wait, uint32_t progress) bool protectPin(bool use_cached) { - if (use_cached && session_isPinCached()) { + if (use_cached && session_isUnlocked()) { return true; } - // TODO If maximum number of PIN attempts: - // error_shutdown("Too many wrong PIN", "attempts. Storage has", "been wiped.", NULL, "Please unplug", "the device."); - const char *pin = ""; if (config_hasPin()) { pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); diff --git a/firmware/trezor.c b/firmware/trezor.c index fd59578025..50b7b60eed 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -91,7 +91,6 @@ int main(void) { #if EMULATOR memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); - HW_ENTROPY_DATA[0] = 1; #else desig_get_unique_id((uint32_t*)HW_ENTROPY_DATA); #endif From 05f3b74b65e8605c8d704f284d4430a86fc0251e Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 8 Feb 2019 16:40:24 +0100 Subject: [PATCH 16/31] Fix rebase. --- firmware/reset.c | 1 - 1 file changed, 1 deletion(-) diff --git a/firmware/reset.c b/firmware/reset.c index 8fa650c443..9813c0969f 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -169,7 +169,6 @@ void reset_backup(bool separated, const char* mnemonic) } config_setUnfinishedBackup(false); - storage_update(); if (separated) { fsm_sendSuccess(_("Seed successfully backed up")); From 3c05a2da12e4fc7115c6a3e38cfc00cf4f38281c Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 8 Feb 2019 16:56:36 +0100 Subject: [PATCH 17/31] Fix rebase. --- common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.c b/common.c index 7d019ec310..7d1cfdd7af 100644 --- a/common.c +++ b/common.c @@ -38,7 +38,7 @@ void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, oledClear(); oledDrawBitmap(0, 0, icon); - oledDrawStringCenter((icon->height - FONT_HEIGHT)/2 + 1, "FATAL ERROR", FONT_STANDARD); + oledDrawStringCenter(OLED_WIDTH / 2, (icon->height - FONT_HEIGHT)/2 + 1, "FATAL ERROR", FONT_STANDARD); snprintf(line, sizeof(line), "Expr: %s", expr ? expr : "(null)"); oledDrawString(0, y, line, FONT_STANDARD); From faa0664b625cf75e99bcc4e070be5f4d3525a3fe Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 8 Feb 2019 20:56:39 +0100 Subject: [PATCH 18/31] config: Use efficient implementation of U2F counter from trezor-storage. --- firmware/config.c | 15 ++++++--------- vendor/trezor-storage | 2 +- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 8e52a29183..d8a28ccfc0 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -51,6 +51,7 @@ static const uint32_t CONFIG_MAGIC_V10 = 0x726f7473; // 'stor' as uint32_t #define APP 0x0100 #define FLAG_PUBLIC 0x8000 +#define FLAGS_WRITE 0xC000 static const uint16_t KEY_UUID = 0 | APP | FLAG_PUBLIC; // bytes(12) static const uint16_t KEY_VERSION = 1 | APP; // uint32 @@ -61,7 +62,7 @@ static const uint16_t KEY_PASSPHRASE_PROTECTION = 5 | APP; // boo static const uint16_t KEY_HOMESCREEN = 6 | APP | FLAG_PUBLIC; // bytes(1024) static const uint16_t KEY_NEEDS_BACKUP = 7 | APP; // bool static const uint16_t KEY_FLAGS = 8 | APP; // uint32 -static const uint16_t KEY_U2F_COUNTER = 9 | APP | FLAG_PUBLIC; // uint32 +static const uint16_t KEY_U2F_COUNTER = 9 | APP | FLAGS_WRITE; // uint32 static const uint16_t KEY_UNFINISHED_BACKUP = 11 | APP; // bool static const uint16_t KEY_AUTO_LOCK_DELAY_MS = 12 | APP; // uint32 static const uint16_t KEY_NO_BACKUP = 13 | APP; // bool @@ -837,18 +838,14 @@ bool config_getFlags(uint32_t *flags) uint32_t config_nextU2FCounter(void) { - // TODO Implement efficient version. - uint32_t counter = 0; - uint16_t len = 0; - storage_get(KEY_U2F_COUNTER, &counter, sizeof(counter), &len); - counter++; - storage_set(KEY_U2F_COUNTER, &counter, sizeof(counter)); - return counter; + uint32_t u2fcounter = 0; + storage_next_counter(KEY_U2F_COUNTER, &u2fcounter); + return u2fcounter; } void config_setU2FCounter(uint32_t u2fcounter) { - storage_set(KEY_U2F_COUNTER, &u2fcounter, sizeof(u2fcounter)); + storage_set_counter(KEY_U2F_COUNTER, u2fcounter); } uint32_t config_getAutoLockDelayMs() diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 0497802014..5c2765740d 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 0497802014edf03cdcce8cb70889d5a6e0bd3361 +Subproject commit 5c2765740db064c99fe54cbae79f74a3d767973c From 2f9010824da41ce01d7dd1b514acd865fbd90add Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 11 Feb 2019 12:51:51 +0100 Subject: [PATCH 19/31] config: Erase HW_ENTROPY_DATA when no longer needed. --- firmware/config.c | 1 + 1 file changed, 1 insertion(+) diff --git a/firmware/config.c b/firmware/config.c index d8a28ccfc0..71319b81ac 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -345,6 +345,7 @@ void config_init(void) config_upgrade_v10(); storage_init(&protectPinUiCallback, HW_ENTROPY_DATA, HW_ENTROPY_LEN); + memzero(HW_ENTROPY_DATA, sizeof(HW_ENTROPY_DATA)); uint16_t len = 0; if (sectrue == storage_get(KEY_UUID, config_uuid, sizeof(config_uuid), &len) && len == sizeof(config_uuid)) { From 8502ee61a365ac8f5479a4689abf8950e74bca03 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Mon, 11 Feb 2019 18:01:35 +0100 Subject: [PATCH 20/31] Upon fatal error display 'Contact TREZOR support' instead of 'Unplug your device'. --- common.c | 2 +- vendor/trezor-storage | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common.c b/common.c index 7d1cfdd7af..0530ee3fa0 100644 --- a/common.c +++ b/common.c @@ -59,7 +59,7 @@ void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, oledDrawString(0, y, line, FONT_STANDARD); y += FONT_HEIGHT + 1; - oledDrawString(0, y, "Please unplug the device.", FONT_STANDARD); + oledDrawString(0, y, "Contact TREZOR support.", FONT_STANDARD); oledRefresh(); shutdown(); diff --git a/vendor/trezor-storage b/vendor/trezor-storage index 5c2765740d..f05a2ff9cc 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 5c2765740db064c99fe54cbae79f74a3d767973c +Subproject commit f05a2ff9ccb4562ba4bd8a75a3607bbf24a0c074 From 0e48a1a39a481b67463ab3233f683f24787d2e7d Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Tue, 12 Feb 2019 15:46:28 +0100 Subject: [PATCH 21/31] Fix spaces/tabs so that a single convention is used in each file. --- emulator/timer.c | 2 +- firmware/layout2.c | 14 ++-- firmware/protect.c | 154 ++++++++++++++++++++++---------------------- firmware/recovery.c | 12 ++-- firmware/reset.c | 52 +++++++-------- firmware/trezor.c | 4 +- flash.c | 38 +++++------ 7 files changed, 138 insertions(+), 138 deletions(-) diff --git a/emulator/timer.c b/emulator/timer.c index eadbf76cce..efb95564bd 100644 --- a/emulator/timer.c +++ b/emulator/timer.c @@ -27,6 +27,6 @@ uint32_t timer_ms(void) { struct timespec t; clock_gettime(CLOCK_MONOTONIC, &t); - uint32_t msec = t.tv_sec * 1000 + (t.tv_nsec / 1000000); + uint32_t msec = t.tv_sec * 1000 + (t.tv_nsec / 1000000); return msec; } diff --git a/firmware/layout2.c b/firmware/layout2.c index 36e02829f5..1080ef2787 100644 --- a/firmware/layout2.c +++ b/firmware/layout2.c @@ -238,7 +238,7 @@ void layoutHome(void) char label[MAX_LABEL_LEN + 1] = _("Go to trezor.io/start"); if (config_isInitialized()) { - config_getLabel(label, sizeof(label)); + config_getLabel(label, sizeof(label)); } uint8_t homescreen[HOMESCREEN_SIZE]; @@ -257,12 +257,12 @@ void layoutHome(void) } } - bool no_backup = false; - bool unfinished_backup = false; - bool needs_backup = false; - config_getNoBackup(&no_backup); - config_getUnfinishedBackup(&unfinished_backup); - config_getNeedsBackup(&needs_backup); + bool no_backup = false; + bool unfinished_backup = false; + bool needs_backup = false; + config_getNoBackup(&no_backup); + config_getUnfinishedBackup(&unfinished_backup); + config_getNeedsBackup(&needs_backup); if (no_backup) { oledBox(0, 0, 127, 8, false); oledDrawStringCenter(OLED_WIDTH / 2, 0, "SEEDLESS", FONT_STANDARD); diff --git a/firmware/protect.c b/firmware/protect.c index 796997d1fc..51f0754a05 100644 --- a/firmware/protect.c +++ b/firmware/protect.c @@ -149,34 +149,34 @@ const char *requestPin(PinMatrixRequestType type, const char *text) secbool protectPinUiCallback(uint32_t wait, uint32_t progress) { - (void) progress; + (void) progress; - // Convert wait to secstr string. - char secstrbuf[] = _("________0 seconds"); - char *secstr = secstrbuf + 9; - uint32_t secs = wait; - do { - secstr--; - *secstr = (secs % 10) + '0'; - secs /= 10; - } while (secs > 0 && secstr >= secstrbuf); - if (wait == 1) { - // Change "seconds" to "second". - secstrbuf[16] = 0; - } - layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Verifying PIN"), NULL, _("Please wait"), secstr, _("to continue ..."), NULL); + // Convert wait to secstr string. + char secstrbuf[] = _("________0 seconds"); + char *secstr = secstrbuf + 9; + uint32_t secs = wait; + do { + secstr--; + *secstr = (secs % 10) + '0'; + secs /= 10; + } while (secs > 0 && secstr >= secstrbuf); + if (wait == 1) { + // Change "seconds" to "second". + secstrbuf[16] = 0; + } + layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Verifying PIN"), NULL, _("Please wait"), secstr, _("to continue ..."), NULL); - // Check for Cancel / Initialize. - protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); - protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); - if (protectAbortedByCancel || protectAbortedByInitialize) { - msg_tiny_id = 0xFFFF; - usbTiny(0); - fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); - return sectrue; - } + // Check for Cancel / Initialize. + protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); + protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); + if (protectAbortedByCancel || protectAbortedByInitialize) { + msg_tiny_id = 0xFFFF; + usbTiny(0); + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return sectrue; + } - return secfalse; + return secfalse; } bool protectPin(bool use_cached) @@ -187,77 +187,77 @@ bool protectPin(bool use_cached) const char *pin = ""; if (config_hasPin()) { - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); - if (!pin) { - fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); - return false; - } + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); + if (!pin) { + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } } - usbTiny(1); + usbTiny(1); bool ret = config_containsPin(pin); - usbTiny(0); + usbTiny(0); if (!ret) { fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); } - return ret; + return ret; } bool protectChangePin(bool removal) { - static CONFIDENTIAL char old_pin[MAX_PIN_LEN + 1] = ""; - static CONFIDENTIAL char new_pin[MAX_PIN_LEN + 1] = ""; - const char* pin = NULL; + static CONFIDENTIAL char old_pin[MAX_PIN_LEN + 1] = ""; + static CONFIDENTIAL char new_pin[MAX_PIN_LEN + 1] = ""; + const char* pin = NULL; - if (config_hasPin()) { - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); - if (pin == NULL) { - fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); - return false; - } - strlcpy(old_pin, pin, sizeof(old_pin)); - } + if (config_hasPin()) { + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); + if (pin == NULL) { + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } + strlcpy(old_pin, pin, sizeof(old_pin)); + } - if (!removal) { - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst, _("Please enter new PIN:")); - if (pin == NULL) { - memzero(old_pin, sizeof(old_pin)); - fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); - return false; - } - strlcpy(new_pin, pin, sizeof(new_pin)); + if (!removal) { + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst, _("Please enter new PIN:")); + if (pin == NULL) { + memzero(old_pin, sizeof(old_pin)); + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } + strlcpy(new_pin, pin, sizeof(new_pin)); - pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewSecond, _("Please re-enter new PIN:")); - if (pin == NULL) { - memzero(old_pin, sizeof(old_pin)); - memzero(new_pin, sizeof(new_pin)); - fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); - return false; - } + pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewSecond, _("Please re-enter new PIN:")); + if (pin == NULL) { + memzero(old_pin, sizeof(old_pin)); + memzero(new_pin, sizeof(new_pin)); + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } - if (strncmp(new_pin, pin, sizeof(new_pin)) != 0) { - memzero(old_pin, sizeof(old_pin)); - memzero(new_pin, sizeof(new_pin)); - fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); - return false; - } - } + if (strncmp(new_pin, pin, sizeof(new_pin)) != 0) { + memzero(old_pin, sizeof(old_pin)); + memzero(new_pin, sizeof(new_pin)); + fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); + return false; + } + } - usbTiny(1); - bool ret = config_changePin(old_pin, new_pin); - usbTiny(0); - memzero(old_pin, sizeof(old_pin)); - memzero(new_pin, sizeof(new_pin)); - if (ret == false) { - fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); - } - return ret; + usbTiny(1); + bool ret = config_changePin(old_pin, new_pin); + usbTiny(0); + memzero(old_pin, sizeof(old_pin)); + memzero(new_pin, sizeof(new_pin)); + if (ret == false) { + fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); + } + return ret; } bool protectPassphrase(void) { - bool passphrase_protection = false; - config_getPassphraseProtection(&passphrase_protection); + bool passphrase_protection = false; + config_getPassphraseProtection(&passphrase_protection); if (!passphrase_protection || session_isPassphraseCached()) { return true; } diff --git a/firmware/recovery.c b/firmware/recovery.c index f7e5460fc8..dd3b7edb09 100644 --- a/firmware/recovery.c +++ b/firmware/recovery.c @@ -165,13 +165,13 @@ static void recovery_done(void) { if (!dry_run) { // Update mnemonic on config. if (config_setMnemonic(new_mnemonic)) { - if (!enforce_wordlist) { - // not enforcing => mark config as imported - config_setImported(true); - } - fsm_sendSuccess(_("Device recovered")); + if (!enforce_wordlist) { + // not enforcing => mark config as imported + config_setImported(true); + } + fsm_sendSuccess(_("Device recovered")); } else { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); } memzero(new_mnemonic, sizeof(new_mnemonic)); } else { diff --git a/firmware/reset.c b/firmware/reset.c index 9813c0969f..82bf7191d6 100644 --- a/firmware/reset.c +++ b/firmware/reset.c @@ -97,7 +97,7 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Reset mode")); return; } - awaiting_entropy = false; + awaiting_entropy = false; SHA256_CTX ctx; sha256_Init(&ctx); @@ -108,21 +108,21 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len) memzero(int_entropy, 32); if (skip_backup || no_backup) { - if (no_backup) { - config_setNoBackup(); - } else { - config_setNeedsBackup(true); - } - if (config_setMnemonic(mnemonic)) { - fsm_sendSuccess(_("Device successfully initialized")); - } else { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); - } + if (no_backup) { + config_setNoBackup(); + } else { + config_setNeedsBackup(true); + } + if (config_setMnemonic(mnemonic)) { + fsm_sendSuccess(_("Device successfully initialized")); + } else { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); + } layoutHome(); } else { reset_backup(false, mnemonic); } - mnemonic_clear(); + mnemonic_clear(); } static char current_word[10]; @@ -131,15 +131,15 @@ static char current_word[10]; void reset_backup(bool separated, const char* mnemonic) { if (separated) { - bool needs_backup = false; - config_getNeedsBackup(&needs_backup); - if (!needs_backup) { - fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); - return; - } + bool needs_backup = false; + config_getNeedsBackup(&needs_backup); + if (!needs_backup) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); + return; + } - config_setUnfinishedBackup(true); - config_setNeedsBackup(false); + config_setUnfinishedBackup(true); + config_setNeedsBackup(false); } for (int pass = 0; pass < 2; pass++) { @@ -173,12 +173,12 @@ void reset_backup(bool separated, const char* mnemonic) if (separated) { fsm_sendSuccess(_("Seed successfully backed up")); } else { - config_setNeedsBackup(false); - if (config_setMnemonic(mnemonic)) { - fsm_sendSuccess(_("Device successfully initialized")); - } else { - fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); - } + config_setNeedsBackup(false); + if (config_setMnemonic(mnemonic)) { + fsm_sendSuccess(_("Device successfully initialized")); + } else { + fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); + } } layoutHome(); } diff --git a/firmware/trezor.c b/firmware/trezor.c index 50b7b60eed..97b5ddd69f 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -90,9 +90,9 @@ void check_lock_screen(void) int main(void) { #if EMULATOR - memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); + memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); #else - desig_get_unique_id((uint32_t*)HW_ENTROPY_DATA); + desig_get_unique_id((uint32_t*)HW_ENTROPY_DATA); #endif #ifndef APPVER diff --git a/flash.c b/flash.c index 998219c0b0..1501b6aa2a 100644 --- a/flash.c +++ b/flash.c @@ -43,7 +43,7 @@ static const uint32_t FLASH_SECTOR_TABLE[FLASH_SECTOR_COUNT + 1] = { static secbool flash_check_success(uint32_t status) { - return (status & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) ? secfalse : sectrue; + return (status & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) ? secfalse : sectrue; } void flash_init(void) @@ -58,7 +58,7 @@ secbool flash_unlock_write(void) secbool flash_lock_write(void) { - return flash_check_success(svc_flash_lock()); + return flash_check_success(svc_flash_lock()); } const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size) @@ -77,16 +77,16 @@ const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size) secbool flash_erase(uint8_t sector) { ensure(flash_unlock_write(), NULL); - svc_flash_erase_sector(sector); - ensure(flash_lock_write(), NULL); + svc_flash_erase_sector(sector); + ensure(flash_lock_write(), NULL); - // Check whether the sector was really deleted (contains only 0xFF). - const uint32_t addr_start = FLASH_SECTOR_TABLE[sector], addr_end = FLASH_SECTOR_TABLE[sector + 1]; - for (uint32_t addr = addr_start; addr < addr_end; addr += 4) { - if (*((const uint32_t *)FLASH_PTR(addr)) != 0xFFFFFFFF) { - return secfalse; - } - } + // Check whether the sector was really deleted (contains only 0xFF). + const uint32_t addr_start = FLASH_SECTOR_TABLE[sector], addr_end = FLASH_SECTOR_TABLE[sector + 1]; + for (uint32_t addr = addr_start; addr < addr_end; addr += 4) { + if (*((const uint32_t *)FLASH_PTR(addr)) != 0xFFFFFFFF) { + return secfalse; + } + } return sectrue; } @@ -98,14 +98,14 @@ secbool flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data) } if ((*address & data) != data) { - return secfalse; + return secfalse; } - svc_flash_program(FLASH_CR_PROGRAM_X8); - *(volatile uint8_t *) address = data; + svc_flash_program(FLASH_CR_PROGRAM_X8); + *(volatile uint8_t *) address = data; if (*address != data) { - return secfalse; + return secfalse; } return sectrue; @@ -123,14 +123,14 @@ secbool flash_write_word(uint8_t sector, uint32_t offset, uint32_t data) } if ((*address & data) != data) { - return secfalse; + return secfalse; } - svc_flash_program(FLASH_CR_PROGRAM_X32); - *(volatile uint32_t *) address = data; + svc_flash_program(FLASH_CR_PROGRAM_X32); + *(volatile uint32_t *) address = data; if (*address != data) { - return secfalse; + return secfalse; } return sectrue; From dc848be167b183562c2a268df648f8c0087c73a8 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Tue, 12 Feb 2019 17:56:33 +0100 Subject: [PATCH 22/31] config: Cache auto-lock delay. --- firmware/config.c | 28 +++++++++++++++++++++------- vendor/trezor-storage | 2 +- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 71319b81ac..0ec42b3809 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -111,12 +111,15 @@ be added to the storage u2f_counter to get the real counter value. * This corresponds to the number of cleared bits in the U2FAREA. */ static bool sessionSeedCached, sessionSeedUsesPassphrase; - static uint8_t CONFIDENTIAL sessionSeed[64]; static bool sessionPassphraseCached = false; static char CONFIDENTIAL sessionPassphrase[51]; +#define autoLockDelayMsDefault (10 * 60 * 1000U) // 10 minutes +static secbool autoLockDelayMsCached = secfalse; +static uint32_t autoLockDelayMs = autoLockDelayMsDefault; + static const uint32_t CONFIG_VERSION = 10; static const uint8_t FALSE_BYTE = '\x00'; @@ -851,19 +854,29 @@ void config_setU2FCounter(uint32_t u2fcounter) uint32_t config_getAutoLockDelayMs() { - const uint32_t default_delay_ms = 10 * 60 * 1000U; // 10 minutes - uint32_t delay_ms = 0; - if (config_get_uint32(KEY_AUTO_LOCK_DELAY_MS, &delay_ms)) { - return delay_ms; + if (sectrue == autoLockDelayMsCached) { + return autoLockDelayMs; } - return default_delay_ms; + + if (sectrue != storage_is_unlocked()) { + return autoLockDelayMsDefault; + } + + if (!config_get_uint32(KEY_AUTO_LOCK_DELAY_MS, &autoLockDelayMs)) { + autoLockDelayMs = autoLockDelayMsDefault; + } + autoLockDelayMsCached = sectrue; + return autoLockDelayMs; } void config_setAutoLockDelayMs(uint32_t auto_lock_delay_ms) { const uint32_t min_delay_ms = 10 * 1000U; // 10 seconds auto_lock_delay_ms = MAX(auto_lock_delay_ms, min_delay_ms); - storage_set(KEY_AUTO_LOCK_DELAY_MS, &auto_lock_delay_ms, sizeof(auto_lock_delay_ms)); + if (sectrue == storage_set(KEY_AUTO_LOCK_DELAY_MS, &auto_lock_delay_ms, sizeof(auto_lock_delay_ms))) { + autoLockDelayMs = auto_lock_delay_ms; + autoLockDelayMsCached = sectrue; + } } void config_wipe(void) @@ -872,6 +885,7 @@ void config_wipe(void) storage_unlock(PIN_EMPTY); random_buffer((uint8_t *)config_uuid, sizeof(config_uuid)); data2hex(config_uuid, sizeof(config_uuid), config_uuid_str); + autoLockDelayMsCached = secfalse; storage_set(KEY_UUID, config_uuid, sizeof(config_uuid)); storage_set(KEY_VERSION, &CONFIG_VERSION, sizeof(CONFIG_VERSION)); session_clear(false); diff --git a/vendor/trezor-storage b/vendor/trezor-storage index f05a2ff9cc..13b256ab2c 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit f05a2ff9ccb4562ba4bd8a75a3607bbf24a0c074 +Subproject commit 13b256ab2c11791e0c13696a8c507787a374884f From 45193ffc1dd3813ad036b769b7d8743b6af5c9e7 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Wed, 13 Feb 2019 15:53:27 +0100 Subject: [PATCH 23/31] config: Use secbool instead of bool at least internally. --- firmware/config.c | 96 +++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 0ec42b3809..344910497d 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -110,10 +110,10 @@ be added to the storage u2f_counter to get the real counter value. * storage.u2f_counter + config_u2f_offset. * This corresponds to the number of cleared bits in the U2FAREA. */ -static bool sessionSeedCached, sessionSeedUsesPassphrase; +static secbool sessionSeedCached, sessionSeedUsesPassphrase; static uint8_t CONFIDENTIAL sessionSeed[64]; -static bool sessionPassphraseCached = false; +static secbool sessionPassphraseCached = secfalse; static char CONFIDENTIAL sessionPassphrase[51]; #define autoLockDelayMsDefault (10 * 60 * 1000U) // 10 minutes @@ -143,62 +143,62 @@ static uint32_t pin_to_int(const char *pin) return val; } -static bool config_set_bool(uint16_t key, bool value) +static secbool config_set_bool(uint16_t key, bool value) { if (value) { - return (sectrue == storage_set(key, &TRUE_BYTE, sizeof(TRUE_BYTE))); + return storage_set(key, &TRUE_BYTE, sizeof(TRUE_BYTE)); } else { - return (sectrue == storage_set(key, &FALSE_BYTE, sizeof(FALSE_BYTE))); + return storage_set(key, &FALSE_BYTE, sizeof(FALSE_BYTE)); } } -static bool config_get_bool(uint16_t key, bool *value) +static secbool config_get_bool(uint16_t key, bool *value) { uint8_t val = 0; uint16_t len = 0; if (sectrue == storage_get(key, &val, sizeof(val), &len) && len == sizeof(TRUE_BYTE)) { *value = (val == TRUE_BYTE); - return true; + return sectrue; } else { *value = false; - return false; + return secfalse; } } -static bool config_has_key(uint16_t key) +static secbool config_has_key(uint16_t key) { uint16_t len = 0; - return sectrue == storage_get(key, NULL, 0, &len); + return storage_get(key, NULL, 0, &len); } -static bool config_get_string(uint16_t key, char *dest, uint16_t dest_size) +static secbool config_get_string(uint16_t key, char *dest, uint16_t dest_size) { - dest[0] = '\0'; uint16_t len = 0; if (sectrue != storage_get(key, dest, dest_size - 1, &len)) { - return false; + dest[0] = '\0'; + return secfalse; } dest[len] = '\0'; - return true; + return sectrue; } -static bool config_get_uint32(uint16_t key, uint32_t *value) +static secbool config_get_uint32(uint16_t key, uint32_t *value) { uint16_t len = 0; if (sectrue != storage_get(key, value, sizeof(uint32_t), &len) || len != sizeof(uint32_t)) { *value = 0; - return false; + return secfalse; } - return true; + return sectrue; } -static bool config_upgrade_v10(void) +static secbool config_upgrade_v10(void) { #define OLD_STORAGE_SIZE(last_member) (((offsetof(Storage, last_member) + pb_membersize(Storage, last_member)) + 3) & ~3) if (memcmp(FLASH_PTR(FLASH_STORAGE_START), &CONFIG_MAGIC_V10, sizeof(CONFIG_MAGIC_V10)) != 0) { // wrong magic - return false; + return secfalse; } Storage config __attribute__((aligned(4))); @@ -220,7 +220,7 @@ static bool config_upgrade_v10(void) if (config.version > CONFIG_VERSION) { // downgrade -> clear storage config_wipe(); - return false; + return secfalse; } size_t old_config_size = 0; @@ -340,7 +340,7 @@ static bool config_upgrade_v10(void) session_clear(true); - return true; + return sectrue; } void config_init(void) @@ -360,9 +360,9 @@ void config_init(void) void session_clear(bool lock) { - sessionSeedCached = false; + sessionSeedCached = secfalse; memzero(&sessionSeed, sizeof(sessionSeed)); - sessionPassphraseCached = false; + sessionPassphraseCached = secfalse; memzero(&sessionPassphrase, sizeof(sessionPassphrase)); if (lock) { storage_lock(); @@ -494,14 +494,14 @@ void config_setLanguage(const char *lang) void config_setPassphraseProtection(bool passphrase_protection) { - sessionSeedCached = false; - sessionPassphraseCached = false; + sessionSeedCached = secfalse; + sessionPassphraseCached = secfalse; config_set_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection); } bool config_getPassphraseProtection(bool *passphrase_protection) { - return config_get_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection); + return sectrue == config_get_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection); } void config_setHomescreen(const uint8_t *data, uint32_t size) @@ -522,8 +522,8 @@ static void get_root_node_callback(uint32_t iter, uint32_t total) const uint8_t *config_getSeed(bool usePassphrase) { // root node is properly cached - if (usePassphrase == sessionSeedUsesPassphrase - && sessionSeedCached) { + if (usePassphrase == (sectrue == sessionSeedUsesPassphrase) + && sectrue == sessionSeedCached) { return sessionSeed; } @@ -548,8 +548,8 @@ const uint8_t *config_getSeed(bool usePassphrase) mnemonic_to_seed(mnemonic, usePassphrase ? sessionPassphrase : "", sessionSeed, get_root_node_callback); // BIP-0039 memzero(mnemonic, sizeof(mnemonic)); usbTiny(oldTiny); - sessionSeedCached = true; - sessionSeedUsesPassphrase = usePassphrase; + sessionSeedCached = sectrue; + sessionSeedUsesPassphrase = usePassphrase ? sectrue : secfalse; return sessionSeed; } @@ -589,7 +589,7 @@ bool config_getRootNode(HDNode *node, const char *curve, bool usePassphrase) } bool passphrase_protection = false; config_getPassphraseProtection(&passphrase_protection); - if (passphrase_protection && sessionPassphraseCached && sessionPassphrase[0] != '\0') { + if (passphrase_protection && sectrue == sessionPassphraseCached && sessionPassphrase[0] != '\0') { // decrypt hd node uint8_t secret[64]; PBKDF2_HMAC_SHA512_CTX pctx; @@ -621,12 +621,12 @@ bool config_getRootNode(HDNode *node, const char *curve, bool usePassphrase) bool config_getLabel(char *dest, uint16_t dest_size) { - return config_get_string(KEY_LABEL, dest, dest_size); + return sectrue == config_get_string(KEY_LABEL, dest, dest_size); } bool config_getLanguage(char *dest, uint16_t dest_size) { - return config_get_string(KEY_LANGUAGE, dest, dest_size); + return sectrue == config_get_string(KEY_LANGUAGE, dest, dest_size); } bool config_getHomescreen(uint8_t *dest, uint16_t dest_size) @@ -649,7 +649,7 @@ bool config_setMnemonic(const char *mnemonic) return false; } - if (!config_set_bool(KEY_INITIALIZED, true)) { + if (sectrue != config_set_bool(KEY_INITIALIZED, true)) { storage_delete(KEY_MNEMONIC); return false; } @@ -670,17 +670,17 @@ bool config_setMnemonic(const char *mnemonic) bool config_hasNode(void) { - return config_has_key(KEY_NODE); + return sectrue == config_has_key(KEY_NODE); } bool config_hasMnemonic(void) { - return config_has_key(KEY_MNEMONIC); + return sectrue == config_has_key(KEY_MNEMONIC); } bool config_getMnemonic(char *dest, uint16_t dest_size) { - return config_get_string(KEY_MNEMONIC, dest, dest_size); + return sectrue == config_get_string(KEY_MNEMONIC, dest, dest_size); } /* Check whether mnemonic matches storage. The mnemonic must be @@ -718,7 +718,7 @@ bool config_containsPin(const char *pin) bool config_hasPin(void) { - return storage_has_pin(); + return sectrue == storage_has_pin(); } bool config_changePin(const char *old_pin, const char *new_pin) @@ -737,17 +737,17 @@ bool config_changePin(const char *old_pin, const char *new_pin) void session_cachePassphrase(const char *passphrase) { strlcpy(sessionPassphrase, passphrase, sizeof(sessionPassphrase)); - sessionPassphraseCached = true; + sessionPassphraseCached = sectrue; } bool session_isPassphraseCached(void) { - return sessionPassphraseCached; + return sectrue == sessionPassphraseCached; } bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphrase) { - if (!passphrase && !sessionPassphraseCached) { + if (!passphrase && sectrue != sessionPassphraseCached) { return false; } else { passphrase = sessionPassphrase; @@ -774,7 +774,7 @@ bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphras bool session_isUnlocked(void) { - return storage_is_unlocked(); + return sectrue == storage_is_unlocked(); } bool config_isInitialized(void) @@ -786,7 +786,7 @@ bool config_isInitialized(void) bool config_getImported(bool* imported) { - return config_get_bool(KEY_IMPORTED, imported); + return sectrue == config_get_bool(KEY_IMPORTED, imported); } void config_setImported(bool imported) @@ -796,7 +796,7 @@ void config_setImported(bool imported) bool config_getNeedsBackup(bool *needs_backup) { - return config_get_bool(KEY_NEEDS_BACKUP, needs_backup); + return sectrue == config_get_bool(KEY_NEEDS_BACKUP, needs_backup); } void config_setNeedsBackup(bool needs_backup) @@ -806,7 +806,7 @@ void config_setNeedsBackup(bool needs_backup) bool config_getUnfinishedBackup(bool *unfinished_backup) { - return config_get_bool(KEY_UNFINISHED_BACKUP, unfinished_backup); + return sectrue == config_get_bool(KEY_UNFINISHED_BACKUP, unfinished_backup); } void config_setUnfinishedBackup(bool unfinished_backup) @@ -816,7 +816,7 @@ void config_setUnfinishedBackup(bool unfinished_backup) bool config_getNoBackup(bool *no_backup) { - return config_get_bool(KEY_NO_BACKUP, no_backup); + return sectrue == config_get_bool(KEY_NO_BACKUP, no_backup); } void config_setNoBackup(void) @@ -837,7 +837,7 @@ void config_applyFlags(uint32_t flags) bool config_getFlags(uint32_t *flags) { - return config_get_uint32(KEY_FLAGS, flags); + return sectrue == config_get_uint32(KEY_FLAGS, flags); } uint32_t config_nextU2FCounter(void) @@ -862,7 +862,7 @@ uint32_t config_getAutoLockDelayMs() return autoLockDelayMsDefault; } - if (!config_get_uint32(KEY_AUTO_LOCK_DELAY_MS, &autoLockDelayMs)) { + if (sectrue != config_get_uint32(KEY_AUTO_LOCK_DELAY_MS, &autoLockDelayMs)) { autoLockDelayMs = autoLockDelayMsDefault; } autoLockDelayMsCached = sectrue; From 6b66c7540c1f0feec2ed531e12e6babb92bb95d3 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Wed, 13 Feb 2019 17:12:55 +0100 Subject: [PATCH 24/31] config: Remove unused functions config_hasMnemonic() and config_hasNode(). Since mnemonic and node are protected entries, these functions would always return false when storage is locked. We now instead use the INITIALIZED flag which is public. --- firmware/config.c | 32 ++++++++------------------------ firmware/config.h | 4 +--- firmware/fsm_msg_debug.h | 7 ++----- 3 files changed, 11 insertions(+), 32 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 344910497d..32186d0b85 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -165,12 +165,6 @@ static secbool config_get_bool(uint16_t key, bool *value) } } -static secbool config_has_key(uint16_t key) -{ - uint16_t len = 0; - return storage_get(key, NULL, 0, &len); -} - static secbool config_get_string(uint16_t key, char *dest, uint16_t dest_size) { uint16_t len = 0; @@ -410,17 +404,19 @@ static void config_setNode(const HDNodeType *node) { if (sectrue == storage_set(KEY_NODE, &storageHDNode, sizeof(storageHDNode))) { config_set_bool(KEY_INITIALIZED, true); } + memzero(&storageHDNode, sizeof(storageHDNode)); } #if DEBUG_LINK -void config_dumpNode(HDNodeType *node) +bool config_dumpNode(HDNodeType *node) { memzero(node, sizeof(HDNodeType)); StorageHDNode storageNode; uint16_t len = 0; if (sectrue != storage_get(KEY_NODE, &storageNode, sizeof(storageNode), &len) || len != sizeof(StorageHDNode)) { - return; + memzero(&storageNode, sizeof(storageNode)); + return false; } node->depth = storageNode.depth; @@ -437,6 +433,7 @@ void config_dumpNode(HDNodeType *node) } memzero(&storageNode, sizeof(storageNode)); + return true; } #endif @@ -649,11 +646,6 @@ bool config_setMnemonic(const char *mnemonic) return false; } - if (sectrue != config_set_bool(KEY_INITIALIZED, true)) { - storage_delete(KEY_MNEMONIC); - return false; - } - StorageHDNode u2fNode; memzero(&u2fNode, sizeof(u2fNode)); config_compute_u2froot(mnemonic, &u2fNode); @@ -662,22 +654,14 @@ bool config_setMnemonic(const char *mnemonic) if (sectrue != ret) { storage_delete(KEY_MNEMONIC); - storage_delete(KEY_INITIALIZED); return false; } + + config_set_bool(KEY_INITIALIZED, true); + return true; } -bool config_hasNode(void) -{ - return sectrue == config_has_key(KEY_NODE); -} - -bool config_hasMnemonic(void) -{ - return sectrue == config_has_key(KEY_MNEMONIC); -} - bool config_getMnemonic(char *dest, uint16_t dest_size) { return sectrue == config_get_string(KEY_MNEMONIC, dest, dest_size); diff --git a/firmware/config.h b/firmware/config.h index df7bd58f55..9fd8cd089e 100644 --- a/firmware/config.h +++ b/firmware/config.h @@ -113,12 +113,10 @@ bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphras bool config_setMnemonic(const char *mnemonic); bool config_containsMnemonic(const char *mnemonic); -bool config_hasMnemonic(void); bool config_getMnemonic(char *dest, uint16_t dest_size); -bool config_hasNode(void); #if DEBUG_LINK -void config_dumpNode(HDNodeType *node); +bool config_dumpNode(HDNodeType *node); #endif bool config_containsPin(const char *pin); diff --git a/firmware/fsm_msg_debug.h b/firmware/fsm_msg_debug.h index 0ef38279f6..0ed3bd1bce 100644 --- a/firmware/fsm_msg_debug.h +++ b/firmware/fsm_msg_debug.h @@ -52,12 +52,9 @@ void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) resp.has_recovery_word_pos = true; resp.recovery_word_pos = recovery_get_word_pos(); - resp.has_mnemonic = config_getMnemonic(resp.mnemonic, sizeof(resp.mnemonic)); + resp.has_mnemonic = config_getMnemonic(resp.mnemonic, sizeof(resp.mnemonic)); - if (config_hasNode()) { - resp.has_node = true; - config_dumpNode(&(resp.node)); - } + resp.has_node = config_dumpNode(&(resp.node)); resp.has_passphrase_protection = config_getPassphraseProtection(&(resp.passphrase_protection)); From 0b79d0e59687cb4ce9d98d30f830e41c5df3e9f7 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Thu, 14 Feb 2019 15:13:47 +0100 Subject: [PATCH 25/31] config: Store cleartext PIN for DEBUG_LINK. --- firmware/config.c | 63 +++++++++++++++++++++++++++------------- firmware/config.h | 1 + firmware/fsm_msg_debug.h | 5 +--- 3 files changed, 45 insertions(+), 24 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 32186d0b85..69698a5541 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -53,23 +53,24 @@ static const uint32_t CONFIG_MAGIC_V10 = 0x726f7473; // 'stor' as uint32_t #define FLAG_PUBLIC 0x8000 #define FLAGS_WRITE 0xC000 -static const uint16_t KEY_UUID = 0 | APP | FLAG_PUBLIC; // bytes(12) -static const uint16_t KEY_VERSION = 1 | APP; // uint32 -static const uint16_t KEY_MNEMONIC = 2 | APP; // string(241) -static const uint16_t KEY_LANGUAGE = 3 | APP | FLAG_PUBLIC; // string(17) -static const uint16_t KEY_LABEL = 4 | APP | FLAG_PUBLIC; // string(33) -static const uint16_t KEY_PASSPHRASE_PROTECTION = 5 | APP; // bool -static const uint16_t KEY_HOMESCREEN = 6 | APP | FLAG_PUBLIC; // bytes(1024) -static const uint16_t KEY_NEEDS_BACKUP = 7 | APP; // bool -static const uint16_t KEY_FLAGS = 8 | APP; // uint32 -static const uint16_t KEY_U2F_COUNTER = 9 | APP | FLAGS_WRITE; // uint32 -static const uint16_t KEY_UNFINISHED_BACKUP = 11 | APP; // bool -static const uint16_t KEY_AUTO_LOCK_DELAY_MS = 12 | APP; // uint32 -static const uint16_t KEY_NO_BACKUP = 13 | APP; // bool -static const uint16_t KEY_INITIALIZED = 14 | APP | FLAG_PUBLIC; // uint32 -static const uint16_t KEY_NODE = 15 | APP; // node -static const uint16_t KEY_IMPORTED = 16 | APP; // bool -static const uint16_t KEY_U2F_ROOT = 17 | APP | FLAG_PUBLIC; // node +#define KEY_UUID ( 0 | APP | FLAG_PUBLIC) // bytes(12) +#define KEY_VERSION ( 1 | APP) // uint32 +#define KEY_MNEMONIC ( 2 | APP) // string(241) +#define KEY_LANGUAGE ( 3 | APP | FLAG_PUBLIC) // string(17) +#define KEY_LABEL ( 4 | APP | FLAG_PUBLIC) // string(33) +#define KEY_PASSPHRASE_PROTECTION ( 5 | APP | FLAG_PUBLIC) // bool +#define KEY_HOMESCREEN ( 6 | APP | FLAG_PUBLIC) // bytes(1024) +#define KEY_NEEDS_BACKUP ( 7 | APP) // bool +#define KEY_FLAGS ( 8 | APP) // uint32 +#define KEY_U2F_COUNTER ( 9 | APP | FLAGS_WRITE) // uint32 +#define KEY_UNFINISHED_BACKUP ( 11 | APP) // bool +#define KEY_AUTO_LOCK_DELAY_MS ( 12 | APP) // uint32 +#define KEY_NO_BACKUP ( 13 | APP) // bool +#define KEY_INITIALIZED ( 14 | APP | FLAG_PUBLIC) // uint32 +#define KEY_NODE ( 15 | APP) // node +#define KEY_IMPORTED ( 16 | APP) // bool +#define KEY_U2F_ROOT ( 17 | APP | FLAG_PUBLIC) // node +#define KEY_DEBUG_LINK_PIN (255 | APP | FLAG_PUBLIC) // string(10) // The PIN value corresponding to an empty PIN. static const uint32_t PIN_EMPTY = 1; @@ -167,6 +168,10 @@ static secbool config_get_bool(uint16_t key, bool *value) static secbool config_get_string(uint16_t key, char *dest, uint16_t dest_size) { + if (dest_size == 0) { + return secfalse; + } + uint16_t len = 0; if (sectrue != storage_get(key, dest, dest_size - 1, &len)) { dest[0] = '\0'; @@ -712,12 +717,30 @@ bool config_changePin(const char *old_pin, const char *new_pin) return false; } - if (sectrue == storage_change_pin(pin_to_int(old_pin), new_pin_int)) { - return true; + secbool ret = storage_change_pin(pin_to_int(old_pin), new_pin_int); + +#if DEBUG_LINK + if (sectrue == ret) { + if (new_pin_int != PIN_EMPTY) { + storage_set(KEY_DEBUG_LINK_PIN, new_pin, strnlen(new_pin, MAX_PIN_LEN)); + } else { + storage_delete(KEY_DEBUG_LINK_PIN); + } } - return false; +#endif + + memzero(&new_pin_int, sizeof(new_pin_int)); + + return sectrue == ret; } +#if DEBUG_LINK +bool config_getPin(char *dest, uint16_t dest_size) +{ + return sectrue == config_get_string(KEY_DEBUG_LINK_PIN, dest, dest_size); +} +#endif + void session_cachePassphrase(const char *passphrase) { strlcpy(sessionPassphrase, passphrase, sizeof(sessionPassphrase)); diff --git a/firmware/config.h b/firmware/config.h index 9fd8cd089e..fc97ef0f0a 100644 --- a/firmware/config.h +++ b/firmware/config.h @@ -117,6 +117,7 @@ bool config_getMnemonic(char *dest, uint16_t dest_size); #if DEBUG_LINK bool config_dumpNode(HDNodeType *node); +bool config_getPin(char *dest, uint16_t dest_size); #endif bool config_containsPin(const char *pin); diff --git a/firmware/fsm_msg_debug.h b/firmware/fsm_msg_debug.h index 0ed3bd1bce..cf1973ddbd 100644 --- a/firmware/fsm_msg_debug.h +++ b/firmware/fsm_msg_debug.h @@ -32,10 +32,7 @@ void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) resp.layout.size = OLED_BUFSIZE; memcpy(resp.layout.bytes, oledGetBuffer(), OLED_BUFSIZE); - if (config_hasPin()) { - resp.has_pin = true; - strlcpy(resp.pin, "1", sizeof(resp.pin)); - } + resp.has_pin = config_getPin(resp.pin, sizeof(resp.pin)); resp.has_matrix = true; strlcpy(resp.matrix, pinmatrix_get(), sizeof(resp.matrix)); From 55bc3c74302dcd06c9908614d4d88f50b8d78cd2 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Thu, 14 Feb 2019 16:28:29 +0100 Subject: [PATCH 26/31] config: Check metadata magic before upgrading storage from version 10. Bump config version. --- firmware/config.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index 69698a5541..e4824f4ab8 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -46,8 +46,14 @@ #include "supervise.h" #include "storage.h" -/* Magic constant to check validity of storage block for storage versions 1 to 10. */ -static const uint32_t CONFIG_MAGIC_V10 = 0x726f7473; // 'stor' as uint32_t +/* Magic constants to check validity of storage block for storage versions 1 to 10. */ +static const uint32_t CONFIG_MAGIC_V10 = 0x726f7473; // 'stor' as uint32_t + +#if !EMULATOR +static const uint32_t META_MAGIC_V10 = 0x525a5254; // 'TRZR' as uint32_t +#else +static const uint32_t META_MAGIC_V10 = 0xFFFFFFFF; +#endif #define APP 0x0100 #define FLAG_PUBLIC 0x8000 @@ -121,7 +127,7 @@ static char CONFIDENTIAL sessionPassphrase[51]; static secbool autoLockDelayMsCached = secfalse; static uint32_t autoLockDelayMs = autoLockDelayMsDefault; -static const uint32_t CONFIG_VERSION = 10; +static const uint32_t CONFIG_VERSION = 11; static const uint8_t FALSE_BYTE = '\x00'; static const uint8_t TRUE_BYTE = '\x01'; @@ -195,7 +201,8 @@ static secbool config_upgrade_v10(void) { #define OLD_STORAGE_SIZE(last_member) (((offsetof(Storage, last_member) + pb_membersize(Storage, last_member)) + 3) & ~3) - if (memcmp(FLASH_PTR(FLASH_STORAGE_START), &CONFIG_MAGIC_V10, sizeof(CONFIG_MAGIC_V10)) != 0) { + if (memcmp(FLASH_PTR(FLASH_META_MAGIC), &META_MAGIC_V10, sizeof(META_MAGIC_V10)) != 0 || + memcmp(FLASH_PTR(FLASH_STORAGE_START), &CONFIG_MAGIC_V10, sizeof(CONFIG_MAGIC_V10)) != 0) { // wrong magic return secfalse; } From d5e18a489a817c2b1079b34163204d2a04c3bcab Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Thu, 14 Feb 2019 16:53:48 +0100 Subject: [PATCH 27/31] 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 13b256ab2c..94cb1a4dbe 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 13b256ab2c11791e0c13696a8c507787a374884f +Subproject commit 94cb1a4dbe2e28aaaf36cd741800cf5c1b16e08f From b4c0b59c8973298e55ca22c1a69a7399a7abb8c4 Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Thu, 14 Feb 2019 18:59:31 +0100 Subject: [PATCH 28/31] msg: GetFeatures should always return passphrase_protection, needs_backup, unfinished_backup and no_backup, even if the value is not available in storage. --- firmware/fsm_msg_common.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/firmware/fsm_msg_common.h b/firmware/fsm_msg_common.h index 9cafd4d302..10d61a1dc6 100644 --- a/firmware/fsm_msg_common.h +++ b/firmware/fsm_msg_common.h @@ -47,7 +47,7 @@ void fsm_msgGetFeatures(const GetFeatures *msg) resp->has_patch_version = true; resp->patch_version = VERSION_PATCH; resp->has_device_id = true; strlcpy(resp->device_id, config_uuid_str, sizeof(resp->device_id)); resp->has_pin_protection = true; resp->pin_protection = config_hasPin(); - resp->has_passphrase_protection = config_getPassphraseProtection(&(resp->passphrase_protection)); + resp->has_passphrase_protection = true; config_getPassphraseProtection(&(resp->passphrase_protection)); #ifdef SCM_REVISION int len = sizeof(SCM_REVISION) - 1; resp->has_revision = true; memcpy(resp->revision.bytes, SCM_REVISION, len); resp->revision.size = len; @@ -60,9 +60,9 @@ void fsm_msgGetFeatures(const GetFeatures *msg) resp->has_imported = config_getImported(&(resp->imported)); resp->has_pin_cached = true; resp->pin_cached = session_isUnlocked() && config_hasPin(); resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); - resp->has_needs_backup = config_getNeedsBackup(&(resp->needs_backup)); - resp->has_unfinished_backup = config_getUnfinishedBackup(&(resp->unfinished_backup)); - resp->has_no_backup = config_getNoBackup(&(resp->no_backup)); + resp->has_needs_backup = true; config_getNeedsBackup(&(resp->needs_backup)); + resp->has_unfinished_backup = true; config_getUnfinishedBackup(&(resp->unfinished_backup)); + resp->has_no_backup = true; config_getNoBackup(&(resp->no_backup)); resp->has_flags = config_getFlags(&(resp->flags)); resp->has_model = true; strlcpy(resp->model, "1", sizeof(resp->model)); From 5230a0f8468176862025ece3894997562b3b7f6a Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Thu, 14 Feb 2019 20:51:50 +0100 Subject: [PATCH 29/31] config: Do not lock storage after completing loadDevice(). --- firmware/config.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/firmware/config.c b/firmware/config.c index e4824f4ab8..e7de2d0409 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -451,6 +451,7 @@ bool config_dumpNode(HDNodeType *node) void config_loadDevice(const LoadDevice *msg) { + session_clear(false); config_set_bool(KEY_IMPORTED, true); config_setPassphraseProtection(msg->has_passphrase_protection && msg->passphrase_protection); @@ -475,8 +476,6 @@ void config_loadDevice(const LoadDevice *msg) if (msg->has_u2f_counter) { config_setU2FCounter(msg->u2f_counter); } - - session_clear(true); } void config_setLabel(const char *label) From 9a9c537afdf940c809b46cf660afafc16e559284 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 15 Feb 2019 14:12:18 +0100 Subject: [PATCH 30/31] 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 94cb1a4dbe..5688a9e47e 160000 --- a/vendor/trezor-storage +++ b/vendor/trezor-storage @@ -1 +1 @@ -Subproject commit 94cb1a4dbe2e28aaaf36cd741800cf5c1b16e08f +Subproject commit 5688a9e47e6d0d21b63ac22924199de2da696db7 From 67c0f8b8a1e03047adfda73dacbe85cbae099f34 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 15 Feb 2019 14:22:52 +0100 Subject: [PATCH 31/31] storage: use fixed hw_entropy in unprivileged mode --- firmware/trezor.c | 17 +++++++++-------- norcow_config.h | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/firmware/trezor.c b/firmware/trezor.c index 97b5ddd69f..c26ec0deda 100644 --- a/firmware/trezor.c +++ b/firmware/trezor.c @@ -89,12 +89,6 @@ void check_lock_screen(void) int main(void) { -#if EMULATOR - memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); -#else - desig_get_unique_id((uint32_t*)HW_ENTROPY_DATA); -#endif - #ifndef APPVER setup(); __stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks @@ -106,12 +100,19 @@ int main(void) #endif if (!is_mode_unprivileged()) { - + desig_get_unique_id((uint32_t*)HW_ENTROPY_DATA); timer_init(); - #ifdef APPVER // enable MPU (Memory Protection Unit) mpu_config(); +#endif + } else { +#if EMULATOR + memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); +#else + // we are running in unprivileged mode + // use fixed HW_ENTROPY + memset(HW_ENTROPY_DATA, 0x3C, HW_ENTROPY_LEN); #endif } diff --git a/norcow_config.h b/norcow_config.h index d78f0749e5..ba57dfb4b2 100644 --- a/norcow_config.h +++ b/norcow_config.h @@ -29,7 +29,7 @@ /* * The length of the sector header in bytes. The header is preserved between sector erasures. */ -#define NORCOW_HEADER_LEN (0x000) +#define NORCOW_HEADER_LEN (0x100) /* * Current storage version.