mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-27 16:48:09 +00:00
Merge branch 'u2f'
This commit is contained in:
commit
5e57a1ceaf
@ -45,18 +45,18 @@ void layoutFirmwareHash(uint8_t *hash)
|
||||
for (i = 0; i < 4; i++) {
|
||||
data2hex(hash + i * 8, 8, str[i]);
|
||||
}
|
||||
layoutDialog(DIALOG_ICON_QUESTION, "Abort", "Continue", "Compare fingerprints", str[0], str[1], str[2], str[3], NULL, NULL);
|
||||
layoutDialog(&bmp_icon_question, "Abort", "Continue", "Compare fingerprints", str[0], str[1], str[2], str[3], NULL, NULL);
|
||||
}
|
||||
|
||||
void show_halt(void)
|
||||
{
|
||||
layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Unofficial firmware", "aborted.", NULL, "Unplug your TREZOR", "and see our support", "page at mytrezor.com");
|
||||
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Unofficial firmware", "aborted.", NULL, "Unplug your TREZOR", "and see our support", "page at mytrezor.com");
|
||||
system_halt();
|
||||
}
|
||||
|
||||
void show_unofficial_warning(uint8_t *hash)
|
||||
{
|
||||
layoutDialog(DIALOG_ICON_WARNING, "Abort", "I'll take the risk", NULL, "WARNING!", NULL, "Unofficial firmware", "detected.", NULL, NULL);
|
||||
layoutDialog(&bmp_icon_warning, "Abort", "I'll take the risk", NULL, "WARNING!", NULL, "Unofficial firmware", "detected.", NULL, NULL);
|
||||
|
||||
do {
|
||||
delay(100000);
|
||||
@ -124,7 +124,7 @@ void check_firmware_sanity(void)
|
||||
broken++;
|
||||
}
|
||||
if (broken) {
|
||||
layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Firmware appears", "to be broken.", NULL, "Unplug your TREZOR", "and see our support", "page at mytrezor.com");
|
||||
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Firmware appears", "to be broken.", NULL, "Unplug your TREZOR", "and see our support", "page at mytrezor.com");
|
||||
system_halt();
|
||||
}
|
||||
}
|
||||
@ -133,7 +133,7 @@ uint32_t __stack_chk_guard;
|
||||
|
||||
void __attribute__((noreturn)) __stack_chk_fail(void)
|
||||
{
|
||||
layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL);
|
||||
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL);
|
||||
for (;;) {} // loop forever
|
||||
}
|
||||
|
||||
|
@ -272,7 +272,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep)
|
||||
|
||||
if (flash_state == STATE_OPEN) {
|
||||
if (msg_id == 0x0006) { // FirmwareErase message (id 6)
|
||||
layoutDialog(DIALOG_ICON_QUESTION, "Abort", "Continue", NULL, "Install new", "firmware?", NULL, "Never do this without", "your recovery card!", NULL);
|
||||
layoutDialog(&bmp_icon_question, "Abort", "Continue", NULL, "Install new", "firmware?", NULL, "Never do this without", "your recovery card!", NULL);
|
||||
do {
|
||||
delay(100000);
|
||||
buttonUpdate();
|
||||
@ -299,7 +299,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep)
|
||||
}
|
||||
send_msg_failure(dev);
|
||||
flash_state = STATE_END;
|
||||
layoutDialog(DIALOG_ICON_WARNING, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You may now", "unplug your TREZOR.", NULL);
|
||||
layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You may now", "unplug your TREZOR.", NULL);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
@ -310,7 +310,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep)
|
||||
if (buf[9] != 0x0a) { // invalid contents
|
||||
send_msg_failure(dev);
|
||||
flash_state = STATE_END;
|
||||
layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL);
|
||||
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL);
|
||||
return;
|
||||
}
|
||||
// read payload length
|
||||
@ -319,7 +319,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep)
|
||||
if (flash_len > FLASH_TOTAL_SIZE + FLASH_META_DESC_LEN - (FLASH_APP_START - FLASH_ORIGIN)) { // firmware is too big
|
||||
send_msg_failure(dev);
|
||||
flash_state = STATE_END;
|
||||
layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Firmware is too big.", NULL, "Get official firmware", "from mytrezor.com", NULL, NULL);
|
||||
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Firmware is too big.", NULL, "Get official firmware", "from mytrezor.com", NULL, NULL);
|
||||
return;
|
||||
}
|
||||
sha256_Init(&ctx);
|
||||
@ -348,7 +348,7 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep)
|
||||
if (buf[0] != '?') { // invalid contents
|
||||
send_msg_failure(dev);
|
||||
flash_state = STATE_END;
|
||||
layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL);
|
||||
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL);
|
||||
return;
|
||||
}
|
||||
p = buf + 1;
|
||||
@ -432,10 +432,10 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep)
|
||||
}
|
||||
flash_state = STATE_END;
|
||||
if (hash_check_ok) {
|
||||
layoutDialog(DIALOG_ICON_OK, NULL, NULL, NULL, "New firmware", "successfully installed.", NULL, "You may now", "unplug your TREZOR.", NULL);
|
||||
layoutDialog(&bmp_icon_ok, NULL, NULL, NULL, "New firmware", "successfully installed.", NULL, "You may now", "unplug your TREZOR.", NULL);
|
||||
send_msg_success(dev);
|
||||
} else {
|
||||
layoutDialog(DIALOG_ICON_WARNING, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You need to repeat", "the procedure with", "the correct firmware.");
|
||||
layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You need to repeat", "the procedure with", "the correct firmware.");
|
||||
send_msg_failure(dev);
|
||||
}
|
||||
return;
|
||||
|
@ -242,7 +242,7 @@ uint32_t __stack_chk_guard;
|
||||
|
||||
void __attribute__((noreturn)) __stack_chk_fail(void)
|
||||
{
|
||||
layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL);
|
||||
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL);
|
||||
for (;;) {} // loop forever
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ APPVER = 1.0.0
|
||||
NAME = trezor
|
||||
|
||||
OBJS += usb.o
|
||||
OBJS += u2f.o
|
||||
OBJS += messages.o
|
||||
OBJS += storage.o
|
||||
OBJS += trezor.o
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "ripemd160.h"
|
||||
#include "curves.h"
|
||||
#include "secp256k1.h"
|
||||
#include <libopencm3/stm32/flash.h>
|
||||
|
||||
// message methods
|
||||
|
||||
@ -96,7 +97,7 @@ const CoinType *fsm_getCoin(const char *name)
|
||||
const HDNode *fsm_getDerivedNode(const char *curve, uint32_t *address_n, size_t address_n_count)
|
||||
{
|
||||
static HDNode node;
|
||||
if (!storage_getRootNode(&node, curve)) {
|
||||
if (!storage_getRootNode(&node, curve, true)) {
|
||||
fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized or passphrase request cancelled or unsupported curve");
|
||||
layoutHome();
|
||||
return 0;
|
||||
@ -160,7 +161,7 @@ void fsm_msgPing(Ping *msg)
|
||||
RESP_INIT(Success);
|
||||
|
||||
if (msg->has_button_protection && msg->button_protection) {
|
||||
layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "answer to ping?", NULL, NULL, NULL, NULL);
|
||||
layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "answer to ping?", NULL, NULL, NULL, NULL);
|
||||
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
|
||||
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Ping cancelled");
|
||||
layoutHome();
|
||||
@ -195,16 +196,16 @@ void fsm_msgChangePin(ChangePin *msg)
|
||||
bool removal = msg->has_remove && msg->remove;
|
||||
if (removal) {
|
||||
if (storage_hasPin()) {
|
||||
layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "remove current PIN?", NULL, NULL, NULL, NULL);
|
||||
layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "remove current PIN?", NULL, NULL, NULL, NULL);
|
||||
} else {
|
||||
fsm_sendSuccess("PIN removed");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (storage_hasPin()) {
|
||||
layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "change current PIN?", NULL, NULL, NULL, NULL);
|
||||
layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "change current PIN?", NULL, NULL, NULL, NULL);
|
||||
} else {
|
||||
layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "set new PIN?", NULL, NULL, NULL, NULL);
|
||||
layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "set new PIN?", NULL, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
|
||||
@ -232,7 +233,7 @@ void fsm_msgChangePin(ChangePin *msg)
|
||||
void fsm_msgWipeDevice(WipeDevice *msg)
|
||||
{
|
||||
(void)msg;
|
||||
layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "wipe the device?", NULL, "All data will be lost.", NULL, NULL);
|
||||
layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "wipe the device?", NULL, "All data will be lost.", NULL, NULL);
|
||||
if (!protectButton(ButtonRequestType_ButtonRequest_WipeDevice, false)) {
|
||||
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Wipe cancelled");
|
||||
layoutHome();
|
||||
@ -262,7 +263,7 @@ void fsm_msgFirmwareUpload(FirmwareUpload *msg)
|
||||
|
||||
void fsm_msgGetEntropy(GetEntropy *msg)
|
||||
{
|
||||
layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "send entropy?", NULL, NULL, NULL, NULL);
|
||||
layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "send entropy?", NULL, NULL, NULL, NULL);
|
||||
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
|
||||
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Entropy cancelled");
|
||||
layoutHome();
|
||||
@ -331,7 +332,7 @@ void fsm_msgLoadDevice(LoadDevice *msg)
|
||||
return;
|
||||
}
|
||||
|
||||
layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "I take the risk", NULL, "Loading private seed", "is not recommended.", "Continue only if you", "know what you are", "doing!", NULL);
|
||||
layoutDialogSwipe(&bmp_icon_question, "Cancel", "I take the risk", NULL, "Loading private seed", "is not recommended.", "Continue only if you", "know what you are", "doing!", NULL);
|
||||
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
|
||||
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Load cancelled");
|
||||
layoutHome();
|
||||
@ -488,7 +489,7 @@ void fsm_msgClearSession(ClearSession *msg)
|
||||
void fsm_msgApplySettings(ApplySettings *msg)
|
||||
{
|
||||
if (msg->has_label) {
|
||||
layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "change label to", msg->label, "?", NULL, NULL);
|
||||
layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "change label to", msg->label, "?", NULL, NULL);
|
||||
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
|
||||
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Apply settings cancelled");
|
||||
layoutHome();
|
||||
@ -496,7 +497,7 @@ void fsm_msgApplySettings(ApplySettings *msg)
|
||||
}
|
||||
}
|
||||
if (msg->has_language) {
|
||||
layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "change language to", msg->language, "?", NULL, NULL);
|
||||
layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "change language to", msg->language, "?", NULL, NULL);
|
||||
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
|
||||
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Apply settings cancelled");
|
||||
layoutHome();
|
||||
@ -504,7 +505,7 @@ void fsm_msgApplySettings(ApplySettings *msg)
|
||||
}
|
||||
}
|
||||
if (msg->has_use_passphrase) {
|
||||
layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", msg->use_passphrase ? "enable passphrase" : "disable passphrase", "encryption?", NULL, NULL, NULL);
|
||||
layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", msg->use_passphrase ? "enable passphrase" : "disable passphrase", "encryption?", NULL, NULL, NULL);
|
||||
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
|
||||
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Apply settings cancelled");
|
||||
layoutHome();
|
||||
@ -512,7 +513,7 @@ void fsm_msgApplySettings(ApplySettings *msg)
|
||||
}
|
||||
}
|
||||
if (msg->has_homescreen) {
|
||||
layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm", NULL, "Do you really want to", "change the home", "screen ?", NULL, NULL, NULL);
|
||||
layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "change the home", "screen ?", NULL, NULL, NULL);
|
||||
if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) {
|
||||
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Apply settings cancelled");
|
||||
layoutHome();
|
||||
@ -975,4 +976,41 @@ void fsm_msgDebugLinkStop(DebugLinkStop *msg)
|
||||
(void)msg;
|
||||
}
|
||||
|
||||
void fsm_msgDebugLinkMemoryRead(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, (void*) msg->address, length);
|
||||
resp->memory.size = length;
|
||||
msg_debug_write(MessageType_MessageType_DebugLinkMemory, resp);
|
||||
}
|
||||
|
||||
void fsm_msgDebugLinkMemoryWrite(DebugLinkMemoryWrite *msg)
|
||||
{
|
||||
uint32_t length = msg->memory.size;
|
||||
if (msg->flash) {
|
||||
flash_clear_status_flags();
|
||||
flash_unlock();
|
||||
uint32_t* src = (uint32_t *) msg->memory.bytes;
|
||||
for (unsigned int i = 0; i < length; i += 4) {
|
||||
flash_program_word(msg->address + i, *src);
|
||||
src++;
|
||||
}
|
||||
flash_lock();
|
||||
} else {
|
||||
memcpy((void *) msg->address, msg->memory.bytes, length);
|
||||
}
|
||||
}
|
||||
|
||||
void fsm_msgDebugLinkFlashErase(DebugLinkFlashErase *msg)
|
||||
{
|
||||
flash_clear_status_flags();
|
||||
flash_unlock();
|
||||
flash_erase_sector(msg->sector, FLASH_CR_PROGRAM_X32);
|
||||
flash_lock();
|
||||
}
|
||||
#endif
|
||||
|
@ -63,6 +63,9 @@ void fsm_msgWordAck(WordAck *msg);
|
||||
//void fsm_msgDebugLinkDecision(DebugLinkDecision *msg);
|
||||
void fsm_msgDebugLinkGetState(DebugLinkGetState *msg);
|
||||
void fsm_msgDebugLinkStop(DebugLinkStop *msg);
|
||||
void fsm_msgDebugLinkMemoryWrite(DebugLinkMemoryWrite *msg);
|
||||
void fsm_msgDebugLinkMemoryRead(DebugLinkMemoryRead *msg);
|
||||
void fsm_msgDebugLinkFlashErase(DebugLinkFlashErase *msg);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -31,7 +31,7 @@
|
||||
|
||||
void *layoutLast = layoutHome;
|
||||
|
||||
void layoutDialogSwipe(LayoutDialogIcon icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6)
|
||||
void layoutDialogSwipe(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6)
|
||||
{
|
||||
layoutLast = layoutDialogSwipe;
|
||||
oledSwipeLeft();
|
||||
@ -119,7 +119,7 @@ void layoutConfirmOutput(const CoinType *coin, const TxOutputType *out)
|
||||
static char first_half[17 + 1];
|
||||
strlcpy(first_half, out->address, sizeof(first_half));
|
||||
const char *str_out = str_amount(out->amount, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_out, sizeof(buf_out));
|
||||
layoutDialogSwipe(DIALOG_ICON_QUESTION,
|
||||
layoutDialogSwipe(&bmp_icon_question,
|
||||
"Cancel",
|
||||
"Confirm",
|
||||
NULL,
|
||||
@ -136,7 +136,7 @@ void layoutConfirmTx(const CoinType *coin, uint64_t amount_out, uint64_t amount_
|
||||
{
|
||||
const char *str_out = str_amount(amount_out, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_out, sizeof(buf_out));
|
||||
const char *str_fee = str_amount(amount_fee, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_fee, sizeof(buf_fee));
|
||||
layoutDialogSwipe(DIALOG_ICON_QUESTION,
|
||||
layoutDialogSwipe(&bmp_icon_question,
|
||||
"Cancel",
|
||||
"Confirm",
|
||||
NULL,
|
||||
@ -153,7 +153,7 @@ void layoutFeeOverThreshold(const CoinType *coin, uint64_t fee, uint32_t kb)
|
||||
{
|
||||
(void)kb;
|
||||
const char *str_out = str_amount(fee, coin->has_coin_shortcut ? coin->coin_shortcut : NULL, buf_out, sizeof(buf_out));
|
||||
layoutDialogSwipe(DIALOG_ICON_QUESTION,
|
||||
layoutDialogSwipe(&bmp_icon_question,
|
||||
"Cancel",
|
||||
"Confirm",
|
||||
NULL,
|
||||
@ -191,7 +191,7 @@ const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen)
|
||||
void layoutSignMessage(const uint8_t *msg, uint32_t len)
|
||||
{
|
||||
const char **str = split_message(msg, len, 16);
|
||||
layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm",
|
||||
layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm",
|
||||
"Sign message?",
|
||||
str[0], str[1], str[2], str[3], NULL, NULL);
|
||||
}
|
||||
@ -199,7 +199,7 @@ void layoutSignMessage(const uint8_t *msg, uint32_t len)
|
||||
void layoutVerifyAddress(const char *address)
|
||||
{
|
||||
const char **str = split_message((const uint8_t *)address, strlen(address), 17);
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, "Cancel", "Confirm",
|
||||
layoutDialogSwipe(&bmp_icon_info, "Cancel", "Confirm",
|
||||
"Confirm address?",
|
||||
"Message signed by:",
|
||||
NULL, str[0], str[1], str[2], NULL);
|
||||
@ -208,7 +208,7 @@ void layoutVerifyAddress(const char *address)
|
||||
void layoutVerifyMessage(const uint8_t *msg, uint32_t len)
|
||||
{
|
||||
const char **str = split_message(msg, len, 16);
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, "Cancel", "Confirm",
|
||||
layoutDialogSwipe(&bmp_icon_info, "Cancel", "Confirm",
|
||||
"Verified message",
|
||||
str[0], str[1], str[2], str[3], NULL, NULL);
|
||||
}
|
||||
@ -216,7 +216,7 @@ void layoutVerifyMessage(const uint8_t *msg, uint32_t len)
|
||||
void layoutCipherKeyValue(bool encrypt, const char *key)
|
||||
{
|
||||
const char **str = split_message((const uint8_t *)key, strlen(key), 16);
|
||||
layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm",
|
||||
layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm",
|
||||
encrypt ? "Encode value of this key?" : "Decode value of this key?",
|
||||
str[0], str[1], str[2], str[3], NULL, NULL);
|
||||
}
|
||||
@ -224,7 +224,7 @@ void layoutCipherKeyValue(bool encrypt, const char *key)
|
||||
void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing)
|
||||
{
|
||||
const char **str = split_message(msg, len, 16);
|
||||
layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm",
|
||||
layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm",
|
||||
signing ? "Encrypt+Sign message?" : "Encrypt message?",
|
||||
str[0], str[1], str[2], str[3], NULL, NULL);
|
||||
}
|
||||
@ -232,7 +232,7 @@ void layoutEncryptMessage(const uint8_t *msg, uint32_t len, bool signing)
|
||||
void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address)
|
||||
{
|
||||
const char **str = split_message(msg, len, 16);
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "OK",
|
||||
layoutDialogSwipe(&bmp_icon_info, NULL, "OK",
|
||||
address ? "Decrypted signed message" : "Decrypted message",
|
||||
str[0], str[1], str[2], str[3], NULL, NULL);
|
||||
}
|
||||
@ -286,7 +286,7 @@ void layoutPublicKey(const uint8_t *pubkey)
|
||||
data2hex(pubkey, 1, desc + 12);
|
||||
data2hex(pubkey + 1, 32, hex);
|
||||
const char **str = split_message((const uint8_t *)hex, 32*2, 16);
|
||||
layoutDialogSwipe(DIALOG_ICON_QUESTION, NULL, "Continue", NULL,
|
||||
layoutDialogSwipe(&bmp_icon_question, NULL, "Continue", NULL,
|
||||
desc, str[0], str[1], str[2], str[3], NULL);
|
||||
}
|
||||
|
||||
@ -326,7 +326,7 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge)
|
||||
row_user[0] = 0;
|
||||
}
|
||||
|
||||
layoutDialogSwipe(DIALOG_ICON_QUESTION, "Cancel", "Confirm",
|
||||
layoutDialogSwipe(&bmp_icon_question, "Cancel", "Confirm",
|
||||
"Do you want to sign in?",
|
||||
row_proto[0] ? row_proto : NULL,
|
||||
row_hostport[0] ? row_hostport : NULL,
|
||||
@ -335,3 +335,10 @@ void layoutSignIdentity(const IdentityType *identity, const char *challenge)
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appicon) {
|
||||
if (!appicon) {
|
||||
appicon = &bmp_icon_question;
|
||||
}
|
||||
layoutDialog(appicon, NULL, verb, NULL, verb, "U2F security key?", "", appname, "", NULL);
|
||||
}
|
||||
|
@ -22,8 +22,9 @@
|
||||
|
||||
#include "layout.h"
|
||||
#include "types.pb.h"
|
||||
#include "bitmaps.h"
|
||||
|
||||
void layoutDialogSwipe(LayoutDialogIcon icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6);
|
||||
void layoutDialogSwipe(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6);
|
||||
void layoutProgressSwipe(const char *desc, int permil);
|
||||
|
||||
void layoutScreensaver(void);
|
||||
@ -40,5 +41,6 @@ void layoutDecryptMessage(const uint8_t *msg, uint32_t len, const char *address)
|
||||
void layoutAddress(const char *address, const char *desc);
|
||||
void layoutPublicKey(const uint8_t *pubkey);
|
||||
void layoutSignIdentity(const IdentityType *identity, const char *challenge);
|
||||
void layoutU2FDialog(const char *verb, const char *appname, const BITMAP *appicon);
|
||||
|
||||
#endif
|
||||
|
@ -97,9 +97,13 @@ static const struct MessagesMap_t MessagesMap[] = {
|
||||
// {'d', 'i', MessageType_MessageType_DebugLinkDecision, DebugLinkDecision_fields, (void (*)(void *))fsm_msgDebugLinkDecision},
|
||||
{'d', 'i', MessageType_MessageType_DebugLinkGetState, DebugLinkGetState_fields, (void (*)(void *))fsm_msgDebugLinkGetState},
|
||||
{'d', 'i', MessageType_MessageType_DebugLinkStop, DebugLinkStop_fields, (void (*)(void *))fsm_msgDebugLinkStop},
|
||||
{'d', 'i', MessageType_MessageType_DebugLinkMemoryRead, DebugLinkMemoryRead_fields, (void (*)(void *))fsm_msgDebugLinkMemoryRead},
|
||||
{'d', 'i', MessageType_MessageType_DebugLinkMemoryWrite, DebugLinkMemoryWrite_fields, (void (*)(void *))fsm_msgDebugLinkMemoryWrite},
|
||||
{'d', 'i', MessageType_MessageType_DebugLinkFlashErase, DebugLinkFlashErase_fields, (void (*)(void *))fsm_msgDebugLinkFlashErase},
|
||||
// debug out messages
|
||||
{'d', 'o', MessageType_MessageType_DebugLinkState, DebugLinkState_fields, 0},
|
||||
{'d', 'o', MessageType_MessageType_DebugLinkLog, DebugLinkLog_fields, 0},
|
||||
{'d', 'o', MessageType_MessageType_DebugLinkMemory, DebugLinkMemory_fields, 0},
|
||||
#endif
|
||||
// end
|
||||
{0, 0, 0, 0, 0}
|
||||
|
@ -44,6 +44,7 @@ bool protectButton(ButtonRequestType type, bool confirm_only)
|
||||
resp.has_code = true;
|
||||
resp.code = type;
|
||||
usbTiny(1);
|
||||
buttonUpdate(); // Clear button state
|
||||
msg_write(MessageType_MessageType_ButtonRequest, &resp);
|
||||
|
||||
for (;;) {
|
||||
@ -57,7 +58,7 @@ bool protectButton(ButtonRequestType type, bool confirm_only)
|
||||
|
||||
// button acked - check buttons
|
||||
if (acked) {
|
||||
usbDelay(3500);
|
||||
usbDelay(3300);
|
||||
buttonUpdate();
|
||||
if (button.YesUp) {
|
||||
result = true;
|
||||
@ -162,9 +163,9 @@ bool protectPin(bool use_cached)
|
||||
if (wait == 1) {
|
||||
secstrbuf[16] = 0;
|
||||
}
|
||||
layoutDialog(DIALOG_ICON_INFO, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait", secstr, "to continue ...", NULL);
|
||||
layoutDialog(&bmp_icon_info, NULL, NULL, NULL, "Wrong PIN entered", NULL, "Please wait", secstr, "to continue ...", NULL);
|
||||
// wait one second
|
||||
usbDelay(840000);
|
||||
usbDelay(800000);
|
||||
if (msg_tiny_id == MessageType_MessageType_Initialize) {
|
||||
protectAbortedByInitialize = true;
|
||||
msg_tiny_id = 0xFFFF;
|
||||
@ -224,7 +225,7 @@ bool protectPassphrase(void)
|
||||
usbTiny(1);
|
||||
msg_write(MessageType_MessageType_PassphraseRequest, &resp);
|
||||
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, NULL, NULL, NULL, "Please enter your", "passphrase using", "the computer's", "keyboard.", NULL, NULL);
|
||||
layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, "Please enter your", "passphrase using", "the computer's", "keyboard.", NULL, NULL);
|
||||
|
||||
bool result;
|
||||
for (;;) {
|
||||
|
@ -137,3 +137,6 @@ DebugLinkState.recovery_fake_word max_size:12
|
||||
|
||||
DebugLinkLog.bucket max_size:33
|
||||
DebugLinkLog.text max_size:256
|
||||
|
||||
DebugLinkMemory.memory max_size:1024
|
||||
DebugLinkMemoryWrite.memory max_size:1024
|
||||
|
@ -150,7 +150,7 @@ const pb_field_t GetAddress_fields[5] = {
|
||||
};
|
||||
|
||||
const pb_field_t EthereumGetAddress_fields[3] = {
|
||||
PB_FIELD2( 1, UINT32 , REPEATED, CALLBACK, FIRST, EthereumGetAddress, address_n, address_n, 0),
|
||||
PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, EthereumGetAddress, address_n, address_n, 0),
|
||||
PB_FIELD2( 2, BOOL , OPTIONAL, STATIC , OTHER, EthereumGetAddress, show_display, address_n, 0),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
@ -161,7 +161,7 @@ const pb_field_t Address_fields[2] = {
|
||||
};
|
||||
|
||||
const pb_field_t EthereumAddress_fields[2] = {
|
||||
PB_FIELD2( 1, BYTES , REQUIRED, CALLBACK, FIRST, EthereumAddress, address, address, 0),
|
||||
PB_FIELD2( 1, BYTES , REQUIRED, STATIC , FIRST, EthereumAddress, address, address, 0),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
@ -329,13 +329,13 @@ const pb_field_t TxAck_fields[2] = {
|
||||
};
|
||||
|
||||
const pb_field_t EthereumSignTx_fields[9] = {
|
||||
PB_FIELD2( 1, UINT32 , REPEATED, CALLBACK, FIRST, EthereumSignTx, address_n, address_n, 0),
|
||||
PB_FIELD2( 2, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, nonce, address_n, 0),
|
||||
PB_FIELD2( 3, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, gas_price, nonce, 0),
|
||||
PB_FIELD2( 4, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, gas_limit, gas_price, 0),
|
||||
PB_FIELD2( 5, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, to, gas_limit, 0),
|
||||
PB_FIELD2( 6, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, value, to, 0),
|
||||
PB_FIELD2( 7, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumSignTx, data_initial_chunk, value, 0),
|
||||
PB_FIELD2( 1, UINT32 , REPEATED, STATIC , FIRST, EthereumSignTx, address_n, address_n, 0),
|
||||
PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, nonce, address_n, 0),
|
||||
PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, gas_price, nonce, 0),
|
||||
PB_FIELD2( 4, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, gas_limit, gas_price, 0),
|
||||
PB_FIELD2( 5, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, to, gas_limit, 0),
|
||||
PB_FIELD2( 6, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, value, to, 0),
|
||||
PB_FIELD2( 7, BYTES , OPTIONAL, STATIC , OTHER, EthereumSignTx, data_initial_chunk, value, 0),
|
||||
PB_FIELD2( 8, UINT32 , OPTIONAL, STATIC , OTHER, EthereumSignTx, data_length, data_initial_chunk, 0),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
@ -343,13 +343,13 @@ const pb_field_t EthereumSignTx_fields[9] = {
|
||||
const pb_field_t EthereumTxRequest_fields[5] = {
|
||||
PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, EthereumTxRequest, data_length, data_length, 0),
|
||||
PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, EthereumTxRequest, signature_v, data_length, 0),
|
||||
PB_FIELD2( 3, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumTxRequest, signature_r, signature_v, 0),
|
||||
PB_FIELD2( 4, BYTES , OPTIONAL, CALLBACK, OTHER, EthereumTxRequest, signature_s, signature_r, 0),
|
||||
PB_FIELD2( 3, BYTES , OPTIONAL, STATIC , OTHER, EthereumTxRequest, signature_r, signature_v, 0),
|
||||
PB_FIELD2( 4, BYTES , OPTIONAL, STATIC , OTHER, EthereumTxRequest, signature_s, signature_r, 0),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t EthereumTxAck_fields[2] = {
|
||||
PB_FIELD2( 1, BYTES , OPTIONAL, CALLBACK, FIRST, EthereumTxAck, data_chunk, data_chunk, 0),
|
||||
PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, EthereumTxAck, data_chunk, data_chunk, 0),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
@ -423,6 +423,29 @@ const pb_field_t DebugLinkLog_fields[4] = {
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t DebugLinkMemoryRead_fields[3] = {
|
||||
PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, DebugLinkMemoryRead, address, address, 0),
|
||||
PB_FIELD2( 2, UINT32 , OPTIONAL, STATIC , OTHER, DebugLinkMemoryRead, length, address, 0),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t DebugLinkMemory_fields[2] = {
|
||||
PB_FIELD2( 1, BYTES , OPTIONAL, STATIC , FIRST, DebugLinkMemory, memory, memory, 0),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t DebugLinkMemoryWrite_fields[4] = {
|
||||
PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, DebugLinkMemoryWrite, address, address, 0),
|
||||
PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, DebugLinkMemoryWrite, memory, address, 0),
|
||||
PB_FIELD2( 3, BOOL , OPTIONAL, STATIC , OTHER, DebugLinkMemoryWrite, flash, memory, 0),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
const pb_field_t DebugLinkFlashErase_fields[2] = {
|
||||
PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, DebugLinkFlashErase, sector, sector, 0),
|
||||
PB_LAST_FIELD
|
||||
};
|
||||
|
||||
|
||||
/* Check that field information fits in pb_field_t */
|
||||
#if !defined(PB_FIELD_32BIT)
|
||||
@ -433,7 +456,7 @@ const pb_field_t DebugLinkLog_fields[4] = {
|
||||
* numbers or field sizes that are larger than what can fit in 8 or 16 bit
|
||||
* field descriptors.
|
||||
*/
|
||||
STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(GetECDHSessionKey, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_EthereumGetAddress_Address_EthereumAddress_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_EthereumSignTx_EthereumTxRequest_EthereumTxAck_SignIdentity_SignedIdentity_GetECDHSessionKey_ECDHSessionKey_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog)
|
||||
STATIC_ASSERT((pb_membersize(Features, coins[0]) < 65536 && pb_membersize(PublicKey, node) < 65536 && pb_membersize(GetAddress, multisig) < 65536 && pb_membersize(LoadDevice, node) < 65536 && pb_membersize(SimpleSignTx, inputs[0]) < 65536 && pb_membersize(SimpleSignTx, outputs[0]) < 65536 && pb_membersize(SimpleSignTx, transactions[0]) < 65536 && pb_membersize(TxRequest, details) < 65536 && pb_membersize(TxRequest, serialized) < 65536 && pb_membersize(TxAck, tx) < 65536 && pb_membersize(SignIdentity, identity) < 65536 && pb_membersize(GetECDHSessionKey, identity) < 65536 && pb_membersize(DebugLinkState, node) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_Initialize_GetFeatures_Features_ClearSession_ApplySettings_ChangePin_Ping_Success_Failure_ButtonRequest_ButtonAck_PinMatrixRequest_PinMatrixAck_Cancel_PassphraseRequest_PassphraseAck_GetEntropy_Entropy_GetPublicKey_PublicKey_GetAddress_EthereumGetAddress_Address_EthereumAddress_WipeDevice_LoadDevice_ResetDevice_EntropyRequest_EntropyAck_RecoveryDevice_WordRequest_WordAck_SignMessage_VerifyMessage_MessageSignature_EncryptMessage_EncryptedMessage_DecryptMessage_DecryptedMessage_CipherKeyValue_CipheredKeyValue_EstimateTxSize_TxSize_SignTx_SimpleSignTx_TxRequest_TxAck_EthereumSignTx_EthereumTxRequest_EthereumTxAck_SignIdentity_SignedIdentity_GetECDHSessionKey_ECDHSessionKey_FirmwareErase_FirmwareUpload_DebugLinkDecision_DebugLinkGetState_DebugLinkState_DebugLinkStop_DebugLinkLog_DebugLinkMemoryRead_DebugLinkMemory_DebugLinkMemoryWrite_DebugLinkFlashErase)
|
||||
#endif
|
||||
|
||||
#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT)
|
||||
|
@ -72,7 +72,11 @@ typedef enum _MessageType {
|
||||
MessageType_MessageType_DebugLinkGetState = 101,
|
||||
MessageType_MessageType_DebugLinkState = 102,
|
||||
MessageType_MessageType_DebugLinkStop = 103,
|
||||
MessageType_MessageType_DebugLinkLog = 104
|
||||
MessageType_MessageType_DebugLinkLog = 104,
|
||||
MessageType_MessageType_DebugLinkMemoryRead = 110,
|
||||
MessageType_MessageType_DebugLinkMemory = 111,
|
||||
MessageType_MessageType_DebugLinkMemoryWrite = 112,
|
||||
MessageType_MessageType_DebugLinkFlashErase = 113
|
||||
} MessageType;
|
||||
|
||||
/* Struct definitions */
|
||||
@ -197,6 +201,11 @@ typedef struct _DebugLinkDecision {
|
||||
bool yes_no;
|
||||
} DebugLinkDecision;
|
||||
|
||||
typedef struct _DebugLinkFlashErase {
|
||||
bool has_sector;
|
||||
uint32_t sector;
|
||||
} DebugLinkFlashErase;
|
||||
|
||||
typedef struct _DebugLinkLog {
|
||||
bool has_level;
|
||||
uint32_t level;
|
||||
@ -206,6 +215,37 @@ typedef struct _DebugLinkLog {
|
||||
char text[256];
|
||||
} DebugLinkLog;
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
uint8_t bytes[1024];
|
||||
} DebugLinkMemory_memory_t;
|
||||
|
||||
typedef struct _DebugLinkMemory {
|
||||
bool has_memory;
|
||||
DebugLinkMemory_memory_t memory;
|
||||
} DebugLinkMemory;
|
||||
|
||||
typedef struct _DebugLinkMemoryRead {
|
||||
bool has_address;
|
||||
uint32_t address;
|
||||
bool has_length;
|
||||
uint32_t length;
|
||||
} DebugLinkMemoryRead;
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
uint8_t bytes[1024];
|
||||
} DebugLinkMemoryWrite_memory_t;
|
||||
|
||||
typedef struct _DebugLinkMemoryWrite {
|
||||
bool has_address;
|
||||
uint32_t address;
|
||||
bool has_memory;
|
||||
DebugLinkMemoryWrite_memory_t memory;
|
||||
bool has_flash;
|
||||
bool flash;
|
||||
} DebugLinkMemoryWrite;
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
uint8_t bytes[1024];
|
||||
@ -360,39 +400,100 @@ typedef struct _EstimateTxSize {
|
||||
char coin_name[17];
|
||||
} EstimateTxSize;
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
uint8_t bytes[20];
|
||||
} EthereumAddress_address_t;
|
||||
|
||||
typedef struct _EthereumAddress {
|
||||
pb_callback_t address;
|
||||
EthereumAddress_address_t address;
|
||||
} EthereumAddress;
|
||||
|
||||
typedef struct _EthereumGetAddress {
|
||||
pb_callback_t address_n;
|
||||
size_t address_n_count;
|
||||
uint32_t address_n[8];
|
||||
bool has_show_display;
|
||||
bool show_display;
|
||||
} EthereumGetAddress;
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
uint8_t bytes[32];
|
||||
} EthereumSignTx_nonce_t;
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
uint8_t bytes[32];
|
||||
} EthereumSignTx_gas_price_t;
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
uint8_t bytes[32];
|
||||
} EthereumSignTx_gas_limit_t;
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
uint8_t bytes[20];
|
||||
} EthereumSignTx_to_t;
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
uint8_t bytes[32];
|
||||
} EthereumSignTx_value_t;
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
uint8_t bytes[1024];
|
||||
} EthereumSignTx_data_initial_chunk_t;
|
||||
|
||||
typedef struct _EthereumSignTx {
|
||||
pb_callback_t address_n;
|
||||
pb_callback_t nonce;
|
||||
pb_callback_t gas_price;
|
||||
pb_callback_t gas_limit;
|
||||
pb_callback_t to;
|
||||
pb_callback_t value;
|
||||
pb_callback_t data_initial_chunk;
|
||||
size_t address_n_count;
|
||||
uint32_t address_n[8];
|
||||
bool has_nonce;
|
||||
EthereumSignTx_nonce_t nonce;
|
||||
bool has_gas_price;
|
||||
EthereumSignTx_gas_price_t gas_price;
|
||||
bool has_gas_limit;
|
||||
EthereumSignTx_gas_limit_t gas_limit;
|
||||
bool has_to;
|
||||
EthereumSignTx_to_t to;
|
||||
bool has_value;
|
||||
EthereumSignTx_value_t value;
|
||||
bool has_data_initial_chunk;
|
||||
EthereumSignTx_data_initial_chunk_t data_initial_chunk;
|
||||
bool has_data_length;
|
||||
uint32_t data_length;
|
||||
} EthereumSignTx;
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
uint8_t bytes[1024];
|
||||
} EthereumTxAck_data_chunk_t;
|
||||
|
||||
typedef struct _EthereumTxAck {
|
||||
pb_callback_t data_chunk;
|
||||
bool has_data_chunk;
|
||||
EthereumTxAck_data_chunk_t data_chunk;
|
||||
} EthereumTxAck;
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
uint8_t bytes[32];
|
||||
} EthereumTxRequest_signature_r_t;
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
uint8_t bytes[32];
|
||||
} EthereumTxRequest_signature_s_t;
|
||||
|
||||
typedef struct _EthereumTxRequest {
|
||||
bool has_data_length;
|
||||
uint32_t data_length;
|
||||
bool has_signature_v;
|
||||
uint32_t signature_v;
|
||||
pb_callback_t signature_r;
|
||||
pb_callback_t signature_s;
|
||||
bool has_signature_r;
|
||||
EthereumTxRequest_signature_r_t signature_r;
|
||||
bool has_signature_s;
|
||||
EthereumTxRequest_signature_s_t signature_s;
|
||||
} EthereumTxRequest;
|
||||
|
||||
typedef struct _Failure {
|
||||
@ -747,9 +848,9 @@ extern const uint32_t SimpleSignTx_lock_time_default;
|
||||
#define GetPublicKey_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0}
|
||||
#define PublicKey_init_default {HDNodeType_init_default, false, ""}
|
||||
#define GetAddress_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "Bitcoin", false, 0, false, MultisigRedeemScriptType_init_default}
|
||||
#define EthereumGetAddress_init_default {{{NULL}, NULL}, false, 0}
|
||||
#define EthereumGetAddress_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, 0}
|
||||
#define Address_init_default {""}
|
||||
#define EthereumAddress_init_default {{{NULL}, NULL}}
|
||||
#define EthereumAddress_init_default {{0, {0}}}
|
||||
#define WipeDevice_init_default {0}
|
||||
#define LoadDevice_init_default {false, "", false, HDNodeType_init_default, false, "", false, 0, false, "english", false, "", false, 0}
|
||||
#define ResetDevice_init_default {false, 0, false, 256u, false, 0, false, 0, false, "english", false, ""}
|
||||
@ -773,9 +874,9 @@ extern const uint32_t SimpleSignTx_lock_time_default;
|
||||
#define SimpleSignTx_init_default {0, {}, 0, {}, 0, {}, false, "Bitcoin", false, 1u, false, 0u}
|
||||
#define TxRequest_init_default {false, (RequestType)0, false, TxRequestDetailsType_init_default, false, TxRequestSerializedType_init_default}
|
||||
#define TxAck_init_default {false, TransactionType_init_default}
|
||||
#define EthereumSignTx_init_default {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, 0}
|
||||
#define EthereumTxRequest_init_default {false, 0, false, 0, {{NULL}, NULL}, {{NULL}, NULL}}
|
||||
#define EthereumTxAck_init_default {{{NULL}, NULL}}
|
||||
#define EthereumSignTx_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0}
|
||||
#define EthereumTxRequest_init_default {false, 0, false, 0, false, {0, {0}}, false, {0, {0}}}
|
||||
#define EthereumTxAck_init_default {false, {0, {0}}}
|
||||
#define SignIdentity_init_default {false, IdentityType_init_default, false, {0, {0}}, false, "", false, ""}
|
||||
#define SignedIdentity_init_default {false, "", false, {0, {0}}, false, {0, {0}}}
|
||||
#define GetECDHSessionKey_init_default {false, IdentityType_init_default, false, {0, {0}}, false, ""}
|
||||
@ -787,6 +888,10 @@ extern const uint32_t SimpleSignTx_lock_time_default;
|
||||
#define DebugLinkState_init_default {false, {0, {0}}, false, "", false, "", false, "", false, HDNodeType_init_default, false, 0, false, "", false, {0, {0}}, false, "", false, 0}
|
||||
#define DebugLinkStop_init_default {0}
|
||||
#define DebugLinkLog_init_default {false, 0, false, "", false, ""}
|
||||
#define DebugLinkMemoryRead_init_default {false, 0, false, 0}
|
||||
#define DebugLinkMemory_init_default {false, {0, {0}}}
|
||||
#define DebugLinkMemoryWrite_init_default {false, 0, false, {0, {0}}, false, 0}
|
||||
#define DebugLinkFlashErase_init_default {false, 0}
|
||||
#define Initialize_init_zero {0}
|
||||
#define GetFeatures_init_zero {0}
|
||||
#define Features_init_zero {false, "", false, 0, false, 0, false, 0, false, 0, false, "", false, 0, false, 0, false, "", false, "", 0, {CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero, CoinType_init_zero}, false, 0, false, {0, {0}}, false, {0, {0}}, false, 0, false, 0, false, 0}
|
||||
@ -808,9 +913,9 @@ extern const uint32_t SimpleSignTx_lock_time_default;
|
||||
#define GetPublicKey_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0}
|
||||
#define PublicKey_init_zero {HDNodeType_init_zero, false, ""}
|
||||
#define GetAddress_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, "", false, 0, false, MultisigRedeemScriptType_init_zero}
|
||||
#define EthereumGetAddress_init_zero {{{NULL}, NULL}, false, 0}
|
||||
#define EthereumGetAddress_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, 0}
|
||||
#define Address_init_zero {""}
|
||||
#define EthereumAddress_init_zero {{{NULL}, NULL}}
|
||||
#define EthereumAddress_init_zero {{0, {0}}}
|
||||
#define WipeDevice_init_zero {0}
|
||||
#define LoadDevice_init_zero {false, "", false, HDNodeType_init_zero, false, "", false, 0, false, "", false, "", false, 0}
|
||||
#define ResetDevice_init_zero {false, 0, false, 0, false, 0, false, 0, false, "", false, ""}
|
||||
@ -834,9 +939,9 @@ extern const uint32_t SimpleSignTx_lock_time_default;
|
||||
#define SimpleSignTx_init_zero {0, {}, 0, {}, 0, {}, false, "", false, 0, false, 0}
|
||||
#define TxRequest_init_zero {false, (RequestType)0, false, TxRequestDetailsType_init_zero, false, TxRequestSerializedType_init_zero}
|
||||
#define TxAck_init_zero {false, TransactionType_init_zero}
|
||||
#define EthereumSignTx_init_zero {{{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, {{NULL}, NULL}, false, 0}
|
||||
#define EthereumTxRequest_init_zero {false, 0, false, 0, {{NULL}, NULL}, {{NULL}, NULL}}
|
||||
#define EthereumTxAck_init_zero {{{NULL}, NULL}}
|
||||
#define EthereumSignTx_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, {0, {0}}, false, 0}
|
||||
#define EthereumTxRequest_init_zero {false, 0, false, 0, false, {0, {0}}, false, {0, {0}}}
|
||||
#define EthereumTxAck_init_zero {false, {0, {0}}}
|
||||
#define SignIdentity_init_zero {false, IdentityType_init_zero, false, {0, {0}}, false, "", false, ""}
|
||||
#define SignedIdentity_init_zero {false, "", false, {0, {0}}, false, {0, {0}}}
|
||||
#define GetECDHSessionKey_init_zero {false, IdentityType_init_zero, false, {0, {0}}, false, ""}
|
||||
@ -848,6 +953,10 @@ extern const uint32_t SimpleSignTx_lock_time_default;
|
||||
#define DebugLinkState_init_zero {false, {0, {0}}, false, "", false, "", false, "", false, HDNodeType_init_zero, false, 0, false, "", false, {0, {0}}, false, "", false, 0}
|
||||
#define DebugLinkStop_init_zero {0}
|
||||
#define DebugLinkLog_init_zero {false, 0, false, "", false, ""}
|
||||
#define DebugLinkMemoryRead_init_zero {false, 0, false, 0}
|
||||
#define DebugLinkMemory_init_zero {false, {0, {0}}}
|
||||
#define DebugLinkMemoryWrite_init_zero {false, 0, false, {0, {0}}, false, 0}
|
||||
#define DebugLinkFlashErase_init_zero {false, 0}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define Address_address_tag 1
|
||||
@ -867,9 +976,16 @@ extern const uint32_t SimpleSignTx_lock_time_default;
|
||||
#define CipherKeyValue_iv_tag 7
|
||||
#define CipheredKeyValue_value_tag 1
|
||||
#define DebugLinkDecision_yes_no_tag 1
|
||||
#define DebugLinkFlashErase_sector_tag 1
|
||||
#define DebugLinkLog_level_tag 1
|
||||
#define DebugLinkLog_bucket_tag 2
|
||||
#define DebugLinkLog_text_tag 3
|
||||
#define DebugLinkMemory_memory_tag 1
|
||||
#define DebugLinkMemoryRead_address_tag 1
|
||||
#define DebugLinkMemoryRead_length_tag 2
|
||||
#define DebugLinkMemoryWrite_address_tag 1
|
||||
#define DebugLinkMemoryWrite_memory_tag 2
|
||||
#define DebugLinkMemoryWrite_flash_tag 3
|
||||
#define DebugLinkState_layout_tag 1
|
||||
#define DebugLinkState_pin_tag 2
|
||||
#define DebugLinkState_matrix_tag 3
|
||||
@ -1072,6 +1188,10 @@ extern const pb_field_t DebugLinkGetState_fields[1];
|
||||
extern const pb_field_t DebugLinkState_fields[11];
|
||||
extern const pb_field_t DebugLinkStop_fields[1];
|
||||
extern const pb_field_t DebugLinkLog_fields[4];
|
||||
extern const pb_field_t DebugLinkMemoryRead_fields[3];
|
||||
extern const pb_field_t DebugLinkMemory_fields[2];
|
||||
extern const pb_field_t DebugLinkMemoryWrite_fields[4];
|
||||
extern const pb_field_t DebugLinkFlashErase_fields[2];
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define Initialize_size 0
|
||||
@ -1095,7 +1215,9 @@ extern const pb_field_t DebugLinkLog_fields[4];
|
||||
#define GetPublicKey_size 84
|
||||
#define PublicKey_size (121 + HDNodeType_size)
|
||||
#define GetAddress_size (75 + MultisigRedeemScriptType_size)
|
||||
#define EthereumGetAddress_size 50
|
||||
#define Address_size 38
|
||||
#define EthereumAddress_size 22
|
||||
#define WipeDevice_size 0
|
||||
#define LoadDevice_size (320 + HDNodeType_size)
|
||||
#define ResetDevice_size 66
|
||||
@ -1119,6 +1241,9 @@ extern const pb_field_t DebugLinkLog_fields[4];
|
||||
#define SimpleSignTx_size (31 + 0*TxInputType_size + 0*TxOutputType_size + 0*TransactionType_size)
|
||||
#define TxRequest_size (18 + TxRequestDetailsType_size + TxRequestSerializedType_size)
|
||||
#define TxAck_size (6 + TransactionType_size)
|
||||
#define EthereumSignTx_size 1239
|
||||
#define EthereumTxRequest_size 80
|
||||
#define EthereumTxAck_size 1027
|
||||
#define SignIdentity_size (558 + IdentityType_size)
|
||||
#define SignedIdentity_size 140
|
||||
#define GetECDHSessionKey_size (107 + IdentityType_size)
|
||||
@ -1130,6 +1255,10 @@ extern const pb_field_t DebugLinkLog_fields[4];
|
||||
#define DebugLinkState_size (1468 + HDNodeType_size)
|
||||
#define DebugLinkStop_size 0
|
||||
#define DebugLinkLog_size 300
|
||||
#define DebugLinkMemoryRead_size 12
|
||||
#define DebugLinkMemory_size 1027
|
||||
#define DebugLinkMemoryWrite_size 1035
|
||||
#define DebugLinkFlashErase_size 6
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
|
@ -41,7 +41,7 @@ void next_word(void) {
|
||||
if (word_pos == 0) {
|
||||
const char * const *wl = mnemonic_wordlist();
|
||||
strlcpy(fake_word, wl[random_uniform(2048)], sizeof(fake_word));
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, NULL, NULL, NULL, "Please enter the word", NULL, fake_word, NULL, "on your computer", NULL);
|
||||
layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, "Please enter the word", NULL, fake_word, NULL, "on your computer", NULL);
|
||||
} else {
|
||||
fake_word[0] = 0;
|
||||
char desc[] = "##th word";
|
||||
@ -60,7 +60,7 @@ void next_word(void) {
|
||||
if (word_pos == 3 || word_pos == 23) {
|
||||
desc[2] = 'r'; desc[3] = 'd';
|
||||
}
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, NULL, NULL, NULL, "Please enter the", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, "of your mnemonic", NULL);
|
||||
layoutDialogSwipe(&bmp_icon_info, NULL, NULL, NULL, "Please enter the", NULL, (word_pos < 10 ? desc + 1 : desc), NULL, "of your mnemonic", NULL);
|
||||
}
|
||||
WordRequest resp;
|
||||
memset(&resp, 0, sizeof(WordRequest));
|
||||
|
@ -52,7 +52,7 @@ void reset_init(bool display_random, uint32_t _strength, bool passphrase_protect
|
||||
data2hex(int_entropy + 24, 8, ent_str[3]);
|
||||
|
||||
if (display_random) {
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, "Cancel", "Continue", NULL, "Internal entropy:", ent_str[0], ent_str[1], ent_str[2], ent_str[3], NULL);
|
||||
layoutDialogSwipe(&bmp_icon_info, "Cancel", "Continue", NULL, "Internal entropy:", ent_str[0], ent_str[1], ent_str[2], ent_str[3], NULL);
|
||||
if (!protectButton(ButtonRequestType_ButtonRequest_ResetDevice, false)) {
|
||||
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Reset cancelled");
|
||||
layoutHome();
|
||||
@ -129,15 +129,15 @@ void reset_entropy(const uint8_t *ext_entropy, uint32_t len)
|
||||
current_word_display[j + 1] = 0;
|
||||
if (word_pos == (int)strength/32*3) { // last word
|
||||
if (pass == 1) {
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Finish", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL);
|
||||
layoutDialogSwipe(&bmp_icon_info, NULL, "Finish", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL);
|
||||
} else {
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Again", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL);
|
||||
layoutDialogSwipe(&bmp_icon_info, NULL, "Again", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL);
|
||||
}
|
||||
} else {
|
||||
if (pass == 1) {
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Next", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL);
|
||||
layoutDialogSwipe(&bmp_icon_info, NULL, "Next", NULL, "Please check the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL);
|
||||
} else {
|
||||
layoutDialogSwipe(DIALOG_ICON_INFO, NULL, "Next", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL);
|
||||
layoutDialogSwipe(&bmp_icon_info, NULL, "Next", NULL, "Write down the seed", NULL, (word_pos < 10 ? desc + 1 : desc), current_word_display, NULL, NULL);
|
||||
}
|
||||
}
|
||||
if (!protectButton(ButtonRequestType_ButtonRequest_ConfirmWord, true)) {
|
||||
|
@ -48,13 +48,15 @@ char storage_uuid_str[25];
|
||||
/*
|
||||
storage layout:
|
||||
|
||||
offset | type/length | description
|
||||
--------+-------------+-------------------------------
|
||||
0x0000 | 4 bytes | magic = 'stor'
|
||||
0x0004 | 12 bytes | uuid
|
||||
0x0010 | ? | Storage structure
|
||||
0x4000 | 4 kbytes | area for pin failures
|
||||
0x5000 | 12 kbytes | reserved
|
||||
offset | type/length | description
|
||||
--------+--------------+-------------------------------
|
||||
0x0000 | 4 bytes | magic = 'stor'
|
||||
0x0004 | 12 bytes | uuid
|
||||
0x0010 | ? bytes | Storage structure
|
||||
--------+--------------+-------------------------------
|
||||
0x4000 | 4 kbytes | area for pin failures
|
||||
0x5000 | 256 bytes | area for u2f counter updates
|
||||
0x5100 | 11.75 kbytes | reserved
|
||||
|
||||
The area for pin failures looks like this:
|
||||
0 ... 0 pinfail 0xffffffff .. 0xffffffff
|
||||
@ -63,16 +65,29 @@ the number of zeros is the number of pin failures.
|
||||
This layout is used because we can only clear bits without
|
||||
erasing the flash.
|
||||
|
||||
The area for u2f counter updates is just a sequence of zero-bits
|
||||
followed by a sequence of one-bits. The bits in a byte are numbered
|
||||
from LSB to MSB. The number of zero bits is the offset that should
|
||||
be added to the storage u2f_counter to get the real counter value.
|
||||
|
||||
*/
|
||||
|
||||
#define FLASH_STORAGE_PINAREA (FLASH_META_START + 0x4000)
|
||||
#define FLASH_STORAGE_PINAREA_LEN (0x1000)
|
||||
#define FLASH_STORAGE_U2FAREA (FLASH_STORAGE_PINAREA + FLASH_STORAGE_PINAREA_LEN)
|
||||
#define FLASH_STORAGE_U2FAREA_LEN (0x100)
|
||||
#define FLASH_STORAGE_REALLEN (4 + sizeof(storage_uuid) + sizeof(Storage))
|
||||
_Static_assert(FLASH_STORAGE_START + FLASH_STORAGE_REALLEN <= FLASH_STORAGE_PINAREA, "Storage struct is too large for TREZOR flash");
|
||||
_Static_assert((sizeof(storage_uuid) & 3) == 0, "storage uuid unaligned");
|
||||
_Static_assert((sizeof(storage) & 3) == 0, "storage unaligned");
|
||||
|
||||
static bool sessionSeedCached;
|
||||
/* Current u2f offset, i.e. u2f counter is
|
||||
* storage.u2f_counter + storage_u2f_offset.
|
||||
* This corresponds to the number of cleared bits in the U2FAREA.
|
||||
*/
|
||||
static uint32_t storage_u2f_offset;
|
||||
|
||||
static bool sessionSeedCached, sessionSeedUsesPassphrase;
|
||||
|
||||
static uint8_t sessionSeed[64];
|
||||
|
||||
@ -83,12 +98,17 @@ static char sessionPassphrase[51];
|
||||
|
||||
#define STORAGE_VERSION 6
|
||||
|
||||
void storage_show_error(void)
|
||||
{
|
||||
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Storage failure", "detected.", NULL, "Please unplug", "the device.", NULL);
|
||||
for (;;) { }
|
||||
}
|
||||
|
||||
void storage_check_flash_errors(void)
|
||||
{
|
||||
// flash operation failed
|
||||
if (FLASH_SR & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) {
|
||||
layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Storage failure", "detected.", NULL, "Please unplug", "the device.", NULL);
|
||||
for (;;) { }
|
||||
storage_show_error();
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,6 +152,15 @@ bool storage_from_flash(void)
|
||||
storage.has_pin_failed_attempts = false;
|
||||
storage.pin_failed_attempts = 0;
|
||||
}
|
||||
uint32_t *u2fptr = (uint32_t*) FLASH_STORAGE_U2FAREA;
|
||||
while (*u2fptr == 0)
|
||||
u2fptr++;
|
||||
storage_u2f_offset = 32 * (u2fptr - (uint32_t*) FLASH_STORAGE_U2FAREA);
|
||||
uint32_t u2fword = *u2fptr;
|
||||
while ((u2fword & 1) == 0) {
|
||||
storage_u2f_offset++;
|
||||
u2fword >>= 1;
|
||||
}
|
||||
// upgrade storage version
|
||||
if (version != STORAGE_VERSION) {
|
||||
storage.version = STORAGE_VERSION;
|
||||
@ -185,15 +214,13 @@ static uint32_t storage_flash_words(uint32_t addr, uint32_t *src, int nwords) {
|
||||
return addr;
|
||||
}
|
||||
|
||||
void storage_commit(void)
|
||||
static void storage_commit_locked(void)
|
||||
{
|
||||
uint8_t meta_backup[FLASH_META_DESC_LEN];
|
||||
|
||||
// backup meta
|
||||
memcpy(meta_backup, (uint8_t*)FLASH_META_START, FLASH_META_DESC_LEN);
|
||||
|
||||
flash_clear_status_flags();
|
||||
flash_unlock();
|
||||
// erase storage
|
||||
flash_erase_sector(FLASH_META_SECTOR_FIRST, FLASH_CR_PROGRAM_X32);
|
||||
// copy meta
|
||||
@ -209,6 +236,13 @@ void storage_commit(void)
|
||||
flash_program_word(flash, 0);
|
||||
flash += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void storage_commit(void)
|
||||
{
|
||||
flash_clear_status_flags();
|
||||
flash_unlock();
|
||||
storage_commit_locked();
|
||||
flash_lock();
|
||||
storage_check_flash_errors();
|
||||
}
|
||||
@ -298,27 +332,29 @@ void get_root_node_callback(uint32_t iter, uint32_t total)
|
||||
layoutProgress("Waking up", 1000 * iter / total);
|
||||
}
|
||||
|
||||
const uint8_t *storage_getSeed(void)
|
||||
const uint8_t *storage_getSeed(bool usePassphrase)
|
||||
{
|
||||
// root node is properly cached
|
||||
if (sessionSeedCached) {
|
||||
if (usePassphrase == sessionSeedUsesPassphrase
|
||||
&& sessionSeedCached) {
|
||||
return sessionSeed;
|
||||
}
|
||||
|
||||
// if storage has mnemonic, convert it to node and use it
|
||||
if (storage.has_mnemonic) {
|
||||
if (!protectPassphrase()) {
|
||||
if (usePassphrase && !protectPassphrase()) {
|
||||
return NULL;
|
||||
}
|
||||
mnemonic_to_seed(storage.mnemonic, sessionPassphrase, sessionSeed, get_root_node_callback); // BIP-0039
|
||||
mnemonic_to_seed(storage.mnemonic, usePassphrase ? sessionPassphrase : "", sessionSeed, get_root_node_callback); // BIP-0039
|
||||
sessionSeedCached = true;
|
||||
sessionSeedUsesPassphrase = usePassphrase;
|
||||
return sessionSeed;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool storage_getRootNode(HDNode *node, const char *curve)
|
||||
bool storage_getRootNode(HDNode *node, const char *curve, bool usePassphrase)
|
||||
{
|
||||
// if storage has node, decrypt and use it
|
||||
if (storage.has_node && strcmp(curve, SECP256K1_NAME) == 0) {
|
||||
@ -347,7 +383,7 @@ bool storage_getRootNode(HDNode *node, const char *curve)
|
||||
return true;
|
||||
}
|
||||
|
||||
const uint8_t *seed = storage_getSeed();
|
||||
const uint8_t *seed = storage_getSeed(usePassphrase);
|
||||
if (seed == NULL) {
|
||||
return false;
|
||||
}
|
||||
@ -427,23 +463,49 @@ bool session_isPinCached(void)
|
||||
return sessionPinCached;
|
||||
}
|
||||
|
||||
void storage_clearPinArea()
|
||||
void storage_clearPinArea(void)
|
||||
{
|
||||
flash_clear_status_flags();
|
||||
flash_unlock();
|
||||
flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32);
|
||||
flash_lock();
|
||||
storage_check_flash_errors();
|
||||
storage_u2f_offset = 0;
|
||||
}
|
||||
|
||||
// called when u2f area or pin area overflows
|
||||
static void storage_area_recycle(uint32_t new_pinfails)
|
||||
{
|
||||
// first clear storage marker. In case of a failure below it is better
|
||||
// to clear the storage than to allow restarting with zero PIN failures
|
||||
flash_program_word(FLASH_STORAGE_START, 0);
|
||||
if (*(uint32_t *)FLASH_STORAGE_START != 0) {
|
||||
storage_show_error();
|
||||
}
|
||||
|
||||
// erase storage sector
|
||||
flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32);
|
||||
flash_program_word(FLASH_STORAGE_PINAREA, new_pinfails);
|
||||
if (*(uint32_t *)FLASH_STORAGE_PINAREA != new_pinfails) {
|
||||
storage_show_error();
|
||||
}
|
||||
|
||||
if (storage_u2f_offset > 0) {
|
||||
storage.has_u2f_counter = true;
|
||||
storage.u2f_counter += storage_u2f_offset;
|
||||
storage_u2f_offset = 0;
|
||||
}
|
||||
storage_commit_locked();
|
||||
}
|
||||
|
||||
void storage_resetPinFails(uint32_t *pinfailsptr)
|
||||
{
|
||||
flash_clear_status_flags();
|
||||
flash_unlock();
|
||||
if ((uint32_t) (pinfailsptr + 1) - FLASH_STORAGE_PINAREA
|
||||
>= FLASH_STORAGE_PINAREA_LEN) {
|
||||
// erase extra storage sector
|
||||
flash_erase_sector(FLASH_META_SECTOR_LAST, FLASH_CR_PROGRAM_X32);
|
||||
if ((uint32_t) (pinfailsptr + 1)
|
||||
>= FLASH_STORAGE_PINAREA + FLASH_STORAGE_PINAREA_LEN) {
|
||||
// recycle extra storage sector
|
||||
storage_area_recycle(0xffffffff);
|
||||
} else {
|
||||
flash_program_word((uint32_t) pinfailsptr, 0);
|
||||
}
|
||||
@ -480,3 +542,20 @@ bool storage_isInitialized(void)
|
||||
{
|
||||
return storage.has_node || storage.has_mnemonic;
|
||||
}
|
||||
|
||||
uint32_t storage_nextU2FCounter(void)
|
||||
{
|
||||
uint32_t *ptr = ((uint32_t *) FLASH_STORAGE_U2FAREA) + (storage_u2f_offset / 32);
|
||||
uint32_t newval = 0xfffffffe << (storage_u2f_offset & 31);
|
||||
|
||||
flash_clear_status_flags();
|
||||
flash_unlock();
|
||||
flash_program_word((uint32_t) ptr, newval);
|
||||
storage_u2f_offset++;
|
||||
if (storage_u2f_offset >= 8 * FLASH_STORAGE_U2FAREA_LEN) {
|
||||
storage_area_recycle(*storage_getPinFailsPtr());
|
||||
}
|
||||
flash_lock();
|
||||
storage_check_flash_errors();
|
||||
return storage.u2f_counter + storage_u2f_offset;
|
||||
}
|
||||
|
@ -33,9 +33,9 @@ void session_clear(bool clear_pin);
|
||||
|
||||
void storage_loadDevice(LoadDevice *msg);
|
||||
|
||||
const uint8_t *storage_getSeed(void);
|
||||
const uint8_t *storage_getSeed(bool usePassphrase);
|
||||
|
||||
bool storage_getRootNode(HDNode *node, const char *curve);
|
||||
bool storage_getRootNode(HDNode *node, const char *curve, bool usePassphrase);
|
||||
|
||||
const char *storage_getLabel(void);
|
||||
void storage_setLabel(const char *label);
|
||||
@ -61,6 +61,8 @@ void storage_resetPinFails(uint32_t *pinfailptr);
|
||||
bool storage_increasePinFails(uint32_t *pinfailptr);
|
||||
uint32_t *storage_getPinFailsPtr(void);
|
||||
|
||||
uint32_t storage_nextU2FCounter(void);
|
||||
|
||||
bool storage_isInitialized(void);
|
||||
|
||||
extern Storage storage;
|
||||
|
@ -32,7 +32,7 @@ uint32_t __stack_chk_guard;
|
||||
|
||||
void __attribute__((noreturn)) __stack_chk_fail(void)
|
||||
{
|
||||
layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL);
|
||||
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Stack smashing", "detected.", NULL, "Please unplug", "the device.", NULL);
|
||||
for (;;) {} // loop forever
|
||||
}
|
||||
|
||||
|
768
firmware/u2f.c
Normal file
768
firmware/u2f.c
Normal file
@ -0,0 +1,768 @@
|
||||
/*
|
||||
* This file is part of the TREZOR project.
|
||||
*
|
||||
* Copyright (C) 2015 Mark Bryars <mbryars@google.com>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <ecdsa.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "storage.h"
|
||||
#include "bip32.h"
|
||||
#include "layout2.h"
|
||||
#include "usb.h"
|
||||
#include "buttons.h"
|
||||
#include "trezor.h"
|
||||
#include "curves.h"
|
||||
#include "nist256p1.h"
|
||||
#include "rng.h"
|
||||
#include "hmac.h"
|
||||
#include "util.h"
|
||||
#include "macros.h"
|
||||
|
||||
#include "u2f/u2f.h"
|
||||
#include "u2f/u2f_hid.h"
|
||||
#include "u2f/u2f_keys.h"
|
||||
#include "u2f_knownapps.h"
|
||||
#include "u2f.h"
|
||||
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
// About 1/2 Second according to values used in protect.c
|
||||
#define U2F_TIMEOUT (800000/2)
|
||||
#define U2F_OUT_PKT_BUFFER_LEN 128
|
||||
|
||||
// Initialise without a cid
|
||||
static uint32_t cid = 0;
|
||||
|
||||
// Circular Output buffer
|
||||
static uint32_t u2f_out_start = 0;
|
||||
static uint32_t u2f_out_end = 0;
|
||||
static uint8_t u2f_out_packets[U2F_OUT_PKT_BUFFER_LEN][HID_RPT_SIZE];
|
||||
|
||||
#define U2F_PUBKEY_LEN 65
|
||||
#define KEY_PATH_LEN 32
|
||||
#define KEY_HANDLE_LEN (KEY_PATH_LEN + SHA256_DIGEST_LENGTH)
|
||||
|
||||
// Derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r'
|
||||
#define KEY_PATH_ENTRIES (1 + KEY_PATH_LEN / sizeof(uint32_t))
|
||||
|
||||
// Auth/Register request state machine
|
||||
typedef enum {
|
||||
INIT = 0,
|
||||
AUTH = 10,
|
||||
AUTH_PASS = 11,
|
||||
REG = 20,
|
||||
REG_PASS = 21
|
||||
} U2F_STATE;
|
||||
|
||||
static U2F_STATE last_req_state = INIT;
|
||||
|
||||
typedef struct {
|
||||
uint8_t reserved;
|
||||
uint8_t appId[U2F_APPID_SIZE];
|
||||
uint8_t chal[U2F_CHAL_SIZE];
|
||||
uint8_t keyHandle[KEY_HANDLE_LEN];
|
||||
uint8_t pubKey[U2F_PUBKEY_LEN];
|
||||
} U2F_REGISTER_SIG_STR;
|
||||
|
||||
typedef struct {
|
||||
uint8_t appId[U2F_APPID_SIZE];
|
||||
uint8_t flags;
|
||||
uint8_t ctr[4];
|
||||
uint8_t chal[U2F_CHAL_SIZE];
|
||||
} U2F_AUTHENTICATE_SIG_STR;
|
||||
|
||||
|
||||
#if DEBUG_LOG
|
||||
char *debugInt(const uint32_t i)
|
||||
{
|
||||
static uint8_t n = 0;
|
||||
static char id[8][9];
|
||||
uint32hex(i, id[n]);
|
||||
debugLog(0, "", id[n]);
|
||||
char *ret = (char *)id[n];
|
||||
n = (n + 1) % 8;
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
#define debugInt(I) do{}while(0)
|
||||
#endif
|
||||
|
||||
static uint32_t dialog_timeout = 0;
|
||||
|
||||
uint32_t next_cid(void)
|
||||
{
|
||||
// extremely unlikely but hey
|
||||
do {
|
||||
cid = random32();
|
||||
} while (cid == 0 || cid == CID_BROADCAST);
|
||||
return cid;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint8_t buf[57+127*59];
|
||||
uint8_t *buf_ptr;
|
||||
uint32_t len;
|
||||
uint8_t seq;
|
||||
uint8_t cmd;
|
||||
} U2F_ReadBuffer;
|
||||
|
||||
U2F_ReadBuffer *reader;
|
||||
|
||||
void u2fhid_read(char tiny, const U2FHID_FRAME *f)
|
||||
{
|
||||
// Always handle init packets directly
|
||||
if (f->init.cmd == U2FHID_INIT) {
|
||||
u2fhid_init(f);
|
||||
if (tiny && reader && f->cid == cid) {
|
||||
// abort current channel
|
||||
reader->cmd = 0;
|
||||
reader->len = 0;
|
||||
reader->seq = 255;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (tiny) {
|
||||
// read continue packet
|
||||
if (reader == 0 || cid != f->cid) {
|
||||
send_u2fhid_error(f->cid, ERR_CHANNEL_BUSY);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((f->type & TYPE_INIT) && reader->seq == 255) {
|
||||
u2fhid_init_cmd(f);
|
||||
return;
|
||||
}
|
||||
|
||||
if (reader->seq != f->cont.seq) {
|
||||
send_u2fhid_error(f->cid, ERR_INVALID_SEQ);
|
||||
reader->cmd = 0;
|
||||
reader->len = 0;
|
||||
reader->seq = 255;
|
||||
return;
|
||||
}
|
||||
|
||||
// check out of bounds
|
||||
if ((reader->buf_ptr - reader->buf) >= (signed) reader->len
|
||||
|| (reader->buf_ptr + sizeof(f->cont.data) - reader->buf) > (signed) sizeof(reader->buf))
|
||||
return;
|
||||
reader->seq++;
|
||||
memcpy(reader->buf_ptr, f->cont.data, sizeof(f->cont.data));
|
||||
reader->buf_ptr += sizeof(f->cont.data);
|
||||
return;
|
||||
}
|
||||
|
||||
u2fhid_read_start(f);
|
||||
}
|
||||
|
||||
void u2fhid_init_cmd(const U2FHID_FRAME *f) {
|
||||
reader->seq = 0;
|
||||
reader->buf_ptr = reader->buf;
|
||||
reader->len = MSG_LEN(*f);
|
||||
reader->cmd = f->type;
|
||||
memcpy(reader->buf_ptr, f->init.data, sizeof(f->init.data));
|
||||
reader->buf_ptr += sizeof(f->init.data);
|
||||
cid = f->cid;
|
||||
}
|
||||
|
||||
void u2fhid_read_start(const U2FHID_FRAME *f) {
|
||||
U2F_ReadBuffer readbuffer;
|
||||
if (!(f->type & TYPE_INIT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Broadcast is reserved for init
|
||||
if (f->cid == CID_BROADCAST || f->cid == 0) {
|
||||
send_u2fhid_error(f->cid, ERR_INVALID_CID);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((unsigned)MSG_LEN(*f) > sizeof(reader->buf)) {
|
||||
send_u2fhid_error(f->cid, ERR_INVALID_LEN);
|
||||
return;
|
||||
}
|
||||
|
||||
reader = &readbuffer;
|
||||
u2fhid_init_cmd(f);
|
||||
|
||||
usbTiny(1);
|
||||
for(;;) {
|
||||
// Do we need to wait for more data
|
||||
while ((reader->buf_ptr - reader->buf) < (signed)reader->len) {
|
||||
uint8_t lastseq = reader->seq;
|
||||
uint8_t lastcmd = reader->cmd;
|
||||
int counter = U2F_TIMEOUT;
|
||||
while (reader->seq == lastseq && reader->cmd == lastcmd) {
|
||||
if (counter-- == 0) {
|
||||
// timeout
|
||||
send_u2fhid_error(cid, ERR_MSG_TIMEOUT);
|
||||
cid = 0;
|
||||
reader = 0;
|
||||
usbTiny(0);
|
||||
layoutHome();
|
||||
return;
|
||||
}
|
||||
usbPoll();
|
||||
}
|
||||
}
|
||||
|
||||
// We have all the data
|
||||
switch (reader->cmd) {
|
||||
case 0:
|
||||
// message was aborted by init
|
||||
break;
|
||||
case U2FHID_PING:
|
||||
u2fhid_ping(reader->buf, reader->len);
|
||||
break;
|
||||
case U2FHID_MSG:
|
||||
u2fhid_msg((APDU *)reader->buf, reader->len);
|
||||
break;
|
||||
case U2FHID_WINK:
|
||||
u2fhid_wink(reader->buf, reader->len);
|
||||
break;
|
||||
default:
|
||||
send_u2fhid_error(cid, ERR_INVALID_CMD);
|
||||
break;
|
||||
}
|
||||
|
||||
// wait for next commmand/ button press
|
||||
reader->cmd = 0;
|
||||
reader->seq = 255;
|
||||
while (dialog_timeout > 0 && reader->cmd == 0) {
|
||||
dialog_timeout--;
|
||||
usbPoll(); // may trigger new request
|
||||
buttonUpdate();
|
||||
if (button.YesUp &&
|
||||
(last_req_state == AUTH || last_req_state == REG)) {
|
||||
last_req_state++;
|
||||
// standard requires to remember button press for 10 seconds.
|
||||
dialog_timeout = 10 * U2F_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
if (reader->cmd == 0) {
|
||||
last_req_state = INIT;
|
||||
cid = 0;
|
||||
reader = 0;
|
||||
usbTiny(0);
|
||||
layoutHome();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void u2fhid_ping(const uint8_t *buf, uint32_t len)
|
||||
{
|
||||
debugLog(0, "", "u2fhid_ping");
|
||||
send_u2fhid_msg(U2FHID_PING, buf, len);
|
||||
}
|
||||
|
||||
void u2fhid_wink(const uint8_t *buf, uint32_t len)
|
||||
{
|
||||
debugLog(0, "", "u2fhid_wink");
|
||||
(void)buf;
|
||||
|
||||
if (len > 0)
|
||||
return send_u2fhid_error(cid, ERR_INVALID_LEN);
|
||||
|
||||
if (dialog_timeout > 0)
|
||||
dialog_timeout = U2F_TIMEOUT;
|
||||
|
||||
U2FHID_FRAME f;
|
||||
MEMSET_BZERO(&f, sizeof(f));
|
||||
f.cid = cid;
|
||||
f.init.cmd = U2FHID_WINK;
|
||||
f.init.bcntl = 0;
|
||||
queue_u2f_pkt(&f);
|
||||
}
|
||||
|
||||
void u2fhid_init(const U2FHID_FRAME *in)
|
||||
{
|
||||
const U2FHID_INIT_REQ *init_req = (const U2FHID_INIT_REQ *)&in->init.data;
|
||||
U2FHID_FRAME f;
|
||||
U2FHID_INIT_RESP *resp = (U2FHID_INIT_RESP *)f.init.data;
|
||||
|
||||
debugLog(0, "", "u2fhid_init");
|
||||
|
||||
if (in->cid == 0) {
|
||||
send_u2fhid_error(in->cid, ERR_INVALID_CID);
|
||||
return;
|
||||
}
|
||||
|
||||
MEMSET_BZERO(&f, sizeof(f));
|
||||
f.cid = in->cid;
|
||||
f.init.cmd = U2FHID_INIT;
|
||||
f.init.bcnth = 0;
|
||||
f.init.bcntl = U2FHID_INIT_RESP_SIZE;
|
||||
|
||||
memcpy(resp->nonce, init_req->nonce, sizeof(init_req->nonce));
|
||||
resp->cid = in->cid == CID_BROADCAST ? next_cid() : in->cid;
|
||||
resp->versionInterface = U2FHID_IF_VERSION;
|
||||
resp->versionMajor = VERSION_MAJOR;
|
||||
resp->versionMinor = VERSION_MINOR;
|
||||
resp->versionBuild = VERSION_PATCH;
|
||||
resp->capFlags = CAPFLAG_WINK;
|
||||
|
||||
queue_u2f_pkt(&f);
|
||||
}
|
||||
|
||||
void queue_u2f_pkt(const U2FHID_FRAME *u2f_pkt)
|
||||
{
|
||||
// debugLog(0, "", "u2f_write_pkt");
|
||||
uint32_t next = (u2f_out_end + 1) % U2F_OUT_PKT_BUFFER_LEN;
|
||||
if (u2f_out_start == next) {
|
||||
debugLog(0, "", "u2f_write_pkt full");
|
||||
return; // Buffer full :(
|
||||
}
|
||||
memcpy(u2f_out_packets[u2f_out_end], u2f_pkt, HID_RPT_SIZE);
|
||||
u2f_out_end = next;
|
||||
}
|
||||
|
||||
uint8_t *u2f_out_data(void)
|
||||
{
|
||||
if (u2f_out_start == u2f_out_end)
|
||||
return NULL; // No data
|
||||
// debugLog(0, "", "u2f_out_data");
|
||||
uint32_t t = u2f_out_start;
|
||||
u2f_out_start = (u2f_out_start + 1) % U2F_OUT_PKT_BUFFER_LEN;
|
||||
return u2f_out_packets[t];
|
||||
}
|
||||
|
||||
void u2fhid_msg(const APDU *a, uint32_t len)
|
||||
{
|
||||
if ((APDU_LEN(*a) + sizeof(APDU)) > len) {
|
||||
debugLog(0, "", "BAD APDU LENGTH");
|
||||
debugInt(APDU_LEN(*a));
|
||||
debugInt(len);
|
||||
return;
|
||||
}
|
||||
|
||||
if (a->cla != 0) {
|
||||
send_u2f_error(U2F_SW_CLA_NOT_SUPPORTED);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (a->ins) {
|
||||
case U2F_REGISTER:
|
||||
u2f_register(a);
|
||||
break;
|
||||
case U2F_AUTHENTICATE:
|
||||
u2f_authenticate(a);
|
||||
break;
|
||||
case U2F_VERSION:
|
||||
u2f_version(a);
|
||||
break;
|
||||
default:
|
||||
debugLog(0, "", "u2f unknown cmd");
|
||||
send_u2f_error(U2F_SW_INS_NOT_SUPPORTED);
|
||||
}
|
||||
}
|
||||
|
||||
void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data, const uint32_t len)
|
||||
{
|
||||
U2FHID_FRAME f;
|
||||
uint8_t *p = (uint8_t *)data;
|
||||
uint32_t l = len;
|
||||
uint32_t psz;
|
||||
uint8_t seq = 0;
|
||||
|
||||
// debugLog(0, "", "send_u2fhid_msg");
|
||||
|
||||
MEMSET_BZERO(&f, sizeof(f));
|
||||
f.cid = cid;
|
||||
f.init.cmd = cmd;
|
||||
f.init.bcnth = len >> 8;
|
||||
f.init.bcntl = len & 0xff;
|
||||
|
||||
// Init packet
|
||||
psz = MIN(sizeof(f.init.data), l);
|
||||
memcpy(f.init.data, p, psz);
|
||||
queue_u2f_pkt(&f);
|
||||
l -= psz;
|
||||
p += psz;
|
||||
|
||||
// Cont packet(s)
|
||||
for (; l > 0; l -= psz, p += psz) {
|
||||
// debugLog(0, "", "send_u2fhid_msg con");
|
||||
MEMSET_BZERO(&f.cont.data, sizeof(f.cont.data));
|
||||
f.cont.seq = seq++;
|
||||
psz = MIN(sizeof(f.cont.data), l);
|
||||
memcpy(f.cont.data, p, psz);
|
||||
queue_u2f_pkt(&f);
|
||||
}
|
||||
|
||||
if (data + len != p) {
|
||||
debugLog(0, "", "send_u2fhid_msg is bad");
|
||||
debugInt(data + len - p);
|
||||
}
|
||||
}
|
||||
|
||||
void send_u2fhid_error(uint32_t fcid, uint8_t err)
|
||||
{
|
||||
U2FHID_FRAME f;
|
||||
|
||||
MEMSET_BZERO(&f, sizeof(f));
|
||||
f.cid = fcid;
|
||||
f.init.cmd = U2FHID_ERROR;
|
||||
f.init.bcntl = 1;
|
||||
f.init.data[0] = err;
|
||||
queue_u2f_pkt(&f);
|
||||
}
|
||||
|
||||
void u2f_version(const APDU *a)
|
||||
{
|
||||
if (APDU_LEN(*a) != 0) {
|
||||
debugLog(0, "", "u2f version - badlen");
|
||||
send_u2f_error(U2F_SW_WRONG_LENGTH);
|
||||
return;
|
||||
}
|
||||
|
||||
// INCLUDES SW_NO_ERROR
|
||||
static const uint8_t version_response[] = {'U', '2', 'F', '_',
|
||||
'V', '2', 0x90, 0x00};
|
||||
debugLog(0, "", "u2f version");
|
||||
send_u2f_msg(version_response, sizeof(version_response));
|
||||
}
|
||||
|
||||
void getReadableAppId(const uint8_t appid[U2F_APPID_SIZE], const char **appname, const BITMAP **appicon) {
|
||||
unsigned int i;
|
||||
static char buf[8+2+8+1];
|
||||
|
||||
for (i = 0; i < sizeof(u2f_well_known)/sizeof(U2FWellKnown); i++) {
|
||||
if (memcmp(appid, u2f_well_known[i].appid, U2F_APPID_SIZE) == 0) {
|
||||
*appname = u2f_well_known[i].appname;
|
||||
*appicon = u2f_well_known[i].appicon;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
data2hex(appid, 4, &buf[0]);
|
||||
buf[8] = buf[9] = '.';
|
||||
data2hex(appid + (U2F_APPID_SIZE - 4), 4, &buf[10]);
|
||||
*appname = buf;
|
||||
*appicon = NULL;
|
||||
}
|
||||
|
||||
const HDNode *getDerivedNode(uint32_t *address_n, size_t address_n_count)
|
||||
{
|
||||
static HDNode node;
|
||||
if (!storage_getRootNode(&node, NIST256P1_NAME, false)) {
|
||||
layoutHome();
|
||||
debugLog(0, "", "ERR: Device not init");
|
||||
return 0;
|
||||
}
|
||||
if (!address_n || address_n_count == 0) {
|
||||
return &node;
|
||||
}
|
||||
if (hdnode_private_ckd_cached(&node, address_n, address_n_count) == 0) {
|
||||
layoutHome();
|
||||
debugLog(0, "", "ERR: Derive private failed");
|
||||
return 0;
|
||||
}
|
||||
return &node;
|
||||
}
|
||||
|
||||
const HDNode *generateKeyHandle(const uint8_t app_id[], uint8_t key_handle[])
|
||||
{
|
||||
uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN];
|
||||
|
||||
// Derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r'
|
||||
uint32_t i, key_path[KEY_PATH_ENTRIES];
|
||||
key_path[0] = U2F_KEY_PATH;
|
||||
for (i = 1; i < KEY_PATH_ENTRIES; i++) {
|
||||
// high bit for hardened keys
|
||||
key_path[i]= 0x80000000 | random32();
|
||||
}
|
||||
|
||||
// First half of keyhandle is key_path
|
||||
memcpy(key_handle, &key_path[1], KEY_PATH_LEN);
|
||||
|
||||
// prepare keypair from /random data
|
||||
const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES);
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
// For second half of keyhandle
|
||||
// Signature of app_id and random data
|
||||
memcpy(&keybase[0], app_id, U2F_APPID_SIZE);
|
||||
memcpy(&keybase[U2F_APPID_SIZE], key_handle, KEY_PATH_LEN);
|
||||
hmac_sha256(node->private_key, sizeof(node->private_key),
|
||||
keybase, sizeof(keybase), &key_handle[KEY_PATH_LEN]);
|
||||
|
||||
// Done!
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
const HDNode *validateKeyHandle(const uint8_t app_id[], const uint8_t key_handle[])
|
||||
{
|
||||
uint32_t key_path[KEY_PATH_ENTRIES];
|
||||
key_path[0] = U2F_KEY_PATH;
|
||||
memcpy(&key_path[1], key_handle, KEY_PATH_LEN);
|
||||
|
||||
const HDNode *node = getDerivedNode(key_path, KEY_PATH_ENTRIES);
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
uint8_t keybase[U2F_APPID_SIZE + KEY_PATH_LEN];
|
||||
memcpy(&keybase[0], app_id, U2F_APPID_SIZE);
|
||||
memcpy(&keybase[U2F_APPID_SIZE], key_handle, KEY_PATH_LEN);
|
||||
|
||||
|
||||
uint8_t hmac[SHA256_DIGEST_LENGTH];
|
||||
hmac_sha256(node->private_key, sizeof(node->private_key),
|
||||
keybase, sizeof(keybase), hmac);
|
||||
|
||||
if (memcmp(&key_handle[KEY_PATH_LEN], hmac, SHA256_DIGEST_LENGTH) != 0)
|
||||
return NULL;
|
||||
|
||||
// Done!
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
void u2f_register(const APDU *a)
|
||||
{
|
||||
static U2F_REGISTER_REQ last_req;
|
||||
const U2F_REGISTER_REQ *req = (U2F_REGISTER_REQ *)a->data;
|
||||
|
||||
if (!storage_isInitialized()) {
|
||||
send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate basic request parameters
|
||||
debugLog(0, "", "u2f register");
|
||||
if (APDU_LEN(*a) != sizeof(U2F_REGISTER_REQ)) {
|
||||
debugLog(0, "", "u2f register - badlen");
|
||||
send_u2f_error(U2F_SW_WRONG_LENGTH);
|
||||
return;
|
||||
}
|
||||
|
||||
// If this request is different from last request, reset state machine
|
||||
if (memcmp(&last_req, req, sizeof(last_req)) != 0) {
|
||||
memcpy(&last_req, req, sizeof(last_req));
|
||||
last_req_state = INIT;
|
||||
}
|
||||
|
||||
// First Time request, return not present and display request dialog
|
||||
if (last_req_state == INIT) {
|
||||
// wake up crypto system to be ready for signing
|
||||
getDerivedNode(NULL, 0);
|
||||
// error: testof-user-presence is required
|
||||
buttonUpdate(); // Clear button state
|
||||
const char *appname;
|
||||
const BITMAP *appicon;
|
||||
getReadableAppId(req->appId, &appname, &appicon);
|
||||
layoutU2FDialog("Register", appname, appicon);
|
||||
last_req_state = REG;
|
||||
}
|
||||
|
||||
// Still awaiting Keypress
|
||||
if (last_req_state == REG) {
|
||||
// error: testof-user-presence is required
|
||||
send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED);
|
||||
dialog_timeout = U2F_TIMEOUT;
|
||||
return;
|
||||
}
|
||||
|
||||
// Buttons said yes
|
||||
if (last_req_state == REG_PASS) {
|
||||
uint8_t data[sizeof(U2F_REGISTER_RESP) + 2];
|
||||
U2F_REGISTER_RESP *resp = (U2F_REGISTER_RESP *)&data;
|
||||
MEMSET_BZERO(data, sizeof(data));
|
||||
|
||||
|
||||
resp->registerId = U2F_REGISTER_ID;
|
||||
resp->keyHandleLen = KEY_HANDLE_LEN;
|
||||
// Generate keypair for this appId
|
||||
const HDNode *node =
|
||||
generateKeyHandle(req->appId, (uint8_t*)&resp->keyHandleCertSig);
|
||||
|
||||
if (!node) {
|
||||
debugLog(0, "", "getDerivedNode Fail");
|
||||
send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle
|
||||
return;
|
||||
}
|
||||
|
||||
ecdsa_get_public_key65(node->curve->params, node->private_key,
|
||||
(uint8_t *)&resp->pubKey);
|
||||
|
||||
memcpy(resp->keyHandleCertSig + resp->keyHandleLen,
|
||||
U2F_ATT_CERT, sizeof(U2F_ATT_CERT));
|
||||
|
||||
uint8_t sig[64];
|
||||
U2F_REGISTER_SIG_STR sig_base;
|
||||
sig_base.reserved = 0;
|
||||
memcpy(sig_base.appId, req->appId, U2F_APPID_SIZE);
|
||||
memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE);
|
||||
memcpy(sig_base.keyHandle, &resp->keyHandleCertSig, KEY_HANDLE_LEN);
|
||||
memcpy(sig_base.pubKey, &resp->pubKey, U2F_PUBKEY_LEN);
|
||||
ecdsa_sign(&nist256p1, U2F_ATT_PRIV_KEY, (uint8_t *)&sig_base,
|
||||
sizeof(sig_base), sig, NULL);
|
||||
|
||||
// Where to write the signature in the response
|
||||
uint8_t *resp_sig = resp->keyHandleCertSig +
|
||||
resp->keyHandleLen + sizeof(U2F_ATT_CERT);
|
||||
// Convert to der for the response
|
||||
const uint8_t sig_len = ecdsa_sig_to_der(sig, resp_sig);
|
||||
|
||||
// Append success bytes
|
||||
memcpy(resp->keyHandleCertSig + resp->keyHandleLen +
|
||||
sizeof(U2F_ATT_CERT) + sig_len,
|
||||
"\x90\x00", 2);
|
||||
|
||||
int l = 1 /* registerId */ + U2F_PUBKEY_LEN +
|
||||
1 /* keyhandleLen */ + resp->keyHandleLen +
|
||||
sizeof(U2F_ATT_CERT) + sig_len + 2;
|
||||
|
||||
last_req_state = INIT;
|
||||
dialog_timeout = 0;
|
||||
send_u2f_msg(data, l);
|
||||
return;
|
||||
}
|
||||
|
||||
// Didnt expect to get here
|
||||
dialog_timeout = 0;
|
||||
}
|
||||
|
||||
void u2f_authenticate(const APDU *a)
|
||||
{
|
||||
const U2F_AUTHENTICATE_REQ *req = (U2F_AUTHENTICATE_REQ *)a->data;
|
||||
static U2F_AUTHENTICATE_REQ last_req;
|
||||
|
||||
if (!storage_isInitialized()) {
|
||||
send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (APDU_LEN(*a) < 64) { /// FIXME: decent value
|
||||
debugLog(0, "", "u2f authenticate - badlen");
|
||||
send_u2f_error(U2F_SW_WRONG_LENGTH);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->keyHandleLen != KEY_HANDLE_LEN) {
|
||||
debugLog(0, "", "u2f auth - bad keyhandle len");
|
||||
send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle
|
||||
return;
|
||||
}
|
||||
|
||||
const HDNode *node =
|
||||
validateKeyHandle(req->appId, req->keyHandle);
|
||||
|
||||
if (!node) {
|
||||
debugLog(0, "", "u2f auth - bad keyhandle len");
|
||||
send_u2f_error(U2F_SW_WRONG_DATA); // error:bad key handle
|
||||
return;
|
||||
}
|
||||
|
||||
if (a->p1 == U2F_AUTH_CHECK_ONLY) {
|
||||
debugLog(0, "", "u2f authenticate check");
|
||||
// This is a success for a good keyhandle
|
||||
// A failed check would have happened earlier
|
||||
// error: testof-user-presence is required
|
||||
send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (a->p1 != U2F_AUTH_ENFORCE) {
|
||||
debugLog(0, "", "u2f authenticate unknown");
|
||||
// error:bad key handle
|
||||
send_u2f_error(U2F_SW_WRONG_DATA);
|
||||
return;
|
||||
}
|
||||
|
||||
debugLog(0, "", "u2f authenticate enforce");
|
||||
|
||||
if (memcmp(&last_req, req, sizeof(last_req)) != 0) {
|
||||
memcpy(&last_req, req, sizeof(last_req));
|
||||
last_req_state = INIT;
|
||||
}
|
||||
|
||||
if (last_req_state == INIT) {
|
||||
// error: testof-user-presence is required
|
||||
buttonUpdate(); // Clear button state
|
||||
const char *appname;
|
||||
const BITMAP *appicon;
|
||||
getReadableAppId(req->appId, &appname, &appicon);
|
||||
layoutU2FDialog("Authenticate", appname, appicon);
|
||||
last_req_state = AUTH;
|
||||
}
|
||||
|
||||
// Awaiting Keypress
|
||||
if (last_req_state == AUTH) {
|
||||
// error: testof-user-presence is required
|
||||
send_u2f_error(U2F_SW_CONDITIONS_NOT_SATISFIED);
|
||||
dialog_timeout = U2F_TIMEOUT;
|
||||
return;
|
||||
}
|
||||
|
||||
// Buttons said yes
|
||||
if (last_req_state == AUTH_PASS) {
|
||||
uint8_t buf[sizeof(U2F_AUTHENTICATE_RESP) + 2];
|
||||
U2F_AUTHENTICATE_RESP *resp =
|
||||
(U2F_AUTHENTICATE_RESP *)&buf;
|
||||
|
||||
const uint32_t ctr = storage_nextU2FCounter();
|
||||
resp->flags = U2F_AUTH_FLAG_TUP;
|
||||
resp->ctr[0] = ctr >> 24 & 0xff;
|
||||
resp->ctr[1] = ctr >> 16 & 0xff;
|
||||
resp->ctr[2] = ctr >> 8 & 0xff;
|
||||
resp->ctr[3] = ctr & 0xff;
|
||||
|
||||
// Build and sign response
|
||||
U2F_AUTHENTICATE_SIG_STR sig_base;
|
||||
uint8_t sig[64];
|
||||
memcpy(sig_base.appId, req->appId, U2F_APPID_SIZE);
|
||||
sig_base.flags = resp->flags;
|
||||
memcpy(sig_base.ctr, resp->ctr, 4);
|
||||
memcpy(sig_base.chal, req->chal, U2F_CHAL_SIZE);
|
||||
ecdsa_sign(&nist256p1, node->private_key,
|
||||
(uint8_t *)&sig_base, sizeof(sig_base), sig,
|
||||
NULL);
|
||||
|
||||
// Copy DER encoded signature into response
|
||||
const uint8_t sig_len = ecdsa_sig_to_der(sig, resp->sig);
|
||||
|
||||
// Append OK
|
||||
memcpy(buf + sizeof(U2F_AUTHENTICATE_RESP) -
|
||||
U2F_MAX_EC_SIG_SIZE + sig_len,
|
||||
"\x90\x00", 2);
|
||||
last_req_state = INIT;
|
||||
dialog_timeout = 0;
|
||||
send_u2f_msg(buf, sizeof(U2F_AUTHENTICATE_RESP) -
|
||||
U2F_MAX_EC_SIG_SIZE + sig_len +
|
||||
2);
|
||||
}
|
||||
}
|
||||
|
||||
void send_u2f_error(const uint16_t err)
|
||||
{
|
||||
uint8_t data[2];
|
||||
data[0] = err >> 8 & 0xFF;
|
||||
data[1] = err & 0xFF;
|
||||
send_u2f_msg(data, 2);
|
||||
}
|
||||
|
||||
void send_u2f_msg(const uint8_t *data, const uint32_t len)
|
||||
{
|
||||
send_u2fhid_msg(U2FHID_MSG, data, len);
|
||||
}
|
62
firmware/u2f.h
Normal file
62
firmware/u2f.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of the TREZOR project.
|
||||
*
|
||||
* Copyright (C) 2015 Mark Bryars <mbryars@google.com>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __U2F_H__
|
||||
#define __U2F_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "u2f/u2f_hid.h"
|
||||
#include "trezor.h"
|
||||
|
||||
#define U2F_KEY_PATH 0x80553246
|
||||
|
||||
typedef struct {
|
||||
uint8_t cla, ins, p1, p2;
|
||||
uint8_t lc1, lc2, lc3;
|
||||
uint8_t data[];
|
||||
} APDU;
|
||||
|
||||
#define APDU_LEN(A) (uint32_t)(((A).lc1 << 16) + ((A).lc2 << 8) + ((A).lc3))
|
||||
|
||||
void u2fhid_read(char tiny, const U2FHID_FRAME *buf);
|
||||
void u2fhid_init_cmd(const U2FHID_FRAME *f);
|
||||
void u2fhid_read_start(const U2FHID_FRAME *f);
|
||||
bool u2fhid_write(uint8_t *buf);
|
||||
void u2fhid_init(const U2FHID_FRAME *in);
|
||||
void u2fhid_ping(const uint8_t *buf, uint32_t len);
|
||||
void u2fhid_wink(const uint8_t *buf, uint32_t len);
|
||||
void u2fhid_sync(const uint8_t *buf, uint32_t len);
|
||||
void u2fhid_lock(const uint8_t *buf, uint32_t len);
|
||||
void u2fhid_msg(const APDU *a, uint32_t len);
|
||||
void queue_u2f_pkt(const U2FHID_FRAME *u2f_pkt);
|
||||
|
||||
uint8_t *u2f_out_data(void);
|
||||
void u2f_register(const APDU *a);
|
||||
void u2f_version(const APDU *a);
|
||||
void u2f_authenticate(const APDU *a);
|
||||
|
||||
void send_u2f_msg(const uint8_t *data, uint32_t len);
|
||||
void send_u2f_error(uint16_t err);
|
||||
|
||||
void send_u2fhid_msg(const uint8_t cmd, const uint8_t *data,
|
||||
const uint32_t len);
|
||||
void send_u2fhid_error(uint32_t fcid, uint8_t err);
|
||||
|
||||
#endif
|
45
firmware/u2f/genkeys.sh
Normal file
45
firmware/u2f/genkeys.sh
Normal file
@ -0,0 +1,45 @@
|
||||
#!/bin/bash
|
||||
|
||||
cat > u2f_keys.h <<EOF
|
||||
#ifndef __U2F_KEYS_H_INCLUDED__
|
||||
#define __U2F_KEYS_H_INCLUDED__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
const uint8_t U2F_ATT_PRIV_KEY[] = {
|
||||
EOF
|
||||
|
||||
if [ \! -e trezordevkey.pem ]; then
|
||||
openssl ecparam -genkey -out trezordevkey.pem -name prime256v1
|
||||
fi
|
||||
openssl ec -in trezordevkey.pem -text |
|
||||
perl -e '$key = "\t"; while (<>) {
|
||||
if (/priv:/) { $priv = 1 }
|
||||
elsif (/pub:/) { $priv = 0 }
|
||||
elsif ($priv) {
|
||||
while ($_ =~ s/.*?([0-9a-f]{2})//) {
|
||||
$key .= "0x$1,";
|
||||
if ($num++ % 8 == 7) { $key .= "\n\t"; }
|
||||
else {$key .= " ";}
|
||||
}
|
||||
}
|
||||
}
|
||||
$key =~ s/,\s*$/\n/s;
|
||||
print $key;' >> u2f_keys.h
|
||||
cat >> u2f_keys.h <<EOF
|
||||
};
|
||||
|
||||
const uint8_t U2F_ATT_CERT[] = {
|
||||
EOF
|
||||
|
||||
openssl req -new -key trezordevkey.pem -out trezordevcert.req -subj "/CN=Trezor U2F"
|
||||
openssl x509 -req -in trezordevcert.req -signkey trezordevkey.pem -days 3650 -out trezordevcert.pem
|
||||
openssl x509 -in trezordevcert.pem -outform der | od -tx1 -w12 -Anone | perl -pe 's/ ([0-9a-f]{2})/ 0x$1,/g; $_ =~ s/^ /\t/;' >> u2f_keys.h
|
||||
|
||||
cat >> u2f_keys.h <<EOF
|
||||
};
|
||||
|
||||
#endif // __U2F_KEYS_H_INCLUDED__
|
||||
EOF
|
||||
|
||||
rm trezordevcert.req trezordevcert.pem
|
5
firmware/u2f/trezordevkey.pem
Normal file
5
firmware/u2f/trezordevkey.pem
Normal file
@ -0,0 +1,5 @@
|
||||
-----BEGIN EC PRIVATE KEY-----
|
||||
MHcCAQEEIHEmrCv2RNxhhq2D7x/N8SpXtc+iAAuK0CfpVuhUxQqLoAoGCCqGSM49
|
||||
AwEHoUQDQgAE2Ri9+opUrJLpDakfynqiZFTA0XM2MU3eg6VLhrXfTvBSZZodb/y3
|
||||
Rn8azduKMwgLXu2RiRP0Q6UmG8d7aGBvwQ==
|
||||
-----END EC PRIVATE KEY-----
|
143
firmware/u2f/u2f.h
Normal file
143
firmware/u2f/u2f.h
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
Copyright (C) 2013-2015 Yubico AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Common U2F raw message format header.
|
||||
// 2014-08-14 J Ehrensvard, Yubico, Inc.
|
||||
|
||||
#ifndef __U2F_H_INCLUDED__
|
||||
#define __U2F_H_INCLUDED__
|
||||
|
||||
#ifdef _MSC_VER // Windows
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long int uint64_t;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
// General constants
|
||||
|
||||
#define U2F_EC_KEY_SIZE 32 // EC key size in bytes
|
||||
#define U2F_EC_POINT_SIZE ((U2F_EC_KEY_SIZE * 2) + 1) // Size of EC point
|
||||
#define U2F_MAX_KH_SIZE 128 // Max size of key handle
|
||||
#define U2F_MAX_ATT_CERT_SIZE 1024 // Max size of attestation certificate
|
||||
#define U2F_MAX_EC_SIG_SIZE 72 // Max size of DER coded EC signature
|
||||
#define U2F_CTR_SIZE 4 // Size of counter field
|
||||
#define U2F_APPID_SIZE 32 // Size of application id
|
||||
#define U2F_CHAL_SIZE 32 // Size of challenge
|
||||
|
||||
#define ENC_SIZE(x) ((x + 7) & 0xfff8)
|
||||
|
||||
// EC (uncompressed) point
|
||||
|
||||
#define U2F_POINT_UNCOMPRESSED 0x04 // Uncompressed point format
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t pointFormat; // Point type
|
||||
uint8_t x[U2F_EC_KEY_SIZE]; // X-value
|
||||
uint8_t y[U2F_EC_KEY_SIZE]; // Y-value
|
||||
} U2F_EC_POINT;
|
||||
|
||||
// U2F native commands
|
||||
|
||||
#define U2F_REGISTER 0x01 // Registration command
|
||||
#define U2F_AUTHENTICATE 0x02 // Authenticate/sign command
|
||||
#define U2F_VERSION 0x03 // Read version string command
|
||||
|
||||
#define U2F_VENDOR_FIRST 0x40 // First vendor defined command
|
||||
#define U2F_VENDOR_LAST 0x7f // Last vendor defined command
|
||||
|
||||
// U2F_CMD_REGISTER command defines
|
||||
|
||||
#define U2F_REGISTER_ID 0x05 // Version 2 registration identifier
|
||||
#define U2F_REGISTER_HASH_ID 0x00 // Version 2 hash identintifier
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t chal[U2F_CHAL_SIZE]; // Challenge
|
||||
uint8_t appId[U2F_APPID_SIZE]; // Application id
|
||||
} U2F_REGISTER_REQ;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t registerId; // Registration identifier (U2F_REGISTER_ID_V2)
|
||||
U2F_EC_POINT pubKey; // Generated public key
|
||||
uint8_t keyHandleLen; // Length of key handle
|
||||
uint8_t keyHandleCertSig[U2F_MAX_KH_SIZE + // Key handle
|
||||
U2F_MAX_ATT_CERT_SIZE + // Attestation certificate
|
||||
U2F_MAX_EC_SIG_SIZE]; // Registration signature
|
||||
} U2F_REGISTER_RESP;
|
||||
|
||||
// U2F_CMD_AUTHENTICATE command defines
|
||||
|
||||
// Authentication control byte
|
||||
|
||||
#define U2F_AUTH_ENFORCE 0x03 // Enforce user presence and sign
|
||||
#define U2F_AUTH_CHECK_ONLY 0x07 // Check only
|
||||
#define U2F_AUTH_FLAG_TUP 0x01 // Test of user presence set
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t chal[U2F_CHAL_SIZE]; // Challenge
|
||||
uint8_t appId[U2F_APPID_SIZE]; // Application id
|
||||
uint8_t keyHandleLen; // Length of key handle
|
||||
uint8_t keyHandle[U2F_MAX_KH_SIZE]; // Key handle
|
||||
} U2F_AUTHENTICATE_REQ;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t flags; // U2F_AUTH_FLAG_ values
|
||||
uint8_t ctr[U2F_CTR_SIZE]; // Counter field (big-endian)
|
||||
uint8_t sig[U2F_MAX_EC_SIG_SIZE]; // Signature
|
||||
} U2F_AUTHENTICATE_RESP;
|
||||
|
||||
// Common raw message format (ISO7816-4:2005 mapping)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t cla; // Class - reserved
|
||||
uint8_t ins; // U2F instruction
|
||||
uint8_t p1; // U2F parameter 1
|
||||
uint8_t p2; // U2F parameter 2
|
||||
uint8_t lc1; // Length field, set to zero
|
||||
uint8_t lc2; // Length field, MSB
|
||||
uint8_t lc3; // Length field, LSB
|
||||
uint8_t data[1]; // Data field
|
||||
} U2F_MSG;
|
||||
|
||||
// Command status responses
|
||||
|
||||
#define U2F_SW_NO_ERROR 0x9000 // SW_NO_ERROR
|
||||
#define U2F_SW_WRONG_LENGTH 0x6700 // SW_WRONG_LENGTH
|
||||
#define U2F_SW_DATA_INVALID 0x6984 // SW_WRONG_DATA
|
||||
#define U2F_SW_CONDITIONS_NOT_SATISFIED 0x6985 // SW_CONDITIONS_NOT_SATISFIED
|
||||
#define U2F_SW_WRONG_DATA 0x6a80 // SW_WRONG_DATA
|
||||
#define U2F_SW_INS_NOT_SUPPORTED 0x6d00 // SW_INS_NOT_SUPPORTED
|
||||
#define U2F_SW_CLA_NOT_SUPPORTED 0x6e00 // SW_CLA_NOT_SUPPORTED
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __U2F_H_INCLUDED__
|
142
firmware/u2f/u2f_hid.h
Normal file
142
firmware/u2f/u2f_hid.h
Normal file
@ -0,0 +1,142 @@
|
||||
/*
|
||||
Copyright (C) 2013-2015 Yubico AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Common U2F HID transport header.
|
||||
// 2014-08-21 J Ehrensvard, Yubico, Inc.
|
||||
|
||||
#ifndef __U2FHID_H_INCLUDED__
|
||||
#define __U2FHID_H_INCLUDED__
|
||||
|
||||
#ifdef _MSC_VER // Windows
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned long int uint64_t;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
// Size of HID reports
|
||||
|
||||
#define HID_RPT_SIZE 64 // Default size of raw HID report
|
||||
|
||||
// Frame layout - command- and continuation frames
|
||||
|
||||
#define CID_BROADCAST 0xffffffff // Broadcast channel id
|
||||
|
||||
#define TYPE_MASK 0x80 // Frame type mask
|
||||
#define TYPE_INIT 0x80 // Initial frame identifier
|
||||
#define TYPE_CONT 0x00 // Continuation frame identifier
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t cid; // Channel identifier
|
||||
union
|
||||
{
|
||||
uint8_t type; // Frame type - b7 defines type
|
||||
struct
|
||||
{
|
||||
uint8_t cmd; // Command - b7 set
|
||||
uint8_t bcnth; // Message byte count - high part
|
||||
uint8_t bcntl; // Message byte count - low part
|
||||
uint8_t data[HID_RPT_SIZE - 7]; // Data payload
|
||||
} init;
|
||||
struct
|
||||
{
|
||||
uint8_t seq; // Sequence number - b7 cleared
|
||||
uint8_t data[HID_RPT_SIZE - 5]; // Data payload
|
||||
} cont;
|
||||
};
|
||||
} U2FHID_FRAME;
|
||||
|
||||
#define FRAME_TYPE(f) ((f).type & TYPE_MASK)
|
||||
#define FRAME_CMD(f) ((f).init.cmd & ~TYPE_MASK)
|
||||
#define MSG_LEN(f) (((f).init.bcnth << 8) + (f).init.bcntl)
|
||||
#define FRAME_SEQ(f) ((f).cont.seq & ~TYPE_MASK)
|
||||
|
||||
// HID usage- and usage-page definitions
|
||||
|
||||
#define FIDO_USAGE_PAGE 0xf1d0 // FIDO alliance HID usage page
|
||||
#define FIDO_USAGE_U2FHID 0x01 // U2FHID usage for top-level collection
|
||||
#define FIDO_USAGE_DATA_IN 0x20 // Raw IN data report
|
||||
#define FIDO_USAGE_DATA_OUT 0x21 // Raw OUT data report
|
||||
|
||||
// General constants
|
||||
|
||||
#define U2FHID_IF_VERSION 2 // Current interface implementation version
|
||||
#define U2FHID_FRAME_TIMEOUT 500 // Default frame timeout in ms
|
||||
#define U2FHID_TRANS_TIMEOUT 3000 // Default message timeout in ms
|
||||
|
||||
// U2FHID native commands
|
||||
|
||||
#define U2FHID_PING (TYPE_INIT | 0x01) // Echo data through local processor only
|
||||
#define U2FHID_MSG (TYPE_INIT | 0x03) // Send U2F message frame
|
||||
#define U2FHID_LOCK (TYPE_INIT | 0x04) // Send lock channel command
|
||||
#define U2FHID_INIT (TYPE_INIT | 0x06) // Channel initialization
|
||||
#define U2FHID_WINK (TYPE_INIT | 0x08) // Send device identification wink
|
||||
#define U2FHID_ERROR (TYPE_INIT | 0x3f) // Error response
|
||||
|
||||
#define U2FHID_VENDOR_FIRST (TYPE_INIT | 0x40) // First vendor defined command
|
||||
#define U2FHID_VENDOR_LAST (TYPE_INIT | 0x7f) // Last vendor defined command
|
||||
|
||||
// U2FHID_INIT command defines
|
||||
|
||||
#define INIT_NONCE_SIZE 8 // Size of channel initialization challenge
|
||||
#define CAPFLAG_WINK 0x01 // Device supports WINK command
|
||||
#define CAPFLAG_LOCK 0x02 // Device supports LOCK command
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce
|
||||
} U2FHID_INIT_REQ;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t nonce[INIT_NONCE_SIZE]; // Client application nonce
|
||||
uint32_t cid; // Channel identifier
|
||||
uint8_t versionInterface; // Interface version
|
||||
uint8_t versionMajor; // Major version number
|
||||
uint8_t versionMinor; // Minor version number
|
||||
uint8_t versionBuild; // Build version number
|
||||
uint8_t capFlags; // Capabilities flags
|
||||
} U2FHID_INIT_RESP;
|
||||
|
||||
#define U2FHID_INIT_RESP_SIZE 17
|
||||
|
||||
// Low-level error codes. Return as negatives.
|
||||
|
||||
#define ERR_NONE 0x00 // No error
|
||||
#define ERR_INVALID_CMD 0x01 // Invalid command
|
||||
#define ERR_INVALID_PAR 0x02 // Invalid parameter
|
||||
#define ERR_INVALID_LEN 0x03 // Invalid message length
|
||||
#define ERR_INVALID_SEQ 0x04 // Invalid message sequencing
|
||||
#define ERR_MSG_TIMEOUT 0x05 // Message has timed out
|
||||
#define ERR_CHANNEL_BUSY 0x06 // Channel busy
|
||||
#define ERR_LOCK_REQUIRED 0x0a // Command requires channel lock
|
||||
#define ERR_INVALID_CID 0x0b // Command not allowed on this cid
|
||||
#define ERR_OTHER 0x7f // Other unspecified error
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // __U2FHID_H_INCLUDED__
|
40
firmware/u2f/u2f_keys.h
Normal file
40
firmware/u2f/u2f_keys.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef __U2F_KEYS_H_INCLUDED__
|
||||
#define __U2F_KEYS_H_INCLUDED__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
const uint8_t U2F_ATT_PRIV_KEY[] = {
|
||||
0x71, 0x26, 0xac, 0x2b, 0xf6, 0x44, 0xdc, 0x61,
|
||||
0x86, 0xad, 0x83, 0xef, 0x1f, 0xcd, 0xf1, 0x2a,
|
||||
0x57, 0xb5, 0xcf, 0xa2, 0x00, 0x0b, 0x8a, 0xd0,
|
||||
0x27, 0xe9, 0x56, 0xe8, 0x54, 0xc5, 0x0a, 0x8b
|
||||
};
|
||||
|
||||
const uint8_t U2F_ATT_CERT[] = {
|
||||
0x30, 0x82, 0x01, 0x18, 0x30, 0x81, 0xc0, 0x02, 0x09, 0x00, 0xb1, 0xd9,
|
||||
0x8f, 0x42, 0x64, 0x72, 0xd3, 0x2c, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86,
|
||||
0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11,
|
||||
0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0a, 0x54, 0x72, 0x65, 0x7a, 0x6f,
|
||||
0x72, 0x20, 0x55, 0x32, 0x46, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x36, 0x30,
|
||||
0x34, 0x32, 0x39, 0x31, 0x33, 0x33, 0x31, 0x35, 0x33, 0x5a, 0x17, 0x0d,
|
||||
0x32, 0x36, 0x30, 0x34, 0x32, 0x37, 0x31, 0x33, 0x33, 0x31, 0x35, 0x33,
|
||||
0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03,
|
||||
0x0c, 0x0a, 0x54, 0x72, 0x65, 0x7a, 0x6f, 0x72, 0x20, 0x55, 0x32, 0x46,
|
||||
0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
|
||||
0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
|
||||
0x42, 0x00, 0x04, 0xd9, 0x18, 0xbd, 0xfa, 0x8a, 0x54, 0xac, 0x92, 0xe9,
|
||||
0x0d, 0xa9, 0x1f, 0xca, 0x7a, 0xa2, 0x64, 0x54, 0xc0, 0xd1, 0x73, 0x36,
|
||||
0x31, 0x4d, 0xde, 0x83, 0xa5, 0x4b, 0x86, 0xb5, 0xdf, 0x4e, 0xf0, 0x52,
|
||||
0x65, 0x9a, 0x1d, 0x6f, 0xfc, 0xb7, 0x46, 0x7f, 0x1a, 0xcd, 0xdb, 0x8a,
|
||||
0x33, 0x08, 0x0b, 0x5e, 0xed, 0x91, 0x89, 0x13, 0xf4, 0x43, 0xa5, 0x26,
|
||||
0x1b, 0xc7, 0x7b, 0x68, 0x60, 0x6f, 0xc1, 0x30, 0x0a, 0x06, 0x08, 0x2a,
|
||||
0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x47, 0x00, 0x30, 0x44,
|
||||
0x02, 0x20, 0x24, 0x1e, 0x81, 0xff, 0xd2, 0xe5, 0xe6, 0x15, 0x36, 0x94,
|
||||
0xc3, 0x55, 0x2e, 0x8f, 0xeb, 0xd7, 0x1e, 0x89, 0x35, 0x92, 0x1c, 0xb4,
|
||||
0x83, 0x41, 0x43, 0x71, 0x1c, 0x76, 0xea, 0xee, 0xf3, 0x95, 0x02, 0x20,
|
||||
0x5f, 0x80, 0xeb, 0x10, 0xf2, 0x5c, 0xcc, 0x39, 0x8b, 0x3c, 0xa8, 0xa9,
|
||||
0xad, 0xa4, 0x02, 0x7f, 0x93, 0x13, 0x20, 0x77, 0xb7, 0xab, 0xce, 0x77,
|
||||
0x46, 0x5a, 0x27, 0xf5, 0x3d, 0x33, 0xa1, 0x1d,
|
||||
};
|
||||
|
||||
#endif // __U2F_KEYS_H_INCLUDED__
|
72
firmware/u2f_knownapps.h
Normal file
72
firmware/u2f_knownapps.h
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* This file is part of the TREZOR project.
|
||||
*
|
||||
* Copyright (C) 2016 Jochen Hoenicke <hoenicke@gmail.com>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __U2F_KNOWNAPPS_H_INCLUDED__
|
||||
#define __U2F_KNOWNAPPS_H_INCLUDED__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "u2f/u2f.h"
|
||||
#include "bitmaps.h"
|
||||
|
||||
typedef struct {
|
||||
const uint8_t appid[U2F_APPID_SIZE];
|
||||
const char *appname;
|
||||
const BITMAP *appicon;
|
||||
} U2FWellKnown;
|
||||
|
||||
static const U2FWellKnown u2f_well_known[4] = {
|
||||
{
|
||||
// https://www.gstatic.com/securitykey/origins.json
|
||||
{ 0xa5,0x46,0x72,0xb2,0x22,0xc4,0xcf,0x95,
|
||||
0xe1,0x51,0xed,0x8d,0x4d,0x3c,0x76,0x7a,
|
||||
0x6c,0xc3,0x49,0x43,0x59,0x43,0x79,0x4e,
|
||||
0x88,0x4f,0x3d,0x02,0x3a,0x82,0x29,0xfd },
|
||||
"Google",
|
||||
&bmp_u2f_google
|
||||
},
|
||||
{
|
||||
// https://github.com/u2f/trusted_facets
|
||||
{ 0x70,0x61,0x7d,0xfe,0xd0,0x65,0x86,0x3a,
|
||||
0xf4,0x7c,0x15,0x55,0x6c,0x91,0x79,0x88,
|
||||
0x80,0x82,0x8c,0xc4,0x07,0xfd,0xf7,0x0a,
|
||||
0xe8,0x50,0x11,0x56,0x94,0x65,0xa0,0x75 },
|
||||
"Github",
|
||||
&bmp_u2f_github
|
||||
},
|
||||
{
|
||||
// https://www.dropbox.com/u2f-app-id.json
|
||||
{ 0xc5,0x0f,0x8a,0x7b,0x70,0x8e,0x92,0xf8,
|
||||
0x2e,0x7a,0x50,0xe2,0xbd,0xc5,0x5d,0x8f,
|
||||
0xd9,0x1a,0x22,0xfe,0x6b,0x29,0xc0,0xcd,
|
||||
0xf7,0x80,0x55,0x30,0x84,0x2a,0xf5,0x81 },
|
||||
"Dropbox",
|
||||
&bmp_u2f_dropbox
|
||||
},
|
||||
{
|
||||
// https://slushpool.com/static/security/u2f.json
|
||||
{ 0x08,0xb2,0xa3,0xd4,0x19,0x39,0xaa,0x31,
|
||||
0x66,0x84,0x93,0xcb,0x36,0xcd,0xcc,0x4f,
|
||||
0x16,0xc4,0xd9,0xb4,0xc8,0x23,0x8b,0x73,
|
||||
0xc2,0xf6,0x72,0xc0,0x33,0x00,0x71,0x97 },
|
||||
"Slush Pool",
|
||||
&bmp_u2f_slushpool
|
||||
}
|
||||
};
|
||||
|
||||
#endif // U2F_KNOWNAPPS_INCLUDED
|
120
firmware/usb.c
120
firmware/usb.c
@ -24,13 +24,22 @@
|
||||
#include "usb.h"
|
||||
#include "debug.h"
|
||||
#include "messages.h"
|
||||
#include "u2f.h"
|
||||
#include "storage.h"
|
||||
#include "util.h"
|
||||
|
||||
#if DEBUG_LINK
|
||||
#define USB_INTERFACE_INDEX_U2F 2
|
||||
#else
|
||||
#define USB_INTERFACE_INDEX_U2F 1
|
||||
#endif
|
||||
|
||||
#define ENDPOINT_ADDRESS_IN (0x81)
|
||||
#define ENDPOINT_ADDRESS_OUT (0x01)
|
||||
#define ENDPOINT_ADDRESS_DEBUG_IN (0x82)
|
||||
#define ENDPOINT_ADDRESS_DEBUG_OUT (0x02)
|
||||
#define ENDPOINT_ADDRESS_U2F_IN (0x83)
|
||||
#define ENDPOINT_ADDRESS_U2F_OUT (0x03)
|
||||
|
||||
static const struct usb_device_descriptor dev_descr = {
|
||||
.bLength = USB_DT_DEVICE_SIZE,
|
||||
@ -87,6 +96,24 @@ static const uint8_t hid_report_descriptor_debug[] = {
|
||||
0xc0 // END_COLLECTION
|
||||
};
|
||||
|
||||
static const uint8_t hid_report_descriptor_u2f[] = {
|
||||
0x06, 0xd0, 0xf1, // USAGE_PAGE (FIDO Alliance)
|
||||
0x09, 0x01, // USAGE (U2F HID Authenticator Device)
|
||||
0xa1, 0x01, // COLLECTION (Application)
|
||||
0x09, 0x20, // USAGE (Input Report Data)
|
||||
0x15, 0x00, // LOGICAL_MINIMUM (0)
|
||||
0x26,0xff, 0x00, // LOGICAL_MAXIMUM (255)
|
||||
0x75,0x08, // REPORT_SIZE (8)
|
||||
0x95,0x40, // REPORT_COUNT (64)
|
||||
0x81,0x02, // INPUT (Data,Var,Abs)
|
||||
0x09,0x21, // USAGE (Output Report Data)
|
||||
0x15,0x00, // LOGICAL_MINIMUM (0)
|
||||
0x26,0xff, 0x00, // LOGICAL_MAXIMUM (255)
|
||||
0x75,0x08, // REPORT_SIZE (8)
|
||||
0x95,0x40, // REPORT_COUNT (64)
|
||||
0x91,0x02, // OUTPUT (Data,Var,Abs)
|
||||
0xc0 // END_COLLECTION
|
||||
};
|
||||
|
||||
static const struct {
|
||||
struct usb_hid_descriptor hid_descriptor;
|
||||
@ -108,6 +135,27 @@ static const struct {
|
||||
}
|
||||
};
|
||||
|
||||
static const struct {
|
||||
struct usb_hid_descriptor hid_descriptor_u2f;
|
||||
struct {
|
||||
uint8_t bReportDescriptorType;
|
||||
uint16_t wDescriptorLength;
|
||||
} __attribute__((packed)) hid_report_u2f;
|
||||
} __attribute__((packed)) hid_function_u2f = {
|
||||
.hid_descriptor_u2f = {
|
||||
.bLength = sizeof(hid_function_u2f),
|
||||
.bDescriptorType = USB_DT_HID,
|
||||
.bcdHID = 0x0111,
|
||||
.bCountryCode = 0,
|
||||
.bNumDescriptors = 1,
|
||||
},
|
||||
.hid_report_u2f = {
|
||||
.bReportDescriptorType = USB_DT_REPORT,
|
||||
.wDescriptorLength = sizeof(hid_report_descriptor_u2f),
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static const struct usb_endpoint_descriptor hid_endpoints[2] = {{
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
@ -139,6 +187,37 @@ static const struct usb_interface_descriptor hid_iface[] = {{
|
||||
.extralen = sizeof(hid_function),
|
||||
}};
|
||||
|
||||
static const struct usb_endpoint_descriptor hid_endpoints_u2f[2] = {{
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = ENDPOINT_ADDRESS_U2F_IN,
|
||||
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
|
||||
.wMaxPacketSize = 64,
|
||||
.bInterval = 2,
|
||||
}, {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = ENDPOINT_ADDRESS_U2F_OUT,
|
||||
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
|
||||
.wMaxPacketSize = 64,
|
||||
.bInterval = 2,
|
||||
}};
|
||||
|
||||
static const struct usb_interface_descriptor hid_iface_u2f[] = {{
|
||||
.bLength = USB_DT_INTERFACE_SIZE,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = USB_INTERFACE_INDEX_U2F,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_HID,
|
||||
.bInterfaceSubClass = 0,
|
||||
.bInterfaceProtocol = 0,
|
||||
.iInterface = 0,
|
||||
.endpoint = hid_endpoints_u2f,
|
||||
.extra = &hid_function_u2f,
|
||||
.extralen = sizeof(hid_function_u2f),
|
||||
}};
|
||||
|
||||
#if DEBUG_LINK
|
||||
static const struct usb_endpoint_descriptor hid_endpoints_debug[2] = {{
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
@ -180,6 +259,9 @@ static const struct usb_interface ifaces[] = {{
|
||||
.num_altsetting = 1,
|
||||
.altsetting = hid_iface_debug,
|
||||
#endif
|
||||
}, {
|
||||
.num_altsetting = 1,
|
||||
.altsetting = hid_iface_u2f,
|
||||
}};
|
||||
|
||||
static const struct usb_config_descriptor config = {
|
||||
@ -187,9 +269,9 @@ static const struct usb_config_descriptor config = {
|
||||
.bDescriptorType = USB_DT_CONFIGURATION,
|
||||
.wTotalLength = 0,
|
||||
#if DEBUG_LINK
|
||||
.bNumInterfaces = 2,
|
||||
.bNumInterfaces = 3,
|
||||
#else
|
||||
.bNumInterfaces = 1,
|
||||
.bNumInterfaces = 2,
|
||||
#endif
|
||||
.bConfigurationValue = 1,
|
||||
.iConfiguration = 0,
|
||||
@ -214,15 +296,29 @@ static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uin
|
||||
(req->wValue != 0x2200))
|
||||
return 0;
|
||||
|
||||
/* Handle the HID report descriptor. */
|
||||
if (req->wIndex == USB_INTERFACE_INDEX_U2F) {
|
||||
debugLog(0, "", "hid_control_request u2f");
|
||||
*buf = (uint8_t *)hid_report_descriptor_u2f;
|
||||
*len = sizeof(hid_report_descriptor_u2f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if DEBUG_LINK
|
||||
if (req->wIndex == 1) {
|
||||
debugLog(0, "", "hid_control_request debug");
|
||||
*buf = (uint8_t *)hid_report_descriptor_debug;
|
||||
*len = sizeof(hid_report_descriptor_debug);
|
||||
} else {
|
||||
debugLog(0, "", "hid_control_request trezor");
|
||||
*buf = (uint8_t *)hid_report_descriptor;
|
||||
*len = sizeof(hid_report_descriptor);
|
||||
}
|
||||
|
||||
return 1;
|
||||
#else
|
||||
debugLog(0, "", "hid_control_request trezor");
|
||||
*buf = (uint8_t *)hid_report_descriptor;
|
||||
*len = sizeof(hid_report_descriptor);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -241,6 +337,16 @@ static void hid_rx_callback(usbd_device *dev, uint8_t ep)
|
||||
}
|
||||
}
|
||||
|
||||
static void hid_u2f_rx_callback(usbd_device *dev, uint8_t ep)
|
||||
{
|
||||
(void)ep;
|
||||
static uint8_t buf[64] __attribute__ ((aligned(4)));
|
||||
|
||||
debugLog(0, "", "hid_u2f_rx_callback");
|
||||
if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_U2F_OUT, buf, 64) != 64) return;
|
||||
u2fhid_read(tiny, (const U2FHID_FRAME *)buf);
|
||||
}
|
||||
|
||||
#if DEBUG_LINK
|
||||
static void hid_debug_rx_callback(usbd_device *dev, uint8_t ep)
|
||||
{
|
||||
@ -262,6 +368,8 @@ static void hid_set_config(usbd_device *dev, uint16_t wValue)
|
||||
|
||||
usbd_ep_setup(dev, ENDPOINT_ADDRESS_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0);
|
||||
usbd_ep_setup(dev, ENDPOINT_ADDRESS_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_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, hid_u2f_rx_callback);
|
||||
#if DEBUG_LINK
|
||||
usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_IN, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0);
|
||||
usbd_ep_setup(dev, ENDPOINT_ADDRESS_DEBUG_OUT, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_debug_rx_callback);
|
||||
@ -293,6 +401,10 @@ void usbPoll(void)
|
||||
if (data) {
|
||||
while ( usbd_ep_write_packet(usbd_dev, ENDPOINT_ADDRESS_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
|
||||
// write pending debug data
|
||||
data = msg_debug_out_data();
|
||||
|
@ -23,6 +23,10 @@ const uint8_t bmp_logo48_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x
|
||||
const uint8_t bmp_logo48_empty_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x01, 0x81, 0x80, 0x00, 0x00, 0x06, 0x00, 0x60, 0x00, 0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x10, 0x7e, 0x08, 0x00, 0x00, 0x21, 0x81, 0x84, 0x00, 0x00, 0x22, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x22, 0x00, 0x00, 0x48, 0x00, 0x12, 0x00, 0x00, 0x88, 0x00, 0x11, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x00, 0x90, 0x00, 0x09, 0x00, 0x03, 0x9f, 0xff, 0xf9, 0xc0, 0x04, 0x00, 0x00, 0x00, 0x20, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x00, 0x00, 0x00, 0x10, 0x08, 0x3f, 0xff, 0xfc, 0x10, 0x08, 0x40, 0x00, 0x02, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x80, 0x00, 0x01, 0x10, 0x08, 0x60, 0x00, 0x06, 0x10, 0x08, 0x1c, 0x00, 0x38, 0x10, 0x08, 0x03, 0x81, 0xc0, 0x10, 0x07, 0x00, 0x7e, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0x07, 0x00, 0x00, 0x1c, 0x00, 0x38, 0x00, 0x00, 0x03, 0x81, 0xc0, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
|
||||
const uint8_t bmp_logo64_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xfc, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3f, 0xf0, 0x1f, 0xf8, 0x00, 0x00, 0x3f, 0xc0, 0x07, 0xf8, 0x00, 0x00, 0x7f, 0x80, 0x03, 0xfc, 0x00, 0x00, 0x7f, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0x80, 0x03, 0xff, 0xf0, 0x1f, 0xc0, 0x00, 0x00, 0x07, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x1f, 0xe0, 0x00, 0x00, 0x0f, 0xf0, 0x1f, 0xfc, 0x00, 0x00, 0x7f, 0xf0, 0x1f, 0xff, 0x00, 0x01, 0xff, 0xf0, 0x1f, 0xff, 0xf0, 0x1f, 0xff, 0xf0, 0x1f, 0xff, 0xfc, 0x7f, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
|
||||
const uint8_t bmp_logo64_empty_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x00, 0x00, 0x01, 0x80, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40, 0x00, 0x00, 0x08, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x0f, 0xe0, 0x10, 0x00, 0x00, 0x20, 0x30, 0x18, 0x08, 0x00, 0x00, 0x20, 0x40, 0x04, 0x08, 0x00, 0x00, 0x40, 0x80, 0x02, 0x04, 0x00, 0x00, 0x41, 0x00, 0x01, 0x04, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x82, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x84, 0x00, 0x00, 0x42, 0x00, 0x00, 0x87, 0xff, 0xff, 0xc2, 0x00, 0x03, 0x80, 0x00, 0x00, 0x03, 0x80, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x70, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x7f, 0xfc, 0x00, 0x10, 0x10, 0x3f, 0x80, 0x03, 0xf8, 0x10, 0x10, 0x40, 0x00, 0x00, 0x04, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x80, 0x00, 0x00, 0x02, 0x10, 0x10, 0x60, 0x00, 0x00, 0x0c, 0x10, 0x10, 0x1c, 0x00, 0x00, 0x70, 0x10, 0x10, 0x03, 0x00, 0x01, 0x80, 0x10, 0x10, 0x00, 0xf0, 0x1e, 0x00, 0x10, 0x10, 0x00, 0x0c, 0x60, 0x00, 0x10, 0x0e, 0x00, 0x03, 0x80, 0x00, 0xe0, 0x01, 0xc0, 0x00, 0x00, 0x07, 0x00, 0x00, 0x30, 0x00, 0x00, 0x18, 0x00, 0x00, 0x0e, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x01, 0xc0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
|
||||
const uint8_t bmp_u2f_dropbox_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x03, 0x00, 0x01, 0xf0, 0x0f, 0x80, 0x07, 0xf8, 0x1f, 0xe0, 0x0f, 0xfc, 0x3f, 0xf8, 0x3f, 0xfe, 0x7f, 0xfc, 0x7f, 0xfe, 0x7f, 0xff, 0x7f, 0xfc, 0x1f, 0xfe, 0x3f, 0xf0, 0x0f, 0xfc, 0x1f, 0xe0, 0x03, 0xf8, 0x07, 0x80, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, 0x60, 0x07, 0x80, 0x01, 0xf0, 0x1f, 0xe0, 0x03, 0xf8, 0x3f, 0xf0, 0x0f, 0xfc, 0x7f, 0xfc, 0x3f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x1f, 0xfe, 0x7f, 0xfc, 0x0f, 0xfc, 0x3f, 0xf0, 0x03, 0xf9, 0x9f, 0xc0, 0x00, 0xe3, 0xc7, 0x80, 0x00, 0x47, 0xe2, 0x00, 0x03, 0x1f, 0xf8, 0x40, 0x03, 0xff, 0xfd, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xff, 0x00, 0x00, 0x3f, 0xfc, 0x00, 0x00, 0x0f, 0xf8, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, };
|
||||
const uint8_t bmp_u2f_github_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x78, 0x1f, 0x80, 0x01, 0xf8, 0x1f, 0xe0, 0x03, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xf8, 0x00, 0x00, 0x1f, 0xf8, 0x20, 0x04, 0x1f, 0xf0, 0x70, 0x0e, 0x0f, 0x70, 0xf0, 0x0f, 0x0e, 0x70, 0xf8, 0x1f, 0x0e, 0x70, 0x70, 0x0e, 0x0e, 0x30, 0x70, 0x0e, 0x0c, 0x38, 0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x38, 0x0e, 0x00, 0x00, 0x70, 0x07, 0x80, 0x01, 0xe0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
|
||||
const uint8_t bmp_u2f_google_data[] = { 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x7f, 0xfe, 0x00, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xc0, 0x07, 0xf0, 0x0f, 0xe0, 0x0f, 0xc0, 0x03, 0xf0, 0x1f, 0x00, 0x01, 0xf8, 0x3e, 0x00, 0x00, 0xfc, 0x3c, 0x00, 0x01, 0xfc, 0x7c, 0x0f, 0xf3, 0xfe, 0x78, 0x1f, 0xff, 0xfe, 0x78, 0x3f, 0xff, 0xfe, 0xf0, 0x3f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0x00, 0x1f, 0xf0, 0x7f, 0xfe, 0x1f, 0xf0, 0x3f, 0xfe, 0x1f, 0x78, 0x3f, 0xfc, 0x1e, 0x78, 0x1f, 0xf8, 0x3e, 0x7c, 0x07, 0xf0, 0x3e, 0x3c, 0x00, 0x00, 0x7c, 0x3e, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x00, 0xf8, 0x0f, 0xc0, 0x03, 0xf0, 0x07, 0xf0, 0x0f, 0xe0, 0x03, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x00, 0x7f, 0xfe, 0x00, 0x00, 0x0f, 0xf0, 0x00, };
|
||||
const uint8_t bmp_u2f_slushpool_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x01, 0xee, 0x00, 0x01, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xf8, 0x00, 0xfe, 0x0f, 0xf8, 0x00, 0xfe, 0x03, 0xf8, 0x00, 0xfc, 0x03, 0xf8, 0x00, 0xfc, 0x03, 0xf8, 0x01, 0xfc, 0x03, 0xf8, 0x01, 0xfc, 0x03, 0xf0, 0x01, 0xfc, 0x07, 0xf0, 0x01, 0xfc, 0x1f, 0xf0, 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xf0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x0f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
|
||||
|
||||
const BITMAP bmp_digit0 = {16, 16, bmp_digit0_data};
|
||||
const BITMAP bmp_digit1 = {16, 16, bmp_digit1_data};
|
||||
@ -47,3 +51,7 @@ const BITMAP bmp_logo48 = {40, 48, bmp_logo48_data};
|
||||
const BITMAP bmp_logo48_empty = {40, 48, bmp_logo48_empty_data};
|
||||
const BITMAP bmp_logo64 = {48, 64, bmp_logo64_data};
|
||||
const BITMAP bmp_logo64_empty = {48, 64, bmp_logo64_empty_data};
|
||||
const BITMAP bmp_u2f_dropbox = {32, 32, bmp_u2f_dropbox_data};
|
||||
const BITMAP bmp_u2f_github = {32, 32, bmp_u2f_github_data};
|
||||
const BITMAP bmp_u2f_google = {32, 32, bmp_u2f_google_data};
|
||||
const BITMAP bmp_u2f_slushpool = {32, 32, bmp_u2f_slushpool_data};
|
||||
|
@ -31,5 +31,9 @@ extern const BITMAP bmp_logo48;
|
||||
extern const BITMAP bmp_logo48_empty;
|
||||
extern const BITMAP bmp_logo64;
|
||||
extern const BITMAP bmp_logo64_empty;
|
||||
extern const BITMAP bmp_u2f_dropbox;
|
||||
extern const BITMAP bmp_u2f_github;
|
||||
extern const BITMAP bmp_u2f_google;
|
||||
extern const BITMAP bmp_u2f_slushpool;
|
||||
|
||||
#endif
|
||||
|
BIN
gen/bitmaps/u2f_dropbox.png
Normal file
BIN
gen/bitmaps/u2f_dropbox.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 263 B |
BIN
gen/bitmaps/u2f_github.png
Normal file
BIN
gen/bitmaps/u2f_github.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 236 B |
BIN
gen/bitmaps/u2f_google.png
Normal file
BIN
gen/bitmaps/u2f_google.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 240 B |
BIN
gen/bitmaps/u2f_slushpool.png
Normal file
BIN
gen/bitmaps/u2f_slushpool.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 214 B |
28
layout.c
28
layout.c
@ -22,33 +22,13 @@
|
||||
#include "layout.h"
|
||||
#include "oled.h"
|
||||
|
||||
void layoutDialog(LayoutDialogIcon icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6)
|
||||
void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6)
|
||||
{
|
||||
int left = 0;
|
||||
oledClear();
|
||||
switch (icon) {
|
||||
case DIALOG_NOICON:
|
||||
break;
|
||||
case DIALOG_ICON_ERROR:
|
||||
oledDrawBitmap(0, 0, &bmp_icon_error);
|
||||
left = 20;
|
||||
break;
|
||||
case DIALOG_ICON_INFO:
|
||||
oledDrawBitmap(0, 0, &bmp_icon_info);
|
||||
left = 20;
|
||||
break;
|
||||
case DIALOG_ICON_QUESTION:
|
||||
oledDrawBitmap(0, 0, &bmp_icon_question);
|
||||
left = 20;
|
||||
break;
|
||||
case DIALOG_ICON_WARNING:
|
||||
oledDrawBitmap(0, 0, &bmp_icon_warning);
|
||||
left = 20;
|
||||
break;
|
||||
case DIALOG_ICON_OK:
|
||||
oledDrawBitmap(0, 0, &bmp_icon_ok);
|
||||
left = 20;
|
||||
break;
|
||||
if (icon) {
|
||||
oledDrawBitmap(0, 0, icon);
|
||||
left = icon->width + 4;
|
||||
}
|
||||
if (line1) oledDrawString(left, 0 * 9, line1);
|
||||
if (line2) oledDrawString(left, 1 * 9, line2);
|
||||
|
12
layout.h
12
layout.h
@ -22,17 +22,9 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include "bitmaps.h"
|
||||
|
||||
typedef enum {
|
||||
DIALOG_NOICON = 0,
|
||||
DIALOG_ICON_ERROR,
|
||||
DIALOG_ICON_INFO,
|
||||
DIALOG_ICON_QUESTION,
|
||||
DIALOG_ICON_WARNING,
|
||||
DIALOG_ICON_OK,
|
||||
} LayoutDialogIcon;
|
||||
|
||||
void layoutDialog(LayoutDialogIcon icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6);
|
||||
void layoutDialog(const BITMAP *icon, const char *btnNo, const char *btnYes, const char *desc, const char *line1, const char *line2, const char *line3, const char *line4, const char *line5, const char *line6);
|
||||
void layoutProgressUpdate(bool refresh);
|
||||
void layoutProgress(const char *desc, int permil);
|
||||
|
||||
|
2
vendor/trezor-common
vendored
2
vendor/trezor-common
vendored
@ -1 +1 @@
|
||||
Subproject commit e6295a33cda4f0541311c9098569531c2d84220b
|
||||
Subproject commit 70d8ac8f85f16a0a16019749402f26dcc635d841
|
Loading…
Reference in New Issue
Block a user