From 9f29a7caa23ead46432cbcbdb8f2bf00b5fa7de0 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Thu, 12 May 2022 17:29:35 +0200 Subject: [PATCH] UI handling WIP --- src/apdu_constants.h | 1 + src/main.c | 23 ++-- src_features/signMessageEIP712/context.c | 8 ++ src_features/signMessageEIP712/entrypoint.c | 35 ++++-- src_features/signMessageEIP712/field_hash.c | 5 + src_features/signMessageEIP712/path.c | 13 ++ src_features/signMessageEIP712/ui_flow_712.c | 53 +++++++++ src_features/signMessageEIP712/ui_flow_712.h | 8 ++ src_features/signMessageEIP712/ui_logic.c | 112 ++++++++++++++++++ src_features/signMessageEIP712/ui_logic.h | 25 ++++ .../signMessageEIP712_v0/cmd_signMessage712.c | 14 +-- 11 files changed, 271 insertions(+), 26 deletions(-) create mode 100644 src_features/signMessageEIP712/ui_flow_712.c create mode 100644 src_features/signMessageEIP712/ui_flow_712.h create mode 100644 src_features/signMessageEIP712/ui_logic.c create mode 100644 src_features/signMessageEIP712/ui_logic.h diff --git a/src/apdu_constants.h b/src/apdu_constants.h index a9cceb4..a5934ce 100644 --- a/src/apdu_constants.h +++ b/src/apdu_constants.h @@ -172,5 +172,6 @@ void handleStarkwareUnsafeSign(uint8_t p1, bool handle_eip712_struct_def(const uint8_t *const apdu_buf); bool handle_eip712_struct_impl(const uint8_t *const apdu_buf); +bool handle_eip712_sign(const uint8_t *const apdu_buf); #endif // _APDU_CONSTANTS_H_ diff --git a/src/main.c b/src/main.c index fdc82bf..5af4e52 100644 --- a/src/main.c +++ b/src/main.c @@ -663,13 +663,20 @@ void handleApdu(unsigned int *flags, unsigned int *tx) { break; case INS_SIGN_EIP_712_MESSAGE: - memset(tmpCtx.transactionContext.tokenSet, 0, MAX_ITEMS); - handleSignEIP712Message_v0(G_io_apdu_buffer[OFFSET_P1], - G_io_apdu_buffer[OFFSET_P2], - G_io_apdu_buffer + OFFSET_CDATA, - G_io_apdu_buffer[OFFSET_LC], - flags, - tx); + if (G_io_apdu_buffer[OFFSET_P2] == 0) + { + memset(tmpCtx.transactionContext.tokenSet, 0, MAX_ITEMS); + handleSignEIP712Message_v0(G_io_apdu_buffer[OFFSET_P1], + G_io_apdu_buffer[OFFSET_P2], + G_io_apdu_buffer + OFFSET_CDATA, + G_io_apdu_buffer[OFFSET_LC], + flags, + tx); + } + else + { + handle_eip712_sign(G_io_apdu_buffer); + } break; #ifdef HAVE_ETH2 @@ -696,10 +703,12 @@ void handleApdu(unsigned int *flags, unsigned int *tx) { #endif case INS_EIP712_STRUCT_DEF: + *flags |= IO_ASYNCH_REPLY; handle_eip712_struct_def(G_io_apdu_buffer); break; case INS_EIP712_STRUCT_IMPL: + *flags |= IO_ASYNCH_REPLY; handle_eip712_struct_impl(G_io_apdu_buffer); break; diff --git a/src_features/signMessageEIP712/context.c b/src_features/signMessageEIP712/context.c index de53326..3a08d04 100644 --- a/src_features/signMessageEIP712/context.c +++ b/src_features/signMessageEIP712/context.c @@ -6,6 +6,7 @@ #include "sol_typenames.h" #include "path.h" #include "field_hash.h" +#include "ui_logic.h" uint8_t *typenames_array; uint8_t *structs_array; @@ -35,6 +36,11 @@ bool init_eip712_context(void) return false; } + if (ui_712_init() == false) + { + return false; + } + // set types pointer if ((structs_array = mem_alloc(sizeof(uint8_t))) == NULL) { @@ -45,3 +51,5 @@ bool init_eip712_context(void) *structs_array = 0; return true; } + +// TODO: Make a deinit function diff --git a/src_features/signMessageEIP712/entrypoint.c b/src_features/signMessageEIP712/entrypoint.c index 20395ea..5e00b87 100644 --- a/src_features/signMessageEIP712/entrypoint.c +++ b/src_features/signMessageEIP712/entrypoint.c @@ -11,6 +11,7 @@ #include "field_hash.h" #include "path.h" #include "shared_context.h" +#include "ui_logic.h" // lib functions @@ -419,18 +420,34 @@ bool handle_eip712_struct_impl(const uint8_t *const apdu_buf) apdu_buf[OFFSET_INS]); ret = false; } - if (ret) - { - G_io_apdu_buffer[0] = 0x90; - G_io_apdu_buffer[1] = 0x00; - } - else + if (!ret) { + // Send back the response, do not restart the event loop G_io_apdu_buffer[0] = 0x6A; G_io_apdu_buffer[1] = 0x80; + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); } - //*flags |= IO_ASYNCH_REPLY; - // Send back the response, do not restart the event loop - io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); return ret; } + +bool handle_eip712_sign(const uint8_t *const apdu_buf) +{ + uint8_t i; + + if (apdu_buf[OFFSET_LC] < 1) { + PRINTF("Invalid data\n"); + THROW(0x6a80); + } + tmpCtx.messageSigningContext712.pathLength = apdu_buf[OFFSET_DATA]; + if ((tmpCtx.messageSigningContext712.pathLength < 0x01) || + (tmpCtx.messageSigningContext712.pathLength > MAX_BIP32_PATH)) { + PRINTF("Invalid path\n"); + THROW(0x6a80); + } + for (i = 0; i < tmpCtx.messageSigningContext712.pathLength; i++) { + tmpCtx.messageSigningContext712.bip32Path[i] = U4BE(apdu_buf + OFFSET_LC + 1 + (i * 4), 0); + } + + ui_712_end_sign(); + return true; +} diff --git a/src_features/signMessageEIP712/field_hash.c b/src_features/signMessageEIP712/field_hash.c index 97f326a..8637adf 100644 --- a/src_features/signMessageEIP712/field_hash.c +++ b/src_features/signMessageEIP712/field_hash.c @@ -6,6 +6,7 @@ #include "mem_utils.h" #include "eip712.h" #include "shared_context.h" +#include "ui_logic.h" static s_field_hashing *fh = NULL; @@ -145,6 +146,7 @@ bool field_hash(const uint8_t *data, // deallocate it mem_dealloc(len); + ui_712_new_field(field_ptr, data, data_length); path_advance(); fh->state = FHS_IDLE; } @@ -154,6 +156,9 @@ bool field_hash(const uint8_t *data, { return false; } + G_io_apdu_buffer[0] = 0x90; + G_io_apdu_buffer[1] = 0x00; + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); } return true; diff --git a/src_features/signMessageEIP712/path.c b/src_features/signMessageEIP712/path.c index 59a8223..fb87573 100644 --- a/src_features/signMessageEIP712/path.c +++ b/src_features/signMessageEIP712/path.c @@ -8,6 +8,7 @@ #include "shared_context.h" #include "ethUtils.h" #include "mem_utils.h" +#include "ui_logic.h" static s_path *path_struct = NULL; @@ -295,6 +296,7 @@ bool path_set_root(const char *const struct_name, uint8_t name_length) { if (path_struct == NULL) { + PRINTF("NULL check failed!\n"); return false; } @@ -302,6 +304,12 @@ bool path_set_root(const char *const struct_name, uint8_t name_length) if (path_struct->root_struct == NULL) { + PRINTF("Struct name not found ("); + for (int i = 0; i < name_length; ++i) + { + PRINTF("%c", struct_name[i]); + } + PRINTF(")!\n"); return false; } @@ -315,6 +323,7 @@ bool path_set_root(const char *const struct_name, uint8_t name_length) cx_keccak_init(hash_ctx, 256); // init hash if ((thash_ptr = type_hash(structs_array, struct_name, name_length)) == NULL) { + PRINTF("Memory allocation failed!\n"); return false; } // start the progressive hash on it @@ -347,6 +356,7 @@ bool path_set_root(const char *const struct_name, uint8_t name_length) // because the first field could be a struct type path_update(); + ui_712_new_root_struct(path_struct->root_struct); return true; } @@ -458,6 +468,9 @@ bool path_new_array_depth(uint8_t size) cx_keccak_init(hash_ctx, 256); // init hash } + G_io_apdu_buffer[0] = 0x90; + G_io_apdu_buffer[1] = 0x00; + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); return true; } diff --git a/src_features/signMessageEIP712/ui_flow_712.c b/src_features/signMessageEIP712/ui_flow_712.c new file mode 100644 index 0000000..6db752b --- /dev/null +++ b/src_features/signMessageEIP712/ui_flow_712.c @@ -0,0 +1,53 @@ +#include "ui_flow_712.h" +#include "ui_logic.h" +#include "shared_context.h" // strings + +// clang-format off +UX_STEP_NOCB( + ux_712_step_review, + pnn, + { + &C_icon_eye, + "Review", + "typed message", + }); +UX_STEP_NOCB( + ux_712_step_dynamic, + bnnn_paging, + { + .title = strings.tmp.tmp2, + .text = strings.tmp.tmp, + } +); +UX_STEP_INIT( + ux_712_step_dummy, + NULL, + NULL, + { + ui_712_next_field(); + } +); +UX_STEP_CB( + ux_712_step_approve, + pb, + NULL,//io_seproxyhal_touch_signMessage712_ok(NULL), + { + &C_icon_validate_14, + "Approve", + }); +UX_STEP_CB( + ux_712_step_reject, + pb, + NULL,//io_seproxyhal_touch_signMessage712_cancel(NULL), + { + &C_icon_crossmark, + "Reject", + }); +// clang-format on + +UX_FLOW(ux_712_flow, + &ux_712_step_review, + &ux_712_step_dynamic, + &ux_712_step_dummy, + &ux_712_step_approve, + &ux_712_step_reject); diff --git a/src_features/signMessageEIP712/ui_flow_712.h b/src_features/signMessageEIP712/ui_flow_712.h new file mode 100644 index 0000000..46f3120 --- /dev/null +++ b/src_features/signMessageEIP712/ui_flow_712.h @@ -0,0 +1,8 @@ +#ifndef UI_FLOW_712_H_ +#define UI_FLOW_712_H_ + +#include "ux_flow_engine.h" + +extern const ux_flow_step_t* const ux_712_flow[]; + +#endif // UI_FLOW_712_H_ diff --git a/src_features/signMessageEIP712/ui_logic.c b/src_features/signMessageEIP712/ui_logic.c new file mode 100644 index 0000000..3bc1704 --- /dev/null +++ b/src_features/signMessageEIP712/ui_logic.c @@ -0,0 +1,112 @@ +#include +#include +#include "ui_logic.h" +#include "mem.h" +#include "mem_utils.h" +#include "os_io.h" +#include "ux_flow_engine.h" +#include "ui_flow_712.h" +#include "shared_context.h" +#include "eip712.h" // get_struct_name + +static t_ui_context *ui_ctx = NULL; + +/** + * Called on the intermediate dummy screen between the dynamic step + * && the approve/reject screen + */ +void ui_712_next_field(void) +{ + if (!ui_ctx->end_reached) + { + // reply to previous APDU + G_io_apdu_buffer[0] = 0x90; + G_io_apdu_buffer[1] = 0x00; + io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, 2); + } + else + { + if (ui_ctx->pos == UI_712_POS_REVIEW) + { + ux_flow_next(); + ui_ctx->pos = UI_712_POS_END; + } + else + { + ux_flow_prev(); + ui_ctx->pos = UI_712_POS_REVIEW; + } + } +} + +/** + * Used to notify of a new struct to review (domain or message) + */ +void ui_712_new_root_struct(const void *const struct_ptr) +{ + strcpy(strings.tmp.tmp2, "Review struct"); + const char *struct_name; + uint8_t struct_name_length; + if ((struct_name = get_struct_name(struct_ptr, &struct_name_length)) != NULL) + { + strncpy(strings.tmp.tmp, struct_name, struct_name_length); + strings.tmp.tmp[struct_name_length] = '\0'; + } + if (!ui_ctx->shown) + { + ux_flow_init(0, ux_712_flow, NULL); + ui_ctx->shown = true; + } + else + { + ux_flow_prev(); + } +} + +/** + * Used to notify of a new field to review in the current struct (key + value) + * + * @param[in] field_ptr pointer to the new struct field + * @param[in] data pointer to the field's raw value + * @param[in] length field's raw value byte-length + */ +void ui_712_new_field(const void *const field_ptr, const uint8_t *const data, uint8_t length) +{ + const char *key; + uint8_t key_len; + + if ((key = get_struct_field_keyname(field_ptr, &key_len)) != NULL) + { + strncpy(strings.tmp.tmp2, key, MIN(key_len, sizeof(strings.tmp.tmp2) - 1)); + strings.tmp.tmp2[key_len] = '\0'; + } + // TODO: Encode data as string based on data type + (void)data; + (void)length; + strcpy(strings.tmp.tmp, "Field value"); + ux_flow_prev(); +} + +/** + * Used to signal that we are done with reviewing the structs and we can now have + * the option to approve or reject the signature + */ +void ui_712_end_sign(void) +{ + ui_ctx->end_reached = true; + ui_712_next_field(); +} + +/** + * Initializes the UI context structure in memory + */ +bool ui_712_init(void) +{ + if ((ui_ctx = MEM_ALLOC_AND_ALIGN_TO_TYPE(sizeof(*ui_ctx), *ui_ctx))) + { + ui_ctx->shown = false; + ui_ctx->end_reached = false; + ui_ctx->pos = UI_712_POS_REVIEW; + } + return ui_ctx != NULL; +} diff --git a/src_features/signMessageEIP712/ui_logic.h b/src_features/signMessageEIP712/ui_logic.h new file mode 100644 index 0000000..7e6e82e --- /dev/null +++ b/src_features/signMessageEIP712/ui_logic.h @@ -0,0 +1,25 @@ +#ifndef UI_LOGIC_712_H_ +#define UI_LOGIC_712_H_ + +#include + +typedef enum +{ + UI_712_POS_REVIEW, + UI_712_POS_END +} e_ui_position; + +typedef struct +{ + bool shown; + bool end_reached; + e_ui_position pos; +} t_ui_context; + +bool ui_712_init(void); +void ui_712_next_field(void); +void ui_712_new_root_struct(const void *const struct_ptr); +void ui_712_new_field(const void *const field_ptr, const uint8_t *const data, uint8_t length); +void ui_712_end_sign(void); + +#endif // UI_LOGIC_712_H_ diff --git a/src_features/signMessageEIP712_v0/cmd_signMessage712.c b/src_features/signMessageEIP712_v0/cmd_signMessage712.c index 3834711..6abd4f7 100644 --- a/src_features/signMessageEIP712_v0/cmd_signMessage712.c +++ b/src_features/signMessageEIP712_v0/cmd_signMessage712.c @@ -13,7 +13,7 @@ void handleSignEIP712Message_v0(uint8_t p1, UNUSED(tx); if ((p1 != 00) || (p2 != 00)) { - //THROW(0x6B00); // TODO: TMP + THROW(0x6B00); } if (appState != APP_STATE_IDLE) { reset_app_context(); @@ -21,17 +21,11 @@ void handleSignEIP712Message_v0(uint8_t p1, workBuffer = parseBip32(workBuffer, &dataLength, &tmpCtx.messageSigningContext.bip32); - if (workBuffer == NULL) { + if ((workBuffer == NULL) || (dataLength < (32 + 32))) { THROW(0x6a80); } - if (p2 == 0) // TODO: TMP - { - if (dataLength < (32 + 32)) { - THROW(0x6a80); - } - memmove(tmpCtx.messageSigningContext712.domainHash, workBuffer, 32); - memmove(tmpCtx.messageSigningContext712.messageHash, workBuffer + 32, 32); - } + memmove(tmpCtx.messageSigningContext712.domainHash, workBuffer, 32); + memmove(tmpCtx.messageSigningContext712.messageHash, workBuffer + 32, 32); #ifdef NO_CONSENT io_seproxyhal_touch_signMessage_ok(NULL);