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:
commit
97a061244e
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
_attic/
|
||||
*.o
|
||||
*.a
|
||||
*.d
|
||||
|
@ -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)
|
||||
|
@ -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
19
bootloader/ChangeLog
Normal 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
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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))
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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')
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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 $@
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -1,4 +1,6 @@
|
||||
#!/usr/bin/env python2
|
||||
#!/usr/bin/env python
|
||||
from __future__ import print_function
|
||||
|
||||
handlers = [
|
||||
'hard_fault_handler',
|
||||
'mem_manage_handler',
|
||||
|
16
memory.c
16
memory.c
@ -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
10
oled.c
@ -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
2
oled.h
@ -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);
|
||||
|
2
vendor/trezor-common
vendored
2
vendor/trezor-common
vendored
@ -1 +1 @@
|
||||
Subproject commit 61af3d5e931ab41f0b81f462fbdc626d6bbec4f4
|
||||
Subproject commit 9d2ab7318db08a47b35588b0593fb66129214f8d
|
Loading…
Reference in New Issue
Block a user