format: start using clang-format with style=Google

pull/25/head
Pavol Rusnak 5 years ago
parent e1bc0ebc40
commit eba242b806
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D

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

@ -19,33 +19,31 @@
#include <string.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/rcc.h>
#include "bootloader.h"
#include "signatures.h"
#include "buttons.h"
#include "layout.h"
#include "memory.h"
#include "oled.h"
#include "rng.h"
#include "setup.h"
#include "signatures.h"
#include "usb.h"
#include "oled.h"
#include "util.h"
#include "signatures.h"
#include "layout.h"
#include "rng.h"
#include "memory.h"
void layoutFirmwareFingerprint(const uint8_t *hash)
{
void layoutFirmwareFingerprint(const uint8_t *hash) {
char str[4][17];
for (int i = 0; i < 4; 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 {
delay(100000);
buttonUpdate();
@ -53,15 +51,16 @@ bool get_button_response(void)
return button.YesUp;
}
void show_halt(const char *line1, const char *line2)
{
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, line2, NULL, "Unplug your TREZOR,", "reinstall firmware.", NULL);
void show_halt(const char *line1, const char *line2) {
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, line2, NULL,
"Unplug your TREZOR,", "reinstall firmware.", NULL);
shutdown();
}
static void show_unofficial_warning(const uint8_t *hash)
{
layoutDialog(&bmp_icon_warning, "Abort", "I'll take the risk", NULL, "WARNING!", NULL, "Unofficial firmware", "detected.", NULL, NULL);
static void show_unofficial_warning(const uint8_t *hash) {
layoutDialog(&bmp_icon_warning, "Abort", "I'll take the risk", NULL,
"WARNING!", NULL, "Unofficial firmware", "detected.", NULL,
NULL);
bool but = get_button_response();
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
}
static void __attribute__((noreturn)) load_app(int signed_firmware)
{
static void __attribute__((noreturn)) load_app(int signed_firmware) {
// zero out SRAM
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();
oledDrawBitmap(0, 0, &bmp_logo64);
if (firmware_present_new()) {
oledDrawStringCenter(90, 10, "TREZOR", 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 {
oledDrawStringCenter(90, 10, "Welcome!", FONT_STANDARD);
oledDrawStringCenter(90, 30, "Please visit", FONT_STANDARD);
@ -104,12 +105,12 @@ static void bootloader_loop(void)
usbLoop();
}
int main(void)
{
int main(void) {
#ifndef APPVER
setup();
#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
memory_protect();
oledInit();
@ -121,12 +122,12 @@ int main(void)
bool left_pressed = (buttonRead() & BTN_PIN_NO) == 0;
if (firmware_present_new() && !left_pressed) {
oledClear();
oledDrawBitmap(40, 0, &bmp_logo64_empty);
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];
int signed_firmware = signatures_new_ok(hdr, fingerprint);
@ -135,7 +136,9 @@ int main(void)
}
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();
}

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

@ -19,13 +19,13 @@
#include <string.h>
#include "signatures.h"
#include "ecdsa.h"
#include "secp256k1.h"
#include "sha2.h"
#include "bootloader.h"
#include "ecdsa.h"
#include "memory.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_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_SIG3 (FLASH_META_START + 0x00C0)
bool firmware_present_old(void)
{
if (memcmp(FLASH_PTR(FLASH_META_START), &FIRMWARE_MAGIC_OLD, 4)) { // magic does not match
bool firmware_present_old(void) {
if (memcmp(FLASH_PTR(FLASH_META_START), &FIRMWARE_MAGIC_OLD,
4)) { // magic does not match
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;
}
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 true;
}
int signatures_old_ok(void)
{
int signatures_old_ok(void) {
const uint32_t codelen = *((const uint32_t *)FLASH_META_CODELEN);
const uint8_t sigindex1 = *((const uint8_t *)FLASH_META_SIGINDEX1);
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 (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;
}
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;
}
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_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;
memcpy(&copy, hdr, sizeof(image_header));
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);
}
bool firmware_present_new(void)
{
const image_header *hdr = (const image_header *)FLASH_PTR(FLASH_FWHEADER_START);
bool firmware_present_new(void) {
const image_header *hdr =
(const image_header *)FLASH_PTR(FLASH_FWHEADER_START);
if (hdr->magic != FIRMWARE_MAGIC_NEW) return false;
// we need to ignore hdrlen for now
// because we keep reset_handler ptr there
@ -130,8 +136,7 @@ bool firmware_present_new(void)
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];
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);
}
if (hdr->sigindex1 < 1 || hdr->sigindex1 > 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 < 1 || hdr->sigindex1 > 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->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;
}
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;
}
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_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++) {
if (src[i]) return 0;
}
return 1;
}
int check_firmware_hashes(const image_header *hdr)
{
int check_firmware_hashes(const image_header *hdr) {
uint8_t hash[32];
// check hash of the first code chunk
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++;
}
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;
}
// check unused chunks

@ -17,32 +17,32 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/usb/usbd.h>
#include <libopencm3/stm32/flash.h>
#include <libopencm3/usb/usbd.h>
#include <string.h>
#include "buttons.h"
#include "bootloader.h"
#include "buttons.h"
#include "ecdsa.h"
#include "layout.h"
#include "memory.h"
#include "memzero.h"
#include "oled.h"
#include "rng.h"
#include "secp256k1.h"
#include "sha2.h"
#include "signatures.h"
#include "usb.h"
#include "layout.h"
#include "util.h"
#include "signatures.h"
#include "sha2.h"
#include "ecdsa.h"
#include "secp256k1.h"
#include "memzero.h"
#include "memory.h"
#include "usb21_standard.h"
#include "webusb.h"
#include "winusb.h"
#include "usb_desc.h"
#include "usb_send.h"
#include "usb_erase.h"
#include "usb_send.h"
enum {
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_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 chunk_pos = flash_pos % FW_CHUNK_SIZE;
if (chunk_pos == 0) {
@ -92,8 +91,11 @@ static void check_and_write_chunk(void)
flash_wait_for_last_operation();
flash_clear_status_flags();
flash_unlock();
for (uint32_t i = offset/sizeof(uint32_t); i < chunk_pos/sizeof(uint32_t); i++) {
flash_program_word(FLASH_FWHEADER_START + chunk_idx * FW_CHUNK_SIZE + i * sizeof(uint32_t), FW_CHUNK[i]);
for (uint32_t i = offset / sizeof(uint32_t); i < chunk_pos / sizeof(uint32_t);
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_lock();
@ -115,8 +117,7 @@ static void check_and_write_chunk(void)
chunk_idx++;
}
static void rx_callback(usbd_device *dev, uint8_t ep)
{
static void rx_callback(usbd_device *dev, uint8_t ep) {
(void)ep;
static uint16_t msg_id = 0xFFFF;
static uint8_t buf[64] __attribute__((aligned(4)));
@ -130,8 +131,10 @@ static void rx_callback(usbd_device *dev, uint8_t ep)
return;
}
if (flash_state == STATE_READY || flash_state == STATE_OPEN || flash_state == STATE_FLASHSTART || flash_state == STATE_CHECK) {
if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { // invalid start - discard
if (flash_state == STATE_READY || flash_state == STATE_OPEN ||
flash_state == STATE_FLASHSTART || flash_state == STATE_CHECK) {
if (buf[0] != '?' || buf[1] != '#' ||
buf[2] != '#') { // invalid start - discard
return;
}
// struct.unpack(">HL") => msg, size
@ -153,16 +156,22 @@ static void rx_callback(usbd_device *dev, uint8_t ep)
return;
}
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();
if (but) {
erase_storage_code_progress();
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);
} else {
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);
}
return;
@ -173,7 +182,9 @@ static void rx_callback(usbd_device *dev, uint8_t ep)
if (msg_id == 0x0006) { // FirmwareErase message (id 6)
bool proceed = false;
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();
} else {
proceed = true;
@ -181,8 +192,10 @@ static void rx_callback(usbd_device *dev, uint8_t ep)
if (proceed) {
// check whether the current firmware is signed (old or new method)
if (firmware_present_new()) {
const image_header *hdr = (const image_header *)FLASH_PTR(FLASH_FWHEADER_START);
old_was_signed = signatures_new_ok(hdr, NULL) & check_firmware_hashes(hdr);
const image_header *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()) {
old_was_signed = signatures_old_ok();
} else {
@ -194,7 +207,9 @@ static void rx_callback(usbd_device *dev, uint8_t ep)
} else {
send_msg_failure(dev);
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;
}
@ -218,7 +233,8 @@ static void rx_callback(usbd_device *dev, uint8_t ep)
show_halt("Firmware is too small.", NULL);
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);
flash_state = STATE_END;
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;
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++;
@ -303,7 +320,6 @@ static void rx_callback(usbd_device *dev, uint8_t ep)
}
if (flash_state == STATE_CHECK) {
// use the firmware header from RAM
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
// 2) signatures 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();
// check erasure
uint8_t hash[32];
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);
show_halt("Error installing", "firmware.");
return;
@ -344,7 +365,8 @@ static void rx_callback(usbd_device *dev, uint8_t ep)
// write firmware header only when hash was confirmed
if (hash_check_ok) {
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 {
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;
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);
shutdown();
} 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);
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;
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 uint8_t usbd_control_buffer[256] __attribute__((aligned(2)));
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 = {
.bLength = USB_DT_BOS_SIZE,
.bDescriptorType = USB_DT_BOS,
.bNumDeviceCaps = sizeof(capabilities) / sizeof(capabilities[0]),
.capabilities = capabilities
};
.capabilities = capabilities};
static void usbInit(void)
{
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));
static void usbInit(void) {
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));
usbd_register_set_config_callback(usbd_dev, set_config);
usb21_setup(usbd_dev, &bos_descriptor);
webusb_setup(usbd_dev, "trezor.io/start");
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;
if (btn_final) {
return;
@ -428,13 +454,13 @@ static void checkButtons(void)
}
}
void usbLoop(void)
{
void usbLoop(void) {
bool firmware_present = firmware_present_new();
usbInit();
for (;;) {
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();
}
}

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

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

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

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

@ -17,25 +17,28 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include "common.h"
#include "rng.h"
#include <stdio.h>
#include "bitmaps.h"
#include "firmware/usb.h"
#include "layout.h"
#include "oled.h"
#include "rng.h"
#include "util.h"
#include "bitmaps.h"
#include "firmware/usb.h"
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;
char line[128] = {0};
int y = icon->height + 3;
oledClear();
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)");
oledDrawString(0, y, line, FONT_STANDARD);
@ -62,18 +65,19 @@ void __attribute__((noreturn)) __fatal_error(const char *expr, const char *msg,
shutdown();
}
void __attribute__((noreturn)) 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.");
void __attribute__((noreturn))
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();
}
#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);
}
#endif
void hal_delay(uint32_t ms)
{
usbSleep(ms);
}
void hal_delay(uint32_t ms) { usbSleep(ms); }

@ -26,10 +26,17 @@
#define HW_ENTROPY_LEN (12 + 32)
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)) error_shutdown(const char *line1, const char *line2, const char *line3, const char *line4);
void __attribute__((noreturn))
__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);

@ -17,17 +17,17 @@
* 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/usbd.h>
#include <string.h>
#include "bitmaps.h"
#include "buttons.h"
#include "hmac.h"
#include "layout.h"
#include "oled.h"
#include "setup.h"
#include "hmac.h"
#include "pbkdf2.h"
#include "rng.h"
#include "setup.h"
const int states = 2;
int state = 0;
@ -58,63 +58,82 @@ static const struct usb_device_descriptor dev_descr = {
/* got via usbhid-dump from CP2110 */
static const uint8_t hid_report_descriptor[] = {
0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x09, 0x01, 0x75, 0x08, 0x95, 0x40, 0x26, 0xFF, 0x00,
0x15, 0x00, 0x85, 0x01, 0x95, 0x01, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x02,
0x95, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x03, 0x95, 0x03, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x04, 0x95, 0x04, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
0x91, 0x02, 0x85, 0x05, 0x95, 0x05, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x06,
0x95, 0x06, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x07, 0x95, 0x07, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x08, 0x95, 0x08, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
0x91, 0x02, 0x85, 0x09, 0x95, 0x09, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0A,
0x95, 0x0A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0B, 0x95, 0x0B, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0C, 0x95, 0x0C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
0x91, 0x02, 0x85, 0x0D, 0x95, 0x0D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0E,
0x95, 0x0E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0F, 0x95, 0x0F, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x10, 0x95, 0x10, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
0x91, 0x02, 0x85, 0x11, 0x95, 0x11, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x12,
0x95, 0x12, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x13, 0x95, 0x13, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x14, 0x95, 0x14, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
0x91, 0x02, 0x85, 0x15, 0x95, 0x15, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x16,
0x95, 0x16, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x17, 0x95, 0x17, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x18, 0x95, 0x18, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
0x91, 0x02, 0x85, 0x19, 0x95, 0x19, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1A,
0x95, 0x1A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1B, 0x95, 0x1B, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1C, 0x95, 0x1C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
0x91, 0x02, 0x85, 0x1D, 0x95, 0x1D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1E,
0x95, 0x1E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1F, 0x95, 0x1F, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x20, 0x95, 0x20, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
0x91, 0x02, 0x85, 0x21, 0x95, 0x21, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x22,
0x95, 0x22, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x23, 0x95, 0x23, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x24, 0x95, 0x24, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
0x91, 0x02, 0x85, 0x25, 0x95, 0x25, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x26,
0x95, 0x26, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x27, 0x95, 0x27, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x28, 0x95, 0x28, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
0x91, 0x02, 0x85, 0x29, 0x95, 0x29, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2A,
0x95, 0x2A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2B, 0x95, 0x2B, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2C, 0x95, 0x2C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
0x91, 0x02, 0x85, 0x2D, 0x95, 0x2D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2E,
0x95, 0x2E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2F, 0x95, 0x2F, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x30, 0x95, 0x30, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
0x91, 0x02, 0x85, 0x31, 0x95, 0x31, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x32,
0x95, 0x32, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x33, 0x95, 0x33, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x34, 0x95, 0x34, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
0x91, 0x02, 0x85, 0x35, 0x95, 0x35, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x36,
0x95, 0x36, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x37, 0x95, 0x37, 0x09, 0x01,
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,
0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x09, 0x01, 0x75, 0x08, 0x95,
0x40, 0x26, 0xFF, 0x00, 0x15, 0x00, 0x85, 0x01, 0x95, 0x01, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x02, 0x95, 0x02, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x03, 0x95, 0x03, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x04, 0x95, 0x04, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x05, 0x95, 0x05, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x06, 0x95, 0x06, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x07, 0x95, 0x07, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x08, 0x95, 0x08, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x09, 0x95, 0x09, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0A, 0x95, 0x0A, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0B, 0x95, 0x0B, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0C, 0x95, 0x0C, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0D, 0x95, 0x0D, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0E, 0x95, 0x0E, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0F, 0x95, 0x0F, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x10, 0x95, 0x10, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x11, 0x95, 0x11, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x12, 0x95, 0x12, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x13, 0x95, 0x13, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x14, 0x95, 0x14, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x15, 0x95, 0x15, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x16, 0x95, 0x16, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x17, 0x95, 0x17, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x18, 0x95, 0x18, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x19, 0x95, 0x19, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1A, 0x95, 0x1A, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1B, 0x95, 0x1B, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1C, 0x95, 0x1C, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1D, 0x95, 0x1D, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1E, 0x95, 0x1E, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1F, 0x95, 0x1F, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x20, 0x95, 0x20, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x21, 0x95, 0x21, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x22, 0x95, 0x22, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x23, 0x95, 0x23, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x24, 0x95, 0x24, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x25, 0x95, 0x25, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x26, 0x95, 0x26, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x27, 0x95, 0x27, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x28, 0x95, 0x28, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x29, 0x95, 0x29, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2A, 0x95, 0x2A, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2B, 0x95, 0x2B, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2C, 0x95, 0x2C, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2D, 0x95, 0x2D, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2E, 0x95, 0x2E, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2F, 0x95, 0x2F, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x30, 0x95, 0x30, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x31, 0x95, 0x31, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x32, 0x95, 0x32, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x33, 0x95, 0x33, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x34, 0x95, 0x34, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x35, 0x95, 0x35, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x36, 0x95, 0x36, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x37, 0x95, 0x37, 0x09, 0x01,
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,
};
@ -124,8 +143,9 @@ static const struct {
uint8_t bReportDescriptorType;
uint16_t wDescriptorLength;
} __attribute__((packed)) hid_report;
} __attribute__((packed)) hid_function = {
.hid_descriptor = {
} __attribute__((packed))
hid_function = {.hid_descriptor =
{
.bLength = sizeof(hid_function),
.bDescriptorType = USB_DT_HID,
.bcdHID = 0x0111,
@ -135,17 +155,18 @@ static const struct {
.hid_report = {
.bReportDescriptorType = USB_DT_REPORT,
.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,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x81,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.wMaxPacketSize = 64,
.bInterval = 1,
}, {
},
{
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x02,
@ -192,14 +213,14 @@ static const char *usb_strings[] = {
"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)dev;
if ((req->bmRequestType != 0x81) ||
(req->bRequest != USB_REQ_GET_DESCRIPTOR) ||
(req->wValue != 0x2200))
(req->bRequest != USB_REQ_GET_DESCRIPTOR) || (req->wValue != 0x2200))
return 0;
/* 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;
}
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)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;
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_register_control_callback(
dev,
USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE,
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
hid_control_request);
dev, USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE,
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, hid_control_request);
}
static usbd_device *usbd_dev;
static uint8_t usbd_control_buffer[128];
void usbInit(void)
{
usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer));
void usbInit(void) {
usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, 3,
usbd_control_buffer, sizeof(usbd_control_buffer));
usbd_register_set_config_callback(usbd_dev, hid_set_config);
}
int main(void)
{
int main(void) {
#ifndef APPVER
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();
#else
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
usbInit();

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

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

@ -89,7 +89,8 @@ static void setup_flash(void) {
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) {
perror("Failed to map flash emulation file");
exit(1);

@ -55,9 +55,11 @@ static int socket_setup(int port) {
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) {
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) {
perror("Failed to write socket");
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) {
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 (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_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));
return 0;
}

@ -17,45 +17,125 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/flash.h>
#include <stdint.h>
#include <string.h>
#include <libopencm3/stm32/flash.h>
#include "bl_data.h"
#include "memory.h"
#include "layout.h"
#include "gettext.h"
#include "layout.h"
#include "memory.h"
#include "util.h"
static int known_bootloader(int r, const uint8_t *hash) {
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 == 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
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
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
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 ==
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
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
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;
}
void check_bootloader(void)
{
void check_bootloader(void) {
#if MEMORY_PROTECT
uint8_t hash[32];
int r = memory_bootloader_hash(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();
}
@ -72,7 +152,8 @@ void check_bootloader(void)
// ATTEMPTING TO OVERWRITE BOOTLOADER WITH UNSIGNED FIRMWARE MAY BRICK
// 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
memory_write_unlock();
@ -95,13 +176,17 @@ void check_bootloader(void)
r = memory_bootloader_hash(hash);
if (r == 32 && 0 == memcmp(hash, bl_hash, 32)) {
// 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();
return;
}
}
// 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();
#endif
}

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

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

@ -17,36 +17,37 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <stdint.h>
#include <libopencm3/stm32/flash.h>
#include <stdint.h>
#include <string.h>
#include "messages.pb.h"
#include "common.h"
#include "trezor.h"
#include "sha2.h"
#include "aes/aes.h"
#include "pbkdf2.h"
#include "hmac.h"
#include "bip32.h"
#include "bip39.h"
#include "curves.h"
#include "util.h"
#include "memory.h"
#include "rng.h"
#include "common.h"
#include "config.h"
#include "curves.h"
#include "debug.h"
#include "protect.h"
#include "layout2.h"
#include "usb.h"
#include "gettext.h"
#include "u2f.h"
#include "hmac.h"
#include "layout2.h"
#include "memory.h"
#include "memzero.h"
#include "supervise.h"
#include "pbkdf2.h"
#include "protect.h"
#include "rng.h"
#include "sha2.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
#if !EMULATOR
@ -132,8 +133,7 @@ static const uint32_t CONFIG_VERSION = 11;
static const uint8_t FALSE_BYTE = '\x00';
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;
size_t i = 0;
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;
}
static secbool config_set_bool(uint16_t key, bool value)
{
static secbool config_set_bool(uint16_t key, bool value) {
if (value) {
return storage_set(key, &TRUE_BYTE, sizeof(TRUE_BYTE));
} 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;
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);
return sectrue;
} 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) {
return secfalse;
}
@ -184,8 +183,7 @@ static secbool config_get_bytes(uint16_t key, uint8_t *dest, uint16_t dest_size,
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) {
return secfalse;
}
@ -199,10 +197,10 @@ static secbool config_get_string(uint16_t key, char *dest, uint16_t dest_size)
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;
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;
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_LEN 0x100
static secbool config_upgrade_v10(void)
{
#define OLD_STORAGE_SIZE(last_member) (((offsetof(Storage, last_member) + pb_membersize(Storage, last_member)) + 3) & ~3)
static secbool config_upgrade_v10(void) {
#define OLD_STORAGE_SIZE(last_member) \
(((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 ||
memcmp(FLASH_PTR(FLASH_META_START + FLASH_META_LEN), &CONFIG_MAGIC_V10, sizeof(CONFIG_MAGIC_V10)) != 0) {
if (memcmp(FLASH_PTR(FLASH_META_START), &META_MAGIC_V10,
sizeof(META_MAGIC_V10)) != 0 ||
memcmp(FLASH_PTR(FLASH_META_START + FLASH_META_LEN), &CONFIG_MAGIC_V10,
sizeof(CONFIG_MAGIC_V10)) != 0) {
// wrong magic
return secfalse;
}
@ -225,8 +227,14 @@ static secbool config_upgrade_v10(void)
Storage config __attribute__((aligned(4)));
_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(&config, FLASH_PTR(FLASH_META_START + FLASH_META_LEN + sizeof(CONFIG_MAGIC_V10) + sizeof(config_uuid)), sizeof(config));
memcpy(
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 2: since 1.2.1
@ -267,14 +275,16 @@ static secbool config_upgrade_v10(void)
// Erase newly added fields.
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;
uint32_t pin_wait = 0;
if (config.version <= 5) {
// 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) {
pinctr = 31;
}
@ -296,7 +306,8 @@ static secbool config_upgrade_v10(void)
while (*u2fptr == 0) {
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;
while ((u2fword & 1) == 0) {
u2f_offset++;
@ -365,8 +376,7 @@ static secbool config_upgrade_v10(void)
return sectrue;
}
void config_init(void)
{
void config_init(void) {
char oldTiny = usbTiny(1);
config_upgrade_v10();
@ -381,7 +391,9 @@ void config_init(void)
uint16_t len = 0;
// 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));
storage_set(KEY_UUID, config_uuid, sizeof(config_uuid));
storage_set(KEY_VERSION, &CONFIG_VERSION, sizeof(CONFIG_VERSION));
@ -391,8 +403,7 @@ void config_init(void)
usbTiny(oldTiny);
}
void session_clear(bool lock)
{
void session_clear(bool lock) {
sessionSeedCached = secfalse;
memzero(&sessionSeed, sizeof(sessionSeed));
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);
}
static void config_compute_u2froot(const char* mnemonic, StorageHDNode *u2froot) {
static void config_compute_u2froot(const char *mnemonic,
StorageHDNode *u2froot) {
static CONFIDENTIAL HDNode node;
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);
hdnode_from_seed(sessionSeed, 64, NIST256P1_NAME, &node);
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));
u2froot->has_private_key = true;
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));
session_clear(false); // invalidate seed cache
}
@ -447,13 +460,14 @@ static void config_setNode(const HDNodeType *node) {
}
#if DEBUG_LINK
bool config_dumpNode(HDNodeType *node)
{
bool config_dumpNode(HDNodeType *node) {
memzero(node, sizeof(HDNodeType));
StorageHDNode storageNode;
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));
return false;
}
@ -476,11 +490,11 @@ bool config_dumpNode(HDNodeType *node)
}
#endif
void config_loadDevice(const LoadDevice *msg)
{
void config_loadDevice(const LoadDevice *msg) {
session_clear(false);
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) {
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') {
storage_delete(KEY_LABEL);
} 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) {
return;
}
@ -527,20 +539,18 @@ void config_setLanguage(const char *lang)
storage_set(KEY_LANGUAGE, lang, strnlen(lang, MAX_LANGUAGE_LEN));
}
void config_setPassphraseProtection(bool passphrase_protection)
{
void config_setPassphraseProtection(bool passphrase_protection) {
sessionSeedCached = secfalse;
sessionPassphraseCached = secfalse;
config_set_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection);
}
bool config_getPassphraseProtection(bool *passphrase_protection)
{
return sectrue == config_get_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection);
bool config_getPassphraseProtection(bool *passphrase_protection) {
return sectrue ==
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) {
storage_set(KEY_HOMESCREEN, data, size);
} 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);
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
if (usePassphrase == (sectrue == sessionSeedUsesPassphrase)
&& sectrue == sessionSeedCached) {
if (usePassphrase == (sectrue == sessionSeedUsesPassphrase) &&
sectrue == sessionSeedCached) {
return sessionSeed;
}
@ -580,7 +588,8 @@ const uint8_t *config_getSeed(bool usePassphrase)
}
}
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));
usbTiny(oldTiny);
sessionSeedCached = sectrue;
@ -591,15 +600,17 @@ const uint8_t *config_getSeed(bool usePassphrase)
return NULL;
}
static bool config_loadNode(const StorageHDNode *node, const char *curve, HDNode *out) {
return hdnode_from_xprv(node->depth, node->child_num, node->chain_code.bytes, node->private_key.bytes, curve, out);
static bool config_loadNode(const StorageHDNode *node, const char *curve,
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;
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));
return false;
}
@ -608,12 +619,14 @@ bool config_getU2FRoot(HDNode *node)
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
StorageHDNode storageHDNode;
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()) {
memzero(&storageHDNode, sizeof(storageHDNode));
return false;
@ -624,23 +637,29 @@ bool config_getRootNode(HDNode *node, const char *curve, bool usePassphrase)
}
bool passphrase_protection = false;
config_getPassphraseProtection(&passphrase_protection);
if (passphrase_protection && sectrue == sessionPassphraseCached && sessionPassphrase[0] != '\0') {
if (passphrase_protection && sectrue == sessionPassphraseCached &&
sessionPassphrase[0] != '\0') {
// decrypt hd node
uint8_t secret[64];
PBKDF2_HMAC_SHA512_CTX pctx;
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);
for (int i = 0; i < 8; i++) {
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);
usbTiny(oldTiny);
aes_decrypt_ctx ctx;
aes_decrypt_key256(secret, &ctx);
aes_cbc_decrypt(node->chain_code, node->chain_code, 32, secret + 32, &ctx);
aes_cbc_decrypt(node->private_key, node->private_key, 32, secret + 32, &ctx);
aes_cbc_decrypt(node->chain_code, node->chain_code, 32, secret + 32,
&ctx);
aes_cbc_decrypt(node->private_key, node->private_key, 32, secret + 32,
&ctx);
}
return true;
}
@ -654,18 +673,15 @@ bool config_getRootNode(HDNode *node, const char *curve, bool usePassphrase)
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);
}
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);
}
bool config_getHomescreen(uint8_t *dest, uint16_t dest_size)
{
bool config_getHomescreen(uint8_t *dest, uint16_t dest_size) {
uint16_t len = 0;
secbool ret = storage_get(KEY_HOMESCREEN, dest, dest_size, &len);
if (sectrue != ret || len != HOMESCREEN_SIZE) {
@ -674,13 +690,13 @@ bool config_getHomescreen(uint8_t *dest, uint16_t dest_size)
return true;
}
bool config_setMnemonic(const char *mnemonic)
{
bool config_setMnemonic(const char *mnemonic) {
if (mnemonic == NULL) {
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;
}
@ -700,24 +716,23 @@ bool config_setMnemonic(const char *mnemonic)
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);
}
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);
}
/* Check whether mnemonic matches storage. The mnemonic must be
* a null-terminated string.
*/
bool config_containsMnemonic(const char *mnemonic)
{
bool config_containsMnemonic(const char *mnemonic) {
uint16_t len = 0;
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;
}
@ -727,7 +742,8 @@ bool config_containsMnemonic(const char *mnemonic)
memzero(stored_mnemonic, sizeof(stored_mnemonic));
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;
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
* 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);
secbool ret = storage_unlock(pin_to_int(pin));
usbTiny(oldTiny);
return sectrue == ret;
}
bool config_hasPin(void)
{
return sectrue == storage_has_pin();
}
bool config_hasPin(void) { 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);
if (new_pin_int == 0) {
return false;
@ -781,25 +792,22 @@ bool config_changePin(const char *old_pin, const char *new_pin)
}
#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);
}
#endif
void session_cachePassphrase(const char *passphrase)
{
void session_cachePassphrase(const char *passphrase) {
strlcpy(sessionPassphrase, passphrase, sizeof(sessionPassphrase));
sessionPassphraseCached = sectrue;
}
bool session_isPassphraseCached(void)
{
bool session_isPassphraseCached(void) {
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) {
return false;
} else {
@ -825,60 +833,45 @@ bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphras
return true;
}
bool session_isUnlocked(void)
{
return sectrue == storage_is_unlocked();
}
bool session_isUnlocked(void) { return sectrue == storage_is_unlocked(); }
bool config_isInitialized(void)
{
bool config_isInitialized(void) {
bool initialized = false;
config_get_bool(KEY_INITIALIZED, &initialized);
return initialized;
}
bool config_getImported(bool* imported)
{
bool config_getImported(bool *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);
}
bool config_getNeedsBackup(bool *needs_backup)
{
bool config_getNeedsBackup(bool *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);
}
bool config_getUnfinishedBackup(bool *unfinished_backup)
{
bool config_getUnfinishedBackup(bool *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);
}
bool config_getNoBackup(bool *no_backup)
{
bool config_getNoBackup(bool *no_backup) {
return sectrue == config_get_bool(KEY_NO_BACKUP, no_backup);
}
void config_setNoBackup(void)
{
config_set_bool(KEY_NO_BACKUP, true);
}
void config_setNoBackup(void) { config_set_bool(KEY_NO_BACKUP, true); }
void config_applyFlags(uint32_t flags)
{
void config_applyFlags(uint32_t flags) {
uint32_t old_flags = 0;
config_get_uint32(KEY_FLAGS, &old_flags);
flags |= old_flags;
@ -888,25 +881,21 @@ void config_applyFlags(uint32_t 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);
}
uint32_t config_nextU2FCounter(void)
{
uint32_t config_nextU2FCounter(void) {
uint32_t u2fcounter = 0;
storage_next_counter(KEY_U2F_COUNTER, &u2fcounter);
return u2fcounter;
}
void config_setU2FCounter(uint32_t u2fcounter)
{
void config_setU2FCounter(uint32_t u2fcounter) {
storage_set_counter(KEY_U2F_COUNTER, u2fcounter);
}
uint32_t config_getAutoLockDelayMs()
{
uint32_t config_getAutoLockDelayMs() {
if (sectrue == autoLockDelayMsCached) {
return autoLockDelayMs;
}
@ -922,18 +911,17 @@ uint32_t config_getAutoLockDelayMs()
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
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;
autoLockDelayMsCached = sectrue;
}
}
void config_wipe(void)
{
void config_wipe(void) {
char oldTiny = usbTiny(1);
storage_wipe();
if (storage_is_unlocked() != sectrue) {

@ -109,12 +109,14 @@ void config_setHomescreen(const uint8_t *data, uint32_t size);
void session_cachePassphrase(const char *passphrase);
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_containsMnemonic(const char *mnemonic);
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
bool config_dumpNode(HDNodeType *node);

@ -17,24 +17,23 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "crypto.h"
#include "sha2.h"
#include "pbkdf2.h"
#include <string.h>
#include "address.h"
#include "aes/aes.h"
#include "hmac.h"
#include "base58.h"
#include "bip32.h"
#include "layout.h"
#include "cash_addr.h"
#include "coins.h"
#include "curves.h"
#include "hmac.h"
#include "layout.h"
#include "pbkdf2.h"
#include "secp256k1.h"
#include "address.h"
#include "coins.h"
#include "base58.h"
#include "segwit_addr.h"
#include "cash_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) {
out[0] = len & 0xFF;
return 1;
@ -53,8 +52,7 @@ uint32_t ser_length(uint32_t len, uint8_t *out)
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) {
hasher_Update(hasher, (const uint8_t *)&len, 1);
return 1;
@ -71,8 +69,7 @@ uint32_t ser_length_hash(Hasher *hasher, uint32_t len)
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) {
*out = in[0];
return 1;
@ -89,19 +86,21 @@ uint32_t deser_length(const uint8_t *in, uint32_t *out)
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
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
const curve_info *ed25519_curve_info = get_curve_by_name(ED25519_NAME);
if (ed25519_curve_info && node->curve == ed25519_curve_info) {
// 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 {
// Ensure 256-bit digest before proceeding
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_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];
uint32_t l = ser_length(message_len, varint);
hasher_Update(&hasher, varint, l);
@ -122,8 +124,9 @@ static void cryptoMessageHash(const CoinInfo *coin, const uint8_t *message, size
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];
cryptoMessageHash(coin, message, message_len, hash);
@ -148,8 +151,9 @@ int cryptoMessageSign(const CoinInfo *coin, HDNode *node, InputScriptType script
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
if (signature[0] < 27 || signature[0] > 43) {
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
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;
}
// 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;
}
} 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);
if (memcmp(recovered_raw, addr_raw, len) != 0
|| len != address_prefix_bytes_len(coin->address_type) + 20) {
ecdsa_get_address_raw(pubkey, coin->address_type,
coin->curve->hasher_pubkey, recovered_raw);
if (memcmp(recovered_raw, addr_raw, len) != 0 ||
len != address_prefix_bytes_len(coin->address_type) + 20) {
return 2;
}
} else
// segwit-in-p2sh
if (signature[0] >= 35 && signature[0] <= 38) {
size_t len = base58_decode_check(address, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE);
ecdsa_get_address_segwit_p2sh_raw(pubkey, coin->address_type_p2sh, coin->curve->hasher_pubkey, recovered_raw);
if (memcmp(recovered_raw, addr_raw, len) != 0
|| len != address_prefix_bytes_len(coin->address_type_p2sh) + 20) {
size_t len = base58_decode_check(address, coin->curve->hasher_base58,
addr_raw, MAX_ADDR_RAW_SIZE);
ecdsa_get_address_segwit_p2sh_raw(pubkey, coin->address_type_p2sh,
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;
}
} else
@ -204,13 +214,13 @@ int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t mes
if (signature[0] >= 39 && signature[0] <= 42) {
int witver;
size_t len;
if (!coin->bech32_prefix
|| !segwit_addr_decode(&witver, recovered_raw, &len, coin->bech32_prefix, address)) {
if (!coin->bech32_prefix ||
!segwit_addr_decode(&witver, recovered_raw, &len, coin->bech32_prefix,
address)) {
return 4;
}
ecdsa_get_pubkeyhash(pubkey, coin->curve->hasher_pubkey, addr_raw);
if (memcmp(recovered_raw, addr_raw, len) != 0
|| witver != 0 || len != 20) {
if (memcmp(recovered_raw, addr_raw, len) != 0 || witver != 0 || len != 20) {
return 2;
}
} else {
@ -221,7 +231,10 @@ int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t mes
}
/* 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
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);
memcpy(payload + 1 + l, msg, msg_size);
memcpy(payload + 1 + l + msg_size, address_raw, 21);
hdnode_from_xprv(0, 0, 0, privkey, privkey, SECP256K1_NAME, &node);
if (cryptoMessageSign(&node, msg, msg_size, payload + 1 + l + msg_size + 21) != 0) {
return 1;
hdnode_from_xprv(0, 0, 0, privkey, privkey, SECP256K1_NAME,
&node); if (cryptoMessageSign(&node, msg, msg_size, payload + 1 + l + msg_size +
21) != 0) { return 1;
}
*payload_len = 1 + l + msg_size + 21 + 65;
} else {
@ -261,11 +274,13 @@ int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_siz
uint8_t salt[22 + 33];
memcpy(salt, "Bitcoin Secure Message", 22);
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
aes_encrypt_ctx 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
uint8_t out[32];
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;
}
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) {
return 1;
@ -294,7 +312,8 @@ int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_le
memcpy(salt, "Bitcoin Secure Message", 22);
salt[22] = 0x02 | (nonce->y.val[0] & 0x01);
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
uint8_t out[32];
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_cfb_decrypt(payload, payload, payload_len, keying_bytes + 64, &ctx);
// check first byte
if (payload[0] != 0x00 && payload[0] != 0x01 && payload[0] != 0x80 && payload[0] != 0x81) {
return 3;
if (payload[0] != 0x00 && payload[0] != 0x01 && payload[0] != 0x80 &&
payload[0] != 0x81) { return 3;
}
*signing = payload[0] & 0x01;
*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) {
return 4;
}
// FIXME: cryptoMessageVerify changed to take the address_type as a parameter.
if (cryptoMessageVerify(payload + 1 + l, o, payload + 1 + l + o, payload + 1 + l + o + 21) != 0) {
return 5;
// FIXME: cryptoMessageVerify changed to take the address_type
as a parameter. if (cryptoMessageVerify(payload + 1 + l, o, payload + 1 + l + o,
payload + 1 + l + o + 21) != 0) { return 5;
}
memcpy(address_raw, payload + 1 + l + o, 21);
} 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 uint32_t *address_n;
uint32_t address_n_count;
@ -346,8 +366,7 @@ const HDNode *cryptoMultisigPubkey(const CoinInfo *coin, const MultisigRedeemScr
node_ptr = &(multisig->nodes[index]);
address_n = multisig->address_n;
address_n_count = multisig->address_n_count;
} else
if (multisig->pubkeys_count) { // use multisig->pubkeys
} else if (multisig->pubkeys_count) { // use multisig->pubkeys
if (index >= multisig->pubkeys_count) {
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->has_public_key || node_ptr->public_key.size != 33) return 0;
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;
}
layoutProgressUpdate(true);
@ -373,13 +394,14 @@ const HDNode *cryptoMultisigPubkey(const CoinInfo *coin, const MultisigRedeemScr
return &node;
}
uint32_t cryptoMultisigPubkeyCount(const MultisigRedeemScriptType *multisig)
{
return multisig->nodes_count ? multisig->nodes_count : multisig->pubkeys_count;
uint32_t cryptoMultisigPubkeyCount(const MultisigRedeemScriptType *multisig) {
return multisig->nodes_count ? multisig->nodes_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++) {
const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i);
if (pubnode && memcmp(pubnode->public_key, pubkey, 33) == 0) {
@ -389,8 +411,8 @@ int cryptoMultisigPubkeyIndex(const CoinInfo *coin, const MultisigRedeemScriptTy
return -1;
}
int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t *hash)
{
int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig,
uint8_t *hash) {
static const HDNodeType *pubnodes[15], *swap;
const uint32_t n = cryptoMultisigPubkeyCount(multisig);
if (n < 1 || n > 15) {
@ -402,21 +424,22 @@ int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t
for (uint32_t i = 0; i < n; i++) {
if (multisig->nodes_count) { // use multisig->nodes
pubnodes[i] = &(multisig->nodes[i]);
} else
if (multisig->pubkeys_count) { // use multisig->pubkeys
} else if (multisig->pubkeys_count) { // use multisig->pubkeys
pubnodes[i] = &(multisig->pubkeys[i].node);
} else {
return 0;
}
}
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;
}
// minsort according to pubkey
for (uint32_t i = 0; i < n - 1; i++) {
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];
pubnodes[i] = pubnodes[j];
pubnodes[j] = swap;
@ -428,9 +451,12 @@ int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t
sha256_Init(&ctx);
sha256_Update(&ctx, (const uint8_t *)&(multisig->m), sizeof(uint32_t));
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]->fingerprint), sizeof(uint32_t));
sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->child_num), sizeof(uint32_t));
sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->depth),
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]->public_key.bytes, 33);
}
@ -440,28 +466,32 @@ int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t
return 1;
}
int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash)
{
int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash) {
SHA256_CTX ctx;
sha256_Init(&ctx);
sha256_Update(&ctx, (const uint8_t *)&(identity->index), sizeof(uint32_t));
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);
}
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);
}
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]) {
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]) {
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);
return 1;

@ -20,13 +20,13 @@
#ifndef __CRYPTO_H__
#define __CRYPTO_H__
#include <bip32.h>
#include <ecdsa.h>
#include <pb.h>
#include <sha2.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <ecdsa.h>
#include <bip32.h>
#include <sha2.h>
#include <pb.h>
#include "coins.h"
#include "hasher.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);
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
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 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);
*/
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);
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);

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

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

@ -20,22 +20,22 @@
*/
#include "ethereum.h"
#include "address.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 "transaction.h"
#include "ecdsa.h"
#include "messages.pb.h"
#include "protect.h"
#include "crypto.h"
#include "secp256k1.h"
#include "sha3.h"
#include "address.h"
#include "transaction.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. */
#define MAX_CHAIN_ID 2147483629
@ -48,16 +48,14 @@ static uint32_t chain_id;
static uint32_t tx_type;
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);
}
/*
* 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];
if (length == 1 && firstbyte <= 0x7f) {
/* 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.
*/
static void hash_rlp_list_length(uint32_t length)
{
static void hash_rlp_list_length(uint32_t length) {
uint8_t buf[4];
if (length <= 55) {
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.
*/
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_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.
* 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) {
return;
}
@ -144,8 +139,7 @@ static void hash_rlp_number(uint32_t number)
* NOTE: supports up to 16MB of data (how unlikely...)
* 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) {
return 1;
} 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) {
return 1;
}
else if (number <= 0xff) {
} else if (number <= 0xff) {
return 2;
}
else if (number <= 0xffff) {
} else if (number <= 0xffff) {
return 3;
}
else if (number <= 0xffffff) {
} else if (number <= 0xffffff) {
return 4;
} else {
return 5;
}
}
static void send_request_chunk(void)
{
int progress = 1000 - (data_total > 1000000
? data_left / (data_total/800)
static void send_request_chunk(void) {
int progress = 1000 - (data_total > 1000000 ? data_left / (data_total / 800)
: data_left * 800 / data_total);
layoutProgress(_("Signing"), progress);
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);
}
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;
return (v & 2) == 0;
}
static void send_signature(void)
{
static void send_signature(void) {
uint8_t hash[32], sig[64];
uint8_t v;
layoutProgress(_("Signing"), 1000);
@ -209,7 +195,8 @@ static void send_signature(void)
}
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"));
ethereum_signing_abort();
return;
@ -245,8 +232,8 @@ static void send_signature(void)
* using standard ethereum units.
* 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;
bn_read_uint32(1000000000, &bn1e9);
const char *suffix = NULL;
@ -254,12 +241,10 @@ static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token,
if (token == UnknownToken) {
strlcpy(buf, "Unknown token value", buflen);
return;
} else
if (token != NULL) {
} else if (token != NULL) {
suffix = token->ticker;
decimals = token->decimals;
} else
if (bn_is_less(amnt, &bn1e9)) {
} else if (bn_is_less(amnt, &bn1e9)) {
suffix = " Wei";
decimals = 0;
} else {
@ -272,8 +257,9 @@ static void ethereumFormatAmount(const bignum256 *amnt, const TokenType *token,
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;
uint8_t pad_val[32];
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;
// constants from trezor-common/defs/ethereum/networks.json
switch (chain_id) {
case 30: rskip60 = true; break;
case 31: rskip60 = true; break;
case 30:
rskip60 = true;
break;
case 31:
rskip60 = true;
break;
}
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));
}
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
_("Confirm"),
NULL,
_("Send"),
amount,
_to1,
_to2,
_to3,
NULL
);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("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 summary[20];
uint32_t printed = 0;
@ -351,27 +332,17 @@ static void layoutEthereumData(const uint8_t *data, uint32_t len, uint32_t total
number = number / 10;
}
char *summarystart = summary;
if (total_len == printed)
summarystart = summary + 4;
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
_("Confirm"),
NULL,
_("Transaction data:"),
hexdata[0],
hexdata[1],
hexdata[2],
summarystart,
NULL
);
if (total_len == printed) summarystart = summary + 4;
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Transaction data:"), hexdata[0], hexdata[1], hexdata[2],
summarystart, NULL);
}
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_limit, uint32_t gas_limit_len,
bool is_token)
{
bool is_token) {
bignum256 val, gas;
uint8_t pad_val[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));
}
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
_("Confirm"),
NULL,
_("Really send"),
tx_value,
_("paying up to"),
gas_value,
_("for gas?"),
NULL
);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), 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 ..)
*/
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) {
return false;
}
@ -450,17 +412,14 @@ static bool ethereum_signing_check(const EthereumSignTx *msg)
return true;
}
void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node)
{
void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) {
ethereum_signing = true;
sha3_256_Init(&keccak_ctx);
memzero(&msg_tx_request, sizeof(EthereumTxRequest));
/* set fields to 0, to avoid conditions later */
if (!msg->has_value)
msg->value.size = 0;
if (!msg->has_data_initial_chunk)
msg->data_initial_chunk.size = 0;
if (!msg->has_value) msg->value.size = 0;
if (!msg->has_data_initial_chunk) msg->data_initial_chunk.size = 0;
bool toset;
uint8_t pubkeyhash[20];
if (msg->has_to && ethereum_parse(msg->to, pubkeyhash)) {
@ -470,13 +429,13 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node)
toset = false;
memzero(pubkeyhash, sizeof(pubkeyhash));
}
if (!msg->has_nonce)
msg->nonce.size = 0;
if (!msg->has_nonce) msg->nonce.size = 0;
/* eip-155 chain id */
if (msg->has_chain_id) {
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();
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_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();
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.
*/
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();
return;
}
@ -517,7 +478,8 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node)
data_total = 0;
}
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();
return;
}
@ -532,15 +494,20 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node)
const TokenType *token = NULL;
// detect ERC-20 token
if (toset && msg->value.size == 0 && data_total == 68 && 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) {
if (toset && msg->value.size == 0 && data_total == 68 &&
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);
}
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 {
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)) {
@ -550,7 +517,8 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node)
}
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)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
ethereum_signing_abort();
@ -558,9 +526,9 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node)
}
}
layoutEthereumFee(msg->value.bytes, msg->value.size,
msg->gas_price.bytes, msg->gas_price.size,
msg->gas_limit.bytes, msg->gas_limit.size, token != NULL);
layoutEthereumFee(msg->value.bytes, msg->value.size, msg->gas_price.bytes,
msg->gas_price.size, msg->gas_limit.bytes,
msg->gas_limit.size, token != NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
ethereum_signing_abort();
@ -573,11 +541,14 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node)
layoutProgress(_("Signing"), 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_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]);
rlp_length +=
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(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) {
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) {
fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Ethereum signing mode"));
fsm_sendFailure(FailureType_Failure_UnexpectedMessage,
_("Not in Ethereum signing mode"));
layoutHome();
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)) {
fsm_sendFailure(FailureType_Failure_DataError, _("Empty data chunk received"));
fsm_sendFailure(FailureType_Failure_DataError,
_("Empty data chunk received"));
ethereum_signing_abort();
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) {
memzero(privkey, sizeof(privkey));
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;
sha3_256_Init(&ctx);
sha3_Update(&ctx, (const uint8_t *)"\x19" "Ethereum Signed Message:\n", 26);
uint8_t c;
if (message_len > 1000000000) { c = '0' + message_len / 1000000000 % 10; sha3_Update(&ctx, &c, 1); }
if (message_len > 100000000) { c = '0' + message_len / 100000000 % 10; sha3_Update(&ctx, &c, 1); }
if (message_len > 10000000) { 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);
if (message_len > 1000000000) {
c = '0' + message_len / 1000000000 % 10;
sha3_Update(&ctx, &c, 1);
}
if (message_len > 100000000) {
c = '0' + message_len / 100000000 % 10;
sha3_Update(&ctx, &c, 1);
}
if (message_len > 10000000) {
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);
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];
if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash)) {
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);
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"));
return;
}
@ -701,8 +701,7 @@ void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node, E
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) {
fsm_sendFailure(FailureType_Failure_DataError, _("Malformed signature"));
return 1;
@ -726,8 +725,8 @@ int ethereum_message_verify(const EthereumVerifyMessage *msg)
if (v >= 27) {
v -= 27;
}
if (v >= 2 ||
ecdsa_recover_pub_from_sig(&secp256k1, pubkey, msg->signature.bytes, hash, v) != 0) {
if (v >= 2 || ecdsa_recover_pub_from_sig(
&secp256k1, pubkey, msg->signature.bytes, hash, v) != 0) {
return 2;
}
@ -743,14 +742,12 @@ int ethereum_message_verify(const EthereumVerifyMessage *msg)
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);
size_t len = strlen(address);
if (len == 40) {
// do nothing
} else
if (len == 42) {
} else if (len == 42) {
// check for "0x" prefix and strip it when required
if (address[0] != '0') 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++) {
if (address[i] >= '0' && address[i] <= '9') {
pubkeyhash[i / 2] |= (address[i] - '0') << ((1 - (i % 2)) * 4);
} else
if (address[i] >= 'a' && address[i] <= 'f') {
} else if (address[i] >= 'a' && address[i] <= 'f') {
pubkeyhash[i / 2] |= ((address[i] - 'a') + 10) << ((1 - (i % 2)) * 4);
} else
if (address[i] >= 'A' && address[i] <= 'F') {
} else if (address[i] >= 'A' && address[i] <= 'F') {
pubkeyhash[i / 2] |= ((address[i] - 'A') + 10) << ((1 - (i % 2)) * 4);
} else {
return false;

@ -20,8 +20,8 @@
#ifndef __ETHEREUM_H__
#define __ETHEREUM_H__
#include <stdint.h>
#include <stdbool.h>
#include <stdint.h>
#include "bip32.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_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);
bool ethereum_parse(const char *address, uint8_t pubkeyhash[20]);

@ -19,45 +19,44 @@
#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 "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 "hmac.h"
#include "crypto.h"
#include "base58.h"
#include "bip32.h"
#include "bip39.h"
#include "coins.h"
#include "config.h"
#include "crypto.h"
#include "curves.h"
#include "secp256k1.h"
#include "debug.h"
#include "ecdsa.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 "nem2.h"
#include "oled.h"
#include "pinmatrix.h"
#include "protect.h"
#include "recovery.h"
#include "reset.h"
#include "rfc6979.h"
#include "gettext.h"
#include "supervise.h"
#include "messages.pb.h"
#include "rng.h"
#include "secp256k1.h"
#include "signing.h"
#include "stellar.h"
#include "lisk.h"
#include "memzero.h"
#include "supervise.h"
#include "transaction.h"
#include "trezor.h"
#include "usb.h"
#include "util.h"
// message methods
@ -76,7 +75,8 @@ static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned));
#define CHECK_NOT_INITIALIZED \
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; \
}
@ -99,8 +99,7 @@ static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned));
return; \
}
void fsm_sendSuccess(const char *text)
{
void fsm_sendSuccess(const char *text) {
RESP_INIT(Success);
if (text) {
resp->has_message = true;
@ -110,7 +109,8 @@ void fsm_sendSuccess(const char *text)
}
#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
void fsm_sendFailure(FailureType code, const char *text)
#endif
@ -184,8 +184,7 @@ void fsm_sendFailure(FailureType code, const char *text)
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;
if (has_name) {
coin = coinByName(name);
@ -200,37 +199,45 @@ static const CoinInfo *fsm_getCoin(bool has_name, const char *name)
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;
if (fingerprint) {
*fingerprint = 0;
}
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();
return 0;
}
if (!address_n || address_n_count == 0) {
return &node;
}
if (hdnode_private_ckd_cached(&node, address_n, address_n_count, fingerprint) == 0) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key"));
if (hdnode_private_ckd_cached(&node, address_n, address_n_count,
fingerprint) == 0) {
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to derive private key"));
layoutHome();
return 0;
}
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;
for (;;) {
const char *display_addr = address;
if (prefixlen && !qrcode) {
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)) {
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_ethereum.h"
#include "fsm_msg_common.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_stellar.h"
#include "fsm_msg_lisk.h"
#include "fsm_msg_debug.h"

@ -24,19 +24,21 @@
#include "messages-crypto.pb.h"
#include "messages-debug.pb.h"
#include "messages-ethereum.pb.h"
#include "messages-lisk.pb.h"
#include "messages-management.pb.h"
#include "messages-nem.pb.h"
#include "messages-stellar.pb.h"
#include "messages-lisk.pb.h"
// message functions
void fsm_sendSuccess(const char *text);
#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
void fsm_sendFailure(FailureType code, const char *text);
#endif
@ -67,7 +69,8 @@ void fsm_msgSetU2FCounter(const SetU2FCounter *msg);
// coin
void fsm_msgGetPublicKey(const GetPublicKey *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_msgSignMessage(const SignMessage *msg);
void fsm_msgVerifyMessage(const VerifyMessage *msg);
@ -92,7 +95,9 @@ void fsm_msgDebugLinkFlashErase(const DebugLinkFlashErase *msg);
// ethereum
void fsm_msgEthereumGetAddress(const EthereumGetAddress *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_msgEthereumSignMessage(const EthereumSignMessage *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_msgLiskSignMessage(const LiskSignMessage *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
void fsm_msgNEMGetAddress(NEMGetAddress *msg); // not const because we mutate msg->network
void fsm_msgNEMSignTx(NEMSignTx *msg); // not const because we mutate msg->network
void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg); // not const because we mutate msg->payload
void fsm_msgNEMGetAddress(
NEMGetAddress *msg); // not const because we mutate msg->network
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
void fsm_msgStellarGetAddress(const StellarGetAddress *msg);

@ -17,15 +17,15 @@
* 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);
CHECK_INITIALIZED
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);
if (!coin) return;
@ -35,7 +35,8 @@ void fsm_msgGetPublicKey(const GetPublicKey *msg)
curve = msg->ecdsa_curve_name;
}
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;
hdnode_fill_public_key(node);
@ -64,16 +65,21 @@ void fsm_msgGetPublicKey(const GetPublicKey *msg)
}
resp->has_xpub = true;
if (coin->xpub_magic && (script_type == InputScriptType_SPENDADDRESS || script_type == InputScriptType_SPENDMULTISIG)) {
hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub, sizeof(resp->xpub));
} else
if (coin->has_segwit && coin->xpub_magic_segwit_p2sh && script_type == InputScriptType_SPENDP2SHWITNESS) {
hdnode_serialize_public(node, fingerprint, coin->xpub_magic_segwit_p2sh, 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));
if (coin->xpub_magic && (script_type == InputScriptType_SPENDADDRESS ||
script_type == InputScriptType_SPENDMULTISIG)) {
hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub,
sizeof(resp->xpub));
} else if (coin->has_segwit && coin->xpub_magic_segwit_p2sh &&
script_type == InputScriptType_SPENDP2SHWITNESS) {
hdnode_serialize_public(node, fingerprint, coin->xpub_magic_segwit_p2sh,
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 {
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();
return;
}
@ -82,13 +88,15 @@ void fsm_msgGetPublicKey(const GetPublicKey *msg)
layoutHome();
}
void fsm_msgSignTx(const SignTx *msg)
{
void fsm_msgSignTx(const SignTx *msg) {
CHECK_INITIALIZED
CHECK_PARAM(msg->inputs_count > 0, _("Transaction must have at least one input"));
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_PARAM(msg->inputs_count > 0,
_("Transaction must have at least one input"));
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
@ -100,15 +108,13 @@ void fsm_msgSignTx(const SignTx *msg)
signing_init(msg, coin, node);
}
void fsm_msgTxAck(TxAck *msg)
{
void fsm_msgTxAck(TxAck *msg) {
CHECK_PARAM(msg->has_tx, _("No transaction provided"));
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;
// m : no path
@ -182,8 +188,7 @@ static bool path_mismatched(const CoinInfo *coin, const GetAddress *msg)
return false;
}
void fsm_msgGetAddress(const GetAddress *msg)
{
void fsm_msgGetAddress(const GetAddress *msg) {
RESP_INIT(Address);
CHECK_INITIALIZED
@ -192,7 +197,8 @@ void fsm_msgGetAddress(const GetAddress *msg)
const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name);
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;
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
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"));
layoutHome();
return;
@ -223,7 +230,9 @@ void fsm_msgGetAddress(const GetAddress *msg)
bool mismatch = path_mismatched(coin, msg);
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)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
@ -233,7 +242,9 @@ void fsm_msgGetAddress(const GetAddress *msg)
bool is_cashaddr = coin->cashaddr_prefix != NULL;
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;
}
}
@ -243,9 +254,9 @@ void fsm_msgGetAddress(const GetAddress *msg)
layoutHome();
}
void fsm_msgSignMessage(const SignMessage *msg)
{
// CHECK_PARAM(is_ascii_only(msg->message.bytes, msg->message.size), _("Cannot sign non-ASCII strings"));
void fsm_msgSignMessage(const SignMessage *msg) {
// CHECK_PARAM(is_ascii_only(msg->message.bytes, msg->message.size), _("Cannot
// sign non-ASCII strings"));
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);
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;
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;
hdnode_fill_public_key(node);
if (!compute_address(coin, msg->script_type, node, false, NULL, resp->address)) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Error computing address"));
if (!compute_address(coin, msg->script_type, node, false, NULL,
resp->address)) {
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Error computing address"));
layoutHome();
return;
}
@ -278,20 +293,22 @@ void fsm_msgSignMessage(const SignMessage *msg)
resp->signature.size = 65;
msg_write(MessageType_MessageType_MessageSignature, resp);
} else {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Error signing message"));
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Error signing message"));
}
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_message, _("No message provided"));
const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name);
if (!coin) return;
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);
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);

@ -17,8 +17,7 @@
* 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();
signing_abort();
if (msg && msg->has_state && msg->state.size == 64) {
@ -37,44 +36,63 @@ void fsm_msgInitialize(const Initialize *msg)
fsm_msgGetFeatures(0);
}
void fsm_msgGetFeatures(const GetFeatures *msg)
{
void fsm_msgGetFeatures(const GetFeatures *msg) {
(void)msg;
RESP_INIT(Features);
resp->has_vendor = true; strlcpy(resp->vendor, "trezor.io", sizeof(resp->vendor));
resp->has_major_version = true; resp->major_version = VERSION_MAJOR;
resp->has_minor_version = true; resp->minor_version = VERSION_MINOR;
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));
resp->has_vendor = true;
strlcpy(resp->vendor, "trezor.io", sizeof(resp->vendor));
resp->has_major_version = true;
resp->major_version = VERSION_MAJOR;
resp->has_minor_version = true;
resp->minor_version = VERSION_MINOR;
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
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
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_initialized = true; resp->initialized = config_isInitialized();
resp->has_initialized = true;
resp->initialized = config_isInitialized();
resp->has_imported = config_getImported(&(resp->imported));
resp->has_pin_cached = true; resp->pin_cached = session_isUnlocked() && config_hasPin();
resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached();
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_pin_cached = true;
resp->pin_cached = session_isUnlocked() && config_hasPin();
resp->has_passphrase_cached = true;
resp->passphrase_cached = session_isPassphraseCached();
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_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);
}
void fsm_msgPing(const Ping *msg)
{
void fsm_msgPing(const Ping *msg) {
RESP_INIT(Success);
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)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
@ -101,21 +119,26 @@ void fsm_msgPing(const Ping *msg)
layoutHome();
}
void fsm_msgChangePin(const ChangePin *msg)
{
void fsm_msgChangePin(const ChangePin *msg) {
bool removal = msg->has_remove && msg->remove;
if (removal) {
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 {
fsm_sendSuccess(_("PIN removed"));
return;
}
} else {
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 {
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)) {
@ -135,26 +158,29 @@ void fsm_msgChangePin(const ChangePin *msg)
layoutHome();
}
void fsm_msgWipeDevice(const WipeDevice *msg)
{
void fsm_msgWipeDevice(const WipeDevice *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)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
return;
}
config_wipe();
// the following does not work on Mac anyway :-/ Linux/Windows are fine, so it is not needed
// usbReconnect(); // force re-enumeration because of the serial number change
// the following does not work on Mac anyway :-/ Linux/Windows are fine, so it
// is not needed usbReconnect(); // force re-enumeration because of the serial
// number change
fsm_sendSuccess(_("Device wiped"));
layoutHome();
}
void fsm_msgGetEntropy(const GetEntropy *msg)
{
void fsm_msgGetEntropy(const GetEntropy *msg) {
#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)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
@ -172,13 +198,15 @@ void fsm_msgGetEntropy(const GetEntropy *msg)
layoutHome();
}
void fsm_msgLoadDevice(const LoadDevice *msg)
{
void fsm_msgLoadDevice(const LoadDevice *msg) {
CHECK_PIN
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)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
@ -187,7 +215,8 @@ void fsm_msgLoadDevice(const LoadDevice *msg)
if (msg->has_mnemonic && !(msg->has_skip_checksum && msg->skip_checksum)) {
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();
return;
}
@ -198,16 +227,16 @@ void fsm_msgLoadDevice(const LoadDevice *msg)
layoutHome();
}
void fsm_msgResetDevice(const ResetDevice *msg)
{
void fsm_msgResetDevice(const ResetDevice *msg) {
CHECK_PIN
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(
msg->has_display_random && msg->display_random,
reset_init(msg->has_display_random && msg->display_random,
msg->has_strength ? msg->strength : 128,
msg->has_passphrase_protection && msg->passphrase_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_u2f_counter ? msg->u2f_counter : 0,
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) {
reset_entropy(msg->entropy.bytes, msg->entropy.size);
} 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_PIN_UNCACHED
(void)msg;
(void)
msg;
char mnemonic[MAX_MNEMONIC_LEN + 1];
if (config_getMnemonic(mnemonic, sizeof(mnemonic))) {
reset_backup(true, mnemonic);
@ -242,8 +269,7 @@ void fsm_msgBackupDevice(const BackupDevice *msg)
memzero(mnemonic, sizeof(mnemonic));
}
void fsm_msgCancel(const Cancel *msg)
{
void fsm_msgCancel(const Cancel *msg) {
(void)msg;
recovery_abort();
signing_abort();
@ -251,23 +277,24 @@ void fsm_msgCancel(const Cancel *msg)
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
}
void fsm_msgClearSession(const ClearSession *msg)
{
void fsm_msgClearSession(const ClearSession *msg) {
(void)msg;
session_clear(true); // clear PIN as well
layoutScreensaver();
fsm_sendSuccess(_("Session cleared"));
}
void fsm_msgApplySettings(const ApplySettings *msg)
{
CHECK_PARAM(msg->has_label || msg->has_language || msg->has_use_passphrase || msg->has_homescreen || msg->has_auto_lock_delay_ms,
void fsm_msgApplySettings(const ApplySettings *msg) {
CHECK_PARAM(msg->has_label || msg->has_language || msg->has_use_passphrase ||
msg->has_homescreen || msg->has_auto_lock_delay_ms,
_("No setting provided"));
CHECK_PIN
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)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
@ -275,7 +302,9 @@ void fsm_msgApplySettings(const ApplySettings *msg)
}
}
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)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
@ -283,7 +312,11 @@ void fsm_msgApplySettings(const ApplySettings *msg)
}
}
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)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
@ -291,7 +324,9 @@ void fsm_msgApplySettings(const ApplySettings *msg)
}
}
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)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
@ -300,7 +335,9 @@ void fsm_msgApplySettings(const ApplySettings *msg)
}
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)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
@ -327,8 +364,7 @@ void fsm_msgApplySettings(const ApplySettings *msg)
layoutHome();
}
void fsm_msgApplyFlags(const ApplyFlags *msg)
{
void fsm_msgApplyFlags(const ApplyFlags *msg) {
CHECK_PIN
if (msg->has_flags) {
@ -337,8 +373,7 @@ void fsm_msgApplyFlags(const ApplyFlags *msg)
fsm_sendSuccess(_("Flags applied"));
}
void fsm_msgRecoveryDevice(const RecoveryDevice *msg)
{
void fsm_msgRecoveryDevice(const RecoveryDevice *msg) {
CHECK_PIN_UNCACHED
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_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(
msg->has_word_count ? msg->word_count : 12,
recovery_init(msg->has_word_count ? msg->word_count : 12,
msg->has_passphrase_protection && msg->passphrase_protection,
msg->has_pin_protection && msg->pin_protection,
msg->has_language ? msg->language : 0,
msg->has_label ? msg->label : 0,
msg->has_enforce_wordlist && msg->enforce_wordlist,
msg->has_type ? msg->type : 0,
msg->has_u2f_counter ? msg->u2f_counter : 0,
dry_run
);
msg->has_u2f_counter ? msg->u2f_counter : 0, dry_run);
}
void fsm_msgWordAck(const WordAck *msg)
{
recovery_word(msg->word);
}
void fsm_msgWordAck(const WordAck *msg) { recovery_word(msg->word); }
void fsm_msgSetU2FCounter(const SetU2FCounter *msg)
{
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you want to set"), _("the U2F counter?"), NULL, NULL, NULL, NULL);
void fsm_msgSetU2FCounter(const SetU2FCounter *msg) {
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Do you want to set"), _("the U2F counter?"), NULL, NULL,
NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();

@ -17,17 +17,18 @@
* 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_PARAM(msg->has_key, _("No key 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
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;
bool encrypt = msg->has_encrypt && msg->encrypt;
@ -58,11 +59,13 @@ void fsm_msgCipherKeyValue(const CipherKeyValue *msg)
if (encrypt) {
aes_encrypt_ctx 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 {
aes_decrypt_ctx 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->value.size = msg->value.size;
@ -70,13 +73,13 @@ void fsm_msgCipherKeyValue(const CipherKeyValue *msg)
layoutHome();
}
void fsm_msgSignIdentity(const SignIdentity *msg)
{
void fsm_msgSignIdentity(const SignIdentity *msg) {
RESP_INIT(SignedIdentity);
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)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
@ -86,7 +89,8 @@ void fsm_msgSignIdentity(const SignIdentity *msg)
CHECK_PIN
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"));
layoutHome();
return;
@ -94,10 +98,14 @@ void fsm_msgSignIdentity(const SignIdentity *msg)
uint32_t address_n[5];
address_n[0] = 0x80000000 | 13;
address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | ((uint32_t) hash[ 3] << 24);
address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | ((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);
address_n[1] = 0x80000000 | hash[0] | (hash[1] << 8) | (hash[2] << 16) |
((uint32_t)hash[3] << 24);
address_n[2] = 0x80000000 | hash[4] | (hash[5] << 8) | (hash[6] << 16) |
((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;
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);
if (!node) return;
bool sign_ssh = msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0);
bool sign_gpg = msg->identity.has_proto && (strcmp(msg->identity.proto, "gpg") == 0);
bool sign_ssh =
msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0);
bool sign_gpg =
msg->identity.has_proto && (strcmp(msg->identity.proto, "gpg") == 0);
int result = 0;
layoutProgressSwipe(_("Signing"), 0);
if (sign_ssh) { // SSH does not sign visual challenge
result = sshMessageSign(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
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 {
uint8_t digest[64];
sha256_Raw(msg->challenge_hidden.bytes, msg->challenge_hidden.size, digest);
sha256_Raw((const uint8_t *)msg->challenge_visual, strlen(msg->challenge_visual), digest + 32);
result = cryptoMessageSign(&(coins[0]), node, InputScriptType_SPENDADDRESS, digest, 64, resp->signature.bytes);
sha256_Raw((const uint8_t *)msg->challenge_visual,
strlen(msg->challenge_visual), digest + 32);
result = cryptoMessageSign(&(coins[0]), node, InputScriptType_SPENDADDRESS,
digest, 64, resp->signature.bytes);
}
if (result == 0) {
@ -128,7 +142,9 @@ void fsm_msgSignIdentity(const SignIdentity *msg)
resp->has_address = false;
} else {
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->public_key.size = 33;
@ -141,13 +157,13 @@ void fsm_msgSignIdentity(const SignIdentity *msg)
resp->signature.size = 65;
msg_write(MessageType_MessageType_SignedIdentity, resp);
} else {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Error signing identity"));
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Error signing identity"));
}
layoutHome();
}
void fsm_msgGetECDHSessionKey(const GetECDHSessionKey *msg)
{
void fsm_msgGetECDHSessionKey(const GetECDHSessionKey *msg) {
RESP_INIT(ECDHSessionKey);
CHECK_INITIALIZED
@ -162,7 +178,8 @@ void fsm_msgGetECDHSessionKey(const GetECDHSessionKey *msg)
CHECK_PIN
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"));
layoutHome();
return;
@ -170,10 +187,14 @@ void fsm_msgGetECDHSessionKey(const GetECDHSessionKey *msg)
uint32_t address_n[5];
address_n[0] = 0x80000000 | 17;
address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | ((uint32_t) hash[ 3] << 24);
address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | ((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);
address_n[1] = 0x80000000 | hash[0] | (hash[1] << 8) | (hash[2] << 16) |
((uint32_t)hash[3] << 24);
address_n[2] = 0x80000000 | hash[4] | (hash[5] << 8) | (hash[6] << 16) |
((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;
if (msg->has_ecdsa_curve_name) {
@ -184,25 +205,27 @@ void fsm_msgGetECDHSessionKey(const GetECDHSessionKey *msg)
if (!node) return;
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->session_key.size = result_size;
msg_write(MessageType_MessageType_ECDHSessionKey, resp);
} else {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Error getting ECDH session key"));
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Error getting ECDH session key"));
}
layoutHome();
}
void fsm_msgCosiCommit(const CosiCommit *msg)
{
void fsm_msgCosiCommit(const CosiCommit *msg) {
RESP_INIT(CosiCommitment);
CHECK_INITIALIZED
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)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
@ -211,7 +234,8 @@ void fsm_msgCosiCommit(const CosiCommit *msg)
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;
uint8_t nonce[32];
@ -232,17 +256,19 @@ void fsm_msgCosiCommit(const CosiCommit *msg)
layoutHome();
}
void fsm_msgCosiSign(const CosiSign *msg)
{
void fsm_msgCosiSign(const CosiSign *msg) {
RESP_INIT(CosiSignature);
CHECK_INITIALIZED
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_pubkey && msg->global_pubkey.size == 32, _("Invalid global pubkey"));
CHECK_PARAM(msg->has_global_commitment && msg->global_commitment.size == 32,
_("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)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
@ -251,7 +277,8 @@ void fsm_msgCosiSign(const CosiSign *msg)
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;
uint8_t nonce[32];
@ -263,7 +290,9 @@ void fsm_msgCosiSign(const CosiSign *msg)
resp->has_signature = true;
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);
layoutHome();

@ -19,8 +19,7 @@
#if DEBUG_LINK
void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg)
{
void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) {
(void)msg;
// 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));
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.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.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);
}
void fsm_msgDebugLinkStop(const DebugLinkStop *msg)
{
(void)msg;
}
void fsm_msgDebugLinkStop(const DebugLinkStop *msg) { (void)msg; }
void fsm_msgDebugLinkMemoryRead(const DebugLinkMemoryRead *msg)
{
void fsm_msgDebugLinkMemoryRead(const DebugLinkMemoryRead *msg) {
RESP_INIT(DebugLinkMemory);
uint32_t length = 1024;
if (msg->has_length && msg->length < length)
length = msg->length;
if (msg->has_length && msg->length < length) length = msg->length;
resp->has_memory = true;
memcpy(resp->memory.bytes, FLASH_PTR(msg->address), length);
resp->memory.size = length;
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;
if (msg->flash) {
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_erase_sector(msg->sector);
uint32_t dummy = svc_flash_lock();

@ -17,8 +17,7 @@
* 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);
CHECK_INITIALIZED
@ -31,7 +30,8 @@ void fsm_msgEthereumGetPublicKey(const EthereumGetPublicKey *msg)
const char *curve = coin->curve_name;
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;
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);
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);
layoutHome();
}
void fsm_msgEthereumSignTx(EthereumSignTx *msg)
{
void fsm_msgEthereumSignTx(EthereumSignTx *msg) {
CHECK_INITIALIZED
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;
ethereum_signing_init(msg, node);
}
void fsm_msgEthereumTxAck(const EthereumTxAck *msg)
{
void fsm_msgEthereumTxAck(const EthereumTxAck *msg) {
ethereum_signing_txack(msg);
}
void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg)
{
void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg) {
RESP_INIT(EthereumAddress);
CHECK_INITIALIZED
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;
uint8_t pubkeyhash[20];
if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash))
return;
if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash)) 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;
uint32_t chain_id = 0;
// constants from trezor-common/defs/ethereum/networks.json
switch (slip44) {
case 137: rskip60 = true; chain_id = 30; break;
case 37310: rskip60 = true; chain_id = 31; break;
case 137:
rskip60 = true;
chain_id = 30;
break;
case 37310:
rskip60 = true;
chain_id = 31;
break;
}
resp->has_address = true;
@ -114,7 +120,8 @@ void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg)
char desc[16];
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;
}
}
@ -123,8 +130,7 @@ void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg)
layoutHome();
}
void fsm_msgEthereumSignMessage(const EthereumSignMessage *msg)
{
void fsm_msgEthereumSignMessage(const EthereumSignMessage *msg) {
RESP_INIT(EthereumMessageSignature);
CHECK_INITIALIZED
@ -138,15 +144,15 @@ void fsm_msgEthereumSignMessage(const EthereumSignMessage *msg)
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;
ethereum_message_sign(msg, node, resp);
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_message, _("No message provided"));

@ -17,15 +17,15 @@
* 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_PIN
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;
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);
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;
}
}
@ -43,15 +44,15 @@ void fsm_msgLiskGetAddress(const LiskGetAddress *msg)
layoutHome();
}
void fsm_msgLiskGetPublicKey(const LiskGetPublicKey *msg)
{
void fsm_msgLiskGetPublicKey(const LiskGetPublicKey *msg) {
CHECK_INITIALIZED
CHECK_PIN
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;
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);
layoutHome();
}
void fsm_msgLiskSignMessage(const LiskSignMessage *msg)
{
void fsm_msgLiskSignMessage(const LiskSignMessage *msg) {
CHECK_INITIALIZED
CHECK_PIN
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;
hdnode_fill_public_key(node);
@ -95,11 +97,11 @@ void fsm_msgLiskSignMessage(const LiskSignMessage *msg)
layoutHome();
}
void fsm_msgLiskVerifyMessage(const LiskVerifyMessage *msg)
{
void fsm_msgLiskVerifyMessage(const LiskVerifyMessage *msg) {
if (lisk_verify_message(msg)) {
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);
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
@ -121,15 +123,15 @@ void fsm_msgLiskVerifyMessage(const LiskVerifyMessage *msg)
layoutHome();
}
void fsm_msgLiskSignTx(LiskSignTx *msg)
{
void fsm_msgLiskSignTx(LiskSignTx *msg) {
CHECK_INITIALIZED
CHECK_PIN
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;
hdnode_fill_public_key(node);

@ -17,32 +17,33 @@
* 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) {
msg->network = NEM_NETWORK_MAINNET;
}
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_PIN
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 (!hdnode_get_nem_address(node, msg->network, resp->address))
return;
if (!hdnode_get_nem_address(node, msg->network, resp->address)) return;
if (msg->has_show_display && msg->show_display) {
char desc[16];
strlcpy(desc, network, 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;
}
}
@ -55,33 +56,45 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) {
const char *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"));
// Ensure exactly one transaction is provided
unsigned int provided = msg->has_transfer +
msg->has_provision_namespace +
msg->has_mosaic_creation +
msg->has_supply_change +
unsigned int provided = msg->has_transfer + msg->has_provision_namespace +
msg->has_mosaic_creation + msg->has_supply_change +
msg->has_aggregate_modification +
msg->has_importance_transfer;
CHECK_PARAM(provided != 0, _("No transaction provided"));
CHECK_PARAM(provided == 1, _("More than one transaction provided"));
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(msg->has_provision_namespace, 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));
NEM_CHECK_PARAM_WHEN(
msg->has_transfer,
nem_validate_transfer(&msg->transfer, msg->transaction.network));
NEM_CHECK_PARAM_WHEN(
msg->has_provision_namespace,
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;
if (msg->has_multisig) {
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 {
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);
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();
return;
}
@ -104,91 +118,118 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) {
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;
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];
hdnode_get_nem_address(node, common->network, address);
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)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user"));
fsm_sendFailure(FailureType_Failure_ActionCancelled,
_("Signing cancelled by user"));
layoutHome();
return;
}
if (msg->has_provision_namespace && !nem_askProvisionNamespace(common, &msg->provision_namespace, network)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user"));
if (msg->has_provision_namespace &&
!nem_askProvisionNamespace(common, &msg->provision_namespace, network)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled,
_("Signing cancelled by user"));
layoutHome();
return;
}
if (msg->has_mosaic_creation && !nem_askMosaicCreation(common, &msg->mosaic_creation, network, address)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user"));
if (msg->has_mosaic_creation &&
!nem_askMosaicCreation(common, &msg->mosaic_creation, network, address)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled,
_("Signing cancelled by user"));
layoutHome();
return;
}
if (msg->has_supply_change && !nem_askSupplyChange(common, &msg->supply_change, network)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user"));
if (msg->has_supply_change &&
!nem_askSupplyChange(common, &msg->supply_change, network)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled,
_("Signing cancelled by user"));
layoutHome();
return;
}
if (msg->has_aggregate_modification && !nem_askAggregateModification(common, &msg->aggregate_modification, network, !msg->has_multisig)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user"));
if (msg->has_aggregate_modification &&
!nem_askAggregateModification(common, &msg->aggregate_modification,
network, !msg->has_multisig)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled,
_("Signing cancelled by user"));
layoutHome();
return;
}
if (msg->has_importance_transfer && !nem_askImportanceTransfer(common, &msg->importance_transfer, network)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, _("Signing cancelled by user"));
if (msg->has_importance_transfer &&
!nem_askImportanceTransfer(common, &msg->importance_transfer, network)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled,
_("Signing cancelled by user"));
layoutHome();
return;
}
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) {
uint8_t buffer[sizeof(resp->data.bytes)];
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();
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();
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();
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();
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();
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();
return;
}
@ -198,39 +239,51 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) {
return;
}
} 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();
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();
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();
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();
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();
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();
return;
}
}
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->signature.size = sizeof(ed25519_signature);
@ -239,27 +292,23 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) {
layoutHome();
}
void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg)
{
void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg) {
RESP_INIT(NEMDecryptedMessage);
CHECK_INITIALIZED
CHECK_PARAM(nem_network_name(msg->network), _("Invalid NEM network"));
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->public_key.size == 32, _("Invalid public key"));
char address[NEM_ADDRESS_SIZE + 1];
nem_get_address(msg->public_key.bytes, msg->network, address);
layoutNEMDialog(&bmp_icon_question,
_("Cancel"),
_("Confirm"),
_("Decrypt message"),
_("Confirm address?"),
address);
layoutNEMDialog(&bmp_icon_question, _("Cancel"), _("Confirm"),
_("Decrypt message"), _("Confirm address?"), address);
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
@ -268,7 +317,8 @@ void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg)
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;
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;
// hdnode_nem_decrypt mutates the IV, so this will modify msg
bool ret = hdnode_nem_decrypt(node,
msg->public_key.bytes,
iv,
salt,
payload,
size,
resp->payload.bytes);
bool ret = hdnode_nem_decrypt(node, msg->public_key.bytes, iv, salt, payload,
size, resp->payload.bytes);
if (!ret) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to decrypt payload"));
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to decrypt payload"));
layoutHome();
return;
}

@ -17,8 +17,7 @@
* 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);
CHECK_INITIALIZED
@ -27,19 +26,16 @@ void fsm_msgStellarGetAddress(const StellarGetAddress *msg)
const HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count);
if (!node) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key"));
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to derive private key"));
return;
}
if (msg->has_show_display && msg->show_display) {
const char **str_addr_rows = stellar_lineBreakAddress(node->public_key + 1);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), _("Share public account ID?"),
str_addr_rows[0],
str_addr_rows[1],
str_addr_rows[2],
NULL,
NULL, NULL
);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"),
_("Share public account ID?"), str_addr_rows[0],
str_addr_rows[1], str_addr_rows[2], NULL, NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
@ -48,20 +44,21 @@ void fsm_msgStellarGetAddress(const StellarGetAddress *msg)
}
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);
layoutHome();
}
void fsm_msgStellarSignTx(const StellarSignTx *msg)
{
void fsm_msgStellarSignTx(const StellarSignTx *msg) {
CHECK_INITIALIZED
CHECK_PIN
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();
return;
}
@ -75,8 +72,7 @@ void fsm_msgStellarSignTx(const StellarSignTx *msg)
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_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
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_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_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_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_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_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_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_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_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_allOperationsConfirmed()) {

@ -17,47 +17,54 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <ctype.h>
#include <stdint.h>
#include <string.h>
#include <ctype.h>
#include "layout2.h"
#include "bignum.h"
#include "bitmaps.h"
#include "config.h"
#include "gettext.h"
#include "layout2.h"
#include "memzero.h"
#include "nem2.h"
#include "oled.h"
#include "bitmaps.h"
#include "string.h"
#include "util.h"
#include "qrcodegen.h"
#include "timer.h"
#include "bignum.h"
#include "secp256k1.h"
#include "nem2.h"
#include "gettext.h"
#include "memzero.h"
#include "string.h"
#include "timer.h"
#include "util.h"
#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) {
return 0;
}
switch (coin_type & 0x7fffffff) {
case 40: return "EXP"; // Expanse
case 43: return "NEM"; // NEM
case 60: return "ETH"; // Ethereum Mainnet
case 61: return "ETC"; // Ethereum Classic Mainnet
case 108: return "UBQ"; // UBIQ
case 137: return "RSK"; // Rootstock Mainnet
case 37310: return "tRSK"; // Rootstock Testnet
case 40:
return "EXP"; // Expanse
case 43:
return "NEM"; // NEM
case 60:
return "ETH"; // Ethereum Mainnet
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;
}
#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) {
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
static char path[100];
if (address_n_count == 5 &&
(address_n[0] == (0x80000000 + 44) || address_n[0] == (0x80000000 + 49) || address_n[0] == (0x80000000 + 84)) &&
(address_n[1] & 0x80000000) &&
(address_n[2] & 0x80000000) &&
(address_n[3] <= 1) &&
(address_n[4] <= BIP32_MAX_LAST_ELEMENT)) {
(address_n[0] == (0x80000000 + 44) || address_n[0] == (0x80000000 + 49) ||
address_n[0] == (0x80000000 + 84)) &&
(address_n[1] & 0x80000000) && (address_n[2] & 0x80000000) &&
(address_n[3] <= 1) && (address_n[4] <= BIP32_MAX_LAST_ELEMENT)) {
bool native_segwit = (address_n[0] == (0x80000000 + 84));
bool p2sh_segwit = (address_n[0] == (0x80000000 + 49));
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) {
abbr = coin->coin_shortcut + 1;
}
} else
if (p2sh_segwit) {
} else if (p2sh_segwit) {
if (coin && coin->has_segwit && coin->has_address_type_p2sh) {
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]);
}
}
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) {
memzero(path, 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];
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--) {
uint32_t i = address_n[n];
if (i & 0x80000000) {
*c = '\''; c--;
*c = '\'';
c--;
}
i = i & 0x7fffffff;
do {
*c = '0' + (i % 10); c--;
*c = '0' + (i % 10);
c--;
i /= 10;
} while (i > 0);
*c = '/'; c--;
}
*c = 'm'; c--;
*c = ' '; c--;
*c = ':'; c--;
*c = 'h'; c--;
*c = 't'; c--;
*c = 'a'; c--;
*c = '/';
c--;
}
*c = 'm';
c--;
*c = ' ';
c--;
*c = ':';
c--;
*c = 'h';
c--;
*c = 't';
c--;
*c = 'a';
c--;
*c = 'P';
return c;
}
// 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];
if (rowlen > 32) {
rowlen = 32;
@ -184,8 +200,7 @@ const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen)
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];
memzero(hex, sizeof(hex));
uint32_t size = len;
@ -202,15 +217,17 @@ const char **split_message_hex(const uint8_t *msg, uint32_t len)
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;
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) {
oledClear();
} else {
@ -220,15 +237,13 @@ void layoutProgressSwipe(const char *desc, int permil)
layoutProgress(desc, permil);
}
void layoutScreensaver(void)
{
void layoutScreensaver(void) {
layoutLast = layoutScreensaver;
oledClear();
oledRefresh();
}
void layoutHome(void)
{
void layoutHome(void) {
if (layoutLast == layoutHome || layoutLast == layoutScreensaver) {
oledClear();
} else {
@ -251,7 +266,8 @@ void layoutHome(void)
} else {
if (label[0] != '\0') {
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 {
oledDrawBitmap(40, 0, &bmp_logo64);
}
@ -279,15 +295,16 @@ void layoutHome(void)
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 this is a cashaddr address, remove the prefix from the
* string presented to the user
*/
int prefix_len = strlen(coin->cashaddr_prefix);
if (strncmp(address, coin->cashaddr_prefix, prefix_len) == 0
&& address[prefix_len] == ':') {
if (strncmp(address, coin->cashaddr_prefix, prefix_len) == 0 &&
address[prefix_len] == ':') {
address += prefix_len + 1;
}
}
@ -321,18 +338,21 @@ static void render_address_dialog(const CoinInfo *coin, const char *address, con
oledRefresh();
}
void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out)
{
void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out) {
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));
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;
render_address_dialog(coin, address, _("Confirm sending"), str_out, extra_line);
const char *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;
char str_out[32];
const uint32_t tx_type = *(const uint32_t *)(data + 4);
@ -355,26 +375,18 @@ void layoutConfirmOmni(const uint8_t *data, uint32_t size)
break;
}
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 {
desc = _("Unknown transaction");
str_out[0] = 0;
}
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
_("Confirm"),
NULL,
_("Confirm OMNI Transaction:"),
NULL,
desc,
NULL,
str_out,
NULL
);
}
static bool is_valid_ascii(const uint8_t *data, uint32_t size)
{
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Confirm OMNI Transaction:"), NULL, desc, NULL, str_out,
NULL);
}
static bool is_valid_ascii(const uint8_t *data, uint32_t size) {
for (uint32_t i = 0; i < size; i++) {
if (data[i] < ' ' || data[i] > '~') {
return false;
@ -383,125 +395,100 @@ static bool is_valid_ascii(const uint8_t *data, uint32_t size)
return true;
}
void layoutConfirmOpReturn(const uint8_t *data, uint32_t size)
{
void layoutConfirmOpReturn(const uint8_t *data, uint32_t size) {
const char **str;
if (!is_valid_ascii(data, size)) {
str = split_message_hex(data, size);
} else {
str = split_message(data, size, 20);
}
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
_("Confirm"),
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)
{
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), 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) {
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_fee, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_fee, sizeof(str_fee));
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
_("Confirm"),
NULL,
_("Really send"),
str_out,
_("from your wallet?"),
_("Fee included:"),
str_fee,
NULL
);
}
void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee)
{
bn_format_uint64(amount_out, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY,
0, false, str_out, sizeof(str_out));
bn_format_uint64(amount_fee, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY,
0, false, str_fee, sizeof(str_fee));
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Really send"), str_out, _("from your wallet?"),
_("Fee included:"), str_fee, NULL);
}
void layoutFeeOverThreshold(const CoinInfo *coin, uint64_t fee) {
char str_fee[32];
bn_format_uint64(fee, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0, false, str_fee, sizeof(str_fee));
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
_("Confirm"),
NULL,
_("Fee"),
str_fee,
_("is unexpectedly high."),
NULL,
_("Send anyway?"),
NULL
);
}
void layoutSignMessage(const uint8_t *msg, uint32_t len)
{
bn_format_uint64(fee, NULL, coin->coin_shortcut, BITCOIN_DIVISIBILITY, 0,
false, str_fee, sizeof(str_fee));
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Fee"), str_fee, _("is unexpectedly high."), NULL,
_("Send anyway?"), NULL);
}
void layoutSignMessage(const uint8_t *msg, uint32_t len) {
const char **str;
if (!is_valid_ascii(msg, len)) {
str = split_message_hex(msg, len);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"),
_("Sign binary message?"),
str[0], str[1], str[2], str[3], NULL, NULL);
_("Sign binary message?"), str[0], str[1], str[2], str[3],
NULL, NULL);
} else {
str = split_message(msg, len, 20);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"),
_("Sign message?"),
str[0], str[1], str[2], str[3], NULL, NULL);
_("Sign message?"), str[0], str[1], str[2], str[3], NULL,
NULL);
}
}
void layoutVerifyMessage(const uint8_t *msg, uint32_t len)
{
void layoutVerifyMessage(const uint8_t *msg, uint32_t len) {
const char **str;
if (!is_valid_ascii(msg, len)) {
str = split_message_hex(msg, len);
layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"),
_("Verified binary message"),
str[0], str[1], str[2], str[3], NULL, NULL);
_("Verified binary message"), str[0], str[1], str[2],
str[3], NULL, NULL);
} else {
str = split_message(msg, len, 20);
layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"),
_("Verified message"),
str[0], str[1], str[2], str[3], NULL, NULL);
_("Verified message"), str[0], str[1], str[2], str[3],
NULL, NULL);
}
}
void layoutVerifyAddress(const CoinInfo *coin, const char *address)
{
render_address_dialog(coin, address, _("Confirm address?"), _("Message signed by:"), 0);
void layoutVerifyAddress(const CoinInfo *coin, const char *address) {
render_address_dialog(coin, address, _("Confirm address?"),
_("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);
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);
}
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);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"),
signing ? _("Encrypt+Sign message?") : _("Encrypt message?"),
str[0], str[1], str[2], str[3], NULL, NULL);
layoutDialogSwipe(
&bmp_icon_question, _("Cancel"), _("Confirm"),
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);
layoutDialogSwipe(&bmp_icon_info, NULL, _("OK"),
address ? _("Decrypted signed message") : _("Decrypted message"),
str[0], str[1], str[2], str[3], NULL, NULL);
layoutDialogSwipe(
&bmp_icon_info, NULL, _("OK"),
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;
layoutSwipe();
@ -531,13 +518,14 @@ void layoutResetWord(const char *word, int pass, int word_pos, bool last)
}
index_str[1] = '0' + word_pos % 10;
if (word_pos == 1 || word_pos == 21) {
index_str[2] = 's'; index_str[3] = 't';
} else
if (word_pos == 2 || word_pos == 22) {
index_str[2] = 'n'; index_str[3] = 'd';
} else
if (word_pos == 3 || word_pos == 23) {
index_str[2] = 'r'; index_str[3] = 'd';
index_str[2] = 's';
index_str[3] = 't';
} else if (word_pos == 2 || word_pos == 22) {
index_str[2] = 'n';
index_str[3] = 'd';
} else if (word_pos == 3 || word_pos == 23) {
index_str[2] = 'r';
index_str[3] = 'd';
}
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;
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);
oledHLine(OLED_HEIGHT - 13);
layoutButtonYes(btnYes);
@ -555,8 +544,9 @@ void layoutResetWord(const char *word, int pass, int word_pos, bool last)
#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) {
layoutSwipe();
} else {
@ -569,23 +559,18 @@ void layoutAddress(const char *address, const char *desc, bool qrcode, bool igno
char address_upcase[addrlen + 1];
if (ignorecase) {
for (uint32_t i = 0; i < addrlen + 1; i++) {
address_upcase[i] = address[i] >= 'a' && address[i] <= 'z' ?
address[i] + 'A' - 'a' : address[i];
address_upcase[i] = address[i] >= 'a' && address[i] <= 'z'
? address[i] + 'A' - 'a'
: address[i];
}
}
uint8_t codedata[qrcodegen_BUFFER_LEN_FOR_VERSION(QR_MAX_VERSION)];
uint8_t tempdata[qrcodegen_BUFFER_LEN_FOR_VERSION(QR_MAX_VERSION)];
int side = 0;
if (qrcodegen_encodeText(
ignorecase ? address_upcase : address,
tempdata,
codedata,
qrcodegen_Ecc_LOW,
qrcodegen_VERSION_MIN,
QR_MAX_VERSION,
qrcodegen_Mask_AUTO,
true)) {
if (qrcodegen_encodeText(ignorecase ? address_upcase : address, tempdata,
codedata, qrcodegen_Ecc_LOW, qrcodegen_VERSION_MIN,
QR_MAX_VERSION, qrcodegen_Mask_AUTO, true)) {
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 j = 0; j < side; j++) {
if (qrcodegen_getModule(codedata, i, j)) {
oledBox(offset + i * 2, offset + j * 2,
offset + 1 + i * 2, offset + 1 + j * 2, false);
oledBox(offset + i * 2, offset + j * 2, offset + 1 + i * 2,
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);
}
if (addrlen > 10) { // don't split short addresses
uint32_t rowlen = (addrlen - 1) / (addrlen <= 42 ? 2 : addrlen <= 63 ? 3 : 4) + 1;
const char **str = split_message((const uint8_t *)address, addrlen, rowlen);
uint32_t 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++) {
oledDrawString(0, (i + 1) * 9 + 4, str[i], FONT_FIXED);
}
} else {
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) {
@ -634,8 +623,7 @@ void layoutAddress(const char *address, const char *desc, bool qrcode, bool igno
oledRefresh();
}
void layoutPublicKey(const uint8_t *pubkey)
{
void layoutPublicKey(const uint8_t *pubkey) {
char desc[16];
strlcpy(desc, "Public Key: 00", sizeof(desc));
if (pubkey[0] == 1) {
@ -645,12 +633,11 @@ void layoutPublicKey(const uint8_t *pubkey)
data2hex(pubkey, 1, desc + 12);
}
const char **str = split_message_hex(pubkey + 1, 32 * 2);
layoutDialogSwipe(&bmp_icon_question, NULL, _("Continue"), NULL,
desc, str[0], str[1], str[2], str[3], NULL);
layoutDialogSwipe(&bmp_icon_question, NULL, _("Continue"), NULL, desc, str[0],
str[1], str[2], str[3], NULL);
}
void layoutSignIdentity(const IdentityType *identity, const char *challenge)
{
void layoutSignIdentity(const IdentityType *identity, const char *challenge) {
char row_proto[8 + 11 + 1];
char row_hostport[64 + 6 + 1];
char row_user[64 + 8 + 1];
@ -665,7 +652,10 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge)
} else {
strlcpy(row_proto, identity->proto, sizeof(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));
}
} else {
@ -708,14 +698,10 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge)
_("Do you want to sign in?"),
row_proto[0] ? row_proto : NULL,
row_hostport[0] ? row_hostport : NULL,
row_user[0] ? row_user : NULL,
challenge,
NULL,
NULL);
row_user[0] ? row_user : NULL, challenge, NULL, NULL);
}
void layoutDecryptIdentity(const IdentityType *identity)
{
void layoutDecryptIdentity(const IdentityType *identity) {
char row_proto[8 + 11 + 1];
char row_hostport[64 + 6 + 1];
char row_user[64 + 8 + 1];
@ -723,7 +709,10 @@ void layoutDecryptIdentity(const IdentityType *identity)
if (identity->has_proto && identity->proto[0]) {
strlcpy(row_proto, identity->proto, sizeof(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));
} else {
strlcpy(row_proto, _("Decrypt for:"), sizeof(row_proto));
@ -750,17 +739,16 @@ void layoutDecryptIdentity(const IdentityType *identity)
_("Do you want to decrypt?"),
row_proto[0] ? row_proto : NULL,
row_hostport[0] ? row_hostport : NULL,
row_user[0] ? row_user : NULL,
NULL,
NULL,
NULL);
row_user[0] ? row_user : NULL, NULL, NULL, NULL);
}
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];
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];
layoutDialogSwipe(icon,
btnNo,
btnYes,
desc,
line1,
first_third,
second_third,
third_third,
NULL,
NULL);
layoutDialogSwipe(icon, btnNo, 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];
nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, quantity, multiplier, str_out, sizeof(str_out));
nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, fee, NULL, str_fee, sizeof(str_fee));
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
_("Next"),
desc,
_("Confirm transfer of"),
str_out,
_("and network fee of"),
str_fee,
NULL,
NULL);
nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, quantity, multiplier,
str_out, sizeof(str_out));
nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, fee, NULL, str_fee,
sizeof(str_fee));
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), 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];
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) {
nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, fee2, NULL, str_fee2, sizeof(str_fee2));
}
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
confirm ? _("Confirm") : _("Next"),
desc,
fee1_desc,
str_fee1,
fee2_desc,
fee2_desc ? str_fee2 : NULL,
NULL,
NULL);
nem_mosaicFormatAmount(NEM_MOSAIC_DEFINITION_XEM, fee2, NULL, str_fee2,
sizeof(str_fee2));
}
layoutDialogSwipe(
&bmp_icon_question, _("Cancel"), confirm ? _("Confirm") : _("Next"), 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];
nem_mosaicFormatAmount(definition, quantity, multiplier, str_out, sizeof(str_out));
nem_mosaicFormatAmount(definition, quantity, multiplier, str_out,
sizeof(str_out));
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,
_("Cancel"),
_("Next"),
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"),
definition->has_name ? definition->name : _("Mosaic"),
_("Confirm transfer of"),
str_out,
_("Confirm transfer of"), str_out,
definition->has_levy ? _("and levy of") : NULL,
definition->has_levy ? str_levy : NULL,
NULL,
NULL);
definition->has_levy ? str_levy : 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];
nem_mosaicFormatName(namespace, mosaic, mosaic_name, sizeof(mosaic_name));
@ -853,97 +826,93 @@ void layoutNEMTransferUnknownMosaic(const char *namespace, const char *mosaic, u
*decimal = '\0';
}
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
_("I take the risk"),
_("Unknown Mosaic"),
_("Confirm transfer of"),
str_out,
_("raw units of"),
mosaic_name,
NULL,
NULL);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("I take the risk"),
_("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) {
char encoded[(length - 1) * 2 + 1];
data2hex(&payload[1], length - 1, encoded);
const char **str = split_message((uint8_t *) encoded, sizeof(encoded) - 1, 16);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"),
encrypted ? _("Encrypted hex data") : _("Unencrypted hex data"),
str[0], str[1], str[2], str[3], NULL, NULL);
const char **str =
split_message((uint8_t *)encoded, sizeof(encoded) - 1, 16);
layoutDialogSwipe(
&bmp_icon_question, _("Cancel"), _("Next"),
encrypted ? _("Encrypted hex data") : _("Unencrypted hex data"), str[0],
str[1], str[2], str[3], NULL, NULL);
} else {
const char **str = split_message(payload, length, 16);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"),
encrypted ? _("Encrypted message") : _("Unencrypted message"),
str[0], str[1], str[2], str[3], NULL, NULL);
layoutDialogSwipe(
&bmp_icon_question, _("Cancel"), _("Next"),
encrypted ? _("Encrypted message") : _("Unencrypted message"), str[0],
str[1], str[2], str[3], NULL, NULL);
}
}
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"),
_("Mosaic Description"),
str[0], str[1], str[2], str[3], NULL, NULL);
_("Mosaic Description"), str[0], str[1], str[2], str[3],
NULL, NULL);
}
void layoutNEMLevy(const NEMMosaicDefinition *definition, uint8_t network) {
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;
} 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];
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];
switch (definition->levy) {
case NEMMosaicLevy_MosaicLevy_Percentile:
bn_format_uint64(definition->fee, NULL, NULL, 0, 0, false, str_out, sizeof(str_out));
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
_("Next"),
_("Percentile Levy"),
_("Raw levy value is"),
str_out,
_("in"),
mosaic ? (mosaic == definition ? _("the same mosaic") : mosaic->name) : mosaic_name,
NULL,
NULL);
bn_format_uint64(definition->fee, NULL, NULL, 0, 0, false, str_out,
sizeof(str_out));
layoutDialogSwipe(
&bmp_icon_question, _("Cancel"), _("Next"), _("Percentile Levy"),
_("Raw levy value is"), str_out, _("in"),
mosaic ? (mosaic == definition ? _("the same mosaic") : mosaic->name)
: mosaic_name,
NULL, NULL);
break;
case NEMMosaicLevy_MosaicLevy_Absolute:
default:
nem_mosaicFormatAmount(mosaic, definition->fee, NULL, str_out, sizeof(str_out));
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
_("Next"),
_("Absolute Levy"),
_("Levy is"),
str_out,
mosaic ? (mosaic == definition ? _("in the same mosaic") : NULL) : _("in raw units of"),
mosaic ? NULL : mosaic_name,
NULL,
NULL);
nem_mosaicFormatAmount(mosaic, definition->fee, NULL, str_out,
sizeof(str_out));
layoutDialogSwipe(
&bmp_icon_question, _("Cancel"), _("Next"), _("Absolute Levy"),
_("Levy is"), str_out,
mosaic ? (mosaic == definition ? _("in the same mosaic") : NULL)
: _("in raw units of"),
mosaic ? NULL : mosaic_name, NULL, NULL);
break;
}
}
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;
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;
}
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_buf[32];
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[3], "length", sizeof(str[3]));
}
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), desc,
str[0], str[1], str[2], str[3], NULL, NULL);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), desc, str[0],
str[1], str[2], str[3], NULL, NULL);
}

@ -20,10 +20,10 @@
#ifndef __LAYOUT2_H__
#define __LAYOUT2_H__
#include "layout.h"
#include "coins.h"
#include "bitmaps.h"
#include "bignum.h"
#include "bitmaps.h"
#include "coins.h"
#include "layout.h"
#include "trezor.h"
#include "messages-bitcoin.pb.h"
@ -38,7 +38,10 @@ extern void *layoutLast;
#define layoutSwipe oledSwipeLeft
#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 layoutScreensaver(void);
@ -46,31 +49,44 @@ void layoutHome(void);
void layoutConfirmOutput(const CoinInfo *coin, const TxOutputType *out);
void layoutConfirmOmni(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 layoutSignMessage(const uint8_t *msg, uint32_t len);
void layoutVerifyAddress(const CoinInfo *coin, const char *address);
void layoutVerifyMessage(const uint8_t *msg, uint32_t len);
void layoutCipherKeyValue(bool encrypt, const char *key);
void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing);
void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address);
void layoutDecryptMessage(const uint8_t *msg, uint32_t len,
const char *address);
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 layoutSignIdentity(const IdentityType *identity, const char *challenge);
void layoutDecryptIdentity(const IdentityType *identity);
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 layoutNEMTransferXEM(const char *desc, uint64_t quantity, const bignum256 *multiplier, uint64_t fee);
void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc, 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 layoutNEMDialog(const BITMAP *icon, const char *btnNo, const char *btnYes,
const char *desc, const char *line1, const char *address);
void layoutNEMTransferXEM(const char *desc, uint64_t quantity,
const bignum256 *multiplier, uint64_t fee);
void layoutNEMNetworkFee(const char *desc, bool confirm, const char *fee1_desc,
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 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_hex(const uint8_t *msg, uint32_t len);

@ -18,23 +18,26 @@
*/
#include "lisk.h"
#include "fsm.h"
#include "curves.h"
#include "layout2.h"
#include "bitmaps.h"
#include "util.h"
#include "gettext.h"
#include "crypto.h"
#include "protect.h"
#include "curves.h"
#include "fsm.h"
#include "gettext.h"
#include "layout2.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];
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_Init(&ctx);
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);
}
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);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
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;
}
bool lisk_verify_message(const LiskVerifyMessage *msg)
{
bool lisk_verify_message(const LiskVerifyMessage *msg) {
uint8_t hash[32];
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) {
memcpy(msg->transaction.sender_public_key.bytes, &node->public_key[1], 32);
}
// For CastVotes transactions, recipientId should be equal to transaction creator address.
if(msg->transaction.type == LiskTransactionType_CastVotes && !msg->transaction.has_recipient_id) {
// For CastVotes transactions, recipientId should be equal to transaction
// creator address.
if (msg->transaction.type == LiskTransactionType_CastVotes &&
!msg->transaction.has_recipient_id) {
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];
write_le(data, value);
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));
}
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];
data[0] = value >> 56;
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));
}
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) {
case LiskTransactionType_Transfer:
if (asset->has_data) {
@ -128,7 +130,8 @@ static void lisk_hashupdate_asset(SHA256_CTX *ctx, LiskTransactionType type, Lis
break;
case LiskTransactionType_RegisterDelegate:
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;
case LiskTransactionType_CastVotes: {
@ -139,7 +142,8 @@ static void lisk_hashupdate_asset(SHA256_CTX *ctx, LiskTransactionType type, Lis
}
case LiskTransactionType_RegisterSecondPassphrase:
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;
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.life_time), 1);
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;
default:
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid transaction type"));
fsm_sendFailure(FailureType_Failure_DataError,
_("Invalid transaction type"));
break;
}
}
#define MAX_LISK_VALUE_SIZE 20
static void lisk_format_value(uint64_t value, char *formated_value)
{
bn_format_uint64(value, NULL, " LSK", 8, 0, false, formated_value, MAX_LISK_VALUE_SIZE);
static void lisk_format_value(uint64_t value, char *formated_value) {
bn_format_uint64(value, NULL, " LSK", 8, 0, false, formated_value,
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);
if (msg->has_transaction) {
@ -174,7 +179,8 @@ void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp)
switch (msg->transaction.type) {
case LiskTransactionType_Transfer:
layoutRequireConfirmTx(msg->transaction.recipient_id, msg->transaction.amount);
layoutRequireConfirmTx(msg->transaction.recipient_id,
msg->transaction.amount);
break;
case LiskTransactionType_RegisterDelegate:
layoutRequireConfirmDelegateRegistration(&msg->transaction.asset);
@ -189,14 +195,15 @@ void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp)
layoutRequireConfirmMultisig(&msg->transaction.asset);
break;
default:
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid transaction type"));
fsm_sendFailure(FailureType_Failure_DataError,
_("Invalid transaction type"));
layoutHome();
break;
}
if (!protectButton((
msg->transaction.type == LiskTransactionType_RegisterSecondPassphrase ?
ButtonRequestType_ButtonRequest_PublicKey :
ButtonRequestType_ButtonRequest_SignTx),
if (!protectButton((msg->transaction.type ==
LiskTransactionType_RegisterSecondPassphrase
? ButtonRequestType_ButtonRequest_PublicKey
: ButtonRequestType_ButtonRequest_SignTx),
false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Signing cancelled");
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);
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;
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)
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') {
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid recipient_id"));
if (msg->transaction.recipient_id[i] < '0' ||
msg->transaction.recipient_id[i] > '9') {
fsm_sendFailure(FailureType_Failure_DataError,
_("Invalid recipient_id"));
layoutHome();
return;
}
@ -241,12 +252,14 @@ void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp)
// if signature exist calculate second 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];
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->signature.size = 64;
@ -254,73 +267,51 @@ void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp)
}
// Layouts
void layoutLiskPublicKey(const uint8_t *pubkey)
{
void layoutLiskPublicKey(const uint8_t *pubkey) {
const char **str = split_message_hex(pubkey, 32);
layoutDialogSwipe(&bmp_icon_question, NULL, _("Continue"), NULL,
_("Public Key:"), str[0], str[1], str[2], str[3], NULL);
}
void layoutLiskVerifyAddress(const char *address)
{
const char **str = split_message((const uint8_t *)address, strlen(address), 10);
void layoutLiskVerifyAddress(const char *address) {
const char **str =
split_message((const uint8_t *)address, strlen(address), 10);
layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Confirm"),
_("Confirm address?"),
_("Message signed by:"),
str[0], str[1], NULL, NULL, NULL);
_("Confirm address?"), _("Message signed by:"), 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];
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);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"),
NULL,
_("Confirm sending"),
formated_amount,
_("to:"),
str[0],
str[1],
NULL
);
}
void layoutRequireConfirmFee(uint64_t fee, uint64_t amount)
{
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Confirm sending"), formated_amount, _("to:"), str[0],
str[1], NULL);
}
void layoutRequireConfirmFee(uint64_t fee, uint64_t amount) {
char formated_amount[MAX_LISK_VALUE_SIZE];
char formated_fee[MAX_LISK_VALUE_SIZE];
lisk_format_value(amount, formated_amount);
lisk_format_value(fee, formated_fee);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"),
NULL,
_("Confirm transaction"),
formated_amount,
_("fee:"),
formated_fee,
NULL,
NULL
);
}
void layoutRequireConfirmDelegateRegistration(LiskTransactionAsset *asset)
{
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Confirm transaction"), formated_amount, _("fee:"),
formated_fee, NULL, NULL);
}
void layoutRequireConfirmDelegateRegistration(LiskTransactionAsset *asset) {
if (asset->has_delegate && asset->delegate.has_username) {
const char **str = split_message((const uint8_t *)asset->delegate.username, strlen(asset->delegate.username), 20);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"),
NULL,
_("Confirm transaction"),
_("Do you really want to"),
_("register a delegate?"),
str[0],
str[1],
NULL
);
const char **str = split_message((const uint8_t *)asset->delegate.username,
strlen(asset->delegate.username), 20);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Confirm transaction"), _("Do you really want to"),
_("register a delegate?"), str[0], str[1], NULL);
}
}
void layoutRequireConfirmCastVotes(LiskTransactionAsset *asset)
{
void layoutRequireConfirmCastVotes(LiskTransactionAsset *asset) {
uint8_t plus = 0;
uint8_t minus = 0;
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(minus, "Remove ", NULL, 0, 0, false, remove_votes_txt, sizeof(remove_votes_txt));
bn_format_uint64(plus, "Add ", NULL, 0, 0, false, add_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"),
NULL,
_("Confirm transaction"),
add_votes_txt,
remove_votes_txt,
NULL,
NULL,
NULL
);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
_("Confirm transaction"), add_votes_txt, remove_votes_txt,
NULL, NULL, NULL);
}
void layoutRequireConfirmMultisig(LiskTransactionAsset *asset)
{
void layoutRequireConfirmMultisig(LiskTransactionAsset *asset) {
char keys_group_str[25];
char life_time_str[14];
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.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"),
NULL,
_("Confirm transaction"),
keys_group_str,
life_time_str,
min_str,
NULL,
NULL
);
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.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"), NULL,
_("Confirm transaction"), keys_group_str, life_time_str,
min_str, NULL, NULL);
}

@ -26,7 +26,8 @@
#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);
void lisk_sign_tx(const HDNode *node, LiskSignTx *msg, LiskSignedTx *resp);

@ -19,17 +19,17 @@
#include <string.h>
#include "trezor.h"
#include "messages.h"
#include "debug.h"
#include "fsm.h"
#include "util.h"
#include "gettext.h"
#include "memzero.h"
#include "messages.h"
#include "trezor.h"
#include "util.h"
#include "messages.pb.h"
#include "pb_decode.h"
#include "pb_encode.h"
#include "messages.pb.h"
struct MessagesMap_t {
char type; // n = normal, d = debug
@ -42,13 +42,11 @@ struct MessagesMap_t {
static const struct MessagesMap_t MessagesMap[] = {
#include "messages_map.h"
// end
{0, 0, 0, 0, 0}
};
{0, 0, 0, 0, 0}};
#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;
while (m->type) {
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;
}
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;
while (m->type) {
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
static inline void msg_out_append(uint8_t c)
{
static inline void msg_out_append(uint8_t c) {
if (msg_out_cur == 0) {
msg_out[msg_out_end * 64] = '?';
msg_out_cur = 1;
@ -101,8 +97,7 @@ static inline void msg_out_append(uint8_t c)
#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) {
msg_debug_out[msg_debug_out_end * 64] = '?';
msg_debug_out_cur = 1;
@ -117,8 +112,7 @@ static inline void msg_debug_out_append(uint8_t c)
#endif
static inline void msg_out_pad(void)
{
static inline void msg_out_pad(void) {
if (msg_out_cur == 0) return;
while (msg_out_cur < 64) {
msg_out[msg_out_end * 64 + msg_out_cur] = 0;
@ -130,8 +124,7 @@ static inline void msg_out_pad(void)
#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;
while (msg_debug_out_cur < 64) {
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
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;
for (size_t i = 0; i < count; 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
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;
for (size_t i = 0; i < count; 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
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);
if (!fields) { // unknown message
return false;
@ -220,8 +212,8 @@ enum {
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];
memzero(msg_data, sizeof(msg_data));
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 uint8_t msg_in[MSG_IN_SIZE];
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 (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;
}
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);
if (!fields) { // unknown message
fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Unknown message"));
fsm_sendFailure(FailureType_Failure_UnexpectedMessage,
_("Unknown message"));
return;
}
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);
msg_pos = len - 9;
} else
if (read_state == READSTATE_READING) {
} else if (read_state == READSTATE_READING) {
if (buf[0] != '?') { // invalid contents
read_state = READSTATE_IDLE;
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;
uint8_t *data = msg_out + (msg_out_start * 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
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;
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);
@ -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(PinMatrixAck), "msg_tiny too tiny");
#if DEBUG_LINK
_Static_assert(sizeof(msg_tiny) >= sizeof(DebugLinkDecision), "msg_tiny too tiny");
_Static_assert(sizeof(msg_tiny) >= sizeof(DebugLinkGetState), "msg_tiny too tiny");
_Static_assert(sizeof(msg_tiny) >= sizeof(DebugLinkDecision),
"msg_tiny too tiny");
_Static_assert(sizeof(msg_tiny) >= sizeof(DebugLinkGetState),
"msg_tiny too tiny");
#endif
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 (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') {
return;
}
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) {
return;
}
@ -369,7 +362,8 @@ void msg_read_tiny(const uint8_t *buf, int len)
msg_tiny_id = 0xFFFF;
}
} else {
fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Unknown message"));
fsm_sendFailure(FailureType_Failure_UnexpectedMessage,
_("Unknown message"));
msg_tiny_id = 0xFFFF;
}
}

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

@ -23,10 +23,10 @@
#include "fsm.h"
#include "gettext.h"
#include "layout2.h"
#include "memzero.h"
#include "protect.h"
#include "rng.h"
#include "secp256k1.h"
#include "memzero.h"
const char *nem_validate_common(NEMTransactionCommon *common, bool inner) {
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) {
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) {
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) {
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) {
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) {
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)) {
@ -61,15 +66,18 @@ const char *nem_validate_common(NEMTransactionCommon *common, bool inner) {
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_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");
}
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++) {
const NEMMosaic *mosaic = &transfer->mosaics[i];
@ -82,52 +90,75 @@ const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network)
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_sink) return _("No rental sink 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;
}
const char *nem_validate_mosaic_creation(const NEMMosaicCreation *mosaic_creation, uint8_t network) {
if (!mosaic_creation->has_definition) return _("No mosaic definition provided");
const char *nem_validate_mosaic_creation(
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_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_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_name)
return _("Name 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_mosaic) return _("No mosaic name provided");
if (!mosaic_creation->definition.has_namespace)
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_fee) return _("No levy address provided");
if (!mosaic_creation->definition.has_levy_address) 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_fee)
return _("No levy address provided");
if (!mosaic_creation->definition.has_levy_address)
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_supply) return _("No supply provided");
if (!mosaic_creation->definition.has_mutable_supply) return _("No supply mutability 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.has_mutable_supply)
return _("No supply mutability 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.supply > NEM_MAX_SUPPLY) return _("Invalid supply provided");
if (mosaic_creation->definition.divisibility > NEM_MAX_DIVISIBILITY)
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;
}
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_mosaic) return _("No mosaic 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;
}
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) {
return _("No modifications provided");
}
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_public_key) return _("No cosignatory public key provided");
if (modification->public_key.size != 32) return _("Invalid cosignatory public key provided");
if (!modification->has_public_key)
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");
}
}
@ -156,15 +192,19 @@ const char *nem_validate_aggregate_modification(const NEMAggregateModification *
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_public_key) return _("No remote account provided");
if (importance_transfer->public_key.size != 32) return _("Invalid remote account provided");
if (!importance_transfer->has_public_key)
return _("No remote account provided");
if (importance_transfer->public_key.size != 32)
return _("Invalid remote account provided");
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) {
const NEMMosaic *xem = NULL;
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++) {
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) {
xem = mosaic;
@ -187,22 +228,18 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran
bn_read_uint64(transfer->amount, &multiplier);
if (unknownMosaic) {
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
_("I take the risk"),
_("Unknown Mosaics"),
_("Divisibility and levy"),
_("cannot be shown for"),
_("unknown mosaics!"),
NULL,
NULL,
NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("I take the risk"),
_("Unknown Mosaics"), _("Divisibility and levy"),
_("cannot be shown for"), _("unknown mosaics!"), NULL,
NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput,
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)) {
return false;
}
@ -215,12 +252,15 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran
}
if (definitions[i]) {
layoutNEMTransferMosaic(definitions[i], mosaic->quantity, &multiplier, common->network);
layoutNEMTransferMosaic(definitions[i], mosaic->quantity, &multiplier,
common->network);
} 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;
}
}
@ -232,18 +272,15 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran
}
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)) {
return false;
}
}
layoutNEMDialog(&bmp_icon_question,
_("Cancel"),
_("Confirm"),
desc,
_("Confirm transfer to"),
transfer->recipient);
layoutNEMDialog(&bmp_icon_question, _("Cancel"), _("Confirm"), desc,
_("Confirm transfer to"), transfer->recipient);
if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) {
return false;
}
@ -251,15 +288,19 @@ bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *tran
return true;
}
bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMTransfer *transfer) {
static uint8_t encrypted[NEM_ENCRYPTED_PAYLOAD_SIZE(sizeof(transfer->payload.bytes))];
bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node,
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;
size_t size = transfer->payload.size;
if (transfer->has_public_key) {
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;
}
@ -269,16 +310,12 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM
const uint8_t *iv = &encrypted[NEM_SALT_SIZE];
uint8_t *buffer = &encrypted[NEM_SALT_SIZE + AES_BLOCK_SIZE];
bool ret = hdnode_nem_encrypt(node,
transfer->public_key.bytes,
iv,
salt,
payload,
size,
buffer);
bool ret = hdnode_nem_encrypt(node, transfer->public_key.bytes, iv, salt,
payload, size, buffer);
if (!ret) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to encrypt payload"));
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to encrypt payload"));
return false;
}
@ -286,34 +323,26 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM
size = NEM_ENCRYPTED_PAYLOAD_SIZE(size);
}
bool ret = nem_transaction_create_transfer(context,
common->network,
common->timestamp,
NULL,
common->fee,
common->deadline,
transfer->recipient,
transfer->amount,
payload,
size,
transfer->has_public_key,
transfer->mosaics_count);
bool ret = nem_transaction_create_transfer(
context, common->network, common->timestamp, NULL, common->fee,
common->deadline, transfer->recipient, transfer->amount, payload, size,
transfer->has_public_key, transfer->mosaics_count);
if (!ret) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to create transfer transaction"));
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to create transfer transaction"));
return false;
}
for (size_t i = 0; i < transfer->mosaics_count; i++) {
const NEMMosaic *mosaic = &transfer->mosaics[i];
ret = nem_transaction_write_mosaic(context,
mosaic->namespace,
mosaic->mosaic,
mosaic->quantity);
ret = nem_transaction_write_mosaic(context, mosaic->namespace,
mosaic->mosaic, mosaic->quantity);
if (!ret) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to attach mosaics"));
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to attach mosaics"));
return false;
}
}
@ -321,22 +350,22 @@ bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEM
return true;
}
bool nem_askProvisionNamespace(const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace, const char *desc) {
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
_("Next"),
desc,
_("Create namespace"),
bool nem_askProvisionNamespace(const NEMTransactionCommon *common,
const NEMProvisionNamespace *provision_namespace,
const char *desc) {
layoutDialogSwipe(
&bmp_icon_question, _("Cancel"), _("Next"), desc, _("Create namespace"),
provision_namespace->namespace,
provision_namespace->has_parent ? _("under namespace") : NULL,
provision_namespace->has_parent ? provision_namespace->parent : NULL,
NULL,
NULL);
NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, 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)) {
return false;
}
@ -344,30 +373,23 @@ bool nem_askProvisionNamespace(const NEMTransactionCommon *common, const NEMProv
return true;
}
bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace) {
return nem_transaction_create_provision_namespace(context,
common->network,
common->timestamp,
NULL,
common->fee,
common->deadline,
provision_namespace->namespace,
bool nem_fsmProvisionNamespace(
nem_transaction_ctx *context, const NEMTransactionCommon *common,
const NEMProvisionNamespace *provision_namespace) {
return nem_transaction_create_provision_namespace(
context, common->network, common->timestamp, NULL, common->fee,
common->deadline, provision_namespace->namespace,
provision_namespace->has_parent ? provision_namespace->parent : NULL,
provision_namespace->sink,
provision_namespace->fee);
provision_namespace->sink, provision_namespace->fee);
}
bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation, const char *desc, const char *address) {
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
_("Next"),
desc,
_("Create mosaic"),
mosaic_creation->definition.mosaic,
_("under namespace"),
mosaic_creation->definition.namespace,
NULL,
NULL);
bool nem_askMosaicCreation(const NEMTransactionCommon *common,
const NEMMosaicCreation *mosaic_creation,
const char *desc, const char *address) {
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), desc,
_("Create mosaic"), mosaic_creation->definition.mosaic,
_("under namespace"), mosaic_creation->definition.namespace,
NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return false;
}
@ -379,25 +401,19 @@ bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCr
char str_out[32];
bn_format_uint64(mosaic_creation->definition.supply,
NULL,
NULL,
mosaic_creation->definition.divisibility,
bn_format_uint64(mosaic_creation->definition.supply, NULL, NULL,
mosaic_creation->definition.divisibility,
true,
str_out,
mosaic_creation->definition.divisibility, true, str_out,
sizeof(str_out));
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
_("Next"),
_("Properties"),
mosaic_creation->definition.mutable_supply ? _("Mutable supply:") : _("Immutable supply:"),
str_out,
_("Mosaic will be"),
mosaic_creation->definition.transferable ? _("transferable") : _("non-transferable"),
NULL,
NULL);
layoutDialogSwipe(
&bmp_icon_question, _("Cancel"), _("Next"), _("Properties"),
mosaic_creation->definition.mutable_supply ? _("Mutable supply:")
: _("Immutable supply:"),
str_out, _("Mosaic will be"),
mosaic_creation->definition.transferable ? _("transferable")
: _("non-transferable"),
NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return false;
}
@ -409,22 +425,12 @@ bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCr
}
if (strcmp(address, mosaic_creation->definition.levy_address) == 0) {
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
_("Next"),
_("Levy Recipient"),
_("Levy will be paid to"),
_("yourself"),
NULL,
NULL,
NULL,
NULL);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"),
_("Levy Recipient"), _("Levy will be paid to"),
_("yourself"), NULL, NULL, NULL, NULL);
} else {
layoutNEMDialog(&bmp_icon_question,
_("Cancel"),
_("Next"),
_("Levy Recipient"),
_("Levy will be paid to"),
layoutNEMDialog(&bmp_icon_question, _("Cancel"), _("Next"),
_("Levy Recipient"), _("Levy will be paid to"),
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)) {
return false;
}
@ -441,62 +449,51 @@ bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCr
return true;
}
bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation) {
return nem_transaction_create_mosaic_creation(context,
common->network,
common->timestamp,
NULL,
common->fee,
common->deadline,
mosaic_creation->definition.namespace,
bool nem_fsmMosaicCreation(nem_transaction_ctx *context,
const NEMTransactionCommon *common,
const NEMMosaicCreation *mosaic_creation) {
return nem_transaction_create_mosaic_creation(
context, common->network, common->timestamp, NULL, common->fee,
common->deadline, mosaic_creation->definition.namespace,
mosaic_creation->definition.mosaic,
mosaic_creation->definition.description,
mosaic_creation->definition.divisibility,
mosaic_creation->definition.supply,
mosaic_creation->definition.mutable_supply,
mosaic_creation->definition.transferable,
mosaic_creation->definition.levy,
mosaic_creation->definition.fee,
mosaic_creation->definition.levy, mosaic_creation->definition.fee,
mosaic_creation->definition.levy_address,
mosaic_creation->definition.levy_namespace,
mosaic_creation->definition.levy_mosaic,
mosaic_creation->sink,
mosaic_creation->definition.levy_mosaic, mosaic_creation->sink,
mosaic_creation->fee);
}
bool nem_askSupplyChange(const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change, const char *desc) {
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
_("Next"),
desc,
_("Modify supply for"),
supply_change->mosaic,
_("under namespace"),
supply_change->namespace,
NULL,
NULL);
bool nem_askSupplyChange(const NEMTransactionCommon *common,
const NEMMosaicSupplyChange *supply_change,
const char *desc) {
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), desc,
_("Modify supply for"), supply_change->mosaic,
_("under namespace"), supply_change->namespace, NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return false;
}
char str_out[32];
bn_format_uint64(supply_change->delta, NULL, NULL, 0, 0, false, str_out, sizeof(str_out));
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
_("Next"),
desc,
supply_change->type == NEMSupplyChangeType_SupplyChange_Increase ? _("Increase supply by") : _("Decrease supply by"),
str_out,
_("whole units"),
NULL,
NULL,
NULL);
bn_format_uint64(supply_change->delta, NULL, NULL, 0, 0, false, str_out,
sizeof(str_out));
layoutDialogSwipe(
&bmp_icon_question, _("Cancel"), _("Next"), desc,
supply_change->type == NEMSupplyChangeType_SupplyChange_Increase
? _("Increase supply by")
: _("Decrease supply by"),
str_out, _("whole units"), NULL, NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, 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)) {
return false;
}
@ -504,31 +501,23 @@ bool nem_askSupplyChange(const NEMTransactionCommon *common, const NEMMosaicSupp
return true;
}
bool nem_fsmSupplyChange(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change) {
return nem_transaction_create_mosaic_supply_change(context,
common->network,
common->timestamp,
NULL,
common->fee,
common->deadline,
supply_change->namespace,
supply_change->mosaic,
supply_change->type,
supply_change->delta);
bool nem_fsmSupplyChange(nem_transaction_ctx *context,
const NEMTransactionCommon *common,
const NEMMosaicSupplyChange *supply_change) {
return nem_transaction_create_mosaic_supply_change(
context, common->network, common->timestamp, NULL, common->fee,
common->deadline, 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) {
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
_("Next"),
desc,
_("Convert account to"),
_("multisig account?"),
NULL,
NULL,
NULL,
NULL);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), desc,
_("Convert account to"), _("multisig account?"), NULL,
NULL, NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return false;
}
@ -537,14 +526,15 @@ bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMA
char address[NEM_ADDRESS_SIZE + 1];
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);
layoutNEMDialog(&bmp_icon_question,
_("Cancel"),
_("Next"),
desc,
modification->type == NEMModificationType_CosignatoryModification_Add ? _("Add cosignatory") : _("Remove cosignatory"),
layoutNEMDialog(
&bmp_icon_question, _("Cancel"), _("Next"), desc,
modification->type == NEMModificationType_CosignatoryModification_Add
? _("Add cosignatory")
: _("Remove cosignatory"),
address);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
return false;
@ -555,30 +545,21 @@ bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMA
if (relative_change) {
char str_out[32];
bn_format_uint64(relative_change < 0 ? -relative_change : relative_change,
NULL,
NULL,
0,
0,
false,
str_out,
sizeof(str_out));
NULL, NULL, 0, 0, false, str_out, sizeof(str_out));
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
_("Next"),
desc,
creation ? _("Set minimum") : (relative_change < 0 ? _("Decrease minimum") : _("Increase minimum")),
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Next"), desc,
creation ? _("Set minimum")
: (relative_change < 0 ? _("Decrease minimum")
: _("Increase minimum")),
creation ? _("cosignatories to") : _("cosignatories by"),
str_out,
NULL,
NULL,
NULL);
str_out, NULL, NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, 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)) {
return false;
}
@ -586,50 +567,49 @@ bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMA
return true;
}
bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification) {
bool ret = nem_transaction_create_aggregate_modification(context,
common->network,
common->timestamp,
NULL,
common->fee,
common->deadline,
aggregate_modification->modifications_count,
bool nem_fsmAggregateModification(
nem_transaction_ctx *context, const NEMTransactionCommon *common,
const NEMAggregateModification *aggregate_modification) {
bool ret = nem_transaction_create_aggregate_modification(
context, common->network, common->timestamp, NULL, common->fee,
common->deadline, aggregate_modification->modifications_count,
aggregate_modification->relative_change != 0);
if (!ret) return false;
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,
modification->type,
modification->public_key.bytes);
ret = nem_transaction_write_cosignatory_modification(
context, modification->type, modification->public_key.bytes);
if (!ret) return false;
}
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;
}
return true;
}
bool nem_askImportanceTransfer(const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer, const char *desc) {
layoutDialogSwipe(&bmp_icon_question,
_("Cancel"),
_("Next"),
desc,
importance_transfer->mode == NEMImportanceTransferMode_ImportanceTransfer_Activate ? _("Activate remote") : _("Deactivate remote"),
_("harvesting?"),
NULL,
NULL,
NULL,
NULL);
bool nem_askImportanceTransfer(const NEMTransactionCommon *common,
const NEMImportanceTransfer *importance_transfer,
const char *desc) {
layoutDialogSwipe(
&bmp_icon_question, _("Cancel"), _("Next"), desc,
importance_transfer->mode ==
NEMImportanceTransferMode_ImportanceTransfer_Activate
? _("Activate remote")
: _("Deactivate remote"),
_("harvesting?"), NULL, NULL, NULL, NULL);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, 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)) {
return false;
}
@ -637,22 +617,19 @@ bool nem_askImportanceTransfer(const NEMTransactionCommon *common, const NEMImpo
return true;
}
bool nem_fsmImportanceTransfer(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer) {
return nem_transaction_create_importance_transfer(context,
common->network,
common->timestamp,
NULL,
common->fee,
common->deadline,
importance_transfer->mode,
bool nem_fsmImportanceTransfer(
nem_transaction_ctx *context, const NEMTransactionCommon *common,
const NEMImportanceTransfer *importance_transfer) {
return nem_transaction_create_importance_transfer(
context, common->network, common->timestamp, NULL, common->fee,
common->deadline, importance_transfer->mode,
importance_transfer->public_key.bytes);
}
bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee) {
layoutNEMDialog(&bmp_icon_question,
_("Cancel"),
_("Next"),
desc,
bool nem_askMultisig(const char *address, const char *desc, bool cosigning,
uint64_t fee) {
layoutNEMDialog(
&bmp_icon_question, _("Cancel"), _("Next"), desc,
cosigning ? _("Cosign transaction for") : _("Initiate transaction for"),
address);
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmOutput, false)) {
@ -667,35 +644,32 @@ bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint
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;
if (cosigning) {
ret = nem_transaction_create_multisig_signature(context,
common->network,
common->timestamp,
NULL,
common->fee,
common->deadline,
inner);
ret = nem_transaction_create_multisig_signature(
context, common->network, common->timestamp, NULL, common->fee,
common->deadline, inner);
} else {
ret = nem_transaction_create_multisig(context,
common->network,
common->timestamp,
NULL,
common->fee,
common->deadline,
inner);
ret = nem_transaction_create_multisig(context, common->network,
common->timestamp, NULL, common->fee,
common->deadline, inner);
}
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 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++) {
const NEMMosaicDefinition *definition = &NEM_MOSAIC_DEFINITIONS[i];
@ -707,7 +681,10 @@ const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *m
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;
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;
}
return bn_format(&val,
NULL,
return bn_format(
&val, NULL,
definition && definition->has_ticker ? definition->ticker : NULL,
definition && definition->has_divisibility ? definition->divisibility : 0,
-divisor,
false,
str_out,
size);
-divisor, false, str_out, size);
}
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;
}
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;
bn_read_uint64(quantity, &amnt);
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) {
return false;
}
@ -794,7 +772,8 @@ bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quanti
bn_read_uint64(quantity, &amnt);
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) {
case NEMMosaicLevy_MosaicLevy_Absolute:
@ -802,7 +781,8 @@ bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quanti
case NEMMosaicLevy_MosaicLevy_Percentile:
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:
return false;

@ -29,47 +29,90 @@
const char *nem_validate_common(NEMTransactionCommon *common, bool inner);
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_mosaic_creation(const NEMMosaicCreation *mosaic_creation, uint8_t network);
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_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_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_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_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_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_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_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 char *nem_validate_provision_namespace(
const NEMProvisionNamespace *provision_namespace, uint8_t network);
const char *nem_validate_mosaic_creation(
const NEMMosaicCreation *mosaic_creation, uint8_t network);
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_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_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_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_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_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_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_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);
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);
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) {
void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition,
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) {
strlcpy(str_out, namespace, size);
strlcat(str_out, ".", size);
strlcat(str_out, mosaic, size);
}
static inline bool nem_mosaicMatches(const NEMMosaicDefinition *definition, const char *namespace, const char *mosaic, uint8_t network) {
if (strcmp(namespace, definition->namespace) == 0 && strcmp(mosaic, definition->mosaic) == 0) {
static inline bool nem_mosaicMatches(const NEMMosaicDefinition *definition,
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) {
return true;
}

@ -17,19 +17,17 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/flash.h>
#include "otp.h"
#include <libopencm3/stm32/flash.h>
#define FLASH_OTP_BASE 0x1FFF7800U
#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);
}
bool flash_otp_lock(uint8_t block)
{
bool flash_otp_lock(uint8_t block) {
if (block >= FLASH_OTP_NUM_BLOCKS) {
return false;
}
@ -39,25 +37,29 @@ bool flash_otp_lock(uint8_t block)
return true;
}
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) {
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) {
return false;
}
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;
}
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) {
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) {
return false;
}
flash_unlock();
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_lock();

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

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

@ -18,28 +18,27 @@
*/
#include "protect.h"
#include "buttons.h"
#include "config.h"
#include "debug.h"
#include "fsm.h"
#include "gettext.h"
#include "layout2.h"
#include "memory.h"
#include "memzero.h"
#include "messages.h"
#include "usb.h"
#include "messages.pb.h"
#include "oled.h"
#include "buttons.h"
#include "pinmatrix.h"
#include "fsm.h"
#include "layout2.h"
#include "usb.h"
#include "util.h"
#include "debug.h"
#include "gettext.h"
#include "memzero.h"
#include "messages.pb.h"
#define MAX_WRONG_PINS 15
bool protectAbortedByCancel = false;
bool protectAbortedByInitialize = false;
bool protectButton(ButtonRequestType type, bool confirm_only)
{
bool protectButton(ButtonRequestType type, bool confirm_only) {
ButtonRequest resp;
bool result = false;
bool acked = false;
@ -79,7 +78,8 @@ bool protectButton(ButtonRequestType type, bool confirm_only)
// check for Cancel / Initialize
protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel);
protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize);
protectAbortedByInitialize =
(msg_tiny_id == MessageType_MessageType_Initialize);
if (protectAbortedByCancel || protectAbortedByInitialize) {
msg_tiny_id = 0xFFFF;
result = false;
@ -111,8 +111,7 @@ bool protectButton(ButtonRequestType type, bool confirm_only)
return result;
}
const char *requestPin(PinMatrixRequestType type, const char *text)
{
const char *requestPin(PinMatrixRequestType type, const char *text) {
PinMatrixRequest resp;
memzero(&resp, sizeof(PinMatrixRequest));
resp.has_type = true;
@ -131,7 +130,8 @@ const char *requestPin(PinMatrixRequestType type, const char *text)
}
// check for Cancel / Initialize
protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel);
protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize);
protectAbortedByInitialize =
(msg_tiny_id == MessageType_MessageType_Initialize);
if (protectAbortedByCancel || protectAbortedByInitialize) {
pinmatrix_done(0);
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.
char secstrbuf[] = _("________0 seconds");
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, 2 * 9, _("Please wait"), 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
oledFrame(0, OLED_HEIGHT - 8, OLED_WIDTH - 1, OLED_HEIGHT - 1);
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();
// Check for Cancel / Initialize.
protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel);
protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize);
protectAbortedByInitialize =
(msg_tiny_id == MessageType_MessageType_Initialize);
if (protectAbortedByCancel || protectAbortedByInitialize) {
msg_tiny_id = 0xFFFF;
usbTiny(0);
@ -189,15 +191,15 @@ secbool protectPinUiCallback(uint32_t wait, uint32_t progress, const char* messa
return secfalse;
}
bool protectPin(bool use_cached)
{
bool protectPin(bool use_cached) {
if (use_cached && session_isUnlocked()) {
return true;
}
const char *pin = "";
if (config_hasPin()) {
pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:"));
pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current,
_("Please enter current PIN:"));
if (!pin) {
fsm_sendFailure(FailureType_Failure_PinCancelled, NULL);
return false;
@ -211,14 +213,14 @@ bool protectPin(bool use_cached)
return ret;
}
bool protectChangePin(bool removal)
{
bool protectChangePin(bool removal) {
static CONFIDENTIAL char old_pin[MAX_PIN_LEN + 1] = "";
static CONFIDENTIAL char new_pin[MAX_PIN_LEN + 1] = "";
const char *pin = NULL;
if (config_hasPin()) {
pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:"));
pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current,
_("Please enter current PIN:"));
if (pin == NULL) {
fsm_sendFailure(FailureType_Failure_PinCancelled, NULL);
return false;
@ -239,7 +241,8 @@ bool protectChangePin(bool removal)
}
if (!removal) {
pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst, _("Please enter new PIN:"));
pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst,
_("Please enter new PIN:"));
if (pin == NULL) {
memzero(old_pin, sizeof(old_pin));
fsm_sendFailure(FailureType_Failure_PinCancelled, NULL);
@ -247,7 +250,8 @@ bool protectChangePin(bool removal)
}
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) {
memzero(old_pin, sizeof(old_pin));
memzero(new_pin, sizeof(new_pin));
@ -272,8 +276,7 @@ bool protectChangePin(bool removal)
return ret;
}
bool protectPassphrase(void)
{
bool protectPassphrase(void) {
bool passphrase_protection = false;
config_getPassphraseProtection(&passphrase_protection);
if (!passphrase_protection || session_isPassphraseCached()) {
@ -285,12 +288,15 @@ bool protectPassphrase(void)
usbTiny(1);
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;
for (;;) {
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) {
msg_tiny_id = 0xFFFF;
PassphraseAck *ppa = (PassphraseAck *)msg_tiny;
@ -300,7 +306,8 @@ bool protectPassphrase(void)
}
// check for Cancel / Initialize
protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel);
protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize);
protectAbortedByInitialize =
(msg_tiny_id == MessageType_MessageType_Initialize);
if (protectAbortedByCancel || protectAbortedByInitialize) {
msg_tiny_id = 0xFFFF;
result = false;

@ -25,7 +25,8 @@
#include "secbool.h"
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 protectChangePin(bool removal);
bool protectPassphrase(void);

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

@ -18,21 +18,21 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <ctype.h>
#include "recovery.h"
#include "fsm.h"
#include <ctype.h>
#include "bip39.h"
#include "config.h"
#include "fsm.h"
#include "gettext.h"
#include "layout2.h"
#include "protect.h"
#include "memzero.h"
#include "messages.h"
#include "rng.h"
#include "bip39.h"
#include "messages.pb.h"
#include "oled.h"
#include "usb.h"
#include "gettext.h"
#include "protect.h"
#include "recovery-table.h"
#include "memzero.h"
#include "messages.pb.h"
#include "rng.h"
#include "usb.h"
/* number of words expected in the new seed */
static uint32_t word_count;
@ -129,11 +129,14 @@ static void format_number(char *dest, int number) {
}
dest[1] = '0' + number % 10;
if (number == 1 || number == 21) {
dest[2] = 's'; dest[3] = 't';
dest[2] = 's';
dest[3] = 't';
} else if (number == 2 || number == 22) {
dest[2] = 'n'; dest[3] = 'd';
dest[2] = 'n';
dest[3] = 'd';
} 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;
memzero(&resp, sizeof(WordRequest));
resp.has_type = true;
resp.type = awaiting_word == 1 ? WordRequestType_WordRequestType_Plain
: (word_index % 4 == 3) ? WordRequestType_WordRequestType_Matrix6
resp.type = awaiting_word == 1
? WordRequestType_WordRequestType_Plain
: (word_index % 4 == 3)
? WordRequestType_WordRequestType_Matrix6
: WordRequestType_WordRequestType_Matrix9;
msg_write(MessageType_MessageType_WordRequest, &resp);
}
@ -171,27 +176,30 @@ static void recovery_done(void) {
}
fsm_sendSuccess(_("Device recovered"));
} 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));
} else {
// Inform the user about new mnemonic correctness (as well as whether it is the same as the current one).
bool match = (config_isInitialized() && config_containsMnemonic(new_mnemonic));
// Inform the user about new mnemonic correctness (as well as whether it
// is the same as the current one).
bool match =
(config_isInitialized() && config_containsMnemonic(new_mnemonic));
memzero(new_mnemonic, sizeof(new_mnemonic));
if (match) {
layoutDialog(&bmp_icon_ok, NULL, _("Confirm"), NULL,
_("The seed is valid"),
_("and MATCHES"),
_("The seed is valid"), _("and MATCHES"),
_("the one in the device."), NULL, NULL, NULL);
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 {
layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL,
_("The seed is valid"),
_("but does NOT MATCH"),
_("The seed is valid"), _("but does NOT MATCH"),
_("the one in the device."), NULL, NULL, NULL);
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"));
}
}
@ -201,11 +209,12 @@ static void recovery_done(void) {
if (!dry_run) {
session_clear(true);
} else {
layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL,
_("The seed is"), _("INVALID!"), NULL, NULL, NULL, NULL);
layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL, _("The seed is"),
_("INVALID!"), NULL, NULL, NULL, NULL);
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;
layoutHome();
@ -222,7 +231,8 @@ static void recovery_done(void) {
* memcmp(last, "last + 1", prefixlen) != 0
* 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
char *dest = choice;
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
* 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 displayedChoices = nColumns * 3;
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";
int nr = (word_index / 4) + 1;
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 {
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 choice = word_matrix[nColumns * row + col];
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) {
oledInvert(x - 32 + 1, y - 1, x - 32 + 63 - 1, y + 8);
} else {
@ -296,8 +308,7 @@ static void display_choices(bool twoColumn, char choices[9][12], int num)
/* avoid picking out of range numbers */
for (int i = 0; i < displayedChoices; i++) {
if (word_matrix[i] >= num)
word_matrix[i] = 0;
if (word_matrix[i] >= num) word_matrix[i] = 0;
}
/* two column layout: middle column = right column */
if (twoColumn) {
@ -343,8 +354,7 @@ static void next_matrix(void) {
num = TABLE1(word_pincode + 1) - idx;
for (uint32_t i = 0; i < num; i++) {
add_choice(word_choices[i], (word_table2[idx + i] >> 12),
wl[TABLE2(idx + i)],
wl[TABLE2(idx + i + 1) - 1]);
wl[TABLE2(idx + i)], wl[TABLE2(idx + i + 1) - 1]);
}
break;
@ -366,8 +376,7 @@ static void next_matrix(void) {
/* num: the number of choices. */
num = 9;
for (uint32_t i = 0; i < num; i++) {
add_choice(word_choices[i], 1,
wl[TABLE2(TABLE1(9*i))],
add_choice(word_choices[i], 1, wl[TABLE2(TABLE1(9 * i))],
wl[TABLE2(TABLE1(9 * (i + 1))) - 1]);
}
break;
@ -386,8 +395,7 @@ static void recovery_digit(const char digit) {
/* backspace: undo */
if ((word_index % 4) == 0) {
/* undo complete word */
if (word_index > 0)
word_index -= 4;
if (word_index > 0) word_index -= 4;
} else {
word_index--;
word_pincode /= 9;
@ -440,18 +448,24 @@ void next_word(void) {
if (word_pos == 0) {
const char *const *wl = mnemonic_wordlist();
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 {
fake_word[0] = 0;
char desc[] = "##th word";
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();
}
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;
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;
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)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
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 (strcmp(word, fake_word) != 0) {
if (!dry_run) {
session_clear(true);
}
fsm_sendFailure(FailureType_Failure_ProcessError, _("Wrong word retyped"));
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Wrong word retyped"));
layoutHome();
return;
}
@ -524,7 +540,8 @@ static void recovery_scrambledword(const char *word)
if (!dry_run) {
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();
return;
}
@ -543,8 +560,7 @@ static void recovery_scrambledword(const char *word)
/* Function called when a word was entered by user. Used
* for scrambled recovery.
*/
void recovery_word(const char *word)
{
void recovery_word(const char *word) {
switch (awaiting_word) {
case 2:
recovery_digit(word[0]);
@ -553,15 +569,15 @@ void recovery_word(const char *word)
recovery_scrambledword(word);
break;
default:
fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Recovery mode"));
fsm_sendFailure(FailureType_Failure_UnexpectedMessage,
_("Not in Recovery mode"));
break;
}
}
/* Abort recovery.
*/
void recovery_abort(void)
{
void recovery_abort(void) {
if (awaiting_word) {
layoutHome();
awaiting_word = 0;
@ -570,14 +586,8 @@ void recovery_abort(void)
#if DEBUG_LINK
const char *recovery_get_fake_word(void)
{
return fake_word;
}
const char *recovery_get_fake_word(void) { return fake_word; }
uint32_t recovery_get_word_pos(void)
{
return word_pos;
}
uint32_t recovery_get_word_pos(void) { return word_pos; }
#endif

@ -20,10 +20,13 @@
#ifndef __RECOVERY_H__
#define __RECOVERY_H__
#include <stdint.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_abort(void);
const char *recovery_get_fake_word(void);

@ -18,18 +18,18 @@
*/
#include "reset.h"
#include "bip39.h"
#include "config.h"
#include "rng.h"
#include "sha2.h"
#include "messages.h"
#include "fsm.h"
#include "gettext.h"
#include "layout2.h"
#include "memzero.h"
#include "messages.h"
#include "messages.pb.h"
#include "protect.h"
#include "bip39.h"
#include "rng.h"
#include "sha2.h"
#include "util.h"
#include "gettext.h"
#include "messages.pb.h"
#include "memzero.h"
static uint32_t strength;
static uint8_t int_entropy[32];
@ -37,8 +37,10 @@ static bool awaiting_entropy = false;
static bool skip_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;
strength = _strength;
@ -46,12 +48,15 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect
no_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();
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)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
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]);
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)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome();
@ -91,10 +98,10 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect
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) {
fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Reset mode"));
fsm_sendFailure(FailureType_Failure_UnexpectedMessage,
_("Not in Reset mode"));
return;
}
awaiting_entropy = false;
@ -116,7 +123,8 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len)
if (config_setMnemonic(mnemonic)) {
fsm_sendSuccess(_("Device successfully initialized"));
} else {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic"));
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to store mnemonic"));
}
layoutHome();
} else {
@ -128,13 +136,13 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len)
static char current_word[10];
// 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) {
bool needs_backup = false;
config_getNeedsBackup(&needs_backup);
if (!needs_backup) {
fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up"));
fsm_sendFailure(FailureType_Failure_UnexpectedMessage,
_("Seed already backed up"));
return;
}
@ -147,9 +155,11 @@ void reset_backup(bool separated, const char* mnemonic)
while (mnemonic[i] != 0) {
// copy current_word
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];
i++; j++;
i++;
j++;
}
current_word[j] = 0;
if (mnemonic[i] != 0) {
@ -177,7 +187,8 @@ void reset_backup(bool separated, const char* mnemonic)
if (config_setMnemonic(mnemonic)) {
fsm_sendSuccess(_("Device successfully initialized"));
} else {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic"));
fsm_sendFailure(FailureType_Failure_ProcessError,
_("Failed to store mnemonic"));
}
}
layoutHome();
@ -190,8 +201,6 @@ uint32_t reset_get_int_entropy(uint8_t *entropy) {
return 32;
}
const char *reset_get_word(void) {
return current_word;
}
const char *reset_get_word(void) { return current_word; }
#endif

@ -20,10 +20,13 @@
#ifndef __RESET_H__
#define __RESET_H__
#include <stdint.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_backup(bool separated, const char *mnemonic);
uint32_t reset_get_int_entropy(uint8_t *entropy);

File diff suppressed because it is too large Load Diff

@ -20,14 +20,15 @@
#ifndef __SIGNING_H__
#define __SIGNING_H__
#include <stdint.h>
#include <stdbool.h>
#include <stdint.h>
#include "bip32.h"
#include "coins.h"
#include "hasher.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_txack(TransactionType *tx);

File diff suppressed because it is too large Load Diff

@ -21,11 +21,11 @@
#define __STELLAR_H__
#include <stdbool.h>
#include "base32.h"
#include "bip32.h"
#include "crypto.h"
#include "messages.pb.h"
#include "fsm.h"
#include "base32.h"
#include "messages.pb.h"
// 56 character base-32 encoded string
#define STELLAR_ADDRESS_SIZE 56
@ -55,12 +55,14 @@ typedef struct {
// Signing process
bool stellar_signingInit(const StellarSignTx *tx);
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_confirmPaymentOp(const StellarPaymentOp *msg);
bool stellar_confirmPathPaymentOp(const StellarPathPaymentOp *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_confirmChangeTrustOp(const StellarChangeTrustOp *msg);
bool stellar_confirmAllowTrustOp(const StellarAllowTrustOp *msg);
@ -69,14 +71,22 @@ bool stellar_confirmManageDataOp(const StellarManageDataOp *msg);
bool stellar_confirmBumpSequenceOp(const StellarBumpSequenceOp *msg);
// 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_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
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);
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_uint64(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_price(uint32_t numerator, uint32_t denominator, char *out, size_t outlen);
void stellar_format_asset(const StellarAssetType *asset, char *str_formatted,
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_getAddressBytes(const char *str_address, uint8_t *out_bytes);

@ -17,22 +17,22 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include "transaction.h"
#include "ecdsa.h"
#include <string.h>
#include "address.h"
#include "base58.h"
#include "cash_addr.h"
#include "coins.h"
#include "util.h"
#include "crypto.h"
#include "debug.h"
#include "protect.h"
#include "ecdsa.h"
#include "layout2.h"
#include "crypto.h"
#include "ripemd160.h"
#include "base58.h"
#include "address.h"
#include "memzero.h"
#include "messages.pb.h"
#include "protect.h"
#include "ripemd160.h"
#include "segwit_addr.h"
#include "cash_addr.h"
#include "memzero.h"
#include "util.h"
#define SEGWIT_VERSION_0 0
@ -58,7 +58,8 @@
#define TXSIZE_P2PKHASH 25
/* size of a p2sh script (hash, push, 20 scripthash, equal) */
#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
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;
}
bool compute_address(const CoinInfo *coin,
InputScriptType script_type,
const HDNode *node,
bool has_multisig, const MultisigRedeemScriptType *multisig,
bool compute_address(const CoinInfo *coin, InputScriptType script_type,
const HDNode *node, bool has_multisig,
const MultisigRedeemScriptType *multisig,
char address[MAX_ADDR_SIZE]) {
uint8_t raw[MAX_ADDR_RAW_SIZE];
uint8_t digest[32];
size_t prelen;
@ -122,7 +121,8 @@ bool compute_address(const CoinInfo *coin,
if (!coin->has_segwit || !coin->bech32_prefix) {
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;
}
} 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);
address_write_prefix_bytes(coin->address_type_p2sh, raw);
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;
}
} else if (coin->cashaddr_prefix) {
@ -154,7 +155,8 @@ bool compute_address(const CoinInfo *coin,
prelen = address_prefix_bytes_len(coin->address_type_p2sh);
address_write_prefix_bytes(coin->address_type_p2sh, raw);
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;
}
}
@ -164,7 +166,8 @@ bool compute_address(const CoinInfo *coin,
return 0;
}
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;
}
} else if (script_type == InputScriptType_SPENDP2SHWITNESS) {
@ -175,20 +178,25 @@ bool compute_address(const CoinInfo *coin,
if (!coin->has_address_type_p2sh) {
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) {
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)) {
return 0;
}
} 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;
}
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));
out->amount = in->amount;
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
}
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);
} 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
}
}
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);
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;
return r;
}
@ -239,24 +254,26 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T
return 0; // failed to compile output
}
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
}
hdnode_fill_public_key(&node);
if (!compute_address(coin, input_script_type, &node,
in->has_multisig, &in->multisig,
in->address)) {
if (!compute_address(coin, input_script_type, &node, in->has_multisig,
&in->multisig, in->address)) {
return 0; // failed to compile output
}
} else if (!in->has_address) {
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;
if (coin->has_address_type // p2pkh
&& addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type))
&& address_check_prefix(addr_raw, coin->address_type)) {
&& addr_raw_len ==
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[1] = 0xA9; // OP_HASH_160
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.size = 25;
} else if (coin->has_address_type_p2sh // p2sh
&& addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(coin->address_type_p2sh))
&& address_check_prefix(addr_raw, coin->address_type_p2sh)) {
&& addr_raw_len == 20 + (prefix_len = address_prefix_bytes_len(
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[1] = 0x14; // pushing 20 bytes
memcpy(out->script_pubkey.bytes + 2, addr_raw + prefix_len, 20);
out->script_pubkey.bytes[22] = 0x87; // OP_EQUAL
out->script_pubkey.size = 23;
} else if (coin->cashaddr_prefix
&& cash_addr_decode(addr_raw, &addr_raw_len, coin->cashaddr_prefix, in->address)) {
if (addr_raw_len == 21
&& addr_raw[0] == (CASHADDR_P2KH | CASHADDR_160)) {
} else if (coin->cashaddr_prefix &&
cash_addr_decode(addr_raw, &addr_raw_len, coin->cashaddr_prefix,
in->address)) {
if (addr_raw_len == 21 && addr_raw[0] == (CASHADDR_P2KH | CASHADDR_160)) {
out->script_pubkey.bytes[0] = 0x76; // OP_DUP
out->script_pubkey.bytes[1] = 0xA9; // OP_HASH_160
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.size = 25;
} else if (addr_raw_len == 21
&& addr_raw[0] == (CASHADDR_P2SH | CASHADDR_160)) {
} else if (addr_raw_len == 21 &&
addr_raw[0] == (CASHADDR_P2SH | CASHADDR_160)) {
out->script_pubkey.bytes[0] = 0xA9; // OP_HASH_160
out->script_pubkey.bytes[1] = 0x14; // pushing 20 bytes
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) {
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;
}
// segwit:
@ -320,8 +339,8 @@ int compile_output(const CoinInfo *coin, const HDNode *root, TxOutputType *in, T
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
out[0] = 0x76; // OP_DUP
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
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;
const uint32_t m = multisig->m;
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;
uint32_t r = 0;
if (out) {
out[r] = 0x50 + m; r++;
out[r] = 0x50 + m;
r++;
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);
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] = 0xAE; r++; // OP_CHECKMULTISIG
out[r] = 0x50 + n;
r++;
out[r] = 0xAE;
r++; // OP_CHECKMULTISIG
} else {
r = 1 + 34 * n + 2;
}
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;
const uint32_t m = multisig->m;
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);
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++) {
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);
if (!pubnode) return 0;
hasher_Update(&hasher, pubnode->public_key, 33);
@ -388,31 +416,40 @@ uint32_t compile_script_multisig_hash(const CoinInfo *coin, const MultisigRedeem
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;
r += op_push(signature_len + 1, out + r);
memcpy(out + r, signature, signature_len); r += signature_len;
out[r] = sighash; r++;
memcpy(out + r, signature, signature_len);
r += signature_len;
out[r] = sighash;
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;
}
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;
if (!coin->decred) {
// 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++) {
if (multisig->signatures[i].size == 0) {
continue;
}
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;
out[r] = sighash; r++;
memcpy(out + r, multisig->signatures[i].bytes,
multisig->signatures[i].size);
r += multisig->signatures[i].size;
out[r] = sighash;
r++;
}
uint32_t script_len = compile_script_multisig(coin, multisig, 0);
if (script_len == 0) {
@ -425,8 +462,7 @@ uint32_t serialize_script_multisig(const CoinInfo *coin, const MultisigRedeemScr
// 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++) {
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;
}
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);
hasher_Update(hasher, data, 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);
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;
hasher_Update(hasher, (const uint8_t *)&output->amount, 8); r += 8;
hasher_Update(hasher, (const uint8_t *)&output->amount, 8);
r += 8;
if (decred) {
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;
}
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);
memcpy(out + r, data, 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;
if (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);
}
uint32_t tx_serialize_header_hash(TxStruct *tx)
{
uint32_t tx_serialize_header_hash(TxStruct *tx) {
int r = 4;
if (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);
}
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) {
// already got all inputs
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];
}
r += 32;
memcpy(out + r, &input->prev_index, 4); r += 4;
memcpy(out + r, &input->prev_index, 4);
r += 4;
if (tx->is_decred) {
uint8_t tree = input->decred_tree & 0xFF;
out[r++] = tree;
} 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->size += r;
@ -531,8 +568,7 @@ uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out
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) {
// already got all inputs
return 0;
@ -544,9 +580,11 @@ uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input)
r += tx_prevout_hash(&(tx->hasher), input);
if (tx->is_decred) {
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 {
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);
@ -556,8 +594,8 @@ uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input)
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 uint32_t block_height = 0x00000000;
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) {
r += ser_length(tx->inputs_len, out + r);
}
memcpy(out + r, &amount, 8); r += 8;
memcpy(out + r, &block_height, 4); r += 4;
memcpy(out + r, &block_index, 4); r += 4;
r += tx_serialize_script(input->script_sig.size, input->script_sig.bytes, out + r);
memcpy(out + r, &amount, 8);
r += 8;
memcpy(out + r, &block_height, 4);
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->size += r;
@ -581,8 +623,8 @@ uint32_t tx_serialize_decred_witness(TxStruct *tx, const TxInputType *input, uin
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) {
// already got all inputs
return 0;
@ -594,7 +636,8 @@ uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxInputType *input
if (input == NULL) {
r += ser_length_hash(&(tx->hasher), 0);
} 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++;
@ -603,26 +646,22 @@ uint32_t tx_serialize_decred_witness_hash(TxStruct *tx, const TxInputType *input
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);
}
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);
}
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);
if (tx->overwintered) {
if (tx->version == 3) {
memcpy(out + 4, &(tx->expiry), 4);
out[8] = 0x00; // nJoinSplit
return 9;
} else
if (tx->version == 4) {
} else if (tx->version == 4) {
memcpy(out + 4, &(tx->expiry), 4);
memzero(out + 8, 8); // valueBalance
out[16] = 0x00; // nShieldedSpend
@ -638,8 +677,7 @@ uint32_t tx_serialize_footer(TxStruct *tx, uint8_t *out)
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);
if (tx->overwintered) {
hasher_Update(&(tx->hasher), (const uint8_t *)&(tx->expiry), 4);
@ -653,8 +691,8 @@ uint32_t tx_serialize_footer_hash(TxStruct *tx)
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) {
// not all inputs provided
return 0;
@ -667,23 +705,24 @@ uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_
if (tx->have_outputs == 0) {
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) {
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++;
if (tx->have_outputs == tx->outputs_len
&& !tx->is_segwit) {
if (tx->have_outputs == tx->outputs_len && !tx->is_segwit) {
r += tx_serialize_footer(tx, out + r);
}
tx->size += 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) {
// not all inputs provided
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);
tx->have_outputs++;
if (tx->have_outputs == tx->outputs_len
&& !tx->is_segwit) {
if (tx->have_outputs == tx->outputs_len && !tx->is_segwit) {
r += tx_serialize_footer_hash(tx);
}
tx->size += 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) {
// not all inputs provided
return 0;
@ -726,8 +764,10 @@ uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_
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->outputs_len = outputs_len;
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);
}
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);
if (!reverse) return;
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) {
uint32_t input_script_size;
if (txinput->has_multisig) {
uint32_t multisig_script_size = TXSIZE_MULTISIGSCRIPT
+ txinput->multisig.pubkeys_count * (1 + TXSIZE_PUBKEY);
uint32_t multisig_script_size =
TXSIZE_MULTISIGSCRIPT +
txinput->multisig.pubkeys_count * (1 + TXSIZE_PUBKEY);
input_script_size = 1 // the OP_FALSE bug in multisig
+ txinput->multisig.m * (1 + TXSIZE_SIGNATURE)
+ op_push_size(multisig_script_size) + multisig_script_size;
+ txinput->multisig.m * (1 + TXSIZE_SIGNATURE) +
op_push_size(multisig_script_size) +
multisig_script_size;
} else {
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 weight = 4 * TXSIZE_INPUT;
if (txinput->script_type == InputScriptType_SPENDADDRESS
|| txinput->script_type == InputScriptType_SPENDMULTISIG) {
if (txinput->script_type == InputScriptType_SPENDADDRESS ||
txinput->script_type == InputScriptType_SPENDMULTISIG) {
input_script_size += ser_length_size(input_script_size);
weight += 4 * input_script_size;
} else if (txinput->script_type == InputScriptType_SPENDWITNESS
|| txinput->script_type == InputScriptType_SPENDP2SHWITNESS) {
} else if (txinput->script_type == InputScriptType_SPENDWITNESS ||
txinput->script_type == InputScriptType_SPENDP2SHWITNESS) {
if (txinput->script_type == InputScriptType_SPENDP2SHWITNESS) {
weight += 4 * (2 + (txinput->has_multisig
? TXSIZE_WITNESSSCRIPT : TXSIZE_WITNESSPKHASH));
weight += 4 * (2 + (txinput->has_multisig ? TXSIZE_WITNESSSCRIPT
: TXSIZE_WITNESSPKHASH));
} else {
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 output_script_size = 0;
if (txoutput->script_type == OutputScriptType_PAYTOOPRETURN) {
output_script_size = 1 + op_push_size(txoutput->op_return_data.size)
+ txoutput->op_return_data.size;
output_script_size = 1 + op_push_size(txoutput->op_return_data.size) +
txoutput->op_return_data.size;
} else if (txoutput->address_n_count > 0) {
if (txoutput->script_type == OutputScriptType_PAYTOWITNESS) {
output_script_size = txoutput->has_multisig
? TXSIZE_WITNESSSCRIPT : TXSIZE_WITNESSPKHASH;
output_script_size =
txoutput->has_multisig ? TXSIZE_WITNESSSCRIPT : TXSIZE_WITNESSPKHASH;
} else if (txoutput->script_type == OutputScriptType_PAYTOP2SHWITNESS) {
output_script_size = TXSIZE_P2SCRIPT;
} else {
output_script_size = txoutput->has_multisig
? TXSIZE_P2SCRIPT : TXSIZE_P2PKHASH;
output_script_size =
txoutput->has_multisig ? TXSIZE_P2SCRIPT : TXSIZE_P2PKHASH;
}
} else {
uint8_t addr_raw[MAX_ADDR_RAW_SIZE];
int witver;
size_t addr_raw_len;
if (coin->cashaddr_prefix
&& cash_addr_decode(addr_raw, &addr_raw_len, coin->cashaddr_prefix, txoutput->address)) {
if (addr_raw_len == 21
&& addr_raw[0] == (CASHADDR_P2KH | CASHADDR_160)) {
if (coin->cashaddr_prefix &&
cash_addr_decode(addr_raw, &addr_raw_len, coin->cashaddr_prefix,
txoutput->address)) {
if (addr_raw_len == 21 && addr_raw[0] == (CASHADDR_P2KH | CASHADDR_160)) {
output_script_size = TXSIZE_P2PKHASH;
} else if (addr_raw_len == 21
&& addr_raw[0] == (CASHADDR_P2SH | CASHADDR_160)) {
} else if (addr_raw_len == 21 &&
addr_raw[0] == (CASHADDR_P2SH | CASHADDR_160)) {
output_script_size = TXSIZE_P2SCRIPT;
}
} else if (coin->bech32_prefix
&& segwit_addr_decode(&witver, addr_raw, &addr_raw_len, coin->bech32_prefix, txoutput->address)) {
} else if (coin->bech32_prefix &&
segwit_addr_decode(&witver, addr_raw, &addr_raw_len,
coin->bech32_prefix, txoutput->address)) {
output_script_size = 2 + addr_raw_len;
} else {
addr_raw_len = base58_decode_check(txoutput->address, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE);
if (coin->has_address_type
&& address_check_prefix(addr_raw, coin->address_type)) {
addr_raw_len =
base58_decode_check(txoutput->address, coin->curve->hasher_base58,
addr_raw, MAX_ADDR_RAW_SIZE);
if (coin->has_address_type &&
address_check_prefix(addr_raw, coin->address_type)) {
output_script_size = TXSIZE_P2PKHASH;
} else if (coin->has_address_type_p2sh
&& address_check_prefix(addr_raw, coin->address_type_p2sh)) {
} else if (coin->has_address_type_p2sh &&
address_check_prefix(addr_raw, coin->address_type_p2sh)) {
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 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;
}

@ -22,11 +22,11 @@
#include <stdbool.h>
#include <stdint.h>
#include "sha2.h"
#include "bip32.h"
#include "coins.h"
#include "hasher.h"
#include "messages-bitcoin.pb.h"
#include "sha2.h"
#define TX_OVERWINTERED 0x80000000
@ -53,31 +53,53 @@ typedef struct {
Hasher hasher;
} TxStruct;
bool compute_address(const CoinInfo *coin, InputScriptType script_type, const HDNode *node, bool has_multisig, const MultisigRedeemScriptType *multisig, char address[MAX_ADDR_SIZE]);
uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash, uint8_t *out);
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);
bool compute_address(const CoinInfo *coin, InputScriptType script_type,
const HDNode *node, bool has_multisig,
const MultisigRedeemScriptType *multisig,
char address[MAX_ADDR_SIZE]);
uint32_t compile_script_sig(uint32_t address_type, const uint8_t *pubkeyhash,
uint8_t *out);
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_script_hash(Hasher *hasher, uint32_t size, const uint8_t *data);
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_footer(TxStruct *tx, uint8_t *out);
uint32_t tx_serialize_input(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);
uint32_t tx_serialize_input(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_input_hash(TxStruct *tx, const TxInputType *input);
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_decred_witness_hash(TxStruct *tx, const TxInputType *input);
uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data,
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);
uint32_t tx_input_weight(const CoinInfo *coin, const TxInputType *txinput);

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

@ -17,29 +17,29 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <ecdsa.h>
#include <string.h>
#include "debug.h"
#include "config.h"
#include "bip32.h"
#include "layout2.h"
#include "usb.h"
#include "buttons.h"
#include "trezor.h"
#include "config.h"
#include "curves.h"
#include "debug.h"
#include "gettext.h"
#include "hmac.h"
#include "layout2.h"
#include "memzero.h"
#include "nist256p1.h"
#include "rng.h"
#include "hmac.h"
#include "trezor.h"
#include "usb.h"
#include "util.h"
#include "gettext.h"
#include "memzero.h"
#include "u2f.h"
#include "u2f/u2f.h"
#include "u2f/u2f_hid.h"
#include "u2f/u2f_keys.h"
#include "u2f_knownapps.h"
#include "u2f.h"
// About 1/2 Second according to values used in protect.c
#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))
// 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"
// Auth/Register request state machine
@ -92,8 +93,7 @@ typedef struct {
static uint32_t dialog_timeout = 0;
uint32_t next_cid(void)
{
uint32_t next_cid(void) {
// extremely unlikely but hey
do {
cid = random32();
@ -116,8 +116,7 @@ typedef struct {
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
if (f->init.cmd == U2FHID_INIT) {
u2fhid_init(f);
@ -151,8 +150,9 @@ void u2fhid_read(char tiny, const U2FHID_FRAME *f)
}
// check out of bounds
if ((reader->buf_ptr - reader->buf) >= (signed) reader->len
|| (reader->buf_ptr + sizeof(f->cont.data) - reader->buf) > (signed) sizeof(reader->buf))
if ((reader->buf_ptr - reader->buf) >= (signed)reader->len ||
(reader->buf_ptr + sizeof(f->cont.data) - reader->buf) >
(signed)sizeof(reader->buf))
return;
reader->seq++;
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--;
usbPoll(); // may trigger new request
buttonUpdate();
if (button.YesUp &&
(last_req_state == AUTH || last_req_state == REG)) {
if (button.YesUp && (last_req_state == AUTH || last_req_state == REG)) {
last_req_state++;
// standard requires to remember button press for 10 seconds.
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");
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");
(void)buf;
if (len > 0)
return send_u2fhid_error(cid, ERR_INVALID_LEN);
if (len > 0) return send_u2fhid_error(cid, ERR_INVALID_LEN);
if (dialog_timeout > 0)
dialog_timeout = U2F_TIMEOUT;
if (dialog_timeout > 0) dialog_timeout = U2F_TIMEOUT;
U2FHID_FRAME f;
memzero(&f, sizeof(f));
@ -286,8 +281,7 @@ void u2fhid_wink(const uint8_t *buf, uint32_t len)
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;
U2FHID_FRAME f;
U2FHID_INIT_RESP resp;
@ -318,8 +312,7 @@ void u2fhid_init(const U2FHID_FRAME *in)
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");
uint32_t next = (u2f_out_end + 1) % U2F_OUT_PKT_BUFFER_LEN;
if (u2f_out_start == next) {
@ -330,18 +323,15 @@ void queue_u2f_pkt(const U2FHID_FRAME *u2f_pkt)
u2f_out_end = next;
}
uint8_t *u2f_out_data(void)
{
if (u2f_out_start == u2f_out_end)
return NULL; // No data
uint8_t *u2f_out_data(void) {
if (u2f_out_start == u2f_out_end) return NULL; // No data
// debugLog(0, "", "u2f_out_data");
uint32_t t = u2f_out_start;
u2f_out_start = (u2f_out_start + 1) % U2F_OUT_PKT_BUFFER_LEN;
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) {
debugLog(0, "", "BAD APDU LENGTH");
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) {
debugLog(0, "", "send_u2fhid_msg failed");
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;
memzero(&f, sizeof(f));
@ -426,8 +415,7 @@ void send_u2fhid_error(uint32_t fcid, uint8_t err)
queue_u2f_pkt(&f);
}
void u2f_version(const APDU *a)
{
void u2f_version(const APDU *a) {
if (APDU_LEN(*a) != 0) {
debugLog(0, "", "u2f version - badlen");
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));
}
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];
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) {
*appname = u2f_well_known[i].appname;
return;
@ -457,8 +447,8 @@ static void getReadableAppId(const uint8_t appid[U2F_APPID_SIZE], const char **a
*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;
if (!config_getU2FRoot(&node)) {
layoutHome();
@ -478,8 +468,8 @@ static const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count)
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];
// 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
const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES);
if (!node)
return NULL;
if (!node) return NULL;
// For second half of keyhandle
// Signature of app_id and random data
memcpy(&keybase[0], app_id, U2F_APPID_SIZE);
memcpy(&keybase[U2F_APPID_SIZE], key_handle, KEY_PATH_LEN);
hmac_sha256(node->private_key, sizeof(node->private_key),
keybase, sizeof(keybase), &key_handle[KEY_PATH_LEN]);
hmac_sha256(node->private_key, sizeof(node->private_key), keybase,
sizeof(keybase), &key_handle[KEY_PATH_LEN]);
// Done!
return node;
}
static const HDNode *validateKeyHandle(const uint8_t app_id[], const uint8_t key_handle[])
{
static const HDNode *validateKeyHandle(const uint8_t app_id[],
const uint8_t key_handle[]) {
uint32_t key_path[KEY_PATH_ENTRIES];
memcpy(key_path, key_handle, KEY_PATH_LEN);
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);
if (!node)
return NULL;
if (!node) return NULL;
uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN];
memcpy(&keybase[0], app_id, U2F_APPID_SIZE);
memcpy(&keybase[U2F_APPID_SIZE], key_handle, KEY_PATH_LEN);
uint8_t hmac[SHA256_DIGEST_LENGTH];
hmac_sha256(node->private_key, sizeof(node->private_key),
keybase, sizeof(keybase), hmac);
hmac_sha256(node->private_key, sizeof(node->private_key), keybase,
sizeof(keybase), hmac);
if (memcmp(&key_handle[KEY_PATH_LEN], hmac, SHA256_DIGEST_LENGTH) != 0)
return NULL;
@ -540,9 +526,7 @@ static const HDNode *validateKeyHandle(const uint8_t app_id[], const uint8_t key
return node;
}
void u2f_register(const APDU *a)
{
void u2f_register(const APDU *a) {
static U2F_REGISTER_REQ last_req;
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
buttonUpdate(); // Clear button state
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 {
const char *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,
(uint8_t *)&resp->pubKey);
memcpy(resp->keyHandleCertSig + resp->keyHandleLen,
U2F_ATT_CERT, sizeof(U2F_ATT_CERT));
memcpy(resp->keyHandleCertSig + resp->keyHandleLen, U2F_ATT_CERT,
sizeof(U2F_ATT_CERT));
uint8_t sig[64];
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.keyHandle, &resp->keyHandleCertSig, KEY_HANDLE_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);
return;
}
// Where to write the signature in the response
uint8_t *resp_sig = resp->keyHandleCertSig +
resp->keyHandleLen + sizeof(U2F_ATT_CERT);
uint8_t *resp_sig =
resp->keyHandleCertSig + resp->keyHandleLen + sizeof(U2F_ATT_CERT);
// Convert to der for the response
const uint8_t sig_len = ecdsa_sig_to_der(sig, resp_sig);
// Append success bytes
memcpy(resp->keyHandleCertSig + resp->keyHandleLen +
sizeof(U2F_ATT_CERT) + sig_len,
memcpy(resp->keyHandleCertSig + resp->keyHandleLen + sizeof(U2F_ATT_CERT) +
sig_len,
"\x90\x00", 2);
int l = 1 /* registerId */ + U2F_PUBKEY_LEN +
1 /* keyhandleLen */ + resp->keyHandleLen +
sizeof(U2F_ATT_CERT) + sig_len + 2;
int l = 1 /* registerId */ + U2F_PUBKEY_LEN + 1 /* keyhandleLen */ +
resp->keyHandleLen + sizeof(U2F_ATT_CERT) + sig_len + 2;
last_req_state = INIT;
dialog_timeout = 0;
@ -648,8 +635,7 @@ void u2f_register(const APDU *a)
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;
static U2F_AUTHENTICATE_REQ last_req;
@ -670,8 +656,7 @@ void u2f_authenticate(const APDU *a)
return;
}
const HDNode *node =
validateKeyHandle(req->appId, req->keyHandle);
const HDNode *node = validateKeyHandle(req->appId, req->keyHandle);
if (!node) {
debugLog(0, "", "u2f auth - bad keyhandle len");
@ -722,8 +707,7 @@ void u2f_authenticate(const APDU *a)
// Buttons said yes
if (last_req_state == AUTH_PASS) {
uint8_t buf[sizeof(U2F_AUTHENTICATE_RESP) + 2];
U2F_AUTHENTICATE_RESP *resp =
(U2F_AUTHENTICATE_RESP *)&buf;
U2F_AUTHENTICATE_RESP *resp = (U2F_AUTHENTICATE_RESP *)&buf;
const uint32_t ctr = config_nextU2FCounter();
resp->flags = U2F_AUTH_FLAG_TUP;
@ -739,7 +723,9 @@ void u2f_authenticate(const APDU *a)
sig_base.flags = resp->flags;
memcpy(sig_base.ctr, resp->ctr, 4);
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);
return;
}
@ -748,26 +734,22 @@ void u2f_authenticate(const APDU *a)
const uint8_t sig_len = ecdsa_sig_to_der(sig, resp->sig);
// Append OK
memcpy(buf + sizeof(U2F_AUTHENTICATE_RESP) -
U2F_MAX_EC_SIG_SIZE + sig_len,
memcpy(buf + sizeof(U2F_AUTHENTICATE_RESP) - U2F_MAX_EC_SIG_SIZE + sig_len,
"\x90\x00", 2);
last_req_state = INIT;
dialog_timeout = 0;
send_u2f_msg(buf, sizeof(U2F_AUTHENTICATE_RESP) -
U2F_MAX_EC_SIG_SIZE + sig_len +
2);
send_u2f_msg(
buf, sizeof(U2F_AUTHENTICATE_RESP) - U2F_MAX_EC_SIG_SIZE + sig_len + 2);
}
}
void send_u2f_error(const uint16_t err)
{
void send_u2f_error(const uint16_t err) {
uint8_t data[2];
data[0] = err >> 8 & 0xFF;
data[1] = err & 0xFF;
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);
}

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

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

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

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

@ -17,23 +17,22 @@
* 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/usbd.h>
#include "trezor.h"
#include "usb.h"
#include "config.h"
#include "debug.h"
#include "messages.h"
#include "timer.h"
#include "trezor.h"
#include "u2f.h"
#include "config.h"
#include "usb.h"
#include "util.h"
#include "timer.h"
#include "usb21_standard.h"
#include "webusb.h"
#include "winusb.h"
#define USB_INTERFACE_INDEX_MAIN 0
#if DEBUG_LINK
#define USB_INTERFACE_INDEX_DEBUG 1
@ -59,7 +58,7 @@
X(SERIAL_NUMBER, config_uuid_str) \
X(INTERFACE_MAIN, "TREZOR 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,
enum {
@ -69,9 +68,7 @@ enum {
#undef X
#define X(name, value) value,
static const char *usb_strings[] = {
USB_STRINGS
};
static const char *usb_strings[] = {USB_STRINGS};
#undef X
static const struct usb_device_descriptor dev_descr = {
@ -116,8 +113,9 @@ static const struct {
uint8_t bReportDescriptorType;
uint16_t wDescriptorLength;
} __attribute__((packed)) hid_report_u2f;
} __attribute__((packed)) hid_function_u2f = {
.hid_descriptor_u2f = {
} __attribute__((packed))
hid_function_u2f = {.hid_descriptor_u2f =
{
.bLength = sizeof(hid_function_u2f),
.bDescriptorType = USB_DT_HID,
.bcdHID = 0x0111,
@ -127,17 +125,18 @@ static const struct {
.hid_report_u2f = {
.bReportDescriptorType = USB_DT_REPORT,
.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,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = ENDPOINT_ADDRESS_U2F_IN,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.wMaxPacketSize = 64,
.bInterval = 1,
}, {
},
{
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = ENDPOINT_ADDRESS_U2F_OUT,
@ -162,14 +161,16 @@ static const struct usb_interface_descriptor hid_iface_u2f[] = {{
}};
#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,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_IN,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.wMaxPacketSize = 64,
.bInterval = 1,
}, {
},
{
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_OUT,
@ -195,14 +196,16 @@ static const struct usb_interface_descriptor webusb_iface_debug[] = {{
#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,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = ENDPOINT_ADDRESS_MAIN_IN,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.wMaxPacketSize = 64,
.bInterval = 1,
}, {
},
{
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = ENDPOINT_ADDRESS_MAIN_OUT,
@ -226,18 +229,20 @@ static const struct usb_interface_descriptor webusb_iface_main[] = {{
.extralen = 0,
}};
// Windows are strict about interfaces appearing
// in correct order
static const struct usb_interface ifaces[] = {{
static const struct usb_interface ifaces[] = {
{
.num_altsetting = 1,
.altsetting = webusb_iface_main,
#if DEBUG_LINK
}, {
},
{
.num_altsetting = 1,
.altsetting = webusb_iface_debug,
#endif
}, {
},
{
.num_altsetting = 1,
.altsetting = hid_iface_u2f,
}};
@ -254,16 +259,16 @@ static const struct usb_config_descriptor config = {
.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)dev;
wait_random();
if ((req->bmRequestType != 0x81) ||
(req->bRequest != USB_REQ_GET_DESCRIPTOR) ||
(req->wValue != 0x2200))
(req->bRequest != USB_REQ_GET_DESCRIPTOR) || (req->wValue != 0x2200))
return 0;
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 void main_rx_callback(usbd_device *dev, uint8_t ep)
{
static void main_rx_callback(usbd_device *dev, uint8_t ep) {
(void)ep;
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");
if (!tiny) {
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;
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
static void debug_rx_callback(usbd_device *dev, uint8_t ep)
{
static void debug_rx_callback(usbd_device *dev, uint8_t ep) {
(void)ep;
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");
if (!tiny) {
msg_debug_read(buf, 64);
@ -312,43 +316,47 @@ static void debug_rx_callback(usbd_device *dev, uint8_t ep)
}
#endif
static void set_config(usbd_device *dev, uint16_t wValue)
{
static void set_config(usbd_device *dev, uint16_t wValue) {
(void)wValue;
usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0);
usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, 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);
usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64,
0);
usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64,
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
usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0);
usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, debug_rx_callback);
usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64,
0);
usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_OUT, USB_ENDPOINT_ATTR_INTERRUPT,
64, debug_rx_callback);
#endif
usbd_register_control_callback(
dev,
USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE,
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
hid_control_request);
dev, USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE,
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, hid_control_request);
}
static usbd_device *usbd_dev = NULL;
static uint8_t usbd_control_buffer[256] __attribute__((aligned(2)));
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 = {
.bLength = USB_DT_BOS_SIZE,
.bDescriptorType = USB_DT_BOS,
.bNumDeviceCaps = sizeof(capabilities) / sizeof(capabilities[0]),
.capabilities = capabilities
};
.capabilities = capabilities};
void usbInit(void)
{
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));
void usbInit(void) {
usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings,
sizeof(usb_strings) / sizeof(*usb_strings),
usbd_control_buffer, sizeof(usbd_control_buffer));
usbd_register_set_config_callback(usbd_dev, set_config);
usb21_setup(usbd_dev, &bos_descriptor);
static const char *origin_url = "trezor.io/start";
@ -358,8 +366,7 @@ void usbInit(void)
winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN);
}
void usbPoll(void)
{
void usbPoll(void) {
if (usbd_dev == NULL) {
return;
}
@ -370,23 +377,28 @@ void usbPoll(void)
// write pending data
data = msg_out_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();
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
// write pending debug data
data = msg_debug_out_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
}
void usbReconnect(void)
{
void usbReconnect(void) {
if (usbd_dev != NULL) {
usbd_disconnect(usbd_dev, 1);
delay(1000);
@ -394,15 +406,13 @@ void usbReconnect(void)
}
}
char usbTiny(char set)
{
char usbTiny(char set) {
char old = tiny;
tiny = set;
return old;
}
void usbSleep(uint32_t millis)
{
void usbSleep(uint32_t millis) {
uint32_t start = timer_ms();
while ((timer_ms() - start) < millis) {

@ -17,8 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <libopencm3/stm32/flash.h>
#include <string.h>
#include "common.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
};
static secbool flash_check_success(uint32_t status)
{
return (status & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) ? secfalse : sectrue;
static secbool flash_check_success(uint32_t status) {
return (status & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR |
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();
return sectrue;
}
secbool flash_lock_write(void)
{
return flash_check_success(svc_flash_lock());
}
secbool flash_lock_write(void) { 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) {
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);
}
secbool flash_erase(uint8_t sector)
{
secbool flash_erase(uint8_t sector) {
ensure(flash_unlock_write(), NULL);
svc_flash_erase_sector(sector);
ensure(flash_lock_write(), NULL);
// 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) {
if (*((const uint32_t *)FLASH_PTR(addr)) != 0xFFFFFFFF) {
return secfalse;
@ -90,8 +85,7 @@ secbool flash_erase(uint8_t sector)
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);
if (address == NULL) {
return secfalse;
@ -111,8 +105,7 @@ secbool flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data)
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);
if (address == NULL) {
return secfalse;

@ -26,12 +26,15 @@
#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
#define FLASH_SR_RDERR 0
#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);

@ -22,22 +22,30 @@
#include "layout.h"
#include "oled.h"
void layoutButtonNo(const char *btnNo)
{
void layoutButtonNo(const char *btnNo) {
oledDrawString(1, OLED_HEIGHT - 8, "\x15", FONT_STANDARD);
oledDrawString(fontCharWidth(FONT_STANDARD, '\x15') + 3, OLED_HEIGHT - 8, btnNo, FONT_STANDARD);
oledInvert(0, OLED_HEIGHT - 9, fontCharWidth(FONT_STANDARD, '\x15') + oledStringWidth(btnNo, FONT_STANDARD) + 2, OLED_HEIGHT - 1);
oledDrawString(fontCharWidth(FONT_STANDARD, '\x15') + 3, OLED_HEIGHT - 8,
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)
{
oledDrawString(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 1, OLED_HEIGHT - 8, "\x06", FONT_STANDARD);
oledDrawStringRight(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 3, 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 layoutButtonYes(const char *btnYes) {
oledDrawString(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 1,
OLED_HEIGHT - 8, "\x06", FONT_STANDARD);
oledDrawStringRight(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 3,
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;
oledClear();
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 (line4) oledDrawString(left, 3 * 9, line4, FONT_STANDARD);
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) {
oledHLine(OLED_HEIGHT - 21);
}
@ -69,8 +78,7 @@ void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, con
oledRefresh();
}
void layoutProgressUpdate(bool refresh)
{
void layoutProgressUpdate(bool refresh) {
static uint8_t step = 0;
switch (step) {
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();
layoutProgressUpdate(false);
// progressbar

@ -20,13 +20,16 @@
#ifndef __LAYOUT_H__
#define __LAYOUT_H__
#include <stdlib.h>
#include <stdbool.h>
#include <stdlib.h>
#include "bitmaps.h"
void layoutButtonNo(const char *btnNo);
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 layoutProgress(const char *desc, int permil);

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

@ -24,10 +24,12 @@
#define NORCOW_SECTOR_COUNT 2
#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)

118
oled.c

@ -22,9 +22,9 @@
#include <string.h>
#include "memzero.h"
#include "oled.h"
#include "util.h"
#include "memzero.h"
#define OLED_SETCONTRAST 0x81
#define OLED_DISPLAYALLON_RESUME 0xA4
@ -76,8 +76,7 @@ static bool is_debug_link = 0;
/*
* 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)) {
return;
}
@ -87,8 +86,7 @@ void oledDrawPixel(int x, int 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)) {
return;
}
@ -98,8 +96,7 @@ void oledClearPixel(int x, int 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)) {
return;
}
@ -110,23 +107,22 @@ void oledInvertPixel(int x, int y)
/*
* 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);
for (int i = 0; i < len; i++) {
spi_send(base, data[i]);
}
while (!(SPI_SR(base) & SPI_SR_TXE));
while ((SPI_SR(base) & SPI_SR_BSY));
while (!(SPI_SR(base) & SPI_SR_TXE))
;
while ((SPI_SR(base) & SPI_SR_BSY))
;
}
/*
* Initialize the display.
*/
void oledInit()
{
static const uint8_t s[25] = {
OLED_DISPLAYOFF,
void oledInit() {
static const uint8_t s[25] = {OLED_DISPLAYOFF,
OLED_SETDISPLAYCLOCKDIV,
0x80,
OLED_SETMULTIPLEX,
@ -150,8 +146,7 @@ void oledInit()
0x40,
OLED_DISPLAYALLON_RESUME,
OLED_NORMALDISPLAY,
OLED_DISPLAYON
};
OLED_DISPLAYON};
gpio_clear(OLED_DC_PORT, OLED_DC_PIN); // set to CMD
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)
*/
void oledClear()
{
memzero(_oledbuffer, sizeof(_oledbuffer));
}
void oledClear() { memzero(_oledbuffer, sizeof(_oledbuffer)); }
void oledInvertDebugLink()
{
void oledInvertDebugLink() {
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 - 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 - 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 - 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);
}
}
@ -199,9 +200,10 @@ void oledInvertDebugLink()
* not the content of the display.
*/
#if !EMULATOR
void oledRefresh()
{
static const uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00, OLED_SETHIGHCOLUMN | 0x00, OLED_SETSTARTLINE | 0x00};
void oledRefresh() {
static const uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00,
OLED_SETHIGHCOLUMN | 0x00,
OLED_SETSTARTLINE | 0x00};
// draw triangle in upper right corner
oledInvertDebugLink();
@ -221,24 +223,18 @@ void oledRefresh()
}
#endif
const uint8_t *oledGetBuffer()
{
return _oledbuffer;
}
const uint8_t *oledGetBuffer() { return _oledbuffer; }
void oledSetDebugLink(bool set)
{
void oledSetDebugLink(bool set) {
is_debug_link = set;
oledRefresh();
}
void oledSetBuffer(uint8_t *buf)
{
void oledSetBuffer(uint8_t *buf) {
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) {
return;
}
@ -257,7 +253,8 @@ void oledDrawChar(int x, int y, char c, int font)
if (zoom <= 1) {
oledDrawPixel(x + xo, y + yo);
} else {
oledBox(x + xo * zoom, y + yo * zoom, x + (xo + 1) * zoom - 1, y + (yo + 1) * zoom - 1, true);
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;
}
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;
int l = 0;
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;
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);
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 j = 0; j < bmp->height; j++) {
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.
*/
void oledInvert(int x1, int y1, int x2, int y2)
{
void oledInvert(int x1, int y1, int x2, int y2) {
x1 = MAX(x1, 0);
y1 = MAX(y1, 0);
x2 = MIN(x2, OLED_WIDTH - 1);
@ -345,8 +337,7 @@ void oledInvert(int x1, int y1, int x2, int y2)
/*
* 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);
y1 = MAX(y1, 0);
x2 = MIN(x2, OLED_WIDTH - 1);
@ -370,8 +361,7 @@ void oledHLine(int y) {
/*
* Draw a rectangle frame.
*/
void oledFrame(int x1, int y1, int x2, int y2)
{
void oledFrame(int x1, int y1, int x2, int y2) {
for (int x = x1; x <= x2; x++) {
oledDrawPixel(x, y1);
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.
* This clears the display.
*/
void oledSwipeLeft(void)
{
void oledSwipeLeft(void) {
for (int i = 0; i < OLED_WIDTH; i++) {
for (int j = 0; j < OLED_HEIGHT / 8; j++) {
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.
* This clears the display.
*/
void oledSwipeRight(void)
{
void oledSwipeRight(void) {
for (int i = 0; i < OLED_WIDTH / 4; i++) {
for (int j = 0; j < OLED_HEIGHT / 8; j++) {
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 + 1 + 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[k * 4 + 0 + j * OLED_WIDTH] =
_oledbuffer[k * 4 + 4 + j * OLED_WIDTH];
_oledbuffer[k * 4 + 1 + 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 - 2] = 0;

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

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

@ -20,19 +20,20 @@
#include <libopencm3/cm3/mpu.h>
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/spi.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/rng.h>
#include <libopencm3/stm32/spi.h>
#include "rng.h"
#include "layout.h"
#include "rng.h"
#include "util.h"
uint32_t __stack_chk_guard;
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();
}
@ -40,30 +41,25 @@ void __attribute__((noreturn)) __stack_chk_fail(void) {
fault_handler("Stack smashing");
}
void nmi_handler(void)
{
void nmi_handler(void) {
// Clock Security System triggered NMI
if ((RCC_CIR & RCC_CIR_CSSF) != 0) {
fault_handler("Clock instability");
}
}
void hard_fault_handler(void) {
fault_handler("Hard fault");
}
void hard_fault_handler(void) { fault_handler("Hard fault"); }
void mem_manage_handler(void) {
fault_handler("Memory fault");
}
void mem_manage_handler(void) { fault_handler("Memory fault"); }
void setup(void)
{
// set SCB_CCR STKALIGN bit to make sure 8-byte stack alignment on exception entry is in effect.
// This is not strictly necessary for the current TREZOR system.
// This is here to comply with guidance from section 3.3.3 "Binary compatibility with other Cortex processors"
// of the ARM Cortex-M3 Processor Technical Reference Manual.
// According to section 4.4.2 and 4.4.7 of the "STM32F10xxx/20xxx/21xxx/L1xxxx Cortex-M3 programming manual",
// STM32F2 series MCUs are r2p0 and always have this bit set on reset already.
void setup(void) {
// set SCB_CCR STKALIGN bit to make sure 8-byte stack alignment on exception
// entry is in effect. This is not strictly necessary for the current TREZOR
// system. This is here to comply with guidance from section 3.3.3 "Binary
// compatibility with other Cortex processors" of the ARM Cortex-M3 Processor
// Technical Reference Manual. According to section 4.4.2 and 4.4.7 of the
// "STM32F10xxx/20xxx/21xxx/L1xxxx Cortex-M3 programming manual", STM32F2
// series MCUs are r2p0 and always have this bit set on reset already.
SCB_CCR |= SCB_CCR_STKALIGN;
// setup clock
@ -81,8 +77,9 @@ void setup(void)
// enable RNG
rcc_periph_clock_enable(RCC_RNG);
RNG_CR |= RNG_CR_RNGEN;
// to be extra careful and heed the STM32F205xx Reference manual, Section 20.3.1
// we don't use the first random number generated after setting the RNGEN bit in setup
// to be extra careful and heed the STM32F205xx Reference manual,
// Section 20.3.1 we don't use the first random number generated after setting
// the RNGEN bit in setup
random32();
// enable CSS (Clock Security System)
@ -100,7 +97,9 @@ void setup(void)
gpio_set_af(GPIOA, GPIO_AF5, GPIO5 | GPIO7);
// 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_software_slave_management(SPI1);
// spi_set_nss_high(SPI1);
@ -118,16 +117,17 @@ void setup(void)
memset_reg((void *)0x50020000, (void *)0x50020500, 0);
}
void setupApp(void)
{
// for completeness, disable RNG peripheral interrupts for old bootloaders that had
// enabled them in RNG control register (the RNG interrupt was never enabled in the NVIC)
void setupApp(void) {
// for completeness, disable RNG peripheral interrupts for old bootloaders
// that had enabled them in RNG control register (the RNG interrupt was never
// enabled in the NVIC)
RNG_CR &= ~RNG_CR_IE;
// the static variables in random32 are separate between the bootloader and firmware.
// therefore, they need to be initialized here so that we can be sure to avoid dupes.
// this is to try to comply with STM32F205xx Reference manual - Section 20.3.1:
// "Each subsequent generated random number has to be compared with the previously generated
// number. The test fails if any two compared numbers are equal (continuous random number generator test)."
// the static variables in random32 are separate between the bootloader and
// firmware. therefore, they need to be initialized here so that we can be
// sure to avoid dupes. this is to try to comply with STM32F205xx Reference
// manual - Section 20.3.1: "Each subsequent generated random number has to be
// compared with the previously generated number. The test fails if any two
// compared numbers are equal (continuous random number generator test)."
random32();
// enable CSS (Clock Security System)
@ -135,7 +135,9 @@ void setupApp(void)
// hotfix for old bootloader
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_set_af(GPIOA, GPIO_AF10, GPIO10);
@ -163,8 +165,7 @@ void setupApp(void)
#define FLASH_BASE (0x08000000U)
#define SRAM_BASE (0x20000000U)
void mpu_config_off(void)
{
void mpu_config_off(void) {
// Disable MPU
MPU_CTRL = 0;
@ -172,8 +173,7 @@ void mpu_config_off(void)
__asm__ volatile("isb");
}
void mpu_config_bootloader(void)
{
void mpu_config_bootloader(void) {
// Disable MPU
MPU_CTRL = 0;
@ -181,26 +181,33 @@ void mpu_config_bootloader(void)
// Everything (0x00000000 - 0xFFFFFFFF, 4 GiB, read-write)
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)
MPU_RBAR = (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;
MPU_RBAR =
(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)
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)
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)
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
// Peripherals (0x50000000 - 0x5007ffff, read-write, execute never)
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
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)
void mpu_config_firmware(void)
{
void mpu_config_firmware(void) {
#if MEMORY_PROTECT
// Disable MPU
MPU_CTRL = 0;
@ -223,35 +229,44 @@ void mpu_config_firmware(void)
// Flash (0x08000000 - 0x0807FFFF, 1 MiB, read-only)
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
// (0x08008000 - 0x0800FFFF, 32 KiB, read-write, execute never)
MPU_RBAR = (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;
MPU_RBAR =
(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)
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)
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)
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
// (0x40023C00 - 0x40023FFF, privileged read-write, user no, execute never)
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
// Peripherals (0x50000000 - 0x5007ffff, read-write, execute never)
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
// (0x40013800 - 0x40013BFF, read-only, execute never)
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
MPU_CTRL = MPU_CTRL_ENABLE | MPU_CTRL_HFNMIENA;

@ -5,5 +5,5 @@ let
in
stdenv.mkDerivation {
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 ];
}

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

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

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

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

@ -45,6 +45,7 @@ struct usb_bos_descriptor {
/* USB Device Capability Types - USB 3.1 Table 9-14 */
#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

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

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

@ -17,16 +17,14 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "rng.h"
#include "util.h"
#include "rng.h"
inline void delay(uint32_t wait)
{
inline void delay(uint32_t wait) {
while (--wait > 0) __asm__("nop");
}
void wait_random(void)
{
void wait_random(void) {
int wait = random32() & 0xff;
volatile int i = 0;
volatile int j = wait;
@ -45,16 +43,14 @@ void wait_random(void)
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++) {
str[i] = hexdigits[(num >> (28 - i * 4)) & 0xF];
}
}
// 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;
for (uint32_t i = 0; i < len; i++) {
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;
}
uint32_t readprotobufint(const uint8_t **ptr)
{
uint32_t readprotobufint(const uint8_t **ptr) {
uint32_t result = (**ptr & 0x7F);
if (**ptr & 0x80) {
(*ptr)++;

@ -20,9 +20,9 @@
#ifndef __UTIL_H_
#define __UTIL_H_
#include <stdint.h>
#include <stdbool.h>
#include <setup.h>
#include <stdbool.h>
#include <stdint.h>
#if !EMULATOR
#include <libopencm3/cm3/scb.h>
@ -31,9 +31,24 @@
#endif
// 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(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; })
#define MIN_8bits(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);
@ -62,8 +77,8 @@ extern void memset_reg(void *start, void *stop, uint32_t val);
#define FW_SIGNED 0x5A3CA5C3
#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
SCB_VTOR = (uint32_t)vector_table; // * relocate vector table
// Set stack pointer
@ -77,18 +92,18 @@ static inline void __attribute__((noreturn)) jump_to_firmware(const vector_table
// Jump to address
vector_table->reset();
// Prevent compiler from generating stack protector code (which causes CPU fault because the stack is moved)
for (;;);
// Prevent compiler from generating stack protector code (which causes CPU
// 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
__asm__ volatile("msr control, %0" ::"r"(0x1));
}
static inline bool is_mode_unprivileged(void)
{
static inline bool is_mode_unprivileged(void) {
uint32_t r0;
__asm__ volatile("mrs %0, control" : "=r"(r0));
return r0 & 1;
@ -96,10 +111,7 @@ static inline bool is_mode_unprivileged(void)
#else /* EMULATOR */
static inline bool is_mode_unprivileged(void)
{
return true;
}
static inline bool is_mode_unprivileged(void) { return true; }
#endif
#endif

@ -18,22 +18,22 @@
#include <string.h>
#include "usb21_standard.h"
#include "util.h"
#include "webusb.h"
#include "usb21_standard.h"
const struct webusb_platform_descriptor webusb_platform_capability_descriptor = {
.bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE,
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
};
.iLandingPage = 1};
const struct webusb_platform_descriptor webusb_platform_capability_descriptor_no_landing_page = {
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,
@ -41,15 +41,13 @@ const struct webusb_platform_descriptor webusb_platform_capability_descriptor_no
.platformCapabilityUUID = WEBUSB_UUID,
.bcdVersion = 0x0100,
.bVendorCode = WEBUSB_VENDOR_CODE,
.iLandingPage = 0
};
.iLandingPage = 0};
static const char* webusb_https_url;
static int webusb_control_vendor_request(usbd_device *usbd_dev,
struct usb_setup_data *req,
uint8_t **buf, uint16_t *len,
usbd_control_complete_callback* complete) {
static int webusb_control_vendor_request(
usbd_device* usbd_dev, struct usb_setup_data* req, uint8_t** buf,
uint16_t* len, usbd_control_complete_callback* complete) {
(void)complete;
(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) {
(void)wValue;
usbd_register_control_callback(
usbd_dev,
usbd_register_control_callback(usbd_dev,
USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_DEVICE,
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
webusb_control_vendor_request);

@ -25,8 +25,10 @@
// Arbitrary
#define WEBUSB_VENDOR_CODE 0x01
extern const struct webusb_platform_descriptor webusb_platform_capability_descriptor;
extern const struct webusb_platform_descriptor webusb_platform_capability_descriptor_no_landing_page;
extern const struct webusb_platform_descriptor
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);

@ -42,12 +42,17 @@ struct webusb_platform_descriptor {
uint8_t iLandingPage;
} __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
// see also this (for endianness explanation)
// 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 {
uint8_t bLength;

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

@ -19,11 +19,13 @@
#ifndef WINUSB_H_INCLUDED
#define WINUSB_H_INCLUDED
#include <libopencm3/usb/usbd.h>
#include "winusb_defs.h"
// Arbitrary, but must be equivalent to the last character in extra string
#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);

@ -31,13 +31,18 @@
// Apparently using DeviceInterfaceGUID does not always work on Windows 7.
// DeviceInterfaceGUIDs does seem to work.
#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_U (sizeof(WINUSB_EXTENDED_PROPERTIES_GUID_NAME) / 2)
#define WINUSB_EXTENDED_PROPERTIES_GUID_NAME_SIZE_C \
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
#define WINUSB_EXTENDED_PROPERTIES_GUID_DATA u"{0263b512-88cb-4136-9613-5c8e109d8ef5}\x00"
#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_GUID_DATA \
u"{0263b512-88cb-4136-9613-5c8e109d8ef5}\x00"
#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_EXTRA_STRING_INDEX 0xee

Loading…
Cancel
Save