* Add Artis, Dexon, EWC, Thundercore, Volta, Webchain
* Switch to Flow API for Nano S 1.6.0 * Add extra U2F timeout guards for Windows * Review application flow and parameters checks * Refactor signature padding
This commit is contained in:
331
src/main.c
331
src/main.c
@@ -67,6 +67,9 @@ void finalizeParsing(bool);
|
||||
#define P1_FIRST 0x00
|
||||
#define P1_MORE 0x80
|
||||
|
||||
#define COMMON_CLA 0xB0
|
||||
#define COMMON_INS_GET_WALLET_ID 0x04
|
||||
|
||||
#define OFFSET_CLA 0
|
||||
#define OFFSET_INS 1
|
||||
#define OFFSET_P1 2
|
||||
@@ -144,8 +147,16 @@ union {
|
||||
rawDataContext_t rawDataContext;
|
||||
} dataContext;
|
||||
|
||||
typedef enum {
|
||||
APP_STATE_IDLE,
|
||||
APP_STATE_SIGNING_TX,
|
||||
APP_STATE_SIGNING_MESSAGE
|
||||
} app_state_t;
|
||||
|
||||
|
||||
volatile uint8_t dataAllowed;
|
||||
volatile uint8_t contractDetails;
|
||||
volatile uint8_t appState;
|
||||
volatile char addressSummary[32];
|
||||
volatile bool dataPresent;
|
||||
volatile bool tokenProvisioned;
|
||||
@@ -153,17 +164,17 @@ volatile bool currentTokenSet;
|
||||
|
||||
bagl_element_t tmp_element;
|
||||
|
||||
#ifdef TARGET_NANOX
|
||||
#ifdef HAVE_UX_FLOW
|
||||
#include "ux.h"
|
||||
ux_state_t G_ux;
|
||||
bolos_ux_params_t G_ux_params;
|
||||
#else // TARGET_NANOX
|
||||
#else // HAVE_UX_FLOW
|
||||
ux_state_t ux;
|
||||
|
||||
// display stepped screens
|
||||
unsigned int ux_step;
|
||||
unsigned int ux_step_count;
|
||||
#endif // TARGET_NANOX
|
||||
#endif // HAVE_UX_FLOW
|
||||
|
||||
|
||||
typedef struct internalStorage_t {
|
||||
@@ -204,6 +215,13 @@ const bagl_element_t* ui_menu_item_out_over(const bagl_element_t* e) {
|
||||
return e;
|
||||
}
|
||||
|
||||
void reset_app_context() {
|
||||
appState = APP_STATE_IDLE;
|
||||
currentTokenSet = false;
|
||||
os_memset((uint8_t*)&txContext, 0, sizeof(txContext));
|
||||
os_memset((uint8_t*)&tmpContent, 0, sizeof(tmpContent));
|
||||
}
|
||||
|
||||
|
||||
#define BAGL_FONT_OPEN_SANS_LIGHT_16_22PX_AVG_WIDTH 10
|
||||
#define BAGL_FONT_OPEN_SANS_REGULAR_10_13PX_AVG_WIDTH 8
|
||||
@@ -267,7 +285,7 @@ unsigned int ui_idle_blue_button(unsigned int button_mask, unsigned int button_m
|
||||
#endif // #if defined(TARGET_BLUE)
|
||||
|
||||
|
||||
#if defined(TARGET_NANOS)
|
||||
#if defined(TARGET_NANOS) && !defined(HAVE_UX_FLOW)
|
||||
|
||||
|
||||
const ux_menu_entry_t menu_main[];
|
||||
@@ -338,7 +356,7 @@ const ux_menu_entry_t menu_main[] = {
|
||||
UX_MENU_END
|
||||
};
|
||||
|
||||
#endif // #if defined(TARGET_NANOS)
|
||||
#endif // #if defined(TARGET_NANOS) && !defined(HAVE_UX_FLOW)
|
||||
|
||||
#if defined(TARGET_BLUE)
|
||||
const bagl_element_t * ui_settings_blue_toggle_data(const bagl_element_t * e) {
|
||||
@@ -741,7 +759,8 @@ unsigned int ui_address_blue_button(unsigned int button_mask, unsigned int butto
|
||||
}
|
||||
#endif // #if defined(TARGET_BLUE)
|
||||
|
||||
#if defined(TARGET_NANOS)
|
||||
#if defined(TARGET_NANOS) && !defined(HAVE_UX_FLOW)
|
||||
|
||||
const bagl_element_t ui_address_nanos[] = {
|
||||
// type userid x y w h str rad fill fg bg fid iid txt touchparams... ]
|
||||
{{BAGL_RECTANGLE , 0x00, 0, 0, 128, 32, 0, 0, BAGL_FILL, 0x000000, 0xFFFFFF, 0, 0}, NULL, 0, 0, 0, NULL, NULL, NULL},
|
||||
@@ -776,11 +795,10 @@ unsigned int ui_address_prepro(const bagl_element_t* element) {
|
||||
}
|
||||
|
||||
unsigned int ui_address_nanos_button(unsigned int button_mask, unsigned int button_mask_counter);
|
||||
#endif // #if defined(TARGET_NANOS)
|
||||
#endif // #if defined(TARGET_NANOS) && !defined(HAVE_UX_FLOW)
|
||||
|
||||
|
||||
|
||||
#if defined(TARGET_NANOS)
|
||||
#if defined(TARGET_NANOS) && !defined(HAVE_UX_FLOW)
|
||||
const bagl_element_t ui_approval_nanos[] = {
|
||||
// type userid x y w h str rad fill fg bg fid iid txt touchparams... ]
|
||||
{{BAGL_RECTANGLE , 0x00, 0, 0, 128, 32, 0, 0, BAGL_FILL, 0x000000, 0xFFFFFF, 0, 0}, NULL, 0, 0, 0, NULL, NULL, NULL},
|
||||
@@ -875,7 +893,7 @@ unsigned int ui_approval_signMessage_prepro(const bagl_element_t *element) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif // #if defined(TARGET_NANOS)
|
||||
#endif // #if defined(TARGET_NANOS) && !defined(HAVE_UX_FLOW)
|
||||
|
||||
#if defined(TARGET_BLUE)
|
||||
const bagl_element_t ui_data_selector_blue[] = {
|
||||
@@ -921,7 +939,7 @@ unsigned int ui_data_selector_blue_button(unsigned int button_mask, unsigned int
|
||||
#endif // #if defined(TARGET_BLUE)
|
||||
|
||||
|
||||
#if defined(TARGET_NANOS)
|
||||
#if defined(TARGET_NANOS) && !defined(HAVE_UX_FLOW)
|
||||
const bagl_element_t ui_data_selector_nanos[] = {
|
||||
// type userid x y w h str rad
|
||||
// fill fg bg fid iid txt touchparams... ]
|
||||
@@ -956,7 +974,7 @@ unsigned int ui_data_selector_prepro(const bagl_element_t *element) {
|
||||
|
||||
unsigned int ui_data_selector_nanos_button(unsigned int button_mask,
|
||||
unsigned int button_mask_counter);
|
||||
#endif // #if defined(TARGET_NANOS)
|
||||
#endif // #if defined(TARGET_NANOS) && !defined(HAVE_UX_FLOW)
|
||||
|
||||
#if defined(TARGET_BLUE)
|
||||
const bagl_element_t ui_data_parameter_blue[] = {
|
||||
@@ -1017,7 +1035,7 @@ unsigned int ui_data_parameter_blue_button(unsigned int button_mask, unsigned in
|
||||
#endif // #if defined(TARGET_BLUE)
|
||||
|
||||
|
||||
#if defined(TARGET_NANOS)
|
||||
#if defined(TARGET_NANOS) && !defined(HAVE_UX_FLOW)
|
||||
const bagl_element_t ui_data_parameter_nanos[] = {
|
||||
// type userid x y w h str rad
|
||||
// fill fg bg fid iid txt touchparams... ]
|
||||
@@ -1054,9 +1072,9 @@ unsigned int ui_data_parameter_prepro(const bagl_element_t *element) {
|
||||
|
||||
unsigned int ui_data_parameter_nanos_button(unsigned int button_mask,
|
||||
unsigned int button_mask_counter);
|
||||
#endif // #if defined(TARGET_NANOS)
|
||||
#endif // #if defined(TARGET_NANOS) && !defined(HAVE_UX_FLOW)
|
||||
|
||||
#if defined(TARGET_NANOX)
|
||||
#if defined(HAVE_UX_FLOW)
|
||||
|
||||
void display_settings(void);
|
||||
void switch_settings_contract_data(void);
|
||||
@@ -1065,9 +1083,9 @@ void switch_settings_display_data(void);
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
UX_FLOW_DEF_NOCB(
|
||||
ux_idle_flow_1_step,
|
||||
bnn, //pnn,
|
||||
nn, //pnn,
|
||||
{
|
||||
"", //&C_icon_dashboard,
|
||||
//"", //&C_icon_dashboard,
|
||||
"Application",
|
||||
"is ready",
|
||||
});
|
||||
@@ -1091,7 +1109,7 @@ UX_FLOW_DEF_VALID(
|
||||
pb,
|
||||
os_sched_exit(-1),
|
||||
{
|
||||
&C_icon_dashboard,
|
||||
&C_icon_dashboard_x,
|
||||
"Quit",
|
||||
});
|
||||
const ux_flow_step_t * const ux_idle_flow [] = {
|
||||
@@ -1102,6 +1120,28 @@ const ux_flow_step_t * const ux_idle_flow [] = {
|
||||
FLOW_END_STEP,
|
||||
};
|
||||
|
||||
#if defined(TARGET_NANOS)
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_settings_flow_1_step,
|
||||
bnnn_paging,
|
||||
switch_settings_contract_data(),
|
||||
{
|
||||
.title = "Contract data",
|
||||
.text = strings.common.fullAddress,
|
||||
});
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_settings_flow_2_step,
|
||||
bnnn_paging,
|
||||
switch_settings_display_data(),
|
||||
{
|
||||
.title = "Debug data",
|
||||
.text = strings.common.fullAddress + 20
|
||||
});
|
||||
|
||||
#else
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_settings_flow_1_step,
|
||||
bnnn,
|
||||
@@ -1118,18 +1158,20 @@ UX_FLOW_DEF_VALID(
|
||||
bnnn,
|
||||
switch_settings_display_data(),
|
||||
{
|
||||
"Display data",
|
||||
"Debug data",
|
||||
"Display contract data",
|
||||
"details",
|
||||
strings.common.fullAddress + 20
|
||||
});
|
||||
|
||||
#endif
|
||||
|
||||
UX_FLOW_DEF_VALID(
|
||||
ux_settings_flow_3_step,
|
||||
pb,
|
||||
ui_idle(),
|
||||
{
|
||||
&C_icon_back,
|
||||
&C_icon_back_x,
|
||||
"Back",
|
||||
});
|
||||
|
||||
@@ -1403,20 +1445,20 @@ const ux_flow_step_t * const ux_sign_flow [] = {
|
||||
};
|
||||
|
||||
|
||||
#endif // #if defined(TARGET_NANOX)
|
||||
#endif // #if defined(HAVE_UX_FLOW)
|
||||
|
||||
|
||||
void ui_idle(void) {
|
||||
#if defined(TARGET_BLUE)
|
||||
UX_DISPLAY(ui_idle_blue, ui_idle_blue_prepro);
|
||||
#elif defined(TARGET_NANOS)
|
||||
UX_MENU_DISPLAY(0, menu_main, NULL);
|
||||
#elif defined(TARGET_NANOX)
|
||||
#elif defined(HAVE_UX_FLOW)
|
||||
// reserve a display stack slot if none yet
|
||||
if(G_ux.stack_count == 0) {
|
||||
ux_stack_push();
|
||||
}
|
||||
ux_flow_init(0, ux_idle_flow, NULL);
|
||||
#elif defined(TARGET_NANOS)
|
||||
UX_MENU_DISPLAY(0, menu_main, NULL);
|
||||
#endif // #if TARGET_ID
|
||||
}
|
||||
|
||||
@@ -1437,6 +1479,7 @@ unsigned int io_seproxyhal_touch_address_ok(const bagl_element_t *e) {
|
||||
uint32_t tx = set_result_get_publicKey();
|
||||
G_io_apdu_buffer[tx++] = 0x90;
|
||||
G_io_apdu_buffer[tx++] = 0x00;
|
||||
reset_app_context();
|
||||
// Send back the response, do not restart the event loop
|
||||
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
|
||||
// Display back the original UX
|
||||
@@ -1447,6 +1490,7 @@ unsigned int io_seproxyhal_touch_address_ok(const bagl_element_t *e) {
|
||||
unsigned int io_seproxyhal_touch_address_cancel(const bagl_element_t *e) {
|
||||
G_io_apdu_buffer[0] = 0x69;
|
||||
G_io_apdu_buffer[1] = 0x85;
|
||||
reset_app_context();
|
||||
// Send back the response, do not restart the event loop
|
||||
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
|
||||
// Display back the original UX
|
||||
@@ -1476,14 +1520,36 @@ void io_seproxyhal_send_status(uint32_t sw) {
|
||||
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
|
||||
}
|
||||
|
||||
void format_signature_out(const uint8_t* signature) {
|
||||
os_memset(G_io_apdu_buffer + 1, 0x00, 64);
|
||||
uint8_t offset = 1;
|
||||
uint8_t xoffset = 4; //point to r value
|
||||
//copy r
|
||||
uint8_t xlength = signature[xoffset-1];
|
||||
if (xlength == 33) {
|
||||
xlength = 32;
|
||||
xoffset ++;
|
||||
}
|
||||
memmove(G_io_apdu_buffer+offset+32-xlength, signature+xoffset, xlength);
|
||||
offset += 32;
|
||||
xoffset += xlength +2; //move over rvalue and TagLEn
|
||||
//copy s value
|
||||
xlength = signature[xoffset-1];
|
||||
if (xlength == 33) {
|
||||
xlength = 32;
|
||||
xoffset ++;
|
||||
}
|
||||
memmove(G_io_apdu_buffer+offset+32-xlength, signature+xoffset, xlength);
|
||||
}
|
||||
|
||||
unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e) {
|
||||
uint8_t privateKeyData[32];
|
||||
uint8_t signature[100];
|
||||
uint8_t signatureLength;
|
||||
cx_ecfp_private_key_t privateKey;
|
||||
uint32_t tx = 0;
|
||||
uint8_t rLength, sLength, rOffset, sOffset;
|
||||
uint32_t v = getV(&tmpContent.txContent);
|
||||
io_seproxyhal_io_heartbeat();
|
||||
os_perso_derive_node_bip32(CX_CURVE_256K1, tmpCtx.transactionContext.bip32Path,
|
||||
tmpCtx.transactionContext.pathLength,
|
||||
privateKeyData, NULL);
|
||||
@@ -1491,10 +1557,11 @@ unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e) {
|
||||
&privateKey);
|
||||
os_memset(privateKeyData, 0, sizeof(privateKeyData));
|
||||
unsigned int info = 0;
|
||||
io_seproxyhal_io_heartbeat();
|
||||
signatureLength =
|
||||
cx_ecdsa_sign(&privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256,
|
||||
tmpCtx.transactionContext.hash,
|
||||
sizeof(tmpCtx.transactionContext.hash), signature, &info);
|
||||
sizeof(tmpCtx.transactionContext.hash), signature, sizeof(signature), &info);
|
||||
os_memset(&privateKey, 0, sizeof(privateKey));
|
||||
// Parity is present in the sequence tag in the legacy API
|
||||
if (tmpContent.txContent.vLength == 0) {
|
||||
@@ -1512,17 +1579,11 @@ unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e) {
|
||||
if (info & CX_ECCINFO_xGTn) {
|
||||
G_io_apdu_buffer[0] += 2;
|
||||
}
|
||||
rLength = signature[3];
|
||||
sLength = signature[4 + rLength + 1];
|
||||
rOffset = (rLength == 33 ? 1 : 0);
|
||||
sOffset = (sLength == 33 ? 1 : 0);
|
||||
os_memmove(G_io_apdu_buffer + 1, signature + 4 + rOffset, 32);
|
||||
os_memmove(G_io_apdu_buffer + 1 + 32, signature + 4 + rLength + 2 + sOffset,
|
||||
32);
|
||||
format_signature_out(signature);
|
||||
tx = 65;
|
||||
G_io_apdu_buffer[tx++] = 0x90;
|
||||
G_io_apdu_buffer[tx++] = 0x00;
|
||||
|
||||
reset_app_context();
|
||||
// Send back the response, do not restart the event loop
|
||||
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
|
||||
// Display back the original UX
|
||||
@@ -1531,6 +1592,7 @@ unsigned int io_seproxyhal_touch_tx_ok(const bagl_element_t *e) {
|
||||
}
|
||||
|
||||
unsigned int io_seproxyhal_touch_tx_cancel(const bagl_element_t *e) {
|
||||
reset_app_context();
|
||||
G_io_apdu_buffer[0] = 0x69;
|
||||
G_io_apdu_buffer[1] = 0x85;
|
||||
// Send back the response, do not restart the event loop
|
||||
@@ -1547,17 +1609,19 @@ unsigned int io_seproxyhal_touch_signMessage_ok(const bagl_element_t *e) {
|
||||
uint8_t signatureLength;
|
||||
cx_ecfp_private_key_t privateKey;
|
||||
uint32_t tx = 0;
|
||||
uint8_t rLength, sLength, rOffset, sOffset;
|
||||
io_seproxyhal_io_heartbeat();
|
||||
os_perso_derive_node_bip32(
|
||||
CX_CURVE_256K1, tmpCtx.messageSigningContext.bip32Path,
|
||||
tmpCtx.messageSigningContext.pathLength, privateKeyData, NULL);
|
||||
io_seproxyhal_io_heartbeat();
|
||||
cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &privateKey);
|
||||
os_memset(privateKeyData, 0, sizeof(privateKeyData));
|
||||
unsigned int info = 0;
|
||||
io_seproxyhal_io_heartbeat();
|
||||
signatureLength =
|
||||
cx_ecdsa_sign(&privateKey, CX_RND_RFC6979 | CX_LAST, CX_SHA256,
|
||||
tmpCtx.messageSigningContext.hash,
|
||||
sizeof(tmpCtx.messageSigningContext.hash), signature, &info);
|
||||
sizeof(tmpCtx.messageSigningContext.hash), signature, sizeof(signature), &info);
|
||||
os_memset(&privateKey, 0, sizeof(privateKey));
|
||||
G_io_apdu_buffer[0] = 27;
|
||||
if (info & CX_ECCINFO_PARITY_ODD) {
|
||||
@@ -1566,16 +1630,11 @@ unsigned int io_seproxyhal_touch_signMessage_ok(const bagl_element_t *e) {
|
||||
if (info & CX_ECCINFO_xGTn) {
|
||||
G_io_apdu_buffer[0] += 2;
|
||||
}
|
||||
rLength = signature[3];
|
||||
sLength = signature[4 + rLength + 1];
|
||||
rOffset = (rLength == 33 ? 1 : 0);
|
||||
sOffset = (sLength == 33 ? 1 : 0);
|
||||
os_memmove(G_io_apdu_buffer + 1, signature + 4 + rOffset, 32);
|
||||
os_memmove(G_io_apdu_buffer + 1 + 32, signature + 4 + rLength + 2 + sOffset,
|
||||
32);
|
||||
format_signature_out(signature);
|
||||
tx = 65;
|
||||
G_io_apdu_buffer[tx++] = 0x90;
|
||||
G_io_apdu_buffer[tx++] = 0x00;
|
||||
reset_app_context();
|
||||
// Send back the response, do not restart the event loop
|
||||
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
|
||||
// Display back the original UX
|
||||
@@ -1584,6 +1643,7 @@ unsigned int io_seproxyhal_touch_signMessage_ok(const bagl_element_t *e) {
|
||||
}
|
||||
|
||||
unsigned int io_seproxyhal_touch_signMessage_cancel(const bagl_element_t *e) {
|
||||
reset_app_context();
|
||||
G_io_apdu_buffer[0] = 0x69;
|
||||
G_io_apdu_buffer[1] = 0x85;
|
||||
// Send back the response, do not restart the event loop
|
||||
@@ -1606,11 +1666,13 @@ unsigned int io_seproxyhal_touch_data_ok(const bagl_element_t *e) {
|
||||
ui_idle();
|
||||
break;
|
||||
case USTREAM_FAULT:
|
||||
reset_app_context();
|
||||
io_seproxyhal_send_status(0x6A80);
|
||||
ui_idle();
|
||||
break;
|
||||
default:
|
||||
PRINTF("Unexpected parser status\n");
|
||||
reset_app_context();
|
||||
io_seproxyhal_send_status(0x6A80);
|
||||
ui_idle();
|
||||
}
|
||||
@@ -1624,6 +1686,7 @@ unsigned int io_seproxyhal_touch_data_ok(const bagl_element_t *e) {
|
||||
|
||||
|
||||
unsigned int io_seproxyhal_touch_data_cancel(const bagl_element_t *e) {
|
||||
reset_app_context();
|
||||
io_seproxyhal_send_status(0x6985);
|
||||
// Display back the original UX
|
||||
ui_idle();
|
||||
@@ -1798,6 +1861,12 @@ tokenDefinition_t* getKnownToken() {
|
||||
case CHAIN_KIND_POA:
|
||||
numTokens = NUM_TOKENS_POA;
|
||||
break;
|
||||
case CHAIN_KIND_ARTIS_SIGMA1:
|
||||
numTokens = NUM_TOKENS_ARTIS_SIGMA1;
|
||||
break;
|
||||
case CHAIN_KIND_ARTIS_TAU1:
|
||||
numTokens = NUM_TOKENS_ARTIS_TAU1;
|
||||
break;
|
||||
case CHAIN_KIND_RSK:
|
||||
numTokens = NUM_TOKENS_RSK;
|
||||
break;
|
||||
@@ -1852,6 +1921,21 @@ tokenDefinition_t* getKnownToken() {
|
||||
case CHAIN_KIND_TOBALABA:
|
||||
numTokens = NUM_TOKENS_TOBALABA;
|
||||
break;
|
||||
case CHAIN_KIND_DEXON:
|
||||
numTokens = NUM_TOKENS_DEXON;
|
||||
break;
|
||||
case CHAIN_KIND_VOLTA:
|
||||
numTokens = NUM_TOKENS_VOLTA;
|
||||
break;
|
||||
case CHAIN_KIND_EWC:
|
||||
numTokens = NUM_TOKENS_EWC;
|
||||
break;
|
||||
case CHAIN_KIND_WEBCHAIN:
|
||||
numTokens = NUM_TOKENS_WEBCHAIN;
|
||||
break;
|
||||
case CHAIN_KIND_THUNDERCORE:
|
||||
numTokens = NUM_TOKENS_THUNDERCORE;
|
||||
break;
|
||||
}
|
||||
for (i=0; i<numTokens; i++) {
|
||||
switch(chainConfig->kind) {
|
||||
@@ -1868,8 +1952,14 @@ tokenDefinition_t* getKnownToken() {
|
||||
currentToken = (tokenDefinition_t *)PIC(&TOKENS_PIRL[i]);
|
||||
break;
|
||||
case CHAIN_KIND_POA:
|
||||
currentToken = (tokenDefinition_t *)PIC(&TOKENS_POA[i]);
|
||||
break;
|
||||
currentToken = (tokenDefinition_t *)PIC(&TOKENS_POA[i]);
|
||||
break;
|
||||
case CHAIN_KIND_ARTIS_SIGMA1:
|
||||
currentToken = (tokenDefinition_t *)PIC(&TOKENS_ARTIS_SIGMA1[i]);
|
||||
break;
|
||||
case CHAIN_KIND_ARTIS_TAU1:
|
||||
currentToken = (tokenDefinition_t *)PIC(&TOKENS_ARTIS_TAU1[i]);
|
||||
break;
|
||||
case CHAIN_KIND_RSK:
|
||||
currentToken = (tokenDefinition_t *)PIC(&TOKENS_RSK[i]);
|
||||
break;
|
||||
@@ -1924,6 +2014,21 @@ tokenDefinition_t* getKnownToken() {
|
||||
case CHAIN_KIND_TOBALABA:
|
||||
currentToken = (tokenDefinition_t *)PIC(&TOKENS_TOBALABA[i]);
|
||||
break;
|
||||
case CHAIN_KIND_DEXON:
|
||||
currentToken = (tokenDefinition_t *)PIC(&TOKENS_DEXON[i]);
|
||||
break;
|
||||
case CHAIN_KIND_VOLTA:
|
||||
currentToken = (tokenDefinition_t *)PIC(&TOKENS_VOLTA[i]);
|
||||
break;
|
||||
case CHAIN_KIND_EWC:
|
||||
currentToken = (tokenDefinition_t *)PIC(&TOKENS_EWC[i]);
|
||||
break;
|
||||
case CHAIN_KIND_WEBCHAIN:
|
||||
currentToken = (tokenDefinition_t *)PIC(&TOKENS_WEBCHAIN[i]);
|
||||
break;
|
||||
case CHAIN_KIND_THUNDERCORE:
|
||||
currentToken = (tokenDefinition_t *)PIC(&TOKENS_THUNDERCORE[i]);
|
||||
break
|
||||
}
|
||||
if (os_memcmp(currentToken->address, tmpContent.txContent.destination, 20) == 0) {
|
||||
return currentToken;
|
||||
@@ -2028,12 +2133,12 @@ customStatus_e customProcessor(txContext_t *context) {
|
||||
array_hexstr(strings.tmp.tmp, dataContext.rawDataContext.data, 4);
|
||||
#if defined(TARGET_BLUE)
|
||||
UX_DISPLAY(ui_data_selector_blue, ui_data_selector_blue_prepro);
|
||||
#elif defined(HAVE_UX_FLOW)
|
||||
ux_flow_init(0, ux_confirm_selector_flow, NULL);
|
||||
#elif defined(TARGET_NANOS)
|
||||
ux_step = 0;
|
||||
ux_step_count = 2;
|
||||
UX_DISPLAY(ui_data_selector_nanos, ui_data_selector_prepro);
|
||||
#elif defined(TARGET_NANOX)
|
||||
ux_flow_init(0, ux_confirm_selector_flow, NULL);
|
||||
#endif // #if TARGET_ID
|
||||
}
|
||||
else {
|
||||
@@ -2048,12 +2153,12 @@ customStatus_e customProcessor(txContext_t *context) {
|
||||
}
|
||||
#if defined(TARGET_BLUE)
|
||||
UX_DISPLAY(ui_data_parameter_blue, ui_data_parameter_blue_prepro);
|
||||
#elif defined(HAVE_UX_FLOW)
|
||||
ux_flow_init(0, ux_confirm_parameter_flow, NULL);
|
||||
#elif defined(TARGET_NANOS)
|
||||
ux_step = 0;
|
||||
ux_step_count = 2;
|
||||
UX_DISPLAY(ui_data_parameter_nanos, ui_data_parameter_prepro);
|
||||
#elif defined(TARGET_NANOX)
|
||||
ux_flow_init(0, ux_confirm_parameter_flow, NULL);
|
||||
#endif // #if TARGET_ID
|
||||
}
|
||||
}
|
||||
@@ -2067,6 +2172,31 @@ customStatus_e customProcessor(txContext_t *context) {
|
||||
return CUSTOM_NOT_HANDLED;
|
||||
}
|
||||
|
||||
unsigned int const U_os_perso_seed_cookie[] = {
|
||||
0xda7aba5e,
|
||||
0xc1a551c5,
|
||||
};
|
||||
|
||||
#ifndef HAVE_WALLET_ID_SDK
|
||||
|
||||
void handleGetWalletId(volatile unsigned int *tx) {
|
||||
unsigned char t[64];
|
||||
cx_ecfp_256_private_key_t priv;
|
||||
cx_ecfp_256_public_key_t pub;
|
||||
// seed => priv key
|
||||
os_perso_derive_node_bip32(CX_CURVE_256K1, U_os_perso_seed_cookie, 2, t, NULL);
|
||||
// priv key => pubkey
|
||||
cx_ecdsa_init_private_key(CX_CURVE_256K1, t, 32, &priv);
|
||||
cx_ecfp_generate_pair(CX_CURVE_256K1, &pub, &priv, 1);
|
||||
// pubkey -> sha512
|
||||
cx_hash_sha512(pub.W, sizeof(pub.W), t, sizeof(t));
|
||||
// ! cookie !
|
||||
os_memmove(G_io_apdu_buffer, t, 64);
|
||||
*tx = 64;
|
||||
THROW(0x9000);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void handleGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, volatile unsigned int *tx) {
|
||||
UNUSED(dataLength);
|
||||
@@ -2075,7 +2205,7 @@ void handleGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t da
|
||||
uint32_t i;
|
||||
uint8_t bip32PathLength = *(dataBuffer++);
|
||||
cx_ecfp_private_key_t privateKey;
|
||||
|
||||
reset_app_context();
|
||||
if ((bip32PathLength < 0x01) ||
|
||||
(bip32PathLength > MAX_BIP32_PATH)) {
|
||||
PRINTF("Invalid path\n");
|
||||
@@ -2092,11 +2222,14 @@ void handleGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t da
|
||||
dataBuffer += 4;
|
||||
}
|
||||
tmpCtx.publicKeyContext.getChaincode = (p2 == P2_CHAINCODE);
|
||||
io_seproxyhal_io_heartbeat();
|
||||
os_perso_derive_node_bip32(CX_CURVE_256K1, bip32Path, bip32PathLength, privateKeyData, (tmpCtx.publicKeyContext.getChaincode ? tmpCtx.publicKeyContext.chainCode : NULL));
|
||||
cx_ecfp_init_private_key(CX_CURVE_256K1, privateKeyData, 32, &privateKey);
|
||||
io_seproxyhal_io_heartbeat();
|
||||
cx_ecfp_generate_pair(CX_CURVE_256K1, &tmpCtx.publicKeyContext.publicKey, &privateKey, 1);
|
||||
os_memset(&privateKey, 0, sizeof(privateKey));
|
||||
os_memset(privateKeyData, 0, sizeof(privateKeyData));
|
||||
io_seproxyhal_io_heartbeat();
|
||||
getEthAddressStringFromKey(&tmpCtx.publicKeyContext.publicKey, tmpCtx.publicKeyContext.address, &sha3);
|
||||
#ifndef NO_CONSENT
|
||||
if (p1 == P1_NON_CONFIRM)
|
||||
@@ -2121,14 +2254,14 @@ void handleGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t da
|
||||
#if defined(TARGET_BLUE)
|
||||
snprintf(strings.common.fullAddress, sizeof(strings.common.fullAddress), "0x%.*s", 40, tmpCtx.publicKeyContext.address);
|
||||
UX_DISPLAY(ui_address_blue, ui_address_blue_prepro);
|
||||
#elif defined(HAVE_UX_FLOW)
|
||||
snprintf(strings.common.fullAddress, sizeof(strings.common.fullAddress), "0x%.*s", 40, tmpCtx.publicKeyContext.address);
|
||||
ux_flow_init(0, ux_display_public_flow, NULL);
|
||||
#elif defined(TARGET_NANOS)
|
||||
snprintf(strings.common.fullAddress, sizeof(strings.common.fullAddress), "0x%.*s", 40, tmpCtx.publicKeyContext.address);
|
||||
ux_step = 0;
|
||||
ux_step_count = 2;
|
||||
UX_DISPLAY(ui_address_nanos, ui_address_prepro);
|
||||
#elif defined(TARGET_NANOX)
|
||||
snprintf(strings.common.fullAddress, sizeof(strings.common.fullAddress), "0x%.*s", 40, tmpCtx.publicKeyContext.address);
|
||||
ux_flow_init(0, ux_display_public_flow, NULL);
|
||||
#endif // #if TARGET_ID
|
||||
|
||||
*flags |= IO_ASYNCH_REPLY;
|
||||
@@ -2149,6 +2282,7 @@ void finalizeParsing(bool direct) {
|
||||
if (chainConfig->chainId != 0) {
|
||||
uint32_t v = getV(&tmpContent.txContent);
|
||||
if (chainConfig->chainId != v) {
|
||||
reset_app_context();
|
||||
PRINTF("Invalid chainId %d expected %d\n", v, chainConfig->chainId);
|
||||
if (direct) {
|
||||
THROW(0x6A80);
|
||||
@@ -2161,7 +2295,7 @@ void finalizeParsing(bool direct) {
|
||||
}
|
||||
}
|
||||
// Store the hash
|
||||
cx_hash((cx_hash_t *)&sha3, CX_LAST, tmpCtx.transactionContext.hash, 0, tmpCtx.transactionContext.hash);
|
||||
cx_hash((cx_hash_t *)&sha3, CX_LAST, tmpCtx.transactionContext.hash, 0, tmpCtx.transactionContext.hash, 32);
|
||||
// If there is a token to process, check if it is well known
|
||||
if (tokenProvisioned) {
|
||||
tokenDefinition_t *currentToken = getKnownToken();
|
||||
@@ -2177,6 +2311,7 @@ void finalizeParsing(bool direct) {
|
||||
}
|
||||
else {
|
||||
if (dataPresent && !N_storage.dataAllowed) {
|
||||
reset_app_context();
|
||||
PRINTF("Data field forbidden\n");
|
||||
if (direct) {
|
||||
THROW(0x6A80);
|
||||
@@ -2257,14 +2392,14 @@ void finalizeParsing(bool direct) {
|
||||
#else // NO_CONSENT
|
||||
#if defined(TARGET_BLUE)
|
||||
ui_approval_transaction_blue_init();
|
||||
#elif defined(HAVE_UX_FLOW)
|
||||
ux_flow_init(0,
|
||||
((dataPresent && !N_storage.contractDetails) ? ux_approval_tx_data_warning_flow : ux_approval_tx_flow),
|
||||
NULL);
|
||||
#elif defined(TARGET_NANOS)
|
||||
ux_step = 0;
|
||||
ux_step_count = 5;
|
||||
UX_DISPLAY(ui_approval_nanos, ui_approval_prepro);
|
||||
#elif defined(TARGET_NANOX)
|
||||
ux_flow_init(0,
|
||||
((dataPresent && !N_storage.contractDetails) ? ux_approval_tx_data_warning_flow : ux_approval_tx_flow),
|
||||
NULL);
|
||||
#endif // #if TARGET_ID
|
||||
#endif // NO_CONSENT
|
||||
}
|
||||
@@ -2289,10 +2424,10 @@ void handleProvideErc20TokenInformation(uint8_t p1, uint8_t p2, uint8_t *workBuf
|
||||
if (dataLength < tickerLength + 20 + 4 + 4) {
|
||||
THROW(0x6A80);
|
||||
}
|
||||
cx_hash_sha256(workBuffer + offset, tickerLength + 20 + 4 + 4, hash);
|
||||
cx_hash_sha256(workBuffer + offset, tickerLength + 20 + 4 + 4, hash, 32);
|
||||
os_memmove(tmpCtx.transactionContext.currentToken.ticker, workBuffer + offset, tickerLength);
|
||||
tmpCtx.transactionContext.currentToken.ticker[tickerLength] = ' ';
|
||||
tmpCtx.transactionContext.currentToken.ticker[tickerLength + 1] = '\0';
|
||||
tmpCtx.transactionContext.currentToken.ticker[tickerLength + 1] = '\0';
|
||||
offset += tickerLength;
|
||||
dataLength -= tickerLength;
|
||||
os_memmove(tmpCtx.transactionContext.currentToken.address, workBuffer + offset, 20);
|
||||
@@ -2322,6 +2457,14 @@ void handleSign(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataLength
|
||||
parserStatus_e txResult;
|
||||
uint32_t i;
|
||||
if (p1 == P1_FIRST) {
|
||||
if (dataLength < 1) {
|
||||
PRINTF("Invalid data\n");
|
||||
THROW(0x6a80);
|
||||
}
|
||||
if (appState != APP_STATE_IDLE) {
|
||||
reset_app_context();
|
||||
}
|
||||
appState = APP_STATE_SIGNING_TX;
|
||||
tmpCtx.transactionContext.pathLength = workBuffer[0];
|
||||
if ((tmpCtx.transactionContext.pathLength < 0x01) ||
|
||||
(tmpCtx.transactionContext.pathLength > MAX_BIP32_PATH)) {
|
||||
@@ -2331,6 +2474,10 @@ void handleSign(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataLength
|
||||
workBuffer++;
|
||||
dataLength--;
|
||||
for (i = 0; i < tmpCtx.transactionContext.pathLength; i++) {
|
||||
if (dataLength < 4) {
|
||||
PRINTF("Invalid data\n");
|
||||
THROW(0x6a80);
|
||||
}
|
||||
tmpCtx.transactionContext.bip32Path[i] = U4BE(workBuffer, 0);
|
||||
workBuffer += 4;
|
||||
dataLength -= 4;
|
||||
@@ -2346,6 +2493,10 @@ void handleSign(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataLength
|
||||
if (p2 != 0) {
|
||||
THROW(0x6B00);
|
||||
}
|
||||
if ((p1 == P1_MORE) && (appState != APP_STATE_SIGNING_TX)) {
|
||||
PRINTF("Signature not initialized\n");
|
||||
THROW(0x6985);
|
||||
}
|
||||
if (txContext.currentField == TX_RLP_NONE) {
|
||||
PRINTF("Parser not initialized\n");
|
||||
THROW(0x6985);
|
||||
@@ -2398,6 +2549,14 @@ void handleSignPersonalMessage(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint
|
||||
uint32_t base = 10;
|
||||
uint8_t pos = 0;
|
||||
uint32_t i;
|
||||
if (dataLength < 1) {
|
||||
PRINTF("Invalid data\n");
|
||||
THROW(0x6a80);
|
||||
}
|
||||
if (appState != APP_STATE_IDLE) {
|
||||
reset_app_context();
|
||||
}
|
||||
appState = APP_STATE_SIGNING_MESSAGE;
|
||||
tmpCtx.messageSigningContext.pathLength = workBuffer[0];
|
||||
if ((tmpCtx.messageSigningContext.pathLength < 0x01) ||
|
||||
(tmpCtx.messageSigningContext.pathLength > MAX_BIP32_PATH)) {
|
||||
@@ -2407,16 +2566,24 @@ void handleSignPersonalMessage(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint
|
||||
workBuffer++;
|
||||
dataLength--;
|
||||
for (i = 0; i < tmpCtx.messageSigningContext.pathLength; i++) {
|
||||
if (dataLength < 4) {
|
||||
PRINTF("Invalid data\n");
|
||||
THROW(0x6a80);
|
||||
}
|
||||
tmpCtx.messageSigningContext.bip32Path[i] = U4BE(workBuffer, 0);
|
||||
workBuffer += 4;
|
||||
dataLength -= 4;
|
||||
}
|
||||
if (dataLength < 4) {
|
||||
PRINTF("Invalid data\n");
|
||||
THROW(0x6a80);
|
||||
}
|
||||
tmpCtx.messageSigningContext.remainingLength = U4BE(workBuffer, 0);
|
||||
workBuffer += 4;
|
||||
dataLength -= 4;
|
||||
// Initialize message header + length
|
||||
cx_keccak_init(&sha3, 256);
|
||||
cx_hash((cx_hash_t *)&sha3, 0, SIGN_MAGIC, sizeof(SIGN_MAGIC) - 1, NULL);
|
||||
cx_hash((cx_hash_t *)&sha3, 0, (uint8_t*)SIGN_MAGIC, sizeof(SIGN_MAGIC) - 1, NULL, 0);
|
||||
for (index = 1; (((index * base) <= tmpCtx.messageSigningContext.remainingLength) &&
|
||||
(((index * base) / base) == index));
|
||||
index *= base);
|
||||
@@ -2424,7 +2591,7 @@ void handleSignPersonalMessage(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint
|
||||
tmp[pos++] = '0' + ((tmpCtx.messageSigningContext.remainingLength / index) % base);
|
||||
}
|
||||
tmp[pos] = '\0';
|
||||
cx_hash((cx_hash_t *)&sha3, 0, tmp, pos, NULL);
|
||||
cx_hash((cx_hash_t *)&sha3, 0, (uint8_t*)tmp, pos, NULL, 0);
|
||||
cx_sha256_init(&tmpContent.sha2);
|
||||
}
|
||||
else if (p1 != P1_MORE) {
|
||||
@@ -2433,15 +2600,19 @@ void handleSignPersonalMessage(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint
|
||||
if (p2 != 0) {
|
||||
THROW(0x6B00);
|
||||
}
|
||||
if ((p1 == P1_MORE) && (appState != APP_STATE_SIGNING_MESSAGE)) {
|
||||
PRINTF("Signature not initialized\n");
|
||||
THROW(0x6985);
|
||||
}
|
||||
if (dataLength > tmpCtx.messageSigningContext.remainingLength) {
|
||||
THROW(0x6A80);
|
||||
}
|
||||
cx_hash((cx_hash_t *)&sha3, 0, workBuffer, dataLength, NULL);
|
||||
cx_hash((cx_hash_t *)&tmpContent.sha2, 0, workBuffer, dataLength, NULL);
|
||||
cx_hash((cx_hash_t *)&sha3, 0, workBuffer, dataLength, NULL, 0);
|
||||
cx_hash((cx_hash_t *)&tmpContent.sha2, 0, workBuffer, dataLength, NULL, 0);
|
||||
tmpCtx.messageSigningContext.remainingLength -= dataLength;
|
||||
if (tmpCtx.messageSigningContext.remainingLength == 0) {
|
||||
cx_hash((cx_hash_t *)&sha3, CX_LAST, workBuffer, 0, tmpCtx.messageSigningContext.hash);
|
||||
cx_hash((cx_hash_t *)&tmpContent.sha2, CX_LAST, workBuffer, 0, hashMessage);
|
||||
cx_hash((cx_hash_t *)&sha3, CX_LAST, workBuffer, 0, tmpCtx.messageSigningContext.hash, 32);
|
||||
cx_hash((cx_hash_t *)&tmpContent.sha2, CX_LAST, workBuffer, 0, hashMessage, 32);
|
||||
|
||||
#define HASH_LENGTH 4
|
||||
array_hexstr(strings.common.fullAddress, hashMessage, HASH_LENGTH / 2);
|
||||
@@ -2455,13 +2626,13 @@ void handleSignPersonalMessage(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint
|
||||
#else NO_CONSENT
|
||||
#if defined(TARGET_BLUE)
|
||||
ui_approval_message_sign_blue_init();
|
||||
#elif defined(HAVE_UX_FLOW)
|
||||
ux_flow_init(0, ux_sign_flow, NULL);
|
||||
#elif defined(TARGET_NANOS)
|
||||
ux_step = 0;
|
||||
ux_step_count = 2;
|
||||
UX_DISPLAY(ui_approval_signMessage_nanos,
|
||||
ui_approval_signMessage_prepro);
|
||||
#elif defined(TARGET_NANOX)
|
||||
ux_flow_init(0, ux_sign_flow, NULL);
|
||||
#endif // #if TARGET_ID
|
||||
#endif // NO_CONSENT
|
||||
|
||||
@@ -2477,6 +2648,16 @@ void handleApdu(volatile unsigned int *flags, volatile unsigned int *tx) {
|
||||
|
||||
BEGIN_TRY {
|
||||
TRY {
|
||||
|
||||
#ifndef HAVE_WALLET_ID_SDK
|
||||
|
||||
if ((G_io_apdu_buffer[OFFSET_CLA] == COMMON_CLA) && (G_io_apdu_buffer[OFFSET_INS] == COMMON_INS_GET_WALLET_ID)) {
|
||||
handleGetWalletId(tx);
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (G_io_apdu_buffer[OFFSET_CLA] != CLA) {
|
||||
THROW(0x6E00);
|
||||
}
|
||||
@@ -2523,7 +2704,7 @@ void handleApdu(volatile unsigned int *flags, volatile unsigned int *tx) {
|
||||
case 0x6000:
|
||||
// Wipe the transaction context and report the exception
|
||||
sw = e;
|
||||
os_memset(&txContext, 0, sizeof(txContext));
|
||||
reset_app_context();
|
||||
break;
|
||||
case 0x9000:
|
||||
// All is well
|
||||
@@ -2532,6 +2713,7 @@ void handleApdu(volatile unsigned int *flags, volatile unsigned int *tx) {
|
||||
default:
|
||||
// Internal error
|
||||
sw = 0x6800 | (e & 0x7FF);
|
||||
reset_app_context();
|
||||
break;
|
||||
}
|
||||
// Unexpected exception => report
|
||||
@@ -2573,6 +2755,8 @@ void sample_main(void) {
|
||||
THROW(0x6982);
|
||||
}
|
||||
|
||||
PRINTF("New APDU received:\n%.*H\n", rx, G_io_apdu_buffer);
|
||||
|
||||
handleApdu(&flags, &tx);
|
||||
}
|
||||
CATCH(EXCEPTION_IO_RESET) {
|
||||
@@ -2583,7 +2767,7 @@ void sample_main(void) {
|
||||
case 0x6000:
|
||||
// Wipe the transaction context and report the exception
|
||||
sw = e;
|
||||
os_memset(&txContext, 0, sizeof(txContext));
|
||||
reset_app_context();
|
||||
break;
|
||||
case 0x9000:
|
||||
// All is well
|
||||
@@ -2592,6 +2776,7 @@ void sample_main(void) {
|
||||
default:
|
||||
// Internal error
|
||||
sw = 0x6800 | (e & 0x7FF);
|
||||
reset_app_context();
|
||||
break;
|
||||
}
|
||||
if (e != 0x9000) {
|
||||
@@ -2647,7 +2832,7 @@ unsigned char io_event(unsigned char channel) {
|
||||
case SEPROXYHAL_TAG_TICKER_EVENT:
|
||||
UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer,
|
||||
{
|
||||
#ifndef TARGET_NANOX
|
||||
#ifndef HAVE_UX_FLOW
|
||||
if (UX_ALLOWED) {
|
||||
if (ux_step_count) {
|
||||
// prepare next screen
|
||||
@@ -2656,7 +2841,7 @@ unsigned char io_event(unsigned char channel) {
|
||||
UX_REDISPLAY();
|
||||
}
|
||||
}
|
||||
#endif // TARGET_NANOX
|
||||
#endif // HAVE_UX_FLOW
|
||||
});
|
||||
break;
|
||||
}
|
||||
@@ -2736,7 +2921,7 @@ __attribute__((section(".boot"))) int main(int arg0) {
|
||||
chainConfig = (chain_config_t *)PIC(&C_chain_config);
|
||||
}
|
||||
|
||||
os_memset(&txContext, 0, sizeof(txContext));
|
||||
reset_app_context();
|
||||
|
||||
// ensure exception will work as planned
|
||||
os_boot();
|
||||
|
||||
Reference in New Issue
Block a user