1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-07-04 13:52:35 +00:00

format: start using clang-format with style=Google

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

2
.clang-format Normal file
View File

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

View File

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

View File

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

View File

@ -19,16 +19,16 @@
#include <string.h> #include <string.h>
#include "signatures.h"
#include "ecdsa.h"
#include "secp256k1.h"
#include "sha2.h"
#include "bootloader.h" #include "bootloader.h"
#include "ecdsa.h"
#include "memory.h" #include "memory.h"
#include "memzero.h" #include "memzero.h"
#include "secp256k1.h"
#include "sha2.h"
#include "signatures.h"
const uint32_t FIRMWARE_MAGIC_OLD = 0x525a5254; // TRZR const uint32_t FIRMWARE_MAGIC_OLD = 0x525a5254; // TRZR
const uint32_t FIRMWARE_MAGIC_NEW = 0x465a5254; // TRZF const uint32_t FIRMWARE_MAGIC_NEW = 0x465a5254; // TRZF
#define PUBKEYS 5 #define PUBKEYS 5
@ -42,152 +42,162 @@ static const uint8_t * const pubkey[PUBKEYS] = {
#define SIGNATURES 3 #define SIGNATURES 3
#define FLASH_META_START 0x08008000 #define FLASH_META_START 0x08008000
#define FLASH_META_CODELEN (FLASH_META_START + 0x0004) #define FLASH_META_CODELEN (FLASH_META_START + 0x0004)
#define FLASH_META_SIGINDEX1 (FLASH_META_START + 0x0008) #define FLASH_META_SIGINDEX1 (FLASH_META_START + 0x0008)
#define FLASH_META_SIGINDEX2 (FLASH_META_START + 0x0009) #define FLASH_META_SIGINDEX2 (FLASH_META_START + 0x0009)
#define FLASH_META_SIGINDEX3 (FLASH_META_START + 0x000A) #define FLASH_META_SIGINDEX3 (FLASH_META_START + 0x000A)
#define FLASH_OLD_APP_START 0x08010000 #define FLASH_OLD_APP_START 0x08010000
#define FLASH_META_SIG1 (FLASH_META_START + 0x0040) #define FLASH_META_SIG1 (FLASH_META_START + 0x0040)
#define FLASH_META_SIG2 (FLASH_META_START + 0x0080) #define FLASH_META_SIG2 (FLASH_META_START + 0x0080)
#define FLASH_META_SIG3 (FLASH_META_START + 0x00C0) #define FLASH_META_SIG3 (FLASH_META_START + 0x00C0)
bool firmware_present_old(void) bool firmware_present_old(void) {
{ if (memcmp(FLASH_PTR(FLASH_META_START), &FIRMWARE_MAGIC_OLD,
if (memcmp(FLASH_PTR(FLASH_META_START), &FIRMWARE_MAGIC_OLD, 4)) { // magic does not match 4)) { // magic does not match
return false; return false;
} }
if (*((const uint32_t *)FLASH_PTR(FLASH_META_CODELEN)) < 8192) { // firmware reports smaller size than 8192 if (*((const uint32_t *)FLASH_PTR(FLASH_META_CODELEN)) <
return false; 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 }
return false; if (*((const uint32_t *)FLASH_PTR(FLASH_META_CODELEN)) >
} FLASH_APP_LEN) { // firmware reports bigger size than flash size
return false;
}
return true; return true;
} }
int signatures_old_ok(void) int signatures_old_ok(void) {
{ const uint32_t codelen = *((const uint32_t *)FLASH_META_CODELEN);
const uint32_t codelen = *((const uint32_t *)FLASH_META_CODELEN); const uint8_t sigindex1 = *((const uint8_t *)FLASH_META_SIGINDEX1);
const uint8_t sigindex1 = *((const uint8_t *)FLASH_META_SIGINDEX1); const uint8_t sigindex2 = *((const uint8_t *)FLASH_META_SIGINDEX2);
const uint8_t sigindex2 = *((const uint8_t *)FLASH_META_SIGINDEX2); const uint8_t sigindex3 = *((const uint8_t *)FLASH_META_SIGINDEX3);
const uint8_t sigindex3 = *((const uint8_t *)FLASH_META_SIGINDEX3);
if (codelen > FLASH_APP_LEN) { if (codelen > FLASH_APP_LEN) {
return false; return false;
} }
uint8_t hash[32]; uint8_t hash[32];
sha256_Raw(FLASH_PTR(FLASH_OLD_APP_START), codelen, hash); sha256_Raw(FLASH_PTR(FLASH_OLD_APP_START), codelen, hash);
if (sigindex1 < 1 || sigindex1 > PUBKEYS) return SIG_FAIL; // invalid index if (sigindex1 < 1 || sigindex1 > PUBKEYS) return SIG_FAIL; // invalid index
if (sigindex2 < 1 || sigindex2 > PUBKEYS) return SIG_FAIL; // invalid index if (sigindex2 < 1 || sigindex2 > PUBKEYS) return SIG_FAIL; // invalid index
if (sigindex3 < 1 || sigindex3 > PUBKEYS) return SIG_FAIL; // invalid index if (sigindex3 < 1 || sigindex3 > PUBKEYS) return SIG_FAIL; // invalid index
if (sigindex1 == sigindex2) return SIG_FAIL; // duplicate use if (sigindex1 == sigindex2) return SIG_FAIL; // duplicate use
if (sigindex1 == sigindex3) return SIG_FAIL; // duplicate use if (sigindex1 == sigindex3) return SIG_FAIL; // duplicate use
if (sigindex2 == sigindex3) return SIG_FAIL; // duplicate use if (sigindex2 == sigindex3) return SIG_FAIL; // duplicate use
if (0 != ecdsa_verify_digest(&secp256k1, pubkey[sigindex1 - 1], (const uint8_t *)FLASH_META_SIG1, hash)) { // failure if (0 != ecdsa_verify_digest(&secp256k1, pubkey[sigindex1 - 1],
return SIG_FAIL; (const uint8_t *)FLASH_META_SIG1,
} hash)) { // failure
if (0 != ecdsa_verify_digest(&secp256k1, pubkey[sigindex2 - 1], (const uint8_t *)FLASH_META_SIG2, hash)) { // failure return SIG_FAIL;
return SIG_FAIL; }
} if (0 != ecdsa_verify_digest(&secp256k1, pubkey[sigindex2 - 1],
if (0 != ecdsa_verify_digest(&secp256k1, pubkey[sigindex3 - 1], (const uint8_t *)FLASH_META_SIG3, hash)) { // failture (const uint8_t *)FLASH_META_SIG2,
return SIG_FAIL; hash)) { // failure
} return SIG_FAIL;
}
if (0 != ecdsa_verify_digest(&secp256k1, pubkey[sigindex3 - 1],
(const uint8_t *)FLASH_META_SIG3,
hash)) { // failture
return SIG_FAIL;
}
return SIG_OK; return SIG_OK;
} }
void compute_firmware_fingerprint(const image_header *hdr, uint8_t hash[32]) void compute_firmware_fingerprint(const image_header *hdr, uint8_t hash[32]) {
{ image_header copy;
image_header copy; memcpy(&copy, hdr, sizeof(image_header));
memcpy(&copy, hdr, sizeof(image_header)); memzero(copy.sig1, sizeof(copy.sig1));
memzero(copy.sig1, sizeof(copy.sig1)); memzero(copy.sig2, sizeof(copy.sig2));
memzero(copy.sig2, sizeof(copy.sig2)); memzero(copy.sig3, sizeof(copy.sig3));
memzero(copy.sig3, sizeof(copy.sig3)); copy.sigindex1 = 0;
copy.sigindex1 = 0; copy.sigindex2 = 0;
copy.sigindex2 = 0; copy.sigindex3 = 0;
copy.sigindex3 = 0; sha256_Raw((const uint8_t *)&copy, sizeof(image_header), hash);
sha256_Raw((const uint8_t *)&copy, sizeof(image_header), hash);
} }
bool firmware_present_new(void) bool firmware_present_new(void) {
{ const image_header *hdr =
const image_header *hdr = (const image_header *)FLASH_PTR(FLASH_FWHEADER_START); (const image_header *)FLASH_PTR(FLASH_FWHEADER_START);
if (hdr->magic != FIRMWARE_MAGIC_NEW) return false; if (hdr->magic != FIRMWARE_MAGIC_NEW) return false;
// we need to ignore hdrlen for now // we need to ignore hdrlen for now
// because we keep reset_handler ptr there // because we keep reset_handler ptr there
// for compatibility with older bootloaders // for compatibility with older bootloaders
// after this is no longer necessary, let's uncomment the line below: // after this is no longer necessary, let's uncomment the line below:
// if (hdr->hdrlen != FLASH_FWHEADER_LEN) return false; // if (hdr->hdrlen != FLASH_FWHEADER_LEN) return false;
if (hdr->codelen > FLASH_APP_LEN) return false; if (hdr->codelen > FLASH_APP_LEN) return false;
if (hdr->codelen < 4096) return false; if (hdr->codelen < 4096) return false;
return true; return true;
} }
int signatures_new_ok(const image_header *hdr, uint8_t store_fingerprint[32]) int signatures_new_ok(const image_header *hdr, uint8_t store_fingerprint[32]) {
{ uint8_t hash[32];
uint8_t hash[32]; compute_firmware_fingerprint(hdr, hash);
compute_firmware_fingerprint(hdr, hash);
if (store_fingerprint) { if (store_fingerprint) {
memcpy(store_fingerprint, hash, 32); memcpy(store_fingerprint, hash, 32);
} }
if (hdr->sigindex1 < 1 || hdr->sigindex1 > PUBKEYS) return SIG_FAIL; // invalid index if (hdr->sigindex1 < 1 || hdr->sigindex1 > PUBKEYS)
if (hdr->sigindex2 < 1 || hdr->sigindex2 > PUBKEYS) return SIG_FAIL; // invalid index return SIG_FAIL; // invalid index
if (hdr->sigindex3 < 1 || hdr->sigindex3 > PUBKEYS) return SIG_FAIL; // invalid index if (hdr->sigindex2 < 1 || hdr->sigindex2 > PUBKEYS)
return SIG_FAIL; // invalid index
if (hdr->sigindex3 < 1 || hdr->sigindex3 > PUBKEYS)
return SIG_FAIL; // invalid index
if (hdr->sigindex1 == hdr->sigindex2) return SIG_FAIL; // duplicate use if (hdr->sigindex1 == hdr->sigindex2) return SIG_FAIL; // duplicate use
if (hdr->sigindex1 == hdr->sigindex3) return SIG_FAIL; // duplicate use if (hdr->sigindex1 == hdr->sigindex3) return SIG_FAIL; // duplicate use
if (hdr->sigindex2 == hdr->sigindex3) return SIG_FAIL; // duplicate use if (hdr->sigindex2 == hdr->sigindex3) return SIG_FAIL; // duplicate use
if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex1 - 1], hdr->sig1, hash)) { // failure if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex1 - 1],
return SIG_FAIL; hdr->sig1, hash)) { // failure
} return SIG_FAIL;
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->sigindex2 - 1],
} hdr->sig2, hash)) { // failure
if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex3 - 1], hdr->sig3, hash)) { // failure return SIG_FAIL;
return SIG_FAIL; }
} if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex3 - 1],
hdr->sig3, hash)) { // failure
return SIG_FAIL;
}
return SIG_OK; return SIG_OK;
} }
int mem_is_empty(const uint8_t *src, uint32_t len) int mem_is_empty(const uint8_t *src, uint32_t len) {
{ for (uint32_t i = 0; i < len; i++) {
for (uint32_t i = 0; i < len; i++) { if (src[i]) return 0;
if (src[i]) return 0; }
} return 1;
return 1;
} }
int check_firmware_hashes(const image_header *hdr) int check_firmware_hashes(const image_header *hdr) {
{ uint8_t hash[32];
uint8_t hash[32]; // check hash of the first code chunk
// check hash of the first code chunk sha256_Raw(FLASH_PTR(FLASH_APP_START), (64 - 1) * 1024, hash);
sha256_Raw(FLASH_PTR(FLASH_APP_START), (64 - 1) * 1024, hash); if (0 != memcmp(hash, hdr->hashes, 32)) return SIG_FAIL;
if (0 != memcmp(hash, hdr->hashes, 32)) return SIG_FAIL; // check remaining used chunks
// check remaining used chunks uint32_t total_len = FLASH_FWHEADER_LEN + hdr->codelen;
uint32_t total_len = FLASH_FWHEADER_LEN + hdr->codelen; int used_chunks = total_len / FW_CHUNK_SIZE;
int used_chunks = total_len / FW_CHUNK_SIZE; if (total_len % FW_CHUNK_SIZE > 0) {
if (total_len % FW_CHUNK_SIZE > 0) { used_chunks++;
used_chunks++; }
} for (int i = 1; i < used_chunks; i++) {
for (int i = 1; i < used_chunks; i++) { sha256_Raw(FLASH_PTR(FLASH_FWHEADER_START + (64 * i) * 1024), 64 * 1024,
sha256_Raw(FLASH_PTR(FLASH_FWHEADER_START + (64 * i) * 1024), 64 * 1024, hash); hash);
if (0 != memcmp(hdr->hashes + 32 * i, hash, 32)) return SIG_FAIL; if (0 != memcmp(hdr->hashes + 32 * i, hash, 32)) return SIG_FAIL;
} }
// check unused chunks // check unused chunks
for (int i = used_chunks; i < 16; i++) { for (int i = used_chunks; i < 16; i++) {
if (!mem_is_empty(hdr->hashes + 32 * i, 32)) return SIG_FAIL; if (!mem_is_empty(hdr->hashes + 32 * i, 32)) return SIG_FAIL;
} }
// all OK // all OK
return SIG_OK; return SIG_OK;
} }

View File

@ -23,11 +23,11 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
extern const uint32_t FIRMWARE_MAGIC_OLD; // TRZR extern const uint32_t FIRMWARE_MAGIC_OLD; // TRZR
extern const uint32_t FIRMWARE_MAGIC_NEW; // TRZF extern const uint32_t FIRMWARE_MAGIC_NEW; // TRZF
#define SIG_OK 0x5A3CA5C3 #define SIG_OK 0x5A3CA5C3
#define SIG_FAIL 0x00000000 #define SIG_FAIL 0x00000000
bool firmware_present_old(void); bool firmware_present_old(void);
int signatures_old_ok(void); int signatures_old_ok(void);
@ -38,23 +38,23 @@ int signatures_old_ok(void);
// immediately following the chunk hashes // immediately following the chunk hashes
typedef struct { typedef struct {
uint32_t magic; uint32_t magic;
uint32_t hdrlen; uint32_t hdrlen;
uint32_t expiry; uint32_t expiry;
uint32_t codelen; uint32_t codelen;
uint32_t version; uint32_t version;
uint32_t fix_version; uint32_t fix_version;
uint8_t __reserved1[8]; uint8_t __reserved1[8];
uint8_t hashes[512]; uint8_t hashes[512];
uint8_t sig1[64]; uint8_t sig1[64];
uint8_t sig2[64]; uint8_t sig2[64];
uint8_t sig3[64]; uint8_t sig3[64];
uint8_t sigindex1; uint8_t sigindex1;
uint8_t sigindex2; uint8_t sigindex2;
uint8_t sigindex3; uint8_t sigindex3;
uint8_t __reserved2[220]; uint8_t __reserved2[220];
uint8_t __sigmask; uint8_t __sigmask;
uint8_t __sig[64]; uint8_t __sig[64];
} __attribute__((packed)) image_header; } __attribute__((packed)) image_header;
#define FW_CHUNK_SIZE 65536 #define FW_CHUNK_SIZE 65536

View File

@ -17,425 +17,451 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <libopencm3/usb/usbd.h>
#include <libopencm3/stm32/flash.h> #include <libopencm3/stm32/flash.h>
#include <libopencm3/usb/usbd.h>
#include <string.h> #include <string.h>
#include "buttons.h"
#include "bootloader.h" #include "bootloader.h"
#include "buttons.h"
#include "ecdsa.h"
#include "layout.h"
#include "memory.h"
#include "memzero.h"
#include "oled.h" #include "oled.h"
#include "rng.h" #include "rng.h"
#include "usb.h"
#include "layout.h"
#include "util.h"
#include "signatures.h"
#include "sha2.h"
#include "ecdsa.h"
#include "secp256k1.h" #include "secp256k1.h"
#include "memzero.h" #include "sha2.h"
#include "memory.h" #include "signatures.h"
#include "usb.h"
#include "util.h"
#include "usb21_standard.h" #include "usb21_standard.h"
#include "webusb.h" #include "webusb.h"
#include "winusb.h" #include "winusb.h"
#include "usb_desc.h" #include "usb_desc.h"
#include "usb_send.h"
#include "usb_erase.h" #include "usb_erase.h"
#include "usb_send.h"
enum { enum {
STATE_READY, STATE_READY,
STATE_OPEN, STATE_OPEN,
STATE_FLASHSTART, STATE_FLASHSTART,
STATE_FLASHING, STATE_FLASHING,
STATE_CHECK, STATE_CHECK,
STATE_END, STATE_END,
}; };
static uint32_t flash_pos = 0, flash_len = 0; static uint32_t flash_pos = 0, flash_len = 0;
static uint32_t chunk_idx = 0; static uint32_t chunk_idx = 0;
static char flash_state = STATE_READY; static char flash_state = STATE_READY;
static uint32_t FW_HEADER[FLASH_FWHEADER_LEN/sizeof(uint32_t)]; static uint32_t FW_HEADER[FLASH_FWHEADER_LEN / sizeof(uint32_t)];
static uint32_t FW_CHUNK[FW_CHUNK_SIZE/sizeof(uint32_t)]; static uint32_t FW_CHUNK[FW_CHUNK_SIZE / sizeof(uint32_t)];
static void check_and_write_chunk(void) static void check_and_write_chunk(void) {
{ uint32_t offset = (chunk_idx == 0) ? FLASH_FWHEADER_LEN : 0;
uint32_t offset = (chunk_idx == 0) ? FLASH_FWHEADER_LEN : 0; uint32_t chunk_pos = flash_pos % FW_CHUNK_SIZE;
uint32_t chunk_pos = flash_pos % FW_CHUNK_SIZE; if (chunk_pos == 0) {
if (chunk_pos == 0) { chunk_pos = FW_CHUNK_SIZE;
chunk_pos = FW_CHUNK_SIZE; }
} uint8_t hash[32];
uint8_t hash[32]; SHA256_CTX ctx;
SHA256_CTX ctx; sha256_Init(&ctx);
sha256_Init(&ctx); sha256_Update(&ctx, (const uint8_t *)FW_CHUNK + offset, chunk_pos - offset);
sha256_Update(&ctx, (const uint8_t *)FW_CHUNK + offset, chunk_pos - offset); if (chunk_pos < 64 * 1024) {
if (chunk_pos < 64 * 1024) { // pad with FF
// pad with FF for (uint32_t i = chunk_pos; i < 64 * 1024; i += 4) {
for (uint32_t i = chunk_pos; i < 64 * 1024; i += 4) { sha256_Update(&ctx, (const uint8_t *)"\xFF\xFF\xFF\xFF", 4);
sha256_Update(&ctx, (const uint8_t *)"\xFF\xFF\xFF\xFF", 4); }
} }
} sha256_Final(&ctx, hash);
sha256_Final(&ctx, hash);
const image_header *hdr = (const image_header *)FW_HEADER; const image_header *hdr = (const image_header *)FW_HEADER;
// invalid chunk sent // invalid chunk sent
if (0 != memcmp(hash, hdr->hashes + chunk_idx * 32, 32)) { if (0 != memcmp(hash, hdr->hashes + chunk_idx * 32, 32)) {
// erase storage // erase storage
erase_storage(); erase_storage();
flash_state = STATE_END; flash_state = STATE_END;
show_halt("Error installing", "firmware."); show_halt("Error installing", "firmware.");
return; return;
} }
flash_wait_for_last_operation(); flash_wait_for_last_operation();
flash_clear_status_flags(); flash_clear_status_flags();
flash_unlock(); flash_unlock();
for (uint32_t i = offset/sizeof(uint32_t); i < chunk_pos/sizeof(uint32_t); i++) { for (uint32_t i = offset / sizeof(uint32_t); i < chunk_pos / sizeof(uint32_t);
flash_program_word(FLASH_FWHEADER_START + chunk_idx * FW_CHUNK_SIZE + i * sizeof(uint32_t), FW_CHUNK[i]); i++) {
} flash_program_word(
flash_wait_for_last_operation(); FLASH_FWHEADER_START + chunk_idx * FW_CHUNK_SIZE + i * sizeof(uint32_t),
flash_lock(); FW_CHUNK[i]);
}
flash_wait_for_last_operation();
flash_lock();
// all done // all done
if (flash_len == flash_pos) { if (flash_len == flash_pos) {
// check remaining chunks if any // check remaining chunks if any
for (uint32_t i = chunk_idx + 1; i < 16; i++) { for (uint32_t i = chunk_idx + 1; i < 16; i++) {
// hash should be empty if the chunk is unused // hash should be empty if the chunk is unused
if (!mem_is_empty(hdr->hashes + 32 * i, 32)) { if (!mem_is_empty(hdr->hashes + 32 * i, 32)) {
flash_state = STATE_END; flash_state = STATE_END;
show_halt("Error installing", "firmware."); show_halt("Error installing", "firmware.");
return; return;
} }
} }
} }
memzero(FW_CHUNK, sizeof(FW_CHUNK)); memzero(FW_CHUNK, sizeof(FW_CHUNK));
chunk_idx++; chunk_idx++;
} }
static void rx_callback(usbd_device *dev, uint8_t ep) static void rx_callback(usbd_device *dev, uint8_t ep) {
{ (void)ep;
(void)ep; static uint16_t msg_id = 0xFFFF;
static uint16_t msg_id = 0xFFFF; static uint8_t buf[64] __attribute__((aligned(4)));
static uint8_t buf[64] __attribute__((aligned(4))); static uint32_t w;
static uint32_t w; static int wi;
static int wi; static int old_was_signed;
static int old_was_signed;
if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_OUT, buf, 64) != 64) return; if (usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_OUT, buf, 64) != 64) return;
if (flash_state == STATE_END) { if (flash_state == STATE_END) {
return; return;
} }
if (flash_state == STATE_READY || flash_state == STATE_OPEN || flash_state == STATE_FLASHSTART || flash_state == STATE_CHECK) { if (flash_state == STATE_READY || flash_state == STATE_OPEN ||
if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { // invalid start - discard flash_state == STATE_FLASHSTART || flash_state == STATE_CHECK) {
return; if (buf[0] != '?' || buf[1] != '#' ||
} buf[2] != '#') { // invalid start - discard
// struct.unpack(">HL") => msg, size return;
msg_id = (buf[3] << 8) + buf[4]; }
} // struct.unpack(">HL") => msg, size
msg_id = (buf[3] << 8) + buf[4];
}
if (flash_state == STATE_READY || flash_state == STATE_OPEN) { if (flash_state == STATE_READY || flash_state == STATE_OPEN) {
if (msg_id == 0x0000) { // Initialize message (id 0) if (msg_id == 0x0000) { // Initialize message (id 0)
send_msg_features(dev); send_msg_features(dev);
flash_state = STATE_OPEN; flash_state = STATE_OPEN;
return; return;
} }
if (msg_id == 0x0037) { // GetFeatures message (id 55) if (msg_id == 0x0037) { // GetFeatures message (id 55)
send_msg_features(dev); send_msg_features(dev);
return; return;
} }
if (msg_id == 0x0001) { // Ping message (id 1) if (msg_id == 0x0001) { // Ping message (id 1)
send_msg_success(dev); send_msg_success(dev);
return; return;
} }
if (msg_id == 0x0005) { // WipeDevice message (id 5) if (msg_id == 0x0005) { // WipeDevice message (id 5)
layoutDialog(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "wipe the device?", NULL, "All data will be lost.", NULL, NULL); layoutDialog(&bmp_icon_question, "Cancel", "Confirm", NULL,
bool but = get_button_response(); "Do you really want to", "wipe the device?", NULL,
if (but) { "All data will be lost.", NULL, NULL);
erase_storage_code_progress(); bool but = get_button_response();
flash_state = STATE_END; if (but) {
layoutDialog(&bmp_icon_ok, NULL, NULL, NULL, "Device", "successfully wiped.", NULL, "You may now", "unplug your TREZOR.", NULL); erase_storage_code_progress();
send_msg_success(dev); flash_state = STATE_END;
} else { layoutDialog(&bmp_icon_ok, NULL, NULL, NULL, "Device",
flash_state = STATE_END; "successfully wiped.", NULL, "You may now",
layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Device wipe", "aborted.", NULL, "You may now", "unplug your TREZOR.", NULL); "unplug your TREZOR.", NULL);
send_msg_failure(dev); send_msg_success(dev);
} } else {
return; flash_state = STATE_END;
} layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Device wipe",
} "aborted.", NULL, "You may now", "unplug your TREZOR.",
NULL);
send_msg_failure(dev);
}
return;
}
}
if (flash_state == STATE_OPEN) { if (flash_state == STATE_OPEN) {
if (msg_id == 0x0006) { // FirmwareErase message (id 6) if (msg_id == 0x0006) { // FirmwareErase message (id 6)
bool proceed = false; bool proceed = false;
if (firmware_present_new()) { if (firmware_present_new()) {
layoutDialog(&bmp_icon_question, "Abort", "Continue", NULL, "Install new", "firmware?", NULL, "Never do this without", "your recovery card!", NULL); layoutDialog(&bmp_icon_question, "Abort", "Continue", NULL,
proceed = get_button_response(); "Install new", "firmware?", NULL, "Never do this without",
} else { "your recovery card!", NULL);
proceed = true; proceed = get_button_response();
} } else {
if (proceed) { proceed = true;
// check whether the current firmware is signed (old or new method) }
if (firmware_present_new()) { if (proceed) {
const image_header *hdr = (const image_header *)FLASH_PTR(FLASH_FWHEADER_START); // check whether the current firmware is signed (old or new method)
old_was_signed = signatures_new_ok(hdr, NULL) & check_firmware_hashes(hdr); if (firmware_present_new()) {
} else if (firmware_present_old()) { const image_header *hdr =
old_was_signed = signatures_old_ok(); (const image_header *)FLASH_PTR(FLASH_FWHEADER_START);
} else { old_was_signed =
old_was_signed = SIG_FAIL; signatures_new_ok(hdr, NULL) & check_firmware_hashes(hdr);
} } else if (firmware_present_old()) {
erase_code_progress(); old_was_signed = signatures_old_ok();
send_msg_success(dev); } else {
flash_state = STATE_FLASHSTART; old_was_signed = SIG_FAIL;
} else { }
send_msg_failure(dev); erase_code_progress();
flash_state = STATE_END; send_msg_success(dev);
layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You may now", "unplug your TREZOR.", NULL); flash_state = STATE_FLASHSTART;
} } else {
return; send_msg_failure(dev);
} flash_state = STATE_END;
return; layoutDialog(&bmp_icon_warning, NULL, NULL, NULL,
} "Firmware installation", "aborted.", NULL, "You may now",
"unplug your TREZOR.", NULL);
}
return;
}
return;
}
if (flash_state == STATE_FLASHSTART) { if (flash_state == STATE_FLASHSTART) {
if (msg_id == 0x0007) { // FirmwareUpload message (id 7) if (msg_id == 0x0007) { // FirmwareUpload message (id 7)
if (buf[9] != 0x0a) { // invalid contents if (buf[9] != 0x0a) { // invalid contents
send_msg_failure(dev); send_msg_failure(dev);
flash_state = STATE_END; flash_state = STATE_END;
show_halt("Error installing", "firmware."); show_halt("Error installing", "firmware.");
return; return;
} }
// read payload length // read payload length
const uint8_t *p = buf + 10; const uint8_t *p = buf + 10;
flash_len = readprotobufint(&p); flash_len = readprotobufint(&p);
if (flash_len <= FLASH_FWHEADER_LEN) { // firmware is too small if (flash_len <= FLASH_FWHEADER_LEN) { // firmware is too small
send_msg_failure(dev); send_msg_failure(dev);
flash_state = STATE_END; flash_state = STATE_END;
show_halt("Firmware is too small.", NULL); show_halt("Firmware is too small.", NULL);
return; return;
} }
if (flash_len > FLASH_FWHEADER_LEN + FLASH_APP_LEN) { // firmware is too big if (flash_len >
send_msg_failure(dev); FLASH_FWHEADER_LEN + FLASH_APP_LEN) { // firmware is too big
flash_state = STATE_END; send_msg_failure(dev);
show_halt("Firmware is too big.", NULL); flash_state = STATE_END;
return; show_halt("Firmware is too big.", NULL);
} return;
// check firmware magic }
if (memcmp(p, &FIRMWARE_MAGIC_NEW, 4) != 0) { // check firmware magic
send_msg_failure(dev); if (memcmp(p, &FIRMWARE_MAGIC_NEW, 4) != 0) {
flash_state = STATE_END; send_msg_failure(dev);
show_halt("Wrong firmware header.", NULL); flash_state = STATE_END;
return; show_halt("Wrong firmware header.", NULL);
} return;
memzero(FW_HEADER, sizeof(FW_HEADER)); }
memzero(FW_CHUNK, sizeof(FW_CHUNK)); memzero(FW_HEADER, sizeof(FW_HEADER));
flash_state = STATE_FLASHING; memzero(FW_CHUNK, sizeof(FW_CHUNK));
flash_pos = 0; flash_state = STATE_FLASHING;
chunk_idx = 0; flash_pos = 0;
w = 0; chunk_idx = 0;
while (p < buf + 64) { w = 0;
w = (w >> 8) | (*p << 24); // assign byte to first byte of uint32_t w while (p < buf + 64) {
wi++; w = (w >> 8) | (*p << 24); // assign byte to first byte of uint32_t w
if (wi == 4) { wi++;
FW_HEADER[flash_pos / 4] = w; if (wi == 4) {
flash_pos += 4; FW_HEADER[flash_pos / 4] = w;
wi = 0; flash_pos += 4;
} wi = 0;
p++; }
} p++;
return; }
} return;
return; }
} return;
}
if (flash_state == STATE_FLASHING) { if (flash_state == STATE_FLASHING) {
if (buf[0] != '?') { // invalid contents if (buf[0] != '?') { // invalid contents
send_msg_failure(dev); send_msg_failure(dev);
flash_state = STATE_END; flash_state = STATE_END;
show_halt("Error installing", "firmware."); show_halt("Error installing", "firmware.");
return; return;
} }
static uint8_t flash_anim = 0; static uint8_t flash_anim = 0;
if (flash_anim % 32 == 4) { if (flash_anim % 32 == 4) {
layoutProgress("INSTALLING ... Please wait", 1000 * flash_pos / flash_len); layoutProgress("INSTALLING ... Please wait",
} 1000 * flash_pos / flash_len);
flash_anim++; }
flash_anim++;
const uint8_t *p = buf + 1; const uint8_t *p = buf + 1;
while (p < buf + 64 && flash_pos < flash_len) { while (p < buf + 64 && flash_pos < flash_len) {
w = (w >> 8) | (*p << 24); // assign byte to first byte of uint32_t w w = (w >> 8) | (*p << 24); // assign byte to first byte of uint32_t w
wi++; wi++;
if (wi == 4) { if (wi == 4) {
if (flash_pos < FLASH_FWHEADER_LEN) { if (flash_pos < FLASH_FWHEADER_LEN) {
FW_HEADER[flash_pos / 4] = w; FW_HEADER[flash_pos / 4] = w;
} else { } else {
FW_CHUNK[(flash_pos % FW_CHUNK_SIZE)/ 4] = w; FW_CHUNK[(flash_pos % FW_CHUNK_SIZE) / 4] = w;
} }
flash_pos += 4; flash_pos += 4;
wi = 0; wi = 0;
// finished the whole chunk // finished the whole chunk
if (flash_pos % FW_CHUNK_SIZE == 0) { if (flash_pos % FW_CHUNK_SIZE == 0) {
check_and_write_chunk(); check_and_write_chunk();
} }
} }
p++; p++;
} }
// flashing done // flashing done
if (flash_pos == flash_len) { if (flash_pos == flash_len) {
// flush remaining data in the last chunk // flush remaining data in the last chunk
if (flash_pos % FW_CHUNK_SIZE > 0) { if (flash_pos % FW_CHUNK_SIZE > 0) {
check_and_write_chunk(); check_and_write_chunk();
} }
flash_state = STATE_CHECK; flash_state = STATE_CHECK;
const image_header *hdr = (const image_header *)FW_HEADER; const image_header *hdr = (const image_header *)FW_HEADER;
if (SIG_OK != signatures_new_ok(hdr, NULL)) { if (SIG_OK != signatures_new_ok(hdr, NULL)) {
send_msg_buttonrequest_firmwarecheck(dev); send_msg_buttonrequest_firmwarecheck(dev);
return; return;
} }
} else { } else {
return; return;
} }
} }
if (flash_state == STATE_CHECK) { if (flash_state == STATE_CHECK) {
// use the firmware header from RAM
const image_header *hdr = (const image_header *)FW_HEADER;
// use the firmware header from RAM bool hash_check_ok;
const image_header *hdr = (const image_header *)FW_HEADER; // show fingerprint of unsigned firmware
if (SIG_OK != signatures_new_ok(hdr, NULL)) {
if (msg_id != 0x001B) { // ButtonAck message (id 27)
return;
}
uint8_t hash[32];
compute_firmware_fingerprint(hdr, hash);
layoutFirmwareFingerprint(hash);
hash_check_ok = get_button_response();
} else {
hash_check_ok = true;
}
bool hash_check_ok; layoutProgress("INSTALLING ... Please wait", 1000);
// show fingerprint of unsigned firmware // wipe storage if:
if (SIG_OK != signatures_new_ok(hdr, NULL)) { // 1) old firmware was unsigned or not present
if (msg_id != 0x001B) { // ButtonAck message (id 27) // 2) signatures are not OK
return; // 3) hashes are not OK
} if (SIG_OK != old_was_signed || SIG_OK != signatures_new_ok(hdr, NULL) ||
uint8_t hash[32]; SIG_OK != check_firmware_hashes(hdr)) {
compute_firmware_fingerprint(hdr, hash); // erase storage
layoutFirmwareFingerprint(hash); erase_storage();
hash_check_ok = get_button_response(); // check erasure
} else { uint8_t hash[32];
hash_check_ok = true; 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) {
send_msg_failure(dev);
show_halt("Error installing", "firmware.");
return;
}
}
flash_wait_for_last_operation();
flash_clear_status_flags();
flash_unlock();
// 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]);
}
} else {
for (size_t i = 0; i < FLASH_FWHEADER_LEN / sizeof(uint32_t); i++) {
flash_program_word(FLASH_FWHEADER_START + i * sizeof(uint32_t), 0);
}
}
flash_wait_for_last_operation();
flash_lock();
layoutProgress("INSTALLING ... Please wait", 1000); flash_state = STATE_END;
// wipe storage if: if (hash_check_ok) {
// 1) old firmware was unsigned or not present layoutDialog(&bmp_icon_ok, NULL, NULL, NULL, "New firmware",
// 2) signatures are not OK "successfully installed.", NULL, "You may now",
// 3) hashes are not OK "unplug your TREZOR.", NULL);
if (SIG_OK != old_was_signed || SIG_OK != signatures_new_ok(hdr, NULL) || SIG_OK != check_firmware_hashes(hdr)) { send_msg_success(dev);
// erase storage shutdown();
erase_storage(); } else {
// check erasure layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Firmware installation",
uint8_t hash[32]; "aborted.", NULL, "You need to repeat", "the procedure with",
sha256_Raw(FLASH_PTR(FLASH_STORAGE_START), FLASH_STORAGE_LEN, hash); "the correct firmware.");
if (memcmp(hash, "\x2d\x86\x4c\x0b\x78\x9a\x43\x21\x4e\xee\x85\x24\xd3\x18\x20\x75\x12\x5e\x5c\xa2\xcd\x52\x7f\x35\x82\xec\x87\xff\xd9\x40\x76\xbc", 32) != 0) { send_msg_failure(dev);
send_msg_failure(dev); shutdown();
show_halt("Error installing", "firmware."); }
return; return;
} }
}
flash_wait_for_last_operation();
flash_clear_status_flags();
flash_unlock();
// 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]);
}
} else {
for (size_t i = 0; i < FLASH_FWHEADER_LEN/sizeof(uint32_t); i++) {
flash_program_word(FLASH_FWHEADER_START + i * sizeof(uint32_t), 0);
}
}
flash_wait_for_last_operation();
flash_lock();
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);
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.");
send_msg_failure(dev);
shutdown();
}
return;
}
} }
static void set_config(usbd_device *dev, uint16_t wValue) static void set_config(usbd_device *dev, uint16_t wValue) {
{ (void)wValue;
(void)wValue;
usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0);
usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, rx_callback); usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64,
rx_callback);
} }
static usbd_device *usbd_dev; static usbd_device *usbd_dev;
static uint8_t usbd_control_buffer[256] __attribute__ ((aligned (2))); static uint8_t usbd_control_buffer[256] __attribute__((aligned(2)));
static const struct usb_device_capability_descriptor* capabilities[] = { static const struct usb_device_capability_descriptor *capabilities[] = {
(const struct usb_device_capability_descriptor*)&webusb_platform_capability_descriptor, (const struct usb_device_capability_descriptor
*)&webusb_platform_capability_descriptor,
}; };
static const struct usb_bos_descriptor bos_descriptor = { static const struct usb_bos_descriptor bos_descriptor = {
.bLength = USB_DT_BOS_SIZE, .bLength = USB_DT_BOS_SIZE,
.bDescriptorType = USB_DT_BOS, .bDescriptorType = USB_DT_BOS,
.bNumDeviceCaps = sizeof(capabilities)/sizeof(capabilities[0]), .bNumDeviceCaps = sizeof(capabilities) / sizeof(capabilities[0]),
.capabilities = capabilities .capabilities = capabilities};
};
static void usbInit(void) static void usbInit(void) {
{ usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings,
usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, sizeof(usb_strings)/sizeof(const char *), usbd_control_buffer, sizeof(usbd_control_buffer)); sizeof(usb_strings) / sizeof(const char *),
usbd_register_set_config_callback(usbd_dev, set_config); usbd_control_buffer, sizeof(usbd_control_buffer));
usb21_setup(usbd_dev, &bos_descriptor); usbd_register_set_config_callback(usbd_dev, set_config);
webusb_setup(usbd_dev, "trezor.io/start"); usb21_setup(usbd_dev, &bos_descriptor);
winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN); 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;
static bool btn_left = false, btn_right = false, btn_final = false; if (btn_final) {
if (btn_final) { return;
return; }
} uint16_t state = gpio_port_read(BTN_PORT);
uint16_t state = gpio_port_read(BTN_PORT); if ((state & (BTN_PIN_YES | BTN_PIN_NO)) != (BTN_PIN_YES | BTN_PIN_NO)) {
if ((state & (BTN_PIN_YES | BTN_PIN_NO)) != (BTN_PIN_YES | BTN_PIN_NO)) { if ((state & BTN_PIN_NO) != BTN_PIN_NO) {
if ((state & BTN_PIN_NO) != BTN_PIN_NO) { btn_left = true;
btn_left = true; }
} if ((state & BTN_PIN_YES) != BTN_PIN_YES) {
if ((state & BTN_PIN_YES) != BTN_PIN_YES) { btn_right = true;
btn_right = true; }
} }
} if (btn_left) {
if (btn_left) { oledBox(0, 0, 3, 3, true);
oledBox(0, 0, 3, 3, true); }
} if (btn_right) {
if (btn_right) { oledBox(OLED_WIDTH - 4, 0, OLED_WIDTH - 1, 3, true);
oledBox(OLED_WIDTH - 4, 0, OLED_WIDTH - 1, 3, true); }
} if (btn_left || btn_right) {
if (btn_left || btn_right) { oledRefresh();
oledRefresh(); }
} if (btn_left && btn_right) {
if (btn_left && btn_right) { btn_final = true;
btn_final = true; }
}
} }
void usbLoop(void) void usbLoop(void) {
{ bool firmware_present = firmware_present_new();
bool firmware_present = firmware_present_new(); usbInit();
usbInit(); for (;;) {
for (;;) { usbd_poll(usbd_dev);
usbd_poll(usbd_dev); if (!firmware_present &&
if (!firmware_present && (flash_state == STATE_READY || flash_state == STATE_OPEN)) { (flash_state == STATE_READY || flash_state == STATE_OPEN)) {
checkButtons(); checkButtons();
} }
} }
} }

View File

@ -1,75 +1,77 @@
#define USB_INTERFACE_INDEX_MAIN 0 #define USB_INTERFACE_INDEX_MAIN 0
#define ENDPOINT_ADDRESS_IN (0x81) #define ENDPOINT_ADDRESS_IN (0x81)
#define ENDPOINT_ADDRESS_OUT (0x01) #define ENDPOINT_ADDRESS_OUT (0x01)
static const struct usb_device_descriptor dev_descr = { static const struct usb_device_descriptor dev_descr = {
.bLength = USB_DT_DEVICE_SIZE, .bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE, .bDescriptorType = USB_DT_DEVICE,
.bcdUSB = 0x0210, .bcdUSB = 0x0210,
.bDeviceClass = 0, .bDeviceClass = 0,
.bDeviceSubClass = 0, .bDeviceSubClass = 0,
.bDeviceProtocol = 0, .bDeviceProtocol = 0,
.bMaxPacketSize0 = 64, .bMaxPacketSize0 = 64,
.idVendor = 0x1209, .idVendor = 0x1209,
.idProduct = 0x53c0, .idProduct = 0x53c0,
.bcdDevice = 0x0100, .bcdDevice = 0x0100,
.iManufacturer = 1, .iManufacturer = 1,
.iProduct = 2, .iProduct = 2,
.iSerialNumber = 3, .iSerialNumber = 3,
.bNumConfigurations = 1, .bNumConfigurations = 1,
}; };
static const struct usb_endpoint_descriptor endpoints[2] = {{ static const struct usb_endpoint_descriptor endpoints[2] = {
.bLength = USB_DT_ENDPOINT_SIZE, {
.bDescriptorType = USB_DT_ENDPOINT, .bLength = USB_DT_ENDPOINT_SIZE,
.bEndpointAddress = ENDPOINT_ADDRESS_IN, .bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .bEndpointAddress = ENDPOINT_ADDRESS_IN,
.wMaxPacketSize = 64, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.bInterval = 1, .wMaxPacketSize = 64,
}, { .bInterval = 1,
.bLength = USB_DT_ENDPOINT_SIZE, },
.bDescriptorType = USB_DT_ENDPOINT, {
.bEndpointAddress = ENDPOINT_ADDRESS_OUT, .bLength = USB_DT_ENDPOINT_SIZE,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .bDescriptorType = USB_DT_ENDPOINT,
.wMaxPacketSize = 64, .bEndpointAddress = ENDPOINT_ADDRESS_OUT,
.bInterval = 1, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
}}; .wMaxPacketSize = 64,
.bInterval = 1,
}};
static const struct usb_interface_descriptor iface[] = {{ static const struct usb_interface_descriptor iface[] = {{
.bLength = USB_DT_INTERFACE_SIZE, .bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE, .bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN,
.bAlternateSetting = 0, .bAlternateSetting = 0,
.bNumEndpoints = 2, .bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_VENDOR, .bInterfaceClass = USB_CLASS_VENDOR,
.bInterfaceSubClass = 0, .bInterfaceSubClass = 0,
.bInterfaceProtocol = 0, .bInterfaceProtocol = 0,
.iInterface = 0, .iInterface = 0,
.endpoint = endpoints, .endpoint = endpoints,
.extra = NULL, .extra = NULL,
.extralen = 0, .extralen = 0,
}}; }};
static const struct usb_interface ifaces[] = {{ static const struct usb_interface ifaces[] = {{
.num_altsetting = 1, .num_altsetting = 1,
.altsetting = iface, .altsetting = iface,
}}; }};
static const struct usb_config_descriptor config = { static const struct usb_config_descriptor config = {
.bLength = USB_DT_CONFIGURATION_SIZE, .bLength = USB_DT_CONFIGURATION_SIZE,
.bDescriptorType = USB_DT_CONFIGURATION, .bDescriptorType = USB_DT_CONFIGURATION,
.wTotalLength = 0, .wTotalLength = 0,
.bNumInterfaces = 1, .bNumInterfaces = 1,
.bConfigurationValue = 1, .bConfigurationValue = 1,
.iConfiguration = 0, .iConfiguration = 0,
.bmAttributes = 0x80, .bmAttributes = 0x80,
.bMaxPower = 0x32, .bMaxPower = 0x32,
.interface = ifaces, .interface = ifaces,
}; };
static const char *usb_strings[] = { static const char *usb_strings[] = {
"SatoshiLabs", "SatoshiLabs",
"TREZOR", "TREZOR",
"000000000000000000000000", "000000000000000000000000",
}; };

View File

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

View File

@ -1,86 +1,92 @@
static void send_msg_success(usbd_device *dev) static void send_msg_success(usbd_device *dev) {
{ uint8_t response[64];
uint8_t response[64]; memzero(response, sizeof(response));
memzero(response, sizeof(response)); // response: Success message (id 2), payload len 0
// response: Success message (id 2), payload len 0 memcpy(response,
memcpy(response, // header
// header "?##"
"?##" // msg_id
// msg_id "\x00\x02"
"\x00\x02" // msg_size
// msg_size "\x00\x00\x00\x00",
"\x00\x00\x00\x00", 9);
9); while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {
while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} }
} }
static void send_msg_failure(usbd_device *dev) static void send_msg_failure(usbd_device *dev) {
{ uint8_t response[64];
uint8_t response[64]; memzero(response, sizeof(response));
memzero(response, sizeof(response)); // response: Failure message (id 3), payload len 2
// response: Failure message (id 3), payload len 2 // - code = 99 (Failure_FirmwareError)
// - code = 99 (Failure_FirmwareError) memcpy(response,
memcpy(response, // header
// header "?##"
"?##" // msg_id
// msg_id "\x00\x03"
"\x00\x03" // msg_size
// msg_size "\x00\x00\x00\x02"
"\x00\x00\x00\x02" // data
// data "\x08"
"\x08" "\x63", "\x63",
11); 11);
while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {
}
} }
static void send_msg_features(usbd_device *dev) static void send_msg_features(usbd_device *dev) {
{ uint8_t response[64];
uint8_t response[64]; memzero(response, sizeof(response));
memzero(response, sizeof(response)); // response: Features message (id 17), payload len 25
// response: Features message (id 17), payload len 25 // - vendor = "trezor.io"
// - vendor = "trezor.io" // - major_version = VERSION_MAJOR
// - major_version = VERSION_MAJOR // - minor_version = VERSION_MINOR
// - minor_version = VERSION_MINOR // - patch_version = VERSION_PATCH
// - patch_version = VERSION_PATCH // - bootloader_mode = True
// - bootloader_mode = True // - firmware_present = True/False
// - firmware_present = True/False // - model = "1"
// - model = "1" memcpy(response,
memcpy(response, // header
// header "?##"
"?##" // msg_id
// msg_id "\x00\x11"
"\x00\x11" // msg_size
// msg_size "\x00\x00\x00\x16"
"\x00\x00\x00\x16" // data
// data "\x0a"
"\x0a" "\x09" "trezor.io" "\x09"
"\x10" VERSION_MAJOR_CHAR "trezor.io"
"\x18" VERSION_MINOR_CHAR "\x10" VERSION_MAJOR_CHAR "\x18" VERSION_MINOR_CHAR
"\x20" VERSION_PATCH_CHAR "\x20" VERSION_PATCH_CHAR
"\x28" "\x01" "\x28"
"\x90\x01" "\x00" "\x01"
"\xaa" "\x01" "1", "\x90\x01"
34); "\x00"
response[30] = firmware_present_new() ? 0x01 : 0x00; "\xaa"
while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} "\x01"
"1",
34);
response[30] = firmware_present_new() ? 0x01 : 0x00;
while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {
}
} }
static void send_msg_buttonrequest_firmwarecheck(usbd_device *dev) static void send_msg_buttonrequest_firmwarecheck(usbd_device *dev) {
{ uint8_t response[64];
uint8_t response[64]; memzero(response, sizeof(response));
memzero(response, sizeof(response)); // response: ButtonRequest message (id 26), payload len 2
// response: ButtonRequest message (id 26), payload len 2 // - code = ButtonRequest_FirmwareCheck (9)
// - code = ButtonRequest_FirmwareCheck (9) memcpy(response,
memcpy(response, // header
// header "?##"
"?##" // msg_id
// msg_id "\x00\x1a"
"\x00\x1a" // msg_size
// msg_size "\x00\x00\x00\x02"
"\x00\x00\x00\x02" // data
// data "\x08"
"\x08" "\x09", "\x09",
11 11);
); while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {
while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} }
} }

View File

@ -22,52 +22,49 @@
struct buttonState button; struct buttonState button;
#if !EMULATOR #if !EMULATOR
uint16_t buttonRead(void) { uint16_t buttonRead(void) { return gpio_port_read(BTN_PORT); }
return gpio_port_read(BTN_PORT);
}
#endif #endif
void buttonUpdate() void buttonUpdate() {
{ static uint16_t last_state = BTN_PIN_YES | BTN_PIN_NO;
static uint16_t last_state = BTN_PIN_YES | BTN_PIN_NO;
uint16_t state = buttonRead(); uint16_t state = buttonRead();
if ((state & BTN_PIN_YES) == 0) { // Yes button is down if ((state & BTN_PIN_YES) == 0) { // Yes button is down
if ((last_state & BTN_PIN_YES) == 0) { // last Yes was down if ((last_state & BTN_PIN_YES) == 0) { // last Yes was down
if (button.YesDown < 2000000000) button.YesDown++; if (button.YesDown < 2000000000) button.YesDown++;
button.YesUp = false; button.YesUp = false;
} else { // last Yes was up } else { // last Yes was up
button.YesDown = 0; button.YesDown = 0;
button.YesUp = false; button.YesUp = false;
} }
} else { // Yes button is up } else { // Yes button is up
if ((last_state & BTN_PIN_YES) == 0) { // last Yes was down if ((last_state & BTN_PIN_YES) == 0) { // last Yes was down
button.YesDown = 0; button.YesDown = 0;
button.YesUp = true; button.YesUp = true;
} else { // last Yes was up } else { // last Yes was up
button.YesDown = 0; button.YesDown = 0;
button.YesUp = false; button.YesUp = false;
} }
} }
if ((state & BTN_PIN_NO) == 0) { // No button is down if ((state & BTN_PIN_NO) == 0) { // No button is down
if ((last_state & BTN_PIN_NO) == 0) { // last No was down if ((last_state & BTN_PIN_NO) == 0) { // last No was down
if (button.NoDown < 2000000000) button.NoDown++; if (button.NoDown < 2000000000) button.NoDown++;
button.NoUp = false; button.NoUp = false;
} else { // last No was up } else { // last No was up
button.NoDown = 0; button.NoDown = 0;
button.NoUp = false; button.NoUp = false;
} }
} else { // No button is up } else { // No button is up
if ((last_state & BTN_PIN_NO) == 0) { // last No was down if ((last_state & BTN_PIN_NO) == 0) { // last No was down
button.NoDown = 0; button.NoDown = 0;
button.NoUp = true; button.NoUp = true;
} else { // last No was up } else { // last No was up
button.NoDown = 0; button.NoDown = 0;
button.NoUp = false; button.NoUp = false;
} }
} }
last_state = state; last_state = state;
} }

View File

@ -24,10 +24,10 @@
#include <stdbool.h> #include <stdbool.h>
struct buttonState { struct buttonState {
volatile bool YesUp; volatile bool YesUp;
volatile int YesDown; volatile int YesDown;
volatile bool NoUp; volatile bool NoUp;
volatile int NoDown; volatile int NoDown;
}; };
extern struct buttonState button; extern struct buttonState button;
@ -36,15 +36,15 @@ uint16_t buttonRead(void);
void buttonUpdate(void); void buttonUpdate(void);
#ifndef BTN_PORT #ifndef BTN_PORT
#define BTN_PORT GPIOC #define BTN_PORT GPIOC
#endif #endif
#ifndef BTN_PIN_YES #ifndef BTN_PIN_YES
#define BTN_PIN_YES GPIO2 #define BTN_PIN_YES GPIO2
#endif #endif
#ifndef BTN_PIN_NO #ifndef BTN_PIN_NO
#define BTN_PIN_NO GPIO5 #define BTN_PIN_NO GPIO5
#endif #endif
#endif #endif

View File

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

View File

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

View File

@ -17,17 +17,17 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h>
#include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/hid.h> #include <libopencm3/usb/hid.h>
#include <libopencm3/usb/usbd.h>
#include <string.h>
#include "bitmaps.h" #include "bitmaps.h"
#include "buttons.h" #include "buttons.h"
#include "hmac.h"
#include "layout.h" #include "layout.h"
#include "oled.h" #include "oled.h"
#include "setup.h"
#include "hmac.h"
#include "pbkdf2.h" #include "pbkdf2.h"
#include "rng.h" #include "rng.h"
#include "setup.h"
const int states = 2; const int states = 2;
int state = 0; int state = 0;
@ -40,252 +40,270 @@ uint8_t *salt = (uint8_t *)"TREZOR";
uint32_t saltlen; uint32_t saltlen;
static const struct usb_device_descriptor dev_descr = { static const struct usb_device_descriptor dev_descr = {
.bLength = USB_DT_DEVICE_SIZE, .bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE, .bDescriptorType = USB_DT_DEVICE,
.bcdUSB = 0x0200, .bcdUSB = 0x0200,
.bDeviceClass = 0, .bDeviceClass = 0,
.bDeviceSubClass = 0, .bDeviceSubClass = 0,
.bDeviceProtocol = 0, .bDeviceProtocol = 0,
.bMaxPacketSize0 = 64, .bMaxPacketSize0 = 64,
.idVendor = 0x1209, .idVendor = 0x1209,
.idProduct = 0x53c1, .idProduct = 0x53c1,
.bcdDevice = 0x0100, .bcdDevice = 0x0100,
.iManufacturer = 1, .iManufacturer = 1,
.iProduct = 2, .iProduct = 2,
.iSerialNumber = 3, .iSerialNumber = 3,
.bNumConfigurations = 1, .bNumConfigurations = 1,
}; };
/* got via usbhid-dump from CP2110 */ /* got via usbhid-dump from CP2110 */
static const uint8_t hid_report_descriptor[] = { static const uint8_t hid_report_descriptor[] = {
0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x09, 0x01, 0x75, 0x08, 0x95, 0x40, 0x26, 0xFF, 0x00, 0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x09, 0x01, 0x75, 0x08, 0x95,
0x15, 0x00, 0x85, 0x01, 0x95, 0x01, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x02, 0x40, 0x26, 0xFF, 0x00, 0x15, 0x00, 0x85, 0x01, 0x95, 0x01, 0x09, 0x01,
0x95, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x03, 0x95, 0x03, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x02, 0x95, 0x02, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x04, 0x95, 0x04, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x03, 0x95, 0x03, 0x09, 0x01,
0x91, 0x02, 0x85, 0x05, 0x95, 0x05, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x06, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x04, 0x95, 0x04, 0x09, 0x01,
0x95, 0x06, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x07, 0x95, 0x07, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x05, 0x95, 0x05, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x08, 0x95, 0x08, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x06, 0x95, 0x06, 0x09, 0x01,
0x91, 0x02, 0x85, 0x09, 0x95, 0x09, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0A, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x07, 0x95, 0x07, 0x09, 0x01,
0x95, 0x0A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0B, 0x95, 0x0B, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x08, 0x95, 0x08, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0C, 0x95, 0x0C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x09, 0x95, 0x09, 0x09, 0x01,
0x91, 0x02, 0x85, 0x0D, 0x95, 0x0D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0E, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0A, 0x95, 0x0A, 0x09, 0x01,
0x95, 0x0E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0F, 0x95, 0x0F, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0B, 0x95, 0x0B, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x10, 0x95, 0x10, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0C, 0x95, 0x0C, 0x09, 0x01,
0x91, 0x02, 0x85, 0x11, 0x95, 0x11, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x12, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0D, 0x95, 0x0D, 0x09, 0x01,
0x95, 0x12, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x13, 0x95, 0x13, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0E, 0x95, 0x0E, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x14, 0x95, 0x14, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0F, 0x95, 0x0F, 0x09, 0x01,
0x91, 0x02, 0x85, 0x15, 0x95, 0x15, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x16, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x10, 0x95, 0x10, 0x09, 0x01,
0x95, 0x16, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x17, 0x95, 0x17, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x11, 0x95, 0x11, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x18, 0x95, 0x18, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x12, 0x95, 0x12, 0x09, 0x01,
0x91, 0x02, 0x85, 0x19, 0x95, 0x19, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1A, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x13, 0x95, 0x13, 0x09, 0x01,
0x95, 0x1A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1B, 0x95, 0x1B, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x14, 0x95, 0x14, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1C, 0x95, 0x1C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x15, 0x95, 0x15, 0x09, 0x01,
0x91, 0x02, 0x85, 0x1D, 0x95, 0x1D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1E, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x16, 0x95, 0x16, 0x09, 0x01,
0x95, 0x1E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1F, 0x95, 0x1F, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x17, 0x95, 0x17, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x20, 0x95, 0x20, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x18, 0x95, 0x18, 0x09, 0x01,
0x91, 0x02, 0x85, 0x21, 0x95, 0x21, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x22, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x19, 0x95, 0x19, 0x09, 0x01,
0x95, 0x22, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x23, 0x95, 0x23, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1A, 0x95, 0x1A, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x24, 0x95, 0x24, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1B, 0x95, 0x1B, 0x09, 0x01,
0x91, 0x02, 0x85, 0x25, 0x95, 0x25, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x26, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1C, 0x95, 0x1C, 0x09, 0x01,
0x95, 0x26, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x27, 0x95, 0x27, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1D, 0x95, 0x1D, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x28, 0x95, 0x28, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1E, 0x95, 0x1E, 0x09, 0x01,
0x91, 0x02, 0x85, 0x29, 0x95, 0x29, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2A, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1F, 0x95, 0x1F, 0x09, 0x01,
0x95, 0x2A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2B, 0x95, 0x2B, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x20, 0x95, 0x20, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2C, 0x95, 0x2C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x21, 0x95, 0x21, 0x09, 0x01,
0x91, 0x02, 0x85, 0x2D, 0x95, 0x2D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2E, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x22, 0x95, 0x22, 0x09, 0x01,
0x95, 0x2E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2F, 0x95, 0x2F, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x23, 0x95, 0x23, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x30, 0x95, 0x30, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x24, 0x95, 0x24, 0x09, 0x01,
0x91, 0x02, 0x85, 0x31, 0x95, 0x31, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x32, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x25, 0x95, 0x25, 0x09, 0x01,
0x95, 0x32, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x33, 0x95, 0x33, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x26, 0x95, 0x26, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x34, 0x95, 0x34, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x27, 0x95, 0x27, 0x09, 0x01,
0x91, 0x02, 0x85, 0x35, 0x95, 0x35, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x36, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x28, 0x95, 0x28, 0x09, 0x01,
0x95, 0x36, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x37, 0x95, 0x37, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x29, 0x95, 0x29, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x38, 0x95, 0x38, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2A, 0x95, 0x2A, 0x09, 0x01,
0x91, 0x02, 0x85, 0x39, 0x95, 0x39, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3A, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2B, 0x95, 0x2B, 0x09, 0x01,
0x95, 0x3A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3B, 0x95, 0x3B, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2C, 0x95, 0x2C, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3C, 0x95, 0x3C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2D, 0x95, 0x2D, 0x09, 0x01,
0x91, 0x02, 0x85, 0x3D, 0x95, 0x3D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3E, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2E, 0x95, 0x2E, 0x09, 0x01,
0x95, 0x3E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3F, 0x95, 0x3F, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2F, 0x95, 0x2F, 0x09, 0x01,
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x40, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x41, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x30, 0x95, 0x30, 0x09, 0x01,
0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x42, 0x95, 0x06, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x43, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x31, 0x95, 0x31, 0x09, 0x01,
0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x44, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x45, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x32, 0x95, 0x32, 0x09, 0x01,
0x95, 0x04, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x46, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x47, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x33, 0x95, 0x33, 0x09, 0x01,
0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x50, 0x95, 0x08, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x51, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x34, 0x95, 0x34, 0x09, 0x01,
0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x52, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x60, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x35, 0x95, 0x35, 0x09, 0x01,
0x95, 0x0A, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x61, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x62, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x36, 0x95, 0x36, 0x09, 0x01,
0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x63, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x64, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x37, 0x95, 0x37, 0x09, 0x01,
0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x65, 0x95, 0x3E, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x66, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x38, 0x95, 0x38, 0x09, 0x01,
0x95, 0x13, 0x09, 0x01, 0xB1, 0x02, 0xC0, 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,
}; };
static const struct { static const struct {
struct usb_hid_descriptor hid_descriptor; struct usb_hid_descriptor hid_descriptor;
struct { struct {
uint8_t bReportDescriptorType; uint8_t bReportDescriptorType;
uint16_t wDescriptorLength; uint16_t wDescriptorLength;
} __attribute__((packed)) hid_report; } __attribute__((packed)) hid_report;
} __attribute__((packed)) hid_function = { } __attribute__((packed))
.hid_descriptor = { hid_function = {.hid_descriptor =
.bLength = sizeof(hid_function), {
.bDescriptorType = USB_DT_HID, .bLength = sizeof(hid_function),
.bcdHID = 0x0111, .bDescriptorType = USB_DT_HID,
.bCountryCode = 0, .bcdHID = 0x0111,
.bNumDescriptors = 1, .bCountryCode = 0,
}, .bNumDescriptors = 1,
.hid_report = { },
.bReportDescriptorType = USB_DT_REPORT, .hid_report = {
.wDescriptorLength = sizeof(hid_report_descriptor), .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, .bLength = USB_DT_ENDPOINT_SIZE,
.bEndpointAddress = 0x81, .bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .bEndpointAddress = 0x81,
.wMaxPacketSize = 64, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.bInterval = 1, .wMaxPacketSize = 64,
}, { .bInterval = 1,
.bLength = USB_DT_ENDPOINT_SIZE, },
.bDescriptorType = USB_DT_ENDPOINT, {
.bEndpointAddress = 0x02, .bLength = USB_DT_ENDPOINT_SIZE,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .bDescriptorType = USB_DT_ENDPOINT,
.wMaxPacketSize = 64, .bEndpointAddress = 0x02,
.bInterval = 1, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
}}; .wMaxPacketSize = 64,
.bInterval = 1,
}};
static const struct usb_interface_descriptor hid_iface[] = {{ static const struct usb_interface_descriptor hid_iface[] = {{
.bLength = USB_DT_INTERFACE_SIZE, .bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE, .bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0, .bInterfaceNumber = 0,
.bAlternateSetting = 0, .bAlternateSetting = 0,
.bNumEndpoints = 2, .bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_HID, .bInterfaceClass = USB_CLASS_HID,
.bInterfaceSubClass = 0, .bInterfaceSubClass = 0,
.bInterfaceProtocol = 0, .bInterfaceProtocol = 0,
.iInterface = 0, .iInterface = 0,
.endpoint = hid_endpoints, .endpoint = hid_endpoints,
.extra = &hid_function, .extra = &hid_function,
.extralen = sizeof(hid_function), .extralen = sizeof(hid_function),
}}; }};
static const struct usb_interface ifaces[] = {{ static const struct usb_interface ifaces[] = {{
.num_altsetting = 1, .num_altsetting = 1,
.altsetting = hid_iface, .altsetting = hid_iface,
}}; }};
static const struct usb_config_descriptor config = { static const struct usb_config_descriptor config = {
.bLength = USB_DT_CONFIGURATION_SIZE, .bLength = USB_DT_CONFIGURATION_SIZE,
.bDescriptorType = USB_DT_CONFIGURATION, .bDescriptorType = USB_DT_CONFIGURATION,
.wTotalLength = 0, .wTotalLength = 0,
.bNumInterfaces = 1, .bNumInterfaces = 1,
.bConfigurationValue = 1, .bConfigurationValue = 1,
.iConfiguration = 0, .iConfiguration = 0,
.bmAttributes = 0x80, .bmAttributes = 0x80,
.bMaxPower = 0x32, .bMaxPower = 0x32,
.interface = ifaces, .interface = ifaces,
}; };
static const char *usb_strings[] = { static const char *usb_strings[] = {
"SatoshiLabs", "SatoshiLabs",
"TREZOR", "TREZOR",
"01234567", "01234567",
}; };
static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete) static int hid_control_request(usbd_device *dev, struct usb_setup_data *req,
{ uint8_t **buf, uint16_t *len,
(void)complete; usbd_control_complete_callback *complete) {
(void)dev; (void)complete;
(void)dev;
if ((req->bmRequestType != 0x81) || if ((req->bmRequestType != 0x81) ||
(req->bRequest != USB_REQ_GET_DESCRIPTOR) || (req->bRequest != USB_REQ_GET_DESCRIPTOR) || (req->wValue != 0x2200))
(req->wValue != 0x2200)) return 0;
return 0;
/* Handle the HID report descriptor. */ /* Handle the HID report descriptor. */
*buf = (uint8_t *)hid_report_descriptor; *buf = (uint8_t *)hid_report_descriptor;
*len = sizeof(hid_report_descriptor); *len = sizeof(hid_report_descriptor);
return 1; return 1;
} }
static void hid_rx_callback(usbd_device *dev, uint8_t ep) static void hid_rx_callback(usbd_device *dev, uint8_t ep) {
{ (void)dev;
(void)dev; (void)ep;
(void)ep;
} }
static void hid_set_config(usbd_device *dev, uint16_t wValue) static void hid_set_config(usbd_device *dev, uint16_t wValue) {
{ (void)wValue;
(void)wValue;
usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0);
usbd_ep_setup(dev, 0x02, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_rx_callback); usbd_ep_setup(dev, 0x02, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_rx_callback);
usbd_register_control_callback( usbd_register_control_callback(
dev, dev, USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE,
USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE, USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, hid_control_request);
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
hid_control_request);
} }
static usbd_device *usbd_dev; static usbd_device *usbd_dev;
static uint8_t usbd_control_buffer[128]; static uint8_t usbd_control_buffer[128];
void usbInit(void) void usbInit(void) {
{ usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, 3,
usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer)); usbd_control_buffer, sizeof(usbd_control_buffer));
usbd_register_set_config_callback(usbd_dev, hid_set_config); usbd_register_set_config_callback(usbd_dev, hid_set_config);
} }
int main(void) int main(void) {
{
#ifndef APPVER #ifndef APPVER
setup(); setup();
__stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks __stack_chk_guard = random32(); // this supports compiler provided
oledInit(); // unpredictable stack protection checks
oledInit();
#else #else
setupApp(); setupApp();
__stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks __stack_chk_guard = random32(); // this supports compiler provided
// unpredictable stack protection checks
#endif #endif
usbInit(); usbInit();
passlen = strlen((char *)pass); passlen = strlen((char *)pass);
saltlen = strlen((char *)salt); saltlen = strlen((char *)salt);
for (;;) { for (;;) {
frame = 0; frame = 0;
switch (state) { switch (state) {
case 0: case 0:
oledClear(); oledClear();
oledDrawBitmap(40, 0, &bmp_logo64); oledDrawBitmap(40, 0, &bmp_logo64);
break; break;
} }
oledRefresh(); oledRefresh();
do { do {
usbd_poll(usbd_dev); usbd_poll(usbd_dev);
switch (state) { switch (state) {
case 1: case 1:
layoutProgress("WORKING", frame % 41 * 25); layoutProgress("WORKING", frame % 41 * 25);
pbkdf2_hmac_sha512(pass, passlen, salt, saltlen, 100, seed, 64); pbkdf2_hmac_sha512(pass, passlen, salt, saltlen, 100, seed, 64);
usbd_ep_write_packet(usbd_dev, 0x81, seed, 64); usbd_ep_write_packet(usbd_dev, 0x81, seed, 64);
break; break;
} }
buttonUpdate(); buttonUpdate();
frame += 1; frame += 1;
} while (!button.YesUp && !button.NoUp); } while (!button.YesUp && !button.NoUp);
if (button.YesUp) { if (button.YesUp) {
state = (state + 1) % states; state = (state + 1) % states;
oledSwipeLeft(); oledSwipeLeft();
} else { } else {
state = (state + states - 1) % states; state = (state + states - 1) % states;
oledSwipeRight(); oledSwipeRight();
} }
} }
return 0; return 0;
} }

View File

@ -24,17 +24,17 @@
#endif #endif
uint16_t buttonRead(void) { uint16_t buttonRead(void) {
uint16_t state = 0; uint16_t state = 0;
#if !HEADLESS #if !HEADLESS
const uint8_t *scancodes = SDL_GetKeyboardState(NULL); const uint8_t *scancodes = SDL_GetKeyboardState(NULL);
if (scancodes[SDL_SCANCODE_LEFT]) { if (scancodes[SDL_SCANCODE_LEFT]) {
state |= BTN_PIN_NO; state |= BTN_PIN_NO;
} }
if (scancodes[SDL_SCANCODE_RIGHT]) { if (scancodes[SDL_SCANCODE_RIGHT]) {
state |= BTN_PIN_YES; state |= BTN_PIN_YES;
} }
#endif #endif
return ~state; return ~state;
} }

View File

@ -17,16 +17,14 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h>
#include <assert.h> #include <assert.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h>
#include <unistd.h> #include <unistd.h>
#include "memory.h" #include "memory.h"
void flash_lock(void) { void flash_lock(void) { sync(); }
sync();
}
void flash_unlock(void) {} void flash_unlock(void) {}
@ -35,105 +33,104 @@ void flash_clear_status_flags(void) {}
void flash_lock_option_bytes(void) {} void flash_lock_option_bytes(void) {}
void flash_unlock_option_bytes(void) {} void flash_unlock_option_bytes(void) {}
void flash_program_option_bytes(uint32_t data) { void flash_program_option_bytes(uint32_t data) { (void)data; }
(void) data;
}
static ssize_t sector_to_offset(uint8_t sector) { static ssize_t sector_to_offset(uint8_t sector) {
switch (sector) { switch (sector) {
case 0: case 0:
return 0x0; return 0x0;
case 1: case 1:
return 0x4000; return 0x4000;
case 2: case 2:
return 0x8000; return 0x8000;
case 3: case 3:
return 0xC000; return 0xC000;
case 4: case 4:
return 0x10000; return 0x10000;
case 5: case 5:
return 0x20000; return 0x20000;
case 6: case 6:
return 0x40000; return 0x40000;
case 7: case 7:
return 0x60000; return 0x60000;
case 8: case 8:
return 0x80000; return 0x80000;
default: default:
return -1; return -1;
} }
} }
static void *sector_to_address(uint8_t sector) { static void *sector_to_address(uint8_t sector) {
ssize_t offset = sector_to_offset(sector); ssize_t offset = sector_to_offset(sector);
if (offset < 0) { if (offset < 0) {
return NULL; return NULL;
} }
return (void *) FLASH_PTR(FLASH_ORIGIN + offset); return (void *)FLASH_PTR(FLASH_ORIGIN + offset);
} }
static ssize_t sector_to_size(uint8_t sector) { static ssize_t sector_to_size(uint8_t sector) {
ssize_t start = sector_to_offset(sector); ssize_t start = sector_to_offset(sector);
if (start < 0) { if (start < 0) {
return -1; return -1;
} }
ssize_t end = sector_to_offset(sector + 1); ssize_t end = sector_to_offset(sector + 1);
if (end < 0) { if (end < 0) {
return -1; return -1;
} }
return end - start; return end - start;
} }
void flash_erase_sector(uint8_t sector, uint32_t program_size) { void flash_erase_sector(uint8_t sector, uint32_t program_size) {
(void) program_size; (void)program_size;
void *address = sector_to_address(sector); void *address = sector_to_address(sector);
if (address == NULL) { if (address == NULL) {
return; return;
} }
ssize_t size = sector_to_size(sector); ssize_t size = sector_to_size(sector);
if (size < 0) { if (size < 0) {
return; return;
} }
memset(address, 0xFF, size); memset(address, 0xFF, size);
} }
void flash_erase_all_sectors(uint32_t program_size) { void flash_erase_all_sectors(uint32_t program_size) {
(void) program_size; (void)program_size;
memset(emulator_flash_base, 0xFF, FLASH_TOTAL_SIZE); memset(emulator_flash_base, 0xFF, FLASH_TOTAL_SIZE);
} }
void flash_program_word(uint32_t address, uint32_t data) { void flash_program_word(uint32_t address, uint32_t data) {
*(volatile uint32_t *)FLASH_PTR(address) = data; *(volatile uint32_t *)FLASH_PTR(address) = data;
} }
void flash_program_byte(uint32_t address, uint8_t data) { void flash_program_byte(uint32_t address, uint8_t data) {
*(volatile uint8_t *)FLASH_PTR(address) = data; *(volatile uint8_t *)FLASH_PTR(address) = data;
} }
static bool flash_locked = true; static bool flash_locked = true;
void svc_flash_unlock(void) { void svc_flash_unlock(void) {
assert (flash_locked); assert(flash_locked);
flash_locked = false; flash_locked = false;
} }
void svc_flash_program(uint32_t size) { void svc_flash_program(uint32_t size) {
(void) size; (void)size;
assert (!flash_locked); assert(!flash_locked);
} }
void svc_flash_erase_sector(uint16_t sector) { void svc_flash_erase_sector(uint16_t sector) {
assert (!flash_locked); assert(!flash_locked);
assert (sector >= FLASH_STORAGE_SECTOR_FIRST && sector <= FLASH_STORAGE_SECTOR_LAST); assert(sector >= FLASH_STORAGE_SECTOR_FIRST &&
flash_erase_sector(sector, 3); sector <= FLASH_STORAGE_SECTOR_LAST);
flash_erase_sector(sector, 3);
} }
uint32_t svc_flash_lock(void) { uint32_t svc_flash_lock(void) {
assert (!flash_locked); assert(!flash_locked);
flash_locked = true; flash_locked = true;
sync(); sync();
return 0; return 0;
} }

View File

@ -37,114 +37,114 @@ static SDL_Rect dstrect;
#define ENV_OLED_SCALE "TREZOR_OLED_SCALE" #define ENV_OLED_SCALE "TREZOR_OLED_SCALE"
static int emulatorFullscreen(void) { static int emulatorFullscreen(void) {
const char *variable = getenv(ENV_OLED_FULLSCREEN); const char *variable = getenv(ENV_OLED_FULLSCREEN);
if (!variable) { if (!variable) {
return 0; return 0;
} }
return atoi(variable); return atoi(variable);
} }
static int emulatorScale(void) { static int emulatorScale(void) {
const char *variable = getenv(ENV_OLED_SCALE); const char *variable = getenv(ENV_OLED_SCALE);
if (!variable) { if (!variable) {
return 1; return 1;
} }
int scale = atoi(variable); int scale = atoi(variable);
if (scale >= 1 && scale <= 16) { if (scale >= 1 && scale <= 16) {
return scale; return scale;
} }
return 1; return 1;
} }
void oledInit(void) { void oledInit(void) {
if (SDL_Init(SDL_INIT_VIDEO) != 0) { if (SDL_Init(SDL_INIT_VIDEO) != 0) {
fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError()); fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError());
exit(1); exit(1);
} }
atexit(SDL_Quit); atexit(SDL_Quit);
int scale = emulatorScale(); int scale = emulatorScale();
int fullscreen = emulatorFullscreen(); int fullscreen = emulatorFullscreen();
SDL_Window *window = SDL_CreateWindow("TREZOR", SDL_Window *window = SDL_CreateWindow(
SDL_WINDOWPOS_UNDEFINED, "TREZOR", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, OLED_WIDTH * scale, OLED_HEIGHT * scale,
OLED_WIDTH * scale, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
OLED_HEIGHT * scale,
fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
if (window == NULL) { if (window == NULL) {
fprintf(stderr, "Failed to create window: %s\n", SDL_GetError()); fprintf(stderr, "Failed to create window: %s\n", SDL_GetError());
exit(1); exit(1);
} }
renderer = SDL_CreateRenderer(window, -1, 0); renderer = SDL_CreateRenderer(window, -1, 0);
if (!renderer) { if (!renderer) {
fprintf(stderr, "Failed to create renderer: %s\n", SDL_GetError()); fprintf(stderr, "Failed to create renderer: %s\n", SDL_GetError());
exit(1); exit(1);
} }
if (fullscreen) { if (fullscreen) {
SDL_DisplayMode current_mode; SDL_DisplayMode current_mode;
if (SDL_GetCurrentDisplayMode(0, &current_mode) != 0) if (SDL_GetCurrentDisplayMode(0, &current_mode) != 0) {
{ fprintf(stderr, "Failed to get current display mode: %s\n",
fprintf(stderr, "Failed to get current display mode: %s\n", SDL_GetError()); SDL_GetError());
exit(1); exit(1);
} }
dstrect.x = (current_mode.w - OLED_WIDTH * scale) / 2; dstrect.x = (current_mode.w - OLED_WIDTH * scale) / 2;
dstrect.y = (current_mode.h - OLED_HEIGHT * scale) / 2; dstrect.y = (current_mode.h - OLED_HEIGHT * scale) / 2;
SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderClear(renderer); SDL_RenderClear(renderer);
SDL_ShowCursor(SDL_DISABLE); SDL_ShowCursor(SDL_DISABLE);
} else { } else {
dstrect.x = 0; dstrect.x = 0;
dstrect.y = 0; dstrect.y = 0;
} }
dstrect.w = OLED_WIDTH * scale; dstrect.w = OLED_WIDTH * scale;
dstrect.h = OLED_HEIGHT * scale; dstrect.h = OLED_HEIGHT * scale;
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, OLED_WIDTH, OLED_HEIGHT); texture =
SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING, OLED_WIDTH, OLED_HEIGHT);
oledClear(); oledClear();
oledRefresh(); oledRefresh();
} }
void oledRefresh(void) { void oledRefresh(void) {
/* Draw triangle in upper right corner */ /* Draw triangle in upper right corner */
oledInvertDebugLink(); oledInvertDebugLink();
const uint8_t *buffer = oledGetBuffer(); const uint8_t *buffer = oledGetBuffer();
static uint32_t data[OLED_HEIGHT][OLED_WIDTH]; static uint32_t data[OLED_HEIGHT][OLED_WIDTH];
for (size_t i = 0; i < OLED_BUFSIZE; i++) { for (size_t i = 0; i < OLED_BUFSIZE; i++) {
int x = (OLED_BUFSIZE - 1 - i) % OLED_WIDTH; int x = (OLED_BUFSIZE - 1 - i) % OLED_WIDTH;
int y = (OLED_BUFSIZE - 1 - i) / OLED_WIDTH * 8 + 7; int y = (OLED_BUFSIZE - 1 - i) / OLED_WIDTH * 8 + 7;
for (uint8_t shift = 0; shift < 8; shift++, y--) { for (uint8_t shift = 0; shift < 8; shift++, y--) {
bool set = (buffer[i] >> shift) & 1; bool set = (buffer[i] >> shift) & 1;
data[y][x] = set ? 0xFFFFFFFF : 0xFF000000; data[y][x] = set ? 0xFFFFFFFF : 0xFF000000;
} }
} }
SDL_UpdateTexture(texture, NULL, data, OLED_WIDTH * sizeof(uint32_t)); SDL_UpdateTexture(texture, NULL, data, OLED_WIDTH * sizeof(uint32_t));
SDL_RenderCopy(renderer, texture, NULL, &dstrect); SDL_RenderCopy(renderer, texture, NULL, &dstrect);
SDL_RenderPresent(renderer); SDL_RenderPresent(renderer);
/* Return it back */ /* Return it back */
oledInvertDebugLink(); oledInvertDebugLink();
} }
void emulatorPoll(void) { void emulatorPoll(void) {
SDL_Event event; SDL_Event event;
if (SDL_PollEvent(&event)) { if (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) { if (event.type == SDL_QUIT) {
exit(1); exit(1);
} }
} }
} }
#endif #endif

View File

@ -20,13 +20,13 @@
#include "rng.h" #include "rng.h"
uint32_t random32(void) { uint32_t random32(void) {
static uint32_t last = 0; static uint32_t last = 0;
uint32_t new; uint32_t new;
do { do {
emulatorRandom(&new, sizeof(new)); emulatorRandom(&new, sizeof(new));
} while (last == new); } while (last == new);
last = new; last = new;
return new; return new;
} }

View File

@ -48,60 +48,61 @@ static void setup_urandom(void);
static void setup_flash(void); static void setup_flash(void);
void setup(void) { void setup(void) {
setup_urandom(); setup_urandom();
setup_flash(); setup_flash();
} }
void __attribute__((noreturn)) shutdown(void) { void __attribute__((noreturn)) shutdown(void) {
for(;;) pause(); for (;;) pause();
} }
void emulatorRandom(void *buffer, size_t size) { void emulatorRandom(void *buffer, size_t size) {
ssize_t n, len = 0; ssize_t n, len = 0;
do { do {
n = read(random_fd, (char*)buffer + len, size - len); n = read(random_fd, (char *)buffer + len, size - len);
if (n < 0) { if (n < 0) {
perror("Failed to read " RANDOM_DEV_FILE); perror("Failed to read " RANDOM_DEV_FILE);
exit(1); exit(1);
} }
len += n; len += n;
} while (len != (ssize_t)size); } while (len != (ssize_t)size);
} }
static void setup_urandom(void) { static void setup_urandom(void) {
random_fd = open(RANDOM_DEV_FILE, O_RDONLY); random_fd = open(RANDOM_DEV_FILE, O_RDONLY);
if (random_fd < 0) { if (random_fd < 0) {
perror("Failed to open " RANDOM_DEV_FILE); perror("Failed to open " RANDOM_DEV_FILE);
exit(1); exit(1);
} }
} }
static void setup_flash(void) { static void setup_flash(void) {
int fd = open(EMULATOR_FLASH_FILE, O_RDWR | O_SYNC | O_CREAT, 0644); int fd = open(EMULATOR_FLASH_FILE, O_RDWR | O_SYNC | O_CREAT, 0644);
if (fd < 0) { if (fd < 0) {
perror("Failed to open flash emulation file"); perror("Failed to open flash emulation file");
exit(1); exit(1);
} }
off_t length = lseek(fd, 0, SEEK_END); off_t length = lseek(fd, 0, SEEK_END);
if (length < 0) { if (length < 0) {
perror("Failed to read length of flash emulation file"); perror("Failed to read length of flash emulation file");
exit(1); exit(1);
} }
emulator_flash_base = mmap(NULL, FLASH_TOTAL_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); emulator_flash_base =
if (emulator_flash_base == MAP_FAILED) { mmap(NULL, FLASH_TOTAL_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
perror("Failed to map flash emulation file"); if (emulator_flash_base == MAP_FAILED) {
exit(1); perror("Failed to map flash emulation file");
} exit(1);
}
if (length < FLASH_TOTAL_SIZE) { if (length < FLASH_TOTAL_SIZE) {
if (ftruncate(fd, FLASH_TOTAL_SIZE) != 0) { if (ftruncate(fd, FLASH_TOTAL_SIZE) != 0) {
perror("Failed to initialize flash emulation file"); perror("Failed to initialize flash emulation file");
exit(1); exit(1);
} }
/* Initialize the flash */ /* Initialize the flash */
flash_erase_all_sectors(FLASH_CR_PROGRAM_X32); flash_erase_all_sectors(FLASH_CR_PROGRAM_X32);
} }
} }

View File

@ -24,21 +24,21 @@
#if (!defined __APPLE__) && (!defined HAVE_STRLCPY) #if (!defined __APPLE__) && (!defined HAVE_STRLCPY)
size_t strlcpy(char *dst, const char *src, size_t size) { size_t strlcpy(char *dst, const char *src, size_t size) {
size_t ret = strlen(src); size_t ret = strlen(src);
if (size) { if (size) {
size_t len = MIN(ret, size - 1); size_t len = MIN(ret, size - 1);
memcpy(dst, src, len); memcpy(dst, src, len);
dst[len] = '\0'; dst[len] = '\0';
} }
return ret; return ret;
} }
size_t strlcat(char *dst, const char *src, size_t size) { size_t strlcat(char *dst, const char *src, size_t size) {
size_t n = strnlen(dst, size); size_t n = strnlen(dst, size);
return n + strlcpy(&dst[n], src, size - n); return n + strlcpy(&dst[n], src, size - n);
} }
#endif #endif

View File

@ -24,9 +24,9 @@
void timer_init(void) {} void timer_init(void) {}
uint32_t timer_ms(void) { uint32_t timer_ms(void) {
struct timespec t; struct timespec t;
clock_gettime(CLOCK_MONOTONIC, &t); clock_gettime(CLOCK_MONOTONIC, &t);
uint32_t msec = t.tv_sec * 1000 + (t.tv_nsec / 1000000); uint32_t msec = t.tv_sec * 1000 + (t.tv_nsec / 1000000);
return msec; return msec;
} }

View File

@ -27,97 +27,101 @@
#define TREZOR_UDP_PORT 21324 #define TREZOR_UDP_PORT 21324
struct usb_socket { struct usb_socket {
int fd; int fd;
struct sockaddr_in from; struct sockaddr_in from;
socklen_t fromlen; socklen_t fromlen;
}; };
static struct usb_socket usb_main; static struct usb_socket usb_main;
static struct usb_socket usb_debug; static struct usb_socket usb_debug;
static int socket_setup(int port) { static int socket_setup(int port) {
int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (fd < 0) { if (fd < 0) {
perror("Failed to create socket"); perror("Failed to create socket");
exit(1); exit(1);
} }
struct sockaddr_in addr; struct sockaddr_in addr;
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
addr.sin_port = htons(port); addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) != 0) { if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
perror("Failed to bind socket"); perror("Failed to bind socket");
exit(1); exit(1);
} }
return fd; return fd;
} }
static size_t socket_write(struct usb_socket *sock, const void *buffer, size_t size) { static size_t socket_write(struct usb_socket *sock, const void *buffer,
if (sock->fromlen > 0) { size_t size) {
ssize_t n = sendto(sock->fd, buffer, size, MSG_DONTWAIT, (const struct sockaddr *) &sock->from, sock->fromlen); if (sock->fromlen > 0) {
if (n < 0 || ((size_t) n) != size) { ssize_t n = sendto(sock->fd, buffer, size, MSG_DONTWAIT,
perror("Failed to write socket"); (const struct sockaddr *)&sock->from, sock->fromlen);
return 0; if (n < 0 || ((size_t)n) != size) {
} perror("Failed to write socket");
} return 0;
}
}
return size; return size;
} }
static size_t socket_read(struct usb_socket *sock, void *buffer, size_t size) { static size_t socket_read(struct usb_socket *sock, void *buffer, size_t size) {
sock->fromlen = sizeof(sock->from); sock->fromlen = sizeof(sock->from);
ssize_t n = recvfrom(sock->fd, buffer, size, MSG_DONTWAIT, (struct sockaddr *) &sock->from, &sock->fromlen); ssize_t n = recvfrom(sock->fd, buffer, size, MSG_DONTWAIT,
(struct sockaddr *)&sock->from, &sock->fromlen);
if (n < 0) { if (n < 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK) { if (errno != EAGAIN && errno != EWOULDBLOCK) {
perror("Failed to read socket"); perror("Failed to read socket");
} }
return 0; return 0;
} }
static const char msg_ping[] = { 'P', 'I', 'N', 'G', 'P', 'I', 'N', 'G' }; static const char msg_ping[] = {'P', 'I', 'N', 'G', 'P', 'I', 'N', 'G'};
static const char msg_pong[] = { 'P', 'O', 'N', 'G', 'P', 'O', 'N', 'G' }; static const char msg_pong[] = {'P', 'O', 'N', 'G', 'P', 'O', 'N', 'G'};
if (n == sizeof(msg_ping) && memcmp(buffer, msg_ping, sizeof(msg_ping)) == 0) { if (n == sizeof(msg_ping) &&
socket_write(sock, msg_pong, sizeof(msg_pong)); memcmp(buffer, msg_ping, sizeof(msg_ping)) == 0) {
return 0; socket_write(sock, msg_pong, sizeof(msg_pong));
} return 0;
}
return n; return n;
} }
void emulatorSocketInit(void) { void emulatorSocketInit(void) {
usb_main.fd = socket_setup(TREZOR_UDP_PORT); usb_main.fd = socket_setup(TREZOR_UDP_PORT);
usb_main.fromlen = 0; usb_main.fromlen = 0;
usb_debug.fd = socket_setup(TREZOR_UDP_PORT + 1); usb_debug.fd = socket_setup(TREZOR_UDP_PORT + 1);
usb_debug.fromlen = 0; usb_debug.fromlen = 0;
} }
size_t emulatorSocketRead(int *iface, void *buffer, size_t size) { size_t emulatorSocketRead(int *iface, void *buffer, size_t size) {
size_t n = socket_read(&usb_main, buffer, size); size_t n = socket_read(&usb_main, buffer, size);
if (n > 0) { if (n > 0) {
*iface = 0; *iface = 0;
return n; return n;
} }
n = socket_read(&usb_debug, buffer, size); n = socket_read(&usb_debug, buffer, size);
if (n > 0) { if (n > 0) {
*iface = 1; *iface = 1;
return n; return n;
} }
return 0; return 0;
} }
size_t emulatorSocketWrite(int iface, const void *buffer, size_t size) { size_t emulatorSocketWrite(int iface, const void *buffer, size_t size) {
if (iface == 0) { if (iface == 0) {
return socket_write(&usb_main, buffer, size); return socket_write(&usb_main, buffer, size);
} }
if (iface == 1) { if (iface == 1) {
return socket_write(&usb_debug, buffer, size); return socket_write(&usb_debug, buffer, size);
} }
return 0; return 0;
} }

View File

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

View File

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

View File

@ -20,35 +20,35 @@
#ifndef __COINS_H__ #ifndef __COINS_H__
#define __COINS_H__ #define __COINS_H__
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include "bip32.h" #include "bip32.h"
#include "hasher.h" #include "hasher.h"
typedef struct _CoinInfo { typedef struct _CoinInfo {
const char *coin_name; const char *coin_name;
const char *coin_shortcut; const char *coin_shortcut;
uint64_t maxfee_kb; uint64_t maxfee_kb;
const char *signed_message_header; const char *signed_message_header;
bool has_address_type; bool has_address_type;
bool has_address_type_p2sh; bool has_address_type_p2sh;
bool has_segwit; bool has_segwit;
bool has_fork_id; bool has_fork_id;
bool force_bip143; bool force_bip143;
bool decred; bool decred;
// address types > 0xFF represent a two-byte prefix in big-endian order // address types > 0xFF represent a two-byte prefix in big-endian order
uint32_t address_type; uint32_t address_type;
uint32_t address_type_p2sh; uint32_t address_type_p2sh;
uint32_t xpub_magic; uint32_t xpub_magic;
uint32_t xpub_magic_segwit_p2sh; uint32_t xpub_magic_segwit_p2sh;
uint32_t xpub_magic_segwit_native; uint32_t xpub_magic_segwit_native;
uint32_t fork_id; uint32_t fork_id;
const char *bech32_prefix; const char *bech32_prefix;
const char *cashaddr_prefix; const char *cashaddr_prefix;
uint32_t coin_type; uint32_t coin_type;
const char *curve_name; const char *curve_name;
const curve_info *curve; const curve_info *curve;
} CoinInfo; } CoinInfo;
#include "coin_info.h" #include "coin_info.h"
@ -56,7 +56,9 @@ typedef struct _CoinInfo {
const CoinInfo *coinByName(const char *name); const CoinInfo *coinByName(const char *name);
const CoinInfo *coinByAddressType(uint32_t address_type); const CoinInfo *coinByAddressType(uint32_t address_type);
const CoinInfo *coinBySlip44(uint32_t coin_type); const CoinInfo *coinBySlip44(uint32_t coin_type);
bool coinExtractAddressType(const CoinInfo *coin, const char *addr, uint32_t *address_type); bool coinExtractAddressType(const CoinInfo *coin, const char *addr,
bool coinExtractAddressTypeRaw(const CoinInfo *coin, const uint8_t *addr_raw, uint32_t *address_type); uint32_t *address_type);
bool coinExtractAddressTypeRaw(const CoinInfo *coin, const uint8_t *addr_raw,
uint32_t *address_type);
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@ -24,66 +24,66 @@
#include "messages-management.pb.h" #include "messages-management.pb.h"
#define STORAGE_FIELD(TYPE, NAME) \ #define STORAGE_FIELD(TYPE, NAME) \
bool has_##NAME; \ bool has_##NAME; \
TYPE NAME; TYPE NAME;
#define STORAGE_STRING(NAME, SIZE) \ #define STORAGE_STRING(NAME, SIZE) \
bool has_##NAME; \ bool has_##NAME; \
char NAME[SIZE]; char NAME[SIZE];
#define STORAGE_BYTES(NAME, SIZE) \ #define STORAGE_BYTES(NAME, SIZE) \
bool has_##NAME; \ bool has_##NAME; \
struct { \ struct { \
uint32_t size; \ uint32_t size; \
uint8_t bytes[SIZE]; \ uint8_t bytes[SIZE]; \
} NAME; } NAME;
#define STORAGE_BOOL(NAME) STORAGE_FIELD(bool, NAME) #define STORAGE_BOOL(NAME) STORAGE_FIELD(bool, NAME)
#define STORAGE_NODE(NAME) STORAGE_FIELD(StorageHDNode, NAME) #define STORAGE_NODE(NAME) STORAGE_FIELD(StorageHDNode, NAME)
#define STORAGE_UINT32(NAME) STORAGE_FIELD(uint32_t, NAME) #define STORAGE_UINT32(NAME) STORAGE_FIELD(uint32_t, NAME)
typedef struct { typedef struct {
uint32_t depth; uint32_t depth;
uint32_t fingerprint; uint32_t fingerprint;
uint32_t child_num; uint32_t child_num;
struct { struct {
uint32_t size; uint32_t size;
uint8_t bytes[32]; uint8_t bytes[32];
} chain_code; } chain_code;
STORAGE_BYTES(private_key, 32); STORAGE_BYTES(private_key, 32);
STORAGE_BYTES(public_key, 33); STORAGE_BYTES(public_key, 33);
} StorageHDNode; } StorageHDNode;
typedef struct _Storage { typedef struct _Storage {
uint32_t version; uint32_t version;
STORAGE_NODE (node) STORAGE_NODE(node)
STORAGE_STRING (mnemonic, 241) STORAGE_STRING(mnemonic, 241)
STORAGE_BOOL (passphrase_protection) STORAGE_BOOL(passphrase_protection)
STORAGE_UINT32 (pin_failed_attempts) STORAGE_UINT32(pin_failed_attempts)
STORAGE_STRING (pin, 10) STORAGE_STRING(pin, 10)
STORAGE_STRING (language, 17) STORAGE_STRING(language, 17)
STORAGE_STRING (label, 33) STORAGE_STRING(label, 33)
STORAGE_BOOL (imported) STORAGE_BOOL(imported)
STORAGE_BYTES (homescreen, 1024) STORAGE_BYTES(homescreen, 1024)
STORAGE_UINT32 (u2f_counter) STORAGE_UINT32(u2f_counter)
STORAGE_BOOL (needs_backup) STORAGE_BOOL(needs_backup)
STORAGE_UINT32 (flags) STORAGE_UINT32(flags)
STORAGE_NODE (u2froot) STORAGE_NODE(u2froot)
STORAGE_BOOL (unfinished_backup) STORAGE_BOOL(unfinished_backup)
STORAGE_UINT32 (auto_lock_delay_ms) STORAGE_UINT32(auto_lock_delay_ms)
STORAGE_BOOL (no_backup) STORAGE_BOOL(no_backup)
} Storage; } Storage;
extern Storage configUpdate; extern Storage configUpdate;
#define MAX_PIN_LEN 9 #define MAX_PIN_LEN 9
#define MAX_LABEL_LEN 32 #define MAX_LABEL_LEN 32
#define MAX_LANGUAGE_LEN 16 #define MAX_LANGUAGE_LEN 16
#define MAX_MNEMONIC_LEN 240 #define MAX_MNEMONIC_LEN 240
#define HOMESCREEN_SIZE 1024 #define HOMESCREEN_SIZE 1024
#define UUID_SIZE 12 #define UUID_SIZE 12
void config_init(void); void config_init(void);
void session_clear(bool lock); void session_clear(bool lock);
@ -109,12 +109,14 @@ void config_setHomescreen(const uint8_t *data, uint32_t size);
void session_cachePassphrase(const char *passphrase); void session_cachePassphrase(const char *passphrase);
bool session_isPassphraseCached(void); bool session_isPassphraseCached(void);
bool session_getState(const uint8_t *salt, uint8_t *state, const char *passphrase); bool session_getState(const uint8_t *salt, uint8_t *state,
const char *passphrase);
bool config_setMnemonic(const char *mnemonic); bool config_setMnemonic(const char *mnemonic);
bool config_containsMnemonic(const char *mnemonic); bool config_containsMnemonic(const char *mnemonic);
bool config_getMnemonic(char *dest, uint16_t dest_size); bool config_getMnemonic(char *dest, uint16_t dest_size);
bool config_getMnemonicBytes(uint8_t *dest, uint16_t dest_size, uint16_t *real_size); bool config_getMnemonicBytes(uint8_t *dest, uint16_t dest_size,
uint16_t *real_size);
#if DEBUG_LINK #if DEBUG_LINK
bool config_dumpNode(HDNodeType *node); bool config_dumpNode(HDNodeType *node);
@ -151,6 +153,6 @@ void config_setAutoLockDelayMs(uint32_t auto_lock_delay_ms);
void config_wipe(void); void config_wipe(void);
extern char config_uuid_str[2*UUID_SIZE + 1]; extern char config_uuid_str[2 * UUID_SIZE + 1];
#endif #endif

View File

@ -17,452 +17,482 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h>
#include "crypto.h" #include "crypto.h"
#include "sha2.h" #include <string.h>
#include "pbkdf2.h"
#include "aes/aes.h"
#include "hmac.h"
#include "bip32.h"
#include "layout.h"
#include "curves.h"
#include "secp256k1.h"
#include "address.h" #include "address.h"
#include "coins.h" #include "aes/aes.h"
#include "base58.h" #include "base58.h"
#include "segwit_addr.h" #include "bip32.h"
#include "cash_addr.h" #include "cash_addr.h"
#include "coins.h"
#include "curves.h"
#include "hmac.h"
#include "layout.h"
#include "pbkdf2.h"
#include "secp256k1.h"
#include "segwit_addr.h"
#include "sha2.h"
uint32_t ser_length(uint32_t len, uint8_t *out) uint32_t ser_length(uint32_t len, uint8_t *out) {
{ if (len < 253) {
if (len < 253) { out[0] = len & 0xFF;
out[0] = len & 0xFF; return 1;
return 1; }
} if (len < 0x10000) {
if (len < 0x10000) { out[0] = 253;
out[0] = 253; out[1] = len & 0xFF;
out[1] = len & 0xFF; out[2] = (len >> 8) & 0xFF;
out[2] = (len >> 8) & 0xFF; return 3;
return 3; }
} out[0] = 254;
out[0] = 254; out[1] = len & 0xFF;
out[1] = len & 0xFF; out[2] = (len >> 8) & 0xFF;
out[2] = (len >> 8) & 0xFF; out[3] = (len >> 16) & 0xFF;
out[3] = (len >> 16) & 0xFF; out[4] = (len >> 24) & 0xFF;
out[4] = (len >> 24) & 0xFF; return 5;
return 5;
} }
uint32_t ser_length_hash(Hasher *hasher, uint32_t len) uint32_t ser_length_hash(Hasher *hasher, uint32_t len) {
{ if (len < 253) {
if (len < 253) { hasher_Update(hasher, (const uint8_t *)&len, 1);
hasher_Update(hasher, (const uint8_t *)&len, 1); return 1;
return 1; }
} if (len < 0x10000) {
if (len < 0x10000) { uint8_t d = 253;
uint8_t d = 253; hasher_Update(hasher, &d, 1);
hasher_Update(hasher, &d, 1); hasher_Update(hasher, (const uint8_t *)&len, 2);
hasher_Update(hasher, (const uint8_t *)&len, 2); return 3;
return 3; }
} uint8_t d = 254;
uint8_t d = 254; hasher_Update(hasher, &d, 1);
hasher_Update(hasher, &d, 1); hasher_Update(hasher, (const uint8_t *)&len, 4);
hasher_Update(hasher, (const uint8_t *)&len, 4); return 5;
return 5;
} }
uint32_t deser_length(const uint8_t *in, uint32_t *out) uint32_t deser_length(const uint8_t *in, uint32_t *out) {
{ if (in[0] < 253) {
if (in[0] < 253) { *out = in[0];
*out = in[0]; return 1;
return 1; }
} if (in[0] == 253) {
if (in[0] == 253) { *out = in[1] + (in[2] << 8);
*out = in[1] + (in[2] << 8); return 1 + 2;
return 1 + 2; }
} if (in[0] == 254) {
if (in[0] == 254) { *out = in[1] + (in[2] << 8) + (in[3] << 16) + ((uint32_t)in[4] << 24);
*out = in[1] + (in[2] << 8) + (in[3] << 16) + ((uint32_t) in[4] << 24); return 1 + 4;
return 1 + 4; }
} *out = 0; // ignore 64 bit
*out = 0; // ignore 64 bit return 1 + 8;
return 1 + 8;
} }
int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) int sshMessageSign(HDNode *node, const uint8_t *message, size_t message_len,
{ uint8_t *signature) {
signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes
return hdnode_sign(node, message, message_len, HASHER_SHA2, signature + 1, NULL, NULL); return hdnode_sign(node, message, message_len, HASHER_SHA2, signature + 1,
NULL, NULL);
} }
int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len, uint8_t *signature) int gpgMessageSign(HDNode *node, const uint8_t *message, size_t message_len,
{ uint8_t *signature) {
signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes signature[0] = 0; // prefix: pad with zero, so all signatures are 65 bytes
const curve_info *ed25519_curve_info = get_curve_by_name(ED25519_NAME); const curve_info *ed25519_curve_info = get_curve_by_name(ED25519_NAME);
if (ed25519_curve_info && node->curve == ed25519_curve_info) { if (ed25519_curve_info && node->curve == ed25519_curve_info) {
// GPG supports variable size digest for Ed25519 signatures // GPG supports variable size digest for Ed25519 signatures
return hdnode_sign(node, message, message_len, 0, signature + 1, NULL, NULL); return hdnode_sign(node, message, message_len, 0, signature + 1, NULL,
} else { NULL);
// Ensure 256-bit digest before proceeding } else {
if (message_len != 32) { // Ensure 256-bit digest before proceeding
return 1; if (message_len != 32) {
} return 1;
return hdnode_sign_digest(node, message, signature + 1, NULL, NULL); }
} return hdnode_sign_digest(node, message, signature + 1, NULL, NULL);
}
} }
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,
Hasher hasher; size_t message_len,
hasher_Init(&hasher, coin->curve->hasher_sign); uint8_t hash[HASHER_DIGEST_LENGTH]) {
hasher_Update(&hasher, (const uint8_t *)coin->signed_message_header, strlen(coin->signed_message_header)); Hasher hasher;
uint8_t varint[5]; hasher_Init(&hasher, coin->curve->hasher_sign);
uint32_t l = ser_length(message_len, varint); hasher_Update(&hasher, (const uint8_t *)coin->signed_message_header,
hasher_Update(&hasher, varint, l); strlen(coin->signed_message_header));
hasher_Update(&hasher, message, message_len); uint8_t varint[5];
hasher_Final(&hasher, hash); uint32_t l = ser_length(message_len, varint);
hasher_Update(&hasher, varint, l);
hasher_Update(&hasher, message, message_len);
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,
uint8_t hash[HASHER_DIGEST_LENGTH]; size_t message_len, uint8_t *signature) {
cryptoMessageHash(coin, message, message_len, hash); uint8_t hash[HASHER_DIGEST_LENGTH];
cryptoMessageHash(coin, message, message_len, hash);
uint8_t pby; uint8_t pby;
int result = hdnode_sign_digest(node, hash, signature + 1, &pby, NULL); int result = hdnode_sign_digest(node, hash, signature + 1, &pby, NULL);
if (result == 0) { if (result == 0) {
switch (script_type) { switch (script_type) {
case InputScriptType_SPENDP2SHWITNESS: case InputScriptType_SPENDP2SHWITNESS:
// segwit-in-p2sh // segwit-in-p2sh
signature[0] = 35 + pby; signature[0] = 35 + pby;
break; break;
case InputScriptType_SPENDWITNESS: case InputScriptType_SPENDWITNESS:
// segwit // segwit
signature[0] = 39 + pby; signature[0] = 39 + pby;
break; break;
default: default:
// p2pkh // p2pkh
signature[0] = 31 + pby; signature[0] = 31 + pby;
break; break;
} }
} }
return result; return result;
} }
int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message, size_t message_len, const char *address, const uint8_t *signature) int cryptoMessageVerify(const CoinInfo *coin, const uint8_t *message,
{ size_t message_len, const char *address,
// check for invalid signature prefix const uint8_t *signature) {
if (signature[0] < 27 || signature[0] > 43) { // check for invalid signature prefix
return 1; if (signature[0] < 27 || signature[0] > 43) {
} return 1;
}
uint8_t hash[HASHER_DIGEST_LENGTH]; uint8_t hash[HASHER_DIGEST_LENGTH];
cryptoMessageHash(coin, message, message_len, hash); cryptoMessageHash(coin, message, message_len, hash);
uint8_t recid = (signature[0] - 27) % 4; uint8_t recid = (signature[0] - 27) % 4;
bool compressed = signature[0] >= 31; bool compressed = signature[0] >= 31;
// check if signature verifies the digest and recover the public key // check if signature verifies the digest and recover the public key
uint8_t pubkey[65]; uint8_t pubkey[65];
if (ecdsa_recover_pub_from_sig(coin->curve->params, pubkey, signature + 1, hash, recid) != 0) { if (ecdsa_recover_pub_from_sig(coin->curve->params, pubkey, signature + 1,
return 3; hash, recid) != 0) {
} return 3;
// convert public key to compressed pubkey if necessary }
if (compressed) { // convert public key to compressed pubkey if necessary
pubkey[0] = 0x02 | (pubkey[64] & 1); if (compressed) {
} pubkey[0] = 0x02 | (pubkey[64] & 1);
}
// check if the address is correct // check if the address is correct
uint8_t addr_raw[MAX_ADDR_RAW_SIZE]; uint8_t addr_raw[MAX_ADDR_RAW_SIZE];
uint8_t recovered_raw[MAX_ADDR_RAW_SIZE]; uint8_t recovered_raw[MAX_ADDR_RAW_SIZE];
// p2pkh // p2pkh
if (signature[0] >= 27 && signature[0] <= 34) { if (signature[0] >= 27 && signature[0] <= 34) {
size_t len; size_t len;
if (coin->cashaddr_prefix) { if (coin->cashaddr_prefix) {
if (!cash_addr_decode(addr_raw, &len, coin->cashaddr_prefix, address)) { if (!cash_addr_decode(addr_raw, &len, coin->cashaddr_prefix, address)) {
return 2; return 2;
} }
} else { } else {
len = base58_decode_check(address, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); len = base58_decode_check(address, coin->curve->hasher_base58, addr_raw,
} MAX_ADDR_RAW_SIZE);
ecdsa_get_address_raw(pubkey, coin->address_type, coin->curve->hasher_pubkey, recovered_raw); }
if (memcmp(recovered_raw, addr_raw, len) != 0 ecdsa_get_address_raw(pubkey, coin->address_type,
|| len != address_prefix_bytes_len(coin->address_type) + 20) { coin->curve->hasher_pubkey, recovered_raw);
return 2; if (memcmp(recovered_raw, addr_raw, len) != 0 ||
} len != address_prefix_bytes_len(coin->address_type) + 20) {
} else return 2;
// segwit-in-p2sh }
if (signature[0] >= 35 && signature[0] <= 38) { } else
size_t len = base58_decode_check(address, coin->curve->hasher_base58, addr_raw, MAX_ADDR_RAW_SIZE); // segwit-in-p2sh
ecdsa_get_address_segwit_p2sh_raw(pubkey, coin->address_type_p2sh, coin->curve->hasher_pubkey, recovered_raw); if (signature[0] >= 35 && signature[0] <= 38) {
if (memcmp(recovered_raw, addr_raw, len) != 0 size_t len = base58_decode_check(address, coin->curve->hasher_base58,
|| len != address_prefix_bytes_len(coin->address_type_p2sh) + 20) { addr_raw, MAX_ADDR_RAW_SIZE);
return 2; ecdsa_get_address_segwit_p2sh_raw(pubkey, coin->address_type_p2sh,
} coin->curve->hasher_pubkey,
} else recovered_raw);
// segwit if (memcmp(recovered_raw, addr_raw, len) != 0 ||
if (signature[0] >= 39 && signature[0] <= 42) { len != address_prefix_bytes_len(coin->address_type_p2sh) + 20) {
int witver; return 2;
size_t len; }
if (!coin->bech32_prefix } else
|| !segwit_addr_decode(&witver, recovered_raw, &len, coin->bech32_prefix, address)) { // segwit
return 4; if (signature[0] >= 39 && signature[0] <= 42) {
} int witver;
ecdsa_get_pubkeyhash(pubkey, coin->curve->hasher_pubkey, addr_raw); size_t len;
if (memcmp(recovered_raw, addr_raw, len) != 0 if (!coin->bech32_prefix ||
|| witver != 0 || len != 20) { !segwit_addr_decode(&witver, recovered_raw, &len, coin->bech32_prefix,
return 2; address)) {
} return 4;
} else { }
return 4; ecdsa_get_pubkeyhash(pubkey, coin->curve->hasher_pubkey, addr_raw);
} if (memcmp(recovered_raw, addr_raw, len) != 0 || witver != 0 || len != 20) {
return 2;
}
} else {
return 4;
}
return 0; return 0;
} }
/* ECIES disabled /* ECIES disabled
int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t *payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t *privkey, const uint8_t *address_raw) int cryptoMessageEncrypt(curve_point *pubkey, const uint8_t *msg, size_t
msg_size, bool display_only, uint8_t *nonce, size_t *nonce_len, uint8_t
*payload, size_t *payload_len, uint8_t *hmac, size_t *hmac_len, const uint8_t
*privkey, const uint8_t *address_raw)
{ {
if (privkey && address_raw) { // signing == true if (privkey && address_raw) { // signing == true
HDNode node; HDNode node;
payload[0] = display_only ? 0x81 : 0x01; payload[0] = display_only ? 0x81 : 0x01;
uint32_t l = ser_length(msg_size, payload + 1); uint32_t l = ser_length(msg_size, payload + 1);
memcpy(payload + 1 + l, msg, msg_size); memcpy(payload + 1 + l, msg, msg_size);
memcpy(payload + 1 + l + msg_size, address_raw, 21); memcpy(payload + 1 + l + msg_size, address_raw, 21);
hdnode_from_xprv(0, 0, 0, privkey, privkey, SECP256K1_NAME, &node); hdnode_from_xprv(0, 0, 0, privkey, privkey, SECP256K1_NAME,
if (cryptoMessageSign(&node, msg, msg_size, payload + 1 + l + msg_size + 21) != 0) { &node); if (cryptoMessageSign(&node, msg, msg_size, payload + 1 + l + msg_size +
return 1; 21) != 0) { return 1;
} }
*payload_len = 1 + l + msg_size + 21 + 65; *payload_len = 1 + l + msg_size + 21 + 65;
} else { } else {
payload[0] = display_only ? 0x80 : 0x00; payload[0] = display_only ? 0x80 : 0x00;
uint32_t l = ser_length(msg_size, payload + 1); uint32_t l = ser_length(msg_size, payload + 1);
memcpy(payload + 1 + l, msg, msg_size); memcpy(payload + 1 + l, msg, msg_size);
*payload_len = 1 + l + msg_size; *payload_len = 1 + l + msg_size;
} }
// generate random nonce // generate random nonce
curve_point R; curve_point R;
bignum256 k; bignum256 k;
if (generate_k_random(&secp256k1, &k) != 0) { if (generate_k_random(&secp256k1, &k) != 0) {
return 2; return 2;
} }
// compute k*G // compute k*G
scalar_multiply(&secp256k1, &k, &R); scalar_multiply(&secp256k1, &k, &R);
nonce[0] = 0x02 | (R.y.val[0] & 0x01); nonce[0] = 0x02 | (R.y.val[0] & 0x01);
bn_write_be(&R.x, nonce + 1); bn_write_be(&R.x, nonce + 1);
*nonce_len = 33; *nonce_len = 33;
// compute shared secret // compute shared secret
point_multiply(&secp256k1, &k, pubkey, &R); point_multiply(&secp256k1, &k, pubkey, &R);
uint8_t shared_secret[33]; uint8_t shared_secret[33];
shared_secret[0] = 0x02 | (R.y.val[0] & 0x01); shared_secret[0] = 0x02 | (R.y.val[0] & 0x01);
bn_write_be(&R.x, shared_secret + 1); bn_write_be(&R.x, shared_secret + 1);
// generate keying bytes // generate keying bytes
uint8_t keying_bytes[80]; uint8_t keying_bytes[80];
uint8_t salt[22 + 33]; uint8_t salt[22 + 33];
memcpy(salt, "Bitcoin Secure Message", 22); memcpy(salt, "Bitcoin Secure Message", 22);
memcpy(salt + 22, nonce, 33); memcpy(salt + 22, nonce, 33);
pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes, 80); pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes,
// encrypt payload 80);
aes_encrypt_ctx ctx; // encrypt payload
aes_encrypt_key256(keying_bytes, &ctx); aes_encrypt_ctx ctx;
aes_cfb_encrypt(payload, payload, *payload_len, keying_bytes + 64, &ctx); aes_encrypt_key256(keying_bytes, &ctx);
// compute hmac aes_cfb_encrypt(payload, payload, *payload_len, keying_bytes + 64,
uint8_t out[32]; &ctx);
hmac_sha256(keying_bytes + 32, 32, payload, *payload_len, out); // compute hmac
memcpy(hmac, out, 8); uint8_t out[32];
*hmac_len = 8; hmac_sha256(keying_bytes + 32, 32, payload, *payload_len, out);
memcpy(hmac, out, 8);
*hmac_len = 8;
return 0; return 0;
} }
int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t payload_len, const uint8_t *hmac, size_t hmac_len, const uint8_t *privkey, uint8_t *msg, size_t *msg_len, bool *display_only, bool *signing, uint8_t *address_raw) int cryptoMessageDecrypt(curve_point *nonce, uint8_t *payload, size_t
payload_len, const uint8_t *hmac, size_t hmac_len, const uint8_t *privkey,
uint8_t *msg, size_t *msg_len, bool *display_only, bool *signing, uint8_t
*address_raw)
{ {
if (hmac_len != 8) { if (hmac_len != 8) {
return 1; return 1;
} }
// compute shared secret // compute shared secret
curve_point R; curve_point R;
bignum256 k; bignum256 k;
bn_read_be(privkey, &k); bn_read_be(privkey, &k);
point_multiply(&secp256k1, &k, nonce, &R); point_multiply(&secp256k1, &k, nonce, &R);
uint8_t shared_secret[33]; uint8_t shared_secret[33];
shared_secret[0] = 0x02 | (R.y.val[0] & 0x01); shared_secret[0] = 0x02 | (R.y.val[0] & 0x01);
bn_write_be(&R.x, shared_secret + 1); bn_write_be(&R.x, shared_secret + 1);
// generate keying bytes // generate keying bytes
uint8_t keying_bytes[80]; uint8_t keying_bytes[80];
uint8_t salt[22 + 33]; uint8_t salt[22 + 33];
memcpy(salt, "Bitcoin Secure Message", 22); memcpy(salt, "Bitcoin Secure Message", 22);
salt[22] = 0x02 | (nonce->y.val[0] & 0x01); salt[22] = 0x02 | (nonce->y.val[0] & 0x01);
bn_write_be(&(nonce->x), salt + 23); bn_write_be(&(nonce->x), salt + 23);
pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes, 80); pbkdf2_hmac_sha256(shared_secret, 33, salt, 22 + 33, 2048, keying_bytes,
// compute hmac 80);
uint8_t out[32]; // compute hmac
hmac_sha256(keying_bytes + 32, 32, payload, payload_len, out); uint8_t out[32];
if (memcmp(hmac, out, 8) != 0) { hmac_sha256(keying_bytes + 32, 32, payload, payload_len, out);
return 2; if (memcmp(hmac, out, 8) != 0) {
} return 2;
// decrypt payload }
aes_encrypt_ctx ctx; // decrypt payload
aes_encrypt_key256(keying_bytes, &ctx); aes_encrypt_ctx ctx;
aes_cfb_decrypt(payload, payload, payload_len, keying_bytes + 64, &ctx); aes_encrypt_key256(keying_bytes, &ctx);
// check first byte aes_cfb_decrypt(payload, payload, payload_len, keying_bytes + 64, &ctx);
if (payload[0] != 0x00 && payload[0] != 0x01 && payload[0] != 0x80 && payload[0] != 0x81) { // check first byte
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; *signing = payload[0] & 0x01;
uint32_t l, o; *display_only = payload[0] & 0x80;
l = deser_length(payload + 1, &o); uint32_t l, o;
if (*signing) { l = deser_length(payload + 1, &o);
// FIXME: assumes a raw address is 21 bytes (also below). if (*signing) {
if (1 + l + o + 21 + 65 != payload_len) { // FIXME: assumes a raw address is 21 bytes (also below).
return 4; 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) { // FIXME: cryptoMessageVerify changed to take the address_type
return 5; 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 { memcpy(address_raw, payload + 1 + l + o, 21);
if (1 + l + o != payload_len) { } else {
return 4; if (1 + l + o != payload_len) {
} return 4;
} }
memcpy(msg, payload + 1 + l, o); }
*msg_len = o; memcpy(msg, payload + 1 + l, o);
return 0; *msg_len = o;
return 0;
} }
*/ */
const HDNode *cryptoMultisigPubkey(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, uint32_t index) const HDNode *cryptoMultisigPubkey(const CoinInfo *coin,
{ const MultisigRedeemScriptType *multisig,
const HDNodeType *node_ptr; uint32_t index) {
const uint32_t *address_n; const HDNodeType *node_ptr;
uint32_t address_n_count; const uint32_t *address_n;
if (multisig->nodes_count) { // use multisig->nodes uint32_t address_n_count;
if (index >= multisig->nodes_count) { if (multisig->nodes_count) { // use multisig->nodes
return 0; if (index >= multisig->nodes_count) {
} return 0;
node_ptr = &(multisig->nodes[index]); }
address_n = multisig->address_n; node_ptr = &(multisig->nodes[index]);
address_n_count = multisig->address_n_count; address_n = multisig->address_n;
} else address_n_count = multisig->address_n_count;
if (multisig->pubkeys_count) { // use multisig->pubkeys } else if (multisig->pubkeys_count) { // use multisig->pubkeys
if (index >= multisig->pubkeys_count) { if (index >= multisig->pubkeys_count) {
return 0; return 0;
} }
node_ptr = &(multisig->pubkeys[index].node); node_ptr = &(multisig->pubkeys[index].node);
address_n = multisig->pubkeys[index].address_n; address_n = multisig->pubkeys[index].address_n;
address_n_count = multisig->pubkeys[index].address_n_count; address_n_count = multisig->pubkeys[index].address_n_count;
} else { } else {
return 0; return 0;
} }
if (node_ptr->chain_code.size != 32) return 0; if (node_ptr->chain_code.size != 32) return 0;
if (!node_ptr->has_public_key || node_ptr->public_key.size != 33) return 0; if (!node_ptr->has_public_key || node_ptr->public_key.size != 33) return 0;
static HDNode node; static HDNode node;
if (!hdnode_from_xpub(node_ptr->depth, node_ptr->child_num, node_ptr->chain_code.bytes, node_ptr->public_key.bytes, coin->curve_name, &node)) { if (!hdnode_from_xpub(node_ptr->depth, node_ptr->child_num,
return 0; node_ptr->chain_code.bytes, node_ptr->public_key.bytes,
} coin->curve_name, &node)) {
layoutProgressUpdate(true); return 0;
for (uint32_t i = 0; i < address_n_count; i++) { }
if (!hdnode_public_ckd(&node, address_n[i])) { layoutProgressUpdate(true);
return 0; for (uint32_t i = 0; i < address_n_count; i++) {
} if (!hdnode_public_ckd(&node, address_n[i])) {
layoutProgressUpdate(true); return 0;
} }
return &node; layoutProgressUpdate(true);
}
return &node;
} }
uint32_t cryptoMultisigPubkeyCount(const MultisigRedeemScriptType *multisig) uint32_t cryptoMultisigPubkeyCount(const MultisigRedeemScriptType *multisig) {
{ return multisig->nodes_count ? multisig->nodes_count
return multisig->nodes_count ? multisig->nodes_count : multisig->pubkeys_count; : multisig->pubkeys_count;
} }
int cryptoMultisigPubkeyIndex(const CoinInfo *coin, const MultisigRedeemScriptType *multisig, const uint8_t *pubkey) int cryptoMultisigPubkeyIndex(const CoinInfo *coin,
{ const MultisigRedeemScriptType *multisig,
for (size_t i = 0; i < cryptoMultisigPubkeyCount(multisig); i++) { const uint8_t *pubkey) {
const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i); for (size_t i = 0; i < cryptoMultisigPubkeyCount(multisig); i++) {
if (pubnode && memcmp(pubnode->public_key, pubkey, 33) == 0) { const HDNode *pubnode = cryptoMultisigPubkey(coin, multisig, i);
return i; if (pubnode && memcmp(pubnode->public_key, pubkey, 33) == 0) {
} return i;
} }
return -1; }
return -1;
} }
int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig, uint8_t *hash) int cryptoMultisigFingerprint(const MultisigRedeemScriptType *multisig,
{ uint8_t *hash) {
static const HDNodeType *pubnodes[15], *swap; static const HDNodeType *pubnodes[15], *swap;
const uint32_t n = cryptoMultisigPubkeyCount(multisig); const uint32_t n = cryptoMultisigPubkeyCount(multisig);
if (n < 1 || n > 15) { if (n < 1 || n > 15) {
return 0; return 0;
} }
if (!multisig->has_m || multisig->m < 1 || multisig->m > 15) { if (!multisig->has_m || multisig->m < 1 || multisig->m > 15) {
return 0; return 0;
} }
for (uint32_t i = 0; i < n; i++) { for (uint32_t i = 0; i < n; i++) {
if (multisig->nodes_count) { // use multisig->nodes if (multisig->nodes_count) { // use multisig->nodes
pubnodes[i] = &(multisig->nodes[i]); pubnodes[i] = &(multisig->nodes[i]);
} else } else if (multisig->pubkeys_count) { // use multisig->pubkeys
if (multisig->pubkeys_count) { // use multisig->pubkeys pubnodes[i] = &(multisig->pubkeys[i].node);
pubnodes[i] = &(multisig->pubkeys[i].node); } else {
} else { return 0;
return 0; }
} }
} for (uint32_t i = 0; i < n; i++) {
for (uint32_t i = 0; i < n; i++) { if (!pubnodes[i]->has_public_key || pubnodes[i]->public_key.size != 33)
if (!pubnodes[i]->has_public_key || pubnodes[i]->public_key.size != 33) return 0; return 0;
if (pubnodes[i]->chain_code.size != 32) return 0; if (pubnodes[i]->chain_code.size != 32) return 0;
} }
// minsort according to pubkey // minsort according to pubkey
for (uint32_t i = 0; i < n - 1; i++) { for (uint32_t i = 0; i < n - 1; i++) {
for (uint32_t j = n - 1; j > i; j--) { for (uint32_t j = n - 1; j > i; j--) {
if (memcmp(pubnodes[i]->public_key.bytes, pubnodes[j]->public_key.bytes, 33) > 0) { if (memcmp(pubnodes[i]->public_key.bytes, pubnodes[j]->public_key.bytes,
swap = pubnodes[i]; 33) > 0) {
pubnodes[i] = pubnodes[j]; swap = pubnodes[i];
pubnodes[j] = swap; pubnodes[i] = pubnodes[j];
} pubnodes[j] = swap;
} }
} }
// hash sorted nodes }
SHA256_CTX ctx; // hash sorted nodes
sha256_Init(&ctx); SHA256_CTX ctx;
sha256_Update(&ctx, (const uint8_t *)&(multisig->m), sizeof(uint32_t)); sha256_Init(&ctx);
for (uint32_t i = 0; i < n; i++) { sha256_Update(&ctx, (const uint8_t *)&(multisig->m), sizeof(uint32_t));
sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->depth), sizeof(uint32_t)); for (uint32_t i = 0; i < n; i++) {
sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->fingerprint), sizeof(uint32_t)); sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->depth),
sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->child_num), sizeof(uint32_t)); sizeof(uint32_t));
sha256_Update(&ctx, pubnodes[i]->chain_code.bytes, 32); sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->fingerprint),
sha256_Update(&ctx, pubnodes[i]->public_key.bytes, 33); sizeof(uint32_t));
} sha256_Update(&ctx, (const uint8_t *)&(pubnodes[i]->child_num),
sha256_Update(&ctx, (const uint8_t *)&n, sizeof(uint32_t)); sizeof(uint32_t));
sha256_Final(&ctx, hash); sha256_Update(&ctx, pubnodes[i]->chain_code.bytes, 32);
layoutProgressUpdate(true); sha256_Update(&ctx, pubnodes[i]->public_key.bytes, 33);
return 1; }
sha256_Update(&ctx, (const uint8_t *)&n, sizeof(uint32_t));
sha256_Final(&ctx, hash);
layoutProgressUpdate(true);
return 1;
} }
int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash) int cryptoIdentityFingerprint(const IdentityType *identity, uint8_t *hash) {
{ SHA256_CTX ctx;
SHA256_CTX ctx; sha256_Init(&ctx);
sha256_Init(&ctx); sha256_Update(&ctx, (const uint8_t *)&(identity->index), sizeof(uint32_t));
sha256_Update(&ctx, (const uint8_t *)&(identity->index), sizeof(uint32_t)); if (identity->has_proto && identity->proto[0]) {
if (identity->has_proto && identity->proto[0]) { sha256_Update(&ctx, (const uint8_t *)(identity->proto),
sha256_Update(&ctx, (const uint8_t *)(identity->proto), strlen(identity->proto)); strlen(identity->proto));
sha256_Update(&ctx, (const uint8_t *)"://", 3); sha256_Update(&ctx, (const uint8_t *)"://", 3);
} }
if (identity->has_user && identity->user[0]) { if (identity->has_user && identity->user[0]) {
sha256_Update(&ctx, (const uint8_t *)(identity->user), strlen(identity->user)); sha256_Update(&ctx, (const uint8_t *)(identity->user),
sha256_Update(&ctx, (const uint8_t *)"@", 1); 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)); if (identity->has_host && identity->host[0]) {
} sha256_Update(&ctx, (const uint8_t *)(identity->host),
if (identity->has_port && identity->port[0]) { strlen(identity->host));
sha256_Update(&ctx, (const uint8_t *)":", 1); }
sha256_Update(&ctx, (const uint8_t *)(identity->port), strlen(identity->port)); if (identity->has_port && identity->port[0]) {
} sha256_Update(&ctx, (const uint8_t *)":", 1);
if (identity->has_path && identity->path[0]) { sha256_Update(&ctx, (const uint8_t *)(identity->port),
sha256_Update(&ctx, (const uint8_t *)(identity->path), strlen(identity->path)); strlen(identity->port));
} }
sha256_Final(&ctx, hash); if (identity->has_path && identity->path[0]) {
return 1; sha256_Update(&ctx, (const uint8_t *)(identity->path),
strlen(identity->path));
}
sha256_Final(&ctx, hash);
return 1;
} }

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -19,235 +19,242 @@
#include <libopencm3/stm32/flash.h> #include <libopencm3/stm32/flash.h>
#include "trezor.h"
#include "fsm.h"
#include "messages.h"
#include "bip32.h"
#include "config.h"
#include "coins.h"
#include "debug.h"
#include "transaction.h"
#include "rng.h"
#include "oled.h"
#include "protect.h"
#include "pinmatrix.h"
#include "layout2.h"
#include "address.h" #include "address.h"
#include "base58.h"
#include "ecdsa.h"
#include "reset.h"
#include "recovery.h"
#include "memory.h"
#include "usb.h"
#include "util.h"
#include "signing.h"
#include "aes/aes.h" #include "aes/aes.h"
#include "hmac.h"
#include "crypto.h"
#include "base58.h" #include "base58.h"
#include "bip32.h"
#include "bip39.h" #include "bip39.h"
#include "coins.h"
#include "config.h"
#include "crypto.h"
#include "curves.h" #include "curves.h"
#include "secp256k1.h" #include "debug.h"
#include "ecdsa.h"
#include "ethereum.h" #include "ethereum.h"
#include "fsm.h"
#include "gettext.h"
#include "hmac.h"
#include "layout2.h"
#include "lisk.h"
#include "memory.h"
#include "memzero.h"
#include "messages.h"
#include "messages.pb.h"
#include "nem.h" #include "nem.h"
#include "nem2.h" #include "nem2.h"
#include "oled.h"
#include "pinmatrix.h"
#include "protect.h"
#include "recovery.h"
#include "reset.h"
#include "rfc6979.h" #include "rfc6979.h"
#include "gettext.h" #include "rng.h"
#include "supervise.h" #include "secp256k1.h"
#include "messages.pb.h" #include "signing.h"
#include "stellar.h" #include "stellar.h"
#include "lisk.h" #include "supervise.h"
#include "memzero.h" #include "transaction.h"
#include "trezor.h"
#include "usb.h"
#include "util.h"
// message methods // message methods
static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__ ((aligned)); static uint8_t msg_resp[MSG_OUT_SIZE] __attribute__((aligned));
#define RESP_INIT(TYPE) \ #define RESP_INIT(TYPE) \
TYPE *resp = (TYPE *) (void *) msg_resp; \ TYPE *resp = (TYPE *)(void *)msg_resp; \
_Static_assert(sizeof(msg_resp) >= sizeof(TYPE), #TYPE " is too large"); \ _Static_assert(sizeof(msg_resp) >= sizeof(TYPE), #TYPE " is too large"); \
memzero(resp, sizeof(TYPE)); memzero(resp, sizeof(TYPE));
#define CHECK_INITIALIZED \ #define CHECK_INITIALIZED \
if (!config_isInitialized()) { \ if (!config_isInitialized()) { \
fsm_sendFailure(FailureType_Failure_NotInitialized, NULL); \ fsm_sendFailure(FailureType_Failure_NotInitialized, NULL); \
return; \ return; \
} }
#define CHECK_NOT_INITIALIZED \ #define CHECK_NOT_INITIALIZED \
if (config_isInitialized()) { \ if (config_isInitialized()) { \
fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Device is already initialized. Use Wipe first.")); \ fsm_sendFailure(FailureType_Failure_UnexpectedMessage, \
return; \ _("Device is already initialized. Use Wipe first.")); \
} return; \
}
#define CHECK_PIN \ #define CHECK_PIN \
if (!protectPin(true)) { \ if (!protectPin(true)) { \
layoutHome(); \ layoutHome(); \
return; \ return; \
} }
#define CHECK_PIN_UNCACHED \ #define CHECK_PIN_UNCACHED \
if (!protectPin(false)) { \ if (!protectPin(false)) { \
layoutHome(); \ layoutHome(); \
return; \ return; \
} }
#define CHECK_PARAM(cond, errormsg) \ #define CHECK_PARAM(cond, errormsg) \
if (!(cond)) { \ if (!(cond)) { \
fsm_sendFailure(FailureType_Failure_DataError, (errormsg)); \ fsm_sendFailure(FailureType_Failure_DataError, (errormsg)); \
layoutHome(); \ layoutHome(); \
return; \ return; \
} }
void fsm_sendSuccess(const char *text) void fsm_sendSuccess(const char *text) {
{ RESP_INIT(Success);
RESP_INIT(Success); if (text) {
if (text) { resp->has_message = true;
resp->has_message = true; strlcpy(resp->message, text, sizeof(resp->message));
strlcpy(resp->message, text, sizeof(resp->message)); }
} msg_write(MessageType_MessageType_Success, resp);
msg_write(MessageType_MessageType_Success, resp);
} }
#if DEBUG_LINK #if DEBUG_LINK
void fsm_sendFailureDebug(FailureType code, const char *text, const char *source) void fsm_sendFailureDebug(FailureType code, const char *text,
const char *source)
#else #else
void fsm_sendFailure(FailureType code, const char *text) void fsm_sendFailure(FailureType code, const char *text)
#endif #endif
{ {
if (protectAbortedByCancel) { if (protectAbortedByCancel) {
protectAbortedByCancel = false; protectAbortedByCancel = false;
} }
if (protectAbortedByInitialize) { if (protectAbortedByInitialize) {
fsm_msgInitialize((Initialize *)0); fsm_msgInitialize((Initialize *)0);
protectAbortedByInitialize = false; protectAbortedByInitialize = false;
return; return;
} }
RESP_INIT(Failure); RESP_INIT(Failure);
resp->has_code = true; resp->has_code = true;
resp->code = code; resp->code = code;
if (!text) { if (!text) {
switch (code) { switch (code) {
case FailureType_Failure_UnexpectedMessage: case FailureType_Failure_UnexpectedMessage:
text = _("Unexpected message"); text = _("Unexpected message");
break; break;
case FailureType_Failure_ButtonExpected: case FailureType_Failure_ButtonExpected:
text = _("Button expected"); text = _("Button expected");
break; break;
case FailureType_Failure_DataError: case FailureType_Failure_DataError:
text = _("Data error"); text = _("Data error");
break; break;
case FailureType_Failure_ActionCancelled: case FailureType_Failure_ActionCancelled:
text = _("Action cancelled by user"); text = _("Action cancelled by user");
break; break;
case FailureType_Failure_PinExpected: case FailureType_Failure_PinExpected:
text = _("PIN expected"); text = _("PIN expected");
break; break;
case FailureType_Failure_PinCancelled: case FailureType_Failure_PinCancelled:
text = _("PIN cancelled"); text = _("PIN cancelled");
break; break;
case FailureType_Failure_PinInvalid: case FailureType_Failure_PinInvalid:
text = _("PIN invalid"); text = _("PIN invalid");
break; break;
case FailureType_Failure_InvalidSignature: case FailureType_Failure_InvalidSignature:
text = _("Invalid signature"); text = _("Invalid signature");
break; break;
case FailureType_Failure_ProcessError: case FailureType_Failure_ProcessError:
text = _("Process error"); text = _("Process error");
break; break;
case FailureType_Failure_NotEnoughFunds: case FailureType_Failure_NotEnoughFunds:
text = _("Not enough funds"); text = _("Not enough funds");
break; break;
case FailureType_Failure_NotInitialized: case FailureType_Failure_NotInitialized:
text = _("Device not initialized"); text = _("Device not initialized");
break; break;
case FailureType_Failure_PinMismatch: case FailureType_Failure_PinMismatch:
text = _("PIN mismatch"); text = _("PIN mismatch");
break; break;
case FailureType_Failure_FirmwareError: case FailureType_Failure_FirmwareError:
text = _("Firmware error"); text = _("Firmware error");
break; break;
} }
} }
#if DEBUG_LINK #if DEBUG_LINK
resp->has_message = true; resp->has_message = true;
strlcpy(resp->message, source, sizeof(resp->message)); strlcpy(resp->message, source, sizeof(resp->message));
if (text) { if (text) {
strlcat(resp->message, text, sizeof(resp->message)); strlcat(resp->message, text, sizeof(resp->message));
} }
#else #else
if (text) { if (text) {
resp->has_message = true; resp->has_message = true;
strlcpy(resp->message, text, sizeof(resp->message)); strlcpy(resp->message, text, sizeof(resp->message));
} }
#endif #endif
msg_write(MessageType_MessageType_Failure, resp); msg_write(MessageType_MessageType_Failure, resp);
} }
static const CoinInfo *fsm_getCoin(bool has_name, const char *name) static const CoinInfo *fsm_getCoin(bool has_name, const char *name) {
{ const CoinInfo *coin;
const CoinInfo *coin; if (has_name) {
if (has_name) { coin = coinByName(name);
coin = coinByName(name); } else {
} else { coin = coinByName("Bitcoin");
coin = coinByName("Bitcoin"); }
} if (!coin) {
if (!coin) { fsm_sendFailure(FailureType_Failure_DataError, _("Invalid coin name"));
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid coin name")); layoutHome();
layoutHome(); return 0;
return 0; }
} return coin;
return coin;
} }
static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, size_t address_n_count, uint32_t *fingerprint) static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n,
{ size_t address_n_count,
static CONFIDENTIAL HDNode node; uint32_t *fingerprint) {
if (fingerprint) { static CONFIDENTIAL HDNode node;
*fingerprint = 0; 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")); if (!config_getRootNode(&node, curve, true)) {
layoutHome(); fsm_sendFailure(FailureType_Failure_NotInitialized,
return 0; _("Device not initialized or passphrase request cancelled "
} "or unsupported curve"));
if (!address_n || address_n_count == 0) { layoutHome();
return &node; return 0;
} }
if (hdnode_private_ckd_cached(&node, address_n, address_n_count, fingerprint) == 0) { if (!address_n || address_n_count == 0) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); return &node;
layoutHome(); }
return 0; if (hdnode_private_ckd_cached(&node, address_n, address_n_count,
} fingerprint) == 0) {
return &node; 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,
bool qrcode = false; const uint32_t *address_n, size_t address_n_count,
for (;;) { bool address_is_account) {
const char* display_addr = address; bool qrcode = false;
if (prefixlen && !qrcode) { for (;;) {
display_addr += prefixlen; const char *display_addr = address;
} if (prefixlen && !qrcode) {
layoutAddress(display_addr, desc, qrcode, ignorecase, address_n, address_n_count, address_is_account); display_addr += prefixlen;
if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) { }
return true; layoutAddress(display_addr, desc, qrcode, ignorecase, address_n,
} address_n_count, address_is_account);
if (protectAbortedByCancel || protectAbortedByInitialize) { if (protectButton(ButtonRequestType_ButtonRequest_Address, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); return true;
layoutHome(); }
return false; if (protectAbortedByCancel || protectAbortedByInitialize) {
} fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
qrcode = !qrcode; layoutHome();
} return false;
}
qrcode = !qrcode;
}
} }
#include "fsm_msg_common.h"
#include "fsm_msg_coin.h" #include "fsm_msg_coin.h"
#include "fsm_msg_ethereum.h" #include "fsm_msg_common.h"
#include "fsm_msg_crypto.h" #include "fsm_msg_crypto.h"
#include "fsm_msg_debug.h"
#include "fsm_msg_ethereum.h"
#include "fsm_msg_lisk.h"
#include "fsm_msg_nem.h" #include "fsm_msg_nem.h"
#include "fsm_msg_stellar.h" #include "fsm_msg_stellar.h"
#include "fsm_msg_lisk.h"
#include "fsm_msg_debug.h"

View File

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

View File

@ -17,296 +17,313 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
void fsm_msgGetPublicKey(const GetPublicKey *msg) void fsm_msgGetPublicKey(const GetPublicKey *msg) {
{ RESP_INIT(PublicKey);
RESP_INIT(PublicKey);
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PIN CHECK_PIN
InputScriptType script_type = msg->has_script_type ? msg->script_type : InputScriptType_SPENDADDRESS; InputScriptType script_type =
msg->has_script_type ? msg->script_type : InputScriptType_SPENDADDRESS;
const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name);
if (!coin) return; if (!coin) return;
const char *curve = coin->curve_name; const char *curve = coin->curve_name;
if (msg->has_ecdsa_curve_name) { if (msg->has_ecdsa_curve_name) {
curve = msg->ecdsa_curve_name; curve = msg->ecdsa_curve_name;
} }
uint32_t fingerprint; uint32_t fingerprint;
HDNode *node = node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count, &fingerprint); HDNode *node = node = fsm_getDerivedNode(curve, msg->address_n,
if (!node) return; msg->address_n_count, &fingerprint);
hdnode_fill_public_key(node); if (!node) return;
hdnode_fill_public_key(node);
if (msg->has_show_display && msg->show_display) { if (msg->has_show_display && msg->show_display) {
layoutPublicKey(node->public_key); layoutPublicKey(node->public_key);
if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) { if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
return; return;
} }
} }
resp->has_node = true; resp->has_node = true;
resp->node.depth = node->depth; resp->node.depth = node->depth;
resp->node.fingerprint = fingerprint; resp->node.fingerprint = fingerprint;
resp->node.child_num = node->child_num; resp->node.child_num = node->child_num;
resp->node.chain_code.size = 32; resp->node.chain_code.size = 32;
memcpy(resp->node.chain_code.bytes, node->chain_code, 32); memcpy(resp->node.chain_code.bytes, node->chain_code, 32);
resp->node.has_private_key = false; resp->node.has_private_key = false;
resp->node.has_public_key = true; resp->node.has_public_key = true;
resp->node.public_key.size = 33; resp->node.public_key.size = 33;
memcpy(resp->node.public_key.bytes, node->public_key, 33); memcpy(resp->node.public_key.bytes, node->public_key, 33);
if (node->public_key[0] == 1) { if (node->public_key[0] == 1) {
/* ed25519 public key */ /* ed25519 public key */
resp->node.public_key.bytes[0] = 0; resp->node.public_key.bytes[0] = 0;
} }
resp->has_xpub = true; resp->has_xpub = true;
if (coin->xpub_magic && (script_type == InputScriptType_SPENDADDRESS || script_type == InputScriptType_SPENDMULTISIG)) { if (coin->xpub_magic && (script_type == InputScriptType_SPENDADDRESS ||
hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub, sizeof(resp->xpub)); script_type == InputScriptType_SPENDMULTISIG)) {
} else hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub,
if (coin->has_segwit && coin->xpub_magic_segwit_p2sh && script_type == InputScriptType_SPENDP2SHWITNESS) { sizeof(resp->xpub));
hdnode_serialize_public(node, fingerprint, coin->xpub_magic_segwit_p2sh, resp->xpub, sizeof(resp->xpub)); } else if (coin->has_segwit && coin->xpub_magic_segwit_p2sh &&
} else script_type == InputScriptType_SPENDP2SHWITNESS) {
if (coin->has_segwit && coin->xpub_magic_segwit_native && script_type == InputScriptType_SPENDWITNESS) { hdnode_serialize_public(node, fingerprint, coin->xpub_magic_segwit_p2sh,
hdnode_serialize_public(node, fingerprint, coin->xpub_magic_segwit_native, resp->xpub, sizeof(resp->xpub)); resp->xpub, sizeof(resp->xpub));
} else { } else if (coin->has_segwit && coin->xpub_magic_segwit_native &&
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid combination of coin and script_type")); script_type == InputScriptType_SPENDWITNESS) {
layoutHome(); hdnode_serialize_public(node, fingerprint, coin->xpub_magic_segwit_native,
return; resp->xpub, sizeof(resp->xpub));
} } else {
fsm_sendFailure(FailureType_Failure_DataError,
_("Invalid combination of coin and script_type"));
layoutHome();
return;
}
msg_write(MessageType_MessageType_PublicKey, resp); msg_write(MessageType_MessageType_PublicKey, resp);
layoutHome(); layoutHome();
} }
void fsm_msgSignTx(const SignTx *msg) void fsm_msgSignTx(const SignTx *msg) {
{ CHECK_INITIALIZED
CHECK_INITIALIZED
CHECK_PARAM(msg->inputs_count > 0, _("Transaction must have at least one input")); CHECK_PARAM(msg->inputs_count > 0,
CHECK_PARAM(msg->outputs_count > 0, _("Transaction must have at least one output")); _("Transaction must have at least one input"));
CHECK_PARAM(msg->inputs_count + msg->outputs_count >= msg->inputs_count, _("Value overflow")); CHECK_PARAM(msg->outputs_count > 0,
_("Transaction must have at least one output"));
CHECK_PARAM(msg->inputs_count + msg->outputs_count >= msg->inputs_count,
_("Value overflow"));
CHECK_PIN CHECK_PIN
const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name);
if (!coin) return; if (!coin) return;
const HDNode *node = fsm_getDerivedNode(coin->curve_name, NULL, 0, NULL); const HDNode *node = fsm_getDerivedNode(coin->curve_name, NULL, 0, NULL);
if (!node) return; if (!node) return;
signing_init(msg, coin, node); signing_init(msg, coin, node);
} }
void fsm_msgTxAck(TxAck *msg) void fsm_msgTxAck(TxAck *msg) {
{ CHECK_PARAM(msg->has_tx, _("No transaction provided"));
CHECK_PARAM(msg->has_tx, _("No transaction provided"));
signing_txack(&(msg->tx)); signing_txack(&(msg->tx));
} }
static bool path_mismatched(const CoinInfo *coin, const GetAddress *msg) static bool path_mismatched(const CoinInfo *coin, const GetAddress *msg) {
{ bool mismatch = false;
bool mismatch = false;
// m : no path // m : no path
if (msg->address_n_count == 0) { if (msg->address_n_count == 0) {
return false; return false;
} }
// m/44' : BIP44 Legacy // m/44' : BIP44 Legacy
// m / purpose' / coin_type' / account' / change / address_index // m / purpose' / coin_type' / account' / change / address_index
if (msg->address_n[0] == (0x80000000 + 44)) { if (msg->address_n[0] == (0x80000000 + 44)) {
mismatch |= (msg->script_type != InputScriptType_SPENDADDRESS); mismatch |= (msg->script_type != InputScriptType_SPENDADDRESS);
mismatch |= (msg->address_n_count != 5); mismatch |= (msg->address_n_count != 5);
mismatch |= (msg->address_n[1] != coin->coin_type); mismatch |= (msg->address_n[1] != coin->coin_type);
mismatch |= (msg->address_n[2] & 0x80000000) == 0; mismatch |= (msg->address_n[2] & 0x80000000) == 0;
mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000;
mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000;
return mismatch; return mismatch;
} }
// m/45' - BIP45 Copay Abandoned Multisig P2SH // m/45' - BIP45 Copay Abandoned Multisig P2SH
// m / purpose' / cosigner_index / change / address_index // m / purpose' / cosigner_index / change / address_index
if (msg->address_n[0] == (0x80000000 + 45)) { if (msg->address_n[0] == (0x80000000 + 45)) {
mismatch |= (msg->script_type != InputScriptType_SPENDMULTISIG); mismatch |= (msg->script_type != InputScriptType_SPENDMULTISIG);
mismatch |= (msg->address_n_count != 4); mismatch |= (msg->address_n_count != 4);
mismatch |= (msg->address_n[1] & 0x80000000) == 0x80000000; mismatch |= (msg->address_n[1] & 0x80000000) == 0x80000000;
mismatch |= (msg->address_n[2] & 0x80000000) == 0x80000000; mismatch |= (msg->address_n[2] & 0x80000000) == 0x80000000;
mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000;
return mismatch; return mismatch;
} }
// m/48' - BIP48 Copay Multisig P2SH // m/48' - BIP48 Copay Multisig P2SH
// m / purpose' / coin_type' / account' / change / address_index // m / purpose' / coin_type' / account' / change / address_index
if (msg->address_n[0] == (0x80000000 + 48)) { if (msg->address_n[0] == (0x80000000 + 48)) {
mismatch |= (msg->script_type != InputScriptType_SPENDMULTISIG); mismatch |= (msg->script_type != InputScriptType_SPENDMULTISIG);
mismatch |= (msg->address_n_count != 5); mismatch |= (msg->address_n_count != 5);
mismatch |= (msg->address_n[1] != coin->coin_type); mismatch |= (msg->address_n[1] != coin->coin_type);
mismatch |= (msg->address_n[2] & 0x80000000) == 0; mismatch |= (msg->address_n[2] & 0x80000000) == 0;
mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000;
mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000;
return mismatch; return mismatch;
} }
// m/49' : BIP49 SegWit // m/49' : BIP49 SegWit
// m / purpose' / coin_type' / account' / change / address_index // m / purpose' / coin_type' / account' / change / address_index
if (msg->address_n[0] == (0x80000000 + 49)) { if (msg->address_n[0] == (0x80000000 + 49)) {
mismatch |= (msg->script_type != InputScriptType_SPENDP2SHWITNESS); mismatch |= (msg->script_type != InputScriptType_SPENDP2SHWITNESS);
mismatch |= !coin->has_segwit; mismatch |= !coin->has_segwit;
mismatch |= !coin->has_address_type_p2sh; mismatch |= !coin->has_address_type_p2sh;
mismatch |= (msg->address_n_count != 5); mismatch |= (msg->address_n_count != 5);
mismatch |= (msg->address_n[1] != coin->coin_type); mismatch |= (msg->address_n[1] != coin->coin_type);
mismatch |= (msg->address_n[2] & 0x80000000) == 0; mismatch |= (msg->address_n[2] & 0x80000000) == 0;
mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000;
mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000;
return mismatch; return mismatch;
} }
// m/84' : BIP84 Native SegWit // m/84' : BIP84 Native SegWit
// m / purpose' / coin_type' / account' / change / address_index // m / purpose' / coin_type' / account' / change / address_index
if (msg->address_n[0] == (0x80000000 + 84)) { if (msg->address_n[0] == (0x80000000 + 84)) {
mismatch |= (msg->script_type != InputScriptType_SPENDWITNESS); mismatch |= (msg->script_type != InputScriptType_SPENDWITNESS);
mismatch |= !coin->has_segwit; mismatch |= !coin->has_segwit;
mismatch |= !coin->bech32_prefix; mismatch |= !coin->bech32_prefix;
mismatch |= (msg->address_n_count != 5); mismatch |= (msg->address_n_count != 5);
mismatch |= (msg->address_n[1] != coin->coin_type); mismatch |= (msg->address_n[1] != coin->coin_type);
mismatch |= (msg->address_n[2] & 0x80000000) == 0; mismatch |= (msg->address_n[2] & 0x80000000) == 0;
mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000; mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000;
mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000; mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000;
return mismatch; return mismatch;
} }
return false; return false;
} }
void fsm_msgGetAddress(const GetAddress *msg) void fsm_msgGetAddress(const GetAddress *msg) {
{ RESP_INIT(Address);
RESP_INIT(Address);
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PIN CHECK_PIN
const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name);
if (!coin) return; if (!coin) return;
HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, msg->address_n_count, NULL); HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n,
if (!node) return; msg->address_n_count, NULL);
hdnode_fill_public_key(node); if (!node) return;
hdnode_fill_public_key(node);
char address[MAX_ADDR_SIZE]; char address[MAX_ADDR_SIZE];
if (msg->has_multisig) { // use progress bar only for multisig if (msg->has_multisig) { // use progress bar only for multisig
layoutProgress(_("Computing address"), 0); layoutProgress(_("Computing address"), 0);
} }
if (!compute_address(coin, msg->script_type, node, msg->has_multisig, &msg->multisig, address)) { if (!compute_address(coin, msg->script_type, node, msg->has_multisig,
fsm_sendFailure(FailureType_Failure_DataError, _("Can't encode address")); &msg->multisig, address)) {
layoutHome(); fsm_sendFailure(FailureType_Failure_DataError, _("Can't encode address"));
return; layoutHome();
} return;
}
if (msg->has_show_display && msg->show_display) { if (msg->has_show_display && msg->show_display) {
char desc[20]; char desc[20];
if (msg->has_multisig) { if (msg->has_multisig) {
strlcpy(desc, "Multisig __ of __:", sizeof(desc)); strlcpy(desc, "Multisig __ of __:", sizeof(desc));
const uint32_t m = msg->multisig.m; const uint32_t m = msg->multisig.m;
const uint32_t n = msg->multisig.pubkeys_count; const uint32_t n = msg->multisig.pubkeys_count;
desc[9] = (m < 10) ? ' ': ('0' + (m / 10)); desc[9] = (m < 10) ? ' ' : ('0' + (m / 10));
desc[10] = '0' + (m % 10); desc[10] = '0' + (m % 10);
desc[15] = (n < 10) ? ' ': ('0' + (n / 10)); desc[15] = (n < 10) ? ' ' : ('0' + (n / 10));
desc[16] = '0' + (n % 10); desc[16] = '0' + (n % 10);
} else { } else {
strlcpy(desc, _("Address:"), sizeof(desc)); strlcpy(desc, _("Address:"), sizeof(desc));
} }
bool mismatch = path_mismatched(coin, msg); bool mismatch = path_mismatched(coin, msg);
if (mismatch) { if (mismatch) {
layoutDialogSwipe(&bmp_icon_warning, _("Abort"), _("Continue"), NULL, _("Wrong address path"), _("for selected coin."), NULL, _("Continue at your"), _("own risk!"), NULL); layoutDialogSwipe(&bmp_icon_warning, _("Abort"), _("Continue"), NULL,
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { _("Wrong address path"), _("for selected coin."), NULL,
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); _("Continue at your"), _("own risk!"), NULL);
layoutHome(); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
return; fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
} layoutHome();
} return;
}
}
bool is_cashaddr = coin->cashaddr_prefix != NULL; bool is_cashaddr = coin->cashaddr_prefix != NULL;
bool is_bech32 = msg->script_type == InputScriptType_SPENDWITNESS; bool is_bech32 = msg->script_type == InputScriptType_SPENDWITNESS;
if (!fsm_layoutAddress(address, desc, is_cashaddr || is_bech32, is_cashaddr ? strlen(coin->cashaddr_prefix) + 1 : 0, msg->address_n, msg->address_n_count, false)) { if (!fsm_layoutAddress(address, desc, is_cashaddr || is_bech32,
return; is_cashaddr ? strlen(coin->cashaddr_prefix) + 1 : 0,
} msg->address_n, msg->address_n_count, false)) {
} return;
}
}
strlcpy(resp->address, address, sizeof(resp->address)); strlcpy(resp->address, address, sizeof(resp->address));
msg_write(MessageType_MessageType_Address, resp); msg_write(MessageType_MessageType_Address, resp);
layoutHome(); layoutHome();
} }
void fsm_msgSignMessage(const SignMessage *msg) void fsm_msgSignMessage(const SignMessage *msg) {
{ // CHECK_PARAM(is_ascii_only(msg->message.bytes, msg->message.size), _("Cannot
// CHECK_PARAM(is_ascii_only(msg->message.bytes, msg->message.size), _("Cannot sign non-ASCII strings")); // sign non-ASCII strings"));
RESP_INIT(MessageSignature); RESP_INIT(MessageSignature);
CHECK_INITIALIZED CHECK_INITIALIZED
layoutSignMessage(msg->message.bytes, msg->message.size); layoutSignMessage(msg->message.bytes, msg->message.size);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
return; return;
} }
CHECK_PIN CHECK_PIN
const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name);
if (!coin) return; if (!coin) return;
HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n, msg->address_n_count, NULL); HDNode *node = fsm_getDerivedNode(coin->curve_name, msg->address_n,
if (!node) return; msg->address_n_count, NULL);
if (!node) return;
layoutProgressSwipe(_("Signing"), 0); layoutProgressSwipe(_("Signing"), 0);
if (cryptoMessageSign(coin, node, msg->script_type, msg->message.bytes, msg->message.size, resp->signature.bytes) == 0) { if (cryptoMessageSign(coin, node, msg->script_type, msg->message.bytes,
resp->has_address = true; msg->message.size, resp->signature.bytes) == 0) {
hdnode_fill_public_key(node); resp->has_address = true;
if (!compute_address(coin, msg->script_type, node, false, NULL, resp->address)) { hdnode_fill_public_key(node);
fsm_sendFailure(FailureType_Failure_ProcessError, _("Error computing address")); if (!compute_address(coin, msg->script_type, node, false, NULL,
layoutHome(); resp->address)) {
return; fsm_sendFailure(FailureType_Failure_ProcessError,
} _("Error computing address"));
resp->has_signature = true; layoutHome();
resp->signature.size = 65; return;
msg_write(MessageType_MessageType_MessageSignature, resp); }
} else { resp->has_signature = true;
fsm_sendFailure(FailureType_Failure_ProcessError, _("Error signing message")); resp->signature.size = 65;
} msg_write(MessageType_MessageType_MessageSignature, resp);
layoutHome(); } else {
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_address, _("No address provided")); CHECK_PARAM(msg->has_message, _("No message provided"));
CHECK_PARAM(msg->has_message, _("No message provided"));
const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name); const CoinInfo *coin = fsm_getCoin(msg->has_coin_name, msg->coin_name);
if (!coin) return; if (!coin) return;
layoutProgressSwipe(_("Verifying"), 0); layoutProgressSwipe(_("Verifying"), 0);
if (msg->signature.size == 65 && cryptoMessageVerify(coin, msg->message.bytes, msg->message.size, msg->address, msg->signature.bytes) == 0) { if (msg->signature.size == 65 &&
layoutVerifyAddress(coin, msg->address); cryptoMessageVerify(coin, msg->message.bytes, msg->message.size,
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { msg->address, msg->signature.bytes) == 0) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutVerifyAddress(coin, msg->address);
layoutHome(); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
return; fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
} layoutHome();
layoutVerifyMessage(msg->message.bytes, msg->message.size); return;
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { }
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutVerifyMessage(msg->message.bytes, msg->message.size);
layoutHome(); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
return; fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
} layoutHome();
fsm_sendSuccess(_("Message verified")); return;
} else { }
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); fsm_sendSuccess(_("Message verified"));
} } else {
layoutHome(); fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature"));
}
layoutHome();
} }

View File

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

View File

@ -17,254 +17,283 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
void fsm_msgCipherKeyValue(const CipherKeyValue *msg) void fsm_msgCipherKeyValue(const CipherKeyValue *msg) {
{ CHECK_INITIALIZED
CHECK_INITIALIZED
CHECK_PARAM(msg->has_key, _("No key provided")); CHECK_PARAM(msg->has_key, _("No key provided"));
CHECK_PARAM(msg->has_value, _("No value provided")); CHECK_PARAM(msg->has_value, _("No value provided"));
CHECK_PARAM(msg->value.size % 16 == 0, _("Value length must be a multiple of 16")); CHECK_PARAM(msg->value.size % 16 == 0,
_("Value length must be a multiple of 16"));
CHECK_PIN CHECK_PIN
const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n,
if (!node) return; msg->address_n_count, NULL);
if (!node) return;
bool encrypt = msg->has_encrypt && msg->encrypt; bool encrypt = msg->has_encrypt && msg->encrypt;
bool ask_on_encrypt = msg->has_ask_on_encrypt && msg->ask_on_encrypt; bool ask_on_encrypt = msg->has_ask_on_encrypt && msg->ask_on_encrypt;
bool ask_on_decrypt = msg->has_ask_on_decrypt && msg->ask_on_decrypt; bool ask_on_decrypt = msg->has_ask_on_decrypt && msg->ask_on_decrypt;
if ((encrypt && ask_on_encrypt) || (!encrypt && ask_on_decrypt)) { if ((encrypt && ask_on_encrypt) || (!encrypt && ask_on_decrypt)) {
layoutCipherKeyValue(encrypt, msg->key); layoutCipherKeyValue(encrypt, msg->key);
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
return; return;
} }
} }
uint8_t data[256 + 4]; uint8_t data[256 + 4];
strlcpy((char *)data, msg->key, sizeof(data)); strlcpy((char *)data, msg->key, sizeof(data));
strlcat((char *)data, ask_on_encrypt ? "E1" : "E0", sizeof(data)); strlcat((char *)data, ask_on_encrypt ? "E1" : "E0", sizeof(data));
strlcat((char *)data, ask_on_decrypt ? "D1" : "D0", sizeof(data)); strlcat((char *)data, ask_on_decrypt ? "D1" : "D0", sizeof(data));
hmac_sha512(node->private_key, 32, data, strlen((char *)data), data); hmac_sha512(node->private_key, 32, data, strlen((char *)data), data);
if (msg->iv.size == 16) { if (msg->iv.size == 16) {
// override iv if provided // override iv if provided
memcpy(data + 32, msg->iv.bytes, 16); memcpy(data + 32, msg->iv.bytes, 16);
} }
RESP_INIT(CipheredKeyValue); RESP_INIT(CipheredKeyValue);
if (encrypt) { if (encrypt) {
aes_encrypt_ctx ctx; aes_encrypt_ctx ctx;
aes_encrypt_key256(data, &ctx); aes_encrypt_key256(data, &ctx);
aes_cbc_encrypt(msg->value.bytes, resp->value.bytes, msg->value.size, data + 32, &ctx); aes_cbc_encrypt(msg->value.bytes, resp->value.bytes, msg->value.size,
} else { data + 32, &ctx);
aes_decrypt_ctx ctx; } else {
aes_decrypt_key256(data, &ctx); aes_decrypt_ctx ctx;
aes_cbc_decrypt(msg->value.bytes, resp->value.bytes, msg->value.size, data + 32, &ctx); aes_decrypt_key256(data, &ctx);
} aes_cbc_decrypt(msg->value.bytes, resp->value.bytes, msg->value.size,
resp->has_value = true; data + 32, &ctx);
resp->value.size = msg->value.size; }
msg_write(MessageType_MessageType_CipheredKeyValue, resp); resp->has_value = true;
layoutHome(); resp->value.size = msg->value.size;
msg_write(MessageType_MessageType_CipheredKeyValue, resp);
layoutHome();
} }
void fsm_msgSignIdentity(const SignIdentity *msg) void fsm_msgSignIdentity(const SignIdentity *msg) {
{ RESP_INIT(SignedIdentity);
RESP_INIT(SignedIdentity);
CHECK_INITIALIZED CHECK_INITIALIZED
layoutSignIdentity(&(msg->identity), msg->has_challenge_visual ? msg->challenge_visual : 0); layoutSignIdentity(&(msg->identity),
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { msg->has_challenge_visual ? msg->challenge_visual : 0);
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
layoutHome(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
return; layoutHome();
} return;
}
CHECK_PIN CHECK_PIN
uint8_t hash[32]; uint8_t hash[32];
if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { if (!msg->has_identity ||
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity")); cryptoIdentityFingerprint(&(msg->identity), hash) == 0) {
layoutHome(); fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity"));
return; layoutHome();
} return;
}
uint32_t address_n[5]; uint32_t address_n[5];
address_n[0] = 0x80000000 | 13; address_n[0] = 0x80000000 | 13;
address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | ((uint32_t) hash[ 3] << 24); address_n[1] = 0x80000000 | hash[0] | (hash[1] << 8) | (hash[2] << 16) |
address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | ((uint32_t) hash[ 7] << 24); ((uint32_t)hash[3] << 24);
address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | ((uint32_t) hash[11] << 24); address_n[2] = 0x80000000 | hash[4] | (hash[5] << 8) | (hash[6] << 16) |
address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | ((uint32_t) hash[15] << 24); ((uint32_t)hash[7] << 24);
address_n[3] = 0x80000000 | hash[8] | (hash[9] << 8) | (hash[10] << 16) |
((uint32_t)hash[11] << 24);
address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) |
((uint32_t)hash[15] << 24);
const char *curve = SECP256K1_NAME; const char *curve = SECP256K1_NAME;
if (msg->has_ecdsa_curve_name) { if (msg->has_ecdsa_curve_name) {
curve = msg->ecdsa_curve_name; curve = msg->ecdsa_curve_name;
} }
HDNode *node = fsm_getDerivedNode(curve, address_n, 5, NULL); HDNode *node = fsm_getDerivedNode(curve, address_n, 5, NULL);
if (!node) return; if (!node) return;
bool sign_ssh = msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0); bool sign_ssh =
bool sign_gpg = msg->identity.has_proto && (strcmp(msg->identity.proto, "gpg") == 0); msg->identity.has_proto && (strcmp(msg->identity.proto, "ssh") == 0);
bool sign_gpg =
msg->identity.has_proto && (strcmp(msg->identity.proto, "gpg") == 0);
int result = 0; int result = 0;
layoutProgressSwipe(_("Signing"), 0); layoutProgressSwipe(_("Signing"), 0);
if (sign_ssh) { // SSH does not sign visual challenge if (sign_ssh) { // SSH does not sign visual challenge
result = sshMessageSign(node, msg->challenge_hidden.bytes, msg->challenge_hidden.size, resp->signature.bytes); result = sshMessageSign(node, msg->challenge_hidden.bytes,
} else if (sign_gpg) { // GPG should sign a message digest msg->challenge_hidden.size, resp->signature.bytes);
result = gpgMessageSign(node, msg->challenge_hidden.bytes, msg->challenge_hidden.size, resp->signature.bytes); } else if (sign_gpg) { // GPG should sign a message digest
} else { result = gpgMessageSign(node, msg->challenge_hidden.bytes,
uint8_t digest[64]; msg->challenge_hidden.size, resp->signature.bytes);
sha256_Raw(msg->challenge_hidden.bytes, msg->challenge_hidden.size, digest); } else {
sha256_Raw((const uint8_t *)msg->challenge_visual, strlen(msg->challenge_visual), digest + 32); uint8_t digest[64];
result = cryptoMessageSign(&(coins[0]), node, InputScriptType_SPENDADDRESS, digest, 64, resp->signature.bytes); 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);
}
if (result == 0) { if (result == 0) {
hdnode_fill_public_key(node); hdnode_fill_public_key(node);
if (strcmp(curve, SECP256K1_NAME) != 0) { if (strcmp(curve, SECP256K1_NAME) != 0) {
resp->has_address = false; resp->has_address = false;
} else { } else {
resp->has_address = true; resp->has_address = true;
hdnode_get_address(node, 0x00, resp->address, sizeof(resp->address)); // hardcoded Bitcoin address type hdnode_get_address(
} node, 0x00, resp->address,
resp->has_public_key = true; sizeof(resp->address)); // hardcoded Bitcoin address type
resp->public_key.size = 33; }
memcpy(resp->public_key.bytes, node->public_key, 33); resp->has_public_key = true;
if (node->public_key[0] == 1) { resp->public_key.size = 33;
/* ed25519 public key */ memcpy(resp->public_key.bytes, node->public_key, 33);
resp->public_key.bytes[0] = 0; if (node->public_key[0] == 1) {
} /* ed25519 public key */
resp->has_signature = true; resp->public_key.bytes[0] = 0;
resp->signature.size = 65; }
msg_write(MessageType_MessageType_SignedIdentity, resp); resp->has_signature = true;
} else { resp->signature.size = 65;
fsm_sendFailure(FailureType_Failure_ProcessError, _("Error signing identity")); msg_write(MessageType_MessageType_SignedIdentity, resp);
} } else {
layoutHome(); fsm_sendFailure(FailureType_Failure_ProcessError,
_("Error signing identity"));
}
layoutHome();
} }
void fsm_msgGetECDHSessionKey(const GetECDHSessionKey *msg) void fsm_msgGetECDHSessionKey(const GetECDHSessionKey *msg) {
{ RESP_INIT(ECDHSessionKey);
RESP_INIT(ECDHSessionKey);
CHECK_INITIALIZED CHECK_INITIALIZED
layoutDecryptIdentity(&msg->identity); layoutDecryptIdentity(&msg->identity);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
return; return;
} }
CHECK_PIN CHECK_PIN
uint8_t hash[32]; uint8_t hash[32];
if (!msg->has_identity || cryptoIdentityFingerprint(&(msg->identity), hash) == 0) { if (!msg->has_identity ||
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity")); cryptoIdentityFingerprint(&(msg->identity), hash) == 0) {
layoutHome(); fsm_sendFailure(FailureType_Failure_DataError, _("Invalid identity"));
return; layoutHome();
} return;
}
uint32_t address_n[5]; uint32_t address_n[5];
address_n[0] = 0x80000000 | 17; address_n[0] = 0x80000000 | 17;
address_n[1] = 0x80000000 | hash[ 0] | (hash[ 1] << 8) | (hash[ 2] << 16) | ((uint32_t) hash[ 3] << 24); address_n[1] = 0x80000000 | hash[0] | (hash[1] << 8) | (hash[2] << 16) |
address_n[2] = 0x80000000 | hash[ 4] | (hash[ 5] << 8) | (hash[ 6] << 16) | ((uint32_t) hash[ 7] << 24); ((uint32_t)hash[3] << 24);
address_n[3] = 0x80000000 | hash[ 8] | (hash[ 9] << 8) | (hash[10] << 16) | ((uint32_t) hash[11] << 24); address_n[2] = 0x80000000 | hash[4] | (hash[5] << 8) | (hash[6] << 16) |
address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) | ((uint32_t) hash[15] << 24); ((uint32_t)hash[7] << 24);
address_n[3] = 0x80000000 | hash[8] | (hash[9] << 8) | (hash[10] << 16) |
((uint32_t)hash[11] << 24);
address_n[4] = 0x80000000 | hash[12] | (hash[13] << 8) | (hash[14] << 16) |
((uint32_t)hash[15] << 24);
const char *curve = SECP256K1_NAME; const char *curve = SECP256K1_NAME;
if (msg->has_ecdsa_curve_name) { if (msg->has_ecdsa_curve_name) {
curve = msg->ecdsa_curve_name; curve = msg->ecdsa_curve_name;
} }
const HDNode *node = fsm_getDerivedNode(curve, address_n, 5, NULL); const HDNode *node = fsm_getDerivedNode(curve, address_n, 5, NULL);
if (!node) return; if (!node) return;
int result_size = 0; int result_size = 0;
if (hdnode_get_shared_key(node, msg->peer_public_key.bytes, resp->session_key.bytes, &result_size) == 0) { if (hdnode_get_shared_key(node, msg->peer_public_key.bytes,
resp->has_session_key = true; resp->session_key.bytes, &result_size) == 0) {
resp->session_key.size = result_size; resp->has_session_key = true;
msg_write(MessageType_MessageType_ECDHSessionKey, resp); resp->session_key.size = result_size;
} else { msg_write(MessageType_MessageType_ECDHSessionKey, resp);
fsm_sendFailure(FailureType_Failure_ProcessError, _("Error getting ECDH session key")); } else {
} fsm_sendFailure(FailureType_Failure_ProcessError,
layoutHome(); _("Error getting ECDH session key"));
}
layoutHome();
} }
void fsm_msgCosiCommit(const CosiCommit *msg) void fsm_msgCosiCommit(const CosiCommit *msg) {
{ RESP_INIT(CosiCommitment);
RESP_INIT(CosiCommitment);
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PARAM(msg->has_data, _("No data provided")); CHECK_PARAM(msg->has_data, _("No data provided"));
layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes, msg->data.size, false); layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes,
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { msg->data.size, false);
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
layoutHome(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
return; layoutHome();
} return;
}
CHECK_PIN CHECK_PIN
const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n,
if (!node) return; msg->address_n_count, NULL);
if (!node) return;
uint8_t nonce[32]; uint8_t nonce[32];
sha256_Raw(msg->data.bytes, msg->data.size, nonce); sha256_Raw(msg->data.bytes, msg->data.size, nonce);
rfc6979_state rng; rfc6979_state rng;
init_rfc6979(node->private_key, nonce, &rng); init_rfc6979(node->private_key, nonce, &rng);
generate_rfc6979(nonce, &rng); generate_rfc6979(nonce, &rng);
resp->has_commitment = true; resp->has_commitment = true;
resp->has_pubkey = true; resp->has_pubkey = true;
resp->commitment.size = 32; resp->commitment.size = 32;
resp->pubkey.size = 32; resp->pubkey.size = 32;
ed25519_publickey(nonce, resp->commitment.bytes); ed25519_publickey(nonce, resp->commitment.bytes);
ed25519_publickey(node->private_key, resp->pubkey.bytes); ed25519_publickey(node->private_key, resp->pubkey.bytes);
msg_write(MessageType_MessageType_CosiCommitment, resp); msg_write(MessageType_MessageType_CosiCommitment, resp);
layoutHome(); layoutHome();
} }
void fsm_msgCosiSign(const CosiSign *msg) void fsm_msgCosiSign(const CosiSign *msg) {
{ RESP_INIT(CosiSignature);
RESP_INIT(CosiSignature);
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PARAM(msg->has_data, _("No data provided")); CHECK_PARAM(msg->has_data, _("No data provided"));
CHECK_PARAM(msg->has_global_commitment && msg->global_commitment.size == 32, _("Invalid global commitment")); CHECK_PARAM(msg->has_global_commitment && msg->global_commitment.size == 32,
CHECK_PARAM(msg->has_global_pubkey && msg->global_pubkey.size == 32, _("Invalid global pubkey")); _("Invalid global commitment"));
CHECK_PARAM(msg->has_global_pubkey && msg->global_pubkey.size == 32,
_("Invalid global pubkey"));
layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes, msg->data.size, true); layoutCosiCommitSign(msg->address_n, msg->address_n_count, msg->data.bytes,
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { msg->data.size, true);
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
layoutHome(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
return; layoutHome();
} return;
}
CHECK_PIN CHECK_PIN
const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); const HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n,
if (!node) return; msg->address_n_count, NULL);
if (!node) return;
uint8_t nonce[32]; uint8_t nonce[32];
sha256_Raw(msg->data.bytes, msg->data.size, nonce); sha256_Raw(msg->data.bytes, msg->data.size, nonce);
rfc6979_state rng; rfc6979_state rng;
init_rfc6979(node->private_key, nonce, &rng); init_rfc6979(node->private_key, nonce, &rng);
generate_rfc6979(nonce, &rng); generate_rfc6979(nonce, &rng);
resp->has_signature = true; resp->has_signature = true;
resp->signature.size = 32; resp->signature.size = 32;
ed25519_cosi_sign(msg->data.bytes, msg->data.size, node->private_key, nonce, msg->global_commitment.bytes, msg->global_pubkey.bytes, resp->signature.bytes); ed25519_cosi_sign(msg->data.bytes, msg->data.size, node->private_key, nonce,
msg->global_commitment.bytes, msg->global_pubkey.bytes,
resp->signature.bytes);
msg_write(MessageType_MessageType_CosiSignature, resp); msg_write(MessageType_MessageType_CosiSignature, resp);
layoutHome(); layoutHome();
} }

View File

@ -19,89 +19,85 @@
#if DEBUG_LINK #if DEBUG_LINK
void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) void fsm_msgDebugLinkGetState(const DebugLinkGetState *msg) {
{ (void)msg;
(void)msg;
// Do not use RESP_INIT because it clears msg_resp, but another message // Do not use RESP_INIT because it clears msg_resp, but another message
// might be being handled // might be being handled
DebugLinkState resp; DebugLinkState resp;
memzero(&resp, sizeof(resp)); memzero(&resp, sizeof(resp));
resp.has_layout = true; resp.has_layout = true;
resp.layout.size = OLED_BUFSIZE; resp.layout.size = OLED_BUFSIZE;
memcpy(resp.layout.bytes, oledGetBuffer(), OLED_BUFSIZE); memcpy(resp.layout.bytes, oledGetBuffer(), OLED_BUFSIZE);
resp.has_pin = config_getPin(resp.pin, sizeof(resp.pin)); resp.has_pin = config_getPin(resp.pin, sizeof(resp.pin));
resp.has_matrix = true; resp.has_matrix = true;
strlcpy(resp.matrix, pinmatrix_get(), sizeof(resp.matrix)); strlcpy(resp.matrix, pinmatrix_get(), sizeof(resp.matrix));
resp.has_reset_entropy = true; resp.has_reset_entropy = true;
resp.reset_entropy.size = reset_get_int_entropy(resp.reset_entropy.bytes); resp.reset_entropy.size = reset_get_int_entropy(resp.reset_entropy.bytes);
resp.has_reset_word = true; resp.has_reset_word = true;
strlcpy(resp.reset_word, reset_get_word(), sizeof(resp.reset_word)); strlcpy(resp.reset_word, reset_get_word(), sizeof(resp.reset_word));
resp.has_recovery_fake_word = true; resp.has_recovery_fake_word = true;
strlcpy(resp.recovery_fake_word, recovery_get_fake_word(), sizeof(resp.recovery_fake_word)); strlcpy(resp.recovery_fake_word, recovery_get_fake_word(),
sizeof(resp.recovery_fake_word));
resp.has_recovery_word_pos = true; resp.has_recovery_word_pos = true;
resp.recovery_word_pos = recovery_get_word_pos(); resp.recovery_word_pos = recovery_get_word_pos();
resp.has_mnemonic_secret = config_getMnemonicBytes(resp.mnemonic_secret.bytes, sizeof(resp.mnemonic_secret.bytes), &resp.mnemonic_secret.size); resp.has_mnemonic_secret = config_getMnemonicBytes(
resp.mnemonic_type = 0; // BIP-39 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_node = config_dumpNode(&(resp.node));
resp.has_passphrase_protection = config_getPassphraseProtection(&(resp.passphrase_protection)); resp.has_passphrase_protection =
config_getPassphraseProtection(&(resp.passphrase_protection));
msg_debug_write(MessageType_MessageType_DebugLinkState, &resp); msg_debug_write(MessageType_MessageType_DebugLinkState, &resp);
} }
void fsm_msgDebugLinkStop(const DebugLinkStop *msg) void fsm_msgDebugLinkStop(const DebugLinkStop *msg) { (void)msg; }
{
(void)msg; void fsm_msgDebugLinkMemoryRead(const DebugLinkMemoryRead *msg) {
RESP_INIT(DebugLinkMemory);
uint32_t length = 1024;
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_msgDebugLinkMemoryRead(const DebugLinkMemoryRead *msg) void fsm_msgDebugLinkMemoryWrite(const DebugLinkMemoryWrite *msg) {
{ uint32_t length = msg->memory.size;
RESP_INIT(DebugLinkMemory); if (msg->flash) {
svc_flash_unlock();
uint32_t length = 1024; svc_flash_program(FLASH_CR_PROGRAM_X32);
if (msg->has_length && msg->length < length) for (uint32_t i = 0; i < length; i += 4) {
length = msg->length; uint32_t word;
resp->has_memory = true; memcpy(&word, msg->memory.bytes + i, 4);
memcpy(resp->memory.bytes, FLASH_PTR(msg->address), length); flash_write32(msg->address + i, word);
resp->memory.size = length; }
msg_debug_write(MessageType_MessageType_DebugLinkMemory, resp); uint32_t dummy = svc_flash_lock();
} (void)dummy;
} else {
void fsm_msgDebugLinkMemoryWrite(const DebugLinkMemoryWrite *msg)
{
uint32_t length = msg->memory.size;
if (msg->flash) {
svc_flash_unlock();
svc_flash_program(FLASH_CR_PROGRAM_X32);
for (uint32_t i = 0; i < length; i += 4) {
uint32_t word;
memcpy(&word, msg->memory.bytes + i, 4);
flash_write32(msg->address + i, word);
}
uint32_t dummy = svc_flash_lock();
(void)dummy;
} else {
#if !EMULATOR #if !EMULATOR
memcpy((void *) msg->address, msg->memory.bytes, length); memcpy((void *)msg->address, msg->memory.bytes, length);
#endif #endif
} }
} }
void fsm_msgDebugLinkFlashErase(const DebugLinkFlashErase *msg) void fsm_msgDebugLinkFlashErase(const DebugLinkFlashErase *msg) {
{ svc_flash_unlock();
svc_flash_unlock(); svc_flash_erase_sector(msg->sector);
svc_flash_erase_sector(msg->sector); uint32_t dummy = svc_flash_lock();
uint32_t dummy = svc_flash_lock(); (void)dummy;
(void)dummy;
} }
#endif #endif

View File

@ -17,163 +17,169 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
void fsm_msgEthereumGetPublicKey(const EthereumGetPublicKey *msg) void fsm_msgEthereumGetPublicKey(const EthereumGetPublicKey *msg) {
{ RESP_INIT(EthereumPublicKey);
RESP_INIT(EthereumPublicKey);
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PIN CHECK_PIN
// we use Bitcoin-like format for ETH // we use Bitcoin-like format for ETH
const CoinInfo *coin = fsm_getCoin(true, "Bitcoin"); const CoinInfo *coin = fsm_getCoin(true, "Bitcoin");
if (!coin) return; if (!coin) return;
const char *curve = coin->curve_name; const char *curve = coin->curve_name;
uint32_t fingerprint; uint32_t fingerprint;
HDNode *node = node = fsm_getDerivedNode(curve, msg->address_n, msg->address_n_count, &fingerprint); HDNode *node = node = fsm_getDerivedNode(curve, msg->address_n,
if (!node) return; msg->address_n_count, &fingerprint);
hdnode_fill_public_key(node); if (!node) return;
hdnode_fill_public_key(node);
if (msg->has_show_display && msg->show_display) { if (msg->has_show_display && msg->show_display) {
layoutPublicKey(node->public_key); layoutPublicKey(node->public_key);
if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) { if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
return; return;
} }
} }
resp->has_node = true; resp->has_node = true;
resp->node.depth = node->depth; resp->node.depth = node->depth;
resp->node.fingerprint = fingerprint; resp->node.fingerprint = fingerprint;
resp->node.child_num = node->child_num; resp->node.child_num = node->child_num;
resp->node.chain_code.size = 32; resp->node.chain_code.size = 32;
memcpy(resp->node.chain_code.bytes, node->chain_code, 32); memcpy(resp->node.chain_code.bytes, node->chain_code, 32);
resp->node.has_private_key = false; resp->node.has_private_key = false;
resp->node.has_public_key = true; resp->node.has_public_key = true;
resp->node.public_key.size = 33; resp->node.public_key.size = 33;
memcpy(resp->node.public_key.bytes, node->public_key, 33); memcpy(resp->node.public_key.bytes, node->public_key, 33);
resp->has_xpub = true; resp->has_xpub = true;
hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub, sizeof(resp->xpub)); hdnode_serialize_public(node, fingerprint, coin->xpub_magic, resp->xpub,
sizeof(resp->xpub));
msg_write(MessageType_MessageType_EthereumPublicKey, resp); msg_write(MessageType_MessageType_EthereumPublicKey, resp);
layoutHome(); layoutHome();
} }
void fsm_msgEthereumSignTx(EthereumSignTx *msg) void fsm_msgEthereumSignTx(EthereumSignTx *msg) {
{ CHECK_INITIALIZED
CHECK_INITIALIZED
CHECK_PIN CHECK_PIN
const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n,
if (!node) return; msg->address_n_count, NULL);
if (!node) return;
ethereum_signing_init(msg, node); ethereum_signing_init(msg, node);
} }
void fsm_msgEthereumTxAck(const EthereumTxAck *msg) void fsm_msgEthereumTxAck(const EthereumTxAck *msg) {
{ ethereum_signing_txack(msg);
ethereum_signing_txack(msg);
} }
void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg) void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg) {
{ RESP_INIT(EthereumAddress);
RESP_INIT(EthereumAddress);
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PIN CHECK_PIN
const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n,
if (!node) return; msg->address_n_count, NULL);
if (!node) return;
uint8_t pubkeyhash[20]; uint8_t pubkeyhash[20];
if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash)) if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash)) return;
return;
uint32_t slip44 = (msg->address_n_count > 1) ? (msg->address_n[1] & 0x7fffffff) : 0; uint32_t slip44 =
bool rskip60 = false; (msg->address_n_count > 1) ? (msg->address_n[1] & 0x7fffffff) : 0;
uint32_t chain_id = 0; bool rskip60 = false;
// constants from trezor-common/defs/ethereum/networks.json uint32_t chain_id = 0;
switch (slip44) { // constants from trezor-common/defs/ethereum/networks.json
case 137: rskip60 = true; chain_id = 30; break; switch (slip44) {
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; resp->has_address = true;
resp->address[0] = '0'; resp->address[0] = '0';
resp->address[1] = 'x'; resp->address[1] = 'x';
ethereum_address_checksum(pubkeyhash, resp->address + 2, rskip60, chain_id); ethereum_address_checksum(pubkeyhash, resp->address + 2, rskip60, chain_id);
// ethereum_address_checksum adds trailing zero // ethereum_address_checksum adds trailing zero
if (msg->has_show_display && msg->show_display) { if (msg->has_show_display && msg->show_display) {
char desc[16]; char desc[16];
strlcpy(desc, "Address:", sizeof(desc)); strlcpy(desc, "Address:", sizeof(desc));
if (!fsm_layoutAddress(resp->address, desc, false, 0, msg->address_n, msg->address_n_count, true)) { if (!fsm_layoutAddress(resp->address, desc, false, 0, msg->address_n,
return; msg->address_n_count, true)) {
} return;
} }
}
msg_write(MessageType_MessageType_EthereumAddress, resp); msg_write(MessageType_MessageType_EthereumAddress, resp);
layoutHome(); layoutHome();
} }
void fsm_msgEthereumSignMessage(const EthereumSignMessage *msg) void fsm_msgEthereumSignMessage(const EthereumSignMessage *msg) {
{ RESP_INIT(EthereumMessageSignature);
RESP_INIT(EthereumMessageSignature);
CHECK_INITIALIZED CHECK_INITIALIZED
layoutSignMessage(msg->message.bytes, msg->message.size); layoutSignMessage(msg->message.bytes, msg->message.size);
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
return; return;
} }
CHECK_PIN CHECK_PIN
const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n,
if (!node) return; msg->address_n_count, NULL);
if (!node) return;
ethereum_message_sign(msg, node, resp); ethereum_message_sign(msg, node, resp);
layoutHome(); layoutHome();
} }
void fsm_msgEthereumVerifyMessage(const EthereumVerifyMessage *msg) void fsm_msgEthereumVerifyMessage(const EthereumVerifyMessage *msg) {
{ CHECK_PARAM(msg->has_address, _("No address provided"));
CHECK_PARAM(msg->has_address, _("No address provided")); CHECK_PARAM(msg->has_message, _("No message provided"));
CHECK_PARAM(msg->has_message, _("No message provided"));
if (ethereum_message_verify(msg) != 0) { if (ethereum_message_verify(msg) != 0) {
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature"));
return; return;
} }
uint8_t pubkeyhash[20]; uint8_t pubkeyhash[20];
if (!ethereum_parse(msg->address, pubkeyhash)) { if (!ethereum_parse(msg->address, pubkeyhash)) {
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid address")); fsm_sendFailure(FailureType_Failure_DataError, _("Invalid address"));
return; return;
} }
layoutVerifyAddress(NULL, msg->address); layoutVerifyAddress(NULL, msg->address);
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
return; return;
} }
layoutVerifyMessage(msg->message.bytes, msg->message.size); layoutVerifyMessage(msg->message.bytes, msg->message.size);
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
return; return;
} }
fsm_sendSuccess(_("Message verified")); fsm_sendSuccess(_("Message verified"));
layoutHome(); layoutHome();
} }

View File

@ -17,126 +17,128 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
void fsm_msgLiskGetAddress(const LiskGetAddress *msg) void fsm_msgLiskGetAddress(const LiskGetAddress *msg) {
{ CHECK_INITIALIZED
CHECK_INITIALIZED
CHECK_PIN CHECK_PIN
RESP_INIT(LiskAddress); RESP_INIT(LiskAddress);
HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n,
if (!node) return; msg->address_n_count, NULL);
if (!node) return;
resp->has_address = true; resp->has_address = true;
hdnode_fill_public_key(node); hdnode_fill_public_key(node);
lisk_get_address_from_public_key(&node->public_key[1], resp->address); lisk_get_address_from_public_key(&node->public_key[1], resp->address);
if (msg->has_show_display && msg->show_display) { if (msg->has_show_display && msg->show_display) {
if (!fsm_layoutAddress(resp->address, _("Address:"), true, 0, msg->address_n, msg->address_n_count, false)) { if (!fsm_layoutAddress(resp->address, _("Address:"), true, 0,
return; msg->address_n, msg->address_n_count, false)) {
} return;
} }
}
msg_write(MessageType_MessageType_LiskAddress, resp); msg_write(MessageType_MessageType_LiskAddress, resp);
layoutHome(); layoutHome();
} }
void fsm_msgLiskGetPublicKey(const LiskGetPublicKey *msg) void fsm_msgLiskGetPublicKey(const LiskGetPublicKey *msg) {
{ CHECK_INITIALIZED
CHECK_INITIALIZED
CHECK_PIN CHECK_PIN
RESP_INIT(LiskPublicKey); RESP_INIT(LiskPublicKey);
HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n,
if (!node) return; msg->address_n_count, NULL);
if (!node) return;
hdnode_fill_public_key(node); hdnode_fill_public_key(node);
resp->has_public_key = true; resp->has_public_key = true;
resp->public_key.size = 32; resp->public_key.size = 32;
if (msg->has_show_display && msg->show_display) { if (msg->has_show_display && msg->show_display) {
layoutLiskPublicKey(&node->public_key[1]); layoutLiskPublicKey(&node->public_key[1]);
if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) { if (!protectButton(ButtonRequestType_ButtonRequest_PublicKey, true)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
return; return;
} }
} }
memcpy(&resp->public_key.bytes, &node->public_key[1], sizeof(resp->public_key.bytes)); memcpy(&resp->public_key.bytes, &node->public_key[1],
sizeof(resp->public_key.bytes));
msg_write(MessageType_MessageType_LiskPublicKey, resp); msg_write(MessageType_MessageType_LiskPublicKey, resp);
layoutHome(); layoutHome();
} }
void fsm_msgLiskSignMessage(const LiskSignMessage *msg) void fsm_msgLiskSignMessage(const LiskSignMessage *msg) {
{ CHECK_INITIALIZED
CHECK_INITIALIZED
CHECK_PIN CHECK_PIN
RESP_INIT(LiskMessageSignature); RESP_INIT(LiskMessageSignature);
HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n,
if (!node) return; msg->address_n_count, NULL);
if (!node) return;
hdnode_fill_public_key(node); hdnode_fill_public_key(node);
lisk_sign_message(node, msg, resp); lisk_sign_message(node, msg, resp);
msg_write(MessageType_MessageType_LiskMessageSignature, resp); msg_write(MessageType_MessageType_LiskMessageSignature, resp);
layoutHome(); layoutHome();
} }
void fsm_msgLiskVerifyMessage(const LiskVerifyMessage *msg) void fsm_msgLiskVerifyMessage(const LiskVerifyMessage *msg) {
{ if (lisk_verify_message(msg)) {
if (lisk_verify_message(msg)) { char address[MAX_LISK_ADDRESS_SIZE];
char address[MAX_LISK_ADDRESS_SIZE]; lisk_get_address_from_public_key((const uint8_t *)&msg->public_key,
lisk_get_address_from_public_key((const uint8_t*)&msg->public_key, address); address);
layoutLiskVerifyAddress(address); layoutLiskVerifyAddress(address);
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
return; return;
} }
layoutVerifyMessage(msg->message.bytes, msg->message.size); layoutVerifyMessage(msg->message.bytes, msg->message.size);
if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
layoutHome(); layoutHome();
return; return;
} }
fsm_sendSuccess(_("Message verified")); fsm_sendSuccess(_("Message verified"));
} else { } else {
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature")); fsm_sendFailure(FailureType_Failure_DataError, _("Invalid signature"));
} }
layoutHome(); layoutHome();
} }
void fsm_msgLiskSignTx(LiskSignTx *msg) void fsm_msgLiskSignTx(LiskSignTx *msg) {
{ CHECK_INITIALIZED
CHECK_INITIALIZED
CHECK_PIN CHECK_PIN
RESP_INIT(LiskSignedTx); RESP_INIT(LiskSignedTx);
HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n, msg->address_n_count, NULL); HDNode *node = fsm_getDerivedNode(ED25519_NAME, msg->address_n,
if (!node) return; msg->address_n_count, NULL);
if (!node) return;
hdnode_fill_public_key(node); hdnode_fill_public_key(node);
lisk_sign_tx(node, msg, resp); lisk_sign_tx(node, msg, resp);
msg_write(MessageType_MessageType_LiskSignedTx, resp); msg_write(MessageType_MessageType_LiskSignedTx, resp);
layoutHome(); layoutHome();
} }

View File

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

View File

@ -17,271 +17,258 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
void fsm_msgStellarGetAddress(const StellarGetAddress *msg) void fsm_msgStellarGetAddress(const StellarGetAddress *msg) {
{ RESP_INIT(StellarAddress);
RESP_INIT(StellarAddress);
CHECK_INITIALIZED CHECK_INITIALIZED
CHECK_PIN CHECK_PIN
const HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); const HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count);
if (!node) { if (!node) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); fsm_sendFailure(FailureType_Failure_ProcessError,
return; _("Failed to derive private key"));
} return;
}
if (msg->has_show_display && msg->show_display) { if (msg->has_show_display && msg->show_display) {
const char **str_addr_rows = stellar_lineBreakAddress(node->public_key + 1); const char **str_addr_rows = stellar_lineBreakAddress(node->public_key + 1);
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), _("Share public account ID?"), layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"),
str_addr_rows[0], _("Share public account ID?"), str_addr_rows[0],
str_addr_rows[1], str_addr_rows[1], str_addr_rows[2], NULL, NULL, NULL);
str_addr_rows[2], if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
NULL, fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
NULL, NULL layoutHome();
); return;
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { }
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); }
layoutHome();
return;
}
}
resp->has_address = true; resp->has_address = true;
stellar_publicAddressAsStr(node->public_key + 1, resp->address, sizeof(resp->address)); stellar_publicAddressAsStr(node->public_key + 1, resp->address,
sizeof(resp->address));
msg_write(MessageType_MessageType_StellarAddress, resp); msg_write(MessageType_MessageType_StellarAddress, resp);
layoutHome(); layoutHome();
} }
void fsm_msgStellarSignTx(const StellarSignTx *msg) void fsm_msgStellarSignTx(const StellarSignTx *msg) {
{ CHECK_INITIALIZED
CHECK_INITIALIZED CHECK_PIN
CHECK_PIN
if (!stellar_signingInit(msg)) { if (!stellar_signingInit(msg)) {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to derive private key")); fsm_sendFailure(FailureType_Failure_ProcessError,
layoutHome(); _("Failed to derive private key"));
return; layoutHome();
} return;
}
// Confirm transaction basics // Confirm transaction basics
stellar_layoutTransactionSummary(msg); stellar_layoutTransactionSummary(msg);
// Respond with a request for the first operation // Respond with a request for the first operation
RESP_INIT(StellarTxOpRequest); RESP_INIT(StellarTxOpRequest);
msg_write(MessageType_MessageType_StellarTxOpRequest, resp); msg_write(MessageType_MessageType_StellarTxOpRequest, resp);
} }
void fsm_msgStellarCreateAccountOp(const StellarCreateAccountOp *msg) void fsm_msgStellarCreateAccountOp(const StellarCreateAccountOp *msg) {
{ if (!stellar_confirmCreateAccountOp(msg)) return;
if (!stellar_confirmCreateAccountOp(msg)) return;
if (stellar_allOperationsConfirmed()) { if (stellar_allOperationsConfirmed()) {
RESP_INIT(StellarSignedTx); RESP_INIT(StellarSignedTx);
stellar_fillSignedTx(resp); stellar_fillSignedTx(resp);
msg_write(MessageType_MessageType_StellarSignedTx, resp); msg_write(MessageType_MessageType_StellarSignedTx, resp);
layoutHome(); layoutHome();
} }
// Request the next operation to sign // Request the next operation to sign
else { else {
RESP_INIT(StellarTxOpRequest); RESP_INIT(StellarTxOpRequest);
msg_write(MessageType_MessageType_StellarTxOpRequest, resp); msg_write(MessageType_MessageType_StellarTxOpRequest, resp);
} }
} }
void fsm_msgStellarPaymentOp(const StellarPaymentOp *msg) void fsm_msgStellarPaymentOp(const StellarPaymentOp *msg) {
{ // This will display additional dialogs to the user
// This will display additional dialogs to the user if (!stellar_confirmPaymentOp(msg)) return;
if (!stellar_confirmPaymentOp(msg)) return;
// Last operation was confirmed, send a StellarSignedTx // Last operation was confirmed, send a StellarSignedTx
if (stellar_allOperationsConfirmed()) { if (stellar_allOperationsConfirmed()) {
RESP_INIT(StellarSignedTx); RESP_INIT(StellarSignedTx);
stellar_fillSignedTx(resp); stellar_fillSignedTx(resp);
msg_write(MessageType_MessageType_StellarSignedTx, resp); msg_write(MessageType_MessageType_StellarSignedTx, resp);
layoutHome(); layoutHome();
} }
// Request the next operation to sign // Request the next operation to sign
else { else {
RESP_INIT(StellarTxOpRequest); RESP_INIT(StellarTxOpRequest);
msg_write(MessageType_MessageType_StellarTxOpRequest, resp); msg_write(MessageType_MessageType_StellarTxOpRequest, resp);
} }
} }
void fsm_msgStellarPathPaymentOp(const StellarPathPaymentOp *msg) void fsm_msgStellarPathPaymentOp(const StellarPathPaymentOp *msg) {
{ if (!stellar_confirmPathPaymentOp(msg)) return;
if (!stellar_confirmPathPaymentOp(msg)) return;
if (stellar_allOperationsConfirmed()) { if (stellar_allOperationsConfirmed()) {
RESP_INIT(StellarSignedTx); RESP_INIT(StellarSignedTx);
stellar_fillSignedTx(resp); stellar_fillSignedTx(resp);
msg_write(MessageType_MessageType_StellarSignedTx, resp); msg_write(MessageType_MessageType_StellarSignedTx, resp);
layoutHome(); layoutHome();
} }
// Request the next operation to sign // Request the next operation to sign
else { else {
RESP_INIT(StellarTxOpRequest); RESP_INIT(StellarTxOpRequest);
msg_write(MessageType_MessageType_StellarTxOpRequest, resp); msg_write(MessageType_MessageType_StellarTxOpRequest, resp);
} }
} }
void fsm_msgStellarManageOfferOp(const StellarManageOfferOp *msg) void fsm_msgStellarManageOfferOp(const StellarManageOfferOp *msg) {
{ if (!stellar_confirmManageOfferOp(msg)) return;
if (!stellar_confirmManageOfferOp(msg)) return;
if (stellar_allOperationsConfirmed()) { if (stellar_allOperationsConfirmed()) {
RESP_INIT(StellarSignedTx); RESP_INIT(StellarSignedTx);
stellar_fillSignedTx(resp); stellar_fillSignedTx(resp);
msg_write(MessageType_MessageType_StellarSignedTx, resp); msg_write(MessageType_MessageType_StellarSignedTx, resp);
layoutHome(); layoutHome();
} }
// Request the next operation to sign // Request the next operation to sign
else { else {
RESP_INIT(StellarTxOpRequest); RESP_INIT(StellarTxOpRequest);
msg_write(MessageType_MessageType_StellarTxOpRequest, resp); msg_write(MessageType_MessageType_StellarTxOpRequest, resp);
} }
} }
void fsm_msgStellarCreatePassiveOfferOp(const StellarCreatePassiveOfferOp *msg) void fsm_msgStellarCreatePassiveOfferOp(
{ const StellarCreatePassiveOfferOp *msg) {
if (!stellar_confirmCreatePassiveOfferOp(msg)) return; if (!stellar_confirmCreatePassiveOfferOp(msg)) return;
if (stellar_allOperationsConfirmed()) { if (stellar_allOperationsConfirmed()) {
RESP_INIT(StellarSignedTx); RESP_INIT(StellarSignedTx);
stellar_fillSignedTx(resp); stellar_fillSignedTx(resp);
msg_write(MessageType_MessageType_StellarSignedTx, resp); msg_write(MessageType_MessageType_StellarSignedTx, resp);
layoutHome(); layoutHome();
} }
// Request the next operation to sign // Request the next operation to sign
else { else {
RESP_INIT(StellarTxOpRequest); RESP_INIT(StellarTxOpRequest);
msg_write(MessageType_MessageType_StellarTxOpRequest, resp); msg_write(MessageType_MessageType_StellarTxOpRequest, resp);
} }
} }
void fsm_msgStellarSetOptionsOp(const StellarSetOptionsOp *msg) void fsm_msgStellarSetOptionsOp(const StellarSetOptionsOp *msg) {
{ if (!stellar_confirmSetOptionsOp(msg)) return;
if (!stellar_confirmSetOptionsOp(msg)) return;
if (stellar_allOperationsConfirmed()) { if (stellar_allOperationsConfirmed()) {
RESP_INIT(StellarSignedTx); RESP_INIT(StellarSignedTx);
stellar_fillSignedTx(resp); stellar_fillSignedTx(resp);
msg_write(MessageType_MessageType_StellarSignedTx, resp); msg_write(MessageType_MessageType_StellarSignedTx, resp);
layoutHome(); layoutHome();
} }
// Request the next operation to sign // Request the next operation to sign
else { else {
RESP_INIT(StellarTxOpRequest); RESP_INIT(StellarTxOpRequest);
msg_write(MessageType_MessageType_StellarTxOpRequest, resp); msg_write(MessageType_MessageType_StellarTxOpRequest, resp);
} }
} }
void fsm_msgStellarChangeTrustOp(const StellarChangeTrustOp *msg) void fsm_msgStellarChangeTrustOp(const StellarChangeTrustOp *msg) {
{ if (!stellar_confirmChangeTrustOp(msg)) return;
if (!stellar_confirmChangeTrustOp(msg)) return;
if (stellar_allOperationsConfirmed()) { if (stellar_allOperationsConfirmed()) {
RESP_INIT(StellarSignedTx); RESP_INIT(StellarSignedTx);
stellar_fillSignedTx(resp); stellar_fillSignedTx(resp);
msg_write(MessageType_MessageType_StellarSignedTx, resp); msg_write(MessageType_MessageType_StellarSignedTx, resp);
layoutHome(); layoutHome();
} }
// Request the next operation to sign // Request the next operation to sign
else { else {
RESP_INIT(StellarTxOpRequest); RESP_INIT(StellarTxOpRequest);
msg_write(MessageType_MessageType_StellarTxOpRequest, resp); msg_write(MessageType_MessageType_StellarTxOpRequest, resp);
} }
} }
void fsm_msgStellarAllowTrustOp(const StellarAllowTrustOp *msg) void fsm_msgStellarAllowTrustOp(const StellarAllowTrustOp *msg) {
{ if (!stellar_confirmAllowTrustOp(msg)) return;
if (!stellar_confirmAllowTrustOp(msg)) return;
if (stellar_allOperationsConfirmed()) { if (stellar_allOperationsConfirmed()) {
RESP_INIT(StellarSignedTx); RESP_INIT(StellarSignedTx);
stellar_fillSignedTx(resp); stellar_fillSignedTx(resp);
msg_write(MessageType_MessageType_StellarSignedTx, resp); msg_write(MessageType_MessageType_StellarSignedTx, resp);
layoutHome(); layoutHome();
} }
// Request the next operation to sign // Request the next operation to sign
else { else {
RESP_INIT(StellarTxOpRequest); RESP_INIT(StellarTxOpRequest);
msg_write(MessageType_MessageType_StellarTxOpRequest, resp); msg_write(MessageType_MessageType_StellarTxOpRequest, resp);
} }
} }
void fsm_msgStellarAccountMergeOp(const StellarAccountMergeOp *msg) void fsm_msgStellarAccountMergeOp(const StellarAccountMergeOp *msg) {
{ if (!stellar_confirmAccountMergeOp(msg)) return;
if (!stellar_confirmAccountMergeOp(msg)) return;
if (stellar_allOperationsConfirmed()) { if (stellar_allOperationsConfirmed()) {
RESP_INIT(StellarSignedTx); RESP_INIT(StellarSignedTx);
stellar_fillSignedTx(resp); stellar_fillSignedTx(resp);
msg_write(MessageType_MessageType_StellarSignedTx, resp); msg_write(MessageType_MessageType_StellarSignedTx, resp);
layoutHome(); layoutHome();
} }
// Request the next operation to sign // Request the next operation to sign
else { else {
RESP_INIT(StellarTxOpRequest); RESP_INIT(StellarTxOpRequest);
msg_write(MessageType_MessageType_StellarTxOpRequest, resp); msg_write(MessageType_MessageType_StellarTxOpRequest, resp);
} }
} }
void fsm_msgStellarManageDataOp(const StellarManageDataOp *msg) void fsm_msgStellarManageDataOp(const StellarManageDataOp *msg) {
{ if (!stellar_confirmManageDataOp(msg)) return;
if (!stellar_confirmManageDataOp(msg)) return;
if (stellar_allOperationsConfirmed()) { if (stellar_allOperationsConfirmed()) {
RESP_INIT(StellarSignedTx); RESP_INIT(StellarSignedTx);
stellar_fillSignedTx(resp); stellar_fillSignedTx(resp);
msg_write(MessageType_MessageType_StellarSignedTx, resp); msg_write(MessageType_MessageType_StellarSignedTx, resp);
layoutHome(); layoutHome();
} }
// Request the next operation to sign // Request the next operation to sign
else { else {
RESP_INIT(StellarTxOpRequest); RESP_INIT(StellarTxOpRequest);
msg_write(MessageType_MessageType_StellarTxOpRequest, resp); msg_write(MessageType_MessageType_StellarTxOpRequest, resp);
} }
} }
void fsm_msgStellarBumpSequenceOp(const StellarBumpSequenceOp *msg) void fsm_msgStellarBumpSequenceOp(const StellarBumpSequenceOp *msg) {
{ if (!stellar_confirmBumpSequenceOp(msg)) return;
if (!stellar_confirmBumpSequenceOp(msg)) return;
if (stellar_allOperationsConfirmed()) { if (stellar_allOperationsConfirmed()) {
RESP_INIT(StellarSignedTx); RESP_INIT(StellarSignedTx);
stellar_fillSignedTx(resp); stellar_fillSignedTx(resp);
msg_write(MessageType_MessageType_StellarSignedTx, resp); msg_write(MessageType_MessageType_StellarSignedTx, resp);
layoutHome(); layoutHome();
} }
// Request the next operation to sign // Request the next operation to sign
else { else {
RESP_INIT(StellarTxOpRequest); RESP_INIT(StellarTxOpRequest);
msg_write(MessageType_MessageType_StellarTxOpRequest, resp); msg_write(MessageType_MessageType_StellarTxOpRequest, resp);
} }
} }

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@ -19,56 +19,53 @@
#include <string.h> #include <string.h>
#include "trezor.h"
#include "messages.h"
#include "debug.h" #include "debug.h"
#include "fsm.h" #include "fsm.h"
#include "util.h"
#include "gettext.h" #include "gettext.h"
#include "memzero.h" #include "memzero.h"
#include "messages.h"
#include "trezor.h"
#include "util.h"
#include "messages.pb.h"
#include "pb_decode.h" #include "pb_decode.h"
#include "pb_encode.h" #include "pb_encode.h"
#include "messages.pb.h"
struct MessagesMap_t { struct MessagesMap_t {
char type; // n = normal, d = debug char type; // n = normal, d = debug
char dir; // i = in, o = out char dir; // i = in, o = out
uint16_t msg_id; uint16_t msg_id;
const pb_field_t *fields; const pb_field_t *fields;
void (*process_func)(const void *ptr); void (*process_func)(const void *ptr);
}; };
static const struct MessagesMap_t MessagesMap[] = { static const struct MessagesMap_t MessagesMap[] = {
#include "messages_map.h" #include "messages_map.h"
// end // end
{0, 0, 0, 0, 0} {0, 0, 0, 0, 0}};
};
#include "messages_map_limits.h" #include "messages_map_limits.h"
const pb_field_t *MessageFields(char type, char dir, uint16_t msg_id) const pb_field_t *MessageFields(char type, char dir, uint16_t msg_id) {
{ const struct MessagesMap_t *m = MessagesMap;
const struct MessagesMap_t *m = MessagesMap; while (m->type) {
while (m->type) { if (type == m->type && dir == m->dir && msg_id == m->msg_id) {
if (type == m->type && dir == m->dir && msg_id == m->msg_id) { return m->fields;
return m->fields; }
} m++;
m++; }
} return 0;
return 0;
} }
void MessageProcessFunc(char type, char dir, uint16_t msg_id, void *ptr) void MessageProcessFunc(char type, char dir, uint16_t msg_id, void *ptr) {
{ const struct MessagesMap_t *m = MessagesMap;
const struct MessagesMap_t *m = MessagesMap; while (m->type) {
while (m->type) { if (type == m->type && dir == m->dir && msg_id == m->msg_id) {
if (type == m->type && dir == m->dir && msg_id == m->msg_id) { m->process_func(ptr);
m->process_func(ptr); return;
return; }
} m++;
m++; }
}
} }
static uint32_t msg_out_start = 0; static uint32_t msg_out_start = 0;
@ -85,225 +82,219 @@ static uint8_t msg_debug_out[MSG_DEBUG_OUT_SIZE];
#endif #endif
static inline void msg_out_append(uint8_t c) static inline void msg_out_append(uint8_t c) {
{ if (msg_out_cur == 0) {
if (msg_out_cur == 0) { msg_out[msg_out_end * 64] = '?';
msg_out[msg_out_end * 64] = '?'; msg_out_cur = 1;
msg_out_cur = 1; }
} msg_out[msg_out_end * 64 + msg_out_cur] = c;
msg_out[msg_out_end * 64 + msg_out_cur] = c; msg_out_cur++;
msg_out_cur++; if (msg_out_cur == 64) {
if (msg_out_cur == 64) { msg_out_cur = 0;
msg_out_cur = 0; msg_out_end = (msg_out_end + 1) % (MSG_OUT_SIZE / 64);
msg_out_end = (msg_out_end + 1) % (MSG_OUT_SIZE / 64); }
}
} }
#if DEBUG_LINK #if DEBUG_LINK
static inline void msg_debug_out_append(uint8_t c) static inline void msg_debug_out_append(uint8_t c) {
{ if (msg_debug_out_cur == 0) {
if (msg_debug_out_cur == 0) { msg_debug_out[msg_debug_out_end * 64] = '?';
msg_debug_out[msg_debug_out_end * 64] = '?'; msg_debug_out_cur = 1;
msg_debug_out_cur = 1; }
} msg_debug_out[msg_debug_out_end * 64 + msg_debug_out_cur] = c;
msg_debug_out[msg_debug_out_end * 64 + msg_debug_out_cur] = c; msg_debug_out_cur++;
msg_debug_out_cur++; if (msg_debug_out_cur == 64) {
if (msg_debug_out_cur == 64) { msg_debug_out_cur = 0;
msg_debug_out_cur = 0; msg_debug_out_end = (msg_debug_out_end + 1) % (MSG_DEBUG_OUT_SIZE / 64);
msg_debug_out_end = (msg_debug_out_end + 1) % (MSG_DEBUG_OUT_SIZE / 64); }
}
} }
#endif #endif
static inline void msg_out_pad(void) static inline void msg_out_pad(void) {
{ if (msg_out_cur == 0) return;
if (msg_out_cur == 0) return; while (msg_out_cur < 64) {
while (msg_out_cur < 64) { msg_out[msg_out_end * 64 + msg_out_cur] = 0;
msg_out[msg_out_end * 64 + msg_out_cur] = 0; msg_out_cur++;
msg_out_cur++; }
} msg_out_cur = 0;
msg_out_cur = 0; msg_out_end = (msg_out_end + 1) % (MSG_OUT_SIZE / 64);
msg_out_end = (msg_out_end + 1) % (MSG_OUT_SIZE / 64);
} }
#if DEBUG_LINK #if DEBUG_LINK
static inline void msg_debug_out_pad(void) static inline void msg_debug_out_pad(void) {
{ if (msg_debug_out_cur == 0) return;
if (msg_debug_out_cur == 0) return; while (msg_debug_out_cur < 64) {
while (msg_debug_out_cur < 64) { msg_debug_out[msg_debug_out_end * 64 + msg_debug_out_cur] = 0;
msg_debug_out[msg_debug_out_end * 64 + msg_debug_out_cur] = 0; msg_debug_out_cur++;
msg_debug_out_cur++; }
} msg_debug_out_cur = 0;
msg_debug_out_cur = 0; msg_debug_out_end = (msg_debug_out_end + 1) % (MSG_DEBUG_OUT_SIZE / 64);
msg_debug_out_end = (msg_debug_out_end + 1) % (MSG_DEBUG_OUT_SIZE / 64);
} }
#endif #endif
static bool pb_callback_out(pb_ostream_t *stream, const uint8_t *buf, size_t count) static bool pb_callback_out(pb_ostream_t *stream, const uint8_t *buf,
{ size_t count) {
(void)stream; (void)stream;
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
msg_out_append(buf[i]); msg_out_append(buf[i]);
} }
return true; return true;
} }
#if DEBUG_LINK #if DEBUG_LINK
static bool pb_debug_callback_out(pb_ostream_t *stream, const uint8_t *buf, size_t count) static bool pb_debug_callback_out(pb_ostream_t *stream, const uint8_t *buf,
{ size_t count) {
(void)stream; (void)stream;
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
msg_debug_out_append(buf[i]); msg_debug_out_append(buf[i]);
} }
return true; return true;
} }
#endif #endif
bool msg_write_common(char type, uint16_t msg_id, const void *msg_ptr) bool msg_write_common(char type, uint16_t msg_id, const void *msg_ptr) {
{ const pb_field_t *fields = MessageFields(type, 'o', msg_id);
const pb_field_t *fields = MessageFields(type, 'o', msg_id); if (!fields) { // unknown message
if (!fields) { // unknown message return false;
return false; }
}
size_t len; size_t len;
if (!pb_get_encoded_size(&len, fields, msg_ptr)) { if (!pb_get_encoded_size(&len, fields, msg_ptr)) {
return false; return false;
} }
void (*append)(uint8_t); void (*append)(uint8_t);
bool (*pb_callback)(pb_ostream_t *, const uint8_t *, size_t); bool (*pb_callback)(pb_ostream_t *, const uint8_t *, size_t);
if (type == 'n') { if (type == 'n') {
append = msg_out_append; append = msg_out_append;
pb_callback = pb_callback_out; pb_callback = pb_callback_out;
} else } else
#if DEBUG_LINK #if DEBUG_LINK
if (type == 'd') { if (type == 'd') {
append = msg_debug_out_append; append = msg_debug_out_append;
pb_callback = pb_debug_callback_out; pb_callback = pb_debug_callback_out;
} else } else
#endif #endif
{ {
return false; return false;
} }
append('#'); append('#');
append('#'); append('#');
append((msg_id >> 8) & 0xFF); append((msg_id >> 8) & 0xFF);
append(msg_id & 0xFF); append(msg_id & 0xFF);
append((len >> 24) & 0xFF); append((len >> 24) & 0xFF);
append((len >> 16) & 0xFF); append((len >> 16) & 0xFF);
append((len >> 8) & 0xFF); append((len >> 8) & 0xFF);
append(len & 0xFF); append(len & 0xFF);
pb_ostream_t stream = {pb_callback, 0, SIZE_MAX, 0, 0}; pb_ostream_t stream = {pb_callback, 0, SIZE_MAX, 0, 0};
bool status = pb_encode(&stream, fields, msg_ptr); bool status = pb_encode(&stream, fields, msg_ptr);
if (type == 'n') { if (type == 'n') {
msg_out_pad(); msg_out_pad();
} }
#if DEBUG_LINK #if DEBUG_LINK
else if (type == 'd') { else if (type == 'd') {
msg_debug_out_pad(); msg_debug_out_pad();
} }
#endif #endif
return status; return status;
} }
enum { enum {
READSTATE_IDLE, READSTATE_IDLE,
READSTATE_READING, READSTATE_READING,
}; };
void msg_process(char type, uint16_t msg_id, const pb_field_t *fields, uint8_t *msg_raw, uint32_t msg_size) void msg_process(char type, uint16_t msg_id, const pb_field_t *fields,
{ uint8_t *msg_raw, uint32_t msg_size) {
static uint8_t msg_data[MSG_IN_SIZE]; static uint8_t msg_data[MSG_IN_SIZE];
memzero(msg_data, sizeof(msg_data)); memzero(msg_data, sizeof(msg_data));
pb_istream_t stream = pb_istream_from_buffer(msg_raw, msg_size); pb_istream_t stream = pb_istream_from_buffer(msg_raw, msg_size);
bool status = pb_decode(&stream, fields, msg_data); bool status = pb_decode(&stream, fields, msg_data);
if (status) { if (status) {
MessageProcessFunc(type, 'i', msg_id, msg_data); MessageProcessFunc(type, 'i', msg_id, msg_data);
} else { } else {
fsm_sendFailure(FailureType_Failure_DataError, stream.errmsg); fsm_sendFailure(FailureType_Failure_DataError, stream.errmsg);
} }
} }
void msg_read_common(char type, const uint8_t *buf, uint32_t len) void msg_read_common(char type, const uint8_t *buf, uint32_t len) {
{ static char read_state = READSTATE_IDLE;
static char read_state = READSTATE_IDLE; static uint8_t msg_in[MSG_IN_SIZE];
static uint8_t msg_in[MSG_IN_SIZE]; static uint16_t msg_id = 0xFFFF;
static uint16_t msg_id = 0xFFFF; static uint32_t msg_size = 0;
static uint32_t msg_size = 0; static uint32_t msg_pos = 0;
static uint32_t msg_pos = 0; static const pb_field_t *fields = 0;
static const pb_field_t *fields = 0;
if (len != 64) return; if (len != 64) return;
if (read_state == READSTATE_IDLE) { if (read_state == READSTATE_IDLE) {
if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { // invalid start - discard if (buf[0] != '?' || buf[1] != '#' ||
return; 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_id = (buf[3] << 8) + buf[4];
msg_size =
((uint32_t)buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8];
fields = MessageFields(type, 'i', msg_id); fields = MessageFields(type, 'i', msg_id);
if (!fields) { // unknown message if (!fields) { // unknown message
fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Unknown message")); fsm_sendFailure(FailureType_Failure_UnexpectedMessage,
return; _("Unknown message"));
} return;
if (msg_size > MSG_IN_SIZE) { // message is too big :( }
fsm_sendFailure(FailureType_Failure_DataError, _("Message too big")); if (msg_size > MSG_IN_SIZE) { // message is too big :(
return; fsm_sendFailure(FailureType_Failure_DataError, _("Message too big"));
} return;
}
read_state = READSTATE_READING; read_state = READSTATE_READING;
memcpy(msg_in, buf + 9, len - 9); memcpy(msg_in, buf + 9, len - 9);
msg_pos = len - 9; msg_pos = len - 9;
} else } else if (read_state == READSTATE_READING) {
if (read_state == READSTATE_READING) { if (buf[0] != '?') { // invalid contents
if (buf[0] != '?') { // invalid contents read_state = READSTATE_IDLE;
read_state = READSTATE_IDLE; return;
return; }
} /* raw data starts at buf + 1 with len - 1 bytes */
/* raw data starts at buf + 1 with len - 1 bytes */ buf++;
buf++; len = MIN(len - 1, MSG_IN_SIZE - msg_pos);
len = MIN(len - 1, MSG_IN_SIZE - msg_pos);
memcpy(msg_in + msg_pos, buf, len); memcpy(msg_in + msg_pos, buf, len);
msg_pos += len; msg_pos += len;
} }
if (msg_pos >= msg_size) { if (msg_pos >= msg_size) {
msg_process(type, msg_id, fields, msg_in, msg_size); msg_process(type, msg_id, fields, msg_in, msg_size);
msg_pos = 0; msg_pos = 0;
read_state = READSTATE_IDLE; read_state = READSTATE_IDLE;
} }
} }
const uint8_t *msg_out_data(void) const uint8_t *msg_out_data(void) {
{ if (msg_out_start == msg_out_end) return 0;
if (msg_out_start == msg_out_end) return 0; uint8_t *data = msg_out + (msg_out_start * 64);
uint8_t *data = msg_out + (msg_out_start * 64); msg_out_start = (msg_out_start + 1) % (MSG_OUT_SIZE / 64);
msg_out_start = (msg_out_start + 1) % (MSG_OUT_SIZE / 64); debugLog(0, "", "msg_out_data");
debugLog(0, "", "msg_out_data"); return data;
return data;
} }
#if DEBUG_LINK #if DEBUG_LINK
const uint8_t *msg_debug_out_data(void) const uint8_t *msg_debug_out_data(void) {
{ if (msg_debug_out_start == msg_debug_out_end) return 0;
if (msg_debug_out_start == msg_debug_out_end) return 0; uint8_t *data = msg_debug_out + (msg_debug_out_start * 64);
uint8_t *data = msg_debug_out + (msg_debug_out_start * 64); msg_debug_out_start = (msg_debug_out_start + 1) % (MSG_DEBUG_OUT_SIZE / 64);
msg_debug_out_start = (msg_debug_out_start + 1) % (MSG_DEBUG_OUT_SIZE / 64); debugLog(0, "", "msg_debug_out_data");
debugLog(0, "", "msg_debug_out_data"); return data;
return data;
} }
#endif #endif
@ -315,61 +306,64 @@ _Static_assert(sizeof(msg_tiny) >= sizeof(PassphraseAck), "msg_tiny too tiny");
_Static_assert(sizeof(msg_tiny) >= sizeof(ButtonAck), "msg_tiny too tiny"); _Static_assert(sizeof(msg_tiny) >= sizeof(ButtonAck), "msg_tiny too tiny");
_Static_assert(sizeof(msg_tiny) >= sizeof(PinMatrixAck), "msg_tiny too tiny"); _Static_assert(sizeof(msg_tiny) >= sizeof(PinMatrixAck), "msg_tiny too tiny");
#if DEBUG_LINK #if DEBUG_LINK
_Static_assert(sizeof(msg_tiny) >= sizeof(DebugLinkDecision), "msg_tiny too tiny"); _Static_assert(sizeof(msg_tiny) >= sizeof(DebugLinkDecision),
_Static_assert(sizeof(msg_tiny) >= sizeof(DebugLinkGetState), "msg_tiny too tiny"); "msg_tiny too tiny");
_Static_assert(sizeof(msg_tiny) >= sizeof(DebugLinkGetState),
"msg_tiny too tiny");
#endif #endif
uint16_t msg_tiny_id = 0xFFFF; uint16_t msg_tiny_id = 0xFFFF;
void msg_read_tiny(const uint8_t *buf, int len) void msg_read_tiny(const uint8_t *buf, int len) {
{ if (len != 64) return;
if (len != 64) return; if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') {
if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { return;
return; }
} uint16_t msg_id = (buf[3] << 8) + buf[4];
uint16_t msg_id = (buf[3] << 8) + buf[4]; uint32_t msg_size =
uint32_t msg_size = ((uint32_t) buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8]; ((uint32_t)buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8];
if (msg_size > 64 || len - msg_size < 9) { if (msg_size > 64 || len - msg_size < 9) {
return; return;
} }
const pb_field_t *fields = 0; const pb_field_t *fields = 0;
pb_istream_t stream = pb_istream_from_buffer(buf + 9, msg_size); pb_istream_t stream = pb_istream_from_buffer(buf + 9, msg_size);
switch (msg_id) { switch (msg_id) {
case MessageType_MessageType_PinMatrixAck: case MessageType_MessageType_PinMatrixAck:
fields = PinMatrixAck_fields; fields = PinMatrixAck_fields;
break; break;
case MessageType_MessageType_ButtonAck: case MessageType_MessageType_ButtonAck:
fields = ButtonAck_fields; fields = ButtonAck_fields;
break; break;
case MessageType_MessageType_PassphraseAck: case MessageType_MessageType_PassphraseAck:
fields = PassphraseAck_fields; fields = PassphraseAck_fields;
break; break;
case MessageType_MessageType_Cancel: case MessageType_MessageType_Cancel:
fields = Cancel_fields; fields = Cancel_fields;
break; break;
case MessageType_MessageType_Initialize: case MessageType_MessageType_Initialize:
fields = Initialize_fields; fields = Initialize_fields;
break; break;
#if DEBUG_LINK #if DEBUG_LINK
case MessageType_MessageType_DebugLinkDecision: case MessageType_MessageType_DebugLinkDecision:
fields = DebugLinkDecision_fields; fields = DebugLinkDecision_fields;
break; break;
case MessageType_MessageType_DebugLinkGetState: case MessageType_MessageType_DebugLinkGetState:
fields = DebugLinkGetState_fields; fields = DebugLinkGetState_fields;
break; break;
#endif #endif
} }
if (fields) { if (fields) {
bool status = pb_decode(&stream, fields, msg_tiny); bool status = pb_decode(&stream, fields, msg_tiny);
if (status) { if (status) {
msg_tiny_id = msg_id; msg_tiny_id = msg_id;
} else { } else {
fsm_sendFailure(FailureType_Failure_DataError, stream.errmsg); fsm_sendFailure(FailureType_Failure_DataError, stream.errmsg);
msg_tiny_id = 0xFFFF; msg_tiny_id = 0xFFFF;
} }
} else { } else {
fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Unknown message")); fsm_sendFailure(FailureType_Failure_UnexpectedMessage,
msg_tiny_id = 0xFFFF; _("Unknown message"));
} msg_tiny_id = 0xFFFF;
}
} }

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -29,82 +29,125 @@
const char *nem_validate_common(NEMTransactionCommon *common, bool inner); const char *nem_validate_common(NEMTransactionCommon *common, bool inner);
const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network); const char *nem_validate_transfer(const NEMTransfer *transfer, uint8_t network);
const char *nem_validate_provision_namespace(const NEMProvisionNamespace *provision_namespace, uint8_t network); const char *nem_validate_provision_namespace(
const char *nem_validate_mosaic_creation(const NEMMosaicCreation *mosaic_creation, uint8_t network); const NEMProvisionNamespace *provision_namespace, uint8_t network);
const char *nem_validate_supply_change(const NEMMosaicSupplyChange *supply_change); const char *nem_validate_mosaic_creation(
const char *nem_validate_aggregate_modification(const NEMAggregateModification *aggregate_modification, bool creation); const NEMMosaicCreation *mosaic_creation, uint8_t network);
const char *nem_validate_importance_transfer(const NEMImportanceTransfer *importance_transfer); const char *nem_validate_supply_change(
const NEMMosaicSupplyChange *supply_change);
const char *nem_validate_aggregate_modification(
const NEMAggregateModification *aggregate_modification, bool creation);
const char *nem_validate_importance_transfer(
const NEMImportanceTransfer *importance_transfer);
bool nem_askTransfer(const NEMTransactionCommon *common, const NEMTransfer *transfer, const char *desc); bool nem_askTransfer(const NEMTransactionCommon *common,
bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node, const NEMTransactionCommon *common, const NEMTransfer *transfer); const NEMTransfer *transfer, const char *desc);
bool nem_fsmTransfer(nem_transaction_ctx *context, const HDNode *node,
const NEMTransactionCommon *common,
const NEMTransfer *transfer);
bool nem_askProvisionNamespace(const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace, const char *desc); bool nem_askProvisionNamespace(const NEMTransactionCommon *common,
bool nem_fsmProvisionNamespace(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMProvisionNamespace *provision_namespace); const NEMProvisionNamespace *provision_namespace,
const char *desc);
bool nem_fsmProvisionNamespace(
nem_transaction_ctx *context, const NEMTransactionCommon *common,
const NEMProvisionNamespace *provision_namespace);
bool nem_askMosaicCreation(const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation, const char *desc, const char *address); bool nem_askMosaicCreation(const NEMTransactionCommon *common,
bool nem_fsmMosaicCreation(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicCreation *mosaic_creation); const NEMMosaicCreation *mosaic_creation,
const char *desc, const char *address);
bool nem_fsmMosaicCreation(nem_transaction_ctx *context,
const NEMTransactionCommon *common,
const NEMMosaicCreation *mosaic_creation);
bool nem_askSupplyChange(const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change, const char *desc); bool nem_askSupplyChange(const NEMTransactionCommon *common,
bool nem_fsmSupplyChange(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMMosaicSupplyChange *supply_change); const NEMMosaicSupplyChange *supply_change,
const char *desc);
bool nem_fsmSupplyChange(nem_transaction_ctx *context,
const NEMTransactionCommon *common,
const NEMMosaicSupplyChange *supply_change);
bool nem_askAggregateModification(const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification, const char *desc, bool creation); bool nem_askAggregateModification(
bool nem_fsmAggregateModification(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMAggregateModification *aggregate_modification); const NEMTransactionCommon *common,
const NEMAggregateModification *aggregate_modification, const char *desc,
bool creation);
bool nem_fsmAggregateModification(
nem_transaction_ctx *context, const NEMTransactionCommon *common,
const NEMAggregateModification *aggregate_modification);
bool nem_askImportanceTransfer(const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer, const char *desc); bool nem_askImportanceTransfer(const NEMTransactionCommon *common,
bool nem_fsmImportanceTransfer(nem_transaction_ctx *context, const NEMTransactionCommon *common, const NEMImportanceTransfer *importance_transfer); const NEMImportanceTransfer *importance_transfer,
const char *desc);
bool nem_fsmImportanceTransfer(
nem_transaction_ctx *context, const NEMTransactionCommon *common,
const NEMImportanceTransfer *importance_transfer);
bool nem_askMultisig(const char *address, const char *desc, bool cosigning, uint64_t fee); bool nem_askMultisig(const char *address, const char *desc, bool cosigning,
bool nem_fsmMultisig(nem_transaction_ctx *context, const NEMTransactionCommon *common, const nem_transaction_ctx *inner, bool cosigning); uint64_t fee);
bool nem_fsmMultisig(nem_transaction_ctx *context,
const NEMTransactionCommon *common,
const nem_transaction_ctx *inner, bool cosigning);
const NEMMosaicDefinition *nem_mosaicByName(const char *namespace, const char *mosaic, uint8_t network); const NEMMosaicDefinition *nem_mosaicByName(const char *namespace,
const char *mosaic,
uint8_t network);
size_t nem_canonicalizeMosaics(NEMMosaic *mosaics, size_t mosaics_count); size_t nem_canonicalizeMosaics(NEMMosaic *mosaics, size_t mosaics_count);
void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, char *str_out, size_t size); void nem_mosaicFormatAmount(const NEMMosaicDefinition *definition,
bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network, char *str_out, size_t size); uint64_t quantity, const bignum256 *multiplier,
char *str_out, size_t size);
bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition,
uint64_t quantity, const bignum256 *multiplier,
uint8_t network, char *str_out, size_t size);
static inline void nem_mosaicFormatName(const char *namespace, const char *mosaic, char *str_out, size_t size) { static inline void nem_mosaicFormatName(const char *namespace,
strlcpy(str_out, namespace, size); const char *mosaic, char *str_out,
strlcat(str_out, ".", size); size_t size) {
strlcat(str_out, mosaic, 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) { static inline bool nem_mosaicMatches(const NEMMosaicDefinition *definition,
if (strcmp(namespace, definition->namespace) == 0 && strcmp(mosaic, definition->mosaic) == 0) { const char *namespace, const char *mosaic,
if (definition->networks_count == 0) { uint8_t network) {
return true; if (strcmp(namespace, definition->namespace) == 0 &&
} strcmp(mosaic, definition->mosaic) == 0) {
if (definition->networks_count == 0) {
return true;
}
for (size_t i = 0; i < definition->networks_count; i++) { for (size_t i = 0; i < definition->networks_count; i++) {
if (definition->networks[i] == network) { if (definition->networks[i] == network) {
return true; return true;
} }
} }
} }
return false; return false;
} }
static inline int nem_mosaicCompare(const NEMMosaic *a, const NEMMosaic *b) { static inline int nem_mosaicCompare(const NEMMosaic *a, const NEMMosaic *b) {
size_t namespace_length = strlen(a->namespace); size_t namespace_length = strlen(a->namespace);
// Ensure that strlen(a->namespace) <= strlen(b->namespace) // Ensure that strlen(a->namespace) <= strlen(b->namespace)
if (namespace_length > strlen(b->namespace)) { if (namespace_length > strlen(b->namespace)) {
return -nem_mosaicCompare(b, a); return -nem_mosaicCompare(b, a);
} }
int r = strncmp(a->namespace, b->namespace, namespace_length); int r = strncmp(a->namespace, b->namespace, namespace_length);
if (r == 0 && b->namespace[namespace_length] != '\0') { if (r == 0 && b->namespace[namespace_length] != '\0') {
// The next character would be the separator // The next character would be the separator
r = (':' - b->namespace[namespace_length]); r = (':' - b->namespace[namespace_length]);
} }
if (r == 0) { if (r == 0) {
// Finally compare the mosaic // Finally compare the mosaic
r = strcmp(a->mosaic, b->mosaic); r = strcmp(a->mosaic, b->mosaic);
} }
return r; return r;
} }
#endif #endif

View File

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

View File

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

View File

@ -19,64 +19,60 @@
#include <string.h> #include <string.h>
#include "pinmatrix.h"
#include "layout2.h" #include "layout2.h"
#include "oled.h" #include "oled.h"
#include "pinmatrix.h"
#include "rng.h" #include "rng.h"
static char pinmatrix_perm[10] = "XXXXXXXXX"; static char pinmatrix_perm[10] = "XXXXXXXXX";
void pinmatrix_draw(const char *text) void pinmatrix_draw(const char *text) {
{ const BITMAP *bmp_digits[10] = {
const BITMAP *bmp_digits[10] = { &bmp_digit0, &bmp_digit1, &bmp_digit2, &bmp_digit3, &bmp_digit4,
&bmp_digit0, &bmp_digit1, &bmp_digit2, &bmp_digit3, &bmp_digit4, &bmp_digit5, &bmp_digit6, &bmp_digit7, &bmp_digit8, &bmp_digit9,
&bmp_digit5, &bmp_digit6, &bmp_digit7, &bmp_digit8, &bmp_digit9, };
}; layoutSwipe();
layoutSwipe(); const int w = bmp_digit0.width, h = bmp_digit0.height, pad = 2;
const int w = bmp_digit0.width, h = bmp_digit0.height, pad = 2; for (int i = 0; i < 3; i++) {
for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) {
for (int j = 0; j < 3; j++) { // use (2 - j) instead of j to achieve 789456123 layout
// use (2 - j) instead of j to achieve 789456123 layout int k = pinmatrix_perm[i + (2 - j) * 3] - '0';
int k = pinmatrix_perm[i + (2 - j) * 3] - '0'; if (text) {
if (text) { oledDrawStringCenter(OLED_WIDTH / 2, 0, text, FONT_STANDARD);
oledDrawStringCenter(OLED_WIDTH / 2, 0, text, FONT_STANDARD); }
} oledDrawBitmap((OLED_WIDTH - 3 * w - 2 * pad) / 2 + i * (w + pad),
oledDrawBitmap((OLED_WIDTH - 3 * w - 2 * pad) / 2 + i * (w + pad), OLED_HEIGHT - 3 * h - 2 * pad + j * (h + pad), bmp_digits[k]); OLED_HEIGHT - 3 * h - 2 * pad + j * (h + pad),
} bmp_digits[k]);
} }
oledRefresh(); }
oledRefresh();
} }
void pinmatrix_start(const char *text) void pinmatrix_start(const char *text) {
{ for (int i = 0; i < 9; i++) {
for (int i = 0; i < 9; i++) { pinmatrix_perm[i] = '1' + i;
pinmatrix_perm[i] = '1' + i; }
} pinmatrix_perm[9] = 0;
pinmatrix_perm[9] = 0; random_permute(pinmatrix_perm, 9);
random_permute(pinmatrix_perm, 9); pinmatrix_draw(text);
pinmatrix_draw(text);
} }
void pinmatrix_done(char *pin) void pinmatrix_done(char *pin) {
{ int k, i = 0;
int k, i = 0; while (pin && pin[i]) {
while (pin && pin[i]) { k = pin[i] - '1';
k = pin[i] - '1'; if (k >= 0 && k <= 8) {
if (k >= 0 && k <= 8) { pin[i] = pinmatrix_perm[k];
pin[i] = pinmatrix_perm[k]; } else {
} else { pin[i] = 'X';
pin[i] = 'X'; }
} i++;
i++; }
} memset(pinmatrix_perm, 'X', sizeof(pinmatrix_perm) - 1);
memset(pinmatrix_perm, 'X', sizeof(pinmatrix_perm) - 1);
} }
#if DEBUG_LINK #if DEBUG_LINK
const char *pinmatrix_get(void) const char *pinmatrix_get(void) { return pinmatrix_perm; }
{
return pinmatrix_perm;
}
#endif #endif

View File

@ -18,296 +18,303 @@
*/ */
#include "protect.h" #include "protect.h"
#include "config.h"
#include "memory.h"
#include "messages.h"
#include "usb.h"
#include "oled.h"
#include "buttons.h" #include "buttons.h"
#include "pinmatrix.h" #include "config.h"
#include "fsm.h"
#include "layout2.h"
#include "util.h"
#include "debug.h" #include "debug.h"
#include "fsm.h"
#include "gettext.h" #include "gettext.h"
#include "layout2.h"
#include "memory.h"
#include "memzero.h" #include "memzero.h"
#include "messages.h"
#include "messages.pb.h" #include "messages.pb.h"
#include "oled.h"
#include "pinmatrix.h"
#include "usb.h"
#include "util.h"
#define MAX_WRONG_PINS 15 #define MAX_WRONG_PINS 15
bool protectAbortedByCancel = false; bool protectAbortedByCancel = false;
bool protectAbortedByInitialize = false; bool protectAbortedByInitialize = false;
bool protectButton(ButtonRequestType type, bool confirm_only) bool protectButton(ButtonRequestType type, bool confirm_only) {
{ ButtonRequest resp;
ButtonRequest resp; bool result = false;
bool result = false; bool acked = false;
bool acked = false;
#if DEBUG_LINK #if DEBUG_LINK
bool debug_decided = false; bool debug_decided = false;
#endif #endif
memzero(&resp, sizeof(ButtonRequest)); memzero(&resp, sizeof(ButtonRequest));
resp.has_code = true; resp.has_code = true;
resp.code = type; resp.code = type;
usbTiny(1); usbTiny(1);
buttonUpdate(); // Clear button state buttonUpdate(); // Clear button state
msg_write(MessageType_MessageType_ButtonRequest, &resp); msg_write(MessageType_MessageType_ButtonRequest, &resp);
for (;;) { for (;;) {
usbPoll(); usbPoll();
// check for ButtonAck // check for ButtonAck
if (msg_tiny_id == MessageType_MessageType_ButtonAck) { if (msg_tiny_id == MessageType_MessageType_ButtonAck) {
msg_tiny_id = 0xFFFF; msg_tiny_id = 0xFFFF;
acked = true; acked = true;
} }
// button acked - check buttons // button acked - check buttons
if (acked) { if (acked) {
usbSleep(5); usbSleep(5);
buttonUpdate(); buttonUpdate();
if (button.YesUp) { if (button.YesUp) {
result = true; result = true;
break; break;
} }
if (!confirm_only && button.NoUp) { if (!confirm_only && button.NoUp) {
result = false; result = false;
break; break;
} }
} }
// check for Cancel / Initialize // check for Cancel / Initialize
protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel);
protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); protectAbortedByInitialize =
if (protectAbortedByCancel || protectAbortedByInitialize) { (msg_tiny_id == MessageType_MessageType_Initialize);
msg_tiny_id = 0xFFFF; if (protectAbortedByCancel || protectAbortedByInitialize) {
result = false; msg_tiny_id = 0xFFFF;
break; result = false;
} break;
}
#if DEBUG_LINK #if DEBUG_LINK
// check DebugLink // check DebugLink
if (msg_tiny_id == MessageType_MessageType_DebugLinkDecision) { if (msg_tiny_id == MessageType_MessageType_DebugLinkDecision) {
msg_tiny_id = 0xFFFF; msg_tiny_id = 0xFFFF;
DebugLinkDecision *dld = (DebugLinkDecision *)msg_tiny; DebugLinkDecision *dld = (DebugLinkDecision *)msg_tiny;
result = dld->yes_no; result = dld->yes_no;
debug_decided = true; debug_decided = true;
} }
if (acked && debug_decided) { if (acked && debug_decided) {
break; break;
} }
if (msg_tiny_id == MessageType_MessageType_DebugLinkGetState) { if (msg_tiny_id == MessageType_MessageType_DebugLinkGetState) {
msg_tiny_id = 0xFFFF; msg_tiny_id = 0xFFFF;
fsm_msgDebugLinkGetState((DebugLinkGetState *)msg_tiny); fsm_msgDebugLinkGetState((DebugLinkGetState *)msg_tiny);
} }
#endif #endif
} }
usbTiny(0); usbTiny(0);
return result; return result;
} }
const char *requestPin(PinMatrixRequestType type, const char *text) const char *requestPin(PinMatrixRequestType type, const char *text) {
{ PinMatrixRequest resp;
PinMatrixRequest resp; memzero(&resp, sizeof(PinMatrixRequest));
memzero(&resp, sizeof(PinMatrixRequest)); resp.has_type = true;
resp.has_type = true; resp.type = type;
resp.type = type; usbTiny(1);
usbTiny(1); msg_write(MessageType_MessageType_PinMatrixRequest, &resp);
msg_write(MessageType_MessageType_PinMatrixRequest, &resp); pinmatrix_start(text);
pinmatrix_start(text); for (;;) {
for (;;) { usbPoll();
usbPoll(); if (msg_tiny_id == MessageType_MessageType_PinMatrixAck) {
if (msg_tiny_id == MessageType_MessageType_PinMatrixAck) { msg_tiny_id = 0xFFFF;
msg_tiny_id = 0xFFFF; PinMatrixAck *pma = (PinMatrixAck *)msg_tiny;
PinMatrixAck *pma = (PinMatrixAck *)msg_tiny; pinmatrix_done(pma->pin); // convert via pinmatrix
pinmatrix_done(pma->pin); // convert via pinmatrix usbTiny(0);
usbTiny(0); return pma->pin;
return pma->pin; }
} // check for Cancel / Initialize
// check for Cancel / Initialize protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel);
protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); protectAbortedByInitialize =
protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); (msg_tiny_id == MessageType_MessageType_Initialize);
if (protectAbortedByCancel || protectAbortedByInitialize) { if (protectAbortedByCancel || protectAbortedByInitialize) {
pinmatrix_done(0); pinmatrix_done(0);
msg_tiny_id = 0xFFFF; msg_tiny_id = 0xFFFF;
usbTiny(0); usbTiny(0);
return 0; return 0;
} }
#if DEBUG_LINK #if DEBUG_LINK
if (msg_tiny_id == MessageType_MessageType_DebugLinkGetState) { if (msg_tiny_id == MessageType_MessageType_DebugLinkGetState) {
msg_tiny_id = 0xFFFF; msg_tiny_id = 0xFFFF;
fsm_msgDebugLinkGetState((DebugLinkGetState *)msg_tiny); fsm_msgDebugLinkGetState((DebugLinkGetState *)msg_tiny);
} }
#endif #endif
} }
} }
secbool protectPinUiCallback(uint32_t wait, uint32_t progress, const char* message) secbool protectPinUiCallback(uint32_t wait, uint32_t progress,
{ const char *message) {
// Convert wait to secstr string. // Convert wait to secstr string.
char secstrbuf[] = _("________0 seconds"); char secstrbuf[] = _("________0 seconds");
char *secstr = secstrbuf + 9; char *secstr = secstrbuf + 9;
uint32_t secs = wait; uint32_t secs = wait;
do { do {
secstr--; secstr--;
*secstr = (secs % 10) + '0'; *secstr = (secs % 10) + '0';
secs /= 10; secs /= 10;
} while (secs > 0 && secstr >= secstrbuf); } while (secs > 0 && secstr >= secstrbuf);
if (wait == 1) { if (wait == 1) {
// Change "seconds" to "second". // Change "seconds" to "second".
secstrbuf[16] = 0; secstrbuf[16] = 0;
} }
oledClear(); oledClear();
oledDrawStringCenter(OLED_WIDTH / 2, 0 * 9, message, FONT_STANDARD); oledDrawStringCenter(OLED_WIDTH / 2, 0 * 9, message, FONT_STANDARD);
oledDrawStringCenter(OLED_WIDTH / 2, 2 * 9, _("Please wait"), FONT_STANDARD); oledDrawStringCenter(OLED_WIDTH / 2, 2 * 9, _("Please wait"), FONT_STANDARD);
oledDrawStringCenter(OLED_WIDTH / 2, 3 * 9, secstr, FONT_STANDARD); oledDrawStringCenter(OLED_WIDTH / 2, 3 * 9, secstr, FONT_STANDARD);
oledDrawStringCenter(OLED_WIDTH / 2, 4 * 9, _("to continue ..."), FONT_STANDARD); oledDrawStringCenter(OLED_WIDTH / 2, 4 * 9, _("to continue ..."),
// progressbar FONT_STANDARD);
oledFrame(0, OLED_HEIGHT - 8, OLED_WIDTH - 1, OLED_HEIGHT - 1); // progressbar
oledBox(1, OLED_HEIGHT - 7, OLED_WIDTH - 2, OLED_HEIGHT - 2, 0); oledFrame(0, OLED_HEIGHT - 8, OLED_WIDTH - 1, OLED_HEIGHT - 1);
progress = progress * (OLED_WIDTH - 4) / 1000; oledBox(1, OLED_HEIGHT - 7, OLED_WIDTH - 2, OLED_HEIGHT - 2, 0);
if (progress > OLED_WIDTH - 4) { progress = progress * (OLED_WIDTH - 4) / 1000;
progress = OLED_WIDTH - 4; if (progress > OLED_WIDTH - 4) {
} progress = OLED_WIDTH - 4;
oledBox(2, OLED_HEIGHT - 6, 1 + progress, OLED_HEIGHT - 3, 1); }
oledRefresh(); oledBox(2, OLED_HEIGHT - 6, 1 + progress, OLED_HEIGHT - 3, 1);
// Check for Cancel / Initialize. oledRefresh();
protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); // Check for Cancel / Initialize.
protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel);
if (protectAbortedByCancel || protectAbortedByInitialize) { protectAbortedByInitialize =
msg_tiny_id = 0xFFFF; (msg_tiny_id == MessageType_MessageType_Initialize);
usbTiny(0); if (protectAbortedByCancel || protectAbortedByInitialize) {
fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); msg_tiny_id = 0xFFFF;
return sectrue; usbTiny(0);
} fsm_sendFailure(FailureType_Failure_PinCancelled, NULL);
return sectrue;
}
return secfalse; return secfalse;
} }
bool protectPin(bool use_cached) bool protectPin(bool use_cached) {
{ if (use_cached && session_isUnlocked()) {
if (use_cached && session_isUnlocked()) { return true;
return true; }
}
const char *pin = ""; const char *pin = "";
if (config_hasPin()) { if (config_hasPin()) {
pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current,
if (!pin) { _("Please enter current PIN:"));
fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); if (!pin) {
return false; fsm_sendFailure(FailureType_Failure_PinCancelled, NULL);
} return false;
} }
}
bool ret = config_unlock(pin); bool ret = config_unlock(pin);
if (!ret) { if (!ret) {
fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); fsm_sendFailure(FailureType_Failure_PinInvalid, NULL);
} }
return ret; return ret;
} }
bool protectChangePin(bool removal) bool protectChangePin(bool removal) {
{ static CONFIDENTIAL char old_pin[MAX_PIN_LEN + 1] = "";
static CONFIDENTIAL char old_pin[MAX_PIN_LEN + 1] = ""; static CONFIDENTIAL char new_pin[MAX_PIN_LEN + 1] = "";
static CONFIDENTIAL char new_pin[MAX_PIN_LEN + 1] = ""; const char *pin = NULL;
const char* pin = NULL;
if (config_hasPin()) { if (config_hasPin()) {
pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, _("Please enter current PIN:")); pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current,
if (pin == NULL) { _("Please enter current PIN:"));
fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); if (pin == NULL) {
return false; fsm_sendFailure(FailureType_Failure_PinCancelled, NULL);
} return false;
}
// If removing, defer the check to config_changePin(). // If removing, defer the check to config_changePin().
if (!removal) { if (!removal) {
usbTiny(1); usbTiny(1);
bool ret = config_unlock(pin); bool ret = config_unlock(pin);
usbTiny(0); usbTiny(0);
if (ret == false) { if (ret == false) {
fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); fsm_sendFailure(FailureType_Failure_PinInvalid, NULL);
return false; return false;
} }
} }
strlcpy(old_pin, pin, sizeof(old_pin)); strlcpy(old_pin, pin, sizeof(old_pin));
} }
if (!removal) { if (!removal) {
pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst, _("Please enter new PIN:")); pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewFirst,
if (pin == NULL) { _("Please enter new PIN:"));
memzero(old_pin, sizeof(old_pin)); if (pin == NULL) {
fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); memzero(old_pin, sizeof(old_pin));
return false; fsm_sendFailure(FailureType_Failure_PinCancelled, NULL);
} return false;
strlcpy(new_pin, pin, sizeof(new_pin)); }
strlcpy(new_pin, pin, sizeof(new_pin));
pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewSecond, _("Please re-enter new PIN:")); pin = requestPin(PinMatrixRequestType_PinMatrixRequestType_NewSecond,
if (pin == NULL) { _("Please re-enter new PIN:"));
memzero(old_pin, sizeof(old_pin)); if (pin == NULL) {
memzero(new_pin, sizeof(new_pin)); memzero(old_pin, sizeof(old_pin));
fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); memzero(new_pin, sizeof(new_pin));
return false; fsm_sendFailure(FailureType_Failure_PinCancelled, NULL);
} return false;
}
if (strncmp(new_pin, pin, sizeof(new_pin)) != 0) { if (strncmp(new_pin, pin, sizeof(new_pin)) != 0) {
memzero(old_pin, sizeof(old_pin)); memzero(old_pin, sizeof(old_pin));
memzero(new_pin, sizeof(new_pin)); memzero(new_pin, sizeof(new_pin));
fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); fsm_sendFailure(FailureType_Failure_PinMismatch, NULL);
return false; return false;
} }
} }
bool ret = config_changePin(old_pin, new_pin); bool ret = config_changePin(old_pin, new_pin);
memzero(old_pin, sizeof(old_pin)); memzero(old_pin, sizeof(old_pin));
memzero(new_pin, sizeof(new_pin)); memzero(new_pin, sizeof(new_pin));
if (ret == false) { if (ret == false) {
fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); fsm_sendFailure(FailureType_Failure_PinInvalid, NULL);
} }
return ret; return ret;
} }
bool protectPassphrase(void) bool protectPassphrase(void) {
{ bool passphrase_protection = false;
bool passphrase_protection = false; config_getPassphraseProtection(&passphrase_protection);
config_getPassphraseProtection(&passphrase_protection); if (!passphrase_protection || session_isPassphraseCached()) {
if (!passphrase_protection || session_isPassphraseCached()) { return true;
return true; }
}
PassphraseRequest resp; PassphraseRequest resp;
memzero(&resp, sizeof(PassphraseRequest)); memzero(&resp, sizeof(PassphraseRequest));
usbTiny(1); usbTiny(1);
msg_write(MessageType_MessageType_PassphraseRequest, &resp); msg_write(MessageType_MessageType_PassphraseRequest, &resp);
layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter your"), _("passphrase using"), _("the computer's"), _("keyboard."), NULL, NULL); layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter your"),
_("passphrase using"), _("the computer's"), _("keyboard."),
NULL, NULL);
bool result; bool result;
for (;;) { for (;;) {
usbPoll(); usbPoll();
// TODO: correctly process PassphraseAck with state field set (mismatch => Failure) // TODO: correctly process PassphraseAck with state field set (mismatch =>
if (msg_tiny_id == MessageType_MessageType_PassphraseAck) { // Failure)
msg_tiny_id = 0xFFFF; if (msg_tiny_id == MessageType_MessageType_PassphraseAck) {
PassphraseAck *ppa = (PassphraseAck *)msg_tiny; msg_tiny_id = 0xFFFF;
session_cachePassphrase(ppa->has_passphrase ? ppa->passphrase : ""); PassphraseAck *ppa = (PassphraseAck *)msg_tiny;
result = true; session_cachePassphrase(ppa->has_passphrase ? ppa->passphrase : "");
break; result = true;
} break;
// check for Cancel / Initialize }
protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel); // check for Cancel / Initialize
protectAbortedByInitialize = (msg_tiny_id == MessageType_MessageType_Initialize); protectAbortedByCancel = (msg_tiny_id == MessageType_MessageType_Cancel);
if (protectAbortedByCancel || protectAbortedByInitialize) { protectAbortedByInitialize =
msg_tiny_id = 0xFFFF; (msg_tiny_id == MessageType_MessageType_Initialize);
result = false; if (protectAbortedByCancel || protectAbortedByInitialize) {
break; msg_tiny_id = 0xFFFF;
} result = false;
} break;
usbTiny(0); }
layoutHome(); }
return result; usbTiny(0);
layoutHome();
return result;
} }

View File

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

View File

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

View File

@ -18,21 +18,21 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <ctype.h>
#include "recovery.h" #include "recovery.h"
#include "fsm.h" #include <ctype.h>
#include "config.h"
#include "layout2.h"
#include "protect.h"
#include "messages.h"
#include "rng.h"
#include "bip39.h" #include "bip39.h"
#include "oled.h" #include "config.h"
#include "usb.h" #include "fsm.h"
#include "gettext.h" #include "gettext.h"
#include "recovery-table.h" #include "layout2.h"
#include "memzero.h" #include "memzero.h"
#include "messages.h"
#include "messages.pb.h" #include "messages.pb.h"
#include "oled.h"
#include "protect.h"
#include "recovery-table.h"
#include "rng.h"
#include "usb.h"
/* number of words expected in the new seed */ /* number of words expected in the new seed */
static uint32_t word_count; static uint32_t word_count;
@ -112,7 +112,7 @@ static uint8_t word_matrix[9];
* prefix length or table for the very first level, as the prefix length * prefix length or table for the very first level, as the prefix length
* is always one and there are always nine choices on the second level. * is always one and there are always nine choices on the second level.
*/ */
#define MASK_IDX(x) ((x) & 0xfff) #define MASK_IDX(x) ((x)&0xfff)
#define TABLE1(x) MASK_IDX(word_table1[x]) #define TABLE1(x) MASK_IDX(word_table1[x])
#define TABLE2(x) MASK_IDX(word_table2[x]) #define TABLE2(x) MASK_IDX(word_table2[x])
@ -122,93 +122,102 @@ static uint8_t word_matrix[9];
* Parameter number gives the number that we should format. * Parameter number gives the number that we should format.
*/ */
static void format_number(char *dest, int number) { static void format_number(char *dest, int number) {
if (number < 10) { if (number < 10) {
dest[0] = ' '; dest[0] = ' ';
} else { } else {
dest[0] = '0' + number / 10; dest[0] = '0' + number / 10;
} }
dest[1] = '0' + number % 10; dest[1] = '0' + number % 10;
if (number == 1 || number == 21) { if (number == 1 || number == 21) {
dest[2] = 's'; dest[3] = 't'; dest[2] = 's';
} else if (number == 2 || number == 22) { dest[3] = 't';
dest[2] = 'n'; dest[3] = 'd'; } else if (number == 2 || number == 22) {
} else if (number == 3 || number == 23) { dest[2] = 'n';
dest[2] = 'r'; dest[3] = 'd'; dest[3] = 'd';
} } else if (number == 3 || number == 23) {
dest[2] = 'r';
dest[3] = 'd';
}
} }
/* Send a request for a new word/matrix code to the PC. /* Send a request for a new word/matrix code to the PC.
*/ */
static void recovery_request(void) { static void recovery_request(void) {
WordRequest resp; WordRequest resp;
memzero(&resp, sizeof(WordRequest)); memzero(&resp, sizeof(WordRequest));
resp.has_type = true; resp.has_type = true;
resp.type = awaiting_word == 1 ? WordRequestType_WordRequestType_Plain resp.type = awaiting_word == 1
: (word_index % 4 == 3) ? WordRequestType_WordRequestType_Matrix6 ? WordRequestType_WordRequestType_Plain
: WordRequestType_WordRequestType_Matrix9; : (word_index % 4 == 3)
msg_write(MessageType_MessageType_WordRequest, &resp); ? WordRequestType_WordRequestType_Matrix6
: WordRequestType_WordRequestType_Matrix9;
msg_write(MessageType_MessageType_WordRequest, &resp);
} }
/* Called when the last word was entered. /* Called when the last word was entered.
* Check mnemonic and send success/failure. * Check mnemonic and send success/failure.
*/ */
static void recovery_done(void) { static void recovery_done(void) {
char new_mnemonic[MAX_MNEMONIC_LEN + 1] = {0}; char new_mnemonic[MAX_MNEMONIC_LEN + 1] = {0};
strlcpy(new_mnemonic, words[0], sizeof(new_mnemonic)); strlcpy(new_mnemonic, words[0], sizeof(new_mnemonic));
for (uint32_t i = 1; i < word_count; i++) { for (uint32_t i = 1; i < word_count; i++) {
strlcat(new_mnemonic, " ", sizeof(new_mnemonic)); strlcat(new_mnemonic, " ", sizeof(new_mnemonic));
strlcat(new_mnemonic, words[i], sizeof(new_mnemonic)); strlcat(new_mnemonic, words[i], sizeof(new_mnemonic));
} }
if (!enforce_wordlist || mnemonic_check(new_mnemonic)) { if (!enforce_wordlist || mnemonic_check(new_mnemonic)) {
// New mnemonic is valid. // New mnemonic is valid.
if (!dry_run) { if (!dry_run) {
// Update mnemonic on config. // Update mnemonic on config.
if (config_setMnemonic(new_mnemonic)) { if (config_setMnemonic(new_mnemonic)) {
if (!enforce_wordlist) { if (!enforce_wordlist) {
// not enforcing => mark config as imported // not enforcing => mark config as imported
config_setImported(true); config_setImported(true);
} }
fsm_sendSuccess(_("Device recovered")); fsm_sendSuccess(_("Device recovered"));
} else { } else {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); fsm_sendFailure(FailureType_Failure_ProcessError,
} _("Failed to store mnemonic"));
memzero(new_mnemonic, sizeof(new_mnemonic)); }
} else { memzero(new_mnemonic, sizeof(new_mnemonic));
// Inform the user about new mnemonic correctness (as well as whether it is the same as the current one). } else {
bool match = (config_isInitialized() && config_containsMnemonic(new_mnemonic)); // Inform the user about new mnemonic correctness (as well as whether it
memzero(new_mnemonic, sizeof(new_mnemonic)); // is the same as the current one).
if (match) { bool match =
layoutDialog(&bmp_icon_ok, NULL, _("Confirm"), NULL, (config_isInitialized() && config_containsMnemonic(new_mnemonic));
_("The seed is valid"), memzero(new_mnemonic, sizeof(new_mnemonic));
_("and MATCHES"), if (match) {
_("the one in the device."), NULL, NULL, NULL); layoutDialog(&bmp_icon_ok, NULL, _("Confirm"), NULL,
protectButton(ButtonRequestType_ButtonRequest_Other, true); _("The seed is valid"), _("and MATCHES"),
fsm_sendSuccess(_("The seed is valid and matches the one in the device")); _("the one in the device."), NULL, NULL, NULL);
} else { protectButton(ButtonRequestType_ButtonRequest_Other, true);
layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL, fsm_sendSuccess(
_("The seed is valid"), _("The seed is valid and matches the one in the device"));
_("but does NOT MATCH"), } else {
_("the one in the device."), NULL, NULL, NULL); layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL,
protectButton(ButtonRequestType_ButtonRequest_Other, true); _("The seed is valid"), _("but does NOT MATCH"),
fsm_sendFailure(FailureType_Failure_DataError, _("the one in the device."), NULL, NULL, NULL);
_("The seed is valid but does not match the one in the device")); protectButton(ButtonRequestType_ButtonRequest_Other, true);
} fsm_sendFailure(
} FailureType_Failure_DataError,
} else { _("The seed is valid but does not match the one in the device"));
// New mnemonic is invalid. }
memzero(new_mnemonic, sizeof(new_mnemonic)); }
if (!dry_run) { } else {
session_clear(true); // New mnemonic is invalid.
} else { memzero(new_mnemonic, sizeof(new_mnemonic));
layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL, if (!dry_run) {
_("The seed is"), _("INVALID!"), NULL, NULL, NULL, NULL); session_clear(true);
protectButton(ButtonRequestType_ButtonRequest_Other, true); } else {
} layoutDialog(&bmp_icon_error, NULL, _("Confirm"), NULL, _("The seed is"),
fsm_sendFailure(FailureType_Failure_DataError, _("Invalid seed, are words in correct order?")); _("INVALID!"), NULL, NULL, NULL, NULL);
} protectButton(ButtonRequestType_ButtonRequest_Other, true);
awaiting_word = 0; }
layoutHome(); fsm_sendFailure(FailureType_Failure_DataError,
_("Invalid seed, are words in correct order?"));
}
awaiting_word = 0;
layoutHome();
} }
/* Helper function for matrix recovery: /* Helper function for matrix recovery:
@ -222,36 +231,37 @@ static void recovery_done(void) {
* memcmp(last, "last + 1", prefixlen) != 0 * memcmp(last, "last + 1", prefixlen) != 0
* first[prefixlen-2] == last[prefixlen-2] except for range WI-Z. * first[prefixlen-2] == last[prefixlen-2] except for range WI-Z.
*/ */
static void add_choice(char choice[12], int prefixlen, const char *first, const char *last) { static void add_choice(char choice[12], int prefixlen, const char *first,
// assert 1 <= prefixlen <= 4 const char *last) {
char *dest = choice; // assert 1 <= prefixlen <= 4
for (int i = 0; i < prefixlen; i++) { char *dest = choice;
*dest++ = toupper((int) first[i]); for (int i = 0; i < prefixlen; i++) {
} *dest++ = toupper((int)first[i]);
if (first[0] != last[0]) { }
/* special case WI-Z; also used for T-Z, etc. */ if (first[0] != last[0]) {
*dest++ = '-'; /* special case WI-Z; also used for T-Z, etc. */
*dest++ = toupper((int) last[0]); *dest++ = '-';
} else if (last[prefixlen-1] == first[prefixlen-1]) { *dest++ = toupper((int)last[0]);
/* single prefix */ } else if (last[prefixlen - 1] == first[prefixlen - 1]) {
} else if (prefixlen < 3) { /* single prefix */
/* AB-AC, etc. */ } else if (prefixlen < 3) {
*dest++ = '-'; /* AB-AC, etc. */
for (int i = 0; i < prefixlen; i++) { *dest++ = '-';
*dest++ = toupper((int) last[i]); for (int i = 0; i < prefixlen; i++) {
} *dest++ = toupper((int)last[i]);
} else { }
/* RE[A-M] etc. */ } else {
/* remove last and replace with space */ /* RE[A-M] etc. */
dest[-1] = ' '; /* remove last and replace with space */
if (first[prefixlen - 1]) { dest[-1] = ' ';
/* handle special case: CAN[-D] */ if (first[prefixlen - 1]) {
*dest++ = toupper((int)first[prefixlen - 1]); /* handle special case: CAN[-D] */
} *dest++ = toupper((int)first[prefixlen - 1]);
*dest++ = '-'; }
*dest++ = toupper((int) last[prefixlen - 1]); *dest++ = '-';
} *dest++ = toupper((int)last[prefixlen - 1]);
*dest++ = 0; }
*dest++ = 0;
} }
/* Helper function for matrix recovery: /* Helper function for matrix recovery:
@ -259,122 +269,121 @@ static void add_choice(char choice[12], int prefixlen, const char *first, const
* use 2x3 layout, otherwise 3x3 layout. Also generates a random * use 2x3 layout, otherwise 3x3 layout. Also generates a random
* scrambling and stores it in word_matrix. * scrambling and stores it in word_matrix.
*/ */
static void display_choices(bool twoColumn, char choices[9][12], int num) static void display_choices(bool twoColumn, char choices[9][12], int num) {
{ const int nColumns = twoColumn ? 2 : 3;
const int nColumns = twoColumn ? 2 : 3; const int displayedChoices = nColumns * 3;
const int displayedChoices = nColumns * 3; for (int i = 0; i < displayedChoices; i++) {
for (int i = 0; i < displayedChoices; i++) { word_matrix[i] = i;
word_matrix[i] = i; }
} /* scramble matrix */
/* scramble matrix */ random_permute((char *)word_matrix, displayedChoices);
random_permute((char*)word_matrix, displayedChoices);
if (word_index % 4 == 0) { if (word_index % 4 == 0) {
char desc[] = "##th word"; char desc[] = "##th word";
int nr = (word_index / 4) + 1; int nr = (word_index / 4) + 1;
format_number(desc, nr); format_number(desc, nr);
layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter the"), (nr < 10 ? desc + 1 : desc), _("of your mnemonic"), NULL, NULL, NULL); layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter the"),
} else { (nr < 10 ? desc + 1 : desc), _("of your mnemonic"), NULL,
oledBox(0, 27, 127, 63, false); NULL, NULL);
} } else {
oledBox(0, 27, 127, 63, false);
}
for (int row = 0; row < 3; row ++) { for (int row = 0; row < 3; row++) {
int y = 55 - row * 11; int y = 55 - row * 11;
for (int col = 0; col < nColumns; col++) { for (int col = 0; col < nColumns; col++) {
int x = twoColumn ? 64 * col + 32 : 42 * col + 22; int x = twoColumn ? 64 * col + 32 : 42 * col + 22;
int choice = word_matrix[nColumns*row + col]; int choice = word_matrix[nColumns * row + col];
const char *text = choice < num ? choices[choice] : "-"; const char *text = choice < num ? choices[choice] : "-";
oledDrawString(x - oledStringWidth(text, FONT_STANDARD)/2, y, text, FONT_STANDARD); oledDrawString(x - oledStringWidth(text, FONT_STANDARD) / 2, y, text,
if (twoColumn) { FONT_STANDARD);
oledInvert(x - 32 + 1, y - 1, x - 32 + 63 - 1, y + 8); if (twoColumn) {
} else { oledInvert(x - 32 + 1, y - 1, x - 32 + 63 - 1, y + 8);
oledInvert(x - 22 + 1, y - 1, x - 22 + 41 - 1, y + 8); } else {
} oledInvert(x - 22 + 1, y - 1, x - 22 + 41 - 1, y + 8);
} }
} }
oledRefresh(); }
oledRefresh();
/* avoid picking out of range numbers */ /* avoid picking out of range numbers */
for (int i = 0; i < displayedChoices; i++) { for (int i = 0; i < displayedChoices; i++) {
if (word_matrix[i] >= num) if (word_matrix[i] >= num) word_matrix[i] = 0;
word_matrix[i] = 0; }
} /* two column layout: middle column = right column */
/* two column layout: middle column = right column */ if (twoColumn) {
if (twoColumn) { static const uint8_t twolayout[9] = {0, 1, 1, 2, 3, 3, 4, 5, 5};
static const uint8_t twolayout[9] = { 0, 1, 1, 2, 3, 3, 4, 5, 5 }; for (int i = 8; i >= 2; i--) {
for (int i = 8; i >= 2; i--) { word_matrix[i] = word_matrix[twolayout[i]];
word_matrix[i] = word_matrix[twolayout[i]]; }
} }
}
} }
/* Helper function for matrix recovery: /* Helper function for matrix recovery:
* Generates a new matrix and requests the next pin. * Generates a new matrix and requests the next pin.
*/ */
static void next_matrix(void) { static void next_matrix(void) {
const char * const *wl = mnemonic_wordlist(); const char *const *wl = mnemonic_wordlist();
char word_choices[9][12]; char word_choices[9][12];
uint32_t idx, num; uint32_t idx, num;
bool last = (word_index % 4) == 3; bool last = (word_index % 4) == 3;
/* Build the matrix: /* Build the matrix:
* num: number of choices * num: number of choices
* word_choices[][]: the strings containing the choices * word_choices[][]: the strings containing the choices
*/ */
switch (word_index % 4) { switch (word_index % 4) {
case 3: case 3:
/* last level: show up to six words */ /* last level: show up to six words */
/* idx: index in table2 for the entered choice. */ /* idx: index in table2 for the entered choice. */
/* first: the first word. */ /* first: the first word. */
/* num: the number of words to choose from. */ /* num: the number of words to choose from. */
idx = TABLE1(word_pincode / 9) + word_pincode % 9; idx = TABLE1(word_pincode / 9) + word_pincode % 9;
const uint32_t first = TABLE2(idx); const uint32_t first = TABLE2(idx);
num = TABLE2(idx + 1) - first; num = TABLE2(idx + 1) - first;
for (uint32_t i = 0; i < num; i++) { for (uint32_t i = 0; i < num; i++) {
strlcpy(word_choices[i], wl[first + i], sizeof(word_choices[i])); strlcpy(word_choices[i], wl[first + i], sizeof(word_choices[i]));
} }
break; break;
case 2: case 2:
/* third level: show up to nine ranges (using table2) */ /* third level: show up to nine ranges (using table2) */
/* idx: first index in table2 corresponding to pin code. */ /* idx: first index in table2 corresponding to pin code. */
/* num: the number of choices. */ /* num: the number of choices. */
idx = TABLE1(word_pincode); idx = TABLE1(word_pincode);
num = TABLE1(word_pincode + 1) - idx; num = TABLE1(word_pincode + 1) - idx;
for (uint32_t i = 0; i < num; i++) { for (uint32_t i = 0; i < num; i++) {
add_choice(word_choices[i], (word_table2[idx + i] >> 12), add_choice(word_choices[i], (word_table2[idx + i] >> 12),
wl[TABLE2(idx + i)], wl[TABLE2(idx + i)], wl[TABLE2(idx + i + 1) - 1]);
wl[TABLE2(idx + i + 1) - 1]); }
} break;
break;
case 1: case 1:
/* second level: exactly nine ranges (using table1) */ /* second level: exactly nine ranges (using table1) */
/* idx: first index in table1 corresponding to pin code. */ /* idx: first index in table1 corresponding to pin code. */
/* num: the number of choices. */ /* num: the number of choices. */
idx = word_pincode * 9; idx = word_pincode * 9;
num = 9; num = 9;
for (uint32_t i = 0; i < num; i++) { for (uint32_t i = 0; i < num; i++) {
add_choice(word_choices[i], (word_table1[idx + i] >> 12), add_choice(word_choices[i], (word_table1[idx + i] >> 12),
wl[TABLE2(TABLE1(idx + i))], wl[TABLE2(TABLE1(idx + i))],
wl[TABLE2(TABLE1(idx + i + 1)) - 1]); wl[TABLE2(TABLE1(idx + i + 1)) - 1]);
} }
break; break;
case 0: case 0:
/* first level: exactly nine ranges */ /* first level: exactly nine ranges */
/* num: the number of choices. */ /* num: the number of choices. */
num = 9; num = 9;
for (uint32_t i = 0; i < num; i++) { for (uint32_t i = 0; i < num; i++) {
add_choice(word_choices[i], 1, add_choice(word_choices[i], 1, wl[TABLE2(TABLE1(9 * i))],
wl[TABLE2(TABLE1(9*i))], wl[TABLE2(TABLE1(9 * (i + 1))) - 1]);
wl[TABLE2(TABLE1(9*(i+1)))-1]); }
} break;
break; }
} display_choices(last, word_choices, num);
display_choices(last, word_choices, num);
recovery_request(); recovery_request();
} }
/* Function called when a digit was entered by user. /* Function called when a digit was entered by user.
@ -382,202 +391,203 @@ static void next_matrix(void) {
* '\x08' for backspace. * '\x08' for backspace.
*/ */
static void recovery_digit(const char digit) { static void recovery_digit(const char digit) {
if (digit == 8) { if (digit == 8) {
/* backspace: undo */ /* backspace: undo */
if ((word_index % 4) == 0) { if ((word_index % 4) == 0) {
/* undo complete word */ /* undo complete word */
if (word_index > 0) if (word_index > 0) word_index -= 4;
word_index -= 4; } else {
} else { word_index--;
word_index--; word_pincode /= 9;
word_pincode /= 9; }
} next_matrix();
next_matrix(); return;
return; }
}
if (digit < '1' || digit > '9') { if (digit < '1' || digit > '9') {
recovery_request(); recovery_request();
return; return;
} }
int choice = word_matrix[digit - '1']; int choice = word_matrix[digit - '1'];
if ((word_index % 4) == 3) { if ((word_index % 4) == 3) {
/* received final word */ /* received final word */
/* Mark the chosen word for 250 ms */ /* Mark the chosen word for 250 ms */
int y = 54 - ((digit - '1') / 3) * 11; int y = 54 - ((digit - '1') / 3) * 11;
int x = 64 * (((digit - '1') % 3) > 0); int x = 64 * (((digit - '1') % 3) > 0);
oledInvert(x + 1, y, x + 62, y + 9); oledInvert(x + 1, y, x + 62, y + 9);
oledRefresh(); oledRefresh();
usbTiny(1); usbTiny(1);
usbSleep(250); usbSleep(250);
usbTiny(0); usbTiny(0);
/* index of the chosen word */ /* index of the chosen word */
int idx = TABLE2(TABLE1(word_pincode / 9) + (word_pincode % 9)) + choice; int idx = TABLE2(TABLE1(word_pincode / 9) + (word_pincode % 9)) + choice;
uint32_t widx = word_index / 4; uint32_t widx = word_index / 4;
word_pincode = 0; word_pincode = 0;
strlcpy(words[widx], mnemonic_wordlist()[idx], sizeof(words[widx])); strlcpy(words[widx], mnemonic_wordlist()[idx], sizeof(words[widx]));
if (widx + 1 == word_count) { if (widx + 1 == word_count) {
recovery_done(); recovery_done();
return; return;
} }
/* next word */ /* next word */
} else { } else {
word_pincode = word_pincode * 9 + choice; word_pincode = word_pincode * 9 + choice;
} }
word_index++; word_index++;
next_matrix(); next_matrix();
} }
/* Helper function for scrambled recovery: /* Helper function for scrambled recovery:
* Ask the user for the next word. * Ask the user for the next word.
*/ */
void next_word(void) { void next_word(void) {
word_pos = word_order[word_index]; word_pos = word_order[word_index];
if (word_pos == 0) { if (word_pos == 0) {
const char * const *wl = mnemonic_wordlist(); const char *const *wl = mnemonic_wordlist();
strlcpy(fake_word, wl[random_uniform(2048)], sizeof(fake_word)); strlcpy(fake_word, wl[random_uniform(2048)], sizeof(fake_word));
layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter the word"), NULL, fake_word, NULL, _("on your computer"), NULL); layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL,
} else { _("Please enter the word"), NULL, fake_word, NULL,
fake_word[0] = 0; _("on your computer"), NULL);
char desc[] = "##th word"; } else {
format_number(desc, word_pos); fake_word[0] = 0;
layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, _("Please enter the"), NULL, (word_pos < 10 ? desc + 1 : desc), NULL, _("of your mnemonic"), NULL); char desc[] = "##th word";
} format_number(desc, word_pos);
recovery_request(); 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,
if (_word_count != 12 && _word_count != 18 && _word_count != 24) return; 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; word_count = _word_count;
enforce_wordlist = _enforce_wordlist; enforce_wordlist = _enforce_wordlist;
dry_run = _dry_run; dry_run = _dry_run;
if (!dry_run) { if (!dry_run) {
layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("recover the device?"), NULL, NULL, NULL, NULL); layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL,
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { _("Do you really want to"), _("recover the device?"),
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); NULL, NULL, NULL, NULL);
layoutHome(); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
return; fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
} layoutHome();
} return;
}
}
if (!dry_run) { if (!dry_run) {
if (pin_protection && !protectChangePin(false)) { if (pin_protection && !protectChangePin(false)) {
layoutHome(); layoutHome();
return; return;
} }
config_setPassphraseProtection(passphrase_protection); config_setPassphraseProtection(passphrase_protection);
config_setLanguage(language); config_setLanguage(language);
config_setLabel(label); config_setLabel(label);
config_setU2FCounter(u2f_counter); config_setU2FCounter(u2f_counter);
} }
if ((type & RecoveryDeviceType_RecoveryDeviceType_Matrix) != 0) { if ((type & RecoveryDeviceType_RecoveryDeviceType_Matrix) != 0) {
awaiting_word = 2; awaiting_word = 2;
word_index = 0; word_index = 0;
word_pincode = 0; word_pincode = 0;
next_matrix(); next_matrix();
} else { } else {
for (uint32_t i = 0; i < word_count; i++) { for (uint32_t i = 0; i < word_count; i++) {
word_order[i] = i + 1; word_order[i] = i + 1;
} }
for (uint32_t i = word_count; i < 24; i++) { for (uint32_t i = word_count; i < 24; i++) {
word_order[i] = 0; word_order[i] = 0;
} }
random_permute(word_order, 24); random_permute(word_order, 24);
awaiting_word = 1; awaiting_word = 1;
word_index = 0; word_index = 0;
next_word(); next_word();
} }
} }
static void recovery_scrambledword(const char *word) static void recovery_scrambledword(const char *word) {
{ if (word_pos == 0) { // fake word
if (word_pos == 0) { // fake word if (strcmp(word, fake_word) != 0) {
if (strcmp(word, fake_word) != 0) { if (!dry_run) {
if (!dry_run) { session_clear(true);
session_clear(true); }
} fsm_sendFailure(FailureType_Failure_ProcessError,
fsm_sendFailure(FailureType_Failure_ProcessError, _("Wrong word retyped")); _("Wrong word retyped"));
layoutHome(); layoutHome();
return; return;
} }
} else { // real word } else { // real word
if (enforce_wordlist) { // check if word is valid if (enforce_wordlist) { // check if word is valid
const char * const *wl = mnemonic_wordlist(); const char *const *wl = mnemonic_wordlist();
bool found = false; bool found = false;
while (*wl) { while (*wl) {
if (strcmp(word, *wl) == 0) { if (strcmp(word, *wl) == 0) {
found = true; found = true;
break; break;
} }
wl++; wl++;
} }
if (!found) { if (!found) {
if (!dry_run) { if (!dry_run) {
session_clear(true); session_clear(true);
} }
fsm_sendFailure(FailureType_Failure_DataError, _("Word not found in a wordlist")); fsm_sendFailure(FailureType_Failure_DataError,
layoutHome(); _("Word not found in a wordlist"));
return; layoutHome();
} return;
} }
strlcpy(words[word_pos - 1], word, sizeof(words[word_pos - 1])); }
} strlcpy(words[word_pos - 1], word, sizeof(words[word_pos - 1]));
}
if (word_index + 1 == 24) { // last one if (word_index + 1 == 24) { // last one
recovery_done(); recovery_done();
} else { } else {
word_index++; word_index++;
next_word(); next_word();
} }
} }
/* Function called when a word was entered by user. Used /* Function called when a word was entered by user. Used
* for scrambled recovery. * for scrambled recovery.
*/ */
void recovery_word(const char *word) void recovery_word(const char *word) {
{ switch (awaiting_word) {
switch (awaiting_word) { case 2:
case 2: recovery_digit(word[0]);
recovery_digit(word[0]); break;
break; case 1:
case 1: recovery_scrambledword(word);
recovery_scrambledword(word); break;
break; default:
default: fsm_sendFailure(FailureType_Failure_UnexpectedMessage,
fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Recovery mode")); _("Not in Recovery mode"));
break; break;
} }
} }
/* Abort recovery. /* Abort recovery.
*/ */
void recovery_abort(void) void recovery_abort(void) {
{ if (awaiting_word) {
if (awaiting_word) { layoutHome();
layoutHome(); awaiting_word = 0;
awaiting_word = 0; }
}
} }
#if DEBUG_LINK #if DEBUG_LINK
const char *recovery_get_fake_word(void) const char *recovery_get_fake_word(void) { return fake_word; }
{
return fake_word;
}
uint32_t recovery_get_word_pos(void) uint32_t recovery_get_word_pos(void) { return word_pos; }
{
return word_pos;
}
#endif #endif

View File

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

View File

@ -18,180 +18,189 @@
*/ */
#include "reset.h" #include "reset.h"
#include "bip39.h"
#include "config.h" #include "config.h"
#include "fsm.h"
#include "gettext.h"
#include "layout2.h"
#include "memzero.h"
#include "messages.h"
#include "messages.pb.h"
#include "protect.h"
#include "rng.h" #include "rng.h"
#include "sha2.h" #include "sha2.h"
#include "messages.h"
#include "fsm.h"
#include "layout2.h"
#include "protect.h"
#include "bip39.h"
#include "util.h" #include "util.h"
#include "gettext.h"
#include "messages.pb.h"
#include "memzero.h"
static uint32_t strength; static uint32_t strength;
static uint8_t int_entropy[32]; static uint8_t int_entropy[32];
static bool awaiting_entropy = false; static bool awaiting_entropy = false;
static bool skip_backup = false; static bool skip_backup = false;
static bool no_backup = false; static bool no_backup = false;
void reset_init(bool display_random, uint32_t _strength, bool passphrase_protection, bool pin_protection, const char *language, const char *label, uint32_t u2f_counter, bool _skip_backup, bool _no_backup) void reset_init(bool display_random, uint32_t _strength,
{ bool passphrase_protection, bool pin_protection,
if (_strength != 128 && _strength != 192 && _strength != 256) return; 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; strength = _strength;
skip_backup = _skip_backup; skip_backup = _skip_backup;
no_backup = _no_backup; no_backup = _no_backup;
if (display_random && (skip_backup || no_backup)) { if (display_random && (skip_backup || no_backup)) {
fsm_sendFailure(FailureType_Failure_ProcessError, "Can't show internal entropy when backup is skipped"); fsm_sendFailure(FailureType_Failure_ProcessError,
layoutHome(); "Can't show internal entropy when backup is skipped");
return; 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,
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { _("Do you really want to"), _("create a new wallet?"), NULL,
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); _("By continuing you"), _("agree to trezor.io/tos"), NULL);
layoutHome(); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
return; fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
} layoutHome();
return;
}
random_buffer(int_entropy, 32); random_buffer(int_entropy, 32);
char ent_str[4][17]; char ent_str[4][17];
data2hex(int_entropy , 8, ent_str[0]); data2hex(int_entropy, 8, ent_str[0]);
data2hex(int_entropy + 8, 8, ent_str[1]); data2hex(int_entropy + 8, 8, ent_str[1]);
data2hex(int_entropy + 16, 8, ent_str[2]); data2hex(int_entropy + 16, 8, ent_str[2]);
data2hex(int_entropy + 24, 8, ent_str[3]); data2hex(int_entropy + 24, 8, ent_str[3]);
if (display_random) { if (display_random) {
layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Continue"), NULL, _("Internal entropy:"), ent_str[0], ent_str[1], ent_str[2], ent_str[3], NULL); layoutDialogSwipe(&bmp_icon_info, _("Cancel"), _("Continue"), NULL,
if (!protectButton(ButtonRequestType_ButtonRequest_ResetDevice, false)) { _("Internal entropy:"), ent_str[0], ent_str[1],
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); ent_str[2], ent_str[3], NULL);
layoutHome(); if (!protectButton(ButtonRequestType_ButtonRequest_ResetDevice, false)) {
return; fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
} layoutHome();
} return;
}
}
if (pin_protection && !protectChangePin(false)) { if (pin_protection && !protectChangePin(false)) {
layoutHome(); layoutHome();
return; return;
} }
config_setPassphraseProtection(passphrase_protection); config_setPassphraseProtection(passphrase_protection);
config_setLanguage(language); config_setLanguage(language);
config_setLabel(label); config_setLabel(label);
config_setU2FCounter(u2f_counter); config_setU2FCounter(u2f_counter);
EntropyRequest resp; EntropyRequest resp;
memzero(&resp, sizeof(EntropyRequest)); memzero(&resp, sizeof(EntropyRequest));
msg_write(MessageType_MessageType_EntropyRequest, &resp); msg_write(MessageType_MessageType_EntropyRequest, &resp);
awaiting_entropy = true; awaiting_entropy = true;
} }
void reset_entropy(const uint8_t *ext_entropy, uint32_t len) void reset_entropy(const uint8_t *ext_entropy, uint32_t len) {
{ if (!awaiting_entropy) {
if (!awaiting_entropy) { fsm_sendFailure(FailureType_Failure_UnexpectedMessage,
fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Not in Reset mode")); _("Not in Reset mode"));
return; return;
} }
awaiting_entropy = false; awaiting_entropy = false;
SHA256_CTX ctx; SHA256_CTX ctx;
sha256_Init(&ctx); sha256_Init(&ctx);
sha256_Update(&ctx, int_entropy, 32); sha256_Update(&ctx, int_entropy, 32);
sha256_Update(&ctx, ext_entropy, len); sha256_Update(&ctx, ext_entropy, len);
sha256_Final(&ctx, int_entropy); sha256_Final(&ctx, int_entropy);
const char* mnemonic = mnemonic_from_data(int_entropy, strength / 8); const char *mnemonic = mnemonic_from_data(int_entropy, strength / 8);
memzero(int_entropy, 32); memzero(int_entropy, 32);
if (skip_backup || no_backup) { if (skip_backup || no_backup) {
if (no_backup) { if (no_backup) {
config_setNoBackup(); config_setNoBackup();
} else { } else {
config_setNeedsBackup(true); config_setNeedsBackup(true);
} }
if (config_setMnemonic(mnemonic)) { if (config_setMnemonic(mnemonic)) {
fsm_sendSuccess(_("Device successfully initialized")); fsm_sendSuccess(_("Device successfully initialized"));
} else { } else {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); fsm_sendFailure(FailureType_Failure_ProcessError,
} _("Failed to store mnemonic"));
layoutHome(); }
} else { layoutHome();
reset_backup(false, mnemonic); } else {
} reset_backup(false, mnemonic);
mnemonic_clear(); }
mnemonic_clear();
} }
static char current_word[10]; static char current_word[10];
// separated == true if called as a separate workflow via BackupMessage // separated == true if called as a separate workflow via BackupMessage
void reset_backup(bool separated, const char* mnemonic) void reset_backup(bool separated, const char *mnemonic) {
{ if (separated) {
if (separated) { bool needs_backup = false;
bool needs_backup = false; config_getNeedsBackup(&needs_backup);
config_getNeedsBackup(&needs_backup); if (!needs_backup) {
if (!needs_backup) { fsm_sendFailure(FailureType_Failure_UnexpectedMessage,
fsm_sendFailure(FailureType_Failure_UnexpectedMessage, _("Seed already backed up")); _("Seed already backed up"));
return; return;
} }
config_setUnfinishedBackup(true); config_setUnfinishedBackup(true);
config_setNeedsBackup(false); config_setNeedsBackup(false);
} }
for (int pass = 0; pass < 2; pass++) { for (int pass = 0; pass < 2; pass++) {
int i = 0, word_pos = 1; int i = 0, word_pos = 1;
while (mnemonic[i] != 0) { while (mnemonic[i] != 0) {
// copy current_word // copy current_word
int j = 0; int j = 0;
while (mnemonic[i] != ' ' && mnemonic[i] != 0 && j + 1 < (int)sizeof(current_word)) { while (mnemonic[i] != ' ' && mnemonic[i] != 0 &&
current_word[j] = mnemonic[i]; j + 1 < (int)sizeof(current_word)) {
i++; j++; current_word[j] = mnemonic[i];
} i++;
current_word[j] = 0; j++;
if (mnemonic[i] != 0) { }
i++; current_word[j] = 0;
} if (mnemonic[i] != 0) {
layoutResetWord(current_word, pass, word_pos, mnemonic[i] == 0); i++;
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) { }
if (!separated) { layoutResetWord(current_word, pass, word_pos, mnemonic[i] == 0);
session_clear(true); if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) {
} if (!separated) {
layoutHome(); session_clear(true);
fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); }
return; layoutHome();
} fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL);
word_pos++; return;
} }
} word_pos++;
}
}
config_setUnfinishedBackup(false); config_setUnfinishedBackup(false);
if (separated) { if (separated) {
fsm_sendSuccess(_("Seed successfully backed up")); fsm_sendSuccess(_("Seed successfully backed up"));
} else { } else {
config_setNeedsBackup(false); config_setNeedsBackup(false);
if (config_setMnemonic(mnemonic)) { if (config_setMnemonic(mnemonic)) {
fsm_sendSuccess(_("Device successfully initialized")); fsm_sendSuccess(_("Device successfully initialized"));
} else { } else {
fsm_sendFailure(FailureType_Failure_ProcessError, _("Failed to store mnemonic")); fsm_sendFailure(FailureType_Failure_ProcessError,
} _("Failed to store mnemonic"));
} }
layoutHome(); }
layoutHome();
} }
#if DEBUG_LINK #if DEBUG_LINK
uint32_t reset_get_int_entropy(uint8_t *entropy) { uint32_t reset_get_int_entropy(uint8_t *entropy) {
memcpy(entropy, int_entropy, 32); memcpy(entropy, int_entropy, 32);
return 32; return 32;
} }
const char *reset_get_word(void) { const char *reset_get_word(void) { return current_word; }
return current_word;
}
#endif #endif

View File

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

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -21,11 +21,11 @@
#define __STELLAR_H__ #define __STELLAR_H__
#include <stdbool.h> #include <stdbool.h>
#include "base32.h"
#include "bip32.h" #include "bip32.h"
#include "crypto.h" #include "crypto.h"
#include "messages.pb.h"
#include "fsm.h" #include "fsm.h"
#include "base32.h" #include "messages.pb.h"
// 56 character base-32 encoded string // 56 character base-32 encoded string
#define STELLAR_ADDRESS_SIZE 56 #define STELLAR_ADDRESS_SIZE 56
@ -35,32 +35,34 @@
#define STELLAR_KEY_SIZE 32 #define STELLAR_KEY_SIZE 32
typedef struct { typedef struct {
// BIP32 path to the address being used for signing // BIP32 path to the address being used for signing
uint32_t address_n[10]; uint32_t address_n[10];
size_t address_n_count; size_t address_n_count;
uint8_t signing_pubkey[32]; uint8_t signing_pubkey[32];
// 1 - public network, 2 - official testnet, 3 - other private network // 1 - public network, 2 - official testnet, 3 - other private network
uint8_t network_type; uint8_t network_type;
// Total number of operations expected // Total number of operations expected
uint32_t num_operations; uint32_t num_operations;
// Number that have been confirmed by the user // Number that have been confirmed by the user
uint32_t confirmed_operations; uint32_t confirmed_operations;
// sha256 context that will eventually be signed // sha256 context that will eventually be signed
SHA256_CTX sha256_ctx; SHA256_CTX sha256_ctx;
} StellarTransaction; } StellarTransaction;
// Signing process // Signing process
bool stellar_signingInit(const StellarSignTx *tx); bool stellar_signingInit(const StellarSignTx *tx);
void stellar_signingAbort(const char *reason); void stellar_signingAbort(const char *reason);
bool stellar_confirmSourceAccount(bool has_source_account, const char *str_account); bool stellar_confirmSourceAccount(bool has_source_account,
const char *str_account);
bool stellar_confirmCreateAccountOp(const StellarCreateAccountOp *msg); bool stellar_confirmCreateAccountOp(const StellarCreateAccountOp *msg);
bool stellar_confirmPaymentOp(const StellarPaymentOp *msg); bool stellar_confirmPaymentOp(const StellarPaymentOp *msg);
bool stellar_confirmPathPaymentOp(const StellarPathPaymentOp *msg); bool stellar_confirmPathPaymentOp(const StellarPathPaymentOp *msg);
bool stellar_confirmManageOfferOp(const StellarManageOfferOp *msg); bool stellar_confirmManageOfferOp(const StellarManageOfferOp *msg);
bool stellar_confirmCreatePassiveOfferOp(const StellarCreatePassiveOfferOp *msg); bool stellar_confirmCreatePassiveOfferOp(
const StellarCreatePassiveOfferOp *msg);
bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg); bool stellar_confirmSetOptionsOp(const StellarSetOptionsOp *msg);
bool stellar_confirmChangeTrustOp(const StellarChangeTrustOp *msg); bool stellar_confirmChangeTrustOp(const StellarChangeTrustOp *msg);
bool stellar_confirmAllowTrustOp(const StellarAllowTrustOp *msg); bool stellar_confirmAllowTrustOp(const StellarAllowTrustOp *msg);
@ -69,14 +71,22 @@ bool stellar_confirmManageDataOp(const StellarManageDataOp *msg);
bool stellar_confirmBumpSequenceOp(const StellarBumpSequenceOp *msg); bool stellar_confirmBumpSequenceOp(const StellarBumpSequenceOp *msg);
// Layout // Layout
void stellar_layoutTransactionDialog(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5); void stellar_layoutTransactionDialog(const char *line1, const char *line2,
const char *line3, const char *line4,
const char *line5);
void stellar_layoutTransactionSummary(const StellarSignTx *msg); void stellar_layoutTransactionSummary(const StellarSignTx *msg);
void stellar_layoutSigningDialog(const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, uint32_t *address_n, size_t address_n_count, const char *warning, bool is_final_step); void stellar_layoutSigningDialog(const char *line1, const char *line2,
const char *line3, const char *line4,
const char *line5, uint32_t *address_n,
size_t address_n_count, const char *warning,
bool is_final_step);
// Helpers // Helpers
const HDNode *stellar_deriveNode(const uint32_t *address_n, size_t address_n_count); const HDNode *stellar_deriveNode(const uint32_t *address_n,
size_t address_n_count);
size_t stellar_publicAddressAsStr(const uint8_t *bytes, char *out, size_t outlen); size_t stellar_publicAddressAsStr(const uint8_t *bytes, char *out,
size_t outlen);
const char **stellar_lineBreakAddress(const uint8_t *addrbytes); const char **stellar_lineBreakAddress(const uint8_t *addrbytes);
void stellar_hashupdate_uint32(uint32_t value); void stellar_hashupdate_uint32(uint32_t value);
@ -94,11 +104,13 @@ void stellar_getSignatureForActiveTx(uint8_t *out_signature);
void stellar_format_uint32(uint32_t number, char *out, size_t outlen); void stellar_format_uint32(uint32_t number, char *out, size_t outlen);
void stellar_format_uint64(uint64_t number, char *out, size_t outlen); void stellar_format_uint64(uint64_t number, char *out, size_t outlen);
void stellar_format_stroops(uint64_t number, char *out, size_t outlen); void stellar_format_stroops(uint64_t number, char *out, size_t outlen);
void stellar_format_asset(const StellarAssetType *asset, char *str_formatted, size_t len); void stellar_format_asset(const StellarAssetType *asset, char *str_formatted,
void stellar_format_price(uint32_t numerator, uint32_t denominator, char *out, size_t outlen); size_t len);
void stellar_format_price(uint32_t numerator, uint32_t denominator, char *out,
size_t outlen);
bool stellar_validateAddress(const char *str_address); bool stellar_validateAddress(const char *str_address);
bool stellar_getAddressBytes(const char* str_address, uint8_t *out_bytes); bool stellar_getAddressBytes(const char *str_address, uint8_t *out_bytes);
uint16_t stellar_crc16(uint8_t *bytes, uint32_t length); uint16_t stellar_crc16(uint8_t *bytes, uint32_t length);
#endif #endif

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -17,140 +17,143 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "common.h"
#include "trezor.h" #include "trezor.h"
#include "oled.h"
#include "bitmaps.h" #include "bitmaps.h"
#include "util.h" #include "bl_check.h"
#include "usb.h" #include "buttons.h"
#include "setup.h" #include "common.h"
#include "config.h" #include "config.h"
#include "gettext.h"
#include "layout.h" #include "layout.h"
#include "layout2.h" #include "layout2.h"
#include "rng.h"
#include "timer.h"
#include "buttons.h"
#include "gettext.h"
#include "bl_check.h"
#include "memzero.h" #include "memzero.h"
#include "oled.h"
#include "rng.h"
#include "setup.h"
#include "timer.h"
#include "usb.h"
#include "util.h"
#if !EMULATOR #if !EMULATOR
#include "otp.h"
#include <libopencm3/stm32/desig.h> #include <libopencm3/stm32/desig.h>
#include "otp.h"
#endif #endif
/* Screen timeout */ /* Screen timeout */
uint32_t system_millis_lock_start; uint32_t system_millis_lock_start;
void check_lock_screen(void) void check_lock_screen(void) {
{ buttonUpdate();
buttonUpdate();
// wake from screensaver on any button // wake from screensaver on any button
if (layoutLast == layoutScreensaver && (button.NoUp || button.YesUp)) { if (layoutLast == layoutScreensaver && (button.NoUp || button.YesUp)) {
layoutHome(); layoutHome();
return; return;
} }
// button held for long enough (2 seconds) // button held for long enough (2 seconds)
if (layoutLast == layoutHome && button.NoDown >= 285000 * 2) { if (layoutLast == layoutHome && button.NoDown >= 285000 * 2) {
layoutDialog(&bmp_icon_question, _("Cancel"), _("Lock Device"), NULL,
_("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);
do {
usbSleep(5);
buttonUpdate();
} while (!button.NoUp);
// wait until NoButton is released // wait for confirmation/cancellation of the dialog
usbTiny(1); do {
do { usbSleep(5);
usbSleep(5); buttonUpdate();
buttonUpdate(); } while (!button.YesUp && !button.NoUp);
} while (!button.NoUp); usbTiny(0);
// wait for confirmation/cancellation of the dialog if (button.YesUp) {
do { // lock the screen
usbSleep(5); session_clear(true);
buttonUpdate(); layoutScreensaver();
} while (!button.YesUp && !button.NoUp); } else {
usbTiny(0); // resume homescreen
layoutHome();
}
}
if (button.YesUp) { // if homescreen is shown for too long
// lock the screen if (layoutLast == layoutHome) {
session_clear(true); if ((timer_ms() - system_millis_lock_start) >=
layoutScreensaver(); config_getAutoLockDelayMs()) {
} else { // lock the screen
// resume homescreen session_clear(true);
layoutHome(); layoutScreensaver();
} }
} }
// if homescreen is shown for too long
if (layoutLast == layoutHome) {
if ((timer_ms() - system_millis_lock_start) >= config_getAutoLockDelayMs()) {
// lock the screen
session_clear(true);
layoutScreensaver();
}
}
} }
static void collect_hw_entropy(bool privileged) static void collect_hw_entropy(bool privileged) {
{
#if EMULATOR #if EMULATOR
(void)privileged; (void)privileged;
memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN); memzero(HW_ENTROPY_DATA, HW_ENTROPY_LEN);
#else #else
if (privileged) { if (privileged) {
desig_get_unique_id((uint32_t *)HW_ENTROPY_DATA); desig_get_unique_id((uint32_t *)HW_ENTROPY_DATA);
// set entropy in the OTP randomness block // set entropy in the OTP randomness block
if (!flash_otp_is_locked(FLASH_OTP_BLOCK_RANDOMNESS)) { if (!flash_otp_is_locked(FLASH_OTP_BLOCK_RANDOMNESS)) {
uint8_t entropy[FLASH_OTP_BLOCK_SIZE]; uint8_t entropy[FLASH_OTP_BLOCK_SIZE];
random_buffer(entropy, FLASH_OTP_BLOCK_SIZE); random_buffer(entropy, FLASH_OTP_BLOCK_SIZE);
flash_otp_write(FLASH_OTP_BLOCK_RANDOMNESS, 0, entropy, FLASH_OTP_BLOCK_SIZE); flash_otp_write(FLASH_OTP_BLOCK_RANDOMNESS, 0, entropy,
flash_otp_lock(FLASH_OTP_BLOCK_RANDOMNESS); 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); // collect entropy from OTP randomness block
} else { flash_otp_read(FLASH_OTP_BLOCK_RANDOMNESS, 0, HW_ENTROPY_DATA + 12,
// unprivileged mode => use fixed HW_ENTROPY FLASH_OTP_BLOCK_SIZE);
memset(HW_ENTROPY_DATA, 0x3C, HW_ENTROPY_LEN); } else {
} // unprivileged mode => use fixed HW_ENTROPY
memset(HW_ENTROPY_DATA, 0x3C, HW_ENTROPY_LEN);
}
#endif #endif
} }
int main(void) int main(void) {
{
#ifndef APPVER #ifndef APPVER
setup(); setup();
__stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks __stack_chk_guard = random32(); // this supports compiler provided
oledInit(); // unpredictable stack protection checks
oledInit();
#else #else
check_bootloader(); check_bootloader();
setupApp(); setupApp();
__stack_chk_guard = random32(); // this supports compiler provided unpredictable stack protection checks __stack_chk_guard = random32(); // this supports compiler provided
// unpredictable stack protection checks
#endif #endif
if (!is_mode_unprivileged()) { if (!is_mode_unprivileged()) {
collect_hw_entropy(true); collect_hw_entropy(true);
timer_init(); timer_init();
#ifdef APPVER #ifdef APPVER
// enable MPU (Memory Protection Unit) // enable MPU (Memory Protection Unit)
mpu_config_firmware(); mpu_config_firmware();
#endif #endif
} else { } else {
collect_hw_entropy(false); collect_hw_entropy(false);
} }
#if DEBUG_LINK #if DEBUG_LINK
oledSetDebugLink(1); oledSetDebugLink(1);
config_wipe(); config_wipe();
#endif #endif
oledDrawBitmap(40, 0, &bmp_logo64); oledDrawBitmap(40, 0, &bmp_logo64);
oledRefresh(); oledRefresh();
config_init(); config_init();
layoutHome(); layoutHome();
usbInit(); usbInit();
for (;;) { for (;;) {
usbPoll(); usbPoll();
check_lock_screen(); check_lock_screen();
} }
return 0; return 0;
} }

File diff suppressed because it is too large Load Diff

View File

@ -20,17 +20,17 @@
#ifndef __U2F_H__ #ifndef __U2F_H__
#define __U2F_H__ #define __U2F_H__
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include "u2f/u2f_hid.h" #include <stdint.h>
#include "trezor.h" #include "trezor.h"
#include "u2f/u2f_hid.h"
#define U2F_KEY_PATH 0x80553246 #define U2F_KEY_PATH 0x80553246
typedef struct { typedef struct {
uint8_t cla, ins, p1, p2; uint8_t cla, ins, p1, p2;
uint8_t lc1, lc2, lc3; uint8_t lc1, lc2, lc3;
uint8_t data[]; uint8_t data[];
} APDU; } APDU;
#define APDU_LEN(A) (uint32_t)(((A).lc1 << 16) + ((A).lc2 << 8) + ((A).lc3)) #define APDU_LEN(A) (uint32_t)(((A).lc1 << 16) + ((A).lc2 << 8) + ((A).lc3))
@ -56,7 +56,7 @@ void send_u2f_msg(const uint8_t *data, uint32_t len);
void send_u2f_error(uint16_t err); void send_u2f_error(uint16_t err);
void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data,
const uint32_t len); const uint32_t len);
void send_u2fhid_error(uint32_t fcid, uint8_t err); void send_u2fhid_error(uint32_t fcid, uint8_t err);
#endif #endif

View File

@ -4,37 +4,35 @@
#include <stdint.h> #include <stdint.h>
const uint8_t U2F_ATT_PRIV_KEY[] = { const uint8_t U2F_ATT_PRIV_KEY[] = {
0x71, 0x26, 0xac, 0x2b, 0xf6, 0x44, 0xdc, 0x61, 0x71, 0x26, 0xac, 0x2b, 0xf6, 0x44, 0xdc, 0x61, 0x86, 0xad, 0x83,
0x86, 0xad, 0x83, 0xef, 0x1f, 0xcd, 0xf1, 0x2a, 0xef, 0x1f, 0xcd, 0xf1, 0x2a, 0x57, 0xb5, 0xcf, 0xa2, 0x00, 0x0b,
0x57, 0xb5, 0xcf, 0xa2, 0x00, 0x0b, 0x8a, 0xd0, 0x8a, 0xd0, 0x27, 0xe9, 0x56, 0xe8, 0x54, 0xc5, 0x0a, 0x8b};
0x27, 0xe9, 0x56, 0xe8, 0x54, 0xc5, 0x0a, 0x8b
};
const uint8_t U2F_ATT_CERT[] = { const uint8_t U2F_ATT_CERT[] = {
0x30, 0x82, 0x01, 0x18, 0x30, 0x81, 0xc0, 0x02, 0x09, 0x00, 0xb1, 0xd9, 0x30, 0x82, 0x01, 0x18, 0x30, 0x81, 0xc0, 0x02, 0x09, 0x00, 0xb1, 0xd9,
0x8f, 0x42, 0x64, 0x72, 0xd3, 0x2c, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x8f, 0x42, 0x64, 0x72, 0xd3, 0x2c, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11,
0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0a, 0x54, 0x72, 0x65, 0x7a, 0x6f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0a, 0x54, 0x72, 0x65, 0x7a, 0x6f,
0x72, 0x20, 0x55, 0x32, 0x46, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30, 0x72, 0x20, 0x55, 0x32, 0x46, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30,
0x34, 0x32, 0x39, 0x31, 0x33, 0x33, 0x31, 0x35, 0x33, 0x5a, 0x17, 0x0d, 0x34, 0x32, 0x39, 0x31, 0x33, 0x33, 0x31, 0x35, 0x33, 0x5a, 0x17, 0x0d,
0x32, 0x36, 0x30, 0x34, 0x32, 0x37, 0x31, 0x33, 0x33, 0x31, 0x35, 0x33, 0x32, 0x36, 0x30, 0x34, 0x32, 0x37, 0x31, 0x33, 0x33, 0x31, 0x35, 0x33,
0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03,
0x0c, 0x0a, 0x54, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x20, 0x55, 0x32, 0x46, 0x0c, 0x0a, 0x54, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x20, 0x55, 0x32, 0x46,
0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
0x42, 0x00, 0x04, 0xd9, 0x18, 0xbd, 0xfa, 0x8a, 0x54, 0xac, 0x92, 0xe9, 0x42, 0x00, 0x04, 0xd9, 0x18, 0xbd, 0xfa, 0x8a, 0x54, 0xac, 0x92, 0xe9,
0x0d, 0xa9, 0x1f, 0xca, 0x7a, 0xa2, 0x64, 0x54, 0xc0, 0xd1, 0x73, 0x36, 0x0d, 0xa9, 0x1f, 0xca, 0x7a, 0xa2, 0x64, 0x54, 0xc0, 0xd1, 0x73, 0x36,
0x31, 0x4d, 0xde, 0x83, 0xa5, 0x4b, 0x86, 0xb5, 0xdf, 0x4e, 0xf0, 0x52, 0x31, 0x4d, 0xde, 0x83, 0xa5, 0x4b, 0x86, 0xb5, 0xdf, 0x4e, 0xf0, 0x52,
0x65, 0x9a, 0x1d, 0x6f, 0xfc, 0xb7, 0x46, 0x7f, 0x1a, 0xcd, 0xdb, 0x8a, 0x65, 0x9a, 0x1d, 0x6f, 0xfc, 0xb7, 0x46, 0x7f, 0x1a, 0xcd, 0xdb, 0x8a,
0x33, 0x08, 0x0b, 0x5e, 0xed, 0x91, 0x89, 0x13, 0xf4, 0x43, 0xa5, 0x26, 0x33, 0x08, 0x0b, 0x5e, 0xed, 0x91, 0x89, 0x13, 0xf4, 0x43, 0xa5, 0x26,
0x1b, 0xc7, 0x7b, 0x68, 0x60, 0x6f, 0xc1, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x1b, 0xc7, 0x7b, 0x68, 0x60, 0x6f, 0xc1, 0x30, 0x0a, 0x06, 0x08, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x47, 0x00, 0x30, 0x44, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x47, 0x00, 0x30, 0x44,
0x02, 0x20, 0x24, 0x1e, 0x81, 0xff, 0xd2, 0xe5, 0xe6, 0x15, 0x36, 0x94, 0x02, 0x20, 0x24, 0x1e, 0x81, 0xff, 0xd2, 0xe5, 0xe6, 0x15, 0x36, 0x94,
0xc3, 0x55, 0x2e, 0x8f, 0xeb, 0xd7, 0x1e, 0x89, 0x35, 0x92, 0x1c, 0xb4, 0xc3, 0x55, 0x2e, 0x8f, 0xeb, 0xd7, 0x1e, 0x89, 0x35, 0x92, 0x1c, 0xb4,
0x83, 0x41, 0x43, 0x71, 0x1c, 0x76, 0xea, 0xee, 0xf3, 0x95, 0x02, 0x20, 0x83, 0x41, 0x43, 0x71, 0x1c, 0x76, 0xea, 0xee, 0xf3, 0x95, 0x02, 0x20,
0x5f, 0x80, 0xeb, 0x10, 0xf2, 0x5c, 0xcc, 0x39, 0x8b, 0x3c, 0xa8, 0xa9, 0x5f, 0x80, 0xeb, 0x10, 0xf2, 0x5c, 0xcc, 0x39, 0x8b, 0x3c, 0xa8, 0xa9,
0xad, 0xa4, 0x02, 0x7f, 0x93, 0x13, 0x20, 0x77, 0xb7, 0xab, 0xce, 0x77, 0xad, 0xa4, 0x02, 0x7f, 0x93, 0x13, 0x20, 0x77, 0xb7, 0xab, 0xce, 0x77,
0x46, 0x5a, 0x27, 0xf5, 0x3d, 0x33, 0xa1, 0x1d, 0x46, 0x5a, 0x27, 0xf5, 0x3d, 0x33, 0xa1, 0x1d,
}; };
#endif // __U2F_KEYS_H_INCLUDED__ #endif // __U2F_KEYS_H_INCLUDED__

View File

@ -24,14 +24,15 @@
#include "u2f/u2f.h" #include "u2f/u2f.h"
typedef struct { typedef struct {
const uint8_t appid[U2F_APPID_SIZE]; const uint8_t appid[U2F_APPID_SIZE];
const char *appname; const char *appname;
} U2FWellKnown; } U2FWellKnown;
// contents generated via script in // contents generated via script in
// trezor-common/defs/webauthn/gen.py // trezor-common/defs/webauthn/gen.py
// do not edit manually // do not edit manually
// clang-format off
static const U2FWellKnown u2f_well_known[] = { static const U2FWellKnown u2f_well_known[] = {
{ {
// U2F: https://bitbucket.org // U2F: https://bitbucket.org
@ -144,5 +145,6 @@ static const U2FWellKnown u2f_well_known[] = {
"demo.yubico.com" "demo.yubico.com"
}, },
}; };
// clang-format on
#endif // U2F_KNOWNAPPS_INCLUDED #endif // U2F_KNOWNAPPS_INCLUDED

View File

@ -21,15 +21,13 @@
#include "usb.h" #include "usb.h"
#include "debug.h"
#include "messages.h" #include "messages.h"
#include "timer.h" #include "timer.h"
#include "debug.h"
static volatile char tiny = 0; static volatile char tiny = 0;
void usbInit(void) { void usbInit(void) { emulatorSocketInit(); }
emulatorSocketInit();
}
#if DEBUG_LINK #if DEBUG_LINK
#define _ISDBG (((iface == 1) ? 'd' : 'n')) #define _ISDBG (((iface == 1) ? 'd' : 'n'))
@ -38,42 +36,42 @@ void usbInit(void) {
#endif #endif
void usbPoll(void) { void usbPoll(void) {
emulatorPoll(); emulatorPoll();
static uint8_t buffer[64]; static uint8_t buffer[64];
int iface = 0; int iface = 0;
if (emulatorSocketRead(&iface, buffer, sizeof(buffer)) > 0) { if (emulatorSocketRead(&iface, buffer, sizeof(buffer)) > 0) {
if (!tiny) { if (!tiny) {
msg_read_common(_ISDBG, buffer, sizeof(buffer)); msg_read_common(_ISDBG, buffer, sizeof(buffer));
} else { } else {
msg_read_tiny(buffer, sizeof(buffer)); msg_read_tiny(buffer, sizeof(buffer));
} }
} }
const uint8_t *data = msg_out_data(); const uint8_t *data = msg_out_data();
if (data != NULL) { if (data != NULL) {
emulatorSocketWrite(0, data, 64); emulatorSocketWrite(0, data, 64);
} }
#if DEBUG_LINK #if DEBUG_LINK
data = msg_debug_out_data(); data = msg_debug_out_data();
if (data != NULL) { if (data != NULL) {
emulatorSocketWrite(1, data, 64); emulatorSocketWrite(1, data, 64);
} }
#endif #endif
} }
char usbTiny(char set) { char usbTiny(char set) {
char old = tiny; char old = tiny;
tiny = set; tiny = set;
return old; return old;
} }
void usbSleep(uint32_t millis) { void usbSleep(uint32_t millis) {
uint32_t start = timer_ms(); uint32_t start = timer_ms();
while ((timer_ms() - start) < millis) { while ((timer_ms() - start) < millis) {
usbPoll(); usbPoll();
} }
} }

View File

@ -17,23 +17,22 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/hid.h> #include <libopencm3/usb/hid.h>
#include <libopencm3/usb/usbd.h>
#include "trezor.h" #include "config.h"
#include "usb.h"
#include "debug.h" #include "debug.h"
#include "messages.h" #include "messages.h"
#include "u2f.h"
#include "config.h"
#include "util.h"
#include "timer.h" #include "timer.h"
#include "trezor.h"
#include "u2f.h"
#include "usb.h"
#include "util.h"
#include "usb21_standard.h" #include "usb21_standard.h"
#include "webusb.h" #include "webusb.h"
#include "winusb.h" #include "winusb.h"
#define USB_INTERFACE_INDEX_MAIN 0 #define USB_INTERFACE_INDEX_MAIN 0
#if DEBUG_LINK #if DEBUG_LINK
#define USB_INTERFACE_INDEX_DEBUG 1 #define USB_INTERFACE_INDEX_DEBUG 1
@ -44,370 +43,381 @@
#define USB_INTERFACE_COUNT 2 #define USB_INTERFACE_COUNT 2
#endif #endif
#define ENDPOINT_ADDRESS_MAIN_IN (0x81) #define ENDPOINT_ADDRESS_MAIN_IN (0x81)
#define ENDPOINT_ADDRESS_MAIN_OUT (0x01) #define ENDPOINT_ADDRESS_MAIN_OUT (0x01)
#if DEBUG_LINK #if DEBUG_LINK
#define ENDPOINT_ADDRESS_DEBUG_IN (0x82) #define ENDPOINT_ADDRESS_DEBUG_IN (0x82)
#define ENDPOINT_ADDRESS_DEBUG_OUT (0x02) #define ENDPOINT_ADDRESS_DEBUG_OUT (0x02)
#endif #endif
#define ENDPOINT_ADDRESS_U2F_IN (0x83) #define ENDPOINT_ADDRESS_U2F_IN (0x83)
#define ENDPOINT_ADDRESS_U2F_OUT (0x03) #define ENDPOINT_ADDRESS_U2F_OUT (0x03)
#define USB_STRINGS \ #define USB_STRINGS \
X(MANUFACTURER, "SatoshiLabs") \ X(MANUFACTURER, "SatoshiLabs") \
X(PRODUCT, "TREZOR") \ X(PRODUCT, "TREZOR") \
X(SERIAL_NUMBER, config_uuid_str) \ X(SERIAL_NUMBER, config_uuid_str) \
X(INTERFACE_MAIN, "TREZOR Interface") \ X(INTERFACE_MAIN, "TREZOR Interface") \
X(INTERFACE_DEBUG, "TREZOR Debug Link Interface") \ X(INTERFACE_DEBUG, "TREZOR Debug Link Interface") \
X(INTERFACE_U2F, "TREZOR U2F Interface") \ X(INTERFACE_U2F, "TREZOR U2F Interface")
#define X(name, value) USB_STRING_##name, #define X(name, value) USB_STRING_##name,
enum { enum {
USB_STRING_LANGID_CODES, // LANGID code array USB_STRING_LANGID_CODES, // LANGID code array
USB_STRINGS USB_STRINGS
}; };
#undef X #undef X
#define X(name, value) value, #define X(name, value) value,
static const char *usb_strings[] = { static const char *usb_strings[] = {USB_STRINGS};
USB_STRINGS
};
#undef X #undef X
static const struct usb_device_descriptor dev_descr = { static const struct usb_device_descriptor dev_descr = {
.bLength = USB_DT_DEVICE_SIZE, .bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE, .bDescriptorType = USB_DT_DEVICE,
.bcdUSB = 0x0210, .bcdUSB = 0x0210,
.bDeviceClass = 0, .bDeviceClass = 0,
.bDeviceSubClass = 0, .bDeviceSubClass = 0,
.bDeviceProtocol = 0, .bDeviceProtocol = 0,
.bMaxPacketSize0 = 64, .bMaxPacketSize0 = 64,
.idVendor = 0x1209, .idVendor = 0x1209,
.idProduct = 0x53c1, .idProduct = 0x53c1,
.bcdDevice = 0x0100, .bcdDevice = 0x0100,
.iManufacturer = USB_STRING_MANUFACTURER, .iManufacturer = USB_STRING_MANUFACTURER,
.iProduct = USB_STRING_PRODUCT, .iProduct = USB_STRING_PRODUCT,
.iSerialNumber = USB_STRING_SERIAL_NUMBER, .iSerialNumber = USB_STRING_SERIAL_NUMBER,
.bNumConfigurations = 1, .bNumConfigurations = 1,
}; };
static const uint8_t hid_report_descriptor_u2f[] = { static const uint8_t hid_report_descriptor_u2f[] = {
0x06, 0xd0, 0xf1, // USAGE_PAGE (FIDO Alliance) 0x06, 0xd0, 0xf1, // USAGE_PAGE (FIDO Alliance)
0x09, 0x01, // USAGE (U2F HID Authenticator Device) 0x09, 0x01, // USAGE (U2F HID Authenticator Device)
0xa1, 0x01, // COLLECTION (Application) 0xa1, 0x01, // COLLECTION (Application)
0x09, 0x20, // USAGE (Input Report Data) 0x09, 0x20, // USAGE (Input Report Data)
0x15, 0x00, // LOGICAL_MINIMUM (0) 0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8) 0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x40, // REPORT_COUNT (64) 0x95, 0x40, // REPORT_COUNT (64)
0x81, 0x02, // INPUT (Data,Var,Abs) 0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x21, // USAGE (Output Report Data) 0x09, 0x21, // USAGE (Output Report Data)
0x15, 0x00, // LOGICAL_MINIMUM (0) 0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8) 0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x40, // REPORT_COUNT (64) 0x95, 0x40, // REPORT_COUNT (64)
0x91, 0x02, // OUTPUT (Data,Var,Abs) 0x91, 0x02, // OUTPUT (Data,Var,Abs)
0xc0 // END_COLLECTION 0xc0 // END_COLLECTION
}; };
static const struct { static const struct {
struct usb_hid_descriptor hid_descriptor_u2f; struct usb_hid_descriptor hid_descriptor_u2f;
struct { struct {
uint8_t bReportDescriptorType; uint8_t bReportDescriptorType;
uint16_t wDescriptorLength; uint16_t wDescriptorLength;
} __attribute__((packed)) hid_report_u2f; } __attribute__((packed)) hid_report_u2f;
} __attribute__((packed)) hid_function_u2f = { } __attribute__((packed))
.hid_descriptor_u2f = { hid_function_u2f = {.hid_descriptor_u2f =
.bLength = sizeof(hid_function_u2f), {
.bDescriptorType = USB_DT_HID, .bLength = sizeof(hid_function_u2f),
.bcdHID = 0x0111, .bDescriptorType = USB_DT_HID,
.bCountryCode = 0, .bcdHID = 0x0111,
.bNumDescriptors = 1, .bCountryCode = 0,
}, .bNumDescriptors = 1,
.hid_report_u2f = { },
.bReportDescriptorType = USB_DT_REPORT, .hid_report_u2f = {
.wDescriptorLength = sizeof(hid_report_descriptor_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, .bLength = USB_DT_ENDPOINT_SIZE,
.bEndpointAddress = ENDPOINT_ADDRESS_U2F_IN, .bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .bEndpointAddress = ENDPOINT_ADDRESS_U2F_IN,
.wMaxPacketSize = 64, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.bInterval = 1, .wMaxPacketSize = 64,
}, { .bInterval = 1,
.bLength = USB_DT_ENDPOINT_SIZE, },
.bDescriptorType = USB_DT_ENDPOINT, {
.bEndpointAddress = ENDPOINT_ADDRESS_U2F_OUT, .bLength = USB_DT_ENDPOINT_SIZE,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .bDescriptorType = USB_DT_ENDPOINT,
.wMaxPacketSize = 64, .bEndpointAddress = ENDPOINT_ADDRESS_U2F_OUT,
.bInterval = 1, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
}}; .wMaxPacketSize = 64,
.bInterval = 1,
}};
static const struct usb_interface_descriptor hid_iface_u2f[] = {{ static const struct usb_interface_descriptor hid_iface_u2f[] = {{
.bLength = USB_DT_INTERFACE_SIZE, .bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE, .bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = USB_INTERFACE_INDEX_U2F, .bInterfaceNumber = USB_INTERFACE_INDEX_U2F,
.bAlternateSetting = 0, .bAlternateSetting = 0,
.bNumEndpoints = 2, .bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_HID, .bInterfaceClass = USB_CLASS_HID,
.bInterfaceSubClass = 0, .bInterfaceSubClass = 0,
.bInterfaceProtocol = 0, .bInterfaceProtocol = 0,
.iInterface = USB_STRING_INTERFACE_U2F, .iInterface = USB_STRING_INTERFACE_U2F,
.endpoint = hid_endpoints_u2f, .endpoint = hid_endpoints_u2f,
.extra = &hid_function_u2f, .extra = &hid_function_u2f,
.extralen = sizeof(hid_function_u2f), .extralen = sizeof(hid_function_u2f),
}}; }};
#if DEBUG_LINK #if DEBUG_LINK
static const struct usb_endpoint_descriptor webusb_endpoints_debug[2] = {{ static const struct usb_endpoint_descriptor webusb_endpoints_debug[2] = {
.bLength = USB_DT_ENDPOINT_SIZE, {
.bDescriptorType = USB_DT_ENDPOINT, .bLength = USB_DT_ENDPOINT_SIZE,
.bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_IN, .bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_IN,
.wMaxPacketSize = 64, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.bInterval = 1, .wMaxPacketSize = 64,
}, { .bInterval = 1,
.bLength = USB_DT_ENDPOINT_SIZE, },
.bDescriptorType = USB_DT_ENDPOINT, {
.bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_OUT, .bLength = USB_DT_ENDPOINT_SIZE,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .bDescriptorType = USB_DT_ENDPOINT,
.wMaxPacketSize = 64, .bEndpointAddress = ENDPOINT_ADDRESS_DEBUG_OUT,
.bInterval = 1, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
}}; .wMaxPacketSize = 64,
.bInterval = 1,
}};
static const struct usb_interface_descriptor webusb_iface_debug[] = {{ static const struct usb_interface_descriptor webusb_iface_debug[] = {{
.bLength = USB_DT_INTERFACE_SIZE, .bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE, .bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = USB_INTERFACE_INDEX_DEBUG, .bInterfaceNumber = USB_INTERFACE_INDEX_DEBUG,
.bAlternateSetting = 0, .bAlternateSetting = 0,
.bNumEndpoints = 2, .bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_VENDOR, .bInterfaceClass = USB_CLASS_VENDOR,
.bInterfaceSubClass = 0, .bInterfaceSubClass = 0,
.bInterfaceProtocol = 0, .bInterfaceProtocol = 0,
.iInterface = USB_STRING_INTERFACE_DEBUG, .iInterface = USB_STRING_INTERFACE_DEBUG,
.endpoint = webusb_endpoints_debug, .endpoint = webusb_endpoints_debug,
.extra = NULL, .extra = NULL,
.extralen = 0, .extralen = 0,
}}; }};
#endif #endif
static const struct usb_endpoint_descriptor webusb_endpoints_main[2] = {{ static const struct usb_endpoint_descriptor webusb_endpoints_main[2] = {
.bLength = USB_DT_ENDPOINT_SIZE, {
.bDescriptorType = USB_DT_ENDPOINT, .bLength = USB_DT_ENDPOINT_SIZE,
.bEndpointAddress = ENDPOINT_ADDRESS_MAIN_IN, .bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_IN,
.wMaxPacketSize = 64, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.bInterval = 1, .wMaxPacketSize = 64,
}, { .bInterval = 1,
.bLength = USB_DT_ENDPOINT_SIZE, },
.bDescriptorType = USB_DT_ENDPOINT, {
.bEndpointAddress = ENDPOINT_ADDRESS_MAIN_OUT, .bLength = USB_DT_ENDPOINT_SIZE,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .bDescriptorType = USB_DT_ENDPOINT,
.wMaxPacketSize = 64, .bEndpointAddress = ENDPOINT_ADDRESS_MAIN_OUT,
.bInterval = 1, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
}}; .wMaxPacketSize = 64,
.bInterval = 1,
}};
static const struct usb_interface_descriptor webusb_iface_main[] = {{ static const struct usb_interface_descriptor webusb_iface_main[] = {{
.bLength = USB_DT_INTERFACE_SIZE, .bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE, .bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN,
.bAlternateSetting = 0, .bAlternateSetting = 0,
.bNumEndpoints = 2, .bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_VENDOR, .bInterfaceClass = USB_CLASS_VENDOR,
.bInterfaceSubClass = 0, .bInterfaceSubClass = 0,
.bInterfaceProtocol = 0, .bInterfaceProtocol = 0,
.iInterface = USB_STRING_INTERFACE_MAIN, .iInterface = USB_STRING_INTERFACE_MAIN,
.endpoint = webusb_endpoints_main, .endpoint = webusb_endpoints_main,
.extra = NULL, .extra = NULL,
.extralen = 0, .extralen = 0,
}}; }};
// Windows are strict about interfaces appearing // Windows are strict about interfaces appearing
// in correct order // in correct order
static const struct usb_interface ifaces[] = {{ static const struct usb_interface ifaces[] = {
.num_altsetting = 1, {
.altsetting = webusb_iface_main, .num_altsetting = 1,
.altsetting = webusb_iface_main,
#if DEBUG_LINK #if DEBUG_LINK
}, { },
.num_altsetting = 1, {
.altsetting = webusb_iface_debug, .num_altsetting = 1,
.altsetting = webusb_iface_debug,
#endif #endif
}, { },
.num_altsetting = 1, {
.altsetting = hid_iface_u2f, .num_altsetting = 1,
}}; .altsetting = hid_iface_u2f,
}};
static const struct usb_config_descriptor config = { static const struct usb_config_descriptor config = {
.bLength = USB_DT_CONFIGURATION_SIZE, .bLength = USB_DT_CONFIGURATION_SIZE,
.bDescriptorType = USB_DT_CONFIGURATION, .bDescriptorType = USB_DT_CONFIGURATION,
.wTotalLength = 0, .wTotalLength = 0,
.bNumInterfaces = USB_INTERFACE_COUNT, .bNumInterfaces = USB_INTERFACE_COUNT,
.bConfigurationValue = 1, .bConfigurationValue = 1,
.iConfiguration = 0, .iConfiguration = 0,
.bmAttributes = 0x80, .bmAttributes = 0x80,
.bMaxPower = 0x32, .bMaxPower = 0x32,
.interface = ifaces, .interface = ifaces,
}; };
static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete) static int hid_control_request(usbd_device *dev, struct usb_setup_data *req,
{ uint8_t **buf, uint16_t *len,
(void)complete; usbd_control_complete_callback *complete) {
(void)dev; (void)complete;
(void)dev;
wait_random(); wait_random();
if ((req->bmRequestType != 0x81) || if ((req->bmRequestType != 0x81) ||
(req->bRequest != USB_REQ_GET_DESCRIPTOR) || (req->bRequest != USB_REQ_GET_DESCRIPTOR) || (req->wValue != 0x2200))
(req->wValue != 0x2200)) return 0;
return 0;
debugLog(0, "", "hid_control_request u2f"); debugLog(0, "", "hid_control_request u2f");
*buf = (uint8_t *)hid_report_descriptor_u2f; *buf = (uint8_t *)hid_report_descriptor_u2f;
*len = MIN_8bits(*len, sizeof(hid_report_descriptor_u2f)); *len = MIN_8bits(*len, sizeof(hid_report_descriptor_u2f));
return 1; return 1;
} }
static volatile char tiny = 0; static volatile char tiny = 0;
static void main_rx_callback(usbd_device *dev, uint8_t ep) static void main_rx_callback(usbd_device *dev, uint8_t ep) {
{ (void)ep;
(void)ep; static CONFIDENTIAL uint8_t buf[64] __attribute__((aligned(4)));
static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4))); if (usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_MAIN_OUT, buf, 64) != 64)
if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_MAIN_OUT, buf, 64) != 64) return; return;
debugLog(0, "", "main_rx_callback"); debugLog(0, "", "main_rx_callback");
if (!tiny) { if (!tiny) {
msg_read(buf, 64); msg_read(buf, 64);
} else { } else {
msg_read_tiny(buf, 64); msg_read_tiny(buf, 64);
} }
} }
static void u2f_rx_callback(usbd_device *dev, uint8_t ep) static void u2f_rx_callback(usbd_device *dev, uint8_t ep) {
{ (void)ep;
(void)ep; static CONFIDENTIAL uint8_t buf[64] __attribute__((aligned(4)));
static CONFIDENTIAL uint8_t buf[64] __attribute__ ((aligned(4)));
debugLog(0, "", "u2f_rx_callback"); debugLog(0, "", "u2f_rx_callback");
if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_U2F_OUT, buf, 64) != 64) return; if (usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_U2F_OUT, buf, 64) != 64) return;
u2fhid_read(tiny, (const U2FHID_FRAME *) (void*) buf); u2fhid_read(tiny, (const U2FHID_FRAME *)(void *)buf);
} }
#if DEBUG_LINK #if DEBUG_LINK
static void debug_rx_callback(usbd_device *dev, uint8_t ep) static void debug_rx_callback(usbd_device *dev, uint8_t ep) {
{ (void)ep;
(void)ep; static uint8_t buf[64] __attribute__((aligned(4)));
static uint8_t buf[64] __attribute__ ((aligned(4))); if (usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_DEBUG_OUT, buf, 64) != 64)
if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_DEBUG_OUT, buf, 64) != 64) return; return;
debugLog(0, "", "debug_rx_callback"); debugLog(0, "", "debug_rx_callback");
if (!tiny) { if (!tiny) {
msg_debug_read(buf, 64); msg_debug_read(buf, 64);
} else { } else {
msg_read_tiny(buf, 64); msg_read_tiny(buf, 64);
} }
} }
#endif #endif
static void set_config(usbd_device *dev, uint16_t wValue) static void set_config(usbd_device *dev, uint16_t wValue) {
{ (void)wValue;
(void)wValue;
usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64,
usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, main_rx_callback); 0);
usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); usbd_ep_setup(dev, ENDPOINT_ADDRESS_MAIN_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64,
usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, u2f_rx_callback); main_rx_callback);
usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64,
0);
usbd_ep_setup(dev, ENDPOINT_ADDRESS_U2F_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64,
u2f_rx_callback);
#if DEBUG_LINK #if DEBUG_LINK
usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0); usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64,
usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, debug_rx_callback); 0);
usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_OUT, USB_ENDPOINT_ATTR_INTERRUPT,
64, debug_rx_callback);
#endif #endif
usbd_register_control_callback( usbd_register_control_callback(
dev, dev, USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE,
USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE, USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, hid_control_request);
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
hid_control_request);
} }
static usbd_device *usbd_dev = NULL; static usbd_device *usbd_dev = NULL;
static uint8_t usbd_control_buffer[256] __attribute__ ((aligned (2))); static uint8_t usbd_control_buffer[256] __attribute__((aligned(2)));
static const struct usb_device_capability_descriptor* capabilities[] = { static const struct usb_device_capability_descriptor *capabilities[] = {
(const struct usb_device_capability_descriptor*)&webusb_platform_capability_descriptor_no_landing_page, (const struct usb_device_capability_descriptor
*)&webusb_platform_capability_descriptor_no_landing_page,
}; };
static const struct usb_bos_descriptor bos_descriptor = { static const struct usb_bos_descriptor bos_descriptor = {
.bLength = USB_DT_BOS_SIZE, .bLength = USB_DT_BOS_SIZE,
.bDescriptorType = USB_DT_BOS, .bDescriptorType = USB_DT_BOS,
.bNumDeviceCaps = sizeof(capabilities)/sizeof(capabilities[0]), .bNumDeviceCaps = sizeof(capabilities) / sizeof(capabilities[0]),
.capabilities = capabilities .capabilities = capabilities};
};
void usbInit(void) void usbInit(void) {
{ usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings,
usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, sizeof(usb_strings) / sizeof(*usb_strings), usbd_control_buffer, sizeof(usbd_control_buffer)); sizeof(usb_strings) / sizeof(*usb_strings),
usbd_register_set_config_callback(usbd_dev, set_config); usbd_control_buffer, sizeof(usbd_control_buffer));
usb21_setup(usbd_dev, &bos_descriptor); usbd_register_set_config_callback(usbd_dev, set_config);
static const char* origin_url = "trezor.io/start"; usb21_setup(usbd_dev, &bos_descriptor);
webusb_setup(usbd_dev, origin_url); static const char *origin_url = "trezor.io/start";
// Debug link interface does not have WinUSB set; webusb_setup(usbd_dev, origin_url);
// if you really need debug link on windows, edit the descriptor in winusb.c // Debug link interface does not have WinUSB set;
winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN); // if you really need debug link on windows, edit the descriptor in winusb.c
winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN);
} }
void usbPoll(void) void usbPoll(void) {
{ if (usbd_dev == NULL) {
if (usbd_dev == NULL) { return;
return; }
}
static const uint8_t *data; static const uint8_t *data;
// poll read buffer // poll read buffer
usbd_poll(usbd_dev); usbd_poll(usbd_dev);
// write pending data // write pending data
data = msg_out_data(); data = msg_out_data();
if (data) { if (data) {
while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_MAIN_IN, data, 64) != 64 ) {} while (usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_MAIN_IN, data, 64) !=
} 64) {
data = u2f_out_data(); }
if (data) { }
while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_U2F_IN, data, 64) != 64 ) {} data = u2f_out_data();
} if (data) {
while (usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_U2F_IN, data, 64) !=
64) {
}
}
#if DEBUG_LINK #if DEBUG_LINK
// write pending debug data // write pending debug data
data = msg_debug_out_data(); data = msg_debug_out_data();
if (data) { if (data) {
while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_DEBUG_IN, data, 64) != 64 ) {} while (usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_DEBUG_IN, data,
} 64) != 64) {
}
}
#endif #endif
} }
void usbReconnect(void) void usbReconnect(void) {
{ if (usbd_dev != NULL) {
if (usbd_dev != NULL) { usbd_disconnect(usbd_dev, 1);
usbd_disconnect(usbd_dev, 1); delay(1000);
delay(1000); usbd_disconnect(usbd_dev, 0);
usbd_disconnect(usbd_dev, 0); }
}
} }
char usbTiny(char set) char usbTiny(char set) {
{ char old = tiny;
char old = tiny; tiny = set;
tiny = set; return old;
return old;
} }
void usbSleep(uint32_t millis) void usbSleep(uint32_t millis) {
{ uint32_t start = timer_ms();
uint32_t start = timer_ms();
while ((timer_ms() - start) < millis) { while ((timer_ms() - start) < millis) {
if (usbd_dev != NULL) { if (usbd_dev != NULL) {
usbd_poll(usbd_dev); usbd_poll(usbd_dev);
} }
} }
} }

185
flash.c
View File

@ -17,8 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h>
#include <libopencm3/stm32/flash.h> #include <libopencm3/stm32/flash.h>
#include <string.h>
#include "common.h" #include "common.h"
#include "flash.h" #include "flash.h"
@ -26,112 +26,105 @@
#include "supervise.h" #include "supervise.h"
static const uint32_t FLASH_SECTOR_TABLE[FLASH_SECTOR_COUNT + 1] = { static const uint32_t FLASH_SECTOR_TABLE[FLASH_SECTOR_COUNT + 1] = {
[ 0] = 0x08000000, // - 0x08003FFF | 16 KiB [0] = 0x08000000, // - 0x08003FFF | 16 KiB
[ 1] = 0x08004000, // - 0x08007FFF | 16 KiB [1] = 0x08004000, // - 0x08007FFF | 16 KiB
[ 2] = 0x08008000, // - 0x0800BFFF | 16 KiB [2] = 0x08008000, // - 0x0800BFFF | 16 KiB
[ 3] = 0x0800C000, // - 0x0800FFFF | 16 KiB [3] = 0x0800C000, // - 0x0800FFFF | 16 KiB
[ 4] = 0x08010000, // - 0x0801FFFF | 64 KiB [4] = 0x08010000, // - 0x0801FFFF | 64 KiB
[ 5] = 0x08020000, // - 0x0803FFFF | 128 KiB [5] = 0x08020000, // - 0x0803FFFF | 128 KiB
[ 6] = 0x08040000, // - 0x0805FFFF | 128 KiB [6] = 0x08040000, // - 0x0805FFFF | 128 KiB
[ 7] = 0x08060000, // - 0x0807FFFF | 128 KiB [7] = 0x08060000, // - 0x0807FFFF | 128 KiB
[ 8] = 0x08080000, // - 0x0809FFFF | 128 KiB [8] = 0x08080000, // - 0x0809FFFF | 128 KiB
[ 9] = 0x080A0000, // - 0x080BFFFF | 128 KiB [9] = 0x080A0000, // - 0x080BFFFF | 128 KiB
[10] = 0x080C0000, // - 0x080DFFFF | 128 KiB [10] = 0x080C0000, // - 0x080DFFFF | 128 KiB
[11] = 0x080E0000, // - 0x080FFFFF | 128 KiB [11] = 0x080E0000, // - 0x080FFFFF | 128 KiB
[12] = 0x08100000, // last element - not a valid sector [12] = 0x08100000, // last element - not a valid sector
}; };
static secbool flash_check_success(uint32_t status) static secbool flash_check_success(uint32_t status) {
{ return (status & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR |
return (status & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) ? secfalse : sectrue; FLASH_SR_WRPERR))
? secfalse
: sectrue;
} }
void flash_init(void) void flash_init(void) {}
{
secbool flash_unlock_write(void) {
svc_flash_unlock();
return sectrue;
} }
secbool flash_unlock_write(void) secbool flash_lock_write(void) { return flash_check_success(svc_flash_lock()); }
{
svc_flash_unlock(); const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size) {
return sectrue; if (sector >= FLASH_SECTOR_COUNT) {
return NULL;
}
const uint32_t addr = FLASH_SECTOR_TABLE[sector] + offset;
const uint32_t next = FLASH_SECTOR_TABLE[sector + 1];
if (addr + size > next) {
return NULL;
}
return (const void *)FLASH_PTR(addr);
} }
secbool flash_lock_write(void) secbool flash_erase(uint8_t sector) {
{ ensure(flash_unlock_write(), NULL);
return flash_check_success(svc_flash_lock()); 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];
for (uint32_t addr = addr_start; addr < addr_end; addr += 4) {
if (*((const uint32_t *)FLASH_PTR(addr)) != 0xFFFFFFFF) {
return secfalse;
}
}
return sectrue;
} }
const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size) 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 (sector >= FLASH_SECTOR_COUNT) { if (address == NULL) {
return NULL; return secfalse;
} }
const uint32_t addr = FLASH_SECTOR_TABLE[sector] + offset;
const uint32_t next = FLASH_SECTOR_TABLE[sector + 1]; if ((*address & data) != data) {
if (addr + size > next) { return secfalse;
return NULL; }
}
return (const void *) FLASH_PTR(addr); svc_flash_program(FLASH_CR_PROGRAM_X8);
*(volatile uint8_t *)address = data;
if (*address != data) {
return secfalse;
}
return sectrue;
} }
secbool flash_erase(uint8_t sector) secbool flash_write_word(uint8_t sector, uint32_t offset, uint32_t data) {
{ uint32_t *address = (uint32_t *)flash_get_address(sector, offset, 4);
ensure(flash_unlock_write(), NULL); if (address == NULL) {
svc_flash_erase_sector(sector); return secfalse;
ensure(flash_lock_write(), NULL); }
// Check whether the sector was really deleted (contains only 0xFF). if (offset % 4 != 0) {
const uint32_t addr_start = FLASH_SECTOR_TABLE[sector], addr_end = FLASH_SECTOR_TABLE[sector + 1]; return secfalse;
for (uint32_t addr = addr_start; addr < addr_end; addr += 4) { }
if (*((const uint32_t *)FLASH_PTR(addr)) != 0xFFFFFFFF) {
return secfalse; if ((*address & data) != data) {
} return secfalse;
} }
return sectrue;
} svc_flash_program(FLASH_CR_PROGRAM_X32);
*(volatile uint32_t *)address = data;
secbool flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data)
{ if (*address != data) {
uint8_t *address = (uint8_t *) flash_get_address(sector, offset, 1); return secfalse;
if (address == NULL) { }
return secfalse;
} return sectrue;
if ((*address & data) != data) {
return secfalse;
}
svc_flash_program(FLASH_CR_PROGRAM_X8);
*(volatile uint8_t *) address = data;
if (*address != data) {
return secfalse;
}
return sectrue;
}
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;
}
if (offset % 4 != 0) {
return secfalse;
}
if ((*address & data) != data) {
return secfalse;
}
svc_flash_program(FLASH_CR_PROGRAM_X32);
*(volatile uint32_t *) address = data;
if (*address != data) {
return secfalse;
}
return sectrue;
} }

View File

@ -26,12 +26,15 @@
#define FLASH_SECTOR_COUNT 24 #define FLASH_SECTOR_COUNT 24
// note: FLASH_SR_RDERR is STM32F42xxx and STM32F43xxx specific (STM32F427) (reference RM0090 section 3.7.5) // note: FLASH_SR_RDERR is STM32F42xxx and STM32F43xxx specific (STM32F427)
// (reference RM0090 section 3.7.5)
#ifndef STM32F427xx #ifndef STM32F427xx
#define FLASH_SR_RDERR 0 #define FLASH_SR_RDERR 0
#endif #endif
#define FLASH_STATUS_ALL_FLAGS (FLASH_SR_RDERR | FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR | FLASH_SR_WRPERR | FLASH_SR_SOP | FLASH_SR_EOP) #define FLASH_STATUS_ALL_FLAGS \
(FLASH_SR_RDERR | FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR | \
FLASH_SR_WRPERR | FLASH_SR_SOP | FLASH_SR_EOP)
void flash_init(void); void flash_init(void);
@ -44,4 +47,4 @@ secbool __wur flash_erase(uint8_t sector);
secbool __wur flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data); secbool __wur flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data);
secbool __wur flash_write_word(uint8_t sector, uint32_t offset, uint32_t data); secbool __wur flash_write_word(uint8_t sector, uint32_t offset, uint32_t data);
#endif // FLASH_H #endif // FLASH_H

173
layout.c
View File

@ -22,95 +22,102 @@
#include "layout.h" #include "layout.h"
#include "oled.h" #include "oled.h"
void layoutButtonNo(const char *btnNo) void layoutButtonNo(const char *btnNo) {
{ oledDrawString(1, OLED_HEIGHT - 8, "\x15", FONT_STANDARD);
oledDrawString(1, OLED_HEIGHT - 8, "\x15", FONT_STANDARD); oledDrawString(fontCharWidth(FONT_STANDARD, '\x15') + 3, OLED_HEIGHT - 8,
oledDrawString(fontCharWidth(FONT_STANDARD, '\x15') + 3, OLED_HEIGHT - 8, btnNo, FONT_STANDARD); btnNo, FONT_STANDARD);
oledInvert(0, OLED_HEIGHT - 9, fontCharWidth(FONT_STANDARD, '\x15') + oledStringWidth(btnNo, FONT_STANDARD) + 2, OLED_HEIGHT - 1); oledInvert(0, OLED_HEIGHT - 9,
fontCharWidth(FONT_STANDARD, '\x15') +
oledStringWidth(btnNo, FONT_STANDARD) + 2,
OLED_HEIGHT - 1);
} }
void layoutButtonYes(const char *btnYes) void layoutButtonYes(const char *btnYes) {
{ oledDrawString(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 1,
oledDrawString(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 1, OLED_HEIGHT - 8, "\x06", FONT_STANDARD); OLED_HEIGHT - 8, "\x06", FONT_STANDARD);
oledDrawStringRight(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 3, OLED_HEIGHT - 8, btnYes, FONT_STANDARD); oledDrawStringRight(OLED_WIDTH - fontCharWidth(FONT_STANDARD, '\x06') - 3,
oledInvert(OLED_WIDTH - oledStringWidth(btnYes, FONT_STANDARD) - fontCharWidth(FONT_STANDARD, '\x06') - 4, OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1); OLED_HEIGHT - 8, btnYes, FONT_STANDARD);
oledInvert(OLED_WIDTH - oledStringWidth(btnYes, FONT_STANDARD) -
fontCharWidth(FONT_STANDARD, '\x06') - 4,
OLED_HEIGHT - 9, OLED_WIDTH - 1, OLED_HEIGHT - 1);
} }
void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6) void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes,
{ const char *desc, const char *line1, const char *line2,
int left = 0; const char *line3, const char *line4, const char *line5,
oledClear(); const char *line6) {
if (icon) { int left = 0;
oledDrawBitmap(0, 0, icon); oledClear();
left = icon->width + 4; if (icon) {
} oledDrawBitmap(0, 0, icon);
if (line1) oledDrawString(left, 0 * 9, line1, FONT_STANDARD); left = icon->width + 4;
if (line2) oledDrawString(left, 1 * 9, line2, FONT_STANDARD); }
if (line3) oledDrawString(left, 2 * 9, line3, FONT_STANDARD); if (line1) oledDrawString(left, 0 * 9, line1, FONT_STANDARD);
if (line4) oledDrawString(left, 3 * 9, line4, FONT_STANDARD); if (line2) oledDrawString(left, 1 * 9, line2, FONT_STANDARD);
if (desc) { if (line3) oledDrawString(left, 2 * 9, line3, FONT_STANDARD);
oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 2 * 9 - 1, desc, FONT_STANDARD); if (line4) oledDrawString(left, 3 * 9, line4, FONT_STANDARD);
if (btnYes || btnNo) { if (desc) {
oledHLine(OLED_HEIGHT - 21); oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 2 * 9 - 1, desc,
} FONT_STANDARD);
} else { if (btnYes || btnNo) {
if (line5) oledDrawString(left, 4 * 9, line5, FONT_STANDARD); oledHLine(OLED_HEIGHT - 21);
if (line6) oledDrawString(left, 5 * 9, line6, FONT_STANDARD); }
if (btnYes || btnNo) { } else {
oledHLine(OLED_HEIGHT - 13); if (line5) oledDrawString(left, 4 * 9, line5, FONT_STANDARD);
} if (line6) oledDrawString(left, 5 * 9, line6, FONT_STANDARD);
} if (btnYes || btnNo) {
if (btnNo) { oledHLine(OLED_HEIGHT - 13);
layoutButtonNo(btnNo); }
} }
if (btnYes) { if (btnNo) {
layoutButtonYes(btnYes); layoutButtonNo(btnNo);
} }
oledRefresh(); if (btnYes) {
layoutButtonYes(btnYes);
}
oledRefresh();
} }
void layoutProgressUpdate(bool refresh) void layoutProgressUpdate(bool refresh) {
{ static uint8_t step = 0;
static uint8_t step = 0; switch (step) {
switch (step) { case 0:
case 0: oledDrawBitmap(40, 0, &bmp_gears0);
oledDrawBitmap(40, 0, &bmp_gears0); break;
break; case 1:
case 1: oledDrawBitmap(40, 0, &bmp_gears1);
oledDrawBitmap(40, 0, &bmp_gears1); break;
break; case 2:
case 2: oledDrawBitmap(40, 0, &bmp_gears2);
oledDrawBitmap(40, 0, &bmp_gears2); break;
break; case 3:
case 3: oledDrawBitmap(40, 0, &bmp_gears3);
oledDrawBitmap(40, 0, &bmp_gears3); break;
break; }
} step = (step + 1) % 4;
step = (step + 1) % 4; if (refresh) {
if (refresh) { oledRefresh();
oledRefresh(); }
}
} }
void layoutProgress(const char *desc, int permil) void layoutProgress(const char *desc, int permil) {
{ oledClear();
oledClear(); layoutProgressUpdate(false);
layoutProgressUpdate(false); // progressbar
// progressbar oledFrame(0, OLED_HEIGHT - 8, OLED_WIDTH - 1, OLED_HEIGHT - 1);
oledFrame(0, OLED_HEIGHT - 8, OLED_WIDTH - 1, OLED_HEIGHT - 1); oledBox(1, OLED_HEIGHT - 7, OLED_WIDTH - 2, OLED_HEIGHT - 2, 0);
oledBox(1, OLED_HEIGHT - 7, OLED_WIDTH - 2, OLED_HEIGHT - 2, 0); permil = permil * (OLED_WIDTH - 4) / 1000;
permil = permil * (OLED_WIDTH - 4) / 1000; if (permil < 0) {
if (permil < 0) { permil = 0;
permil = 0; }
} if (permil > OLED_WIDTH - 4) {
if (permil > OLED_WIDTH - 4) { permil = OLED_WIDTH - 4;
permil = OLED_WIDTH - 4; }
} oledBox(2, OLED_HEIGHT - 6, 1 + permil, OLED_HEIGHT - 3, 1);
oledBox(2, OLED_HEIGHT - 6, 1 + permil, OLED_HEIGHT - 3, 1); // text
// text oledBox(0, OLED_HEIGHT - 16, OLED_WIDTH - 1, OLED_HEIGHT - 16 + 7, 0);
oledBox(0, OLED_HEIGHT - 16, OLED_WIDTH - 1, OLED_HEIGHT - 16 + 7, 0); if (desc) {
if (desc) { oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 16, desc, FONT_STANDARD);
oledDrawStringCenter(OLED_WIDTH / 2, OLED_HEIGHT - 16, desc, FONT_STANDARD); }
} oledRefresh();
oledRefresh();
} }

View File

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

View File

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

View File

@ -58,47 +58,47 @@
*/ */
#define FLASH_ORIGIN (0x08000000) #define FLASH_ORIGIN (0x08000000)
#if EMULATOR #if EMULATOR
extern uint8_t *emulator_flash_base; extern uint8_t *emulator_flash_base;
#define FLASH_PTR(x) (emulator_flash_base + (x - FLASH_ORIGIN)) #define FLASH_PTR(x) (emulator_flash_base + (x - FLASH_ORIGIN))
#else #else
#define FLASH_PTR(x) (const uint8_t*) (x) #define FLASH_PTR(x) (const uint8_t *)(x)
#endif #endif
#define FLASH_TOTAL_SIZE (1024 * 1024) #define FLASH_TOTAL_SIZE (1024 * 1024)
#define FLASH_BOOT_START (FLASH_ORIGIN) #define FLASH_BOOT_START (FLASH_ORIGIN)
#define FLASH_BOOT_LEN (0x8000) #define FLASH_BOOT_LEN (0x8000)
#define FLASH_STORAGE_START (FLASH_BOOT_START + FLASH_BOOT_LEN) #define FLASH_STORAGE_START (FLASH_BOOT_START + FLASH_BOOT_LEN)
#define FLASH_STORAGE_LEN (0x8000) #define FLASH_STORAGE_LEN (0x8000)
#define FLASH_FWHEADER_START (FLASH_STORAGE_START + FLASH_STORAGE_LEN) #define FLASH_FWHEADER_START (FLASH_STORAGE_START + FLASH_STORAGE_LEN)
#define FLASH_FWHEADER_LEN (0x400) #define FLASH_FWHEADER_LEN (0x400)
#define FLASH_APP_START (FLASH_FWHEADER_START + FLASH_FWHEADER_LEN) #define FLASH_APP_START (FLASH_FWHEADER_START + FLASH_FWHEADER_LEN)
#define FLASH_APP_LEN (FLASH_TOTAL_SIZE - (FLASH_APP_START - FLASH_ORIGIN)) #define FLASH_APP_LEN (FLASH_TOTAL_SIZE - (FLASH_APP_START - FLASH_ORIGIN))
#define FLASH_BOOT_SECTOR_FIRST 0 #define FLASH_BOOT_SECTOR_FIRST 0
#define FLASH_BOOT_SECTOR_LAST 1 #define FLASH_BOOT_SECTOR_LAST 1
#define FLASH_STORAGE_SECTOR_FIRST 2 #define FLASH_STORAGE_SECTOR_FIRST 2
#define FLASH_STORAGE_SECTOR_LAST 3 #define FLASH_STORAGE_SECTOR_LAST 3
#define FLASH_CODE_SECTOR_FIRST 4 #define FLASH_CODE_SECTOR_FIRST 4
#define FLASH_CODE_SECTOR_LAST 11 #define FLASH_CODE_SECTOR_LAST 11
void memory_protect(void); void memory_protect(void);
void memory_write_unlock(void); void memory_write_unlock(void);
int memory_bootloader_hash(uint8_t *hash); int memory_bootloader_hash(uint8_t *hash);
static inline void flash_write32(uint32_t addr, uint32_t word) { static inline void flash_write32(uint32_t addr, uint32_t word) {
*(volatile uint32_t *) FLASH_PTR(addr) = word; *(volatile uint32_t *)FLASH_PTR(addr) = word;
} }
static inline void flash_write8(uint32_t addr, uint8_t byte) { static inline void flash_write8(uint32_t addr, uint8_t byte) {
*(volatile uint8_t *) FLASH_PTR(addr) = byte; *(volatile uint8_t *)FLASH_PTR(addr) = byte;
} }
#endif #endif

View File

@ -23,11 +23,13 @@
#include "flash.h" #include "flash.h"
#define NORCOW_SECTOR_COUNT 2 #define NORCOW_SECTOR_COUNT 2
#define NORCOW_SECTOR_SIZE (16*1024) #define NORCOW_SECTOR_SIZE (16 * 1024)
#define NORCOW_SECTORS {2, 3} #define NORCOW_SECTORS \
{ 2, 3 }
/* /*
* The length of the sector header in bytes. The header is preserved between sector erasures. * The length of the sector header in bytes. The header is preserved between
* sector erasures.
*/ */
#define NORCOW_HEADER_LEN (0) #define NORCOW_HEADER_LEN (0)

544
oled.c
View File

@ -22,39 +22,39 @@
#include <string.h> #include <string.h>
#include "memzero.h"
#include "oled.h" #include "oled.h"
#include "util.h" #include "util.h"
#include "memzero.h"
#define OLED_SETCONTRAST 0x81 #define OLED_SETCONTRAST 0x81
#define OLED_DISPLAYALLON_RESUME 0xA4 #define OLED_DISPLAYALLON_RESUME 0xA4
#define OLED_DISPLAYALLON 0xA5 #define OLED_DISPLAYALLON 0xA5
#define OLED_NORMALDISPLAY 0xA6 #define OLED_NORMALDISPLAY 0xA6
#define OLED_INVERTDISPLAY 0xA7 #define OLED_INVERTDISPLAY 0xA7
#define OLED_DISPLAYOFF 0xAE #define OLED_DISPLAYOFF 0xAE
#define OLED_DISPLAYON 0xAF #define OLED_DISPLAYON 0xAF
#define OLED_SETDISPLAYOFFSET 0xD3 #define OLED_SETDISPLAYOFFSET 0xD3
#define OLED_SETCOMPINS 0xDA #define OLED_SETCOMPINS 0xDA
#define OLED_SETVCOMDETECT 0xDB #define OLED_SETVCOMDETECT 0xDB
#define OLED_SETDISPLAYCLOCKDIV 0xD5 #define OLED_SETDISPLAYCLOCKDIV 0xD5
#define OLED_SETPRECHARGE 0xD9 #define OLED_SETPRECHARGE 0xD9
#define OLED_SETMULTIPLEX 0xA8 #define OLED_SETMULTIPLEX 0xA8
#define OLED_SETLOWCOLUMN 0x00 #define OLED_SETLOWCOLUMN 0x00
#define OLED_SETHIGHCOLUMN 0x10 #define OLED_SETHIGHCOLUMN 0x10
#define OLED_SETSTARTLINE 0x40 #define OLED_SETSTARTLINE 0x40
#define OLED_MEMORYMODE 0x20 #define OLED_MEMORYMODE 0x20
#define OLED_COMSCANINC 0xC0 #define OLED_COMSCANINC 0xC0
#define OLED_COMSCANDEC 0xC8 #define OLED_COMSCANDEC 0xC8
#define OLED_SEGREMAP 0xA0 #define OLED_SEGREMAP 0xA0
#define OLED_CHARGEPUMP 0x8D #define OLED_CHARGEPUMP 0x8D
#define SPI_BASE SPI1 #define SPI_BASE SPI1
#define OLED_DC_PORT GPIOB #define OLED_DC_PORT GPIOB
#define OLED_DC_PIN GPIO0 // PB0 | Data/Command #define OLED_DC_PIN GPIO0 // PB0 | Data/Command
#define OLED_CS_PORT GPIOA #define OLED_CS_PORT GPIOA
#define OLED_CS_PIN GPIO4 // PA4 | SPI Select #define OLED_CS_PIN GPIO4 // PA4 | SPI Select
#define OLED_RST_PORT GPIOB #define OLED_RST_PORT GPIOB
#define OLED_RST_PIN GPIO1 // PB1 | Reset display #define OLED_RST_PIN GPIO1 // PB1 | Reset display
/* TREZOR has a display of size OLED_WIDTH x OLED_HEIGHT (128x64). /* TREZOR has a display of size OLED_WIDTH x OLED_HEIGHT (128x64).
* The contents of this display are buffered in _oledbuffer. This is * The contents of this display are buffered in _oledbuffer. This is
@ -70,126 +70,127 @@ static bool is_debug_link = 0;
/* /*
* macros to convert coordinate to bit position * macros to convert coordinate to bit position
*/ */
#define OLED_OFFSET(x, y) (OLED_BUFSIZE - 1 - (x) - ((y)/8)*OLED_WIDTH) #define OLED_OFFSET(x, y) (OLED_BUFSIZE - 1 - (x) - ((y) / 8) * OLED_WIDTH)
#define OLED_MASK(x, y) (1 << (7 - (y) % 8)) #define OLED_MASK(x, y) (1 << (7 - (y) % 8))
/* /*
* Draws a white pixel at x, y * Draws a white pixel at x, y
*/ */
void oledDrawPixel(int x, int y) void oledDrawPixel(int x, int y) {
{ if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) {
if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) { return;
return; }
} _oledbuffer[OLED_OFFSET(x, y)] |= OLED_MASK(x, y);
_oledbuffer[OLED_OFFSET(x, y)] |= OLED_MASK(x, y);
} }
/* /*
* Clears pixel at x, y * Clears pixel at x, y
*/ */
void oledClearPixel(int x, int y) void oledClearPixel(int x, int y) {
{ if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) {
if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) { return;
return; }
} _oledbuffer[OLED_OFFSET(x, y)] &= ~OLED_MASK(x, y);
_oledbuffer[OLED_OFFSET(x, y)] &= ~OLED_MASK(x, y);
} }
/* /*
* Inverts pixel at x, y * Inverts pixel at x, y
*/ */
void oledInvertPixel(int x, int y) void oledInvertPixel(int x, int y) {
{ if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) {
if ((x < 0) || (y < 0) || (x >= OLED_WIDTH) || (y >= OLED_HEIGHT)) { return;
return; }
} _oledbuffer[OLED_OFFSET(x, y)] ^= OLED_MASK(x, y);
_oledbuffer[OLED_OFFSET(x, y)] ^= OLED_MASK(x, y);
} }
#if !EMULATOR #if !EMULATOR
/* /*
* Send a block of data via the SPI bus. * Send a block of data via the SPI bus.
*/ */
static inline void SPISend(uint32_t base, const uint8_t *data, int len) static inline void SPISend(uint32_t base, const uint8_t *data, int len) {
{ delay(1);
delay(1); for (int i = 0; i < len; i++) {
for (int i = 0; i < len; i++) { spi_send(base, data[i]);
spi_send(base, data[i]); }
} while (!(SPI_SR(base) & SPI_SR_TXE))
while (!(SPI_SR(base) & SPI_SR_TXE)); ;
while ((SPI_SR(base) & SPI_SR_BSY)); while ((SPI_SR(base) & SPI_SR_BSY))
;
} }
/* /*
* Initialize the display. * Initialize the display.
*/ */
void oledInit() void oledInit() {
{ static const uint8_t s[25] = {OLED_DISPLAYOFF,
static const uint8_t s[25] = { OLED_SETDISPLAYCLOCKDIV,
OLED_DISPLAYOFF, 0x80,
OLED_SETDISPLAYCLOCKDIV, OLED_SETMULTIPLEX,
0x80, 0x3F, // 128x64
OLED_SETMULTIPLEX, OLED_SETDISPLAYOFFSET,
0x3F, // 128x64 0x00,
OLED_SETDISPLAYOFFSET, OLED_SETSTARTLINE | 0x00,
0x00, OLED_CHARGEPUMP,
OLED_SETSTARTLINE | 0x00, 0x14,
OLED_CHARGEPUMP, OLED_MEMORYMODE,
0x14, 0x00,
OLED_MEMORYMODE, OLED_SEGREMAP | 0x01,
0x00, OLED_COMSCANDEC,
OLED_SEGREMAP | 0x01, OLED_SETCOMPINS,
OLED_COMSCANDEC, 0x12, // 128x64
OLED_SETCOMPINS, OLED_SETCONTRAST,
0x12, // 128x64 0xCF,
OLED_SETCONTRAST, OLED_SETPRECHARGE,
0xCF, 0xF1,
OLED_SETPRECHARGE, OLED_SETVCOMDETECT,
0xF1, 0x40,
OLED_SETVCOMDETECT, OLED_DISPLAYALLON_RESUME,
0x40, OLED_NORMALDISPLAY,
OLED_DISPLAYALLON_RESUME, OLED_DISPLAYON};
OLED_NORMALDISPLAY,
OLED_DISPLAYON
};
gpio_clear(OLED_DC_PORT, OLED_DC_PIN); // set to CMD gpio_clear(OLED_DC_PORT, OLED_DC_PIN); // set to CMD
gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect
// Reset the LCD // Reset the LCD
gpio_set(OLED_RST_PORT, OLED_RST_PIN); gpio_set(OLED_RST_PORT, OLED_RST_PIN);
delay(40); delay(40);
gpio_clear(OLED_RST_PORT, OLED_RST_PIN); gpio_clear(OLED_RST_PORT, OLED_RST_PIN);
delay(400); delay(400);
gpio_set(OLED_RST_PORT, OLED_RST_PIN); gpio_set(OLED_RST_PORT, OLED_RST_PIN);
// init // init
gpio_clear(OLED_CS_PORT, OLED_CS_PIN); // SPI select gpio_clear(OLED_CS_PORT, OLED_CS_PIN); // SPI select
SPISend(SPI_BASE, s, 25); SPISend(SPI_BASE, s, 25);
gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect
oledClear(); oledClear();
oledRefresh(); oledRefresh();
} }
#endif #endif
/* /*
* Clears the display buffer (sets all pixels to black) * Clears the display buffer (sets all pixels to black)
*/ */
void oledClear() void oledClear() { memzero(_oledbuffer, sizeof(_oledbuffer)); }
{
memzero(_oledbuffer, sizeof(_oledbuffer));
}
void oledInvertDebugLink() void oledInvertDebugLink() {
{ if (is_debug_link) {
if (is_debug_link) { oledInvertPixel(OLED_WIDTH - 5, 0);
oledInvertPixel(OLED_WIDTH - 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, 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, 0);
oledInvertPixel(OLED_WIDTH - 3, 2); oledInvertPixel(OLED_WIDTH - 2, 2); oledInvertPixel(OLED_WIDTH - 1, 2); oledInvertPixel(OLED_WIDTH - 2, 0);
oledInvertPixel(OLED_WIDTH - 2, 3); oledInvertPixel(OLED_WIDTH - 1, 3); oledInvertPixel(OLED_WIDTH - 1, 0);
oledInvertPixel(OLED_WIDTH - 1, 4); 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,225 +200,216 @@ void oledInvertDebugLink()
* not the content of the display. * not the content of the display.
*/ */
#if !EMULATOR #if !EMULATOR
void oledRefresh() void oledRefresh() {
{ static const uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00,
static const uint8_t s[3] = {OLED_SETLOWCOLUMN | 0x00, OLED_SETHIGHCOLUMN | 0x00, OLED_SETSTARTLINE | 0x00}; OLED_SETHIGHCOLUMN | 0x00,
OLED_SETSTARTLINE | 0x00};
// draw triangle in upper right corner // draw triangle in upper right corner
oledInvertDebugLink(); oledInvertDebugLink();
gpio_clear(OLED_CS_PORT, OLED_CS_PIN); // SPI select gpio_clear(OLED_CS_PORT, OLED_CS_PIN); // SPI select
SPISend(SPI_BASE, s, 3); SPISend(SPI_BASE, s, 3);
gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect
gpio_set(OLED_DC_PORT, OLED_DC_PIN); // set to DATA gpio_set(OLED_DC_PORT, OLED_DC_PIN); // set to DATA
gpio_clear(OLED_CS_PORT, OLED_CS_PIN); // SPI select gpio_clear(OLED_CS_PORT, OLED_CS_PIN); // SPI select
SPISend(SPI_BASE, _oledbuffer, sizeof(_oledbuffer)); SPISend(SPI_BASE, _oledbuffer, sizeof(_oledbuffer));
gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect gpio_set(OLED_CS_PORT, OLED_CS_PIN); // SPI deselect
gpio_clear(OLED_DC_PORT, OLED_DC_PIN); // set to CMD gpio_clear(OLED_DC_PORT, OLED_DC_PIN); // set to CMD
// return it back // return it back
oledInvertDebugLink(); oledInvertDebugLink();
} }
#endif #endif
const uint8_t *oledGetBuffer() const uint8_t *oledGetBuffer() { return _oledbuffer; }
{
return _oledbuffer; void oledSetDebugLink(bool set) {
is_debug_link = set;
oledRefresh();
} }
void oledSetDebugLink(bool set) void oledSetBuffer(uint8_t *buf) {
{ memcpy(_oledbuffer, buf, sizeof(_oledbuffer));
is_debug_link = set;
oledRefresh();
} }
void oledSetBuffer(uint8_t *buf) void oledDrawChar(int x, int y, char c, int font) {
{ if (x >= OLED_WIDTH || y >= OLED_HEIGHT || y <= -FONT_HEIGHT) {
memcpy(_oledbuffer, buf, sizeof(_oledbuffer)); return;
} }
void oledDrawChar(int x, int y, char c, int font) int zoom = (font & FONT_DOUBLE ? 2 : 1);
{ int char_width = fontCharWidth(font & 0x7f, c);
if (x >= OLED_WIDTH || y >= OLED_HEIGHT || y <= -FONT_HEIGHT) { const uint8_t *char_data = fontCharData(font & 0x7f, c);
return;
}
int zoom = (font & FONT_DOUBLE ? 2 : 1); if (x <= -char_width * zoom) {
int char_width = fontCharWidth(font & 0x7f, c); return;
const uint8_t *char_data = fontCharData(font & 0x7f, c); }
if (x <= -char_width * zoom) { for (int xo = 0; xo < char_width; xo++) {
return; for (int yo = 0; yo < FONT_HEIGHT; yo++) {
} if (char_data[xo] & (1 << (FONT_HEIGHT - 1 - yo))) {
if (zoom <= 1) {
for (int xo = 0; xo < char_width; xo++) { oledDrawPixel(x + xo, y + yo);
for (int yo = 0; yo < FONT_HEIGHT; yo++) { } else {
if (char_data[xo] & (1 << (FONT_HEIGHT - 1 - yo))) { oledBox(x + xo * zoom, y + yo * zoom, x + (xo + 1) * zoom - 1,
if (zoom <= 1) { y + (yo + 1) * zoom - 1, true);
oledDrawPixel(x + xo, y + yo); }
} else { }
oledBox(x + xo * zoom, y + yo * zoom, x + (xo + 1) * zoom - 1, y + (yo + 1) * zoom - 1, true); }
} }
}
}
}
} }
char oledConvertChar(const char c) { char oledConvertChar(const char c) {
uint8_t a = c; uint8_t a = c;
if (a < 0x80) return c; if (a < 0x80) return c;
// UTF-8 handling: https://en.wikipedia.org/wiki/UTF-8#Description // UTF-8 handling: https://en.wikipedia.org/wiki/UTF-8#Description
// bytes 11xxxxxx are first byte of UTF-8 characters // bytes 11xxxxxx are first byte of UTF-8 characters
// bytes 10xxxxxx are successive UTF-8 characters // bytes 10xxxxxx are successive UTF-8 characters
if (a >= 0xC0) return '_'; if (a >= 0xC0) return '_';
return 0; return 0;
} }
int oledStringWidth(const char *text, int font) { int oledStringWidth(const char *text, int font) {
if (!text) return 0; if (!text) return 0;
int size = (font & FONT_DOUBLE ? 2 : 1); int size = (font & FONT_DOUBLE ? 2 : 1);
int l = 0; int l = 0;
for (; *text; text++) { for (; *text; text++) {
char c = oledConvertChar(*text); char c = oledConvertChar(*text);
if (c) { if (c) {
l += size * (fontCharWidth(font & 0x7f, c) + 1); l += size * (fontCharWidth(font & 0x7f, c) + 1);
} }
} }
return l; return l;
} }
void oledDrawString(int x, int y, const char* text, int font) void oledDrawString(int x, int y, const char *text, int font) {
{ if (!text) return;
if (!text) return; int l = 0;
int l = 0; int size = (font & FONT_DOUBLE ? 2 : 1);
int size = (font & FONT_DOUBLE ? 2 : 1); for (; *text; text++) {
for (; *text; text++) { char c = oledConvertChar(*text);
char c = oledConvertChar(*text); if (c) {
if (c) { oledDrawChar(x + l, y, c, font);
oledDrawChar(x + l, y, c, font); l += size * (fontCharWidth(font & 0x7f, c) + 1);
l += size * (fontCharWidth(font & 0x7f, c) + 1); }
} }
}
} }
void oledDrawStringCenter(int x, int y, const char* text, int font) void oledDrawStringCenter(int x, int y, const char *text, int font) {
{ x = x - oledStringWidth(text, font) / 2;
x = x - oledStringWidth(text, font) / 2; oledDrawString(x, y, text, font);
oledDrawString(x, y, text, font);
} }
void oledDrawStringRight(int x, int y, const char* text, int font) void oledDrawStringRight(int x, int y, const char *text, int font) {
{ x -= oledStringWidth(text, font);
x -= oledStringWidth(text, font); oledDrawString(x, y, text, font);
oledDrawString(x, y, text, font);
} }
void oledDrawBitmap(int x, int y, const BITMAP *bmp) void oledDrawBitmap(int x, int y, const BITMAP *bmp) {
{ for (int i = 0; i < bmp->width; i++) {
for (int i = 0; i < bmp->width; i++) { for (int j = 0; j < bmp->height; j++) {
for (int j = 0; j < bmp->height; j++) { if (bmp->data[(i / 8) + j * bmp->width / 8] & (1 << (7 - i % 8))) {
if (bmp->data[(i / 8) + j * bmp->width / 8] & (1 << (7 - i % 8))) { oledDrawPixel(x + i, y + j);
oledDrawPixel(x + i, y + j); } else {
} else { oledClearPixel(x + i, y + j);
oledClearPixel(x + i, y + j); }
} }
} }
}
} }
/* /*
* Inverts box between (x1,y1) and (x2,y2) inclusive. * Inverts box between (x1,y1) and (x2,y2) inclusive.
*/ */
void oledInvert(int x1, int y1, int x2, int y2) void oledInvert(int x1, int y1, int x2, int y2) {
{ x1 = MAX(x1, 0);
x1 = MAX(x1, 0); y1 = MAX(y1, 0);
y1 = MAX(y1, 0); x2 = MIN(x2, OLED_WIDTH - 1);
x2 = MIN(x2, OLED_WIDTH - 1); y2 = MIN(y2, OLED_HEIGHT - 1);
y2 = MIN(y2, OLED_HEIGHT - 1); for (int x = x1; x <= x2; x++) {
for (int x = x1; x <= x2; x++) { for (int y = y1; y <= y2; y++) {
for (int y = y1; y <= y2; y++) { oledInvertPixel(x, y);
oledInvertPixel(x,y); }
} }
}
} }
/* /*
* Draw a filled rectangle. * Draw a filled rectangle.
*/ */
void oledBox(int x1, int y1, int x2, int y2, bool set) void oledBox(int x1, int y1, int x2, int y2, bool set) {
{ x1 = MAX(x1, 0);
x1 = MAX(x1, 0); y1 = MAX(y1, 0);
y1 = MAX(y1, 0); x2 = MIN(x2, OLED_WIDTH - 1);
x2 = MIN(x2, OLED_WIDTH - 1); y2 = MIN(y2, OLED_HEIGHT - 1);
y2 = MIN(y2, OLED_HEIGHT - 1); for (int x = x1; x <= x2; x++) {
for (int x = x1; x <= x2; x++) { for (int y = y1; y <= y2; y++) {
for (int y = y1; y <= y2; y++) { set ? oledDrawPixel(x, y) : oledClearPixel(x, y);
set ? oledDrawPixel(x, y) : oledClearPixel(x, y); }
} }
}
} }
void oledHLine(int y) { void oledHLine(int y) {
if (y < 0 || y >= OLED_HEIGHT) { if (y < 0 || y >= OLED_HEIGHT) {
return; return;
} }
for (int x = 0; x < OLED_WIDTH; x++) { for (int x = 0; x < OLED_WIDTH; x++) {
oledDrawPixel(x, y); oledDrawPixel(x, y);
} }
} }
/* /*
* Draw a rectangle frame. * Draw a rectangle frame.
*/ */
void oledFrame(int x1, int y1, int x2, int y2) void oledFrame(int x1, int y1, int x2, int y2) {
{ for (int x = x1; x <= x2; x++) {
for (int x = x1; x <= x2; x++) { oledDrawPixel(x, y1);
oledDrawPixel(x, y1); oledDrawPixel(x, y2);
oledDrawPixel(x, y2); }
} for (int y = y1 + 1; y < y2; y++) {
for (int y = y1 + 1; y < y2; y++) { oledDrawPixel(x1, y);
oledDrawPixel(x1, y); oledDrawPixel(x2, y);
oledDrawPixel(x2, y); }
}
} }
/* /*
* Animates the display, swiping the current contents out to the left. * Animates the display, swiping the current contents out to the left.
* This clears the display. * This clears the display.
*/ */
void oledSwipeLeft(void) void oledSwipeLeft(void) {
{ for (int i = 0; i < OLED_WIDTH; i++) {
for (int i = 0; i < OLED_WIDTH; i++) { for (int j = 0; j < OLED_HEIGHT / 8; j++) {
for (int j = 0; j < OLED_HEIGHT / 8; j++) { for (int k = OLED_WIDTH - 1; k > 0; k--) {
for (int k = OLED_WIDTH-1; k > 0; k--) { _oledbuffer[j * OLED_WIDTH + k] = _oledbuffer[j * OLED_WIDTH + k - 1];
_oledbuffer[j * OLED_WIDTH + k] = _oledbuffer[j * OLED_WIDTH + k - 1]; }
} _oledbuffer[j * OLED_WIDTH] = 0;
_oledbuffer[j * OLED_WIDTH] = 0; }
} oledRefresh();
oledRefresh(); }
}
} }
/* /*
* Animates the display, swiping the current contents out to the right. * Animates the display, swiping the current contents out to the right.
* This clears the display. * This clears the display.
*/ */
void oledSwipeRight(void) void oledSwipeRight(void) {
{ for (int i = 0; i < OLED_WIDTH / 4; i++) {
for (int i = 0; i < OLED_WIDTH / 4; i++) { for (int j = 0; j < OLED_HEIGHT / 8; j++) {
for (int j = 0; j < OLED_HEIGHT / 8; j++) { for (int k = 0; k < OLED_WIDTH / 4 - 1; k++) {
for (int k = 0; k < OLED_WIDTH / 4 - 1; k++) { _oledbuffer[k * 4 + 0 + j * OLED_WIDTH] =
_oledbuffer[k * 4 + 0 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 4 + 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 + 1 + j * OLED_WIDTH] =
_oledbuffer[k * 4 + 2 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 6 + j * OLED_WIDTH]; _oledbuffer[k * 4 + 5 + j * OLED_WIDTH];
_oledbuffer[k * 4 + 3 + j * OLED_WIDTH] = _oledbuffer[k * 4 + 7 + j * OLED_WIDTH]; _oledbuffer[k * 4 + 2 + j * OLED_WIDTH] =
} _oledbuffer[k * 4 + 6 + j * OLED_WIDTH];
_oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 1] = 0; _oledbuffer[k * 4 + 3 + j * OLED_WIDTH] =
_oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 2] = 0; _oledbuffer[k * 4 + 7 + j * OLED_WIDTH];
_oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 3] = 0; }
_oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 4] = 0; _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 1] = 0;
} _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 2] = 0;
oledRefresh(); _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 3] = 0;
} _oledbuffer[j * OLED_WIDTH + OLED_WIDTH - 4] = 0;
}
oledRefresh();
}
} }

12
oled.h
View File

@ -20,14 +20,14 @@
#ifndef __OLED_H__ #ifndef __OLED_H__
#define __OLED_H__ #define __OLED_H__
#include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include "bitmaps.h" #include "bitmaps.h"
#include "fonts.h" #include "fonts.h"
#define OLED_WIDTH 128 #define OLED_WIDTH 128
#define OLED_HEIGHT 64 #define OLED_HEIGHT 64
#define OLED_BUFSIZE (OLED_WIDTH * OLED_HEIGHT / 8) #define OLED_BUFSIZE (OLED_WIDTH * OLED_HEIGHT / 8)
void oledInit(void); void oledInit(void);
@ -45,9 +45,9 @@ void oledInvertPixel(int x, int y);
void oledDrawChar(int x, int y, char c, int zoom); void oledDrawChar(int x, int y, char c, int zoom);
int oledStringWidth(const char *text, int font); int oledStringWidth(const char *text, int font);
void oledDrawString(int x, int y, const char* text, int font); 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);
void oledDrawStringRight(int x, int y, const char* text, int font); void oledDrawStringRight(int x, int y, const char *text, int font);
void oledDrawBitmap(int x, int y, const BITMAP *bmp); void oledDrawBitmap(int x, int y, const BITMAP *bmp);
void oledInvert(int x1, int y1, int x2, int y2); void oledInvert(int x1, int y1, int x2, int y2);
void oledBox(int x1, int y1, int x2, int y2, bool set); void oledBox(int x1, int y1, int x2, int y2, bool set);

21
rng.c
View File

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

View File

@ -23,11 +23,11 @@
#include <stdint.h> #include <stdint.h>
typedef uint32_t secbool; typedef uint32_t secbool;
#define sectrue 0xAAAAAAAAU #define sectrue 0xAAAAAAAAU
#define secfalse 0x00000000U #define secfalse 0x00000000U
#ifndef __wur #ifndef __wur
#define __wur __attribute__ ((warn_unused_result)) #define __wur __attribute__((warn_unused_result))
#endif #endif
#endif #endif

397
setup.c
View File

@ -20,249 +20,264 @@
#include <libopencm3/cm3/mpu.h> #include <libopencm3/cm3/mpu.h>
#include <libopencm3/cm3/nvic.h> #include <libopencm3/cm3/nvic.h>
#include <libopencm3/cm3/scb.h> #include <libopencm3/cm3/scb.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h> #include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/spi.h> #include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/rng.h> #include <libopencm3/stm32/rng.h>
#include <libopencm3/stm32/spi.h>
#include "rng.h"
#include "layout.h" #include "layout.h"
#include "rng.h"
#include "util.h" #include "util.h"
uint32_t __stack_chk_guard; uint32_t __stack_chk_guard;
static inline void __attribute__((noreturn)) fault_handler(const char *line1) { static inline void __attribute__((noreturn)) fault_handler(const char *line1) {
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, "detected.", NULL, "Please unplug", "the device.", NULL); layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, "detected.", NULL,
shutdown(); "Please unplug", "the device.", NULL);
shutdown();
} }
void __attribute__((noreturn)) __stack_chk_fail(void) { void __attribute__((noreturn)) __stack_chk_fail(void) {
fault_handler("Stack smashing"); fault_handler("Stack smashing");
} }
void nmi_handler(void) void nmi_handler(void) {
{ // Clock Security System triggered NMI
// Clock Security System triggered NMI if ((RCC_CIR & RCC_CIR_CSSF) != 0) {
if ((RCC_CIR & RCC_CIR_CSSF) != 0) { fault_handler("Clock instability");
fault_handler("Clock instability"); }
}
} }
void hard_fault_handler(void) { void hard_fault_handler(void) { fault_handler("Hard fault"); }
fault_handler("Hard fault");
void mem_manage_handler(void) { 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.
SCB_CCR |= SCB_CCR_STKALIGN;
// setup clock
struct rcc_clock_scale clock = rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_120MHZ];
rcc_clock_setup_hse_3v3(&clock);
// enable GPIO clock - A (oled), B(oled), C (buttons)
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_GPIOB);
rcc_periph_clock_enable(RCC_GPIOC);
// enable SPI clock
rcc_periph_clock_enable(RCC_SPI1);
// 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
random32();
// enable CSS (Clock Security System)
RCC_CR |= RCC_CR_CSSON;
// set GPIO for buttons
gpio_mode_setup(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO2 | GPIO5);
// set GPIO for OLED display
gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO4);
gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO0 | GPIO1);
// enable SPI 1 for OLED display
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO5 | GPIO7);
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_enable_ss_output(SPI1);
// spi_enable_software_slave_management(SPI1);
// spi_set_nss_high(SPI1);
// spi_clear_mode_fault(SPI1);
spi_enable(SPI1);
// enable OTG_FS
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO10);
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11 | GPIO12);
gpio_set_af(GPIOA, GPIO_AF10, GPIO10 | GPIO11 | GPIO12);
// enable OTG FS clock
rcc_periph_clock_enable(RCC_OTGFS);
// clear USB OTG_FS peripheral dedicated RAM
memset_reg((void *)0x50020000, (void *)0x50020500, 0);
} }
void mem_manage_handler(void) { void setupApp(void) {
fault_handler("Memory fault"); // 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)."
random32();
// enable CSS (Clock Security System)
RCC_CR |= RCC_CR_CSSON;
// 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);
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO10);
gpio_set_af(GPIOA, GPIO_AF10, GPIO10);
} }
void setup(void) #define MPU_RASR_SIZE_32B (0x04UL << MPU_RASR_SIZE_LSB)
{ #define MPU_RASR_SIZE_1KB (0x09UL << MPU_RASR_SIZE_LSB)
// set SCB_CCR STKALIGN bit to make sure 8-byte stack alignment on exception entry is in effect. #define MPU_RASR_SIZE_4KB (0x0BUL << MPU_RASR_SIZE_LSB)
// This is not strictly necessary for the current TREZOR system. #define MPU_RASR_SIZE_8KB (0x0CUL << MPU_RASR_SIZE_LSB)
// This is here to comply with guidance from section 3.3.3 "Binary compatibility with other Cortex processors" #define MPU_RASR_SIZE_16KB (0x0DUL << MPU_RASR_SIZE_LSB)
// of the ARM Cortex-M3 Processor Technical Reference Manual. #define MPU_RASR_SIZE_32KB (0x0EUL << MPU_RASR_SIZE_LSB)
// According to section 4.4.2 and 4.4.7 of the "STM32F10xxx/20xxx/21xxx/L1xxxx Cortex-M3 programming manual", #define MPU_RASR_SIZE_64KB (0x0FUL << MPU_RASR_SIZE_LSB)
// STM32F2 series MCUs are r2p0 and always have this bit set on reset already.
SCB_CCR |= SCB_CCR_STKALIGN;
// setup clock
struct rcc_clock_scale clock = rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_120MHZ];
rcc_clock_setup_hse_3v3(&clock);
// enable GPIO clock - A (oled), B(oled), C (buttons)
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_GPIOB);
rcc_periph_clock_enable(RCC_GPIOC);
// enable SPI clock
rcc_periph_clock_enable(RCC_SPI1);
// 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
random32();
// enable CSS (Clock Security System)
RCC_CR |= RCC_CR_CSSON;
// set GPIO for buttons
gpio_mode_setup(GPIOC, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO2 | GPIO5);
// set GPIO for OLED display
gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO4);
gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO0 | GPIO1);
// enable SPI 1 for OLED display
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO5 | GPIO7);
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_enable_ss_output(SPI1);
// spi_enable_software_slave_management(SPI1);
// spi_set_nss_high(SPI1);
// spi_clear_mode_fault(SPI1);
spi_enable(SPI1);
// enable OTG_FS
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO10);
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11 | GPIO12);
gpio_set_af(GPIOA, GPIO_AF10, GPIO10 | GPIO11 | GPIO12);
// enable OTG FS clock
rcc_periph_clock_enable(RCC_OTGFS);
// clear USB OTG_FS peripheral dedicated RAM
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)
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)."
random32();
// enable CSS (Clock Security System)
RCC_CR |= RCC_CR_CSSON;
// 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);
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO10);
gpio_set_af(GPIOA, GPIO_AF10, GPIO10);
}
#define MPU_RASR_SIZE_32B (0x04UL << MPU_RASR_SIZE_LSB)
#define MPU_RASR_SIZE_1KB (0x09UL << MPU_RASR_SIZE_LSB)
#define MPU_RASR_SIZE_4KB (0x0BUL << MPU_RASR_SIZE_LSB)
#define MPU_RASR_SIZE_8KB (0x0CUL << MPU_RASR_SIZE_LSB)
#define MPU_RASR_SIZE_16KB (0x0DUL << MPU_RASR_SIZE_LSB)
#define MPU_RASR_SIZE_32KB (0x0EUL << MPU_RASR_SIZE_LSB)
#define MPU_RASR_SIZE_64KB (0x0FUL << MPU_RASR_SIZE_LSB)
#define MPU_RASR_SIZE_128KB (0x10UL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_128KB (0x10UL << MPU_RASR_SIZE_LSB)
#define MPU_RASR_SIZE_256KB (0x11UL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_256KB (0x11UL << MPU_RASR_SIZE_LSB)
#define MPU_RASR_SIZE_512KB (0x12UL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_512KB (0x12UL << MPU_RASR_SIZE_LSB)
#define MPU_RASR_SIZE_1MB (0x13UL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_1MB (0x13UL << MPU_RASR_SIZE_LSB)
#define MPU_RASR_SIZE_512MB (0x1CUL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_512MB (0x1CUL << MPU_RASR_SIZE_LSB)
#define MPU_RASR_SIZE_4GB (0x1FUL << MPU_RASR_SIZE_LSB) #define MPU_RASR_SIZE_4GB (0x1FUL << MPU_RASR_SIZE_LSB)
// http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/BABDJJGF.html // http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/BABDJJGF.html
#define MPU_RASR_ATTR_FLASH (MPU_RASR_ATTR_C) #define MPU_RASR_ATTR_FLASH (MPU_RASR_ATTR_C)
#define MPU_RASR_ATTR_SRAM (MPU_RASR_ATTR_C | MPU_RASR_ATTR_S) #define MPU_RASR_ATTR_SRAM (MPU_RASR_ATTR_C | MPU_RASR_ATTR_S)
#define MPU_RASR_ATTR_PERIPH (MPU_RASR_ATTR_B | MPU_RASR_ATTR_S) #define MPU_RASR_ATTR_PERIPH (MPU_RASR_ATTR_B | MPU_RASR_ATTR_S)
#define FLASH_BASE (0x08000000U) #define FLASH_BASE (0x08000000U)
#define SRAM_BASE (0x20000000U) #define SRAM_BASE (0x20000000U)
void mpu_config_off(void) void mpu_config_off(void) {
{ // Disable MPU
// Disable MPU MPU_CTRL = 0;
MPU_CTRL = 0;
__asm__ volatile("dsb"); __asm__ volatile("dsb");
__asm__ volatile("isb"); __asm__ volatile("isb");
} }
void mpu_config_bootloader(void) void mpu_config_bootloader(void) {
{ // Disable MPU
// Disable MPU MPU_CTRL = 0;
MPU_CTRL = 0;
// Note: later entries overwrite previous ones // Note: later entries overwrite previous ones
// Everything (0x00000000 - 0xFFFFFFFF, 4 GiB, read-write) // Everything (0x00000000 - 0xFFFFFFFF, 4 GiB, read-write)
MPU_RBAR = 0 | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB); MPU_RBAR = 0 | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_4GB | MPU_RASR_ATTR_AP_PRW_URW; MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_4GB |
MPU_RASR_ATTR_AP_PRW_URW;
// Flash (0x8007FE0 - 0x08007FFF, 32 B, no-access) // Flash (0x8007FE0 - 0x08007FFF, 32 B, no-access)
MPU_RBAR = (FLASH_BASE + 0x7FE0) | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB); MPU_RBAR =
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_32B | MPU_RASR_ATTR_AP_PNO_UNO; (FLASH_BASE + 0x7FE0) | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_32B |
MPU_RASR_ATTR_AP_PNO_UNO;
// SRAM (0x20000000 - 0x2001FFFF, read-write, execute never) // SRAM (0x20000000 - 0x2001FFFF, read-write, execute never)
MPU_RBAR = SRAM_BASE | MPU_RBAR_VALID | (2 << MPU_RBAR_REGION_LSB); MPU_RBAR = SRAM_BASE | MPU_RBAR_VALID | (2 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_SRAM | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_SRAM | MPU_RASR_SIZE_128KB |
MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN;
// Peripherals (0x40000000 - 0x4001FFFF, read-write, execute never) // Peripherals (0x40000000 - 0x4001FFFF, read-write, execute never)
MPU_RBAR = PERIPH_BASE | MPU_RBAR_VALID | (3 << MPU_RBAR_REGION_LSB); MPU_RBAR = PERIPH_BASE | MPU_RBAR_VALID | (3 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_128KB |
// Peripherals (0x40020000 - 0x40023FFF, read-write, execute never) MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN;
MPU_RBAR = 0x40020000 | MPU_RBAR_VALID | (4 << MPU_RBAR_REGION_LSB); // Peripherals (0x40020000 - 0x40023FFF, read-write, execute never)
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_16KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; MPU_RBAR = 0x40020000 | MPU_RBAR_VALID | (4 << MPU_RBAR_REGION_LSB);
// Don't enable DMA controller access MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_16KB |
// Peripherals (0x50000000 - 0x5007ffff, read-write, execute never) MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN;
MPU_RBAR = 0x50000000 | MPU_RBAR_VALID | (5 << MPU_RBAR_REGION_LSB); // Don't enable DMA controller access
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_512KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; // 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;
// Enable MPU // Enable MPU
MPU_CTRL = MPU_CTRL_ENABLE | MPU_CTRL_HFNMIENA; MPU_CTRL = MPU_CTRL_ENABLE | MPU_CTRL_HFNMIENA;
// Enable memory fault handler // Enable memory fault handler
SCB_SHCSR |= SCB_SHCSR_MEMFAULTENA; SCB_SHCSR |= SCB_SHCSR_MEMFAULTENA;
__asm__ volatile("dsb"); __asm__ volatile("dsb");
__asm__ volatile("isb"); __asm__ volatile("isb");
} }
// Never use in bootloader! Disables access to PPB (including MPU, NVIC, SCB) // Never use in bootloader! Disables access to PPB (including MPU, NVIC, SCB)
void mpu_config_firmware(void) void mpu_config_firmware(void) {
{
#if MEMORY_PROTECT #if MEMORY_PROTECT
// Disable MPU // Disable MPU
MPU_CTRL = 0; MPU_CTRL = 0;
// Note: later entries overwrite previous ones // Note: later entries overwrite previous ones
// Flash (0x08000000 - 0x0807FFFF, 1 MiB, read-only) // Flash (0x08000000 - 0x0807FFFF, 1 MiB, read-only)
MPU_RBAR = FLASH_BASE | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB); MPU_RBAR = FLASH_BASE | MPU_RBAR_VALID | (0 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_1MB | MPU_RASR_ATTR_AP_PRO_URO; MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_1MB |
MPU_RASR_ATTR_AP_PRO_URO;
// Metadata in Flash is read-write when unlocked // Metadata in Flash is read-write when unlocked
// (0x08008000 - 0x0800FFFF, 32 KiB, read-write, execute never) // (0x08008000 - 0x0800FFFF, 32 KiB, read-write, execute never)
MPU_RBAR = (FLASH_BASE + 0x8000) | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB); MPU_RBAR =
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_32KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; (FLASH_BASE + 0x8000) | MPU_RBAR_VALID | (1 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_FLASH | MPU_RASR_SIZE_32KB |
MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN;
// SRAM (0x20000000 - 0x2001FFFF, read-write, execute never) // SRAM (0x20000000 - 0x2001FFFF, read-write, execute never)
MPU_RBAR = SRAM_BASE | MPU_RBAR_VALID | (2 << MPU_RBAR_REGION_LSB); MPU_RBAR = SRAM_BASE | MPU_RBAR_VALID | (2 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_SRAM | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_SRAM | MPU_RASR_SIZE_128KB |
MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN;
// Peripherals (0x40000000 - 0x4001FFFF, read-write, execute never) // Peripherals (0x40000000 - 0x4001FFFF, read-write, execute never)
MPU_RBAR = PERIPH_BASE | MPU_RBAR_VALID | (3 << MPU_RBAR_REGION_LSB); MPU_RBAR = PERIPH_BASE | MPU_RBAR_VALID | (3 << MPU_RBAR_REGION_LSB);
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_128KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_128KB |
// Peripherals (0x40020000 - 0x40023FFF, read-write, execute never) MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN;
MPU_RBAR = 0x40020000 | MPU_RBAR_VALID | (4 << MPU_RBAR_REGION_LSB); // Peripherals (0x40020000 - 0x40023FFF, read-write, execute never)
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_16KB | MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN; MPU_RBAR = 0x40020000 | MPU_RBAR_VALID | (4 << MPU_RBAR_REGION_LSB);
// Flash controller is protected MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_16KB |
// (0x40023C00 - 0x40023FFF, privileged read-write, user no, execute never) MPU_RASR_ATTR_AP_PRW_URW | MPU_RASR_ATTR_XN;
MPU_RBAR = 0x40023c00 | MPU_RBAR_VALID | (5 << MPU_RBAR_REGION_LSB); // Flash controller is protected
MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_1KB | MPU_RASR_ATTR_AP_PRW_UNO | MPU_RASR_ATTR_XN; // (0x40023C00 - 0x40023FFF, privileged read-write, user no, execute never)
// Don't enable DMA controller access MPU_RBAR = 0x40023c00 | MPU_RBAR_VALID | (5 << MPU_RBAR_REGION_LSB);
// Peripherals (0x50000000 - 0x5007ffff, read-write, execute never) MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_1KB |
MPU_RBAR = 0x50000000 | MPU_RBAR_VALID | (6 << MPU_RBAR_REGION_LSB); MPU_RASR_ATTR_AP_PRW_UNO | 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; // Don't enable DMA controller access
// SYSCFG_* registers are disabled // Peripherals (0x50000000 - 0x5007ffff, read-write, execute never)
// (0x40013800 - 0x40013BFF, read-only, execute never) MPU_RBAR = 0x50000000 | MPU_RBAR_VALID | (6 << MPU_RBAR_REGION_LSB);
MPU_RBAR = 0x40013800 | MPU_RBAR_VALID | (7 << MPU_RBAR_REGION_LSB); MPU_RASR = MPU_RASR_ENABLE | MPU_RASR_ATTR_PERIPH | MPU_RASR_SIZE_512KB |
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_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;
// Enable MPU // Enable MPU
MPU_CTRL = MPU_CTRL_ENABLE | MPU_CTRL_HFNMIENA; MPU_CTRL = MPU_CTRL_ENABLE | MPU_CTRL_HFNMIENA;
// Enable memory fault handler // Enable memory fault handler
SCB_SHCSR |= SCB_SHCSR_MEMFAULTENA; SCB_SHCSR |= SCB_SHCSR_MEMFAULTENA;
__asm__ volatile("dsb"); __asm__ volatile("dsb");
__asm__ volatile("isb"); __asm__ volatile("isb");
// Switch to unprivileged software execution to prevent access to MPU // Switch to unprivileged software execution to prevent access to MPU
set_mode_unprivileged(); set_mode_unprivileged();
#endif #endif
} }

View File

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

View File

@ -17,77 +17,75 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "supervise.h"
#include <libopencm3/stm32/flash.h> #include <libopencm3/stm32/flash.h>
#include <stdint.h> #include <stdint.h>
#include "supervise.h"
#include "memory.h" #include "memory.h"
#if !EMULATOR #if !EMULATOR
static void svhandler_flash_unlock(void) { static void svhandler_flash_unlock(void) {
flash_wait_for_last_operation(); flash_wait_for_last_operation();
flash_clear_status_flags(); flash_clear_status_flags();
flash_unlock(); flash_unlock();
} }
static void svhandler_flash_program(uint32_t psize) { static void svhandler_flash_program(uint32_t psize) {
/* Wait for any write operation to complete. */ /* Wait for any write operation to complete. */
flash_wait_for_last_operation(); flash_wait_for_last_operation();
/* check program size argument */ /* check program size argument */
if (psize != FLASH_CR_PROGRAM_X8 if (psize != FLASH_CR_PROGRAM_X8 && psize != FLASH_CR_PROGRAM_X16 &&
&& psize != FLASH_CR_PROGRAM_X16 psize != FLASH_CR_PROGRAM_X32 && psize != FLASH_CR_PROGRAM_X64)
&& psize != FLASH_CR_PROGRAM_X32 return;
&& psize != FLASH_CR_PROGRAM_X64) FLASH_CR = (FLASH_CR & ~(FLASH_CR_PROGRAM_MASK << FLASH_CR_PROGRAM_SHIFT)) |
return; (psize << FLASH_CR_PROGRAM_SHIFT);
FLASH_CR = (FLASH_CR & ~(FLASH_CR_PROGRAM_MASK << FLASH_CR_PROGRAM_SHIFT)) FLASH_CR |= FLASH_CR_PG;
| (psize << FLASH_CR_PROGRAM_SHIFT);
FLASH_CR |= FLASH_CR_PG;
} }
static void svhandler_flash_erase_sector(uint16_t sector) { static void svhandler_flash_erase_sector(uint16_t sector) {
/* we only allow erasing storage sectors 2 and 3. */ /* we only allow erasing storage sectors 2 and 3. */
if (sector < FLASH_STORAGE_SECTOR_FIRST || if (sector < FLASH_STORAGE_SECTOR_FIRST ||
sector > FLASH_STORAGE_SECTOR_LAST) { sector > FLASH_STORAGE_SECTOR_LAST) {
return; return;
} }
flash_erase_sector(sector, FLASH_CR_PROGRAM_X32); flash_erase_sector(sector, FLASH_CR_PROGRAM_X32);
} }
static uint32_t svhandler_flash_lock(void) { static uint32_t svhandler_flash_lock(void) {
/* Wait for any write operation to complete. */ /* Wait for any write operation to complete. */
flash_wait_for_last_operation(); flash_wait_for_last_operation();
/* Disable writes to flash. */ /* Disable writes to flash. */
FLASH_CR &= ~FLASH_CR_PG; FLASH_CR &= ~FLASH_CR_PG;
/* lock flash register */ /* lock flash register */
FLASH_CR |= FLASH_CR_LOCK; FLASH_CR |= FLASH_CR_LOCK;
/* return flash status register */ /* return flash status register */
return FLASH_SR; return FLASH_SR;
} }
extern volatile uint32_t system_millis; extern volatile uint32_t system_millis;
void svc_handler_main(uint32_t *stack) { void svc_handler_main(uint32_t *stack) {
uint8_t svc_number = ((uint8_t*) stack[6])[-2]; uint8_t svc_number = ((uint8_t *)stack[6])[-2];
switch (svc_number) { switch (svc_number) {
case SVC_FLASH_UNLOCK: case SVC_FLASH_UNLOCK:
svhandler_flash_unlock(); svhandler_flash_unlock();
break; break;
case SVC_FLASH_PROGRAM: case SVC_FLASH_PROGRAM:
svhandler_flash_program(stack[0]); svhandler_flash_program(stack[0]);
break; break;
case SVC_FLASH_ERASE: case SVC_FLASH_ERASE:
svhandler_flash_erase_sector(stack[0]); svhandler_flash_erase_sector(stack[0]);
break; break;
case SVC_FLASH_LOCK: case SVC_FLASH_LOCK:
stack[0] = svhandler_flash_lock(); stack[0] = svhandler_flash_lock();
break; break;
case SVC_TIMER_MS: case SVC_TIMER_MS:
stack[0] = system_millis; stack[0] = system_millis;
break; break;
default: default:
stack[0] = 0xffffffff; stack[0] = 0xffffffff;
break; break;
} }
} }
#endif #endif

View File

@ -22,18 +22,20 @@
#if !EMULATOR #if !EMULATOR
#define SVC_FLASH_UNLOCK 0 #include <stdint.h>
#define SVC_FLASH_ERASE 1
#define SVC_FLASH_UNLOCK 0
#define SVC_FLASH_ERASE 1
#define SVC_FLASH_PROGRAM 2 #define SVC_FLASH_PROGRAM 2
#define SVC_FLASH_LOCK 3 #define SVC_FLASH_LOCK 3
#define SVC_TIMER_MS 4 #define SVC_TIMER_MS 4
/* Unlocks flash. This function needs to be called before programming /* Unlocks flash. This function needs to be called before programming
* or erasing. Multiple calls of flash_program and flash_erase can * or erasing. Multiple calls of flash_program and flash_erase can
* follow and should be completed with flash_lock(). * follow and should be completed with flash_lock().
*/ */
inline void svc_flash_unlock(void) { inline void svc_flash_unlock(void) {
__asm__ __volatile__ ("svc %0" :: "i" (SVC_FLASH_UNLOCK) : "memory"); __asm__ __volatile__("svc %0" ::"i"(SVC_FLASH_UNLOCK) : "memory");
} }
/* Enable flash write operations. /* Enable flash write operations.
@ -41,32 +43,32 @@ inline void svc_flash_unlock(void) {
* should be one of the FLASH_CR_PROGRAM_X.. constants * should be one of the FLASH_CR_PROGRAM_X.. constants
*/ */
inline void svc_flash_program(uint32_t program_size) { inline void svc_flash_program(uint32_t program_size) {
register uint32_t r0 __asm__("r0") = program_size; register uint32_t r0 __asm__("r0") = program_size;
__asm__ __volatile__ ("svc %0" :: "i" (SVC_FLASH_PROGRAM), "r" (r0) : "memory"); __asm__ __volatile__("svc %0" ::"i"(SVC_FLASH_PROGRAM), "r"(r0) : "memory");
} }
/* Erase a flash sector. /* Erase a flash sector.
* @param sector sector number 0..11 * @param sector sector number 0..11
* (this only allows erasing meta sectors 2 and 3 though). * (this only allows erasing meta sectors 2 and 3 though).
*/ */
inline void svc_flash_erase_sector(uint8_t sector) { inline void svc_flash_erase_sector(uint8_t sector) {
register uint32_t r0 __asm__("r0") = sector; register uint32_t r0 __asm__("r0") = sector;
__asm__ __volatile__ ("svc %0" :: "i" (SVC_FLASH_ERASE), "r" (r0) : "memory"); __asm__ __volatile__("svc %0" ::"i"(SVC_FLASH_ERASE), "r"(r0) : "memory");
} }
/* Lock flash after programming or erasing. /* Lock flash after programming or erasing.
* @return flash status register (FLASH_SR) * @return flash status register (FLASH_SR)
*/ */
inline uint32_t svc_flash_lock(void) { inline uint32_t svc_flash_lock(void) {
register uint32_t r0 __asm__("r0"); register uint32_t r0 __asm__("r0");
__asm__ __volatile__ ("svc %1" : "=r" (r0) : "i" (SVC_FLASH_LOCK) : "memory"); __asm__ __volatile__("svc %1" : "=r"(r0) : "i"(SVC_FLASH_LOCK) : "memory");
return r0; return r0;
} }
inline uint32_t svc_timer_ms(void) { inline uint32_t svc_timer_ms(void) {
register uint32_t r0 __asm__("r0"); register uint32_t r0 __asm__("r0");
__asm__ __volatile__ ("svc %1" : "=r" (r0) : "i" (SVC_TIMER_MS) : "memory"); __asm__ __volatile__("svc %1" : "=r"(r0) : "i"(SVC_TIMER_MS) : "memory");
return r0; return r0;
} }
#else #else

47
timer.c
View File

@ -17,12 +17,11 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>. * along with this library. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "timer.h" #include "timer.h"
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/cm3/systick.h> #include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/vector.h> #include <libopencm3/cm3/vector.h>
#include <libopencm3/stm32/rcc.h>
/* 1 tick = 1 ms */ /* 1 tick = 1 ms */
extern volatile uint32_t system_millis; extern volatile uint32_t system_millis;
@ -31,32 +30,30 @@ extern volatile uint32_t system_millis;
* Initialise the Cortex-M3 SysTick timer * Initialise the Cortex-M3 SysTick timer
*/ */
void timer_init(void) { void timer_init(void) {
system_millis = 0; system_millis = 0;
/* /*
* MCU clock (120 MHz) as source * MCU clock (120 MHz) as source
* *
* (120 MHz / 8) = 15 clock pulses * (120 MHz / 8) = 15 clock pulses
* *
*/ */
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8); systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8);
STK_CVR = 0; STK_CVR = 0;
/* /*
* 1 tick = 1 ms @ 120 MHz * 1 tick = 1 ms @ 120 MHz
* *
* (15 clock pulses * 1000 ms) = 15000 clock pulses * (15 clock pulses * 1000 ms) = 15000 clock pulses
* *
* Send an interrupt every (N - 1) clock pulses * Send an interrupt every (N - 1) clock pulses
*/ */
systick_set_reload(14999); systick_set_reload(14999);
/* SysTick as interrupt */ /* SysTick as interrupt */
systick_interrupt_enable(); systick_interrupt_enable();
systick_counter_enable(); systick_counter_enable();
} }
void sys_tick_handler(void) { void sys_tick_handler(void) { system_millis++; }
system_millis++;
}

View File

@ -16,82 +16,79 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "usb21_standard.h"
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include "util.h" #include "util.h"
#include "usb21_standard.h"
static uint16_t build_bos_descriptor(const struct usb_bos_descriptor *bos, static uint16_t build_bos_descriptor(const struct usb_bos_descriptor *bos,
uint8_t *buf, uint16_t len) uint8_t *buf, uint16_t len) {
{ uint8_t *tmpbuf = buf;
uint8_t *tmpbuf = buf; uint16_t count, total = 0, totallen = 0;
uint16_t count, total = 0, totallen = 0; uint16_t i;
uint16_t i;
memcpy(buf, bos, count = MIN(len, bos->bLength)); memcpy(buf, bos, count = MIN(len, bos->bLength));
buf += count; buf += count;
len -= count; len -= count;
total += count; total += count;
totallen += bos->bLength; totallen += bos->bLength;
/* For each device capability */ /* For each device capability */
for (i = 0; i < bos->bNumDeviceCaps; i++) { for (i = 0; i < bos->bNumDeviceCaps; i++) {
/* Copy device capability descriptor. */ /* Copy device capability descriptor. */
const struct usb_device_capability_descriptor *cap = const struct usb_device_capability_descriptor *cap = bos->capabilities[i];
bos->capabilities[i];
memcpy(buf, cap, count = MIN(len, cap->bLength)); memcpy(buf, cap, count = MIN(len, cap->bLength));
buf += count; buf += count;
len -= count; len -= count;
total += count; total += count;
totallen += cap->bLength; totallen += cap->bLength;
} }
/* Fill in wTotalLength. */ /* Fill in wTotalLength. */
*(uint16_t *)(tmpbuf + 2) = totallen; *(uint16_t *)(tmpbuf + 2) = totallen;
return total; return total;
} }
static const struct usb_bos_descriptor* usb21_bos; static const struct usb_bos_descriptor *usb21_bos;
static int usb21_standard_get_descriptor(usbd_device* usbd_dev, static int usb21_standard_get_descriptor(
struct usb_setup_data *req, usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf,
uint8_t **buf, uint16_t *len, uint16_t *len, usbd_control_complete_callback *complete) {
usbd_control_complete_callback* complete) { (void)complete;
(void)complete; (void)usbd_dev;
(void)usbd_dev;
wait_random(); wait_random();
if (req->bRequest == USB_REQ_GET_DESCRIPTOR) { if (req->bRequest == USB_REQ_GET_DESCRIPTOR) {
int descr_type = req->wValue >> 8; int descr_type = req->wValue >> 8;
if (descr_type == USB_DT_BOS) { if (descr_type == USB_DT_BOS) {
if (!usb21_bos) { if (!usb21_bos) {
return USBD_REQ_NOTSUPP; return USBD_REQ_NOTSUPP;
} }
*len = MIN_8bits(*len, build_bos_descriptor(usb21_bos, *buf, *len)); *len = MIN_8bits(*len, build_bos_descriptor(usb21_bos, *buf, *len));
return USBD_REQ_HANDLED; return USBD_REQ_HANDLED;
} }
} }
return USBD_REQ_NEXT_CALLBACK; return USBD_REQ_NEXT_CALLBACK;
} }
static void usb21_set_config(usbd_device* usbd_dev, uint16_t wValue) { static void usb21_set_config(usbd_device *usbd_dev, uint16_t wValue) {
(void)wValue; (void)wValue;
usbd_register_control_callback( usbd_register_control_callback(
usbd_dev, usbd_dev, USB_REQ_TYPE_IN | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE,
USB_REQ_TYPE_IN | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE, USB_REQ_TYPE_DIRECTION | USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
USB_REQ_TYPE_DIRECTION | USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, &usb21_standard_get_descriptor);
&usb21_standard_get_descriptor);
} }
void usb21_setup(usbd_device* usbd_dev, const struct usb_bos_descriptor* binary_object_store) { void usb21_setup(usbd_device *usbd_dev,
usb21_bos = binary_object_store; const struct usb_bos_descriptor *binary_object_store) {
usb21_bos = binary_object_store;
/* Register the control request handler _before_ the config is set */ /* Register the control request handler _before_ the config is set */
usb21_set_config(usbd_dev, 0x0000); usb21_set_config(usbd_dev, 0x0000);
usbd_register_set_config_callback(usbd_dev, usb21_set_config); usbd_register_set_config_callback(usbd_dev, usb21_set_config);
} }

View File

@ -22,29 +22,30 @@
#include <libopencm3/usb/usbd.h> #include <libopencm3/usb/usbd.h>
/* USB 3.1 Descriptor Types - Table 9-6 */ /* USB 3.1 Descriptor Types - Table 9-6 */
#define USB_DT_BOS 15 #define USB_DT_BOS 15
#define USB_DT_DEVICE_CAPABILITY 16 #define USB_DT_DEVICE_CAPABILITY 16
struct usb_device_capability_descriptor { struct usb_device_capability_descriptor {
uint8_t bLength; uint8_t bLength;
uint8_t bDescriptorType; uint8_t bDescriptorType;
uint8_t bDevCapabilityType; uint8_t bDevCapabilityType;
} __attribute__((packed)); } __attribute__((packed));
struct usb_bos_descriptor { struct usb_bos_descriptor {
uint8_t bLength; uint8_t bLength;
uint8_t bDescriptorType; uint8_t bDescriptorType;
uint16_t wTotalLength; uint16_t wTotalLength;
uint8_t bNumDeviceCaps; uint8_t bNumDeviceCaps;
/* Descriptor ends here. The following are used internally: */ /* Descriptor ends here. The following are used internally: */
const struct usb_device_capability_descriptor **capabilities; const struct usb_device_capability_descriptor** capabilities;
} __attribute__((packed)); } __attribute__((packed));
#define USB_DT_BOS_SIZE 5 #define USB_DT_BOS_SIZE 5
/* USB Device Capability Types - USB 3.1 Table 9-14 */ /* USB Device Capability Types - USB 3.1 Table 9-14 */
#define USB_DC_PLATFORM 5 #define USB_DC_PLATFORM 5
extern void usb21_setup(usbd_device* usbd_dev, const struct usb_bos_descriptor* binary_object_store); extern void usb21_setup(usbd_device* usbd_dev,
const struct usb_bos_descriptor* binary_object_store);
#endif #endif

View File

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

View File

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

101
util.c
View File

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

82
util.h
View File

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

131
webusb.c
View File

@ -18,90 +18,87 @@
#include <string.h> #include <string.h>
#include "usb21_standard.h"
#include "util.h" #include "util.h"
#include "webusb.h" #include "webusb.h"
#include "usb21_standard.h"
const struct webusb_platform_descriptor webusb_platform_capability_descriptor = { const struct webusb_platform_descriptor webusb_platform_capability_descriptor =
.bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE, {.bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE,
.bDescriptorType = USB_DT_DEVICE_CAPABILITY, .bDescriptorType = USB_DT_DEVICE_CAPABILITY,
.bDevCapabilityType = USB_DC_PLATFORM, .bDevCapabilityType = USB_DC_PLATFORM,
.bReserved = 0, .bReserved = 0,
.platformCapabilityUUID = WEBUSB_UUID, .platformCapabilityUUID = WEBUSB_UUID,
.bcdVersion = 0x0100, .bcdVersion = 0x0100,
.bVendorCode = WEBUSB_VENDOR_CODE, .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
.bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE, webusb_platform_capability_descriptor_no_landing_page = {
.bDescriptorType = USB_DT_DEVICE_CAPABILITY, .bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE,
.bDevCapabilityType = USB_DC_PLATFORM, .bDescriptorType = USB_DT_DEVICE_CAPABILITY,
.bReserved = 0, .bDevCapabilityType = USB_DC_PLATFORM,
.platformCapabilityUUID = WEBUSB_UUID, .bReserved = 0,
.bcdVersion = 0x0100, .platformCapabilityUUID = WEBUSB_UUID,
.bVendorCode = WEBUSB_VENDOR_CODE, .bcdVersion = 0x0100,
.iLandingPage = 0 .bVendorCode = WEBUSB_VENDOR_CODE,
}; .iLandingPage = 0};
static const char* webusb_https_url; static const char* webusb_https_url;
static int webusb_control_vendor_request(usbd_device *usbd_dev, static int webusb_control_vendor_request(
struct usb_setup_data *req, usbd_device* usbd_dev, struct usb_setup_data* req, uint8_t** buf,
uint8_t **buf, uint16_t *len, uint16_t* len, usbd_control_complete_callback* complete) {
usbd_control_complete_callback* complete) { (void)complete;
(void)complete; (void)usbd_dev;
(void)usbd_dev;
wait_random(); wait_random();
if (req->bRequest != WEBUSB_VENDOR_CODE) { if (req->bRequest != WEBUSB_VENDOR_CODE) {
return USBD_REQ_NEXT_CALLBACK; return USBD_REQ_NEXT_CALLBACK;
} }
int status = USBD_REQ_NOTSUPP; int status = USBD_REQ_NOTSUPP;
switch (req->wIndex) { switch (req->wIndex) {
case WEBUSB_REQ_GET_URL: { case WEBUSB_REQ_GET_URL: {
struct webusb_url_descriptor* url = (struct webusb_url_descriptor*)(*buf); struct webusb_url_descriptor* url = (struct webusb_url_descriptor*)(*buf);
uint16_t index = req->wValue; uint16_t index = req->wValue;
if (index == 0) { if (index == 0) {
return USBD_REQ_NOTSUPP; return USBD_REQ_NOTSUPP;
} }
if (index == 1) { if (index == 1) {
size_t url_len = strlen(webusb_https_url); size_t url_len = strlen(webusb_https_url);
url->bLength = WEBUSB_DT_URL_DESCRIPTOR_SIZE + url_len; url->bLength = WEBUSB_DT_URL_DESCRIPTOR_SIZE + url_len;
url->bDescriptorType = WEBUSB_DT_URL; url->bDescriptorType = WEBUSB_DT_URL;
url->bScheme = WEBUSB_URL_SCHEME_HTTPS; url->bScheme = WEBUSB_URL_SCHEME_HTTPS;
memcpy(&url->URL, webusb_https_url, url_len); memcpy(&url->URL, webusb_https_url, url_len);
*len = MIN_8bits(*len, url->bLength); *len = MIN_8bits(*len, url->bLength);
status = USBD_REQ_HANDLED; status = USBD_REQ_HANDLED;
} else { } else {
// TODO: stall instead? // TODO: stall instead?
status = USBD_REQ_NOTSUPP; status = USBD_REQ_NOTSUPP;
} }
break; break;
} }
default: { default: {
status = USBD_REQ_NOTSUPP; status = USBD_REQ_NOTSUPP;
break; break;
} }
} }
return status; return status;
} }
static void webusb_set_config(usbd_device* usbd_dev, uint16_t wValue) { static void webusb_set_config(usbd_device* usbd_dev, uint16_t wValue) {
(void)wValue; (void)wValue;
usbd_register_control_callback( usbd_register_control_callback(usbd_dev,
usbd_dev, USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_DEVICE,
USB_REQ_TYPE_VENDOR | USB_REQ_TYPE_DEVICE, USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT, webusb_control_vendor_request);
webusb_control_vendor_request);
} }
void webusb_setup(usbd_device* usbd_dev, const char* https_url) { void webusb_setup(usbd_device* usbd_dev, const char* https_url) {
webusb_https_url = https_url; webusb_https_url = https_url;
usbd_register_set_config_callback(usbd_dev, webusb_set_config); usbd_register_set_config_callback(usbd_dev, webusb_set_config);
} }

View File

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

View File

@ -21,7 +21,7 @@
#include <stdint.h> #include <stdint.h>
#define WEBUSB_REQ_GET_URL 0x02 #define WEBUSB_REQ_GET_URL 0x02
#define WEBUSB_DT_DESCRIPTOR_SET_HEADER 0 #define WEBUSB_DT_DESCRIPTOR_SET_HEADER 0
#define WEBUSB_DT_CONFIGURATION_SUBSET_HEADER 1 #define WEBUSB_DT_CONFIGURATION_SUBSET_HEADER 1
@ -32,28 +32,33 @@
#define WEBUSB_URL_SCHEME_HTTPS 1 #define WEBUSB_URL_SCHEME_HTTPS 1
struct webusb_platform_descriptor { struct webusb_platform_descriptor {
uint8_t bLength; uint8_t bLength;
uint8_t bDescriptorType; uint8_t bDescriptorType;
uint8_t bDevCapabilityType; uint8_t bDevCapabilityType;
uint8_t bReserved; uint8_t bReserved;
uint8_t platformCapabilityUUID[16]; uint8_t platformCapabilityUUID[16];
uint16_t bcdVersion; uint16_t bcdVersion;
uint8_t bVendorCode; uint8_t bVendorCode;
uint8_t iLandingPage; uint8_t iLandingPage;
} __attribute__((packed)); } __attribute__((packed));
#define WEBUSB_PLATFORM_DESCRIPTOR_SIZE sizeof(struct webusb_platform_descriptor) #define WEBUSB_PLATFORM_DESCRIPTOR_SIZE \
sizeof(struct webusb_platform_descriptor)
// from https://wicg.github.io/webusb/#webusb-platform-capability-descriptor // from https://wicg.github.io/webusb/#webusb-platform-capability-descriptor
// see also this (for endianness explanation) // see also this (for endianness explanation)
// https://github.com/WICG/webusb/issues/115#issuecomment-352206549 // https://github.com/WICG/webusb/issues/115#issuecomment-352206549
#define WEBUSB_UUID {0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47,0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65} #define WEBUSB_UUID \
{ \
0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, 0x8B, 0xFD, 0xA0, 0x76, \
0x88, 0x15, 0xB6, 0x65 \
}
struct webusb_url_descriptor { struct webusb_url_descriptor {
uint8_t bLength; uint8_t bLength;
uint8_t bDescriptorType; uint8_t bDescriptorType;
uint8_t bScheme; uint8_t bScheme;
char URL[]; char URL[];
} __attribute__((packed)); } __attribute__((packed));
#define WEBUSB_DT_URL_DESCRIPTOR_SIZE 3 #define WEBUSB_DT_URL_DESCRIPTOR_SIZE 3

223
winusb.c
View File

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

Some files were not shown because too many files have changed in this diff Show More