mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-22 14:28:07 +00:00
parent
88563ebaa5
commit
73edc7cb74
@ -41,6 +41,7 @@
|
||||
#include "layout2.h"
|
||||
#include "usb.h"
|
||||
#include "gettext.h"
|
||||
#include "u2f.h"
|
||||
|
||||
/* magic constant to check validity of storage block */
|
||||
static const uint32_t storage_magic = 0x726f7473; // 'stor' as uint32_t
|
||||
@ -108,7 +109,7 @@ static bool sessionPinCached;
|
||||
static bool sessionPassphraseCached;
|
||||
static char CONFIDENTIAL sessionPassphrase[51];
|
||||
|
||||
#define STORAGE_VERSION 8
|
||||
#define STORAGE_VERSION 9
|
||||
|
||||
void storage_show_error(void)
|
||||
{
|
||||
@ -126,6 +127,7 @@ void storage_check_flash_errors(void)
|
||||
|
||||
bool storage_from_flash(void)
|
||||
{
|
||||
storage_clear_update();
|
||||
if (memcmp((void *)FLASH_STORAGE_START, &storage_magic, sizeof(storage_magic)) != 0) {
|
||||
// wrong magic
|
||||
return false;
|
||||
@ -140,6 +142,7 @@ bool storage_from_flash(void)
|
||||
// version 6: since 1.3.6
|
||||
// version 7: since 1.5.1
|
||||
// version 8: since 1.5.2
|
||||
// version 9: since 1.6.1
|
||||
if (version > STORAGE_VERSION) {
|
||||
// downgrade -> clear storage
|
||||
return false;
|
||||
@ -156,13 +159,20 @@ bool storage_from_flash(void)
|
||||
old_storage_size = 460;
|
||||
} else
|
||||
if (version == 3 || version == 4 || version == 5) {
|
||||
// added homescreen
|
||||
old_storage_size = 1488;
|
||||
} else
|
||||
if (version == 6 || version == 7) {
|
||||
// added u2fcounter
|
||||
old_storage_size = 1496;
|
||||
} else
|
||||
if (version == 8) {
|
||||
// added flags and needsBackup
|
||||
old_storage_size = 1504;
|
||||
} else
|
||||
if (version == 9) {
|
||||
// added u2froot
|
||||
old_storage_size = 1704;
|
||||
}
|
||||
|
||||
// erase newly added fields
|
||||
@ -204,8 +214,15 @@ bool storage_from_flash(void)
|
||||
storage_u2f_offset++;
|
||||
u2fword >>= 1;
|
||||
}
|
||||
// note: we don't update storage version on flash at this point,
|
||||
// but it is already upgraded when it comes to content
|
||||
// force recomputing u2f root for storage version < 9.
|
||||
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;
|
||||
}
|
||||
|
||||
@ -242,6 +259,29 @@ static uint32_t storage_flash_words(uint32_t addr, const uint32_t *src, int nwor
|
||||
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, HDNodeType *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));
|
||||
memset(&node, 0, 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)
|
||||
@ -261,6 +301,11 @@ static void storage_commit_locked(bool update)
|
||||
memcpy(&storageUpdate.node, &storageRom->node, sizeof(HDNodeType));
|
||||
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(HDNodeType));
|
||||
} 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;
|
||||
@ -467,6 +512,12 @@ const uint8_t *storage_getSeed(bool usePassphrase)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool storage_getU2FRoot(HDNode *node)
|
||||
{
|
||||
return storageRom->has_u2froot
|
||||
&& hdnode_from_xprv(storageRom->u2froot.depth, storageRom->u2froot.child_num, storageRom->u2froot.chain_code.bytes, storageRom->u2froot.private_key.bytes, NIST256P1_NAME, node);
|
||||
}
|
||||
|
||||
bool storage_getRootNode(HDNode *node, const char *curve, bool usePassphrase)
|
||||
{
|
||||
// if storage has node, decrypt and use it
|
||||
|
@ -37,6 +37,7 @@ void storage_loadDevice(LoadDevice *msg);
|
||||
|
||||
const uint8_t *storage_getSeed(bool usePassphrase);
|
||||
|
||||
bool storage_getU2FRoot(HDNode *node);
|
||||
bool storage_getRootNode(HDNode *node, const char *curve, bool usePassphrase);
|
||||
|
||||
const char *storage_getLabel(void);
|
||||
|
@ -59,7 +59,7 @@ static uint8_t u2f_out_packets[U2F_OUT_PKT_BUFFER_LEN][HID_RPT_SIZE];
|
||||
#define KEY_HANDLE_LEN (KEY_PATH_LEN + SHA256_DIGEST_LENGTH)
|
||||
|
||||
// Derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r'
|
||||
#define KEY_PATH_ENTRIES (1 + KEY_PATH_LEN / sizeof(uint32_t))
|
||||
#define KEY_PATH_ENTRIES (KEY_PATH_LEN / sizeof(uint32_t))
|
||||
|
||||
// Defined as UsbSignHandler.BOGUS_APP_ID_HASH
|
||||
// in https://github.com/google/u2f-ref-code/blob/master/u2f-chrome-extension/usbsignhandler.js#L118
|
||||
@ -450,7 +450,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_getRootNode(&node, NIST256P1_NAME, false)) {
|
||||
if (!storage_getU2FRoot(&node)) {
|
||||
layoutHome();
|
||||
debugLog(0, "", "ERR: Device not init");
|
||||
return 0;
|
||||
@ -472,14 +472,13 @@ static const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handl
|
||||
|
||||
// Derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r'
|
||||
uint32_t key_path[KEY_PATH_ENTRIES];
|
||||
key_path[0] = U2F_KEY_PATH;
|
||||
for (uint32_t i = 1; i < KEY_PATH_ENTRIES; i++) {
|
||||
for (uint32_t i = 0; i < KEY_PATH_ENTRIES; i++) {
|
||||
// high bit for hardened keys
|
||||
key_path[i]= 0x80000000 | random32();
|
||||
}
|
||||
|
||||
// First half of keyhandle is key_path
|
||||
memcpy(key_handle, &key_path[1], KEY_PATH_LEN);
|
||||
memcpy(key_handle, key_path, KEY_PATH_LEN);
|
||||
|
||||
// prepare keypair from /random data
|
||||
const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES);
|
||||
@ -501,9 +500,8 @@ static const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handl
|
||||
static const HDNode *validateKeyHandle(const uint8_t app_id[], const uint8_t key_handle[])
|
||||
{
|
||||
uint32_t key_path[KEY_PATH_ENTRIES];
|
||||
key_path[0] = U2F_KEY_PATH;
|
||||
memcpy(&key_path[1], key_handle, KEY_PATH_LEN);
|
||||
for (unsigned int i = 1; i < KEY_PATH_ENTRIES; i++) {
|
||||
memcpy(key_path, key_handle, KEY_PATH_LEN);
|
||||
for (unsigned int i = 0; i < KEY_PATH_ENTRIES; i++) {
|
||||
// check high bit for hardened keys
|
||||
if (! (key_path[i] & 0x80000000)) {
|
||||
return NULL;
|
||||
@ -557,8 +555,6 @@ void u2f_register(const APDU *a)
|
||||
|
||||
// First Time request, return not present and display request dialog
|
||||
if (last_req_state == INIT) {
|
||||
// wake up crypto system to be ready for signing
|
||||
getDerivedNode(NULL, 0);
|
||||
// error: testof-user-presence is required
|
||||
buttonUpdate(); // Clear button state
|
||||
if (0 == memcmp(req->appId, BOGUS_APPID, U2F_APPID_SIZE)) {
|
||||
|
Loading…
Reference in New Issue
Block a user