2022-05-23 16:39:24 +02:00
|
|
|
#include <stdbool.h>
|
2022-09-08 10:20:44 +02:00
|
|
|
#include <ctype.h>
|
2022-09-09 17:23:24 +02:00
|
|
|
#include <string.h>
|
2020-06-27 13:24:04 +02:00
|
|
|
#include "apdu_constants.h"
|
2022-09-02 14:22:11 +02:00
|
|
|
#include "sign_message.h"
|
|
|
|
|
#include "ui_flow_signMessage.h"
|
|
|
|
|
|
|
|
|
|
static uint8_t processed_size;
|
2022-09-08 10:21:58 +02:00
|
|
|
static struct
|
|
|
|
|
{
|
|
|
|
|
sign_message_state sign_state : 1;
|
|
|
|
|
bool ui_started : 1;
|
|
|
|
|
} states;
|
2020-06-27 13:24:04 +02:00
|
|
|
|
2021-07-05 11:01:51 +02:00
|
|
|
static const char SIGN_MAGIC[] =
|
2020-12-01 16:20:13 +01:00
|
|
|
"\x19"
|
|
|
|
|
"Ethereum Signed Message:\n";
|
2020-06-27 13:24:04 +02:00
|
|
|
|
2022-09-02 14:22:11 +02:00
|
|
|
|
2022-09-15 13:26:11 +02:00
|
|
|
/**
|
|
|
|
|
* Send a response APDU with the given Status Word
|
|
|
|
|
*
|
|
|
|
|
* @param[in] sw status word
|
|
|
|
|
*/
|
|
|
|
|
static void apdu_reply(uint16_t sw)
|
|
|
|
|
{
|
|
|
|
|
*(uint16_t *) G_io_apdu_buffer = __builtin_bswap16(sw);
|
|
|
|
|
io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-15 11:45:05 +02:00
|
|
|
/**
|
|
|
|
|
* Get unprocessed data from last received APDU
|
|
|
|
|
*
|
|
|
|
|
* @return pointer to data in APDU buffer
|
|
|
|
|
*/
|
2022-09-08 10:20:44 +02:00
|
|
|
static const uint8_t *unprocessed_data(void)
|
2022-09-02 14:22:11 +02:00
|
|
|
{
|
|
|
|
|
return &G_io_apdu_buffer[OFFSET_CDATA] + processed_size;
|
2022-05-23 16:39:24 +02:00
|
|
|
}
|
|
|
|
|
|
2022-09-15 11:45:05 +02:00
|
|
|
/**
|
|
|
|
|
* Get size of unprocessed data from last received APDU
|
|
|
|
|
*
|
|
|
|
|
* @return size of data in bytes
|
|
|
|
|
*/
|
2022-09-08 10:20:44 +02:00
|
|
|
static size_t unprocessed_length(void)
|
2022-09-02 14:22:11 +02:00
|
|
|
{
|
|
|
|
|
return G_io_apdu_buffer[OFFSET_LC] - processed_size;
|
2022-05-23 16:39:24 +02:00
|
|
|
}
|
|
|
|
|
|
2022-09-15 11:45:05 +02:00
|
|
|
/**
|
|
|
|
|
* Get used space from UI buffer
|
|
|
|
|
*
|
|
|
|
|
* @return size in bytes
|
|
|
|
|
*/
|
2022-09-08 10:20:44 +02:00
|
|
|
static size_t ui_buffer_length(void)
|
|
|
|
|
{
|
|
|
|
|
return strlen(UI_191_BUFFER);
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-15 11:45:05 +02:00
|
|
|
/**
|
|
|
|
|
* Get remaining space from UI buffer
|
|
|
|
|
*
|
|
|
|
|
* @return size in bytes
|
|
|
|
|
*/
|
2022-09-08 10:20:44 +02:00
|
|
|
static size_t remaining_ui_buffer_length(void)
|
2022-09-02 14:22:11 +02:00
|
|
|
{
|
|
|
|
|
// -1 for the ending NULL byte
|
2022-09-08 10:20:44 +02:00
|
|
|
return (sizeof(UI_191_BUFFER) - 1) - ui_buffer_length();
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-15 11:45:05 +02:00
|
|
|
/**
|
|
|
|
|
* Get free space from UI buffer
|
|
|
|
|
*
|
|
|
|
|
* @return pointer to the free space
|
|
|
|
|
*/
|
2022-09-08 10:20:44 +02:00
|
|
|
static char *remaining_ui_buffer(void)
|
|
|
|
|
{
|
|
|
|
|
return &UI_191_BUFFER[ui_buffer_length()];
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-15 11:45:05 +02:00
|
|
|
/**
|
|
|
|
|
* Reset the UI buffer
|
|
|
|
|
*
|
|
|
|
|
* Simply sets its first byte to a NULL character
|
|
|
|
|
*/
|
2022-09-08 10:20:44 +02:00
|
|
|
static void reset_ui_buffer(void)
|
|
|
|
|
{
|
|
|
|
|
UI_191_BUFFER[0] = '\0';
|
2022-05-23 16:39:24 +02:00
|
|
|
}
|
|
|
|
|
|
2022-09-15 11:45:05 +02:00
|
|
|
/**
|
|
|
|
|
* Handle the data specific to the first APDU of an EIP-191 signature
|
|
|
|
|
*
|
|
|
|
|
* @param[in] data the APDU payload
|
|
|
|
|
* @param[in] length the payload size
|
|
|
|
|
* @return pointer to the start of the start of the message; \ref NULL if it failed
|
|
|
|
|
*/
|
|
|
|
|
static const uint8_t *first_apdu_data(const uint8_t *data, uint16_t *length)
|
2022-09-02 14:22:11 +02:00
|
|
|
{
|
|
|
|
|
if (appState != APP_STATE_IDLE) {
|
|
|
|
|
reset_app_context();
|
|
|
|
|
}
|
|
|
|
|
appState = APP_STATE_SIGNING_MESSAGE;
|
|
|
|
|
data = parseBip32(data, length, &tmpCtx.messageSigningContext.bip32);
|
|
|
|
|
if (data == NULL) {
|
2022-09-15 13:26:11 +02:00
|
|
|
apdu_reply(0x6a80);
|
2022-09-02 14:22:11 +02:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2022-07-08 11:12:50 +02:00
|
|
|
|
2022-09-02 14:22:11 +02:00
|
|
|
if (*length < sizeof(uint32_t)) {
|
|
|
|
|
PRINTF("Invalid data\n");
|
2022-09-15 13:26:11 +02:00
|
|
|
apdu_reply(0x6a80);
|
2022-09-02 14:22:11 +02:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tmpCtx.messageSigningContext.remainingLength = U4BE(data, 0);
|
|
|
|
|
data += sizeof(uint32_t);
|
|
|
|
|
*length -= sizeof(uint32_t);
|
|
|
|
|
|
|
|
|
|
// Initialize message header + length
|
|
|
|
|
cx_keccak_init(&global_sha3, 256);
|
|
|
|
|
cx_hash((cx_hash_t *) &global_sha3,
|
|
|
|
|
0,
|
|
|
|
|
(uint8_t *) SIGN_MAGIC,
|
|
|
|
|
sizeof(SIGN_MAGIC) - 1,
|
|
|
|
|
NULL,
|
|
|
|
|
0);
|
|
|
|
|
snprintf(strings.tmp.tmp2,
|
|
|
|
|
sizeof(strings.tmp.tmp2),
|
|
|
|
|
"%u",
|
|
|
|
|
tmpCtx.messageSigningContext.remainingLength);
|
|
|
|
|
cx_hash((cx_hash_t *) &global_sha3,
|
|
|
|
|
0,
|
|
|
|
|
(uint8_t *) strings.tmp.tmp2,
|
|
|
|
|
strlen(strings.tmp.tmp2),
|
|
|
|
|
NULL,
|
|
|
|
|
0);
|
2022-09-08 10:20:44 +02:00
|
|
|
reset_ui_buffer();
|
2022-09-08 10:21:58 +02:00
|
|
|
states.sign_state = STATE_191_HASH_DISPLAY;
|
|
|
|
|
states.ui_started = false;
|
2022-09-02 14:22:11 +02:00
|
|
|
return data;
|
|
|
|
|
}
|
2022-07-08 11:12:50 +02:00
|
|
|
|
2022-09-15 11:45:05 +02:00
|
|
|
/**
|
|
|
|
|
* Feed the progressive hash with new data
|
|
|
|
|
*
|
|
|
|
|
* @param[in] data the new data
|
|
|
|
|
* @param[in] length the data length
|
|
|
|
|
* @return whether it was successful or not
|
|
|
|
|
*/
|
|
|
|
|
static bool feed_hash(const uint8_t *const data, uint8_t length)
|
2022-09-02 14:22:11 +02:00
|
|
|
{
|
|
|
|
|
if (length > tmpCtx.messageSigningContext.remainingLength)
|
|
|
|
|
{
|
|
|
|
|
PRINTF("Error: Length mismatch ! (%u > %u)!\n",
|
|
|
|
|
length,
|
|
|
|
|
tmpCtx.messageSigningContext.remainingLength);
|
2022-09-15 13:26:11 +02:00
|
|
|
apdu_reply(0x6a80);
|
2022-09-02 14:22:11 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
cx_hash((cx_hash_t *) &global_sha3, 0, data, length, NULL, 0);
|
|
|
|
|
if ((tmpCtx.messageSigningContext.remainingLength -= length) == 0)
|
|
|
|
|
{
|
|
|
|
|
// Finalize hash
|
2020-12-01 16:20:13 +01:00
|
|
|
cx_hash((cx_hash_t *) &global_sha3,
|
2022-09-02 14:22:11 +02:00
|
|
|
CX_LAST,
|
2020-12-01 16:20:13 +01:00
|
|
|
NULL,
|
2022-09-02 14:22:11 +02:00
|
|
|
0,
|
|
|
|
|
tmpCtx.messageSigningContext.hash,
|
|
|
|
|
32);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-15 11:45:05 +02:00
|
|
|
/**
|
|
|
|
|
* Feed the UI with new data
|
|
|
|
|
*/
|
|
|
|
|
static void feed_display(void)
|
2022-09-02 14:22:11 +02:00
|
|
|
{
|
2022-09-08 10:20:44 +02:00
|
|
|
int c;
|
2022-05-23 16:39:24 +02:00
|
|
|
|
2022-09-08 10:20:44 +02:00
|
|
|
while ((unprocessed_length() > 0) && (remaining_ui_buffer_length() > 0))
|
2022-09-02 14:22:11 +02:00
|
|
|
{
|
2022-09-08 10:20:44 +02:00
|
|
|
c = *(char*)unprocessed_data();
|
|
|
|
|
if (isspace(c)) // to replace all white-space characters as spaces
|
|
|
|
|
{
|
|
|
|
|
c = ' ';
|
|
|
|
|
}
|
|
|
|
|
if (isprint(c))
|
|
|
|
|
{
|
|
|
|
|
sprintf(remaining_ui_buffer(), "%c", (char)c);
|
|
|
|
|
processed_size += 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (remaining_ui_buffer_length() >= 4) // 4 being the fixed length of \x00
|
|
|
|
|
{
|
|
|
|
|
snprintf(remaining_ui_buffer(), remaining_ui_buffer_length(), "\\x%02x", c);
|
|
|
|
|
processed_size += 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// fill the rest of the UI buffer spaces, to consider the buffer full
|
|
|
|
|
while (remaining_ui_buffer_length())
|
|
|
|
|
{
|
|
|
|
|
sprintf(remaining_ui_buffer(), " ");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-09-02 14:22:11 +02:00
|
|
|
}
|
2022-05-23 16:39:24 +02:00
|
|
|
|
2022-09-08 10:20:44 +02:00
|
|
|
if ((remaining_ui_buffer_length() == 0)
|
|
|
|
|
|| (tmpCtx.messageSigningContext.remainingLength == 0))
|
2022-09-02 14:22:11 +02:00
|
|
|
{
|
2022-09-08 10:21:58 +02:00
|
|
|
if (!states.ui_started)
|
2022-09-02 14:22:11 +02:00
|
|
|
{
|
2022-09-08 18:41:49 +02:00
|
|
|
ui_191_start();
|
2022-09-08 10:21:58 +02:00
|
|
|
states.ui_started = true;
|
2022-09-02 14:22:11 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-09-08 18:41:49 +02:00
|
|
|
ui_191_switch_to_message();
|
2022-09-02 14:22:11 +02:00
|
|
|
}
|
2020-06-27 13:24:04 +02:00
|
|
|
}
|
2022-09-02 14:22:11 +02:00
|
|
|
|
|
|
|
|
if ((unprocessed_length() == 0) && (tmpCtx.messageSigningContext.remainingLength > 0))
|
|
|
|
|
{
|
2022-09-15 13:26:11 +02:00
|
|
|
apdu_reply(0x9000);
|
2020-10-07 16:56:40 +02:00
|
|
|
}
|
2022-09-02 14:22:11 +02:00
|
|
|
}
|
|
|
|
|
|
2022-09-15 11:45:05 +02:00
|
|
|
/**
|
|
|
|
|
* EIP-191 APDU handler
|
|
|
|
|
*
|
|
|
|
|
* @param[in] p1 instruction parameter 1
|
|
|
|
|
* @param[in] p2 instruction parameter 2
|
|
|
|
|
* @param[in] payload received data
|
|
|
|
|
* @param[in] length data length
|
|
|
|
|
* @return whether the handling of the APDU was successful or not
|
|
|
|
|
*/
|
2022-09-02 14:22:11 +02:00
|
|
|
bool handleSignPersonalMessage(uint8_t p1,
|
|
|
|
|
uint8_t p2,
|
|
|
|
|
const uint8_t *const payload,
|
|
|
|
|
uint8_t length)
|
|
|
|
|
{
|
|
|
|
|
const uint8_t *data = payload;
|
|
|
|
|
|
|
|
|
|
(void)p2;
|
|
|
|
|
processed_size = 0;
|
|
|
|
|
if (p1 == P1_FIRST)
|
|
|
|
|
{
|
|
|
|
|
if ((data = first_apdu_data(data, (uint16_t*)&length)) == NULL)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
processed_size = data - payload;
|
2020-06-27 13:24:04 +02:00
|
|
|
}
|
2022-09-02 14:22:11 +02:00
|
|
|
else if (p1 != P1_MORE)
|
|
|
|
|
{
|
|
|
|
|
PRINTF("Error: Unexpected P1 (%u)!\n", p1);
|
2022-09-15 13:26:11 +02:00
|
|
|
apdu_reply(0x6B00);
|
|
|
|
|
return false;
|
2020-12-01 16:20:13 +01:00
|
|
|
}
|
2022-05-23 16:39:24 +02:00
|
|
|
|
2022-09-02 14:22:11 +02:00
|
|
|
if (!feed_hash(data, length))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-05-23 16:39:24 +02:00
|
|
|
|
2022-09-08 10:21:58 +02:00
|
|
|
if (states.sign_state == STATE_191_HASH_DISPLAY)
|
2022-09-02 14:22:11 +02:00
|
|
|
{
|
|
|
|
|
feed_display();
|
|
|
|
|
}
|
|
|
|
|
else // hash only
|
|
|
|
|
{
|
|
|
|
|
if (tmpCtx.messageSigningContext.remainingLength == 0)
|
|
|
|
|
{
|
2022-09-08 18:41:49 +02:00
|
|
|
#ifdef NO_CONSENT
|
|
|
|
|
io_seproxyhal_touch_signMessage_ok();
|
|
|
|
|
#else
|
|
|
|
|
ui_191_switch_to_sign();
|
|
|
|
|
#endif
|
2022-09-02 14:22:11 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-09-15 13:26:11 +02:00
|
|
|
apdu_reply(0x9000);
|
2022-09-02 14:22:11 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2022-05-23 16:39:24 +02:00
|
|
|
|
2022-09-08 18:41:49 +02:00
|
|
|
/**
|
|
|
|
|
* Decide whether to show the question to show more of the message or not
|
|
|
|
|
*/
|
|
|
|
|
void question_switcher(void)
|
2022-09-02 14:22:11 +02:00
|
|
|
{
|
2022-09-08 18:41:49 +02:00
|
|
|
if ((states.sign_state == STATE_191_HASH_DISPLAY)
|
|
|
|
|
&& ((tmpCtx.messageSigningContext.remainingLength > 0)
|
|
|
|
|
|| (unprocessed_length() > 0)))
|
2022-09-02 14:22:11 +02:00
|
|
|
{
|
2022-09-08 18:41:49 +02:00
|
|
|
ui_191_switch_to_question();
|
2022-09-02 14:22:11 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-09-08 18:41:49 +02:00
|
|
|
// Go to Sign / Cancel
|
|
|
|
|
ui_191_switch_to_sign();
|
2022-09-02 14:22:11 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-06-27 13:24:04 +02:00
|
|
|
|
2022-09-08 18:41:49 +02:00
|
|
|
/**
|
|
|
|
|
* The user has decided to skip the rest of the message
|
|
|
|
|
*/
|
|
|
|
|
void skip_rest_of_message(void)
|
2022-09-02 14:22:11 +02:00
|
|
|
{
|
2022-09-08 10:21:58 +02:00
|
|
|
states.sign_state = STATE_191_HASH_ONLY;
|
2022-09-02 14:22:11 +02:00
|
|
|
if (tmpCtx.messageSigningContext.remainingLength > 0)
|
|
|
|
|
{
|
2022-09-15 13:26:11 +02:00
|
|
|
apdu_reply(0x9000);
|
2022-09-02 14:22:11 +02:00
|
|
|
}
|
2022-09-06 09:41:16 +02:00
|
|
|
else
|
|
|
|
|
{
|
2022-09-08 18:41:49 +02:00
|
|
|
ui_191_switch_to_sign();
|
2022-09-06 09:41:16 +02:00
|
|
|
}
|
2022-09-02 14:22:11 +02:00
|
|
|
}
|
2020-06-27 13:24:04 +02:00
|
|
|
|
2022-09-08 18:41:49 +02:00
|
|
|
/**
|
|
|
|
|
* The user has decided to see the next chunk of the message
|
|
|
|
|
*/
|
|
|
|
|
void continue_displaying_message(void)
|
2022-09-02 14:22:11 +02:00
|
|
|
{
|
2022-09-08 18:41:49 +02:00
|
|
|
reset_ui_buffer();
|
|
|
|
|
if (unprocessed_length() > 0)
|
2022-09-02 14:22:11 +02:00
|
|
|
{
|
2022-09-08 18:41:49 +02:00
|
|
|
feed_display();
|
2020-12-01 16:20:13 +01:00
|
|
|
}
|
2020-06-27 13:24:04 +02:00
|
|
|
}
|