1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-07-05 06:12:34 +00:00

Updated branch u2f

This commit is contained in:
Jochen Hoenicke 2016-04-29 16:19:54 +02:00
commit cf38291ca4
48 changed files with 520 additions and 281 deletions

9
.gitmodules vendored
View File

@ -1,9 +1,12 @@
[submodule "trezor-crypto"] [submodule "trezor-crypto"]
path = trezor-crypto path = vendor/trezor-crypto
url = https://github.com/trezor/trezor-crypto.git url = https://github.com/trezor/trezor-crypto.git
[submodule "trezor-common"] [submodule "trezor-common"]
path = trezor-common path = vendor/trezor-common
url = https://github.com/trezor/trezor-common.git url = https://github.com/trezor/trezor-common.git
[submodule "trezor-qrenc"] [submodule "trezor-qrenc"]
path = trezor-qrenc path = vendor/trezor-qrenc
url = https://github.com/trezor/trezor-qrenc.git url = https://github.com/trezor/trezor-qrenc.git
[submodule "libopencm3"]
path = vendor/libopencm3
url = https://github.com/libopencm3/libopencm3.git

View File

@ -4,11 +4,10 @@ install:
- sudo add-apt-repository ppa:terry.guo/gcc-arm-embedded -y - sudo add-apt-repository ppa:terry.guo/gcc-arm-embedded -y
- sudo apt-get update - sudo apt-get update
- sudo apt-get install -y build-essential git gcc-arm-none-eabi - sudo apt-get install -y build-essential git gcc-arm-none-eabi
- git clone https://github.com/libopencm3/libopencm3
script: script:
- make -C libopencm3 - make -C vendor/libopencm3
- TOOLCHAIN_DIR=libopencm3 make - make
- TOOLCHAIN_DIR=../libopencm3 make -C firmware - make -C firmware
- TOOLCHAIN_DIR=../libopencm3 make -C bootloader - make -C bootloader
- TOOLCHAIN_DIR=../libopencm3 make -C demo - make -C demo

View File

@ -9,12 +9,3 @@ RUN apt-get update
# install build tools and dependencies # install build tools and dependencies
RUN apt-get install -y build-essential git python gcc-arm-none-eabi 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

View File

@ -1,5 +1,5 @@
TOP_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) TOP_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
TOOLCHAIN_DIR ?= $(TOP_DIR)/../libopencm3 TOOLCHAIN_DIR ?= $(TOP_DIR)vendor/libopencm3
PREFIX ?= arm-none-eabi- PREFIX ?= arm-none-eabi-
CC = $(PREFIX)gcc CC = $(PREFIX)gcc
@ -9,9 +9,12 @@ OBJDUMP = $(PREFIX)objdump
FLASH = st-flash FLASH = st-flash
OPENOCD = openocd OPENOCD = openocd
OPTFLAGS = -O3 -g -DNDEBUG OPTFLAGS ?= -O3
DBGFLAGS ?= -g -DNDEBUG
CFLAGS += $(OPTFLAGS) \ CFLAGS += $(OPTFLAGS) \
$(DBGFLAGS) \
-std=c99 \
-W \ -W \
-Wall \ -Wall \
-Wextra \ -Wextra \
@ -42,9 +45,10 @@ CFLAGS += $(OPTFLAGS) \
-DSTM32F2 \ -DSTM32F2 \
-I$(TOOLCHAIN_DIR)/include \ -I$(TOOLCHAIN_DIR)/include \
-I$(TOP_DIR) \ -I$(TOP_DIR) \
-I$(TOP_DIR)/gen \ -I$(TOP_DIR)gen \
-I$(TOP_DIR)/trezor-crypto \ -I$(TOP_DIR)vendor/trezor-crypto \
-I$(TOP_DIR)/trezor-qrenc -I$(TOP_DIR)vendor/trezor-crypto/ed25519-donna \
-I$(TOP_DIR)vendor/trezor-qrenc
ifdef APPVER ifdef APPVER
CFLAGS += -DAPPVER=$(APPVER) CFLAGS += -DAPPVER=$(APPVER)

View File

@ -8,13 +8,23 @@ http://bitcointrezor.com/
How to build TREZOR firmware? 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` 2. `git clone https://github.com/trezor/trezor-mcu.git`
3. `cd trezor-mcu` 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) 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. 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? How to get fingerprint of firmware signed and distributed by SatoshiLabs?
------------------------------------------------------------------------- -------------------------------------------------------------------------

22
bootloader-docker-build.sh Executable file
View 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)"

View File

@ -4,12 +4,12 @@ OBJS += bootloader.o
OBJS += signatures.o OBJS += signatures.o
OBJS += usb.o OBJS += usb.o
OBJS += ../trezor-crypto/bignum.o OBJS += ../vendor/trezor-crypto/bignum.o
OBJS += ../trezor-crypto/ecdsa.small.o OBJS += ../vendor/trezor-crypto/ecdsa.small.o
OBJS += ../trezor-crypto/hmac.o OBJS += ../vendor/trezor-crypto/hmac.o
OBJS += ../trezor-crypto/ripemd160.o OBJS += ../vendor/trezor-crypto/ripemd160.o
OBJS += ../trezor-crypto/secp256k1.small.o OBJS += ../vendor/trezor-crypto/secp256k1.small.o
OBJS += ../trezor-crypto/sha2.o OBJS += ../vendor/trezor-crypto/sha2.o
CFLAGS += -DUSE_PRECOMPUTED_IV=0 CFLAGS += -DUSE_PRECOMPUTED_IV=0
CFLAGS += -DUSE_PRECOMPUTED_CP=0 CFLAGS += -DUSE_PRECOMPUTED_CP=0

View File

@ -38,7 +38,23 @@
#error Bootloader cannot be used in app mode #error Bootloader cannot be used in app mode
#endif #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); 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(); buttonUpdate();
} while (!button.YesUp && !button.NoUp); } while (!button.YesUp && !button.NoUp);
if (button.YesUp) { if (button.NoUp) {
return; // yes button was pressed -> return 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"); layoutFirmwareHash(hash);
system_halt();
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) void load_app(void)
{ {
// jump to app // jump to app
SCB_VTOR = FLASH_APP_START; // & 0xFFFF; 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))(); (*(void (**)())(FLASH_APP_START + 4))();
} }
@ -128,8 +154,9 @@ int main(void)
oledDrawBitmap(40, 0, &bmp_logo64_empty); oledDrawBitmap(40, 0, &bmp_logo64_empty);
oledRefresh(); oledRefresh();
if (!signatures_ok()) { uint8_t hash[32];
show_unofficial_warning(); if (!signatures_ok(hash)) {
show_unofficial_warning(hash);
} }
load_app(); load_app();

View File

@ -22,15 +22,17 @@
#define VERSION_MAJOR 1 #define VERSION_MAJOR 1
#define VERSION_MINOR 2 #define VERSION_MINOR 2
#define VERSION_PATCH 5 #define VERSION_PATCH 6
#define STR(X) #X #define STR(X) #X
#define VERSTR(X) STR(X) #define VERSTR(X) STR(X)
#define VERSION_MAJOR_CHAR "\x01" #define VERSION_MAJOR_CHAR "\x01"
#define VERSION_MINOR_CHAR "\x02" #define VERSION_MINOR_CHAR "\x02"
#define VERSION_PATCH_CHAR "\x05" #define VERSION_PATCH_CHAR "\x06"
#include "memory.h" #include "memory.h"
void layoutFirmwareHash(uint8_t *hash);
#endif #endif

View File

@ -18,10 +18,12 @@
*/ */
#include <stdint.h> #include <stdint.h>
#include <string.h>
#include "signatures.h" #include "signatures.h"
#include "ecdsa.h" #include "ecdsa.h"
#include "secp256k1.h" #include "secp256k1.h"
#include "sha2.h"
#include "bootloader.h" #include "bootloader.h"
#define PUBKEYS 5 #define PUBKEYS 5
@ -36,7 +38,7 @@ static const uint8_t *pubkey[PUBKEYS] = {
#define SIGNATURES 3 #define SIGNATURES 3
int signatures_ok(void) int signatures_ok(uint8_t *store_hash)
{ {
uint32_t codelen = *((uint32_t *)FLASH_META_CODELEN); uint32_t codelen = *((uint32_t *)FLASH_META_CODELEN);
uint8_t sigindex1, sigindex2, sigindex3; uint8_t sigindex1, sigindex2, sigindex3;
@ -53,13 +55,19 @@ int signatures_ok(void)
if (sigindex1 == sigindex3) return 0; // duplicate use if (sigindex1 == sigindex3) return 0; // duplicate use
if (sigindex2 == 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; 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; 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; return 0;
} }

View File

@ -20,6 +20,6 @@
#ifndef __SIGNATURES_H__ #ifndef __SIGNATURES_H__
#define __SIGNATURES_H__ #define __SIGNATURES_H__
int signatures_ok(void); int signatures_ok(uint8_t *store_hash);
#endif #endif

View File

@ -425,15 +425,9 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep)
if (msg_id != 0x001B) { // ButtonAck message (id 27) if (msg_id != 0x001B) { // ButtonAck message (id 27)
return; return;
} }
char digest[64]; uint8_t hash[32];
sha256_End(&ctx, digest); sha256_Final(&ctx, hash);
char str[4][17]; layoutFirmwareHash(hash);
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);
do { do {
delay(100000); delay(100000);
buttonUpdate(); buttonUpdate();
@ -444,7 +438,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep)
layoutProgress("INSTALLING ... Please wait", 1000); layoutProgress("INSTALLING ... Please wait", 1000);
uint8_t flags = *((uint8_t *)FLASH_META_FLAGS); uint8_t flags = *((uint8_t *)FLASH_META_FLAGS);
// check if to restore old storage area but only if signatures are ok // 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 // copy new stuff
memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_DESC_LEN); memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_DESC_LEN);
// replace "TRZR" in header with 0000 when hash not confirmed // replace "TRZR" in header with 0000 when hash not confirmed

View File

@ -21,6 +21,7 @@
#define __BUTTONS_H__ #define __BUTTONS_H__
#include <libopencm3/stm32/gpio.h> #include <libopencm3/stm32/gpio.h>
#include <stdbool.h>
struct buttonState { struct buttonState {
volatile bool YesUp; volatile bool YesUp;

View File

@ -4,14 +4,14 @@ NAME = demo
OBJS += demo.o OBJS += demo.o
OBJS += ../trezor-crypto/bignum.o OBJS += ../vendor/trezor-crypto/bignum.o
OBJS += ../trezor-crypto/bip32.o OBJS += ../vendor/trezor-crypto/bip32.o
OBJS += ../trezor-crypto/ecdsa.o OBJS += ../vendor/trezor-crypto/ecdsa.o
OBJS += ../trezor-crypto/hmac.o OBJS += ../vendor/trezor-crypto/hmac.o
OBJS += ../trezor-crypto/ripemd160.o OBJS += ../vendor/trezor-crypto/ripemd160.o
OBJS += ../trezor-crypto/secp256k1.o OBJS += ../vendor/trezor-crypto/secp256k1.o
OBJS += ../trezor-crypto/sha2.o OBJS += ../vendor/trezor-crypto/sha2.o
OBJS += ../trezor-crypto/bip39.o OBJS += ../vendor/trezor-crypto/bip39.o
OBJS += ../trezor-crypto/pbkdf2.o OBJS += ../vendor/trezor-crypto/pbkdf2.o
include ../Makefile.include include ../Makefile.include

View File

@ -8,12 +8,14 @@ docker run -t -v $(pwd)/output:/output $IMAGETAG /bin/sh -c "\
cd trezor-mcu && \ cd trezor-mcu && \
git checkout $FIRMWARETAG && \ git checkout $FIRMWARETAG && \
git submodule update --init && \ git submodule update --init && \
make -C vendor/libopencm3 && \
make && \ make && \
cd firmware && \ make -C firmware && \
make && \ cp firmware/trezor.bin /output/trezor-$FIRMWARETAG.bin"
cp trezor.bin /output/trezor-$FIRMWARETAG.bin"
echo "---------------------" echo "---------------------"
echo "Firmware fingerprint:" echo "Firmware fingerprint:"
FILENAME=output/trezor-$FIRMWARETAG.bin
sha256sum output/trezor-$FIRMWARETAG.bin sha256sum "$FILENAME"
FILESIZE=$(stat -c%s "$FILENAME")
echo "Firmware size: $FILESIZE bytes (out of 491520 maximum)"

View File

@ -20,25 +20,27 @@ OBJS += crypto.o
OBJS += debug.o OBJS += debug.o
OBJS += ../trezor-crypto/bignum.o OBJS += ../vendor/trezor-crypto/bignum.o
OBJS += ../trezor-crypto/ecdsa.o OBJS += ../vendor/trezor-crypto/ecdsa.o
OBJS += ../trezor-crypto/secp256k1.o OBJS += ../vendor/trezor-crypto/curves.o
OBJS += ../trezor-crypto/nist256p1.o OBJS += ../vendor/trezor-crypto/secp256k1.o
OBJS += ../trezor-crypto/hmac.o OBJS += ../vendor/trezor-crypto/nist256p1.o
OBJS += ../trezor-crypto/bip32.o OBJS += ../vendor/trezor-crypto/ed25519-donna/ed25519.o
OBJS += ../trezor-crypto/bip39.o OBJS += ../vendor/trezor-crypto/hmac.o
OBJS += ../trezor-crypto/pbkdf2.o OBJS += ../vendor/trezor-crypto/bip32.o
OBJS += ../trezor-crypto/base58.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 += ../vendor/trezor-crypto/ripemd160.o
OBJS += ../trezor-crypto/sha2.o OBJS += ../vendor/trezor-crypto/sha2.o
OBJS += ../trezor-crypto/aescrypt.o OBJS += ../vendor/trezor-crypto/aescrypt.o
OBJS += ../trezor-crypto/aeskey.o OBJS += ../vendor/trezor-crypto/aeskey.o
OBJS += ../trezor-crypto/aestab.o OBJS += ../vendor/trezor-crypto/aestab.o
OBJS += ../trezor-crypto/aes_modes.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_common.o
OBJS += protob/pb_decode.o OBJS += protob/pb_decode.o
@ -55,3 +57,5 @@ CFLAGS += -DQR_MAX_VERSION=0
CFLAGS += -DDEBUG_LINK=0 CFLAGS += -DDEBUG_LINK=0
CFLAGS += -DDEBUG_LOG=0 CFLAGS += -DDEBUG_LOG=0
CFLAGS += -DSCM_REVISION='"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')"' CFLAGS += -DSCM_REVISION='"$(shell git rev-parse HEAD | sed 's:\(..\):\\x\1:g')"'
CFLAGS += -DED25519_CUSTOMRANDOM=1
CFLAGS += -DED25519_CUSTOMHASH=1

View File

@ -25,8 +25,8 @@
#include "hmac.h" #include "hmac.h"
#include "bip32.h" #include "bip32.h"
#include "layout.h" #include "layout.h"
#include "curves.h"
#include "secp256k1.h" #include "secp256k1.h"
#include "nist256p1.h"
uint32_t ser_length(uint32_t len, uint8_t *out) 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; 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 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_CTX ctx;
sha256_Init(&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, varint, l);
sha256_Update(&ctx, message, message_len); sha256_Update(&ctx, message, message_len);
uint8_t hash[32]; uint8_t hash[32];
sha256_Final(hash, &ctx); sha256_Final(&ctx, hash);
sha256_Raw(hash, 32, hash); sha256_Raw(hash, 32, hash);
uint8_t pby; 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) { if (result == 0) {
signature[0] = 27 + pby + 4; 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) 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; SHA256_CTX ctx;
uint8_t pubkey[65], addr_raw[21], hash[32]; 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 // calculate hash
sha256_Init(&ctx); sha256_Init(&ctx);
sha256_Update(&ctx, (const uint8_t *)"\x18" "Bitcoin Signed Message:" "\n", 25); 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); uint32_t l = ser_length(message_len, varint);
sha256_Update(&ctx, varint, l); sha256_Update(&ctx, varint, l);
sha256_Update(&ctx, message, message_len); sha256_Update(&ctx, message, message_len);
sha256_Final(hash, &ctx); sha256_Final(&ctx, hash);
sha256_Raw(hash, 32, hash); sha256_Raw(hash, 32, hash);
// e = -hash
bn_read_be(hash, &e); uint8_t recid = signature[0] - 27;
bn_subtract(&secp256k1.order, &e, &e); if (recid >= 8) {
// r = r^-1 return 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);
} }
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); ecdsa_get_address_raw(pubkey, address_raw[0], addr_raw);
if (memcmp(addr_raw, address_raw, 21) != 0) { if (memcmp(addr_raw, address_raw, 21) != 0) {
return 2; return 2;
} }
// check if signature verifies the digest
if (ecdsa_verify_digest(&secp256k1, pubkey, signature + 1, hash) != 0) {
return 3;
}
return 0; 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) int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw)
{ {
if (privkey && address_raw) { // signing == true if (privkey && address_raw) { // signing == true
HDNode node;
payload[0] = display_only ? 0x81 : 0x01; payload[0] = display_only ? 0x81 : 0x01;
uint32_t l = ser_length(msg_size, payload + 1); uint32_t l = ser_length(msg_size, payload + 1);
memcpy(payload + 1 + l, msg, msg_size); memcpy(payload + 1 + l, msg, msg_size);
memcpy(payload + 1 + l + msg_size, address_raw, 21); 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; return 1;
} }
*payload_len = 1 + l + msg_size + 21 + 65; *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; if (!hdnodepath->node.has_public_key || hdnodepath->node.public_key.size != 33) return 0;
static HDNode node; 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; return 0;
} }
layoutProgressUpdate(true); 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, ptr[i]->node.public_key.bytes, 33);
} }
sha256_Update(&ctx, (const uint8_t *)&n, sizeof(uint32_t)); sha256_Update(&ctx, (const uint8_t *)&n, sizeof(uint32_t));
sha256_Final(hash, &ctx); sha256_Final(&ctx, hash);
layoutProgressUpdate(true); layoutProgressUpdate(true);
return 1; return 1;
} }
@ -373,6 +363,6 @@ int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash)
if (identity->has_path && identity->path[0]) { if (identity->has_path && identity->path[0]) {
sha256_Update(&ctx, (const uint8_t *)(identity->path), strlen(identity->path)); sha256_Update(&ctx, (const uint8_t *)(identity->path), strlen(identity->path));
} }
sha256_Final(hash, &ctx); sha256_Final(&ctx, hash);
return 1; return 1;
} }

View File

@ -24,6 +24,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <ecdsa.h> #include <ecdsa.h>
#include <bip32.h>
#include <sha2.h> #include <sha2.h>
#include <pb.h> #include <pb.h>
#include "types.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); 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); int cryptoMessageVerify(const uint8_t *message, size_t message_len, const uint8_t *address_raw, const uint8_t *signature);

View File

@ -44,8 +44,8 @@
#include "base58.h" #include "base58.h"
#include "bip39.h" #include "bip39.h"
#include "ripemd160.h" #include "ripemd160.h"
#include "curves.h"
#include "secp256k1.h" #include "secp256k1.h"
#include "nist256p1.h"
// message methods // message methods
@ -93,11 +93,11 @@ const CoinType *fsm_getCoin(const char *name)
return coin; 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; static HDNode node;
if (!storage_getRootNode(&node)) { if (!storage_getRootNode(&node, curve)) {
fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized or passphrase request cancelled"); fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized or passphrase request cancelled or unsupported curve");
layoutHome(); layoutHome();
return 0; return 0;
} }
@ -282,22 +282,29 @@ void fsm_msgGetPublicKey(GetPublicKey *msg)
{ {
RESP_INIT(PublicKey); RESP_INIT(PublicKey);
if (!storage_isInitialized()) {
fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized");
return;
}
if (!protectPin(true)) { if (!protectPin(true)) {
layoutHome(); layoutHome();
return; 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; if (!node) return;
uint8_t public_key[33]; // copy public key to temporary buffer if (msg->has_show_display && msg->show_display) {
memcpy(public_key, node->public_key, sizeof(public_key)); layoutPublicKey(node->public_key);
if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) {
if (msg->has_ecdsa_curve_name) { fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show public key cancelled");
const ecdsa_curve *curve = get_curve_by_name(msg->ecdsa_curve_name); layoutHome();
if (curve) { return;
// correct public key (since fsm_getDerivedNode uses secp256k1 curve)
ecdsa_get_public_key33(curve, node->private_key, public_key);
} }
} }
@ -309,7 +316,7 @@ void fsm_msgGetPublicKey(GetPublicKey *msg)
resp->node.has_private_key = false; resp->node.has_private_key = false;
resp->node.has_public_key = true; resp->node.has_public_key = true;
resp->node.public_key.size = 33; 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; resp->has_xpub = true;
hdnode_serialize_public(node, resp->xpub, sizeof(resp->xpub)); hdnode_serialize_public(node, resp->xpub, sizeof(resp->xpub));
msg_write(MessageType_MessageType_PublicKey, resp); msg_write(MessageType_MessageType_PublicKey, resp);
@ -363,6 +370,11 @@ void fsm_msgResetDevice(ResetDevice *msg)
void fsm_msgSignTx(SignTx *msg) void fsm_msgSignTx(SignTx *msg)
{ {
if (!storage_isInitialized()) {
fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized");
return;
}
if (msg->inputs_count < 1) { if (msg->inputs_count < 1) {
fsm_sendFailure(FailureType_Failure_Other, "Transaction must have at least one input"); fsm_sendFailure(FailureType_Failure_Other, "Transaction must have at least one input");
layoutHome(); layoutHome();
@ -382,10 +394,10 @@ void fsm_msgSignTx(SignTx *msg)
const CoinType *coin = fsm_getCoin(msg->coin_name); const CoinType *coin = fsm_getCoin(msg->coin_name);
if (!coin) return; if (!coin) return;
const HDNode *node = fsm_getDerivedNode(0, 0); const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, 0, 0);
if (!node) return; 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) void fsm_msgCancel(Cancel *msg)
@ -406,6 +418,10 @@ void fsm_msgTxAck(TxAck *msg)
void fsm_msgCipherKeyValue(CipherKeyValue *msg) void fsm_msgCipherKeyValue(CipherKeyValue *msg)
{ {
if (!storage_isInitialized()) {
fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized");
return;
}
if (!msg->has_key) { if (!msg->has_key) {
fsm_sendFailure(FailureType_Failure_SyntaxError, "No key provided"); fsm_sendFailure(FailureType_Failure_SyntaxError, "No key provided");
return; return;
@ -422,7 +438,7 @@ void fsm_msgCipherKeyValue(CipherKeyValue *msg)
layoutHome(); layoutHome();
return; 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 (!node) return;
bool encrypt = msg->has_encrypt && msg->encrypt; bool encrypt = msg->has_encrypt && msg->encrypt;
@ -531,6 +547,11 @@ void fsm_msgGetAddress(GetAddress *msg)
{ {
RESP_INIT(Address); RESP_INIT(Address);
if (!storage_isInitialized()) {
fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized");
return;
}
if (!protectPin(true)) { if (!protectPin(true)) {
layoutHome(); layoutHome();
return; return;
@ -538,7 +559,7 @@ void fsm_msgGetAddress(GetAddress *msg)
const CoinType *coin = fsm_getCoin(msg->coin_name); const CoinType *coin = fsm_getCoin(msg->coin_name);
if (!coin) return; 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 (!node) return;
if (msg->has_multisig) { if (msg->has_multisig) {
@ -599,6 +620,11 @@ void fsm_msgSignMessage(SignMessage *msg)
{ {
RESP_INIT(MessageSignature); RESP_INIT(MessageSignature);
if (!storage_isInitialized()) {
fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized");
return;
}
layoutSignMessage(msg->message.bytes, msg->message.size); layoutSignMessage(msg->message.bytes, msg->message.size);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign message cancelled"); 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); const CoinType *coin = fsm_getCoin(msg->coin_name);
if (!coin) return; 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 (!node) return;
layoutProgressSwipe("Signing", 0); 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; resp->has_address = true;
uint8_t addr_raw[21]; uint8_t addr_raw[21];
ecdsa_get_address_raw(node->public_key, coin->address_type, addr_raw); 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"); 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) { 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); 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"); fsm_sendSuccess("Message verified");
} else { } else {
fsm_sendFailure(FailureType_Failure_InvalidSignature, "Invalid signature"); fsm_sendFailure(FailureType_Failure_InvalidSignature, "Invalid signature");
@ -660,6 +696,11 @@ void fsm_msgSignIdentity(SignIdentity *msg)
{ {
RESP_INIT(SignedIdentity); 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); layoutSignIdentity(&(msg->identity), msg->has_challenge_visual ? msg->challenge_visual : 0);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Sign identity cancelled"); 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[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); 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; 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_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; int result = 0;
layoutProgressSwipe("Signing", 0); layoutProgressSwipe("Signing", 0);
if (sign_ssh) { // SSH does not sign visual challenge 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 { } else {
uint8_t digest[64]; uint8_t digest[64];
sha256_Raw(msg->challenge_hidden.bytes, msg->challenge_hidden.size, digest); 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); 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 (result == 0) {
if (sign_ssh) { if (strcmp(curve, SECP256K1_NAME) != 0) {
resp->has_address = false; resp->has_address = false;
} else { } else {
resp->has_address = true; resp->has_address = true;
@ -724,7 +761,7 @@ void fsm_msgSignIdentity(SignIdentity *msg)
} }
resp->has_public_key = true; resp->has_public_key = true;
resp->public_key.size = 33; 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->has_signature = true;
resp->signature.size = 65; resp->signature.size = 65;
msg_write(MessageType_MessageType_SignedIdentity, resp); msg_write(MessageType_MessageType_SignedIdentity, resp);
@ -736,6 +773,10 @@ void fsm_msgSignIdentity(SignIdentity *msg)
void fsm_msgEncryptMessage(EncryptMessage *msg) void fsm_msgEncryptMessage(EncryptMessage *msg)
{ {
if (!storage_isInitialized()) {
fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized");
return;
}
if (!msg->has_pubkey) { if (!msg->has_pubkey) {
fsm_sendFailure(FailureType_Failure_SyntaxError, "No public key provided"); fsm_sendFailure(FailureType_Failure_SyntaxError, "No public key provided");
return; return;
@ -765,7 +806,7 @@ void fsm_msgEncryptMessage(EncryptMessage *msg)
layoutHome(); layoutHome();
return; 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; if (!node) return;
uint8_t public_key[33]; uint8_t public_key[33];
ecdsa_get_public_key33(&secp256k1, node->private_key, public_key); ecdsa_get_public_key33(&secp256k1, node->private_key, public_key);
@ -792,6 +833,10 @@ void fsm_msgEncryptMessage(EncryptMessage *msg)
void fsm_msgDecryptMessage(DecryptMessage *msg) void fsm_msgDecryptMessage(DecryptMessage *msg)
{ {
if (!storage_isInitialized()) {
fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized");
return;
}
if (!msg->has_nonce) { if (!msg->has_nonce) {
fsm_sendFailure(FailureType_Failure_SyntaxError, "No nonce provided"); fsm_sendFailure(FailureType_Failure_SyntaxError, "No nonce provided");
return; return;
@ -813,7 +858,7 @@ void fsm_msgDecryptMessage(DecryptMessage *msg)
layoutHome(); layoutHome();
return; 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 (!node) return;
layoutProgressSwipe("Decrypting", 0); layoutProgressSwipe("Decrypting", 0);

View File

@ -196,10 +196,19 @@ void layoutSignMessage(const uint8_t *msg, uint32_t len)
str[0], str[1], str[2], str[3], NULL, NULL); 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) void layoutVerifyMessage(const uint8_t *msg, uint32_t len)
{ {
const char **str = split_message(msg, len, 16); const char **str = split_message(msg, len, 16);
layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "OK", layoutDialogSwipe(DIALOG_ICON_INFO, "Cancel", "Confirm",
"Verified message", "Verified message",
str[0], str[1], str[2], str[3], NULL, NULL); str[0], str[1], str[2], str[3], NULL, NULL);
} }
@ -270,6 +279,17 @@ void layoutAddress(const char *address, const char *desc)
oledRefresh(); 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) void layoutSignIdentity(const IdentityType *identity, const char *challenge)
{ {
char row_proto[8 + 11 + 1]; char row_proto[8 + 11 + 1];

View File

@ -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 layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_fee);
void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee, uint32_t kb); void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee, uint32_t kb);
void layoutSignMessage(const uint8_t *msg, uint32_t len); void layoutSignMessage(const uint8_t *msg, uint32_t len);
void layoutVerifyAddress(const char *address);
void layoutVerifyMessage(const uint8_t *msg, uint32_t len); void layoutVerifyMessage(const uint8_t *msg, uint32_t len);
void layoutCipherKeyValue(bool encrypt, const char *key); void layoutCipherKeyValue(bool encrypt, const char *key);
void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing); void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing);
void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address); void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address);
void layoutAddress(const char *address, const char *desc); void layoutAddress(const char *address, const char *desc);
void layoutPublicKey(const uint8_t *pubkey);
void layoutSignIdentity(const IdentityType *identity, const char *challenge); void layoutSignIdentity(const IdentityType *identity, const char *challenge);
#endif #endif

View File

@ -139,7 +139,7 @@ static uint8_t msg_debug_out[MSG_DEBUG_OUT_SIZE];
#endif #endif
inline void msg_out_append(uint8_t c) static inline void msg_out_append(uint8_t c)
{ {
if (msg_out_cur == 0) { if (msg_out_cur == 0) {
msg_out[msg_out_end * 64] = '?'; msg_out[msg_out_end * 64] = '?';
@ -155,7 +155,7 @@ inline void msg_out_append(uint8_t c)
#if DEBUG_LINK #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) { if (msg_debug_out_cur == 0) {
msg_debug_out[msg_debug_out_end * 64] = '?'; msg_debug_out[msg_debug_out_end * 64] = '?';
@ -171,7 +171,7 @@ inline void msg_debug_out_append(uint8_t c)
#endif #endif
inline void msg_out_pad(void) static inline void msg_out_pad(void)
{ {
if (msg_out_cur == 0) return; if (msg_out_cur == 0) return;
while (msg_out_cur < 64) { while (msg_out_cur < 64) {

View File

@ -12,7 +12,11 @@ const char SignMessage_coin_name_default[17] = "Bitcoin";
const char EncryptMessage_coin_name_default[17] = "Bitcoin"; const char EncryptMessage_coin_name_default[17] = "Bitcoin";
const char EstimateTxSize_coin_name_default[17] = "Bitcoin"; const char EstimateTxSize_coin_name_default[17] = "Bitcoin";
const char SignTx_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 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] = { const pb_field_t Initialize_fields[1] = {
@ -123,9 +127,10 @@ const pb_field_t Entropy_fields[2] = {
PB_LAST_FIELD 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( 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( 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 PB_LAST_FIELD
}; };
@ -279,18 +284,22 @@ const pb_field_t TxSize_fields[2] = {
PB_LAST_FIELD 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( 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( 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( 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 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( 1, MESSAGE , REPEATED, STATIC , FIRST, SimpleSignTx, inputs, inputs, &TxInputType_fields),
PB_FIELD2( 2, MESSAGE , REPEATED, STATIC , OTHER, SimpleSignTx, outputs, inputs, &TxOutputType_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( 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( 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 PB_LAST_FIELD
}; };

View File

@ -426,6 +426,8 @@ typedef struct _GetPublicKey {
uint32_t address_n[8]; uint32_t address_n[8];
bool has_ecdsa_curve_name; bool has_ecdsa_curve_name;
char ecdsa_curve_name[32]; char ecdsa_curve_name[32];
bool has_show_display;
bool show_display;
} GetPublicKey; } GetPublicKey;
typedef struct _LoadDevice { typedef struct _LoadDevice {
@ -551,6 +553,10 @@ typedef struct _SignTx {
uint32_t inputs_count; uint32_t inputs_count;
bool has_coin_name; bool has_coin_name;
char coin_name[17]; char coin_name[17];
bool has_version;
uint32_t version;
bool has_lock_time;
uint32_t lock_time;
} SignTx; } SignTx;
typedef struct { typedef struct {
@ -581,6 +587,10 @@ typedef struct _SimpleSignTx {
TransactionType transactions[0]; TransactionType transactions[0];
bool has_coin_name; bool has_coin_name;
char coin_name[17]; char coin_name[17];
bool has_version;
uint32_t version;
bool has_lock_time;
uint32_t lock_time;
} SimpleSignTx; } SimpleSignTx;
typedef struct _Success { 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 EncryptMessage_coin_name_default[17];
extern const char EstimateTxSize_coin_name_default[17]; extern const char EstimateTxSize_coin_name_default[17];
extern const char SignTx_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 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 */ /* Initializer values for message structs */
#define Initialize_init_default {0} #define Initialize_init_default {0}
@ -661,7 +675,7 @@ extern const char SimpleSignTx_coin_name_default[17];
#define PassphraseAck_init_default {""} #define PassphraseAck_init_default {""}
#define GetEntropy_init_default {0} #define GetEntropy_init_default {0}
#define Entropy_init_default {{0, {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 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 GetAddress_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "Bitcoin", false, 0, false, MultisigRedeemScriptType_init_default}
#define Address_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 CipheredKeyValue_init_default {false, {0, {0}}}
#define EstimateTxSize_init_default {0, 0, false, "Bitcoin"} #define EstimateTxSize_init_default {0, 0, false, "Bitcoin"}
#define TxSize_init_default {false, 0} #define TxSize_init_default {false, 0}
#define SignTx_init_default {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"} #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 TxRequest_init_default {false, (RequestType)0, false, TxRequestDetailsType_init_default, false, TxRequestSerializedType_init_default}
#define TxAck_init_default {false, TransactionType_init_default} #define TxAck_init_default {false, TransactionType_init_default}
#define SignIdentity_init_default {false, IdentityType_init_default, false, {0, {0}}, false, "", false, ""} #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 PassphraseAck_init_zero {""}
#define GetEntropy_init_zero {0} #define GetEntropy_init_zero {0}
#define Entropy_init_zero {{0, {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 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 GetAddress_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0, false, MultisigRedeemScriptType_init_zero}
#define Address_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 CipheredKeyValue_init_zero {false, {0, {0}}}
#define EstimateTxSize_init_zero {0, 0, false, ""} #define EstimateTxSize_init_zero {0, 0, false, ""}
#define TxSize_init_zero {false, 0} #define TxSize_init_zero {false, 0}
#define SignTx_init_zero {0, 0, false, ""} #define SignTx_init_zero {0, 0, false, "", false, 0, false, 0}
#define SimpleSignTx_init_zero {0, {}, 0, {}, 0, {}, false, ""} #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 TxRequest_init_zero {false, (RequestType)0, false, TxRequestDetailsType_init_zero, false, TxRequestSerializedType_init_zero}
#define TxAck_init_zero {false, TransactionType_init_zero} #define TxAck_init_zero {false, TransactionType_init_zero}
#define SignIdentity_init_zero {false, IdentityType_init_zero, false, {0, {0}}, false, "", false, ""} #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 GetEntropy_size_tag 1
#define GetPublicKey_address_n_tag 1 #define GetPublicKey_address_n_tag 1
#define GetPublicKey_ecdsa_curve_name_tag 2 #define GetPublicKey_ecdsa_curve_name_tag 2
#define GetPublicKey_show_display_tag 3
#define LoadDevice_mnemonic_tag 1 #define LoadDevice_mnemonic_tag 1
#define LoadDevice_node_tag 2 #define LoadDevice_node_tag 2
#define LoadDevice_pin_tag 3 #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_outputs_count_tag 1
#define SignTx_inputs_count_tag 2 #define SignTx_inputs_count_tag 2
#define SignTx_coin_name_tag 3 #define SignTx_coin_name_tag 3
#define SignTx_version_tag 4
#define SignTx_lock_time_tag 5
#define SignedIdentity_address_tag 1 #define SignedIdentity_address_tag 1
#define SignedIdentity_public_key_tag 2 #define SignedIdentity_public_key_tag 2
#define SignedIdentity_signature_tag 3 #define SignedIdentity_signature_tag 3
@ -876,6 +893,8 @@ extern const char SimpleSignTx_coin_name_default[17];
#define SimpleSignTx_outputs_tag 2 #define SimpleSignTx_outputs_tag 2
#define SimpleSignTx_transactions_tag 3 #define SimpleSignTx_transactions_tag 3
#define SimpleSignTx_coin_name_tag 4 #define SimpleSignTx_coin_name_tag 4
#define SimpleSignTx_version_tag 5
#define SimpleSignTx_lock_time_tag 6
#define Success_message_tag 1 #define Success_message_tag 1
#define TxAck_tx_tag 1 #define TxAck_tx_tag 1
#define TxRequest_request_type_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 PassphraseAck_fields[2];
extern const pb_field_t GetEntropy_fields[2]; extern const pb_field_t GetEntropy_fields[2];
extern const pb_field_t Entropy_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 PublicKey_fields[3];
extern const pb_field_t GetAddress_fields[5]; extern const pb_field_t GetAddress_fields[5];
extern const pb_field_t Address_fields[2]; 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 CipheredKeyValue_fields[2];
extern const pb_field_t EstimateTxSize_fields[4]; extern const pb_field_t EstimateTxSize_fields[4];
extern const pb_field_t TxSize_fields[2]; extern const pb_field_t TxSize_fields[2];
extern const pb_field_t SignTx_fields[4]; extern const pb_field_t SignTx_fields[6];
extern const pb_field_t SimpleSignTx_fields[5]; extern const pb_field_t SimpleSignTx_fields[7];
extern const pb_field_t TxRequest_fields[4]; extern const pb_field_t TxRequest_fields[4];
extern const pb_field_t TxAck_fields[2]; extern const pb_field_t TxAck_fields[2];
extern const pb_field_t SignIdentity_fields[5]; 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 PassphraseAck_size 53
#define GetEntropy_size 6 #define GetEntropy_size 6
#define Entropy_size 1027 #define Entropy_size 1027
#define GetPublicKey_size 82 #define GetPublicKey_size 84
#define PublicKey_size (121 + HDNodeType_size) #define PublicKey_size (121 + HDNodeType_size)
#define GetAddress_size (75 + MultisigRedeemScriptType_size) #define GetAddress_size (75 + MultisigRedeemScriptType_size)
#define Address_size 38 #define Address_size 38
@ -985,8 +1004,8 @@ extern const pb_field_t DebugLinkLog_fields[4];
#define CipheredKeyValue_size 1027 #define CipheredKeyValue_size 1027
#define EstimateTxSize_size 31 #define EstimateTxSize_size 31
#define TxSize_size 6 #define TxSize_size 6
#define SignTx_size 31 #define SignTx_size 43
#define SimpleSignTx_size (19 + 0*TxInputType_size + 0*TxOutputType_size + 0*TransactionType_size) #define SimpleSignTx_size (31 + 0*TxInputType_size + 0*TxOutputType_size + 0*TransactionType_size)
#define TxRequest_size (18 + TxRequestDetailsType_size + TxRequestSerializedType_size) #define TxRequest_size (18 + TxRequestDetailsType_size + TxRequestSerializedType_size)
#define TxAck_size (6 + TransactionType_size) #define TxAck_size (6 + TransactionType_size)
#define SignIdentity_size (558 + IdentityType_size) #define SignIdentity_size (558 + IdentityType_size)

View File

@ -1 +1 @@
../../trezor-common/protob/messages.proto ../../vendor/trezor-common/protob/messages.proto

View File

@ -1 +1 @@
../../trezor-common/protob/storage.proto ../../vendor/trezor-common/protob/storage.proto

View File

@ -53,7 +53,8 @@ typedef enum _ButtonRequestType {
ButtonRequestType_ButtonRequest_ProtectCall = 7, ButtonRequestType_ButtonRequest_ProtectCall = 7,
ButtonRequestType_ButtonRequest_SignTx = 8, ButtonRequestType_ButtonRequest_SignTx = 8,
ButtonRequestType_ButtonRequest_FirmwareCheck = 9, ButtonRequestType_ButtonRequest_FirmwareCheck = 9,
ButtonRequestType_ButtonRequest_Address = 10 ButtonRequestType_ButtonRequest_Address = 10,
ButtonRequestType_ButtonRequest_PublicKey = 11
} ButtonRequestType; } ButtonRequestType;
typedef enum _PinMatrixRequestType { typedef enum _PinMatrixRequestType {

View File

@ -1 +1 @@
../../trezor-common/protob/types.proto ../../vendor/trezor-common/protob/types.proto

View File

@ -77,7 +77,7 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect
awaiting_entropy = true; 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) 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_Init(&ctx);
sha256_Update(&ctx, int_entropy, 32); sha256_Update(&ctx, int_entropy, 32);
sha256_Update(&ctx, ext_entropy, len); 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)); strlcpy(storage.mnemonic, mnemonic_from_data(int_entropy, strength / 8), sizeof(storage.mnemonic));
memset(int_entropy, 0, 32); memset(int_entropy, 0, 32);
awaiting_entropy = false; 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) { if (word_pos == 3 || word_pos == 23) {
desc[2] = 'r'; desc[3] = 'd'; 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 (word_pos == (int)strength/32*3) { // last word
if (pass == 1) { 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 { } 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 { } else {
if (pass == 1) { 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 { } 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)) { if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) {

View File

@ -51,8 +51,8 @@ static TxStruct to, tp, ti;
static SHA256_CTX tc; static SHA256_CTX tc;
static uint8_t hash[32], hash_check[32], privkey[32], pubkey[33], sig[64]; static uint8_t hash[32], hash_check[32], privkey[32], pubkey[33], sig[64];
static uint64_t to_spend, spending, change_spend; static uint64_t to_spend, spending, change_spend;
const uint32_t version = 1; static uint32_t version = 1;
const uint32_t lock_time = 0; static uint32_t lock_time = 0;
static uint32_t progress, progress_step, progress_meta_step; static uint32_t progress, progress_step, progress_meta_step;
static bool multisig_fp_set, multisig_fp_mismatch; static bool multisig_fp_set, multisig_fp_mismatch;
static uint8_t multisig_fp[32]; static uint8_t multisig_fp[32];
@ -224,12 +224,14 @@ void send_req_finished(void)
msg_write(MessageType_MessageType_TxRequest, &resp); 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; inputs_count = _inputs_count;
outputs_count = _outputs_count; outputs_count = _outputs_count;
coin = _coin; coin = _coin;
root = _root; root = _root;
version = _version;
lock_time = _lock_time;
idx1 = 0; idx1 = 0;
to_spend = 0; to_spend = 0;
@ -414,7 +416,7 @@ void signing_txack(TransactionType *tx)
idx1++; idx1++;
send_req_3_output(); send_req_3_output();
} else { } else {
sha256_Final(hash_check, &tc); sha256_Final(&tc, hash_check);
// check fees // check fees
if (spending > to_spend) { if (spending > to_spend) {
fsm_sendFailure(FailureType_Failure_NotEnoughFunds, "Not enough funds"); fsm_sendFailure(FailureType_Failure_NotEnoughFunds, "Not enough funds");
@ -525,7 +527,7 @@ void signing_txack(TransactionType *tx)
idx2++; idx2++;
send_req_4_output(); send_req_4_output();
} else { } else {
sha256_Final(hash, &tc); sha256_Final(&tc, hash);
if (memcmp(hash, hash_check, 32) != 0) { if (memcmp(hash, hash_check, 32) != 0) {
fsm_sendFailure(FailureType_Failure_Other, "Transaction has changed during signing"); fsm_sendFailure(FailureType_Failure_Other, "Transaction has changed during signing");
signing_abort(); signing_abort();

View File

@ -25,7 +25,7 @@
#include "bip32.h" #include "bip32.h"
#include "types.pb.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_abort(void);
void signing_txack(TransactionType *tx); void signing_txack(TransactionType *tx);

View File

@ -31,6 +31,7 @@
#include "pbkdf2.h" #include "pbkdf2.h"
#include "bip32.h" #include "bip32.h"
#include "bip39.h" #include "bip39.h"
#include "curves.h"
#include "util.h" #include "util.h"
#include "memory.h" #include "memory.h"
#include "rng.h" #include "rng.h"
@ -45,8 +46,8 @@ Storage storage;
uint8_t storage_uuid[12]; uint8_t storage_uuid[12];
char storage_uuid_str[25]; char storage_uuid_str[25];
static bool sessionRootNodeCached; static bool sessionSeedCached;
static HDNode sessionRootNode; static uint8_t sessionSeed[64];
static bool sessionPinCached; static bool sessionPinCached;
@ -126,8 +127,10 @@ void storage_reset(void)
void session_clear(bool clear_pin) void session_clear(bool clear_pin)
{ {
sessionRootNodeCached = false; memset(&sessionRootNode, 0, sizeof(sessionRootNode)); sessionSeedCached = false;
sessionPassphraseCached = false; memset(&sessionPassphrase, 0, sizeof(sessionPassphrase)); memset(&sessionSeed, 0, sizeof(sessionSeed));
sessionPassphraseCached = false;
memset(&sessionPassphrase, 0, sizeof(sessionPassphrase));
if (clear_pin) { if (clear_pin) {
sessionPinCached = false; sessionPinCached = false;
} }
@ -186,14 +189,14 @@ void storage_loadDevice(LoadDevice *msg)
storage.has_node = true; storage.has_node = true;
storage.has_mnemonic = false; storage.has_mnemonic = false;
memcpy(&storage.node, &(msg->node), sizeof(HDNodeType)); memcpy(&storage.node, &(msg->node), sizeof(HDNodeType));
sessionRootNodeCached = false; sessionSeedCached = false;
memset(&sessionRootNode, 0, sizeof(sessionRootNode)); memset(&sessionSeed, 0, sizeof(sessionSeed));
} else if (msg->has_mnemonic) { } else if (msg->has_mnemonic) {
storage.has_mnemonic = true; storage.has_mnemonic = true;
storage.has_node = false; storage.has_node = false;
strlcpy(storage.mnemonic, msg->mnemonic, sizeof(storage.mnemonic)); strlcpy(storage.mnemonic, msg->mnemonic, sizeof(storage.mnemonic));
sessionRootNodeCached = false; sessionSeedCached = false;
memset(&sessionRootNode, 0, sizeof(sessionRootNode)); memset(&sessionSeed, 0, sizeof(sessionSeed));
} }
if (msg->has_language) { if (msg->has_language) {
@ -224,7 +227,7 @@ void storage_setLanguage(const char *lang)
void storage_setPassphraseProtection(bool passphrase_protection) void storage_setPassphraseProtection(bool passphrase_protection)
{ {
sessionRootNodeCached = false; sessionSeedCached = false;
sessionPassphraseCached = false; sessionPassphraseCached = false;
storage.has_passphrase_protection = true; 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); layoutProgress("Waking up", 1000 * iter / total);
} }
bool storage_getRootNode(HDNode *node) const uint8_t *storage_getSeed(void)
{ {
// root node is properly cached // root node is properly cached
if (sessionRootNodeCached) { if (sessionSeedCached) {
memcpy(node, &sessionRootNode, sizeof(HDNode)); return sessionSeed;
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 storage has mnemonic, convert it to node and use it // if storage has mnemonic, convert it to node and use it
if (storage.has_mnemonic) { 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()) { if (!protectPassphrase()) {
return false; return false;
} }
uint8_t seed[64]; 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) {
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) {
return false; return false;
} }
memcpy(node, &sessionRootNode, sizeof(HDNode)); if (storage.has_passphrase_protection && storage.passphrase_protection && sessionPassphraseCached && strlen(sessionPassphrase) > 0) {
sessionRootNodeCached = true; // 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 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) const char *storage_getLabel(void)

View File

@ -33,7 +33,9 @@ void session_clear(bool clear_pin);
void storage_loadDevice(LoadDevice *msg); 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); const char *storage_getLabel(void);
void storage_setLabel(const char *label); void storage_setLabel(const char *label);

View File

@ -223,7 +223,7 @@ uint32_t compile_script_multisig_hash(const MultisigRedeemScriptType *multisig,
d[1] = 0xAE; d[1] = 0xAE;
sha256_Update(&ctx, d, 2); sha256_Update(&ctx, d, 2);
sha256_Final(hash, &ctx); sha256_Final(&ctx, hash);
return 1; 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) 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); sha256_Raw(hash, 32, hash);
if (!reverse) return; if (!reverse) return;
uint8_t i, k; uint8_t i, k;

View File

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

View File

@ -1,2 +0,0 @@
*.c
*.h

19
gitian/gitian.yml Normal file
View 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
View File

@ -55,13 +55,30 @@
#define OLED_RST_PORT GPIOB #define OLED_RST_PORT GPIOB
#define OLED_RST_PIN GPIO1 // PB1 | Reset display #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_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_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)) #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 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) inline void SPISend(uint32_t base, uint8_t *data, int len)
{ {
int i; int i;
@ -72,6 +89,9 @@ inline void SPISend(uint32_t base, uint8_t *data, int len)
delay(800); delay(800);
} }
/*
* Initialize the display.
*/
void oledInit() void oledInit()
{ {
static uint8_t s[25] = { static uint8_t s[25] = {
@ -121,11 +141,20 @@ void oledInit()
oledRefresh(); oledRefresh();
} }
/*
* Clears the display buffer (sets all pixels to black)
*/
void oledClear() void oledClear()
{ {
memset(_oledbuffer, 0, sizeof(_oledbuffer)); 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() void oledRefresh()
{ {
static uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00, OLED_SETHIGHCOLUMN | 0x00, OLED_SETSTARTLINE | 0x00}; static uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00, OLED_SETHIGHCOLUMN | 0x00, OLED_SETSTARTLINE | 0x00};
@ -164,7 +193,7 @@ const uint8_t *oledGetBuffer()
return _oledbuffer; return _oledbuffer;
} }
void oledSetDebug(char set) void oledSetDebug(bool set)
{ {
is_debug_mode = set; is_debug_mode = set;
oledRefresh(); oledRefresh();
@ -187,7 +216,7 @@ void oledClearPixel(int x, int y)
OLED_BUFCLR(x,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; int char_width;
const uint8_t *char_data; const uint8_t *char_data;
@ -197,11 +226,15 @@ void oledDrawChar(int x, int y, char c)
char_width = fontCharWidth(c); char_width = fontCharWidth(c);
char_data = fontCharData(c); char_data = fontCharData(c);
int xoffset, yoffset; int xo, yo;
for (xoffset = 0; xoffset < char_width; xoffset++) { for (xo = 0; xo < char_width; xo++) {
for (yoffset = 0; yoffset < FONT_HEIGHT; yoffset++) { for (yo = 0; yo < FONT_HEIGHT; yo++) {
if (char_data[xoffset] & (1 << (FONT_HEIGHT - 1 - yoffset))) { if (char_data[xo] & (1 << (FONT_HEIGHT - 1 - yo))) {
oledDrawPixel(x + xoffset, y + yoffset); 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) void oledDrawString(int x, int y, const char* text)
{ {
if (!text) return; if (!text) return;
int size = 1;
if (*text == 0x01) { // double size
text++;
size = 2;
}
int l = 0; int l = 0;
char c; char c;
for (; *text; text++) { for (; *text; text++) {
c = oledConvertChar(*text); c = oledConvertChar(*text);
if (c) { if (c) {
oledDrawChar(x + l, y, c); oledDrawChar(x + l, y, c, size);
l += fontCharWidth(c) + 1; 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; int x, y;
for (x = x1; x <= x2; x++) { for (x = x1; x <= x2; x++) {
for (y = y1; y <= y2; y++) { 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) void oledFrame(int x1, int y1, int x2, int y2)
{ {
int x, y; 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) void oledSwipeLeft(void)
{ {
int i, j, k; 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) void oledSwipeRight(void)
{ {
int i, j, k; int i, j, k;

7
oled.h
View File

@ -21,6 +21,7 @@
#define __OLED_H__ #define __OLED_H__
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#include "bitmaps.h" #include "bitmaps.h"
#include "fonts.h" #include "fonts.h"
@ -33,19 +34,19 @@ void oledInit(void);
void oledClear(void); void oledClear(void);
void oledRefresh(void); void oledRefresh(void);
void oledSetDebug(char set); void oledSetDebug(bool set);
void oledSetBuffer(uint8_t *buf); void oledSetBuffer(uint8_t *buf);
const uint8_t *oledGetBuffer(void); const uint8_t *oledGetBuffer(void);
void oledDrawPixel(int x, int y); void oledDrawPixel(int x, int y);
void oledClearPixel(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); int oledStringWidth(const char *text);
void oledDrawString(int x, int y, const char* text); void oledDrawString(int x, int y, const char* text);
void oledDrawStringCenter(int y, const char* text); void oledDrawStringCenter(int y, const char* text);
void oledDrawStringRight(int x, int y, const char* text); void oledDrawStringRight(int x, int y, const char* text);
void oledDrawBitmap(int x, int y, const BITMAP *bmp); void oledDrawBitmap(int x, int y, const BITMAP *bmp);
void oledInvert(int x1, int y1, int x2, int y2); 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 oledHLine(int y);
void oledFrame(int x1, int y1, int x2, int y2); void oledFrame(int x1, int y1, int x2, int y2);
void oledSwipeLeft(void); void oledSwipeLeft(void);

View File

@ -25,7 +25,7 @@
void setup(void) void setup(void)
{ {
// setup clock // 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); rcc_clock_setup_hse_3v3(&clock);
// enable GPIO clock - A (oled), B(oled), C (buttons) // 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
View File

@ -22,7 +22,7 @@
#include <stdint.h> #include <stdint.h>
inline void delay(uint32_t wait); void delay(uint32_t wait);
// converts uint32 to hexa (8 digits) // converts uint32 to hexa (8 digits)
void uint32hex(uint32_t num, char *str); void uint32hex(uint32_t num, char *str);

1
vendor/libopencm3 vendored Submodule

@ -0,0 +1 @@
Subproject commit d3fff11c1f68b706591c0d51c82d18a0bc88dc17

1
vendor/trezor-common vendored Submodule

@ -0,0 +1 @@
Subproject commit 0567a429cfc8c6fdf9e08c79270750c102fc4f70

1
vendor/trezor-crypto vendored Submodule

@ -0,0 +1 @@
Subproject commit ed6debf8c4ec5ef9c7ef31a1a7eddf76aa33ccd8

1
vendor/trezor-qrenc vendored Submodule

@ -0,0 +1 @@
Subproject commit 9e0228f54db6241524bb89acd3e89040701e0380