mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-04-20 17:19:01 +00:00
Updated branch u2f
This commit is contained in:
commit
cf38291ca4
9
.gitmodules
vendored
9
.gitmodules
vendored
@ -1,9 +1,12 @@
|
||||
[submodule "trezor-crypto"]
|
||||
path = trezor-crypto
|
||||
path = vendor/trezor-crypto
|
||||
url = https://github.com/trezor/trezor-crypto.git
|
||||
[submodule "trezor-common"]
|
||||
path = trezor-common
|
||||
path = vendor/trezor-common
|
||||
url = https://github.com/trezor/trezor-common.git
|
||||
[submodule "trezor-qrenc"]
|
||||
path = trezor-qrenc
|
||||
path = vendor/trezor-qrenc
|
||||
url = https://github.com/trezor/trezor-qrenc.git
|
||||
[submodule "libopencm3"]
|
||||
path = vendor/libopencm3
|
||||
url = https://github.com/libopencm3/libopencm3.git
|
||||
|
11
.travis.yml
11
.travis.yml
@ -4,11 +4,10 @@ install:
|
||||
- sudo add-apt-repository ppa:terry.guo/gcc-arm-embedded -y
|
||||
- sudo apt-get update
|
||||
- sudo apt-get install -y build-essential git gcc-arm-none-eabi
|
||||
- git clone https://github.com/libopencm3/libopencm3
|
||||
|
||||
script:
|
||||
- make -C libopencm3
|
||||
- TOOLCHAIN_DIR=libopencm3 make
|
||||
- TOOLCHAIN_DIR=../libopencm3 make -C firmware
|
||||
- TOOLCHAIN_DIR=../libopencm3 make -C bootloader
|
||||
- TOOLCHAIN_DIR=../libopencm3 make -C demo
|
||||
- make -C vendor/libopencm3
|
||||
- make
|
||||
- make -C firmware
|
||||
- make -C bootloader
|
||||
- make -C demo
|
||||
|
@ -9,12 +9,3 @@ RUN apt-get update
|
||||
# install build tools and dependencies
|
||||
|
||||
RUN apt-get install -y build-essential git python gcc-arm-none-eabi
|
||||
|
||||
# clone the source code
|
||||
|
||||
RUN git clone https://github.com/libopencm3/libopencm3
|
||||
|
||||
# build libopencm3
|
||||
|
||||
ENV LIBOPENCM3_GITREV 7b29caed1a726b5cef4c269b6a6ef7a1f1dd105c
|
||||
RUN cd libopencm3 && git checkout $LIBOPENCM3_GITREV && make
|
||||
|
@ -1,5 +1,5 @@
|
||||
TOP_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
|
||||
TOOLCHAIN_DIR ?= $(TOP_DIR)/../libopencm3
|
||||
TOOLCHAIN_DIR ?= $(TOP_DIR)vendor/libopencm3
|
||||
|
||||
PREFIX ?= arm-none-eabi-
|
||||
CC = $(PREFIX)gcc
|
||||
@ -9,9 +9,12 @@ OBJDUMP = $(PREFIX)objdump
|
||||
FLASH = st-flash
|
||||
OPENOCD = openocd
|
||||
|
||||
OPTFLAGS = -O3 -g -DNDEBUG
|
||||
OPTFLAGS ?= -O3
|
||||
DBGFLAGS ?= -g -DNDEBUG
|
||||
|
||||
CFLAGS += $(OPTFLAGS) \
|
||||
$(DBGFLAGS) \
|
||||
-std=c99 \
|
||||
-W \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
@ -42,9 +45,10 @@ CFLAGS += $(OPTFLAGS) \
|
||||
-DSTM32F2 \
|
||||
-I$(TOOLCHAIN_DIR)/include \
|
||||
-I$(TOP_DIR) \
|
||||
-I$(TOP_DIR)/gen \
|
||||
-I$(TOP_DIR)/trezor-crypto \
|
||||
-I$(TOP_DIR)/trezor-qrenc
|
||||
-I$(TOP_DIR)gen \
|
||||
-I$(TOP_DIR)vendor/trezor-crypto \
|
||||
-I$(TOP_DIR)vendor/trezor-crypto/ed25519-donna \
|
||||
-I$(TOP_DIR)vendor/trezor-qrenc
|
||||
|
||||
ifdef APPVER
|
||||
CFLAGS += -DAPPVER=$(APPVER)
|
||||
|
12
README.md
12
README.md
@ -8,13 +8,23 @@ http://bitcointrezor.com/
|
||||
How to build TREZOR firmware?
|
||||
-----------------------------
|
||||
|
||||
1. Install Docker (from docker.com or from your distribution repositories)
|
||||
1. <a href="https://docs.docker.com/engine/installation/">Install Docker</a>
|
||||
2. `git clone https://github.com/trezor/trezor-mcu.git`
|
||||
3. `cd trezor-mcu`
|
||||
4. `./firmware-docker-build.sh TAG` (where TAG is v1.3.2 for example, if left blank the script builds latest commit)
|
||||
|
||||
This creates file `output/trezor-TAG.bin` and prints its fingerprint at the last line of the build log.
|
||||
|
||||
How to build TREZOR bootloader?
|
||||
-----------------------------
|
||||
|
||||
1. <a href="https://docs.docker.com/engine/installation/">Install Docker</a>
|
||||
2. `git clone https://github.com/trezor/trezor-mcu.git`
|
||||
3. `cd trezor-mcu`
|
||||
4. `./bootloader-docker-build.sh`
|
||||
|
||||
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?
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
|
22
bootloader-docker-build.sh
Executable file
22
bootloader-docker-build.sh
Executable file
@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
IMAGETAG=trezor-mcu-build
|
||||
FIRMWARETAG=${1:-master}
|
||||
|
||||
docker build -t $IMAGETAG .
|
||||
docker run -t -v $(pwd)/output:/output $IMAGETAG /bin/sh -c "\
|
||||
git clone https://github.com/trezor/trezor-mcu && \
|
||||
cd trezor-mcu && \
|
||||
git checkout $FIRMWARETAG && \
|
||||
git submodule update --init && \
|
||||
make -C vendor/libopencm3 && \
|
||||
export OPTFLAGS=-Os
|
||||
make && \
|
||||
make -C bootloader && \
|
||||
cp bootloader/bootloader.bin /output/bootloader-$FIRMWARETAG.bin"
|
||||
|
||||
echo "---------------------"
|
||||
echo "Bootloader fingerprint:"
|
||||
FILENAME=output/bootloader-$FIRMWARETAG.bin
|
||||
sha256sum "$FILENAME"
|
||||
FILESIZE=$(stat -c%s "$FILENAME")
|
||||
echo "Bootloader size: $FILESIZE bytes (out of 32768 maximum)"
|
@ -4,12 +4,12 @@ OBJS += bootloader.o
|
||||
OBJS += signatures.o
|
||||
OBJS += usb.o
|
||||
|
||||
OBJS += ../trezor-crypto/bignum.o
|
||||
OBJS += ../trezor-crypto/ecdsa.small.o
|
||||
OBJS += ../trezor-crypto/hmac.o
|
||||
OBJS += ../trezor-crypto/ripemd160.o
|
||||
OBJS += ../trezor-crypto/secp256k1.small.o
|
||||
OBJS += ../trezor-crypto/sha2.o
|
||||
OBJS += ../vendor/trezor-crypto/bignum.o
|
||||
OBJS += ../vendor/trezor-crypto/ecdsa.small.o
|
||||
OBJS += ../vendor/trezor-crypto/hmac.o
|
||||
OBJS += ../vendor/trezor-crypto/ripemd160.o
|
||||
OBJS += ../vendor/trezor-crypto/secp256k1.small.o
|
||||
OBJS += ../vendor/trezor-crypto/sha2.o
|
||||
|
||||
CFLAGS += -DUSE_PRECOMPUTED_IV=0
|
||||
CFLAGS += -DUSE_PRECOMPUTED_CP=0
|
||||
|
@ -38,7 +38,23 @@
|
||||
#error Bootloader cannot be used in app mode
|
||||
#endif
|
||||
|
||||
void show_unofficial_warning(void)
|
||||
void layoutFirmwareHash(uint8_t *hash)
|
||||
{
|
||||
char str[4][17];
|
||||
int i;
|
||||
for (i = 0; i < 4; i++) {
|
||||
data2hex(hash + i * 8, 8, str[i]);
|
||||
}
|
||||
layoutDialog(DIALOG_ICON_QUESTION, "Abort", "Continue", "Compare fingerprints", str[0], str[1], str[2], str[3], NULL, NULL);
|
||||
}
|
||||
|
||||
void show_halt(void)
|
||||
{
|
||||
layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Unofficial firmware", "aborted.", NULL, "Unplug your TREZOR", "and see our support", "page at mytrezor.com");
|
||||
system_halt();
|
||||
}
|
||||
|
||||
void show_unofficial_warning(uint8_t *hash)
|
||||
{
|
||||
layoutDialog(DIALOG_ICON_WARNING, "Abort", "I'll take the risk", NULL, "WARNING!", NULL, "Unofficial firmware", "detected.", NULL, NULL);
|
||||
|
||||
@ -47,19 +63,29 @@ void show_unofficial_warning(void)
|
||||
buttonUpdate();
|
||||
} while (!button.YesUp && !button.NoUp);
|
||||
|
||||
if (button.YesUp) {
|
||||
return; // yes button was pressed -> return
|
||||
if (button.NoUp) {
|
||||
show_halt(); // no button was pressed -> halt
|
||||
}
|
||||
|
||||
layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Unofficial firmware", "aborted.", NULL, "Unplug your TREZOR", "and see our support", "page at mytrezor.com");
|
||||
system_halt();
|
||||
layoutFirmwareHash(hash);
|
||||
|
||||
do {
|
||||
delay(100000);
|
||||
buttonUpdate();
|
||||
} while (!button.YesUp && !button.NoUp);
|
||||
|
||||
if (button.NoUp) {
|
||||
show_halt(); // no button was pressed -> halt
|
||||
}
|
||||
|
||||
// everything is OK, user pressed 2x Continue -> continue program
|
||||
}
|
||||
|
||||
void load_app(void)
|
||||
{
|
||||
// jump to app
|
||||
SCB_VTOR = FLASH_APP_START; // & 0xFFFF;
|
||||
asm volatile("msr msp, %0"::"g" (*(volatile uint32_t *)FLASH_APP_START));
|
||||
__asm__ volatile("msr msp, %0"::"g" (*(volatile uint32_t *)FLASH_APP_START));
|
||||
(*(void (**)())(FLASH_APP_START + 4))();
|
||||
}
|
||||
|
||||
@ -128,8 +154,9 @@ int main(void)
|
||||
oledDrawBitmap(40, 0, &bmp_logo64_empty);
|
||||
oledRefresh();
|
||||
|
||||
if (!signatures_ok()) {
|
||||
show_unofficial_warning();
|
||||
uint8_t hash[32];
|
||||
if (!signatures_ok(hash)) {
|
||||
show_unofficial_warning(hash);
|
||||
}
|
||||
|
||||
load_app();
|
||||
|
@ -22,15 +22,17 @@
|
||||
|
||||
#define VERSION_MAJOR 1
|
||||
#define VERSION_MINOR 2
|
||||
#define VERSION_PATCH 5
|
||||
#define VERSION_PATCH 6
|
||||
|
||||
#define STR(X) #X
|
||||
#define VERSTR(X) STR(X)
|
||||
|
||||
#define VERSION_MAJOR_CHAR "\x01"
|
||||
#define VERSION_MINOR_CHAR "\x02"
|
||||
#define VERSION_PATCH_CHAR "\x05"
|
||||
#define VERSION_PATCH_CHAR "\x06"
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
void layoutFirmwareHash(uint8_t *hash);
|
||||
|
||||
#endif
|
||||
|
@ -18,10 +18,12 @@
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "signatures.h"
|
||||
#include "ecdsa.h"
|
||||
#include "secp256k1.h"
|
||||
#include "sha2.h"
|
||||
#include "bootloader.h"
|
||||
|
||||
#define PUBKEYS 5
|
||||
@ -36,7 +38,7 @@ static const uint8_t *pubkey[PUBKEYS] = {
|
||||
|
||||
#define SIGNATURES 3
|
||||
|
||||
int signatures_ok(void)
|
||||
int signatures_ok(uint8_t *store_hash)
|
||||
{
|
||||
uint32_t codelen = *((uint32_t *)FLASH_META_CODELEN);
|
||||
uint8_t sigindex1, sigindex2, sigindex3;
|
||||
@ -53,13 +55,19 @@ int signatures_ok(void)
|
||||
if (sigindex1 == sigindex3) return 0; // duplicate use
|
||||
if (sigindex2 == sigindex3) return 0; // duplicate use
|
||||
|
||||
if (ecdsa_verify(&secp256k1, pubkey[sigindex1 - 1], (uint8_t *)FLASH_META_SIG1, (uint8_t *)FLASH_APP_START, codelen) != 0) { // failure
|
||||
uint8_t hash[32];
|
||||
sha256_Raw((uint8_t *)FLASH_APP_START, codelen, hash);
|
||||
if (store_hash) {
|
||||
memcpy(store_hash, hash, 32);
|
||||
}
|
||||
|
||||
if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex1 - 1], (uint8_t *)FLASH_META_SIG1, hash) != 0) { // failure
|
||||
return 0;
|
||||
}
|
||||
if (ecdsa_verify(&secp256k1, pubkey[sigindex2 - 1], (uint8_t *)FLASH_META_SIG2, (uint8_t *)FLASH_APP_START, codelen) != 0) { // failure
|
||||
if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex2 - 1], (uint8_t *)FLASH_META_SIG2, hash) != 0) { // failure
|
||||
return 0;
|
||||
}
|
||||
if (ecdsa_verify(&secp256k1, pubkey[sigindex3 - 1], (uint8_t *)FLASH_META_SIG3, (uint8_t *)FLASH_APP_START, codelen) != 0) { // failture
|
||||
if (ecdsa_verify_digest(&secp256k1, pubkey[sigindex3 - 1], (uint8_t *)FLASH_META_SIG3, hash) != 0) { // failture
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,6 @@
|
||||
#ifndef __SIGNATURES_H__
|
||||
#define __SIGNATURES_H__
|
||||
|
||||
int signatures_ok(void);
|
||||
int signatures_ok(uint8_t *store_hash);
|
||||
|
||||
#endif
|
||||
|
@ -425,15 +425,9 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep)
|
||||
if (msg_id != 0x001B) { // ButtonAck message (id 27)
|
||||
return;
|
||||
}
|
||||
char digest[64];
|
||||
sha256_End(&ctx, digest);
|
||||
char str[4][17];
|
||||
strlcpy(str[0], digest, 17);
|
||||
strlcpy(str[1], digest + 16, 17);
|
||||
strlcpy(str[2], digest + 32, 17);
|
||||
strlcpy(str[3], digest + 48, 17);
|
||||
layoutDialog(DIALOG_ICON_QUESTION, "Abort", "Continue", "Compare fingerprints", str[0], str[1], str[2], str[3], NULL, NULL);
|
||||
|
||||
uint8_t hash[32];
|
||||
sha256_Final(&ctx, hash);
|
||||
layoutFirmwareHash(hash);
|
||||
do {
|
||||
delay(100000);
|
||||
buttonUpdate();
|
||||
@ -444,7 +438,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep)
|
||||
layoutProgress("INSTALLING ... Please wait", 1000);
|
||||
uint8_t flags = *((uint8_t *)FLASH_META_FLAGS);
|
||||
// check if to restore old storage area but only if signatures are ok
|
||||
if ((flags & 0x01) && signatures_ok()) {
|
||||
if ((flags & 0x01) && signatures_ok(NULL)) {
|
||||
// copy new stuff
|
||||
memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_DESC_LEN);
|
||||
// replace "TRZR" in header with 0000 when hash not confirmed
|
||||
|
@ -21,6 +21,7 @@
|
||||
#define __BUTTONS_H__
|
||||
|
||||
#include <libopencm3/stm32/gpio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct buttonState {
|
||||
volatile bool YesUp;
|
||||
|
@ -4,14 +4,14 @@ NAME = demo
|
||||
|
||||
OBJS += demo.o
|
||||
|
||||
OBJS += ../trezor-crypto/bignum.o
|
||||
OBJS += ../trezor-crypto/bip32.o
|
||||
OBJS += ../trezor-crypto/ecdsa.o
|
||||
OBJS += ../trezor-crypto/hmac.o
|
||||
OBJS += ../trezor-crypto/ripemd160.o
|
||||
OBJS += ../trezor-crypto/secp256k1.o
|
||||
OBJS += ../trezor-crypto/sha2.o
|
||||
OBJS += ../trezor-crypto/bip39.o
|
||||
OBJS += ../trezor-crypto/pbkdf2.o
|
||||
OBJS += ../vendor/trezor-crypto/bignum.o
|
||||
OBJS += ../vendor/trezor-crypto/bip32.o
|
||||
OBJS += ../vendor/trezor-crypto/ecdsa.o
|
||||
OBJS += ../vendor/trezor-crypto/hmac.o
|
||||
OBJS += ../vendor/trezor-crypto/ripemd160.o
|
||||
OBJS += ../vendor/trezor-crypto/secp256k1.o
|
||||
OBJS += ../vendor/trezor-crypto/sha2.o
|
||||
OBJS += ../vendor/trezor-crypto/bip39.o
|
||||
OBJS += ../vendor/trezor-crypto/pbkdf2.o
|
||||
|
||||
include ../Makefile.include
|
||||
|
@ -8,12 +8,14 @@ docker run -t -v $(pwd)/output:/output $IMAGETAG /bin/sh -c "\
|
||||
cd trezor-mcu && \
|
||||
git checkout $FIRMWARETAG && \
|
||||
git submodule update --init && \
|
||||
make -C vendor/libopencm3 && \
|
||||
make && \
|
||||
cd firmware && \
|
||||
make && \
|
||||
cp trezor.bin /output/trezor-$FIRMWARETAG.bin"
|
||||
make -C firmware && \
|
||||
cp firmware/trezor.bin /output/trezor-$FIRMWARETAG.bin"
|
||||
|
||||
echo "---------------------"
|
||||
echo "Firmware fingerprint:"
|
||||
|
||||
sha256sum output/trezor-$FIRMWARETAG.bin
|
||||
FILENAME=output/trezor-$FIRMWARETAG.bin
|
||||
sha256sum "$FILENAME"
|
||||
FILESIZE=$(stat -c%s "$FILENAME")
|
||||
echo "Firmware size: $FILESIZE bytes (out of 491520 maximum)"
|
||||
|
@ -20,25 +20,27 @@ OBJS += crypto.o
|
||||
|
||||
OBJS += debug.o
|
||||
|
||||
OBJS += ../trezor-crypto/bignum.o
|
||||
OBJS += ../trezor-crypto/ecdsa.o
|
||||
OBJS += ../trezor-crypto/secp256k1.o
|
||||
OBJS += ../trezor-crypto/nist256p1.o
|
||||
OBJS += ../trezor-crypto/hmac.o
|
||||
OBJS += ../trezor-crypto/bip32.o
|
||||
OBJS += ../trezor-crypto/bip39.o
|
||||
OBJS += ../trezor-crypto/pbkdf2.o
|
||||
OBJS += ../trezor-crypto/base58.o
|
||||
OBJS += ../vendor/trezor-crypto/bignum.o
|
||||
OBJS += ../vendor/trezor-crypto/ecdsa.o
|
||||
OBJS += ../vendor/trezor-crypto/curves.o
|
||||
OBJS += ../vendor/trezor-crypto/secp256k1.o
|
||||
OBJS += ../vendor/trezor-crypto/nist256p1.o
|
||||
OBJS += ../vendor/trezor-crypto/ed25519-donna/ed25519.o
|
||||
OBJS += ../vendor/trezor-crypto/hmac.o
|
||||
OBJS += ../vendor/trezor-crypto/bip32.o
|
||||
OBJS += ../vendor/trezor-crypto/bip39.o
|
||||
OBJS += ../vendor/trezor-crypto/pbkdf2.o
|
||||
OBJS += ../vendor/trezor-crypto/base58.o
|
||||
|
||||
OBJS += ../trezor-crypto/ripemd160.o
|
||||
OBJS += ../trezor-crypto/sha2.o
|
||||
OBJS += ../vendor/trezor-crypto/ripemd160.o
|
||||
OBJS += ../vendor/trezor-crypto/sha2.o
|
||||
|
||||
OBJS += ../trezor-crypto/aescrypt.o
|
||||
OBJS += ../trezor-crypto/aeskey.o
|
||||
OBJS += ../trezor-crypto/aestab.o
|
||||
OBJS += ../trezor-crypto/aes_modes.o
|
||||
OBJS += ../vendor/trezor-crypto/aescrypt.o
|
||||
OBJS += ../vendor/trezor-crypto/aeskey.o
|
||||
OBJS += ../vendor/trezor-crypto/aestab.o
|
||||
OBJS += ../vendor/trezor-crypto/aes_modes.o
|
||||
|
||||
OBJS += ../trezor-qrenc/qr_encode.o
|
||||
OBJS += ../vendor/trezor-qrenc/qr_encode.o
|
||||
|
||||
# OBJS += protob/pb_common.o
|
||||
OBJS += protob/pb_decode.o
|
||||
@ -55,3 +57,5 @@ CFLAGS += -DQR_MAX_VERSION=0
|
||||
CFLAGS += -DDEBUG_LINK=0
|
||||
CFLAGS += -DDEBUG_LOG=0
|
||||
CFLAGS += -DSCM_REVISION='"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')"'
|
||||
CFLAGS += -DED25519_CUSTOMRANDOM=1
|
||||
CFLAGS += -DED25519_CUSTOMHASH=1
|
||||
|
@ -25,8 +25,8 @@
|
||||
#include "hmac.h"
|
||||
#include "bip32.h"
|
||||
#include "layout.h"
|
||||
#include "curves.h"
|
||||
#include "secp256k1.h"
|
||||
#include "nist256p1.h"
|
||||
|
||||
uint32_t ser_length(uint32_t len, uint8_t *out)
|
||||
{
|
||||
@ -84,13 +84,23 @@ uint32_t deser_length(const uint8_t *in, uint32_t *out)
|
||||
return 1 + 8;
|
||||
}
|
||||
|
||||
int sshMessageSign(const uint8_t *message, size_t message_len, const uint8_t *privkey, uint8_t *signature)
|
||||
int sshMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature)
|
||||
{
|
||||
signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes
|
||||
return ecdsa_sign(&nist256p1, privkey, message, message_len, signature + 1, NULL);
|
||||
return hdnode_sign(node, message, message_len, signature + 1, NULL);
|
||||
}
|
||||
|
||||
int cryptoMessageSign(const uint8_t *message, size_t message_len, const uint8_t *privkey, uint8_t *signature)
|
||||
int gpgMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature)
|
||||
{
|
||||
// GPG should sign a SHA256 digest of the original message.
|
||||
if (message_len != 32) {
|
||||
return 1;
|
||||
}
|
||||
signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes
|
||||
return hdnode_sign_digest(node, message, signature + 1, NULL);
|
||||
}
|
||||
|
||||
int cryptoMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature)
|
||||
{
|
||||
SHA256_CTX ctx;
|
||||
sha256_Init(&ctx);
|
||||
@ -100,10 +110,10 @@ int cryptoMessageSign(const uint8_t *message, size_t message_len, const uint8_t
|
||||
sha256_Update(&ctx, varint, l);
|
||||
sha256_Update(&ctx, message, message_len);
|
||||
uint8_t hash[32];
|
||||
sha256_Final(hash, &ctx);
|
||||
sha256_Final(&ctx, hash);
|
||||
sha256_Raw(hash, 32, hash);
|
||||
uint8_t pby;
|
||||
int result = ecdsa_sign_digest(&secp256k1, privkey, hash, signature + 1, &pby);
|
||||
int result = hdnode_sign_digest(node, hash, signature + 1, &pby);
|
||||
if (result == 0) {
|
||||
signature[0] = 27 + pby + 4;
|
||||
}
|
||||
@ -112,28 +122,9 @@ int cryptoMessageSign(const uint8_t *message, size_t message_len, const uint8_t
|
||||
|
||||
int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature)
|
||||
{
|
||||
bignum256 r, s, e;
|
||||
curve_point cp, cp2;
|
||||
SHA256_CTX ctx;
|
||||
uint8_t pubkey[65], addr_raw[21], hash[32];
|
||||
|
||||
uint8_t nV = signature[0];
|
||||
if (nV < 27 || nV >= 35) {
|
||||
return 1;
|
||||
}
|
||||
bool compressed;
|
||||
compressed = (nV >= 31);
|
||||
if (compressed) {
|
||||
nV -= 4;
|
||||
}
|
||||
uint8_t recid = nV - 27;
|
||||
// read r and s
|
||||
bn_read_be(signature + 1, &r);
|
||||
bn_read_be(signature + 33, &s);
|
||||
// x = r
|
||||
memcpy(&cp.x, &r, sizeof(bignum256));
|
||||
// compute y from x
|
||||
uncompress_coords(&secp256k1, recid % 2, &cp.x, &cp.y);
|
||||
// calculate hash
|
||||
sha256_Init(&ctx);
|
||||
sha256_Update(&ctx, (const uint8_t *)"\x18" "Bitcoin Signed Message:" "\n", 25);
|
||||
@ -141,43 +132,42 @@ int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_
|
||||
uint32_t l = ser_length(message_len, varint);
|
||||
sha256_Update(&ctx, varint, l);
|
||||
sha256_Update(&ctx, message, message_len);
|
||||
sha256_Final(hash, &ctx);
|
||||
sha256_Final(&ctx, hash);
|
||||
sha256_Raw(hash, 32, hash);
|
||||
// e = -hash
|
||||
bn_read_be(hash, &e);
|
||||
bn_subtract(&secp256k1.order, &e, &e);
|
||||
// r = r^-1
|
||||
bn_inverse(&r, &secp256k1.order);
|
||||
point_multiply(&secp256k1, &s, &cp, &cp);
|
||||
scalar_multiply(&secp256k1, &e, &cp2);
|
||||
point_add(&secp256k1, &cp2, &cp);
|
||||
point_multiply(&secp256k1, &r, &cp, &cp);
|
||||
pubkey[0] = 0x04;
|
||||
bn_write_be(&cp.x, pubkey + 1);
|
||||
bn_write_be(&cp.y, pubkey + 33);
|
||||
// check if the address is correct
|
||||
if (compressed) {
|
||||
pubkey[0] = 0x02 | (cp.y.val[0] & 0x01);
|
||||
|
||||
uint8_t recid = signature[0] - 27;
|
||||
if (recid >= 8) {
|
||||
return 1;
|
||||
}
|
||||
bool compressed = (recid >= 4);
|
||||
recid &= 3;
|
||||
|
||||
// check if signature verifies the digest and recover the public key
|
||||
if (ecdsa_verify_digest_recover(&secp256k1, pubkey, signature + 1, hash, recid) != 0) {
|
||||
return 3;
|
||||
}
|
||||
// convert public key to compressed pubkey if necessary
|
||||
if (compressed) {
|
||||
pubkey[0] = 0x02 | (pubkey[64] & 1);
|
||||
}
|
||||
// check if the address is correct
|
||||
ecdsa_get_address_raw(pubkey, address_raw[0], addr_raw);
|
||||
if (memcmp(addr_raw, address_raw, 21) != 0) {
|
||||
return 2;
|
||||
}
|
||||
// check if signature verifies the digest
|
||||
if (ecdsa_verify_digest(&secp256k1, pubkey, signature + 1, hash) != 0) {
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
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
|
||||
HDNode node;
|
||||
payload[0] = display_only ? 0x81 : 0x01;
|
||||
uint32_t l = ser_length(msg_size, payload + 1);
|
||||
memcpy(payload + 1 + l, msg, msg_size);
|
||||
memcpy(payload + 1 + l + msg_size, address_raw, 21);
|
||||
if (cryptoMessageSign(msg, msg_size, privkey, payload + 1 + l + msg_size + 21) != 0) {
|
||||
hdnode_from_xprv(0, 0, 0, privkey, privkey, SECP256K1_NAME, &node);
|
||||
if (cryptoMessageSign(&node, msg, msg_size, payload + 1 + l + msg_size + 21) != 0) {
|
||||
return 1;
|
||||
}
|
||||
*payload_len = 1 + l + msg_size + 21 + 65;
|
||||
@ -282,7 +272,7 @@ uint8_t *cryptoHDNodePathToPubkey(const HDNodePathType *hdnodepath)
|
||||
{
|
||||
if (!hdnodepath->node.has_public_key || hdnodepath->node.public_key.size != 33) return 0;
|
||||
static HDNode node;
|
||||
if (hdnode_from_xpub(hdnodepath->node.depth, hdnodepath->node.fingerprint, hdnodepath->node.child_num, hdnodepath->node.chain_code.bytes, hdnodepath->node.public_key.bytes, &node) == 0) {
|
||||
if (hdnode_from_xpub(hdnodepath->node.depth, hdnodepath->node.fingerprint, hdnodepath->node.child_num, hdnodepath->node.chain_code.bytes, hdnodepath->node.public_key.bytes, SECP256K1_NAME, &node) == 0) {
|
||||
return 0;
|
||||
}
|
||||
layoutProgressUpdate(true);
|
||||
@ -345,7 +335,7 @@ int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t
|
||||
sha256_Update(&ctx, ptr[i]->node.public_key.bytes, 33);
|
||||
}
|
||||
sha256_Update(&ctx, (const uint8_t *)&n, sizeof(uint32_t));
|
||||
sha256_Final(hash, &ctx);
|
||||
sha256_Final(&ctx, hash);
|
||||
layoutProgressUpdate(true);
|
||||
return 1;
|
||||
}
|
||||
@ -373,6 +363,6 @@ int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash)
|
||||
if (identity->has_path && identity->path[0]) {
|
||||
sha256_Update(&ctx, (const uint8_t *)(identity->path), strlen(identity->path));
|
||||
}
|
||||
sha256_Final(hash, &ctx);
|
||||
sha256_Final(&ctx, hash);
|
||||
return 1;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <ecdsa.h>
|
||||
#include <bip32.h>
|
||||
#include <sha2.h>
|
||||
#include <pb.h>
|
||||
#include "types.pb.h"
|
||||
@ -32,9 +33,11 @@ uint32_t ser_length(uint32_t len, uint8_t *out);
|
||||
|
||||
uint32_t ser_length_hash(SHA256_CTX *ctx, uint32_t len);
|
||||
|
||||
int sshMessageSign(const uint8_t *message, size_t message_len, const uint8_t *privkey, uint8_t *signature);
|
||||
int sshMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature);
|
||||
|
||||
int cryptoMessageSign(const uint8_t *message, size_t message_len, const uint8_t *privkey, uint8_t *signature);
|
||||
int gpgMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature);
|
||||
|
||||
int cryptoMessageSign(const HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature);
|
||||
|
||||
int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature);
|
||||
|
||||
|
123
firmware/fsm.c
123
firmware/fsm.c
@ -44,8 +44,8 @@
|
||||
#include "base58.h"
|
||||
#include "bip39.h"
|
||||
#include "ripemd160.h"
|
||||
#include "curves.h"
|
||||
#include "secp256k1.h"
|
||||
#include "nist256p1.h"
|
||||
|
||||
// message methods
|
||||
|
||||
@ -93,11 +93,11 @@ const CoinType *fsm_getCoin(const char *name)
|
||||
return coin;
|
||||
}
|
||||
|
||||
const HDNode *fsm_getDerivedNode(uint32_t *address_n, size_t address_n_count)
|
||||
const HDNode *fsm_getDerivedNode(const char *curve, uint32_t *address_n, size_t address_n_count)
|
||||
{
|
||||
static HDNode node;
|
||||
if (!storage_getRootNode(&node)) {
|
||||
fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized or passphrase request cancelled");
|
||||
if (!storage_getRootNode(&node, curve)) {
|
||||
fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized or passphrase request cancelled or unsupported curve");
|
||||
layoutHome();
|
||||
return 0;
|
||||
}
|
||||
@ -282,22 +282,29 @@ void fsm_msgGetPublicKey(GetPublicKey *msg)
|
||||
{
|
||||
RESP_INIT(PublicKey);
|
||||
|
||||
if (!storage_isInitialized()) {
|
||||
fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!protectPin(true)) {
|
||||
layoutHome();
|
||||
return;
|
||||
}
|
||||
|
||||
const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count);
|
||||
const char *curve = SECP256K1_NAME;
|
||||
if (msg->has_ecdsa_curve_name) {
|
||||
curve = msg->ecdsa_curve_name;
|
||||
}
|
||||
const HDNode *node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count);
|
||||
if (!node) return;
|
||||
|
||||
uint8_t public_key[33]; // copy public key to temporary buffer
|
||||
memcpy(public_key, node->public_key, sizeof(public_key));
|
||||
|
||||
if (msg->has_ecdsa_curve_name) {
|
||||
const ecdsa_curve *curve = get_curve_by_name(msg->ecdsa_curve_name);
|
||||
if (curve) {
|
||||
// correct public key (since fsm_getDerivedNode uses secp256k1 curve)
|
||||
ecdsa_get_public_key33(curve, node->private_key, public_key);
|
||||
if (msg->has_show_display && msg->show_display) {
|
||||
layoutPublicKey(node->public_key);
|
||||
if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) {
|
||||
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show public key cancelled");
|
||||
layoutHome();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -309,7 +316,7 @@ void fsm_msgGetPublicKey(GetPublicKey *msg)
|
||||
resp->node.has_private_key = false;
|
||||
resp->node.has_public_key = true;
|
||||
resp->node.public_key.size = 33;
|
||||
memcpy(resp->node.public_key.bytes, public_key, 33);
|
||||
memcpy(resp->node.public_key.bytes, node->public_key, 33);
|
||||
resp->has_xpub = true;
|
||||
hdnode_serialize_public(node, resp->xpub, sizeof(resp->xpub));
|
||||
msg_write(MessageType_MessageType_PublicKey, resp);
|
||||
@ -363,6 +370,11 @@ void fsm_msgResetDevice(ResetDevice *msg)
|
||||
|
||||
void fsm_msgSignTx(SignTx *msg)
|
||||
{
|
||||
if (!storage_isInitialized()) {
|
||||
fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg->inputs_count < 1) {
|
||||
fsm_sendFailure(FailureType_Failure_Other, "Transaction must have at least one input");
|
||||
layoutHome();
|
||||
@ -382,10 +394,10 @@ void fsm_msgSignTx(SignTx *msg)
|
||||
|
||||
const CoinType *coin = fsm_getCoin(msg->coin_name);
|
||||
if (!coin) return;
|
||||
const HDNode *node = fsm_getDerivedNode(0, 0);
|
||||
const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, 0, 0);
|
||||
if (!node) return;
|
||||
|
||||
signing_init(msg->inputs_count, msg->outputs_count, coin, node);
|
||||
signing_init(msg->inputs_count, msg->outputs_count, coin, node, msg->version, msg->lock_time);
|
||||
}
|
||||
|
||||
void fsm_msgCancel(Cancel *msg)
|
||||
@ -406,6 +418,10 @@ void fsm_msgTxAck(TxAck *msg)
|
||||
|
||||
void fsm_msgCipherKeyValue(CipherKeyValue *msg)
|
||||
{
|
||||
if (!storage_isInitialized()) {
|
||||
fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized");
|
||||
return;
|
||||
}
|
||||
if (!msg->has_key) {
|
||||
fsm_sendFailure(FailureType_Failure_SyntaxError, "No key provided");
|
||||
return;
|
||||
@ -422,7 +438,7 @@ void fsm_msgCipherKeyValue(CipherKeyValue *msg)
|
||||
layoutHome();
|
||||
return;
|
||||
}
|
||||
const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count);
|
||||
const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count);
|
||||
if (!node) return;
|
||||
|
||||
bool encrypt = msg->has_encrypt && msg->encrypt;
|
||||
@ -531,6 +547,11 @@ void fsm_msgGetAddress(GetAddress *msg)
|
||||
{
|
||||
RESP_INIT(Address);
|
||||
|
||||
if (!storage_isInitialized()) {
|
||||
fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!protectPin(true)) {
|
||||
layoutHome();
|
||||
return;
|
||||
@ -538,7 +559,7 @@ void fsm_msgGetAddress(GetAddress *msg)
|
||||
|
||||
const CoinType *coin = fsm_getCoin(msg->coin_name);
|
||||
if (!coin) return;
|
||||
const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count);
|
||||
const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count);
|
||||
if (!node) return;
|
||||
|
||||
if (msg->has_multisig) {
|
||||
@ -599,6 +620,11 @@ void fsm_msgSignMessage(SignMessage *msg)
|
||||
{
|
||||
RESP_INIT(MessageSignature);
|
||||
|
||||
if (!storage_isInitialized()) {
|
||||
fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
layoutSignMessage(msg->message.bytes, msg->message.size);
|
||||
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
|
||||
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign message cancelled");
|
||||
@ -613,11 +639,11 @@ void fsm_msgSignMessage(SignMessage *msg)
|
||||
|
||||
const CoinType *coin = fsm_getCoin(msg->coin_name);
|
||||
if (!coin) return;
|
||||
const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count);
|
||||
const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count);
|
||||
if (!node) return;
|
||||
|
||||
layoutProgressSwipe("Signing", 0);
|
||||
if (cryptoMessageSign(msg->message.bytes, msg->message.size, node->private_key, resp->signature.bytes) == 0) {
|
||||
if (cryptoMessageSign(node, msg->message.bytes, msg->message.size, resp->signature.bytes) == 0) {
|
||||
resp->has_address = true;
|
||||
uint8_t addr_raw[21];
|
||||
ecdsa_get_address_raw(node->public_key, coin->address_type, addr_raw);
|
||||
@ -647,8 +673,18 @@ void fsm_msgVerifyMessage(VerifyMessage *msg)
|
||||
fsm_sendFailure(FailureType_Failure_InvalidSignature, "Invalid address");
|
||||
}
|
||||
if (msg->signature.size == 65 && cryptoMessageVerify(msg->message.bytes, msg->message.size, addr_raw, msg->signature.bytes) == 0) {
|
||||
layoutVerifyAddress(msg->address);
|
||||
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
|
||||
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Message verification cancelled");
|
||||
layoutHome();
|
||||
return;
|
||||
}
|
||||
layoutVerifyMessage(msg->message.bytes, msg->message.size);
|
||||
protectButton(ButtonRequestType_ButtonRequest_Other, true);
|
||||
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
|
||||
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Message verification cancelled");
|
||||
layoutHome();
|
||||
return;
|
||||
}
|
||||
fsm_sendSuccess("Message verified");
|
||||
} else {
|
||||
fsm_sendFailure(FailureType_Failure_InvalidSignature, "Invalid signature");
|
||||
@ -660,6 +696,11 @@ void fsm_msgSignIdentity(SignIdentity *msg)
|
||||
{
|
||||
RESP_INIT(SignedIdentity);
|
||||
|
||||
if (!storage_isInitialized()) {
|
||||
fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
layoutSignIdentity(&(msg->identity), msg->has_challenge_visual ? msg->challenge_visual : 0);
|
||||
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
|
||||
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign identity cancelled");
|
||||
@ -686,35 +727,31 @@ void fsm_msgSignIdentity(SignIdentity *msg)
|
||||
address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | (hash[11] << 24);
|
||||
address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | (hash[15] << 24);
|
||||
|
||||
const HDNode *node = fsm_getDerivedNode(address_n, 5);
|
||||
const char *curve = SECP256K1_NAME;
|
||||
if (msg->has_ecdsa_curve_name) {
|
||||
curve = msg->ecdsa_curve_name;
|
||||
}
|
||||
const HDNode *node = fsm_getDerivedNode(curve, address_n, 5);
|
||||
if (!node) return;
|
||||
|
||||
uint8_t public_key[33]; // copy public key to temporary buffer
|
||||
memcpy(public_key, node->public_key, sizeof(public_key));
|
||||
|
||||
if (msg->has_ecdsa_curve_name) {
|
||||
const ecdsa_curve *curve = get_curve_by_name(msg->ecdsa_curve_name);
|
||||
if (curve) {
|
||||
// correct public key (since fsm_getDerivedNode uses secp256k1 curve)
|
||||
ecdsa_get_public_key33(curve, node->private_key, public_key);
|
||||
}
|
||||
}
|
||||
|
||||
bool sign_ssh = msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0);
|
||||
bool sign_gpg = msg->identity.has_proto && (strcmp(msg->identity.proto, "gpg") == 0);
|
||||
|
||||
int result = 0;
|
||||
layoutProgressSwipe("Signing", 0);
|
||||
if (sign_ssh) { // SSH does not sign visual challenge
|
||||
result = sshMessageSign(msg->challenge_hidden.bytes, msg->challenge_hidden.size, node->private_key, resp->signature.bytes);
|
||||
result = sshMessageSign(node, msg->challenge_hidden.bytes, msg->challenge_hidden.size, resp->signature.bytes);
|
||||
} else if (sign_gpg) { // GPG should sign a message digest
|
||||
result = gpgMessageSign(node, msg->challenge_hidden.bytes, msg->challenge_hidden.size, resp->signature.bytes);
|
||||
} else {
|
||||
uint8_t digest[64];
|
||||
sha256_Raw(msg->challenge_hidden.bytes, msg->challenge_hidden.size, digest);
|
||||
sha256_Raw((const uint8_t *)msg->challenge_visual, strlen(msg->challenge_visual), digest + 32);
|
||||
result = cryptoMessageSign(digest, 64, node->private_key, resp->signature.bytes);
|
||||
result = cryptoMessageSign(node, digest, 64, resp->signature.bytes);
|
||||
}
|
||||
|
||||
if (result == 0) {
|
||||
if (sign_ssh) {
|
||||
if (strcmp(curve, SECP256K1_NAME) != 0) {
|
||||
resp->has_address = false;
|
||||
} else {
|
||||
resp->has_address = true;
|
||||
@ -724,7 +761,7 @@ void fsm_msgSignIdentity(SignIdentity *msg)
|
||||
}
|
||||
resp->has_public_key = true;
|
||||
resp->public_key.size = 33;
|
||||
memcpy(resp->public_key.bytes, public_key, 33);
|
||||
memcpy(resp->public_key.bytes, node->public_key, 33);
|
||||
resp->has_signature = true;
|
||||
resp->signature.size = 65;
|
||||
msg_write(MessageType_MessageType_SignedIdentity, resp);
|
||||
@ -736,6 +773,10 @@ void fsm_msgSignIdentity(SignIdentity *msg)
|
||||
|
||||
void fsm_msgEncryptMessage(EncryptMessage *msg)
|
||||
{
|
||||
if (!storage_isInitialized()) {
|
||||
fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized");
|
||||
return;
|
||||
}
|
||||
if (!msg->has_pubkey) {
|
||||
fsm_sendFailure(FailureType_Failure_SyntaxError, "No public key provided");
|
||||
return;
|
||||
@ -765,7 +806,7 @@ void fsm_msgEncryptMessage(EncryptMessage *msg)
|
||||
layoutHome();
|
||||
return;
|
||||
}
|
||||
node = fsm_getDerivedNode(msg->address_n, msg->address_n_count);
|
||||
node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count);
|
||||
if (!node) return;
|
||||
uint8_t public_key[33];
|
||||
ecdsa_get_public_key33(&secp256k1, node->private_key, public_key);
|
||||
@ -792,6 +833,10 @@ void fsm_msgEncryptMessage(EncryptMessage *msg)
|
||||
|
||||
void fsm_msgDecryptMessage(DecryptMessage *msg)
|
||||
{
|
||||
if (!storage_isInitialized()) {
|
||||
fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized");
|
||||
return;
|
||||
}
|
||||
if (!msg->has_nonce) {
|
||||
fsm_sendFailure(FailureType_Failure_SyntaxError, "No nonce provided");
|
||||
return;
|
||||
@ -813,7 +858,7 @@ void fsm_msgDecryptMessage(DecryptMessage *msg)
|
||||
layoutHome();
|
||||
return;
|
||||
}
|
||||
const HDNode *node = fsm_getDerivedNode(msg->address_n, msg->address_n_count);
|
||||
const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count);
|
||||
if (!node) return;
|
||||
|
||||
layoutProgressSwipe("Decrypting", 0);
|
||||
|
@ -196,10 +196,19 @@ void layoutSignMessage(const uint8_t *msg, uint32_t len)
|
||||
str[0], str[1], str[2], str[3], NULL, NULL);
|
||||
}
|
||||
|
||||
void layoutVerifyAddress(const char *address)
|
||||
{
|
||||
const char **str = split_message((const uint8_t *)address, strlen(address), 17);
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, "Cancel", "Confirm",
|
||||
"Confirm address?",
|
||||
"Message signed by:",
|
||||
NULL, str[0], str[1], str[2], NULL);
|
||||
}
|
||||
|
||||
void layoutVerifyMessage(const uint8_t *msg, uint32_t len)
|
||||
{
|
||||
const char **str = split_message(msg, len, 16);
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "OK",
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, "Cancel", "Confirm",
|
||||
"Verified message",
|
||||
str[0], str[1], str[2], str[3], NULL, NULL);
|
||||
}
|
||||
@ -270,6 +279,17 @@ void layoutAddress(const char *address, const char *desc)
|
||||
oledRefresh();
|
||||
}
|
||||
|
||||
void layoutPublicKey(const uint8_t *pubkey)
|
||||
{
|
||||
char hex[32*2+1], desc[16];
|
||||
strlcpy(desc, "Public Key: 00", sizeof(desc));
|
||||
data2hex(pubkey, 1, desc + 12);
|
||||
data2hex(pubkey + 1, 32, hex);
|
||||
const char **str = split_message((const uint8_t *)hex, 32*2, 16);
|
||||
layoutDialogSwipe(DIALOG_ICON_QUESTION, NULL, "Continue", NULL,
|
||||
desc, str[0], str[1], str[2], str[3], NULL);
|
||||
}
|
||||
|
||||
void layoutSignIdentity(const IdentityType *identity, const char *challenge)
|
||||
{
|
||||
char row_proto[8 + 11 + 1];
|
||||
|
@ -32,11 +32,13 @@ void layoutConfirmOutput(const CoinType *coin, const TxOutputType *out);
|
||||
void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_fee);
|
||||
void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee, uint32_t kb);
|
||||
void layoutSignMessage(const uint8_t *msg, uint32_t len);
|
||||
void layoutVerifyAddress(const char *address);
|
||||
void layoutVerifyMessage(const uint8_t *msg, uint32_t len);
|
||||
void layoutCipherKeyValue(bool encrypt, const char *key);
|
||||
void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing);
|
||||
void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address);
|
||||
void layoutAddress(const char *address, const char *desc);
|
||||
void layoutPublicKey(const uint8_t *pubkey);
|
||||
void layoutSignIdentity(const IdentityType *identity, const char *challenge);
|
||||
|
||||
#endif
|
||||
|
@ -139,7 +139,7 @@ static uint8_t msg_debug_out[MSG_DEBUG_OUT_SIZE];
|
||||
|
||||
#endif
|
||||
|
||||
inline void msg_out_append(uint8_t c)
|
||||
static inline void msg_out_append(uint8_t c)
|
||||
{
|
||||
if (msg_out_cur == 0) {
|
||||
msg_out[msg_out_end * 64] = '?';
|
||||
@ -155,7 +155,7 @@ inline void msg_out_append(uint8_t c)
|
||||
|
||||
#if DEBUG_LINK
|
||||
|
||||
inline void msg_debug_out_append(uint8_t c)
|
||||
static inline void msg_debug_out_append(uint8_t c)
|
||||
{
|
||||
if (msg_debug_out_cur == 0) {
|
||||
msg_debug_out[msg_debug_out_end * 64] = '?';
|
||||
@ -171,7 +171,7 @@ inline void msg_debug_out_append(uint8_t c)
|
||||
|
||||
#endif
|
||||
|
||||
inline void msg_out_pad(void)
|
||||
static inline void msg_out_pad(void)
|
||||
{
|
||||
if (msg_out_cur == 0) return;
|
||||
while (msg_out_cur < 64) {
|
||||
|
@ -12,7 +12,11 @@ const char SignMessage_coin_name_default[17] = "Bitcoin";
|
||||
const char EncryptMessage_coin_name_default[17] = "Bitcoin";
|
||||
const char EstimateTxSize_coin_name_default[17] = "Bitcoin";
|
||||
const char SignTx_coin_name_default[17] = "Bitcoin";
|
||||
const uint32_t SignTx_version_default = 1u;
|
||||
const uint32_t SignTx_lock_time_default = 0u;
|
||||
const char SimpleSignTx_coin_name_default[17] = "Bitcoin";
|
||||
const uint32_t SimpleSignTx_version_default = 1u;
|
||||
const uint32_t SimpleSignTx_lock_time_default = 0u;
|
||||
|
||||
|
||||
const pb_field_t Initialize_fields[1] = {
|
||||
@ -123,9 +127,10 @@ const pb_field_t Entropy_fields[2] = {
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t GetPublicKey_fields[3] = {
|
||||
const pb_field_t GetPublicKey_fields[4] = {
|
||||
PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, GetPublicKey, address_n, address_n, 0),
|
||||
PB_FIELD2( 2, STRING , OPTIONAL, STATIC , OTHER, GetPublicKey, ecdsa_curve_name, address_n, 0),
|
||||
PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, GetPublicKey, show_display, ecdsa_curve_name, 0),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
@ -279,18 +284,22 @@ const pb_field_t TxSize_fields[2] = {
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t SignTx_fields[4] = {
|
||||
const pb_field_t SignTx_fields[6] = {
|
||||
PB_FIELD2( 1, UINT32 , REQUIRED, STATIC , FIRST, SignTx, outputs_count, outputs_count, 0),
|
||||
PB_FIELD2( 2, UINT32 , REQUIRED, STATIC , OTHER, SignTx, inputs_count, outputs_count, 0),
|
||||
PB_FIELD2( 3, STRING , OPTIONAL, STATIC , OTHER, SignTx, coin_name, inputs_count, &SignTx_coin_name_default),
|
||||
PB_FIELD2( 4, UINT32 , OPTIONAL, STATIC , OTHER, SignTx, version, coin_name, &SignTx_version_default),
|
||||
PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, SignTx, lock_time, version, &SignTx_lock_time_default),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t SimpleSignTx_fields[5] = {
|
||||
const pb_field_t SimpleSignTx_fields[7] = {
|
||||
PB_FIELD2( 1, MESSAGE , REPEATED, STATIC , FIRST, SimpleSignTx, inputs, inputs, &TxInputType_fields),
|
||||
PB_FIELD2( 2, MESSAGE , REPEATED, STATIC , OTHER, SimpleSignTx, outputs, inputs, &TxOutputType_fields),
|
||||
PB_FIELD2( 3, MESSAGE , REPEATED, STATIC , OTHER, SimpleSignTx, transactions, outputs, &TransactionType_fields),
|
||||
PB_FIELD2( 4, STRING , OPTIONAL, STATIC , OTHER, SimpleSignTx, coin_name, transactions, &SimpleSignTx_coin_name_default),
|
||||
PB_FIELD2( 5, UINT32 , OPTIONAL, STATIC , OTHER, SimpleSignTx, version, coin_name, &SimpleSignTx_version_default),
|
||||
PB_FIELD2( 6, UINT32 , OPTIONAL, STATIC , OTHER, SimpleSignTx, lock_time, version, &SimpleSignTx_lock_time_default),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
|
@ -426,6 +426,8 @@ typedef struct _GetPublicKey {
|
||||
uint32_t address_n[8];
|
||||
bool has_ecdsa_curve_name;
|
||||
char ecdsa_curve_name[32];
|
||||
bool has_show_display;
|
||||
bool show_display;
|
||||
} GetPublicKey;
|
||||
|
||||
typedef struct _LoadDevice {
|
||||
@ -551,6 +553,10 @@ typedef struct _SignTx {
|
||||
uint32_t inputs_count;
|
||||
bool has_coin_name;
|
||||
char coin_name[17];
|
||||
bool has_version;
|
||||
uint32_t version;
|
||||
bool has_lock_time;
|
||||
uint32_t lock_time;
|
||||
} SignTx;
|
||||
|
||||
typedef struct {
|
||||
@ -581,6 +587,10 @@ typedef struct _SimpleSignTx {
|
||||
TransactionType transactions[0];
|
||||
bool has_coin_name;
|
||||
char coin_name[17];
|
||||
bool has_version;
|
||||
uint32_t version;
|
||||
bool has_lock_time;
|
||||
uint32_t lock_time;
|
||||
} SimpleSignTx;
|
||||
|
||||
typedef struct _Success {
|
||||
@ -640,7 +650,11 @@ extern const char SignMessage_coin_name_default[17];
|
||||
extern const char EncryptMessage_coin_name_default[17];
|
||||
extern const char EstimateTxSize_coin_name_default[17];
|
||||
extern const char SignTx_coin_name_default[17];
|
||||
extern const uint32_t SignTx_version_default;
|
||||
extern const uint32_t SignTx_lock_time_default;
|
||||
extern const char SimpleSignTx_coin_name_default[17];
|
||||
extern const uint32_t SimpleSignTx_version_default;
|
||||
extern const uint32_t SimpleSignTx_lock_time_default;
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define Initialize_init_default {0}
|
||||
@ -661,7 +675,7 @@ extern const char SimpleSignTx_coin_name_default[17];
|
||||
#define PassphraseAck_init_default {""}
|
||||
#define GetEntropy_init_default {0}
|
||||
#define Entropy_init_default {{0, {0}}}
|
||||
#define GetPublicKey_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, ""}
|
||||
#define GetPublicKey_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0}
|
||||
#define PublicKey_init_default {HDNodeType_init_default, false, ""}
|
||||
#define GetAddress_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "Bitcoin", false, 0, false, MultisigRedeemScriptType_init_default}
|
||||
#define Address_init_default {""}
|
||||
@ -684,8 +698,8 @@ extern const char SimpleSignTx_coin_name_default[17];
|
||||
#define CipheredKeyValue_init_default {false, {0, {0}}}
|
||||
#define EstimateTxSize_init_default {0, 0, false, "Bitcoin"}
|
||||
#define TxSize_init_default {false, 0}
|
||||
#define SignTx_init_default {0, 0, false, "Bitcoin"}
|
||||
#define SimpleSignTx_init_default {0, {}, 0, {}, 0, {}, false, "Bitcoin"}
|
||||
#define SignTx_init_default {0, 0, false, "Bitcoin", false, 1u, false, 0u}
|
||||
#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 SignIdentity_init_default {false, IdentityType_init_default, false, {0, {0}}, false, "", false, ""}
|
||||
@ -715,7 +729,7 @@ extern const char SimpleSignTx_coin_name_default[17];
|
||||
#define PassphraseAck_init_zero {""}
|
||||
#define GetEntropy_init_zero {0}
|
||||
#define Entropy_init_zero {{0, {0}}}
|
||||
#define GetPublicKey_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, ""}
|
||||
#define GetPublicKey_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0}
|
||||
#define PublicKey_init_zero {HDNodeType_init_zero, false, ""}
|
||||
#define GetAddress_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0, false, MultisigRedeemScriptType_init_zero}
|
||||
#define Address_init_zero {""}
|
||||
@ -738,8 +752,8 @@ extern const char SimpleSignTx_coin_name_default[17];
|
||||
#define CipheredKeyValue_init_zero {false, {0, {0}}}
|
||||
#define EstimateTxSize_init_zero {0, 0, false, ""}
|
||||
#define TxSize_init_zero {false, 0}
|
||||
#define SignTx_init_zero {0, 0, false, ""}
|
||||
#define SimpleSignTx_init_zero {0, {}, 0, {}, 0, {}, false, ""}
|
||||
#define SignTx_init_zero {0, 0, false, "", false, 0, false, 0}
|
||||
#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 SignIdentity_init_zero {false, IdentityType_init_zero, false, {0, {0}}, false, "", false, ""}
|
||||
@ -829,6 +843,7 @@ extern const char SimpleSignTx_coin_name_default[17];
|
||||
#define GetEntropy_size_tag 1
|
||||
#define GetPublicKey_address_n_tag 1
|
||||
#define GetPublicKey_ecdsa_curve_name_tag 2
|
||||
#define GetPublicKey_show_display_tag 3
|
||||
#define LoadDevice_mnemonic_tag 1
|
||||
#define LoadDevice_node_tag 2
|
||||
#define LoadDevice_pin_tag 3
|
||||
@ -869,6 +884,8 @@ extern const char SimpleSignTx_coin_name_default[17];
|
||||
#define SignTx_outputs_count_tag 1
|
||||
#define SignTx_inputs_count_tag 2
|
||||
#define SignTx_coin_name_tag 3
|
||||
#define SignTx_version_tag 4
|
||||
#define SignTx_lock_time_tag 5
|
||||
#define SignedIdentity_address_tag 1
|
||||
#define SignedIdentity_public_key_tag 2
|
||||
#define SignedIdentity_signature_tag 3
|
||||
@ -876,6 +893,8 @@ extern const char SimpleSignTx_coin_name_default[17];
|
||||
#define SimpleSignTx_outputs_tag 2
|
||||
#define SimpleSignTx_transactions_tag 3
|
||||
#define SimpleSignTx_coin_name_tag 4
|
||||
#define SimpleSignTx_version_tag 5
|
||||
#define SimpleSignTx_lock_time_tag 6
|
||||
#define Success_message_tag 1
|
||||
#define TxAck_tx_tag 1
|
||||
#define TxRequest_request_type_tag 1
|
||||
@ -906,7 +925,7 @@ extern const pb_field_t PassphraseRequest_fields[1];
|
||||
extern const pb_field_t PassphraseAck_fields[2];
|
||||
extern const pb_field_t GetEntropy_fields[2];
|
||||
extern const pb_field_t Entropy_fields[2];
|
||||
extern const pb_field_t GetPublicKey_fields[3];
|
||||
extern const pb_field_t GetPublicKey_fields[4];
|
||||
extern const pb_field_t PublicKey_fields[3];
|
||||
extern const pb_field_t GetAddress_fields[5];
|
||||
extern const pb_field_t Address_fields[2];
|
||||
@ -929,8 +948,8 @@ extern const pb_field_t CipherKeyValue_fields[8];
|
||||
extern const pb_field_t CipheredKeyValue_fields[2];
|
||||
extern const pb_field_t EstimateTxSize_fields[4];
|
||||
extern const pb_field_t TxSize_fields[2];
|
||||
extern const pb_field_t SignTx_fields[4];
|
||||
extern const pb_field_t SimpleSignTx_fields[5];
|
||||
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 SignIdentity_fields[5];
|
||||
@ -962,7 +981,7 @@ extern const pb_field_t DebugLinkLog_fields[4];
|
||||
#define PassphraseAck_size 53
|
||||
#define GetEntropy_size 6
|
||||
#define Entropy_size 1027
|
||||
#define GetPublicKey_size 82
|
||||
#define GetPublicKey_size 84
|
||||
#define PublicKey_size (121 + HDNodeType_size)
|
||||
#define GetAddress_size (75 + MultisigRedeemScriptType_size)
|
||||
#define Address_size 38
|
||||
@ -985,8 +1004,8 @@ extern const pb_field_t DebugLinkLog_fields[4];
|
||||
#define CipheredKeyValue_size 1027
|
||||
#define EstimateTxSize_size 31
|
||||
#define TxSize_size 6
|
||||
#define SignTx_size 31
|
||||
#define SimpleSignTx_size (19 + 0*TxInputType_size + 0*TxOutputType_size + 0*TransactionType_size)
|
||||
#define SignTx_size 43
|
||||
#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 SignIdentity_size (558 + IdentityType_size)
|
||||
|
@ -1 +1 @@
|
||||
../../trezor-common/protob/messages.proto
|
||||
../../vendor/trezor-common/protob/messages.proto
|
@ -1 +1 @@
|
||||
../../trezor-common/protob/storage.proto
|
||||
../../vendor/trezor-common/protob/storage.proto
|
@ -53,7 +53,8 @@ typedef enum _ButtonRequestType {
|
||||
ButtonRequestType_ButtonRequest_ProtectCall = 7,
|
||||
ButtonRequestType_ButtonRequest_SignTx = 8,
|
||||
ButtonRequestType_ButtonRequest_FirmwareCheck = 9,
|
||||
ButtonRequestType_ButtonRequest_Address = 10
|
||||
ButtonRequestType_ButtonRequest_Address = 10,
|
||||
ButtonRequestType_ButtonRequest_PublicKey = 11
|
||||
} ButtonRequestType;
|
||||
|
||||
typedef enum _PinMatrixRequestType {
|
||||
|
@ -1 +1 @@
|
||||
../../trezor-common/protob/types.proto
|
||||
../../vendor/trezor-common/protob/types.proto
|
@ -77,7 +77,7 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect
|
||||
awaiting_entropy = true;
|
||||
}
|
||||
|
||||
static char current_word[10];
|
||||
static char current_word[10], current_word_display[11];
|
||||
|
||||
void reset_entropy(const uint8_t *ext_entropy, uint32_t len)
|
||||
{
|
||||
@ -89,7 +89,7 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len)
|
||||
sha256_Init(&ctx);
|
||||
sha256_Update(&ctx, int_entropy, 32);
|
||||
sha256_Update(&ctx, ext_entropy, len);
|
||||
sha256_Final(int_entropy, &ctx);
|
||||
sha256_Final(&ctx, int_entropy);
|
||||
strlcpy(storage.mnemonic, mnemonic_from_data(int_entropy, strength / 8), sizeof(storage.mnemonic));
|
||||
memset(int_entropy, 0, 32);
|
||||
awaiting_entropy = false;
|
||||
@ -122,17 +122,22 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len)
|
||||
if (word_pos == 3 || word_pos == 23) {
|
||||
desc[2] = 'r'; desc[3] = 'd';
|
||||
}
|
||||
current_word_display[0] = 0x01;
|
||||
for (j = 0; current_word[j]; j++) {
|
||||
current_word_display[j + 1] = current_word[j] + 'A' - 'a';
|
||||
}
|
||||
current_word_display[j + 1] = 0;
|
||||
if (word_pos == (int)strength/32*3) { // last word
|
||||
if (pass == 1) {
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Finish", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, current_word, NULL);
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Finish", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL);
|
||||
} else {
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Again", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, current_word, NULL);
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Again", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL);
|
||||
}
|
||||
} else {
|
||||
if (pass == 1) {
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Next", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, current_word, NULL);
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Next", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL);
|
||||
} else {
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Next", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, current_word, NULL);
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Next", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL);
|
||||
}
|
||||
}
|
||||
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) {
|
||||
|
@ -51,8 +51,8 @@ static TxStruct to, tp, ti;
|
||||
static SHA256_CTX tc;
|
||||
static uint8_t hash[32], hash_check[32], privkey[32], pubkey[33], sig[64];
|
||||
static uint64_t to_spend, spending, change_spend;
|
||||
const uint32_t version = 1;
|
||||
const uint32_t lock_time = 0;
|
||||
static uint32_t version = 1;
|
||||
static uint32_t lock_time = 0;
|
||||
static uint32_t progress, progress_step, progress_meta_step;
|
||||
static bool multisig_fp_set, multisig_fp_mismatch;
|
||||
static uint8_t multisig_fp[32];
|
||||
@ -224,12 +224,14 @@ void send_req_finished(void)
|
||||
msg_write(MessageType_MessageType_TxRequest, &resp);
|
||||
}
|
||||
|
||||
void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinType *_coin, const HDNode *_root)
|
||||
void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinType *_coin, const HDNode *_root, uint32_t _version, uint32_t _lock_time)
|
||||
{
|
||||
inputs_count = _inputs_count;
|
||||
outputs_count = _outputs_count;
|
||||
coin = _coin;
|
||||
root = _root;
|
||||
version = _version;
|
||||
lock_time = _lock_time;
|
||||
|
||||
idx1 = 0;
|
||||
to_spend = 0;
|
||||
@ -414,7 +416,7 @@ void signing_txack(TransactionType *tx)
|
||||
idx1++;
|
||||
send_req_3_output();
|
||||
} else {
|
||||
sha256_Final(hash_check, &tc);
|
||||
sha256_Final(&tc, hash_check);
|
||||
// check fees
|
||||
if (spending > to_spend) {
|
||||
fsm_sendFailure(FailureType_Failure_NotEnoughFunds, "Not enough funds");
|
||||
@ -525,7 +527,7 @@ void signing_txack(TransactionType *tx)
|
||||
idx2++;
|
||||
send_req_4_output();
|
||||
} else {
|
||||
sha256_Final(hash, &tc);
|
||||
sha256_Final(&tc, hash);
|
||||
if (memcmp(hash, hash_check, 32) != 0) {
|
||||
fsm_sendFailure(FailureType_Failure_Other, "Transaction has changed during signing");
|
||||
signing_abort();
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include "bip32.h"
|
||||
#include "types.pb.h"
|
||||
|
||||
void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinType *_coin, const HDNode *_root);
|
||||
void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinType *_coin, const HDNode *_root, uint32_t _version, uint32_t _lock_time);
|
||||
void signing_abort(void);
|
||||
void signing_txack(TransactionType *tx);
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "pbkdf2.h"
|
||||
#include "bip32.h"
|
||||
#include "bip39.h"
|
||||
#include "curves.h"
|
||||
#include "util.h"
|
||||
#include "memory.h"
|
||||
#include "rng.h"
|
||||
@ -45,8 +46,8 @@ Storage storage;
|
||||
uint8_t storage_uuid[12];
|
||||
char storage_uuid_str[25];
|
||||
|
||||
static bool sessionRootNodeCached;
|
||||
static HDNode sessionRootNode;
|
||||
static bool sessionSeedCached;
|
||||
static uint8_t sessionSeed[64];
|
||||
|
||||
static bool sessionPinCached;
|
||||
|
||||
@ -126,8 +127,10 @@ void storage_reset(void)
|
||||
|
||||
void session_clear(bool clear_pin)
|
||||
{
|
||||
sessionRootNodeCached = false; memset(&sessionRootNode, 0, sizeof(sessionRootNode));
|
||||
sessionPassphraseCached = false; memset(&sessionPassphrase, 0, sizeof(sessionPassphrase));
|
||||
sessionSeedCached = false;
|
||||
memset(&sessionSeed, 0, sizeof(sessionSeed));
|
||||
sessionPassphraseCached = false;
|
||||
memset(&sessionPassphrase, 0, sizeof(sessionPassphrase));
|
||||
if (clear_pin) {
|
||||
sessionPinCached = false;
|
||||
}
|
||||
@ -186,14 +189,14 @@ void storage_loadDevice(LoadDevice *msg)
|
||||
storage.has_node = true;
|
||||
storage.has_mnemonic = false;
|
||||
memcpy(&storage.node, &(msg->node), sizeof(HDNodeType));
|
||||
sessionRootNodeCached = false;
|
||||
memset(&sessionRootNode, 0, sizeof(sessionRootNode));
|
||||
sessionSeedCached = false;
|
||||
memset(&sessionSeed, 0, sizeof(sessionSeed));
|
||||
} else if (msg->has_mnemonic) {
|
||||
storage.has_mnemonic = true;
|
||||
storage.has_node = false;
|
||||
strlcpy(storage.mnemonic, msg->mnemonic, sizeof(storage.mnemonic));
|
||||
sessionRootNodeCached = false;
|
||||
memset(&sessionRootNode, 0, sizeof(sessionRootNode));
|
||||
sessionSeedCached = false;
|
||||
memset(&sessionSeed, 0, sizeof(sessionSeed));
|
||||
}
|
||||
|
||||
if (msg->has_language) {
|
||||
@ -224,7 +227,7 @@ void storage_setLanguage(const char *lang)
|
||||
|
||||
void storage_setPassphraseProtection(bool passphrase_protection)
|
||||
{
|
||||
sessionRootNodeCached = false;
|
||||
sessionSeedCached = false;
|
||||
sessionPassphraseCached = false;
|
||||
|
||||
storage.has_passphrase_protection = true;
|
||||
@ -249,56 +252,56 @@ void get_root_node_callback(uint32_t iter, uint32_t total)
|
||||
layoutProgress("Waking up", 1000 * iter / total);
|
||||
}
|
||||
|
||||
bool storage_getRootNode(HDNode *node)
|
||||
const uint8_t *storage_getSeed(void)
|
||||
{
|
||||
// root node is properly cached
|
||||
if (sessionRootNodeCached) {
|
||||
memcpy(node, &sessionRootNode, sizeof(HDNode));
|
||||
return true;
|
||||
}
|
||||
|
||||
// if storage has node, decrypt and use it
|
||||
if (storage.has_node) {
|
||||
if (!protectPassphrase()) {
|
||||
return false;
|
||||
}
|
||||
if (hdnode_from_xprv(storage.node.depth, storage.node.fingerprint, storage.node.child_num, storage.node.chain_code.bytes, storage.node.private_key.bytes, &sessionRootNode) == 0) {
|
||||
return false;
|
||||
}
|
||||
if (storage.has_passphrase_protection && storage.passphrase_protection && strlen(sessionPassphrase)) {
|
||||
// decrypt hd node
|
||||
uint8_t secret[64];
|
||||
uint8_t salt[12];
|
||||
memcpy(salt, "TREZORHD", 8);
|
||||
layoutProgressSwipe("Waking up", 0);
|
||||
pbkdf2_hmac_sha512((const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), salt, 8, BIP39_PBKDF2_ROUNDS, secret, 64, get_root_node_callback);
|
||||
aes_decrypt_ctx ctx;
|
||||
aes_decrypt_key256(secret, &ctx);
|
||||
aes_cbc_decrypt(sessionRootNode.chain_code, sessionRootNode.chain_code, 32, secret + 32, &ctx);
|
||||
aes_cbc_decrypt(sessionRootNode.private_key, sessionRootNode.private_key, 32, secret + 32, &ctx);
|
||||
}
|
||||
memcpy(node, &sessionRootNode, sizeof(HDNode));
|
||||
sessionRootNodeCached = true;
|
||||
return true;
|
||||
if (sessionSeedCached) {
|
||||
return sessionSeed;
|
||||
}
|
||||
|
||||
// if storage has mnemonic, convert it to node and use it
|
||||
if (storage.has_mnemonic) {
|
||||
if (!protectPassphrase()) {
|
||||
return NULL;
|
||||
}
|
||||
mnemonic_to_seed(storage.mnemonic, sessionPassphrase, sessionSeed, get_root_node_callback); // BIP-0039
|
||||
sessionSeedCached = true;
|
||||
return sessionSeed;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool storage_getRootNode(HDNode *node, const char *curve)
|
||||
{
|
||||
// if storage has node, decrypt and use it
|
||||
if (storage.has_node && strcmp(curve, SECP256K1_NAME) == 0) {
|
||||
if (!protectPassphrase()) {
|
||||
return false;
|
||||
}
|
||||
uint8_t seed[64];
|
||||
layoutProgressSwipe("Waking up", 0);
|
||||
mnemonic_to_seed(storage.mnemonic, sessionPassphrase, seed, get_root_node_callback); // BIP-0039
|
||||
if (hdnode_from_seed(seed, sizeof(seed), &sessionRootNode) == 0) {
|
||||
if (hdnode_from_xprv(storage.node.depth, storage.node.fingerprint, storage.node.child_num, storage.node.chain_code.bytes, storage.node.private_key.bytes, curve, node) == 0) {
|
||||
return false;
|
||||
}
|
||||
memcpy(node, &sessionRootNode, sizeof(HDNode));
|
||||
sessionRootNodeCached = true;
|
||||
if (storage.has_passphrase_protection && storage.passphrase_protection && sessionPassphraseCached && strlen(sessionPassphrase) > 0) {
|
||||
// decrypt hd node
|
||||
uint8_t secret[64];
|
||||
uint8_t salt[12];
|
||||
memcpy(salt, "TREZORHD", 8);
|
||||
pbkdf2_hmac_sha512((const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), salt, 8, BIP39_PBKDF2_ROUNDS, secret, 64, get_root_node_callback);
|
||||
aes_decrypt_ctx ctx;
|
||||
aes_decrypt_key256(secret, &ctx);
|
||||
aes_cbc_decrypt(node->chain_code, node->chain_code, 32, secret + 32, &ctx);
|
||||
aes_cbc_decrypt(node->private_key, node->private_key, 32, secret + 32, &ctx);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
const uint8_t *seed = storage_getSeed();
|
||||
if (seed == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return hdnode_from_seed(seed, 64, curve, node);
|
||||
}
|
||||
|
||||
const char *storage_getLabel(void)
|
||||
|
@ -33,7 +33,9 @@ void session_clear(bool clear_pin);
|
||||
|
||||
void storage_loadDevice(LoadDevice *msg);
|
||||
|
||||
bool storage_getRootNode(HDNode *node);
|
||||
const uint8_t *storage_getSeed(void);
|
||||
|
||||
bool storage_getRootNode(HDNode *node, const char *curve);
|
||||
|
||||
const char *storage_getLabel(void);
|
||||
void storage_setLabel(const char *label);
|
||||
|
@ -223,7 +223,7 @@ uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig,
|
||||
d[1] = 0xAE;
|
||||
sha256_Update(&ctx, d, 2);
|
||||
|
||||
sha256_Final(hash, &ctx);
|
||||
sha256_Final(&ctx, hash);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -425,7 +425,7 @@ void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t v
|
||||
|
||||
void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse)
|
||||
{
|
||||
sha256_Final(hash, &(t->ctx));
|
||||
sha256_Final(&(t->ctx), hash);
|
||||
sha256_Raw(hash, 32, hash);
|
||||
if (!reverse) return;
|
||||
uint8_t i, k;
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
#define VERSION_MAJOR 1
|
||||
#define VERSION_MINOR 3
|
||||
#define VERSION_PATCH 4
|
||||
#define VERSION_PATCH 5
|
||||
|
||||
#define STR(X) #X
|
||||
#define VERSTR(X) STR(X)
|
||||
|
2
gen/bitmaps/.gitignore
vendored
2
gen/bitmaps/.gitignore
vendored
@ -1,2 +0,0 @@
|
||||
*.c
|
||||
*.h
|
19
gitian/gitian.yml
Normal file
19
gitian/gitian.yml
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
name: "trezor-mcu"
|
||||
enable_cache: true
|
||||
suites:
|
||||
- "trusty"
|
||||
architectures:
|
||||
- "amd64"
|
||||
packages:
|
||||
- "build-essential"
|
||||
- "gcc-arm-none-eabi"
|
||||
reference_datetime: "2015-06-01 00:00:00"
|
||||
remotes:
|
||||
- "url": "https://github.com/trezor/trezor-mcu.git"
|
||||
"dir": "trezor-mcu"
|
||||
files: []
|
||||
script: |
|
||||
make -C vendor/libopencm3
|
||||
make
|
||||
make -C firmware
|
76
oled.c
76
oled.c
@ -55,13 +55,30 @@
|
||||
#define OLED_RST_PORT GPIOB
|
||||
#define OLED_RST_PIN GPIO1 // PB1 | Reset display
|
||||
|
||||
/* TREZOR has a display of size OLED_WIDTH x OLED_HEIGHT (128x64).
|
||||
* The contents of this display are buffered in _oledbuffer. This is
|
||||
* an array of OLED_WIDTH * OLED_HEIGHT/8 bytes. At byte y*OLED_WIDTH + x
|
||||
* it stores the column of pixels from (x,8y) to (x,8y+7); the LSB stores
|
||||
* the top most pixel. The pixel (0,0) is the top left corner of the
|
||||
* display.
|
||||
*/
|
||||
|
||||
/* Macros to manipulate a single pixel in _oledbuffer:
|
||||
* OLED_BUFSET(X,Y) sets pixel X,Y (white)
|
||||
* OLED_BUFCLR(X,Y) clears pixel X,Y (black)
|
||||
* OLED_BUFTGL(X,Y) toggles pixel X,Y (inverts it)
|
||||
*/
|
||||
|
||||
#define OLED_BUFSET(X,Y) _oledbuffer[OLED_BUFSIZE - 1 - (X) - ((Y)/8)*OLED_WIDTH] |= (1 << (7 - (Y)%8))
|
||||
#define OLED_BUFCLR(X,Y) _oledbuffer[OLED_BUFSIZE - 1 - (X) - ((Y)/8)*OLED_WIDTH] &= ~(1 << (7 - (Y)%8))
|
||||
#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 char is_debug_mode = 0;
|
||||
static bool is_debug_mode = 0;
|
||||
|
||||
/*
|
||||
* Send a block of data via the SPI bus.
|
||||
*/
|
||||
inline void SPISend(uint32_t base, uint8_t *data, int len)
|
||||
{
|
||||
int i;
|
||||
@ -72,6 +89,9 @@ inline void SPISend(uint32_t base, uint8_t *data, int len)
|
||||
delay(800);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the display.
|
||||
*/
|
||||
void oledInit()
|
||||
{
|
||||
static uint8_t s[25] = {
|
||||
@ -121,11 +141,20 @@ void oledInit()
|
||||
oledRefresh();
|
||||
}
|
||||
|
||||
/*
|
||||
* Clears the display buffer (sets all pixels to black)
|
||||
*/
|
||||
void oledClear()
|
||||
{
|
||||
memset(_oledbuffer, 0, sizeof(_oledbuffer));
|
||||
}
|
||||
|
||||
/*
|
||||
* Refresh the display. This copies the buffer to the display to show the
|
||||
* contents. This must be called after every operation to the buffer to
|
||||
* make the change visible. All other operations only change the buffer
|
||||
* not the content of the display.
|
||||
*/
|
||||
void oledRefresh()
|
||||
{
|
||||
static uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00, OLED_SETHIGHCOLUMN | 0x00, OLED_SETSTARTLINE | 0x00};
|
||||
@ -164,7 +193,7 @@ const uint8_t *oledGetBuffer()
|
||||
return _oledbuffer;
|
||||
}
|
||||
|
||||
void oledSetDebug(char set)
|
||||
void oledSetDebug(bool set)
|
||||
{
|
||||
is_debug_mode = set;
|
||||
oledRefresh();
|
||||
@ -187,7 +216,7 @@ void oledClearPixel(int x, int y)
|
||||
OLED_BUFCLR(x,y);
|
||||
}
|
||||
|
||||
void oledDrawChar(int x, int y, char c)
|
||||
void oledDrawChar(int x, int y, char c, int zoom)
|
||||
{
|
||||
int char_width;
|
||||
const uint8_t *char_data;
|
||||
@ -197,11 +226,15 @@ void oledDrawChar(int x, int y, char c)
|
||||
char_width = fontCharWidth(c);
|
||||
char_data = fontCharData(c);
|
||||
|
||||
int xoffset, yoffset;
|
||||
for (xoffset = 0; xoffset < char_width; xoffset++) {
|
||||
for (yoffset = 0; yoffset < FONT_HEIGHT; yoffset++) {
|
||||
if (char_data[xoffset] & (1 << (FONT_HEIGHT - 1 - yoffset))) {
|
||||
oledDrawPixel(x + xoffset, y + yoffset);
|
||||
int xo, yo;
|
||||
for (xo = 0; xo < char_width; xo++) {
|
||||
for (yo = 0; yo < FONT_HEIGHT; yo++) {
|
||||
if (char_data[xo] & (1 << (FONT_HEIGHT - 1 - yo))) {
|
||||
if (zoom <= 1) {
|
||||
oledDrawPixel(x + xo, y + yo);
|
||||
} else {
|
||||
oledBox(x + xo * zoom, y + yo * zoom, x + (xo + 1) * zoom - 1, y + (yo + 1) * zoom - 1, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -233,13 +266,18 @@ int oledStringWidth(const char *text) {
|
||||
void oledDrawString(int x, int y, const char* text)
|
||||
{
|
||||
if (!text) return;
|
||||
int size = 1;
|
||||
if (*text == 0x01) { // double size
|
||||
text++;
|
||||
size = 2;
|
||||
}
|
||||
int l = 0;
|
||||
char c;
|
||||
for (; *text; text++) {
|
||||
c = oledConvertChar(*text);
|
||||
if (c) {
|
||||
oledDrawChar(x + l, y, c);
|
||||
l += fontCharWidth(c) + 1;
|
||||
oledDrawChar(x + l, y, c, size);
|
||||
l += size * (fontCharWidth(c) + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -283,12 +321,15 @@ void oledInvert(int x1, int y1, int x2, int y2)
|
||||
}
|
||||
}
|
||||
|
||||
void oledBox(int x1, int y1, int x2, int y2, char val)
|
||||
/*
|
||||
* Draw a filled rectangle.
|
||||
*/
|
||||
void oledBox(int x1, int y1, int x2, int y2, bool set)
|
||||
{
|
||||
int x, y;
|
||||
for (x = x1; x <= x2; x++) {
|
||||
for (y = y1; y <= y2; y++) {
|
||||
val ? oledDrawPixel(x, y) : oledClearPixel(x, y);
|
||||
set ? oledDrawPixel(x, y) : oledClearPixel(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -300,6 +341,9 @@ void oledHLine(int y) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw a rectangle frame.
|
||||
*/
|
||||
void oledFrame(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
int x, y;
|
||||
@ -313,6 +357,10 @@ void oledFrame(int x1, int y1, int x2, int y2)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Animates the display, swiping the current contents out to the left.
|
||||
* This clears the display.
|
||||
*/
|
||||
void oledSwipeLeft(void)
|
||||
{
|
||||
int i, j, k;
|
||||
@ -333,6 +381,10 @@ void oledSwipeLeft(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Animates the display, swiping the current contents out to the right.
|
||||
* This clears the display.
|
||||
*/
|
||||
void oledSwipeRight(void)
|
||||
{
|
||||
int i, j, k;
|
||||
|
7
oled.h
7
oled.h
@ -21,6 +21,7 @@
|
||||
#define __OLED_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "bitmaps.h"
|
||||
#include "fonts.h"
|
||||
@ -33,19 +34,19 @@ void oledInit(void);
|
||||
void oledClear(void);
|
||||
void oledRefresh(void);
|
||||
|
||||
void oledSetDebug(char set);
|
||||
void oledSetDebug(bool set);
|
||||
void oledSetBuffer(uint8_t *buf);
|
||||
const uint8_t *oledGetBuffer(void);
|
||||
void oledDrawPixel(int x, int y);
|
||||
void oledClearPixel(int x, int y);
|
||||
void oledDrawChar(int x, int y, char c);
|
||||
void oledDrawChar(int x, int y, char c, int zoom);
|
||||
int oledStringWidth(const char *text);
|
||||
void oledDrawString(int x, int y, const char* text);
|
||||
void oledDrawStringCenter(int y, const char* text);
|
||||
void oledDrawStringRight(int x, int y, const char* text);
|
||||
void oledDrawBitmap(int x, int y, const BITMAP *bmp);
|
||||
void oledInvert(int x1, int y1, int x2, int y2);
|
||||
void oledBox(int x1, int y1, int x2, int y2, char val);
|
||||
void oledBox(int x1, int y1, int x2, int y2, bool set);
|
||||
void oledHLine(int y);
|
||||
void oledFrame(int x1, int y1, int x2, int y2);
|
||||
void oledSwipeLeft(void);
|
||||
|
2
setup.c
2
setup.c
@ -25,7 +25,7 @@
|
||||
void setup(void)
|
||||
{
|
||||
// setup clock
|
||||
clock_scale_t clock = hse_8mhz_3v3[CLOCK_3V3_120MHZ];
|
||||
struct rcc_clock_scale clock = rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_120MHZ];
|
||||
rcc_clock_setup_hse_3v3(&clock);
|
||||
|
||||
// enable GPIO clock - A (oled), B(oled), C (buttons)
|
||||
|
@ -1 +0,0 @@
|
||||
Subproject commit 72268e816b8e8e06f698b3729223a255c7c74167
|
@ -1 +0,0 @@
|
||||
Subproject commit cbbc0bdc7197e74d647aedcbfd064c43544318cf
|
@ -1 +0,0 @@
|
||||
Subproject commit 1183aa714615dfaa9cfb771bca7ec8c11929a4c2
|
2
util.h
2
util.h
@ -22,7 +22,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
inline void delay(uint32_t wait);
|
||||
void delay(uint32_t wait);
|
||||
|
||||
// converts uint32 to hexa (8 digits)
|
||||
void uint32hex(uint32_t num, char *str);
|
||||
|
1
vendor/libopencm3
vendored
Submodule
1
vendor/libopencm3
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit d3fff11c1f68b706591c0d51c82d18a0bc88dc17
|
1
vendor/trezor-common
vendored
Submodule
1
vendor/trezor-common
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 0567a429cfc8c6fdf9e08c79270750c102fc4f70
|
1
vendor/trezor-crypto
vendored
Submodule
1
vendor/trezor-crypto
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit ed6debf8c4ec5ef9c7ef31a1a7eddf76aa33ccd8
|
1
vendor/trezor-qrenc
vendored
Submodule
1
vendor/trezor-qrenc
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 9e0228f54db6241524bb89acd3e89040701e0380
|
Loading…
Reference in New Issue
Block a user