1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-01-20 20:31:06 +00:00

Merge branch 'master' into u2f

This commit is contained in:
Pavol Rusnak 2016-05-16 18:19:31 +02:00
commit c123db71b9
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
15 changed files with 202 additions and 126 deletions

View File

@ -1,6 +1,6 @@
# initialize from the image # initialize from the image
FROM ubuntu:14.04 FROM ubuntu:16.04
# update repositories # update repositories

View File

@ -13,3 +13,8 @@ libtrezor.a: $(OBJS)
ar rcs libtrezor.a $(OBJS) ar rcs libtrezor.a $(OBJS)
include Makefile.include include Makefile.include
.PHONY: vendor
vendor:
git submodule update --init

View File

@ -1,12 +1,10 @@
TREZOR Firmware # TREZOR Firmware
===============
[![Build Status](https://travis-ci.org/trezor/trezor-mcu.svg?branch=master)](https://travis-ci.org/trezor/trezor-mcu) [![Build Status](https://travis-ci.org/trezor/trezor-mcu.svg?branch=master)](https://travis-ci.org/trezor/trezor-mcu) [![gitter](https://badges.gitter.im/trezor/community.svg)](https://gitter.im/trezor/community)
http://bitcointrezor.com/ http://bitcointrezor.com/
How to build TREZOR firmware? ## How to build TREZOR firmware?
-----------------------------
1. <a href="https://docs.docker.com/engine/installation/">Install Docker</a> 1. <a href="https://docs.docker.com/engine/installation/">Install Docker</a>
2. `git clone https://github.com/trezor/trezor-mcu.git` 2. `git clone https://github.com/trezor/trezor-mcu.git`
@ -15,8 +13,7 @@ How to build TREZOR firmware?
This creates file `output/trezor-TAG.bin` and prints its fingerprint at the last line of the build log. This creates file `output/trezor-TAG.bin` and prints its fingerprint at the last line of the build log.
How to build TREZOR bootloader? ## How to build TREZOR bootloader?
-----------------------------
1. <a href="https://docs.docker.com/engine/installation/">Install Docker</a> 1. <a href="https://docs.docker.com/engine/installation/">Install Docker</a>
2. `git clone https://github.com/trezor/trezor-mcu.git` 2. `git clone https://github.com/trezor/trezor-mcu.git`
@ -25,8 +22,7 @@ How to build TREZOR bootloader?
This creates file `output/bootloader.bin` and prints its fingerprint and size at the last line of the build log. This creates file `output/bootloader.bin` and prints its fingerprint and size at the last line of the build log.
How to get fingerprint of firmware signed and distributed by SatoshiLabs? ## How to get fingerprint of firmware signed and distributed by SatoshiLabs?
-------------------------------------------------------------------------
1. Pick version of firmware binary listed on https://mytrezor.com/data/firmware/releases.json 1. Pick version of firmware binary listed on https://mytrezor.com/data/firmware/releases.json
2. Download it: `wget -O trezor.signed.bin.hex https://mytrezor.com/data/firmware/trezor-1.1.0.bin.hex` 2. Download it: `wget -O trezor.signed.bin.hex https://mytrezor.com/data/firmware/trezor-1.1.0.bin.hex`

View File

@ -273,7 +273,7 @@ int main(void)
switch (state) { switch (state) {
case 1: case 1:
layoutProgress("WORKING", frame % 41 * 25); layoutProgress("WORKING", frame % 41 * 25);
pbkdf2_hmac_sha512(pass, passlen, salt, saltlen, 100, seed, 64, NULL); pbkdf2_hmac_sha512(pass, passlen, salt, saltlen, 100, seed);
usbd_ep_write_packet(usbd_dev, 0x81, seed, 64); usbd_ep_write_packet(usbd_dev, 0x81, seed, 64);
break; break;
} }

View File

@ -21,12 +21,12 @@
#include "coins.h" #include "coins.h"
const CoinType coins[COINS_COUNT] = { const CoinType coins[COINS_COUNT] = {
{true, "Bitcoin", true, "BTC", true, 0, true, 100000, true, 5}, {true, "Bitcoin", true, "BTC", true, 0, true, 100000, true, 5, true, 6, true, 10},
{true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196}, {true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, 3, true, 40},
{true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5}, {true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, false, 0, false, 0},
{true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 5}, {true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 5, false, 0, false, 0},
{true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22}, {true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, false, 0, false, 0},
{true, "Dash", true, "DASH", true, 76, true, 100000, true, 16}, {true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, false, 0, false, 0},
}; };
const CoinType *coinByShortcut(const char *shortcut) const CoinType *coinByShortcut(const char *shortcut)

View File

@ -158,6 +158,7 @@ int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_
return 0; return 0;
} }
/* ECIES disabled
int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw) int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw)
{ {
if (privkey && address_raw) { // signing == true if (privkey && address_raw) { // signing == true
@ -195,10 +196,10 @@ int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_siz
bn_write_be(&R.x, shared_secret + 1); bn_write_be(&R.x, shared_secret + 1);
// generate keying bytes // generate keying bytes
uint8_t keying_bytes[80]; uint8_t keying_bytes[80];
uint8_t salt[22 + 33 + 4]; uint8_t salt[22 + 33];
memcpy(salt, "Bitcoin Secure Message", 22); memcpy(salt, "Bitcoin Secure Message", 22);
memcpy(salt + 22, nonce, 33); memcpy(salt + 22, nonce, 33);
pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes, 80, NULL); pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes, 80);
// encrypt payload // encrypt payload
aes_encrypt_ctx ctx; aes_encrypt_ctx ctx;
aes_encrypt_key256(keying_bytes, &ctx); aes_encrypt_key256(keying_bytes, &ctx);
@ -227,11 +228,11 @@ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_le
bn_write_be(&R.x, shared_secret + 1); bn_write_be(&R.x, shared_secret + 1);
// generate keying bytes // generate keying bytes
uint8_t keying_bytes[80]; uint8_t keying_bytes[80];
uint8_t salt[22 + 33 + 4]; uint8_t salt[22 + 33];
memcpy(salt, "Bitcoin Secure Message", 22); memcpy(salt, "Bitcoin Secure Message", 22);
salt[22] = 0x02 | (nonce->y.val[0] & 0x01); salt[22] = 0x02 | (nonce->y.val[0] & 0x01);
bn_write_be(&(nonce->x), salt + 23); bn_write_be(&(nonce->x), salt + 23);
pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes, 80, NULL); pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes, 80);
// compute hmac // compute hmac
uint8_t out[32]; uint8_t out[32];
hmac_sha256(keying_bytes + 32, 32, payload, payload_len, out); hmac_sha256(keying_bytes + 32, 32, payload, payload_len, out);
@ -267,6 +268,7 @@ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_le
*msg_len = o; *msg_len = o;
return 0; return 0;
} }
*/
uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath) uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath)
{ {

View File

@ -41,11 +41,11 @@ int cryptoMessageSign(const HDNode *node, const uint8_t *message, size_t message
int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature); int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature);
// ECIES: http://memwallet.info/btcmssgs.html /* ECIES disabled
int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw); int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw);
int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_len, const uint8_t *hmac, size_t hmac_len, const uint8_t *privkey, uint8_t *msg, size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw); int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_len, const uint8_t *hmac, size_t hmac_len, const uint8_t *privkey, uint8_t *msg, size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw);
*/
uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath); uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath);

View File

@ -35,7 +35,7 @@ void oledDebug(const char *line)
oledClear(); oledClear();
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
if (lines[i]) { if (lines[i]) {
oledDrawChar(0, i * 8, '0' + (id + i) % 10); oledDrawChar(0, i * 8, '0' + (id + i) % 10, 1);
oledDrawString(8, i * 8, lines[i]); oledDrawString(8, i * 8, lines[i]);
} }
} }

View File

@ -771,6 +771,7 @@ void fsm_msgSignIdentity(SignIdentity *msg)
layoutHome(); layoutHome();
} }
/* ECIES disabled
void fsm_msgEncryptMessage(EncryptMessage *msg) void fsm_msgEncryptMessage(EncryptMessage *msg)
{ {
if (!storage_isInitialized()) { if (!storage_isInitialized()) {
@ -888,6 +889,7 @@ void fsm_msgDecryptMessage(DecryptMessage *msg)
msg_write(MessageType_MessageType_DecryptedMessage, resp); msg_write(MessageType_MessageType_DecryptedMessage, resp);
layoutHome(); layoutHome();
} }
*/
void fsm_msgEstimateTxSize(EstimateTxSize *msg) void fsm_msgEstimateTxSize(EstimateTxSize *msg)
{ {

View File

@ -63,8 +63,10 @@ static const struct MessagesMap_t MessagesMap[] = {
{'n', 'i', MessageType_MessageType_SignMessage, SignMessage_fields, (void (*)(void *))fsm_msgSignMessage}, {'n', 'i', MessageType_MessageType_SignMessage, SignMessage_fields, (void (*)(void *))fsm_msgSignMessage},
{'n', 'i', MessageType_MessageType_SignIdentity, SignIdentity_fields, (void (*)(void *))fsm_msgSignIdentity}, {'n', 'i', MessageType_MessageType_SignIdentity, SignIdentity_fields, (void (*)(void *))fsm_msgSignIdentity},
{'n', 'i', MessageType_MessageType_VerifyMessage, VerifyMessage_fields, (void (*)(void *))fsm_msgVerifyMessage}, {'n', 'i', MessageType_MessageType_VerifyMessage, VerifyMessage_fields, (void (*)(void *))fsm_msgVerifyMessage},
/* ECIES disabled
{'n', 'i', MessageType_MessageType_EncryptMessage, EncryptMessage_fields, (void (*)(void *))fsm_msgEncryptMessage}, {'n', 'i', MessageType_MessageType_EncryptMessage, EncryptMessage_fields, (void (*)(void *))fsm_msgEncryptMessage},
{'n', 'i', MessageType_MessageType_DecryptMessage, DecryptMessage_fields, (void (*)(void *))fsm_msgDecryptMessage}, {'n', 'i', MessageType_MessageType_DecryptMessage, DecryptMessage_fields, (void (*)(void *))fsm_msgDecryptMessage},
*/
// {'n', 'i', MessageType_MessageType_PassphraseAck, PassphraseAck_fields, (void (*)(void *))fsm_msgPassphraseAck}, // {'n', 'i', MessageType_MessageType_PassphraseAck, PassphraseAck_fields, (void (*)(void *))fsm_msgPassphraseAck},
{'n', 'i', MessageType_MessageType_EstimateTxSize, EstimateTxSize_fields, (void (*)(void *))fsm_msgEstimateTxSize}, {'n', 'i', MessageType_MessageType_EstimateTxSize, EstimateTxSize_fields, (void (*)(void *))fsm_msgEstimateTxSize},
{'n', 'i', MessageType_MessageType_RecoveryDevice, RecoveryDevice_fields, (void (*)(void *))fsm_msgRecoveryDevice}, {'n', 'i', MessageType_MessageType_RecoveryDevice, RecoveryDevice_fields, (void (*)(void *))fsm_msgRecoveryDevice},
@ -83,8 +85,10 @@ static const struct MessagesMap_t MessagesMap[] = {
{'n', 'o', MessageType_MessageType_EntropyRequest, EntropyRequest_fields, 0}, {'n', 'o', MessageType_MessageType_EntropyRequest, EntropyRequest_fields, 0},
{'n', 'o', MessageType_MessageType_MessageSignature, MessageSignature_fields, 0}, {'n', 'o', MessageType_MessageType_MessageSignature, MessageSignature_fields, 0},
{'n', 'o', MessageType_MessageType_SignedIdentity, SignedIdentity_fields, 0}, {'n', 'o', MessageType_MessageType_SignedIdentity, SignedIdentity_fields, 0},
/* ECIES disabled
{'n', 'o', MessageType_MessageType_EncryptedMessage, EncryptedMessage_fields, 0}, {'n', 'o', MessageType_MessageType_EncryptedMessage, EncryptedMessage_fields, 0},
{'n', 'o', MessageType_MessageType_DecryptedMessage, DecryptedMessage_fields, 0}, {'n', 'o', MessageType_MessageType_DecryptedMessage, DecryptedMessage_fields, 0},
*/
{'n', 'o', MessageType_MessageType_PassphraseRequest, PassphraseRequest_fields, 0}, {'n', 'o', MessageType_MessageType_PassphraseRequest, PassphraseRequest_fields, 0},
{'n', 'o', MessageType_MessageType_TxSize, TxSize_fields, 0}, {'n', 'o', MessageType_MessageType_TxSize, TxSize_fields, 0},
{'n', 'o', MessageType_MessageType_WordRequest, WordRequest_fields, 0}, {'n', 'o', MessageType_MessageType_WordRequest, WordRequest_fields, 0},
@ -184,7 +188,7 @@ static inline void msg_out_pad(void)
#if DEBUG_LINK #if DEBUG_LINK
inline void msg_debug_out_pad(void) static inline void msg_debug_out_pad(void)
{ {
if (msg_debug_out_cur == 0) return; if (msg_debug_out_cur == 0) return;
while (msg_debug_out_cur < 64) { while (msg_debug_out_cur < 64) {

View File

@ -142,31 +142,29 @@ const char *requestPin(PinMatrixRequestType type, const char *text)
bool protectPin(bool use_cached) bool protectPin(bool use_cached)
{ {
if (!storage.has_pin || strlen(storage.pin) == 0 || (use_cached && session_isPinCached())) { if (!storage.has_pin || storage.pin[0] == 0 || (use_cached && session_isPinCached())) {
return true; return true;
} }
uint32_t fails = storage_getPinFails(); uint32_t *fails = storage_getPinFailsPtr();
if (fails) { uint32_t wait = ~*fails;
uint32_t wait; while (wait > 0) {
wait = (fails < 32) ? (1u << fails) : 0xFFFFFFFF; // convert wait to secstr string
while (--wait > 0) { char secstrbuf[20];
// convert wait to secstr string strlcpy(secstrbuf, "________0 seconds", sizeof(secstrbuf));
char secstrbuf[20]; char *secstr = secstrbuf + 9;
strlcpy(secstrbuf, "________0 seconds", sizeof(secstrbuf)); uint32_t secs = wait;
char *secstr = secstrbuf + 9; while (secs > 0 && secstr >= secstrbuf) {
uint32_t secs = wait; secstr--;
while (secs > 0 && secstr >= secstrbuf) { *secstr = (secs % 10) + '0';
secstr--; secs /= 10;
*secstr = (secs % 10) + '0';
secs /= 10;
}
if (wait == 1) {
secstrbuf[16] = 0;
}
layoutDialog(DIALOG_ICON_INFO, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait", secstr, "to continue ...", NULL);
// wait one second
usbDelay(840000);
} }
if (wait == 1) {
secstrbuf[16] = 0;
}
layoutDialog(DIALOG_ICON_INFO, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait", secstr, "to continue ...", NULL);
// wait one second
usbDelay(840000);
wait--;
} }
const char *pin; const char *pin;
pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, "Please enter current PIN:"); pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, "Please enter current PIN:");
@ -174,11 +172,9 @@ bool protectPin(bool use_cached)
fsm_sendFailure(FailureType_Failure_PinCancelled, "PIN Cancelled"); fsm_sendFailure(FailureType_Failure_PinCancelled, "PIN Cancelled");
return false; return false;
} }
storage_increasePinFails(); if (storage_increasePinFails(fails) && storage_isPinCorrect(pin)) {
bool increase_failed = (fails >= storage_getPinFails());
if (storage_isPinCorrect(pin) && !increase_failed) {
session_cachePin(); session_cachePin();
storage_resetPinFails(); storage_resetPinFails(fails);
return true; return true;
} else { } else {
fsm_sendFailure(FailureType_Failure_PinInvalid, "Invalid PIN"); fsm_sendFailure(FailureType_Failure_PinInvalid, "Invalid PIN");

View File

@ -5,6 +5,8 @@
const uint32_t CoinType_address_type_default = 0u; const uint32_t CoinType_address_type_default = 0u;
const uint32_t CoinType_address_type_p2sh_default = 5u; const uint32_t CoinType_address_type_p2sh_default = 5u;
const uint32_t CoinType_address_type_p2wpkh_default = 6u;
const uint32_t CoinType_address_type_p2wsh_default = 10u;
const uint32_t TxInputType_sequence_default = 4294967295u; const uint32_t TxInputType_sequence_default = 4294967295u;
const InputScriptType TxInputType_script_type_default = InputScriptType_SPENDADDRESS; const InputScriptType TxInputType_script_type_default = InputScriptType_SPENDADDRESS;
const uint32_t IdentityType_index_default = 0u; const uint32_t IdentityType_index_default = 0u;
@ -26,12 +28,14 @@ const pb_field_t HDNodePathType_fields[3] = {
PB_LAST_FIELD PB_LAST_FIELD
}; };
const pb_field_t CoinType_fields[6] = { const pb_field_t CoinType_fields[8] = {
PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, CoinType, coin_name, coin_name, 0), PB_FIELD2( 1, STRING , OPTIONAL, STATIC , FIRST, CoinType, coin_name, coin_name, 0),
PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, CoinType, coin_shortcut, coin_name, 0), PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, CoinType, coin_shortcut, coin_name, 0),
PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type, coin_shortcut, &CoinType_address_type_default), PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type, coin_shortcut, &CoinType_address_type_default),
PB_FIELD2( 4, UINT64 , OPTIONAL, STATIC , OTHER, CoinType, maxfee_kb, address_type, 0), PB_FIELD2( 4, UINT64 , OPTIONAL, STATIC , OTHER, CoinType, maxfee_kb, address_type, 0),
PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type_p2sh, maxfee_kb, &CoinType_address_type_p2sh_default), PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type_p2sh, maxfee_kb, &CoinType_address_type_p2sh_default),
PB_FIELD2( 6, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type_p2wpkh, address_type_p2sh, &CoinType_address_type_p2wpkh_default),
PB_FIELD2( 7, UINT32 , OPTIONAL, STATIC , OTHER, CoinType, address_type_p2wsh, address_type_p2wpkh, &CoinType_address_type_p2wsh_default),
PB_LAST_FIELD PB_LAST_FIELD
}; };

View File

@ -75,6 +75,10 @@ typedef struct _CoinType {
uint64_t maxfee_kb; uint64_t maxfee_kb;
bool has_address_type_p2sh; bool has_address_type_p2sh;
uint32_t address_type_p2sh; uint32_t address_type_p2sh;
bool has_address_type_p2wpkh;
uint32_t address_type_p2wpkh;
bool has_address_type_p2wsh;
uint32_t address_type_p2wsh;
} CoinType; } CoinType;
typedef struct { typedef struct {
@ -248,6 +252,8 @@ extern const pb_extension_type_t wire_debug_out;
/* Default values for struct fields */ /* Default values for struct fields */
extern const uint32_t CoinType_address_type_default; extern const uint32_t CoinType_address_type_default;
extern const uint32_t CoinType_address_type_p2sh_default; extern const uint32_t CoinType_address_type_p2sh_default;
extern const uint32_t CoinType_address_type_p2wpkh_default;
extern const uint32_t CoinType_address_type_p2wsh_default;
extern const uint32_t TxInputType_sequence_default; extern const uint32_t TxInputType_sequence_default;
extern const InputScriptType TxInputType_script_type_default; extern const InputScriptType TxInputType_script_type_default;
extern const uint32_t IdentityType_index_default; extern const uint32_t IdentityType_index_default;
@ -255,7 +261,7 @@ extern const uint32_t IdentityType_index_default;
/* Initializer values for message structs */ /* Initializer values for message structs */
#define HDNodeType_init_default {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define HDNodeType_init_default {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}}
#define HDNodePathType_init_default {HDNodeType_init_default, 0, {0, 0, 0, 0, 0, 0, 0, 0}} #define HDNodePathType_init_default {HDNodeType_init_default, 0, {0, 0, 0, 0, 0, 0, 0, 0}}
#define CoinType_init_default {false, "", false, "", false, 0u, false, 0, false, 5u} #define CoinType_init_default {false, "", false, "", false, 0u, false, 0, false, 5u, false, 6u, false, 10u}
#define MultisigRedeemScriptType_init_default {0, {HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default}, 0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}, false, 0} #define MultisigRedeemScriptType_init_default {0, {HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default, HDNodePathType_init_default}, 0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}, false, 0}
#define TxInputType_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 4294967295u, false, InputScriptType_SPENDADDRESS, false, MultisigRedeemScriptType_init_default} #define TxInputType_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 4294967295u, false, InputScriptType_SPENDADDRESS, false, MultisigRedeemScriptType_init_default}
#define TxOutputType_init_default {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_default, false, {0, {0}}} #define TxOutputType_init_default {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_default, false, {0, {0}}}
@ -266,7 +272,7 @@ extern const uint32_t IdentityType_index_default;
#define IdentityType_init_default {false, "", false, "", false, "", false, "", false, "", false, 0u} #define IdentityType_init_default {false, "", false, "", false, "", false, "", false, "", false, 0u}
#define HDNodeType_init_zero {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define HDNodeType_init_zero {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}}
#define HDNodePathType_init_zero {HDNodeType_init_zero, 0, {0, 0, 0, 0, 0, 0, 0, 0}} #define HDNodePathType_init_zero {HDNodeType_init_zero, 0, {0, 0, 0, 0, 0, 0, 0, 0}}
#define CoinType_init_zero {false, "", false, "", false, 0, false, 0, false, 0} #define CoinType_init_zero {false, "", false, "", false, 0, false, 0, false, 0, false, 0, false, 0}
#define MultisigRedeemScriptType_init_zero {0, {HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero}, 0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}, false, 0} #define MultisigRedeemScriptType_init_zero {0, {HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero, HDNodePathType_init_zero}, 0, {{0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}, {0, {0}}}, false, 0}
#define TxInputType_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 0, false, (InputScriptType)0, false, MultisigRedeemScriptType_init_zero} #define TxInputType_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 0, false, (InputScriptType)0, false, MultisigRedeemScriptType_init_zero}
#define TxOutputType_init_zero {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, {0, {0}}} #define TxOutputType_init_zero {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, {0, {0}}}
@ -282,6 +288,8 @@ extern const uint32_t IdentityType_index_default;
#define CoinType_address_type_tag 3 #define CoinType_address_type_tag 3
#define CoinType_maxfee_kb_tag 4 #define CoinType_maxfee_kb_tag 4
#define CoinType_address_type_p2sh_tag 5 #define CoinType_address_type_p2sh_tag 5
#define CoinType_address_type_p2wpkh_tag 6
#define CoinType_address_type_p2wsh_tag 7
#define HDNodeType_depth_tag 1 #define HDNodeType_depth_tag 1
#define HDNodeType_fingerprint_tag 2 #define HDNodeType_fingerprint_tag 2
#define HDNodeType_child_num_tag 3 #define HDNodeType_child_num_tag 3
@ -334,7 +342,7 @@ extern const uint32_t IdentityType_index_default;
/* Struct field encoding specification for nanopb */ /* Struct field encoding specification for nanopb */
extern const pb_field_t HDNodeType_fields[7]; extern const pb_field_t HDNodeType_fields[7];
extern const pb_field_t HDNodePathType_fields[3]; extern const pb_field_t HDNodePathType_fields[3];
extern const pb_field_t CoinType_fields[6]; extern const pb_field_t CoinType_fields[8];
extern const pb_field_t MultisigRedeemScriptType_fields[4]; extern const pb_field_t MultisigRedeemScriptType_fields[4];
extern const pb_field_t TxInputType_fields[8]; extern const pb_field_t TxInputType_fields[8];
extern const pb_field_t TxOutputType_fields[7]; extern const pb_field_t TxOutputType_fields[7];
@ -347,7 +355,7 @@ extern const pb_field_t IdentityType_fields[7];
/* Maximum encoded size of messages (where known) */ /* Maximum encoded size of messages (where known) */
#define HDNodeType_size 121 #define HDNodeType_size 121
#define HDNodePathType_size 171 #define HDNodePathType_size 171
#define CoinType_size 53 #define CoinType_size 65
#define MultisigRedeemScriptType_size 3741 #define MultisigRedeemScriptType_size 3741
#define TxInputType_size 5497 #define TxInputType_size 5497
#define TxOutputType_size 3929 #define TxOutputType_size 3929

View File

@ -40,13 +40,40 @@
#include "protect.h" #include "protect.h"
#include "layout2.h" #include "layout2.h"
_Static_assert(sizeof(Storage) <= FLASH_STORAGE_LEN, "Storage struct is too large for TREZOR flash");
Storage storage; Storage storage;
uint8_t storage_uuid[12]; uint8_t storage_uuid[12];
char storage_uuid_str[25]; char storage_uuid_str[25];
/*
storage layout:
offset | type/length | description
--------+-------------+-------------------------------
0x0000 | 4 bytes | magic = 'stor'
0x0004 | 12 bytes | uuid
0x0010 | ? | Storage structure
0x4000 | 4 kbytes | area for pin failures
0x5000 | 12 kbytes | reserved
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.
*/
#define FLASH_STORAGE_PINAREA (FLASH_META_START + 0x4000)
#define FLASH_STORAGE_PINAREA_LEN (0x1000)
#define FLASH_STORAGE_REALLEN (4 + sizeof(storage_uuid) + sizeof(Storage))
_Static_assert(FLASH_STORAGE_START + FLASH_STORAGE_REALLEN <= FLASH_STORAGE_PINAREA, "Storage struct is too large for TREZOR flash");
_Static_assert((sizeof(storage_uuid) & 3) == 0, "storage uuid unaligned");
_Static_assert((sizeof(storage) & 3) == 0, "storage unaligned");
static bool sessionSeedCached; static bool sessionSeedCached;
static uint8_t sessionSeed[64]; static uint8_t sessionSeed[64];
static bool sessionPinCached; static bool sessionPinCached;
@ -54,36 +81,41 @@ static bool sessionPinCached;
static bool sessionPassphraseCached; static bool sessionPassphraseCached;
static char sessionPassphrase[51]; static char sessionPassphrase[51];
/* #define STORAGE_VERSION 6
storage layout:
offset | type/length | description void storage_check_flash_errors(void)
--------+-------------+------------------------------- {
0x0000 | 4 bytes | magic = 'stor' // flash operation failed
0x0004 | 12 bytes | uuid if (FLASH_SR & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) {
0x0010 | ? | Storage structure layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Storage failure", "detected.", NULL, "Please unplug", "the device.", NULL);
*/ for (;;) { }
}
#define STORAGE_VERSION 5 }
void storage_from_flash(uint32_t version) void storage_from_flash(uint32_t version)
{ {
switch (version) { // version 1: since 1.0.0
case 1: // copy (since 1.0.0) // version 2: since 1.2.1
memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); // version 3: since 1.3.1
break; // version 4: since 1.3.2
case 2: // copy (since 1.2.1) // version 5: since 1.3.3
memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); // version 6: since 1.3.6
break; memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage));
case 3: // copy (since 1.3.1) if (version <= 5) {
memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); // convert PIN failure counter from version 5 format
break; uint32_t pinctr = storage.has_pin_failed_attempts
case 4: // copy (since 1.3.2) ? storage.pin_failed_attempts : 0;
memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); if (pinctr > 31)
break; pinctr = 31;
case 5: // copy (since 1.3.3) flash_clear_status_flags();
memcpy(&storage, (void *)(FLASH_STORAGE_START + 4 + sizeof(storage_uuid)), sizeof(Storage)); flash_unlock();
break; // erase extra storage sector
flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32);
flash_program_word(FLASH_STORAGE_PINAREA, 0xffffffff << pinctr);
flash_lock();
storage_check_flash_errors();
storage.has_pin_failed_attempts = false;
storage.pin_failed_attempts = 0;
} }
storage.version = STORAGE_VERSION; storage.version = STORAGE_VERSION;
} }
@ -136,35 +168,41 @@ void session_clear(bool clear_pin)
} }
} }
static uint8_t meta_backup[FLASH_META_LEN]; static uint32_t storage_flash_words(uint32_t addr, uint32_t *src, int nwords) {
int i;
for (i = 0; i < nwords; i++) {
flash_program_word(addr, *src++);
addr += 4;
}
return addr;
}
void storage_commit(void) void storage_commit(void)
{ {
int i; uint8_t meta_backup[FLASH_META_DESC_LEN];
uint32_t *w;
// backup meta // backup meta
memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_LEN); memcpy(meta_backup, (uint8_t*)FLASH_META_START, FLASH_META_DESC_LEN);
flash_clear_status_flags(); flash_clear_status_flags();
flash_unlock(); flash_unlock();
// erase storage // erase storage
for (i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) { flash_erase_sector(FLASH_META_SECTOR_FIRST, FLASH_CR_PROGRAM_X32);
flash_erase_sector(i, FLASH_CR_PROGRAM_X32); // copy meta
} uint32_t flash = FLASH_META_START;
// modify storage flash = storage_flash_words(flash, (uint32_t *)meta_backup, FLASH_META_DESC_LEN/4);
memcpy(meta_backup + FLASH_META_DESC_LEN, "stor", 4); // copy storage
memcpy(meta_backup + FLASH_META_DESC_LEN + 4, storage_uuid, sizeof(storage_uuid)); flash_program_word(flash, *(uint32_t *) "stor");
memcpy(meta_backup + FLASH_META_DESC_LEN + 4 + sizeof(storage_uuid), &storage, sizeof(Storage)); flash += 4;
// copy it back flash = storage_flash_words(flash, (uint32_t *)&storage_uuid, sizeof(storage_uuid)/4);
for (i = 0; i < FLASH_META_LEN / 4; i++) { flash = storage_flash_words(flash, (uint32_t *)&storage, sizeof(storage)/4);
w = (uint32_t *)(meta_backup + i * 4); // fill remainder with zero for future extensions
flash_program_word(FLASH_META_START + i * 4, *w); while (flash < FLASH_STORAGE_PINAREA) {
flash_program_word(flash, 0);
flash += 4;
} }
flash_lock(); flash_lock();
// flash operation failed storage_check_flash_errors();
if (FLASH_SR & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) {
layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Storage failure", "detected.", NULL, "Please unplug", "the device.", NULL);
for (;;) { }
}
} }
void storage_loadDevice(LoadDevice *msg) void storage_loadDevice(LoadDevice *msg)
@ -285,9 +323,14 @@ bool storage_getRootNode(HDNode *node, const char *curve)
if (storage.has_passphrase_protection && storage.passphrase_protection && sessionPassphraseCached && strlen(sessionPassphrase) > 0) { if (storage.has_passphrase_protection && storage.passphrase_protection && sessionPassphraseCached && strlen(sessionPassphrase) > 0) {
// decrypt hd node // decrypt hd node
uint8_t secret[64]; uint8_t secret[64];
uint8_t salt[12]; PBKDF2_HMAC_SHA512_CTX pctx;
memcpy(salt, "TREZORHD", 8); pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), (const uint8_t *)"TREZORHD", 8);
pbkdf2_hmac_sha512((const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), salt, 8, BIP39_PBKDF2_ROUNDS, secret, 64, get_root_node_callback); 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);
aes_decrypt_ctx ctx; aes_decrypt_ctx ctx;
aes_decrypt_key256(secret, &ctx); aes_decrypt_key256(secret, &ctx);
aes_cbc_decrypt(node->chain_code, node->chain_code, 32, secret + 32, &ctx); aes_cbc_decrypt(node->chain_code, node->chain_code, 32, secret + 32, &ctx);
@ -344,7 +387,7 @@ bool storage_hasPin(void)
void storage_setPin(const char *pin) void storage_setPin(const char *pin)
{ {
if (pin && strlen(pin) > 0) { if (pin && pin[0]) {
storage.has_pin = true; storage.has_pin = true;
strlcpy(storage.pin, pin, sizeof(storage.pin)); strlcpy(storage.pin, pin, sizeof(storage.pin));
} else { } else {
@ -376,28 +419,44 @@ bool session_isPinCached(void)
return sessionPinCached; return sessionPinCached;
} }
void storage_resetPinFails(void) void storage_resetPinFails(uint32_t *pinfailsptr)
{ {
storage.has_pin_failed_attempts = true; flash_clear_status_flags();
storage.pin_failed_attempts = 0; flash_unlock();
storage_commit(); if ((uint32_t) (pinfailsptr + 1) - FLASH_STORAGE_PINAREA
} >= FLASH_STORAGE_PINAREA_LEN) {
// erase extra storage sector
void storage_increasePinFails(void) flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32);
{
if (!storage.has_pin_failed_attempts) {
storage.has_pin_failed_attempts = true;
storage.pin_failed_attempts = 1;
} else { } else {
storage.pin_failed_attempts++; flash_program_word((uint32_t) pinfailsptr, 0);
} }
storage_commit(); flash_lock();
storage_check_flash_errors();
} }
uint32_t storage_getPinFails(void) bool storage_increasePinFails(uint32_t *pinfailsptr)
{ {
storage_from_flash(STORAGE_VERSION); // reload from flash uint32_t newctr = *pinfailsptr << 1;
return storage.has_pin_failed_attempts ? storage.pin_failed_attempts : 0; // counter already at maximum, we do not increase it any more
// return success so that a good pin is accepted
if (!newctr)
return true;
flash_clear_status_flags();
flash_unlock();
flash_program_word((uint32_t) pinfailsptr, newctr);
flash_lock();
storage_check_flash_errors();
return *pinfailsptr == newctr;
}
uint32_t *storage_getPinFailsPtr(void)
{
uint32_t *pinfailsptr = (uint32_t *) FLASH_STORAGE_PINAREA;
while (*pinfailsptr == 0)
pinfailsptr++;
return pinfailsptr;
} }
bool storage_isInitialized(void) bool storage_isInitialized(void)

View File

@ -56,9 +56,9 @@ bool storage_hasPin(void);
void storage_setPin(const char *pin); void storage_setPin(const char *pin);
void session_cachePin(void); void session_cachePin(void);
bool session_isPinCached(void); bool session_isPinCached(void);
void storage_resetPinFails(void); void storage_resetPinFails(uint32_t *pinfailptr);
void storage_increasePinFails(void); bool storage_increasePinFails(uint32_t *pinfailptr);
uint32_t storage_getPinFails(void); uint32_t *storage_getPinFailsPtr(void);
uint32_t storage_nextU2FCounter(void); uint32_t storage_nextU2FCounter(void);