1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-29 17:48:10 +00:00

Merge branch 'master' into segwit

This commit is contained in:
Pavol Rusnak 2017-02-08 01:06:45 +01:00
commit 97a061244e
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
28 changed files with 242 additions and 109 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
_attic/
*.o
*.a
*.d

View File

@ -90,8 +90,8 @@ flash2: $(NAME).hex
-c "reset" \
-c "shutdown"
upload:
../../python-trezor/trezorctl firmware_update -f $(NAME).bin
upload: sign
trezorctl firmware_update -f $(NAME).bin
sign: $(NAME).bin
../bootloader/firmware_sign.py -f $(NAME).bin
@ -118,10 +118,10 @@ $(NAME).elf: $(OBJS) $(LDSCRIPT) $(TOOLCHAIN_DIR)/lib/libopencm3_stm32f2.a $(TOP
$(LD) -o $(NAME).elf $(OBJS) -ltrezor -lopencm3_stm32f2 $(LDFLAGS)
%.o: %.c Makefile
$(CC) $(CFLAGS) -o $@ -c $<
$(CC) $(CFLAGS) -MMD -o $@ -c $<
%.small.o: %.c Makefile
$(CC) $(CFLAGS) -o $@ -c $<
$(CC) $(CFLAGS) -MMD -o $@ -c $<
clean:
rm -f $(OBJS)
@ -133,3 +133,5 @@ clean:
rm -f *.list
rm -f *.log
rm -f *.srec
-include $(OBJS:.o=.d)

View File

@ -2,7 +2,7 @@
[![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/
https://trezor.io/
## How to build TREZOR firmware?
@ -24,8 +24,8 @@ This creates file `output/bootloader.bin` and prints its fingerprint and size at
## How to get fingerprint of firmware signed and distributed by SatoshiLabs?
1. Pick version of firmware binary listed on https://wallet.mytrezor.com/data/firmware/releases.json
2. Download it: `wget -O trezor.signed.bin https://wallet.mytrezor.com/data/firmware/trezor-1.3.6.bin`
1. Pick version of firmware binary listed on https://wallet.trezor.io/data/firmware/releases.json
2. Download it: `wget -O trezor.signed.bin https://wallet.trezor.io/data/firmware/trezor-1.3.6.bin`
3. `./firmware-fingerprint.sh trezor.signed.bin`
Step 3 should produce the same sha256 fingerprint like your local build (for the same version tag).

19
bootloader/ChangeLog Normal file
View File

@ -0,0 +1,19 @@
Version 1.3.1
* Fix button testing so it does not break USB communication
Version 1.3.0
* Add test for buttons
* Clean USB descriptor
* Return firmware_present in Features response
* Don't halt on broken firware, stay in bootloader
Version 1.2.7
* Optimize speed of firmware update
Version 1.2.6
* Show hash of unofficial firmware
* Use stack protector
* Clean USB descriptor
Version 1.2.5
* Initial import of code

View File

@ -50,7 +50,7 @@ void layoutFirmwareHash(uint8_t *hash)
void show_halt(void)
{
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Unofficial firmware", "aborted.", NULL, "Unplug your TREZOR", "and see our support", "page at mytrezor.com");
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Unofficial firmware", "aborted.", NULL, "Unplug your TREZOR", "contact our support.", NULL);
system_halt();
}

View File

@ -1,10 +1,12 @@
#!/usr/bin/env python2
#!/usr/bin/env python
from __future__ import print_function
bl = open('bl.bin').read()
fw = open('fw.bin').read()
combined = bl + fw[:256] + (32768-256)*'\x00' + fw[256:]
open('combined.bin', 'w').write(combined)
print 'bootloader : %d bytes' % len(bl)
print 'firmware : %d bytes' % len(fw)
print 'combined : %d bytes' % len(combined)
print('bootloader : %d bytes' % len(bl))
print('firmware : %d bytes' % len(fw))
print('combined : %d bytes' % len(combined))

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python2
#!/usr/bin/env python
import sys
import os

View File

@ -1,10 +1,16 @@
#!/usr/bin/env python2
#!/usr/bin/python
from __future__ import print_function
import argparse
import hashlib
import struct
import binascii
import ecdsa
try:
raw_input
except:
raw_input = input
SLOTS = 3
pubkeys = {
@ -31,17 +37,17 @@ def prepare(data):
# Takes raw OR signed firmware and clean out metadata structure
# This produces 'clean' data for signing
meta = 'TRZR' # magic
if data[:4] == 'TRZR':
meta = b'TRZR' # magic
if data[:4] == b'TRZR':
meta += data[4:4 + struct.calcsize('<I')]
else:
meta += struct.pack('<I', len(data)) # length of the code
meta += '\x00' * SLOTS # signature index #1-#3
meta += '\x01' # flags
meta += '\x00' * 52 # reserved
meta += '\x00' * 64 * SLOTS # signature #1-#3
meta += b'\x00' * SLOTS # signature index #1-#3
meta += b'\x01' # flags
meta += b'\x00' * 52 # reserved
meta += b'\x00' * 64 * SLOTS # signature #1-#3
if data[:4] == 'TRZR':
if data[:4] == b'TRZR':
# Replace existing header
out = meta + data[len(meta):]
else:
@ -54,19 +60,22 @@ def check_signatures(data):
# Analyses given firmware and prints out
# status of included signatures
indexes = [ ord(x) for x in data[INDEXES_START:INDEXES_START + SLOTS] ]
try:
indexes = [ ord(x) for x in data[INDEXES_START:INDEXES_START + SLOTS] ]
except:
indexes = [ x for x in data[INDEXES_START:INDEXES_START + SLOTS] ]
to_sign = prepare(data)[256:] # without meta
fingerprint = hashlib.sha256(to_sign).hexdigest()
print "Firmware fingerprint:", fingerprint
print("Firmware fingerprint:", fingerprint)
used = []
for x in range(SLOTS):
signature = data[SIG_START + 64 * x:SIG_START + 64 * x + 64]
if indexes[x] == 0:
print "Slot #%d" % (x + 1), 'is empty'
print("Slot #%d" % (x + 1), 'is empty')
else:
pk = pubkeys[indexes[x]]
verify = ecdsa.VerifyingKey.from_string(binascii.unhexlify(pk)[1:],
@ -76,13 +85,13 @@ def check_signatures(data):
verify.verify(signature, to_sign, hashfunc=hashlib.sha256)
if indexes[x] in used:
print "Slot #%d signature: DUPLICATE" % (x + 1), binascii.hexlify(signature)
print("Slot #%d signature: DUPLICATE" % (x + 1), binascii.hexlify(signature))
else:
used.append(indexes[x])
print "Slot #%d signature: VALID" % (x + 1), binascii.hexlify(signature)
print("Slot #%d signature: VALID" % (x + 1), binascii.hexlify(signature))
except:
print "Slot #%d signature: INVALID" % (x + 1), binascii.hexlify(signature)
print("Slot #%d signature: INVALID" % (x + 1), binascii.hexlify(signature))
def modify(data, slot, index, signature):
@ -104,8 +113,8 @@ def sign(data, is_pem):
raise Exception("Invalid slot")
if is_pem:
print "Paste ECDSA private key in PEM format and press Enter:"
print "(blank private key removes the signature on given index)"
print("Paste ECDSA private key in PEM format and press Enter:")
print("(blank private key removes the signature on given index)")
pem_key = ''
while True:
key = raw_input()
@ -117,8 +126,8 @@ def sign(data, is_pem):
return modify(data, slot, 0, '\x00' * 64)
key = ecdsa.SigningKey.from_pem(pem_key)
else:
print "Paste SECEXP (in hex) and press Enter:"
print "(blank private key removes the signature on given index)"
print("Paste SECEXP (in hex) and press Enter:")
print("(blank private key removes the signature on given index)")
secexp = raw_input()
if secexp.strip() == '':
# Blank key,let's remove existing signature from slot
@ -128,9 +137,9 @@ def sign(data, is_pem):
to_sign = prepare(data)[256:] # without meta
# Locate proper index of current signing key
pubkey = '04' + binascii.hexlify(key.get_verifying_key().to_string())
pubkey = b'04' + binascii.hexlify(key.get_verifying_key().to_string())
index = None
for i, pk in pubkeys.iteritems():
for i, pk in pubkeys.items():
if pk == pubkey:
index = i
break
@ -148,15 +157,15 @@ def main(args):
curve=ecdsa.curves.SECP256k1,
hashfunc=hashlib.sha256)
print "PRIVATE KEY (SECEXP):"
print binascii.hexlify(key.to_string())
print
print("PRIVATE KEY (SECEXP):")
print(binascii.hexlify(key.to_string()))
print()
print "PRIVATE KEY (PEM):"
print key.to_pem()
print("PRIVATE KEY (PEM):")
print(key.to_pem())
print "PUBLIC KEY:"
print '04' + binascii.hexlify(key.get_verifying_key().to_string())
print("PUBLIC KEY:")
print('04' + binascii.hexlify(key.get_verifying_key().to_string()))
return
if not args.path:
@ -165,14 +174,14 @@ def main(args):
data = open(args.path, 'rb').read()
assert len(data) % 4 == 0
if data[:4] != 'TRZR':
print "Metadata has been added..."
if data[:4] != b'TRZR':
print("Metadata has been added...")
data = prepare(data)
if data[:4] != 'TRZR':
if data[:4] != b'TRZR':
raise Exception("Firmware header expected")
print "Firmware size %d bytes" % len(data)
print("Firmware size %d bytes" % len(data))
check_signatures(data)

View File

@ -1,27 +1,31 @@
#!/usr/bin/env python2
#!/usr/bin/env python
from __future__ import print_function
import hashlib
import os
import subprocess
import ecdsa
from binascii import hexlify, unhexlify
print 'master secret:',
h = raw_input()
print('master secret:', end='')
try:
h = raw_input()
except:
h = input()
if h:
h = unhexlify(h)
h = unhexlify(h).encode('ascii')
else:
h = hashlib.sha256(os.urandom(1024)).digest()
print
print 'master secret:', hexlify(h)
print
print()
print('master secret:', hexlify(h))
print()
for i in range(1, 6):
se = hashlib.sha256(h + chr(i)).hexdigest()
print 'seckey', i, ':', se
se = hashlib.sha256(h + chr(i).encode('ascii')).hexdigest()
print('seckey', i, ':', se)
sk = ecdsa.SigningKey.from_secret_exponent(secexp = int(se, 16), curve=ecdsa.curves.SECP256k1, hashfunc=hashlib.sha256)
print 'pubkey', i, ':', '04' + hexlify(sk.get_verifying_key().to_string())
print sk.to_pem()
print('pubkey', i, ':', (b'04' + hexlify(sk.get_verifying_key().to_string())).decode('ascii'))
print(sk.to_pem().decode('ascii'))
p = subprocess.Popen('ssss-split -t 3 -n 5 -x'.split(' '), stdin = subprocess.PIPE)
p.communicate(input = hexlify(h) + '\n')

View File

@ -335,7 +335,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep)
if (flash_len > FLASH_TOTAL_SIZE + FLASH_META_DESC_LEN - (FLASH_APP_START - FLASH_ORIGIN)) { // firmware is too big
send_msg_failure(dev);
flash_state = STATE_END;
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Firmware is too big.", NULL, "Get official firmware", "from mytrezor.com", NULL, NULL);
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Firmware is too big.", NULL, "Get official firmware", "from trezor.io/start", NULL, NULL);
return;
}
sha256_Init(&ctx);

View File

@ -1,3 +1,9 @@
Version 1.4.2
* Stable release, optional update
* New Matrix-based recovery method
* Minor Ethereum fixes (including EIP-155 replay protection)
* Minor USB, U2F and GPG fixes
Version 1.4.1
* Stable release, optional update
* Support for Zcash JoinSplit transactions
@ -36,7 +42,7 @@ Version 1.3.4
* Updated maxfee per kb for coins
Version 1.3.3
* Stable release, optional update
* Stable release, required update
* Ask for PIN on GetAddress and GetPublicKey
* Signing speed improved

View File

@ -35,6 +35,7 @@ static bool ethereum_signing = false;
static uint32_t data_total, data_left;
static EthereumTxRequest resp;
static uint8_t privkey[32];
static uint8_t chain_id;
struct SHA3_CTX keccak_ctx;
static inline void hash_data(const uint8_t *buf, size_t size)
@ -150,6 +151,15 @@ static void send_signature(void)
uint8_t hash[32], sig[64];
uint8_t v;
layoutProgress("Signing", 1000);
/* eip-155 replay protection */
if (chain_id != 0) {
/* hash v=chain_id, r=0, s=0 */
hash_rlp_field(&chain_id, 1);
hash_rlp_length(0, 0);
hash_rlp_length(0, 0);
}
keccak_Final(&keccak_ctx, hash);
if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v, ethereum_is_canonic) != 0) {
fsm_sendFailure(FailureType_Failure_Other, "Signing failed");
@ -163,7 +173,11 @@ static void send_signature(void)
resp.has_data_length = false;
resp.has_signature_v = true;
resp.signature_v = v + 27;
if (chain_id) {
resp.signature_v = v + 2 * chain_id + 35;
} else {
resp.signature_v = v + 27;
}
resp.has_signature_r = true;
resp.signature_r.size = 32;
@ -228,7 +242,11 @@ static void ethereumFormatAmount(bignum256 *val, char buffer[25])
// remove trailing dot.
if (value_ptr[-1] == '.')
value_ptr--;
strcpy(value_ptr, " ETH");
if (chain_id == 61 || chain_id == 62) {
strcpy(value_ptr, " ETC");
} else {
strcpy(value_ptr, " ETH");
}
// value is at most 16 + 4 + 1 characters long
} else {
// value is bigger than 1e9 ETH => won't fit on display (probably won't happen unless you are Vitalik)
@ -383,7 +401,7 @@ static void layoutEthereumFee(const uint8_t *value, uint32_t value_len,
static bool ethereum_signing_check(EthereumSignTx *msg)
{
if (!msg->has_nonce || !msg->has_gas_price || !msg->has_gas_limit) {
if (!msg->has_gas_price || !msg->has_gas_limit) {
return false;
}
@ -418,13 +436,22 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node)
msg->data_initial_chunk.size = 0;
if (!msg->has_to)
msg->to.size = 0;
if (!msg->has_nonce)
msg->nonce.size = 0;
if (msg->has_data_length) {
if (msg->data_length == 0) {
fsm_sendFailure(FailureType_Failure_Other, "Invalid data length provided");
/* eip-155 chain id */
if (msg->has_chain_id) {
if (msg->chain_id < 1 || msg->chain_id > 109) {
fsm_sendFailure(FailureType_Failure_Other, "Chain Id out of bounds");
ethereum_signing_abort();
return;
}
chain_id = (uint8_t) msg->chain_id;
} else {
chain_id = 0;
}
if (msg->has_data_length && msg->data_length > 0) {
if (!msg->has_data_initial_chunk || msg->data_initial_chunk.size == 0) {
fsm_sendFailure(FailureType_Failure_Other, "Data length provided, but no initial chunk");
ethereum_signing_abort();
@ -491,6 +518,11 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node)
rlp_length += rlp_calculate_length(msg->to.size, msg->to.bytes[0]);
rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]);
rlp_length += rlp_calculate_length(data_total, msg->data_initial_chunk.bytes[0]);
if (chain_id) {
rlp_length += rlp_calculate_length(1, chain_id);
rlp_length += rlp_calculate_length(0, 0);
rlp_length += rlp_calculate_length(0, 0);
}
/* Stage 2: Store header fields */
hash_rlp_list_length(rlp_length);

View File

@ -65,7 +65,7 @@ void layoutHome(void)
oledSwipeLeft();
}
layoutLast = layoutHome;
const char *label = storage_isInitialized() ? storage_getLabel() : "Go to mytrezor.com";
const char *label = storage_isInitialized() ? storage_getLabel() : "Go to trezor.io/start";
const uint8_t *homescreen = storage_getHomescreen();
if (homescreen) {
BITMAP b;
@ -319,10 +319,12 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge)
char row_hostport[64 + 6 + 1];
char row_user[64 + 8 + 1];
bool is_gpg = (strcmp(identity->proto, "gpg") == 0);
if (identity->has_proto && identity->proto[0]) {
if (strcmp(identity->proto, "https") == 0) {
strlcpy(row_proto, "Web sign in to:", sizeof(row_proto));
} else if (strcmp(identity->proto, "gpg") == 0) {
} else if (is_gpg) {
strlcpy(row_proto, "GPG sign for:", sizeof(row_proto));
} else {
strlcpy(row_proto, identity->proto, sizeof(row_proto));
@ -351,6 +353,21 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge)
row_user[0] = 0;
}
if (is_gpg) {
// Split "First Last <first@last.com>" into 2 lines:
// "First Last"
// "first@last.com"
char *email_start = strchr(row_hostport, '<');
if (email_start) {
strlcpy(row_user, email_start + 1, sizeof(row_user));
*email_start = 0;
char *email_end = strchr(row_user, '>');
if (email_end) {
*email_end = 0;
}
}
}
layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm",
"Do you want to sign in?",
row_proto[0] ? row_proto : NULL,

View File

@ -1,7 +1,7 @@
all: messages.pb.c storage.pb.c types.pb.c
%.pb.c: %.pb %.options
nanopb $< -L '#include "%s"' -T
nanopb_generator.py $< -L '#include "%s"' -T
%.pb: %.proto
protoc -I/usr/include -I. $< -o $@

View File

@ -336,7 +336,7 @@ const pb_field_t TxAck_fields[2] = {
PB_LAST_FIELD
};
const pb_field_t EthereumSignTx_fields[9] = {
const pb_field_t EthereumSignTx_fields[10] = {
PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, EthereumSignTx, address_n, address_n, 0),
PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, nonce, address_n, 0),
PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, gas_price, nonce, 0),
@ -345,6 +345,7 @@ const pb_field_t EthereumSignTx_fields[9] = {
PB_FIELD2( 6, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, value, to, 0),
PB_FIELD2( 7, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, data_initial_chunk, value, 0),
PB_FIELD2( 8, UINT32 , OPTIONAL, STATIC , OTHER, EthereumSignTx, data_length, data_initial_chunk, 0),
PB_FIELD2( 9, UINT32 , OPTIONAL, STATIC , OTHER, EthereumSignTx, chain_id, data_length, 0),
PB_LAST_FIELD
};

View File

@ -460,6 +460,8 @@ typedef struct _EthereumSignTx {
EthereumSignTx_data_initial_chunk_t data_initial_chunk;
bool has_data_length;
uint32_t data_length;
bool has_chain_id;
uint32_t chain_id;
} EthereumSignTx;
typedef struct {
@ -894,7 +896,7 @@ extern const uint32_t SimpleSignTx_lock_time_default;
#define SimpleSignTx_init_default {0, {}, 0, {}, 0, {}, false, "Bitcoin", false, 1u, false, 0u}
#define TxRequest_init_default {false, (RequestType)0, false, TxRequestDetailsType_init_default, false, TxRequestSerializedType_init_default}
#define TxAck_init_default {false, TransactionType_init_default}
#define EthereumSignTx_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0}
#define EthereumSignTx_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0}
#define EthereumTxRequest_init_default {false, 0, false, 0, false, {0, {0}}, false, {0, {0}}}
#define EthereumTxAck_init_default {false, {0, {0}}}
#define SignIdentity_init_default {false, IdentityType_init_default, false, {0, {0}}, false, "", false, ""}
@ -960,7 +962,7 @@ extern const uint32_t SimpleSignTx_lock_time_default;
#define SimpleSignTx_init_zero {0, {}, 0, {}, 0, {}, false, "", false, 0, false, 0}
#define TxRequest_init_zero {false, (RequestType)0, false, TxRequestDetailsType_init_zero, false, TxRequestSerializedType_init_zero}
#define TxAck_init_zero {false, TransactionType_init_zero}
#define EthereumSignTx_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0}
#define EthereumSignTx_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0}
#define EthereumTxRequest_init_zero {false, 0, false, 0, false, {0, {0}}, false, {0, {0}}}
#define EthereumTxAck_init_zero {false, {0, {0}}}
#define SignIdentity_init_zero {false, IdentityType_init_zero, false, {0, {0}}, false, "", false, ""}
@ -1049,6 +1051,7 @@ extern const uint32_t SimpleSignTx_lock_time_default;
#define EthereumSignTx_value_tag 6
#define EthereumSignTx_data_initial_chunk_tag 7
#define EthereumSignTx_data_length_tag 8
#define EthereumSignTx_chain_id_tag 9
#define EthereumTxAck_data_chunk_tag 1
#define EthereumTxRequest_data_length_tag 1
#define EthereumTxRequest_signature_v_tag 2
@ -1204,7 +1207,7 @@ extern const pb_field_t SignTx_fields[6];
extern const pb_field_t SimpleSignTx_fields[7];
extern const pb_field_t TxRequest_fields[4];
extern const pb_field_t TxAck_fields[2];
extern const pb_field_t EthereumSignTx_fields[9];
extern const pb_field_t EthereumSignTx_fields[10];
extern const pb_field_t EthereumTxRequest_fields[5];
extern const pb_field_t EthereumTxAck_fields[2];
extern const pb_field_t SignIdentity_fields[5];
@ -1272,7 +1275,7 @@ extern const pb_field_t DebugLinkFlashErase_fields[2];
#define SimpleSignTx_size (31 + 0*TxInputType_size + 0*TxOutputType_size + 0*TransactionType_size)
#define TxRequest_size (18 + TxRequestDetailsType_size + TxRequestSerializedType_size)
#define TxAck_size (6 + TransactionType_size)
#define EthereumSignTx_size 1239
#define EthereumSignTx_size 1245
#define EthereumTxRequest_size 80
#define EthereumTxAck_size 1027
#define SignIdentity_size (558 + IdentityType_size)

View File

@ -214,7 +214,7 @@ static void display_choices(bool twoColumn, char choices[9][12], int num)
format_number(desc, nr);
layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, "Please enter the", (nr < 10 ? desc + 1 : desc), "of your mnemonic", NULL, NULL, NULL);
} else {
oledBox(0, 18, 127, 63, false);
oledBox(0, 27, 127, 63, false);
}
for (row = 0; row < 3; row ++) {
@ -224,6 +224,11 @@ static void display_choices(bool twoColumn, char choices[9][12], int num)
int choice = word_matrix[nColumns*row + col];
const char *text = choice < num ? choices[choice] : "-";
oledDrawString(x - oledStringWidth(text)/2, y, text);
if (twoColumn) {
oledInvert(x - 32 + 1, y - 1, x - 32 + 63 - 1, y + 8);
} else {
oledInvert(x - 22 + 1, y - 1, x - 22 + 41 - 1, y + 8);
}
}
}
oledRefresh();
@ -324,7 +329,7 @@ static void recovery_digit(const char digit) {
/* received final word */
int y = 54 - ((digit - '1')/3)*11;
int x = 64 * (((digit - '1') % 3) > 0);
oledInvert(x, y, x + 63, y + 9);
oledInvert(x + 1, y, x + 62, y + 9);
oledRefresh();
usbSleep(250);

View File

@ -99,11 +99,8 @@ int main(void)
timer_init();
#if DEBUG_LOG
oledSetDebug(1);
#endif
#if DEBUG_LINK
oledSetDebugLink(1);
storage_reset(); // wipe storage if debug link
storage_reset_uuid();
storage_commit();

View File

@ -22,7 +22,7 @@
#define VERSION_MAJOR 1
#define VERSION_MINOR 4
#define VERSION_PATCH 1
#define VERSION_PATCH 2
#define STR(X) #X
#define VERSTR(X) STR(X)

View File

@ -505,6 +505,12 @@ 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++) {
// check high bit for hardened keys
if (! (key_path[i] & 0x80000000)) {
return NULL;
}
}
const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES);
if (!node)

View File

@ -44,6 +44,27 @@
#define ENDPOINT_ADDRESS_U2F_IN (0x83)
#define ENDPOINT_ADDRESS_U2F_OUT (0x03)
#define USB_STRINGS \
X(MANUFACTURER, "SatoshiLabs") \
X(PRODUCT, "TREZOR") \
X(SERIAL_NUMBER, storage_uuid_str) \
X(INTERFACE_MAIN, "TREZOR Interface") \
X(INTERFACE_DEBUG, "TREZOR Debug Link Interface") \
X(INTERFACE_U2F, "U2F Interface")
#define X(name, value) USB_STRING_##name,
enum {
USB_STRING_LANGID_CODES, // LANGID code array
USB_STRINGS
};
#undef X
#define X(name, value) value,
static const char *usb_strings[] = {
USB_STRINGS
};
#undef X
static const struct usb_device_descriptor dev_descr = {
.bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE,
@ -55,9 +76,9 @@ static const struct usb_device_descriptor dev_descr = {
.idVendor = 0x534c,
.idProduct = 0x0001,
.bcdDevice = 0x0100,
.iManufacturer = 1,
.iProduct = 2,
.iSerialNumber = 3,
.iManufacturer = USB_STRING_MANUFACTURER,
.iProduct = USB_STRING_PRODUCT,
.iSerialNumber = USB_STRING_SERIAL_NUMBER,
.bNumConfigurations = 1,
};
@ -186,7 +207,7 @@ static const struct usb_interface_descriptor hid_iface[] = {{
.bInterfaceClass = USB_CLASS_HID,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
.iInterface = 0,
.iInterface = USB_STRING_INTERFACE_MAIN,
.endpoint = hid_endpoints,
.extra = &hid_function,
.extralen = sizeof(hid_function),
@ -217,7 +238,7 @@ static const struct usb_interface_descriptor hid_iface_u2f[] = {{
.bInterfaceClass = USB_CLASS_HID,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
.iInterface = 0,
.iInterface = USB_STRING_INTERFACE_U2F,
.endpoint = hid_endpoints_u2f,
.extra = &hid_function_u2f,
.extralen = sizeof(hid_function_u2f),
@ -249,7 +270,7 @@ static const struct usb_interface_descriptor hid_iface_debug[] = {{
.bInterfaceClass = USB_CLASS_HID,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
.iInterface = 0,
.iInterface = USB_STRING_INTERFACE_DEBUG,
.endpoint = hid_endpoints_debug,
.extra = &hid_function,
.extralen = sizeof(hid_function),
@ -285,12 +306,6 @@ static const struct usb_config_descriptor config = {
.interface = ifaces,
};
static const char *usb_strings[] = {
"SatoshiLabs",
"TREZOR",
(const char *)storage_uuid_str,
};
static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete)
{
(void)complete;
@ -388,7 +403,7 @@ static uint8_t usbd_control_buffer[128];
void usbInit(void)
{
usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer));
usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, sizeof(usb_strings) / sizeof(*usb_strings), usbd_control_buffer, sizeof(usbd_control_buffer));
usbd_register_set_config_callback(usbd_dev, hid_set_config);
}

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python2
#!/usr/bin/env python
from __future__ import print_function
import glob
import os
from PIL import Image
@ -10,14 +11,14 @@ imgs = []
def encode_pixels(img):
r = ''
img = [ (x[0] + x[1] + x[2] > 384 and '1' or '0') for x in img]
for i in range(len(img) / 8):
for i in range(len(img) // 8):
c = ''.join(img[i * 8 : i * 8 + 8])
r += '0x%02x, ' % int(c, 2)
return r
cnt = 0
for fn in sorted(glob.glob('*.png')):
print 'Processing:', fn
print('Processing:', fn)
im = Image.open(fn)
name = os.path.splitext(fn)[0]
w, h = im.size

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python2
#!/usr/bin/env python
from __future__ import print_function
from PIL import Image
class Img(object):
@ -23,12 +24,12 @@ cur = ''
for i in range(256):
x = (i % 16) * 10
y = (i / 16) * 10
y = (i // 16) * 10
cur = ''
while img.pixel(x, y) != None:
val = ''.join(img.pixel(x, y + j) for j in range(8))
x += 1
cur += '\\x%02x' % int(val, 2)
cur = '\\x%02x' % (len(cur) / 4) + cur
cur = '\\x%02x' % (len(cur) // 4) + cur
ch = chr(i) if i >= 32 and i <= 126 else '_'
print '\t/* 0x%02x %c */ (uint8_t *)"%s",' % (i, ch , cur)
print('\t/* 0x%02x %c */ (uint8_t *)"%s",' % (i, ch , cur))

View File

@ -1,4 +1,6 @@
#!/usr/bin/env python2
#!/usr/bin/env python
from __future__ import print_function
handlers = [
'hard_fault_handler',
'mem_manage_handler',

View File

@ -27,13 +27,23 @@
void memory_protect(void)
{
// Reference STM32F205 Flash programming manual revision 5 http://www.st.com/resource/en/programming_manual/cd00233952.pdf
// Section 2.6 Option bytes
// set RDP level 2 WRP for sectors 0 and 1
if ((((*OPTION_BYTES_1) & 0xFFFF) == 0xCCFF) && (((*OPTION_BYTES_2) & 0xFFFF) == 0xFFFC)) {
if ((((*OPTION_BYTES_1) & 0xFFEC) == 0xCCEC) && (((*OPTION_BYTES_2) & 0xFFF) == 0xFFC)) {
return; // already set up correctly - bail out
}
flash_unlock_option_bytes();
// WRP + RDP
flash_program_option_bytes(0xFFFC0000 + 0xCCFF);
// Section 2.8.6 Flash option control register (FLASH_OPTCR)
// Bits 31:28 Reserved, must be kept cleared.
// Bits 27:16 nWRP: Not write protect: write protect bootloader code in flash main memory sectors 0 and 1 (Section 2.3; table 2)
// Bits 15:8 RDP: Read protect: level 2 chip read protection active
// Bits 7:5 USER: User option bytes: no reset on standby, no reset on stop, software watchdog
// Bit 4 Reserved, must be kept cleared.
// Bits 3:2 BOR_LEV: BOR reset Level: BOR off
// Bit 1 OPTSTRT: Option start: ignored by flash_program_option_bytes
// Bit 0 OPTLOCK: Option lock: ignored by flash_program_option_bytes
flash_program_option_bytes(0x0FFCCCEC);
flash_lock_option_bytes();
}

10
oled.c
View File

@ -74,7 +74,7 @@
#define OLED_BUFTGL(X,Y) _oledbuffer[OLED_BUFSIZE - 1 - (X) - ((Y)/8)*OLED_WIDTH] ^= (1 << (7 - (Y)%8))
static uint8_t _oledbuffer[OLED_BUFSIZE];
static bool is_debug_mode = 0;
static bool is_debug_link = 0;
/*
* Send a block of data via the SPI bus.
@ -161,7 +161,7 @@ void oledRefresh()
static uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00, OLED_SETHIGHCOLUMN | 0x00, OLED_SETSTARTLINE | 0x00};
// draw triangle in upper right corner
if (is_debug_mode) {
if (is_debug_link) {
OLED_BUFTGL(OLED_WIDTH - 5, 0); OLED_BUFTGL(OLED_WIDTH - 4, 0); OLED_BUFTGL(OLED_WIDTH - 3, 0); OLED_BUFTGL(OLED_WIDTH - 2, 0); OLED_BUFTGL(OLED_WIDTH - 1, 0);
OLED_BUFTGL(OLED_WIDTH - 4, 1); OLED_BUFTGL(OLED_WIDTH - 3, 1); OLED_BUFTGL(OLED_WIDTH - 2, 1); OLED_BUFTGL(OLED_WIDTH - 1, 1);
OLED_BUFTGL(OLED_WIDTH - 3, 2); OLED_BUFTGL(OLED_WIDTH - 2, 2); OLED_BUFTGL(OLED_WIDTH - 1, 2);
@ -180,7 +180,7 @@ void oledRefresh()
gpio_clear(OLED_DC_PORT, OLED_DC_PIN); // set to CMD
// return it back
if (is_debug_mode) {
if (is_debug_link) {
OLED_BUFTGL(OLED_WIDTH - 5, 0); OLED_BUFTGL(OLED_WIDTH - 4, 0); OLED_BUFTGL(OLED_WIDTH - 3, 0); OLED_BUFTGL(OLED_WIDTH - 2, 0); OLED_BUFTGL(OLED_WIDTH - 1, 0);
OLED_BUFTGL(OLED_WIDTH - 4, 1); OLED_BUFTGL(OLED_WIDTH - 3, 1); OLED_BUFTGL(OLED_WIDTH - 2, 1); OLED_BUFTGL(OLED_WIDTH - 1, 1);
OLED_BUFTGL(OLED_WIDTH - 3, 2); OLED_BUFTGL(OLED_WIDTH - 2, 2); OLED_BUFTGL(OLED_WIDTH - 1, 2);
@ -194,9 +194,9 @@ const uint8_t *oledGetBuffer()
return _oledbuffer;
}
void oledSetDebug(bool set)
void oledSetDebugLink(bool set)
{
is_debug_mode = set;
is_debug_link = set;
oledRefresh();
}

2
oled.h
View File

@ -34,7 +34,7 @@ void oledInit(void);
void oledClear(void);
void oledRefresh(void);
void oledSetDebug(bool set);
void oledSetDebugLink(bool set);
void oledSetBuffer(uint8_t *buf);
const uint8_t *oledGetBuffer(void);
void oledDrawPixel(int x, int y);

@ -1 +1 @@
Subproject commit 61af3d5e931ab41f0b81f462fbdc626d6bbec4f4
Subproject commit 9d2ab7318db08a47b35588b0593fb66129214f8d