* 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:
BTChip github
2020-01-18 12:47:53 +01:00
parent 658164ae18
commit 0e3c0f9263
44 changed files with 363 additions and 88 deletions

View File

@@ -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();