From 5dc1a0cfcd8e9e4e4e514094227dde3fad816eaa Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Mon, 23 May 2022 16:39:24 +0200 Subject: [PATCH] EIP-191 clear signing --- src_features/signMessage/cmd_signMessage.c | 123 ++++++++++++++++-- .../signMessage/ui_flow_signMessage.c | 2 +- 2 files changed, 113 insertions(+), 12 deletions(-) diff --git a/src_features/signMessage/cmd_signMessage.c b/src_features/signMessage/cmd_signMessage.c index 2c5ec6f..a7592a3 100644 --- a/src_features/signMessage/cmd_signMessage.c +++ b/src_features/signMessage/cmd_signMessage.c @@ -1,3 +1,4 @@ +#include #include "shared_context.h" #include "apdu_constants.h" #include "utils.h" @@ -7,12 +8,108 @@ static const char SIGN_MAGIC[] = "\x19" "Ethereum Signed Message:\n"; +/** + * Check if a given character is a "special" displayable ASCII character + * + * @param[in] c character we're checking + * @return wether the character is special or not + */ +static inline bool is_char_special(char c) { + return ((c >= '\b') && (c <= '\r')); +} + +/** + * Check if a given data is made of ASCII characters + * + * @param[in] data the input data + * @param[in] the length of the input data + * @return wether the data is fully ASCII or not + */ +static bool is_data_ascii(const uint8_t *const data, uint8_t length) { + for (uint8_t idx = 0; idx < length; ++idx) { + if (!is_char_special(data[idx]) && ((data[idx] < 0x20) || (data[idx] > 0x7e))) { + return false; + } + } + return true; +} + +/** + * Initialize value string that will be displayed in the UX STEP + * + * @param[in] if the value is ASCII + */ +static void init_value_str(bool is_ascii) { + if (is_ascii) { + strings.tmp.tmp[0] = '\0'; // init string as empty + } else { + strcpy(strings.tmp.tmp, "0x"); // will display the hex bytes instead + } +} + +/** + * Update the global UI string variable by formatting & appending the new data to it + * + * @param[in] data the input data + * @param[in] length the data length + * @param[in] is_ascii wether the data is ASCII or not + */ +static void feed_value_str(const uint8_t *const data, uint8_t length, bool is_ascii) { + uint16_t value_strlen = strlen(strings.tmp.tmp); + + if ((value_strlen + 1) < sizeof(strings.tmp.tmp)) { + if (is_ascii) { + uint8_t src_idx = 0; + uint16_t dst_idx = value_strlen; + bool prev_is_special = false; + + while ((src_idx < length) && (dst_idx < sizeof(strings.tmp.tmp))) { + if (prev_is_special) { + if (!is_char_special(data[src_idx])) { + prev_is_special = false; + } + } else { + if (is_char_special(data[src_idx])) { + prev_is_special = true; + strings.tmp.tmp[dst_idx] = ' '; + dst_idx += 1; + } + } + if (!is_char_special(data[src_idx])) { + strings.tmp.tmp[dst_idx] = data[src_idx]; + dst_idx += 1; + } + src_idx += 1; + } + + if (dst_idx < sizeof(strings.tmp.tmp)) { + strings.tmp.tmp[dst_idx] = '\0'; + } else { + const char marker[] = "..."; + + memcpy(strings.tmp.tmp + sizeof(strings.tmp.tmp) - sizeof(marker), + marker, + sizeof(marker)); + } + } else { + snprintf(strings.tmp.tmp + value_strlen, + sizeof(strings.tmp.tmp) - value_strlen, + "%.*H", + length, + data); + } + } +} + void handleSignPersonalMessage(uint8_t p1, uint8_t p2, uint8_t *workBuffer, uint16_t dataLength, unsigned int *flags, unsigned int *tx) { + // Point to this unused global variable for persistency + bool *is_ascii = (bool *) &strings.tmp.tmp2[0]; + UNUSED(tx); uint8_t hashMessage[INT256_LENGTH]; if (p1 == P1_FIRST) { @@ -29,6 +126,7 @@ void handleSignPersonalMessage(uint8_t p1, reset_app_context(); } appState = APP_STATE_SIGNING_MESSAGE; + tmpCtx.messageSigningContext.pathLength = workBuffer[0]; if ((tmpCtx.messageSigningContext.pathLength < 0x01) || (tmpCtx.messageSigningContext.pathLength > MAX_BIP32_PATH)) { @@ -38,21 +136,21 @@ void handleSignPersonalMessage(uint8_t p1, workBuffer++; dataLength--; for (i = 0; i < tmpCtx.messageSigningContext.pathLength; i++) { - if (dataLength < 4) { + if (dataLength < sizeof(uint32_t)) { PRINTF("Invalid data\n"); THROW(0x6a80); } tmpCtx.messageSigningContext.bip32Path[i] = U4BE(workBuffer, 0); - workBuffer += 4; - dataLength -= 4; + workBuffer += sizeof(uint32_t); + dataLength -= sizeof(uint32_t); } - if (dataLength < 4) { + if (dataLength < sizeof(uint32_t)) { PRINTF("Invalid data\n"); THROW(0x6a80); } tmpCtx.messageSigningContext.remainingLength = U4BE(workBuffer, 0); - workBuffer += 4; - dataLength -= 4; + workBuffer += sizeof(uint32_t); + dataLength -= sizeof(uint32_t); // Initialize message header + length cx_keccak_init(&global_sha3, 256); cx_hash((cx_hash_t *) &global_sha3, @@ -71,6 +169,10 @@ void handleSignPersonalMessage(uint8_t p1, tmp[pos] = '\0'; cx_hash((cx_hash_t *) &global_sha3, 0, (uint8_t *) tmp, pos, NULL, 0); cx_sha256_init(&tmpContent.sha2); + + *is_ascii = is_data_ascii(workBuffer, dataLength); + init_value_str(*is_ascii); + } else if (p1 != P1_MORE) { THROW(0x6B00); } @@ -84,9 +186,13 @@ void handleSignPersonalMessage(uint8_t p1, if (dataLength > tmpCtx.messageSigningContext.remainingLength) { THROW(0x6A80); } + cx_hash((cx_hash_t *) &global_sha3, 0, workBuffer, dataLength, NULL, 0); cx_hash((cx_hash_t *) &tmpContent.sha2, 0, workBuffer, dataLength, NULL, 0); tmpCtx.messageSigningContext.remainingLength -= dataLength; + + feed_value_str(workBuffer, dataLength, *is_ascii); + if (tmpCtx.messageSigningContext.remainingLength == 0) { cx_hash((cx_hash_t *) &global_sha3, CX_LAST, @@ -95,11 +201,6 @@ void handleSignPersonalMessage(uint8_t p1, tmpCtx.messageSigningContext.hash, 32); cx_hash((cx_hash_t *) &tmpContent.sha2, CX_LAST, workBuffer, 0, hashMessage, 32); - snprintf(strings.tmp.tmp, - sizeof(strings.tmp.tmp), - "%.*H", - sizeof(hashMessage), - hashMessage); #ifdef NO_CONSENT io_seproxyhal_touch_signMessage_ok(NULL); diff --git a/src_features/signMessage/ui_flow_signMessage.c b/src_features/signMessage/ui_flow_signMessage.c index 6672977..ee8e39e 100644 --- a/src_features/signMessage/ui_flow_signMessage.c +++ b/src_features/signMessage/ui_flow_signMessage.c @@ -14,7 +14,7 @@ UX_STEP_NOCB( ux_sign_flow_2_step, bnnn_paging, { - .title = "Message hash", + .title = "Message", .text = strings.tmp.tmp, }); UX_STEP_CB(