diff --git a/src_features/signMessageEIP712/commands_712.c b/src_features/signMessageEIP712/commands_712.c index 05438e6c95..174e6ed5e8 100644 --- a/src_features/signMessageEIP712/commands_712.c +++ b/src_features/signMessageEIP712/commands_712.c @@ -29,6 +29,7 @@ #define P2_FILT_ACTIVATE 0x00 #define P2_FILT_DISCARDED_PATH 0x01 #define P2_FILT_MESSAGE_INFO 0x0F +#define P2_FILT_CONTRACT_NAME 0xFB #define P2_FILT_DATE_TIME 0xFC #define P2_FILT_AMOUNT_JOIN_TOKEN 0xFD #define P2_FILT_AMOUNT_JOIN_VALUE 0xFE @@ -198,6 +199,11 @@ uint16_t handle_eip712_filtering(uint8_t p1, reply_apdu = false; } break; +#ifdef HAVE_TRUSTED_NAME + case P2_FILT_CONTRACT_NAME: + ret = filtering_trusted_name(cdata, length, p1 == 1); + break; +#endif case P2_FILT_DATE_TIME: ret = filtering_date_time(cdata, length, p1 == 1); break; diff --git a/src_features/signMessageEIP712/filtering.c b/src_features/signMessageEIP712/filtering.c index 2a41cd5a83..c0274252a8 100644 --- a/src_features/signMessageEIP712/filtering.c +++ b/src_features/signMessageEIP712/filtering.c @@ -15,11 +15,13 @@ #ifdef HAVE_LEDGER_PKI #include "os_pki.h" #endif +#include "trusted_name.h" #define FILT_MAGIC_MESSAGE_INFO 183 #define FILT_MAGIC_AMOUNT_JOIN_TOKEN 11 #define FILT_MAGIC_AMOUNT_JOIN_VALUE 22 #define FILT_MAGIC_DATETIME 33 +#define FILT_MAGIC_TRUSTED_NAME 44 #define FILT_MAGIC_RAW_FIELD 72 #define TOKEN_IDX_ADDR_IN_DOMAIN 0xff @@ -319,6 +321,119 @@ bool filtering_discarded_path(const uint8_t *payload, uint8_t length) { return true; } +#ifdef HAVE_TRUSTED_NAME +/** + * Command to display a field as a trusted name + * + * @param[in] payload the payload to parse + * @param[in] length the payload length + * @param[in] discarded if the filter targets a field that is does not exist (within an empty array) + * @return whether it was successful or not + */ +bool filtering_trusted_name(const uint8_t *payload, uint8_t length, bool discarded) { + uint8_t name_len; + const char *name; + uint8_t types_count; + e_name_type *types; + uint8_t sources_count; + e_name_source *sources; + uint8_t sig_len; + const uint8_t *sig; + uint8_t offset = 0; + + if (path_get_root_type() != ROOT_MESSAGE) { + apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED; + return false; + } + + // Parsing + if ((offset + sizeof(name_len)) > length) { + return false; + } + name_len = payload[offset++]; + if ((offset + name_len) > length) { + return false; + } + name = (char *) &payload[offset]; + offset += name_len; + if ((offset + sizeof(types_count)) > length) { + return false; + } + types_count = payload[offset++]; + if ((offset + types_count) > length) { + return false; + } + types = (e_name_type *) &payload[offset]; + // sanity check + for (int i = 0; i < types_count; ++i) { + switch (types[i]) { + case TYPE_ACCOUNT: + case TYPE_CONTRACT: + break; + default: + return false; + } + } + offset += types_count; + if ((offset + sizeof(sources_count)) > length) { + return false; + } + sources_count = payload[offset++]; + if ((offset + sources_count) > length) { + return false; + } + sources = (e_name_source *) &payload[offset]; + // sanity check + for (int i = 0; i < sources_count; ++i) { + switch (sources[i]) { + case SOURCE_LAB: + case SOURCE_CAL: + case SOURCE_ENS: + case SOURCE_UD: + case SOURCE_FN: + case SOURCE_DNS: + break; + default: + return false; + } + } + offset += sources_count; + // + if ((offset + sizeof(sig_len)) > length) { + return false; + } + sig_len = payload[offset++]; + if ((offset + sig_len) != length) { + return false; + } + sig = &payload[offset]; + + // Verification + cx_sha256_t hash_ctx; + if (!sig_verif_start(&hash_ctx, FILT_MAGIC_TRUSTED_NAME)) { + return false; + } + hash_filtering_path((cx_hash_t *) &hash_ctx, discarded); + hash_nbytes((uint8_t *) name, sizeof(char) * name_len, (cx_hash_t *) &hash_ctx); + hash_nbytes(types, types_count, (cx_hash_t *) &hash_ctx); + hash_nbytes(sources, sources_count, (cx_hash_t *) &hash_ctx); + if (!sig_verif_end(&hash_ctx, sig, sig_len)) { + return false; + } + + // Handling + if (!check_typename("address")) { + return false; + } + if (name_len > 0) { // don't substitute for an empty name + ui_712_set_title(name, name_len); + } + ui_712_flag_field(true, name_len > 0, false, false, true); + ui_712_set_trusted_name_requirements(types_count, types); + return true; +} +#endif // HAVE_TRUSTED_NAME + /** * Command to display a field as a date-time * @@ -376,7 +491,7 @@ bool filtering_date_time(const uint8_t *payload, uint8_t length, bool discarded) if (name_len > 0) { // don't substitute for an empty name ui_712_set_title(name, name_len); } - ui_712_flag_field(true, name_len > 0, false, true); + ui_712_flag_field(true, name_len > 0, false, true, false); return true; } @@ -428,7 +543,7 @@ bool filtering_amount_join_token(const uint8_t *payload, uint8_t length, bool di if (!check_typename("address") || !check_token_index(token_idx)) { return false; } - ui_712_flag_field(false, false, true, false); + ui_712_flag_field(false, false, true, false, false); ui_712_token_join_prepare_addr_check(token_idx); return true; } @@ -509,7 +624,7 @@ bool filtering_amount_join_value(const uint8_t *payload, uint8_t length, bool di if (!check_typename("uint") || !check_token_index(token_idx)) { return false; } - ui_712_flag_field(false, false, true, false); + ui_712_flag_field(false, false, true, false, false); ui_712_token_join_prepare_amount(token_idx, name, name_len); return true; } @@ -569,7 +684,7 @@ bool filtering_raw_field(const uint8_t *payload, uint8_t length, bool discarded) if (name_len > 0) { // don't substitute for an empty name ui_712_set_title(name, name_len); } - ui_712_flag_field(true, name_len > 0, false, false); + ui_712_flag_field(true, name_len > 0, false, false, false); } return true; } diff --git a/src_features/signMessageEIP712/filtering.h b/src_features/signMessageEIP712/filtering.h index 8143edfb16..9d41df16a7 100644 --- a/src_features/signMessageEIP712/filtering.h +++ b/src_features/signMessageEIP712/filtering.h @@ -9,6 +9,7 @@ #define MAX_FILTERS 50 bool filtering_message_info(const uint8_t *payload, uint8_t length); +bool filtering_trusted_name(const uint8_t *payload, uint8_t length, bool discarded); bool filtering_date_time(const uint8_t *payload, uint8_t length, bool discarded); bool filtering_amount_join_token(const uint8_t *payload, uint8_t length, bool discarded); bool filtering_amount_join_value(const uint8_t *payload, uint8_t length, bool discarded); diff --git a/src_features/signMessageEIP712/ui_logic.c b/src_features/signMessageEIP712/ui_logic.c index 1914506dbe..e5c7d236de 100644 --- a/src_features/signMessageEIP712/ui_logic.c +++ b/src_features/signMessageEIP712/ui_logic.c @@ -19,6 +19,7 @@ #include "common_ui.h" #include "uint_common.h" #include "filtering.h" +#include "trusted_name.h" #define AMOUNT_JOIN_FLAG_TOKEN (1 << 0) #define AMOUNT_JOIN_FLAG_VALUE (1 << 1) @@ -42,6 +43,7 @@ typedef enum { #define UI_712_FIELD_NAME_PROVIDED (1 << 1) #define UI_712_AMOUNT_JOIN (1 << 2) #define UI_712_DATETIME (1 << 3) +#define UI_712_TRUSTED_NAME (1 << 4) typedef struct { s_amount_join joins[MAX_ASSETS]; @@ -61,6 +63,9 @@ typedef struct { uint32_t filters_crc[MAX_FILTERS]; uint8_t discarded_path_length; char discarded_path[255]; +#ifdef HAVE_TRUSTED_NAME + e_name_type name_types; +#endif #ifdef SCREEN_SIZE_WALLET char ui_pairs_buffer[(SHARED_CTX_FIELD_1_SIZE + SHARED_CTX_FIELD_2_SIZE) * 2]; #endif @@ -491,6 +496,38 @@ static bool update_amount_join(const uint8_t *data, uint8_t length) { return true; } +#ifdef HAVE_TRUSTED_NAME +/** + * Try to substitute given address by a matching contract name + * + * Fallback on showing the address if no match is found. + * + * @param[in] data the data that needs formatting + * @param[in] length its length + * @return whether it was successful or not + */ +static bool ui_712_format_trusted_name(const uint8_t *data, uint8_t length) { + uint8_t types_count = 0; + e_name_type types[8]; + uint8_t types_bak = ui_ctx->name_types; + + if (length != ADDRESS_LENGTH) { + return false; + } + for (int i = 0; types_bak > 0; ++i) { + if (types_bak & 1) { + types[types_count++] = i; + } + types_bak >>= 1; + } + if (has_trusted_name(types_count, types, &eip712_context->chain_id, data)) { + strcpy(strings.tmp.tmp, g_trusted_name); + PRINTF("IT'S A MATCH!\n"); + } + return true; +} +#endif + /** * Format given data as a human-readable date/time representation * @@ -606,6 +643,14 @@ bool ui_712_feed_to_display(const void *field_ptr, } } +#ifdef HAVE_TRUSTED_NAME + if (ui_ctx->field_flags & UI_712_TRUSTED_NAME) { + if (!ui_712_format_trusted_name(data, length)) { + return false; + } + } +#endif + // Check if this field is supposed to be displayed if (last && ui_712_field_shown()) { ui_712_redraw_generic_step(); @@ -682,8 +727,13 @@ unsigned int ui_712_reject() { * @param[in] name_provided if a substitution name has been provided * @param[in] token_join if this field is part of a token join * @param[in] datetime if this field should be shown and formatted as a date/time + * @param[in] trusted_name if this field should be shown as a trusted contract name */ -void ui_712_flag_field(bool show, bool name_provided, bool token_join, bool datetime) { +void ui_712_flag_field(bool show, + bool name_provided, + bool token_join, + bool datetime, + bool trusted_name) { if (show) { ui_ctx->field_flags |= UI_712_FIELD_SHOWN; } @@ -696,6 +746,9 @@ void ui_712_flag_field(bool show, bool name_provided, bool token_join, bool date if (datetime) { ui_ctx->field_flags |= UI_712_DATETIME; } + if (trusted_name) { + ui_ctx->field_flags |= UI_712_TRUSTED_NAME; + } } /** @@ -841,6 +894,16 @@ const char *ui_712_get_discarded_path(uint8_t *length) { return ui_ctx->discarded_path; } +#ifdef HAVE_TRUSTED_NAME +void ui_712_set_trusted_name_requirements(uint8_t types_count, const e_name_type *types) { + // pack into one byte to save on space + ui_ctx->name_types = 0; + for (int i = 0; i < types_count; ++i) { + ui_ctx->name_types |= (1 << types[i]); + } +} +#endif + #ifdef SCREEN_SIZE_WALLET /* * Get UI pairs buffer diff --git a/src_features/signMessageEIP712/ui_logic.h b/src_features/signMessageEIP712/ui_logic.h index d04c8db100..2ee134e7a4 100644 --- a/src_features/signMessageEIP712/ui_logic.h +++ b/src_features/signMessageEIP712/ui_logic.h @@ -6,6 +6,7 @@ #include #include "ux.h" #include "uint256.h" +#include "trusted_name.h" typedef enum { EIP712_FILTERING_BASIC, EIP712_FILTERING_FULL } e_eip712_filtering_mode; typedef enum { @@ -30,7 +31,11 @@ void ui_712_set_title(const char *str, size_t length); void ui_712_set_value(const char *str, size_t length); void ui_712_message_hash(void); void ui_712_redraw_generic_step(void); -void ui_712_flag_field(bool show, bool name_provided, bool token_join, bool datetime); +void ui_712_flag_field(bool show, + bool name_provided, + bool token_join, + bool datetime, + bool contract_name); void ui_712_field_flags_reset(void); void ui_712_finalize_field(void); void ui_712_set_filtering_mode(e_eip712_filtering_mode mode); @@ -46,6 +51,9 @@ bool ui_712_show_raw_key(const void *field_ptr); bool ui_712_push_new_filter_path(void); void ui_712_set_discarded_path(const char *path, uint8_t length); const char *ui_712_get_discarded_path(uint8_t *length); +#ifdef HAVE_TRUSTED_NAME +void ui_712_set_trusted_name_requirements(uint8_t types_count, const e_name_type *types); +#endif #ifdef SCREEN_SIZE_WALLET char *get_ui_pairs_buffer(size_t *size); #endif