1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-07-03 21:32:33 +00:00

format: start using clang-format with style=Google

This commit is contained in:
Pavol Rusnak 2019-03-29 17:10:31 +01:00
parent e1bc0ebc40
commit eba242b806
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
102 changed files with 14020 additions and 13572 deletions

2
.clang-format Normal file
View File

@ -0,0 +1,2 @@
---
BasedOnStyle: Google

View File

@ -19,33 +19,31 @@
#include <string.h> #include <string.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/cm3/scb.h> #include <libopencm3/cm3/scb.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/rcc.h>
#include "bootloader.h" #include "bootloader.h"
#include "signatures.h"
#include "buttons.h" #include "buttons.h"
#include "setup.h"
#include "usb.h"
#include "oled.h"
#include "util.h"
#include "signatures.h"
#include "layout.h" #include "layout.h"
#include "rng.h"
#include "memory.h" #include "memory.h"
#include "oled.h"
#include "rng.h"
#include "setup.h"
#include "signatures.h"
#include "usb.h"
#include "util.h"
void layoutFirmwareFingerprint(const uint8_t *hash) void layoutFirmwareFingerprint(const uint8_t *hash) {
{
char str[4][17]; char str[4][17];
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
data2hex(hash + i * 8, 8, str[i]); data2hex(hash + i * 8, 8, str[i]);
} }
layoutDialog(&bmp_icon_question, "Abort", "Continue", "Compare fingerprints", str[0], str[1], str[2], str[3], NULL, NULL); layoutDialog(&bmp_icon_question, "Abort", "Continue", "Compare fingerprints",
str[0], str[1], str[2], str[3], NULL, NULL);
} }
bool get_button_response(void) bool get_button_response(void) {
{
do { do {
delay(100000); delay(100000);
buttonUpdate(); buttonUpdate();
@ -53,15 +51,16 @@ bool get_button_response(void)
return button.YesUp; return button.YesUp;
} }
void show_halt(const char *line1, const char *line2) void show_halt(const char *line1, const char *line2) {
{ layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, line2, NULL,
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, line2, NULL, "Unplug your TREZOR,", "reinstall firmware.", NULL); "Unplug your TREZOR,", "reinstall firmware.", NULL);
shutdown(); shutdown();
} }
static void show_unofficial_warning(const uint8_t *hash) static void show_unofficial_warning(const uint8_t *hash) {
{ layoutDialog(&bmp_icon_warning, "Abort", "I'll take the risk", NULL,
layoutDialog(&bmp_icon_warning, "Abort", "I'll take the risk", NULL, "WARNING!", NULL, "Unofficial firmware", "detected.", NULL, NULL); "WARNING!", NULL, "Unofficial firmware", "detected.", NULL,
NULL);
bool but = get_button_response(); bool but = get_button_response();
if (!but) { // no button was pressed -> halt if (!but) { // no button was pressed -> halt
@ -78,22 +77,24 @@ static void show_unofficial_warning(const uint8_t *hash)
// everything is OK, user pressed 2x Continue -> continue program // everything is OK, user pressed 2x Continue -> continue program
} }
static void __attribute__((noreturn)) load_app(int signed_firmware) static void __attribute__((noreturn)) load_app(int signed_firmware) {
{
// zero out SRAM // zero out SRAM
memset_reg(_ram_start, _ram_end, 0); memset_reg(_ram_start, _ram_end, 0);
jump_to_firmware((const vector_table_t *) FLASH_PTR(FLASH_APP_START), signed_firmware); jump_to_firmware((const vector_table_t *)FLASH_PTR(FLASH_APP_START),
signed_firmware);
} }
static void bootloader_loop(void) static void bootloader_loop(void) {
{
oledClear(); oledClear();
oledDrawBitmap(0, 0, &bmp_logo64); oledDrawBitmap(0, 0, &bmp_logo64);
if (firmware_present_new()) { if (firmware_present_new()) {
oledDrawStringCenter(90, 10, "TREZOR", FONT_STANDARD); oledDrawStringCenter(90, 10, "TREZOR", FONT_STANDARD);
oledDrawStringCenter(90, 30, "Bootloader", FONT_STANDARD); oledDrawStringCenter(90, 30, "Bootloader", FONT_STANDARD);
oledDrawStringCenter(90, 50, VERSTR(VERSION_MAJOR) "." VERSTR(VERSION_MINOR) "." VERSTR(VERSION_PATCH), FONT_STANDARD); oledDrawStringCenter(90, 50,
VERSTR(VERSION_MAJOR) "." VERSTR(
VERSION_MINOR) "." VERSTR(VERSION_PATCH),
FONT_STANDARD);
} else { } else {
oledDrawStringCenter(90, 10, "Welcome!", FONT_STANDARD); oledDrawStringCenter(90, 10, "Welcome!", FONT_STANDARD);
oledDrawStringCenter(90, 30, "Please visit", FONT_STANDARD); oledDrawStringCenter(90, 30, "Please visit", FONT_STANDARD);
@ -104,12 +105,12 @@ static void bootloader_loop(void)
usbLoop(); usbLoop();
} }
int main(void) int main(void) {
{
#ifndef APPVER #ifndef APPVER
setup(); setup();
#endif #endif
__stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks __stack_chk_guard = random32(); // this supports compiler provided
// unpredictable stack protection checks
#ifndef APPVER #ifndef APPVER
memory_protect(); memory_protect();
oledInit(); oledInit();
@ -121,12 +122,12 @@ int main(void)
bool left_pressed = (buttonRead() & BTN_PIN_NO) == 0; bool left_pressed = (buttonRead() & BTN_PIN_NO) == 0;
if (firmware_present_new() && !left_pressed) { if (firmware_present_new() && !left_pressed) {
oledClear(); oledClear();
oledDrawBitmap(40, 0, &bmp_logo64_empty); oledDrawBitmap(40, 0, &bmp_logo64_empty);
oledRefresh(); oledRefresh();
const image_header *hdr = (const image_header *)FLASH_PTR(FLASH_FWHEADER_START); const image_header *hdr =
(const image_header *)FLASH_PTR(FLASH_FWHEADER_START);
uint8_t fingerprint[32]; uint8_t fingerprint[32];
int signed_firmware = signatures_new_ok(hdr, fingerprint); int signed_firmware = signatures_new_ok(hdr, fingerprint);
@ -135,7 +136,9 @@ int main(void)
} }
if (SIG_OK != check_firmware_hashes(hdr)) { if (SIG_OK != check_firmware_hashes(hdr)) {
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Broken firmware", "detected.", NULL, "Unplug your TREZOR,", "reinstall firmware.", NULL); layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Broken firmware",
"detected.", NULL, "Unplug your TREZOR,",
"reinstall firmware.", NULL);
shutdown(); shutdown();
} }

View File

@ -31,8 +31,8 @@
#define VERSION_MINOR_CHAR "\x08" #define VERSION_MINOR_CHAR "\x08"
#define VERSION_PATCH_CHAR "\x00" #define VERSION_PATCH_CHAR "\x00"
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
void show_halt(const char *line1, const char *line2); void show_halt(const char *line1, const char *line2);
void layoutFirmwareFingerprint(const uint8_t *hash); void layoutFirmwareFingerprint(const uint8_t *hash);

View File

@ -19,13 +19,13 @@
#include <string.h> #include <string.h>
#include "signatures.h"
#include "ecdsa.h"
#include "secp256k1.h"
#include "sha2.h"
#include "bootloader.h" #include "bootloader.h"
#include "ecdsa.h"
#include "memory.h" #include "memory.h"
#include "memzero.h" #include "memzero.h"
#include "secp256k1.h"
#include "sha2.h"
#include "signatures.h"
const uint32_t FIRMWARE_MAGIC_OLD = 0x525a5254; // TRZR const uint32_t FIRMWARE_MAGIC_OLD = 0x525a5254; // TRZR
const uint32_t FIRMWARE_MAGIC_NEW = 0x465a5254; // TRZF const uint32_t FIRMWARE_MAGIC_NEW = 0x465a5254; // TRZF
@ -52,23 +52,24 @@ static const uint8_t * const pubkey[PUBKEYS] = {
#define FLASH_META_SIG2 (FLASH_META_START + 0x0080) #define FLASH_META_SIG2 (FLASH_META_START + 0x0080)
#define FLASH_META_SIG3 (FLASH_META_START + 0x00C0) #define FLASH_META_SIG3 (FLASH_META_START + 0x00C0)
bool firmware_present_old(void) bool firmware_present_old(void) {
{ if (memcmp(FLASH_PTR(FLASH_META_START), &FIRMWARE_MAGIC_OLD,
if (memcmp(FLASH_PTR(FLASH_META_START), &FIRMWARE_MAGIC_OLD, 4)) { // magic does not match 4)) { // magic does not match
return false; return false;
} }
if (*((const uint32_t *)FLASH_PTR(FLASH_META_CODELEN)) < 8192) { // firmware reports smaller size than 8192 if (*((const uint32_t *)FLASH_PTR(FLASH_META_CODELEN)) <
8192) { // firmware reports smaller size than 8192
return false; return false;
} }
if (*((const uint32_t *)FLASH_PTR(FLASH_META_CODELEN)) > FLASH_APP_LEN) { // firmware reports bigger size than flash size if (*((const uint32_t *)FLASH_PTR(FLASH_META_CODELEN)) >
FLASH_APP_LEN) { // firmware reports bigger size than flash size
return false; return false;
} }
return true; return true;
} }
int signatures_old_ok(void) int signatures_old_ok(void) {
{
const uint32_t codelen = *((const uint32_t *)FLASH_META_CODELEN); const uint32_t codelen = *((const uint32_t *)FLASH_META_CODELEN);
const uint8_t sigindex1 = *((const uint8_t *)FLASH_META_SIGINDEX1); const uint8_t sigindex1 = *((const uint8_t *)FLASH_META_SIGINDEX1);
const uint8_t sigindex2 = *((const uint8_t *)FLASH_META_SIGINDEX2); const uint8_t sigindex2 = *((const uint8_t *)FLASH_META_SIGINDEX2);
@ -89,21 +90,26 @@ int signatures_old_ok(void)
if (sigindex1 == sigindex3) return SIG_FAIL; // duplicate use if (sigindex1 == sigindex3) return SIG_FAIL; // duplicate use
if (sigindex2 == sigindex3) return SIG_FAIL; // duplicate use if (sigindex2 == sigindex3) return SIG_FAIL; // duplicate use
if (0 != ecdsa_verify_digest(&secp256k1, pubkey[sigindex1 - 1], (const uint8_t *)FLASH_META_SIG1, hash)) { // failure if (0 != ecdsa_verify_digest(&secp256k1, pubkey[sigindex1 - 1],
(const uint8_t *)FLASH_META_SIG1,
hash)) { // failure
return SIG_FAIL; return SIG_FAIL;
} }
if (0 != ecdsa_verify_digest(&secp256k1, pubkey[sigindex2 - 1], (const uint8_t *)FLASH_META_SIG2, hash)) { // failure if (0 != ecdsa_verify_digest(&secp256k1, pubkey[sigindex2 - 1],
(const uint8_t *)FLASH_META_SIG2,
hash)) { // failure
return SIG_FAIL; return SIG_FAIL;
} }
if (0 != ecdsa_verify_digest(&secp256k1, pubkey[sigindex3 - 1], (const uint8_t *)FLASH_META_SIG3, hash)) { // failture if (0 != ecdsa_verify_digest(&secp256k1, pubkey[sigindex3 - 1],
(const uint8_t *)FLASH_META_SIG3,
hash)) { // failture
return SIG_FAIL; return SIG_FAIL;
} }
return SIG_OK; return SIG_OK;
} }
void compute_firmware_fingerprint(const image_header *hdr, uint8_t hash[32]) void compute_firmware_fingerprint(const image_header *hdr, uint8_t hash[32]) {
{
image_header copy; image_header copy;
memcpy(&copy, hdr, sizeof(image_header)); memcpy(&copy, hdr, sizeof(image_header));
memzero(copy.sig1, sizeof(copy.sig1)); memzero(copy.sig1, sizeof(copy.sig1));
@ -115,9 +121,9 @@ void compute_firmware_fingerprint(const image_header *hdr, uint8_t hash[32])
sha256_Raw((const uint8_t *)&copy, sizeof(image_header), hash); sha256_Raw((const uint8_t *)&copy, sizeof(image_header), hash);
} }
bool firmware_present_new(void) bool firmware_present_new(void) {
{ const image_header *hdr =
const image_header *hdr = (const image_header *)FLASH_PTR(FLASH_FWHEADER_START); (const image_header *)FLASH_PTR(FLASH_FWHEADER_START);
if (hdr->magic != FIRMWARE_MAGIC_NEW) return false; if (hdr->magic != FIRMWARE_MAGIC_NEW) return false;
// we need to ignore hdrlen for now // we need to ignore hdrlen for now
// because we keep reset_handler ptr there // because we keep reset_handler ptr there
@ -130,8 +136,7 @@ bool firmware_present_new(void)
return true; return true;
} }
int signatures_new_ok(const image_header *hdr, uint8_t store_fingerprint[32]) int signatures_new_ok(const image_header *hdr, uint8_t store_fingerprint[32]) {
{
uint8_t hash[32]; uint8_t hash[32];
compute_firmware_fingerprint(hdr, hash); compute_firmware_fingerprint(hdr, hash);
@ -139,37 +144,41 @@ int signatures_new_ok(const image_header *hdr, uint8_t store_fingerprint[32])
memcpy(store_fingerprint, hash, 32); memcpy(store_fingerprint, hash, 32);
} }
if (hdr->sigindex1 < 1 || hdr->sigindex1 > PUBKEYS) return SIG_FAIL; // invalid index if (hdr->sigindex1 < 1 || hdr->sigindex1 > PUBKEYS)
if (hdr->sigindex2 < 1 || hdr->sigindex2 > PUBKEYS) return SIG_FAIL; // invalid index return SIG_FAIL; // invalid index
if (hdr->sigindex3 < 1 || hdr->sigindex3 > PUBKEYS) return SIG_FAIL; // invalid index if (hdr->sigindex2 < 1 || hdr->sigindex2 > PUBKEYS)
return SIG_FAIL; // invalid index
if (hdr->sigindex3 < 1 || hdr->sigindex3 > PUBKEYS)
return SIG_FAIL; // invalid index
if (hdr->sigindex1 == hdr->sigindex2) return SIG_FAIL; // duplicate use if (hdr->sigindex1 == hdr->sigindex2) return SIG_FAIL; // duplicate use
if (hdr->sigindex1 == hdr->sigindex3) return SIG_FAIL; // duplicate use if (hdr->sigindex1 == hdr->sigindex3) return SIG_FAIL; // duplicate use
if (hdr->sigindex2 == hdr->sigindex3) return SIG_FAIL; // duplicate use if (hdr->sigindex2 == hdr->sigindex3) return SIG_FAIL; // duplicate use
if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex1 - 1], hdr->sig1, hash)) { // failure if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex1 - 1],
hdr->sig1, hash)) { // failure
return SIG_FAIL; return SIG_FAIL;
} }
if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex2 - 1], hdr->sig2, hash)) { // failure if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex2 - 1],
hdr->sig2, hash)) { // failure
return SIG_FAIL; return SIG_FAIL;
} }
if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex3 - 1], hdr->sig3, hash)) { // failure if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex3 - 1],
hdr->sig3, hash)) { // failure
return SIG_FAIL; return SIG_FAIL;
} }
return SIG_OK; return SIG_OK;
} }
int mem_is_empty(const uint8_t *src, uint32_t len) int mem_is_empty(const uint8_t *src, uint32_t len) {
{
for (uint32_t i = 0; i < len; i++) { for (uint32_t i = 0; i < len; i++) {
if (src[i]) return 0; if (src[i]) return 0;
} }
return 1; return 1;
} }
int check_firmware_hashes(const image_header *hdr) int check_firmware_hashes(const image_header *hdr) {
{
uint8_t hash[32]; uint8_t hash[32];
// check hash of the first code chunk // check hash of the first code chunk
sha256_Raw(FLASH_PTR(FLASH_APP_START), (64 - 1) * 1024, hash); sha256_Raw(FLASH_PTR(FLASH_APP_START), (64 - 1) * 1024, hash);
@ -181,7 +190,8 @@ int check_firmware_hashes(const image_header *hdr)
used_chunks++; used_chunks++;
} }
for (int i = 1; i < used_chunks; i++) { for (int i = 1; i < used_chunks; i++) {
sha256_Raw(FLASH_PTR(FLASH_FWHEADER_START + (64 * i) * 1024), 64 * 1024, hash); sha256_Raw(FLASH_PTR(FLASH_FWHEADER_START + (64 * i) * 1024), 64 * 1024,
hash);
if (0 != memcmp(hdr->hashes + 32 * i, hash, 32)) return SIG_FAIL; if (0 != memcmp(hdr->hashes + 32 * i, hash, 32)) return SIG_FAIL;
} }
// check unused chunks // check unused chunks

View File

@ -17,32 +17,32 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <libopencm3/usb/usbd.h>
#include <libopencm3/stm32/flash.h> #include <libopencm3/stm32/flash.h>
#include <libopencm3/usb/usbd.h>
#include <string.h> #include <string.h>
#include "buttons.h"
#include "bootloader.h" #include "bootloader.h"
#include "buttons.h"
#include "ecdsa.h"
#include "layout.h"
#include "memory.h"
#include "memzero.h"
#include "oled.h" #include "oled.h"
#include "rng.h" #include "rng.h"
#include "usb.h"
#include "layout.h"
#include "util.h"
#include "signatures.h"
#include "sha2.h"
#include "ecdsa.h"
#include "secp256k1.h" #include "secp256k1.h"
#include "memzero.h" #include "sha2.h"
#include "memory.h" #include "signatures.h"
#include "usb.h"
#include "util.h"
#include "usb21_standard.h" #include "usb21_standard.h"
#include "webusb.h" #include "webusb.h"
#include "winusb.h" #include "winusb.h"
#include "usb_desc.h" #include "usb_desc.h"
#include "usb_send.h"
#include "usb_erase.h" #include "usb_erase.h"
#include "usb_send.h"
enum { enum {
STATE_READY, STATE_READY,
@ -60,8 +60,7 @@ static char flash_state = STATE_READY;
static uint32_t FW_HEADER[FLASH_FWHEADER_LEN / sizeof(uint32_t)]; static uint32_t FW_HEADER[FLASH_FWHEADER_LEN / sizeof(uint32_t)];
static uint32_t FW_CHUNK[FW_CHUNK_SIZE / sizeof(uint32_t)]; static uint32_t FW_CHUNK[FW_CHUNK_SIZE / sizeof(uint32_t)];
static void check_and_write_chunk(void) static void check_and_write_chunk(void) {
{
uint32_t offset = (chunk_idx == 0) ? FLASH_FWHEADER_LEN : 0; uint32_t offset = (chunk_idx == 0) ? FLASH_FWHEADER_LEN : 0;
uint32_t chunk_pos = flash_pos % FW_CHUNK_SIZE; uint32_t chunk_pos = flash_pos % FW_CHUNK_SIZE;
if (chunk_pos == 0) { if (chunk_pos == 0) {
@ -92,8 +91,11 @@ static void check_and_write_chunk(void)
flash_wait_for_last_operation(); flash_wait_for_last_operation();
flash_clear_status_flags(); flash_clear_status_flags();
flash_unlock(); flash_unlock();
for (uint32_t i = offset/sizeof(uint32_t); i < chunk_pos/sizeof(uint32_t); i++) { for (uint32_t i = offset / sizeof(uint32_t); i < chunk_pos / sizeof(uint32_t);
flash_program_word(FLASH_FWHEADER_START + chunk_idx * FW_CHUNK_SIZE + i * sizeof(uint32_t), FW_CHUNK[i]); i++) {
flash_program_word(
FLASH_FWHEADER_START + chunk_idx * FW_CHUNK_SIZE + i * sizeof(uint32_t),
FW_CHUNK[i]);
} }
flash_wait_for_last_operation(); flash_wait_for_last_operation();
flash_lock(); flash_lock();
@ -115,8 +117,7 @@ static void check_and_write_chunk(void)
chunk_idx++; chunk_idx++;
} }
static void rx_callback(usbd_device *dev, uint8_t ep) static void rx_callback(usbd_device *dev, uint8_t ep) {
{
(void)ep; (void)ep;
static uint16_t msg_id = 0xFFFF; static uint16_t msg_id = 0xFFFF;
static uint8_t buf[64] __attribute__((aligned(4))); static uint8_t buf[64] __attribute__((aligned(4)));
@ -130,8 +131,10 @@ static void rx_callback(usbd_device *dev, uint8_t ep)
return; return;
} }
if (flash_state == STATE_READY || flash_state == STATE_OPEN || flash_state == STATE_FLASHSTART || flash_state == STATE_CHECK) { if (flash_state == STATE_READY || flash_state == STATE_OPEN ||
if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { // invalid start - discard flash_state == STATE_FLASHSTART || flash_state == STATE_CHECK) {
if (buf[0] != '?' || buf[1] != '#' ||
buf[2] != '#') { // invalid start - discard
return; return;
} }
// struct.unpack(">HL") => msg, size // struct.unpack(">HL") => msg, size
@ -153,16 +156,22 @@ static void rx_callback(usbd_device *dev, uint8_t ep)
return; return;
} }
if (msg_id == 0x0005) { // WipeDevice message (id 5) if (msg_id == 0x0005) { // WipeDevice message (id 5)
layoutDialog(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "wipe the device?", NULL, "All data will be lost.", NULL, NULL); layoutDialog(&bmp_icon_question, "Cancel", "Confirm", NULL,
"Do you really want to", "wipe the device?", NULL,
"All data will be lost.", NULL, NULL);
bool but = get_button_response(); bool but = get_button_response();
if (but) { if (but) {
erase_storage_code_progress(); erase_storage_code_progress();
flash_state = STATE_END; flash_state = STATE_END;
layoutDialog(&bmp_icon_ok, NULL, NULL, NULL, "Device", "successfully wiped.", NULL, "You may now", "unplug your TREZOR.", NULL); layoutDialog(&bmp_icon_ok, NULL, NULL, NULL, "Device",
"successfully wiped.", NULL, "You may now",
"unplug your TREZOR.", NULL);
send_msg_success(dev); send_msg_success(dev);
} else { } else {
flash_state = STATE_END; flash_state = STATE_END;
layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Device wipe", "aborted.", NULL, "You may now", "unplug your TREZOR.", NULL); layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Device wipe",
"aborted.", NULL, "You may now", "unplug your TREZOR.",
NULL);
send_msg_failure(dev); send_msg_failure(dev);
} }
return; return;
@ -173,7 +182,9 @@ static void rx_callback(usbd_device *dev, uint8_t ep)
if (msg_id == 0x0006) { // FirmwareErase message (id 6) if (msg_id == 0x0006) { // FirmwareErase message (id 6)
bool proceed = false; bool proceed = false;
if (firmware_present_new()) { if (firmware_present_new()) {
layoutDialog(&bmp_icon_question, "Abort", "Continue", NULL, "Install new", "firmware?", NULL, "Never do this without", "your recovery card!", NULL); layoutDialog(&bmp_icon_question, "Abort", "Continue", NULL,
"Install new", "firmware?", NULL, "Never do this without",
"your recovery card!", NULL);
proceed = get_button_response(); proceed = get_button_response();
} else { } else {
proceed = true; proceed = true;
@ -181,8 +192,10 @@ static void rx_callback(usbd_device *dev, uint8_t ep)
if (proceed) { if (proceed) {
// check whether the current firmware is signed (old or new method) // check whether the current firmware is signed (old or new method)
if (firmware_present_new()) { if (firmware_present_new()) {
const image_header *hdr = (const image_header *)FLASH_PTR(FLASH_FWHEADER_START); const image_header *hdr =
old_was_signed = signatures_new_ok(hdr, NULL) & check_firmware_hashes(hdr); (const image_header *)FLASH_PTR(FLASH_FWHEADER_START);
old_was_signed =
signatures_new_ok(hdr, NULL) & check_firmware_hashes(hdr);
} else if (firmware_present_old()) { } else if (firmware_present_old()) {
old_was_signed = signatures_old_ok(); old_was_signed = signatures_old_ok();
} else { } else {
@ -194,7 +207,9 @@ static void rx_callback(usbd_device *dev, uint8_t ep)
} else { } else {
send_msg_failure(dev); send_msg_failure(dev);
flash_state = STATE_END; flash_state = STATE_END;
layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You may now", "unplug your TREZOR.", NULL); layoutDialog(&bmp_icon_warning, NULL, NULL, NULL,
"Firmware installation", "aborted.", NULL, "You may now",
"unplug your TREZOR.", NULL);
} }
return; return;
} }
@ -218,7 +233,8 @@ static void rx_callback(usbd_device *dev, uint8_t ep)
show_halt("Firmware is too small.", NULL); show_halt("Firmware is too small.", NULL);
return; return;
} }
if (flash_len > FLASH_FWHEADER_LEN + FLASH_APP_LEN) { // firmware is too big if (flash_len >
FLASH_FWHEADER_LEN + FLASH_APP_LEN) { // firmware is too big
send_msg_failure(dev); send_msg_failure(dev);
flash_state = STATE_END; flash_state = STATE_END;
show_halt("Firmware is too big.", NULL); show_halt("Firmware is too big.", NULL);
@ -262,7 +278,8 @@ static void rx_callback(usbd_device *dev, uint8_t ep)
static uint8_t flash_anim = 0; static uint8_t flash_anim = 0;
if (flash_anim % 32 == 4) { if (flash_anim % 32 == 4) {
layoutProgress("INSTALLING ... Please wait", 1000 * flash_pos / flash_len); layoutProgress("INSTALLING ... Please wait",
1000 * flash_pos / flash_len);
} }
flash_anim++; flash_anim++;
@ -303,7 +320,6 @@ static void rx_callback(usbd_device *dev, uint8_t ep)
} }
if (flash_state == STATE_CHECK) { if (flash_state == STATE_CHECK) {
// use the firmware header from RAM // use the firmware header from RAM
const image_header *hdr = (const image_header *)FW_HEADER; const image_header *hdr = (const image_header *)FW_HEADER;
@ -326,13 +342,18 @@ static void rx_callback(usbd_device *dev, uint8_t ep)
// 1) old firmware was unsigned or not present // 1) old firmware was unsigned or not present
// 2) signatures are not OK // 2) signatures are not OK
// 3) hashes are not OK // 3) hashes are not OK
if (SIG_OK != old_was_signed || SIG_OK != signatures_new_ok(hdr, NULL) || SIG_OK != check_firmware_hashes(hdr)) { if (SIG_OK != old_was_signed || SIG_OK != signatures_new_ok(hdr, NULL) ||
SIG_OK != check_firmware_hashes(hdr)) {
// erase storage // erase storage
erase_storage(); erase_storage();
// check erasure // check erasure
uint8_t hash[32]; uint8_t hash[32];
sha256_Raw(FLASH_PTR(FLASH_STORAGE_START), FLASH_STORAGE_LEN, hash); sha256_Raw(FLASH_PTR(FLASH_STORAGE_START), FLASH_STORAGE_LEN, hash);
if (memcmp(hash, "\x2d\x86\x4c\x0b\x78\x9a\x43\x21\x4e\xee\x85\x24\xd3\x18\x20\x75\x12\x5e\x5c\xa2\xcd\x52\x7f\x35\x82\xec\x87\xff\xd9\x40\x76\xbc", 32) != 0) { if (memcmp(hash,
"\x2d\x86\x4c\x0b\x78\x9a\x43\x21\x4e\xee\x85\x24\xd3\x18\x20"
"\x75\x12\x5e\x5c\xa2\xcd\x52\x7f\x35\x82\xec\x87\xff\xd9\x40"
"\x76\xbc",
32) != 0) {
send_msg_failure(dev); send_msg_failure(dev);
show_halt("Error installing", "firmware."); show_halt("Error installing", "firmware.");
return; return;
@ -344,7 +365,8 @@ static void rx_callback(usbd_device *dev, uint8_t ep)
// write firmware header only when hash was confirmed // write firmware header only when hash was confirmed
if (hash_check_ok) { if (hash_check_ok) {
for (size_t i = 0; i < FLASH_FWHEADER_LEN / sizeof(uint32_t); i++) { for (size_t i = 0; i < FLASH_FWHEADER_LEN / sizeof(uint32_t); i++) {
flash_program_word(FLASH_FWHEADER_START + i * sizeof(uint32_t), FW_HEADER[i]); flash_program_word(FLASH_FWHEADER_START + i * sizeof(uint32_t),
FW_HEADER[i]);
} }
} else { } else {
for (size_t i = 0; i < FLASH_FWHEADER_LEN / sizeof(uint32_t); i++) { for (size_t i = 0; i < FLASH_FWHEADER_LEN / sizeof(uint32_t); i++) {
@ -356,11 +378,15 @@ static void rx_callback(usbd_device *dev, uint8_t ep)
flash_state = STATE_END; flash_state = STATE_END;
if (hash_check_ok) { if (hash_check_ok) {
layoutDialog(&bmp_icon_ok, NULL, NULL, NULL, "New firmware", "successfully installed.", NULL, "You may now", "unplug your TREZOR.", NULL); layoutDialog(&bmp_icon_ok, NULL, NULL, NULL, "New firmware",
"successfully installed.", NULL, "You may now",
"unplug your TREZOR.", NULL);
send_msg_success(dev); send_msg_success(dev);
shutdown(); shutdown();
} else { } else {
layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You need to repeat", "the procedure with", "the correct firmware."); layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Firmware installation",
"aborted.", NULL, "You need to repeat", "the procedure with",
"the correct firmware.");
send_msg_failure(dev); send_msg_failure(dev);
shutdown(); shutdown();
} }
@ -368,39 +394,39 @@ static void rx_callback(usbd_device *dev, uint8_t ep)
} }
} }
static void set_config(usbd_device *dev, uint16_t wValue) static void set_config(usbd_device *dev, uint16_t wValue) {
{
(void)wValue; (void)wValue;
usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0);
usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, rx_callback); usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64,
rx_callback);
} }
static usbd_device *usbd_dev; static usbd_device *usbd_dev;
static uint8_t usbd_control_buffer[256] __attribute__((aligned(2))); static uint8_t usbd_control_buffer[256] __attribute__((aligned(2)));
static const struct usb_device_capability_descriptor *capabilities[] = { static const struct usb_device_capability_descriptor *capabilities[] = {
(const struct usb_device_capability_descriptor*)&webusb_platform_capability_descriptor, (const struct usb_device_capability_descriptor
*)&webusb_platform_capability_descriptor,
}; };
static const struct usb_bos_descriptor bos_descriptor = { static const struct usb_bos_descriptor bos_descriptor = {
.bLength = USB_DT_BOS_SIZE, .bLength = USB_DT_BOS_SIZE,
.bDescriptorType = USB_DT_BOS, .bDescriptorType = USB_DT_BOS,
.bNumDeviceCaps = sizeof(capabilities) / sizeof(capabilities[0]), .bNumDeviceCaps = sizeof(capabilities) / sizeof(capabilities[0]),
.capabilities = capabilities .capabilities = capabilities};
};
static void usbInit(void) static void usbInit(void) {
{ usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings,
usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, sizeof(usb_strings)/sizeof(const char *), usbd_control_buffer, sizeof(usbd_control_buffer)); sizeof(usb_strings) / sizeof(const char *),
usbd_control_buffer, sizeof(usbd_control_buffer));
usbd_register_set_config_callback(usbd_dev, set_config); usbd_register_set_config_callback(usbd_dev, set_config);
usb21_setup(usbd_dev, &bos_descriptor); usb21_setup(usbd_dev, &bos_descriptor);
webusb_setup(usbd_dev, "trezor.io/start"); webusb_setup(usbd_dev, "trezor.io/start");
winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN); winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN);
} }
static void checkButtons(void) static void checkButtons(void) {
{
static bool btn_left = false, btn_right = false, btn_final = false; static bool btn_left = false, btn_right = false, btn_final = false;
if (btn_final) { if (btn_final) {
return; return;
@ -428,13 +454,13 @@ static void checkButtons(void)
} }
} }
void usbLoop(void) void usbLoop(void) {
{
bool firmware_present = firmware_present_new(); bool firmware_present = firmware_present_new();
usbInit(); usbInit();
for (;;) { for (;;) {
usbd_poll(usbd_dev); usbd_poll(usbd_dev);
if (!firmware_present && (flash_state == STATE_READY || flash_state == STATE_OPEN)) { if (!firmware_present &&
(flash_state == STATE_READY || flash_state == STATE_OPEN)) {
checkButtons(); checkButtons();
} }
} }

View File

@ -20,14 +20,16 @@ static const struct usb_device_descriptor dev_descr = {
.bNumConfigurations = 1, .bNumConfigurations = 1,
}; };
static const struct usb_endpoint_descriptor endpoints[2] = {{ static const struct usb_endpoint_descriptor endpoints[2] = {
{
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = ENDPOINT_ADDRESS_IN, .bEndpointAddress = ENDPOINT_ADDRESS_IN,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.wMaxPacketSize = 64, .wMaxPacketSize = 64,
.bInterval = 1, .bInterval = 1,
}, { },
{
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = ENDPOINT_ADDRESS_OUT, .bEndpointAddress = ENDPOINT_ADDRESS_OUT,

View File

@ -1,29 +1,34 @@
static void erase_storage_code_progress(void) static void erase_storage_code_progress(void) {
{
flash_wait_for_last_operation(); flash_wait_for_last_operation();
flash_clear_status_flags(); flash_clear_status_flags();
flash_unlock(); flash_unlock();
// erase storage area // erase storage area
for (int i = FLASH_STORAGE_SECTOR_FIRST; i <= FLASH_STORAGE_SECTOR_LAST; i++) { for (int i = FLASH_STORAGE_SECTOR_FIRST; i <= FLASH_STORAGE_SECTOR_LAST;
layoutProgress("WIPING ... Please wait", 1000 * (i - FLASH_STORAGE_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_STORAGE_SECTOR_FIRST)); i++) {
layoutProgress("WIPING ... Please wait",
1000 * (i - FLASH_STORAGE_SECTOR_FIRST) /
(FLASH_CODE_SECTOR_LAST - FLASH_STORAGE_SECTOR_FIRST));
flash_erase_sector(i, FLASH_CR_PROGRAM_X32); flash_erase_sector(i, FLASH_CR_PROGRAM_X32);
} }
// erase code area // erase code area
for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) {
layoutProgress("WIPING ... Please wait", 1000 * (i - FLASH_STORAGE_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_STORAGE_SECTOR_FIRST)); layoutProgress("WIPING ... Please wait",
1000 * (i - FLASH_STORAGE_SECTOR_FIRST) /
(FLASH_CODE_SECTOR_LAST - FLASH_STORAGE_SECTOR_FIRST));
flash_erase_sector(i, FLASH_CR_PROGRAM_X32); flash_erase_sector(i, FLASH_CR_PROGRAM_X32);
} }
flash_wait_for_last_operation(); flash_wait_for_last_operation();
flash_lock(); flash_lock();
} }
static void erase_code_progress(void) static void erase_code_progress(void) {
{
flash_wait_for_last_operation(); flash_wait_for_last_operation();
flash_clear_status_flags(); flash_clear_status_flags();
flash_unlock(); flash_unlock();
for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) {
layoutProgress("PREPARING ... Please wait", 1000 * (i - FLASH_CODE_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_CODE_SECTOR_FIRST)); layoutProgress("PREPARING ... Please wait",
1000 * (i - FLASH_CODE_SECTOR_FIRST) /
(FLASH_CODE_SECTOR_LAST - FLASH_CODE_SECTOR_FIRST));
flash_erase_sector(i, FLASH_CR_PROGRAM_X32); flash_erase_sector(i, FLASH_CR_PROGRAM_X32);
} }
layoutProgress("INSTALLING ... Please wait", 0); layoutProgress("INSTALLING ... Please wait", 0);
@ -31,12 +36,12 @@ static void erase_code_progress(void)
flash_lock(); flash_lock();
} }
static void erase_storage(void) static void erase_storage(void) {
{
flash_wait_for_last_operation(); flash_wait_for_last_operation();
flash_clear_status_flags(); flash_clear_status_flags();
flash_unlock(); flash_unlock();
for (int i = FLASH_STORAGE_SECTOR_FIRST; i <= FLASH_STORAGE_SECTOR_LAST; i++) { for (int i = FLASH_STORAGE_SECTOR_FIRST; i <= FLASH_STORAGE_SECTOR_LAST;
i++) {
flash_erase_sector(i, FLASH_CR_PROGRAM_X32); flash_erase_sector(i, FLASH_CR_PROGRAM_X32);
} }
flash_wait_for_last_operation(); flash_wait_for_last_operation();

View File

@ -1,5 +1,4 @@
static void send_msg_success(usbd_device *dev) static void send_msg_success(usbd_device *dev) {
{
uint8_t response[64]; uint8_t response[64];
memzero(response, sizeof(response)); memzero(response, sizeof(response));
// response: Success message (id 2), payload len 0 // response: Success message (id 2), payload len 0
@ -11,11 +10,11 @@ static void send_msg_success(usbd_device *dev)
// msg_size // msg_size
"\x00\x00\x00\x00", "\x00\x00\x00\x00",
9); 9);
while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {
}
} }
static void send_msg_failure(usbd_device *dev) static void send_msg_failure(usbd_device *dev) {
{
uint8_t response[64]; uint8_t response[64];
memzero(response, sizeof(response)); memzero(response, sizeof(response));
// response: Failure message (id 3), payload len 2 // response: Failure message (id 3), payload len 2
@ -28,13 +27,14 @@ static void send_msg_failure(usbd_device *dev)
// msg_size // msg_size
"\x00\x00\x00\x02" "\x00\x00\x00\x02"
// data // data
"\x08" "\x63", "\x08"
"\x63",
11); 11);
while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {
}
} }
static void send_msg_features(usbd_device *dev) static void send_msg_features(usbd_device *dev) {
{
uint8_t response[64]; uint8_t response[64];
memzero(response, sizeof(response)); memzero(response, sizeof(response));
// response: Features message (id 17), payload len 25 // response: Features message (id 17), payload len 25
@ -53,20 +53,25 @@ static void send_msg_features(usbd_device *dev)
// msg_size // msg_size
"\x00\x00\x00\x16" "\x00\x00\x00\x16"
// data // data
"\x0a" "\x09" "trezor.io" "\x0a"
"\x10" VERSION_MAJOR_CHAR "\x09"
"\x18" VERSION_MINOR_CHAR "trezor.io"
"\x10" VERSION_MAJOR_CHAR "\x18" VERSION_MINOR_CHAR
"\x20" VERSION_PATCH_CHAR "\x20" VERSION_PATCH_CHAR
"\x28" "\x01" "\x28"
"\x90\x01" "\x00" "\x01"
"\xaa" "\x01" "1", "\x90\x01"
"\x00"
"\xaa"
"\x01"
"1",
34); 34);
response[30] = firmware_present_new() ? 0x01 : 0x00; response[30] = firmware_present_new() ? 0x01 : 0x00;
while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {
}
} }
static void send_msg_buttonrequest_firmwarecheck(usbd_device *dev) static void send_msg_buttonrequest_firmwarecheck(usbd_device *dev) {
{
uint8_t response[64]; uint8_t response[64];
memzero(response, sizeof(response)); memzero(response, sizeof(response));
// response: ButtonRequest message (id 26), payload len 2 // response: ButtonRequest message (id 26), payload len 2
@ -79,8 +84,9 @@ static void send_msg_buttonrequest_firmwarecheck(usbd_device *dev)
// msg_size // msg_size
"\x00\x00\x00\x02" "\x00\x00\x00\x02"
// data // data
"\x08" "\x09", "\x08"
11 "\x09",
); 11);
while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {
}
} }

View File

@ -22,13 +22,10 @@
struct buttonState button; struct buttonState button;
#if !EMULATOR #if !EMULATOR
uint16_t buttonRead(void) { uint16_t buttonRead(void) { return gpio_port_read(BTN_PORT); }
return gpio_port_read(BTN_PORT);
}
#endif #endif
void buttonUpdate() void buttonUpdate() {
{
static uint16_t last_state = BTN_PIN_YES | BTN_PIN_NO; static uint16_t last_state = BTN_PIN_YES | BTN_PIN_NO;
uint16_t state = buttonRead(); uint16_t state = buttonRead();

View File

@ -17,25 +17,28 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stdio.h>
#include "common.h" #include "common.h"
#include "rng.h" #include <stdio.h>
#include "layout.h"
#include "oled.h"
#include "util.h"
#include "bitmaps.h" #include "bitmaps.h"
#include "firmware/usb.h" #include "firmware/usb.h"
#include "layout.h"
#include "oled.h"
#include "rng.h"
#include "util.h"
uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN];
void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line_num, const char *func) { void __attribute__((noreturn))
__fatal_error(const char *expr, const char *msg, const char *file, int line_num,
const char *func) {
const BITMAP *icon = &bmp_icon_error; const BITMAP *icon = &bmp_icon_error;
char line[128] = {0}; char line[128] = {0};
int y = icon->height + 3; int y = icon->height + 3;
oledClear(); oledClear();
oledDrawBitmap(0, 0, icon); oledDrawBitmap(0, 0, icon);
oledDrawStringCenter(OLED_WIDTH / 2, (icon->height - FONT_HEIGHT)/2 + 1, "FATAL ERROR", FONT_STANDARD); oledDrawStringCenter(OLED_WIDTH / 2, (icon->height - FONT_HEIGHT) / 2 + 1,
"FATAL ERROR", FONT_STANDARD);
snprintf(line, sizeof(line), "Expr: %s", expr ? expr : "(null)"); snprintf(line, sizeof(line), "Expr: %s", expr ? expr : "(null)");
oledDrawString(0, y, line, FONT_STANDARD); oledDrawString(0, y, line, FONT_STANDARD);
@ -62,18 +65,19 @@ void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg,
shutdown(); shutdown();
} }
void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4) { void __attribute__((noreturn))
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, line2, line3, line4, "Please unplug", "the device."); error_shutdown(const char *line1, const char *line2, const char *line3,
const char *line4) {
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, line2, line3, line4,
"Please unplug", "the device.");
shutdown(); shutdown();
} }
#ifndef NDEBUG #ifndef NDEBUG
void __assert_func(const char *file, int line, const char *func, const char *expr) { void __assert_func(const char *file, int line, const char *func,
const char *expr) {
__fatal_error(expr, "assert failed", file, line, func); __fatal_error(expr, "assert failed", file, line, func);
} }
#endif #endif
void hal_delay(uint32_t ms) void hal_delay(uint32_t ms) { usbSleep(ms); }
{
usbSleep(ms);
}

View File

@ -26,10 +26,17 @@
#define HW_ENTROPY_LEN (12 + 32) #define HW_ENTROPY_LEN (12 + 32)
extern uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN]; extern uint8_t HW_ENTROPY_DATA[HW_ENTROPY_LEN];
void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg, const char *file, int line, const char *func); void __attribute__((noreturn))
void __attribute__((noreturn)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4); __fatal_error(const char *expr, const char *msg, const char *file, int line,
const char *func);
void __attribute__((noreturn))
error_shutdown(const char *line1, const char *line2, const char *line3,
const char *line4);
#define ensure(expr, msg) (((expr) == sectrue) ? (void)0 : __fatal_error(#expr, msg, __FILE__, __LINE__, __func__)) #define ensure(expr, msg) \
(((expr) == sectrue) \
? (void)0 \
: __fatal_error(#expr, msg, __FILE__, __LINE__, __func__))
void hal_delay(uint32_t ms); void hal_delay(uint32_t ms);

View File

@ -17,17 +17,17 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h>
#include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/hid.h> #include <libopencm3/usb/hid.h>
#include <libopencm3/usb/usbd.h>
#include <string.h>
#include "bitmaps.h" #include "bitmaps.h"
#include "buttons.h" #include "buttons.h"
#include "hmac.h"
#include "layout.h" #include "layout.h"
#include "oled.h" #include "oled.h"
#include "setup.h"
#include "hmac.h"
#include "pbkdf2.h" #include "pbkdf2.h"
#include "rng.h" #include "rng.h"
#include "setup.h"
const int states = 2; const int states = 2;
int state = 0; int state = 0;
@ -58,63 +58,82 @@ static const struct usb_device_descriptor dev_descr = {
/* got via usbhid-dump from CP2110 */ /* got via usbhid-dump from CP2110 */
static const uint8_t hid_report_descriptor[] = { static const uint8_t hid_report_descriptor[] = {
0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x09, 0x01, 0x75, 0x08, 0x95, 0x40, 0x26, 0xFF, 0x00, 0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x09, 0x01, 0x75, 0x08, 0x95,
0x15, 0x00, 0x85, 0x01, 0x95, 0x01, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x02, 0x40, 0x26, 0xFF, 0x00, 0x15, 0x00, 0x85, 0x01, 0x95, 0x01, 0x09, 0x01,
0x95, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x03, 0x95, 0x03, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x02, 0x95, 0x02, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x04, 0x95, 0x04, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x03, 0x95, 0x03, 0x09, 0x01,
0x91, 0x02, 0x85, 0x05, 0x95, 0x05, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x06, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x04, 0x95, 0x04, 0x09, 0x01,
0x95, 0x06, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x07, 0x95, 0x07, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x05, 0x95, 0x05, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x08, 0x95, 0x08, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x06, 0x95, 0x06, 0x09, 0x01,
0x91, 0x02, 0x85, 0x09, 0x95, 0x09, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0A, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x07, 0x95, 0x07, 0x09, 0x01,
0x95, 0x0A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0B, 0x95, 0x0B, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x08, 0x95, 0x08, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0C, 0x95, 0x0C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x09, 0x95, 0x09, 0x09, 0x01,
0x91, 0x02, 0x85, 0x0D, 0x95, 0x0D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0E, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0A, 0x95, 0x0A, 0x09, 0x01,
0x95, 0x0E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0F, 0x95, 0x0F, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0B, 0x95, 0x0B, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x10, 0x95, 0x10, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0C, 0x95, 0x0C, 0x09, 0x01,
0x91, 0x02, 0x85, 0x11, 0x95, 0x11, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x12, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0D, 0x95, 0x0D, 0x09, 0x01,
0x95, 0x12, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x13, 0x95, 0x13, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0E, 0x95, 0x0E, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x14, 0x95, 0x14, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0F, 0x95, 0x0F, 0x09, 0x01,
0x91, 0x02, 0x85, 0x15, 0x95, 0x15, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x16, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x10, 0x95, 0x10, 0x09, 0x01,
0x95, 0x16, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x17, 0x95, 0x17, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x11, 0x95, 0x11, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x18, 0x95, 0x18, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x12, 0x95, 0x12, 0x09, 0x01,
0x91, 0x02, 0x85, 0x19, 0x95, 0x19, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1A, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x13, 0x95, 0x13, 0x09, 0x01,
0x95, 0x1A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1B, 0x95, 0x1B, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x14, 0x95, 0x14, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1C, 0x95, 0x1C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x15, 0x95, 0x15, 0x09, 0x01,
0x91, 0x02, 0x85, 0x1D, 0x95, 0x1D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1E, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x16, 0x95, 0x16, 0x09, 0x01,
0x95, 0x1E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1F, 0x95, 0x1F, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x17, 0x95, 0x17, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x20, 0x95, 0x20, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x18, 0x95, 0x18, 0x09, 0x01,
0x91, 0x02, 0x85, 0x21, 0x95, 0x21, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x22, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x19, 0x95, 0x19, 0x09, 0x01,
0x95, 0x22, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x23, 0x95, 0x23, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1A, 0x95, 0x1A, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x24, 0x95, 0x24, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1B, 0x95, 0x1B, 0x09, 0x01,
0x91, 0x02, 0x85, 0x25, 0x95, 0x25, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x26, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1C, 0x95, 0x1C, 0x09, 0x01,
0x95, 0x26, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x27, 0x95, 0x27, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1D, 0x95, 0x1D, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x28, 0x95, 0x28, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1E, 0x95, 0x1E, 0x09, 0x01,
0x91, 0x02, 0x85, 0x29, 0x95, 0x29, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2A, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1F, 0x95, 0x1F, 0x09, 0x01,
0x95, 0x2A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2B, 0x95, 0x2B, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x20, 0x95, 0x20, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2C, 0x95, 0x2C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x21, 0x95, 0x21, 0x09, 0x01,
0x91, 0x02, 0x85, 0x2D, 0x95, 0x2D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2E, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x22, 0x95, 0x22, 0x09, 0x01,
0x95, 0x2E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2F, 0x95, 0x2F, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x23, 0x95, 0x23, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x30, 0x95, 0x30, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x24, 0x95, 0x24, 0x09, 0x01,
0x91, 0x02, 0x85, 0x31, 0x95, 0x31, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x32, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x25, 0x95, 0x25, 0x09, 0x01,
0x95, 0x32, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x33, 0x95, 0x33, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x26, 0x95, 0x26, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x34, 0x95, 0x34, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x27, 0x95, 0x27, 0x09, 0x01,
0x91, 0x02, 0x85, 0x35, 0x95, 0x35, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x36, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x28, 0x95, 0x28, 0x09, 0x01,
0x95, 0x36, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x37, 0x95, 0x37, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x29, 0x95, 0x29, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x38, 0x95, 0x38, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2A, 0x95, 0x2A, 0x09, 0x01,
0x91, 0x02, 0x85, 0x39, 0x95, 0x39, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3A, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2B, 0x95, 0x2B, 0x09, 0x01,
0x95, 0x3A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3B, 0x95, 0x3B, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2C, 0x95, 0x2C, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3C, 0x95, 0x3C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2D, 0x95, 0x2D, 0x09, 0x01,
0x91, 0x02, 0x85, 0x3D, 0x95, 0x3D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3E, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2E, 0x95, 0x2E, 0x09, 0x01,
0x95, 0x3E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3F, 0x95, 0x3F, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2F, 0x95, 0x2F, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x40, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x41, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x30, 0x95, 0x30, 0x09, 0x01,
0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x42, 0x95, 0x06, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x43, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x31, 0x95, 0x31, 0x09, 0x01,
0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x44, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x45, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x32, 0x95, 0x32, 0x09, 0x01,
0x95, 0x04, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x46, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x47, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x33, 0x95, 0x33, 0x09, 0x01,
0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x50, 0x95, 0x08, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x51, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x34, 0x95, 0x34, 0x09, 0x01,
0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x52, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x60, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x35, 0x95, 0x35, 0x09, 0x01,
0x95, 0x0A, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x61, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x62, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x36, 0x95, 0x36, 0x09, 0x01,
0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x63, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x64, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x37, 0x95, 0x37, 0x09, 0x01,
0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x65, 0x95, 0x3E, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x66, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x38, 0x95, 0x38, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x39, 0x95, 0x39, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3A, 0x95, 0x3A, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3B, 0x95, 0x3B, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3C, 0x95, 0x3C, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3D, 0x95, 0x3D, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3E, 0x95, 0x3E, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3F, 0x95, 0x3F, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x40, 0x95, 0x01, 0x09, 0x01,
0xB1, 0x02, 0x85, 0x41, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x42,
0x95, 0x06, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x43, 0x95, 0x01, 0x09, 0x01,
0xB1, 0x02, 0x85, 0x44, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x45,
0x95, 0x04, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x46, 0x95, 0x02, 0x09, 0x01,
0xB1, 0x02, 0x85, 0x47, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x50,
0x95, 0x08, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x51, 0x95, 0x01, 0x09, 0x01,
0xB1, 0x02, 0x85, 0x52, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x60,
0x95, 0x0A, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x61, 0x95, 0x3F, 0x09, 0x01,
0xB1, 0x02, 0x85, 0x62, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x63,
0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x64, 0x95, 0x3F, 0x09, 0x01,
0xB1, 0x02, 0x85, 0x65, 0x95, 0x3E, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x66,
0x95, 0x13, 0x09, 0x01, 0xB1, 0x02, 0xC0, 0x95, 0x13, 0x09, 0x01, 0xB1, 0x02, 0xC0,
}; };
@ -124,8 +143,9 @@ static const struct {
uint8_t bReportDescriptorType; uint8_t bReportDescriptorType;
uint16_t wDescriptorLength; uint16_t wDescriptorLength;
} __attribute__((packed)) hid_report; } __attribute__((packed)) hid_report;
} __attribute__((packed)) hid_function = { } __attribute__((packed))
.hid_descriptor = { hid_function = {.hid_descriptor =
{
.bLength = sizeof(hid_function), .bLength = sizeof(hid_function),
.bDescriptorType = USB_DT_HID, .bDescriptorType = USB_DT_HID,
.bcdHID = 0x0111, .bcdHID = 0x0111,
@ -135,17 +155,18 @@ static const struct {
.hid_report = { .hid_report = {
.bReportDescriptorType = USB_DT_REPORT, .bReportDescriptorType = USB_DT_REPORT,
.wDescriptorLength = sizeof(hid_report_descriptor), .wDescriptorLength = sizeof(hid_report_descriptor),
} }};
};
static const struct usb_endpoint_descriptor hid_endpoints[2] = {{ static const struct usb_endpoint_descriptor hid_endpoints[2] = {
{
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x81, .bEndpointAddress = 0x81,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.wMaxPacketSize = 64, .wMaxPacketSize = 64,
.bInterval = 1, .bInterval = 1,
}, { },
{
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x02, .bEndpointAddress = 0x02,
@ -192,14 +213,14 @@ static const char *usb_strings[] = {
"01234567", "01234567",
}; };
static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete) static int hid_control_request(usbd_device *dev, struct usb_setup_data *req,
{ uint8_t **buf, uint16_t *len,
usbd_control_complete_callback *complete) {
(void)complete; (void)complete;
(void)dev; (void)dev;
if ((req->bmRequestType != 0x81) || if ((req->bmRequestType != 0x81) ||
(req->bRequest != USB_REQ_GET_DESCRIPTOR) || (req->bRequest != USB_REQ_GET_DESCRIPTOR) || (req->wValue != 0x2200))
(req->wValue != 0x2200))
return 0; return 0;
/* Handle the HID report descriptor. */ /* Handle the HID report descriptor. */
@ -209,44 +230,41 @@ static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uin
return 1; return 1;
} }
static void hid_rx_callback(usbd_device *dev, uint8_t ep) static void hid_rx_callback(usbd_device *dev, uint8_t ep) {
{
(void)dev; (void)dev;
(void)ep; (void)ep;
} }
static void hid_set_config(usbd_device *dev, uint16_t wValue) static void hid_set_config(usbd_device *dev, uint16_t wValue) {
{
(void)wValue; (void)wValue;
usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0);
usbd_ep_setup(dev, 0x02, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_rx_callback); usbd_ep_setup(dev, 0x02, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_rx_callback);
usbd_register_control_callback( usbd_register_control_callback(
dev, dev, USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE,
USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE, USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, hid_control_request);
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
hid_control_request);
} }
static usbd_device *usbd_dev; static usbd_device *usbd_dev;
static uint8_t usbd_control_buffer[128]; static uint8_t usbd_control_buffer[128];
void usbInit(void) void usbInit(void) {
{ usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, 3,
usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer)); usbd_control_buffer, sizeof(usbd_control_buffer));
usbd_register_set_config_callback(usbd_dev, hid_set_config); usbd_register_set_config_callback(usbd_dev, hid_set_config);
} }
int main(void) int main(void) {
{
#ifndef APPVER #ifndef APPVER
setup(); setup();
__stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks __stack_chk_guard = random32(); // this supports compiler provided
// unpredictable stack protection checks
oledInit(); oledInit();
#else #else
setupApp(); setupApp();
__stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks __stack_chk_guard = random32(); // this supports compiler provided
// unpredictable stack protection checks
#endif #endif
usbInit(); usbInit();

View File

@ -17,16 +17,14 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h>
#include <assert.h> #include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h>
#include <unistd.h> #include <unistd.h>
#include "memory.h" #include "memory.h"
void flash_lock(void) { void flash_lock(void) { sync(); }
sync();
}
void flash_unlock(void) {} void flash_unlock(void) {}
@ -35,9 +33,7 @@ void flash_clear_status_flags(void) {}
void flash_lock_option_bytes(void) {} void flash_lock_option_bytes(void) {}
void flash_unlock_option_bytes(void) {} void flash_unlock_option_bytes(void) {}
void flash_program_option_bytes(uint32_t data) { void flash_program_option_bytes(uint32_t data) { (void)data; }
(void) data;
}
static ssize_t sector_to_offset(uint8_t sector) { static ssize_t sector_to_offset(uint8_t sector) {
switch (sector) { switch (sector) {
@ -128,7 +124,8 @@ void svc_flash_program(uint32_t size) {
} }
void svc_flash_erase_sector(uint16_t sector) { void svc_flash_erase_sector(uint16_t sector) {
assert(!flash_locked); assert(!flash_locked);
assert (sector >= FLASH_STORAGE_SECTOR_FIRST && sector <= FLASH_STORAGE_SECTOR_LAST); assert(sector >= FLASH_STORAGE_SECTOR_FIRST &&
sector <= FLASH_STORAGE_SECTOR_LAST);
flash_erase_sector(sector, 3); flash_erase_sector(sector, 3);
} }
uint32_t svc_flash_lock(void) { uint32_t svc_flash_lock(void) {

View File

@ -66,11 +66,9 @@ void oledInit(void) {
int scale = emulatorScale(); int scale = emulatorScale();
int fullscreen = emulatorFullscreen(); int fullscreen = emulatorFullscreen();
SDL_Window *window = SDL_CreateWindow("TREZOR", SDL_Window *window = SDL_CreateWindow(
SDL_WINDOWPOS_UNDEFINED, "TREZOR", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, OLED_WIDTH * scale, OLED_HEIGHT * scale,
OLED_WIDTH * scale,
OLED_HEIGHT * scale,
fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
if (window == NULL) { if (window == NULL) {
@ -85,9 +83,9 @@ void oledInit(void) {
} }
if (fullscreen) { if (fullscreen) {
SDL_DisplayMode current_mode; SDL_DisplayMode current_mode;
if (SDL_GetCurrentDisplayMode(0, &current_mode) != 0) if (SDL_GetCurrentDisplayMode(0, &current_mode) != 0) {
{ fprintf(stderr, "Failed to get current display mode: %s\n",
fprintf(stderr, "Failed to get current display mode: %s\n", SDL_GetError()); SDL_GetError());
exit(1); exit(1);
} }
@ -105,7 +103,9 @@ void oledInit(void) {
dstrect.w = OLED_WIDTH * scale; dstrect.w = OLED_WIDTH * scale;
dstrect.h = OLED_HEIGHT * scale; dstrect.h = OLED_HEIGHT * scale;
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, OLED_WIDTH, OLED_HEIGHT); texture =
SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING, OLED_WIDTH, OLED_HEIGHT);
oledClear(); oledClear();
oledRefresh(); oledRefresh();

View File

@ -89,7 +89,8 @@ static void setup_flash(void) {
exit(1); exit(1);
} }
emulator_flash_base = mmap(NULL, FLASH_TOTAL_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); emulator_flash_base =
mmap(NULL, FLASH_TOTAL_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (emulator_flash_base == MAP_FAILED) { if (emulator_flash_base == MAP_FAILED) {
perror("Failed to map flash emulation file"); perror("Failed to map flash emulation file");
exit(1); exit(1);

View File

@ -55,9 +55,11 @@ static int socket_setup(int port) {
return fd; return fd;
} }
static size_t socket_write(struct usb_socket *sock, const void *buffer, size_t size) { static size_t socket_write(struct usb_socket *sock, const void *buffer,
size_t size) {
if (sock->fromlen > 0) { if (sock->fromlen > 0) {
ssize_t n = sendto(sock->fd, buffer, size, MSG_DONTWAIT, (const struct sockaddr *) &sock->from, sock->fromlen); ssize_t n = sendto(sock->fd, buffer, size, MSG_DONTWAIT,
(const struct sockaddr *)&sock->from, sock->fromlen);
if (n < 0 || ((size_t)n) != size) { if (n < 0 || ((size_t)n) != size) {
perror("Failed to write socket"); perror("Failed to write socket");
return 0; return 0;
@ -69,7 +71,8 @@ static size_t socket_write(struct usb_socket *sock, const void *buffer, size_t s
static size_t socket_read(struct usb_socket *sock, void *buffer, size_t size) { static size_t socket_read(struct usb_socket *sock, void *buffer, size_t size) {
sock->fromlen = sizeof(sock->from); sock->fromlen = sizeof(sock->from);
ssize_t n = recvfrom(sock->fd, buffer, size, MSG_DONTWAIT, (struct sockaddr *) &sock->from, &sock->fromlen); ssize_t n = recvfrom(sock->fd, buffer, size, MSG_DONTWAIT,
(struct sockaddr *)&sock->from, &sock->fromlen);
if (n < 0) { if (n < 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK) { if (errno != EAGAIN && errno != EWOULDBLOCK) {
@ -81,7 +84,8 @@ static size_t socket_read(struct usb_socket *sock, void *buffer, size_t size) {
static const char msg_ping[] = {'P', 'I', 'N', 'G', 'P', 'I', 'N', 'G'}; static const char msg_ping[] = {'P', 'I', 'N', 'G', 'P', 'I', 'N', 'G'};
static const char msg_pong[] = {'P', 'O', 'N', 'G', 'P', 'O', 'N', 'G'}; static const char msg_pong[] = {'P', 'O', 'N', 'G', 'P', 'O', 'N', 'G'};
if (n == sizeof(msg_ping) && memcmp(buffer, msg_ping, sizeof(msg_ping)) == 0) { if (n == sizeof(msg_ping) &&
memcmp(buffer, msg_ping, sizeof(msg_ping)) == 0) {
socket_write(sock, msg_pong, sizeof(msg_pong)); socket_write(sock, msg_pong, sizeof(msg_pong));
return 0; return 0;
} }

View File

@ -17,45 +17,125 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <libopencm3/stm32/flash.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <libopencm3/stm32/flash.h>
#include "bl_data.h" #include "bl_data.h"
#include "memory.h"
#include "layout.h"
#include "gettext.h" #include "gettext.h"
#include "layout.h"
#include "memory.h"
#include "util.h" #include "util.h"
static int known_bootloader(int r, const uint8_t *hash) { static int known_bootloader(int r, const uint8_t *hash) {
if (r != 32) return 0; if (r != 32) return 0;
if (0 == memcmp(hash, "\xbf\x72\xe2\x5e\x2c\x2f\xc1\xba\x57\x04\x50\xfa\xdf\xb6\x6f\xaa\x5a\x71\x6d\xcd\xc0\x33\x35\x88\x55\x7b\x77\x54\x0a\xb8\x7e\x98", 32)) return 1; // 1.2.0a if (0 ==
if (0 == memcmp(hash, "\x77\xb8\xe2\xf2\x5f\xaa\x8e\x8c\x7d\x9f\x5b\x32\x3b\x27\xce\x05\x6c\xa3\xdb\xc2\x3f\x56\xc3\x7e\xe3\x3f\x97\x7c\xa6\xeb\x4d\x3e", 32)) return 1; // 1.2.0b memcmp(hash,
if (0 == memcmp(hash, "\xc4\xc3\x25\x39\xb4\xa0\x25\xa8\xe7\x53\xa4\xc4\x62\x64\x28\x59\x11\xa4\x5f\xcb\x14\xf4\x71\x81\x79\xe7\x11\xb1\xce\x99\x05\x24", 32)) return 1; // 1.2.5 "\xbf\x72\xe2\x5e\x2c\x2f\xc1\xba\x57\x04\x50\xfa\xdf\xb6\x6f\xaa"
if (0 == memcmp(hash, "\x42\x59\x66\x94\xa0\xf2\x9d\x1e\xc2\x35\x71\x29\x2d\x54\x39\xd8\x2f\xa1\x8c\x07\x37\xcb\x10\x7e\x98\xf6\x1e\xf5\x93\x4d\xe7\x16", 32)) return 1; // 1.3.0a "\x5a\x71\x6d\xcd\xc0\x33\x35\x88\x55\x7b\x77\x54\x0a\xb8\x7e\x98",
if (0 == memcmp(hash, "\x3a\xcf\x2e\x51\x0b\x0f\xe1\x56\xb5\x58\xbb\xf7\x9c\x7e\x48\x5e\xb0\x26\xe5\xe0\x8c\xb4\x4d\x15\x2d\x44\xd6\x4e\x0c\x6a\x41\x37", 32)) return 1; // 1.3.0b 32))
if (0 == memcmp(hash, "\x15\x85\x21\x5b\xc6\xe5\x5a\x34\x07\xa8\xb3\xee\xe2\x79\x03\x4e\x95\xb9\xc4\x34\x00\x33\xe1\xb6\xae\x16\x0c\xe6\x61\x19\x67\x15", 32)) return 1; // 1.3.1 return 1; // 1.2.0a
if (0 == memcmp(hash, "\x76\x51\xb7\xca\xba\x5a\xae\x0c\xc1\xc6\x5c\x83\x04\xf7\x60\x39\x6f\x77\x60\x6c\xd3\x99\x0c\x99\x15\x98\xf0\xe2\x2a\x81\xe0\x07", 32)) return 1; // 1.3.2 if (0 ==
// note to those verifying these values: bootloader versions above this comment are aligned/padded to 32KiB with trailing 0xFF bytes and versions below are padded with 0x00. memcmp(hash,
// for more info, refer to "make -C bootloader align" and "firmware/bl_data.py". "\x77\xb8\xe2\xf2\x5f\xaa\x8e\x8c\x7d\x9f\x5b\x32\x3b\x27\xce\x05"
if (0 == memcmp(hash, "\x8c\xe8\xd7\x9e\xdf\x43\x0c\x03\x42\x64\x68\x6c\xa9\xb1\xd7\x8d\x26\xed\xb2\xac\xab\x71\x39\xbe\x8f\x98\x5c\x2a\x3c\x6c\xae\x11", 32)) return 1; // 1.3.3 "\x6c\xa3\xdb\xc2\x3f\x56\xc3\x7e\xe3\x3f\x97\x7c\xa6\xeb\x4d\x3e",
if (0 == memcmp(hash, "\x63\x30\xfc\xec\x16\x72\xfa\xd3\x0b\x42\x1b\x60\xf7\x4f\x83\x9a\x39\x39\x33\x45\x65\xcb\x70\x3b\x2b\xd7\x18\x2e\xa2\xdd\xa0\x19", 32)) return 1; // 1.4.0 shipped with fw 1.6.1 32))
if (0 == memcmp(hash, "\xaf\xb4\xcf\x7a\x4a\x57\x96\x10\x0e\xd5\x41\x6b\x75\x12\x1b\xc7\x10\x08\xc2\xa2\xfd\x54\x49\xbd\x8f\x63\xcc\x22\xa6\xa7\xd6\x80", 32)) return 1; // 1.5.0 shipped with fw 1.6.2 return 1; // 1.2.0b
if (0 == memcmp(hash, "\x51\x12\x90\xa8\x72\x3f\xaf\xe7\x34\x15\x25\x9d\x25\x96\x76\x54\x06\x32\x5c\xe2\x4b\x4b\x80\x03\x2c\x0b\x70\xb0\x5d\x98\x46\xe9", 32)) return 1; // 1.5.1 shipped with fw 1.6.3 if (0 ==
if (0 == memcmp(hash, "\x3e\xc4\xbd\xd5\x77\xea\x0c\x36\xc7\xba\xb7\xb9\xa3\x5b\x87\x17\xb3\xf1\xfc\x2f\x80\x9e\x69\x0c\x8a\xbe\x5b\x05\xfb\xc2\x43\xc6", 32)) return 1; // 1.6.0 shipped with fw 1.7.0 memcmp(hash,
if (0 == memcmp(hash, "\x8e\x83\x02\x3f\x0d\x4f\x82\x4f\x64\x71\x20\x75\x2b\x6c\x71\x6f\x55\xd7\x95\x70\x66\x8f\xd4\x90\x65\xd5\xb7\x97\x6e\x7a\x6e\x19", 32)) return 1; // 1.6.0 shipped with fw 1.7.1 and 1.7.2 "\xc4\xc3\x25\x39\xb4\xa0\x25\xa8\xe7\x53\xa4\xc4\x62\x64\x28\x59"
if (0 == memcmp(hash, "\xa2\x36\x6e\x77\xde\x8e\xfd\xfd\xc9\x99\xf4\x72\x20\xc0\x16\xe3\x3f\x6d\x24\x24\xe2\x45\x90\x79\x11\x7a\x90\xb3\xa8\x88\xba\xdd", 32)) return 1; // 1.6.1 shipped with fw 1.7.3 "\x11\xa4\x5f\xcb\x14\xf4\x71\x81\x79\xe7\x11\xb1\xce\x99\x05\x24",
if (0 == memcmp(hash, "\xf7\xfa\x16\x5b\xe6\xd7\x80\xf3\xe1\xaf\x00\xab\xc0\x7d\xf8\xb3\x07\x6b\xcd\xad\x72\xd7\x0d\xa2\x2a\x63\xd8\x89\x6b\x63\x91\xd8", 32)) return 1; // 1.8.0 shipped with fw 1.8.0 32))
return 1; // 1.2.5
if (0 ==
memcmp(hash,
"\x42\x59\x66\x94\xa0\xf2\x9d\x1e\xc2\x35\x71\x29\x2d\x54\x39\xd8"
"\x2f\xa1\x8c\x07\x37\xcb\x10\x7e\x98\xf6\x1e\xf5\x93\x4d\xe7\x16",
32))
return 1; // 1.3.0a
if (0 ==
memcmp(hash,
"\x3a\xcf\x2e\x51\x0b\x0f\xe1\x56\xb5\x58\xbb\xf7\x9c\x7e\x48\x5e"
"\xb0\x26\xe5\xe0\x8c\xb4\x4d\x15\x2d\x44\xd6\x4e\x0c\x6a\x41\x37",
32))
return 1; // 1.3.0b
if (0 ==
memcmp(hash,
"\x15\x85\x21\x5b\xc6\xe5\x5a\x34\x07\xa8\xb3\xee\xe2\x79\x03\x4e"
"\x95\xb9\xc4\x34\x00\x33\xe1\xb6\xae\x16\x0c\xe6\x61\x19\x67\x15",
32))
return 1; // 1.3.1
if (0 ==
memcmp(hash,
"\x76\x51\xb7\xca\xba\x5a\xae\x0c\xc1\xc6\x5c\x83\x04\xf7\x60\x39"
"\x6f\x77\x60\x6c\xd3\x99\x0c\x99\x15\x98\xf0\xe2\x2a\x81\xe0\x07",
32))
return 1; // 1.3.2
// note to those verifying these values: bootloader versions above this
// comment are aligned/padded to 32KiB with trailing 0xFF bytes and versions
// below are padded with 0x00.
// for more info, refer to "make -C
// bootloader align" and
// "firmware/bl_data.py".
if (0 ==
memcmp(hash,
"\x8c\xe8\xd7\x9e\xdf\x43\x0c\x03\x42\x64\x68\x6c\xa9\xb1\xd7\x8d"
"\x26\xed\xb2\xac\xab\x71\x39\xbe\x8f\x98\x5c\x2a\x3c\x6c\xae\x11",
32))
return 1; // 1.3.3
if (0 ==
memcmp(hash,
"\x63\x30\xfc\xec\x16\x72\xfa\xd3\x0b\x42\x1b\x60\xf7\x4f\x83\x9a"
"\x39\x39\x33\x45\x65\xcb\x70\x3b\x2b\xd7\x18\x2e\xa2\xdd\xa0\x19",
32))
return 1; // 1.4.0 shipped with fw 1.6.1
if (0 ==
memcmp(hash,
"\xaf\xb4\xcf\x7a\x4a\x57\x96\x10\x0e\xd5\x41\x6b\x75\x12\x1b\xc7"
"\x10\x08\xc2\xa2\xfd\x54\x49\xbd\x8f\x63\xcc\x22\xa6\xa7\xd6\x80",
32))
return 1; // 1.5.0 shipped with fw 1.6.2
if (0 ==
memcmp(hash,
"\x51\x12\x90\xa8\x72\x3f\xaf\xe7\x34\x15\x25\x9d\x25\x96\x76\x54"
"\x06\x32\x5c\xe2\x4b\x4b\x80\x03\x2c\x0b\x70\xb0\x5d\x98\x46\xe9",
32))
return 1; // 1.5.1 shipped with fw 1.6.3
if (0 ==
memcmp(hash,
"\x3e\xc4\xbd\xd5\x77\xea\x0c\x36\xc7\xba\xb7\xb9\xa3\x5b\x87\x17"
"\xb3\xf1\xfc\x2f\x80\x9e\x69\x0c\x8a\xbe\x5b\x05\xfb\xc2\x43\xc6",
32))
return 1; // 1.6.0 shipped with fw 1.7.0
if (0 ==
memcmp(hash,
"\x8e\x83\x02\x3f\x0d\x4f\x82\x4f\x64\x71\x20\x75\x2b\x6c\x71\x6f"
"\x55\xd7\x95\x70\x66\x8f\xd4\x90\x65\xd5\xb7\x97\x6e\x7a\x6e\x19",
32))
return 1; // 1.6.0 shipped with fw 1.7.1 and 1.7.2
if (0 ==
memcmp(hash,
"\xa2\x36\x6e\x77\xde\x8e\xfd\xfd\xc9\x99\xf4\x72\x20\xc0\x16\xe3"
"\x3f\x6d\x24\x24\xe2\x45\x90\x79\x11\x7a\x90\xb3\xa8\x88\xba\xdd",
32))
return 1; // 1.6.1 shipped with fw 1.7.3
if (0 ==
memcmp(hash,
"\xf7\xfa\x16\x5b\xe6\xd7\x80\xf3\xe1\xaf\x00\xab\xc0\x7d\xf8\xb3"
"\x07\x6b\xcd\xad\x72\xd7\x0d\xa2\x2a\x63\xd8\x89\x6b\x63\x91\xd8",
32))
return 1; // 1.8.0 shipped with fw 1.8.0
return 0; return 0;
} }
void check_bootloader(void) void check_bootloader(void) {
{
#if MEMORY_PROTECT #if MEMORY_PROTECT
uint8_t hash[32]; uint8_t hash[32];
int r = memory_bootloader_hash(hash); int r = memory_bootloader_hash(hash);
if (!known_bootloader(r, hash)) { if (!known_bootloader(r, hash)) {
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Unknown bootloader"), _("detected."), NULL, _("Unplug your TREZOR"), _("contact our support."), NULL); layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Unknown bootloader"),
_("detected."), NULL, _("Unplug your TREZOR"),
_("contact our support."), NULL);
shutdown(); shutdown();
} }
@ -72,7 +152,8 @@ void check_bootloader(void)
// ATTEMPTING TO OVERWRITE BOOTLOADER WITH UNSIGNED FIRMWARE MAY BRICK // ATTEMPTING TO OVERWRITE BOOTLOADER WITH UNSIGNED FIRMWARE MAY BRICK
// YOUR DEVICE. // YOUR DEVICE.
layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, _("Updating bootloader"), NULL, NULL, _("DO NOT UNPLUG"), _("YOUR TREZOR!"), NULL); layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, _("Updating bootloader"),
NULL, NULL, _("DO NOT UNPLUG"), _("YOUR TREZOR!"), NULL);
// unlock sectors // unlock sectors
memory_write_unlock(); memory_write_unlock();
@ -95,13 +176,17 @@ void check_bootloader(void)
r = memory_bootloader_hash(hash); r = memory_bootloader_hash(hash);
if (r == 32 && 0 == memcmp(hash, bl_hash, 32)) { if (r == 32 && 0 == memcmp(hash, bl_hash, 32)) {
// OK -> show info and halt // OK -> show info and halt
layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Update finished"), _("successfully."), NULL, _("Please reconnect"), _("the device."), NULL); layoutDialog(&bmp_icon_info, NULL, NULL, NULL, _("Update finished"),
_("successfully."), NULL, _("Please reconnect"),
_("the device."), NULL);
shutdown(); shutdown();
return; return;
} }
} }
// show info and halt // show info and halt
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Bootloader update"), _("broken."), NULL, _("Unplug your TREZOR"), _("contact our support."), NULL); layoutDialog(&bmp_icon_error, NULL, NULL, NULL, _("Bootloader update"),
_("broken."), NULL, _("Unplug your TREZOR"),
_("contact our support."), NULL);
shutdown(); shutdown();
#endif #endif
} }

View File

@ -17,14 +17,13 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h>
#include "coins.h" #include "coins.h"
#include <string.h>
#include "address.h" #include "address.h"
#include "ecdsa.h"
#include "base58.h" #include "base58.h"
#include "ecdsa.h"
const CoinInfo *coinByName(const char *name) const CoinInfo *coinByName(const char *name) {
{
if (!name) return 0; if (!name) return 0;
for (int i = 0; i < COINS_COUNT; i++) { for (int i = 0; i < COINS_COUNT; i++) {
if (strcmp(name, coins[i].coin_name) == 0) { if (strcmp(name, coins[i].coin_name) == 0) {
@ -34,8 +33,7 @@ const CoinInfo *coinByName(const char *name)
return 0; return 0;
} }
const CoinInfo *coinByAddressType(uint32_t address_type) const CoinInfo *coinByAddressType(uint32_t address_type) {
{
for (int i = 0; i < COINS_COUNT; i++) { for (int i = 0; i < COINS_COUNT; i++) {
if (address_type == coins[i].address_type) { if (address_type == coins[i].address_type) {
return &(coins[i]); return &(coins[i]);
@ -44,8 +42,7 @@ const CoinInfo *coinByAddressType(uint32_t address_type)
return 0; return 0;
} }
const CoinInfo *coinBySlip44(uint32_t coin_type) const CoinInfo *coinBySlip44(uint32_t coin_type) {
{
for (int i = 0; i < COINS_COUNT; i++) { for (int i = 0; i < COINS_COUNT; i++) {
if (coin_type == coins[i].coin_type) { if (coin_type == coins[i].coin_type) {
return &(coins[i]); return &(coins[i]);
@ -54,24 +51,27 @@ const CoinInfo *coinBySlip44(uint32_t coin_type)
return 0; return 0;
} }
bool coinExtractAddressType(const CoinInfo *coin, const char *addr, uint32_t *address_type) bool coinExtractAddressType(const CoinInfo *coin, const char *addr,
{ uint32_t *address_type) {
if (!addr) return false; if (!addr) return false;
uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; uint8_t addr_raw[MAX_ADDR_RAW_SIZE];
int len = base58_decode_check(addr, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); int len = base58_decode_check(addr, coin->curve->hasher_base58, addr_raw,
MAX_ADDR_RAW_SIZE);
if (len >= 21) { if (len >= 21) {
return coinExtractAddressTypeRaw(coin, addr_raw, address_type); return coinExtractAddressTypeRaw(coin, addr_raw, address_type);
} }
return false; return false;
} }
bool coinExtractAddressTypeRaw(const CoinInfo *coin, const uint8_t *addr_raw, uint32_t *address_type) bool coinExtractAddressTypeRaw(const CoinInfo *coin, const uint8_t *addr_raw,
{ uint32_t *address_type) {
if (coin->has_address_type && address_check_prefix(addr_raw, coin->address_type)) { if (coin->has_address_type &&
address_check_prefix(addr_raw, coin->address_type)) {
*address_type = coin->address_type; *address_type = coin->address_type;
return true; return true;
} }
if (coin->has_address_type_p2sh && address_check_prefix(addr_raw, coin->address_type_p2sh)) { if (coin->has_address_type_p2sh &&
address_check_prefix(addr_raw, coin->address_type_p2sh)) {
*address_type = coin->address_type_p2sh; *address_type = coin->address_type_p2sh;
return true; return true;
} }

View File

@ -20,8 +20,8 @@
#ifndef __COINS_H__ #ifndef __COINS_H__
#define __COINS_H__ #define __COINS_H__
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include "bip32.h" #include "bip32.h"
#include "hasher.h" #include "hasher.h"
@ -56,7 +56,9 @@ typedef struct _CoinInfo {
const CoinInfo *coinByName(const char *name); const CoinInfo *coinByName(const char *name);
const CoinInfo *coinByAddressType(uint32_t address_type); const CoinInfo *coinByAddressType(uint32_t address_type);
const CoinInfo *coinBySlip44(uint32_t coin_type); const CoinInfo *coinBySlip44(uint32_t coin_type);
bool coinExtractAddressType(const CoinInfo *coin, const char *addr, uint32_t *address_type); bool coinExtractAddressType(const CoinInfo *coin, const char *addr,
bool coinExtractAddressTypeRaw(const CoinInfo *coin, const uint8_t *addr_raw, uint32_t *address_type); uint32_t *address_type);
bool coinExtractAddressTypeRaw(const CoinInfo *coin, const uint8_t *addr_raw,
uint32_t *address_type);
#endif #endif

View File

@ -17,36 +17,37 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h>
#include <stdint.h>
#include <libopencm3/stm32/flash.h> #include <libopencm3/stm32/flash.h>
#include <stdint.h>
#include <string.h>
#include "messages.pb.h" #include "messages.pb.h"
#include "common.h"
#include "trezor.h"
#include "sha2.h"
#include "aes/aes.h" #include "aes/aes.h"
#include "pbkdf2.h"
#include "hmac.h"
#include "bip32.h" #include "bip32.h"
#include "bip39.h" #include "bip39.h"
#include "curves.h" #include "common.h"
#include "util.h"
#include "memory.h"
#include "rng.h"
#include "config.h" #include "config.h"
#include "curves.h"
#include "debug.h" #include "debug.h"
#include "protect.h"
#include "layout2.h"
#include "usb.h"
#include "gettext.h" #include "gettext.h"
#include "u2f.h" #include "hmac.h"
#include "layout2.h"
#include "memory.h"
#include "memzero.h" #include "memzero.h"
#include "supervise.h" #include "pbkdf2.h"
#include "protect.h"
#include "rng.h"
#include "sha2.h"
#include "storage.h" #include "storage.h"
#include "supervise.h"
#include "trezor.h"
#include "u2f.h"
#include "usb.h"
#include "util.h"
/* Magic constants to check validity of storage block for storage versions 1 to 10. */ /* Magic constants to check validity of storage block for storage versions 1
* to 10. */
static const uint32_t CONFIG_MAGIC_V10 = 0x726f7473; // 'stor' as uint32_t static const uint32_t CONFIG_MAGIC_V10 = 0x726f7473; // 'stor' as uint32_t
#if !EMULATOR #if !EMULATOR
@ -132,8 +133,7 @@ static const uint32_t CONFIG_VERSION = 11;
static const uint8_t FALSE_BYTE = '\x00'; static const uint8_t FALSE_BYTE = '\x00';
static const uint8_t TRUE_BYTE = '\x01'; static const uint8_t TRUE_BYTE = '\x01';
static uint32_t pin_to_int(const char *pin) static uint32_t pin_to_int(const char *pin) {
{
uint32_t val = 1; uint32_t val = 1;
size_t i = 0; size_t i = 0;
for (i = 0; i < MAX_PIN_LEN && pin[i] != '\0'; ++i) { for (i = 0; i < MAX_PIN_LEN && pin[i] != '\0'; ++i) {
@ -150,8 +150,7 @@ static uint32_t pin_to_int(const char *pin)
return val; return val;
} }
static secbool config_set_bool(uint16_t key, bool value) static secbool config_set_bool(uint16_t key, bool value) {
{
if (value) { if (value) {
return storage_set(key, &TRUE_BYTE, sizeof(TRUE_BYTE)); return storage_set(key, &TRUE_BYTE, sizeof(TRUE_BYTE));
} else { } else {
@ -159,11 +158,11 @@ static secbool config_set_bool(uint16_t key, bool value)
} }
} }
static secbool config_get_bool(uint16_t key, bool *value) static secbool config_get_bool(uint16_t key, bool *value) {
{
uint8_t val = 0; uint8_t val = 0;
uint16_t len = 0; uint16_t len = 0;
if (sectrue == storage_get(key, &val, sizeof(val), &len) && len == sizeof(TRUE_BYTE)) { if (sectrue == storage_get(key, &val, sizeof(val), &len) &&
len == sizeof(TRUE_BYTE)) {
*value = (val == TRUE_BYTE); *value = (val == TRUE_BYTE);
return sectrue; return sectrue;
} else { } else {
@ -172,8 +171,8 @@ static secbool config_get_bool(uint16_t key, bool *value)
} }
} }
static secbool config_get_bytes(uint16_t key, uint8_t *dest, uint16_t dest_size, uint16_t *real_size) static secbool config_get_bytes(uint16_t key, uint8_t *dest, uint16_t dest_size,
{ uint16_t *real_size) {
if (dest_size == 0) { if (dest_size == 0) {
return secfalse; return secfalse;
} }
@ -184,8 +183,7 @@ static secbool config_get_bytes(uint16_t key, uint8_t *dest, uint16_t dest_size,
return sectrue; return sectrue;
} }
static secbool config_get_string(uint16_t key, char *dest, uint16_t dest_size) static secbool config_get_string(uint16_t key, char *dest, uint16_t dest_size) {
{
if (dest_size == 0) { if (dest_size == 0) {
return secfalse; return secfalse;
} }
@ -199,10 +197,10 @@ static secbool config_get_string(uint16_t key, char *dest, uint16_t dest_size)
return sectrue; return sectrue;
} }
static secbool config_get_uint32(uint16_t key, uint32_t *value) static secbool config_get_uint32(uint16_t key, uint32_t *value) {
{
uint16_t len = 0; uint16_t len = 0;
if (sectrue != storage_get(key, value, sizeof(uint32_t), &len) || len != sizeof(uint32_t)) { if (sectrue != storage_get(key, value, sizeof(uint32_t), &len) ||
len != sizeof(uint32_t)) {
*value = 0; *value = 0;
return secfalse; return secfalse;
} }
@ -212,12 +210,16 @@ static secbool config_get_uint32(uint16_t key, uint32_t *value)
#define FLASH_META_START 0x08008000 #define FLASH_META_START 0x08008000
#define FLASH_META_LEN 0x100 #define FLASH_META_LEN 0x100
static secbool config_upgrade_v10(void) static secbool config_upgrade_v10(void) {
{ #define OLD_STORAGE_SIZE(last_member) \
#define OLD_STORAGE_SIZE(last_member) (((offsetof(Storage, last_member) + pb_membersize(Storage, last_member)) + 3) & ~3) (((offsetof(Storage, last_member) + pb_membersize(Storage, last_member)) + \
3) & \
~3)
if (memcmp(FLASH_PTR(FLASH_META_START), &META_MAGIC_V10, sizeof(META_MAGIC_V10)) != 0 || if (memcmp(FLASH_PTR(FLASH_META_START), &META_MAGIC_V10,
memcmp(FLASH_PTR(FLASH_META_START + FLASH_META_LEN), &CONFIG_MAGIC_V10, sizeof(CONFIG_MAGIC_V10)) != 0) { sizeof(META_MAGIC_V10)) != 0 ||
memcmp(FLASH_PTR(FLASH_META_START + FLASH_META_LEN), &CONFIG_MAGIC_V10,
sizeof(CONFIG_MAGIC_V10)) != 0) {
// wrong magic // wrong magic
return secfalse; return secfalse;
} }
@ -225,8 +227,14 @@ static secbool config_upgrade_v10(void)
Storage config __attribute__((aligned(4))); Storage config __attribute__((aligned(4)));
_Static_assert((sizeof(config) & 3) == 0, "storage unaligned"); _Static_assert((sizeof(config) & 3) == 0, "storage unaligned");
memcpy(config_uuid, FLASH_PTR(FLASH_META_START + FLASH_META_LEN + sizeof(CONFIG_MAGIC_V10)), sizeof(config_uuid)); memcpy(
memcpy(&config, FLASH_PTR(FLASH_META_START + FLASH_META_LEN + sizeof(CONFIG_MAGIC_V10) + sizeof(config_uuid)), sizeof(config)); config_uuid,
FLASH_PTR(FLASH_META_START + FLASH_META_LEN + sizeof(CONFIG_MAGIC_V10)),
sizeof(config_uuid));
memcpy(&config,
FLASH_PTR(FLASH_META_START + FLASH_META_LEN +
sizeof(CONFIG_MAGIC_V10) + sizeof(config_uuid)),
sizeof(config));
// version 1: since 1.0.0 // version 1: since 1.0.0
// version 2: since 1.2.1 // version 2: since 1.2.1
@ -267,14 +275,16 @@ static secbool config_upgrade_v10(void)
// Erase newly added fields. // Erase newly added fields.
if (old_config_size != sizeof(Storage)) { if (old_config_size != sizeof(Storage)) {
memzero((char*)&config + old_config_size, sizeof(Storage) - old_config_size); memzero((char *)&config + old_config_size,
sizeof(Storage) - old_config_size);
} }
const uint32_t FLASH_STORAGE_PINAREA = FLASH_META_START + 0x4000; const uint32_t FLASH_STORAGE_PINAREA = FLASH_META_START + 0x4000;
uint32_t pin_wait = 0; uint32_t pin_wait = 0;
if (config.version <= 5) { if (config.version <= 5) {
// Get PIN failure counter from version 5 format. // Get PIN failure counter from version 5 format.
uint32_t pinctr = config.has_pin_failed_attempts ? config.pin_failed_attempts : 0; uint32_t pinctr =
config.has_pin_failed_attempts ? config.pin_failed_attempts : 0;
if (pinctr > 31) { if (pinctr > 31) {
pinctr = 31; pinctr = 31;
} }
@ -296,7 +306,8 @@ static secbool config_upgrade_v10(void)
while (*u2fptr == 0) { while (*u2fptr == 0) {
u2fptr++; u2fptr++;
} }
u2f_offset = 32 * (u2fptr - (const uint32_t*) FLASH_PTR(FLASH_STORAGE_U2FAREA)); u2f_offset =
32 * (u2fptr - (const uint32_t *)FLASH_PTR(FLASH_STORAGE_U2FAREA));
uint32_t u2fword = *u2fptr; uint32_t u2fword = *u2fptr;
while ((u2fword & 1) == 0) { while ((u2fword & 1) == 0) {
u2f_offset++; u2f_offset++;
@ -365,8 +376,7 @@ static secbool config_upgrade_v10(void)
return sectrue; return sectrue;
} }
void config_init(void) void config_init(void) {
{
char oldTiny = usbTiny(1); char oldTiny = usbTiny(1);
config_upgrade_v10(); config_upgrade_v10();
@ -381,7 +391,9 @@ void config_init(void)
uint16_t len = 0; uint16_t len = 0;
// If UUID is not set, then the config is uninitialized. // If UUID is not set, then the config is uninitialized.
if (sectrue != storage_get(KEY_UUID, config_uuid, sizeof(config_uuid), &len) || len != sizeof(config_uuid)) { if (sectrue !=
storage_get(KEY_UUID, config_uuid, sizeof(config_uuid), &len) ||
len != sizeof(config_uuid)) {
random_buffer((uint8_t *)config_uuid, sizeof(config_uuid)); random_buffer((uint8_t *)config_uuid, sizeof(config_uuid));
storage_set(KEY_UUID, config_uuid, sizeof(config_uuid)); storage_set(KEY_UUID, config_uuid, sizeof(config_uuid));
storage_set(KEY_VERSION, &CONFIG_VERSION, sizeof(CONFIG_VERSION)); storage_set(KEY_VERSION, &CONFIG_VERSION, sizeof(CONFIG_VERSION));
@ -391,8 +403,7 @@ void config_init(void)
usbTiny(oldTiny); usbTiny(oldTiny);
} }
void session_clear(bool lock) void session_clear(bool lock) {
{
sessionSeedCached = secfalse; sessionSeedCached = secfalse;
memzero(&sessionSeed, sizeof(sessionSeed)); memzero(&sessionSeed, sizeof(sessionSeed));
sessionPassphraseCached = secfalse; sessionPassphraseCached = secfalse;
@ -402,15 +413,16 @@ void session_clear(bool lock)
} }
} }
static void get_u2froot_callback(uint32_t iter, uint32_t total) static void get_u2froot_callback(uint32_t iter, uint32_t total) {
{
layoutProgress(_("Updating"), 1000 * iter / total); layoutProgress(_("Updating"), 1000 * iter / total);
} }
static void config_compute_u2froot(const char* mnemonic, StorageHDNode *u2froot) { static void config_compute_u2froot(const char *mnemonic,
StorageHDNode *u2froot) {
static CONFIDENTIAL HDNode node; static CONFIDENTIAL HDNode node;
char oldTiny = usbTiny(1); char oldTiny = usbTiny(1);
mnemonic_to_seed(mnemonic, "", sessionSeed, get_u2froot_callback); // BIP-0039 mnemonic_to_seed(mnemonic, "", sessionSeed,
get_u2froot_callback); // BIP-0039
usbTiny(oldTiny); usbTiny(oldTiny);
hdnode_from_seed(sessionSeed, 64, NIST256P1_NAME, &node); hdnode_from_seed(sessionSeed, 64, NIST256P1_NAME, &node);
hdnode_private_ckd(&node, U2F_KEY_PATH); hdnode_private_ckd(&node, U2F_KEY_PATH);
@ -420,7 +432,8 @@ static void config_compute_u2froot(const char* mnemonic, StorageHDNode *u2froot)
memcpy(u2froot->chain_code.bytes, node.chain_code, sizeof(node.chain_code)); memcpy(u2froot->chain_code.bytes, node.chain_code, sizeof(node.chain_code));
u2froot->has_private_key = true; u2froot->has_private_key = true;
u2froot->private_key.size = sizeof(node.private_key); u2froot->private_key.size = sizeof(node.private_key);
memcpy(u2froot->private_key.bytes, node.private_key, sizeof(node.private_key)); memcpy(u2froot->private_key.bytes, node.private_key,
sizeof(node.private_key));
memzero(&node, sizeof(node)); memzero(&node, sizeof(node));
session_clear(false); // invalidate seed cache session_clear(false); // invalidate seed cache
} }
@ -447,13 +460,14 @@ static void config_setNode(const HDNodeType *node) {
} }
#if DEBUG_LINK #if DEBUG_LINK
bool config_dumpNode(HDNodeType *node) bool config_dumpNode(HDNodeType *node) {
{
memzero(node, sizeof(HDNodeType)); memzero(node, sizeof(HDNodeType));
StorageHDNode storageNode; StorageHDNode storageNode;
uint16_t len = 0; uint16_t len = 0;
if (sectrue != storage_get(KEY_NODE, &storageNode, sizeof(storageNode), &len) || len != sizeof(StorageHDNode)) { if (sectrue !=
storage_get(KEY_NODE, &storageNode, sizeof(storageNode), &len) ||
len != sizeof(StorageHDNode)) {
memzero(&storageNode, sizeof(storageNode)); memzero(&storageNode, sizeof(storageNode));
return false; return false;
} }
@ -476,11 +490,11 @@ bool config_dumpNode(HDNodeType *node)
} }
#endif #endif
void config_loadDevice(const LoadDevice *msg) void config_loadDevice(const LoadDevice *msg) {
{
session_clear(false); session_clear(false);
config_set_bool(KEY_IMPORTED, true); config_set_bool(KEY_IMPORTED, true);
config_setPassphraseProtection(msg->has_passphrase_protection && msg->passphrase_protection); config_setPassphraseProtection(msg->has_passphrase_protection &&
msg->passphrase_protection);
if (msg->has_pin) { if (msg->has_pin) {
config_changePin("", msg->pin); config_changePin("", msg->pin);
@ -505,8 +519,7 @@ void config_loadDevice(const LoadDevice *msg)
} }
} }
void config_setLabel(const char *label) void config_setLabel(const char *label) {
{
if (label == NULL || label[0] == '\0') { if (label == NULL || label[0] == '\0') {
storage_delete(KEY_LABEL); storage_delete(KEY_LABEL);
} else { } else {
@ -514,8 +527,7 @@ void config_setLabel(const char *label)
} }
} }
void config_setLanguage(const char *lang) void config_setLanguage(const char *lang) {
{
if (lang == NULL) { if (lang == NULL) {
return; return;
} }
@ -527,20 +539,18 @@ void config_setLanguage(const char *lang)
storage_set(KEY_LANGUAGE, lang, strnlen(lang, MAX_LANGUAGE_LEN)); storage_set(KEY_LANGUAGE, lang, strnlen(lang, MAX_LANGUAGE_LEN));
} }
void config_setPassphraseProtection(bool passphrase_protection) void config_setPassphraseProtection(bool passphrase_protection) {
{
sessionSeedCached = secfalse; sessionSeedCached = secfalse;
sessionPassphraseCached = secfalse; sessionPassphraseCached = secfalse;
config_set_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection); config_set_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection);
} }
bool config_getPassphraseProtection(bool *passphrase_protection) bool config_getPassphraseProtection(bool *passphrase_protection) {
{ return sectrue ==
return sectrue == config_get_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection); config_get_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection);
} }
void config_setHomescreen(const uint8_t *data, uint32_t size) void config_setHomescreen(const uint8_t *data, uint32_t size) {
{
if (data != NULL && size == HOMESCREEN_SIZE) { if (data != NULL && size == HOMESCREEN_SIZE) {
storage_set(KEY_HOMESCREEN, data, size); storage_set(KEY_HOMESCREEN, data, size);
} else { } else {
@ -548,17 +558,15 @@ void config_setHomescreen(const uint8_t *data, uint32_t size)
} }
} }
static void get_root_node_callback(uint32_t iter, uint32_t total) static void get_root_node_callback(uint32_t iter, uint32_t total) {
{
usbSleep(1); usbSleep(1);
layoutProgress(_("Waking up"), 1000 * iter / total); layoutProgress(_("Waking up"), 1000 * iter / total);
} }
const uint8_t *config_getSeed(bool usePassphrase) const uint8_t *config_getSeed(bool usePassphrase) {
{
// root node is properly cached // root node is properly cached
if (usePassphrase == (sectrue == sessionSeedUsesPassphrase) if (usePassphrase == (sectrue == sessionSeedUsesPassphrase) &&
&& sectrue == sessionSeedCached) { sectrue == sessionSeedCached) {
return sessionSeed; return sessionSeed;
} }
@ -580,7 +588,8 @@ const uint8_t *config_getSeed(bool usePassphrase)
} }
} }
char oldTiny = usbTiny(1); char oldTiny = usbTiny(1);
mnemonic_to_seed(mnemonic, usePassphrase ? sessionPassphrase : "", sessionSeed, get_root_node_callback); // BIP-0039 mnemonic_to_seed(mnemonic, usePassphrase ? sessionPassphrase : "",
sessionSeed, get_root_node_callback); // BIP-0039
memzero(mnemonic, sizeof(mnemonic)); memzero(mnemonic, sizeof(mnemonic));
usbTiny(oldTiny); usbTiny(oldTiny);
sessionSeedCached = sectrue; sessionSeedCached = sectrue;
@ -591,15 +600,17 @@ const uint8_t *config_getSeed(bool usePassphrase)
return NULL; return NULL;
} }
static bool config_loadNode(const StorageHDNode *node, const char *curve, HDNode *out) { static bool config_loadNode(const StorageHDNode *node, const char *curve,
return hdnode_from_xprv(node->depth, node->child_num, node->chain_code.bytes, node->private_key.bytes, curve, out); HDNode *out) {
return hdnode_from_xprv(node->depth, node->child_num, node->chain_code.bytes,
node->private_key.bytes, curve, out);
} }
bool config_getU2FRoot(HDNode *node) bool config_getU2FRoot(HDNode *node) {
{
StorageHDNode u2fNode; StorageHDNode u2fNode;
uint16_t len = 0; uint16_t len = 0;
if (sectrue != storage_get(KEY_U2F_ROOT, &u2fNode, sizeof(u2fNode), &len) || len != sizeof(StorageHDNode)) { if (sectrue != storage_get(KEY_U2F_ROOT, &u2fNode, sizeof(u2fNode), &len) ||
len != sizeof(StorageHDNode)) {
memzero(&u2fNode, sizeof(u2fNode)); memzero(&u2fNode, sizeof(u2fNode));
return false; return false;
} }
@ -608,12 +619,14 @@ bool config_getU2FRoot(HDNode *node)
return ret; return ret;
} }
bool config_getRootNode(HDNode *node, const char *curve, bool usePassphrase) bool config_getRootNode(HDNode *node, const char *curve, bool usePassphrase) {
{
// if storage has node, decrypt and use it // if storage has node, decrypt and use it
StorageHDNode storageHDNode; StorageHDNode storageHDNode;
uint16_t len = 0; uint16_t len = 0;
if (strcmp(curve, SECP256K1_NAME) == 0 && sectrue == storage_get(KEY_NODE, &storageHDNode, sizeof(storageHDNode), &len) && len == sizeof(StorageHDNode)) { if (strcmp(curve, SECP256K1_NAME) == 0 &&
sectrue ==
storage_get(KEY_NODE, &storageHDNode, sizeof(storageHDNode), &len) &&
len == sizeof(StorageHDNode)) {
if (!protectPassphrase()) { if (!protectPassphrase()) {
memzero(&storageHDNode, sizeof(storageHDNode)); memzero(&storageHDNode, sizeof(storageHDNode));
return false; return false;
@ -624,23 +637,29 @@ bool config_getRootNode(HDNode *node, const char *curve, bool usePassphrase)
} }
bool passphrase_protection = false; bool passphrase_protection = false;
config_getPassphraseProtection(&passphrase_protection); config_getPassphraseProtection(&passphrase_protection);
if (passphrase_protection && sectrue == sessionPassphraseCached && sessionPassphrase[0] != '\0') { if (passphrase_protection && sectrue == sessionPassphraseCached &&
sessionPassphrase[0] != '\0') {
// decrypt hd node // decrypt hd node
uint8_t secret[64]; uint8_t secret[64];
PBKDF2_HMAC_SHA512_CTX pctx; PBKDF2_HMAC_SHA512_CTX pctx;
char oldTiny = usbTiny(1); char oldTiny = usbTiny(1);
pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)sessionPassphrase, strlen(sessionPassphrase), (const uint8_t *)"TREZORHD", 8, 1); pbkdf2_hmac_sha512_Init(&pctx, (const uint8_t *)sessionPassphrase,
strlen(sessionPassphrase),
(const uint8_t *)"TREZORHD", 8, 1);
get_root_node_callback(0, BIP39_PBKDF2_ROUNDS); get_root_node_callback(0, BIP39_PBKDF2_ROUNDS);
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 8); pbkdf2_hmac_sha512_Update(&pctx, BIP39_PBKDF2_ROUNDS / 8);
get_root_node_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 8, BIP39_PBKDF2_ROUNDS); get_root_node_callback((i + 1) * BIP39_PBKDF2_ROUNDS / 8,
BIP39_PBKDF2_ROUNDS);
} }
pbkdf2_hmac_sha512_Final(&pctx, secret); pbkdf2_hmac_sha512_Final(&pctx, secret);
usbTiny(oldTiny); usbTiny(oldTiny);
aes_decrypt_ctx ctx; aes_decrypt_ctx ctx;
aes_decrypt_key256(secret, &ctx); aes_decrypt_key256(secret, &ctx);
aes_cbc_decrypt(node->chain_code, node->chain_code, 32, secret + 32, &ctx); aes_cbc_decrypt(node->chain_code, node->chain_code, 32, secret + 32,
aes_cbc_decrypt(node->private_key, node->private_key, 32, secret + 32, &ctx); &ctx);
aes_cbc_decrypt(node->private_key, node->private_key, 32, secret + 32,
&ctx);
} }
return true; return true;
} }
@ -654,18 +673,15 @@ bool config_getRootNode(HDNode *node, const char *curve, bool usePassphrase)
return hdnode_from_seed(seed, 64, curve, node); return hdnode_from_seed(seed, 64, curve, node);
} }
bool config_getLabel(char *dest, uint16_t dest_size) bool config_getLabel(char *dest, uint16_t dest_size) {
{
return sectrue == config_get_string(KEY_LABEL, dest, dest_size); return sectrue == config_get_string(KEY_LABEL, dest, dest_size);
} }
bool config_getLanguage(char *dest, uint16_t dest_size) bool config_getLanguage(char *dest, uint16_t dest_size) {
{
return sectrue == config_get_string(KEY_LANGUAGE, dest, dest_size); return sectrue == config_get_string(KEY_LANGUAGE, dest, dest_size);
} }
bool config_getHomescreen(uint8_t *dest, uint16_t dest_size) bool config_getHomescreen(uint8_t *dest, uint16_t dest_size) {
{
uint16_t len = 0; uint16_t len = 0;
secbool ret = storage_get(KEY_HOMESCREEN, dest, dest_size, &len); secbool ret = storage_get(KEY_HOMESCREEN, dest, dest_size, &len);
if (sectrue != ret || len != HOMESCREEN_SIZE) { if (sectrue != ret || len != HOMESCREEN_SIZE) {
@ -674,13 +690,13 @@ bool config_getHomescreen(uint8_t *dest, uint16_t dest_size)
return true; return true;
} }
bool config_setMnemonic(const char *mnemonic) bool config_setMnemonic(const char *mnemonic) {
{
if (mnemonic == NULL) { if (mnemonic == NULL) {
return false; return false;
} }
if (sectrue != storage_set(KEY_MNEMONIC, mnemonic, strnlen(mnemonic, MAX_MNEMONIC_LEN))) { if (sectrue != storage_set(KEY_MNEMONIC, mnemonic,
strnlen(mnemonic, MAX_MNEMONIC_LEN))) {
return false; return false;
} }
@ -700,24 +716,23 @@ bool config_setMnemonic(const char *mnemonic)
return true; return true;
} }
bool config_getMnemonicBytes(uint8_t *dest, uint16_t dest_size, uint16_t *real_size) bool config_getMnemonicBytes(uint8_t *dest, uint16_t dest_size,
{ uint16_t *real_size) {
return sectrue == config_get_bytes(KEY_MNEMONIC, dest, dest_size, real_size); return sectrue == config_get_bytes(KEY_MNEMONIC, dest, dest_size, real_size);
} }
bool config_getMnemonic(char *dest, uint16_t dest_size) bool config_getMnemonic(char *dest, uint16_t dest_size) {
{
return sectrue == config_get_string(KEY_MNEMONIC, dest, dest_size); return sectrue == config_get_string(KEY_MNEMONIC, dest, dest_size);
} }
/* Check whether mnemonic matches storage. The mnemonic must be /* Check whether mnemonic matches storage. The mnemonic must be
* a null-terminated string. * a null-terminated string.
*/ */
bool config_containsMnemonic(const char *mnemonic) bool config_containsMnemonic(const char *mnemonic) {
{
uint16_t len = 0; uint16_t len = 0;
uint8_t stored_mnemonic[MAX_MNEMONIC_LEN]; uint8_t stored_mnemonic[MAX_MNEMONIC_LEN];
if (sectrue != storage_get(KEY_MNEMONIC, stored_mnemonic, sizeof(stored_mnemonic), &len)) { if (sectrue != storage_get(KEY_MNEMONIC, stored_mnemonic,
sizeof(stored_mnemonic), &len)) {
return false; return false;
} }
@ -727,7 +742,8 @@ bool config_containsMnemonic(const char *mnemonic)
memzero(stored_mnemonic, sizeof(stored_mnemonic)); memzero(stored_mnemonic, sizeof(stored_mnemonic));
uint8_t digest_input[SHA256_DIGEST_LENGTH]; uint8_t digest_input[SHA256_DIGEST_LENGTH];
sha256_Raw((const uint8_t*)mnemonic, strnlen(mnemonic, MAX_MNEMONIC_LEN), digest_input); sha256_Raw((const uint8_t *)mnemonic, strnlen(mnemonic, MAX_MNEMONIC_LEN),
digest_input);
uint8_t diff = 0; uint8_t diff = 0;
for (size_t i = 0; i < sizeof(digest_input); i++) { for (size_t i = 0; i < sizeof(digest_input); i++) {
@ -741,21 +757,16 @@ bool config_containsMnemonic(const char *mnemonic)
/* Check whether pin matches storage. The pin must be /* Check whether pin matches storage. The pin must be
* a null-terminated string with at most 9 characters. * a null-terminated string with at most 9 characters.
*/ */
bool config_unlock(const char *pin) bool config_unlock(const char *pin) {
{
char oldTiny = usbTiny(1); char oldTiny = usbTiny(1);
secbool ret = storage_unlock(pin_to_int(pin)); secbool ret = storage_unlock(pin_to_int(pin));
usbTiny(oldTiny); usbTiny(oldTiny);
return sectrue == ret; return sectrue == ret;
} }
bool config_hasPin(void) bool config_hasPin(void) { return sectrue == storage_has_pin(); }
{
return sectrue == storage_has_pin();
}
bool config_changePin(const char *old_pin, const char *new_pin) bool config_changePin(const char *old_pin, const char *new_pin) {
{
uint32_t new_pin_int = pin_to_int(new_pin); uint32_t new_pin_int = pin_to_int(new_pin);
if (new_pin_int == 0) { if (new_pin_int == 0) {
return false; return false;
@ -781,25 +792,22 @@ bool config_changePin(const char *old_pin, const char *new_pin)
} }
#if DEBUG_LINK #if DEBUG_LINK
bool config_getPin(char *dest, uint16_t dest_size) bool config_getPin(char *dest, uint16_t dest_size) {
{
return sectrue == config_get_string(KEY_DEBUG_LINK_PIN, dest, dest_size); return sectrue == config_get_string(KEY_DEBUG_LINK_PIN, dest, dest_size);
} }
#endif #endif
void session_cachePassphrase(const char *passphrase) void session_cachePassphrase(const char *passphrase) {
{
strlcpy(sessionPassphrase, passphrase, sizeof(sessionPassphrase)); strlcpy(sessionPassphrase, passphrase, sizeof(sessionPassphrase));
sessionPassphraseCached = sectrue; sessionPassphraseCached = sectrue;
} }
bool session_isPassphraseCached(void) bool session_isPassphraseCached(void) {
{
return sectrue == sessionPassphraseCached; return sectrue == sessionPassphraseCached;
} }
bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphrase) bool session_getState(const uint8_t *salt, uint8_t *state,
{ const char *passphrase) {
if (!passphrase && sectrue != sessionPassphraseCached) { if (!passphrase && sectrue != sessionPassphraseCached) {
return false; return false;
} else { } else {
@ -825,60 +833,45 @@ bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphras
return true; return true;
} }
bool session_isUnlocked(void) bool session_isUnlocked(void) { return sectrue == storage_is_unlocked(); }
{
return sectrue == storage_is_unlocked();
}
bool config_isInitialized(void) bool config_isInitialized(void) {
{
bool initialized = false; bool initialized = false;
config_get_bool(KEY_INITIALIZED, &initialized); config_get_bool(KEY_INITIALIZED, &initialized);
return initialized; return initialized;
} }
bool config_getImported(bool* imported) bool config_getImported(bool *imported) {
{
return sectrue == config_get_bool(KEY_IMPORTED, imported); return sectrue == config_get_bool(KEY_IMPORTED, imported);
} }
void config_setImported(bool imported) void config_setImported(bool imported) {
{
config_set_bool(KEY_IMPORTED, imported); config_set_bool(KEY_IMPORTED, imported);
} }
bool config_getNeedsBackup(bool *needs_backup) bool config_getNeedsBackup(bool *needs_backup) {
{
return sectrue == config_get_bool(KEY_NEEDS_BACKUP, needs_backup); return sectrue == config_get_bool(KEY_NEEDS_BACKUP, needs_backup);
} }
void config_setNeedsBackup(bool needs_backup) void config_setNeedsBackup(bool needs_backup) {
{
config_set_bool(KEY_NEEDS_BACKUP, needs_backup); config_set_bool(KEY_NEEDS_BACKUP, needs_backup);
} }
bool config_getUnfinishedBackup(bool *unfinished_backup) bool config_getUnfinishedBackup(bool *unfinished_backup) {
{
return sectrue == config_get_bool(KEY_UNFINISHED_BACKUP, unfinished_backup); return sectrue == config_get_bool(KEY_UNFINISHED_BACKUP, unfinished_backup);
} }
void config_setUnfinishedBackup(bool unfinished_backup) void config_setUnfinishedBackup(bool unfinished_backup) {
{
config_set_bool(KEY_UNFINISHED_BACKUP, unfinished_backup); config_set_bool(KEY_UNFINISHED_BACKUP, unfinished_backup);
} }
bool config_getNoBackup(bool *no_backup) bool config_getNoBackup(bool *no_backup) {
{
return sectrue == config_get_bool(KEY_NO_BACKUP, no_backup); return sectrue == config_get_bool(KEY_NO_BACKUP, no_backup);
} }
void config_setNoBackup(void) void config_setNoBackup(void) { config_set_bool(KEY_NO_BACKUP, true); }
{
config_set_bool(KEY_NO_BACKUP, true);
}
void config_applyFlags(uint32_t flags) void config_applyFlags(uint32_t flags) {
{
uint32_t old_flags = 0; uint32_t old_flags = 0;
config_get_uint32(KEY_FLAGS, &old_flags); config_get_uint32(KEY_FLAGS, &old_flags);
flags |= old_flags; flags |= old_flags;
@ -888,25 +881,21 @@ void config_applyFlags(uint32_t flags)
storage_set(KEY_FLAGS, &flags, sizeof(flags)); storage_set(KEY_FLAGS, &flags, sizeof(flags));
} }
bool config_getFlags(uint32_t *flags) bool config_getFlags(uint32_t *flags) {
{
return sectrue == config_get_uint32(KEY_FLAGS, flags); return sectrue == config_get_uint32(KEY_FLAGS, flags);
} }
uint32_t config_nextU2FCounter(void) uint32_t config_nextU2FCounter(void) {
{
uint32_t u2fcounter = 0; uint32_t u2fcounter = 0;
storage_next_counter(KEY_U2F_COUNTER, &u2fcounter); storage_next_counter(KEY_U2F_COUNTER, &u2fcounter);
return u2fcounter; return u2fcounter;
} }
void config_setU2FCounter(uint32_t u2fcounter) void config_setU2FCounter(uint32_t u2fcounter) {
{
storage_set_counter(KEY_U2F_COUNTER, u2fcounter); storage_set_counter(KEY_U2F_COUNTER, u2fcounter);
} }
uint32_t config_getAutoLockDelayMs() uint32_t config_getAutoLockDelayMs() {
{
if (sectrue == autoLockDelayMsCached) { if (sectrue == autoLockDelayMsCached) {
return autoLockDelayMs; return autoLockDelayMs;
} }
@ -922,18 +911,17 @@ uint32_t config_getAutoLockDelayMs()
return autoLockDelayMs; return autoLockDelayMs;
} }
void config_setAutoLockDelayMs(uint32_t auto_lock_delay_ms) void config_setAutoLockDelayMs(uint32_t auto_lock_delay_ms) {
{
const uint32_t min_delay_ms = 10 * 1000U; // 10 seconds const uint32_t min_delay_ms = 10 * 1000U; // 10 seconds
auto_lock_delay_ms = MAX(auto_lock_delay_ms, min_delay_ms); auto_lock_delay_ms = MAX(auto_lock_delay_ms, min_delay_ms);
if (sectrue == storage_set(KEY_AUTO_LOCK_DELAY_MS, &auto_lock_delay_ms, sizeof(auto_lock_delay_ms))) { if (sectrue == storage_set(KEY_AUTO_LOCK_DELAY_MS, &auto_lock_delay_ms,
sizeof(auto_lock_delay_ms))) {
autoLockDelayMs = auto_lock_delay_ms; autoLockDelayMs = auto_lock_delay_ms;
autoLockDelayMsCached = sectrue; autoLockDelayMsCached = sectrue;
} }
} }
void config_wipe(void) void config_wipe(void) {
{
char oldTiny = usbTiny(1); char oldTiny = usbTiny(1);
storage_wipe(); storage_wipe();
if (storage_is_unlocked() != sectrue) { if (storage_is_unlocked() != sectrue) {

View File

@ -109,12 +109,14 @@ void config_setHomescreen(const uint8_t *data, uint32_t size);
void session_cachePassphrase(const char *passphrase); void session_cachePassphrase(const char *passphrase);
bool session_isPassphraseCached(void); bool session_isPassphraseCached(void);
bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphrase); bool session_getState(const uint8_t *salt, uint8_t *state,
const char *passphrase);
bool config_setMnemonic(const char *mnemonic); bool config_setMnemonic(const char *mnemonic);
bool config_containsMnemonic(const char *mnemonic); bool config_containsMnemonic(const char *mnemonic);
bool config_getMnemonic(char *dest, uint16_t dest_size); bool config_getMnemonic(char *dest, uint16_t dest_size);
bool config_getMnemonicBytes(uint8_t *dest, uint16_t dest_size, uint16_t *real_size); bool config_getMnemonicBytes(uint8_t *dest, uint16_t dest_size,
uint16_t *real_size);
#if DEBUG_LINK #if DEBUG_LINK
bool config_dumpNode(HDNodeType *node); bool config_dumpNode(HDNodeType *node);

View File

@ -17,24 +17,23 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h>
#include "crypto.h" #include "crypto.h"
#include "sha2.h" #include <string.h>
#include "pbkdf2.h"
#include "aes/aes.h"
#include "hmac.h"
#include "bip32.h"
#include "layout.h"
#include "curves.h"
#include "secp256k1.h"
#include "address.h" #include "address.h"
#include "coins.h" #include "aes/aes.h"
#include "base58.h" #include "base58.h"
#include "segwit_addr.h" #include "bip32.h"
#include "cash_addr.h" #include "cash_addr.h"
#include "coins.h"
#include "curves.h"
#include "hmac.h"
#include "layout.h"
#include "pbkdf2.h"
#include "secp256k1.h"
#include "segwit_addr.h"
#include "sha2.h"
uint32_t ser_length(uint32_t len, uint8_t *out) uint32_t ser_length(uint32_t len, uint8_t *out) {
{
if (len < 253) { if (len < 253) {
out[0] = len & 0xFF; out[0] = len & 0xFF;
return 1; return 1;
@ -53,8 +52,7 @@ uint32_t ser_length(uint32_t len, uint8_t *out)
return 5; return 5;
} }
uint32_t ser_length_hash(Hasher *hasher, uint32_t len) uint32_t ser_length_hash(Hasher *hasher, uint32_t len) {
{
if (len < 253) { if (len < 253) {
hasher_Update(hasher, (const uint8_t *)&len, 1); hasher_Update(hasher, (const uint8_t *)&len, 1);
return 1; return 1;
@ -71,8 +69,7 @@ uint32_t ser_length_hash(Hasher *hasher, uint32_t len)
return 5; return 5;
} }
uint32_t deser_length(const uint8_t *in, uint32_t *out) uint32_t deser_length(const uint8_t *in, uint32_t *out) {
{
if (in[0] < 253) { if (in[0] < 253) {
*out = in[0]; *out = in[0];
return 1; return 1;
@ -89,19 +86,21 @@ uint32_t deser_length(const uint8_t *in, uint32_t *out)
return 1 + 8; return 1 + 8;
} }
int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) int sshMessageSign(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 hdnode_sign(node, message, message_len, HASHER_SHA2, signature + 1, NULL, NULL); return hdnode_sign(node, message, message_len, HASHER_SHA2, signature + 1,
NULL, NULL);
} }
int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) int gpgMessageSign(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
const curve_info *ed25519_curve_info = get_curve_by_name(ED25519_NAME); const curve_info *ed25519_curve_info = get_curve_by_name(ED25519_NAME);
if (ed25519_curve_info && node->curve == ed25519_curve_info) { if (ed25519_curve_info && node->curve == ed25519_curve_info) {
// GPG supports variable size digest for Ed25519 signatures // GPG supports variable size digest for Ed25519 signatures
return hdnode_sign(node, message, message_len, 0, signature + 1, NULL, NULL); return hdnode_sign(node, message, message_len, 0, signature + 1, NULL,
NULL);
} else { } else {
// Ensure 256-bit digest before proceeding // Ensure 256-bit digest before proceeding
if (message_len != 32) { if (message_len != 32) {
@ -111,10 +110,13 @@ int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uin
} }
} }
static void cryptoMessageHash(const CoinInfo *coin, const uint8_t *message, size_t message_len, uint8_t hash[HASHER_DIGEST_LENGTH]) { static void cryptoMessageHash(const CoinInfo *coin, const uint8_t *message,
size_t message_len,
uint8_t hash[HASHER_DIGEST_LENGTH]) {
Hasher hasher; Hasher hasher;
hasher_Init(&hasher, coin->curve->hasher_sign); hasher_Init(&hasher, coin->curve->hasher_sign);
hasher_Update(&hasher, (const uint8_t *)coin->signed_message_header, strlen(coin->signed_message_header)); hasher_Update(&hasher, (const uint8_t *)coin->signed_message_header,
strlen(coin->signed_message_header));
uint8_t varint[5]; uint8_t varint[5];
uint32_t l = ser_length(message_len, varint); uint32_t l = ser_length(message_len, varint);
hasher_Update(&hasher, varint, l); hasher_Update(&hasher, varint, l);
@ -122,8 +124,9 @@ static void cryptoMessageHash(const CoinInfo *coin, const uint8_t *message, size
hasher_Final(&hasher, hash); hasher_Final(&hasher, hash);
} }
int cryptoMessageSign(const CoinInfo *coin, HDNode *node, InputScriptType script_type, const uint8_t *message, size_t message_len, uint8_t *signature) int cryptoMessageSign(const CoinInfo *coin, HDNode *node,
{ InputScriptType script_type, const uint8_t *message,
size_t message_len, uint8_t *signature) {
uint8_t hash[HASHER_DIGEST_LENGTH]; uint8_t hash[HASHER_DIGEST_LENGTH];
cryptoMessageHash(coin, message, message_len, hash); cryptoMessageHash(coin, message, message_len, hash);
@ -148,8 +151,9 @@ int cryptoMessageSign(const CoinInfo *coin, HDNode *node, InputScriptType script
return result; return result;
} }
int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t message_len, const char *address, const uint8_t *signature) int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message,
{ size_t message_len, const char *address,
const uint8_t *signature) {
// check for invalid signature prefix // check for invalid signature prefix
if (signature[0] < 27 || signature[0] > 43) { if (signature[0] < 27 || signature[0] > 43) {
return 1; return 1;
@ -163,7 +167,8 @@ int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t mes
// check if signature verifies the digest and recover the public key // check if signature verifies the digest and recover the public key
uint8_t pubkey[65]; uint8_t pubkey[65];
if (ecdsa_recover_pub_from_sig(coin->curve->params, pubkey, signature + 1, hash, recid) != 0) { if (ecdsa_recover_pub_from_sig(coin->curve->params, pubkey, signature + 1,
hash, recid) != 0) {
return 3; return 3;
} }
// convert public key to compressed pubkey if necessary // convert public key to compressed pubkey if necessary
@ -183,20 +188,25 @@ int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t mes
return 2; return 2;
} }
} else { } else {
len = base58_decode_check(address, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); len = base58_decode_check(address, coin->curve->hasher_base58, addr_raw,
MAX_ADDR_RAW_SIZE);
} }
ecdsa_get_address_raw(pubkey, coin->address_type, coin->curve->hasher_pubkey, recovered_raw); ecdsa_get_address_raw(pubkey, coin->address_type,
if (memcmp(recovered_raw, addr_raw, len) != 0 coin->curve->hasher_pubkey, recovered_raw);
|| len != address_prefix_bytes_len(coin->address_type) + 20) { if (memcmp(recovered_raw, addr_raw, len) != 0 ||
len != address_prefix_bytes_len(coin->address_type) + 20) {
return 2; return 2;
} }
} else } else
// segwit-in-p2sh // segwit-in-p2sh
if (signature[0] >= 35 && signature[0] <= 38) { if (signature[0] >= 35 && signature[0] <= 38) {
size_t len = base58_decode_check(address, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); size_t len = base58_decode_check(address, coin->curve->hasher_base58,
ecdsa_get_address_segwit_p2sh_raw(pubkey, coin->address_type_p2sh, coin->curve->hasher_pubkey, recovered_raw); addr_raw, MAX_ADDR_RAW_SIZE);
if (memcmp(recovered_raw, addr_raw, len) != 0 ecdsa_get_address_segwit_p2sh_raw(pubkey, coin->address_type_p2sh,
|| len != address_prefix_bytes_len(coin->address_type_p2sh) + 20) { coin->curve->hasher_pubkey,
recovered_raw);
if (memcmp(recovered_raw, addr_raw, len) != 0 ||
len != address_prefix_bytes_len(coin->address_type_p2sh) + 20) {
return 2; return 2;
} }
} else } else
@ -204,13 +214,13 @@ int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t mes
if (signature[0] >= 39 && signature[0] <= 42) { if (signature[0] >= 39 && signature[0] <= 42) {
int witver; int witver;
size_t len; size_t len;
if (!coin->bech32_prefix if (!coin->bech32_prefix ||
|| !segwit_addr_decode(&witver, recovered_raw, &len, coin->bech32_prefix, address)) { !segwit_addr_decode(&witver, recovered_raw, &len, coin->bech32_prefix,
address)) {
return 4; return 4;
} }
ecdsa_get_pubkeyhash(pubkey, coin->curve->hasher_pubkey, addr_raw); ecdsa_get_pubkeyhash(pubkey, coin->curve->hasher_pubkey, addr_raw);
if (memcmp(recovered_raw, addr_raw, len) != 0 if (memcmp(recovered_raw, addr_raw, len) != 0 || witver != 0 || len != 20) {
|| witver != 0 || len != 20) {
return 2; return 2;
} }
} else { } else {
@ -221,7 +231,10 @@ int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t mes
} }
/* ECIES disabled /* ECIES disabled
int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw) int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t
msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t
*payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t
*privkey, const uint8_t *address_raw)
{ {
if (privkey && address_raw) { // signing == true if (privkey && address_raw) { // signing == true
HDNode node; HDNode node;
@ -229,9 +242,9 @@ int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_siz
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);
hdnode_from_xprv(0, 0, 0, privkey, privkey, SECP256K1_NAME, &node); hdnode_from_xprv(0, 0, 0, privkey, privkey, SECP256K1_NAME,
if (cryptoMessageSign(&node, msg, msg_size, payload + 1 + l + msg_size + 21) != 0) { &node); if (cryptoMessageSign(&node, msg, msg_size, payload + 1 + l + msg_size +
return 1; 21) != 0) { return 1;
} }
*payload_len = 1 + l + msg_size + 21 + 65; *payload_len = 1 + l + msg_size + 21 + 65;
} else { } else {
@ -261,11 +274,13 @@ int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_siz
uint8_t salt[22 + 33]; uint8_t salt[22 + 33];
memcpy(salt, "Bitcoin Secure Message", 22); memcpy(salt, "Bitcoin Secure Message", 22);
memcpy(salt + 22, nonce, 33); memcpy(salt + 22, nonce, 33);
pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes, 80); pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes,
80);
// encrypt payload // encrypt payload
aes_encrypt_ctx ctx; aes_encrypt_ctx ctx;
aes_encrypt_key256(keying_bytes, &ctx); aes_encrypt_key256(keying_bytes, &ctx);
aes_cfb_encrypt(payload, payload, *payload_len, keying_bytes + 64, &ctx); aes_cfb_encrypt(payload, payload, *payload_len, keying_bytes + 64,
&ctx);
// compute hmac // compute hmac
uint8_t out[32]; uint8_t out[32];
hmac_sha256(keying_bytes + 32, 32, payload, *payload_len, out); hmac_sha256(keying_bytes + 32, 32, payload, *payload_len, out);
@ -275,7 +290,10 @@ int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_siz
return 0; return 0;
} }
int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_len, const uint8_t *hmac, size_t hmac_len, const uint8_t *privkey, uint8_t *msg, size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw) int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t
payload_len, const uint8_t *hmac, size_t hmac_len, const uint8_t *privkey,
uint8_t *msg, size_t *msg_len, bool *display_only, bool *signing, uint8_t
*address_raw)
{ {
if (hmac_len != 8) { if (hmac_len != 8) {
return 1; return 1;
@ -294,7 +312,8 @@ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_le
memcpy(salt, "Bitcoin Secure Message", 22); memcpy(salt, "Bitcoin Secure Message", 22);
salt[22] = 0x02 | (nonce->y.val[0] & 0x01); salt[22] = 0x02 | (nonce->y.val[0] & 0x01);
bn_write_be(&(nonce->x), salt + 23); bn_write_be(&(nonce->x), salt + 23);
pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes, 80); pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes,
80);
// compute hmac // compute hmac
uint8_t out[32]; uint8_t out[32];
hmac_sha256(keying_bytes + 32, 32, payload, payload_len, out); hmac_sha256(keying_bytes + 32, 32, payload, payload_len, out);
@ -306,8 +325,8 @@ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_le
aes_encrypt_key256(keying_bytes, &ctx); aes_encrypt_key256(keying_bytes, &ctx);
aes_cfb_decrypt(payload, payload, payload_len, keying_bytes + 64, &ctx); aes_cfb_decrypt(payload, payload, payload_len, keying_bytes + 64, &ctx);
// check first byte // check first byte
if (payload[0] != 0x00 && payload[0] != 0x01 && payload[0] != 0x80 && payload[0] != 0x81) { if (payload[0] != 0x00 && payload[0] != 0x01 && payload[0] != 0x80 &&
return 3; payload[0] != 0x81) { return 3;
} }
*signing = payload[0] & 0x01; *signing = payload[0] & 0x01;
*display_only = payload[0] & 0x80; *display_only = payload[0] & 0x80;
@ -318,9 +337,9 @@ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_le
if (1 + l + o + 21 + 65 != payload_len) { if (1 + l + o + 21 + 65 != payload_len) {
return 4; return 4;
} }
// FIXME: cryptoMessageVerify changed to take the address_type as a parameter. // FIXME: cryptoMessageVerify changed to take the address_type
if (cryptoMessageVerify(payload + 1 + l, o, payload + 1 + l + o, payload + 1 + l + o + 21) != 0) { as a parameter. if (cryptoMessageVerify(payload + 1 + l, o, payload + 1 + l + o,
return 5; payload + 1 + l + o + 21) != 0) { return 5;
} }
memcpy(address_raw, payload + 1 + l + o, 21); memcpy(address_raw, payload + 1 + l + o, 21);
} else { } else {
@ -334,8 +353,9 @@ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_le
} }
*/ */
const HDNode *cryptoMultisigPubkey(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint32_t index) const HDNode *cryptoMultisigPubkey(const CoinInfo *coin,
{ const MultisigRedeemScriptType *multisig,
uint32_t index) {
const HDNodeType *node_ptr; const HDNodeType *node_ptr;
const uint32_t *address_n; const uint32_t *address_n;
uint32_t address_n_count; uint32_t address_n_count;
@ -346,8 +366,7 @@ const HDNode *cryptoMultisigPubkey(const CoinInfo *coin, const MultisigRedeemScr
node_ptr = &(multisig->nodes[index]); node_ptr = &(multisig->nodes[index]);
address_n = multisig->address_n; address_n = multisig->address_n;
address_n_count = multisig->address_n_count; address_n_count = multisig->address_n_count;
} else } else if (multisig->pubkeys_count) { // use multisig->pubkeys
if (multisig->pubkeys_count) { // use multisig->pubkeys
if (index >= multisig->pubkeys_count) { if (index >= multisig->pubkeys_count) {
return 0; return 0;
} }
@ -360,7 +379,9 @@ const HDNode *cryptoMultisigPubkey(const CoinInfo *coin, const MultisigRedeemScr
if (node_ptr->chain_code.size != 32) return 0; if (node_ptr->chain_code.size != 32) return 0;
if (!node_ptr->has_public_key || node_ptr->public_key.size != 33) return 0; if (!node_ptr->has_public_key || node_ptr->public_key.size != 33) return 0;
static HDNode node; static HDNode node;
if (!hdnode_from_xpub(node_ptr->depth, node_ptr->child_num, node_ptr->chain_code.bytes, node_ptr->public_key.bytes, coin->curve_name, &node)) { if (!hdnode_from_xpub(node_ptr->depth, node_ptr->child_num,
node_ptr->chain_code.bytes, node_ptr->public_key.bytes,
coin->curve_name, &node)) {
return 0; return 0;
} }
layoutProgressUpdate(true); layoutProgressUpdate(true);
@ -373,13 +394,14 @@ const HDNode *cryptoMultisigPubkey(const CoinInfo *coin, const MultisigRedeemScr
return &node; return &node;
} }
uint32_t cryptoMultisigPubkeyCount(const MultisigRedeemScriptType *multisig) uint32_t cryptoMultisigPubkeyCount(const MultisigRedeemScriptType *multisig) {
{ return multisig->nodes_count ? multisig->nodes_count
return multisig->nodes_count ? multisig->nodes_count : multisig->pubkeys_count; : multisig->pubkeys_count;
} }
int cryptoMultisigPubkeyIndex(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, const uint8_t *pubkey) int cryptoMultisigPubkeyIndex(const CoinInfo *coin,
{ const MultisigRedeemScriptType *multisig,
const uint8_t *pubkey) {
for (size_t i = 0; i < cryptoMultisigPubkeyCount(multisig); i++) { for (size_t i = 0; i < cryptoMultisigPubkeyCount(multisig); i++) {
const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i); const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i);
if (pubnode && memcmp(pubnode->public_key, pubkey, 33) == 0) { if (pubnode && memcmp(pubnode->public_key, pubkey, 33) == 0) {
@ -389,8 +411,8 @@ int cryptoMultisigPubkeyIndex(const CoinInfo *coin, const MultisigRedeemScriptTy
return -1; return -1;
} }
int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t *hash) int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig,
{ uint8_t *hash) {
static const HDNodeType *pubnodes[15], *swap; static const HDNodeType *pubnodes[15], *swap;
const uint32_t n = cryptoMultisigPubkeyCount(multisig); const uint32_t n = cryptoMultisigPubkeyCount(multisig);
if (n < 1 || n > 15) { if (n < 1 || n > 15) {
@ -402,21 +424,22 @@ int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t
for (uint32_t i = 0; i < n; i++) { for (uint32_t i = 0; i < n; i++) {
if (multisig->nodes_count) { // use multisig->nodes if (multisig->nodes_count) { // use multisig->nodes
pubnodes[i] = &(multisig->nodes[i]); pubnodes[i] = &(multisig->nodes[i]);
} else } else if (multisig->pubkeys_count) { // use multisig->pubkeys
if (multisig->pubkeys_count) { // use multisig->pubkeys
pubnodes[i] = &(multisig->pubkeys[i].node); pubnodes[i] = &(multisig->pubkeys[i].node);
} else { } else {
return 0; return 0;
} }
} }
for (uint32_t i = 0; i < n; i++) { for (uint32_t i = 0; i < n; i++) {
if (!pubnodes[i]->has_public_key || pubnodes[i]->public_key.size != 33) return 0; if (!pubnodes[i]->has_public_key || pubnodes[i]->public_key.size != 33)
return 0;
if (pubnodes[i]->chain_code.size != 32) return 0; if (pubnodes[i]->chain_code.size != 32) return 0;
} }
// minsort according to pubkey // minsort according to pubkey
for (uint32_t i = 0; i < n - 1; i++) { for (uint32_t i = 0; i < n - 1; i++) {
for (uint32_t j = n - 1; j > i; j--) { for (uint32_t j = n - 1; j > i; j--) {
if (memcmp(pubnodes[i]->public_key.bytes, pubnodes[j]->public_key.bytes, 33) > 0) { if (memcmp(pubnodes[i]->public_key.bytes, pubnodes[j]->public_key.bytes,
33) > 0) {
swap = pubnodes[i]; swap = pubnodes[i];
pubnodes[i] = pubnodes[j]; pubnodes[i] = pubnodes[j];
pubnodes[j] = swap; pubnodes[j] = swap;
@ -428,9 +451,12 @@ int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t
sha256_Init(&ctx); sha256_Init(&ctx);
sha256_Update(&ctx, (const uint8_t *)&(multisig->m), sizeof(uint32_t)); sha256_Update(&ctx, (const uint8_t *)&(multisig->m), sizeof(uint32_t));
for (uint32_t i = 0; i < n; i++) { for (uint32_t i = 0; i < n; i++) {
sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->depth), sizeof(uint32_t)); sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->depth),
sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->fingerprint), sizeof(uint32_t)); sizeof(uint32_t));
sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->child_num), sizeof(uint32_t)); sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->fingerprint),
sizeof(uint32_t));
sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->child_num),
sizeof(uint32_t));
sha256_Update(&ctx, pubnodes[i]->chain_code.bytes, 32); sha256_Update(&ctx, pubnodes[i]->chain_code.bytes, 32);
sha256_Update(&ctx, pubnodes[i]->public_key.bytes, 33); sha256_Update(&ctx, pubnodes[i]->public_key.bytes, 33);
} }
@ -440,28 +466,32 @@ int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t
return 1; return 1;
} }
int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash) int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash) {
{
SHA256_CTX ctx; SHA256_CTX ctx;
sha256_Init(&ctx); sha256_Init(&ctx);
sha256_Update(&ctx, (const uint8_t *)&(identity->index), sizeof(uint32_t)); sha256_Update(&ctx, (const uint8_t *)&(identity->index), sizeof(uint32_t));
if (identity->has_proto && identity->proto[0]) { if (identity->has_proto && identity->proto[0]) {
sha256_Update(&ctx, (const uint8_t *)(identity->proto), strlen(identity->proto)); sha256_Update(&ctx, (const uint8_t *)(identity->proto),
strlen(identity->proto));
sha256_Update(&ctx, (const uint8_t *)"://", 3); sha256_Update(&ctx, (const uint8_t *)"://", 3);
} }
if (identity->has_user && identity->user[0]) { if (identity->has_user && identity->user[0]) {
sha256_Update(&ctx, (const uint8_t *)(identity->user), strlen(identity->user)); sha256_Update(&ctx, (const uint8_t *)(identity->user),
strlen(identity->user));
sha256_Update(&ctx, (const uint8_t *)"@", 1); sha256_Update(&ctx, (const uint8_t *)"@", 1);
} }
if (identity->has_host && identity->host[0]) { if (identity->has_host && identity->host[0]) {
sha256_Update(&ctx, (const uint8_t *)(identity->host), strlen(identity->host)); sha256_Update(&ctx, (const uint8_t *)(identity->host),
strlen(identity->host));
} }
if (identity->has_port && identity->port[0]) { if (identity->has_port && identity->port[0]) {
sha256_Update(&ctx, (const uint8_t *)":", 1); sha256_Update(&ctx, (const uint8_t *)":", 1);
sha256_Update(&ctx, (const uint8_t *)(identity->port), strlen(identity->port)); sha256_Update(&ctx, (const uint8_t *)(identity->port),
strlen(identity->port));
} }
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(&ctx, hash); sha256_Final(&ctx, hash);
return 1; return 1;

View File

@ -20,13 +20,13 @@
#ifndef __CRYPTO_H__ #ifndef __CRYPTO_H__
#define __CRYPTO_H__ #define __CRYPTO_H__
#include <bip32.h>
#include <ecdsa.h>
#include <pb.h>
#include <sha2.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <ecdsa.h>
#include <bip32.h>
#include <sha2.h>
#include <pb.h>
#include "coins.h" #include "coins.h"
#include "hasher.h" #include "hasher.h"
#include "messages-bitcoin.pb.h" #include "messages-bitcoin.pb.h"
@ -38,27 +38,44 @@ uint32_t ser_length(uint32_t len, uint8_t *out);
uint32_t ser_length_hash(Hasher *hasher, uint32_t len); uint32_t ser_length_hash(Hasher *hasher, uint32_t len);
int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len,
uint8_t *signature);
int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature); int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len,
uint8_t *signature);
int cryptoMessageSign(const CoinInfo *coin, HDNode *node, InputScriptType script_type, const uint8_t *message, size_t message_len, uint8_t *signature); int cryptoMessageSign(const CoinInfo *coin, HDNode *node,
InputScriptType script_type, const uint8_t *message,
size_t message_len, uint8_t *signature);
int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t message_len, const char *address, const uint8_t *signature); int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message,
size_t message_len, const char *address,
const uint8_t *signature);
/* ECIES disabled /* ECIES disabled
int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw); int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t
msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t
*payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t
*privkey, const uint8_t *address_raw);
int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_len, const uint8_t *hmac, size_t hmac_len, const uint8_t *privkey, uint8_t *msg, size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw); int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t
payload_len, const uint8_t *hmac, size_t hmac_len, const uint8_t *privkey,
uint8_t *msg, size_t *msg_len, bool *display_only, bool *signing, uint8_t
*address_raw);
*/ */
const HDNode *cryptoMultisigPubkey(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint32_t index); const HDNode *cryptoMultisigPubkey(const CoinInfo *coin,
const MultisigRedeemScriptType *multisig,
uint32_t index);
uint32_t cryptoMultisigPubkeyCount(const MultisigRedeemScriptType *multisig); uint32_t cryptoMultisigPubkeyCount(const MultisigRedeemScriptType *multisig);
int cryptoMultisigPubkeyIndex(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, const uint8_t *pubkey); int cryptoMultisigPubkeyIndex(const CoinInfo *coin,
const MultisigRedeemScriptType *multisig,
const uint8_t *pubkey);
int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t *hash); int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig,
uint8_t *hash);
int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash); int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash);

View File

@ -17,15 +17,14 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "trezor.h"
#include "debug.h" #include "debug.h"
#include "oled.h" #include "oled.h"
#include "trezor.h"
#include "util.h" #include "util.h"
#if DEBUG_LOG #if DEBUG_LOG
void oledDebug(const char *line) void oledDebug(const char *line) {
{
static const char *lines[8] = {0, 0, 0, 0, 0, 0, 0, 0}; static const char *lines[8] = {0, 0, 0, 0, 0, 0, 0, 0};
static char id = 3; static char id = 3;
for (int i = 0; i < 7; i++) { for (int i = 0; i < 7; i++) {
@ -43,8 +42,7 @@ void oledDebug(const char *line)
id = (id + 1) % 10; id = (id + 1) % 10;
} }
void debugLog(int level, const char *bucket, const char *text) void debugLog(int level, const char *bucket, const char *text) {
{
(void)level; (void)level;
(void)bucket; (void)bucket;
#if EMULATOR #if EMULATOR
@ -54,8 +52,7 @@ void debugLog(int level, const char *bucket, const char *text)
#endif #endif
} }
char *debugInt(const uint32_t i) char *debugInt(const uint32_t i) {
{
static uint8_t n = 0; static uint8_t n = 0;
static char id[8][9]; static char id[8][9];
uint32hex(i, id[n]); uint32hex(i, id[n]);

View File

@ -20,8 +20,8 @@
#ifndef __DEBUG_H__ #ifndef __DEBUG_H__
#define __DEBUG_H__ #define __DEBUG_H__
#include "trezor.h"
#include <stdint.h> #include <stdint.h>
#include "trezor.h"
#if DEBUG_LOG #if DEBUG_LOG
@ -30,8 +30,12 @@ char *debugInt(const uint32_t i);
#else #else
#define debugLog(L, B, T) do{}while(0) #define debugLog(L, B, T) \
#define debugInt(I) do{}while(0) do { \
} while (0)
#define debugInt(I) \
do { \
} while (0)
#endif #endif

View File

@ -20,22 +20,22 @@
*/ */
#include "ethereum.h" #include "ethereum.h"
#include "fsm.h" #include "address.h"
#include "layout2.h"
#include "messages.h"
#include "transaction.h"
#include "ecdsa.h"
#include "protect.h"
#include "crypto.h" #include "crypto.h"
#include "ecdsa.h"
#include "ethereum_networks.h"
#include "ethereum_tokens.h"
#include "fsm.h"
#include "gettext.h"
#include "layout2.h"
#include "memzero.h"
#include "messages.h"
#include "messages.pb.h"
#include "protect.h"
#include "secp256k1.h" #include "secp256k1.h"
#include "sha3.h" #include "sha3.h"
#include "address.h" #include "transaction.h"
#include "util.h" #include "util.h"
#include "gettext.h"
#include "ethereum_tokens.h"
#include "ethereum_networks.h"
#include "memzero.h"
#include "messages.pb.h"
/* maximum supported chain id. v must fit in an uint32_t. */ /* maximum supported chain id. v must fit in an uint32_t. */
#define MAX_CHAIN_ID 2147483629 #define MAX_CHAIN_ID 2147483629
@ -48,16 +48,14 @@ static uint32_t chain_id;
static uint32_t tx_type; static uint32_t tx_type;
struct SHA3_CTX keccak_ctx; struct SHA3_CTX keccak_ctx;
static inline void hash_data(const uint8_t *buf, size_t size) static inline void hash_data(const uint8_t *buf, size_t size) {
{
sha3_Update(&keccak_ctx, buf, size); sha3_Update(&keccak_ctx, buf, size);
} }
/* /*
* Push an RLP encoded length to the hash buffer. * Push an RLP encoded length to the hash buffer.
*/ */
static void hash_rlp_length(uint32_t length, uint8_t firstbyte) static void hash_rlp_length(uint32_t length, uint8_t firstbyte) {
{
uint8_t buf[4]; uint8_t buf[4];
if (length == 1 && firstbyte <= 0x7f) { if (length == 1 && firstbyte <= 0x7f) {
/* empty length header */ /* empty length header */
@ -85,8 +83,7 @@ static void hash_rlp_length(uint32_t length, uint8_t firstbyte)
/* /*
* Push an RLP encoded list length to the hash buffer. * Push an RLP encoded list length to the hash buffer.
*/ */
static void hash_rlp_list_length(uint32_t length) static void hash_rlp_list_length(uint32_t length) {
{
uint8_t buf[4]; uint8_t buf[4];
if (length <= 55) { if (length <= 55) {
buf[0] = 0xc0 + length; buf[0] = 0xc0 + length;
@ -112,8 +109,7 @@ static void hash_rlp_list_length(uint32_t length)
/* /*
* Push an RLP encoded length field and data to the hash buffer. * Push an RLP encoded length field and data to the hash buffer.
*/ */
static void hash_rlp_field(const uint8_t *buf, size_t size) static void hash_rlp_field(const uint8_t *buf, size_t size) {
{
hash_rlp_length(size, buf[0]); hash_rlp_length(size, buf[0]);
hash_data(buf, size); hash_data(buf, size);
} }
@ -122,8 +118,7 @@ static void hash_rlp_field(const uint8_t *buf, size_t size)
* Push an RLP encoded number to the hash buffer. * Push an RLP encoded number to the hash buffer.
* Ethereum yellow paper says to convert to big endian and strip leading zeros. * Ethereum yellow paper says to convert to big endian and strip leading zeros.
*/ */
static void hash_rlp_number(uint32_t number) static void hash_rlp_number(uint32_t number) {
{
if (!number) { if (!number) {
return; return;
} }
@ -144,8 +139,7 @@ static void hash_rlp_number(uint32_t number)
* NOTE: supports up to 16MB of data (how unlikely...) * NOTE: supports up to 16MB of data (how unlikely...)
* FIXME: improve * FIXME: improve
*/ */
static int rlp_calculate_length(int length, uint8_t firstbyte) static int rlp_calculate_length(int length, uint8_t firstbyte) {
{
if (length == 1 && firstbyte <= 0x7f) { if (length == 1 && firstbyte <= 0x7f) {
return 1; return 1;
} else if (length <= 55) { } else if (length <= 55) {
@ -159,28 +153,22 @@ static int rlp_calculate_length(int length, uint8_t firstbyte)
} }
} }
static int rlp_calculate_number_length(uint32_t number) static int rlp_calculate_number_length(uint32_t number) {
{
if (number <= 0x7f) { if (number <= 0x7f) {
return 1; return 1;
} } else if (number <= 0xff) {
else if (number <= 0xff) {
return 2; return 2;
} } else if (number <= 0xffff) {
else if (number <= 0xffff) {
return 3; return 3;
} } else if (number <= 0xffffff) {
else if (number <= 0xffffff) {
return 4; return 4;
} else { } else {
return 5; return 5;
} }
} }
static void send_request_chunk(void) static void send_request_chunk(void) {
{ int progress = 1000 - (data_total > 1000000 ? data_left / (data_total / 800)
int progress = 1000 - (data_total > 1000000
? data_left / (data_total/800)
: data_left * 800 / data_total); : data_left * 800 / data_total);
layoutProgress(_("Signing"), progress); layoutProgress(_("Signing"), progress);
msg_tx_request.has_data_length = true; msg_tx_request.has_data_length = true;
@ -188,14 +176,12 @@ static void send_request_chunk(void)
msg_write(MessageType_MessageType_EthereumTxRequest, &msg_tx_request); msg_write(MessageType_MessageType_EthereumTxRequest, &msg_tx_request);
} }
static int ethereum_is_canonic(uint8_t v, uint8_t signature[64]) static int ethereum_is_canonic(uint8_t v, uint8_t signature[64]) {
{
(void)signature; (void)signature;
return (v & 2) == 0; return (v & 2) == 0;
} }
static void send_signature(void) static void send_signature(void) {
{
uint8_t hash[32], sig[64]; uint8_t hash[32], sig[64];
uint8_t v; uint8_t v;
layoutProgress(_("Signing"), 1000); layoutProgress(_("Signing"), 1000);
@ -209,7 +195,8 @@ static void send_signature(void)
} }
keccak_Final(&keccak_ctx, hash); keccak_Final(&keccak_ctx, hash);
if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v, ethereum_is_canonic) != 0) { if (ecdsa_sign_digest(&secp256k1, privkey, hash, sig, &v,
ethereum_is_canonic) != 0) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed"));
ethereum_signing_abort(); ethereum_signing_abort();
return; return;
@ -245,8 +232,8 @@ static void send_signature(void)
* using standard ethereum units. * using standard ethereum units.
* The buffer must be at least 25 bytes. * The buffer must be at least 25 bytes.
*/ */
static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token, char *buf, int buflen) static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token,
{ char *buf, int buflen) {
bignum256 bn1e9; bignum256 bn1e9;
bn_read_uint32(1000000000, &bn1e9); bn_read_uint32(1000000000, &bn1e9);
const char *suffix = NULL; const char *suffix = NULL;
@ -254,12 +241,10 @@ static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token,
if (token == UnknownToken) { if (token == UnknownToken) {
strlcpy(buf, "Unknown token value", buflen); strlcpy(buf, "Unknown token value", buflen);
return; return;
} else } else if (token != NULL) {
if (token != NULL) {
suffix = token->ticker; suffix = token->ticker;
decimals = token->decimals; decimals = token->decimals;
} else } else if (bn_is_less(amnt, &bn1e9)) {
if (bn_is_less(amnt, &bn1e9)) {
suffix = " Wei"; suffix = " Wei";
decimals = 0; decimals = 0;
} else { } else {
@ -272,8 +257,9 @@ static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token,
bn_format(amnt, NULL, suffix, decimals, 0, false, buf, buflen); bn_format(amnt, NULL, suffix, decimals, 0, false, buf, buflen);
} }
static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, const uint8_t *value, uint32_t value_len, const TokenType *token) static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len,
{ const uint8_t *value, uint32_t value_len,
const TokenType *token) {
bignum256 val; bignum256 val;
uint8_t pad_val[32]; uint8_t pad_val[32];
memzero(pad_val, sizeof(pad_val)); memzero(pad_val, sizeof(pad_val));
@ -301,8 +287,12 @@ static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, const ui
bool rskip60 = false; bool rskip60 = false;
// constants from trezor-common/defs/ethereum/networks.json // constants from trezor-common/defs/ethereum/networks.json
switch (chain_id) { switch (chain_id) {
case 30: rskip60 = true; break; case 30:
case 31: rskip60 = true; break; rskip60 = true;
break;
case 31:
rskip60 = true;
break;
} }
ethereum_address_checksum(to, to_str, rskip60, chain_id); ethereum_address_checksum(to, to_str, rskip60, chain_id);
@ -315,21 +305,12 @@ static void layoutEthereumConfirmTx(const uint8_t *to, uint32_t to_len, const ui
strlcpy(_to3, "", sizeof(_to3)); strlcpy(_to3, "", sizeof(_to3));
} }
layoutDialogSwipe(&bmp_icon_question, layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Cancel"), _("Send"), amount, _to1, _to2, _to3, NULL);
_("Confirm"),
NULL,
_("Send"),
amount,
_to1,
_to2,
_to3,
NULL
);
} }
static void layoutEthereumData(const uint8_t *data, uint32_t len, uint32_t total_len) static void layoutEthereumData(const uint8_t *data, uint32_t len,
{ uint32_t total_len) {
char hexdata[3][17]; char hexdata[3][17];
char summary[20]; char summary[20];
uint32_t printed = 0; uint32_t printed = 0;
@ -351,27 +332,17 @@ static void layoutEthereumData(const uint8_t *data, uint32_t len, uint32_t total
number = number / 10; number = number / 10;
} }
char *summarystart = summary; char *summarystart = summary;
if (total_len == printed) if (total_len == printed) summarystart = summary + 4;
summarystart = summary + 4;
layoutDialogSwipe(&bmp_icon_question, layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Cancel"), _("Transaction data:"), hexdata[0], hexdata[1], hexdata[2],
_("Confirm"), summarystart, NULL);
NULL,
_("Transaction data:"),
hexdata[0],
hexdata[1],
hexdata[2],
summarystart,
NULL
);
} }
static void layoutEthereumFee(const uint8_t *value, uint32_t value_len, static void layoutEthereumFee(const uint8_t *value, uint32_t value_len,
const uint8_t *gas_price, uint32_t gas_price_len, const uint8_t *gas_price, uint32_t gas_price_len,
const uint8_t *gas_limit, uint32_t gas_limit_len, const uint8_t *gas_limit, uint32_t gas_limit_len,
bool is_token) bool is_token) {
{
bignum256 val, gas; bignum256 val, gas;
uint8_t pad_val[32]; uint8_t pad_val[32];
char tx_value[32]; char tx_value[32];
@ -401,17 +372,9 @@ static void layoutEthereumFee(const uint8_t *value, uint32_t value_len,
ethereumFormatAmount(&val, NULL, tx_value, sizeof(tx_value)); ethereumFormatAmount(&val, NULL, tx_value, sizeof(tx_value));
} }
layoutDialogSwipe(&bmp_icon_question, layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Cancel"), _("Really send"), tx_value, _("paying up to"), gas_value,
_("Confirm"), _("for gas?"), NULL);
NULL,
_("Really send"),
tx_value,
_("paying up to"),
gas_value,
_("for gas?"),
NULL
);
} }
/* /*
@ -424,8 +387,7 @@ static void layoutEthereumFee(const uint8_t *value, uint32_t value_len,
* - data (0 ..) * - data (0 ..)
*/ */
static bool ethereum_signing_check(const EthereumSignTx *msg) static bool ethereum_signing_check(const EthereumSignTx *msg) {
{
if (!msg->has_gas_price || !msg->has_gas_limit) { if (!msg->has_gas_price || !msg->has_gas_limit) {
return false; return false;
} }
@ -450,17 +412,14 @@ static bool ethereum_signing_check(const EthereumSignTx *msg)
return true; return true;
} }
void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) {
{
ethereum_signing = true; ethereum_signing = true;
sha3_256_Init(&keccak_ctx); sha3_256_Init(&keccak_ctx);
memzero(&msg_tx_request, sizeof(EthereumTxRequest)); memzero(&msg_tx_request, sizeof(EthereumTxRequest));
/* set fields to 0, to avoid conditions later */ /* set fields to 0, to avoid conditions later */
if (!msg->has_value) if (!msg->has_value) msg->value.size = 0;
msg->value.size = 0; if (!msg->has_data_initial_chunk) msg->data_initial_chunk.size = 0;
if (!msg->has_data_initial_chunk)
msg->data_initial_chunk.size = 0;
bool toset; bool toset;
uint8_t pubkeyhash[20]; uint8_t pubkeyhash[20];
if (msg->has_to && ethereum_parse(msg->to, pubkeyhash)) { if (msg->has_to && ethereum_parse(msg->to, pubkeyhash)) {
@ -470,13 +429,13 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node)
toset = false; toset = false;
memzero(pubkeyhash, sizeof(pubkeyhash)); memzero(pubkeyhash, sizeof(pubkeyhash));
} }
if (!msg->has_nonce) if (!msg->has_nonce) msg->nonce.size = 0;
msg->nonce.size = 0;
/* eip-155 chain id */ /* eip-155 chain id */
if (msg->has_chain_id) { if (msg->has_chain_id) {
if (msg->chain_id < 1) { if (msg->chain_id < 1) {
fsm_sendFailure(FailureType_Failure_DataError, _("Chain Id out of bounds")); fsm_sendFailure(FailureType_Failure_DataError,
_("Chain Id out of bounds"));
ethereum_signing_abort(); ethereum_signing_abort();
return; return;
} }
@ -500,7 +459,8 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node)
if (msg->has_data_length && msg->data_length > 0) { if (msg->has_data_length && msg->data_length > 0) {
if (!msg->has_data_initial_chunk || msg->data_initial_chunk.size == 0) { if (!msg->has_data_initial_chunk || msg->data_initial_chunk.size == 0) {
fsm_sendFailure(FailureType_Failure_DataError, _("Data length provided, but no initial chunk")); fsm_sendFailure(FailureType_Failure_DataError,
_("Data length provided, but no initial chunk"));
ethereum_signing_abort(); ethereum_signing_abort();
return; return;
} }
@ -508,7 +468,8 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node)
* prevent exceeding the limit we use a stricter limit on data length. * prevent exceeding the limit we use a stricter limit on data length.
*/ */
if (msg->data_length > 16000000) { if (msg->data_length > 16000000) {
fsm_sendFailure(FailureType_Failure_DataError, _("Data length exceeds limit")); fsm_sendFailure(FailureType_Failure_DataError,
_("Data length exceeds limit"));
ethereum_signing_abort(); ethereum_signing_abort();
return; return;
} }
@ -517,7 +478,8 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node)
data_total = 0; data_total = 0;
} }
if (msg->data_initial_chunk.size > data_total) { if (msg->data_initial_chunk.size > data_total) {
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid size of initial chunk")); fsm_sendFailure(FailureType_Failure_DataError,
_("Invalid size of initial chunk"));
ethereum_signing_abort(); ethereum_signing_abort();
return; return;
} }
@ -532,15 +494,20 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node)
const TokenType *token = NULL; const TokenType *token = NULL;
// detect ERC-20 token // detect ERC-20 token
if (toset && msg->value.size == 0 && data_total == 68 && msg->data_initial_chunk.size == 68 if (toset && msg->value.size == 0 && data_total == 68 &&
&& memcmp(msg->data_initial_chunk.bytes, "\xa9\x05\x9c\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16) == 0) { msg->data_initial_chunk.size == 68 &&
memcmp(msg->data_initial_chunk.bytes,
"\xa9\x05\x9c\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
16) == 0) {
token = tokenByChainAddress(chain_id, pubkeyhash); token = tokenByChainAddress(chain_id, pubkeyhash);
} }
if (token != NULL) { if (token != NULL) {
layoutEthereumConfirmTx(msg->data_initial_chunk.bytes + 16, 20, msg->data_initial_chunk.bytes + 36, 32, token); layoutEthereumConfirmTx(msg->data_initial_chunk.bytes + 16, 20,
msg->data_initial_chunk.bytes + 36, 32, token);
} else { } else {
layoutEthereumConfirmTx(pubkeyhash, 20, msg->value.bytes, msg->value.size, NULL); layoutEthereumConfirmTx(pubkeyhash, 20, msg->value.bytes, msg->value.size,
NULL);
} }
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
@ -550,7 +517,8 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node)
} }
if (token == NULL && data_total > 0) { if (token == NULL && data_total > 0) {
layoutEthereumData(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size, data_total); layoutEthereumData(msg->data_initial_chunk.bytes,
msg->data_initial_chunk.size, data_total);
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
ethereum_signing_abort(); ethereum_signing_abort();
@ -558,9 +526,9 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node)
} }
} }
layoutEthereumFee(msg->value.bytes, msg->value.size, layoutEthereumFee(msg->value.bytes, msg->value.size, msg->gas_price.bytes,
msg->gas_price.bytes, msg->gas_price.size, msg->gas_price.size, msg->gas_limit.bytes,
msg->gas_limit.bytes, msg->gas_limit.size, token != NULL); msg->gas_limit.size, token != NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
ethereum_signing_abort(); ethereum_signing_abort();
@ -573,11 +541,14 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node)
layoutProgress(_("Signing"), 0); layoutProgress(_("Signing"), 0);
rlp_length += rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]); rlp_length += rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]);
rlp_length += rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]); rlp_length +=
rlp_length += rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]); rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]);
rlp_length +=
rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]);
rlp_length += rlp_calculate_length(toset ? 20 : 0, pubkeyhash[0]); rlp_length += rlp_calculate_length(toset ? 20 : 0, pubkeyhash[0]);
rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]); rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]);
rlp_length += rlp_calculate_length(data_total, msg->data_initial_chunk.bytes[0]); rlp_length +=
rlp_calculate_length(data_total, msg->data_initial_chunk.bytes[0]);
if (tx_type) { if (tx_type) {
rlp_length += rlp_calculate_number_length(tx_type); rlp_length += rlp_calculate_number_length(tx_type);
} }
@ -613,10 +584,10 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node)
} }
} }
void ethereum_signing_txack(const EthereumTxAck *tx) void ethereum_signing_txack(const EthereumTxAck *tx) {
{
if (!ethereum_signing) { if (!ethereum_signing) {
fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Ethereum signing mode")); fsm_sendFailure(FailureType_Failure_UnexpectedMessage,
_("Not in Ethereum signing mode"));
layoutHome(); layoutHome();
return; return;
} }
@ -628,7 +599,8 @@ void ethereum_signing_txack(const EthereumTxAck *tx)
} }
if (data_left > 0 && (!tx->has_data_chunk || tx->data_chunk.size == 0)) { if (data_left > 0 && (!tx->has_data_chunk || tx->data_chunk.size == 0)) {
fsm_sendFailure(FailureType_Failure_DataError, _("Empty data chunk received")); fsm_sendFailure(FailureType_Failure_DataError,
_("Empty data chunk received"));
ethereum_signing_abort(); ethereum_signing_abort();
return; return;
} }
@ -644,8 +616,7 @@ void ethereum_signing_txack(const EthereumTxAck *tx)
} }
} }
void ethereum_signing_abort(void) void ethereum_signing_abort(void) {
{
if (ethereum_signing) { if (ethereum_signing) {
memzero(privkey, sizeof(privkey)); memzero(privkey, sizeof(privkey));
layoutHome(); layoutHome();
@ -653,28 +624,56 @@ void ethereum_signing_abort(void)
} }
} }
static void ethereum_message_hash(const uint8_t *message, size_t message_len, uint8_t hash[32]) static void ethereum_message_hash(const uint8_t *message, size_t message_len,
{ uint8_t hash[32]) {
struct SHA3_CTX ctx; struct SHA3_CTX ctx;
sha3_256_Init(&ctx); sha3_256_Init(&ctx);
sha3_Update(&ctx, (const uint8_t *)"\x19" "Ethereum Signed Message:\n", 26); sha3_Update(&ctx, (const uint8_t *)"\x19" "Ethereum Signed Message:\n", 26);
uint8_t c; uint8_t c;
if (message_len > 1000000000) { c = '0' + message_len / 1000000000 % 10; sha3_Update(&ctx, &c, 1); } if (message_len > 1000000000) {
if (message_len > 100000000) { c = '0' + message_len / 100000000 % 10; sha3_Update(&ctx, &c, 1); } c = '0' + message_len / 1000000000 % 10;
if (message_len > 10000000) { c = '0' + message_len / 10000000 % 10; sha3_Update(&ctx, &c, 1); } sha3_Update(&ctx, &c, 1);
if (message_len > 1000000) { c = '0' + message_len / 1000000 % 10; sha3_Update(&ctx, &c, 1); } }
if (message_len > 100000) { c = '0' + message_len / 100000 % 10; sha3_Update(&ctx, &c, 1); } if (message_len > 100000000) {
if (message_len > 10000) { c = '0' + message_len / 10000 % 10; sha3_Update(&ctx, &c, 1); } c = '0' + message_len / 100000000 % 10;
if (message_len > 1000) { c = '0' + message_len / 1000 % 10; sha3_Update(&ctx, &c, 1); } sha3_Update(&ctx, &c, 1);
if (message_len > 100) { c = '0' + message_len / 100 % 10; sha3_Update(&ctx, &c, 1); } }
if (message_len > 10) { c = '0' + message_len / 10 % 10; sha3_Update(&ctx, &c, 1); } if (message_len > 10000000) {
c = '0' + message_len % 10; sha3_Update(&ctx, &c, 1); c = '0' + message_len / 10000000 % 10;
sha3_Update(&ctx, &c, 1);
}
if (message_len > 1000000) {
c = '0' + message_len / 1000000 % 10;
sha3_Update(&ctx, &c, 1);
}
if (message_len > 100000) {
c = '0' + message_len / 100000 % 10;
sha3_Update(&ctx, &c, 1);
}
if (message_len > 10000) {
c = '0' + message_len / 10000 % 10;
sha3_Update(&ctx, &c, 1);
}
if (message_len > 1000) {
c = '0' + message_len / 1000 % 10;
sha3_Update(&ctx, &c, 1);
}
if (message_len > 100) {
c = '0' + message_len / 100 % 10;
sha3_Update(&ctx, &c, 1);
}
if (message_len > 10) {
c = '0' + message_len / 10 % 10;
sha3_Update(&ctx, &c, 1);
}
c = '0' + message_len % 10;
sha3_Update(&ctx, &c, 1);
sha3_Update(&ctx, message, message_len); sha3_Update(&ctx, message, message_len);
keccak_Final(&ctx, hash); keccak_Final(&ctx, hash);
} }
void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node, EthereumMessageSignature *resp) void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node,
{ EthereumMessageSignature *resp) {
uint8_t pubkeyhash[20]; uint8_t pubkeyhash[20];
if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash)) { if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash)) {
return; return;
@ -690,7 +689,8 @@ void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node, E
ethereum_message_hash(msg->message.bytes, msg->message.size, hash); ethereum_message_hash(msg->message.bytes, msg->message.size, hash);
uint8_t v; uint8_t v;
if (ecdsa_sign_digest(&secp256k1, node->private_key, hash, resp->signature.bytes, &v, ethereum_is_canonic) != 0) { if (ecdsa_sign_digest(&secp256k1, node->private_key, hash,
resp->signature.bytes, &v, ethereum_is_canonic) != 0) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed")); fsm_sendFailure(FailureType_Failure_ProcessError, _("Signing failed"));
return; return;
} }
@ -701,8 +701,7 @@ void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node, E
msg_write(MessageType_MessageType_EthereumMessageSignature, resp); msg_write(MessageType_MessageType_EthereumMessageSignature, resp);
} }
int ethereum_message_verify(const EthereumVerifyMessage *msg) int ethereum_message_verify(const EthereumVerifyMessage *msg) {
{
if (msg->signature.size != 65) { if (msg->signature.size != 65) {
fsm_sendFailure(FailureType_Failure_DataError, _("Malformed signature")); fsm_sendFailure(FailureType_Failure_DataError, _("Malformed signature"));
return 1; return 1;
@ -726,8 +725,8 @@ int ethereum_message_verify(const EthereumVerifyMessage *msg)
if (v >= 27) { if (v >= 27) {
v -= 27; v -= 27;
} }
if (v >= 2 || if (v >= 2 || ecdsa_recover_pub_from_sig(
ecdsa_recover_pub_from_sig(&secp256k1, pubkey, msg->signature.bytes, hash, v) != 0) { &secp256k1, pubkey, msg->signature.bytes, hash, v) != 0) {
return 2; return 2;
} }
@ -743,14 +742,12 @@ int ethereum_message_verify(const EthereumVerifyMessage *msg)
return 0; return 0;
} }
bool ethereum_parse(const char *address, uint8_t pubkeyhash[20]) bool ethereum_parse(const char *address, uint8_t pubkeyhash[20]) {
{
memzero(pubkeyhash, 20); memzero(pubkeyhash, 20);
size_t len = strlen(address); size_t len = strlen(address);
if (len == 40) { if (len == 40) {
// do nothing // do nothing
} else } else if (len == 42) {
if (len == 42) {
// check for "0x" prefix and strip it when required // check for "0x" prefix and strip it when required
if (address[0] != '0') return false; if (address[0] != '0') return false;
if (address[1] != 'x' && address[1] != 'X') return false; if (address[1] != 'x' && address[1] != 'X') return false;
@ -762,11 +759,9 @@ bool ethereum_parse(const char *address, uint8_t pubkeyhash[20])
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) {
if (address[i] >= '0' && address[i] <= '9') { if (address[i] >= '0' && address[i] <= '9') {
pubkeyhash[i / 2] |= (address[i] - '0') << ((1 - (i % 2)) * 4); pubkeyhash[i / 2] |= (address[i] - '0') << ((1 - (i % 2)) * 4);
} else } else if (address[i] >= 'a' && address[i] <= 'f') {
if (address[i] >= 'a' && address[i] <= 'f') {
pubkeyhash[i / 2] |= ((address[i] - 'a') + 10) << ((1 - (i % 2)) * 4); pubkeyhash[i / 2] |= ((address[i] - 'a') + 10) << ((1 - (i % 2)) * 4);
} else } else if (address[i] >= 'A' && address[i] <= 'F') {
if (address[i] >= 'A' && address[i] <= 'F') {
pubkeyhash[i / 2] |= ((address[i] - 'A') + 10) << ((1 - (i % 2)) * 4); pubkeyhash[i / 2] |= ((address[i] - 'A') + 10) << ((1 - (i % 2)) * 4);
} else { } else {
return false; return false;

View File

@ -20,8 +20,8 @@
#ifndef __ETHEREUM_H__ #ifndef __ETHEREUM_H__
#define __ETHEREUM_H__ #define __ETHEREUM_H__
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include "bip32.h" #include "bip32.h"
#include "messages-ethereum.pb.h" #include "messages-ethereum.pb.h"
@ -29,7 +29,8 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node);
void ethereum_signing_abort(void); void ethereum_signing_abort(void);
void ethereum_signing_txack(const EthereumTxAck *msg); void ethereum_signing_txack(const EthereumTxAck *msg);
void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node, EthereumMessageSignature *resp); void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node,
EthereumMessageSignature *resp);
int ethereum_message_verify(const EthereumVerifyMessage *msg); int ethereum_message_verify(const EthereumVerifyMessage *msg);
bool ethereum_parse(const char *address, uint8_t pubkeyhash[20]); bool ethereum_parse(const char *address, uint8_t pubkeyhash[20]);

View File

@ -19,45 +19,44 @@
#include <libopencm3/stm32/flash.h> #include <libopencm3/stm32/flash.h>
#include "trezor.h"
#include "fsm.h"
#include "messages.h"
#include "bip32.h"
#include "config.h"
#include "coins.h"
#include "debug.h"
#include "transaction.h"
#include "rng.h"
#include "oled.h"
#include "protect.h"
#include "pinmatrix.h"
#include "layout2.h"
#include "address.h" #include "address.h"
#include "base58.h"
#include "ecdsa.h"
#include "reset.h"
#include "recovery.h"
#include "memory.h"
#include "usb.h"
#include "util.h"
#include "signing.h"
#include "aes/aes.h" #include "aes/aes.h"
#include "hmac.h"
#include "crypto.h"
#include "base58.h" #include "base58.h"
#include "bip32.h"
#include "bip39.h" #include "bip39.h"
#include "coins.h"
#include "config.h"
#include "crypto.h"
#include "curves.h" #include "curves.h"
#include "secp256k1.h" #include "debug.h"
#include "ecdsa.h"
#include "ethereum.h" #include "ethereum.h"
#include "fsm.h"
#include "gettext.h"
#include "hmac.h"
#include "layout2.h"
#include "lisk.h"
#include "memory.h"
#include "memzero.h"
#include "messages.h"
#include "messages.pb.h"
#include "nem.h" #include "nem.h"
#include "nem2.h" #include "nem2.h"
#include "oled.h"
#include "pinmatrix.h"
#include "protect.h"
#include "recovery.h"
#include "reset.h"
#include "rfc6979.h" #include "rfc6979.h"
#include "gettext.h" #include "rng.h"
#include "supervise.h" #include "secp256k1.h"
#include "messages.pb.h" #include "signing.h"
#include "stellar.h" #include "stellar.h"
#include "lisk.h" #include "supervise.h"
#include "memzero.h" #include "transaction.h"
#include "trezor.h"
#include "usb.h"
#include "util.h"
// message methods // message methods
@ -76,7 +75,8 @@ static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned));
#define CHECK_NOT_INITIALIZED \ #define CHECK_NOT_INITIALIZED \
if (config_isInitialized()) { \ if (config_isInitialized()) { \
fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Device is already initialized. Use Wipe first.")); \ fsm_sendFailure(FailureType_Failure_UnexpectedMessage, \
_("Device is already initialized. Use Wipe first.")); \
return; \ return; \
} }
@ -99,8 +99,7 @@ static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned));
return; \ return; \
} }
void fsm_sendSuccess(const char *text) void fsm_sendSuccess(const char *text) {
{
RESP_INIT(Success); RESP_INIT(Success);
if (text) { if (text) {
resp->has_message = true; resp->has_message = true;
@ -110,7 +109,8 @@ void fsm_sendSuccess(const char *text)
} }
#if DEBUG_LINK #if DEBUG_LINK
void fsm_sendFailureDebug(FailureType code, const char *text, const char *source) void fsm_sendFailureDebug(FailureType code, const char *text,
const char *source)
#else #else
void fsm_sendFailure(FailureType code, const char *text) void fsm_sendFailure(FailureType code, const char *text)
#endif #endif
@ -184,8 +184,7 @@ void fsm_sendFailure(FailureType code, const char *text)
msg_write(MessageType_MessageType_Failure, resp); msg_write(MessageType_MessageType_Failure, resp);
} }
static const CoinInfo *fsm_getCoin(bool has_name, const char *name) static const CoinInfo *fsm_getCoin(bool has_name, const char *name) {
{
const CoinInfo *coin; const CoinInfo *coin;
if (has_name) { if (has_name) {
coin = coinByName(name); coin = coinByName(name);
@ -200,37 +199,45 @@ static const CoinInfo *fsm_getCoin(bool has_name, const char *name)
return coin; return coin;
} }
static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, size_t address_n_count, uint32_t *fingerprint) static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n,
{ size_t address_n_count,
uint32_t *fingerprint) {
static CONFIDENTIAL HDNode node; static CONFIDENTIAL HDNode node;
if (fingerprint) { if (fingerprint) {
*fingerprint = 0; *fingerprint = 0;
} }
if (!config_getRootNode(&node, curve, true)) { if (!config_getRootNode(&node, curve, true)) {
fsm_sendFailure(FailureType_Failure_NotInitialized, _("Device not initialized or passphrase request cancelled or unsupported curve")); fsm_sendFailure(FailureType_Failure_NotInitialized,
_("Device not initialized or passphrase request cancelled "
"or unsupported curve"));
layoutHome(); layoutHome();
return 0; return 0;
} }
if (!address_n || address_n_count == 0) { if (!address_n || address_n_count == 0) {
return &node; return &node;
} }
if (hdnode_private_ckd_cached(&node, address_n, address_n_count, fingerprint) == 0) { if (hdnode_private_ckd_cached(&node, address_n, address_n_count,
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); fingerprint) == 0) {
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to derive private key"));
layoutHome(); layoutHome();
return 0; return 0;
} }
return &node; return &node;
} }
static bool fsm_layoutAddress(const char *address, const char *desc, bool ignorecase, size_t prefixlen, const uint32_t *address_n, size_t address_n_count, bool address_is_account) static bool fsm_layoutAddress(const char *address, const char *desc,
{ bool ignorecase, size_t prefixlen,
const uint32_t *address_n, size_t address_n_count,
bool address_is_account) {
bool qrcode = false; bool qrcode = false;
for (;;) { for (;;) {
const char *display_addr = address; const char *display_addr = address;
if (prefixlen && !qrcode) { if (prefixlen && !qrcode) {
display_addr += prefixlen; display_addr += prefixlen;
} }
layoutAddress(display_addr, desc, qrcode, ignorecase, address_n, address_n_count, address_is_account); layoutAddress(display_addr, desc, qrcode, ignorecase, address_n,
address_n_count, address_is_account);
if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) {
return true; return true;
} }
@ -243,11 +250,11 @@ static bool fsm_layoutAddress(const char *address, const char *desc, bool ignore
} }
} }
#include "fsm_msg_common.h"
#include "fsm_msg_coin.h" #include "fsm_msg_coin.h"
#include "fsm_msg_ethereum.h" #include "fsm_msg_common.h"
#include "fsm_msg_crypto.h" #include "fsm_msg_crypto.h"
#include "fsm_msg_debug.h"
#include "fsm_msg_ethereum.h"
#include "fsm_msg_lisk.h"
#include "fsm_msg_nem.h" #include "fsm_msg_nem.h"
#include "fsm_msg_stellar.h" #include "fsm_msg_stellar.h"
#include "fsm_msg_lisk.h"
#include "fsm_msg_debug.h"

View File

@ -24,19 +24,21 @@
#include "messages-crypto.pb.h" #include "messages-crypto.pb.h"
#include "messages-debug.pb.h" #include "messages-debug.pb.h"
#include "messages-ethereum.pb.h" #include "messages-ethereum.pb.h"
#include "messages-lisk.pb.h"
#include "messages-management.pb.h" #include "messages-management.pb.h"
#include "messages-nem.pb.h" #include "messages-nem.pb.h"
#include "messages-stellar.pb.h" #include "messages-stellar.pb.h"
#include "messages-lisk.pb.h"
// message functions // message functions
void fsm_sendSuccess(const char *text); void fsm_sendSuccess(const char *text);
#if DEBUG_LINK #if DEBUG_LINK
void fsm_sendFailureDebug(FailureType code, const char *text, const char *source); void fsm_sendFailureDebug(FailureType code, const char *text,
const char *source);
#define fsm_sendFailure(code, text) fsm_sendFailureDebug((code), (text), __FILE__ ":" VERSTR(__LINE__) ":") #define fsm_sendFailure(code, text) \
fsm_sendFailureDebug((code), (text), __FILE__ ":" VERSTR(__LINE__) ":")
#else #else
void fsm_sendFailure(FailureType code, const char *text); void fsm_sendFailure(FailureType code, const char *text);
#endif #endif
@ -67,7 +69,8 @@ void fsm_msgSetU2FCounter(const SetU2FCounter *msg);
// coin // coin
void fsm_msgGetPublicKey(const GetPublicKey *msg); void fsm_msgGetPublicKey(const GetPublicKey *msg);
void fsm_msgSignTx(const SignTx *msg); void fsm_msgSignTx(const SignTx *msg);
void fsm_msgTxAck(TxAck *msg); // not const because we mutate input/output scripts void fsm_msgTxAck(
TxAck *msg); // not const because we mutate input/output scripts
void fsm_msgGetAddress(const GetAddress *msg); void fsm_msgGetAddress(const GetAddress *msg);
void fsm_msgSignMessage(const SignMessage *msg); void fsm_msgSignMessage(const SignMessage *msg);
void fsm_msgVerifyMessage(const VerifyMessage *msg); void fsm_msgVerifyMessage(const VerifyMessage *msg);
@ -92,7 +95,9 @@ void fsm_msgDebugLinkFlashErase(const DebugLinkFlashErase *msg);
// ethereum // ethereum
void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg); void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg);
void fsm_msgEthereumGetPublicKey(const EthereumGetPublicKey *msg); void fsm_msgEthereumGetPublicKey(const EthereumGetPublicKey *msg);
void fsm_msgEthereumSignTx(EthereumSignTx *msg); // not const because we mutate transaction during validation void fsm_msgEthereumSignTx(
EthereumSignTx
*msg); // not const because we mutate transaction during validation
void fsm_msgEthereumTxAck(const EthereumTxAck *msg); void fsm_msgEthereumTxAck(const EthereumTxAck *msg);
void fsm_msgEthereumSignMessage(const EthereumSignMessage *msg); void fsm_msgEthereumSignMessage(const EthereumSignMessage *msg);
void fsm_msgEthereumVerifyMessage(const EthereumVerifyMessage *msg); void fsm_msgEthereumVerifyMessage(const EthereumVerifyMessage *msg);
@ -102,12 +107,16 @@ void fsm_msgLiskGetAddress(const LiskGetAddress *msg);
void fsm_msgLiskGetPublicKey(const LiskGetPublicKey *msg); void fsm_msgLiskGetPublicKey(const LiskGetPublicKey *msg);
void fsm_msgLiskSignMessage(const LiskSignMessage *msg); void fsm_msgLiskSignMessage(const LiskSignMessage *msg);
void fsm_msgLiskVerifyMessage(const LiskVerifyMessage *msg); void fsm_msgLiskVerifyMessage(const LiskVerifyMessage *msg);
void fsm_msgLiskSignTx(LiskSignTx *msg); // not const because we mutate transaction during validation void fsm_msgLiskSignTx(LiskSignTx *msg); // not const because we mutate
// transaction during validation
// nem // nem
void fsm_msgNEMGetAddress(NEMGetAddress *msg); // not const because we mutate msg->network void fsm_msgNEMGetAddress(
void fsm_msgNEMSignTx(NEMSignTx *msg); // not const because we mutate msg->network NEMGetAddress *msg); // not const because we mutate msg->network
void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg); // not const because we mutate msg->payload void fsm_msgNEMSignTx(
NEMSignTx *msg); // not const because we mutate msg->network
void fsm_msgNEMDecryptMessage(
NEMDecryptMessage *msg); // not const because we mutate msg->payload
// stellar // stellar
void fsm_msgStellarGetAddress(const StellarGetAddress *msg); void fsm_msgStellarGetAddress(const StellarGetAddress *msg);

View File

@ -17,15 +17,15 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
void fsm_msgGetPublicKey(const GetPublicKey *msg) void fsm_msgGetPublicKey(const GetPublicKey *msg) {
{
RESP_INIT(PublicKey); RESP_INIT(PublicKey);
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PIN CHECK_PIN
InputScriptType script_type = msg->has_script_type ? msg->script_type : InputScriptType_SPENDADDRESS; InputScriptType script_type =
msg->has_script_type ? msg->script_type : InputScriptType_SPENDADDRESS;
const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name);
if (!coin) return; if (!coin) return;
@ -35,7 +35,8 @@ void fsm_msgGetPublicKey(const GetPublicKey *msg)
curve = msg->ecdsa_curve_name; curve = msg->ecdsa_curve_name;
} }
uint32_t fingerprint; uint32_t fingerprint;
HDNode *node = node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count, &fingerprint); HDNode *node = node = fsm_getDerivedNode(curve, msg->address_n,
msg->address_n_count, &fingerprint);
if (!node) return; if (!node) return;
hdnode_fill_public_key(node); hdnode_fill_public_key(node);
@ -64,16 +65,21 @@ void fsm_msgGetPublicKey(const GetPublicKey *msg)
} }
resp->has_xpub = true; resp->has_xpub = true;
if (coin->xpub_magic && (script_type == InputScriptType_SPENDADDRESS || script_type == InputScriptType_SPENDMULTISIG)) { if (coin->xpub_magic && (script_type == InputScriptType_SPENDADDRESS ||
hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub, sizeof(resp->xpub)); script_type == InputScriptType_SPENDMULTISIG)) {
} else hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub,
if (coin->has_segwit && coin->xpub_magic_segwit_p2sh && script_type == InputScriptType_SPENDP2SHWITNESS) { sizeof(resp->xpub));
hdnode_serialize_public(node, fingerprint, coin->xpub_magic_segwit_p2sh, resp->xpub, sizeof(resp->xpub)); } else if (coin->has_segwit && coin->xpub_magic_segwit_p2sh &&
} else script_type == InputScriptType_SPENDP2SHWITNESS) {
if (coin->has_segwit && coin->xpub_magic_segwit_native && script_type == InputScriptType_SPENDWITNESS) { hdnode_serialize_public(node, fingerprint, coin->xpub_magic_segwit_p2sh,
hdnode_serialize_public(node, fingerprint, coin->xpub_magic_segwit_native, resp->xpub, sizeof(resp->xpub)); resp->xpub, sizeof(resp->xpub));
} else if (coin->has_segwit && coin->xpub_magic_segwit_native &&
script_type == InputScriptType_SPENDWITNESS) {
hdnode_serialize_public(node, fingerprint, coin->xpub_magic_segwit_native,
resp->xpub, sizeof(resp->xpub));
} else { } else {
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid combination of coin and script_type")); fsm_sendFailure(FailureType_Failure_DataError,
_("Invalid combination of coin and script_type"));
layoutHome(); layoutHome();
return; return;
} }
@ -82,13 +88,15 @@ void fsm_msgGetPublicKey(const GetPublicKey *msg)
layoutHome(); layoutHome();
} }
void fsm_msgSignTx(const SignTx *msg) void fsm_msgSignTx(const SignTx *msg) {
{
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PARAM(msg->inputs_count > 0, _("Transaction must have at least one input")); CHECK_PARAM(msg->inputs_count > 0,
CHECK_PARAM(msg->outputs_count > 0, _("Transaction must have at least one output")); _("Transaction must have at least one input"));
CHECK_PARAM(msg->inputs_count + msg->outputs_count >= msg->inputs_count, _("Value overflow")); CHECK_PARAM(msg->outputs_count > 0,
_("Transaction must have at least one output"));
CHECK_PARAM(msg->inputs_count + msg->outputs_count >= msg->inputs_count,
_("Value overflow"));
CHECK_PIN CHECK_PIN
@ -100,15 +108,13 @@ void fsm_msgSignTx(const SignTx *msg)
signing_init(msg, coin, node); signing_init(msg, coin, node);
} }
void fsm_msgTxAck(TxAck *msg) void fsm_msgTxAck(TxAck *msg) {
{
CHECK_PARAM(msg->has_tx, _("No transaction provided")); CHECK_PARAM(msg->has_tx, _("No transaction provided"));
signing_txack(&(msg->tx)); signing_txack(&(msg->tx));
} }
static bool path_mismatched(const CoinInfo *coin, const GetAddress *msg) static bool path_mismatched(const CoinInfo *coin, const GetAddress *msg) {
{
bool mismatch = false; bool mismatch = false;
// m : no path // m : no path
@ -182,8 +188,7 @@ static bool path_mismatched(const CoinInfo *coin, const GetAddress *msg)
return false; return false;
} }
void fsm_msgGetAddress(const GetAddress *msg) void fsm_msgGetAddress(const GetAddress *msg) {
{
RESP_INIT(Address); RESP_INIT(Address);
CHECK_INITIALIZED CHECK_INITIALIZED
@ -192,7 +197,8 @@ void fsm_msgGetAddress(const GetAddress *msg)
const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name);
if (!coin) return; if (!coin) return;
HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, msg->address_n_count, NULL); HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n,
msg->address_n_count, NULL);
if (!node) return; if (!node) return;
hdnode_fill_public_key(node); hdnode_fill_public_key(node);
@ -200,7 +206,8 @@ void fsm_msgGetAddress(const GetAddress *msg)
if (msg->has_multisig) { // use progress bar only for multisig if (msg->has_multisig) { // use progress bar only for multisig
layoutProgress(_("Computing address"), 0); layoutProgress(_("Computing address"), 0);
} }
if (!compute_address(coin, msg->script_type, node, msg->has_multisig, &msg->multisig, address)) { if (!compute_address(coin, msg->script_type, node, msg->has_multisig,
&msg->multisig, address)) {
fsm_sendFailure(FailureType_Failure_DataError, _("Can't encode address")); fsm_sendFailure(FailureType_Failure_DataError, _("Can't encode address"));
layoutHome(); layoutHome();
return; return;
@ -223,7 +230,9 @@ void fsm_msgGetAddress(const GetAddress *msg)
bool mismatch = path_mismatched(coin, msg); bool mismatch = path_mismatched(coin, msg);
if (mismatch) { if (mismatch) {
layoutDialogSwipe(&bmp_icon_warning, _("Abort"), _("Continue"), NULL, _("Wrong address path"), _("for selected coin."), NULL, _("Continue at your"), _("own risk!"), NULL); layoutDialogSwipe(&bmp_icon_warning, _("Abort"), _("Continue"), NULL,
_("Wrong address path"), _("for selected coin."), NULL,
_("Continue at your"), _("own risk!"), NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
@ -233,7 +242,9 @@ void fsm_msgGetAddress(const GetAddress *msg)
bool is_cashaddr = coin->cashaddr_prefix != NULL; bool is_cashaddr = coin->cashaddr_prefix != NULL;
bool is_bech32 = msg->script_type == InputScriptType_SPENDWITNESS; bool is_bech32 = msg->script_type == InputScriptType_SPENDWITNESS;
if (!fsm_layoutAddress(address, desc, is_cashaddr || is_bech32, is_cashaddr ? strlen(coin->cashaddr_prefix) + 1 : 0, msg->address_n, msg->address_n_count, false)) { if (!fsm_layoutAddress(address, desc, is_cashaddr || is_bech32,
is_cashaddr ? strlen(coin->cashaddr_prefix) + 1 : 0,
msg->address_n, msg->address_n_count, false)) {
return; return;
} }
} }
@ -243,9 +254,9 @@ void fsm_msgGetAddress(const GetAddress *msg)
layoutHome(); layoutHome();
} }
void fsm_msgSignMessage(const SignMessage *msg) void fsm_msgSignMessage(const SignMessage *msg) {
{ // CHECK_PARAM(is_ascii_only(msg->message.bytes, msg->message.size), _("Cannot
// CHECK_PARAM(is_ascii_only(msg->message.bytes, msg->message.size), _("Cannot sign non-ASCII strings")); // sign non-ASCII strings"));
RESP_INIT(MessageSignature); RESP_INIT(MessageSignature);
@ -262,15 +273,19 @@ void fsm_msgSignMessage(const SignMessage *msg)
const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name);
if (!coin) return; if (!coin) return;
HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, msg->address_n_count, NULL); HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n,
msg->address_n_count, NULL);
if (!node) return; if (!node) return;
layoutProgressSwipe(_("Signing"), 0); layoutProgressSwipe(_("Signing"), 0);
if (cryptoMessageSign(coin, node, msg->script_type, msg->message.bytes, msg->message.size, resp->signature.bytes) == 0) { if (cryptoMessageSign(coin, node, msg->script_type, msg->message.bytes,
msg->message.size, resp->signature.bytes) == 0) {
resp->has_address = true; resp->has_address = true;
hdnode_fill_public_key(node); hdnode_fill_public_key(node);
if (!compute_address(coin, msg->script_type, node, false, NULL, resp->address)) { if (!compute_address(coin, msg->script_type, node, false, NULL,
fsm_sendFailure(FailureType_Failure_ProcessError, _("Error computing address")); resp->address)) {
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Error computing address"));
layoutHome(); layoutHome();
return; return;
} }
@ -278,20 +293,22 @@ void fsm_msgSignMessage(const SignMessage *msg)
resp->signature.size = 65; resp->signature.size = 65;
msg_write(MessageType_MessageType_MessageSignature, resp); msg_write(MessageType_MessageType_MessageSignature, resp);
} else { } else {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Error signing message")); fsm_sendFailure(FailureType_Failure_ProcessError,
_("Error signing message"));
} }
layoutHome(); layoutHome();
} }
void fsm_msgVerifyMessage(const VerifyMessage *msg) void fsm_msgVerifyMessage(const VerifyMessage *msg) {
{
CHECK_PARAM(msg->has_address, _("No address provided")); CHECK_PARAM(msg->has_address, _("No address provided"));
CHECK_PARAM(msg->has_message, _("No message provided")); CHECK_PARAM(msg->has_message, _("No message provided"));
const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name);
if (!coin) return; if (!coin) return;
layoutProgressSwipe(_("Verifying"), 0); layoutProgressSwipe(_("Verifying"), 0);
if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, msg->address, msg->signature.bytes) == 0) { if (msg->signature.size == 65 &&
cryptoMessageVerify(coin, msg->message.bytes, msg->message.size,
msg->address, msg->signature.bytes) == 0) {
layoutVerifyAddress(coin, msg->address); layoutVerifyAddress(coin, msg->address);
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);

View File

@ -17,8 +17,7 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
void fsm_msgInitialize(const Initialize *msg) void fsm_msgInitialize(const Initialize *msg) {
{
recovery_abort(); recovery_abort();
signing_abort(); signing_abort();
if (msg && msg->has_state && msg->state.size == 64) { if (msg && msg->has_state && msg->state.size == 64) {
@ -37,44 +36,63 @@ void fsm_msgInitialize(const Initialize *msg)
fsm_msgGetFeatures(0); fsm_msgGetFeatures(0);
} }
void fsm_msgGetFeatures(const GetFeatures *msg) void fsm_msgGetFeatures(const GetFeatures *msg) {
{
(void)msg; (void)msg;
RESP_INIT(Features); RESP_INIT(Features);
resp->has_vendor = true; strlcpy(resp->vendor, "trezor.io", sizeof(resp->vendor)); resp->has_vendor = true;
resp->has_major_version = true; resp->major_version = VERSION_MAJOR; strlcpy(resp->vendor, "trezor.io", sizeof(resp->vendor));
resp->has_minor_version = true; resp->minor_version = VERSION_MINOR; resp->has_major_version = true;
resp->has_patch_version = true; resp->patch_version = VERSION_PATCH; resp->major_version = VERSION_MAJOR;
resp->has_device_id = true; strlcpy(resp->device_id, config_uuid_str, sizeof(resp->device_id)); resp->has_minor_version = true;
resp->has_pin_protection = true; resp->pin_protection = config_hasPin(); resp->minor_version = VERSION_MINOR;
resp->has_passphrase_protection = true; config_getPassphraseProtection(&(resp->passphrase_protection)); resp->has_patch_version = true;
resp->patch_version = VERSION_PATCH;
resp->has_device_id = true;
strlcpy(resp->device_id, config_uuid_str, sizeof(resp->device_id));
resp->has_pin_protection = true;
resp->pin_protection = config_hasPin();
resp->has_passphrase_protection = true;
config_getPassphraseProtection(&(resp->passphrase_protection));
#ifdef SCM_REVISION #ifdef SCM_REVISION
int len = sizeof(SCM_REVISION) - 1; int len = sizeof(SCM_REVISION) - 1;
resp->has_revision = true; memcpy(resp->revision.bytes, SCM_REVISION, len); resp->revision.size = len; resp->has_revision = true;
memcpy(resp->revision.bytes, SCM_REVISION, len);
resp->revision.size = len;
#endif #endif
resp->has_bootloader_hash = true; resp->bootloader_hash.size = memory_bootloader_hash(resp->bootloader_hash.bytes); resp->has_bootloader_hash = true;
resp->bootloader_hash.size =
memory_bootloader_hash(resp->bootloader_hash.bytes);
resp->has_language = config_getLanguage(resp->language, sizeof(resp->language)); resp->has_language =
config_getLanguage(resp->language, sizeof(resp->language));
resp->has_label = config_getLabel(resp->label, sizeof(resp->label)); resp->has_label = config_getLabel(resp->label, sizeof(resp->label));
resp->has_initialized = true; resp->initialized = config_isInitialized(); resp->has_initialized = true;
resp->initialized = config_isInitialized();
resp->has_imported = config_getImported(&(resp->imported)); resp->has_imported = config_getImported(&(resp->imported));
resp->has_pin_cached = true; resp->pin_cached = session_isUnlocked() && config_hasPin(); resp->has_pin_cached = true;
resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); resp->pin_cached = session_isUnlocked() && config_hasPin();
resp->has_needs_backup = true; config_getNeedsBackup(&(resp->needs_backup)); resp->has_passphrase_cached = true;
resp->has_unfinished_backup = true; config_getUnfinishedBackup(&(resp->unfinished_backup)); resp->passphrase_cached = session_isPassphraseCached();
resp->has_no_backup = true; config_getNoBackup(&(resp->no_backup)); resp->has_needs_backup = true;
config_getNeedsBackup(&(resp->needs_backup));
resp->has_unfinished_backup = true;
config_getUnfinishedBackup(&(resp->unfinished_backup));
resp->has_no_backup = true;
config_getNoBackup(&(resp->no_backup));
resp->has_flags = config_getFlags(&(resp->flags)); resp->has_flags = config_getFlags(&(resp->flags));
resp->has_model = true; strlcpy(resp->model, "1", sizeof(resp->model)); resp->has_model = true;
strlcpy(resp->model, "1", sizeof(resp->model));
msg_write(MessageType_MessageType_Features, resp); msg_write(MessageType_MessageType_Features, resp);
} }
void fsm_msgPing(const Ping *msg) void fsm_msgPing(const Ping *msg) {
{
RESP_INIT(Success); RESP_INIT(Success);
if (msg->has_button_protection && msg->button_protection) { if (msg->has_button_protection && msg->button_protection) {
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("answer to ping?"), NULL, NULL, NULL, NULL); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Do you really want to"), _("answer to ping?"), NULL,
NULL, NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
@ -101,21 +119,26 @@ void fsm_msgPing(const Ping *msg)
layoutHome(); layoutHome();
} }
void fsm_msgChangePin(const ChangePin *msg) void fsm_msgChangePin(const ChangePin *msg) {
{
bool removal = msg->has_remove && msg->remove; bool removal = msg->has_remove && msg->remove;
if (removal) { if (removal) {
if (config_hasPin()) { if (config_hasPin()) {
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("remove current PIN?"), NULL, NULL, NULL, NULL); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Do you really want to"), _("remove current PIN?"),
NULL, NULL, NULL, NULL);
} else { } else {
fsm_sendSuccess(_("PIN removed")); fsm_sendSuccess(_("PIN removed"));
return; return;
} }
} else { } else {
if (config_hasPin()) { if (config_hasPin()) {
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change current PIN?"), NULL, NULL, NULL, NULL); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Do you really want to"), _("change current PIN?"),
NULL, NULL, NULL, NULL);
} else { } else {
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("set new PIN?"), NULL, NULL, NULL, NULL); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Do you really want to"), _("set new PIN?"), NULL,
NULL, NULL, NULL);
} }
} }
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
@ -135,26 +158,29 @@ void fsm_msgChangePin(const ChangePin *msg)
layoutHome(); layoutHome();
} }
void fsm_msgWipeDevice(const WipeDevice *msg) void fsm_msgWipeDevice(const WipeDevice *msg) {
{
(void)msg; (void)msg;
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("wipe the device?"), NULL, _("All data will be lost."), NULL, NULL); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Do you really want to"), _("wipe the device?"), NULL,
_("All data will be lost."), NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_WipeDevice, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_WipeDevice, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
return; return;
} }
config_wipe(); config_wipe();
// the following does not work on Mac anyway :-/ Linux/Windows are fine, so it is not needed // the following does not work on Mac anyway :-/ Linux/Windows are fine, so it
// usbReconnect(); // force re-enumeration because of the serial number change // is not needed usbReconnect(); // force re-enumeration because of the serial
// number change
fsm_sendSuccess(_("Device wiped")); fsm_sendSuccess(_("Device wiped"));
layoutHome(); layoutHome();
} }
void fsm_msgGetEntropy(const GetEntropy *msg) void fsm_msgGetEntropy(const GetEntropy *msg) {
{
#if !DEBUG_RNG #if !DEBUG_RNG
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("send entropy?"), NULL, NULL, NULL, NULL); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Do you really want to"), _("send entropy?"), NULL, NULL,
NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
@ -172,13 +198,15 @@ void fsm_msgGetEntropy(const GetEntropy *msg)
layoutHome(); layoutHome();
} }
void fsm_msgLoadDevice(const LoadDevice *msg) void fsm_msgLoadDevice(const LoadDevice *msg) {
{
CHECK_PIN CHECK_PIN
CHECK_NOT_INITIALIZED CHECK_NOT_INITIALIZED
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("I take the risk"), NULL, _("Loading private seed"), _("is not recommended."), _("Continue only if you"), _("know what you are"), _("doing!"), NULL); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("I take the risk"), NULL,
_("Loading private seed"), _("is not recommended."),
_("Continue only if you"), _("know what you are"),
_("doing!"), NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
@ -187,7 +215,8 @@ void fsm_msgLoadDevice(const LoadDevice *msg)
if (msg->has_mnemonic && !(msg->has_skip_checksum && msg->skip_checksum)) { if (msg->has_mnemonic && !(msg->has_skip_checksum && msg->skip_checksum)) {
if (!mnemonic_check(msg->mnemonic)) { if (!mnemonic_check(msg->mnemonic)) {
fsm_sendFailure(FailureType_Failure_DataError, _("Mnemonic with wrong checksum provided")); fsm_sendFailure(FailureType_Failure_DataError,
_("Mnemonic with wrong checksum provided"));
layoutHome(); layoutHome();
return; return;
} }
@ -198,16 +227,16 @@ void fsm_msgLoadDevice(const LoadDevice *msg)
layoutHome(); layoutHome();
} }
void fsm_msgResetDevice(const ResetDevice *msg) void fsm_msgResetDevice(const ResetDevice *msg) {
{
CHECK_PIN CHECK_PIN
CHECK_NOT_INITIALIZED CHECK_NOT_INITIALIZED
CHECK_PARAM(!msg->has_strength || msg->strength == 128 || msg->strength == 192 || msg->strength == 256, _("Invalid seed strength")); CHECK_PARAM(!msg->has_strength || msg->strength == 128 ||
msg->strength == 192 || msg->strength == 256,
_("Invalid seed strength"));
reset_init( reset_init(msg->has_display_random && msg->display_random,
msg->has_display_random && msg->display_random,
msg->has_strength ? msg->strength : 128, msg->has_strength ? msg->strength : 128,
msg->has_passphrase_protection && msg->passphrase_protection, msg->has_passphrase_protection && msg->passphrase_protection,
msg->has_pin_protection && msg->pin_protection, msg->has_pin_protection && msg->pin_protection,
@ -215,12 +244,10 @@ void fsm_msgResetDevice(const ResetDevice *msg)
msg->has_label ? msg->label : 0, msg->has_label ? msg->label : 0,
msg->has_u2f_counter ? msg->u2f_counter : 0, msg->has_u2f_counter ? msg->u2f_counter : 0,
msg->has_skip_backup ? msg->skip_backup : false, msg->has_skip_backup ? msg->skip_backup : false,
msg->has_no_backup ? msg->no_backup : false msg->has_no_backup ? msg->no_backup : false);
);
} }
void fsm_msgEntropyAck(const EntropyAck *msg) void fsm_msgEntropyAck(const EntropyAck *msg) {
{
if (msg->has_entropy) { if (msg->has_entropy) {
reset_entropy(msg->entropy.bytes, msg->entropy.size); reset_entropy(msg->entropy.bytes, msg->entropy.size);
} else { } else {
@ -228,13 +255,13 @@ void fsm_msgEntropyAck(const EntropyAck *msg)
} }
} }
void fsm_msgBackupDevice(const BackupDevice *msg) void fsm_msgBackupDevice(const BackupDevice *msg) {
{
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PIN_UNCACHED CHECK_PIN_UNCACHED
(void)msg; (void)
msg;
char mnemonic[MAX_MNEMONIC_LEN + 1]; char mnemonic[MAX_MNEMONIC_LEN + 1];
if (config_getMnemonic(mnemonic, sizeof(mnemonic))) { if (config_getMnemonic(mnemonic, sizeof(mnemonic))) {
reset_backup(true, mnemonic); reset_backup(true, mnemonic);
@ -242,8 +269,7 @@ void fsm_msgBackupDevice(const BackupDevice *msg)
memzero(mnemonic, sizeof(mnemonic)); memzero(mnemonic, sizeof(mnemonic));
} }
void fsm_msgCancel(const Cancel *msg) void fsm_msgCancel(const Cancel *msg) {
{
(void)msg; (void)msg;
recovery_abort(); recovery_abort();
signing_abort(); signing_abort();
@ -251,23 +277,24 @@ void fsm_msgCancel(const Cancel *msg)
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
} }
void fsm_msgClearSession(const ClearSession *msg) void fsm_msgClearSession(const ClearSession *msg) {
{
(void)msg; (void)msg;
session_clear(true); // clear PIN as well session_clear(true); // clear PIN as well
layoutScreensaver(); layoutScreensaver();
fsm_sendSuccess(_("Session cleared")); fsm_sendSuccess(_("Session cleared"));
} }
void fsm_msgApplySettings(const ApplySettings *msg) void fsm_msgApplySettings(const ApplySettings *msg) {
{ CHECK_PARAM(msg->has_label || msg->has_language || msg->has_use_passphrase ||
CHECK_PARAM(msg->has_label || msg->has_language || msg->has_use_passphrase || msg->has_homescreen || msg->has_auto_lock_delay_ms, msg->has_homescreen || msg->has_auto_lock_delay_ms,
_("No setting provided")); _("No setting provided"));
CHECK_PIN CHECK_PIN
if (msg->has_label) { if (msg->has_label) {
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change name to"), msg->label, "?", NULL, NULL); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Do you really want to"), _("change name to"),
msg->label, "?", NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
@ -275,7 +302,9 @@ void fsm_msgApplySettings(const ApplySettings *msg)
} }
} }
if (msg->has_language) { if (msg->has_language) {
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change language to"), msg->language, "?", NULL, NULL); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Do you really want to"), _("change language to"),
msg->language, "?", NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
@ -283,7 +312,11 @@ void fsm_msgApplySettings(const ApplySettings *msg)
} }
} }
if (msg->has_use_passphrase) { if (msg->has_use_passphrase) {
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), msg->use_passphrase ? _("enable passphrase") : _("disable passphrase"), _("protection?"), NULL, NULL, NULL); layoutDialogSwipe(
&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Do you really want to"),
msg->use_passphrase ? _("enable passphrase") : _("disable passphrase"),
_("protection?"), NULL, NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
@ -291,7 +324,9 @@ void fsm_msgApplySettings(const ApplySettings *msg)
} }
} }
if (msg->has_homescreen) { if (msg->has_homescreen) {
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change the home"), _("screen?"), NULL, NULL, NULL); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Do you really want to"), _("change the home"),
_("screen?"), NULL, NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
@ -300,7 +335,9 @@ void fsm_msgApplySettings(const ApplySettings *msg)
} }
if (msg->has_auto_lock_delay_ms) { if (msg->has_auto_lock_delay_ms) {
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change auto-lock"), _("delay?"), NULL, NULL, NULL); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Do you really want to"), _("change auto-lock"),
_("delay?"), NULL, NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
@ -327,8 +364,7 @@ void fsm_msgApplySettings(const ApplySettings *msg)
layoutHome(); layoutHome();
} }
void fsm_msgApplyFlags(const ApplyFlags *msg) void fsm_msgApplyFlags(const ApplyFlags *msg) {
{
CHECK_PIN CHECK_PIN
if (msg->has_flags) { if (msg->has_flags) {
@ -337,8 +373,7 @@ void fsm_msgApplyFlags(const ApplyFlags *msg)
fsm_sendSuccess(_("Flags applied")); fsm_sendSuccess(_("Flags applied"));
} }
void fsm_msgRecoveryDevice(const RecoveryDevice *msg) void fsm_msgRecoveryDevice(const RecoveryDevice *msg) {
{
CHECK_PIN_UNCACHED CHECK_PIN_UNCACHED
const bool dry_run = msg->has_dry_run ? msg->dry_run : false; const bool dry_run = msg->has_dry_run ? msg->dry_run : false;
@ -346,29 +381,26 @@ void fsm_msgRecoveryDevice(const RecoveryDevice *msg)
CHECK_NOT_INITIALIZED CHECK_NOT_INITIALIZED
} }
CHECK_PARAM(!msg->has_word_count || msg->word_count == 12 || msg->word_count == 18 || msg->word_count == 24, _("Invalid word count")); CHECK_PARAM(!msg->has_word_count || msg->word_count == 12 ||
msg->word_count == 18 || msg->word_count == 24,
_("Invalid word count"));
recovery_init( recovery_init(msg->has_word_count ? msg->word_count : 12,
msg->has_word_count ? msg->word_count : 12,
msg->has_passphrase_protection && msg->passphrase_protection, msg->has_passphrase_protection && msg->passphrase_protection,
msg->has_pin_protection && msg->pin_protection, msg->has_pin_protection && msg->pin_protection,
msg->has_language ? msg->language : 0, msg->has_language ? msg->language : 0,
msg->has_label ? msg->label : 0, msg->has_label ? msg->label : 0,
msg->has_enforce_wordlist && msg->enforce_wordlist, msg->has_enforce_wordlist && msg->enforce_wordlist,
msg->has_type ? msg->type : 0, msg->has_type ? msg->type : 0,
msg->has_u2f_counter ? msg->u2f_counter : 0, msg->has_u2f_counter ? msg->u2f_counter : 0, dry_run);
dry_run
);
} }
void fsm_msgWordAck(const WordAck *msg) void fsm_msgWordAck(const WordAck *msg) { recovery_word(msg->word); }
{
recovery_word(msg->word);
}
void fsm_msgSetU2FCounter(const SetU2FCounter *msg) void fsm_msgSetU2FCounter(const SetU2FCounter *msg) {
{ layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you want to set"), _("the U2F counter?"), NULL, NULL, NULL, NULL); _("Do you want to set"), _("the U2F counter?"), NULL, NULL,
NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();

View File

@ -17,17 +17,18 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
void fsm_msgCipherKeyValue(const CipherKeyValue *msg) void fsm_msgCipherKeyValue(const CipherKeyValue *msg) {
{
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PARAM(msg->has_key, _("No key provided")); CHECK_PARAM(msg->has_key, _("No key provided"));
CHECK_PARAM(msg->has_value, _("No value provided")); CHECK_PARAM(msg->has_value, _("No value provided"));
CHECK_PARAM(msg->value.size % 16 == 0, _("Value length must be a multiple of 16")); CHECK_PARAM(msg->value.size % 16 == 0,
_("Value length must be a multiple of 16"));
CHECK_PIN CHECK_PIN
const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n,
msg->address_n_count, NULL);
if (!node) return; if (!node) return;
bool encrypt = msg->has_encrypt && msg->encrypt; bool encrypt = msg->has_encrypt && msg->encrypt;
@ -58,11 +59,13 @@ void fsm_msgCipherKeyValue(const CipherKeyValue *msg)
if (encrypt) { if (encrypt) {
aes_encrypt_ctx ctx; aes_encrypt_ctx ctx;
aes_encrypt_key256(data, &ctx); aes_encrypt_key256(data, &ctx);
aes_cbc_encrypt(msg->value.bytes, resp->value.bytes, msg->value.size, data + 32, &ctx); aes_cbc_encrypt(msg->value.bytes, resp->value.bytes, msg->value.size,
data + 32, &ctx);
} else { } else {
aes_decrypt_ctx ctx; aes_decrypt_ctx ctx;
aes_decrypt_key256(data, &ctx); aes_decrypt_key256(data, &ctx);
aes_cbc_decrypt(msg->value.bytes, resp->value.bytes, msg->value.size, data + 32, &ctx); aes_cbc_decrypt(msg->value.bytes, resp->value.bytes, msg->value.size,
data + 32, &ctx);
} }
resp->has_value = true; resp->has_value = true;
resp->value.size = msg->value.size; resp->value.size = msg->value.size;
@ -70,13 +73,13 @@ void fsm_msgCipherKeyValue(const CipherKeyValue *msg)
layoutHome(); layoutHome();
} }
void fsm_msgSignIdentity(const SignIdentity *msg) void fsm_msgSignIdentity(const SignIdentity *msg) {
{
RESP_INIT(SignedIdentity); RESP_INIT(SignedIdentity);
CHECK_INITIALIZED CHECK_INITIALIZED
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, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
@ -86,7 +89,8 @@ void fsm_msgSignIdentity(const SignIdentity *msg)
CHECK_PIN CHECK_PIN
uint8_t hash[32]; uint8_t hash[32];
if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { if (!msg->has_identity ||
cryptoIdentityFingerprint(&(msg->identity), hash) == 0) {
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity")); fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity"));
layoutHome(); layoutHome();
return; return;
@ -94,10 +98,14 @@ void fsm_msgSignIdentity(const SignIdentity *msg)
uint32_t address_n[5]; uint32_t address_n[5];
address_n[0] = 0x80000000 | 13; address_n[0] = 0x80000000 | 13;
address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | ((uint32_t) hash[ 3] << 24); address_n[1] = 0x80000000 | hash[0] | (hash[1] << 8) | (hash[2] << 16) |
address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | ((uint32_t) hash[ 7] << 24); ((uint32_t)hash[3] << 24);
address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | ((uint32_t) hash[11] << 24); address_n[2] = 0x80000000 | hash[4] | (hash[5] << 8) | (hash[6] << 16) |
address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | ((uint32_t) hash[15] << 24); ((uint32_t)hash[7] << 24);
address_n[3] = 0x80000000 | hash[8] | (hash[9] << 8) | (hash[10] << 16) |
((uint32_t)hash[11] << 24);
address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) |
((uint32_t)hash[15] << 24);
const char *curve = SECP256K1_NAME; const char *curve = SECP256K1_NAME;
if (msg->has_ecdsa_curve_name) { if (msg->has_ecdsa_curve_name) {
@ -106,20 +114,26 @@ void fsm_msgSignIdentity(const SignIdentity *msg)
HDNode *node = fsm_getDerivedNode(curve, address_n, 5, NULL); HDNode *node = fsm_getDerivedNode(curve, address_n, 5, NULL);
if (!node) return; if (!node) return;
bool sign_ssh = msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0); bool sign_ssh =
bool sign_gpg = msg->identity.has_proto && (strcmp(msg->identity.proto, "gpg") == 0); 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(node, msg->challenge_hidden.bytes, msg->challenge_hidden.size, 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 } else if (sign_gpg) { // GPG should sign a message digest
result = gpgMessageSign(node, msg->challenge_hidden.bytes, msg->challenge_hidden.size, resp->signature.bytes); 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,
result = cryptoMessageSign(&(coins[0]), node, InputScriptType_SPENDADDRESS, digest, 64, resp->signature.bytes); strlen(msg->challenge_visual), digest + 32);
result = cryptoMessageSign(&(coins[0]), node, InputScriptType_SPENDADDRESS,
digest, 64, resp->signature.bytes);
} }
if (result == 0) { if (result == 0) {
@ -128,7 +142,9 @@ void fsm_msgSignIdentity(const SignIdentity *msg)
resp->has_address = false; resp->has_address = false;
} else { } else {
resp->has_address = true; resp->has_address = true;
hdnode_get_address(node, 0x00, resp->address, sizeof(resp->address)); // hardcoded Bitcoin address type hdnode_get_address(
node, 0x00, resp->address,
sizeof(resp->address)); // hardcoded Bitcoin address type
} }
resp->has_public_key = true; resp->has_public_key = true;
resp->public_key.size = 33; resp->public_key.size = 33;
@ -141,13 +157,13 @@ void fsm_msgSignIdentity(const SignIdentity *msg)
resp->signature.size = 65; resp->signature.size = 65;
msg_write(MessageType_MessageType_SignedIdentity, resp); msg_write(MessageType_MessageType_SignedIdentity, resp);
} else { } else {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Error signing identity")); fsm_sendFailure(FailureType_Failure_ProcessError,
_("Error signing identity"));
} }
layoutHome(); layoutHome();
} }
void fsm_msgGetECDHSessionKey(const GetECDHSessionKey *msg) void fsm_msgGetECDHSessionKey(const GetECDHSessionKey *msg) {
{
RESP_INIT(ECDHSessionKey); RESP_INIT(ECDHSessionKey);
CHECK_INITIALIZED CHECK_INITIALIZED
@ -162,7 +178,8 @@ void fsm_msgGetECDHSessionKey(const GetECDHSessionKey *msg)
CHECK_PIN CHECK_PIN
uint8_t hash[32]; uint8_t hash[32];
if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { if (!msg->has_identity ||
cryptoIdentityFingerprint(&(msg->identity), hash) == 0) {
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity")); fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity"));
layoutHome(); layoutHome();
return; return;
@ -170,10 +187,14 @@ void fsm_msgGetECDHSessionKey(const GetECDHSessionKey *msg)
uint32_t address_n[5]; uint32_t address_n[5];
address_n[0] = 0x80000000 | 17; address_n[0] = 0x80000000 | 17;
address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | ((uint32_t) hash[ 3] << 24); address_n[1] = 0x80000000 | hash[0] | (hash[1] << 8) | (hash[2] << 16) |
address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | ((uint32_t) hash[ 7] << 24); ((uint32_t)hash[3] << 24);
address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | ((uint32_t) hash[11] << 24); address_n[2] = 0x80000000 | hash[4] | (hash[5] << 8) | (hash[6] << 16) |
address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | ((uint32_t) hash[15] << 24); ((uint32_t)hash[7] << 24);
address_n[3] = 0x80000000 | hash[8] | (hash[9] << 8) | (hash[10] << 16) |
((uint32_t)hash[11] << 24);
address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) |
((uint32_t)hash[15] << 24);
const char *curve = SECP256K1_NAME; const char *curve = SECP256K1_NAME;
if (msg->has_ecdsa_curve_name) { if (msg->has_ecdsa_curve_name) {
@ -184,25 +205,27 @@ void fsm_msgGetECDHSessionKey(const GetECDHSessionKey *msg)
if (!node) return; if (!node) return;
int result_size = 0; int result_size = 0;
if (hdnode_get_shared_key(node, msg->peer_public_key.bytes, resp->session_key.bytes, &result_size) == 0) { if (hdnode_get_shared_key(node, msg->peer_public_key.bytes,
resp->session_key.bytes, &result_size) == 0) {
resp->has_session_key = true; resp->has_session_key = true;
resp->session_key.size = result_size; resp->session_key.size = result_size;
msg_write(MessageType_MessageType_ECDHSessionKey, resp); msg_write(MessageType_MessageType_ECDHSessionKey, resp);
} else { } else {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Error getting ECDH session key")); fsm_sendFailure(FailureType_Failure_ProcessError,
_("Error getting ECDH session key"));
} }
layoutHome(); layoutHome();
} }
void fsm_msgCosiCommit(const CosiCommit *msg) void fsm_msgCosiCommit(const CosiCommit *msg) {
{
RESP_INIT(CosiCommitment); RESP_INIT(CosiCommitment);
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PARAM(msg->has_data, _("No data provided")); CHECK_PARAM(msg->has_data, _("No data provided"));
layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes, msg->data.size, false); layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes,
msg->data.size, false);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
@ -211,7 +234,8 @@ void fsm_msgCosiCommit(const CosiCommit *msg)
CHECK_PIN CHECK_PIN
const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n,
msg->address_n_count, NULL);
if (!node) return; if (!node) return;
uint8_t nonce[32]; uint8_t nonce[32];
@ -232,17 +256,19 @@ void fsm_msgCosiCommit(const CosiCommit *msg)
layoutHome(); layoutHome();
} }
void fsm_msgCosiSign(const CosiSign *msg) void fsm_msgCosiSign(const CosiSign *msg) {
{
RESP_INIT(CosiSignature); RESP_INIT(CosiSignature);
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PARAM(msg->has_data, _("No data provided")); CHECK_PARAM(msg->has_data, _("No data provided"));
CHECK_PARAM(msg->has_global_commitment && msg->global_commitment.size == 32, _("Invalid global commitment")); CHECK_PARAM(msg->has_global_commitment && msg->global_commitment.size == 32,
CHECK_PARAM(msg->has_global_pubkey && msg->global_pubkey.size == 32, _("Invalid global pubkey")); _("Invalid global commitment"));
CHECK_PARAM(msg->has_global_pubkey && msg->global_pubkey.size == 32,
_("Invalid global pubkey"));
layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes, msg->data.size, true); layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes,
msg->data.size, true);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
@ -251,7 +277,8 @@ void fsm_msgCosiSign(const CosiSign *msg)
CHECK_PIN CHECK_PIN
const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n,
msg->address_n_count, NULL);
if (!node) return; if (!node) return;
uint8_t nonce[32]; uint8_t nonce[32];
@ -263,7 +290,9 @@ void fsm_msgCosiSign(const CosiSign *msg)
resp->has_signature = true; resp->has_signature = true;
resp->signature.size = 32; resp->signature.size = 32;
ed25519_cosi_sign(msg->data.bytes, msg->data.size, node->private_key, nonce, msg->global_commitment.bytes, msg->global_pubkey.bytes, resp->signature.bytes); ed25519_cosi_sign(msg->data.bytes, msg->data.size, node->private_key, nonce,
msg->global_commitment.bytes, msg->global_pubkey.bytes,
resp->signature.bytes);
msg_write(MessageType_MessageType_CosiSignature, resp); msg_write(MessageType_MessageType_CosiSignature, resp);
layoutHome(); layoutHome();

View File

@ -19,8 +19,7 @@
#if DEBUG_LINK #if DEBUG_LINK
void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) {
{
(void)msg; (void)msg;
// Do not use RESP_INIT because it clears msg_resp, but another message // Do not use RESP_INIT because it clears msg_resp, but another message
@ -44,41 +43,39 @@ void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg)
strlcpy(resp.reset_word, reset_get_word(), sizeof(resp.reset_word)); strlcpy(resp.reset_word, reset_get_word(), sizeof(resp.reset_word));
resp.has_recovery_fake_word = true; resp.has_recovery_fake_word = true;
strlcpy(resp.recovery_fake_word, recovery_get_fake_word(), sizeof(resp.recovery_fake_word)); strlcpy(resp.recovery_fake_word, recovery_get_fake_word(),
sizeof(resp.recovery_fake_word));
resp.has_recovery_word_pos = true; resp.has_recovery_word_pos = true;
resp.recovery_word_pos = recovery_get_word_pos(); resp.recovery_word_pos = recovery_get_word_pos();
resp.has_mnemonic_secret = config_getMnemonicBytes(resp.mnemonic_secret.bytes, sizeof(resp.mnemonic_secret.bytes), &resp.mnemonic_secret.size); resp.has_mnemonic_secret = config_getMnemonicBytes(
resp.mnemonic_secret.bytes, sizeof(resp.mnemonic_secret.bytes),
&resp.mnemonic_secret.size);
resp.mnemonic_type = 0; // BIP-39 resp.mnemonic_type = 0; // BIP-39
resp.has_node = config_dumpNode(&(resp.node)); resp.has_node = config_dumpNode(&(resp.node));
resp.has_passphrase_protection = config_getPassphraseProtection(&(resp.passphrase_protection)); resp.has_passphrase_protection =
config_getPassphraseProtection(&(resp.passphrase_protection));
msg_debug_write(MessageType_MessageType_DebugLinkState, &resp); msg_debug_write(MessageType_MessageType_DebugLinkState, &resp);
} }
void fsm_msgDebugLinkStop(const DebugLinkStop *msg) void fsm_msgDebugLinkStop(const DebugLinkStop *msg) { (void)msg; }
{
(void)msg;
}
void fsm_msgDebugLinkMemoryRead(const DebugLinkMemoryRead *msg) void fsm_msgDebugLinkMemoryRead(const DebugLinkMemoryRead *msg) {
{
RESP_INIT(DebugLinkMemory); RESP_INIT(DebugLinkMemory);
uint32_t length = 1024; uint32_t length = 1024;
if (msg->has_length && msg->length < length) if (msg->has_length && msg->length < length) length = msg->length;
length = msg->length;
resp->has_memory = true; resp->has_memory = true;
memcpy(resp->memory.bytes, FLASH_PTR(msg->address), length); memcpy(resp->memory.bytes, FLASH_PTR(msg->address), length);
resp->memory.size = length; resp->memory.size = length;
msg_debug_write(MessageType_MessageType_DebugLinkMemory, resp); msg_debug_write(MessageType_MessageType_DebugLinkMemory, resp);
} }
void fsm_msgDebugLinkMemoryWrite(const DebugLinkMemoryWrite *msg) void fsm_msgDebugLinkMemoryWrite(const DebugLinkMemoryWrite *msg) {
{
uint32_t length = msg->memory.size; uint32_t length = msg->memory.size;
if (msg->flash) { if (msg->flash) {
svc_flash_unlock(); svc_flash_unlock();
@ -97,8 +94,7 @@ void fsm_msgDebugLinkMemoryWrite(const DebugLinkMemoryWrite *msg)
} }
} }
void fsm_msgDebugLinkFlashErase(const DebugLinkFlashErase *msg) void fsm_msgDebugLinkFlashErase(const DebugLinkFlashErase *msg) {
{
svc_flash_unlock(); svc_flash_unlock();
svc_flash_erase_sector(msg->sector); svc_flash_erase_sector(msg->sector);
uint32_t dummy = svc_flash_lock(); uint32_t dummy = svc_flash_lock();

View File

@ -17,8 +17,7 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
void fsm_msgEthereumGetPublicKey(const EthereumGetPublicKey *msg) void fsm_msgEthereumGetPublicKey(const EthereumGetPublicKey *msg) {
{
RESP_INIT(EthereumPublicKey); RESP_INIT(EthereumPublicKey);
CHECK_INITIALIZED CHECK_INITIALIZED
@ -31,7 +30,8 @@ void fsm_msgEthereumGetPublicKey(const EthereumGetPublicKey *msg)
const char *curve = coin->curve_name; const char *curve = coin->curve_name;
uint32_t fingerprint; uint32_t fingerprint;
HDNode *node = node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count, &fingerprint); HDNode *node = node = fsm_getDerivedNode(curve, msg->address_n,
msg->address_n_count, &fingerprint);
if (!node) return; if (!node) return;
hdnode_fill_public_key(node); hdnode_fill_public_key(node);
@ -56,52 +56,58 @@ void fsm_msgEthereumGetPublicKey(const EthereumGetPublicKey *msg)
memcpy(resp->node.public_key.bytes, node->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, fingerprint, coin->xpub_magic, resp->xpub, sizeof(resp->xpub)); hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub,
sizeof(resp->xpub));
msg_write(MessageType_MessageType_EthereumPublicKey, resp); msg_write(MessageType_MessageType_EthereumPublicKey, resp);
layoutHome(); layoutHome();
} }
void fsm_msgEthereumSignTx(EthereumSignTx *msg) void fsm_msgEthereumSignTx(EthereumSignTx *msg) {
{
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PIN CHECK_PIN
const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n,
msg->address_n_count, NULL);
if (!node) return; if (!node) return;
ethereum_signing_init(msg, node); ethereum_signing_init(msg, node);
} }
void fsm_msgEthereumTxAck(const EthereumTxAck *msg) void fsm_msgEthereumTxAck(const EthereumTxAck *msg) {
{
ethereum_signing_txack(msg); ethereum_signing_txack(msg);
} }
void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg) void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg) {
{
RESP_INIT(EthereumAddress); RESP_INIT(EthereumAddress);
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PIN CHECK_PIN
const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n,
msg->address_n_count, NULL);
if (!node) return; if (!node) return;
uint8_t pubkeyhash[20]; uint8_t pubkeyhash[20];
if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash)) if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash)) return;
return;
uint32_t slip44 = (msg->address_n_count > 1) ? (msg->address_n[1] & 0x7fffffff) : 0; uint32_t slip44 =
(msg->address_n_count > 1) ? (msg->address_n[1] & 0x7fffffff) : 0;
bool rskip60 = false; bool rskip60 = false;
uint32_t chain_id = 0; uint32_t chain_id = 0;
// constants from trezor-common/defs/ethereum/networks.json // constants from trezor-common/defs/ethereum/networks.json
switch (slip44) { switch (slip44) {
case 137: rskip60 = true; chain_id = 30; break; case 137:
case 37310: rskip60 = true; chain_id = 31; break; rskip60 = true;
chain_id = 30;
break;
case 37310:
rskip60 = true;
chain_id = 31;
break;
} }
resp->has_address = true; resp->has_address = true;
@ -114,7 +120,8 @@ void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg)
char desc[16]; char desc[16];
strlcpy(desc, "Address:", sizeof(desc)); strlcpy(desc, "Address:", sizeof(desc));
if (!fsm_layoutAddress(resp->address, desc, false, 0, msg->address_n, msg->address_n_count, true)) { if (!fsm_layoutAddress(resp->address, desc, false, 0, msg->address_n,
msg->address_n_count, true)) {
return; return;
} }
} }
@ -123,8 +130,7 @@ void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg)
layoutHome(); layoutHome();
} }
void fsm_msgEthereumSignMessage(const EthereumSignMessage *msg) void fsm_msgEthereumSignMessage(const EthereumSignMessage *msg) {
{
RESP_INIT(EthereumMessageSignature); RESP_INIT(EthereumMessageSignature);
CHECK_INITIALIZED CHECK_INITIALIZED
@ -138,15 +144,15 @@ void fsm_msgEthereumSignMessage(const EthereumSignMessage *msg)
CHECK_PIN CHECK_PIN
const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n,
msg->address_n_count, NULL);
if (!node) return; if (!node) return;
ethereum_message_sign(msg, node, resp); ethereum_message_sign(msg, node, resp);
layoutHome(); layoutHome();
} }
void fsm_msgEthereumVerifyMessage(const EthereumVerifyMessage *msg) void fsm_msgEthereumVerifyMessage(const EthereumVerifyMessage *msg) {
{
CHECK_PARAM(msg->has_address, _("No address provided")); CHECK_PARAM(msg->has_address, _("No address provided"));
CHECK_PARAM(msg->has_message, _("No message provided")); CHECK_PARAM(msg->has_message, _("No message provided"));

View File

@ -17,15 +17,15 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
void fsm_msgLiskGetAddress(const LiskGetAddress *msg) void fsm_msgLiskGetAddress(const LiskGetAddress *msg) {
{
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PIN CHECK_PIN
RESP_INIT(LiskAddress); RESP_INIT(LiskAddress);
HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n,
msg->address_n_count, NULL);
if (!node) return; if (!node) return;
resp->has_address = true; resp->has_address = true;
@ -33,7 +33,8 @@ void fsm_msgLiskGetAddress(const LiskGetAddress *msg)
lisk_get_address_from_public_key(&node->public_key[1], resp->address); lisk_get_address_from_public_key(&node->public_key[1], resp->address);
if (msg->has_show_display && msg->show_display) { if (msg->has_show_display && msg->show_display) {
if (!fsm_layoutAddress(resp->address, _("Address:"), true, 0, msg->address_n, msg->address_n_count, false)) { if (!fsm_layoutAddress(resp->address, _("Address:"), true, 0,
msg->address_n, msg->address_n_count, false)) {
return; return;
} }
} }
@ -43,15 +44,15 @@ void fsm_msgLiskGetAddress(const LiskGetAddress *msg)
layoutHome(); layoutHome();
} }
void fsm_msgLiskGetPublicKey(const LiskGetPublicKey *msg) void fsm_msgLiskGetPublicKey(const LiskGetPublicKey *msg) {
{
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PIN CHECK_PIN
RESP_INIT(LiskPublicKey); RESP_INIT(LiskPublicKey);
HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n,
msg->address_n_count, NULL);
if (!node) return; if (!node) return;
hdnode_fill_public_key(node); hdnode_fill_public_key(node);
@ -68,22 +69,23 @@ void fsm_msgLiskGetPublicKey(const LiskGetPublicKey *msg)
} }
} }
memcpy(&resp->public_key.bytes, &node->public_key[1], sizeof(resp->public_key.bytes)); memcpy(&resp->public_key.bytes, &node->public_key[1],
sizeof(resp->public_key.bytes));
msg_write(MessageType_MessageType_LiskPublicKey, resp); msg_write(MessageType_MessageType_LiskPublicKey, resp);
layoutHome(); layoutHome();
} }
void fsm_msgLiskSignMessage(const LiskSignMessage *msg) void fsm_msgLiskSignMessage(const LiskSignMessage *msg) {
{
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PIN CHECK_PIN
RESP_INIT(LiskMessageSignature); RESP_INIT(LiskMessageSignature);
HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n,
msg->address_n_count, NULL);
if (!node) return; if (!node) return;
hdnode_fill_public_key(node); hdnode_fill_public_key(node);
@ -95,11 +97,11 @@ void fsm_msgLiskSignMessage(const LiskSignMessage *msg)
layoutHome(); layoutHome();
} }
void fsm_msgLiskVerifyMessage(const LiskVerifyMessage *msg) void fsm_msgLiskVerifyMessage(const LiskVerifyMessage *msg) {
{
if (lisk_verify_message(msg)) { if (lisk_verify_message(msg)) {
char address[MAX_LISK_ADDRESS_SIZE]; char address[MAX_LISK_ADDRESS_SIZE];
lisk_get_address_from_public_key((const uint8_t*)&msg->public_key, address); lisk_get_address_from_public_key((const uint8_t *)&msg->public_key,
address);
layoutLiskVerifyAddress(address); layoutLiskVerifyAddress(address);
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
@ -121,15 +123,15 @@ void fsm_msgLiskVerifyMessage(const LiskVerifyMessage *msg)
layoutHome(); layoutHome();
} }
void fsm_msgLiskSignTx(LiskSignTx *msg) void fsm_msgLiskSignTx(LiskSignTx *msg) {
{
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PIN CHECK_PIN
RESP_INIT(LiskSignedTx); RESP_INIT(LiskSignedTx);
HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n,
msg->address_n_count, NULL);
if (!node) return; if (!node) return;
hdnode_fill_public_key(node); hdnode_fill_public_key(node);

View File

@ -17,32 +17,33 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
void fsm_msgNEMGetAddress(NEMGetAddress *msg) void fsm_msgNEMGetAddress(NEMGetAddress *msg) {
{
if (!msg->has_network) { if (!msg->has_network) {
msg->network = NEM_NETWORK_MAINNET; msg->network = NEM_NETWORK_MAINNET;
} }
const char *network; const char *network;
CHECK_PARAM((network = nem_network_name(msg->network)), _("Invalid NEM network")); CHECK_PARAM((network = nem_network_name(msg->network)),
_("Invalid NEM network"));
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PIN CHECK_PIN
RESP_INIT(NEMAddress); RESP_INIT(NEMAddress);
HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n, msg->address_n_count, NULL); HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n,
msg->address_n_count, NULL);
if (!node) return; if (!node) return;
if (!hdnode_get_nem_address(node, msg->network, resp->address)) if (!hdnode_get_nem_address(node, msg->network, resp->address)) return;
return;
if (msg->has_show_display && msg->show_display) { if (msg->has_show_display && msg->show_display) {
char desc[16]; char desc[16];
strlcpy(desc, network, sizeof(desc)); strlcpy(desc, network, sizeof(desc));
strlcat(desc, ":", sizeof(desc)); strlcat(desc, ":", sizeof(desc));
if (!fsm_layoutAddress(resp->address, desc, true, 0, msg->address_n, msg->address_n_count, false)) { if (!fsm_layoutAddress(resp->address, desc, true, 0, msg->address_n,
msg->address_n_count, false)) {
return; return;
} }
} }
@ -55,33 +56,45 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) {
const char *reason; const char *reason;
#define NEM_CHECK_PARAM(s) CHECK_PARAM((reason = (s)) == NULL, reason) #define NEM_CHECK_PARAM(s) CHECK_PARAM((reason = (s)) == NULL, reason)
#define NEM_CHECK_PARAM_WHEN(b, s) CHECK_PARAM(!(b) || (reason = (s)) == NULL, reason) #define NEM_CHECK_PARAM_WHEN(b, s) \
CHECK_PARAM(!(b) || (reason = (s)) == NULL, reason)
CHECK_PARAM(msg->has_transaction, _("No common provided")); CHECK_PARAM(msg->has_transaction, _("No common provided"));
// Ensure exactly one transaction is provided // Ensure exactly one transaction is provided
unsigned int provided = msg->has_transfer + unsigned int provided = msg->has_transfer + msg->has_provision_namespace +
msg->has_provision_namespace + msg->has_mosaic_creation + msg->has_supply_change +
msg->has_mosaic_creation +
msg->has_supply_change +
msg->has_aggregate_modification + msg->has_aggregate_modification +
msg->has_importance_transfer; msg->has_importance_transfer;
CHECK_PARAM(provided != 0, _("No transaction provided")); CHECK_PARAM(provided != 0, _("No transaction provided"));
CHECK_PARAM(provided == 1, _("More than one transaction provided")); CHECK_PARAM(provided == 1, _("More than one transaction provided"));
NEM_CHECK_PARAM(nem_validate_common(&msg->transaction, false)); NEM_CHECK_PARAM(nem_validate_common(&msg->transaction, false));
NEM_CHECK_PARAM_WHEN(msg->has_transfer, nem_validate_transfer(&msg->transfer, msg->transaction.network)); NEM_CHECK_PARAM_WHEN(
NEM_CHECK_PARAM_WHEN(msg->has_provision_namespace, nem_validate_provision_namespace(&msg->provision_namespace, msg->transaction.network)); msg->has_transfer,
NEM_CHECK_PARAM_WHEN(msg->has_mosaic_creation, nem_validate_mosaic_creation(&msg->mosaic_creation, msg->transaction.network)); nem_validate_transfer(&msg->transfer, msg->transaction.network));
NEM_CHECK_PARAM_WHEN(msg->has_supply_change, nem_validate_supply_change(&msg->supply_change)); NEM_CHECK_PARAM_WHEN(
NEM_CHECK_PARAM_WHEN(msg->has_aggregate_modification, nem_validate_aggregate_modification(&msg->aggregate_modification, !msg->has_multisig)); msg->has_provision_namespace,
NEM_CHECK_PARAM_WHEN(msg->has_importance_transfer, nem_validate_importance_transfer(&msg->importance_transfer)); nem_validate_provision_namespace(&msg->provision_namespace,
msg->transaction.network));
NEM_CHECK_PARAM_WHEN(msg->has_mosaic_creation,
nem_validate_mosaic_creation(&msg->mosaic_creation,
msg->transaction.network));
NEM_CHECK_PARAM_WHEN(msg->has_supply_change,
nem_validate_supply_change(&msg->supply_change));
NEM_CHECK_PARAM_WHEN(msg->has_aggregate_modification,
nem_validate_aggregate_modification(
&msg->aggregate_modification, !msg->has_multisig));
NEM_CHECK_PARAM_WHEN(
msg->has_importance_transfer,
nem_validate_importance_transfer(&msg->importance_transfer));
bool cosigning = msg->has_cosigning && msg->cosigning; bool cosigning = msg->has_cosigning && msg->cosigning;
if (msg->has_multisig) { if (msg->has_multisig) {
NEM_CHECK_PARAM(nem_validate_common(&msg->multisig, true)); NEM_CHECK_PARAM(nem_validate_common(&msg->multisig, true));
CHECK_PARAM(msg->transaction.network == msg->multisig.network, _("Inner transaction network is different")); CHECK_PARAM(msg->transaction.network == msg->multisig.network,
_("Inner transaction network is different"));
} else { } else {
CHECK_PARAM(!cosigning, _("No multisig transaction to cosign")); CHECK_PARAM(!cosigning, _("No multisig transaction to cosign"));
} }
@ -96,7 +109,8 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) {
nem_get_address(msg->multisig.signer.bytes, msg->multisig.network, address); nem_get_address(msg->multisig.signer.bytes, msg->multisig.network, address);
if (!nem_askMultisig(address, network, cosigning, msg->transaction.fee)) { if (!nem_askMultisig(address, network, cosigning, msg->transaction.fee)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); fsm_sendFailure(FailureType_Failure_ActionCancelled,
_("Signing cancelled by user"));
layoutHome(); layoutHome();
return; return;
} }
@ -104,91 +118,118 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) {
RESP_INIT(NEMSignedTx); RESP_INIT(NEMSignedTx);
HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->transaction.address_n, msg->transaction.address_n_count, NULL); HDNode *node =
fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->transaction.address_n,
msg->transaction.address_n_count, NULL);
if (!node) return; if (!node) return;
hdnode_fill_public_key(node); hdnode_fill_public_key(node);
const NEMTransactionCommon *common = msg->has_multisig ? &msg->multisig : &msg->transaction; const NEMTransactionCommon *common =
msg->has_multisig ? &msg->multisig : &msg->transaction;
char address[NEM_ADDRESS_SIZE + 1]; char address[NEM_ADDRESS_SIZE + 1];
hdnode_get_nem_address(node, common->network, address); hdnode_get_nem_address(node, common->network, address);
if (msg->has_transfer) { if (msg->has_transfer) {
msg->transfer.mosaics_count = nem_canonicalizeMosaics(msg->transfer.mosaics, msg->transfer.mosaics_count); msg->transfer.mosaics_count = nem_canonicalizeMosaics(
msg->transfer.mosaics, msg->transfer.mosaics_count);
} }
if (msg->has_transfer && !nem_askTransfer(common, &msg->transfer, network)) { if (msg->has_transfer && !nem_askTransfer(common, &msg->transfer, network)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); fsm_sendFailure(FailureType_Failure_ActionCancelled,
_("Signing cancelled by user"));
layoutHome(); layoutHome();
return; return;
} }
if (msg->has_provision_namespace && !nem_askProvisionNamespace(common, &msg->provision_namespace, network)) { if (msg->has_provision_namespace &&
fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); !nem_askProvisionNamespace(common, &msg->provision_namespace, network)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled,
_("Signing cancelled by user"));
layoutHome(); layoutHome();
return; return;
} }
if (msg->has_mosaic_creation && !nem_askMosaicCreation(common, &msg->mosaic_creation, network, address)) { if (msg->has_mosaic_creation &&
fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); !nem_askMosaicCreation(common, &msg->mosaic_creation, network, address)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled,
_("Signing cancelled by user"));
layoutHome(); layoutHome();
return; return;
} }
if (msg->has_supply_change && !nem_askSupplyChange(common, &msg->supply_change, network)) { if (msg->has_supply_change &&
fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); !nem_askSupplyChange(common, &msg->supply_change, network)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled,
_("Signing cancelled by user"));
layoutHome(); layoutHome();
return; return;
} }
if (msg->has_aggregate_modification && !nem_askAggregateModification(common, &msg->aggregate_modification, network, !msg->has_multisig)) { if (msg->has_aggregate_modification &&
fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); !nem_askAggregateModification(common, &msg->aggregate_modification,
network, !msg->has_multisig)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled,
_("Signing cancelled by user"));
layoutHome(); layoutHome();
return; return;
} }
if (msg->has_importance_transfer && !nem_askImportanceTransfer(common, &msg->importance_transfer, network)) { if (msg->has_importance_transfer &&
fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user")); !nem_askImportanceTransfer(common, &msg->importance_transfer, network)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled,
_("Signing cancelled by user"));
layoutHome(); layoutHome();
return; return;
} }
nem_transaction_ctx context; nem_transaction_ctx context;
nem_transaction_start(&context, &node->public_key[1], resp->data.bytes, sizeof(resp->data.bytes)); nem_transaction_start(&context, &node->public_key[1], resp->data.bytes,
sizeof(resp->data.bytes));
if (msg->has_multisig) { if (msg->has_multisig) {
uint8_t buffer[sizeof(resp->data.bytes)]; uint8_t buffer[sizeof(resp->data.bytes)];
nem_transaction_ctx inner; nem_transaction_ctx inner;
nem_transaction_start(&inner, msg->multisig.signer.bytes, buffer, sizeof(buffer)); nem_transaction_start(&inner, msg->multisig.signer.bytes, buffer,
sizeof(buffer));
if (msg->has_transfer && !nem_fsmTransfer(&inner, NULL, &msg->multisig, &msg->transfer)) { if (msg->has_transfer &&
!nem_fsmTransfer(&inner, NULL, &msg->multisig, &msg->transfer)) {
layoutHome(); layoutHome();
return; return;
} }
if (msg->has_provision_namespace && !nem_fsmProvisionNamespace(&inner, &msg->multisig, &msg->provision_namespace)) { if (msg->has_provision_namespace &&
!nem_fsmProvisionNamespace(&inner, &msg->multisig,
&msg->provision_namespace)) {
layoutHome(); layoutHome();
return; return;
} }
if (msg->has_mosaic_creation && !nem_fsmMosaicCreation(&inner, &msg->multisig, &msg->mosaic_creation)) { if (msg->has_mosaic_creation &&
!nem_fsmMosaicCreation(&inner, &msg->multisig, &msg->mosaic_creation)) {
layoutHome(); layoutHome();
return; return;
} }
if (msg->has_supply_change && !nem_fsmSupplyChange(&inner, &msg->multisig, &msg->supply_change)) { if (msg->has_supply_change &&
!nem_fsmSupplyChange(&inner, &msg->multisig, &msg->supply_change)) {
layoutHome(); layoutHome();
return; return;
} }
if (msg->has_aggregate_modification && !nem_fsmAggregateModification(&inner, &msg->multisig, &msg->aggregate_modification)) { if (msg->has_aggregate_modification &&
!nem_fsmAggregateModification(&inner, &msg->multisig,
&msg->aggregate_modification)) {
layoutHome(); layoutHome();
return; return;
} }
if (msg->has_importance_transfer && !nem_fsmImportanceTransfer(&inner, &msg->multisig, &msg->importance_transfer)) { if (msg->has_importance_transfer &&
!nem_fsmImportanceTransfer(&inner, &msg->multisig,
&msg->importance_transfer)) {
layoutHome(); layoutHome();
return; return;
} }
@ -198,39 +239,51 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) {
return; return;
} }
} else { } else {
if (msg->has_transfer && !nem_fsmTransfer(&context, node, &msg->transaction, &msg->transfer)) { if (msg->has_transfer &&
!nem_fsmTransfer(&context, node, &msg->transaction, &msg->transfer)) {
layoutHome(); layoutHome();
return; return;
} }
if (msg->has_provision_namespace && !nem_fsmProvisionNamespace(&context, &msg->transaction, &msg->provision_namespace)) { if (msg->has_provision_namespace &&
!nem_fsmProvisionNamespace(&context, &msg->transaction,
&msg->provision_namespace)) {
layoutHome(); layoutHome();
return; return;
} }
if (msg->has_mosaic_creation && !nem_fsmMosaicCreation(&context, &msg->transaction, &msg->mosaic_creation)) { if (msg->has_mosaic_creation &&
!nem_fsmMosaicCreation(&context, &msg->transaction,
&msg->mosaic_creation)) {
layoutHome(); layoutHome();
return; return;
} }
if (msg->has_supply_change && !nem_fsmSupplyChange(&context, &msg->transaction, &msg->supply_change)) { if (msg->has_supply_change &&
!nem_fsmSupplyChange(&context, &msg->transaction,
&msg->supply_change)) {
layoutHome(); layoutHome();
return; return;
} }
if (msg->has_aggregate_modification && !nem_fsmAggregateModification(&context, &msg->transaction, &msg->aggregate_modification)) { if (msg->has_aggregate_modification &&
!nem_fsmAggregateModification(&context, &msg->transaction,
&msg->aggregate_modification)) {
layoutHome(); layoutHome();
return; return;
} }
if (msg->has_importance_transfer && !nem_fsmImportanceTransfer(&context, &msg->transaction, &msg->importance_transfer)) { if (msg->has_importance_transfer &&
!nem_fsmImportanceTransfer(&context, &msg->transaction,
&msg->importance_transfer)) {
layoutHome(); layoutHome();
return; return;
} }
} }
resp->has_data = true; resp->has_data = true;
resp->data.size = nem_transaction_end(&context, node->private_key, resp->signature.bytes); resp->data.size =
nem_transaction_end(&context, node->private_key, resp->signature.bytes);
resp->has_signature = true; resp->has_signature = true;
resp->signature.size = sizeof(ed25519_signature); resp->signature.size = sizeof(ed25519_signature);
@ -239,27 +292,23 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) {
layoutHome(); layoutHome();
} }
void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg) void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg) {
{
RESP_INIT(NEMDecryptedMessage); RESP_INIT(NEMDecryptedMessage);
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PARAM(nem_network_name(msg->network), _("Invalid NEM network")); CHECK_PARAM(nem_network_name(msg->network), _("Invalid NEM network"));
CHECK_PARAM(msg->has_payload, _("No payload provided")); CHECK_PARAM(msg->has_payload, _("No payload provided"));
CHECK_PARAM(msg->payload.size >= NEM_ENCRYPTED_PAYLOAD_SIZE(0), _("Invalid encrypted payload")); CHECK_PARAM(msg->payload.size >= NEM_ENCRYPTED_PAYLOAD_SIZE(0),
_("Invalid encrypted payload"));
CHECK_PARAM(msg->has_public_key, _("No public key provided")); CHECK_PARAM(msg->has_public_key, _("No public key provided"));
CHECK_PARAM(msg->public_key.size == 32, _("Invalid public key")); CHECK_PARAM(msg->public_key.size == 32, _("Invalid public key"));
char address[NEM_ADDRESS_SIZE + 1]; char address[NEM_ADDRESS_SIZE + 1];
nem_get_address(msg->public_key.bytes, msg->network, address); nem_get_address(msg->public_key.bytes, msg->network, address);
layoutNEMDialog(&bmp_icon_question, layoutNEMDialog(&bmp_icon_question, _("Cancel"), _("Confirm"),
_("Cancel"), _("Decrypt message"), _("Confirm address?"), address);
_("Confirm"),
_("Decrypt message"),
_("Confirm address?"),
address);
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
@ -268,7 +317,8 @@ void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg)
CHECK_PIN CHECK_PIN
const HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n, msg->address_n_count, NULL); const HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n,
msg->address_n_count, NULL);
if (!node) return; if (!node) return;
const uint8_t *salt = msg->payload.bytes; const uint8_t *salt = msg->payload.bytes;
@ -278,15 +328,11 @@ void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg)
size_t size = msg->payload.size - NEM_SALT_SIZE - AES_BLOCK_SIZE; size_t size = msg->payload.size - NEM_SALT_SIZE - AES_BLOCK_SIZE;
// hdnode_nem_decrypt mutates the IV, so this will modify msg // hdnode_nem_decrypt mutates the IV, so this will modify msg
bool ret = hdnode_nem_decrypt(node, bool ret = hdnode_nem_decrypt(node, msg->public_key.bytes, iv, salt, payload,
msg->public_key.bytes, size, resp->payload.bytes);
iv,
salt,
payload,
size,
resp->payload.bytes);
if (!ret) { if (!ret) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to decrypt payload")); fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to decrypt payload"));
layoutHome(); layoutHome();
return; return;
} }

View File

@ -17,8 +17,7 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
void fsm_msgStellarGetAddress(const StellarGetAddress *msg) void fsm_msgStellarGetAddress(const StellarGetAddress *msg) {
{
RESP_INIT(StellarAddress); RESP_INIT(StellarAddress);
CHECK_INITIALIZED CHECK_INITIALIZED
@ -27,19 +26,16 @@ void fsm_msgStellarGetAddress(const StellarGetAddress *msg)
const HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); const HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count);
if (!node) { if (!node) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to derive private key"));
return; return;
} }
if (msg->has_show_display && msg->show_display) { if (msg->has_show_display && msg->show_display) {
const char **str_addr_rows = stellar_lineBreakAddress(node->public_key + 1); const char **str_addr_rows = stellar_lineBreakAddress(node->public_key + 1);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), _("Share public account ID?"), layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"),
str_addr_rows[0], _("Share public account ID?"), str_addr_rows[0],
str_addr_rows[1], str_addr_rows[1], str_addr_rows[2], NULL, NULL, NULL);
str_addr_rows[2],
NULL,
NULL, NULL
);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
@ -48,20 +44,21 @@ void fsm_msgStellarGetAddress(const StellarGetAddress *msg)
} }
resp->has_address = true; resp->has_address = true;
stellar_publicAddressAsStr(node->public_key + 1, resp->address, sizeof(resp->address)); stellar_publicAddressAsStr(node->public_key + 1, resp->address,
sizeof(resp->address));
msg_write(MessageType_MessageType_StellarAddress, resp); msg_write(MessageType_MessageType_StellarAddress, resp);
layoutHome(); layoutHome();
} }
void fsm_msgStellarSignTx(const StellarSignTx *msg) void fsm_msgStellarSignTx(const StellarSignTx *msg) {
{
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PIN CHECK_PIN
if (!stellar_signingInit(msg)) { if (!stellar_signingInit(msg)) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to derive private key"));
layoutHome(); layoutHome();
return; return;
} }
@ -75,8 +72,7 @@ void fsm_msgStellarSignTx(const StellarSignTx *msg)
msg_write(MessageType_MessageType_StellarTxOpRequest, resp); msg_write(MessageType_MessageType_StellarTxOpRequest, resp);
} }
void fsm_msgStellarCreateAccountOp(const StellarCreateAccountOp *msg) void fsm_msgStellarCreateAccountOp(const StellarCreateAccountOp *msg) {
{
if (!stellar_confirmCreateAccountOp(msg)) return; if (!stellar_confirmCreateAccountOp(msg)) return;
if (stellar_allOperationsConfirmed()) { if (stellar_allOperationsConfirmed()) {
@ -94,8 +90,7 @@ void fsm_msgStellarCreateAccountOp(const StellarCreateAccountOp *msg)
} }
} }
void fsm_msgStellarPaymentOp(const StellarPaymentOp *msg) void fsm_msgStellarPaymentOp(const StellarPaymentOp *msg) {
{
// This will display additional dialogs to the user // This will display additional dialogs to the user
if (!stellar_confirmPaymentOp(msg)) return; if (!stellar_confirmPaymentOp(msg)) return;
@ -115,8 +110,7 @@ void fsm_msgStellarPaymentOp(const StellarPaymentOp *msg)
} }
} }
void fsm_msgStellarPathPaymentOp(const StellarPathPaymentOp *msg) void fsm_msgStellarPathPaymentOp(const StellarPathPaymentOp *msg) {
{
if (!stellar_confirmPathPaymentOp(msg)) return; if (!stellar_confirmPathPaymentOp(msg)) return;
if (stellar_allOperationsConfirmed()) { if (stellar_allOperationsConfirmed()) {
@ -134,8 +128,7 @@ void fsm_msgStellarPathPaymentOp(const StellarPathPaymentOp *msg)
} }
} }
void fsm_msgStellarManageOfferOp(const StellarManageOfferOp *msg) void fsm_msgStellarManageOfferOp(const StellarManageOfferOp *msg) {
{
if (!stellar_confirmManageOfferOp(msg)) return; if (!stellar_confirmManageOfferOp(msg)) return;
if (stellar_allOperationsConfirmed()) { if (stellar_allOperationsConfirmed()) {
@ -153,8 +146,8 @@ void fsm_msgStellarManageOfferOp(const StellarManageOfferOp *msg)
} }
} }
void fsm_msgStellarCreatePassiveOfferOp(const StellarCreatePassiveOfferOp *msg) void fsm_msgStellarCreatePassiveOfferOp(
{ const StellarCreatePassiveOfferOp *msg) {
if (!stellar_confirmCreatePassiveOfferOp(msg)) return; if (!stellar_confirmCreatePassiveOfferOp(msg)) return;
if (stellar_allOperationsConfirmed()) { if (stellar_allOperationsConfirmed()) {
@ -172,8 +165,7 @@ void fsm_msgStellarCreatePassiveOfferOp(const StellarCreatePassiveOfferOp *msg)
} }
} }
void fsm_msgStellarSetOptionsOp(const StellarSetOptionsOp *msg) void fsm_msgStellarSetOptionsOp(const StellarSetOptionsOp *msg) {
{
if (!stellar_confirmSetOptionsOp(msg)) return; if (!stellar_confirmSetOptionsOp(msg)) return;
if (stellar_allOperationsConfirmed()) { if (stellar_allOperationsConfirmed()) {
@ -191,8 +183,7 @@ void fsm_msgStellarSetOptionsOp(const StellarSetOptionsOp *msg)
} }
} }
void fsm_msgStellarChangeTrustOp(const StellarChangeTrustOp *msg) void fsm_msgStellarChangeTrustOp(const StellarChangeTrustOp *msg) {
{
if (!stellar_confirmChangeTrustOp(msg)) return; if (!stellar_confirmChangeTrustOp(msg)) return;
if (stellar_allOperationsConfirmed()) { if (stellar_allOperationsConfirmed()) {
@ -210,8 +201,7 @@ void fsm_msgStellarChangeTrustOp(const StellarChangeTrustOp *msg)
} }
} }
void fsm_msgStellarAllowTrustOp(const StellarAllowTrustOp *msg) void fsm_msgStellarAllowTrustOp(const StellarAllowTrustOp *msg) {
{
if (!stellar_confirmAllowTrustOp(msg)) return; if (!stellar_confirmAllowTrustOp(msg)) return;
if (stellar_allOperationsConfirmed()) { if (stellar_allOperationsConfirmed()) {
@ -229,8 +219,7 @@ void fsm_msgStellarAllowTrustOp(const StellarAllowTrustOp *msg)
} }
} }
void fsm_msgStellarAccountMergeOp(const StellarAccountMergeOp *msg) void fsm_msgStellarAccountMergeOp(const StellarAccountMergeOp *msg) {
{
if (!stellar_confirmAccountMergeOp(msg)) return; if (!stellar_confirmAccountMergeOp(msg)) return;
if (stellar_allOperationsConfirmed()) { if (stellar_allOperationsConfirmed()) {
@ -248,8 +237,7 @@ void fsm_msgStellarAccountMergeOp(const StellarAccountMergeOp *msg)
} }
} }
void fsm_msgStellarManageDataOp(const StellarManageDataOp *msg) void fsm_msgStellarManageDataOp(const StellarManageDataOp *msg) {
{
if (!stellar_confirmManageDataOp(msg)) return; if (!stellar_confirmManageDataOp(msg)) return;
if (stellar_allOperationsConfirmed()) { if (stellar_allOperationsConfirmed()) {
@ -267,8 +255,7 @@ void fsm_msgStellarManageDataOp(const StellarManageDataOp *msg)
} }
} }
void fsm_msgStellarBumpSequenceOp(const StellarBumpSequenceOp *msg) void fsm_msgStellarBumpSequenceOp(const StellarBumpSequenceOp *msg) {
{
if (!stellar_confirmBumpSequenceOp(msg)) return; if (!stellar_confirmBumpSequenceOp(msg)) return;
if (stellar_allOperationsConfirmed()) { if (stellar_allOperationsConfirmed()) {

View File

@ -17,47 +17,54 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <ctype.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <ctype.h>
#include "layout2.h"
#include "config.h"
#include "oled.h"
#include "bitmaps.h"
#include "string.h"
#include "util.h"
#include "qrcodegen.h"
#include "timer.h"
#include "bignum.h" #include "bignum.h"
#include "secp256k1.h" #include "bitmaps.h"
#include "nem2.h" #include "config.h"
#include "gettext.h" #include "gettext.h"
#include "layout2.h"
#include "memzero.h" #include "memzero.h"
#include "nem2.h"
#include "oled.h"
#include "qrcodegen.h"
#include "secp256k1.h"
#include "string.h"
#include "timer.h"
#include "util.h"
#define BITCOIN_DIVISIBILITY (8) #define BITCOIN_DIVISIBILITY (8)
static const char *slip44_extras(uint32_t coin_type) static const char *slip44_extras(uint32_t coin_type) {
{
if ((coin_type & 0x80000000) == 0) { if ((coin_type & 0x80000000) == 0) {
return 0; return 0;
} }
switch (coin_type & 0x7fffffff) { switch (coin_type & 0x7fffffff) {
case 40: return "EXP"; // Expanse case 40:
case 43: return "NEM"; // NEM return "EXP"; // Expanse
case 60: return "ETH"; // Ethereum Mainnet case 43:
case 61: return "ETC"; // Ethereum Classic Mainnet return "NEM"; // NEM
case 108: return "UBQ"; // UBIQ case 60:
case 137: return "RSK"; // Rootstock Mainnet return "ETH"; // Ethereum Mainnet
case 37310: return "tRSK"; // Rootstock Testnet case 61:
return "ETC"; // Ethereum Classic Mainnet
case 108:
return "UBQ"; // UBIQ
case 137:
return "RSK"; // Rootstock Mainnet
case 37310:
return "tRSK"; // Rootstock Testnet
} }
return 0; return 0;
} }
#define BIP32_MAX_LAST_ELEMENT 1000000 #define BIP32_MAX_LAST_ELEMENT 1000000
static const char *address_n_str(const uint32_t *address_n, size_t address_n_count, bool address_is_account) static const char *address_n_str(const uint32_t *address_n,
{ size_t address_n_count,
bool address_is_account) {
if (address_n_count > 8) { if (address_n_count > 8) {
return _("Unknown long path"); return _("Unknown long path");
} }
@ -68,11 +75,10 @@ static const char *address_n_str(const uint32_t *address_n, size_t address_n_cou
// known BIP44/49 path // known BIP44/49 path
static char path[100]; static char path[100];
if (address_n_count == 5 && if (address_n_count == 5 &&
(address_n[0] == (0x80000000 + 44) || address_n[0] == (0x80000000 + 49) || address_n[0] == (0x80000000 + 84)) && (address_n[0] == (0x80000000 + 44) || address_n[0] == (0x80000000 + 49) ||
(address_n[1] & 0x80000000) && address_n[0] == (0x80000000 + 84)) &&
(address_n[2] & 0x80000000) && (address_n[1] & 0x80000000) && (address_n[2] & 0x80000000) &&
(address_n[3] <= 1) && (address_n[3] <= 1) && (address_n[4] <= BIP32_MAX_LAST_ELEMENT)) {
(address_n[4] <= BIP32_MAX_LAST_ELEMENT)) {
bool native_segwit = (address_n[0] == (0x80000000 + 84)); bool native_segwit = (address_n[0] == (0x80000000 + 84));
bool p2sh_segwit = (address_n[0] == (0x80000000 + 49)); bool p2sh_segwit = (address_n[0] == (0x80000000 + 49));
bool legacy = false; bool legacy = false;
@ -82,8 +88,7 @@ static const char *address_n_str(const uint32_t *address_n, size_t address_n_cou
if (coin && coin->has_segwit && coin->bech32_prefix) { if (coin && coin->has_segwit && coin->bech32_prefix) {
abbr = coin->coin_shortcut + 1; abbr = coin->coin_shortcut + 1;
} }
} else } else if (p2sh_segwit) {
if (p2sh_segwit) {
if (coin && coin->has_segwit && coin->has_address_type_p2sh) { if (coin && coin->has_segwit && coin->has_address_type_p2sh) {
abbr = coin->coin_shortcut + 1; abbr = coin->coin_shortcut + 1;
} }
@ -97,7 +102,9 @@ static const char *address_n_str(const uint32_t *address_n, size_t address_n_cou
abbr = slip44_extras(address_n[1]); abbr = slip44_extras(address_n[1]);
} }
} }
const uint32_t accnum = address_is_account ? ((address_n[4] & 0x7fffffff) + 1) : (address_n[2] & 0x7fffffff) + 1; const uint32_t accnum = address_is_account
? ((address_n[4] & 0x7fffffff) + 1)
: (address_n[2] & 0x7fffffff) + 1;
if (abbr && accnum < 100) { if (abbr && accnum < 100) {
memzero(path, sizeof(path)); memzero(path, sizeof(path));
strlcpy(path, abbr, sizeof(path)); strlcpy(path, abbr, sizeof(path));
@ -132,34 +139,43 @@ static const char *address_n_str(const uint32_t *address_n, size_t address_n_cou
static char address_str[7 + 8 * (1 + 10 + 1) + 1]; static char address_str[7 + 8 * (1 + 10 + 1) + 1];
char *c = address_str + sizeof(address_str) - 1; char *c = address_str + sizeof(address_str) - 1;
*c = 0; c--; *c = 0;
c--;
for (int n = (int)address_n_count - 1; n >= 0; n--) { for (int n = (int)address_n_count - 1; n >= 0; n--) {
uint32_t i = address_n[n]; uint32_t i = address_n[n];
if (i & 0x80000000) { if (i & 0x80000000) {
*c = '\''; c--; *c = '\'';
c--;
} }
i = i & 0x7fffffff; i = i & 0x7fffffff;
do { do {
*c = '0' + (i % 10); c--; *c = '0' + (i % 10);
c--;
i /= 10; i /= 10;
} while (i > 0); } while (i > 0);
*c = '/'; c--; *c = '/';
c--;
} }
*c = 'm'; c--; *c = 'm';
*c = ' '; c--; c--;
*c = ':'; c--; *c = ' ';
*c = 'h'; c--; c--;
*c = 't'; c--; *c = ':';
*c = 'a'; c--; c--;
*c = 'h';
c--;
*c = 't';
c--;
*c = 'a';
c--;
*c = 'P'; *c = 'P';
return c; return c;
} }
// split longer string into 4 rows, rowlen chars each // split longer string into 4 rows, rowlen chars each
const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen) const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen) {
{
static char str[4][32 + 1]; static char str[4][32 + 1];
if (rowlen > 32) { if (rowlen > 32) {
rowlen = 32; rowlen = 32;
@ -184,8 +200,7 @@ const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen)
return ret; return ret;
} }
const char **split_message_hex(const uint8_t *msg, uint32_t len) const char **split_message_hex(const uint8_t *msg, uint32_t len) {
{
char hex[32 * 2 + 1]; char hex[32 * 2 + 1];
memzero(hex, sizeof(hex)); memzero(hex, sizeof(hex));
uint32_t size = len; uint32_t size = len;
@ -202,15 +217,17 @@ const char **split_message_hex(const uint8_t *msg, uint32_t len)
void *layoutLast = layoutHome; void *layoutLast = layoutHome;
void layoutDialogSwipe(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) void layoutDialogSwipe(const BITMAP *icon, const char *btnNo,
{ const char *btnYes, const char *desc, const char *line1,
const char *line2, const char *line3, const char *line4,
const char *line5, const char *line6) {
layoutLast = layoutDialogSwipe; layoutLast = layoutDialogSwipe;
layoutSwipe(); layoutSwipe();
layoutDialog(icon, btnNo, btnYes, desc, line1, line2, line3, line4, line5, line6); layoutDialog(icon, btnNo, btnYes, desc, line1, line2, line3, line4, line5,
line6);
} }
void layoutProgressSwipe(const char *desc, int permil) void layoutProgressSwipe(const char *desc, int permil) {
{
if (layoutLast == layoutProgressSwipe) { if (layoutLast == layoutProgressSwipe) {
oledClear(); oledClear();
} else { } else {
@ -220,15 +237,13 @@ void layoutProgressSwipe(const char *desc, int permil)
layoutProgress(desc, permil); layoutProgress(desc, permil);
} }
void layoutScreensaver(void) void layoutScreensaver(void) {
{
layoutLast = layoutScreensaver; layoutLast = layoutScreensaver;
oledClear(); oledClear();
oledRefresh(); oledRefresh();
} }
void layoutHome(void) void layoutHome(void) {
{
if (layoutLast == layoutHome || layoutLast == layoutScreensaver) { if (layoutLast == layoutHome || layoutLast == layoutScreensaver) {
oledClear(); oledClear();
} else { } else {
@ -251,7 +266,8 @@ void layoutHome(void)
} else { } else {
if (label[0] != '\0') { if (label[0] != '\0') {
oledDrawBitmap(44, 4, &bmp_logo48); oledDrawBitmap(44, 4, &bmp_logo48);
oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 8, label, FONT_STANDARD); oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 8, label,
FONT_STANDARD);
} else { } else {
oledDrawBitmap(40, 0, &bmp_logo64); oledDrawBitmap(40, 0, &bmp_logo64);
} }
@ -279,15 +295,16 @@ void layoutHome(void)
system_millis_lock_start = timer_ms(); system_millis_lock_start = timer_ms();
} }
static void render_address_dialog(const CoinInfo *coin, const char *address, const char *line1, const char *line2, const char *extra_line) static void render_address_dialog(const CoinInfo *coin, const char *address,
{ const char *line1, const char *line2,
const char *extra_line) {
if (coin && coin->cashaddr_prefix) { if (coin && coin->cashaddr_prefix) {
/* If this is a cashaddr address, remove the prefix from the /* If this is a cashaddr address, remove the prefix from the
* string presented to the user * string presented to the user
*/ */
int prefix_len = strlen(coin->cashaddr_prefix); int prefix_len = strlen(coin->cashaddr_prefix);
if (strncmp(address, coin->cashaddr_prefix, prefix_len) == 0 if (strncmp(address, coin->cashaddr_prefix, prefix_len) == 0 &&
&& address[prefix_len] == ':') { address[prefix_len] == ':') {
address += prefix_len + 1; address += prefix_len + 1;
} }
} }
@ -321,18 +338,21 @@ static void render_address_dialog(const CoinInfo *coin, const char *address, con
oledRefresh(); oledRefresh();
} }
void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) {
{
char str_out[32 + 3]; char str_out[32 + 3];
bn_format_uint64(out->amount, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out) - 3); bn_format_uint64(out->amount, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY,
0, false, str_out, sizeof(str_out) - 3);
strlcat(str_out, " to", sizeof(str_out)); strlcat(str_out, " to", sizeof(str_out));
const char *address = out->address; const char *address = out->address;
const char *extra_line = (out->address_n_count > 0) ? address_n_str(out->address_n, out->address_n_count, false) : 0; const char *extra_line =
render_address_dialog(coin, address, _("Confirm sending"), str_out, extra_line); (out->address_n_count > 0)
? address_n_str(out->address_n, out->address_n_count, false)
: 0;
render_address_dialog(coin, address, _("Confirm sending"), str_out,
extra_line);
} }
void layoutConfirmOmni(const uint8_t *data, uint32_t size) void layoutConfirmOmni(const uint8_t *data, uint32_t size) {
{
const char *desc; const char *desc;
char str_out[32]; char str_out[32];
const uint32_t tx_type = *(const uint32_t *)(data + 4); const uint32_t tx_type = *(const uint32_t *)(data + 4);
@ -355,26 +375,18 @@ void layoutConfirmOmni(const uint8_t *data, uint32_t size)
break; break;
} }
const uint64_t amount = *(const uint64_t *)(data + 12); const uint64_t amount = *(const uint64_t *)(data + 12);
bn_format_uint64(amount, NULL, suffix, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out)); bn_format_uint64(amount, NULL, suffix, BITCOIN_DIVISIBILITY, 0, false,
str_out, sizeof(str_out));
} else { } else {
desc = _("Unknown transaction"); desc = _("Unknown transaction");
str_out[0] = 0; str_out[0] = 0;
} }
layoutDialogSwipe(&bmp_icon_question, layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Cancel"), _("Confirm OMNI Transaction:"), NULL, desc, NULL, str_out,
_("Confirm"), NULL);
NULL,
_("Confirm OMNI Transaction:"),
NULL,
desc,
NULL,
str_out,
NULL
);
} }
static bool is_valid_ascii(const uint8_t *data, uint32_t size) static bool is_valid_ascii(const uint8_t *data, uint32_t size) {
{
for (uint32_t i = 0; i < size; i++) { for (uint32_t i = 0; i < size; i++) {
if (data[i] < ' ' || data[i] > '~') { if (data[i] < ' ' || data[i] > '~') {
return false; return false;
@ -383,125 +395,100 @@ static bool is_valid_ascii(const uint8_t *data, uint32_t size)
return true; return true;
} }
void layoutConfirmOpReturn(const uint8_t *data, uint32_t size) void layoutConfirmOpReturn(const uint8_t *data, uint32_t size) {
{
const char **str; const char **str;
if (!is_valid_ascii(data, size)) { if (!is_valid_ascii(data, size)) {
str = split_message_hex(data, size); str = split_message_hex(data, size);
} else { } else {
str = split_message(data, size, 20); str = split_message(data, size, 20);
} }
layoutDialogSwipe(&bmp_icon_question, layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Cancel"), _("Confirm OP_RETURN:"), str[0], str[1], str[2], str[3],
_("Confirm"), NULL);
NULL,
_("Confirm OP_RETURN:"),
str[0],
str[1],
str[2],
str[3],
NULL
);
} }
void layoutConfirmTx(const CoinInfo *coin, uint64_t amount_out, uint64_t amount_fee) void layoutConfirmTx(const CoinInfo *coin, uint64_t amount_out,
{ uint64_t amount_fee) {
char str_out[32], str_fee[32]; char str_out[32], str_fee[32];
bn_format_uint64(amount_out, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_out, sizeof(str_out)); bn_format_uint64(amount_out, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY,
bn_format_uint64(amount_fee, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_fee, sizeof(str_fee)); 0, false, str_out, sizeof(str_out));
layoutDialogSwipe(&bmp_icon_question, bn_format_uint64(amount_fee, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY,
_("Cancel"), 0, false, str_fee, sizeof(str_fee));
_("Confirm"), layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
NULL, _("Really send"), str_out, _("from your wallet?"),
_("Really send"), _("Fee included:"), str_fee, NULL);
str_out,
_("from your wallet?"),
_("Fee included:"),
str_fee,
NULL
);
} }
void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee) void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee) {
{
char str_fee[32]; char str_fee[32];
bn_format_uint64(fee, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_fee, sizeof(str_fee)); bn_format_uint64(fee, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0,
layoutDialogSwipe(&bmp_icon_question, false, str_fee, sizeof(str_fee));
_("Cancel"), layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Confirm"), _("Fee"), str_fee, _("is unexpectedly high."), NULL,
NULL, _("Send anyway?"), NULL);
_("Fee"),
str_fee,
_("is unexpectedly high."),
NULL,
_("Send anyway?"),
NULL
);
} }
void layoutSignMessage(const uint8_t *msg, uint32_t len) void layoutSignMessage(const uint8_t *msg, uint32_t len) {
{
const char **str; const char **str;
if (!is_valid_ascii(msg, len)) { if (!is_valid_ascii(msg, len)) {
str = split_message_hex(msg, len); str = split_message_hex(msg, len);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"),
_("Sign binary message?"), _("Sign binary message?"), str[0], str[1], str[2], str[3],
str[0], str[1], str[2], str[3], NULL, NULL); NULL, NULL);
} else { } else {
str = split_message(msg, len, 20); str = split_message(msg, len, 20);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"),
_("Sign message?"), _("Sign message?"), str[0], str[1], str[2], str[3], NULL,
str[0], str[1], str[2], str[3], NULL, NULL); NULL);
} }
} }
void layoutVerifyMessage(const uint8_t *msg, uint32_t len) void layoutVerifyMessage(const uint8_t *msg, uint32_t len) {
{
const char **str; const char **str;
if (!is_valid_ascii(msg, len)) { if (!is_valid_ascii(msg, len)) {
str = split_message_hex(msg, len); str = split_message_hex(msg, len);
layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"), layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"),
_("Verified binary message"), _("Verified binary message"), str[0], str[1], str[2],
str[0], str[1], str[2], str[3], NULL, NULL); str[3], NULL, NULL);
} else { } else {
str = split_message(msg, len, 20); str = split_message(msg, len, 20);
layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"), layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"),
_("Verified message"), _("Verified message"), str[0], str[1], str[2], str[3],
str[0], str[1], str[2], str[3], NULL, NULL); NULL, NULL);
} }
} }
void layoutVerifyAddress(const CoinInfo *coin, const char *address) void layoutVerifyAddress(const CoinInfo *coin, const char *address) {
{ render_address_dialog(coin, address, _("Confirm address?"),
render_address_dialog(coin, address, _("Confirm address?"), _("Message signed by:"), 0); _("Message signed by:"), 0);
} }
void layoutCipherKeyValue(bool encrypt, const char *key) void layoutCipherKeyValue(bool encrypt, const char *key) {
{
const char **str = split_message((const uint8_t *)key, strlen(key), 16); const char **str = split_message((const uint8_t *)key, strlen(key), 16);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"),
encrypt ? _("Encrypt value of this key?") : _("Decrypt value of this key?"), encrypt ? _("Encrypt value of this key?")
: _("Decrypt value of this key?"),
str[0], str[1], str[2], str[3], NULL, NULL); str[0], str[1], str[2], str[3], NULL, NULL);
} }
void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing) void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing) {
{
const char **str = split_message(msg, len, 16); const char **str = split_message(msg, len, 16);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), layoutDialogSwipe(
signing ? _("Encrypt+Sign message?") : _("Encrypt message?"), &bmp_icon_question, _("Cancel"), _("Confirm"),
str[0], str[1], str[2], str[3], NULL, NULL); signing ? _("Encrypt+Sign message?") : _("Encrypt message?"), str[0],
str[1], str[2], str[3], NULL, NULL);
} }
void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address) void layoutDecryptMessage(const uint8_t *msg, uint32_t len,
{ const char *address) {
const char **str = split_message(msg, len, 16); const char **str = split_message(msg, len, 16);
layoutDialogSwipe(&bmp_icon_info, NULL, _("OK"), layoutDialogSwipe(
address ? _("Decrypted signed message") : _("Decrypted message"), &bmp_icon_info, NULL, _("OK"),
str[0], str[1], str[2], str[3], NULL, NULL); address ? _("Decrypted signed message") : _("Decrypted message"), str[0],
str[1], str[2], str[3], NULL, NULL);
} }
void layoutResetWord(const char *word, int pass, int word_pos, bool last) void layoutResetWord(const char *word, int pass, int word_pos, bool last) {
{
layoutLast = layoutResetWord; layoutLast = layoutResetWord;
layoutSwipe(); layoutSwipe();
@ -531,13 +518,14 @@ void layoutResetWord(const char *word, int pass, int word_pos, bool last)
} }
index_str[1] = '0' + word_pos % 10; index_str[1] = '0' + word_pos % 10;
if (word_pos == 1 || word_pos == 21) { if (word_pos == 1 || word_pos == 21) {
index_str[2] = 's'; index_str[3] = 't'; index_str[2] = 's';
} else index_str[3] = 't';
if (word_pos == 2 || word_pos == 22) { } else if (word_pos == 2 || word_pos == 22) {
index_str[2] = 'n'; index_str[3] = 'd'; index_str[2] = 'n';
} else index_str[3] = 'd';
if (word_pos == 3 || word_pos == 23) { } else if (word_pos == 3 || word_pos == 23) {
index_str[2] = 'r'; index_str[3] = 'd'; index_str[2] = 'r';
index_str[3] = 'd';
} }
int left = 0; int left = 0;
@ -546,7 +534,8 @@ void layoutResetWord(const char *word, int pass, int word_pos, bool last)
left = bmp_icon_info.width + 4; left = bmp_icon_info.width + 4;
oledDrawString(left, 0 * 9, action, FONT_STANDARD); oledDrawString(left, 0 * 9, action, FONT_STANDARD);
oledDrawString(left, 2 * 9, word_pos < 10 ? index_str + 1 : index_str, FONT_STANDARD); oledDrawString(left, 2 * 9, word_pos < 10 ? index_str + 1 : index_str,
FONT_STANDARD);
oledDrawString(left, 3 * 9, word, FONT_STANDARD | FONT_DOUBLE); oledDrawString(left, 3 * 9, word, FONT_STANDARD | FONT_DOUBLE);
oledHLine(OLED_HEIGHT - 13); oledHLine(OLED_HEIGHT - 13);
layoutButtonYes(btnYes); layoutButtonYes(btnYes);
@ -555,8 +544,9 @@ void layoutResetWord(const char *word, int pass, int word_pos, bool last)
#define QR_MAX_VERSION 9 #define QR_MAX_VERSION 9
void layoutAddress(const char *address, const char *desc, bool qrcode, bool ignorecase, const uint32_t *address_n, size_t address_n_count, bool address_is_account) void layoutAddress(const char *address, const char *desc, bool qrcode,
{ bool ignorecase, const uint32_t *address_n,
size_t address_n_count, bool address_is_account) {
if (layoutLast != layoutAddress) { if (layoutLast != layoutAddress) {
layoutSwipe(); layoutSwipe();
} else { } else {
@ -569,23 +559,18 @@ void layoutAddress(const char *address, const char *desc, bool qrcode, bool igno
char address_upcase[addrlen + 1]; char address_upcase[addrlen + 1];
if (ignorecase) { if (ignorecase) {
for (uint32_t i = 0; i < addrlen + 1; i++) { for (uint32_t i = 0; i < addrlen + 1; i++) {
address_upcase[i] = address[i] >= 'a' && address[i] <= 'z' ? address_upcase[i] = address[i] >= 'a' && address[i] <= 'z'
address[i] + 'A' - 'a' : address[i]; ? address[i] + 'A' - 'a'
: address[i];
} }
} }
uint8_t codedata[qrcodegen_BUFFER_LEN_FOR_VERSION(QR_MAX_VERSION)]; uint8_t codedata[qrcodegen_BUFFER_LEN_FOR_VERSION(QR_MAX_VERSION)];
uint8_t tempdata[qrcodegen_BUFFER_LEN_FOR_VERSION(QR_MAX_VERSION)]; uint8_t tempdata[qrcodegen_BUFFER_LEN_FOR_VERSION(QR_MAX_VERSION)];
int side = 0; int side = 0;
if (qrcodegen_encodeText( if (qrcodegen_encodeText(ignorecase ? address_upcase : address, tempdata,
ignorecase ? address_upcase : address, codedata, qrcodegen_Ecc_LOW, qrcodegen_VERSION_MIN,
tempdata, QR_MAX_VERSION, qrcodegen_Mask_AUTO, true)) {
codedata,
qrcodegen_Ecc_LOW,
qrcodegen_VERSION_MIN,
QR_MAX_VERSION,
qrcodegen_Mask_AUTO,
true)) {
side = qrcodegen_getSize(codedata); side = qrcodegen_getSize(codedata);
} }
@ -595,8 +580,8 @@ void layoutAddress(const char *address, const char *desc, bool qrcode, bool igno
for (int i = 0; i < side; i++) { for (int i = 0; i < side; i++) {
for (int j = 0; j < side; j++) { for (int j = 0; j < side; j++) {
if (qrcodegen_getModule(codedata, i, j)) { if (qrcodegen_getModule(codedata, i, j)) {
oledBox(offset + i * 2, offset + j * 2, oledBox(offset + i * 2, offset + j * 2, offset + 1 + i * 2,
offset + 1 + i * 2, offset + 1 + j * 2, false); offset + 1 + j * 2, false);
} }
} }
} }
@ -615,15 +600,19 @@ void layoutAddress(const char *address, const char *desc, bool qrcode, bool igno
oledDrawString(0, 0 * 9, desc, FONT_STANDARD); oledDrawString(0, 0 * 9, desc, FONT_STANDARD);
} }
if (addrlen > 10) { // don't split short addresses if (addrlen > 10) { // don't split short addresses
uint32_t rowlen = (addrlen - 1) / (addrlen <= 42 ? 2 : addrlen <= 63 ? 3 : 4) + 1; uint32_t rowlen =
const char **str = split_message((const uint8_t *)address, addrlen, rowlen); (addrlen - 1) / (addrlen <= 42 ? 2 : addrlen <= 63 ? 3 : 4) + 1;
const char **str =
split_message((const uint8_t *)address, addrlen, rowlen);
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
oledDrawString(0, (i + 1) * 9 + 4, str[i], FONT_FIXED); oledDrawString(0, (i + 1) * 9 + 4, str[i], FONT_FIXED);
} }
} else { } else {
oledDrawString(0, (0 + 1) * 9 + 4, address, FONT_FIXED); oledDrawString(0, (0 + 1) * 9 + 4, address, FONT_FIXED);
} }
oledDrawString(0, 42, address_n_str(address_n, address_n_count, address_is_account), FONT_STANDARD); oledDrawString(
0, 42, address_n_str(address_n, address_n_count, address_is_account),
FONT_STANDARD);
} }
if (!qrcode) { if (!qrcode) {
@ -634,8 +623,7 @@ void layoutAddress(const char *address, const char *desc, bool qrcode, bool igno
oledRefresh(); oledRefresh();
} }
void layoutPublicKey(const uint8_t *pubkey) void layoutPublicKey(const uint8_t *pubkey) {
{
char desc[16]; char desc[16];
strlcpy(desc, "Public Key: 00", sizeof(desc)); strlcpy(desc, "Public Key: 00", sizeof(desc));
if (pubkey[0] == 1) { if (pubkey[0] == 1) {
@ -645,12 +633,11 @@ void layoutPublicKey(const uint8_t *pubkey)
data2hex(pubkey, 1, desc + 12); data2hex(pubkey, 1, desc + 12);
} }
const char **str = split_message_hex(pubkey + 1, 32 * 2); const char **str = split_message_hex(pubkey + 1, 32 * 2);
layoutDialogSwipe(&bmp_icon_question, NULL, _("Continue"), NULL, layoutDialogSwipe(&bmp_icon_question, NULL, _("Continue"), NULL, desc, str[0],
desc, str[0], str[1], str[2], str[3], NULL); 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];
char row_hostport[64 + 6 + 1]; char row_hostport[64 + 6 + 1];
char row_user[64 + 8 + 1]; char row_user[64 + 8 + 1];
@ -665,7 +652,10 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge)
} else { } else {
strlcpy(row_proto, identity->proto, sizeof(row_proto)); strlcpy(row_proto, identity->proto, sizeof(row_proto));
char *p = row_proto; char *p = row_proto;
while (*p) { *p = toupper((int)*p); p++; } while (*p) {
*p = toupper((int)*p);
p++;
}
strlcat(row_proto, _(" login to:"), sizeof(row_proto)); strlcat(row_proto, _(" login to:"), sizeof(row_proto));
} }
} else { } else {
@ -708,14 +698,10 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge)
_("Do you want to sign in?"), _("Do you want to sign in?"),
row_proto[0] ? row_proto : NULL, row_proto[0] ? row_proto : NULL,
row_hostport[0] ? row_hostport : NULL, row_hostport[0] ? row_hostport : NULL,
row_user[0] ? row_user : NULL, row_user[0] ? row_user : NULL, challenge, NULL, NULL);
challenge,
NULL,
NULL);
} }
void layoutDecryptIdentity(const IdentityType *identity) void layoutDecryptIdentity(const IdentityType *identity) {
{
char row_proto[8 + 11 + 1]; char row_proto[8 + 11 + 1];
char row_hostport[64 + 6 + 1]; char row_hostport[64 + 6 + 1];
char row_user[64 + 8 + 1]; char row_user[64 + 8 + 1];
@ -723,7 +709,10 @@ void layoutDecryptIdentity(const IdentityType *identity)
if (identity->has_proto && identity->proto[0]) { if (identity->has_proto && identity->proto[0]) {
strlcpy(row_proto, identity->proto, sizeof(row_proto)); strlcpy(row_proto, identity->proto, sizeof(row_proto));
char *p = row_proto; char *p = row_proto;
while (*p) { *p = toupper((int)*p); p++; } while (*p) {
*p = toupper((int)*p);
p++;
}
strlcat(row_proto, _(" decrypt for:"), sizeof(row_proto)); strlcat(row_proto, _(" decrypt for:"), sizeof(row_proto));
} else { } else {
strlcpy(row_proto, _("Decrypt for:"), sizeof(row_proto)); strlcpy(row_proto, _("Decrypt for:"), sizeof(row_proto));
@ -750,17 +739,16 @@ void layoutDecryptIdentity(const IdentityType *identity)
_("Do you want to decrypt?"), _("Do you want to decrypt?"),
row_proto[0] ? row_proto : NULL, row_proto[0] ? row_proto : NULL,
row_hostport[0] ? row_hostport : NULL, row_hostport[0] ? row_hostport : NULL,
row_user[0] ? row_user : NULL, row_user[0] ? row_user : NULL, NULL, NULL, NULL);
NULL,
NULL,
NULL);
} }
void layoutU2FDialog(const char *verb, const char *appname) { void layoutU2FDialog(const char *verb, const char *appname) {
layoutDialog(&bmp_webauthn, NULL, verb, NULL, verb, _("U2F security key?"), NULL, appname, NULL, NULL); layoutDialog(&bmp_webauthn, NULL, verb, NULL, verb, _("U2F security key?"),
NULL, appname, NULL, NULL);
} }
void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *address) { void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes,
const char *desc, const char *line1, const char *address) {
static char first_third[NEM_ADDRESS_SIZE / 3 + 1]; static char first_third[NEM_ADDRESS_SIZE / 3 + 1];
strlcpy(first_third, address, sizeof(first_third)); strlcpy(first_third, address, sizeof(first_third));
@ -769,79 +757,64 @@ void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes,
const char *third_third = &address[NEM_ADDRESS_SIZE * 2 / 3]; const char *third_third = &address[NEM_ADDRESS_SIZE * 2 / 3];
layoutDialogSwipe(icon, layoutDialogSwipe(icon, btnNo, btnYes, desc, line1, first_third, second_third,
btnNo, third_third, NULL, NULL);
btnYes,
desc,
line1,
first_third,
second_third,
third_third,
NULL,
NULL);
} }
void layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 *multiplier, uint64_t fee) { void layoutNEMTransferXEM(const char *desc, uint64_t quantity,
const bignum256 *multiplier, uint64_t fee) {
char str_out[32], str_fee[32]; char str_out[32], str_fee[32];
nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, quantity, multiplier, str_out, sizeof(str_out)); nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, quantity, multiplier,
nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, fee, NULL, str_fee, sizeof(str_fee)); str_out, sizeof(str_out));
nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, fee, NULL, str_fee,
sizeof(str_fee));
layoutDialogSwipe(&bmp_icon_question, layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), desc,
_("Cancel"), _("Confirm transfer of"), str_out, _("and network fee of"),
_("Next"), str_fee, NULL, NULL);
desc,
_("Confirm transfer of"),
str_out,
_("and network fee of"),
str_fee,
NULL,
NULL);
} }
void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc, uint64_t fee1, const char *fee2_desc, uint64_t fee2) { void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc,
uint64_t fee1, const char *fee2_desc, uint64_t fee2) {
char str_fee1[32], str_fee2[32]; char str_fee1[32], str_fee2[32];
nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, fee1, NULL, str_fee1, sizeof(str_fee1)); nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, fee1, NULL, str_fee1,
sizeof(str_fee1));
if (fee2_desc) { if (fee2_desc) {
nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, fee2, NULL, str_fee2, sizeof(str_fee2)); nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, fee2, NULL, str_fee2,
sizeof(str_fee2));
} }
layoutDialogSwipe(&bmp_icon_question, layoutDialogSwipe(
_("Cancel"), &bmp_icon_question, _("Cancel"), confirm ? _("Confirm") : _("Next"), desc,
confirm ? _("Confirm") : _("Next"), fee1_desc, str_fee1, fee2_desc, fee2_desc ? str_fee2 : NULL, NULL, NULL);
desc,
fee1_desc,
str_fee1,
fee2_desc,
fee2_desc ? str_fee2 : NULL,
NULL,
NULL);
} }
void layoutNEMTransferMosaic(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network) { void layoutNEMTransferMosaic(const NEMMosaicDefinition *definition,
uint64_t quantity, const bignum256 *multiplier,
uint8_t network) {
char str_out[32], str_levy[32]; char str_out[32], str_levy[32];
nem_mosaicFormatAmount(definition, quantity, multiplier, str_out, sizeof(str_out)); nem_mosaicFormatAmount(definition, quantity, multiplier, str_out,
sizeof(str_out));
if (definition->has_levy) { if (definition->has_levy) {
nem_mosaicFormatLevy(definition, quantity, multiplier, network, str_levy, sizeof(str_levy)); nem_mosaicFormatLevy(definition, quantity, multiplier, network, str_levy,
sizeof(str_levy));
} }
layoutDialogSwipe(&bmp_icon_question, layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"),
_("Cancel"),
_("Next"),
definition->has_name ? definition->name : _("Mosaic"), definition->has_name ? definition->name : _("Mosaic"),
_("Confirm transfer of"), _("Confirm transfer of"), str_out,
str_out,
definition->has_levy ? _("and levy of") : NULL, definition->has_levy ? _("and levy of") : NULL,
definition->has_levy ? str_levy : NULL, definition->has_levy ? str_levy : NULL, NULL, NULL);
NULL,
NULL);
} }
void layoutNEMTransferUnknownMosaic(const char *namespace, const char *mosaic, uint64_t quantity, const bignum256 *multiplier) { void layoutNEMTransferUnknownMosaic(const char *namespace, const char *mosaic,
uint64_t quantity,
const bignum256 *multiplier) {
char mosaic_name[32]; char mosaic_name[32];
nem_mosaicFormatName(namespace, mosaic, mosaic_name, sizeof(mosaic_name)); nem_mosaicFormatName(namespace, mosaic, mosaic_name, sizeof(mosaic_name));
@ -853,97 +826,93 @@ void layoutNEMTransferUnknownMosaic(const char *namespace, const char *mosaic, u
*decimal = '\0'; *decimal = '\0';
} }
layoutDialogSwipe(&bmp_icon_question, layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("I take the risk"),
_("Cancel"), _("Unknown Mosaic"), _("Confirm transfer of"), str_out,
_("I take the risk"), _("raw units of"), mosaic_name, NULL, NULL);
_("Unknown Mosaic"),
_("Confirm transfer of"),
str_out,
_("raw units of"),
mosaic_name,
NULL,
NULL);
} }
void layoutNEMTransferPayload(const uint8_t *payload, size_t length, bool encrypted) { void layoutNEMTransferPayload(const uint8_t *payload, size_t length,
bool encrypted) {
if (length >= 1 && payload[0] == 0xFE) { if (length >= 1 && payload[0] == 0xFE) {
char encoded[(length - 1) * 2 + 1]; char encoded[(length - 1) * 2 + 1];
data2hex(&payload[1], length - 1, encoded); data2hex(&payload[1], length - 1, encoded);
const char **str = split_message((uint8_t *) encoded, sizeof(encoded) - 1, 16); const char **str =
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), split_message((uint8_t *)encoded, sizeof(encoded) - 1, 16);
encrypted ? _("Encrypted hex data") : _("Unencrypted hex data"), layoutDialogSwipe(
str[0], str[1], str[2], str[3], NULL, NULL); &bmp_icon_question, _("Cancel"), _("Next"),
encrypted ? _("Encrypted hex data") : _("Unencrypted hex data"), str[0],
str[1], str[2], str[3], NULL, NULL);
} else { } else {
const char **str = split_message(payload, length, 16); const char **str = split_message(payload, length, 16);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), layoutDialogSwipe(
encrypted ? _("Encrypted message") : _("Unencrypted message"), &bmp_icon_question, _("Cancel"), _("Next"),
str[0], str[1], str[2], str[3], NULL, NULL); encrypted ? _("Encrypted message") : _("Unencrypted message"), str[0],
str[1], str[2], str[3], NULL, NULL);
} }
} }
void layoutNEMMosaicDescription(const char *description) { void layoutNEMMosaicDescription(const char *description) {
const char **str = split_message((uint8_t *) description, strlen(description), 16); const char **str =
split_message((uint8_t *)description, strlen(description), 16);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"),
_("Mosaic Description"), _("Mosaic Description"), str[0], str[1], str[2], str[3],
str[0], str[1], str[2], str[3], NULL, NULL); NULL, NULL);
} }
void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network) { void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network) {
const NEMMosaicDefinition *mosaic; const NEMMosaicDefinition *mosaic;
if (nem_mosaicMatches(definition, definition->levy_namespace, definition->levy_mosaic, network)) { if (nem_mosaicMatches(definition, definition->levy_namespace,
definition->levy_mosaic, network)) {
mosaic = definition; mosaic = definition;
} else { } else {
mosaic = nem_mosaicByName(definition->levy_namespace, definition->levy_mosaic, network); mosaic = nem_mosaicByName(definition->levy_namespace,
definition->levy_mosaic, network);
} }
char mosaic_name[32]; char mosaic_name[32];
if (mosaic == NULL) { if (mosaic == NULL) {
nem_mosaicFormatName(definition->levy_namespace, definition->levy_mosaic, mosaic_name, sizeof(mosaic_name)); nem_mosaicFormatName(definition->levy_namespace, definition->levy_mosaic,
mosaic_name, sizeof(mosaic_name));
} }
char str_out[32]; char str_out[32];
switch (definition->levy) { switch (definition->levy) {
case NEMMosaicLevy_MosaicLevy_Percentile: case NEMMosaicLevy_MosaicLevy_Percentile:
bn_format_uint64(definition->fee, NULL, NULL, 0, 0, false, str_out, sizeof(str_out)); bn_format_uint64(definition->fee, NULL, NULL, 0, 0, false, str_out,
sizeof(str_out));
layoutDialogSwipe(&bmp_icon_question, layoutDialogSwipe(
_("Cancel"), &bmp_icon_question, _("Cancel"), _("Next"), _("Percentile Levy"),
_("Next"), _("Raw levy value is"), str_out, _("in"),
_("Percentile Levy"), mosaic ? (mosaic == definition ? _("the same mosaic") : mosaic->name)
_("Raw levy value is"), : mosaic_name,
str_out, NULL, NULL);
_("in"),
mosaic ? (mosaic == definition ? _("the same mosaic") : mosaic->name) : mosaic_name,
NULL,
NULL);
break; break;
case NEMMosaicLevy_MosaicLevy_Absolute: case NEMMosaicLevy_MosaicLevy_Absolute:
default: default:
nem_mosaicFormatAmount(mosaic, definition->fee, NULL, str_out, sizeof(str_out)); nem_mosaicFormatAmount(mosaic, definition->fee, NULL, str_out,
layoutDialogSwipe(&bmp_icon_question, sizeof(str_out));
_("Cancel"), layoutDialogSwipe(
_("Next"), &bmp_icon_question, _("Cancel"), _("Next"), _("Absolute Levy"),
_("Absolute Levy"), _("Levy is"), str_out,
_("Levy is"), mosaic ? (mosaic == definition ? _("in the same mosaic") : NULL)
str_out, : _("in raw units of"),
mosaic ? (mosaic == definition ? _("in the same mosaic") : NULL) : _("in raw units of"), mosaic ? NULL : mosaic_name, NULL, NULL);
mosaic ? NULL : mosaic_name,
NULL,
NULL);
break; break;
} }
} }
static inline bool is_slip18(const uint32_t *address_n, size_t address_n_count) static inline bool is_slip18(const uint32_t *address_n,
{ size_t address_n_count) {
return address_n_count == 2 && address_n[0] == (0x80000000 + 10018) && (address_n[1] & 0x80000000) && (address_n[1] & 0x7FFFFFFF) <= 9; return address_n_count == 2 && address_n[0] == (0x80000000 + 10018) &&
(address_n[1] & 0x80000000) && (address_n[1] & 0x7FFFFFFF) <= 9;
} }
void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count, const uint8_t *data, uint32_t len, bool final_sign) void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count,
{ const uint8_t *data, uint32_t len, bool final_sign) {
char *desc = final_sign ? _("CoSi sign message?") : _("CoSi commit message?"); char *desc = final_sign ? _("CoSi sign message?") : _("CoSi commit message?");
char desc_buf[32]; char desc_buf[32];
if (is_slip18(address_n, address_n_count)) { if (is_slip18(address_n, address_n_count)) {
@ -968,6 +937,6 @@ void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count, con
strlcpy(str[2], "unsupported", sizeof(str[2])); strlcpy(str[2], "unsupported", sizeof(str[2]));
strlcpy(str[3], "length", sizeof(str[3])); strlcpy(str[3], "length", sizeof(str[3]));
} }
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), desc, layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), desc, str[0],
str[0], str[1], str[2], str[3], NULL, NULL); str[1], str[2], str[3], NULL, NULL);
} }

View File

@ -20,10 +20,10 @@
#ifndef __LAYOUT2_H__ #ifndef __LAYOUT2_H__
#define __LAYOUT2_H__ #define __LAYOUT2_H__
#include "layout.h"
#include "coins.h"
#include "bitmaps.h"
#include "bignum.h" #include "bignum.h"
#include "bitmaps.h"
#include "coins.h"
#include "layout.h"
#include "trezor.h" #include "trezor.h"
#include "messages-bitcoin.pb.h" #include "messages-bitcoin.pb.h"
@ -38,7 +38,10 @@ extern void *layoutLast;
#define layoutSwipe oledSwipeLeft #define layoutSwipe oledSwipeLeft
#endif #endif
void layoutDialogSwipe(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6); void layoutDialogSwipe(const BITMAP *icon, const char *btnNo,
const char *btnYes, const char *desc, const char *line1,
const char *line2, const char *line3, const char *line4,
const char *line5, const char *line6);
void layoutProgressSwipe(const char *desc, int permil); void layoutProgressSwipe(const char *desc, int permil);
void layoutScreensaver(void); void layoutScreensaver(void);
@ -46,31 +49,44 @@ void layoutHome(void);
void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out); void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out);
void layoutConfirmOmni(const uint8_t *data, uint32_t size); void layoutConfirmOmni(const uint8_t *data, uint32_t size);
void layoutConfirmOpReturn(const uint8_t *data, uint32_t size); void layoutConfirmOpReturn(const uint8_t *data, uint32_t size);
void layoutConfirmTx(const CoinInfo *coin, uint64_t amount_out, uint64_t amount_fee); void layoutConfirmTx(const CoinInfo *coin, uint64_t amount_out,
uint64_t amount_fee);
void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee); void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee);
void layoutSignMessage(const uint8_t *msg, uint32_t len); void layoutSignMessage(const uint8_t *msg, uint32_t len);
void layoutVerifyAddress(const CoinInfo *coin, const char *address); void layoutVerifyAddress(const CoinInfo *coin, 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 layoutResetWord(const char *word, int pass, int word_pos, bool last); void layoutResetWord(const char *word, int pass, int word_pos, bool last);
void layoutAddress(const char *address, const char *desc, bool qrcode, bool ignorecase, const uint32_t *address_n, size_t address_n_count, bool address_is_account); void layoutAddress(const char *address, const char *desc, bool qrcode,
bool ignorecase, const uint32_t *address_n,
size_t address_n_count, bool address_is_account);
void layoutPublicKey(const uint8_t *pubkey); void layoutPublicKey(const uint8_t *pubkey);
void layoutSignIdentity(const IdentityType *identity, const char *challenge); void layoutSignIdentity(const IdentityType *identity, const char *challenge);
void layoutDecryptIdentity(const IdentityType *identity); void layoutDecryptIdentity(const IdentityType *identity);
void layoutU2FDialog(const char *verb, const char *appname); void layoutU2FDialog(const char *verb, const char *appname);
void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *address); void layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes,
void layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 *multiplier, uint64_t fee); const char *desc, const char *line1, const char *address);
void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc, uint64_t fee1, const char *fee2_desc, uint64_t fee2); void layoutNEMTransferXEM(const char *desc, uint64_t quantity,
void layoutNEMTransferMosaic(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network); const bignum256 *multiplier, uint64_t fee);
void layoutNEMTransferUnknownMosaic(const char *namespace, const char *mosaic, uint64_t quantity, const bignum256 *multiplier); void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc,
void layoutNEMTransferPayload(const uint8_t *payload, size_t length, bool encrypted); uint64_t fee1, const char *fee2_desc, uint64_t fee2);
void layoutNEMTransferMosaic(const NEMMosaicDefinition *definition,
uint64_t quantity, const bignum256 *multiplier,
uint8_t network);
void layoutNEMTransferUnknownMosaic(const char *namespace, const char *mosaic,
uint64_t quantity,
const bignum256 *multiplier);
void layoutNEMTransferPayload(const uint8_t *payload, size_t length,
bool encrypted);
void layoutNEMMosaicDescription(const char *description); void layoutNEMMosaicDescription(const char *description);
void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network); void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network);
void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count, const uint8_t *data, uint32_t len, bool final_sign); void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count,
const uint8_t *data, uint32_t len, bool final_sign);
const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen); const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen);
const char **split_message_hex(const uint8_t *msg, uint32_t len); const char **split_message_hex(const uint8_t *msg, uint32_t len);

View File

@ -18,23 +18,26 @@
*/ */
#include "lisk.h" #include "lisk.h"
#include "fsm.h"
#include "curves.h"
#include "layout2.h"
#include "bitmaps.h" #include "bitmaps.h"
#include "util.h"
#include "gettext.h"
#include "crypto.h" #include "crypto.h"
#include "protect.h" #include "curves.h"
#include "fsm.h"
#include "gettext.h"
#include "layout2.h"
#include "messages.pb.h" #include "messages.pb.h"
#include "protect.h"
#include "util.h"
void lisk_get_address_from_public_key(const uint8_t *public_key, char *address) { void lisk_get_address_from_public_key(const uint8_t *public_key,
char *address) {
uint64_t digest[4]; uint64_t digest[4];
sha256_Raw(public_key, 32, (uint8_t *)digest); sha256_Raw(public_key, 32, (uint8_t *)digest);
bn_format_uint64(digest[0], NULL, "L", 0, 0, false, address, MAX_LISK_ADDRESS_SIZE); bn_format_uint64(digest[0], NULL, "L", 0, 0, false, address,
MAX_LISK_ADDRESS_SIZE);
} }
void lisk_message_hash(const uint8_t *message, size_t message_len, uint8_t hash[32]) { void lisk_message_hash(const uint8_t *message, size_t message_len,
uint8_t hash[32]) {
SHA256_CTX ctx; SHA256_CTX ctx;
sha256_Init(&ctx); sha256_Init(&ctx);
sha256_Update(&ctx, (const uint8_t *)"\x15" "Lisk Signed Message:\n", 22); sha256_Update(&ctx, (const uint8_t *)"\x15" "Lisk Signed Message:\n", 22);
@ -46,8 +49,8 @@ void lisk_message_hash(const uint8_t *message, size_t message_len, uint8_t hash[
sha256_Raw(hash, 32, hash); sha256_Raw(hash, 32, hash);
} }
void lisk_sign_message(const HDNode *node, const LiskSignMessage *msg, LiskMessageSignature *resp) void lisk_sign_message(const HDNode *node, const LiskSignMessage *msg,
{ LiskMessageSignature *resp) {
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, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
@ -72,40 +75,39 @@ void lisk_sign_message(const HDNode *node, const LiskSignMessage *msg, LiskMessa
resp->public_key.size = 32; resp->public_key.size = 32;
} }
bool lisk_verify_message(const LiskVerifyMessage *msg) bool lisk_verify_message(const LiskVerifyMessage *msg) {
{
uint8_t hash[32]; uint8_t hash[32];
lisk_message_hash(msg->message.bytes, msg->message.size, hash); lisk_message_hash(msg->message.bytes, msg->message.size, hash);
return 0 == ed25519_sign_open(hash, 32, msg->public_key.bytes, msg->signature.bytes ); return 0 == ed25519_sign_open(hash, 32, msg->public_key.bytes,
msg->signature.bytes);
} }
static void lisk_update_raw_tx(const HDNode *node, LiskSignTx *msg) static void lisk_update_raw_tx(const HDNode *node, LiskSignTx *msg) {
{
if (!msg->transaction.has_sender_public_key) { if (!msg->transaction.has_sender_public_key) {
memcpy(msg->transaction.sender_public_key.bytes, &node->public_key[1], 32); memcpy(msg->transaction.sender_public_key.bytes, &node->public_key[1], 32);
} }
// For CastVotes transactions, recipientId should be equal to transaction creator address. // For CastVotes transactions, recipientId should be equal to transaction
if(msg->transaction.type == LiskTransactionType_CastVotes && !msg->transaction.has_recipient_id) { // creator address.
if (msg->transaction.type == LiskTransactionType_CastVotes &&
!msg->transaction.has_recipient_id) {
msg->transaction.has_recipient_id = true; msg->transaction.has_recipient_id = true;
lisk_get_address_from_public_key(&node->public_key[1], msg->transaction.recipient_id); lisk_get_address_from_public_key(&node->public_key[1],
msg->transaction.recipient_id);
} }
} }
static void lisk_hashupdate_uint32(SHA256_CTX *ctx, uint32_t value) static void lisk_hashupdate_uint32(SHA256_CTX *ctx, uint32_t value) {
{
uint8_t data[4]; uint8_t data[4];
write_le(data, value); write_le(data, value);
sha256_Update(ctx, data, sizeof(data)); sha256_Update(ctx, data, sizeof(data));
} }
static void lisk_hashupdate_uint64_le(SHA256_CTX *ctx, uint64_t value) static void lisk_hashupdate_uint64_le(SHA256_CTX *ctx, uint64_t value) {
{
sha256_Update(ctx, (uint8_t *)&value, sizeof(uint64_t)); sha256_Update(ctx, (uint8_t *)&value, sizeof(uint64_t));
} }
static void lisk_hashupdate_uint64_be(SHA256_CTX *ctx, uint64_t value) static void lisk_hashupdate_uint64_be(SHA256_CTX *ctx, uint64_t value) {
{
uint8_t data[8]; uint8_t data[8];
data[0] = value >> 56; data[0] = value >> 56;
data[1] = value >> 48; data[1] = value >> 48;
@ -118,8 +120,8 @@ static void lisk_hashupdate_uint64_be(SHA256_CTX *ctx, uint64_t value)
sha256_Update(ctx, data, sizeof(data)); sha256_Update(ctx, data, sizeof(data));
} }
static void lisk_hashupdate_asset(SHA256_CTX *ctx, LiskTransactionType type, LiskTransactionAsset *asset) static void lisk_hashupdate_asset(SHA256_CTX *ctx, LiskTransactionType type,
{ LiskTransactionAsset *asset) {
switch (type) { switch (type) {
case LiskTransactionType_Transfer: case LiskTransactionType_Transfer:
if (asset->has_data) { if (asset->has_data) {
@ -128,7 +130,8 @@ static void lisk_hashupdate_asset(SHA256_CTX *ctx, LiskTransactionType type, Lis
break; break;
case LiskTransactionType_RegisterDelegate: case LiskTransactionType_RegisterDelegate:
if (asset->has_delegate && asset->delegate.has_username) { if (asset->has_delegate && asset->delegate.has_username) {
sha256_Update(ctx, (const uint8_t *)asset->delegate.username, strlen(asset->delegate.username)); sha256_Update(ctx, (const uint8_t *)asset->delegate.username,
strlen(asset->delegate.username));
} }
break; break;
case LiskTransactionType_CastVotes: { case LiskTransactionType_CastVotes: {
@ -139,7 +142,8 @@ static void lisk_hashupdate_asset(SHA256_CTX *ctx, LiskTransactionType type, Lis
} }
case LiskTransactionType_RegisterSecondPassphrase: case LiskTransactionType_RegisterSecondPassphrase:
if (asset->has_signature && asset->signature.has_public_key) { if (asset->has_signature && asset->signature.has_public_key) {
sha256_Update(ctx, asset->signature.public_key.bytes, asset->signature.public_key.size); sha256_Update(ctx, asset->signature.public_key.bytes,
asset->signature.public_key.size);
} }
break; break;
case LiskTransactionType_RegisterMultisignatureAccount: case LiskTransactionType_RegisterMultisignatureAccount:
@ -147,25 +151,26 @@ static void lisk_hashupdate_asset(SHA256_CTX *ctx, LiskTransactionType type, Lis
sha256_Update(ctx, (uint8_t *)&(asset->multisignature.min), 1); sha256_Update(ctx, (uint8_t *)&(asset->multisignature.min), 1);
sha256_Update(ctx, (uint8_t *)&(asset->multisignature.life_time), 1); sha256_Update(ctx, (uint8_t *)&(asset->multisignature.life_time), 1);
for (int i = 0; i < asset->multisignature.keys_group_count; i++) { for (int i = 0; i < asset->multisignature.keys_group_count; i++) {
sha256_Update(ctx, (uint8_t *)asset->multisignature.keys_group[i], strlen(asset->multisignature.keys_group[i])); sha256_Update(ctx, (uint8_t *)asset->multisignature.keys_group[i],
strlen(asset->multisignature.keys_group[i]));
}; };
} }
break; break;
default: default:
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid transaction type")); fsm_sendFailure(FailureType_Failure_DataError,
_("Invalid transaction type"));
break; break;
} }
} }
#define MAX_LISK_VALUE_SIZE 20 #define MAX_LISK_VALUE_SIZE 20
static void lisk_format_value(uint64_t value, char *formated_value) static void lisk_format_value(uint64_t value, char *formated_value) {
{ bn_format_uint64(value, NULL, " LSK", 8, 0, false, formated_value,
bn_format_uint64(value, NULL, " LSK", 8, 0, false, formated_value, MAX_LISK_VALUE_SIZE); MAX_LISK_VALUE_SIZE);
} }
void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp) void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp) {
{
lisk_update_raw_tx(node, msg); lisk_update_raw_tx(node, msg);
if (msg->has_transaction) { if (msg->has_transaction) {
@ -174,7 +179,8 @@ void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp)
switch (msg->transaction.type) { switch (msg->transaction.type) {
case LiskTransactionType_Transfer: case LiskTransactionType_Transfer:
layoutRequireConfirmTx(msg->transaction.recipient_id, msg->transaction.amount); layoutRequireConfirmTx(msg->transaction.recipient_id,
msg->transaction.amount);
break; break;
case LiskTransactionType_RegisterDelegate: case LiskTransactionType_RegisterDelegate:
layoutRequireConfirmDelegateRegistration(&msg->transaction.asset); layoutRequireConfirmDelegateRegistration(&msg->transaction.asset);
@ -189,14 +195,15 @@ void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp)
layoutRequireConfirmMultisig(&msg->transaction.asset); layoutRequireConfirmMultisig(&msg->transaction.asset);
break; break;
default: default:
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid transaction type")); fsm_sendFailure(FailureType_Failure_DataError,
_("Invalid transaction type"));
layoutHome(); layoutHome();
break; break;
} }
if (!protectButton(( if (!protectButton((msg->transaction.type ==
msg->transaction.type == LiskTransactionType_RegisterSecondPassphrase ? LiskTransactionType_RegisterSecondPassphrase
ButtonRequestType_ButtonRequest_PublicKey : ? ButtonRequestType_ButtonRequest_PublicKey
ButtonRequestType_ButtonRequest_SignTx), : ButtonRequestType_ButtonRequest_SignTx),
false)) { false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled"); fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled");
layoutHome(); layoutHome();
@ -218,15 +225,19 @@ void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp)
sha256_Update(&ctx, msg->transaction.sender_public_key.bytes, 32); sha256_Update(&ctx, msg->transaction.sender_public_key.bytes, 32);
if (msg->transaction.has_requester_public_key) { if (msg->transaction.has_requester_public_key) {
sha256_Update(&ctx, msg->transaction.requester_public_key.bytes, msg->transaction.requester_public_key.size); sha256_Update(&ctx, msg->transaction.requester_public_key.bytes,
msg->transaction.requester_public_key.size);
} }
uint64_t recipient_id = 0; uint64_t recipient_id = 0;
if (msg->transaction.has_recipient_id && msg->transaction.recipient_id[0] != 0) { if (msg->transaction.has_recipient_id &&
msg->transaction.recipient_id[0] != 0) {
// parse integer from lisk address ("123L" -> 123) // parse integer from lisk address ("123L" -> 123)
for (size_t i = 0; i < strlen(msg->transaction.recipient_id) - 1; i++) { for (size_t i = 0; i < strlen(msg->transaction.recipient_id) - 1; i++) {
if (msg->transaction.recipient_id[i] < '0' || msg->transaction.recipient_id[i] > '9') { if (msg->transaction.recipient_id[i] < '0' ||
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid recipient_id")); msg->transaction.recipient_id[i] > '9') {
fsm_sendFailure(FailureType_Failure_DataError,
_("Invalid recipient_id"));
layoutHome(); layoutHome();
return; return;
} }
@ -241,12 +252,14 @@ void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp)
// if signature exist calculate second signature // if signature exist calculate second signature
if (msg->transaction.has_signature) { if (msg->transaction.has_signature) {
sha256_Update(&ctx, msg->transaction.signature.bytes, msg->transaction.signature.size); sha256_Update(&ctx, msg->transaction.signature.bytes,
msg->transaction.signature.size);
} }
uint8_t hash[32]; uint8_t hash[32];
sha256_Final(&ctx, hash); sha256_Final(&ctx, hash);
ed25519_sign(hash, 32, node->private_key, &node->public_key[1], resp->signature.bytes); ed25519_sign(hash, 32, node->private_key, &node->public_key[1],
resp->signature.bytes);
resp->has_signature = true; resp->has_signature = true;
resp->signature.size = 64; resp->signature.size = 64;
@ -254,73 +267,51 @@ void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp)
} }
// Layouts // Layouts
void layoutLiskPublicKey(const uint8_t *pubkey) void layoutLiskPublicKey(const uint8_t *pubkey) {
{
const char **str = split_message_hex(pubkey, 32); const char **str = split_message_hex(pubkey, 32);
layoutDialogSwipe(&bmp_icon_question, NULL, _("Continue"), NULL, layoutDialogSwipe(&bmp_icon_question, NULL, _("Continue"), NULL,
_("Public Key:"), str[0], str[1], str[2], str[3], NULL); _("Public Key:"), str[0], str[1], str[2], str[3], NULL);
} }
void layoutLiskVerifyAddress(const char *address) void layoutLiskVerifyAddress(const char *address) {
{ const char **str =
const char **str = split_message((const uint8_t *)address, strlen(address), 10); split_message((const uint8_t *)address, strlen(address), 10);
layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"), layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"),
_("Confirm address?"), _("Confirm address?"), _("Message signed by:"), str[0],
_("Message signed by:"), str[1], NULL, NULL, NULL);
str[0], str[1], NULL, NULL, NULL);
} }
void layoutRequireConfirmTx(char *recipient_id, uint64_t amount) void layoutRequireConfirmTx(char *recipient_id, uint64_t amount) {
{
char formated_amount[MAX_LISK_VALUE_SIZE]; char formated_amount[MAX_LISK_VALUE_SIZE];
const char **str = split_message((const uint8_t *)recipient_id, strlen(recipient_id), 16); const char **str =
split_message((const uint8_t *)recipient_id, strlen(recipient_id), 16);
lisk_format_value(amount, formated_amount); lisk_format_value(amount, formated_amount);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
NULL, _("Confirm sending"), formated_amount, _("to:"), str[0],
_("Confirm sending"), str[1], NULL);
formated_amount,
_("to:"),
str[0],
str[1],
NULL
);
} }
void layoutRequireConfirmFee(uint64_t fee, uint64_t amount) void layoutRequireConfirmFee(uint64_t fee, uint64_t amount) {
{
char formated_amount[MAX_LISK_VALUE_SIZE]; char formated_amount[MAX_LISK_VALUE_SIZE];
char formated_fee[MAX_LISK_VALUE_SIZE]; char formated_fee[MAX_LISK_VALUE_SIZE];
lisk_format_value(amount, formated_amount); lisk_format_value(amount, formated_amount);
lisk_format_value(fee, formated_fee); lisk_format_value(fee, formated_fee);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
NULL, _("Confirm transaction"), formated_amount, _("fee:"),
_("Confirm transaction"), formated_fee, NULL, NULL);
formated_amount,
_("fee:"),
formated_fee,
NULL,
NULL
);
} }
void layoutRequireConfirmDelegateRegistration(LiskTransactionAsset *asset) void layoutRequireConfirmDelegateRegistration(LiskTransactionAsset *asset) {
{
if (asset->has_delegate && asset->delegate.has_username) { if (asset->has_delegate && asset->delegate.has_username) {
const char **str = split_message((const uint8_t *)asset->delegate.username, strlen(asset->delegate.username), 20); const char **str = split_message((const uint8_t *)asset->delegate.username,
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), strlen(asset->delegate.username), 20);
NULL, layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Confirm transaction"), _("Confirm transaction"), _("Do you really want to"),
_("Do you really want to"), _("register a delegate?"), str[0], str[1], NULL);
_("register a delegate?"),
str[0],
str[1],
NULL
);
} }
} }
void layoutRequireConfirmCastVotes(LiskTransactionAsset *asset) void layoutRequireConfirmCastVotes(LiskTransactionAsset *asset) {
{
uint8_t plus = 0; uint8_t plus = 0;
uint8_t minus = 0; uint8_t minus = 0;
char add_votes_txt[13]; char add_votes_txt[13];
@ -334,37 +325,30 @@ void layoutRequireConfirmCastVotes(LiskTransactionAsset *asset)
} }
} }
bn_format_uint64(plus, "Add ", NULL, 0, 0, false, add_votes_txt, sizeof(add_votes_txt)); bn_format_uint64(plus, "Add ", NULL, 0, 0, false, add_votes_txt,
bn_format_uint64(minus, "Remove ", NULL, 0, 0, false, remove_votes_txt, sizeof(remove_votes_txt)); sizeof(add_votes_txt));
bn_format_uint64(minus, "Remove ", NULL, 0, 0, false, remove_votes_txt,
sizeof(remove_votes_txt));
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
NULL, _("Confirm transaction"), add_votes_txt, remove_votes_txt,
_("Confirm transaction"), NULL, NULL, NULL);
add_votes_txt,
remove_votes_txt,
NULL,
NULL,
NULL
);
} }
void layoutRequireConfirmMultisig(LiskTransactionAsset *asset) void layoutRequireConfirmMultisig(LiskTransactionAsset *asset) {
{
char keys_group_str[25]; char keys_group_str[25];
char life_time_str[14]; char life_time_str[14];
char min_str[8]; char min_str[8];
bn_format_uint64(asset->multisignature.keys_group_count, "Keys group length: ", NULL, 0, 0, false, keys_group_str, sizeof(keys_group_str)); bn_format_uint64(asset->multisignature.keys_group_count,
bn_format_uint64(asset->multisignature.life_time, "Life time: ", NULL, 0, 0, false, life_time_str, sizeof(life_time_str)); "Keys group length: ", NULL, 0, 0, false, keys_group_str,
bn_format_uint64(asset->multisignature.min, "Min: ", NULL, 0, 0, false, min_str, sizeof(min_str)); sizeof(keys_group_str));
bn_format_uint64(asset->multisignature.life_time, "Life time: ", NULL, 0, 0,
false, life_time_str, sizeof(life_time_str));
bn_format_uint64(asset->multisignature.min, "Min: ", NULL, 0, 0, false,
min_str, sizeof(min_str));
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
NULL, _("Confirm transaction"), keys_group_str, life_time_str,
_("Confirm transaction"), min_str, NULL, NULL);
keys_group_str,
life_time_str,
min_str,
NULL,
NULL
);
} }

View File

@ -26,7 +26,8 @@
#define MAX_LISK_ADDRESS_SIZE 23 #define MAX_LISK_ADDRESS_SIZE 23
void lisk_sign_message(const HDNode *node, const LiskSignMessage *msg, LiskMessageSignature *resp); void lisk_sign_message(const HDNode *node, const LiskSignMessage *msg,
LiskMessageSignature *resp);
bool lisk_verify_message(const LiskVerifyMessage *msg); bool lisk_verify_message(const LiskVerifyMessage *msg);
void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp); void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp);

View File

@ -19,17 +19,17 @@
#include <string.h> #include <string.h>
#include "trezor.h"
#include "messages.h"
#include "debug.h" #include "debug.h"
#include "fsm.h" #include "fsm.h"
#include "util.h"
#include "gettext.h" #include "gettext.h"
#include "memzero.h" #include "memzero.h"
#include "messages.h"
#include "trezor.h"
#include "util.h"
#include "messages.pb.h"
#include "pb_decode.h" #include "pb_decode.h"
#include "pb_encode.h" #include "pb_encode.h"
#include "messages.pb.h"
struct MessagesMap_t { struct MessagesMap_t {
char type; // n = normal, d = debug char type; // n = normal, d = debug
@ -42,13 +42,11 @@ struct MessagesMap_t {
static const struct MessagesMap_t MessagesMap[] = { static const struct MessagesMap_t MessagesMap[] = {
#include "messages_map.h" #include "messages_map.h"
// end // end
{0, 0, 0, 0, 0} {0, 0, 0, 0, 0}};
};
#include "messages_map_limits.h" #include "messages_map_limits.h"
const pb_field_t *MessageFields(char type, char dir, uint16_t msg_id) const pb_field_t *MessageFields(char type, char dir, uint16_t msg_id) {
{
const struct MessagesMap_t *m = MessagesMap; const struct MessagesMap_t *m = MessagesMap;
while (m->type) { while (m->type) {
if (type == m->type && dir == m->dir && msg_id == m->msg_id) { if (type == m->type && dir == m->dir && msg_id == m->msg_id) {
@ -59,8 +57,7 @@ const pb_field_t *MessageFields(char type, char dir, uint16_t msg_id)
return 0; return 0;
} }
void MessageProcessFunc(char type, char dir, uint16_t msg_id, void *ptr) void MessageProcessFunc(char type, char dir, uint16_t msg_id, void *ptr) {
{
const struct MessagesMap_t *m = MessagesMap; const struct MessagesMap_t *m = MessagesMap;
while (m->type) { while (m->type) {
if (type == m->type && dir == m->dir && msg_id == m->msg_id) { if (type == m->type && dir == m->dir && msg_id == m->msg_id) {
@ -85,8 +82,7 @@ static uint8_t msg_debug_out[MSG_DEBUG_OUT_SIZE];
#endif #endif
static 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] = '?';
msg_out_cur = 1; msg_out_cur = 1;
@ -101,8 +97,7 @@ static inline void msg_out_append(uint8_t c)
#if DEBUG_LINK #if DEBUG_LINK
static 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] = '?';
msg_debug_out_cur = 1; msg_debug_out_cur = 1;
@ -117,8 +112,7 @@ static inline void msg_debug_out_append(uint8_t c)
#endif #endif
static 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) {
msg_out[msg_out_end * 64 + msg_out_cur] = 0; msg_out[msg_out_end * 64 + msg_out_cur] = 0;
@ -130,8 +124,7 @@ static inline void msg_out_pad(void)
#if DEBUG_LINK #if DEBUG_LINK
static inline void msg_debug_out_pad(void) static inline void msg_debug_out_pad(void) {
{
if (msg_debug_out_cur == 0) return; if (msg_debug_out_cur == 0) return;
while (msg_debug_out_cur < 64) { while (msg_debug_out_cur < 64) {
msg_debug_out[msg_debug_out_end * 64 + msg_debug_out_cur] = 0; msg_debug_out[msg_debug_out_end * 64 + msg_debug_out_cur] = 0;
@ -143,8 +136,8 @@ static inline void msg_debug_out_pad(void)
#endif #endif
static bool pb_callback_out(pb_ostream_t *stream, const uint8_t *buf, size_t count) static bool pb_callback_out(pb_ostream_t *stream, const uint8_t *buf,
{ size_t count) {
(void)stream; (void)stream;
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
msg_out_append(buf[i]); msg_out_append(buf[i]);
@ -154,8 +147,8 @@ static bool pb_callback_out(pb_ostream_t *stream, const uint8_t *buf, size_t cou
#if DEBUG_LINK #if DEBUG_LINK
static bool pb_debug_callback_out(pb_ostream_t *stream, const uint8_t *buf, size_t count) static bool pb_debug_callback_out(pb_ostream_t *stream, const uint8_t *buf,
{ size_t count) {
(void)stream; (void)stream;
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
msg_debug_out_append(buf[i]); msg_debug_out_append(buf[i]);
@ -165,8 +158,7 @@ static bool pb_debug_callback_out(pb_ostream_t *stream, const uint8_t *buf, size
#endif #endif
bool msg_write_common(char type, uint16_t msg_id, const void *msg_ptr) bool msg_write_common(char type, uint16_t msg_id, const void *msg_ptr) {
{
const pb_field_t *fields = MessageFields(type, 'o', msg_id); const pb_field_t *fields = MessageFields(type, 'o', msg_id);
if (!fields) { // unknown message if (!fields) { // unknown message
return false; return false;
@ -220,8 +212,8 @@ enum {
READSTATE_READING, READSTATE_READING,
}; };
void msg_process(char type, uint16_t msg_id, const pb_field_t *fields, uint8_t *msg_raw, uint32_t msg_size) void msg_process(char type, uint16_t msg_id, const pb_field_t *fields,
{ uint8_t *msg_raw, uint32_t msg_size) {
static uint8_t msg_data[MSG_IN_SIZE]; static uint8_t msg_data[MSG_IN_SIZE];
memzero(msg_data, sizeof(msg_data)); memzero(msg_data, sizeof(msg_data));
pb_istream_t stream = pb_istream_from_buffer(msg_raw, msg_size); pb_istream_t stream = pb_istream_from_buffer(msg_raw, msg_size);
@ -233,8 +225,7 @@ void msg_process(char type, uint16_t msg_id, const pb_field_t *fields, uint8_t *
} }
} }
void msg_read_common(char type, const uint8_t *buf, uint32_t len) void msg_read_common(char type, const uint8_t *buf, uint32_t len) {
{
static char read_state = READSTATE_IDLE; static char read_state = READSTATE_IDLE;
static uint8_t msg_in[MSG_IN_SIZE]; static uint8_t msg_in[MSG_IN_SIZE];
static uint16_t msg_id = 0xFFFF; static uint16_t msg_id = 0xFFFF;
@ -245,15 +236,18 @@ void msg_read_common(char type, const uint8_t *buf, uint32_t len)
if (len != 64) return; if (len != 64) return;
if (read_state == READSTATE_IDLE) { if (read_state == READSTATE_IDLE) {
if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { // invalid start - discard if (buf[0] != '?' || buf[1] != '#' ||
buf[2] != '#') { // invalid start - discard
return; return;
} }
msg_id = (buf[3] << 8) + buf[4]; msg_id = (buf[3] << 8) + buf[4];
msg_size = ((uint32_t) buf[5] << 24)+ (buf[6] << 16) + (buf[7] << 8) + buf[8]; msg_size =
((uint32_t)buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8];
fields = MessageFields(type, 'i', msg_id); fields = MessageFields(type, 'i', msg_id);
if (!fields) { // unknown message if (!fields) { // unknown message
fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Unknown message")); fsm_sendFailure(FailureType_Failure_UnexpectedMessage,
_("Unknown message"));
return; return;
} }
if (msg_size > MSG_IN_SIZE) { // message is too big :( if (msg_size > MSG_IN_SIZE) { // message is too big :(
@ -265,8 +259,7 @@ void msg_read_common(char type, const uint8_t *buf, uint32_t len)
memcpy(msg_in, buf + 9, len - 9); memcpy(msg_in, buf + 9, len - 9);
msg_pos = len - 9; msg_pos = len - 9;
} else } else if (read_state == READSTATE_READING) {
if (read_state == READSTATE_READING) {
if (buf[0] != '?') { // invalid contents if (buf[0] != '?') { // invalid contents
read_state = READSTATE_IDLE; read_state = READSTATE_IDLE;
return; return;
@ -286,8 +279,7 @@ void msg_read_common(char type, const uint8_t *buf, uint32_t len)
} }
} }
const uint8_t *msg_out_data(void) const uint8_t *msg_out_data(void) {
{
if (msg_out_start == msg_out_end) return 0; if (msg_out_start == msg_out_end) return 0;
uint8_t *data = msg_out + (msg_out_start * 64); uint8_t *data = msg_out + (msg_out_start * 64);
msg_out_start = (msg_out_start + 1) % (MSG_OUT_SIZE / 64); msg_out_start = (msg_out_start + 1) % (MSG_OUT_SIZE / 64);
@ -297,8 +289,7 @@ const uint8_t *msg_out_data(void)
#if DEBUG_LINK #if DEBUG_LINK
const uint8_t *msg_debug_out_data(void) const uint8_t *msg_debug_out_data(void) {
{
if (msg_debug_out_start == msg_debug_out_end) return 0; if (msg_debug_out_start == msg_debug_out_end) return 0;
uint8_t *data = msg_debug_out + (msg_debug_out_start * 64); uint8_t *data = msg_debug_out + (msg_debug_out_start * 64);
msg_debug_out_start = (msg_debug_out_start + 1) % (MSG_DEBUG_OUT_SIZE / 64); msg_debug_out_start = (msg_debug_out_start + 1) % (MSG_DEBUG_OUT_SIZE / 64);
@ -315,19 +306,21 @@ _Static_assert(sizeof(msg_tiny) >= sizeof(PassphraseAck), "msg_tiny too tiny");
_Static_assert(sizeof(msg_tiny) >= sizeof(ButtonAck), "msg_tiny too tiny"); _Static_assert(sizeof(msg_tiny) >= sizeof(ButtonAck), "msg_tiny too tiny");
_Static_assert(sizeof(msg_tiny) >= sizeof(PinMatrixAck), "msg_tiny too tiny"); _Static_assert(sizeof(msg_tiny) >= sizeof(PinMatrixAck), "msg_tiny too tiny");
#if DEBUG_LINK #if DEBUG_LINK
_Static_assert(sizeof(msg_tiny) >= sizeof(DebugLinkDecision), "msg_tiny too tiny"); _Static_assert(sizeof(msg_tiny) >= sizeof(DebugLinkDecision),
_Static_assert(sizeof(msg_tiny) >= sizeof(DebugLinkGetState), "msg_tiny too tiny"); "msg_tiny too tiny");
_Static_assert(sizeof(msg_tiny) >= sizeof(DebugLinkGetState),
"msg_tiny too tiny");
#endif #endif
uint16_t msg_tiny_id = 0xFFFF; uint16_t msg_tiny_id = 0xFFFF;
void msg_read_tiny(const uint8_t *buf, int len) void msg_read_tiny(const uint8_t *buf, int len) {
{
if (len != 64) return; if (len != 64) return;
if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') {
return; return;
} }
uint16_t msg_id = (buf[3] << 8) + buf[4]; uint16_t msg_id = (buf[3] << 8) + buf[4];
uint32_t msg_size = ((uint32_t) buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8]; uint32_t msg_size =
((uint32_t)buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8];
if (msg_size > 64 || len - msg_size < 9) { if (msg_size > 64 || len - msg_size < 9) {
return; return;
} }
@ -369,7 +362,8 @@ void msg_read_tiny(const uint8_t *buf, int len)
msg_tiny_id = 0xFFFF; msg_tiny_id = 0xFFFF;
} }
} else { } else {
fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Unknown message")); fsm_sendFailure(FailureType_Failure_UnexpectedMessage,
_("Unknown message"));
msg_tiny_id = 0xFFFF; msg_tiny_id = 0xFFFF;
} }
} }

View File

@ -20,8 +20,8 @@
#ifndef __MESSAGES_H__ #ifndef __MESSAGES_H__
#define __MESSAGES_H__ #define __MESSAGES_H__
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include "trezor.h" #include "trezor.h"
#define MSG_IN_SIZE (15 * 1024) #define MSG_IN_SIZE (15 * 1024)

View File

@ -23,10 +23,10 @@
#include "fsm.h" #include "fsm.h"
#include "gettext.h" #include "gettext.h"
#include "layout2.h" #include "layout2.h"
#include "memzero.h"
#include "protect.h" #include "protect.h"
#include "rng.h" #include "rng.h"
#include "secp256k1.h" #include "secp256k1.h"
#include "memzero.h"
const char *nem_validate_common(NEMTransactionCommon *common, bool inner) { const char *nem_validate_common(NEMTransactionCommon *common, bool inner) {
if (!common->has_network) { if (!common->has_network) {
@ -35,23 +35,28 @@ const char *nem_validate_common(NEMTransactionCommon *common, bool inner) {
} }
if (common->network > 0xFF || nem_network_name(common->network) == NULL) { if (common->network > 0xFF || nem_network_name(common->network) == NULL) {
return inner ? _("Invalid NEM network in inner transaction") : _("Invalid NEM network"); return inner ? _("Invalid NEM network in inner transaction")
: _("Invalid NEM network");
} }
if (!common->has_timestamp) { if (!common->has_timestamp) {
return inner ? _("No timestamp provided in inner transaction") : _("No timestamp provided"); return inner ? _("No timestamp provided in inner transaction")
: _("No timestamp provided");
} }
if (!common->has_fee) { if (!common->has_fee) {
return inner ? _("No fee provided in inner transaction") : _("No fee provided"); return inner ? _("No fee provided in inner transaction")
: _("No fee provided");
} }
if (!common->has_deadline) { if (!common->has_deadline) {
return inner ? _("No deadline provided in inner transaction") : _("No deadline provided"); return inner ? _("No deadline provided in inner transaction")
: _("No deadline provided");
} }
if (inner != common->has_signer) { if (inner != common->has_signer) {
return inner ? _("No signer provided in inner transaction") : _("Signer not allowed in outer transaction"); return inner ? _("No signer provided in inner transaction")
: _("Signer not allowed in outer transaction");
} }
if (common->has_signer && common->signer.size != sizeof(ed25519_public_key)) { if (common->has_signer && common->signer.size != sizeof(ed25519_public_key)) {
@ -61,15 +66,18 @@ const char *nem_validate_common(NEMTransactionCommon *common, bool inner) {
return NULL; return NULL;
} }
const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network) { const char *nem_validate_transfer(const NEMTransfer *transfer,
uint8_t network) {
if (!transfer->has_recipient) return _("No recipient provided"); if (!transfer->has_recipient) return _("No recipient provided");
if (!transfer->has_amount) return _("No amount provided"); if (!transfer->has_amount) return _("No amount provided");
if (transfer->has_public_key && transfer->public_key.size != sizeof(ed25519_public_key)) { if (transfer->has_public_key &&
transfer->public_key.size != sizeof(ed25519_public_key)) {
return _("Invalid recipient public key"); return _("Invalid recipient public key");
} }
if (!nem_validate_address(transfer->recipient, network)) return _("Invalid recipient address"); if (!nem_validate_address(transfer->recipient, network))
return _("Invalid recipient address");
for (size_t i = 0; i < transfer->mosaics_count; i++) { for (size_t i = 0; i < transfer->mosaics_count; i++) {
const NEMMosaic *mosaic = &transfer->mosaics[i]; const NEMMosaic *mosaic = &transfer->mosaics[i];
@ -82,52 +90,75 @@ const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network)
return NULL; return NULL;
} }
const char *nem_validate_provision_namespace(const NEMProvisionNamespace *provision_namespace, uint8_t network) { const char *nem_validate_provision_namespace(
const NEMProvisionNamespace *provision_namespace, uint8_t network) {
if (!provision_namespace->has_namespace) return _("No namespace provided"); if (!provision_namespace->has_namespace) return _("No namespace provided");
if (!provision_namespace->has_sink) return _("No rental sink provided"); if (!provision_namespace->has_sink) return _("No rental sink provided");
if (!provision_namespace->has_fee) return _("No rental sink fee provided"); if (!provision_namespace->has_fee) return _("No rental sink fee provided");
if (!nem_validate_address(provision_namespace->sink, network)) return _("Invalid rental sink address"); if (!nem_validate_address(provision_namespace->sink, network))
return _("Invalid rental sink address");
return NULL; return NULL;
} }
const char *nem_validate_mosaic_creation(const NEMMosaicCreation *mosaic_creation, uint8_t network) { const char *nem_validate_mosaic_creation(
if (!mosaic_creation->has_definition) return _("No mosaic definition provided"); const NEMMosaicCreation *mosaic_creation, uint8_t network) {
if (!mosaic_creation->has_definition)
return _("No mosaic definition provided");
if (!mosaic_creation->has_sink) return _("No creation sink provided"); if (!mosaic_creation->has_sink) return _("No creation sink provided");
if (!mosaic_creation->has_fee) return _("No creation sink fee provided"); if (!mosaic_creation->has_fee) return _("No creation sink fee provided");
if (!nem_validate_address(mosaic_creation->sink, network)) return _("Invalid creation sink address"); if (!nem_validate_address(mosaic_creation->sink, network))
return _("Invalid creation sink address");
if (mosaic_creation->definition.has_name) return _("Name not allowed in mosaic creation transactions"); if (mosaic_creation->definition.has_name)
if (mosaic_creation->definition.has_ticker) return _("Ticker not allowed in mosaic creation transactions"); return _("Name not allowed in mosaic creation transactions");
if (mosaic_creation->definition.networks_count) return _("Networks not allowed in mosaic creation transactions"); if (mosaic_creation->definition.has_ticker)
return _("Ticker not allowed in mosaic creation transactions");
if (mosaic_creation->definition.networks_count)
return _("Networks not allowed in mosaic creation transactions");
if (!mosaic_creation->definition.has_namespace) return _("No mosaic namespace provided"); if (!mosaic_creation->definition.has_namespace)
if (!mosaic_creation->definition.has_mosaic) return _("No mosaic name provided"); return _("No mosaic namespace provided");
if (!mosaic_creation->definition.has_mosaic)
return _("No mosaic name provided");
if (mosaic_creation->definition.has_levy) { if (mosaic_creation->definition.has_levy) {
if (!mosaic_creation->definition.has_fee) return _("No levy address provided"); if (!mosaic_creation->definition.has_fee)
if (!mosaic_creation->definition.has_levy_address) return _("No levy address provided"); return _("No levy address provided");
if (!mosaic_creation->definition.has_levy_namespace) return _("No levy namespace provided"); if (!mosaic_creation->definition.has_levy_address)
if (!mosaic_creation->definition.has_levy_mosaic) return _("No levy mosaic name provided"); return _("No levy address provided");
if (!mosaic_creation->definition.has_levy_namespace)
return _("No levy namespace provided");
if (!mosaic_creation->definition.has_levy_mosaic)
return _("No levy mosaic name provided");
if (!mosaic_creation->definition.has_divisibility) return _("No divisibility provided"); if (!mosaic_creation->definition.has_divisibility)
return _("No divisibility provided");
if (!mosaic_creation->definition.has_supply) return _("No supply provided"); if (!mosaic_creation->definition.has_supply) return _("No supply provided");
if (!mosaic_creation->definition.has_mutable_supply) return _("No supply mutability provided"); if (!mosaic_creation->definition.has_mutable_supply)
if (!mosaic_creation->definition.has_transferable) return _("No mosaic transferability provided"); return _("No supply mutability provided");
if (!mosaic_creation->definition.has_description) return _("No description provided"); if (!mosaic_creation->definition.has_transferable)
return _("No mosaic transferability provided");
if (!mosaic_creation->definition.has_description)
return _("No description provided");
if (mosaic_creation->definition.divisibility > NEM_MAX_DIVISIBILITY) return _("Invalid divisibility provided"); if (mosaic_creation->definition.divisibility > NEM_MAX_DIVISIBILITY)
if (mosaic_creation->definition.supply > NEM_MAX_SUPPLY) return _("Invalid supply provided"); return _("Invalid divisibility provided");
if (mosaic_creation->definition.supply > NEM_MAX_SUPPLY)
return _("Invalid supply provided");
if (!nem_validate_address(mosaic_creation->definition.levy_address, network)) return _("Invalid levy address"); if (!nem_validate_address(mosaic_creation->definition.levy_address,
network))
return _("Invalid levy address");
} }
return NULL; return NULL;
} }
const char *nem_validate_supply_change(const NEMMosaicSupplyChange *supply_change) { const char *nem_validate_supply_change(
const NEMMosaicSupplyChange *supply_change) {
if (!supply_change->has_namespace) return _("No namespace provided"); if (!supply_change->has_namespace) return _("No namespace provided");
if (!supply_change->has_mosaic) return _("No mosaic provided"); if (!supply_change->has_mosaic) return _("No mosaic provided");
if (!supply_change->has_type) return _("No type provided"); if (!supply_change->has_type) return _("No type provided");
@ -136,19 +167,24 @@ const char *nem_validate_supply_change(const NEMMosaicSupplyChange *supply_chang
return NULL; return NULL;
} }
const char *nem_validate_aggregate_modification(const NEMAggregateModification *aggregate_modification, bool creation) { const char *nem_validate_aggregate_modification(
const NEMAggregateModification *aggregate_modification, bool creation) {
if (creation && aggregate_modification->modifications_count == 0) { if (creation && aggregate_modification->modifications_count == 0) {
return _("No modifications provided"); return _("No modifications provided");
} }
for (size_t i = 0; i < aggregate_modification->modifications_count; i++) { for (size_t i = 0; i < aggregate_modification->modifications_count; i++) {
const NEMCosignatoryModification *modification = &aggregate_modification->modifications[i]; const NEMCosignatoryModification *modification =
&aggregate_modification->modifications[i];
if (!modification->has_type) return _("No modification type provided"); if (!modification->has_type) return _("No modification type provided");
if (!modification->has_public_key) return _("No cosignatory public key provided"); if (!modification->has_public_key)
if (modification->public_key.size != 32) return _("Invalid cosignatory public key provided"); return _("No cosignatory public key provided");
if (modification->public_key.size != 32)
return _("Invalid cosignatory public key provided");
if (creation && modification->type == NEMModificationType_CosignatoryModification_Delete) { if (creation && modification->type ==
NEMModificationType_CosignatoryModification_Delete) {
return _("Cannot remove cosignatory when converting account"); return _("Cannot remove cosignatory when converting account");
} }
} }
@ -156,15 +192,19 @@ const char *nem_validate_aggregate_modification(const NEMAggregateModification *
return NULL; return NULL;
} }
const char *nem_validate_importance_transfer(const NEMImportanceTransfer *importance_transfer) { const char *nem_validate_importance_transfer(
const NEMImportanceTransfer *importance_transfer) {
if (!importance_transfer->has_mode) return _("No mode provided"); if (!importance_transfer->has_mode) return _("No mode provided");
if (!importance_transfer->has_public_key) return _("No remote account provided"); if (!importance_transfer->has_public_key)
if (importance_transfer->public_key.size != 32) return _("Invalid remote account provided"); return _("No remote account provided");
if (importance_transfer->public_key.size != 32)
return _("Invalid remote account provided");
return NULL; return NULL;
} }
bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc) { bool nem_askTransfer(const NEMTransactionCommon *common,
const NEMTransfer *transfer, const char *desc) {
if (transfer->mosaics_count) { if (transfer->mosaics_count) {
const NEMMosaic *xem = NULL; const NEMMosaic *xem = NULL;
bool unknownMosaic = false; bool unknownMosaic = false;
@ -174,7 +214,8 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran
for (size_t i = 0; i < transfer->mosaics_count; i++) { for (size_t i = 0; i < transfer->mosaics_count; i++) {
const NEMMosaic *mosaic = &transfer->mosaics[i]; const NEMMosaic *mosaic = &transfer->mosaics[i];
definitions[i] = nem_mosaicByName(mosaic->namespace, mosaic->mosaic, common->network); definitions[i] =
nem_mosaicByName(mosaic->namespace, mosaic->mosaic, common->network);
if (definitions[i] == NEM_MOSAIC_DEFINITION_XEM) { if (definitions[i] == NEM_MOSAIC_DEFINITION_XEM) {
xem = mosaic; xem = mosaic;
@ -187,22 +228,18 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran
bn_read_uint64(transfer->amount, &multiplier); bn_read_uint64(transfer->amount, &multiplier);
if (unknownMosaic) { if (unknownMosaic) {
layoutDialogSwipe(&bmp_icon_question, layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("I take the risk"),
_("Cancel"), _("Unknown Mosaics"), _("Divisibility and levy"),
_("I take the risk"), _("cannot be shown for"), _("unknown mosaics!"), NULL,
_("Unknown Mosaics"), NULL, NULL);
_("Divisibility and levy"), if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput,
_("cannot be shown for"), false)) {
_("unknown mosaics!"),
NULL,
NULL,
NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return false; return false;
} }
} }
layoutNEMTransferXEM(desc, xem ? xem->quantity : 0, &multiplier, common->fee); layoutNEMTransferXEM(desc, xem ? xem->quantity : 0, &multiplier,
common->fee);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return false; return false;
} }
@ -215,12 +252,15 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran
} }
if (definitions[i]) { if (definitions[i]) {
layoutNEMTransferMosaic(definitions[i], mosaic->quantity, &multiplier, common->network); layoutNEMTransferMosaic(definitions[i], mosaic->quantity, &multiplier,
common->network);
} else { } else {
layoutNEMTransferUnknownMosaic(mosaic->namespace, mosaic->mosaic, mosaic->quantity, &multiplier); layoutNEMTransferUnknownMosaic(mosaic->namespace, mosaic->mosaic,
mosaic->quantity, &multiplier);
} }
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput,
false)) {
return false; return false;
} }
} }
@ -232,18 +272,15 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran
} }
if (transfer->has_payload) { if (transfer->has_payload) {
layoutNEMTransferPayload(transfer->payload.bytes, transfer->payload.size, transfer->has_public_key); layoutNEMTransferPayload(transfer->payload.bytes, transfer->payload.size,
transfer->has_public_key);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return false; return false;
} }
} }
layoutNEMDialog(&bmp_icon_question, layoutNEMDialog(&bmp_icon_question, _("Cancel"), _("Confirm"), desc,
_("Cancel"), _("Confirm transfer to"), transfer->recipient);
_("Confirm"),
desc,
_("Confirm transfer to"),
transfer->recipient);
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
return false; return false;
} }
@ -251,15 +288,19 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran
return true; return true;
} }
bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMTransfer *transfer) { bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node,
static uint8_t encrypted[NEM_ENCRYPTED_PAYLOAD_SIZE(sizeof(transfer->payload.bytes))]; const NEMTransactionCommon *common,
const NEMTransfer *transfer) {
static uint8_t
encrypted[NEM_ENCRYPTED_PAYLOAD_SIZE(sizeof(transfer->payload.bytes))];
const uint8_t *payload = transfer->payload.bytes; const uint8_t *payload = transfer->payload.bytes;
size_t size = transfer->payload.size; size_t size = transfer->payload.size;
if (transfer->has_public_key) { if (transfer->has_public_key) {
if (node == NULL) { if (node == NULL) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Private key unavailable for encrypted message")); fsm_sendFailure(FailureType_Failure_ProcessError,
_("Private key unavailable for encrypted message"));
return false; return false;
} }
@ -269,16 +310,12 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM
const uint8_t *iv = &encrypted[NEM_SALT_SIZE]; const uint8_t *iv = &encrypted[NEM_SALT_SIZE];
uint8_t *buffer = &encrypted[NEM_SALT_SIZE + AES_BLOCK_SIZE]; uint8_t *buffer = &encrypted[NEM_SALT_SIZE + AES_BLOCK_SIZE];
bool ret = hdnode_nem_encrypt(node, bool ret = hdnode_nem_encrypt(node, transfer->public_key.bytes, iv, salt,
transfer->public_key.bytes, payload, size, buffer);
iv,
salt,
payload,
size,
buffer);
if (!ret) { if (!ret) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to encrypt payload")); fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to encrypt payload"));
return false; return false;
} }
@ -286,34 +323,26 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM
size = NEM_ENCRYPTED_PAYLOAD_SIZE(size); size = NEM_ENCRYPTED_PAYLOAD_SIZE(size);
} }
bool ret = nem_transaction_create_transfer(context, bool ret = nem_transaction_create_transfer(
common->network, context, common->network, common->timestamp, NULL, common->fee,
common->timestamp, common->deadline, transfer->recipient, transfer->amount, payload, size,
NULL, transfer->has_public_key, transfer->mosaics_count);
common->fee,
common->deadline,
transfer->recipient,
transfer->amount,
payload,
size,
transfer->has_public_key,
transfer->mosaics_count);
if (!ret) { if (!ret) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to create transfer transaction")); fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to create transfer transaction"));
return false; return false;
} }
for (size_t i = 0; i < transfer->mosaics_count; i++) { for (size_t i = 0; i < transfer->mosaics_count; i++) {
const NEMMosaic *mosaic = &transfer->mosaics[i]; const NEMMosaic *mosaic = &transfer->mosaics[i];
ret = nem_transaction_write_mosaic(context, ret = nem_transaction_write_mosaic(context, mosaic->namespace,
mosaic->namespace, mosaic->mosaic, mosaic->quantity);
mosaic->mosaic,
mosaic->quantity);
if (!ret) { if (!ret) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to attach mosaics")); fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to attach mosaics"));
return false; return false;
} }
} }
@ -321,22 +350,22 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM
return true; return true;
} }
bool nem_askProvisionNamespace(const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace, const char *desc) { bool nem_askProvisionNamespace(const NEMTransactionCommon *common,
layoutDialogSwipe(&bmp_icon_question, const NEMProvisionNamespace *provision_namespace,
_("Cancel"), const char *desc) {
_("Next"), layoutDialogSwipe(
desc, &bmp_icon_question, _("Cancel"), _("Next"), desc, _("Create namespace"),
_("Create namespace"),
provision_namespace->namespace, provision_namespace->namespace,
provision_namespace->has_parent ? _("under namespace") : NULL, provision_namespace->has_parent ? _("under namespace") : NULL,
provision_namespace->has_parent ? provision_namespace->parent : NULL, provision_namespace->has_parent ? provision_namespace->parent : NULL,
NULL, NULL, NULL);
NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return false; return false;
} }
layoutNEMNetworkFee(desc, true, _("Confirm rental fee of"), provision_namespace->fee, _("and network fee of"), common->fee); layoutNEMNetworkFee(desc, true, _("Confirm rental fee of"),
provision_namespace->fee, _("and network fee of"),
common->fee);
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
return false; return false;
} }
@ -344,30 +373,23 @@ bool nem_askProvisionNamespace(const NEMTransactionCommon *common, const NEMProv
return true; return true;
} }
bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace) { bool nem_fsmProvisionNamespace(
return nem_transaction_create_provision_namespace(context, nem_transaction_ctx *context, const NEMTransactionCommon *common,
common->network, const NEMProvisionNamespace *provision_namespace) {
common->timestamp, return nem_transaction_create_provision_namespace(
NULL, context, common->network, common->timestamp, NULL, common->fee,
common->fee, common->deadline, provision_namespace->namespace,
common->deadline,
provision_namespace->namespace,
provision_namespace->has_parent ? provision_namespace->parent : NULL, provision_namespace->has_parent ? provision_namespace->parent : NULL,
provision_namespace->sink, provision_namespace->sink, provision_namespace->fee);
provision_namespace->fee);
} }
bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation, const char *desc, const char *address) { bool nem_askMosaicCreation(const NEMTransactionCommon *common,
layoutDialogSwipe(&bmp_icon_question, const NEMMosaicCreation *mosaic_creation,
_("Cancel"), const char *desc, const char *address) {
_("Next"), layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), desc,
desc, _("Create mosaic"), mosaic_creation->definition.mosaic,
_("Create mosaic"), _("under namespace"), mosaic_creation->definition.namespace,
mosaic_creation->definition.mosaic, NULL, NULL);
_("under namespace"),
mosaic_creation->definition.namespace,
NULL,
NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return false; return false;
} }
@ -379,25 +401,19 @@ bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCr
char str_out[32]; char str_out[32];
bn_format_uint64(mosaic_creation->definition.supply, bn_format_uint64(mosaic_creation->definition.supply, NULL, NULL,
NULL,
NULL,
mosaic_creation->definition.divisibility, mosaic_creation->definition.divisibility,
mosaic_creation->definition.divisibility, mosaic_creation->definition.divisibility, true, str_out,
true,
str_out,
sizeof(str_out)); sizeof(str_out));
layoutDialogSwipe(&bmp_icon_question, layoutDialogSwipe(
_("Cancel"), &bmp_icon_question, _("Cancel"), _("Next"), _("Properties"),
_("Next"), mosaic_creation->definition.mutable_supply ? _("Mutable supply:")
_("Properties"), : _("Immutable supply:"),
mosaic_creation->definition.mutable_supply ? _("Mutable supply:") : _("Immutable supply:"), str_out, _("Mosaic will be"),
str_out, mosaic_creation->definition.transferable ? _("transferable")
_("Mosaic will be"), : _("non-transferable"),
mosaic_creation->definition.transferable ? _("transferable") : _("non-transferable"), NULL, NULL);
NULL,
NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return false; return false;
} }
@ -409,22 +425,12 @@ bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCr
} }
if (strcmp(address, mosaic_creation->definition.levy_address) == 0) { if (strcmp(address, mosaic_creation->definition.levy_address) == 0) {
layoutDialogSwipe(&bmp_icon_question, layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"),
_("Cancel"), _("Levy Recipient"), _("Levy will be paid to"),
_("Next"), _("yourself"), NULL, NULL, NULL, NULL);
_("Levy Recipient"),
_("Levy will be paid to"),
_("yourself"),
NULL,
NULL,
NULL,
NULL);
} else { } else {
layoutNEMDialog(&bmp_icon_question, layoutNEMDialog(&bmp_icon_question, _("Cancel"), _("Next"),
_("Cancel"), _("Levy Recipient"), _("Levy will be paid to"),
_("Next"),
_("Levy Recipient"),
_("Levy will be paid to"),
mosaic_creation->definition.levy_address); mosaic_creation->definition.levy_address);
} }
@ -433,7 +439,9 @@ bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCr
} }
} }
layoutNEMNetworkFee(desc, true, _("Confirm creation fee"), mosaic_creation->fee, _("and network fee of"), common->fee); layoutNEMNetworkFee(desc, true, _("Confirm creation fee"),
mosaic_creation->fee, _("and network fee of"),
common->fee);
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
return false; return false;
} }
@ -441,62 +449,51 @@ bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCr
return true; return true;
} }
bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation) { bool nem_fsmMosaicCreation(nem_transaction_ctx *context,
return nem_transaction_create_mosaic_creation(context, const NEMTransactionCommon *common,
common->network, const NEMMosaicCreation *mosaic_creation) {
common->timestamp, return nem_transaction_create_mosaic_creation(
NULL, context, common->network, common->timestamp, NULL, common->fee,
common->fee, common->deadline, mosaic_creation->definition.namespace,
common->deadline,
mosaic_creation->definition.namespace,
mosaic_creation->definition.mosaic, mosaic_creation->definition.mosaic,
mosaic_creation->definition.description, mosaic_creation->definition.description,
mosaic_creation->definition.divisibility, mosaic_creation->definition.divisibility,
mosaic_creation->definition.supply, mosaic_creation->definition.supply,
mosaic_creation->definition.mutable_supply, mosaic_creation->definition.mutable_supply,
mosaic_creation->definition.transferable, mosaic_creation->definition.transferable,
mosaic_creation->definition.levy, mosaic_creation->definition.levy, mosaic_creation->definition.fee,
mosaic_creation->definition.fee,
mosaic_creation->definition.levy_address, mosaic_creation->definition.levy_address,
mosaic_creation->definition.levy_namespace, mosaic_creation->definition.levy_namespace,
mosaic_creation->definition.levy_mosaic, mosaic_creation->definition.levy_mosaic, mosaic_creation->sink,
mosaic_creation->sink,
mosaic_creation->fee); mosaic_creation->fee);
} }
bool nem_askSupplyChange(const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change, const char *desc) { bool nem_askSupplyChange(const NEMTransactionCommon *common,
layoutDialogSwipe(&bmp_icon_question, const NEMMosaicSupplyChange *supply_change,
_("Cancel"), const char *desc) {
_("Next"), layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), desc,
desc, _("Modify supply for"), supply_change->mosaic,
_("Modify supply for"), _("under namespace"), supply_change->namespace, NULL, NULL);
supply_change->mosaic,
_("under namespace"),
supply_change->namespace,
NULL,
NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return false; return false;
} }
char str_out[32]; char str_out[32];
bn_format_uint64(supply_change->delta, NULL, NULL, 0, 0, false, str_out, sizeof(str_out)); bn_format_uint64(supply_change->delta, NULL, NULL, 0, 0, false, str_out,
sizeof(str_out));
layoutDialogSwipe(&bmp_icon_question, layoutDialogSwipe(
_("Cancel"), &bmp_icon_question, _("Cancel"), _("Next"), desc,
_("Next"), supply_change->type == NEMSupplyChangeType_SupplyChange_Increase
desc, ? _("Increase supply by")
supply_change->type == NEMSupplyChangeType_SupplyChange_Increase ? _("Increase supply by") : _("Decrease supply by"), : _("Decrease supply by"),
str_out, str_out, _("whole units"), NULL, NULL, NULL);
_("whole units"),
NULL,
NULL,
NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return false; return false;
} }
layoutNEMNetworkFee(desc, true, _("Confirm network fee"), common->fee, NULL, 0); layoutNEMNetworkFee(desc, true, _("Confirm network fee"), common->fee, NULL,
0);
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
return false; return false;
} }
@ -504,31 +501,23 @@ bool nem_askSupplyChange(const NEMTransactionCommon *common, const NEMMosaicSupp
return true; return true;
} }
bool nem_fsmSupplyChange(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change) { bool nem_fsmSupplyChange(nem_transaction_ctx *context,
return nem_transaction_create_mosaic_supply_change(context, const NEMTransactionCommon *common,
common->network, const NEMMosaicSupplyChange *supply_change) {
common->timestamp, return nem_transaction_create_mosaic_supply_change(
NULL, context, common->network, common->timestamp, NULL, common->fee,
common->fee, common->deadline, supply_change->namespace, supply_change->mosaic,
common->deadline, supply_change->type, supply_change->delta);
supply_change->namespace,
supply_change->mosaic,
supply_change->type,
supply_change->delta);
} }
bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification, const char *desc, bool creation) { bool nem_askAggregateModification(
const NEMTransactionCommon *common,
const NEMAggregateModification *aggregate_modification, const char *desc,
bool creation) {
if (creation) { if (creation) {
layoutDialogSwipe(&bmp_icon_question, layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), desc,
_("Cancel"), _("Convert account to"), _("multisig account?"), NULL,
_("Next"), NULL, NULL, NULL);
desc,
_("Convert account to"),
_("multisig account?"),
NULL,
NULL,
NULL,
NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return false; return false;
} }
@ -537,14 +526,15 @@ bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMA
char address[NEM_ADDRESS_SIZE + 1]; char address[NEM_ADDRESS_SIZE + 1];
for (size_t i = 0; i < aggregate_modification->modifications_count; i++) { for (size_t i = 0; i < aggregate_modification->modifications_count; i++) {
const NEMCosignatoryModification *modification = &aggregate_modification->modifications[i]; const NEMCosignatoryModification *modification =
&aggregate_modification->modifications[i];
nem_get_address(modification->public_key.bytes, common->network, address); nem_get_address(modification->public_key.bytes, common->network, address);
layoutNEMDialog(&bmp_icon_question, layoutNEMDialog(
_("Cancel"), &bmp_icon_question, _("Cancel"), _("Next"), desc,
_("Next"), modification->type == NEMModificationType_CosignatoryModification_Add
desc, ? _("Add cosignatory")
modification->type == NEMModificationType_CosignatoryModification_Add ? _("Add cosignatory") : _("Remove cosignatory"), : _("Remove cosignatory"),
address); address);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return false; return false;
@ -555,30 +545,21 @@ bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMA
if (relative_change) { if (relative_change) {
char str_out[32]; char str_out[32];
bn_format_uint64(relative_change < 0 ? -relative_change : relative_change, bn_format_uint64(relative_change < 0 ? -relative_change : relative_change,
NULL, NULL, NULL, 0, 0, false, str_out, sizeof(str_out));
NULL,
0,
0,
false,
str_out,
sizeof(str_out));
layoutDialogSwipe(&bmp_icon_question, layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), desc,
_("Cancel"), creation ? _("Set minimum")
_("Next"), : (relative_change < 0 ? _("Decrease minimum")
desc, : _("Increase minimum")),
creation ? _("Set minimum") : (relative_change < 0 ? _("Decrease minimum") : _("Increase minimum")),
creation ? _("cosignatories to") : _("cosignatories by"), creation ? _("cosignatories to") : _("cosignatories by"),
str_out, str_out, NULL, NULL, NULL);
NULL,
NULL,
NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return false; return false;
} }
} }
layoutNEMNetworkFee(desc, true, _("Confirm network fee"), common->fee, NULL, 0); layoutNEMNetworkFee(desc, true, _("Confirm network fee"), common->fee, NULL,
0);
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
return false; return false;
} }
@ -586,50 +567,49 @@ bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMA
return true; return true;
} }
bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification) { bool nem_fsmAggregateModification(
bool ret = nem_transaction_create_aggregate_modification(context, nem_transaction_ctx *context, const NEMTransactionCommon *common,
common->network, const NEMAggregateModification *aggregate_modification) {
common->timestamp, bool ret = nem_transaction_create_aggregate_modification(
NULL, context, common->network, common->timestamp, NULL, common->fee,
common->fee, common->deadline, aggregate_modification->modifications_count,
common->deadline,
aggregate_modification->modifications_count,
aggregate_modification->relative_change != 0); aggregate_modification->relative_change != 0);
if (!ret) return false; if (!ret) return false;
for (size_t i = 0; i < aggregate_modification->modifications_count; i++) { for (size_t i = 0; i < aggregate_modification->modifications_count; i++) {
const NEMCosignatoryModification *modification = &aggregate_modification->modifications[i]; const NEMCosignatoryModification *modification =
&aggregate_modification->modifications[i];
ret = nem_transaction_write_cosignatory_modification(context, ret = nem_transaction_write_cosignatory_modification(
modification->type, context, modification->type, modification->public_key.bytes);
modification->public_key.bytes);
if (!ret) return false; if (!ret) return false;
} }
if (aggregate_modification->relative_change) { if (aggregate_modification->relative_change) {
ret = nem_transaction_write_minimum_cosignatories(context, aggregate_modification->relative_change); ret = nem_transaction_write_minimum_cosignatories(
context, aggregate_modification->relative_change);
if (!ret) return false; if (!ret) return false;
} }
return true; return true;
} }
bool nem_askImportanceTransfer(const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer, const char *desc) { bool nem_askImportanceTransfer(const NEMTransactionCommon *common,
layoutDialogSwipe(&bmp_icon_question, const NEMImportanceTransfer *importance_transfer,
_("Cancel"), const char *desc) {
_("Next"), layoutDialogSwipe(
desc, &bmp_icon_question, _("Cancel"), _("Next"), desc,
importance_transfer->mode == NEMImportanceTransferMode_ImportanceTransfer_Activate ? _("Activate remote") : _("Deactivate remote"), importance_transfer->mode ==
_("harvesting?"), NEMImportanceTransferMode_ImportanceTransfer_Activate
NULL, ? _("Activate remote")
NULL, : _("Deactivate remote"),
NULL, _("harvesting?"), NULL, NULL, NULL, NULL);
NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return false; return false;
} }
layoutNEMNetworkFee(desc, true, _("Confirm network fee"), common->fee, NULL, 0); layoutNEMNetworkFee(desc, true, _("Confirm network fee"), common->fee, NULL,
0);
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
return false; return false;
} }
@ -637,22 +617,19 @@ bool nem_askImportanceTransfer(const NEMTransactionCommon *common, const NEMImpo
return true; return true;
} }
bool nem_fsmImportanceTransfer(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer) { bool nem_fsmImportanceTransfer(
return nem_transaction_create_importance_transfer(context, nem_transaction_ctx *context, const NEMTransactionCommon *common,
common->network, const NEMImportanceTransfer *importance_transfer) {
common->timestamp, return nem_transaction_create_importance_transfer(
NULL, context, common->network, common->timestamp, NULL, common->fee,
common->fee, common->deadline, importance_transfer->mode,
common->deadline,
importance_transfer->mode,
importance_transfer->public_key.bytes); importance_transfer->public_key.bytes);
} }
bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee) { bool nem_askMultisig(const char *address, const char *desc, bool cosigning,
layoutNEMDialog(&bmp_icon_question, uint64_t fee) {
_("Cancel"), layoutNEMDialog(
_("Next"), &bmp_icon_question, _("Cancel"), _("Next"), desc,
desc,
cosigning ? _("Cosign transaction for") : _("Initiate transaction for"), cosigning ? _("Cosign transaction for") : _("Initiate transaction for"),
address); address);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
@ -667,35 +644,32 @@ bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint
return true; return true;
} }
bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning) { bool nem_fsmMultisig(nem_transaction_ctx *context,
const NEMTransactionCommon *common,
const nem_transaction_ctx *inner, bool cosigning) {
bool ret; bool ret;
if (cosigning) { if (cosigning) {
ret = nem_transaction_create_multisig_signature(context, ret = nem_transaction_create_multisig_signature(
common->network, context, common->network, common->timestamp, NULL, common->fee,
common->timestamp, common->deadline, inner);
NULL,
common->fee,
common->deadline,
inner);
} else { } else {
ret = nem_transaction_create_multisig(context, ret = nem_transaction_create_multisig(context, common->network,
common->network, common->timestamp, NULL, common->fee,
common->timestamp, common->deadline, inner);
NULL,
common->fee,
common->deadline,
inner);
} }
if (!ret) { if (!ret) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to create multisig transaction")); fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to create multisig transaction"));
return false; return false;
} }
return true; return true;
} }
const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *mosaic, uint8_t network) { const NEMMosaicDefinition *nem_mosaicByName(const char *namespace,
const char *mosaic,
uint8_t network) {
for (size_t i = 0; i < NEM_MOSAIC_DEFINITIONS_COUNT; i++) { for (size_t i = 0; i < NEM_MOSAIC_DEFINITIONS_COUNT; i++) {
const NEMMosaicDefinition *definition = &NEM_MOSAIC_DEFINITIONS[i]; const NEMMosaicDefinition *definition = &NEM_MOSAIC_DEFINITIONS[i];
@ -707,7 +681,10 @@ const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *m
return NULL; return NULL;
} }
static inline size_t format_amount(const NEMMosaicDefinition *definition, const bignum256 *amnt, const bignum256 *multiplier, int divisor, char *str_out, size_t size) { static inline size_t format_amount(const NEMMosaicDefinition *definition,
const bignum256 *amnt,
const bignum256 *multiplier, int divisor,
char *str_out, size_t size) {
bignum256 val; bignum256 val;
memcpy(&val, amnt, sizeof(bignum256)); memcpy(&val, amnt, sizeof(bignum256));
@ -716,14 +693,11 @@ static inline size_t format_amount(const NEMMosaicDefinition *definition, const
divisor += NEM_MOSAIC_DEFINITION_XEM->divisibility; divisor += NEM_MOSAIC_DEFINITION_XEM->divisibility;
} }
return bn_format(&val, return bn_format(
NULL, &val, NULL,
definition && definition->has_ticker ? definition->ticker : NULL, definition && definition->has_ticker ? definition->ticker : NULL,
definition && definition->has_divisibility ? definition->divisibility : 0, definition && definition->has_divisibility ? definition->divisibility : 0,
-divisor, -divisor, false, str_out, size);
false,
str_out,
size);
} }
size_t nem_canonicalizeMosaics(NEMMosaic *mosaics, size_t mosaics_count) { size_t nem_canonicalizeMosaics(NEMMosaic *mosaics, size_t mosaics_count) {
@ -778,14 +752,18 @@ size_t nem_canonicalizeMosaics(NEMMosaic *mosaics, size_t mosaics_count) {
return actual_count; return actual_count;
} }
void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size) { void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition,
uint64_t quantity, const bignum256 *multiplier,
char *str_out, size_t size) {
bignum256 amnt; bignum256 amnt;
bn_read_uint64(quantity, &amnt); bn_read_uint64(quantity, &amnt);
format_amount(definition, &amnt, multiplier, 0, str_out, size); format_amount(definition, &amnt, multiplier, 0, str_out, size);
} }
bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network, char *str_out, size_t size) { bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition,
uint64_t quantity, const bignum256 *multiplier,
uint8_t network, char *str_out, size_t size) {
if (!definition->has_levy || !definition->has_fee) { if (!definition->has_levy || !definition->has_fee) {
return false; return false;
} }
@ -794,7 +772,8 @@ bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quanti
bn_read_uint64(quantity, &amnt); bn_read_uint64(quantity, &amnt);
bn_read_uint64(definition->fee, &fee); bn_read_uint64(definition->fee, &fee);
const NEMMosaicDefinition *mosaic = nem_mosaicByName(definition->levy_namespace, definition->levy_mosaic, network); const NEMMosaicDefinition *mosaic = nem_mosaicByName(
definition->levy_namespace, definition->levy_mosaic, network);
switch (definition->levy) { switch (definition->levy) {
case NEMMosaicLevy_MosaicLevy_Absolute: case NEMMosaicLevy_MosaicLevy_Absolute:
@ -802,7 +781,8 @@ bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quanti
case NEMMosaicLevy_MosaicLevy_Percentile: case NEMMosaicLevy_MosaicLevy_Percentile:
bn_multiply(&fee, &amnt, &secp256k1.prime); bn_multiply(&fee, &amnt, &secp256k1.prime);
return format_amount(mosaic, &amnt, multiplier, NEM_LEVY_PERCENTILE_DIVISOR, str_out, size); return format_amount(mosaic, &amnt, multiplier,
NEM_LEVY_PERCENTILE_DIVISOR, str_out, size);
default: default:
return false; return false;

View File

@ -29,47 +29,90 @@
const char *nem_validate_common(NEMTransactionCommon *common, bool inner); const char *nem_validate_common(NEMTransactionCommon *common, bool inner);
const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network); const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network);
const char *nem_validate_provision_namespace(const NEMProvisionNamespace *provision_namespace, uint8_t network); const char *nem_validate_provision_namespace(
const char *nem_validate_mosaic_creation(const NEMMosaicCreation *mosaic_creation, uint8_t network); const NEMProvisionNamespace *provision_namespace, uint8_t network);
const char *nem_validate_supply_change(const NEMMosaicSupplyChange *supply_change); const char *nem_validate_mosaic_creation(
const char *nem_validate_aggregate_modification(const NEMAggregateModification *aggregate_modification, bool creation); const NEMMosaicCreation *mosaic_creation, uint8_t network);
const char *nem_validate_importance_transfer(const NEMImportanceTransfer *importance_transfer); const char *nem_validate_supply_change(
const NEMMosaicSupplyChange *supply_change);
const char *nem_validate_aggregate_modification(
const NEMAggregateModification *aggregate_modification, bool creation);
const char *nem_validate_importance_transfer(
const NEMImportanceTransfer *importance_transfer);
bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc); bool nem_askTransfer(const NEMTransactionCommon *common,
bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMTransfer *transfer); const NEMTransfer *transfer, const char *desc);
bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node,
const NEMTransactionCommon *common,
const NEMTransfer *transfer);
bool nem_askProvisionNamespace(const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace, const char *desc); bool nem_askProvisionNamespace(const NEMTransactionCommon *common,
bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace); const NEMProvisionNamespace *provision_namespace,
const char *desc);
bool nem_fsmProvisionNamespace(
nem_transaction_ctx *context, const NEMTransactionCommon *common,
const NEMProvisionNamespace *provision_namespace);
bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation, const char *desc, const char *address); bool nem_askMosaicCreation(const NEMTransactionCommon *common,
bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation); const NEMMosaicCreation *mosaic_creation,
const char *desc, const char *address);
bool nem_fsmMosaicCreation(nem_transaction_ctx *context,
const NEMTransactionCommon *common,
const NEMMosaicCreation *mosaic_creation);
bool nem_askSupplyChange(const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change, const char *desc); bool nem_askSupplyChange(const NEMTransactionCommon *common,
bool nem_fsmSupplyChange(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change); const NEMMosaicSupplyChange *supply_change,
const char *desc);
bool nem_fsmSupplyChange(nem_transaction_ctx *context,
const NEMTransactionCommon *common,
const NEMMosaicSupplyChange *supply_change);
bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification, const char *desc, bool creation); bool nem_askAggregateModification(
bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification); const NEMTransactionCommon *common,
const NEMAggregateModification *aggregate_modification, const char *desc,
bool creation);
bool nem_fsmAggregateModification(
nem_transaction_ctx *context, const NEMTransactionCommon *common,
const NEMAggregateModification *aggregate_modification);
bool nem_askImportanceTransfer(const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer, const char *desc); bool nem_askImportanceTransfer(const NEMTransactionCommon *common,
bool nem_fsmImportanceTransfer(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer); const NEMImportanceTransfer *importance_transfer,
const char *desc);
bool nem_fsmImportanceTransfer(
nem_transaction_ctx *context, const NEMTransactionCommon *common,
const NEMImportanceTransfer *importance_transfer);
bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee); bool nem_askMultisig(const char *address, const char *desc, bool cosigning,
bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning); uint64_t fee);
bool nem_fsmMultisig(nem_transaction_ctx *context,
const NEMTransactionCommon *common,
const nem_transaction_ctx *inner, bool cosigning);
const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *mosaic, uint8_t network); const NEMMosaicDefinition *nem_mosaicByName(const char *namespace,
const char *mosaic,
uint8_t network);
size_t nem_canonicalizeMosaics(NEMMosaic *mosaics, size_t mosaics_count); size_t nem_canonicalizeMosaics(NEMMosaic *mosaics, size_t mosaics_count);
void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size); void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition,
bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network, char *str_out, size_t size); uint64_t quantity, const bignum256 *multiplier,
char *str_out, size_t size);
bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition,
uint64_t quantity, const bignum256 *multiplier,
uint8_t network, char *str_out, size_t size);
static inline void nem_mosaicFormatName(const char *namespace, const char *mosaic, char *str_out, size_t size) { static inline void nem_mosaicFormatName(const char *namespace,
const char *mosaic, char *str_out,
size_t size) {
strlcpy(str_out, namespace, size); strlcpy(str_out, namespace, size);
strlcat(str_out, ".", size); strlcat(str_out, ".", size);
strlcat(str_out, mosaic, size); strlcat(str_out, mosaic, size);
} }
static inline bool nem_mosaicMatches(const NEMMosaicDefinition *definition, const char *namespace, const char *mosaic, uint8_t network) { static inline bool nem_mosaicMatches(const NEMMosaicDefinition *definition,
if (strcmp(namespace, definition->namespace) == 0 && strcmp(mosaic, definition->mosaic) == 0) { const char *namespace, const char *mosaic,
uint8_t network) {
if (strcmp(namespace, definition->namespace) == 0 &&
strcmp(mosaic, definition->mosaic) == 0) {
if (definition->networks_count == 0) { if (definition->networks_count == 0) {
return true; return true;
} }

View File

@ -17,19 +17,17 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <libopencm3/stm32/flash.h>
#include "otp.h" #include "otp.h"
#include <libopencm3/stm32/flash.h>
#define FLASH_OTP_BASE 0x1FFF7800U #define FLASH_OTP_BASE 0x1FFF7800U
#define FLASH_OTP_LOCK_BASE 0x1FFF7A00U #define FLASH_OTP_LOCK_BASE 0x1FFF7A00U
bool flash_otp_is_locked(uint8_t block) bool flash_otp_is_locked(uint8_t block) {
{
return 0x00 == *(volatile uint8_t *)(FLASH_OTP_LOCK_BASE + block); return 0x00 == *(volatile uint8_t *)(FLASH_OTP_LOCK_BASE + block);
} }
bool flash_otp_lock(uint8_t block) bool flash_otp_lock(uint8_t block) {
{
if (block >= FLASH_OTP_NUM_BLOCKS) { if (block >= FLASH_OTP_NUM_BLOCKS) {
return false; return false;
} }
@ -39,25 +37,29 @@ bool flash_otp_lock(uint8_t block)
return true; return true;
} }
bool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data, uint8_t datalen) bool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data,
{ uint8_t datalen) {
if (block >= FLASH_OTP_NUM_BLOCKS || offset + datalen > FLASH_OTP_BLOCK_SIZE) { if (block >= FLASH_OTP_NUM_BLOCKS ||
offset + datalen > FLASH_OTP_BLOCK_SIZE) {
return false; return false;
} }
for (uint8_t i = 0; i < datalen; i++) { for (uint8_t i = 0; i < datalen; i++) {
data[i] = *(volatile uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i); data[i] = *(volatile uint8_t *)(FLASH_OTP_BASE +
block * FLASH_OTP_BLOCK_SIZE + offset + i);
} }
return true; return true;
} }
bool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data, uint8_t datalen) bool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data,
{ uint8_t datalen) {
if (block >= FLASH_OTP_NUM_BLOCKS || offset + datalen > FLASH_OTP_BLOCK_SIZE) { if (block >= FLASH_OTP_NUM_BLOCKS ||
offset + datalen > FLASH_OTP_BLOCK_SIZE) {
return false; return false;
} }
flash_unlock(); flash_unlock();
for (uint8_t i = 0; i < datalen; i++) { for (uint8_t i = 0; i < datalen; i++) {
uint32_t address = FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i; uint32_t address =
FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i;
flash_program_byte(address, data[i]); flash_program_byte(address, data[i]);
} }
flash_lock(); flash_lock();

View File

@ -20,8 +20,8 @@
#ifndef __OTP_H__ #ifndef __OTP_H__
#define __OTP_H__ #define __OTP_H__
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#define FLASH_OTP_NUM_BLOCKS 16 #define FLASH_OTP_NUM_BLOCKS 16
#define FLASH_OTP_BLOCK_SIZE 32 #define FLASH_OTP_BLOCK_SIZE 32
@ -30,7 +30,9 @@
bool flash_otp_is_locked(uint8_t block); bool flash_otp_is_locked(uint8_t block);
bool flash_otp_lock(uint8_t block); bool flash_otp_lock(uint8_t block);
bool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data, uint8_t datalen); bool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data,
bool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data, uint8_t datalen); uint8_t datalen);
bool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data,
uint8_t datalen);
#endif #endif

View File

@ -19,15 +19,14 @@
#include <string.h> #include <string.h>
#include "pinmatrix.h"
#include "layout2.h" #include "layout2.h"
#include "oled.h" #include "oled.h"
#include "pinmatrix.h"
#include "rng.h" #include "rng.h"
static char pinmatrix_perm[10] = "XXXXXXXXX"; static char pinmatrix_perm[10] = "XXXXXXXXX";
void pinmatrix_draw(const char *text) void pinmatrix_draw(const char *text) {
{
const BITMAP *bmp_digits[10] = { const BITMAP *bmp_digits[10] = {
&bmp_digit0, &bmp_digit1, &bmp_digit2, &bmp_digit3, &bmp_digit4, &bmp_digit0, &bmp_digit1, &bmp_digit2, &bmp_digit3, &bmp_digit4,
&bmp_digit5, &bmp_digit6, &bmp_digit7, &bmp_digit8, &bmp_digit9, &bmp_digit5, &bmp_digit6, &bmp_digit7, &bmp_digit8, &bmp_digit9,
@ -41,14 +40,15 @@ void pinmatrix_draw(const char *text)
if (text) { if (text) {
oledDrawStringCenter(OLED_WIDTH / 2, 0, text, FONT_STANDARD); oledDrawStringCenter(OLED_WIDTH / 2, 0, text, FONT_STANDARD);
} }
oledDrawBitmap((OLED_WIDTH - 3 * w - 2 * pad) / 2 + i * (w + pad), OLED_HEIGHT - 3 * h - 2 * pad + j * (h + pad), bmp_digits[k]); oledDrawBitmap((OLED_WIDTH - 3 * w - 2 * pad) / 2 + i * (w + pad),
OLED_HEIGHT - 3 * h - 2 * pad + j * (h + pad),
bmp_digits[k]);
} }
} }
oledRefresh(); oledRefresh();
} }
void pinmatrix_start(const char *text) void pinmatrix_start(const char *text) {
{
for (int i = 0; i < 9; i++) { for (int i = 0; i < 9; i++) {
pinmatrix_perm[i] = '1' + i; pinmatrix_perm[i] = '1' + i;
} }
@ -57,8 +57,7 @@ void pinmatrix_start(const char *text)
pinmatrix_draw(text); pinmatrix_draw(text);
} }
void pinmatrix_done(char *pin) void pinmatrix_done(char *pin) {
{
int k, i = 0; int k, i = 0;
while (pin && pin[i]) { while (pin && pin[i]) {
k = pin[i] - '1'; k = pin[i] - '1';
@ -74,9 +73,6 @@ void pinmatrix_done(char *pin)
#if DEBUG_LINK #if DEBUG_LINK
const char *pinmatrix_get(void) const char *pinmatrix_get(void) { return pinmatrix_perm; }
{
return pinmatrix_perm;
}
#endif #endif

View File

@ -18,28 +18,27 @@
*/ */
#include "protect.h" #include "protect.h"
#include "config.h"
#include "memory.h"
#include "messages.h"
#include "usb.h"
#include "oled.h"
#include "buttons.h" #include "buttons.h"
#include "pinmatrix.h" #include "config.h"
#include "fsm.h"
#include "layout2.h"
#include "util.h"
#include "debug.h" #include "debug.h"
#include "fsm.h"
#include "gettext.h" #include "gettext.h"
#include "layout2.h"
#include "memory.h"
#include "memzero.h" #include "memzero.h"
#include "messages.h"
#include "messages.pb.h" #include "messages.pb.h"
#include "oled.h"
#include "pinmatrix.h"
#include "usb.h"
#include "util.h"
#define MAX_WRONG_PINS 15 #define MAX_WRONG_PINS 15
bool protectAbortedByCancel = false; bool protectAbortedByCancel = false;
bool protectAbortedByInitialize = false; bool protectAbortedByInitialize = false;
bool protectButton(ButtonRequestType type, bool confirm_only) bool protectButton(ButtonRequestType type, bool confirm_only) {
{
ButtonRequest resp; ButtonRequest resp;
bool result = false; bool result = false;
bool acked = false; bool acked = false;
@ -79,7 +78,8 @@ bool protectButton(ButtonRequestType type, bool confirm_only)
// check for Cancel / Initialize // check for Cancel / Initialize
protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel);
protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); protectAbortedByInitialize =
(msg_tiny_id == MessageType_MessageType_Initialize);
if (protectAbortedByCancel || protectAbortedByInitialize) { if (protectAbortedByCancel || protectAbortedByInitialize) {
msg_tiny_id = 0xFFFF; msg_tiny_id = 0xFFFF;
result = false; result = false;
@ -111,8 +111,7 @@ bool protectButton(ButtonRequestType type, bool confirm_only)
return result; return result;
} }
const char *requestPin(PinMatrixRequestType type, const char *text) const char *requestPin(PinMatrixRequestType type, const char *text) {
{
PinMatrixRequest resp; PinMatrixRequest resp;
memzero(&resp, sizeof(PinMatrixRequest)); memzero(&resp, sizeof(PinMatrixRequest));
resp.has_type = true; resp.has_type = true;
@ -131,7 +130,8 @@ const char *requestPin(PinMatrixRequestType type, const char *text)
} }
// check for Cancel / Initialize // check for Cancel / Initialize
protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel);
protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); protectAbortedByInitialize =
(msg_tiny_id == MessageType_MessageType_Initialize);
if (protectAbortedByCancel || protectAbortedByInitialize) { if (protectAbortedByCancel || protectAbortedByInitialize) {
pinmatrix_done(0); pinmatrix_done(0);
msg_tiny_id = 0xFFFF; msg_tiny_id = 0xFFFF;
@ -147,8 +147,8 @@ const char *requestPin(PinMatrixRequestType type, const char *text)
} }
} }
secbool protectPinUiCallback(uint32_t wait, uint32_t progress, const char* message) secbool protectPinUiCallback(uint32_t wait, uint32_t progress,
{ const char *message) {
// Convert wait to secstr string. // Convert wait to secstr string.
char secstrbuf[] = _("________0 seconds"); char secstrbuf[] = _("________0 seconds");
char *secstr = secstrbuf + 9; char *secstr = secstrbuf + 9;
@ -166,7 +166,8 @@ secbool protectPinUiCallback(uint32_t wait, uint32_t progress, const char* messa
oledDrawStringCenter(OLED_WIDTH / 2, 0 * 9, message, FONT_STANDARD); oledDrawStringCenter(OLED_WIDTH / 2, 0 * 9, message, FONT_STANDARD);
oledDrawStringCenter(OLED_WIDTH / 2, 2 * 9, _("Please wait"), FONT_STANDARD); oledDrawStringCenter(OLED_WIDTH / 2, 2 * 9, _("Please wait"), FONT_STANDARD);
oledDrawStringCenter(OLED_WIDTH / 2, 3 * 9, secstr, FONT_STANDARD); oledDrawStringCenter(OLED_WIDTH / 2, 3 * 9, secstr, FONT_STANDARD);
oledDrawStringCenter(OLED_WIDTH / 2, 4 * 9, _("to continue ..."), FONT_STANDARD); oledDrawStringCenter(OLED_WIDTH / 2, 4 * 9, _("to continue ..."),
FONT_STANDARD);
// progressbar // progressbar
oledFrame(0, OLED_HEIGHT - 8, OLED_WIDTH - 1, OLED_HEIGHT - 1); oledFrame(0, OLED_HEIGHT - 8, OLED_WIDTH - 1, OLED_HEIGHT - 1);
oledBox(1, OLED_HEIGHT - 7, OLED_WIDTH - 2, OLED_HEIGHT - 2, 0); oledBox(1, OLED_HEIGHT - 7, OLED_WIDTH - 2, OLED_HEIGHT - 2, 0);
@ -178,7 +179,8 @@ secbool protectPinUiCallback(uint32_t wait, uint32_t progress, const char* messa
oledRefresh(); oledRefresh();
// Check for Cancel / Initialize. // Check for Cancel / Initialize.
protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel);
protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); protectAbortedByInitialize =
(msg_tiny_id == MessageType_MessageType_Initialize);
if (protectAbortedByCancel || protectAbortedByInitialize) { if (protectAbortedByCancel || protectAbortedByInitialize) {
msg_tiny_id = 0xFFFF; msg_tiny_id = 0xFFFF;
usbTiny(0); usbTiny(0);
@ -189,15 +191,15 @@ secbool protectPinUiCallback(uint32_t wait, uint32_t progress, const char* messa
return secfalse; return secfalse;
} }
bool protectPin(bool use_cached) bool protectPin(bool use_cached) {
{
if (use_cached && session_isUnlocked()) { if (use_cached && session_isUnlocked()) {
return true; return true;
} }
const char *pin = ""; const char *pin = "";
if (config_hasPin()) { if (config_hasPin()) {
pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current,
_("Please enter current PIN:"));
if (!pin) { if (!pin) {
fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); fsm_sendFailure(FailureType_Failure_PinCancelled, NULL);
return false; return false;
@ -211,14 +213,14 @@ bool protectPin(bool use_cached)
return ret; return ret;
} }
bool protectChangePin(bool removal) bool protectChangePin(bool removal) {
{
static CONFIDENTIAL char old_pin[MAX_PIN_LEN + 1] = ""; static CONFIDENTIAL char old_pin[MAX_PIN_LEN + 1] = "";
static CONFIDENTIAL char new_pin[MAX_PIN_LEN + 1] = ""; static CONFIDENTIAL char new_pin[MAX_PIN_LEN + 1] = "";
const char *pin = NULL; const char *pin = NULL;
if (config_hasPin()) { if (config_hasPin()) {
pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current,
_("Please enter current PIN:"));
if (pin == NULL) { if (pin == NULL) {
fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); fsm_sendFailure(FailureType_Failure_PinCancelled, NULL);
return false; return false;
@ -239,7 +241,8 @@ bool protectChangePin(bool removal)
} }
if (!removal) { if (!removal) {
pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst, _("Please enter new PIN:")); pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst,
_("Please enter new PIN:"));
if (pin == NULL) { if (pin == NULL) {
memzero(old_pin, sizeof(old_pin)); memzero(old_pin, sizeof(old_pin));
fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); fsm_sendFailure(FailureType_Failure_PinCancelled, NULL);
@ -247,7 +250,8 @@ bool protectChangePin(bool removal)
} }
strlcpy(new_pin, pin, sizeof(new_pin)); strlcpy(new_pin, pin, sizeof(new_pin));
pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewSecond, _("Please re-enter new PIN:")); pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewSecond,
_("Please re-enter new PIN:"));
if (pin == NULL) { if (pin == NULL) {
memzero(old_pin, sizeof(old_pin)); memzero(old_pin, sizeof(old_pin));
memzero(new_pin, sizeof(new_pin)); memzero(new_pin, sizeof(new_pin));
@ -272,8 +276,7 @@ bool protectChangePin(bool removal)
return ret; return ret;
} }
bool protectPassphrase(void) bool protectPassphrase(void) {
{
bool passphrase_protection = false; bool passphrase_protection = false;
config_getPassphraseProtection(&passphrase_protection); config_getPassphraseProtection(&passphrase_protection);
if (!passphrase_protection || session_isPassphraseCached()) { if (!passphrase_protection || session_isPassphraseCached()) {
@ -285,12 +288,15 @@ bool protectPassphrase(void)
usbTiny(1); usbTiny(1);
msg_write(MessageType_MessageType_PassphraseRequest, &resp); msg_write(MessageType_MessageType_PassphraseRequest, &resp);
layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter your"), _("passphrase using"), _("the computer's"), _("keyboard."), NULL, NULL); layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter your"),
_("passphrase using"), _("the computer's"), _("keyboard."),
NULL, NULL);
bool result; bool result;
for (;;) { for (;;) {
usbPoll(); usbPoll();
// TODO: correctly process PassphraseAck with state field set (mismatch => Failure) // TODO: correctly process PassphraseAck with state field set (mismatch =>
// Failure)
if (msg_tiny_id == MessageType_MessageType_PassphraseAck) { if (msg_tiny_id == MessageType_MessageType_PassphraseAck) {
msg_tiny_id = 0xFFFF; msg_tiny_id = 0xFFFF;
PassphraseAck *ppa = (PassphraseAck *)msg_tiny; PassphraseAck *ppa = (PassphraseAck *)msg_tiny;
@ -300,7 +306,8 @@ bool protectPassphrase(void)
} }
// check for Cancel / Initialize // check for Cancel / Initialize
protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel);
protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); protectAbortedByInitialize =
(msg_tiny_id == MessageType_MessageType_Initialize);
if (protectAbortedByCancel || protectAbortedByInitialize) { if (protectAbortedByCancel || protectAbortedByInitialize) {
msg_tiny_id = 0xFFFF; msg_tiny_id = 0xFFFF;
result = false; result = false;

View File

@ -25,7 +25,8 @@
#include "secbool.h" #include "secbool.h"
bool protectButton(ButtonRequestType type, bool confirm_only); bool protectButton(ButtonRequestType type, bool confirm_only);
secbool protectPinUiCallback(uint32_t wait, uint32_t progress, const char* message); secbool protectPinUiCallback(uint32_t wait, uint32_t progress,
const char* message);
bool protectPin(bool use_cached); bool protectPin(bool use_cached);
bool protectChangePin(bool removal); bool protectChangePin(bool removal);
bool protectPassphrase(void); bool protectPassphrase(void);

View File

@ -1,3 +1,4 @@
// clang-format off
/* /*
* This file is part of the TREZOR project, https://trezor.io/ * This file is part of the TREZOR project, https://trezor.io/
* *

View File

@ -18,21 +18,21 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <ctype.h>
#include "recovery.h" #include "recovery.h"
#include "fsm.h" #include <ctype.h>
#include "config.h"
#include "layout2.h"
#include "protect.h"
#include "messages.h"
#include "rng.h"
#include "bip39.h" #include "bip39.h"
#include "oled.h" #include "config.h"
#include "usb.h" #include "fsm.h"
#include "gettext.h" #include "gettext.h"
#include "recovery-table.h" #include "layout2.h"
#include "memzero.h" #include "memzero.h"
#include "messages.h"
#include "messages.pb.h" #include "messages.pb.h"
#include "oled.h"
#include "protect.h"
#include "recovery-table.h"
#include "rng.h"
#include "usb.h"
/* number of words expected in the new seed */ /* number of words expected in the new seed */
static uint32_t word_count; static uint32_t word_count;
@ -129,11 +129,14 @@ static void format_number(char *dest, int number) {
} }
dest[1] = '0' + number % 10; dest[1] = '0' + number % 10;
if (number == 1 || number == 21) { if (number == 1 || number == 21) {
dest[2] = 's'; dest[3] = 't'; dest[2] = 's';
dest[3] = 't';
} else if (number == 2 || number == 22) { } else if (number == 2 || number == 22) {
dest[2] = 'n'; dest[3] = 'd'; dest[2] = 'n';
dest[3] = 'd';
} else if (number == 3 || number == 23) { } else if (number == 3 || number == 23) {
dest[2] = 'r'; dest[3] = 'd'; dest[2] = 'r';
dest[3] = 'd';
} }
} }
@ -143,8 +146,10 @@ static void recovery_request(void) {
WordRequest resp; WordRequest resp;
memzero(&resp, sizeof(WordRequest)); memzero(&resp, sizeof(WordRequest));
resp.has_type = true; resp.has_type = true;
resp.type = awaiting_word == 1 ? WordRequestType_WordRequestType_Plain resp.type = awaiting_word == 1
: (word_index % 4 == 3) ? WordRequestType_WordRequestType_Matrix6 ? WordRequestType_WordRequestType_Plain
: (word_index % 4 == 3)
? WordRequestType_WordRequestType_Matrix6
: WordRequestType_WordRequestType_Matrix9; : WordRequestType_WordRequestType_Matrix9;
msg_write(MessageType_MessageType_WordRequest, &resp); msg_write(MessageType_MessageType_WordRequest, &resp);
} }
@ -171,27 +176,30 @@ static void recovery_done(void) {
} }
fsm_sendSuccess(_("Device recovered")); fsm_sendSuccess(_("Device recovered"));
} else { } else {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to store mnemonic"));
} }
memzero(new_mnemonic, sizeof(new_mnemonic)); memzero(new_mnemonic, sizeof(new_mnemonic));
} else { } else {
// Inform the user about new mnemonic correctness (as well as whether it is the same as the current one). // Inform the user about new mnemonic correctness (as well as whether it
bool match = (config_isInitialized() && config_containsMnemonic(new_mnemonic)); // is the same as the current one).
bool match =
(config_isInitialized() && config_containsMnemonic(new_mnemonic));
memzero(new_mnemonic, sizeof(new_mnemonic)); memzero(new_mnemonic, sizeof(new_mnemonic));
if (match) { if (match) {
layoutDialog(&bmp_icon_ok, NULL, _("Confirm"), NULL, layoutDialog(&bmp_icon_ok, NULL, _("Confirm"), NULL,
_("The seed is valid"), _("The seed is valid"), _("and MATCHES"),
_("and MATCHES"),
_("the one in the device."), NULL, NULL, NULL); _("the one in the device."), NULL, NULL, NULL);
protectButton(ButtonRequestType_ButtonRequest_Other, true); protectButton(ButtonRequestType_ButtonRequest_Other, true);
fsm_sendSuccess(_("The seed is valid and matches the one in the device")); fsm_sendSuccess(
_("The seed is valid and matches the one in the device"));
} else { } else {
layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL, layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL,
_("The seed is valid"), _("The seed is valid"), _("but does NOT MATCH"),
_("but does NOT MATCH"),
_("the one in the device."), NULL, NULL, NULL); _("the one in the device."), NULL, NULL, NULL);
protectButton(ButtonRequestType_ButtonRequest_Other, true); protectButton(ButtonRequestType_ButtonRequest_Other, true);
fsm_sendFailure(FailureType_Failure_DataError, fsm_sendFailure(
FailureType_Failure_DataError,
_("The seed is valid but does not match the one in the device")); _("The seed is valid but does not match the one in the device"));
} }
} }
@ -201,11 +209,12 @@ static void recovery_done(void) {
if (!dry_run) { if (!dry_run) {
session_clear(true); session_clear(true);
} else { } else {
layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL, layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL, _("The seed is"),
_("The seed is"), _("INVALID!"), NULL, NULL, NULL, NULL); _("INVALID!"), NULL, NULL, NULL, NULL);
protectButton(ButtonRequestType_ButtonRequest_Other, true); protectButton(ButtonRequestType_ButtonRequest_Other, true);
} }
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid seed, are words in correct order?")); fsm_sendFailure(FailureType_Failure_DataError,
_("Invalid seed, are words in correct order?"));
} }
awaiting_word = 0; awaiting_word = 0;
layoutHome(); layoutHome();
@ -222,7 +231,8 @@ static void recovery_done(void) {
* memcmp(last, "last + 1", prefixlen) != 0 * memcmp(last, "last + 1", prefixlen) != 0
* first[prefixlen-2] == last[prefixlen-2] except for range WI-Z. * first[prefixlen-2] == last[prefixlen-2] except for range WI-Z.
*/ */
static void add_choice(char choice[12], int prefixlen, const char *first, const char *last) { static void add_choice(char choice[12], int prefixlen, const char *first,
const char *last) {
// assert 1 <= prefixlen <= 4 // assert 1 <= prefixlen <= 4
char *dest = choice; char *dest = choice;
for (int i = 0; i < prefixlen; i++) { for (int i = 0; i < prefixlen; i++) {
@ -259,8 +269,7 @@ static void add_choice(char choice[12], int prefixlen, const char *first, const
* use 2x3 layout, otherwise 3x3 layout. Also generates a random * use 2x3 layout, otherwise 3x3 layout. Also generates a random
* scrambling and stores it in word_matrix. * scrambling and stores it in word_matrix.
*/ */
static void display_choices(bool twoColumn, char choices[9][12], int num) static void display_choices(bool twoColumn, char choices[9][12], int num) {
{
const int nColumns = twoColumn ? 2 : 3; const int nColumns = twoColumn ? 2 : 3;
const int displayedChoices = nColumns * 3; const int displayedChoices = nColumns * 3;
for (int i = 0; i < displayedChoices; i++) { for (int i = 0; i < displayedChoices; i++) {
@ -273,7 +282,9 @@ static void display_choices(bool twoColumn, char choices[9][12], int num)
char desc[] = "##th word"; char desc[] = "##th word";
int nr = (word_index / 4) + 1; int nr = (word_index / 4) + 1;
format_number(desc, nr); format_number(desc, nr);
layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter the"), (nr < 10 ? desc + 1 : desc), _("of your mnemonic"), NULL, NULL, NULL); layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter the"),
(nr < 10 ? desc + 1 : desc), _("of your mnemonic"), NULL,
NULL, NULL);
} else { } else {
oledBox(0, 27, 127, 63, false); oledBox(0, 27, 127, 63, false);
} }
@ -284,7 +295,8 @@ static void display_choices(bool twoColumn, char choices[9][12], int num)
int x = twoColumn ? 64 * col + 32 : 42 * col + 22; int x = twoColumn ? 64 * col + 32 : 42 * col + 22;
int choice = word_matrix[nColumns * row + col]; int choice = word_matrix[nColumns * row + col];
const char *text = choice < num ? choices[choice] : "-"; const char *text = choice < num ? choices[choice] : "-";
oledDrawString(x - oledStringWidth(text, FONT_STANDARD)/2, y, text, FONT_STANDARD); oledDrawString(x - oledStringWidth(text, FONT_STANDARD) / 2, y, text,
FONT_STANDARD);
if (twoColumn) { if (twoColumn) {
oledInvert(x - 32 + 1, y - 1, x - 32 + 63 - 1, y + 8); oledInvert(x - 32 + 1, y - 1, x - 32 + 63 - 1, y + 8);
} else { } else {
@ -296,8 +308,7 @@ static void display_choices(bool twoColumn, char choices[9][12], int num)
/* avoid picking out of range numbers */ /* avoid picking out of range numbers */
for (int i = 0; i < displayedChoices; i++) { for (int i = 0; i < displayedChoices; i++) {
if (word_matrix[i] >= num) if (word_matrix[i] >= num) word_matrix[i] = 0;
word_matrix[i] = 0;
} }
/* two column layout: middle column = right column */ /* two column layout: middle column = right column */
if (twoColumn) { if (twoColumn) {
@ -343,8 +354,7 @@ static void next_matrix(void) {
num = TABLE1(word_pincode + 1) - idx; num = TABLE1(word_pincode + 1) - idx;
for (uint32_t i = 0; i < num; i++) { for (uint32_t i = 0; i < num; i++) {
add_choice(word_choices[i], (word_table2[idx + i] >> 12), add_choice(word_choices[i], (word_table2[idx + i] >> 12),
wl[TABLE2(idx + i)], wl[TABLE2(idx + i)], wl[TABLE2(idx + i + 1) - 1]);
wl[TABLE2(idx + i + 1) - 1]);
} }
break; break;
@ -366,8 +376,7 @@ static void next_matrix(void) {
/* num: the number of choices. */ /* num: the number of choices. */
num = 9; num = 9;
for (uint32_t i = 0; i < num; i++) { for (uint32_t i = 0; i < num; i++) {
add_choice(word_choices[i], 1, add_choice(word_choices[i], 1, wl[TABLE2(TABLE1(9 * i))],
wl[TABLE2(TABLE1(9*i))],
wl[TABLE2(TABLE1(9 * (i + 1))) - 1]); wl[TABLE2(TABLE1(9 * (i + 1))) - 1]);
} }
break; break;
@ -386,8 +395,7 @@ static void recovery_digit(const char digit) {
/* backspace: undo */ /* backspace: undo */
if ((word_index % 4) == 0) { if ((word_index % 4) == 0) {
/* undo complete word */ /* undo complete word */
if (word_index > 0) if (word_index > 0) word_index -= 4;
word_index -= 4;
} else { } else {
word_index--; word_index--;
word_pincode /= 9; word_pincode /= 9;
@ -440,18 +448,24 @@ void next_word(void) {
if (word_pos == 0) { if (word_pos == 0) {
const char *const *wl = mnemonic_wordlist(); const char *const *wl = mnemonic_wordlist();
strlcpy(fake_word, wl[random_uniform(2048)], sizeof(fake_word)); strlcpy(fake_word, wl[random_uniform(2048)], sizeof(fake_word));
layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter the word"), NULL, fake_word, NULL, _("on your computer"), NULL); layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL,
_("Please enter the word"), NULL, fake_word, NULL,
_("on your computer"), NULL);
} else { } else {
fake_word[0] = 0; fake_word[0] = 0;
char desc[] = "##th word"; char desc[] = "##th word";
format_number(desc, word_pos); format_number(desc, word_pos);
layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter the"), NULL, (word_pos < 10 ? desc + 1 : desc), NULL, _("of your mnemonic"), NULL); layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter the"),
NULL, (word_pos < 10 ? desc + 1 : desc), NULL,
_("of your mnemonic"), NULL);
} }
recovery_request(); recovery_request();
} }
void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t type, uint32_t u2f_counter, bool _dry_run) void recovery_init(uint32_t _word_count, bool passphrase_protection,
{ bool pin_protection, const char *language, const char *label,
bool _enforce_wordlist, uint32_t type, uint32_t u2f_counter,
bool _dry_run) {
if (_word_count != 12 && _word_count != 18 && _word_count != 24) return; if (_word_count != 12 && _word_count != 18 && _word_count != 24) return;
word_count = _word_count; word_count = _word_count;
@ -459,7 +473,9 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr
dry_run = _dry_run; dry_run = _dry_run;
if (!dry_run) { if (!dry_run) {
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("recover the device?"), NULL, NULL, NULL, NULL); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Do you really want to"), _("recover the device?"),
NULL, NULL, NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
@ -498,14 +514,14 @@ void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_pr
} }
} }
static void recovery_scrambledword(const char *word) static void recovery_scrambledword(const char *word) {
{
if (word_pos == 0) { // fake word if (word_pos == 0) { // fake word
if (strcmp(word, fake_word) != 0) { if (strcmp(word, fake_word) != 0) {
if (!dry_run) { if (!dry_run) {
session_clear(true); session_clear(true);
} }
fsm_sendFailure(FailureType_Failure_ProcessError, _("Wrong word retyped")); fsm_sendFailure(FailureType_Failure_ProcessError,
_("Wrong word retyped"));
layoutHome(); layoutHome();
return; return;
} }
@ -524,7 +540,8 @@ static void recovery_scrambledword(const char *word)
if (!dry_run) { if (!dry_run) {
session_clear(true); session_clear(true);
} }
fsm_sendFailure(FailureType_Failure_DataError, _("Word not found in a wordlist")); fsm_sendFailure(FailureType_Failure_DataError,
_("Word not found in a wordlist"));
layoutHome(); layoutHome();
return; return;
} }
@ -543,8 +560,7 @@ static void recovery_scrambledword(const char *word)
/* Function called when a word was entered by user. Used /* Function called when a word was entered by user. Used
* for scrambled recovery. * for scrambled recovery.
*/ */
void recovery_word(const char *word) void recovery_word(const char *word) {
{
switch (awaiting_word) { switch (awaiting_word) {
case 2: case 2:
recovery_digit(word[0]); recovery_digit(word[0]);
@ -553,15 +569,15 @@ void recovery_word(const char *word)
recovery_scrambledword(word); recovery_scrambledword(word);
break; break;
default: default:
fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Recovery mode")); fsm_sendFailure(FailureType_Failure_UnexpectedMessage,
_("Not in Recovery mode"));
break; break;
} }
} }
/* Abort recovery. /* Abort recovery.
*/ */
void recovery_abort(void) void recovery_abort(void) {
{
if (awaiting_word) { if (awaiting_word) {
layoutHome(); layoutHome();
awaiting_word = 0; awaiting_word = 0;
@ -570,14 +586,8 @@ void recovery_abort(void)
#if DEBUG_LINK #if DEBUG_LINK
const char *recovery_get_fake_word(void) const char *recovery_get_fake_word(void) { return fake_word; }
{
return fake_word;
}
uint32_t recovery_get_word_pos(void) uint32_t recovery_get_word_pos(void) { return word_pos; }
{
return word_pos;
}
#endif #endif

View File

@ -20,10 +20,13 @@
#ifndef __RECOVERY_H__ #ifndef __RECOVERY_H__
#define __RECOVERY_H__ #define __RECOVERY_H__
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
void recovery_init(uint32_t _word_count, bool passphrase_protection, bool pin_protection, const char *language, const char *label, bool _enforce_wordlist, uint32_t type, uint32_t u2f_counter, bool _dry_run); void recovery_init(uint32_t _word_count, bool passphrase_protection,
bool pin_protection, const char *language, const char *label,
bool _enforce_wordlist, uint32_t type, uint32_t u2f_counter,
bool _dry_run);
void recovery_word(const char *word); void recovery_word(const char *word);
void recovery_abort(void); void recovery_abort(void);
const char *recovery_get_fake_word(void); const char *recovery_get_fake_word(void);

View File

@ -18,18 +18,18 @@
*/ */
#include "reset.h" #include "reset.h"
#include "bip39.h"
#include "config.h" #include "config.h"
#include "fsm.h"
#include "gettext.h"
#include "layout2.h"
#include "memzero.h"
#include "messages.h"
#include "messages.pb.h"
#include "protect.h"
#include "rng.h" #include "rng.h"
#include "sha2.h" #include "sha2.h"
#include "messages.h"
#include "fsm.h"
#include "layout2.h"
#include "protect.h"
#include "bip39.h"
#include "util.h" #include "util.h"
#include "gettext.h"
#include "messages.pb.h"
#include "memzero.h"
static uint32_t strength; static uint32_t strength;
static uint8_t int_entropy[32]; static uint8_t int_entropy[32];
@ -37,8 +37,10 @@ static bool awaiting_entropy = false;
static bool skip_backup = false; static bool skip_backup = false;
static bool no_backup = false; static bool no_backup = false;
void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, uint32_t u2f_counter, bool _skip_backup, bool _no_backup) void reset_init(bool display_random, uint32_t _strength,
{ bool passphrase_protection, bool pin_protection,
const char *language, const char *label, uint32_t u2f_counter,
bool _skip_backup, bool _no_backup) {
if (_strength != 128 && _strength != 192 && _strength != 256) return; if (_strength != 128 && _strength != 192 && _strength != 256) return;
strength = _strength; strength = _strength;
@ -46,12 +48,15 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect
no_backup = _no_backup; no_backup = _no_backup;
if (display_random && (skip_backup || no_backup)) { if (display_random && (skip_backup || no_backup)) {
fsm_sendFailure(FailureType_Failure_ProcessError, "Can't show internal entropy when backup is skipped"); fsm_sendFailure(FailureType_Failure_ProcessError,
"Can't show internal entropy when backup is skipped");
layoutHome(); layoutHome();
return; return;
} }
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("create a new wallet?"), NULL, _("By continuing you"), _("agree to trezor.io/tos"), NULL); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Do you really want to"), _("create a new wallet?"), NULL,
_("By continuing you"), _("agree to trezor.io/tos"), NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
@ -67,7 +72,9 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect
data2hex(int_entropy + 24, 8, ent_str[3]); data2hex(int_entropy + 24, 8, ent_str[3]);
if (display_random) { if (display_random) {
layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Continue"), NULL, _("Internal entropy:"), ent_str[0], ent_str[1], ent_str[2], ent_str[3], NULL); layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Continue"), NULL,
_("Internal entropy:"), ent_str[0], ent_str[1],
ent_str[2], ent_str[3], NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ResetDevice, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ResetDevice, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
@ -91,10 +98,10 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect
awaiting_entropy = true; awaiting_entropy = true;
} }
void reset_entropy(const uint8_t *ext_entropy, uint32_t len) void reset_entropy(const uint8_t *ext_entropy, uint32_t len) {
{
if (!awaiting_entropy) { if (!awaiting_entropy) {
fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Reset mode")); fsm_sendFailure(FailureType_Failure_UnexpectedMessage,
_("Not in Reset mode"));
return; return;
} }
awaiting_entropy = false; awaiting_entropy = false;
@ -116,7 +123,8 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len)
if (config_setMnemonic(mnemonic)) { if (config_setMnemonic(mnemonic)) {
fsm_sendSuccess(_("Device successfully initialized")); fsm_sendSuccess(_("Device successfully initialized"));
} else { } else {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to store mnemonic"));
} }
layoutHome(); layoutHome();
} else { } else {
@ -128,13 +136,13 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len)
static char current_word[10]; static char current_word[10];
// separated == true if called as a separate workflow via BackupMessage // separated == true if called as a separate workflow via BackupMessage
void reset_backup(bool separated, const char* mnemonic) void reset_backup(bool separated, const char *mnemonic) {
{
if (separated) { if (separated) {
bool needs_backup = false; bool needs_backup = false;
config_getNeedsBackup(&needs_backup); config_getNeedsBackup(&needs_backup);
if (!needs_backup) { if (!needs_backup) {
fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); fsm_sendFailure(FailureType_Failure_UnexpectedMessage,
_("Seed already backed up"));
return; return;
} }
@ -147,9 +155,11 @@ void reset_backup(bool separated, const char* mnemonic)
while (mnemonic[i] != 0) { while (mnemonic[i] != 0) {
// copy current_word // copy current_word
int j = 0; int j = 0;
while (mnemonic[i] != ' ' && mnemonic[i] != 0 && j + 1 < (int)sizeof(current_word)) { while (mnemonic[i] != ' ' && mnemonic[i] != 0 &&
j + 1 < (int)sizeof(current_word)) {
current_word[j] = mnemonic[i]; current_word[j] = mnemonic[i];
i++; j++; i++;
j++;
} }
current_word[j] = 0; current_word[j] = 0;
if (mnemonic[i] != 0) { if (mnemonic[i] != 0) {
@ -177,7 +187,8 @@ void reset_backup(bool separated, const char* mnemonic)
if (config_setMnemonic(mnemonic)) { if (config_setMnemonic(mnemonic)) {
fsm_sendSuccess(_("Device successfully initialized")); fsm_sendSuccess(_("Device successfully initialized"));
} else { } else {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to store mnemonic"));
} }
} }
layoutHome(); layoutHome();
@ -190,8 +201,6 @@ uint32_t reset_get_int_entropy(uint8_t *entropy) {
return 32; return 32;
} }
const char *reset_get_word(void) { const char *reset_get_word(void) { return current_word; }
return current_word;
}
#endif #endif

View File

@ -20,10 +20,13 @@
#ifndef __RESET_H__ #ifndef __RESET_H__
#define __RESET_H__ #define __RESET_H__
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, uint32_t u2f_counter, bool _skip_backup, bool _no_backup); void reset_init(bool display_random, uint32_t _strength,
bool passphrase_protection, bool pin_protection,
const char *language, const char *label, uint32_t u2f_counter,
bool _skip_backup, bool _no_backup);
void reset_entropy(const uint8_t *ext_entropy, uint32_t len); void reset_entropy(const uint8_t *ext_entropy, uint32_t len);
void reset_backup(bool separated, const char *mnemonic); void reset_backup(bool separated, const char *mnemonic);
uint32_t reset_get_int_entropy(uint8_t *entropy); uint32_t reset_get_int_entropy(uint8_t *entropy);

File diff suppressed because it is too large Load Diff

View File

@ -20,14 +20,15 @@
#ifndef __SIGNING_H__ #ifndef __SIGNING_H__
#define __SIGNING_H__ #define __SIGNING_H__
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include "bip32.h" #include "bip32.h"
#include "coins.h" #include "coins.h"
#include "hasher.h" #include "hasher.h"
#include "messages-bitcoin.pb.h" #include "messages-bitcoin.pb.h"
void signing_init(const SignTx *msg, const CoinInfo *_coin, const HDNode *_root); void signing_init(const SignTx *msg, const CoinInfo *_coin,
const HDNode *_root);
void signing_abort(void); void signing_abort(void);
void signing_txack(TransactionType *tx); void signing_txack(TransactionType *tx);

File diff suppressed because it is too large Load Diff

View File

@ -21,11 +21,11 @@
#define __STELLAR_H__ #define __STELLAR_H__
#include <stdbool.h> #include <stdbool.h>
#include "base32.h"
#include "bip32.h" #include "bip32.h"
#include "crypto.h" #include "crypto.h"
#include "messages.pb.h"
#include "fsm.h" #include "fsm.h"
#include "base32.h" #include "messages.pb.h"
// 56 character base-32 encoded string // 56 character base-32 encoded string
#define STELLAR_ADDRESS_SIZE 56 #define STELLAR_ADDRESS_SIZE 56
@ -55,12 +55,14 @@ typedef struct {
// Signing process // Signing process
bool stellar_signingInit(const StellarSignTx *tx); bool stellar_signingInit(const StellarSignTx *tx);
void stellar_signingAbort(const char *reason); void stellar_signingAbort(const char *reason);
bool stellar_confirmSourceAccount(bool has_source_account, const char *str_account); bool stellar_confirmSourceAccount(bool has_source_account,
const char *str_account);
bool stellar_confirmCreateAccountOp(const StellarCreateAccountOp *msg); bool stellar_confirmCreateAccountOp(const StellarCreateAccountOp *msg);
bool stellar_confirmPaymentOp(const StellarPaymentOp *msg); bool stellar_confirmPaymentOp(const StellarPaymentOp *msg);
bool stellar_confirmPathPaymentOp(const StellarPathPaymentOp *msg); bool stellar_confirmPathPaymentOp(const StellarPathPaymentOp *msg);
bool stellar_confirmManageOfferOp(const StellarManageOfferOp *msg); bool stellar_confirmManageOfferOp(const StellarManageOfferOp *msg);
bool stellar_confirmCreatePassiveOfferOp(const StellarCreatePassiveOfferOp *msg); bool stellar_confirmCreatePassiveOfferOp(
const StellarCreatePassiveOfferOp *msg);
bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg); bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg);
bool stellar_confirmChangeTrustOp(const StellarChangeTrustOp *msg); bool stellar_confirmChangeTrustOp(const StellarChangeTrustOp *msg);
bool stellar_confirmAllowTrustOp(const StellarAllowTrustOp *msg); bool stellar_confirmAllowTrustOp(const StellarAllowTrustOp *msg);
@ -69,14 +71,22 @@ bool stellar_confirmManageDataOp(const StellarManageDataOp *msg);
bool stellar_confirmBumpSequenceOp(const StellarBumpSequenceOp *msg); bool stellar_confirmBumpSequenceOp(const StellarBumpSequenceOp *msg);
// Layout // Layout
void stellar_layoutTransactionDialog(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5); void stellar_layoutTransactionDialog(const char *line1, const char *line2,
const char *line3, const char *line4,
const char *line5);
void stellar_layoutTransactionSummary(const StellarSignTx *msg); void stellar_layoutTransactionSummary(const StellarSignTx *msg);
void stellar_layoutSigningDialog(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, uint32_t *address_n, size_t address_n_count, const char *warning, bool is_final_step); void stellar_layoutSigningDialog(const char *line1, const char *line2,
const char *line3, const char *line4,
const char *line5, uint32_t *address_n,
size_t address_n_count, const char *warning,
bool is_final_step);
// Helpers // Helpers
const HDNode *stellar_deriveNode(const uint32_t *address_n, size_t address_n_count); const HDNode *stellar_deriveNode(const uint32_t *address_n,
size_t address_n_count);
size_t stellar_publicAddressAsStr(const uint8_t *bytes, char *out, size_t outlen); size_t stellar_publicAddressAsStr(const uint8_t *bytes, char *out,
size_t outlen);
const char **stellar_lineBreakAddress(const uint8_t *addrbytes); const char **stellar_lineBreakAddress(const uint8_t *addrbytes);
void stellar_hashupdate_uint32(uint32_t value); void stellar_hashupdate_uint32(uint32_t value);
@ -94,8 +104,10 @@ void stellar_getSignatureForActiveTx(uint8_t *out_signature);
void stellar_format_uint32(uint32_t number, char *out, size_t outlen); void stellar_format_uint32(uint32_t number, char *out, size_t outlen);
void stellar_format_uint64(uint64_t number, char *out, size_t outlen); void stellar_format_uint64(uint64_t number, char *out, size_t outlen);
void stellar_format_stroops(uint64_t number, char *out, size_t outlen); void stellar_format_stroops(uint64_t number, char *out, size_t outlen);
void stellar_format_asset(const StellarAssetType *asset, char *str_formatted, size_t len); void stellar_format_asset(const StellarAssetType *asset, char *str_formatted,
void stellar_format_price(uint32_t numerator, uint32_t denominator, char *out, size_t outlen); size_t len);
void stellar_format_price(uint32_t numerator, uint32_t denominator, char *out,
size_t outlen);
bool stellar_validateAddress(const char *str_address); bool stellar_validateAddress(const char *str_address);
bool stellar_getAddressBytes(const char *str_address, uint8_t *out_bytes); bool stellar_getAddressBytes(const char *str_address, uint8_t *out_bytes);

View File

@ -17,22 +17,22 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h>
#include "transaction.h" #include "transaction.h"
#include "ecdsa.h" #include <string.h>
#include "coins.h"
#include "util.h"
#include "debug.h"
#include "protect.h"
#include "layout2.h"
#include "crypto.h"
#include "ripemd160.h"
#include "base58.h"
#include "address.h" #include "address.h"
#include "messages.pb.h" #include "base58.h"
#include "segwit_addr.h"
#include "cash_addr.h" #include "cash_addr.h"
#include "coins.h"
#include "crypto.h"
#include "debug.h"
#include "ecdsa.h"
#include "layout2.h"
#include "memzero.h" #include "memzero.h"
#include "messages.pb.h"
#include "protect.h"
#include "ripemd160.h"
#include "segwit_addr.h"
#include "util.h"
#define SEGWIT_VERSION_0 0 #define SEGWIT_VERSION_0 0
@ -58,7 +58,8 @@
#define TXSIZE_P2PKHASH 25 #define TXSIZE_P2PKHASH 25
/* size of a p2sh script (hash, push, 20 scripthash, equal) */ /* size of a p2sh script (hash, push, 20 scripthash, equal) */
#define TXSIZE_P2SCRIPT 23 #define TXSIZE_P2SCRIPT 23
/* size of a Decred witness (without script): 8 amount, 4 block height, 4 block index */ /* size of a Decred witness (without script): 8 amount, 4 block height, 4 block
* index */
#define TXSIZE_DECRED_WITNESS 16 #define TXSIZE_DECRED_WITNESS 16
static const uint8_t segwit_header[2] = {0, 1}; static const uint8_t segwit_header[2] = {0, 1};
@ -100,12 +101,10 @@ uint32_t op_push(uint32_t i, uint8_t *out) {
return 5; return 5;
} }
bool compute_address(const CoinInfo *coin, bool compute_address(const CoinInfo *coin, InputScriptType script_type,
InputScriptType script_type, const HDNode *node, bool has_multisig,
const HDNode *node, const MultisigRedeemScriptType *multisig,
bool has_multisig, const MultisigRedeemScriptType *multisig,
char address[MAX_ADDR_SIZE]) { char address[MAX_ADDR_SIZE]) {
uint8_t raw[MAX_ADDR_RAW_SIZE]; uint8_t raw[MAX_ADDR_RAW_SIZE];
uint8_t digest[32]; uint8_t digest[32];
size_t prelen; size_t prelen;
@ -122,7 +121,8 @@ bool compute_address(const CoinInfo *coin,
if (!coin->has_segwit || !coin->bech32_prefix) { if (!coin->has_segwit || !coin->bech32_prefix) {
return 0; return 0;
} }
if (!segwit_addr_encode(address, coin->bech32_prefix, SEGWIT_VERSION_0, digest, 32)) { if (!segwit_addr_encode(address, coin->bech32_prefix, SEGWIT_VERSION_0,
digest, 32)) {
return 0; return 0;
} }
} else if (script_type == InputScriptType_SPENDP2SHWITNESS) { } else if (script_type == InputScriptType_SPENDP2SHWITNESS) {
@ -140,7 +140,8 @@ bool compute_address(const CoinInfo *coin,
prelen = address_prefix_bytes_len(coin->address_type_p2sh); prelen = address_prefix_bytes_len(coin->address_type_p2sh);
address_write_prefix_bytes(coin->address_type_p2sh, raw); address_write_prefix_bytes(coin->address_type_p2sh, raw);
memcpy(raw + prelen, digest, 32); memcpy(raw + prelen, digest, 32);
if (!base58_encode_check(raw, prelen + 20, coin->curve->hasher_base58, address, MAX_ADDR_SIZE)) { if (!base58_encode_check(raw, prelen + 20, coin->curve->hasher_base58,
address, MAX_ADDR_SIZE)) {
return 0; return 0;
} }
} else if (coin->cashaddr_prefix) { } else if (coin->cashaddr_prefix) {
@ -154,7 +155,8 @@ bool compute_address(const CoinInfo *coin,
prelen = address_prefix_bytes_len(coin->address_type_p2sh); prelen = address_prefix_bytes_len(coin->address_type_p2sh);
address_write_prefix_bytes(coin->address_type_p2sh, raw); address_write_prefix_bytes(coin->address_type_p2sh, raw);
ripemd160(digest, 32, raw + prelen); ripemd160(digest, 32, raw + prelen);
if (!base58_encode_check(raw, prelen + 20, coin->curve->hasher_base58, address, MAX_ADDR_SIZE)) { if (!base58_encode_check(raw, prelen + 20, coin->curve->hasher_base58,
address, MAX_ADDR_SIZE)) {
return 0; return 0;
} }
} }
@ -164,7 +166,8 @@ bool compute_address(const CoinInfo *coin,
return 0; return 0;
} }
ecdsa_get_pubkeyhash(node->public_key, coin->curve->hasher_pubkey, digest); ecdsa_get_pubkeyhash(node->public_key, coin->curve->hasher_pubkey, digest);
if (!segwit_addr_encode(address, coin->bech32_prefix, SEGWIT_VERSION_0, digest, 20)) { if (!segwit_addr_encode(address, coin->bech32_prefix, SEGWIT_VERSION_0,
digest, 20)) {
return 0; return 0;
} }
} else if (script_type == InputScriptType_SPENDP2SHWITNESS) { } else if (script_type == InputScriptType_SPENDP2SHWITNESS) {
@ -175,20 +178,25 @@ bool compute_address(const CoinInfo *coin,
if (!coin->has_address_type_p2sh) { if (!coin->has_address_type_p2sh) {
return 0; return 0;
} }
ecdsa_get_address_segwit_p2sh(node->public_key, coin->address_type_p2sh, coin->curve->hasher_pubkey, coin->curve->hasher_base58, address, MAX_ADDR_SIZE); ecdsa_get_address_segwit_p2sh(
node->public_key, coin->address_type_p2sh, coin->curve->hasher_pubkey,
coin->curve->hasher_base58, address, MAX_ADDR_SIZE);
} else if (coin->cashaddr_prefix) { } else if (coin->cashaddr_prefix) {
ecdsa_get_address_raw(node->public_key, CASHADDR_P2KH | CASHADDR_160, coin->curve->hasher_pubkey, raw); ecdsa_get_address_raw(node->public_key, CASHADDR_P2KH | CASHADDR_160,
coin->curve->hasher_pubkey, raw);
if (!cash_addr_encode(address, coin->cashaddr_prefix, raw, 21)) { if (!cash_addr_encode(address, coin->cashaddr_prefix, raw, 21)) {
return 0; return 0;
} }
} else { } else {
ecdsa_get_address(node->public_key, coin->address_type, coin->curve->hasher_pubkey, coin->curve->hasher_base58, address, MAX_ADDR_SIZE); ecdsa_get_address(node->public_key, coin->address_type,
coin->curve->hasher_pubkey, coin->curve->hasher_base58,
address, MAX_ADDR_SIZE);
} }
return 1; return 1;
} }
int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm) int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in,
{ TxOutputBinType *out, bool needs_confirm) {
memzero(out, sizeof(TxOutputBinType)); memzero(out, sizeof(TxOutputBinType));
out->amount = in->amount; out->amount = in->amount;
out->decred_script_version = in->decred_script_version; out->decred_script_version = in->decred_script_version;
@ -201,19 +209,26 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T
return 0; // failed to compile output return 0; // failed to compile output
} }
if (needs_confirm) { if (needs_confirm) {
if (in->op_return_data.size >= 8 && memcmp(in->op_return_data.bytes, "omni", 4) == 0) { // OMNI transaction if (in->op_return_data.size >= 8 &&
memcmp(in->op_return_data.bytes, "omni", 4) ==
0) { // OMNI transaction
layoutConfirmOmni(in->op_return_data.bytes, in->op_return_data.size); layoutConfirmOmni(in->op_return_data.bytes, in->op_return_data.size);
} else { } else {
layoutConfirmOpReturn(in->op_return_data.bytes, in->op_return_data.size); layoutConfirmOpReturn(in->op_return_data.bytes,
in->op_return_data.size);
} }
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput,
false)) {
return -1; // user aborted return -1; // user aborted
} }
} }
uint32_t r = 0; uint32_t r = 0;
out->script_pubkey.bytes[0] = 0x6A; r++; // OP_RETURN out->script_pubkey.bytes[0] = 0x6A;
r++; // OP_RETURN
r += op_push(in->op_return_data.size, out->script_pubkey.bytes + r); r += op_push(in->op_return_data.size, out->script_pubkey.bytes + r);
memcpy(out->script_pubkey.bytes + r, in->op_return_data.bytes, in->op_return_data.size); r += in->op_return_data.size; memcpy(out->script_pubkey.bytes + r, in->op_return_data.bytes,
in->op_return_data.size);
r += in->op_return_data.size;
out->script_pubkey.size = r; out->script_pubkey.size = r;
return r; return r;
} }
@ -239,24 +254,26 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T
return 0; // failed to compile output return 0; // failed to compile output
} }
memcpy(&node, root, sizeof(HDNode)); memcpy(&node, root, sizeof(HDNode));
if (hdnode_private_ckd_cached(&node, in->address_n, in->address_n_count, NULL) == 0) { if (hdnode_private_ckd_cached(&node, in->address_n, in->address_n_count,
NULL) == 0) {
return 0; // failed to compile output return 0; // failed to compile output
} }
hdnode_fill_public_key(&node); hdnode_fill_public_key(&node);
if (!compute_address(coin, input_script_type, &node, if (!compute_address(coin, input_script_type, &node, in->has_multisig,
in->has_multisig, &in->multisig, &in->multisig, in->address)) {
in->address)) {
return 0; // failed to compile output return 0; // failed to compile output
} }
} else if (!in->has_address) { } else if (!in->has_address) {
return 0; // failed to compile output return 0; // failed to compile output
} }
addr_raw_len = base58_decode_check(in->address, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); addr_raw_len = base58_decode_check(in->address, coin->curve->hasher_base58,
addr_raw, MAX_ADDR_RAW_SIZE);
size_t prefix_len; size_t prefix_len;
if (coin->has_address_type // p2pkh if (coin->has_address_type // p2pkh
&& addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type)) && addr_raw_len ==
&& address_check_prefix(addr_raw, coin->address_type)) { 20 + (prefix_len = address_prefix_bytes_len(coin->address_type)) &&
address_check_prefix(addr_raw, coin->address_type)) {
out->script_pubkey.bytes[0] = 0x76; // OP_DUP out->script_pubkey.bytes[0] = 0x76; // OP_DUP
out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160
out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes
@ -265,17 +282,18 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T
out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG
out->script_pubkey.size = 25; out->script_pubkey.size = 25;
} else if (coin->has_address_type_p2sh // p2sh } else if (coin->has_address_type_p2sh // p2sh
&& addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2sh)) && addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(
&& address_check_prefix(addr_raw, coin->address_type_p2sh)) { coin->address_type_p2sh)) &&
address_check_prefix(addr_raw, coin->address_type_p2sh)) {
out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160
out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes
memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len, 20); memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len, 20);
out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL
out->script_pubkey.size = 23; out->script_pubkey.size = 23;
} else if (coin->cashaddr_prefix } else if (coin->cashaddr_prefix &&
&& cash_addr_decode(addr_raw, &addr_raw_len, coin->cashaddr_prefix, in->address)) { cash_addr_decode(addr_raw, &addr_raw_len, coin->cashaddr_prefix,
if (addr_raw_len == 21 in->address)) {
&& addr_raw[0] == (CASHADDR_P2KH | CASHADDR_160)) { if (addr_raw_len == 21 && addr_raw[0] == (CASHADDR_P2KH | CASHADDR_160)) {
out->script_pubkey.bytes[0] = 0x76; // OP_DUP out->script_pubkey.bytes[0] = 0x76; // OP_DUP
out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160
out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes out->script_pubkey.bytes[2] = 0x14; // pushing 20 bytes
@ -284,8 +302,8 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T
out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG out->script_pubkey.bytes[24] = 0xAC; // OP_CHECKSIG
out->script_pubkey.size = 25; out->script_pubkey.size = 25;
} else if (addr_raw_len == 21 } else if (addr_raw_len == 21 &&
&& addr_raw[0] == (CASHADDR_P2SH | CASHADDR_160)) { addr_raw[0] == (CASHADDR_P2SH | CASHADDR_160)) {
out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160 out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160
out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes
memcpy(out->script_pubkey.bytes + 2, addr_raw + 1, 20); memcpy(out->script_pubkey.bytes + 2, addr_raw + 1, 20);
@ -296,7 +314,8 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T
} }
} else if (coin->bech32_prefix) { } else if (coin->bech32_prefix) {
int witver; int witver;
if (!segwit_addr_decode(&witver, addr_raw, &addr_raw_len, coin->bech32_prefix, in->address)) { if (!segwit_addr_decode(&witver, addr_raw, &addr_raw_len,
coin->bech32_prefix, in->address)) {
return 0; return 0;
} }
// segwit: // segwit:
@ -320,8 +339,8 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T
return out->script_pubkey.size; return out->script_pubkey.size;
} }
uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out) uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash,
{ uint8_t *out) {
if (coinByAddressType(address_type)) { // valid coin type if (coinByAddressType(address_type)) { // valid coin type
out[0] = 0x76; // OP_DUP out[0] = 0x76; // OP_DUP
out[1] = 0xA9; // OP_HASH_160 out[1] = 0xA9; // OP_HASH_160
@ -336,8 +355,9 @@ uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, ui
} }
// if out == NULL just compute the length // if out == NULL just compute the length
uint32_t compile_script_multisig(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t *out) uint32_t compile_script_multisig(const CoinInfo *coin,
{ const MultisigRedeemScriptType *multisig,
uint8_t *out) {
if (!multisig->has_m) return 0; if (!multisig->has_m) return 0;
const uint32_t m = multisig->m; const uint32_t m = multisig->m;
const uint32_t n = cryptoMultisigPubkeyCount(multisig); const uint32_t n = cryptoMultisigPubkeyCount(multisig);
@ -345,23 +365,29 @@ uint32_t compile_script_multisig(const CoinInfo *coin, const MultisigRedeemScrip
if (n < 1 || n > 15) return 0; if (n < 1 || n > 15) return 0;
uint32_t r = 0; uint32_t r = 0;
if (out) { if (out) {
out[r] = 0x50 + m; r++; out[r] = 0x50 + m;
r++;
for (uint32_t i = 0; i < n; i++) { for (uint32_t i = 0; i < n; i++) {
out[r] = 33; r++; // OP_PUSH 33 out[r] = 33;
r++; // OP_PUSH 33
const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i); const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i);
if (!pubnode) return 0; if (!pubnode) return 0;
memcpy(out + r, pubnode->public_key, 33); r += 33; memcpy(out + r, pubnode->public_key, 33);
r += 33;
} }
out[r] = 0x50 + n; r++; out[r] = 0x50 + n;
out[r] = 0xAE; r++; // OP_CHECKMULTISIG r++;
out[r] = 0xAE;
r++; // OP_CHECKMULTISIG
} else { } else {
r = 1 + 34 * n + 2; r = 1 + 34 * n + 2;
} }
return r; return r;
} }
uint32_t compile_script_multisig_hash(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t *hash) uint32_t compile_script_multisig_hash(const CoinInfo *coin,
{ const MultisigRedeemScriptType *multisig,
uint8_t *hash) {
if (!multisig->has_m) return 0; if (!multisig->has_m) return 0;
const uint32_t m = multisig->m; const uint32_t m = multisig->m;
const uint32_t n = cryptoMultisigPubkeyCount(multisig); const uint32_t n = cryptoMultisigPubkeyCount(multisig);
@ -372,9 +398,11 @@ uint32_t compile_script_multisig_hash(const CoinInfo *coin, const MultisigRedeem
hasher_Init(&hasher, coin->curve->hasher_script); hasher_Init(&hasher, coin->curve->hasher_script);
uint8_t d[2]; uint8_t d[2];
d[0] = 0x50 + m; hasher_Update(&hasher, d, 1); d[0] = 0x50 + m;
hasher_Update(&hasher, d, 1);
for (uint32_t i = 0; i < n; i++) { for (uint32_t i = 0; i < n; i++) {
d[0] = 33; hasher_Update(&hasher, d, 1); // OP_PUSH 33 d[0] = 33;
hasher_Update(&hasher, d, 1); // OP_PUSH 33
const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i); const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i);
if (!pubnode) return 0; if (!pubnode) return 0;
hasher_Update(&hasher, pubnode->public_key, 33); hasher_Update(&hasher, pubnode->public_key, 33);
@ -388,31 +416,40 @@ uint32_t compile_script_multisig_hash(const CoinInfo *coin, const MultisigRedeem
return 1; return 1;
} }
uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t sighash, uint8_t *out) uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len,
{ const uint8_t *pubkey, uint32_t pubkey_len,
uint8_t sighash, uint8_t *out) {
uint32_t r = 0; uint32_t r = 0;
r += op_push(signature_len + 1, out + r); r += op_push(signature_len + 1, out + r);
memcpy(out + r, signature, signature_len); r += signature_len; memcpy(out + r, signature, signature_len);
out[r] = sighash; r++; r += signature_len;
out[r] = sighash;
r++;
r += op_push(pubkey_len, out + r); r += op_push(pubkey_len, out + r);
memcpy(out + r, pubkey, pubkey_len); r += pubkey_len; memcpy(out + r, pubkey, pubkey_len);
r += pubkey_len;
return r; return r;
} }
uint32_t serialize_script_multisig(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t sighash, uint8_t *out) uint32_t serialize_script_multisig(const CoinInfo *coin,
{ const MultisigRedeemScriptType *multisig,
uint8_t sighash, uint8_t *out) {
uint32_t r = 0; uint32_t r = 0;
if (!coin->decred) { if (!coin->decred) {
// Decred fixed the off-by-one bug // Decred fixed the off-by-one bug
out[r] = 0x00; r++; out[r] = 0x00;
r++;
} }
for (uint32_t i = 0; i < multisig->signatures_count; i++) { for (uint32_t i = 0; i < multisig->signatures_count; i++) {
if (multisig->signatures[i].size == 0) { if (multisig->signatures[i].size == 0) {
continue; continue;
} }
r += op_push(multisig->signatures[i].size + 1, out + r); r += op_push(multisig->signatures[i].size + 1, out + r);
memcpy(out + r, multisig->signatures[i].bytes, multisig->signatures[i].size); r += multisig->signatures[i].size; memcpy(out + r, multisig->signatures[i].bytes,
out[r] = sighash; r++; multisig->signatures[i].size);
r += multisig->signatures[i].size;
out[r] = sighash;
r++;
} }
uint32_t script_len = compile_script_multisig(coin, multisig, 0); uint32_t script_len = compile_script_multisig(coin, multisig, 0);
if (script_len == 0) { if (script_len == 0) {
@ -425,8 +462,7 @@ uint32_t serialize_script_multisig(const CoinInfo *coin, const MultisigRedeemScr
// tx methods // tx methods
uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input) uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input) {
{
for (int i = 0; i < 32; i++) { for (int i = 0; i < 32; i++) {
hasher_Update(hasher, &(input->prev_hash.bytes[31 - i]), 1); hasher_Update(hasher, &(input->prev_hash.bytes[31 - i]), 1);
} }
@ -434,40 +470,39 @@ uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input)
return 36; return 36;
} }
uint32_t tx_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data) uint32_t tx_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data) {
{
int r = ser_length_hash(hasher, size); int r = ser_length_hash(hasher, size);
hasher_Update(hasher, data, size); hasher_Update(hasher, data, size);
return r + size; return r + size;
} }
uint32_t tx_sequence_hash(Hasher *hasher, const TxInputType *input) uint32_t tx_sequence_hash(Hasher *hasher, const TxInputType *input) {
{
hasher_Update(hasher, (const uint8_t *)&input->sequence, 4); hasher_Update(hasher, (const uint8_t *)&input->sequence, 4);
return 4; return 4;
} }
uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output, bool decred) uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output,
{ bool decred) {
uint32_t r = 0; uint32_t r = 0;
hasher_Update(hasher, (const uint8_t *)&output->amount, 8); r += 8; hasher_Update(hasher, (const uint8_t *)&output->amount, 8);
r += 8;
if (decred) { if (decred) {
uint16_t script_version = output->decred_script_version & 0xFFFF; uint16_t script_version = output->decred_script_version & 0xFFFF;
hasher_Update(hasher, (const uint8_t *)&script_version, 2); r += 2; hasher_Update(hasher, (const uint8_t *)&script_version, 2);
r += 2;
} }
r += tx_script_hash(hasher, output->script_pubkey.size, output->script_pubkey.bytes); r += tx_script_hash(hasher, output->script_pubkey.size,
output->script_pubkey.bytes);
return r; return r;
} }
uint32_t tx_serialize_script(uint32_t size, const uint8_t *data, uint8_t *out) uint32_t tx_serialize_script(uint32_t size, const uint8_t *data, uint8_t *out) {
{
int r = ser_length(size, out); int r = ser_length(size, out);
memcpy(out + r, data, size); memcpy(out + r, data, size);
return r + size; return r + size;
} }
uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out) uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out) {
{
int r = 4; int r = 4;
if (tx->overwintered) { if (tx->overwintered) {
uint32_t ver = tx->version | TX_OVERWINTERED; uint32_t ver = tx->version | TX_OVERWINTERED;
@ -484,8 +519,7 @@ uint32_t tx_serialize_header(TxStruct *tx, uint8_t *out)
return r + ser_length(tx->inputs_len, out + r); return r + ser_length(tx->inputs_len, out + r);
} }
uint32_t tx_serialize_header_hash(TxStruct *tx) uint32_t tx_serialize_header_hash(TxStruct *tx) {
{
int r = 4; int r = 4;
if (tx->overwintered) { if (tx->overwintered) {
uint32_t ver = tx->version | TX_OVERWINTERED; uint32_t ver = tx->version | TX_OVERWINTERED;
@ -502,8 +536,8 @@ uint32_t tx_serialize_header_hash(TxStruct *tx)
return r + ser_length_hash(&(tx->hasher), tx->inputs_len); return r + ser_length_hash(&(tx->hasher), tx->inputs_len);
} }
uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out) uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input,
{ uint8_t *out) {
if (tx->have_inputs >= tx->inputs_len) { if (tx->have_inputs >= tx->inputs_len) {
// already got all inputs // already got all inputs
return 0; return 0;
@ -516,14 +550,17 @@ uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out
*(out + r + i) = input->prev_hash.bytes[31 - i]; *(out + r + i) = input->prev_hash.bytes[31 - i];
} }
r += 32; r += 32;
memcpy(out + r, &input->prev_index, 4); r += 4; memcpy(out + r, &input->prev_index, 4);
r += 4;
if (tx->is_decred) { if (tx->is_decred) {
uint8_t tree = input->decred_tree & 0xFF; uint8_t tree = input->decred_tree & 0xFF;
out[r++] = tree; out[r++] = tree;
} else { } else {
r += tx_serialize_script(input->script_sig.size, input->script_sig.bytes, out + r); r += tx_serialize_script(input->script_sig.size, input->script_sig.bytes,
out + r);
} }
memcpy(out + r, &input->sequence, 4); r += 4; memcpy(out + r, &input->sequence, 4);
r += 4;
tx->have_inputs++; tx->have_inputs++;
tx->size += r; tx->size += r;
@ -531,8 +568,7 @@ uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out
return r; return r;
} }
uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input) uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input) {
{
if (tx->have_inputs >= tx->inputs_len) { if (tx->have_inputs >= tx->inputs_len) {
// already got all inputs // already got all inputs
return 0; return 0;
@ -544,9 +580,11 @@ uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input)
r += tx_prevout_hash(&(tx->hasher), input); r += tx_prevout_hash(&(tx->hasher), input);
if (tx->is_decred) { if (tx->is_decred) {
uint8_t tree = input->decred_tree & 0xFF; uint8_t tree = input->decred_tree & 0xFF;
hasher_Update(&(tx->hasher), (const uint8_t *)&(tree), 1); r++; hasher_Update(&(tx->hasher), (const uint8_t *)&(tree), 1);
r++;
} else { } else {
r += tx_script_hash(&(tx->hasher), input->script_sig.size, input->script_sig.bytes); r += tx_script_hash(&(tx->hasher), input->script_sig.size,
input->script_sig.bytes);
} }
r += tx_sequence_hash(&(tx->hasher), input); r += tx_sequence_hash(&(tx->hasher), input);
@ -556,8 +594,8 @@ uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input)
return r; return r;
} }
uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, uint8_t *out) uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input,
{ uint8_t *out) {
static const uint64_t amount = 0; static const uint64_t amount = 0;
static const uint32_t block_height = 0x00000000; static const uint32_t block_height = 0x00000000;
static const uint32_t block_index = 0xFFFFFFFF; static const uint32_t block_index = 0xFFFFFFFF;
@ -570,10 +608,14 @@ uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, uin
if (tx->have_inputs == 0) { if (tx->have_inputs == 0) {
r += ser_length(tx->inputs_len, out + r); r += ser_length(tx->inputs_len, out + r);
} }
memcpy(out + r, &amount, 8); r += 8; memcpy(out + r, &amount, 8);
memcpy(out + r, &block_height, 4); r += 4; r += 8;
memcpy(out + r, &block_index, 4); r += 4; memcpy(out + r, &block_height, 4);
r += tx_serialize_script(input->script_sig.size, input->script_sig.bytes, out + r); r += 4;
memcpy(out + r, &block_index, 4);
r += 4;
r += tx_serialize_script(input->script_sig.size, input->script_sig.bytes,
out + r);
tx->have_inputs++; tx->have_inputs++;
tx->size += r; tx->size += r;
@ -581,8 +623,8 @@ uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, uin
return r; return r;
} }
uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxInputType *input) uint32_t tx_serialize_decred_witness_hash(TxStruct *tx,
{ const TxInputType *input) {
if (tx->have_inputs >= tx->inputs_len) { if (tx->have_inputs >= tx->inputs_len) {
// already got all inputs // already got all inputs
return 0; return 0;
@ -594,7 +636,8 @@ uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxInputType *input
if (input == NULL) { if (input == NULL) {
r += ser_length_hash(&(tx->hasher), 0); r += ser_length_hash(&(tx->hasher), 0);
} else { } else {
r += tx_script_hash(&(tx->hasher), input->script_sig.size, input->script_sig.bytes); r += tx_script_hash(&(tx->hasher), input->script_sig.size,
input->script_sig.bytes);
} }
tx->have_inputs++; tx->have_inputs++;
@ -603,26 +646,22 @@ uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxInputType *input
return r; return r;
} }
uint32_t tx_serialize_middle(TxStruct *tx, uint8_t *out) uint32_t tx_serialize_middle(TxStruct *tx, uint8_t *out) {
{
return ser_length(tx->outputs_len, out); return ser_length(tx->outputs_len, out);
} }
uint32_t tx_serialize_middle_hash(TxStruct *tx) uint32_t tx_serialize_middle_hash(TxStruct *tx) {
{
return ser_length_hash(&(tx->hasher), tx->outputs_len); return ser_length_hash(&(tx->hasher), tx->outputs_len);
} }
uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out) uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out) {
{
memcpy(out, &(tx->lock_time), 4); memcpy(out, &(tx->lock_time), 4);
if (tx->overwintered) { if (tx->overwintered) {
if (tx->version == 3) { if (tx->version == 3) {
memcpy(out + 4, &(tx->expiry), 4); memcpy(out + 4, &(tx->expiry), 4);
out[8] = 0x00; // nJoinSplit out[8] = 0x00; // nJoinSplit
return 9; return 9;
} else } else if (tx->version == 4) {
if (tx->version == 4) {
memcpy(out + 4, &(tx->expiry), 4); memcpy(out + 4, &(tx->expiry), 4);
memzero(out + 8, 8); // valueBalance memzero(out + 8, 8); // valueBalance
out[16] = 0x00; // nShieldedSpend out[16] = 0x00; // nShieldedSpend
@ -638,8 +677,7 @@ uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out)
return 4; return 4;
} }
uint32_t tx_serialize_footer_hash(TxStruct *tx) uint32_t tx_serialize_footer_hash(TxStruct *tx) {
{
hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->lock_time), 4); hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->lock_time), 4);
if (tx->overwintered) { if (tx->overwintered) {
hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->expiry), 4); hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->expiry), 4);
@ -653,8 +691,8 @@ uint32_t tx_serialize_footer_hash(TxStruct *tx)
return 4; return 4;
} }
uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out) uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output,
{ uint8_t *out) {
if (tx->have_inputs < tx->inputs_len) { if (tx->have_inputs < tx->inputs_len) {
// not all inputs provided // not all inputs provided
return 0; return 0;
@ -667,23 +705,24 @@ uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_
if (tx->have_outputs == 0) { if (tx->have_outputs == 0) {
r += tx_serialize_middle(tx, out + r); r += tx_serialize_middle(tx, out + r);
} }
memcpy(out + r, &output->amount, 8); r += 8; memcpy(out + r, &output->amount, 8);
r += 8;
if (tx->is_decred) { if (tx->is_decred) {
uint16_t script_version = output->decred_script_version & 0xFFFF; uint16_t script_version = output->decred_script_version & 0xFFFF;
memcpy(out + r, &script_version, 2); r += 2; memcpy(out + r, &script_version, 2);
r += 2;
} }
r += tx_serialize_script(output->script_pubkey.size, output->script_pubkey.bytes, out + r); r += tx_serialize_script(output->script_pubkey.size,
output->script_pubkey.bytes, out + r);
tx->have_outputs++; tx->have_outputs++;
if (tx->have_outputs == tx->outputs_len if (tx->have_outputs == tx->outputs_len && !tx->is_segwit) {
&& !tx->is_segwit) {
r += tx_serialize_footer(tx, out + r); r += tx_serialize_footer(tx, out + r);
} }
tx->size += r; tx->size += r;
return r; return r;
} }
uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output) uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output) {
{
if (tx->have_inputs < tx->inputs_len) { if (tx->have_inputs < tx->inputs_len) {
// not all inputs provided // not all inputs provided
return 0; return 0;
@ -698,16 +737,15 @@ uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output)
} }
r += tx_output_hash(&(tx->hasher), output, tx->is_decred); r += tx_output_hash(&(tx->hasher), output, tx->is_decred);
tx->have_outputs++; tx->have_outputs++;
if (tx->have_outputs == tx->outputs_len if (tx->have_outputs == tx->outputs_len && !tx->is_segwit) {
&& !tx->is_segwit) {
r += tx_serialize_footer_hash(tx); r += tx_serialize_footer_hash(tx);
} }
tx->size += r; tx->size += r;
return r; return r;
} }
uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_t datalen) uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data,
{ uint32_t datalen) {
if (tx->have_inputs < tx->inputs_len) { if (tx->have_inputs < tx->inputs_len) {
// not all inputs provided // not all inputs provided
return 0; return 0;
@ -726,8 +764,10 @@ uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_
return datalen; return datalen;
} }
void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t expiry, uint32_t extra_data_len, HasherType hasher_sign, bool overwintered, uint32_t version_group_id) void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len,
{ uint32_t version, uint32_t lock_time, uint32_t expiry,
uint32_t extra_data_len, HasherType hasher_sign, bool overwintered,
uint32_t version_group_id) {
tx->inputs_len = inputs_len; tx->inputs_len = inputs_len;
tx->outputs_len = outputs_len; tx->outputs_len = outputs_len;
tx->version = version; tx->version = version;
@ -745,8 +785,7 @@ void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t v
hasher_Init(&(tx->hasher), hasher_sign); hasher_Init(&(tx->hasher), hasher_sign);
} }
void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse) {
{
hasher_Final(&(t->hasher), hash); hasher_Final(&(t->hasher), hash);
if (!reverse) return; if (!reverse) return;
for (uint8_t i = 0; i < 16; i++) { for (uint8_t i = 0; i < 16; i++) {
@ -759,11 +798,13 @@ void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse)
static uint32_t tx_input_script_size(const TxInputType *txinput) { static uint32_t tx_input_script_size(const TxInputType *txinput) {
uint32_t input_script_size; uint32_t input_script_size;
if (txinput->has_multisig) { if (txinput->has_multisig) {
uint32_t multisig_script_size = TXSIZE_MULTISIGSCRIPT uint32_t multisig_script_size =
+ txinput->multisig.pubkeys_count * (1 + TXSIZE_PUBKEY); TXSIZE_MULTISIGSCRIPT +
txinput->multisig.pubkeys_count * (1 + TXSIZE_PUBKEY);
input_script_size = 1 // the OP_FALSE bug in multisig input_script_size = 1 // the OP_FALSE bug in multisig
+ txinput->multisig.m * (1 + TXSIZE_SIGNATURE) + txinput->multisig.m * (1 + TXSIZE_SIGNATURE) +
+ op_push_size(multisig_script_size) + multisig_script_size; op_push_size(multisig_script_size) +
multisig_script_size;
} else { } else {
input_script_size = (1 + TXSIZE_SIGNATURE + 1 + TXSIZE_PUBKEY); input_script_size = (1 + TXSIZE_SIGNATURE + 1 + TXSIZE_PUBKEY);
} }
@ -778,15 +819,15 @@ uint32_t tx_input_weight(const CoinInfo *coin, const TxInputType *txinput) {
uint32_t input_script_size = tx_input_script_size(txinput); uint32_t input_script_size = tx_input_script_size(txinput);
uint32_t weight = 4 * TXSIZE_INPUT; uint32_t weight = 4 * TXSIZE_INPUT;
if (txinput->script_type == InputScriptType_SPENDADDRESS if (txinput->script_type == InputScriptType_SPENDADDRESS ||
|| txinput->script_type == InputScriptType_SPENDMULTISIG) { txinput->script_type == InputScriptType_SPENDMULTISIG) {
input_script_size += ser_length_size(input_script_size); input_script_size += ser_length_size(input_script_size);
weight += 4 * input_script_size; weight += 4 * input_script_size;
} else if (txinput->script_type == InputScriptType_SPENDWITNESS } else if (txinput->script_type == InputScriptType_SPENDWITNESS ||
|| txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { txinput->script_type == InputScriptType_SPENDP2SHWITNESS) {
if (txinput->script_type == InputScriptType_SPENDP2SHWITNESS) { if (txinput->script_type == InputScriptType_SPENDP2SHWITNESS) {
weight += 4 * (2 + (txinput->has_multisig weight += 4 * (2 + (txinput->has_multisig ? TXSIZE_WITNESSSCRIPT
? TXSIZE_WITNESSSCRIPT : TXSIZE_WITNESSPKHASH)); : TXSIZE_WITNESSPKHASH));
} else { } else {
weight += 4; // empty input script weight += 4; // empty input script
} }
@ -798,41 +839,44 @@ uint32_t tx_input_weight(const CoinInfo *coin, const TxInputType *txinput) {
uint32_t tx_output_weight(const CoinInfo *coin, const TxOutputType *txoutput) { uint32_t tx_output_weight(const CoinInfo *coin, const TxOutputType *txoutput) {
uint32_t output_script_size = 0; uint32_t output_script_size = 0;
if (txoutput->script_type == OutputScriptType_PAYTOOPRETURN) { if (txoutput->script_type == OutputScriptType_PAYTOOPRETURN) {
output_script_size = 1 + op_push_size(txoutput->op_return_data.size) output_script_size = 1 + op_push_size(txoutput->op_return_data.size) +
+ txoutput->op_return_data.size; txoutput->op_return_data.size;
} else if (txoutput->address_n_count > 0) { } else if (txoutput->address_n_count > 0) {
if (txoutput->script_type == OutputScriptType_PAYTOWITNESS) { if (txoutput->script_type == OutputScriptType_PAYTOWITNESS) {
output_script_size = txoutput->has_multisig output_script_size =
? TXSIZE_WITNESSSCRIPT : TXSIZE_WITNESSPKHASH; txoutput->has_multisig ? TXSIZE_WITNESSSCRIPT : TXSIZE_WITNESSPKHASH;
} else if (txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS) { } else if (txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS) {
output_script_size = TXSIZE_P2SCRIPT; output_script_size = TXSIZE_P2SCRIPT;
} else { } else {
output_script_size = txoutput->has_multisig output_script_size =
? TXSIZE_P2SCRIPT : TXSIZE_P2PKHASH; txoutput->has_multisig ? TXSIZE_P2SCRIPT : TXSIZE_P2PKHASH;
} }
} else { } else {
uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; uint8_t addr_raw[MAX_ADDR_RAW_SIZE];
int witver; int witver;
size_t addr_raw_len; size_t addr_raw_len;
if (coin->cashaddr_prefix if (coin->cashaddr_prefix &&
&& cash_addr_decode(addr_raw, &addr_raw_len, coin->cashaddr_prefix, txoutput->address)) { cash_addr_decode(addr_raw, &addr_raw_len, coin->cashaddr_prefix,
if (addr_raw_len == 21 txoutput->address)) {
&& addr_raw[0] == (CASHADDR_P2KH | CASHADDR_160)) { if (addr_raw_len == 21 && addr_raw[0] == (CASHADDR_P2KH | CASHADDR_160)) {
output_script_size = TXSIZE_P2PKHASH; output_script_size = TXSIZE_P2PKHASH;
} else if (addr_raw_len == 21 } else if (addr_raw_len == 21 &&
&& addr_raw[0] == (CASHADDR_P2SH | CASHADDR_160)) { addr_raw[0] == (CASHADDR_P2SH | CASHADDR_160)) {
output_script_size = TXSIZE_P2SCRIPT; output_script_size = TXSIZE_P2SCRIPT;
} }
} else if (coin->bech32_prefix } else if (coin->bech32_prefix &&
&& segwit_addr_decode(&witver, addr_raw, &addr_raw_len, coin->bech32_prefix, txoutput->address)) { segwit_addr_decode(&witver, addr_raw, &addr_raw_len,
coin->bech32_prefix, txoutput->address)) {
output_script_size = 2 + addr_raw_len; output_script_size = 2 + addr_raw_len;
} else { } else {
addr_raw_len = base58_decode_check(txoutput->address, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); addr_raw_len =
if (coin->has_address_type base58_decode_check(txoutput->address, coin->curve->hasher_base58,
&& address_check_prefix(addr_raw, coin->address_type)) { addr_raw, MAX_ADDR_RAW_SIZE);
if (coin->has_address_type &&
address_check_prefix(addr_raw, coin->address_type)) {
output_script_size = TXSIZE_P2PKHASH; output_script_size = TXSIZE_P2PKHASH;
} else if (coin->has_address_type_p2sh } else if (coin->has_address_type_p2sh &&
&& address_check_prefix(addr_raw, coin->address_type_p2sh)) { address_check_prefix(addr_raw, coin->address_type_p2sh)) {
output_script_size = TXSIZE_P2SCRIPT; output_script_size = TXSIZE_P2SCRIPT;
} }
} }
@ -849,7 +893,8 @@ uint32_t tx_output_weight(const CoinInfo *coin, const TxOutputType *txoutput) {
uint32_t tx_decred_witness_weight(const TxInputType *txinput) { uint32_t tx_decred_witness_weight(const TxInputType *txinput) {
uint32_t input_script_size = tx_input_script_size(txinput); uint32_t input_script_size = tx_input_script_size(txinput);
uint32_t size = TXSIZE_DECRED_WITNESS + ser_length_size(input_script_size) + input_script_size; uint32_t size = TXSIZE_DECRED_WITNESS + ser_length_size(input_script_size) +
input_script_size;
return 4 * size; return 4 * size;
} }

View File

@ -22,11 +22,11 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include "sha2.h"
#include "bip32.h" #include "bip32.h"
#include "coins.h" #include "coins.h"
#include "hasher.h" #include "hasher.h"
#include "messages-bitcoin.pb.h" #include "messages-bitcoin.pb.h"
#include "sha2.h"
#define TX_OVERWINTERED 0x80000000 #define TX_OVERWINTERED 0x80000000
@ -53,31 +53,53 @@ typedef struct {
Hasher hasher; Hasher hasher;
} TxStruct; } TxStruct;
bool compute_address(const CoinInfo *coin, InputScriptType script_type, const HDNode *node, bool has_multisig, const MultisigRedeemScriptType *multisig, char address[MAX_ADDR_SIZE]); bool compute_address(const CoinInfo *coin, InputScriptType script_type,
uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out); const HDNode *node, bool has_multisig,
uint32_t compile_script_multisig(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t *out); const MultisigRedeemScriptType *multisig,
uint32_t compile_script_multisig_hash(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t *hash); char address[MAX_ADDR_SIZE]);
uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len, const uint8_t *pubkey, uint32_t pubkey_len, uint8_t sighash, uint8_t *out); uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash,
uint32_t serialize_script_multisig(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint8_t sighash, uint8_t *out); uint8_t *out);
int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, TxOutputBinType *out, bool needs_confirm); uint32_t compile_script_multisig(const CoinInfo *coin,
const MultisigRedeemScriptType *multisig,
uint8_t *out);
uint32_t compile_script_multisig_hash(const CoinInfo *coin,
const MultisigRedeemScriptType *multisig,
uint8_t *hash);
uint32_t serialize_script_sig(const uint8_t *signature, uint32_t signature_len,
const uint8_t *pubkey, uint32_t pubkey_len,
uint8_t sighash, uint8_t *out);
uint32_t serialize_script_multisig(const CoinInfo *coin,
const MultisigRedeemScriptType *multisig,
uint8_t sighash, uint8_t *out);
int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in,
TxOutputBinType *out, bool needs_confirm);
uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input); uint32_t tx_prevout_hash(Hasher *hasher, const TxInputType *input);
uint32_t tx_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data); uint32_t tx_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data);
uint32_t tx_sequence_hash(Hasher *hasher, const TxInputType *input); uint32_t tx_sequence_hash(Hasher *hasher, const TxInputType *input);
uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output, bool decred); uint32_t tx_output_hash(Hasher *hasher, const TxOutputBinType *output,
bool decred);
uint32_t tx_serialize_script(uint32_t size, const uint8_t *data, uint8_t *out); uint32_t tx_serialize_script(uint32_t size, const uint8_t *data, uint8_t *out);
uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out); uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out);
uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out); uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input,
uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out); uint8_t *out);
uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, uint8_t *out); uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output,
uint8_t *out);
uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input,
uint8_t *out);
void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t expiry, uint32_t extra_data_len, HasherType hasher_sign, bool overwintered, uint32_t version_group_id); void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len,
uint32_t version, uint32_t lock_time, uint32_t expiry,
uint32_t extra_data_len, HasherType hasher_sign, bool overwintered,
uint32_t version_group_id);
uint32_t tx_serialize_header_hash(TxStruct *tx); uint32_t tx_serialize_header_hash(TxStruct *tx);
uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input); uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input);
uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output); uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output);
uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_t datalen); uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data,
uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxInputType *input); uint32_t datalen);
uint32_t tx_serialize_decred_witness_hash(TxStruct *tx,
const TxInputType *input);
void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse); void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse);
uint32_t tx_input_weight(const CoinInfo *coin, const TxInputType *txinput); uint32_t tx_input_weight(const CoinInfo *coin, const TxInputType *txinput);

View File

@ -17,32 +17,31 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "common.h"
#include "trezor.h" #include "trezor.h"
#include "oled.h"
#include "bitmaps.h" #include "bitmaps.h"
#include "util.h" #include "bl_check.h"
#include "usb.h" #include "buttons.h"
#include "setup.h" #include "common.h"
#include "config.h" #include "config.h"
#include "gettext.h"
#include "layout.h" #include "layout.h"
#include "layout2.h" #include "layout2.h"
#include "rng.h"
#include "timer.h"
#include "buttons.h"
#include "gettext.h"
#include "bl_check.h"
#include "memzero.h" #include "memzero.h"
#include "oled.h"
#include "rng.h"
#include "setup.h"
#include "timer.h"
#include "usb.h"
#include "util.h"
#if !EMULATOR #if !EMULATOR
#include "otp.h"
#include <libopencm3/stm32/desig.h> #include <libopencm3/stm32/desig.h>
#include "otp.h"
#endif #endif
/* Screen timeout */ /* Screen timeout */
uint32_t system_millis_lock_start; uint32_t system_millis_lock_start;
void check_lock_screen(void) void check_lock_screen(void) {
{
buttonUpdate(); buttonUpdate();
// wake from screensaver on any button // wake from screensaver on any button
@ -53,8 +52,9 @@ void check_lock_screen(void)
// button held for long enough (2 seconds) // button held for long enough (2 seconds)
if (layoutLast == layoutHome && button.NoDown >= 285000 * 2) { if (layoutLast == layoutHome && button.NoDown >= 285000 * 2) {
layoutDialog(&bmp_icon_question, _("Cancel"), _("Lock Device"), NULL,
layoutDialog(&bmp_icon_question, _("Cancel"), _("Lock Device"), NULL, _("Do you really want to"), _("lock your TREZOR?"), NULL, NULL, NULL, NULL); _("Do you really want to"), _("lock your TREZOR?"), NULL, NULL,
NULL, NULL);
// wait until NoButton is released // wait until NoButton is released
usbTiny(1); usbTiny(1);
@ -82,7 +82,8 @@ void check_lock_screen(void)
// if homescreen is shown for too long // if homescreen is shown for too long
if (layoutLast == layoutHome) { if (layoutLast == layoutHome) {
if ((timer_ms() - system_millis_lock_start) >= config_getAutoLockDelayMs()) { if ((timer_ms() - system_millis_lock_start) >=
config_getAutoLockDelayMs()) {
// lock the screen // lock the screen
session_clear(true); session_clear(true);
layoutScreensaver(); layoutScreensaver();
@ -90,8 +91,7 @@ void check_lock_screen(void)
} }
} }
static void collect_hw_entropy(bool privileged) static void collect_hw_entropy(bool privileged) {
{
#if EMULATOR #if EMULATOR
(void)privileged; (void)privileged;
memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN);
@ -102,11 +102,13 @@ static void collect_hw_entropy(bool privileged)
if (!flash_otp_is_locked(FLASH_OTP_BLOCK_RANDOMNESS)) { if (!flash_otp_is_locked(FLASH_OTP_BLOCK_RANDOMNESS)) {
uint8_t entropy[FLASH_OTP_BLOCK_SIZE]; uint8_t entropy[FLASH_OTP_BLOCK_SIZE];
random_buffer(entropy, FLASH_OTP_BLOCK_SIZE); random_buffer(entropy, FLASH_OTP_BLOCK_SIZE);
flash_otp_write(FLASH_OTP_BLOCK_RANDOMNESS, 0, entropy, FLASH_OTP_BLOCK_SIZE); flash_otp_write(FLASH_OTP_BLOCK_RANDOMNESS, 0, entropy,
FLASH_OTP_BLOCK_SIZE);
flash_otp_lock(FLASH_OTP_BLOCK_RANDOMNESS); flash_otp_lock(FLASH_OTP_BLOCK_RANDOMNESS);
} }
// collect entropy from OTP randomness block // collect entropy from OTP randomness block
flash_otp_read(FLASH_OTP_BLOCK_RANDOMNESS, 0, HW_ENTROPY_DATA + 12, FLASH_OTP_BLOCK_SIZE); flash_otp_read(FLASH_OTP_BLOCK_RANDOMNESS, 0, HW_ENTROPY_DATA + 12,
FLASH_OTP_BLOCK_SIZE);
} else { } else {
// unprivileged mode => use fixed HW_ENTROPY // unprivileged mode => use fixed HW_ENTROPY
memset(HW_ENTROPY_DATA, 0x3C, HW_ENTROPY_LEN); memset(HW_ENTROPY_DATA, 0x3C, HW_ENTROPY_LEN);
@ -114,16 +116,17 @@ static void collect_hw_entropy(bool privileged)
#endif #endif
} }
int main(void) int main(void) {
{
#ifndef APPVER #ifndef APPVER
setup(); setup();
__stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks __stack_chk_guard = random32(); // this supports compiler provided
// unpredictable stack protection checks
oledInit(); oledInit();
#else #else
check_bootloader(); check_bootloader();
setupApp(); setupApp();
__stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks __stack_chk_guard = random32(); // this supports compiler provided
// unpredictable stack protection checks
#endif #endif
if (!is_mode_unprivileged()) { if (!is_mode_unprivileged()) {
collect_hw_entropy(true); collect_hw_entropy(true);

View File

@ -17,29 +17,29 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h>
#include <ecdsa.h> #include <ecdsa.h>
#include <string.h>
#include "debug.h"
#include "config.h"
#include "bip32.h" #include "bip32.h"
#include "layout2.h"
#include "usb.h"
#include "buttons.h" #include "buttons.h"
#include "trezor.h" #include "config.h"
#include "curves.h" #include "curves.h"
#include "debug.h"
#include "gettext.h"
#include "hmac.h"
#include "layout2.h"
#include "memzero.h"
#include "nist256p1.h" #include "nist256p1.h"
#include "rng.h" #include "rng.h"
#include "hmac.h" #include "trezor.h"
#include "usb.h"
#include "util.h" #include "util.h"
#include "gettext.h"
#include "memzero.h"
#include "u2f.h"
#include "u2f/u2f.h" #include "u2f/u2f.h"
#include "u2f/u2f_hid.h" #include "u2f/u2f_hid.h"
#include "u2f/u2f_keys.h" #include "u2f/u2f_keys.h"
#include "u2f_knownapps.h" #include "u2f_knownapps.h"
#include "u2f.h"
// About 1/2 Second according to values used in protect.c // About 1/2 Second according to values used in protect.c
#define U2F_TIMEOUT (800000 / 2) #define U2F_TIMEOUT (800000 / 2)
@ -61,7 +61,8 @@ static uint8_t u2f_out_packets[U2F_OUT_PKT_BUFFER_LEN][HID_RPT_SIZE];
#define KEY_PATH_ENTRIES (KEY_PATH_LEN / sizeof(uint32_t)) #define KEY_PATH_ENTRIES (KEY_PATH_LEN / sizeof(uint32_t))
// Defined as UsbSignHandler.BOGUS_APP_ID_HASH // Defined as UsbSignHandler.BOGUS_APP_ID_HASH
// in https://github.com/google/u2f-ref-code/blob/master/u2f-chrome-extension/usbsignhandler.js#L118 // in
// https://github.com/google/u2f-ref-code/blob/master/u2f-chrome-extension/usbsignhandler.js#L118
#define BOGUS_APPID "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" #define BOGUS_APPID "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
// Auth/Register request state machine // Auth/Register request state machine
@ -92,8 +93,7 @@ typedef struct {
static uint32_t dialog_timeout = 0; static uint32_t dialog_timeout = 0;
uint32_t next_cid(void) uint32_t next_cid(void) {
{
// extremely unlikely but hey // extremely unlikely but hey
do { do {
cid = random32(); cid = random32();
@ -116,8 +116,7 @@ typedef struct {
U2F_ReadBuffer *reader; U2F_ReadBuffer *reader;
void u2fhid_read(char tiny, const U2FHID_FRAME *f) void u2fhid_read(char tiny, const U2FHID_FRAME *f) {
{
// Always handle init packets directly // Always handle init packets directly
if (f->init.cmd == U2FHID_INIT) { if (f->init.cmd == U2FHID_INIT) {
u2fhid_init(f); u2fhid_init(f);
@ -151,8 +150,9 @@ void u2fhid_read(char tiny, const U2FHID_FRAME *f)
} }
// check out of bounds // check out of bounds
if ((reader->buf_ptr - reader->buf) >= (signed) reader->len if ((reader->buf_ptr - reader->buf) >= (signed)reader->len ||
|| (reader->buf_ptr + sizeof(f->cont.data) - reader->buf) > (signed) sizeof(reader->buf)) (reader->buf_ptr + sizeof(f->cont.data) - reader->buf) >
(signed)sizeof(reader->buf))
return; return;
reader->seq++; reader->seq++;
memcpy(reader->buf_ptr, f->cont.data, sizeof(f->cont.data)); memcpy(reader->buf_ptr, f->cont.data, sizeof(f->cont.data));
@ -242,8 +242,7 @@ void u2fhid_read_start(const U2FHID_FRAME *f) {
dialog_timeout--; dialog_timeout--;
usbPoll(); // may trigger new request usbPoll(); // may trigger new request
buttonUpdate(); buttonUpdate();
if (button.YesUp && if (button.YesUp && (last_req_state == AUTH || last_req_state == REG)) {
(last_req_state == AUTH || last_req_state == REG)) {
last_req_state++; last_req_state++;
// standard requires to remember button press for 10 seconds. // standard requires to remember button press for 10 seconds.
dialog_timeout = 10 * U2F_TIMEOUT; dialog_timeout = 10 * U2F_TIMEOUT;
@ -261,22 +260,18 @@ void u2fhid_read_start(const U2FHID_FRAME *f) {
} }
} }
void u2fhid_ping(const uint8_t *buf, uint32_t len) void u2fhid_ping(const uint8_t *buf, uint32_t len) {
{
debugLog(0, "", "u2fhid_ping"); debugLog(0, "", "u2fhid_ping");
send_u2fhid_msg(U2FHID_PING, buf, len); send_u2fhid_msg(U2FHID_PING, buf, len);
} }
void u2fhid_wink(const uint8_t *buf, uint32_t len) void u2fhid_wink(const uint8_t *buf, uint32_t len) {
{
debugLog(0, "", "u2fhid_wink"); debugLog(0, "", "u2fhid_wink");
(void)buf; (void)buf;
if (len > 0) if (len > 0) return send_u2fhid_error(cid, ERR_INVALID_LEN);
return send_u2fhid_error(cid, ERR_INVALID_LEN);
if (dialog_timeout > 0) if (dialog_timeout > 0) dialog_timeout = U2F_TIMEOUT;
dialog_timeout = U2F_TIMEOUT;
U2FHID_FRAME f; U2FHID_FRAME f;
memzero(&f, sizeof(f)); memzero(&f, sizeof(f));
@ -286,8 +281,7 @@ void u2fhid_wink(const uint8_t *buf, uint32_t len)
queue_u2f_pkt(&f); queue_u2f_pkt(&f);
} }
void u2fhid_init(const U2FHID_FRAME *in) void u2fhid_init(const U2FHID_FRAME *in) {
{
const U2FHID_INIT_REQ *init_req = (const U2FHID_INIT_REQ *)&in->init.data; const U2FHID_INIT_REQ *init_req = (const U2FHID_INIT_REQ *)&in->init.data;
U2FHID_FRAME f; U2FHID_FRAME f;
U2FHID_INIT_RESP resp; U2FHID_INIT_RESP resp;
@ -318,8 +312,7 @@ void u2fhid_init(const U2FHID_FRAME *in)
queue_u2f_pkt(&f); queue_u2f_pkt(&f);
} }
void queue_u2f_pkt(const U2FHID_FRAME *u2f_pkt) void queue_u2f_pkt(const U2FHID_FRAME *u2f_pkt) {
{
// debugLog(0, "", "u2f_write_pkt"); // debugLog(0, "", "u2f_write_pkt");
uint32_t next = (u2f_out_end + 1) % U2F_OUT_PKT_BUFFER_LEN; uint32_t next = (u2f_out_end + 1) % U2F_OUT_PKT_BUFFER_LEN;
if (u2f_out_start == next) { if (u2f_out_start == next) {
@ -330,18 +323,15 @@ void queue_u2f_pkt(const U2FHID_FRAME *u2f_pkt)
u2f_out_end = next; u2f_out_end = next;
} }
uint8_t *u2f_out_data(void) uint8_t *u2f_out_data(void) {
{ if (u2f_out_start == u2f_out_end) return NULL; // No data
if (u2f_out_start == u2f_out_end)
return NULL; // No data
// debugLog(0, "", "u2f_out_data"); // debugLog(0, "", "u2f_out_data");
uint32_t t = u2f_out_start; uint32_t t = u2f_out_start;
u2f_out_start = (u2f_out_start + 1) % U2F_OUT_PKT_BUFFER_LEN; u2f_out_start = (u2f_out_start + 1) % U2F_OUT_PKT_BUFFER_LEN;
return u2f_out_packets[t]; return u2f_out_packets[t];
} }
void u2fhid_msg(const APDU *a, uint32_t len) void u2fhid_msg(const APDU *a, uint32_t len) {
{
if ((APDU_LEN(*a) + sizeof(APDU)) > len) { if ((APDU_LEN(*a) + sizeof(APDU)) > len) {
debugLog(0, "", "BAD APDU LENGTH"); debugLog(0, "", "BAD APDU LENGTH");
debugInt(APDU_LEN(*a)); debugInt(APDU_LEN(*a));
@ -370,8 +360,8 @@ void u2fhid_msg(const APDU *a, uint32_t len)
} }
} }
void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, const uint32_t len) void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data,
{ const uint32_t len) {
if (len > U2F_MAXIMUM_PAYLOAD_LENGTH) { if (len > U2F_MAXIMUM_PAYLOAD_LENGTH) {
debugLog(0, "", "send_u2fhid_msg failed"); debugLog(0, "", "send_u2fhid_msg failed");
return; return;
@ -414,8 +404,7 @@ void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, const uint32_t len)
} }
} }
void send_u2fhid_error(uint32_t fcid, uint8_t err) void send_u2fhid_error(uint32_t fcid, uint8_t err) {
{
U2FHID_FRAME f; U2FHID_FRAME f;
memzero(&f, sizeof(f)); memzero(&f, sizeof(f));
@ -426,8 +415,7 @@ void send_u2fhid_error(uint32_t fcid, uint8_t err)
queue_u2f_pkt(&f); queue_u2f_pkt(&f);
} }
void u2f_version(const APDU *a) void u2f_version(const APDU *a) {
{
if (APDU_LEN(*a) != 0) { if (APDU_LEN(*a) != 0) {
debugLog(0, "", "u2f version - badlen"); debugLog(0, "", "u2f version - badlen");
send_u2f_error(U2F_SW_WRONG_LENGTH); send_u2f_error(U2F_SW_WRONG_LENGTH);
@ -441,10 +429,12 @@ void u2f_version(const APDU *a)
send_u2f_msg(version_response, sizeof(version_response)); send_u2f_msg(version_response, sizeof(version_response));
} }
static void getReadableAppId(const uint8_t appid[U2F_APPID_SIZE], const char **appname) { static void getReadableAppId(const uint8_t appid[U2F_APPID_SIZE],
const char **appname) {
static char buf[8 + 2 + 8 + 1]; static char buf[8 + 2 + 8 + 1];
for (unsigned int i = 0; i < sizeof(u2f_well_known)/sizeof(U2FWellKnown); i++) { for (unsigned int i = 0; i < sizeof(u2f_well_known) / sizeof(U2FWellKnown);
i++) {
if (memcmp(appid, u2f_well_known[i].appid, U2F_APPID_SIZE) == 0) { if (memcmp(appid, u2f_well_known[i].appid, U2F_APPID_SIZE) == 0) {
*appname = u2f_well_known[i].appname; *appname = u2f_well_known[i].appname;
return; return;
@ -457,8 +447,8 @@ static void getReadableAppId(const uint8_t appid[U2F_APPID_SIZE], const char **a
*appname = buf; *appname = buf;
} }
static const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count) static const HDNode *getDerivedNode(uint32_t *address_n,
{ size_t address_n_count) {
static CONFIDENTIAL HDNode node; static CONFIDENTIAL HDNode node;
if (!config_getU2FRoot(&node)) { if (!config_getU2FRoot(&node)) {
layoutHome(); layoutHome();
@ -478,8 +468,8 @@ static const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count)
return &node; return &node;
} }
static const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handle[]) static const HDNode *generateKeyHandle(const uint8_t app_id[],
{ uint8_t key_handle[]) {
uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN]; uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN];
// Derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r' // Derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r'
@ -494,23 +484,21 @@ static const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handl
// prepare keypair from /random data // prepare keypair from /random data
const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES); const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES);
if (!node) if (!node) return NULL;
return NULL;
// For second half of keyhandle // For second half of keyhandle
// Signature of app_id and random data // Signature of app_id and random data
memcpy(&keybase[0], app_id, U2F_APPID_SIZE); memcpy(&keybase[0], app_id, U2F_APPID_SIZE);
memcpy(&keybase[U2F_APPID_SIZE], key_handle, KEY_PATH_LEN); memcpy(&keybase[U2F_APPID_SIZE], key_handle, KEY_PATH_LEN);
hmac_sha256(node->private_key, sizeof(node->private_key), hmac_sha256(node->private_key, sizeof(node->private_key), keybase,
keybase, sizeof(keybase), &key_handle[KEY_PATH_LEN]); sizeof(keybase), &key_handle[KEY_PATH_LEN]);
// Done! // Done!
return node; return node;
} }
static const HDNode *validateKeyHandle(const uint8_t app_id[],
static const HDNode *validateKeyHandle(const uint8_t app_id[], const uint8_t key_handle[]) const uint8_t key_handle[]) {
{
uint32_t key_path[KEY_PATH_ENTRIES]; uint32_t key_path[KEY_PATH_ENTRIES];
memcpy(key_path, key_handle, KEY_PATH_LEN); memcpy(key_path, key_handle, KEY_PATH_LEN);
for (unsigned int i = 0; i < KEY_PATH_ENTRIES; i++) { for (unsigned int i = 0; i < KEY_PATH_ENTRIES; i++) {
@ -521,17 +509,15 @@ static const HDNode *validateKeyHandle(const uint8_t app_id[], const uint8_t key
} }
const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES); const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES);
if (!node) if (!node) return NULL;
return NULL;
uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN]; uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN];
memcpy(&keybase[0], app_id, U2F_APPID_SIZE); memcpy(&keybase[0], app_id, U2F_APPID_SIZE);
memcpy(&keybase[U2F_APPID_SIZE], key_handle, KEY_PATH_LEN); memcpy(&keybase[U2F_APPID_SIZE], key_handle, KEY_PATH_LEN);
uint8_t hmac[SHA256_DIGEST_LENGTH]; uint8_t hmac[SHA256_DIGEST_LENGTH];
hmac_sha256(node->private_key, sizeof(node->private_key), hmac_sha256(node->private_key, sizeof(node->private_key), keybase,
keybase, sizeof(keybase), hmac); sizeof(keybase), hmac);
if (memcmp(&key_handle[KEY_PATH_LEN], hmac, SHA256_DIGEST_LENGTH) != 0) if (memcmp(&key_handle[KEY_PATH_LEN], hmac, SHA256_DIGEST_LENGTH) != 0)
return NULL; return NULL;
@ -540,9 +526,7 @@ static const HDNode *validateKeyHandle(const uint8_t app_id[], const uint8_t key
return node; return node;
} }
void u2f_register(const APDU *a) {
void u2f_register(const APDU *a)
{
static U2F_REGISTER_REQ last_req; static U2F_REGISTER_REQ last_req;
const U2F_REGISTER_REQ *req = (U2F_REGISTER_REQ *)a->data; const U2F_REGISTER_REQ *req = (U2F_REGISTER_REQ *)a->data;
@ -570,7 +554,9 @@ void u2f_register(const APDU *a)
// error: testof-user-presence is required // error: testof-user-presence is required
buttonUpdate(); // Clear button state buttonUpdate(); // Clear button state
if (0 == memcmp(req->appId, BOGUS_APPID, U2F_APPID_SIZE)) { if (0 == memcmp(req->appId, BOGUS_APPID, U2F_APPID_SIZE)) {
layoutDialog(&bmp_icon_warning, NULL, _("OK"), NULL, _("Another U2F device"), _("was used to register"), _("in this application."), NULL, NULL, NULL); layoutDialog(&bmp_icon_warning, NULL, _("OK"), NULL,
_("Another U2F device"), _("was used to register"),
_("in this application."), NULL, NULL, NULL);
} else { } else {
const char *appname; const char *appname;
getReadableAppId(req->appId, &appname); getReadableAppId(req->appId, &appname);
@ -608,8 +594,8 @@ void u2f_register(const APDU *a)
ecdsa_get_public_key65(node->curve->params, node->private_key, ecdsa_get_public_key65(node->curve->params, node->private_key,
(uint8_t *)&resp->pubKey); (uint8_t *)&resp->pubKey);
memcpy(resp->keyHandleCertSig + resp->keyHandleLen, memcpy(resp->keyHandleCertSig + resp->keyHandleLen, U2F_ATT_CERT,
U2F_ATT_CERT, sizeof(U2F_ATT_CERT)); sizeof(U2F_ATT_CERT));
uint8_t sig[64]; uint8_t sig[64];
U2F_REGISTER_SIG_STR sig_base; U2F_REGISTER_SIG_STR sig_base;
@ -618,25 +604,26 @@ void u2f_register(const APDU *a)
memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE); memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE);
memcpy(sig_base.keyHandle, &resp->keyHandleCertSig, KEY_HANDLE_LEN); memcpy(sig_base.keyHandle, &resp->keyHandleCertSig, KEY_HANDLE_LEN);
memcpy(sig_base.pubKey, &resp->pubKey, U2F_PUBKEY_LEN); memcpy(sig_base.pubKey, &resp->pubKey, U2F_PUBKEY_LEN);
if (ecdsa_sign(&nist256p1, HASHER_SHA2, U2F_ATT_PRIV_KEY, (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, NULL) != 0) { if (ecdsa_sign(&nist256p1, HASHER_SHA2, U2F_ATT_PRIV_KEY,
(uint8_t *)&sig_base, sizeof(sig_base), sig, NULL,
NULL) != 0) {
send_u2f_error(U2F_SW_WRONG_DATA); send_u2f_error(U2F_SW_WRONG_DATA);
return; return;
} }
// Where to write the signature in the response // Where to write the signature in the response
uint8_t *resp_sig = resp->keyHandleCertSig + uint8_t *resp_sig =
resp->keyHandleLen + sizeof(U2F_ATT_CERT); resp->keyHandleCertSig + resp->keyHandleLen + sizeof(U2F_ATT_CERT);
// Convert to der for the response // Convert to der for the response
const uint8_t sig_len = ecdsa_sig_to_der(sig, resp_sig); const uint8_t sig_len = ecdsa_sig_to_der(sig, resp_sig);
// Append success bytes // Append success bytes
memcpy(resp->keyHandleCertSig + resp->keyHandleLen + memcpy(resp->keyHandleCertSig + resp->keyHandleLen + sizeof(U2F_ATT_CERT) +
sizeof(U2F_ATT_CERT) + sig_len, sig_len,
"\x90\x00", 2); "\x90\x00", 2);
int l = 1 /* registerId */ + U2F_PUBKEY_LEN + int l = 1 /* registerId */ + U2F_PUBKEY_LEN + 1 /* keyhandleLen */ +
1 /* keyhandleLen */ + resp->keyHandleLen + resp->keyHandleLen + sizeof(U2F_ATT_CERT) + sig_len + 2;
sizeof(U2F_ATT_CERT) + sig_len + 2;
last_req_state = INIT; last_req_state = INIT;
dialog_timeout = 0; dialog_timeout = 0;
@ -648,8 +635,7 @@ void u2f_register(const APDU *a)
dialog_timeout = 0; dialog_timeout = 0;
} }
void u2f_authenticate(const APDU *a) void u2f_authenticate(const APDU *a) {
{
const U2F_AUTHENTICATE_REQ *req = (U2F_AUTHENTICATE_REQ *)a->data; const U2F_AUTHENTICATE_REQ *req = (U2F_AUTHENTICATE_REQ *)a->data;
static U2F_AUTHENTICATE_REQ last_req; static U2F_AUTHENTICATE_REQ last_req;
@ -670,8 +656,7 @@ void u2f_authenticate(const APDU *a)
return; return;
} }
const HDNode *node = const HDNode *node = validateKeyHandle(req->appId, req->keyHandle);
validateKeyHandle(req->appId, req->keyHandle);
if (!node) { if (!node) {
debugLog(0, "", "u2f auth - bad keyhandle len"); debugLog(0, "", "u2f auth - bad keyhandle len");
@ -722,8 +707,7 @@ void u2f_authenticate(const APDU *a)
// Buttons said yes // Buttons said yes
if (last_req_state == AUTH_PASS) { if (last_req_state == AUTH_PASS) {
uint8_t buf[sizeof(U2F_AUTHENTICATE_RESP) + 2]; uint8_t buf[sizeof(U2F_AUTHENTICATE_RESP) + 2];
U2F_AUTHENTICATE_RESP *resp = U2F_AUTHENTICATE_RESP *resp = (U2F_AUTHENTICATE_RESP *)&buf;
(U2F_AUTHENTICATE_RESP *)&buf;
const uint32_t ctr = config_nextU2FCounter(); const uint32_t ctr = config_nextU2FCounter();
resp->flags = U2F_AUTH_FLAG_TUP; resp->flags = U2F_AUTH_FLAG_TUP;
@ -739,7 +723,9 @@ void u2f_authenticate(const APDU *a)
sig_base.flags = resp->flags; sig_base.flags = resp->flags;
memcpy(sig_base.ctr, resp->ctr, 4); memcpy(sig_base.ctr, resp->ctr, 4);
memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE); memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE);
if (ecdsa_sign(&nist256p1, HASHER_SHA2, node->private_key, (uint8_t *)&sig_base, sizeof(sig_base), sig, NULL, NULL) != 0) { if (ecdsa_sign(&nist256p1, HASHER_SHA2, node->private_key,
(uint8_t *)&sig_base, sizeof(sig_base), sig, NULL,
NULL) != 0) {
send_u2f_error(U2F_SW_WRONG_DATA); send_u2f_error(U2F_SW_WRONG_DATA);
return; return;
} }
@ -748,26 +734,22 @@ void u2f_authenticate(const APDU *a)
const uint8_t sig_len = ecdsa_sig_to_der(sig, resp->sig); const uint8_t sig_len = ecdsa_sig_to_der(sig, resp->sig);
// Append OK // Append OK
memcpy(buf + sizeof(U2F_AUTHENTICATE_RESP) - memcpy(buf + sizeof(U2F_AUTHENTICATE_RESP) - U2F_MAX_EC_SIG_SIZE + sig_len,
U2F_MAX_EC_SIG_SIZE + sig_len,
"\x90\x00", 2); "\x90\x00", 2);
last_req_state = INIT; last_req_state = INIT;
dialog_timeout = 0; dialog_timeout = 0;
send_u2f_msg(buf, sizeof(U2F_AUTHENTICATE_RESP) - send_u2f_msg(
U2F_MAX_EC_SIG_SIZE + sig_len + buf, sizeof(U2F_AUTHENTICATE_RESP) - U2F_MAX_EC_SIG_SIZE + sig_len + 2);
2);
} }
} }
void send_u2f_error(const uint16_t err) void send_u2f_error(const uint16_t err) {
{
uint8_t data[2]; uint8_t data[2];
data[0] = err >> 8 & 0xFF; data[0] = err >> 8 & 0xFF;
data[1] = err & 0xFF; data[1] = err & 0xFF;
send_u2f_msg(data, 2); send_u2f_msg(data, 2);
} }
void send_u2f_msg(const uint8_t *data, const uint32_t len) void send_u2f_msg(const uint8_t *data, const uint32_t len) {
{
send_u2fhid_msg(U2FHID_MSG, data, len); send_u2fhid_msg(U2FHID_MSG, data, len);
} }

View File

@ -20,10 +20,10 @@
#ifndef __U2F_H__ #ifndef __U2F_H__
#define __U2F_H__ #define __U2F_H__
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include "u2f/u2f_hid.h" #include <stdint.h>
#include "trezor.h" #include "trezor.h"
#include "u2f/u2f_hid.h"
#define U2F_KEY_PATH 0x80553246 #define U2F_KEY_PATH 0x80553246

View File

@ -4,11 +4,9 @@
#include <stdint.h> #include <stdint.h>
const uint8_t U2F_ATT_PRIV_KEY[] = { const uint8_t U2F_ATT_PRIV_KEY[] = {
0x71, 0x26, 0xac, 0x2b, 0xf6, 0x44, 0xdc, 0x61, 0x71, 0x26, 0xac, 0x2b, 0xf6, 0x44, 0xdc, 0x61, 0x86, 0xad, 0x83,
0x86, 0xad, 0x83, 0xef, 0x1f, 0xcd, 0xf1, 0x2a, 0xef, 0x1f, 0xcd, 0xf1, 0x2a, 0x57, 0xb5, 0xcf, 0xa2, 0x00, 0x0b,
0x57, 0xb5, 0xcf, 0xa2, 0x00, 0x0b, 0x8a, 0xd0, 0x8a, 0xd0, 0x27, 0xe9, 0x56, 0xe8, 0x54, 0xc5, 0x0a, 0x8b};
0x27, 0xe9, 0x56, 0xe8, 0x54, 0xc5, 0x0a, 0x8b
};
const uint8_t U2F_ATT_CERT[] = { const uint8_t U2F_ATT_CERT[] = {
0x30, 0x82, 0x01, 0x18, 0x30, 0x81, 0xc0, 0x02, 0x09, 0x00, 0xb1, 0xd9, 0x30, 0x82, 0x01, 0x18, 0x30, 0x81, 0xc0, 0x02, 0x09, 0x00, 0xb1, 0xd9,

View File

@ -32,6 +32,7 @@ typedef struct {
// trezor-common/defs/webauthn/gen.py // trezor-common/defs/webauthn/gen.py
// do not edit manually // do not edit manually
// clang-format off
static const U2FWellKnown u2f_well_known[] = { static const U2FWellKnown u2f_well_known[] = {
{ {
// U2F: https://bitbucket.org // U2F: https://bitbucket.org
@ -144,5 +145,6 @@ static const U2FWellKnown u2f_well_known[] = {
"demo.yubico.com" "demo.yubico.com"
}, },
}; };
// clang-format on
#endif // U2F_KNOWNAPPS_INCLUDED #endif // U2F_KNOWNAPPS_INCLUDED

View File

@ -21,15 +21,13 @@
#include "usb.h" #include "usb.h"
#include "debug.h"
#include "messages.h" #include "messages.h"
#include "timer.h" #include "timer.h"
#include "debug.h"
static volatile char tiny = 0; static volatile char tiny = 0;
void usbInit(void) { void usbInit(void) { emulatorSocketInit(); }
emulatorSocketInit();
}
#if DEBUG_LINK #if DEBUG_LINK
#define _ISDBG (((iface == 1) ? 'd' : 'n')) #define _ISDBG (((iface == 1) ? 'd' : 'n'))

View File

@ -17,23 +17,22 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/hid.h> #include <libopencm3/usb/hid.h>
#include <libopencm3/usb/usbd.h>
#include "trezor.h" #include "config.h"
#include "usb.h"
#include "debug.h" #include "debug.h"
#include "messages.h" #include "messages.h"
#include "u2f.h"
#include "config.h"
#include "util.h"
#include "timer.h" #include "timer.h"
#include "trezor.h"
#include "u2f.h"
#include "usb.h"
#include "util.h"
#include "usb21_standard.h" #include "usb21_standard.h"
#include "webusb.h" #include "webusb.h"
#include "winusb.h" #include "winusb.h"
#define USB_INTERFACE_INDEX_MAIN 0 #define USB_INTERFACE_INDEX_MAIN 0
#if DEBUG_LINK #if DEBUG_LINK
#define USB_INTERFACE_INDEX_DEBUG 1 #define USB_INTERFACE_INDEX_DEBUG 1
@ -59,7 +58,7 @@
X(SERIAL_NUMBER, config_uuid_str) \ X(SERIAL_NUMBER, config_uuid_str) \
X(INTERFACE_MAIN, "TREZOR Interface") \ X(INTERFACE_MAIN, "TREZOR Interface") \
X(INTERFACE_DEBUG, "TREZOR Debug Link Interface") \ X(INTERFACE_DEBUG, "TREZOR Debug Link Interface") \
X(INTERFACE_U2F, "TREZOR U2F Interface") \ X(INTERFACE_U2F, "TREZOR U2F Interface")
#define X(name, value) USB_STRING_##name, #define X(name, value) USB_STRING_##name,
enum { enum {
@ -69,9 +68,7 @@ enum {
#undef X #undef X
#define X(name, value) value, #define X(name, value) value,
static const char *usb_strings[] = { static const char *usb_strings[] = {USB_STRINGS};
USB_STRINGS
};
#undef X #undef X
static const struct usb_device_descriptor dev_descr = { static const struct usb_device_descriptor dev_descr = {
@ -116,8 +113,9 @@ static const struct {
uint8_t bReportDescriptorType; uint8_t bReportDescriptorType;
uint16_t wDescriptorLength; uint16_t wDescriptorLength;
} __attribute__((packed)) hid_report_u2f; } __attribute__((packed)) hid_report_u2f;
} __attribute__((packed)) hid_function_u2f = { } __attribute__((packed))
.hid_descriptor_u2f = { hid_function_u2f = {.hid_descriptor_u2f =
{
.bLength = sizeof(hid_function_u2f), .bLength = sizeof(hid_function_u2f),
.bDescriptorType = USB_DT_HID, .bDescriptorType = USB_DT_HID,
.bcdHID = 0x0111, .bcdHID = 0x0111,
@ -127,17 +125,18 @@ static const struct {
.hid_report_u2f = { .hid_report_u2f = {
.bReportDescriptorType = USB_DT_REPORT, .bReportDescriptorType = USB_DT_REPORT,
.wDescriptorLength = sizeof(hid_report_descriptor_u2f), .wDescriptorLength = sizeof(hid_report_descriptor_u2f),
} }};
};
static const struct usb_endpoint_descriptor hid_endpoints_u2f[2] = {{ static const struct usb_endpoint_descriptor hid_endpoints_u2f[2] = {
{
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = ENDPOINT_ADDRESS_U2F_IN, .bEndpointAddress = ENDPOINT_ADDRESS_U2F_IN,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.wMaxPacketSize = 64, .wMaxPacketSize = 64,
.bInterval = 1, .bInterval = 1,
}, { },
{
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = ENDPOINT_ADDRESS_U2F_OUT, .bEndpointAddress = ENDPOINT_ADDRESS_U2F_OUT,
@ -162,14 +161,16 @@ static const struct usb_interface_descriptor hid_iface_u2f[] = {{
}}; }};
#if DEBUG_LINK #if DEBUG_LINK
static const struct usb_endpoint_descriptor webusb_endpoints_debug[2] = {{ static const struct usb_endpoint_descriptor webusb_endpoints_debug[2] = {
{
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_IN, .bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_IN,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.wMaxPacketSize = 64, .wMaxPacketSize = 64,
.bInterval = 1, .bInterval = 1,
}, { },
{
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_OUT, .bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_OUT,
@ -195,14 +196,16 @@ static const struct usb_interface_descriptor webusb_iface_debug[] = {{
#endif #endif
static const struct usb_endpoint_descriptor webusb_endpoints_main[2] = {{ static const struct usb_endpoint_descriptor webusb_endpoints_main[2] = {
{
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = ENDPOINT_ADDRESS_MAIN_IN, .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_IN,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.wMaxPacketSize = 64, .wMaxPacketSize = 64,
.bInterval = 1, .bInterval = 1,
}, { },
{
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = ENDPOINT_ADDRESS_MAIN_OUT, .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_OUT,
@ -226,18 +229,20 @@ static const struct usb_interface_descriptor webusb_iface_main[] = {{
.extralen = 0, .extralen = 0,
}}; }};
// Windows are strict about interfaces appearing // Windows are strict about interfaces appearing
// in correct order // in correct order
static const struct usb_interface ifaces[] = {{ static const struct usb_interface ifaces[] = {
{
.num_altsetting = 1, .num_altsetting = 1,
.altsetting = webusb_iface_main, .altsetting = webusb_iface_main,
#if DEBUG_LINK #if DEBUG_LINK
}, { },
{
.num_altsetting = 1, .num_altsetting = 1,
.altsetting = webusb_iface_debug, .altsetting = webusb_iface_debug,
#endif #endif
}, { },
{
.num_altsetting = 1, .num_altsetting = 1,
.altsetting = hid_iface_u2f, .altsetting = hid_iface_u2f,
}}; }};
@ -254,16 +259,16 @@ static const struct usb_config_descriptor config = {
.interface = ifaces, .interface = ifaces,
}; };
static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete) static int hid_control_request(usbd_device *dev, struct usb_setup_data *req,
{ uint8_t **buf, uint16_t *len,
usbd_control_complete_callback *complete) {
(void)complete; (void)complete;
(void)dev; (void)dev;
wait_random(); wait_random();
if ((req->bmRequestType != 0x81) || if ((req->bmRequestType != 0x81) ||
(req->bRequest != USB_REQ_GET_DESCRIPTOR) || (req->bRequest != USB_REQ_GET_DESCRIPTOR) || (req->wValue != 0x2200))
(req->wValue != 0x2200))
return 0; return 0;
debugLog(0, "", "hid_control_request u2f"); debugLog(0, "", "hid_control_request u2f");
@ -274,11 +279,11 @@ static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uin
static volatile char tiny = 0; static volatile char tiny = 0;
static void main_rx_callback(usbd_device *dev, uint8_t ep) static void main_rx_callback(usbd_device *dev, uint8_t ep) {
{
(void)ep; (void)ep;
static CONFIDENTIAL uint8_t buf[64] __attribute__((aligned(4))); static CONFIDENTIAL uint8_t buf[64] __attribute__((aligned(4)));
if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_MAIN_OUT, buf, 64) != 64) return; if (usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_MAIN_OUT, buf, 64) != 64)
return;
debugLog(0, "", "main_rx_callback"); debugLog(0, "", "main_rx_callback");
if (!tiny) { if (!tiny) {
msg_read(buf, 64); msg_read(buf, 64);
@ -287,8 +292,7 @@ static void main_rx_callback(usbd_device *dev, uint8_t ep)
} }
} }
static void u2f_rx_callback(usbd_device *dev, uint8_t ep) static void u2f_rx_callback(usbd_device *dev, uint8_t ep) {
{
(void)ep; (void)ep;
static CONFIDENTIAL uint8_t buf[64] __attribute__((aligned(4))); static CONFIDENTIAL uint8_t buf[64] __attribute__((aligned(4)));
@ -298,11 +302,11 @@ static void u2f_rx_callback(usbd_device *dev, uint8_t ep)
} }
#if DEBUG_LINK #if DEBUG_LINK
static void debug_rx_callback(usbd_device *dev, uint8_t ep) static void debug_rx_callback(usbd_device *dev, uint8_t ep) {
{
(void)ep; (void)ep;
static uint8_t buf[64] __attribute__((aligned(4))); static uint8_t buf[64] __attribute__((aligned(4)));
if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_DEBUG_OUT, buf, 64) != 64) return; if (usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_DEBUG_OUT, buf, 64) != 64)
return;
debugLog(0, "", "debug_rx_callback"); debugLog(0, "", "debug_rx_callback");
if (!tiny) { if (!tiny) {
msg_debug_read(buf, 64); msg_debug_read(buf, 64);
@ -312,43 +316,47 @@ static void debug_rx_callback(usbd_device *dev, uint8_t ep)
} }
#endif #endif
static void set_config(usbd_device *dev, uint16_t wValue) static void set_config(usbd_device *dev, uint16_t wValue) {
{
(void)wValue; (void)wValue;
usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64,
usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, main_rx_callback); 0);
usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64,
usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, u2f_rx_callback); main_rx_callback);
usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64,
0);
usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64,
u2f_rx_callback);
#if DEBUG_LINK #if DEBUG_LINK
usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64,
usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, debug_rx_callback); 0);
usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_OUT, USB_ENDPOINT_ATTR_INTERRUPT,
64, debug_rx_callback);
#endif #endif
usbd_register_control_callback( usbd_register_control_callback(
dev, dev, USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE,
USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE, USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, hid_control_request);
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
hid_control_request);
} }
static usbd_device *usbd_dev = NULL; static usbd_device *usbd_dev = NULL;
static uint8_t usbd_control_buffer[256] __attribute__((aligned(2))); static uint8_t usbd_control_buffer[256] __attribute__((aligned(2)));
static const struct usb_device_capability_descriptor *capabilities[] = { static const struct usb_device_capability_descriptor *capabilities[] = {
(const struct usb_device_capability_descriptor*)&webusb_platform_capability_descriptor_no_landing_page, (const struct usb_device_capability_descriptor
*)&webusb_platform_capability_descriptor_no_landing_page,
}; };
static const struct usb_bos_descriptor bos_descriptor = { static const struct usb_bos_descriptor bos_descriptor = {
.bLength = USB_DT_BOS_SIZE, .bLength = USB_DT_BOS_SIZE,
.bDescriptorType = USB_DT_BOS, .bDescriptorType = USB_DT_BOS,
.bNumDeviceCaps = sizeof(capabilities) / sizeof(capabilities[0]), .bNumDeviceCaps = sizeof(capabilities) / sizeof(capabilities[0]),
.capabilities = capabilities .capabilities = capabilities};
};
void usbInit(void) void usbInit(void) {
{ usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings,
usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, sizeof(usb_strings) / sizeof(*usb_strings), usbd_control_buffer, sizeof(usbd_control_buffer)); sizeof(usb_strings) / sizeof(*usb_strings),
usbd_control_buffer, sizeof(usbd_control_buffer));
usbd_register_set_config_callback(usbd_dev, set_config); usbd_register_set_config_callback(usbd_dev, set_config);
usb21_setup(usbd_dev, &bos_descriptor); usb21_setup(usbd_dev, &bos_descriptor);
static const char *origin_url = "trezor.io/start"; static const char *origin_url = "trezor.io/start";
@ -358,8 +366,7 @@ void usbInit(void)
winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN); winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN);
} }
void usbPoll(void) void usbPoll(void) {
{
if (usbd_dev == NULL) { if (usbd_dev == NULL) {
return; return;
} }
@ -370,23 +377,28 @@ void usbPoll(void)
// write pending data // write pending data
data = msg_out_data(); data = msg_out_data();
if (data) { if (data) {
while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_MAIN_IN, data, 64) != 64 ) {} while (usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_MAIN_IN, data, 64) !=
64) {
}
} }
data = u2f_out_data(); data = u2f_out_data();
if (data) { if (data) {
while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_U2F_IN, data, 64) != 64 ) {} while (usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_U2F_IN, data, 64) !=
64) {
}
} }
#if DEBUG_LINK #if DEBUG_LINK
// write pending debug data // write pending debug data
data = msg_debug_out_data(); data = msg_debug_out_data();
if (data) { if (data) {
while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_DEBUG_IN, data, 64) != 64 ) {} while (usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_DEBUG_IN, data,
64) != 64) {
}
} }
#endif #endif
} }
void usbReconnect(void) void usbReconnect(void) {
{
if (usbd_dev != NULL) { if (usbd_dev != NULL) {
usbd_disconnect(usbd_dev, 1); usbd_disconnect(usbd_dev, 1);
delay(1000); delay(1000);
@ -394,15 +406,13 @@ void usbReconnect(void)
} }
} }
char usbTiny(char set) char usbTiny(char set) {
{
char old = tiny; char old = tiny;
tiny = set; tiny = set;
return old; return old;
} }
void usbSleep(uint32_t millis) void usbSleep(uint32_t millis) {
{
uint32_t start = timer_ms(); uint32_t start = timer_ms();
while ((timer_ms() - start) < millis) { while ((timer_ms() - start) < millis) {

37
flash.c
View File

@ -17,8 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h>
#include <libopencm3/stm32/flash.h> #include <libopencm3/stm32/flash.h>
#include <string.h>
#include "common.h" #include "common.h"
#include "flash.h" #include "flash.h"
@ -41,28 +41,23 @@ static const uint32_t FLASH_SECTOR_TABLE[FLASH_SECTOR_COUNT + 1] = {
[12] = 0x08100000, // last element - not a valid sector [12] = 0x08100000, // last element - not a valid sector
}; };
static secbool flash_check_success(uint32_t status) static secbool flash_check_success(uint32_t status) {
{ return (status & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR |
return (status & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) ? secfalse : sectrue; FLASH_SR_WRPERR))
? secfalse
: sectrue;
} }
void flash_init(void) void flash_init(void) {}
{
}
secbool flash_unlock_write(void) secbool flash_unlock_write(void) {
{
svc_flash_unlock(); svc_flash_unlock();
return sectrue; return sectrue;
} }
secbool flash_lock_write(void) secbool flash_lock_write(void) { return flash_check_success(svc_flash_lock()); }
{
return flash_check_success(svc_flash_lock());
}
const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size) const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size) {
{
if (sector >= FLASH_SECTOR_COUNT) { if (sector >= FLASH_SECTOR_COUNT) {
return NULL; return NULL;
} }
@ -74,14 +69,14 @@ const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size)
return (const void *)FLASH_PTR(addr); return (const void *)FLASH_PTR(addr);
} }
secbool flash_erase(uint8_t sector) secbool flash_erase(uint8_t sector) {
{
ensure(flash_unlock_write(), NULL); ensure(flash_unlock_write(), NULL);
svc_flash_erase_sector(sector); svc_flash_erase_sector(sector);
ensure(flash_lock_write(), NULL); ensure(flash_lock_write(), NULL);
// Check whether the sector was really deleted (contains only 0xFF). // Check whether the sector was really deleted (contains only 0xFF).
const uint32_t addr_start = FLASH_SECTOR_TABLE[sector], addr_end = FLASH_SECTOR_TABLE[sector + 1]; const uint32_t addr_start = FLASH_SECTOR_TABLE[sector],
addr_end = FLASH_SECTOR_TABLE[sector + 1];
for (uint32_t addr = addr_start; addr < addr_end; addr += 4) { for (uint32_t addr = addr_start; addr < addr_end; addr += 4) {
if (*((const uint32_t *)FLASH_PTR(addr)) != 0xFFFFFFFF) { if (*((const uint32_t *)FLASH_PTR(addr)) != 0xFFFFFFFF) {
return secfalse; return secfalse;
@ -90,8 +85,7 @@ secbool flash_erase(uint8_t sector)
return sectrue; return sectrue;
} }
secbool flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data) secbool flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data) {
{
uint8_t *address = (uint8_t *)flash_get_address(sector, offset, 1); uint8_t *address = (uint8_t *)flash_get_address(sector, offset, 1);
if (address == NULL) { if (address == NULL) {
return secfalse; return secfalse;
@ -111,8 +105,7 @@ secbool flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data)
return sectrue; return sectrue;
} }
secbool flash_write_word(uint8_t sector, uint32_t offset, uint32_t data) secbool flash_write_word(uint8_t sector, uint32_t offset, uint32_t data) {
{
uint32_t *address = (uint32_t *)flash_get_address(sector, offset, 4); uint32_t *address = (uint32_t *)flash_get_address(sector, offset, 4);
if (address == NULL) { if (address == NULL) {
return secfalse; return secfalse;

View File

@ -26,12 +26,15 @@
#define FLASH_SECTOR_COUNT 24 #define FLASH_SECTOR_COUNT 24
// note: FLASH_SR_RDERR is STM32F42xxx and STM32F43xxx specific (STM32F427) (reference RM0090 section 3.7.5) // note: FLASH_SR_RDERR is STM32F42xxx and STM32F43xxx specific (STM32F427)
// (reference RM0090 section 3.7.5)
#ifndef STM32F427xx #ifndef STM32F427xx
#define FLASH_SR_RDERR 0 #define FLASH_SR_RDERR 0
#endif #endif
#define FLASH_STATUS_ALL_FLAGS (FLASH_SR_RDERR | FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR | FLASH_SR_WRPERR | FLASH_SR_SOP | FLASH_SR_EOP) #define FLASH_STATUS_ALL_FLAGS \
(FLASH_SR_RDERR | FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR | \
FLASH_SR_WRPERR | FLASH_SR_SOP | FLASH_SR_EOP)
void flash_init(void); void flash_init(void);

View File

@ -22,22 +22,30 @@
#include "layout.h" #include "layout.h"
#include "oled.h" #include "oled.h"
void layoutButtonNo(const char *btnNo) void layoutButtonNo(const char *btnNo) {
{
oledDrawString(1, OLED_HEIGHT - 8, "\x15", FONT_STANDARD); oledDrawString(1, OLED_HEIGHT - 8, "\x15", FONT_STANDARD);
oledDrawString(fontCharWidth(FONT_STANDARD, '\x15') + 3, OLED_HEIGHT - 8, btnNo, FONT_STANDARD); oledDrawString(fontCharWidth(FONT_STANDARD, '\x15') + 3, OLED_HEIGHT - 8,
oledInvert(0, OLED_HEIGHT - 9, fontCharWidth(FONT_STANDARD, '\x15') + oledStringWidth(btnNo, FONT_STANDARD) + 2, OLED_HEIGHT - 1); btnNo, FONT_STANDARD);
oledInvert(0, OLED_HEIGHT - 9,
fontCharWidth(FONT_STANDARD, '\x15') +
oledStringWidth(btnNo, FONT_STANDARD) + 2,
OLED_HEIGHT - 1);
} }
void layoutButtonYes(const char *btnYes) void layoutButtonYes(const char *btnYes) {
{ oledDrawString(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 1,
oledDrawString(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 1, OLED_HEIGHT - 8, "\x06", FONT_STANDARD); OLED_HEIGHT - 8, "\x06", FONT_STANDARD);
oledDrawStringRight(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 3, OLED_HEIGHT - 8, btnYes, FONT_STANDARD); oledDrawStringRight(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 3,
oledInvert(OLED_WIDTH - oledStringWidth(btnYes, FONT_STANDARD) - fontCharWidth(FONT_STANDARD, '\x06') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); OLED_HEIGHT - 8, btnYes, FONT_STANDARD);
oledInvert(OLED_WIDTH - oledStringWidth(btnYes, FONT_STANDARD) -
fontCharWidth(FONT_STANDARD, '\x06') - 4,
OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1);
} }
void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes,
{ const char *desc, const char *line1, const char *line2,
const char *line3, const char *line4, const char *line5,
const char *line6) {
int left = 0; int left = 0;
oledClear(); oledClear();
if (icon) { if (icon) {
@ -49,7 +57,8 @@ void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, con
if (line3) oledDrawString(left, 2 * 9, line3, FONT_STANDARD); if (line3) oledDrawString(left, 2 * 9, line3, FONT_STANDARD);
if (line4) oledDrawString(left, 3 * 9, line4, FONT_STANDARD); if (line4) oledDrawString(left, 3 * 9, line4, FONT_STANDARD);
if (desc) { if (desc) {
oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 2 * 9 - 1, desc, FONT_STANDARD); oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 2 * 9 - 1, desc,
FONT_STANDARD);
if (btnYes || btnNo) { if (btnYes || btnNo) {
oledHLine(OLED_HEIGHT - 21); oledHLine(OLED_HEIGHT - 21);
} }
@ -69,8 +78,7 @@ void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, con
oledRefresh(); oledRefresh();
} }
void layoutProgressUpdate(bool refresh) void layoutProgressUpdate(bool refresh) {
{
static uint8_t step = 0; static uint8_t step = 0;
switch (step) { switch (step) {
case 0: case 0:
@ -92,8 +100,7 @@ void layoutProgressUpdate(bool refresh)
} }
} }
void layoutProgress(const char *desc, int permil) void layoutProgress(const char *desc, int permil) {
{
oledClear(); oledClear();
layoutProgressUpdate(false); layoutProgressUpdate(false);
// progressbar // progressbar

View File

@ -20,13 +20,16 @@
#ifndef __LAYOUT_H__ #ifndef __LAYOUT_H__
#define __LAYOUT_H__ #define __LAYOUT_H__
#include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h>
#include "bitmaps.h" #include "bitmaps.h"
void layoutButtonNo(const char *btnNo); void layoutButtonNo(const char *btnNo);
void layoutButtonYes(const char *btnYes); void layoutButtonYes(const char *btnYes);
void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6); void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes,
const char *desc, const char *line1, const char *line2,
const char *line3, const char *line4, const char *line5,
const char *line6);
void layoutProgressUpdate(bool refresh); void layoutProgressUpdate(bool refresh);
void layoutProgress(const char *desc, int permil); void layoutProgress(const char *desc, int permil);

View File

@ -17,32 +17,37 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "memory.h"
#include <libopencm3/stm32/flash.h> #include <libopencm3/stm32/flash.h>
#include <stdint.h> #include <stdint.h>
#include "memory.h"
#include "sha2.h" #include "sha2.h"
#define FLASH_OPTION_BYTES_1 (*(const uint64_t *)0x1FFFC000) #define FLASH_OPTION_BYTES_1 (*(const uint64_t *)0x1FFFC000)
#define FLASH_OPTION_BYTES_2 (*(const uint64_t *)0x1FFFC008) #define FLASH_OPTION_BYTES_2 (*(const uint64_t *)0x1FFFC008)
void memory_protect(void) void memory_protect(void) {
{
#if MEMORY_PROTECT #if MEMORY_PROTECT
// Reference STM32F205 Flash programming manual revision 5 http://www.st.com/resource/en/programming_manual/cd00233952.pdf // Reference STM32F205 Flash programming manual revision 5
// Section 2.6 Option bytes // http://www.st.com/resource/en/programming_manual/cd00233952.pdf Section 2.6
// set RDP level 2 WRP for sectors 0 and 1 flash option control register matches // Option bytes
if (((FLASH_OPTION_BYTES_1 & 0xFFEC) == 0xCCEC) && ((FLASH_OPTION_BYTES_2 & 0xFFF) == 0xFFC) && (FLASH_OPTCR == 0x0FFCCCED)) { // set RDP level 2 WRP for sectors 0 and
// 1 flash option control register matches
if (((FLASH_OPTION_BYTES_1 & 0xFFEC) == 0xCCEC) &&
((FLASH_OPTION_BYTES_2 & 0xFFF) == 0xFFC) &&
(FLASH_OPTCR == 0x0FFCCCED)) {
return; // already set up correctly - bail out return; // already set up correctly - bail out
} }
for (int i = FLASH_STORAGE_SECTOR_FIRST; i <= FLASH_STORAGE_SECTOR_LAST; i++) { for (int i = FLASH_STORAGE_SECTOR_FIRST; i <= FLASH_STORAGE_SECTOR_LAST;
i++) {
flash_erase_sector(i, FLASH_CR_PROGRAM_X32); flash_erase_sector(i, FLASH_CR_PROGRAM_X32);
} }
flash_unlock_option_bytes(); flash_unlock_option_bytes();
// Section 2.8.6 Flash option control register (FLASH_OPTCR) // Section 2.8.6 Flash option control register (FLASH_OPTCR)
// Bits 31:28 Reserved, must be kept cleared. // Bits 31:28 Reserved, must be kept cleared.
// Bits 27:16 nWRP: Not write protect: write protect bootloader code in flash main memory sectors 0 and 1 (Section 2.3; table 2) // Bits 27:16 nWRP: Not write protect: write protect bootloader code in
// Bits 15:8 RDP: Read protect: level 2 chip read protection active // flash main memory sectors 0 and 1 (Section 2.3; table 2) Bits 15:8 RDP:
// Bits 7:5 USER: User option bytes: no reset on standby, no reset on stop, software watchdog // Read protect: level 2 chip read protection active Bits 7:5 USER: User
// option bytes: no reset on standby, no reset on stop, software watchdog
// Bit 4 Reserved, must be kept cleared. // Bit 4 Reserved, must be kept cleared.
// Bits 3:2 BOR_LEV: BOR reset Level: BOR off // Bits 3:2 BOR_LEV: BOR reset Level: BOR off
// Bit 1 OPTSTRT: Option start: ignored by flash_program_option_bytes // Bit 1 OPTSTRT: Option start: ignored by flash_program_option_bytes
@ -62,15 +67,13 @@ void memory_protect(void)
// from OPTION_BYTES and not form FLASH_OPCTR register. // from OPTION_BYTES and not form FLASH_OPCTR register.
// //
// Read protection is unaffected and always stays locked to the desired value. // Read protection is unaffected and always stays locked to the desired value.
void memory_write_unlock(void) void memory_write_unlock(void) {
{
flash_unlock_option_bytes(); flash_unlock_option_bytes();
flash_program_option_bytes(0x0FFFCCEC); flash_program_option_bytes(0x0FFFCCEC);
flash_lock_option_bytes(); flash_lock_option_bytes();
} }
int memory_bootloader_hash(uint8_t *hash) int memory_bootloader_hash(uint8_t *hash) {
{
sha256_Raw(FLASH_PTR(FLASH_BOOT_START), FLASH_BOOT_LEN, hash); sha256_Raw(FLASH_PTR(FLASH_BOOT_START), FLASH_BOOT_LEN, hash);
sha256_Raw(hash, 32, hash); sha256_Raw(hash, 32, hash);
return 32; return 32;

View File

@ -24,10 +24,12 @@
#define NORCOW_SECTOR_COUNT 2 #define NORCOW_SECTOR_COUNT 2
#define NORCOW_SECTOR_SIZE (16 * 1024) #define NORCOW_SECTOR_SIZE (16 * 1024)
#define NORCOW_SECTORS {2, 3} #define NORCOW_SECTORS \
{ 2, 3 }
/* /*
* The length of the sector header in bytes. The header is preserved between sector erasures. * The length of the sector header in bytes. The header is preserved between
* sector erasures.
*/ */
#define NORCOW_HEADER_LEN (0) #define NORCOW_HEADER_LEN (0)

118
oled.c
View File

@ -22,9 +22,9 @@
#include <string.h> #include <string.h>
#include "memzero.h"
#include "oled.h" #include "oled.h"
#include "util.h" #include "util.h"
#include "memzero.h"
#define OLED_SETCONTRAST 0x81 #define OLED_SETCONTRAST 0x81
#define OLED_DISPLAYALLON_RESUME 0xA4 #define OLED_DISPLAYALLON_RESUME 0xA4
@ -76,8 +76,7 @@ static bool is_debug_link = 0;
/* /*
* Draws a white pixel at x, y * Draws a white pixel at x, y
*/ */
void oledDrawPixel(int x, int y) void oledDrawPixel(int x, int y) {
{
if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) { if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) {
return; return;
} }
@ -87,8 +86,7 @@ void oledDrawPixel(int x, int y)
/* /*
* Clears pixel at x, y * Clears pixel at x, y
*/ */
void oledClearPixel(int x, int y) void oledClearPixel(int x, int y) {
{
if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) { if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) {
return; return;
} }
@ -98,8 +96,7 @@ void oledClearPixel(int x, int y)
/* /*
* Inverts pixel at x, y * Inverts pixel at x, y
*/ */
void oledInvertPixel(int x, int y) void oledInvertPixel(int x, int y) {
{
if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) { if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) {
return; return;
} }
@ -110,23 +107,22 @@ void oledInvertPixel(int x, int y)
/* /*
* Send a block of data via the SPI bus. * Send a block of data via the SPI bus.
*/ */
static inline void SPISend(uint32_t base, const uint8_t *data, int len) static inline void SPISend(uint32_t base, const uint8_t *data, int len) {
{
delay(1); delay(1);
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
spi_send(base, data[i]); spi_send(base, data[i]);
} }
while (!(SPI_SR(base) & SPI_SR_TXE)); while (!(SPI_SR(base) & SPI_SR_TXE))
while ((SPI_SR(base) & SPI_SR_BSY)); ;
while ((SPI_SR(base) & SPI_SR_BSY))
;
} }
/* /*
* Initialize the display. * Initialize the display.
*/ */
void oledInit() void oledInit() {
{ static const uint8_t s[25] = {OLED_DISPLAYOFF,
static const uint8_t s[25] = {
OLED_DISPLAYOFF,
OLED_SETDISPLAYCLOCKDIV, OLED_SETDISPLAYCLOCKDIV,
0x80, 0x80,
OLED_SETMULTIPLEX, OLED_SETMULTIPLEX,
@ -150,8 +146,7 @@ void oledInit()
0x40, 0x40,
OLED_DISPLAYALLON_RESUME, OLED_DISPLAYALLON_RESUME,
OLED_NORMALDISPLAY, OLED_NORMALDISPLAY,
OLED_DISPLAYON OLED_DISPLAYON};
};
gpio_clear(OLED_DC_PORT, OLED_DC_PIN); // set to CMD gpio_clear(OLED_DC_PORT, OLED_DC_PIN); // set to CMD
gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect
@ -176,18 +171,24 @@ void oledInit()
/* /*
* Clears the display buffer (sets all pixels to black) * Clears the display buffer (sets all pixels to black)
*/ */
void oledClear() void oledClear() { memzero(_oledbuffer, sizeof(_oledbuffer)); }
{
memzero(_oledbuffer, sizeof(_oledbuffer));
}
void oledInvertDebugLink() void oledInvertDebugLink() {
{
if (is_debug_link) { if (is_debug_link) {
oledInvertPixel(OLED_WIDTH - 5, 0); oledInvertPixel(OLED_WIDTH - 4, 0); oledInvertPixel(OLED_WIDTH - 3, 0); oledInvertPixel(OLED_WIDTH - 2, 0); oledInvertPixel(OLED_WIDTH - 1, 0); oledInvertPixel(OLED_WIDTH - 5, 0);
oledInvertPixel(OLED_WIDTH - 4, 1); oledInvertPixel(OLED_WIDTH - 3, 1); oledInvertPixel(OLED_WIDTH - 2, 1); oledInvertPixel(OLED_WIDTH - 1, 1); oledInvertPixel(OLED_WIDTH - 4, 0);
oledInvertPixel(OLED_WIDTH - 3, 2); oledInvertPixel(OLED_WIDTH - 2, 2); oledInvertPixel(OLED_WIDTH - 1, 2); oledInvertPixel(OLED_WIDTH - 3, 0);
oledInvertPixel(OLED_WIDTH - 2, 3); oledInvertPixel(OLED_WIDTH - 1, 3); oledInvertPixel(OLED_WIDTH - 2, 0);
oledInvertPixel(OLED_WIDTH - 1, 0);
oledInvertPixel(OLED_WIDTH - 4, 1);
oledInvertPixel(OLED_WIDTH - 3, 1);
oledInvertPixel(OLED_WIDTH - 2, 1);
oledInvertPixel(OLED_WIDTH - 1, 1);
oledInvertPixel(OLED_WIDTH - 3, 2);
oledInvertPixel(OLED_WIDTH - 2, 2);
oledInvertPixel(OLED_WIDTH - 1, 2);
oledInvertPixel(OLED_WIDTH - 2, 3);
oledInvertPixel(OLED_WIDTH - 1, 3);
oledInvertPixel(OLED_WIDTH - 1, 4); oledInvertPixel(OLED_WIDTH - 1, 4);
} }
} }
@ -199,9 +200,10 @@ void oledInvertDebugLink()
* not the content of the display. * not the content of the display.
*/ */
#if !EMULATOR #if !EMULATOR
void oledRefresh() void oledRefresh() {
{ static const uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00,
static const uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00, OLED_SETHIGHCOLUMN | 0x00, OLED_SETSTARTLINE | 0x00}; OLED_SETHIGHCOLUMN | 0x00,
OLED_SETSTARTLINE | 0x00};
// draw triangle in upper right corner // draw triangle in upper right corner
oledInvertDebugLink(); oledInvertDebugLink();
@ -221,24 +223,18 @@ void oledRefresh()
} }
#endif #endif
const uint8_t *oledGetBuffer() const uint8_t *oledGetBuffer() { return _oledbuffer; }
{
return _oledbuffer;
}
void oledSetDebugLink(bool set) void oledSetDebugLink(bool set) {
{
is_debug_link = set; is_debug_link = set;
oledRefresh(); oledRefresh();
} }
void oledSetBuffer(uint8_t *buf) void oledSetBuffer(uint8_t *buf) {
{
memcpy(_oledbuffer, buf, sizeof(_oledbuffer)); memcpy(_oledbuffer, buf, sizeof(_oledbuffer));
} }
void oledDrawChar(int x, int y, char c, int font) void oledDrawChar(int x, int y, char c, int font) {
{
if (x >= OLED_WIDTH || y >= OLED_HEIGHT || y <= -FONT_HEIGHT) { if (x >= OLED_WIDTH || y >= OLED_HEIGHT || y <= -FONT_HEIGHT) {
return; return;
} }
@ -257,7 +253,8 @@ void oledDrawChar(int x, int y, char c, int font)
if (zoom <= 1) { if (zoom <= 1) {
oledDrawPixel(x + xo, y + yo); oledDrawPixel(x + xo, y + yo);
} else { } else {
oledBox(x + xo * zoom, y + yo * zoom, x + (xo + 1) * zoom - 1, y + (yo + 1) * zoom - 1, true); oledBox(x + xo * zoom, y + yo * zoom, x + (xo + 1) * zoom - 1,
y + (yo + 1) * zoom - 1, true);
} }
} }
} }
@ -287,8 +284,7 @@ int oledStringWidth(const char *text, int font) {
return l; return l;
} }
void oledDrawString(int x, int y, const char* text, int font) void oledDrawString(int x, int y, const char *text, int font) {
{
if (!text) return; if (!text) return;
int l = 0; int l = 0;
int size = (font & FONT_DOUBLE ? 2 : 1); int size = (font & FONT_DOUBLE ? 2 : 1);
@ -301,20 +297,17 @@ void oledDrawString(int x, int y, const char* text, int font)
} }
} }
void oledDrawStringCenter(int x, int y, const char* text, int font) void oledDrawStringCenter(int x, int y, const char *text, int font) {
{
x = x - oledStringWidth(text, font) / 2; x = x - oledStringWidth(text, font) / 2;
oledDrawString(x, y, text, font); oledDrawString(x, y, text, font);
} }
void oledDrawStringRight(int x, int y, const char* text, int font) void oledDrawStringRight(int x, int y, const char *text, int font) {
{
x -= oledStringWidth(text, font); x -= oledStringWidth(text, font);
oledDrawString(x, y, text, font); oledDrawString(x, y, text, font);
} }
void oledDrawBitmap(int x, int y, const BITMAP *bmp) void oledDrawBitmap(int x, int y, const BITMAP *bmp) {
{
for (int i = 0; i < bmp->width; i++) { for (int i = 0; i < bmp->width; i++) {
for (int j = 0; j < bmp->height; j++) { for (int j = 0; j < bmp->height; j++) {
if (bmp->data[(i / 8) + j * bmp->width / 8] & (1 << (7 - i % 8))) { if (bmp->data[(i / 8) + j * bmp->width / 8] & (1 << (7 - i % 8))) {
@ -329,8 +322,7 @@ void oledDrawBitmap(int x, int y, const BITMAP *bmp)
/* /*
* Inverts box between (x1,y1) and (x2,y2) inclusive. * Inverts box between (x1,y1) and (x2,y2) inclusive.
*/ */
void oledInvert(int x1, int y1, int x2, int y2) void oledInvert(int x1, int y1, int x2, int y2) {
{
x1 = MAX(x1, 0); x1 = MAX(x1, 0);
y1 = MAX(y1, 0); y1 = MAX(y1, 0);
x2 = MIN(x2, OLED_WIDTH - 1); x2 = MIN(x2, OLED_WIDTH - 1);
@ -345,8 +337,7 @@ void oledInvert(int x1, int y1, int x2, int y2)
/* /*
* Draw a filled rectangle. * Draw a filled rectangle.
*/ */
void oledBox(int x1, int y1, int x2, int y2, bool set) void oledBox(int x1, int y1, int x2, int y2, bool set) {
{
x1 = MAX(x1, 0); x1 = MAX(x1, 0);
y1 = MAX(y1, 0); y1 = MAX(y1, 0);
x2 = MIN(x2, OLED_WIDTH - 1); x2 = MIN(x2, OLED_WIDTH - 1);
@ -370,8 +361,7 @@ void oledHLine(int y) {
/* /*
* Draw a rectangle frame. * Draw a rectangle frame.
*/ */
void oledFrame(int x1, int y1, int x2, int y2) void oledFrame(int x1, int y1, int x2, int y2) {
{
for (int x = x1; x <= x2; x++) { for (int x = x1; x <= x2; x++) {
oledDrawPixel(x, y1); oledDrawPixel(x, y1);
oledDrawPixel(x, y2); oledDrawPixel(x, y2);
@ -386,8 +376,7 @@ void oledFrame(int x1, int y1, int x2, int y2)
* Animates the display, swiping the current contents out to the left. * Animates the display, swiping the current contents out to the left.
* This clears the display. * This clears the display.
*/ */
void oledSwipeLeft(void) void oledSwipeLeft(void) {
{
for (int i = 0; i < OLED_WIDTH; i++) { for (int i = 0; i < OLED_WIDTH; i++) {
for (int j = 0; j < OLED_HEIGHT / 8; j++) { for (int j = 0; j < OLED_HEIGHT / 8; j++) {
for (int k = OLED_WIDTH - 1; k > 0; k--) { for (int k = OLED_WIDTH - 1; k > 0; k--) {
@ -403,15 +392,18 @@ void oledSwipeLeft(void)
* Animates the display, swiping the current contents out to the right. * Animates the display, swiping the current contents out to the right.
* This clears the display. * This clears the display.
*/ */
void oledSwipeRight(void) void oledSwipeRight(void) {
{
for (int i = 0; i < OLED_WIDTH / 4; i++) { for (int i = 0; i < OLED_WIDTH / 4; i++) {
for (int j = 0; j < OLED_HEIGHT / 8; j++) { for (int j = 0; j < OLED_HEIGHT / 8; j++) {
for (int k = 0; k < OLED_WIDTH / 4 - 1; k++) { for (int k = 0; k < OLED_WIDTH / 4 - 1; k++) {
_oledbuffer[k * 4 + 0 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 4 + j * OLED_WIDTH]; _oledbuffer[k * 4 + 0 + j * OLED_WIDTH] =
_oledbuffer[k * 4 + 1 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 5 + j * OLED_WIDTH]; _oledbuffer[k * 4 + 4 + j * OLED_WIDTH];
_oledbuffer[k * 4 + 2 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 6 + j * OLED_WIDTH]; _oledbuffer[k * 4 + 1 + j * OLED_WIDTH] =
_oledbuffer[k * 4 + 3 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 7 + j * OLED_WIDTH]; _oledbuffer[k * 4 + 5 + j * OLED_WIDTH];
_oledbuffer[k * 4 + 2 + j * OLED_WIDTH] =
_oledbuffer[k * 4 + 6 + j * OLED_WIDTH];
_oledbuffer[k * 4 + 3 + j * OLED_WIDTH] =
_oledbuffer[k * 4 + 7 + j * OLED_WIDTH];
} }
_oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 1] = 0; _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 1] = 0;
_oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 2] = 0; _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 2] = 0;

2
oled.h
View File

@ -20,8 +20,8 @@
#ifndef __OLED_H__ #ifndef __OLED_H__
#define __OLED_H__ #define __OLED_H__
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include "bitmaps.h" #include "bitmaps.h"
#include "fonts.h" #include "fonts.h"

5
rng.c
View File

@ -18,14 +18,13 @@
*/ */
#include <libopencm3/cm3/common.h> #include <libopencm3/cm3/common.h>
#include <libopencm3/stm32/memorymap.h>
#include <libopencm3/stm32/f2/rng.h> #include <libopencm3/stm32/f2/rng.h>
#include <libopencm3/stm32/memorymap.h>
#include "rng.h" #include "rng.h"
#if !EMULATOR #if !EMULATOR
uint32_t random32(void) uint32_t random32(void) {
{
static uint32_t last = 0, new = 0; static uint32_t last = 0, new = 0;
while (new == last) { while (new == last) {
if ((RNG_SR & (RNG_SR_SECS | RNG_SR_CECS | RNG_SR_DRDY)) == RNG_SR_DRDY) { if ((RNG_SR & (RNG_SR_SECS | RNG_SR_CECS | RNG_SR_DRDY)) == RNG_SR_DRDY) {

125
setup.c
View File

@ -20,19 +20,20 @@
#include <libopencm3/cm3/mpu.h> #include <libopencm3/cm3/mpu.h>
#include <libopencm3/cm3/nvic.h> #include <libopencm3/cm3/nvic.h>
#include <libopencm3/cm3/scb.h> #include <libopencm3/cm3/scb.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h> #include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/spi.h> #include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/rng.h> #include <libopencm3/stm32/rng.h>
#include <libopencm3/stm32/spi.h>
#include "rng.h"
#include "layout.h" #include "layout.h"
#include "rng.h"
#include "util.h" #include "util.h"
uint32_t __stack_chk_guard; uint32_t __stack_chk_guard;
static inline void __attribute__((noreturn)) fault_handler(const char *line1) { static inline void __attribute__((noreturn)) fault_handler(const char *line1) {
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, "detected.", NULL, "Please unplug", "the device.", NULL); layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, "detected.", NULL,
"Please unplug", "the device.", NULL);
shutdown(); shutdown();
} }
@ -40,30 +41,25 @@ void __attribute__((noreturn)) __stack_chk_fail(void) {
fault_handler("Stack smashing"); fault_handler("Stack smashing");
} }
void nmi_handler(void) void nmi_handler(void) {
{
// Clock Security System triggered NMI // Clock Security System triggered NMI
if ((RCC_CIR & RCC_CIR_CSSF) != 0) { if ((RCC_CIR & RCC_CIR_CSSF) != 0) {
fault_handler("Clock instability"); fault_handler("Clock instability");
} }
} }
void hard_fault_handler(void) { void hard_fault_handler(void) { fault_handler("Hard fault"); }
fault_handler("Hard fault");
}
void mem_manage_handler(void) { void mem_manage_handler(void) { fault_handler("Memory fault"); }
fault_handler("Memory fault");
}
void setup(void) void setup(void) {
{ // set SCB_CCR STKALIGN bit to make sure 8-byte stack alignment on exception
// set SCB_CCR STKALIGN bit to make sure 8-byte stack alignment on exception entry is in effect. // entry is in effect. This is not strictly necessary for the current TREZOR
// This is not strictly necessary for the current TREZOR system. // system. This is here to comply with guidance from section 3.3.3 "Binary
// This is here to comply with guidance from section 3.3.3 "Binary compatibility with other Cortex processors" // compatibility with other Cortex processors" of the ARM Cortex-M3 Processor
// of the ARM Cortex-M3 Processor Technical Reference Manual. // Technical Reference Manual. According to section 4.4.2 and 4.4.7 of the
// According to section 4.4.2 and 4.4.7 of the "STM32F10xxx/20xxx/21xxx/L1xxxx Cortex-M3 programming manual", // "STM32F10xxx/20xxx/21xxx/L1xxxx Cortex-M3 programming manual", STM32F2
// STM32F2 series MCUs are r2p0 and always have this bit set on reset already. // series MCUs are r2p0 and always have this bit set on reset already.
SCB_CCR |= SCB_CCR_STKALIGN; SCB_CCR |= SCB_CCR_STKALIGN;
// setup clock // setup clock
@ -81,8 +77,9 @@ void setup(void)
// enable RNG // enable RNG
rcc_periph_clock_enable(RCC_RNG); rcc_periph_clock_enable(RCC_RNG);
RNG_CR |= RNG_CR_RNGEN; RNG_CR |= RNG_CR_RNGEN;
// to be extra careful and heed the STM32F205xx Reference manual, Section 20.3.1 // to be extra careful and heed the STM32F205xx Reference manual,
// we don't use the first random number generated after setting the RNGEN bit in setup // Section 20.3.1 we don't use the first random number generated after setting
// the RNGEN bit in setup
random32(); random32();
// enable CSS (Clock Security System) // enable CSS (Clock Security System)
@ -100,7 +97,9 @@ void setup(void)
gpio_set_af(GPIOA, GPIO_AF5, GPIO5 | GPIO7); gpio_set_af(GPIOA, GPIO_AF5, GPIO5 | GPIO7);
// spi_disable_crc(SPI1); // spi_disable_crc(SPI1);
spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_8, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); spi_init_master(
SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_8, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST);
spi_enable_ss_output(SPI1); spi_enable_ss_output(SPI1);
// spi_enable_software_slave_management(SPI1); // spi_enable_software_slave_management(SPI1);
// spi_set_nss_high(SPI1); // spi_set_nss_high(SPI1);
@ -118,16 +117,17 @@ void setup(void)
memset_reg((void *)0x50020000, (void *)0x50020500, 0); memset_reg((void *)0x50020000, (void *)0x50020500, 0);
} }
void setupApp(void) void setupApp(void) {
{ // for completeness, disable RNG peripheral interrupts for old bootloaders
// for completeness, disable RNG peripheral interrupts for old bootloaders that had // that had enabled them in RNG control register (the RNG interrupt was never
// enabled them in RNG control register (the RNG interrupt was never enabled in the NVIC) // enabled in the NVIC)
RNG_CR &= ~RNG_CR_IE; RNG_CR &= ~RNG_CR_IE;
// the static variables in random32 are separate between the bootloader and firmware. // the static variables in random32 are separate between the bootloader and
// therefore, they need to be initialized here so that we can be sure to avoid dupes. // firmware. therefore, they need to be initialized here so that we can be
// this is to try to comply with STM32F205xx Reference manual - Section 20.3.1: // sure to avoid dupes. this is to try to comply with STM32F205xx Reference
// "Each subsequent generated random number has to be compared with the previously generated // manual - Section 20.3.1: "Each subsequent generated random number has to be
// number. The test fails if any two compared numbers are equal (continuous random number generator test)." // compared with the previously generated number. The test fails if any two
// compared numbers are equal (continuous random number generator test)."
random32(); random32();
// enable CSS (Clock Security System) // enable CSS (Clock Security System)
@ -135,7 +135,9 @@ void setupApp(void)
// hotfix for old bootloader // hotfix for old bootloader
gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO9); gpio_mode_setup(GPIOA, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO9);
spi_init_master(SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_8, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST); spi_init_master(
SPI1, SPI_CR1_BAUDRATE_FPCLK_DIV_8, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE,
SPI_CR1_CPHA_CLK_TRANSITION_1, SPI_CR1_DFF_8BIT, SPI_CR1_MSBFIRST);
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO10); gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO10);
gpio_set_af(GPIOA, GPIO_AF10, GPIO10); gpio_set_af(GPIOA, GPIO_AF10, GPIO10);
@ -163,8 +165,7 @@ void setupApp(void)
#define FLASH_BASE (0x08000000U) #define FLASH_BASE (0x08000000U)
#define SRAM_BASE (0x20000000U) #define SRAM_BASE (0x20000000U)
void mpu_config_off(void) void mpu_config_off(void) {
{
// Disable MPU // Disable MPU
MPU_CTRL = 0; MPU_CTRL = 0;
@ -172,8 +173,7 @@ void mpu_config_off(void)
__asm__ volatile("isb"); __asm__ volatile("isb");
} }
void mpu_config_bootloader(void) void mpu_config_bootloader(void) {
{
// Disable MPU // Disable MPU
MPU_CTRL = 0; MPU_CTRL = 0;
@ -181,26 +181,33 @@ void mpu_config_bootloader(void)
// Everything (0x00000000 - 0xFFFFFFFF, 4 GiB, read-write) // Everything (0x00000000 - 0xFFFFFFFF, 4 GiB, read-write)
MPU_RBAR = 0 | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB); MPU_RBAR = 0 | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_4GB | MPU_RASR_ATTR_AP_PRW_URW; MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_4GB |
MPU_RASR_ATTR_AP_PRW_URW;
// Flash (0x8007FE0 - 0x08007FFF, 32 B, no-access) // Flash (0x8007FE0 - 0x08007FFF, 32 B, no-access)
MPU_RBAR = (FLASH_BASE + 0x7FE0) | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB); MPU_RBAR =
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_32B | MPU_RASR_ATTR_AP_PNO_UNO; (FLASH_BASE + 0x7FE0) | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_32B |
MPU_RASR_ATTR_AP_PNO_UNO;
// SRAM (0x20000000 - 0x2001FFFF, read-write, execute never) // SRAM (0x20000000 - 0x2001FFFF, read-write, execute never)
MPU_RBAR = SRAM_BASE | MPU_RBAR_VALID | (2 << MPU_RBAR_REGION_LSB); MPU_RBAR = SRAM_BASE | MPU_RBAR_VALID | (2 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_SRAM | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_SRAM | MPU_RASR_SIZE_128KB |
MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN;
// Peripherals (0x40000000 - 0x4001FFFF, read-write, execute never) // Peripherals (0x40000000 - 0x4001FFFF, read-write, execute never)
MPU_RBAR = PERIPH_BASE | MPU_RBAR_VALID | (3 << MPU_RBAR_REGION_LSB); MPU_RBAR = PERIPH_BASE | MPU_RBAR_VALID | (3 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_128KB |
MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN;
// Peripherals (0x40020000 - 0x40023FFF, read-write, execute never) // Peripherals (0x40020000 - 0x40023FFF, read-write, execute never)
MPU_RBAR = 0x40020000 | MPU_RBAR_VALID | (4 << MPU_RBAR_REGION_LSB); MPU_RBAR = 0x40020000 | MPU_RBAR_VALID | (4 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_16KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_16KB |
MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN;
// Don't enable DMA controller access // Don't enable DMA controller access
// Peripherals (0x50000000 - 0x5007ffff, read-write, execute never) // Peripherals (0x50000000 - 0x5007ffff, read-write, execute never)
MPU_RBAR = 0x50000000 | MPU_RBAR_VALID | (5 << MPU_RBAR_REGION_LSB); MPU_RBAR = 0x50000000 | MPU_RBAR_VALID | (5 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_512KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_512KB |
MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN;
// Enable MPU // Enable MPU
MPU_CTRL = MPU_CTRL_ENABLE | MPU_CTRL_HFNMIENA; MPU_CTRL = MPU_CTRL_ENABLE | MPU_CTRL_HFNMIENA;
@ -213,8 +220,7 @@ void mpu_config_bootloader(void)
} }
// Never use in bootloader! Disables access to PPB (including MPU, NVIC, SCB) // Never use in bootloader! Disables access to PPB (including MPU, NVIC, SCB)
void mpu_config_firmware(void) void mpu_config_firmware(void) {
{
#if MEMORY_PROTECT #if MEMORY_PROTECT
// Disable MPU // Disable MPU
MPU_CTRL = 0; MPU_CTRL = 0;
@ -223,35 +229,44 @@ void mpu_config_firmware(void)
// Flash (0x08000000 - 0x0807FFFF, 1 MiB, read-only) // Flash (0x08000000 - 0x0807FFFF, 1 MiB, read-only)
MPU_RBAR = FLASH_BASE | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB); MPU_RBAR = FLASH_BASE | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_1MB | MPU_RASR_ATTR_AP_PRO_URO; MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_1MB |
MPU_RASR_ATTR_AP_PRO_URO;
// Metadata in Flash is read-write when unlocked // Metadata in Flash is read-write when unlocked
// (0x08008000 - 0x0800FFFF, 32 KiB, read-write, execute never) // (0x08008000 - 0x0800FFFF, 32 KiB, read-write, execute never)
MPU_RBAR = (FLASH_BASE + 0x8000) | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB); MPU_RBAR =
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_32KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; (FLASH_BASE + 0x8000) | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_32KB |
MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN;
// SRAM (0x20000000 - 0x2001FFFF, read-write, execute never) // SRAM (0x20000000 - 0x2001FFFF, read-write, execute never)
MPU_RBAR = SRAM_BASE | MPU_RBAR_VALID | (2 << MPU_RBAR_REGION_LSB); MPU_RBAR = SRAM_BASE | MPU_RBAR_VALID | (2 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_SRAM | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_SRAM | MPU_RASR_SIZE_128KB |
MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN;
// Peripherals (0x40000000 - 0x4001FFFF, read-write, execute never) // Peripherals (0x40000000 - 0x4001FFFF, read-write, execute never)
MPU_RBAR = PERIPH_BASE | MPU_RBAR_VALID | (3 << MPU_RBAR_REGION_LSB); MPU_RBAR = PERIPH_BASE | MPU_RBAR_VALID | (3 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_128KB |
MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN;
// Peripherals (0x40020000 - 0x40023FFF, read-write, execute never) // Peripherals (0x40020000 - 0x40023FFF, read-write, execute never)
MPU_RBAR = 0x40020000 | MPU_RBAR_VALID | (4 << MPU_RBAR_REGION_LSB); MPU_RBAR = 0x40020000 | MPU_RBAR_VALID | (4 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_16KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_16KB |
MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN;
// Flash controller is protected // Flash controller is protected
// (0x40023C00 - 0x40023FFF, privileged read-write, user no, execute never) // (0x40023C00 - 0x40023FFF, privileged read-write, user no, execute never)
MPU_RBAR = 0x40023c00 | MPU_RBAR_VALID | (5 << MPU_RBAR_REGION_LSB); MPU_RBAR = 0x40023c00 | MPU_RBAR_VALID | (5 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_1KB | MPU_RASR_ATTR_AP_PRW_UNO | MPU_RASR_ATTR_XN; MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_1KB |
MPU_RASR_ATTR_AP_PRW_UNO | MPU_RASR_ATTR_XN;
// Don't enable DMA controller access // Don't enable DMA controller access
// Peripherals (0x50000000 - 0x5007ffff, read-write, execute never) // Peripherals (0x50000000 - 0x5007ffff, read-write, execute never)
MPU_RBAR = 0x50000000 | MPU_RBAR_VALID | (6 << MPU_RBAR_REGION_LSB); MPU_RBAR = 0x50000000 | MPU_RBAR_VALID | (6 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_512KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_512KB |
MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN;
// SYSCFG_* registers are disabled // SYSCFG_* registers are disabled
// (0x40013800 - 0x40013BFF, read-only, execute never) // (0x40013800 - 0x40013BFF, read-only, execute never)
MPU_RBAR = 0x40013800 | MPU_RBAR_VALID | (7 << MPU_RBAR_REGION_LSB); MPU_RBAR = 0x40013800 | MPU_RBAR_VALID | (7 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_1KB | MPU_RASR_ATTR_AP_PRO_URO | MPU_RASR_ATTR_XN; MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_1KB |
MPU_RASR_ATTR_AP_PRO_URO | MPU_RASR_ATTR_XN;
// Enable MPU // Enable MPU
MPU_CTRL = MPU_CTRL_ENABLE | MPU_CTRL_HFNMIENA; MPU_CTRL = MPU_CTRL_ENABLE | MPU_CTRL_HFNMIENA;

View File

@ -5,5 +5,5 @@ let
in in
stdenv.mkDerivation { stdenv.mkDerivation {
name = "trezor-mcu-dev"; name = "trezor-mcu-dev";
buildInputs = [ myPython protobuf gnumake gcc gcc-arm-embedded pkgconfig SDL2 SDL2_image ]; buildInputs = [ myPython protobuf gnumake gcc gcc-arm-embedded pkgconfig SDL2 SDL2_image clang-tools ];
} }

View File

@ -17,9 +17,9 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "supervise.h"
#include <libopencm3/stm32/flash.h> #include <libopencm3/stm32/flash.h>
#include <stdint.h> #include <stdint.h>
#include "supervise.h"
#include "memory.h" #include "memory.h"
#if !EMULATOR #if !EMULATOR
@ -34,13 +34,11 @@ static void svhandler_flash_program(uint32_t psize) {
/* Wait for any write operation to complete. */ /* Wait for any write operation to complete. */
flash_wait_for_last_operation(); flash_wait_for_last_operation();
/* check program size argument */ /* check program size argument */
if (psize != FLASH_CR_PROGRAM_X8 if (psize != FLASH_CR_PROGRAM_X8 && psize != FLASH_CR_PROGRAM_X16 &&
&& psize != FLASH_CR_PROGRAM_X16 psize != FLASH_CR_PROGRAM_X32 && psize != FLASH_CR_PROGRAM_X64)
&& psize != FLASH_CR_PROGRAM_X32
&& psize != FLASH_CR_PROGRAM_X64)
return; return;
FLASH_CR = (FLASH_CR & ~(FLASH_CR_PROGRAM_MASK << FLASH_CR_PROGRAM_SHIFT)) FLASH_CR = (FLASH_CR & ~(FLASH_CR_PROGRAM_MASK << FLASH_CR_PROGRAM_SHIFT)) |
| (psize << FLASH_CR_PROGRAM_SHIFT); (psize << FLASH_CR_PROGRAM_SHIFT);
FLASH_CR |= FLASH_CR_PG; FLASH_CR |= FLASH_CR_PG;
} }

View File

@ -22,6 +22,8 @@
#if !EMULATOR #if !EMULATOR
#include <stdint.h>
#define SVC_FLASH_UNLOCK 0 #define SVC_FLASH_UNLOCK 0
#define SVC_FLASH_ERASE 1 #define SVC_FLASH_ERASE 1
#define SVC_FLASH_PROGRAM 2 #define SVC_FLASH_PROGRAM 2

View File

@ -17,12 +17,11 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "timer.h" #include "timer.h"
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/cm3/systick.h> #include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/vector.h> #include <libopencm3/cm3/vector.h>
#include <libopencm3/stm32/rcc.h>
/* 1 tick = 1 ms */ /* 1 tick = 1 ms */
extern volatile uint32_t system_millis; extern volatile uint32_t system_millis;
@ -57,6 +56,4 @@ void timer_init(void) {
systick_counter_enable(); systick_counter_enable();
} }
void sys_tick_handler(void) { void sys_tick_handler(void) { system_millis++; }
system_millis++;
}

View File

@ -16,14 +16,13 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "usb21_standard.h"
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include "util.h" #include "util.h"
#include "usb21_standard.h"
static uint16_t build_bos_descriptor(const struct usb_bos_descriptor *bos, static uint16_t build_bos_descriptor(const struct usb_bos_descriptor *bos,
uint8_t *buf, uint16_t len) uint8_t *buf, uint16_t len) {
{
uint8_t *tmpbuf = buf; uint8_t *tmpbuf = buf;
uint16_t count, total = 0, totallen = 0; uint16_t count, total = 0, totallen = 0;
uint16_t i; uint16_t i;
@ -37,8 +36,7 @@ static uint16_t build_bos_descriptor(const struct usb_bos_descriptor *bos,
/* For each device capability */ /* For each device capability */
for (i = 0; i < bos->bNumDeviceCaps; i++) { for (i = 0; i < bos->bNumDeviceCaps; i++) {
/* Copy device capability descriptor. */ /* Copy device capability descriptor. */
const struct usb_device_capability_descriptor *cap = const struct usb_device_capability_descriptor *cap = bos->capabilities[i];
bos->capabilities[i];
memcpy(buf, cap, count = MIN(len, cap->bLength)); memcpy(buf, cap, count = MIN(len, cap->bLength));
buf += count; buf += count;
@ -55,10 +53,9 @@ static uint16_t build_bos_descriptor(const struct usb_bos_descriptor *bos,
static const struct usb_bos_descriptor *usb21_bos; static const struct usb_bos_descriptor *usb21_bos;
static int usb21_standard_get_descriptor(usbd_device* usbd_dev, static int usb21_standard_get_descriptor(
struct usb_setup_data *req, usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
uint8_t **buf, uint16_t *len, uint16_t *len, usbd_control_complete_callback *complete) {
usbd_control_complete_callback* complete) {
(void)complete; (void)complete;
(void)usbd_dev; (void)usbd_dev;
@ -82,13 +79,13 @@ static void usb21_set_config(usbd_device* usbd_dev, uint16_t wValue) {
(void)wValue; (void)wValue;
usbd_register_control_callback( usbd_register_control_callback(
usbd_dev, usbd_dev, USB_REQ_TYPE_IN | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE,
USB_REQ_TYPE_IN | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE,
USB_REQ_TYPE_DIRECTION | USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, USB_REQ_TYPE_DIRECTION | USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
&usb21_standard_get_descriptor); &usb21_standard_get_descriptor);
} }
void usb21_setup(usbd_device* usbd_dev, const struct usb_bos_descriptor* binary_object_store) { void usb21_setup(usbd_device *usbd_dev,
const struct usb_bos_descriptor *binary_object_store) {
usb21_bos = binary_object_store; usb21_bos = binary_object_store;
/* Register the control request handler _before_ the config is set */ /* Register the control request handler _before_ the config is set */

View File

@ -45,6 +45,7 @@ struct usb_bos_descriptor {
/* USB Device Capability Types - USB 3.1 Table 9-14 */ /* USB Device Capability Types - USB 3.1 Table 9-14 */
#define USB_DC_PLATFORM 5 #define USB_DC_PLATFORM 5
extern void usb21_setup(usbd_device* usbd_dev, const struct usb_bos_descriptor* binary_object_store); extern void usb21_setup(usbd_device* usbd_dev,
const struct usb_bos_descriptor* binary_object_store);
#endif #endif

View File

@ -1,3 +1,4 @@
// clang-format off
/** @defgroup usb_private_defines USB Private Structures /** @defgroup usb_private_defines USB Private Structures
@brief <b>Defined Constants and Types for the USB Private Structures</b> @brief <b>Defined Constants and Types for the USB Private Structures</b>

View File

@ -1,3 +1,4 @@
// clang-format off
/** @defgroup usb_standard_file Generic USB Standard Request Interface /** @defgroup usb_standard_file Generic USB Standard Request Interface
@ingroup USB @ingroup USB

17
util.c
View File

@ -17,16 +17,14 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "rng.h"
#include "util.h" #include "util.h"
#include "rng.h"
inline void delay(uint32_t wait) inline void delay(uint32_t wait) {
{
while (--wait > 0) __asm__("nop"); while (--wait > 0) __asm__("nop");
} }
void wait_random(void) void wait_random(void) {
{
int wait = random32() & 0xff; int wait = random32() & 0xff;
volatile int i = 0; volatile int i = 0;
volatile int j = wait; volatile int j = wait;
@ -45,16 +43,14 @@ void wait_random(void)
static const char *hexdigits = "0123456789ABCDEF"; static const char *hexdigits = "0123456789ABCDEF";
void uint32hex(uint32_t num, char *str) void uint32hex(uint32_t num, char *str) {
{
for (uint32_t i = 0; i < 8; i++) { for (uint32_t i = 0; i < 8; i++) {
str[i] = hexdigits[(num >> (28 - i * 4)) & 0xF]; str[i] = hexdigits[(num >> (28 - i * 4)) & 0xF];
} }
} }
// converts data to hexa // converts data to hexa
void data2hex(const void *data, uint32_t len, char *str) void data2hex(const void *data, uint32_t len, char *str) {
{
const uint8_t *cdata = (uint8_t *)data; const uint8_t *cdata = (uint8_t *)data;
for (uint32_t i = 0; i < len; i++) { for (uint32_t i = 0; i < len; i++) {
str[i * 2] = hexdigits[(cdata[i] >> 4) & 0xF]; str[i * 2] = hexdigits[(cdata[i] >> 4) & 0xF];
@ -63,8 +59,7 @@ void data2hex(const void *data, uint32_t len, char *str)
str[len * 2] = 0; str[len * 2] = 0;
} }
uint32_t readprotobufint(const uint8_t **ptr) uint32_t readprotobufint(const uint8_t **ptr) {
{
uint32_t result = (**ptr & 0x7F); uint32_t result = (**ptr & 0x7F);
if (**ptr & 0x80) { if (**ptr & 0x80) {
(*ptr)++; (*ptr)++;

46
util.h
View File

@ -20,9 +20,9 @@
#ifndef __UTIL_H_ #ifndef __UTIL_H_
#define __UTIL_H_ #define __UTIL_H_
#include <stdint.h>
#include <stdbool.h>
#include <setup.h> #include <setup.h>
#include <stdbool.h>
#include <stdint.h>
#if !EMULATOR #if !EMULATOR
#include <libopencm3/cm3/scb.h> #include <libopencm3/cm3/scb.h>
@ -31,9 +31,24 @@
#endif #endif
// Statement expressions make these macros side-effect safe // Statement expressions make these macros side-effect safe
#define MIN_8bits(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? (_a & 0xFF) : (_b & 0xFF); }) #define MIN_8bits(a, b) \
#define MIN(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a < _b ? _a : _b; }) ({ \
#define MAX(a, b) ({ typeof(a) _a = (a); typeof(b) _b = (b); _a > _b ? _a : _b; }) typeof(a) _a = (a); \
typeof(b) _b = (b); \
_a < _b ? (_a & 0xFF) : (_b & 0xFF); \
})
#define MIN(a, b) \
({ \
typeof(a) _a = (a); \
typeof(b) _b = (b); \
_a < _b ? _a : _b; \
})
#define MAX(a, b) \
({ \
typeof(a) _a = (a); \
typeof(b) _b = (b); \
_a > _b ? _a : _b; \
})
void delay(uint32_t wait); void delay(uint32_t wait);
@ -62,8 +77,8 @@ extern void memset_reg(void *start, void *stop, uint32_t val);
#define FW_SIGNED 0x5A3CA5C3 #define FW_SIGNED 0x5A3CA5C3
#define FW_UNTRUSTED 0x00000000 #define FW_UNTRUSTED 0x00000000
static inline void __attribute__((noreturn)) jump_to_firmware(const vector_table_t *vector_table, int trust) static inline void __attribute__((noreturn))
{ jump_to_firmware(const vector_table_t *vector_table, int trust) {
if (FW_SIGNED == trust) { // trusted signed firmware if (FW_SIGNED == trust) { // trusted signed firmware
SCB_VTOR = (uint32_t)vector_table; // * relocate vector table SCB_VTOR = (uint32_t)vector_table; // * relocate vector table
// Set stack pointer // Set stack pointer
@ -77,18 +92,18 @@ static inline void __attribute__((noreturn)) jump_to_firmware(const vector_table
// Jump to address // Jump to address
vector_table->reset(); vector_table->reset();
// Prevent compiler from generating stack protector code (which causes CPU fault because the stack is moved) // Prevent compiler from generating stack protector code (which causes CPU
for (;;); // fault because the stack is moved)
for (;;)
;
} }
static inline void set_mode_unprivileged(void) static inline void set_mode_unprivileged(void) {
{
// http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/CHDBIBGJ.html // http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/CHDBIBGJ.html
__asm__ volatile("msr control, %0" ::"r"(0x1)); __asm__ volatile("msr control, %0" ::"r"(0x1));
} }
static inline bool is_mode_unprivileged(void) static inline bool is_mode_unprivileged(void) {
{
uint32_t r0; uint32_t r0;
__asm__ volatile("mrs %0, control" : "=r"(r0)); __asm__ volatile("mrs %0, control" : "=r"(r0));
return r0 & 1; return r0 & 1;
@ -96,10 +111,7 @@ static inline bool is_mode_unprivileged(void)
#else /* EMULATOR */ #else /* EMULATOR */
static inline bool is_mode_unprivileged(void) static inline bool is_mode_unprivileged(void) { return true; }
{
return true;
}
#endif #endif
#endif #endif

View File

@ -18,11 +18,22 @@
#include <string.h> #include <string.h>
#include "usb21_standard.h"
#include "util.h" #include "util.h"
#include "webusb.h" #include "webusb.h"
#include "usb21_standard.h"
const struct webusb_platform_descriptor webusb_platform_capability_descriptor = { const struct webusb_platform_descriptor webusb_platform_capability_descriptor =
{.bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE,
.bDescriptorType = USB_DT_DEVICE_CAPABILITY,
.bDevCapabilityType = USB_DC_PLATFORM,
.bReserved = 0,
.platformCapabilityUUID = WEBUSB_UUID,
.bcdVersion = 0x0100,
.bVendorCode = WEBUSB_VENDOR_CODE,
.iLandingPage = 1};
const struct webusb_platform_descriptor
webusb_platform_capability_descriptor_no_landing_page = {
.bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE, .bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE,
.bDescriptorType = USB_DT_DEVICE_CAPABILITY, .bDescriptorType = USB_DT_DEVICE_CAPABILITY,
.bDevCapabilityType = USB_DC_PLATFORM, .bDevCapabilityType = USB_DC_PLATFORM,
@ -30,26 +41,13 @@ const struct webusb_platform_descriptor webusb_platform_capability_descriptor =
.platformCapabilityUUID = WEBUSB_UUID, .platformCapabilityUUID = WEBUSB_UUID,
.bcdVersion = 0x0100, .bcdVersion = 0x0100,
.bVendorCode = WEBUSB_VENDOR_CODE, .bVendorCode = WEBUSB_VENDOR_CODE,
.iLandingPage = 1 .iLandingPage = 0};
};
const struct webusb_platform_descriptor webusb_platform_capability_descriptor_no_landing_page = {
.bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE,
.bDescriptorType = USB_DT_DEVICE_CAPABILITY,
.bDevCapabilityType = USB_DC_PLATFORM,
.bReserved = 0,
.platformCapabilityUUID = WEBUSB_UUID,
.bcdVersion = 0x0100,
.bVendorCode = WEBUSB_VENDOR_CODE,
.iLandingPage = 0
};
static const char* webusb_https_url; static const char* webusb_https_url;
static int webusb_control_vendor_request(usbd_device *usbd_dev, static int webusb_control_vendor_request(
struct usb_setup_data *req, usbd_device* usbd_dev, struct usb_setup_data* req, uint8_t** buf,
uint8_t **buf, uint16_t *len, uint16_t* len, usbd_control_complete_callback* complete) {
usbd_control_complete_callback* complete) {
(void)complete; (void)complete;
(void)usbd_dev; (void)usbd_dev;
@ -93,8 +91,7 @@ static int webusb_control_vendor_request(usbd_device *usbd_dev,
static void webusb_set_config(usbd_device* usbd_dev, uint16_t wValue) { static void webusb_set_config(usbd_device* usbd_dev, uint16_t wValue) {
(void)wValue; (void)wValue;
usbd_register_control_callback( usbd_register_control_callback(usbd_dev,
usbd_dev,
USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_DEVICE, USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_DEVICE,
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
webusb_control_vendor_request); webusb_control_vendor_request);

View File

@ -25,8 +25,10 @@
// Arbitrary // Arbitrary
#define WEBUSB_VENDOR_CODE 0x01 #define WEBUSB_VENDOR_CODE 0x01
extern const struct webusb_platform_descriptor webusb_platform_capability_descriptor; extern const struct webusb_platform_descriptor
extern const struct webusb_platform_descriptor webusb_platform_capability_descriptor_no_landing_page; webusb_platform_capability_descriptor;
extern const struct webusb_platform_descriptor
webusb_platform_capability_descriptor_no_landing_page;
extern void webusb_setup(usbd_device* usbd_dev, const char* https_url); extern void webusb_setup(usbd_device* usbd_dev, const char* https_url);

View File

@ -42,12 +42,17 @@ struct webusb_platform_descriptor {
uint8_t iLandingPage; uint8_t iLandingPage;
} __attribute__((packed)); } __attribute__((packed));
#define WEBUSB_PLATFORM_DESCRIPTOR_SIZE sizeof(struct webusb_platform_descriptor) #define WEBUSB_PLATFORM_DESCRIPTOR_SIZE \
sizeof(struct webusb_platform_descriptor)
// from https://wicg.github.io/webusb/#webusb-platform-capability-descriptor // from https://wicg.github.io/webusb/#webusb-platform-capability-descriptor
// see also this (for endianness explanation) // see also this (for endianness explanation)
// https://github.com/WICG/webusb/issues/115#issuecomment-352206549 // https://github.com/WICG/webusb/issues/115#issuecomment-352206549
#define WEBUSB_UUID {0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47,0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65} #define WEBUSB_UUID \
{ \
0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, 0x8B, 0xFD, 0xA0, 0x76, \
0x88, 0x15, 0xB6, 0x65 \
}
struct webusb_url_descriptor { struct webusb_url_descriptor {
uint8_t bLength; uint8_t bLength;

View File

@ -16,21 +16,19 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "winusb.h"
#include <libopencm3/usb/usbd.h> #include <libopencm3/usb/usbd.h>
#include "util.h" #include "util.h"
#include "winusb.h"
static int usb_descriptor_type(uint16_t wValue) { static int usb_descriptor_type(uint16_t wValue) { return wValue >> 8; }
return wValue >> 8;
}
static int usb_descriptor_index(uint16_t wValue) { static int usb_descriptor_index(uint16_t wValue) { return wValue & 0xFF; }
return wValue & 0xFF;
}
static struct winusb_compatible_id_descriptor winusb_wcid = { static struct winusb_compatible_id_descriptor winusb_wcid = {
.header = { .header =
.dwLength = sizeof(struct winusb_compatible_id_descriptor_header) + {
.dwLength =
sizeof(struct winusb_compatible_id_descriptor_header) +
1 * sizeof(struct winusb_compatible_id_function_section), 1 * sizeof(struct winusb_compatible_id_function_section),
.bcdVersion = WINUSB_BCD_VERSION, .bcdVersion = WINUSB_BCD_VERSION,
.wIndex = WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR, .wIndex = WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR,
@ -38,46 +36,46 @@ static struct winusb_compatible_id_descriptor winusb_wcid = {
.reserved = {0, 0, 0, 0, 0, 0, 0}, .reserved = {0, 0, 0, 0, 0, 0, 0},
}, },
.functions = { .functions = {
{ {// note - bInterfaceNumber is rewritten in winusb_setup with the
// note - bInterfaceNumber is rewritten in winusb_setup with the correct interface number // correct interface number
.bInterfaceNumber = 0, .bInterfaceNumber = 0,
.reserved0 = {1}, .reserved0 = {1},
.compatibleId = "WINUSB", .compatibleId = "WINUSB",
.subCompatibleId = "", .subCompatibleId = "",
.reserved1 = { 0, 0, 0, 0, 0, 0} .reserved1 = {0, 0, 0, 0, 0, 0}},
}, }};
}
};
static const struct usb_string_descriptor winusb_string_descriptor = { static const struct usb_string_descriptor winusb_string_descriptor = {
.bLength = 0x12, .bLength = 0x12,
.bDescriptorType = USB_DT_STRING, .bDescriptorType = USB_DT_STRING,
.wData = WINUSB_EXTRA_STRING .wData = WINUSB_EXTRA_STRING};
};
static const struct winusb_extended_properties_descriptor guid = { static const struct winusb_extended_properties_descriptor guid = {
.header = { .header =
.dwLength = sizeof(struct winusb_extended_properties_descriptor_header) {
+ 1 * sizeof (struct winusb_extended_properties_feature_descriptor), .dwLength =
sizeof(struct winusb_extended_properties_descriptor_header) +
1 * sizeof(
struct winusb_extended_properties_feature_descriptor),
.bcdVersion = WINUSB_BCD_VERSION, .bcdVersion = WINUSB_BCD_VERSION,
.wIndex = WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR, .wIndex = WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR,
.wNumFeatures = 1, .wNumFeatures = 1,
}, },
.features = { .features = {
{ {
.dwLength = sizeof(struct winusb_extended_properties_feature_descriptor), .dwLength =
sizeof(struct winusb_extended_properties_feature_descriptor),
.dwPropertyDataType = WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE, .dwPropertyDataType = WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE,
.wNameLength = WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C, .wNameLength = WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C,
.name = WINUSB_EXTENDED_PROPERTIES_GUID_NAME, .name = WINUSB_EXTENDED_PROPERTIES_GUID_NAME,
.dwPropertyDataLength = WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_C, .dwPropertyDataLength = WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_C,
.propertyData = WINUSB_EXTENDED_PROPERTIES_GUID_DATA, .propertyData = WINUSB_EXTENDED_PROPERTIES_GUID_DATA,
}, },
} }};
};
static int winusb_descriptor_request(usbd_device *usbd_dev, static int winusb_descriptor_request(usbd_device *usbd_dev,
struct usb_setup_data *req, struct usb_setup_data *req, uint8_t **buf,
uint8_t **buf, uint16_t *len, uint16_t *len,
usbd_control_complete_callback *complete) { usbd_control_complete_callback *complete) {
(void)complete; (void)complete;
(void)usbd_dev; (void)usbd_dev;
@ -88,7 +86,8 @@ static int winusb_descriptor_request(usbd_device *usbd_dev,
return USBD_REQ_NEXT_CALLBACK; return USBD_REQ_NEXT_CALLBACK;
} }
if (req->bRequest == USB_REQ_GET_DESCRIPTOR && usb_descriptor_type(req->wValue) == USB_DT_STRING) { if (req->bRequest == USB_REQ_GET_DESCRIPTOR &&
usb_descriptor_type(req->wValue) == USB_DT_STRING) {
if (usb_descriptor_index(req->wValue) == WINUSB_EXTRA_STRING_INDEX) { if (usb_descriptor_index(req->wValue) == WINUSB_EXTRA_STRING_INDEX) {
*buf = (uint8_t *)(&winusb_string_descriptor); *buf = (uint8_t *)(&winusb_string_descriptor);
*len = MIN_8bits(*len, winusb_string_descriptor.bLength); *len = MIN_8bits(*len, winusb_string_descriptor.bLength);
@ -98,10 +97,9 @@ static int winusb_descriptor_request(usbd_device *usbd_dev,
return USBD_REQ_NEXT_CALLBACK; return USBD_REQ_NEXT_CALLBACK;
} }
static int winusb_control_vendor_request(usbd_device *usbd_dev, static int winusb_control_vendor_request(
struct usb_setup_data *req, usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
uint8_t **buf, uint16_t *len, uint16_t *len, usbd_control_complete_callback *complete) {
usbd_control_complete_callback* complete) {
(void)complete; (void)complete;
(void)usbd_dev; (void)usbd_dev;
@ -118,10 +116,12 @@ static int winusb_control_vendor_request(usbd_device *usbd_dev,
*len = MIN_8bits(*len, winusb_wcid.header.dwLength); *len = MIN_8bits(*len, winusb_wcid.header.dwLength);
status = USBD_REQ_HANDLED; status = USBD_REQ_HANDLED;
} else if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == USB_REQ_TYPE_INTERFACE) && } else if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) ==
(req->wIndex == WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR) && USB_REQ_TYPE_INTERFACE) &&
(usb_descriptor_index(req->wValue) == winusb_wcid.functions[0].bInterfaceNumber)) { (req->wIndex ==
WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR) &&
(usb_descriptor_index(req->wValue) ==
winusb_wcid.functions[0].bInterfaceNumber)) {
*buf = (uint8_t *)(&guid); *buf = (uint8_t *)(&guid);
*len = MIN_8bits(*len, guid.header.dwLength); *len = MIN_8bits(*len, guid.header.dwLength);
status = USBD_REQ_HANDLED; status = USBD_REQ_HANDLED;
@ -135,9 +135,7 @@ static int winusb_control_vendor_request(usbd_device *usbd_dev,
static void winusb_set_config(usbd_device *usbd_dev, uint16_t wValue) { static void winusb_set_config(usbd_device *usbd_dev, uint16_t wValue) {
(void)wValue; (void)wValue;
usbd_register_control_callback( usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_VENDOR,
usbd_dev,
USB_REQ_TYPE_VENDOR,
USB_REQ_TYPE_TYPE, USB_REQ_TYPE_TYPE,
winusb_control_vendor_request); winusb_control_vendor_request);
} }
@ -150,16 +148,11 @@ void winusb_setup(usbd_device* usbd_dev, uint8_t interface) {
/* Windows probes the compatible ID before setting the configuration, /* Windows probes the compatible ID before setting the configuration,
so also register the callback now */ so also register the callback now */
usbd_register_control_callback( usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_VENDOR,
usbd_dev,
USB_REQ_TYPE_VENDOR,
USB_REQ_TYPE_TYPE, USB_REQ_TYPE_TYPE,
winusb_control_vendor_request); winusb_control_vendor_request);
usbd_register_control_callback( usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_DEVICE,
usbd_dev,
USB_REQ_TYPE_DEVICE,
USB_REQ_TYPE_RECIPIENT, USB_REQ_TYPE_RECIPIENT,
winusb_descriptor_request); winusb_descriptor_request);
} }

View File

@ -19,11 +19,13 @@
#ifndef WINUSB_H_INCLUDED #ifndef WINUSB_H_INCLUDED
#define WINUSB_H_INCLUDED #define WINUSB_H_INCLUDED
#include <libopencm3/usb/usbd.h>
#include "winusb_defs.h" #include "winusb_defs.h"
// Arbitrary, but must be equivalent to the last character in extra string // Arbitrary, but must be equivalent to the last character in extra string
#define WINUSB_MS_VENDOR_CODE '!' #define WINUSB_MS_VENDOR_CODE '!'
#define WINUSB_EXTRA_STRING {'M', 'S', 'F', 'T', '1', '0', '0', WINUSB_MS_VENDOR_CODE} #define WINUSB_EXTRA_STRING \
{ 'M', 'S', 'F', 'T', '1', '0', '0', WINUSB_MS_VENDOR_CODE }
extern void winusb_setup(usbd_device* usbd_dev, uint8_t interface); extern void winusb_setup(usbd_device* usbd_dev, uint8_t interface);

View File

@ -31,13 +31,18 @@
// Apparently using DeviceInterfaceGUID does not always work on Windows 7. // Apparently using DeviceInterfaceGUID does not always work on Windows 7.
// DeviceInterfaceGUIDs does seem to work. // DeviceInterfaceGUIDs does seem to work.
#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME u"DeviceInterfaceGUIDs" #define WINUSB_EXTENDED_PROPERTIES_GUID_NAME u"DeviceInterfaceGUIDs"
#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_NAME) #define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C \
#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_U (sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_NAME) / 2) sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_NAME)
#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_U \
(sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_NAME) / 2)
// extra null is intentional - it's an array of GUIDs with 1 item // extra null is intentional - it's an array of GUIDs with 1 item
#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA u"{0263b512-88cb-4136-9613-5c8e109d8ef5}\x00" #define WINUSB_EXTENDED_PROPERTIES_GUID_DATA \
#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_C sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_DATA) u"{0263b512-88cb-4136-9613-5c8e109d8ef5}\x00"
#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_U (sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_DATA) / 2) #define WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_C \
sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_DATA)
#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA_SIZE_U \
(sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_DATA) / 2)
#define WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE 7 #define WINUSB_EXTENDED_PROPERTIES_MULTISZ_DATA_TYPE 7
#define WINUSB_EXTRA_STRING_INDEX 0xee #define WINUSB_EXTRA_STRING_INDEX 0xee