From 3a168becb43aa5b2b0710c3a42fc230218b92b5d Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Thu, 12 Jun 2025 14:27:17 +0200 Subject: [PATCH 1/6] Added linked-list "library" --- src/list.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/list.h | 96 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 src/list.c create mode 100644 src/list.h diff --git a/src/list.c b/src/list.c new file mode 100644 index 0000000000..ab733c83d3 --- /dev/null +++ b/src/list.c @@ -0,0 +1,131 @@ +#include "list.h" + +void flist_push_front(s_flist_node **list, s_flist_node *node) { + if ((list != NULL) && (node != NULL)) { + node->next = *list; + *list = node; + } +} + +void flist_pop_front(s_flist_node **list, f_list_node_del func) { + s_flist_node *tmp; + + if (list != NULL) { + tmp = *list; + if (tmp != NULL) { + *list = tmp->next; + if (func != NULL) func(tmp); + } + } +} + +void flist_push_back(s_flist_node **list, s_flist_node *node) { + s_flist_node *tmp; + + if ((list != NULL) && (node != NULL)) { + if (*list == NULL) { + *list = node; + } else { + tmp = *list; + if (tmp != NULL) { + for (; tmp->next != NULL; tmp = tmp->next) + ; + tmp->next = node; + } + } + } +} + +void flist_pop_back(s_flist_node **list, f_list_node_del func) { + s_flist_node *tmp; + + if (list != NULL) { + tmp = *list; + if (tmp != NULL) { + // only one element + if (tmp->next == NULL) { + flist_pop_front(list, func); + } else { + for (; tmp->next->next != NULL; tmp = tmp->next) + ; + if (func != NULL) func(tmp->next); + tmp->next = NULL; + } + } + } +} + +void flist_insert_after(s_flist_node **list, s_flist_node *ref, s_flist_node *node) { + (void) list; + if ((ref != NULL) && (node != NULL)) { + node->next = ref->next; + ref->next = node; + } +} + +void flist_remove(s_flist_node **list, s_flist_node *node, f_list_node_del func) { + s_flist_node *it; + s_flist_node *tmp; + + if ((list != NULL) && (node != NULL)) { + if (node == *list) { + // first element + flist_pop_front(list, func); + } else { + it = *list; + if (it != NULL) { + for (; it->next != node; it = it->next) + ; + tmp = it->next->next; + if (func != NULL) func(it->next); + it->next = tmp; + } + } + } +} + +void flist_clear(s_flist_node **list, f_list_node_del func) { + s_flist_node *tmp; + s_flist_node *next; + + if (list != NULL) { + tmp = *list; + while (tmp != NULL) { + next = tmp->next; + if (func != NULL) func(tmp); + tmp = next; + } + *list = NULL; + } +} + +size_t flist_size(s_flist_node *const *list) { + size_t size = 0; + + if (list != NULL) { + for (s_flist_node *tmp = *list; tmp != NULL; tmp = tmp->next) size += 1; + } + return size; +} + +void flist_sort(s_flist_node **list, f_list_node_cmp func) { + s_flist_node **tmp; + s_flist_node *a, *b; + bool sorted; + + if ((list != NULL) && (func != NULL)) { + do { + sorted = true; + for (tmp = list; (*tmp != NULL) && ((*tmp)->next != NULL); tmp = &(*tmp)->next) { + a = *tmp; + b = a->next; + if (func(a, b) == false) { + *tmp = b; + a->next = b->next; + b->next = a; + sorted = false; + } + } + } while (!sorted); + } +} diff --git a/src/list.h b/src/list.h new file mode 100644 index 0000000000..8101c84065 --- /dev/null +++ b/src/list.h @@ -0,0 +1,96 @@ +#pragma once + +#include +#include + +/* + * Forward list (singly-linked) + */ +typedef struct flist_node { + struct flist_node *next; +} s_flist_node; + +typedef void (*f_list_node_del)(s_flist_node *node); +typedef bool (*f_list_node_cmp)(const s_flist_node *a, const s_flist_node *b); + +/** + * Add a new node at the front of the list + * + * @param[in,out] list pointer to the list + * @param[out] node new node to add + */ +void flist_push_front(s_flist_node **list, s_flist_node *node); + +/** + * Remove the first node from the list + * + * @param[in,out] list pointer to the list + * @param[in] func pointer to the node deletion function + */ +void flist_pop_front(s_flist_node **list, f_list_node_del func); + +/** + * Add a new node at the back of the list + * + * @param[in,out] list pointer to the list + * @param[in,out] node new node to add + */ +void flist_push_back(s_flist_node **list, s_flist_node *node); + +/** + * Remove the last node from the list + * + * @param[in,out] list pointer to the list + * @param[in] func pointer to the node deletion function + */ +void flist_pop_back(s_flist_node **list, f_list_node_del func); + +/** + * Insert a new node after a given list node (reference) + * + * @param[] list pointer to the list + * @param[in,out] ref reference node + * @param[in,out] node new node to add + */ +void flist_insert_after(s_flist_node **list, s_flist_node *ref, s_flist_node *node); + +/** + * Remove a given node from the list + * + * @param[in,out] list pointer to the list + * @param[out] node node to remove + * @param[in] func pointer to the node deletion function + */ +void flist_remove(s_flist_node **list, s_flist_node *node, f_list_node_del func); + +/** + * Remove all nodes from the list + * + * @param[in,out] list pointer to the list + * @param[in] func pointer to the node deletion function + */ +void flist_clear(s_flist_node **list, f_list_node_del func); + +/** + * Get the list size + * + * @param[in] list pointer to the list + */ +size_t flist_size(s_flist_node *const *list); + +/** + * Sort the list + * + * @param[in,out] list pointer to the list + * @param[in] func pointer to the node comparison function + */ +void flist_sort(s_flist_node **list, f_list_node_cmp func); + +/* + * List (doubly-linked) + * TODO: add functions + */ +typedef struct list_node { + s_flist_node _list; + struct list_node *prev; +} s_list_node; From 87cf268f3ec92915f68112d72961bc357836dd1b Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Thu, 5 Jun 2025 13:56:50 +0200 Subject: [PATCH 2/6] Memory profiling improvements - Checks for initialization - Handles memory re-initialization - Shows memory usage (%) --- src/mem.c | 16 +++++++++++++--- tools/valground.py | 43 +++++++++++++++++++++++++++++-------------- 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/mem.c b/src/mem.c index 286bcba0e7..1f10b61d61 100644 --- a/src/mem.c +++ b/src/mem.c @@ -19,8 +19,18 @@ static uint8_t mem_buffer[SIZE_MEM_BUFFER] __attribute__((aligned(sizeof(intmax_ static uint16_t mem_legacy_idx; static mem_ctx_t mem_ctx = NULL; +#ifdef HAVE_MEMORY_PROFILING +#define MP_LOG_PREFIX "==MP " +#endif + bool app_mem_init(void) { - mem_ctx = mem_init(mem_buffer, sizeof(mem_buffer)); + void *buf = mem_buffer; + size_t buf_size = sizeof(mem_buffer); + + mem_ctx = mem_init(buf, buf_size); +#ifdef HAVE_MEMORY_PROFILING + PRINTF(MP_LOG_PREFIX "init;0x%p;%u\n", buf, buf_size); +#endif return mem_ctx != NULL; } @@ -28,7 +38,7 @@ void *app_mem_alloc_impl(size_t size, const char *file, int line) { void *ptr; ptr = mem_alloc(mem_ctx, size); #ifdef HAVE_MEMORY_PROFILING - PRINTF("==MP alloc;%u;0x%p;%s:%u\n", size, ptr, file, line); + PRINTF(MP_LOG_PREFIX "alloc;%u;0x%p;%s:%u\n", size, ptr, file, line); #else (void) file; (void) line; @@ -38,7 +48,7 @@ void *app_mem_alloc_impl(size_t size, const char *file, int line) { void app_mem_free_impl(void *ptr, const char *file, int line) { #ifdef HAVE_MEMORY_PROFILING - PRINTF("==MP free;0x%p;%s:%u\n", ptr, file, line); + PRINTF(MP_LOG_PREFIX "free;0x%p;%s:%u\n", ptr, file, line); #else (void) file; (void) line; diff --git a/tools/valground.py b/tools/valground.py index a4c6afabe3..c40f96a73c 100755 --- a/tools/valground.py +++ b/tools/valground.py @@ -3,6 +3,7 @@ # pytest --device nanosp -s -k my_special_test 2>&1 | ./valground.py import sys +from typing import Optional class Allocation: @@ -20,13 +21,17 @@ class Memory: allocd_max: int allocd_current: int alloc_count: int + addr: int + size: int - def __init__(self): + def __init__(self, addr: int, size: int): self.allocs = {} self.allocd_overtime = 0 self.allocd_max = 0 self.allocd_current = 0 self.alloc_count = 0 + self.addr = addr + self.size = size def alloc(self, ptr: int, size: int, code_loc: str): self.allocs[ptr] = Allocation(size, code_loc) @@ -41,8 +46,25 @@ def free(self, ptr: int, code_loc: str): self.allocd_current -= self.allocs[ptr].size del self.allocs[ptr] + def __del__(self): + if len(self.allocs) == 0: + print("No memory leak detected, congrats!") + else: + print("Memory leaks :") + for addr, info in self.allocs.items(): + print("- [0x%.08x] %u bytes from %s" % (addr, + info.size, + info.code_location)) + + print("\n=== Summary ===") + print("Total overtime = %u bytes" % (self.allocd_overtime)) + used_percentage = self.allocd_max / self.size * 100 + print("Max overtime = %u bytes (%.02f%% full)" % (self.allocd_max, + used_percentage)) + print("Allocations = %u" % (self.alloc_count)) + -mem = Memory() +mem: Optional[Memory] = None for line in sys.stdin: line = line.rstrip() @@ -55,21 +77,14 @@ def free(self, ptr: int, code_loc: str): words = line.split(";") assert len(words) > 2 - if words[0] == "alloc": + if words[0] == "init": + mem = Memory(int(words[1], base=0), int(words[2], base=0)) + elif words[0] == "alloc": mem.alloc(int(words[2], base=0), int(words[1], base=0), words[3]) elif words[0] == "free": mem.free(int(words[1], base=0), words[2]) else: assert False -if len(mem.allocs) == 0: - print("No memory leak detected, congrats!") -else: - print("Memory leaks :") - for addr, info in mem.allocs.items(): - print("- [0x%.08x] %u bytes from %s" % (addr, info.size, info.code_location)) - -print("\n=== Summary ===") -print("Total overtime = %u bytes" % (mem.allocd_overtime)) -print("Max overtime = %u bytes" % (mem.allocd_max)) -print("Allocations = %u" % (mem.alloc_count)) +if mem is None: + print("No memory profiling was found.") From 69a9427b023a6609b51af5cb2a70a68f14522c40 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Wed, 28 May 2025 09:44:32 +0200 Subject: [PATCH 3/6] Migrated EIP-712 feature to the new memory allocator --- src/mem_utils.c | 20 +- src/mem_utils.h | 3 +- src_features/signMessageEIP712/commands_712.c | 7 +- src_features/signMessageEIP712/context_712.c | 17 +- src_features/signMessageEIP712/encode_field.c | 2 +- src_features/signMessageEIP712/field_hash.c | 68 +- src_features/signMessageEIP712/filtering.c | 53 +- .../format_hash_field_type.c | 47 +- .../format_hash_field_type.h | 3 +- src_features/signMessageEIP712/path.c | 181 +++--- src_features/signMessageEIP712/path.h | 4 +- src_features/signMessageEIP712/schema_hash.c | 34 +- .../signMessageEIP712/sol_typenames.c | 140 ++-- .../signMessageEIP712/sol_typenames.h | 4 +- src_features/signMessageEIP712/type_hash.c | 149 ++--- src_features/signMessageEIP712/typed_data.c | 604 +++--------------- src_features/signMessageEIP712/typed_data.h | 54 +- src_features/signMessageEIP712/ui_logic.c | 272 +++++--- src_features/signMessageEIP712/ui_logic.h | 29 +- src_nbgl/ui_gcs.c | 56 +- src_nbgl/ui_sign_712.c | 63 +- 21 files changed, 734 insertions(+), 1076 deletions(-) diff --git a/src/mem_utils.c b/src/mem_utils.c index b5c6eed378..a405153a60 100644 --- a/src/mem_utils.c +++ b/src/mem_utils.c @@ -8,11 +8,9 @@ * Format an unsigned number up to 32-bit into memory into an ASCII string. * * @param[in] value Value to write in memory - * @param[out] length number of characters written to memory - * * @return pointer to memory area or \ref NULL if the allocation failed */ -char *mem_legacy_alloc_and_format_uint(uint32_t value, uint8_t *const length) { +const char *mem_alloc_and_format_uint(uint32_t value) { char *mem_ptr; uint32_t value_copy; uint8_t size; @@ -24,12 +22,8 @@ char *mem_legacy_alloc_and_format_uint(uint32_t value, uint8_t *const length) { size += 1; } // +1 for the null character - if ((mem_ptr = mem_legacy_alloc(sizeof(char) * (size + 1)))) { + if ((mem_ptr = app_mem_alloc(sizeof(char) * (size + 1)))) { snprintf(mem_ptr, (size + 1), "%u", value); - mem_legacy_dealloc(sizeof(char)); // to skip the null character - if (length != NULL) { - *length = size; - } } return mem_ptr; } @@ -63,3 +57,13 @@ void *mem_legacy_alloc_and_align(size_t size, size_t alignment) { mem_legacy_align(alignment); return mem_legacy_alloc(size); } + +char *app_mem_strdup(const char *src) { + char *dst; + size_t length = strlen(src) + 1; + + if ((dst = app_mem_alloc(length)) != NULL) { + memcpy(dst, src, length); + } + return dst; +} diff --git a/src/mem_utils.h b/src/mem_utils.h index 17536aa103..1a03ab2a95 100644 --- a/src/mem_utils.h +++ b/src/mem_utils.h @@ -4,6 +4,7 @@ #define MEM_ALLOC_AND_ALIGN_TYPE(type) mem_legacy_alloc_and_align(sizeof(type), __alignof__(type)) -char *mem_legacy_alloc_and_format_uint(uint32_t value, uint8_t *const written_chars); +const char *mem_alloc_and_format_uint(uint32_t value); uint8_t mem_legacy_align(size_t alignment); void *mem_legacy_alloc_and_align(size_t size, size_t alignment); +char *app_mem_strdup(const char *s); diff --git a/src_features/signMessageEIP712/commands_712.c b/src_features/signMessageEIP712/commands_712.c index f0160b44ff..b8ebdcbc27 100644 --- a/src_features/signMessageEIP712/commands_712.c +++ b/src_features/signMessageEIP712/commands_712.c @@ -225,11 +225,8 @@ uint16_t handle_eip712_filtering(uint8_t p1, ret = false; } if ((p2 > P2_FILT_MESSAGE_INFO) && ret) { - if (ui_712_push_new_filter_path(path_crc)) { - if (!ui_712_filters_counter_incr()) { - ret = false; - apdu_response_code = APDU_RESPONSE_INVALID_DATA; - } + if (!ui_712_push_new_filter_path(path_crc)) { + ret = false; } } if (reply_apdu) { diff --git a/src_features/signMessageEIP712/context_712.c b/src_features/signMessageEIP712/context_712.c index 2e3ddb2ca4..02dbcbcca2 100644 --- a/src_features/signMessageEIP712/context_712.c +++ b/src_features/signMessageEIP712/context_712.c @@ -19,14 +19,17 @@ s_eip712_context *eip712_context = NULL; * @return a boolean indicating if the initialization was successful or not */ bool eip712_context_init(void) { - // switch to legacy allocator - mem_legacy_init(); + if (eip712_context != NULL) { + eip712_context_deinit(); + return false; + } // init global variables - if ((eip712_context = MEM_ALLOC_AND_ALIGN_TYPE(*eip712_context)) == NULL) { + if ((eip712_context = app_mem_alloc(sizeof(*eip712_context))) == NULL) { apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; return false; } + explicit_bzero(eip712_context, sizeof(*eip712_context)); if (sol_typenames_init() == false) { return false; @@ -44,14 +47,10 @@ bool eip712_context_init(void) { return false; } - if (typed_data_init() == false) // this needs to be initialized last ! - { + if (typed_data_init() == false) { return false; } - // Since they are optional, they might not be provided by the JSON data - explicit_bzero(eip712_context->contract_addr, sizeof(eip712_context->contract_addr)); - eip712_context->chain_id = 0; eip712_context->go_home_on_failure = true; struct_state = NOT_INITIALIZED; @@ -67,8 +66,6 @@ void eip712_context_deinit(void) { path_deinit(); field_hash_deinit(); ui_712_deinit(); - // switch back to SDK allocator - app_mem_init(); eip712_context = NULL; reset_app_context(); } diff --git a/src_features/signMessageEIP712/encode_field.c b/src_features/signMessageEIP712/encode_field.c index 5d8156e935..15e34b5827 100644 --- a/src_features/signMessageEIP712/encode_field.c +++ b/src_features/signMessageEIP712/encode_field.c @@ -25,7 +25,7 @@ static void *field_encode(const uint8_t *const value, apdu_response_code = APDU_RESPONSE_INVALID_DATA; return NULL; } - if ((padded_value = mem_legacy_alloc(EIP_712_ENCODED_FIELD_LENGTH)) != NULL) { + if ((padded_value = app_mem_alloc(EIP_712_ENCODED_FIELD_LENGTH)) != NULL) { switch (ptype) { case MSB: memset(padded_value, pval, EIP_712_ENCODED_FIELD_LENGTH - length); diff --git a/src_features/signMessageEIP712/field_hash.c b/src_features/signMessageEIP712/field_hash.c index b90c935fb3..09bf4f1b2e 100644 --- a/src_features/signMessageEIP712/field_hash.c +++ b/src_features/signMessageEIP712/field_hash.c @@ -20,13 +20,17 @@ static s_field_hashing *fh = NULL; * @return whether the initialization was successful or not */ bool field_hash_init(void) { - if (fh == NULL) { - if ((fh = MEM_ALLOC_AND_ALIGN_TYPE(*fh)) == NULL) { - apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; - return false; - } - fh->state = FHS_IDLE; + if (fh != NULL) { + field_hash_deinit(); + return false; + } + + if ((fh = app_mem_alloc(sizeof(*fh))) == NULL) { + apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; + return false; } + explicit_bzero(fh, sizeof(*fh)); + fh->state = FHS_IDLE; return true; } @@ -45,18 +49,16 @@ void field_hash_deinit(void) { * @param[in,out] data_length the value length * @return the data pointer */ -static const uint8_t *field_hash_prepare(const void *const field_ptr, +static const uint8_t *field_hash_prepare(const s_struct_712_field *field_ptr, const uint8_t *data, uint8_t *data_length) { - e_type field_type; cx_err_t error = CX_INTERNAL_ERROR; - field_type = struct_field_type(field_ptr); fh->remaining_size = __builtin_bswap16(*(uint16_t *) &data[0]); // network byte order data += sizeof(uint16_t); *data_length -= sizeof(uint16_t); fh->state = FHS_WAITING_FOR_MORE; - if (IS_DYN(field_type)) { + if (IS_DYN(field_ptr->type)) { CX_CHECK(cx_keccak_init_no_throw(&global_sha3, 256)); } return data; @@ -74,16 +76,14 @@ static const uint8_t *field_hash_prepare(const void *const field_ptr, * @param[in] data_length the value length * @return pointer to the encoded value */ -static const uint8_t *field_hash_finalize_static(const void *const field_ptr, +static const uint8_t *field_hash_finalize_static(const s_struct_712_field *field_ptr, const uint8_t *const data, uint8_t data_length) { uint8_t *value = NULL; - e_type field_type; - field_type = struct_field_type(field_ptr); - switch (field_type) { + switch (field_ptr->type) { case TYPE_SOL_INT: - value = encode_int(data, data_length, get_struct_field_typesize(field_ptr)); + value = encode_int(data, data_length, field_ptr->type_size); break; case TYPE_SOL_UINT: value = encode_uint(data, data_length); @@ -116,7 +116,7 @@ static uint8_t *field_hash_finalize_dynamic(void) { uint8_t *value; cx_err_t error = CX_INTERNAL_ERROR; - if ((value = mem_legacy_alloc(KECCAK256_HASH_BYTESIZE)) == NULL) { + if ((value = app_mem_alloc(KECCAK256_HASH_BYTESIZE)) == NULL) { apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; return NULL; } @@ -138,7 +138,7 @@ static uint8_t *field_hash_finalize_dynamic(void) { * @param[in] field_type the struct field's type * @param[in] hash the field hash */ -static void field_hash_feed_parent(e_type field_type, const uint8_t *const hash) { +static void field_hash_feed_parent(e_type field_type, const uint8_t *hash) { uint8_t len; if (IS_DYN(field_type)) { @@ -149,11 +149,11 @@ static void field_hash_feed_parent(e_type field_type, const uint8_t *const hash) // last thing in mem is the hash of the previous field // and just before it is the current hash context - cx_sha3_t *hash_ctx = (cx_sha3_t *) (hash - sizeof(cx_sha3_t)); + cx_sha3_t *hash_ctx = get_last_hash_ctx(); // continue the progressive hash on it hash_nbytes(hash, len, (cx_hash_t *) hash_ctx); // deallocate it - mem_legacy_dealloc(len); + app_mem_free((void *) hash); } /** @@ -166,17 +166,16 @@ static void field_hash_feed_parent(e_type field_type, const uint8_t *const hash) * @param[in] data_length the value length * @return whether an error occurred or not */ -static bool field_hash_domain_special_fields(const void *const field_ptr, +static bool field_hash_domain_special_fields(const s_struct_712_field *field_ptr, const uint8_t *const data, uint8_t data_length) { const char *key; - uint8_t keylen; const char *ethermint_vc = "cosmos"; - key = get_struct_field_keyname(field_ptr, &keylen); + key = field_ptr->key_name; // copy contract address into context - if (strncmp(key, "verifyingContract", keylen) == 0) { - switch (struct_field_type(field_ptr)) { + if (strncmp(key, "verifyingContract", strlen(key)) == 0) { + switch (field_ptr->type) { case TYPE_SOL_ADDRESS: if (data_length > sizeof(eip712_context->contract_addr)) { apdu_response_code = APDU_RESPONSE_INVALID_DATA; @@ -195,14 +194,13 @@ static bool field_hash_domain_special_fields(const void *const field_ptr, break; default: apdu_response_code = APDU_RESPONSE_INVALID_DATA; - PRINTF("Error: unexpected type for verifyingContract (%u)!\n", - struct_field_type(field_ptr)); + PRINTF("Error: unexpected type for verifyingContract (%u)!\n", field_ptr->type); return false; } memcpy(eip712_context->contract_addr, data, data_length); explicit_bzero(&eip712_context->contract_addr[data_length], sizeof(eip712_context->contract_addr) - data_length); - } else if (strncmp(key, "chainId", keylen) == 0) { + } else if (strncmp(key, "chainId", strlen(key)) == 0) { eip712_context->chain_id = u64_from_BE(data, data_length); } return true; @@ -216,14 +214,12 @@ static bool field_hash_domain_special_fields(const void *const field_ptr, * @param[in] data_length the value length * @return whether an error occurred or not */ -static bool field_hash_finalize(const void *const field_ptr, +static bool field_hash_finalize(const s_struct_712_field *field_ptr, const uint8_t *const data, uint8_t data_length) { const uint8_t *value = NULL; - e_type field_type; - field_type = struct_field_type(field_ptr); - if (!IS_DYN(field_type)) { + if (!IS_DYN(field_ptr->type)) { if ((value = field_hash_finalize_static(field_ptr, data, data_length)) == NULL) { return false; } @@ -233,7 +229,7 @@ static bool field_hash_finalize(const void *const field_ptr, } } - field_hash_feed_parent(field_type, value); + field_hash_feed_parent(field_ptr->type, value); if (path_get_root_type() == ROOT_DOMAIN) { if (field_hash_domain_special_fields(field_ptr, data, data_length) == false) { @@ -255,8 +251,7 @@ static bool field_hash_finalize(const void *const field_ptr, * @return whether the data hashing was successful or not */ bool field_hash(const uint8_t *data, uint8_t data_length, bool partial) { - const void *field_ptr; - e_type field_type; + const s_struct_712_field *field_ptr; bool first = fh->state == FHS_IDLE; if ((fh == NULL) || ((field_ptr = path_get_field()) == NULL)) { @@ -264,7 +259,6 @@ bool field_hash(const uint8_t *data, uint8_t data_length, bool partial) { return false; } - field_type = struct_field_type(field_ptr); // first packet for this frame if (first) { if (!ui_712_show_raw_key(field_ptr)) { @@ -283,7 +277,7 @@ bool field_hash(const uint8_t *data, uint8_t data_length, bool partial) { } fh->remaining_size -= data_length; // if a dynamic type -> continue progressive hash - if (IS_DYN(field_type)) { + if (IS_DYN(field_ptr->type)) { hash_nbytes(data, data_length, (cx_hash_t *) &global_sha3); } if (!ui_712_feed_to_display(field_ptr, data, data_length, first, fh->remaining_size == 0)) { @@ -299,7 +293,7 @@ bool field_hash(const uint8_t *data, uint8_t data_length, bool partial) { return false; } } else { - if (!partial || !IS_DYN(field_type)) // only makes sense if marked as partial + if (!partial || !IS_DYN(field_ptr->type)) // only makes sense if marked as partial { apdu_response_code = APDU_RESPONSE_INVALID_DATA; return false; diff --git a/src_features/signMessageEIP712/filtering.c b/src_features/signMessageEIP712/filtering.c index b65727286a..16bd0e1954 100644 --- a/src_features/signMessageEIP712/filtering.c +++ b/src_features/signMessageEIP712/filtering.c @@ -30,14 +30,16 @@ * @param[out] path_crc pointer to the CRC of the filter path */ static void hash_filtering_path(cx_hash_t *hash_ctx, bool discarded, uint32_t *path_crc) { - const void *field_ptr; + const s_struct_712_field *field_ptr; const char *key; - uint8_t key_len; + const char *path; + uint8_t path_len; if (discarded) { - key = ui_712_get_discarded_path(&key_len); - hash_nbytes((uint8_t *) key, key_len, hash_ctx); - *path_crc = cx_crc32_update(*path_crc, key, key_len); + path = ui_712_get_discarded_path(); + path_len = strlen(path); + hash_nbytes((uint8_t *) path, path_len, hash_ctx); + *path_crc = cx_crc32_update(*path_crc, path, path_len); } else { for (uint8_t i = 0; i < path_get_depth_count(); ++i) { if (i > 0) { @@ -45,17 +47,14 @@ static void hash_filtering_path(cx_hash_t *hash_ctx, bool discarded, uint32_t *p *path_crc = cx_crc32_update(*path_crc, ".", 1); } if ((field_ptr = path_get_nth_field(i + 1)) != NULL) { - if ((key = get_struct_field_keyname(field_ptr, &key_len)) != NULL) { + if ((key = field_ptr->key_name) != NULL) { // field name - hash_nbytes((uint8_t *) key, key_len, hash_ctx); - *path_crc = cx_crc32_update(*path_crc, key, key_len); + hash_nbytes((uint8_t *) key, strlen(key), hash_ctx); + *path_crc = cx_crc32_update(*path_crc, key, strlen(key)); // array levels - if (struct_field_is_array(field_ptr)) { - uint8_t lvl_count; - - get_struct_field_array_lvls_array(field_ptr, &lvl_count); - for (int j = 0; j < lvl_count; ++j) { + if (field_ptr->type_is_array) { + for (int j = 0; j < field_ptr->array_level_count; ++j) { hash_nbytes((uint8_t *) ".[]", 3, hash_ctx); *path_crc = cx_crc32_update(*path_crc, ".[]", 3); } @@ -65,7 +64,7 @@ static void hash_filtering_path(cx_hash_t *hash_ctx, bool discarded, uint32_t *p } } // so it is only usable for the following filter - ui_712_set_discarded_path("", 0); + ui_712_clear_discarded_path(); } /** @@ -159,7 +158,8 @@ static bool check_typename(const char *expected) { uint8_t typename_len = 0; const char *typename; - typename = get_struct_field_typename(path_get_field(), &typename_len); + typename = get_struct_field_typename(path_get_field()); + typename_len = strlen(typename); if ((typename_len != strlen(expected)) || (strncmp(typename, expected, typename_len) != 0)) { PRINTF("Error: expected field of type \"%s\" but got \"", expected); for (int i = 0; i < typename_len; ++i) PRINTF("%c", typename[i]); @@ -248,11 +248,9 @@ bool filtering_message_info(const uint8_t *payload, uint8_t length) { * @return whether a match was found or not */ static bool matches_backup_path(const char *path, uint8_t path_len, uint8_t *offset_ptr) { - const void *field_ptr; + const s_struct_712_field *field_ptr; const char *key; - uint8_t key_len; uint8_t offset = 0; - uint8_t lvl_count; for (uint8_t i = 0; i < path_backup_get_depth_count(); ++i) { if (i > 0) { @@ -262,17 +260,17 @@ static bool matches_backup_path(const char *path, uint8_t path_len, uint8_t *off offset += 1; } if ((field_ptr = path_backup_get_nth_field(i + 1)) != NULL) { - if ((key = get_struct_field_keyname(field_ptr, &key_len)) != NULL) { + if ((key = field_ptr->key_name) != NULL) { // field name - if (((offset + key_len) > path_len) || (memcmp(path + offset, key, key_len) != 0)) { + if (((offset + strlen(key)) > path_len) || + (memcmp(path + offset, key, strlen(key)) != 0)) { return false; } - offset += key_len; + offset += strlen(key); // array levels - if (struct_field_is_array(field_ptr)) { - get_struct_field_array_lvls_array(field_ptr, &lvl_count); - for (int j = 0; j < lvl_count; ++j) { + if (field_ptr->type_is_array) { + for (int j = 0; j < field_ptr->array_level_count; ++j) { if (((offset + 3) > path_len) || (memcmp(path + offset, ".[]", 3) != 0)) { return false; } @@ -646,14 +644,15 @@ bool filtering_amount_join_value(const uint8_t *payload, token_idx = (uint8_t) resolved_idx; // simulate as if we had received a token-join addr ui_712_token_join_prepare_addr_check(token_idx); - amount_join_set_token_received(); + if (!amount_join_set_token_received()) { + return false; + } } if (!check_typename("uint") || !check_token_index(token_idx)) { return false; } ui_712_flag_field(false, false, true, false, false); - ui_712_token_join_prepare_amount(token_idx, name, name_len); - return true; + return ui_712_token_join_prepare_amount(token_idx, name, name_len); } /** diff --git a/src_features/signMessageEIP712/format_hash_field_type.c b/src_features/signMessageEIP712/format_hash_field_type.c index bbc50a2a7c..15db3f6461 100644 --- a/src_features/signMessageEIP712/format_hash_field_type.c +++ b/src_features/signMessageEIP712/format_hash_field_type.c @@ -13,13 +13,12 @@ * @param[in] hash_ctx pointer to the hashing context * @return whether the formatting & hashing were successful or not */ -static bool format_hash_field_type_size(const void *const field_ptr, cx_hash_t *hash_ctx) { +static bool format_hash_field_type_size(const s_struct_712_field *field_ptr, cx_hash_t *hash_ctx) { uint16_t field_size; - char *uint_str_ptr; - uint8_t uint_str_len; + const char *uint_str_ptr; - field_size = get_struct_field_typesize(field_ptr); - switch (struct_field_type(field_ptr)) { + field_size = field_ptr->type_size; + switch (field_ptr->type) { case TYPE_SOL_INT: case TYPE_SOL_UINT: field_size *= 8; // bytes -> bits @@ -31,13 +30,13 @@ static bool format_hash_field_type_size(const void *const field_ptr, cx_hash_t * apdu_response_code = APDU_RESPONSE_INVALID_DATA; return false; } - uint_str_ptr = mem_legacy_alloc_and_format_uint(field_size, &uint_str_len); + uint_str_ptr = mem_alloc_and_format_uint(field_size); if (uint_str_ptr == NULL) { apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; return false; } - hash_nbytes((uint8_t *) uint_str_ptr, uint_str_len, hash_ctx); - mem_legacy_dealloc(uint_str_len); + hash_nbytes((uint8_t *) uint_str_ptr, strlen(uint_str_ptr), hash_ctx); + app_mem_free((void *) uint_str_ptr); return true; } @@ -48,28 +47,24 @@ static bool format_hash_field_type_size(const void *const field_ptr, cx_hash_t * * @param[in] hash_ctx pointer to the hashing context * @return whether the formatting & hashing were successful or not */ -static bool format_hash_field_type_array_levels(const void *const field_ptr, cx_hash_t *hash_ctx) { - uint8_t array_size; - char *uint_str_ptr; - uint8_t uint_str_len; - const void *lvl_ptr; - uint8_t lvls_count; +static bool format_hash_field_type_array_levels(const s_struct_712_field *field_ptr, + cx_hash_t *hash_ctx) { + const char *uint_str_ptr; - lvl_ptr = get_struct_field_array_lvls_array(field_ptr, &lvls_count); - while (lvls_count-- > 0) { + for (int i = 0; i < field_ptr->array_level_count; ++i) { hash_byte('[', hash_ctx); - switch (struct_field_array_depth(lvl_ptr, &array_size)) { + switch (field_ptr->array_levels[i].type) { case ARRAY_DYNAMIC: break; case ARRAY_FIXED_SIZE: - if ((uint_str_ptr = mem_legacy_alloc_and_format_uint(array_size, &uint_str_len)) == + if ((uint_str_ptr = mem_alloc_and_format_uint(field_ptr->array_levels[i].size)) == NULL) { apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; return false; } - hash_nbytes((uint8_t *) uint_str_ptr, uint_str_len, hash_ctx); - mem_legacy_dealloc(uint_str_len); + hash_nbytes((uint8_t *) uint_str_ptr, strlen(uint_str_ptr), hash_ctx); + app_mem_free((void *) uint_str_ptr); break; default: // should not be in here :^) @@ -77,7 +72,6 @@ static bool format_hash_field_type_array_levels(const void *const field_ptr, cx_ return false; } hash_byte(']', hash_ctx); - lvl_ptr = get_next_struct_field_array_lvl(lvl_ptr); } return true; } @@ -89,23 +83,22 @@ static bool format_hash_field_type_array_levels(const void *const field_ptr, cx_ * @param[in] hash_ctx pointer to the hashing context * @return whether the formatting & hashing were successful or not */ -bool format_hash_field_type(const void *const field_ptr, cx_hash_t *hash_ctx) { +bool format_hash_field_type(const s_struct_712_field *field_ptr, cx_hash_t *hash_ctx) { const char *name; - uint8_t length; // field type name - name = get_struct_field_typename(field_ptr, &length); - hash_nbytes((uint8_t *) name, length, hash_ctx); + name = get_struct_field_typename(field_ptr); + hash_nbytes((uint8_t *) name, strlen(name), hash_ctx); // field type size - if (struct_field_has_typesize(field_ptr)) { + if (field_ptr->type_has_size) { if (!format_hash_field_type_size(field_ptr, hash_ctx)) { return false; } } // field type array levels - if (struct_field_is_array(field_ptr)) { + if (field_ptr->type_is_array) { if (!format_hash_field_type_array_levels(field_ptr, hash_ctx)) { return false; } diff --git a/src_features/signMessageEIP712/format_hash_field_type.h b/src_features/signMessageEIP712/format_hash_field_type.h index d4b12b5124..cfc7253af8 100644 --- a/src_features/signMessageEIP712/format_hash_field_type.h +++ b/src_features/signMessageEIP712/format_hash_field_type.h @@ -1,5 +1,6 @@ #pragma once #include "cx.h" +#include "typed_data.h" -bool format_hash_field_type(const void *const field_ptr, cx_hash_t *hash_ctx); +bool format_hash_field_type(const s_struct_712_field *field_ptr, cx_hash_t *hash_ctx); diff --git a/src_features/signMessageEIP712/path.c b/src_features/signMessageEIP712/path.c index 6a81f12d36..a3470d21e3 100644 --- a/src_features/signMessageEIP712/path.c +++ b/src_features/signMessageEIP712/path.c @@ -7,10 +7,18 @@ #include "mem_utils.h" #include "apdu_constants.h" // APDU response codes #include "typed_data.h" +#include "list.h" static s_path *path_struct = NULL; static s_path *path_backup = NULL; +typedef struct { + s_flist_node _list; + cx_sha3_t hash; +} s_hash_ctx; + +static s_hash_ctx *g_hash_ctxs = NULL; + /** * Get the field pointer to by the first N depths of the given path * @@ -20,11 +28,9 @@ static s_path *path_backup = NULL; * @return the field which the first Nth depths points to */ static const void *get_nth_field_from(const s_path *path, uint8_t *fields_count_ptr, uint8_t n) { - const void *struct_ptr = NULL; - const void *field_ptr = NULL; + const s_struct_712 *struct_ptr = NULL; + const s_struct_712_field *field_ptr = NULL; const char *typename; - uint8_t length; - uint8_t fields_count; if (path == NULL) { return NULL; @@ -37,22 +43,25 @@ static const void *get_nth_field_from(const s_path *path, uint8_t *fields_count_ return NULL; } for (uint8_t depth = 0; depth < n; ++depth) { - field_ptr = get_struct_fields_array(struct_ptr, &fields_count); - - if (fields_count_ptr != NULL) { - *fields_count_ptr = fields_count; - } - // check if the index at this depth makes sense - if (path->depths[depth] > fields_count) { + if ((field_ptr = struct_ptr->fields) == NULL) { return NULL; } + if (fields_count_ptr != NULL) { + *fields_count_ptr = 0; + for (const s_struct_712_field *tmp = field_ptr; tmp != NULL; + tmp = (s_struct_712_field *) ((s_flist_node *) tmp)->next) { + *fields_count_ptr += 1; + } + } for (uint8_t index = 0; index < path->depths[depth]; ++index) { - field_ptr = get_next_struct_field(field_ptr); + if ((field_ptr = (s_struct_712_field *) ((s_flist_node *) field_ptr)->next) == NULL) { + return NULL; + } } - if (struct_field_type(field_ptr) == TYPE_CUSTOM) { - typename = get_struct_field_typename(field_ptr, &length); - if ((struct_ptr = get_structn(typename, length)) == NULL) { + if (field_ptr->type == TYPE_CUSTOM) { + typename = get_struct_field_typename(field_ptr); + if ((struct_ptr = get_structn(typename, strlen(typename))) == NULL) { return NULL; } } @@ -96,14 +105,13 @@ const void *path_backup_get_nth_field(uint8_t n) { */ const void *path_get_nth_field_to_last(uint8_t n) { const char *typename; - uint8_t typename_len; const void *field_ptr; const void *struct_ptr = NULL; field_ptr = get_nth_field(NULL, path_struct->depth_count - n); if (field_ptr != NULL) { - typename = get_struct_field_typename(field_ptr, &typename_len); - struct_ptr = get_structn(typename, typename_len); + typename = get_struct_field_typename(field_ptr); + struct_ptr = get_structn(typename, strlen(typename)); } return struct_ptr; } @@ -139,8 +147,17 @@ static bool path_depth_list_push(void) { * * @return pointer to the hashing context */ -static cx_sha3_t *get_last_hash_ctx(void) { - return ((cx_sha3_t *) mem_legacy_alloc(0)) - 1; +cx_sha3_t *get_last_hash_ctx(void) { + s_flist_node *hash_ctx = (s_flist_node *) g_hash_ctxs; + + if (hash_ctx == NULL) return NULL; + for (; hash_ctx->next != NULL; hash_ctx = hash_ctx->next) + ; + return &((s_hash_ctx *) hash_ctx)->hash; +} + +static void remove_last_hash_ctx(void) { + flist_pop_back((s_flist_node **) &g_hash_ctxs, NULL); } /** @@ -159,7 +176,7 @@ static bool finalize_hash_depth(uint8_t *hash) { // finalize hash CX_CHECK( cx_hash_no_throw((cx_hash_t *) hash_ctx, CX_LAST, NULL, 0, hash, KECCAK256_HASH_BYTESIZE)); - mem_legacy_dealloc(sizeof(*hash_ctx)); // remove hash context + remove_last_hash_ctx(); return hashed_bytes > 0; end: return false; @@ -189,16 +206,19 @@ static bool feed_last_hash_depth(const uint8_t *const hash) { * @return whether the memory allocation of the hashing context was successful */ static bool push_new_hash_depth(bool init) { - cx_sha3_t *hash_ctx; + s_hash_ctx *hash_ctx; cx_err_t error = CX_INTERNAL_ERROR; // allocate new hash context - if ((hash_ctx = MEM_ALLOC_AND_ALIGN_TYPE(*hash_ctx)) == NULL) { + if ((hash_ctx = app_mem_alloc(sizeof((*hash_ctx)))) == NULL) { return false; } + explicit_bzero(hash_ctx, sizeof(*hash_ctx)); if (init) { - CX_CHECK(cx_keccak_init_no_throw(hash_ctx, 256)); + CX_CHECK(cx_keccak_init_no_throw(&hash_ctx->hash, 256)); } + + flist_push_back((s_flist_node **) &g_hash_ctxs, (s_flist_node *) hash_ctx); return true; end: return false; @@ -305,12 +325,10 @@ static bool array_depth_list_pop(void) { * @return whether the path update worked or not */ static bool path_update(bool skip_if_array, bool stop_at_array, bool do_typehash) { - uint8_t fields_count; - const void *struct_ptr; - const void *starting_field_ptr; - const void *field_ptr; + const s_struct_712 *struct_ptr; + const s_struct_712_field *starting_field_ptr; + const s_struct_712_field *field_ptr; const char *typename; - uint8_t typename_len; uint8_t hash[KECCAK256_HASH_BYTESIZE]; if (path_struct == NULL) { @@ -320,21 +338,21 @@ static bool path_update(bool skip_if_array, bool stop_at_array, bool do_typehash return false; } field_ptr = starting_field_ptr; - while (struct_field_type(field_ptr) == TYPE_CUSTOM) { + while (field_ptr->type == TYPE_CUSTOM) { // check if we meet one of the given conditions if (((field_ptr == starting_field_ptr) && skip_if_array) || ((field_ptr != starting_field_ptr) && stop_at_array)) { // only if it is the first iteration of that array depth if ((path_struct->array_depths[path_struct->array_depth_count - 1].index == 0) && - struct_field_is_array(field_ptr)) { + field_ptr->type_is_array) { break; } } - typename = get_struct_field_typename(field_ptr, &typename_len); - if ((struct_ptr = get_structn(typename, typename_len)) == NULL) { + typename = get_struct_field_typename(field_ptr); + if ((struct_ptr = get_structn(typename, strlen(typename))) == NULL) { return false; } - if ((field_ptr = get_struct_fields_array(struct_ptr, &fields_count)) == NULL) { + if ((field_ptr = struct_ptr->fields) == NULL) { return false; } @@ -344,7 +362,7 @@ static bool path_update(bool skip_if_array, bool stop_at_array, bool do_typehash if (do_typehash) { // get the struct typehash - if (type_hash(typename, typename_len, hash) == false) { + if (type_hash(typename, strlen(typename), hash) == false) { return false; } if (feed_last_hash_depth(hash) == false) { @@ -430,25 +448,17 @@ bool path_set_root(const char *const struct_name, uint8_t name_length) { * @param[in] size requested array depth size * @return whether the checks and add were successful or not */ -static bool check_and_add_array_depth(const void *depth, +static bool check_and_add_array_depth(s_struct_712_field_array_level *array_lvl, uint8_t total_count, uint8_t pidx, uint8_t size) { - uint8_t expected_size; uint8_t arr_idx; - e_array_type expected_type; arr_idx = (total_count - path_struct->array_depth_count) - 1; - // we skip index 0, since we already have it - for (uint8_t idx = 1; idx < (arr_idx + 1); ++idx) { - if ((depth = get_next_struct_field_array_lvl(depth)) == NULL) { - return false; - } - } - expected_type = struct_field_array_depth(depth, &expected_size); - if ((expected_type == ARRAY_FIXED_SIZE) && (expected_size != size)) { + array_lvl += arr_idx; + if ((array_lvl->type == ARRAY_FIXED_SIZE) && (array_lvl->size != size)) { apdu_response_code = APDU_RESPONSE_INVALID_DATA; - PRINTF("Unexpected array depth size. (expected %d, got %d)\n", expected_size, size); + PRINTF("Unexpected array depth size. (expected %d, got %d)\n", array_lvl->size, size); return false; } // add it @@ -464,7 +474,7 @@ static bool check_and_add_array_depth(const void *depth, * Used for the handling of discarded filtered fields */ static void backup_path(void) { - const void *field_ptr; + const s_struct_712_field *field_ptr; memcpy(path_backup, path_struct, sizeof(*path_backup)); // decrease while it does not point to an array type @@ -472,7 +482,7 @@ static void backup_path(void) { if ((field_ptr = path_backup_get_nth_field(path_backup->depth_count)) == NULL) { return; } - if (struct_field_is_array(field_ptr)) { + if (field_ptr->type_is_array) { break; } path_backup->depth_count -= 1; @@ -486,10 +496,8 @@ static void backup_path(void) { * @param[in] length length of data * @return whether the add was successful or not */ -bool path_new_array_depth(const uint8_t *const data, uint8_t length) { - const void *field_ptr = NULL; - const void *depth = NULL; - uint8_t depth_count; +bool path_new_array_depth(const uint8_t *data, uint8_t length) { + const s_struct_712_field *field_ptr = NULL; uint8_t total_count = 0; uint8_t pidx; bool is_custom; @@ -518,14 +526,17 @@ bool path_new_array_depth(const uint8_t *const data, uint8_t length) { apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED; return false; } - if (struct_field_is_array(field_ptr)) { - if ((depth = get_struct_field_array_lvls_array(field_ptr, &depth_count)) == NULL) { + if (field_ptr->type_is_array) { + if (field_ptr->array_levels == NULL) { apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED; return false; } - total_count += depth_count; + total_count += field_ptr->array_level_count; if (total_count > path_struct->array_depth_count) { - if (!check_and_add_array_depth(depth, total_count, pidx, array_size)) { + if (!check_and_add_array_depth(field_ptr->array_levels, + total_count, + pidx, + array_size)) { return false; } break; @@ -538,13 +549,21 @@ bool path_new_array_depth(const uint8_t *const data, uint8_t length) { PRINTF("Did not find a matching array type.\n"); return false; } - is_custom = struct_field_type(field_ptr) == TYPE_CUSTOM; + is_custom = field_ptr->type == TYPE_CUSTOM; if (push_new_hash_depth(!is_custom) == false) { return false; } if (is_custom) { cx_sha3_t *hash_ctx = get_last_hash_ctx(); - cx_sha3_t *old_ctx = hash_ctx - 1; + cx_sha3_t *old_ctx = NULL; + + // TODO: using a doubly-linked list would improve this + for (s_hash_ctx *tmp = g_hash_ctxs; &tmp->hash != hash_ctx; + tmp = (s_hash_ctx *) ((s_flist_node *) tmp)->next) { + old_ctx = &tmp->hash; + } + + if (old_ctx == NULL) return false; if (array_size > 0) { memcpy(hash_ctx, old_ctx, sizeof(*old_ctx)); @@ -703,13 +722,10 @@ uint8_t path_backup_get_depth_count(void) { bool path_exists_in_backup(const char *path, size_t length) { size_t offset = 0; size_t i; - const void *field_ptr; + const s_struct_712_field *field_ptr; const char *typename; - uint8_t typename_len; - const void *struct_ptr; - uint8_t fields_count; + const s_struct_712 *struct_ptr; const char *key; - uint8_t key_len; field_ptr = get_nth_field_from(path_backup, NULL, path_backup->depth_count); while (offset < length) { @@ -718,27 +734,25 @@ bool path_exists_in_backup(const char *path, size_t length) { } offset += 1; if (((offset + 2) <= length) && (memcmp(path + offset, "[]", 2) == 0)) { - if (!struct_field_is_array(field_ptr)) { + if (!field_ptr->type_is_array) { return false; } offset += 2; } else if (offset < length) { for (i = 0; ((offset + i) < length) && (path[offset + i] != '.'); ++i) ; - typename = get_struct_field_custom_typename(field_ptr, &typename_len); - if ((struct_ptr = get_structn(typename, typename_len)) == NULL) { + typename = field_ptr->type_name; + if ((struct_ptr = get_structn(typename, strlen(typename))) == NULL) { return false; } - field_ptr = get_struct_fields_array(struct_ptr, &fields_count); - while (fields_count > 0) { - key = get_struct_field_keyname(field_ptr, &key_len); - if ((key_len == i) && (memcmp(key, path + offset, i) == 0)) { + for (field_ptr = struct_ptr->fields; field_ptr != NULL; + field_ptr = (s_struct_712_field *) ((s_flist_node *) field_ptr)->next) { + key = field_ptr->key_name; + if ((strlen(key) == i) && (memcmp(key, path + offset, i) == 0)) { break; } - field_ptr = get_next_struct_field(field_ptr); - fields_count -= 1; } - if (fields_count == 0) { + if (field_ptr == NULL) { return false; } offset += i; @@ -755,14 +769,17 @@ bool path_exists_in_backup(const char *path, size_t length) { * @return whether the memory allocation were successful. */ bool path_init(void) { - if (path_struct == NULL) { - if (((path_struct = MEM_ALLOC_AND_ALIGN_TYPE(*path_struct)) == NULL) || - ((path_backup = MEM_ALLOC_AND_ALIGN_TYPE(*path_backup)) == NULL)) { - apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; - } else { - explicit_bzero(path_struct, sizeof(*path_struct)); - explicit_bzero(path_backup, sizeof(*path_backup)); - } + if (path_struct != NULL) { + path_deinit(); + return false; + } + + if (((path_struct = app_mem_alloc(sizeof(*path_struct))) == NULL) || + ((path_backup = app_mem_alloc(sizeof(*path_backup))) == NULL)) { + apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; + } else { + explicit_bzero(path_struct, sizeof(*path_struct)); + explicit_bzero(path_backup, sizeof(*path_backup)); } return (path_struct != NULL) && (path_backup != NULL); } diff --git a/src_features/signMessageEIP712/path.h b/src_features/signMessageEIP712/path.h index f675b62838..fa6df60dff 100644 --- a/src_features/signMessageEIP712/path.h +++ b/src_features/signMessageEIP712/path.h @@ -2,6 +2,7 @@ #include #include +#include "cx.h" #define MAX_PATH_DEPTH 16 #define MAX_ARRAY_DEPTH 8 @@ -28,7 +29,7 @@ const void *path_get_field(void); bool path_advance(bool do_typehash); bool path_init(void); void path_deinit(void); -bool path_new_array_depth(const uint8_t *const data, uint8_t length); +bool path_new_array_depth(const uint8_t *data, uint8_t length); e_root_type path_get_root_type(void); const void *path_get_root(void); const void *path_get_nth_field(uint8_t n); @@ -37,3 +38,4 @@ bool path_exists_in_backup(const char *path, size_t length); const void *path_get_nth_field_to_last(uint8_t n); uint8_t path_get_depth_count(void); uint8_t path_backup_get_depth_count(void); +cx_sha3_t *get_last_hash_ctx(void); diff --git a/src_features/signMessageEIP712/schema_hash.c b/src_features/signMessageEIP712/schema_hash.c index 06ab84dce4..a47e7e4ad7 100644 --- a/src_features/signMessageEIP712/schema_hash.c +++ b/src_features/signMessageEIP712/schema_hash.c @@ -18,44 +18,42 @@ typedef cx_sha256_t cx_sha224_t; * @return whether the schema hash was successful or not */ bool compute_schema_hash(void) { - const void *struct_ptr; - uint8_t structs_count; - const void *field_ptr; - uint8_t fields_count; - const char *name; - uint8_t name_length; + const s_struct_712 *struct_ptr; + const s_struct_712_field *field_ptr; cx_sha224_t hash_ctx; cx_err_t error = CX_INTERNAL_ERROR; cx_sha224_init(&hash_ctx); - struct_ptr = get_structs_array(&structs_count); + struct_ptr = get_struct_list(); hash_byte('{', (cx_hash_t *) &hash_ctx); - while (structs_count-- > 0) { - name = get_struct_name(struct_ptr, &name_length); + while (struct_ptr != NULL) { hash_byte('"', (cx_hash_t *) &hash_ctx); - hash_nbytes((uint8_t *) name, name_length, (cx_hash_t *) &hash_ctx); + hash_nbytes((uint8_t *) struct_ptr->name, + strlen(struct_ptr->name), + (cx_hash_t *) &hash_ctx); hash_nbytes((uint8_t *) "\":[", 3, (cx_hash_t *) &hash_ctx); - field_ptr = get_struct_fields_array(struct_ptr, &fields_count); - while (fields_count-- > 0) { + field_ptr = struct_ptr->fields; + while (field_ptr != NULL) { hash_nbytes((uint8_t *) "{\"name\":\"", 9, (cx_hash_t *) &hash_ctx); - name = get_struct_field_keyname(field_ptr, &name_length); - hash_nbytes((uint8_t *) name, name_length, (cx_hash_t *) &hash_ctx); + hash_nbytes((uint8_t *) field_ptr->key_name, + strlen(field_ptr->key_name), + (cx_hash_t *) &hash_ctx); hash_nbytes((uint8_t *) "\",\"type\":\"", 10, (cx_hash_t *) &hash_ctx); if (!format_hash_field_type(field_ptr, (cx_hash_t *) &hash_ctx)) { return false; } hash_nbytes((uint8_t *) "\"}", 2, (cx_hash_t *) &hash_ctx); - if (fields_count > 0) { + if (((s_flist_node *) field_ptr)->next != NULL) { hash_byte(',', (cx_hash_t *) &hash_ctx); } - field_ptr = get_next_struct_field(field_ptr); + field_ptr = (s_struct_712_field *) ((s_flist_node *) field_ptr)->next; } hash_byte(']', (cx_hash_t *) &hash_ctx); - if (structs_count > 0) { + if (((s_flist_node *) struct_ptr)->next != NULL) { hash_byte(',', (cx_hash_t *) &hash_ctx); } - struct_ptr = get_next_struct(struct_ptr); + struct_ptr = (s_struct_712 *) ((s_flist_node *) struct_ptr)->next; } hash_byte('}', (cx_hash_t *) &hash_ctx); diff --git a/src_features/signMessageEIP712/sol_typenames.c b/src_features/signMessageEIP712/sol_typenames.c index 84de23145b..098354ad68 100644 --- a/src_features/signMessageEIP712/sol_typenames.c +++ b/src_features/signMessageEIP712/sol_typenames.c @@ -1,45 +1,17 @@ #include "sol_typenames.h" #include "mem.h" +#include "mem_utils.h" #include "os_pic.h" #include "apdu_constants.h" // APDU response codes #include "typed_data.h" #include "common_utils.h" // ARRAY_SIZE -// Bit indicating they are more types associated to this typename -#define TYPENAME_MORE_TYPE (1 << 7) +typedef struct { + char *name; + e_type value; +} s_sol_type; -static uint8_t *sol_typenames = NULL; - -enum { IDX_ENUM = 0, IDX_STR_IDX, IDX_COUNT }; - -/** - * Find a match between a typename index and all the type enums associated to it - * - * @param[in] enum_to_idx the type enum to typename index table - * @param[in] t_idx typename index - * @return whether at least one match was found - */ -static bool find_enum_matches(const uint8_t enum_to_idx[TYPES_COUNT - 1][IDX_COUNT], - uint8_t t_idx) { - uint8_t *enum_match = NULL; - - // loop over enum/typename pairs - for (uint8_t e_idx = 0; e_idx < (TYPES_COUNT - 1); ++e_idx) { - if (t_idx == enum_to_idx[e_idx][IDX_STR_IDX]) // match - { - if (enum_match != NULL) // in case of a previous match, mark it - { - *enum_match |= TYPENAME_MORE_TYPE; - } - if ((enum_match = mem_legacy_alloc(sizeof(uint8_t))) == NULL) { - apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; - return false; - } - *enum_match = enum_to_idx[e_idx][IDX_ENUM]; - } - } - return (enum_match != NULL); -} +static s_sol_type *g_sol_types = NULL; /** * Initialize solidity typenames in memory @@ -47,49 +19,46 @@ static bool find_enum_matches(const uint8_t enum_to_idx[TYPES_COUNT - 1][IDX_COU * @return whether the initialization went well or not */ bool sol_typenames_init(void) { - const char *const typenames[] = { - "int", // 0 - "uint", // 1 - "address", // 2 - "bool", // 3 - "string", // 4 - "bytes" // 5 - }; - // \ref TYPES_COUNT - 1 since we don't include \ref TYPE_CUSTOM - const uint8_t enum_to_idx[TYPES_COUNT - 1][IDX_COUNT] = {{TYPE_SOL_INT, 0}, - {TYPE_SOL_UINT, 1}, - {TYPE_SOL_ADDRESS, 2}, - {TYPE_SOL_BOOL, 3}, - {TYPE_SOL_STRING, 4}, - {TYPE_SOL_BYTES_FIX, 5}, - {TYPE_SOL_BYTES_DYN, 5}}; - uint8_t *typename_len_ptr; - char *typename_ptr; + uint8_t count = TYPES_COUNT - 1; // because 0 is custom (so not solidity) - if ((sol_typenames = mem_legacy_alloc(sizeof(uint8_t))) == NULL) { + if (g_sol_types != NULL) { + g_sol_types = NULL; return false; } - *(sol_typenames) = 0; - // loop over typenames - for (uint8_t t_idx = 0; t_idx < ARRAY_SIZE(typenames); ++t_idx) { - // if at least one match was found - if (find_enum_matches(enum_to_idx, t_idx)) { - if ((typename_len_ptr = mem_legacy_alloc(sizeof(uint8_t))) == NULL) { - apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; - return false; - } - // get pointer to the allocated space just above - *typename_len_ptr = strlen(PIC(typenames[t_idx])); - - if ((typename_ptr = mem_legacy_alloc(sizeof(char) * *typename_len_ptr)) == NULL) { - apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; + if ((g_sol_types = app_mem_alloc(sizeof(*g_sol_types) * count)) == NULL) { + apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; + return false; + } + for (int i = 0; i < count; ++i) { + g_sol_types[i].value = i + 1; + switch (g_sol_types[i].value) { + case TYPE_SOL_INT: + g_sol_types[i].name = app_mem_strdup("int"); + break; + case TYPE_SOL_UINT: + g_sol_types[i].name = app_mem_strdup("uint"); + break; + case TYPE_SOL_ADDRESS: + g_sol_types[i].name = app_mem_strdup("address"); + break; + case TYPE_SOL_BOOL: + g_sol_types[i].name = app_mem_strdup("bool"); + break; + case TYPE_SOL_STRING: + g_sol_types[i].name = app_mem_strdup("string"); + break; + case TYPE_SOL_BYTES_FIX: + case TYPE_SOL_BYTES_DYN: + g_sol_types[i].name = app_mem_strdup("bytes"); + break; + default: + apdu_response_code = APDU_RESPONSE_INVALID_DATA; return false; - } - // copy typename - memcpy(typename_ptr, PIC(typenames[t_idx]), *typename_len_ptr); } - // increment array size - *(sol_typenames) += 1; + if (g_sol_types[i].name == NULL) { + apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; + return false; + } } return true; } @@ -98,32 +67,13 @@ bool sol_typenames_init(void) { * Get typename from a given field * * @param[in] field_ptr pointer to a struct field - * @param[out] length length of the returned typename * @return typename or \ref NULL in case it wasn't found */ -const char *get_struct_field_sol_typename(const uint8_t *field_ptr, uint8_t *const length) { - e_type field_type; - const uint8_t *typename_ptr; - uint8_t typenames_count; - bool more_type; - bool typename_found; - - field_type = struct_field_type(field_ptr); - typename_ptr = get_array_in_mem(sol_typenames, &typenames_count); - typename_found = false; - while (typenames_count-- > 0) { - more_type = true; - while (more_type) { - more_type = *typename_ptr & TYPENAME_MORE_TYPE; - e_type type_enum = *typename_ptr & TYPENAME_ENUM; - if (type_enum == field_type) { - typename_found = true; - } - typename_ptr += 1; +const char *get_struct_field_sol_typename(const s_struct_712_field *field_ptr) { + for (int i = 0; i < (TYPES_COUNT - 1); ++i) { + if (field_ptr->type == g_sol_types[i].value) { + return g_sol_types[i].name; } - typename_ptr = (uint8_t *) get_string_in_mem(typename_ptr, length); - if (typename_found) return (char *) typename_ptr; - typename_ptr += *length; } apdu_response_code = APDU_RESPONSE_INVALID_DATA; return NULL; // Not found diff --git a/src_features/signMessageEIP712/sol_typenames.h b/src_features/signMessageEIP712/sol_typenames.h index 77d325154f..c5ad460d08 100644 --- a/src_features/signMessageEIP712/sol_typenames.h +++ b/src_features/signMessageEIP712/sol_typenames.h @@ -2,7 +2,7 @@ #include #include +#include "typed_data.h" bool sol_typenames_init(void); - -const char *get_struct_field_sol_typename(const uint8_t *ptr, uint8_t *const length); +const char *get_struct_field_sol_typename(const s_struct_712_field *field_ptr); diff --git a/src_features/signMessageEIP712/type_hash.c b/src_features/signMessageEIP712/type_hash.c index d46f1f1a5d..8268a97bf9 100644 --- a/src_features/signMessageEIP712/type_hash.c +++ b/src_features/signMessageEIP712/type_hash.c @@ -5,6 +5,7 @@ #include "hash_bytes.h" #include "apdu_constants.h" // APDU response codes #include "typed_data.h" +#include "list.h" /** * Encode & hash the given structure field @@ -12,9 +13,8 @@ * @param[in] field_ptr pointer to the struct field * @return \ref true it finished correctly, \ref false if it didn't (memory allocation) */ -static bool encode_and_hash_field(const void *const field_ptr) { +static bool encode_and_hash_field(const s_struct_712_field *field_ptr) { const char *name; - uint8_t length; if (!format_hash_field_type(field_ptr, (cx_hash_t *) &global_sha3)) { return false; @@ -23,8 +23,8 @@ static bool encode_and_hash_field(const void *const field_ptr) { hash_byte(' ', (cx_hash_t *) &global_sha3); // field name - name = get_struct_field_keyname(field_ptr, &length); - hash_nbytes((uint8_t *) name, length, (cx_hash_t *) &global_sha3); + name = field_ptr->key_name; + hash_nbytes((uint8_t *) name, strlen(name), (cx_hash_t *) &global_sha3); return true; } @@ -35,31 +35,27 @@ static bool encode_and_hash_field(const void *const field_ptr) { * @param[in] str_length length of the formatted string in memory * @return pointer of the string in memory, \ref NULL in case of an error */ -static bool encode_and_hash_type(const void *const struct_ptr) { +static bool encode_and_hash_type(const s_struct_712 *struct_ptr) { const char *struct_name; - uint8_t struct_name_length; - const uint8_t *field_ptr; - uint8_t fields_count; + const s_struct_712_field *field_ptr; // struct name - struct_name = get_struct_name(struct_ptr, &struct_name_length); - hash_nbytes((uint8_t *) struct_name, struct_name_length, (cx_hash_t *) &global_sha3); + struct_name = struct_ptr->name; + hash_nbytes((uint8_t *) struct_name, strlen(struct_name), (cx_hash_t *) &global_sha3); // opening struct parentheses hash_byte('(', (cx_hash_t *) &global_sha3); - field_ptr = get_struct_fields_array(struct_ptr, &fields_count); - for (uint8_t idx = 0; idx < fields_count; ++idx) { + for (field_ptr = struct_ptr->fields; field_ptr != NULL; + field_ptr = (s_struct_712_field *) ((s_flist_node *) field_ptr)->next) { // comma separating struct fields - if (idx > 0) { + if (field_ptr != struct_ptr->fields) { hash_byte(',', (cx_hash_t *) &global_sha3); } if (encode_and_hash_field(field_ptr) == false) { return NULL; } - - field_ptr = get_next_struct_field(field_ptr); } // closing struct parentheses hash_byte(')', (cx_hash_t *) &global_sha3); @@ -67,36 +63,10 @@ static bool encode_and_hash_type(const void *const struct_ptr) { return true; } -/** - * Sort the given structs based by alphabetical order - * - * @param[in] deps_count count of how many struct dependencies pointers - * @param[in,out] deps pointer to the first dependency pointer - */ -static void sort_dependencies(uint8_t deps_count, const void **deps) { - bool changed; - const void *tmp_ptr; - const char *name1, *name2; - uint8_t namelen1, namelen2; - int str_cmp_result; - - do { - changed = false; - for (size_t idx = 0; (idx + 1) < deps_count; ++idx) { - name1 = get_struct_name(*(deps + idx), &namelen1); - name2 = get_struct_name(*(deps + idx + 1), &namelen2); - - str_cmp_result = strncmp(name1, name2, MIN(namelen1, namelen2)); - if ((str_cmp_result > 0) || ((str_cmp_result == 0) && (namelen1 > namelen2))) { - tmp_ptr = *(deps + idx); - *(deps + idx) = *(deps + idx + 1); - *(deps + idx + 1) = tmp_ptr; - - changed = true; - } - } - } while (changed); -} +typedef struct struct_dep { + s_flist_node _list; + const s_struct_712 *s; +} s_struct_dep; /** * Find all the dependencies from a given structure @@ -106,55 +76,67 @@ static void sort_dependencies(uint8_t deps_count, const void **deps) { * @param[in] struct_ptr pointer to the struct we are getting the dependencies of * @return pointer to the first found dependency, \ref NULL otherwise */ -static const void **get_struct_dependencies(uint8_t *const deps_count, - const void **first_dep, - const void *const struct_ptr) { - uint8_t fields_count; - const void *field_ptr; +static bool get_struct_dependencies(s_struct_dep **first_dep, const s_struct_712 *struct_ptr) { + const s_struct_712_field *field_ptr; const char *arg_structname; - uint8_t arg_structname_length; - const void *arg_struct_ptr; - size_t dep_idx; - const void **new_dep; - - field_ptr = get_struct_fields_array(struct_ptr, &fields_count); - for (uint8_t idx = 0; idx < fields_count; ++idx) { - if (struct_field_type(field_ptr) == TYPE_CUSTOM) { + const s_struct_712 *arg_struct_ptr; + s_struct_dep *tmp; + s_struct_dep *new_dep; + + for (field_ptr = struct_ptr->fields; field_ptr != NULL; + field_ptr = (s_struct_712_field *) ((s_flist_node *) field_ptr)->next) { + if (field_ptr->type == TYPE_CUSTOM) { // get struct name - arg_structname = get_struct_field_typename(field_ptr, &arg_structname_length); + arg_structname = get_struct_field_typename(field_ptr); // from its name, get the pointer to its definition - if ((arg_struct_ptr = get_structn(arg_structname, arg_structname_length)) == NULL) { + if ((arg_struct_ptr = get_structn(arg_structname, strlen(arg_structname))) == NULL) { PRINTF("Error: could not find EIP-712 dependency struct \""); - for (int i = 0; i < arg_structname_length; ++i) PRINTF("%c", arg_structname[i]); + for (int i = 0; i < (int) strlen(arg_structname); ++i) + PRINTF("%c", arg_structname[i]); PRINTF("\" during type_hash\n"); - return NULL; + return false; } // check if it is not already present in the dependencies array - for (dep_idx = 0; dep_idx < *deps_count; ++dep_idx) { + for (tmp = *first_dep; tmp != NULL; + tmp = (s_struct_dep *) ((s_flist_node *) tmp)->next) { // it's a match! - if (*(first_dep + dep_idx) == arg_struct_ptr) { + if (tmp->s == arg_struct_ptr) { break; } } // if it's not present in the array, add it and recurse into it - if (dep_idx == *deps_count) { - *deps_count += 1; - if ((new_dep = MEM_ALLOC_AND_ALIGN_TYPE(void *)) == NULL) { + if (tmp == NULL) { + if ((new_dep = app_mem_alloc(sizeof(s_struct_dep))) == NULL) { apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; - return NULL; - } - if (*deps_count == 1) { - first_dep = new_dep; + return false; } - *new_dep = arg_struct_ptr; + explicit_bzero(new_dep, sizeof(*new_dep)); + new_dep->s = arg_struct_ptr; + flist_push_back((s_flist_node **) first_dep, (s_flist_node *) new_dep); // TODO: Move away from recursive calls - get_struct_dependencies(deps_count, first_dep, arg_struct_ptr); + get_struct_dependencies(first_dep, arg_struct_ptr); } } - field_ptr = get_next_struct_field(field_ptr); } - return first_dep; + return true; +} + +static bool compare_struct_deps(const s_struct_dep *a, const s_struct_dep *b) { + const char *name1, *name2; + size_t namelen1, namelen2; + int str_cmp_result; + + name1 = a->s->name; + namelen1 = strlen(name1); + name2 = b->s->name; + namelen2 = strlen(name2); + + str_cmp_result = strncmp(name1, name2, MIN(namelen1, namelen2)); + if ((str_cmp_result > 0) || ((str_cmp_result == 0) && (namelen1 > namelen2))) { + return false; + } + return true; } /** @@ -167,9 +149,7 @@ static const void **get_struct_dependencies(uint8_t *const deps_count, */ bool type_hash(const char *const struct_name, const uint8_t struct_name_length, uint8_t *hash_buf) { const void *struct_ptr; - uint8_t deps_count = 0; - const void **deps; - void *mem_loc_bak = mem_legacy_alloc(0); + s_struct_dep *deps; cx_err_t error = CX_INTERNAL_ERROR; if ((struct_ptr = get_structn(struct_name, struct_name_length)) == NULL) { @@ -179,22 +159,21 @@ bool type_hash(const char *const struct_name, const uint8_t struct_name_length, return false; } CX_CHECK(cx_keccak_init_no_throw(&global_sha3, 256)); - deps = get_struct_dependencies(&deps_count, NULL, struct_ptr); - if ((deps_count > 0) && (deps == NULL)) { + deps = NULL; + if (!get_struct_dependencies(&deps, struct_ptr)) { return false; } - sort_dependencies(deps_count, deps); + flist_sort((s_flist_node **) &deps, (f_list_node_cmp) &compare_struct_deps); if (encode_and_hash_type(struct_ptr) == false) { return false; } // loop over each struct and generate string - for (int idx = 0; idx < deps_count; ++idx) { - if (encode_and_hash_type(*deps) == false) { + for (const s_struct_dep *tmp = deps; tmp != NULL; + tmp = (s_struct_dep *) ((s_flist_node *) tmp)->next) { + if (encode_and_hash_type(tmp->s) == false) { return false; } - deps += 1; } - mem_legacy_dealloc(mem_legacy_alloc(0) - mem_loc_bak); // copy hash into memory CX_CHECK(cx_hash_no_throw((cx_hash_t *) &global_sha3, diff --git a/src_features/signMessageEIP712/typed_data.c b/src_features/signMessageEIP712/typed_data.c index 2e457b748b..802f6cf368 100644 --- a/src_features/signMessageEIP712/typed_data.c +++ b/src_features/signMessageEIP712/typed_data.c @@ -5,7 +5,7 @@ #include "mem.h" #include "mem_utils.h" -static s_typed_data *typed_data = NULL; +static s_struct_712 *g_structs = NULL; /** * Initialize the typed data context @@ -13,396 +13,35 @@ static s_typed_data *typed_data = NULL; * @return whether the memory allocation was successful */ bool typed_data_init(void) { - if (typed_data == NULL) { - if ((typed_data = MEM_ALLOC_AND_ALIGN_TYPE(*typed_data)) == NULL) { - apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; - return false; - } - // set types pointer - if ((typed_data->structs_array = mem_legacy_alloc(sizeof(uint8_t))) == NULL) { - apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; - return false; - } - - // create len(types) - *(typed_data->structs_array) = 0; + if (g_structs != NULL) { + typed_data_deinit(); + return false; } return true; } void typed_data_deinit(void) { - typed_data = NULL; -} - -/** - * Skip TypeDesc from a structure field - * - * @param[in] field_ptr pointer to the beginning of the struct field - * @param[in] ptr pointer to the current location within the struct field - * @return pointer to the data right after - */ -static const uint8_t *field_skip_typedesc(const uint8_t *field_ptr, const uint8_t *ptr) { - (void) ptr; - return field_ptr + sizeof(typedesc_t); -} - -/** - * Skip the type name from a structure field - * - * @param[in] field_ptr pointer to the beginning of the struct field - * @param[in] ptr pointer to the current location within the struct field - * @return pointer to the data right after - */ -static const uint8_t *field_skip_typename(const uint8_t *field_ptr, const uint8_t *ptr) { - uint8_t size = 0; - - if (struct_field_type(field_ptr) == TYPE_CUSTOM) { - get_string_in_mem(ptr, &size); - ptr += (sizeof(size) + size); - } - return ptr; -} - -/** - * Skip the type size from a structure field - * - * @param[in] field_ptr pointer to the beginning of the struct field - * @param[in] ptr pointer to the current location within the struct field - * @return pointer to the data right after - */ -static const uint8_t *field_skip_typesize(const uint8_t *field_ptr, const uint8_t *ptr) { - if (struct_field_has_typesize(field_ptr)) { - ptr += sizeof(typesize_t); - } - return ptr; -} - -/** - * Skip the array levels from a structure field - * - * @param[in] field_ptr pointer to the beginning of the struct field - * @param[in] ptr pointer to the current location within the struct field - * @return pointer to the data right after - */ -static const uint8_t *field_skip_array_levels(const uint8_t *field_ptr, const uint8_t *ptr) { - uint8_t size = 0; - - if (struct_field_is_array(field_ptr)) { - ptr = get_array_in_mem(ptr, &size); - while (size-- > 0) { - ptr = get_next_struct_field_array_lvl(ptr); - } - } - return ptr; -} - -/** - * Skip the key name from a structure field - * - * @param[in] field_ptr pointer to the beginning of the struct field - * @param[in] ptr pointer to the current location within the struct field - * @return pointer to the data right after - */ -static const uint8_t *field_skip_keyname(const uint8_t *field_ptr, const uint8_t *ptr) { - uint8_t size = 0; - uint8_t *new_ptr; - - (void) field_ptr; - new_ptr = (uint8_t *) get_array_in_mem(ptr, &size); - return (const uint8_t *) (new_ptr + size); -} - -/** - * Get data pointer & array size from a given pointer - * - * @param[in] ptr given pointer - * @param[out] array_size pointer to array size - * @return pointer to data - */ -const void *get_array_in_mem(const void *ptr, uint8_t *const array_size) { - if (ptr == NULL) { - return NULL; - } - if (array_size) { - *array_size = *(uint8_t *) ptr; - } - return (ptr + sizeof(*array_size)); -} - -/** - * Get pointer to beginning of string & its length from a given pointer - * - * @param[in] ptr given pointer - * @param[out] string_length pointer to string length - * @return pointer to beginning of the string - */ -const char *get_string_in_mem(const uint8_t *ptr, uint8_t *const string_length) { - return (char *) get_array_in_mem(ptr, string_length); -} - -/** - * Get the TypeDesc from a given struct field pointer - * - * @param[in] field_ptr struct field pointer - * @return TypeDesc - */ -static inline typedesc_t get_struct_field_typedesc(const uint8_t *const field_ptr) { - if (field_ptr == NULL) { - return 0; - } - return *field_ptr; -} - -/** - * Check whether a struct field is an array - * - * @param[in] field_ptr struct field pointer - * @return bool whether it is the case - */ -bool struct_field_is_array(const uint8_t *const field_ptr) { - return (get_struct_field_typedesc(field_ptr) & ARRAY_MASK); -} - -/** - * Check whether a struct field has a type size associated to it - * - * @param[in] field_ptr struct field pointer - * @return bool whether it is the case - */ -bool struct_field_has_typesize(const uint8_t *const field_ptr) { - return (get_struct_field_typedesc(field_ptr) & TYPESIZE_MASK); -} - -/** - * Get type from a struct field - * - * @param[in] field_ptr struct field pointer - * @return its type enum - */ -e_type struct_field_type(const uint8_t *const field_ptr) { - return (get_struct_field_typedesc(field_ptr) & TYPE_MASK); -} - -/** - * Get type size from a struct field - * - * @param[in] field_ptr struct field pointer - * @return its type size - */ -uint8_t get_struct_field_typesize(const uint8_t *const field_ptr) { - if (field_ptr == NULL) { - return 0; - } - return *field_skip_typedesc(field_ptr, NULL); -} - -/** - * Get custom type name from a struct field - * - * @param[in] field_ptr struct field pointer - * @param[out] length the type name length - * @return type name pointer - */ -const char *get_struct_field_custom_typename(const uint8_t *field_ptr, uint8_t *const length) { - const uint8_t *ptr; - - if (field_ptr == NULL) { - return NULL; - } - ptr = field_skip_typedesc(field_ptr, NULL); - return get_string_in_mem(ptr, length); + g_structs = NULL; } /** * Get type name from a struct field * * @param[in] field_ptr struct field pointer - * @param[out] length the type name length * @return type name pointer */ -const char *get_struct_field_typename(const uint8_t *field_ptr, uint8_t *const length) { +const char *get_struct_field_typename(const s_struct_712_field *field_ptr) { if (field_ptr == NULL) { return NULL; } - if (struct_field_type(field_ptr) == TYPE_CUSTOM) { - return get_struct_field_custom_typename(field_ptr, length); + if (field_ptr->type == TYPE_CUSTOM) { + return field_ptr->type_name; } - return get_struct_field_sol_typename(field_ptr, length); + return get_struct_field_sol_typename(field_ptr); } -/** - * Get array type of a given struct field's array depth - * - * @param[in] array_depth_ptr given array depth - * @param[out] array_size pointer to array size - * @return array type of that depth - */ -e_array_type struct_field_array_depth(const uint8_t *array_depth_ptr, uint8_t *const array_size) { - if (array_depth_ptr == NULL) { - return 0; - } - if (*array_depth_ptr == ARRAY_FIXED_SIZE) { - if (array_size != NULL) { - *array_size = *(array_depth_ptr + sizeof(uint8_t)); - } - } - return *array_depth_ptr; -} - -/** - * Get next array depth form a given struct field's array depth - * - * @param[in] array_depth_ptr given array depth - * @return next array depth - */ -const uint8_t *get_next_struct_field_array_lvl(const uint8_t *const array_depth_ptr) { - const uint8_t *ptr; - - if (array_depth_ptr == NULL) { - return NULL; - } - switch (*array_depth_ptr) { - case ARRAY_DYNAMIC: - ptr = array_depth_ptr; - break; - case ARRAY_FIXED_SIZE: - ptr = array_depth_ptr + 1; - break; - default: - // should not be in here :^) - apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED; - return NULL; - } - return ptr + 1; -} - -/** - * Get the array levels from a given struct field - * - * @param[in] field_ptr given struct field - * @param[out] length number of array levels - * @return pointer to the first array level - */ -const uint8_t *get_struct_field_array_lvls_array(const uint8_t *const field_ptr, - uint8_t *const length) { - const uint8_t *ptr; - - if (field_ptr == NULL) { - apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED; - return NULL; - } - ptr = field_skip_typedesc(field_ptr, NULL); - ptr = field_skip_typename(field_ptr, ptr); - ptr = field_skip_typesize(field_ptr, ptr); - return get_array_in_mem(ptr, length); -} - -/** - * Get key name from a given struct field - * - * @param[in] field_ptr given struct field - * @param[out] length name length - * @return key name - */ -const char *get_struct_field_keyname(const uint8_t *field_ptr, uint8_t *const length) { - const uint8_t *ptr; - - if (field_ptr == NULL) { - apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED; - return NULL; - } - ptr = field_skip_typedesc(field_ptr, NULL); - ptr = field_skip_typename(field_ptr, ptr); - ptr = field_skip_typesize(field_ptr, ptr); - ptr = field_skip_array_levels(field_ptr, ptr); - return get_string_in_mem(ptr, length); -} - -/** - * Get next struct field from a given field - * - * @param[in] field_ptr given struct field - * @return pointer to the next field - */ -const uint8_t *get_next_struct_field(const void *const field_ptr) { - const void *ptr; - - if (field_ptr == NULL) { - apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED; - return NULL; - } - ptr = field_skip_typedesc(field_ptr, NULL); - ptr = field_skip_typename(field_ptr, ptr); - ptr = field_skip_typesize(field_ptr, ptr); - ptr = field_skip_array_levels(field_ptr, ptr); - return field_skip_keyname(field_ptr, ptr); -} - -/** - * Get name from a given struct - * - * @param[in] struct_ptr given struct - * @param[out] length name length - * @return struct name - */ -const char *get_struct_name(const uint8_t *const struct_ptr, uint8_t *const length) { - if (struct_ptr == NULL) { - apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED; - return NULL; - } - return (char *) get_string_in_mem(struct_ptr, length); -} - -/** - * Get struct fields from a given struct - * - * @param[in] struct_ptr given struct - * @param[out] length number of fields - * @return struct name - */ -const uint8_t *get_struct_fields_array(const uint8_t *const struct_ptr, uint8_t *const length) { - const void *ptr; - uint8_t name_length; - - if (struct_ptr == NULL) { - apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED; - return NULL; - } - ptr = struct_ptr; - get_struct_name(struct_ptr, &name_length); - ptr += (sizeof(name_length) + name_length); // skip length - return get_array_in_mem(ptr, length); -} - -/** - * Get next struct from a given struct - * - * @param[in] struct_ptr given struct - * @return pointer to next struct - */ -const uint8_t *get_next_struct(const uint8_t *const struct_ptr) { - uint8_t fields_count; - const void *ptr; - - if (struct_ptr == NULL) { - apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED; - return NULL; - } - ptr = get_struct_fields_array(struct_ptr, &fields_count); - while (fields_count-- > 0) { - ptr = get_next_struct_field(ptr); - } - return ptr; -} - -/** - * Get structs array - * - * @param[out] length number of structs - * @return pointer to the first struct - */ -const uint8_t *get_structs_array(uint8_t *const length) { - return get_array_in_mem(typed_data->structs_array, length); +const s_struct_712 *get_struct_list(void) { + return g_structs; } /** @@ -412,23 +51,21 @@ const uint8_t *get_structs_array(uint8_t *const length) { * @param[in] length name length * @return pointer to struct */ -const uint8_t *get_structn(const char *const name, const uint8_t length) { - uint8_t structs_count = 0; - const uint8_t *struct_ptr; - const char *struct_name; - uint8_t name_length; +const s_struct_712 *get_structn(const char *name, uint8_t length) { + const s_struct_712 *struct_ptr; if (name == NULL) { apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED; return NULL; } - struct_ptr = get_structs_array(&structs_count); - while (structs_count-- > 0) { - struct_name = get_struct_name(struct_ptr, &name_length); - if ((length == name_length) && (memcmp(name, struct_name, length) == 0)) { - return struct_ptr; + for (struct_ptr = get_struct_list(); struct_ptr != NULL; + struct_ptr = (s_struct_712 *) ((s_flist_node *) struct_ptr)->next) { + if (struct_ptr->name != NULL) { + if ((length == strlen(struct_ptr->name)) && + (memcmp(name, struct_ptr->name, length) == 0)) { + return struct_ptr; + } } - struct_ptr = get_next_struct(struct_ptr); } apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED; return NULL; @@ -442,43 +79,28 @@ const uint8_t *get_structn(const char *const name, const uint8_t length) { * @return whether it was successful */ bool set_struct_name(uint8_t length, const uint8_t *const name) { - uint8_t *length_ptr; - char *name_ptr; + s_struct_712 *new_struct; - if ((name == NULL) || (typed_data == NULL)) { - apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED; - return false; - } - - // increment number of structs - if ((*(typed_data->structs_array) += 1) == 0) { - PRINTF("EIP712 Structs count overflow!\n"); + if (name == NULL) { apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED; return false; } - // copy length - if ((length_ptr = mem_legacy_alloc(sizeof(uint8_t))) == NULL) { - apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; - return false; - } - *length_ptr = length; - - // copy name - if ((name_ptr = mem_legacy_alloc(sizeof(char) * length)) == NULL) { + if ((new_struct = app_mem_alloc(sizeof(*new_struct))) == NULL) { apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; return false; } - memmove(name_ptr, name, length); + explicit_bzero(new_struct, sizeof(*new_struct)); - // initialize number of fields - if ((typed_data->current_struct_fields_array = mem_legacy_alloc(sizeof(uint8_t))) == NULL) { + if ((new_struct->name = app_mem_alloc(length + 1)) == NULL) { apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; return false; } - *(typed_data->current_struct_fields_array) = 0; - + new_struct->name[length] = '\0'; + memmove(new_struct->name, name, length); struct_state = INITIALIZED; + + flist_push_back((s_flist_node **) &g_structs, (s_flist_node *) new_struct); return true; } @@ -487,25 +109,25 @@ bool set_struct_name(uint8_t length, const uint8_t *const name) { * * @param[in] data the field data * @param[in] data_idx the data index - * @return pointer to the TypeDesc in memory + * @return whether it was successful or not */ -static const typedesc_t *set_struct_field_typedesc(const uint8_t *const data, - uint8_t *data_idx, - uint8_t length) { - typedesc_t *typedesc_ptr; +static bool set_struct_field_typedesc(s_struct_712_field *field, + const uint8_t *const data, + uint8_t *data_idx, + uint8_t length) { + uint8_t typedesc; // copy TypeDesc - if ((*data_idx + sizeof(*typedesc_ptr)) > length) // check buffer bound + if ((*data_idx + sizeof(typedesc)) > length) // check buffer bound { apdu_response_code = APDU_RESPONSE_INVALID_DATA; - return NULL; - } - if ((typedesc_ptr = mem_legacy_alloc(sizeof(uint8_t))) == NULL) { - apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; - return NULL; + return false; } - *typedesc_ptr = data[(*data_idx)++]; - return typedesc_ptr; + typedesc = data[(*data_idx)++]; + field->type_is_array = typedesc & ARRAY_MASK; + field->type_has_size = typedesc & TYPESIZE_MASK; + field->type = typedesc & TYPE_MASK; + return true; } /** @@ -515,36 +137,34 @@ static const typedesc_t *set_struct_field_typedesc(const uint8_t *const data, * @param[in] data_idx the data index * @return whether it was successful */ -static bool set_struct_field_custom_typename(const uint8_t *const data, +static bool set_struct_field_custom_typename(s_struct_712_field *field, + const uint8_t *const data, uint8_t *data_idx, uint8_t length) { - uint8_t *typename_len_ptr; - char *typename; + uint8_t typename_len; // copy custom struct name length - if ((*data_idx + sizeof(*typename_len_ptr)) > length) // check buffer bound + if ((*data_idx + sizeof(typename_len)) > length) // check buffer bound { apdu_response_code = APDU_RESPONSE_INVALID_DATA; return false; } - if ((typename_len_ptr = mem_legacy_alloc(sizeof(uint8_t))) == NULL) { - apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; - return false; - } - *typename_len_ptr = data[(*data_idx)++]; + typename_len = data[(*data_idx)++]; // copy name - if ((*data_idx + *typename_len_ptr) > length) // check buffer bound + if ((*data_idx + typename_len) > length) // check buffer bound { apdu_response_code = APDU_RESPONSE_INVALID_DATA; return false; } - if ((typename = mem_legacy_alloc(sizeof(char) * *typename_len_ptr)) == NULL) { + if ((field->type_name = app_mem_alloc(typename_len + 1)) == NULL) { apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; return false; } - memmove(typename, &data[*data_idx], *typename_len_ptr); - *data_idx += *typename_len_ptr; + + field->type_name[typename_len] = '\0'; + memmove(field->type_name, &data[*data_idx], typename_len); + *data_idx += typename_len; return true; } @@ -555,50 +175,38 @@ static bool set_struct_field_custom_typename(const uint8_t *const data, * @param[in] data_idx the data index * @return whether it was successful */ -static bool set_struct_field_array(const uint8_t *const data, uint8_t *data_idx, uint8_t length) { - uint8_t *array_levels_count; - uint8_t *array_level; - uint8_t *array_level_size; - - if ((*data_idx + sizeof(*array_levels_count)) > length) // check buffer bound +static bool set_struct_field_array(s_struct_712_field *field, + const uint8_t *const data, + uint8_t *data_idx, + uint8_t length) { + if ((*data_idx + sizeof(field->array_level_count)) > length) // check buffer bound { apdu_response_code = APDU_RESPONSE_INVALID_DATA; return false; } - if ((array_levels_count = mem_legacy_alloc(sizeof(uint8_t))) == NULL) { - apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; + field->array_level_count = data[(*data_idx)++]; + if ((field->array_levels = + app_mem_alloc(sizeof(*field->array_levels) * field->array_level_count)) == NULL) { return false; } - *array_levels_count = data[(*data_idx)++]; - for (int idx = 0; idx < *array_levels_count; ++idx) { - if ((*data_idx + sizeof(*array_level)) > length) // check buffer bound + for (int idx = 0; idx < field->array_level_count; ++idx) { + if ((*data_idx + sizeof(field->array_levels[idx].type)) > length) // check buffer bound { apdu_response_code = APDU_RESPONSE_INVALID_DATA; return false; } - if ((array_level = mem_legacy_alloc(sizeof(*array_level))) == NULL) { - apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; - return false; - } - *array_level = data[(*data_idx)++]; - if (*array_level >= ARRAY_TYPES_COUNT) { - apdu_response_code = APDU_RESPONSE_INVALID_DATA; - return false; - } - switch (*array_level) { + field->array_levels[idx].type = data[(*data_idx)++]; + switch (field->array_levels[idx].type) { case ARRAY_DYNAMIC: // nothing to do break; case ARRAY_FIXED_SIZE: - if ((*data_idx + sizeof(*array_level_size)) > length) // check buffer bound + if ((*data_idx + sizeof(field->array_levels[idx].size)) > + length) // check buffer bound { apdu_response_code = APDU_RESPONSE_INVALID_DATA; return false; } - if ((array_level_size = mem_legacy_alloc(sizeof(uint8_t))) == NULL) { - apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; - return false; - } - *array_level_size = data[(*data_idx)++]; + field->array_levels[idx].size = data[(*data_idx)++]; break; default: // should not be in here :^) @@ -616,22 +224,17 @@ static bool set_struct_field_array(const uint8_t *const data, uint8_t *data_idx, * @param[in,out] data_idx the data index * @return whether it was successful */ -static bool set_struct_field_typesize(const uint8_t *const data, +static bool set_struct_field_typesize(s_struct_712_field *field, + const uint8_t *const data, uint8_t *data_idx, uint8_t length) { - uint8_t *typesize_ptr; - // copy TypeSize - if ((*data_idx + sizeof(*typesize_ptr)) > length) // check buffer bound + if ((*data_idx + sizeof(field->type_size)) > length) // check buffer bound { apdu_response_code = APDU_RESPONSE_INVALID_DATA; return false; } - if ((typesize_ptr = mem_legacy_alloc(sizeof(uint8_t))) == NULL) { - apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; - return false; - } - *typesize_ptr = data[(*data_idx)++]; + field->type_size = data[(*data_idx)++]; return true; } @@ -642,34 +245,34 @@ static bool set_struct_field_typesize(const uint8_t *const data, * @param[in,out] data_idx the data index * @return whether it was successful */ -static bool set_struct_field_keyname(const uint8_t *const data, uint8_t *data_idx, uint8_t length) { - uint8_t *keyname_len_ptr; - char *keyname_ptr; +static bool set_struct_field_keyname(s_struct_712_field *field, + const uint8_t *const data, + uint8_t *data_idx, + uint8_t length) { + uint8_t keyname_len; // copy length - if ((*data_idx + sizeof(*keyname_len_ptr)) > length) // check buffer bound + if ((*data_idx + sizeof(keyname_len)) > length) // check buffer bound { apdu_response_code = APDU_RESPONSE_INVALID_DATA; return false; } - if ((keyname_len_ptr = mem_legacy_alloc(sizeof(uint8_t))) == NULL) { - apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; - return false; - } - *keyname_len_ptr = data[(*data_idx)++]; + keyname_len = data[(*data_idx)++]; // copy name - if ((*data_idx + *keyname_len_ptr) > length) // check buffer bound + if ((*data_idx + keyname_len) > length) // check buffer bound { apdu_response_code = APDU_RESPONSE_INVALID_DATA; return false; } - if ((keyname_ptr = mem_legacy_alloc(sizeof(char) * *keyname_len_ptr)) == NULL) { + + if ((field->key_name = app_mem_alloc(keyname_len + 1)) == NULL) { apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; return false; } - memmove(keyname_ptr, &data[*data_idx], *keyname_len_ptr); - *data_idx += *keyname_len_ptr; + field->key_name[keyname_len] = '\0'; + memmove(field->key_name, &data[*data_idx], keyname_len); + *data_idx += keyname_len; return true; } @@ -681,13 +284,12 @@ static bool set_struct_field_keyname(const uint8_t *const data, uint8_t *data_id * @return whether it was successful */ bool set_struct_field(uint8_t length, const uint8_t *const data) { - const typedesc_t *typedesc_ptr; uint8_t data_idx = 0; if ((data == NULL) || (length == 0)) { apdu_response_code = APDU_RESPONSE_INVALID_DATA; return false; - } else if (typed_data == NULL) { + } else if (g_structs == NULL) { apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED; return false; } @@ -697,41 +299,37 @@ bool set_struct_field(uint8_t length, const uint8_t *const data) { return false; } - // increment number of struct fields - if ((*(typed_data->current_struct_fields_array) += 1) == 0) { - PRINTF("EIP712 Struct fields count overflow!\n"); - apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED; - return false; - } + s_struct_712_field *new_field = app_mem_alloc(sizeof(*new_field)); + explicit_bzero(new_field, sizeof(*new_field)); - if ((typedesc_ptr = set_struct_field_typedesc(data, &data_idx, length)) == NULL) { + if (!set_struct_field_typedesc(new_field, data, &data_idx, length)) { return false; } // check TypeSize flag in TypeDesc - if (*typedesc_ptr & TYPESIZE_MASK) { + if (new_field->type_has_size) { // TYPESIZE and TYPE_CUSTOM are mutually exclusive - if ((*typedesc_ptr & TYPE_MASK) == TYPE_CUSTOM) { + if (new_field->type == TYPE_CUSTOM) { apdu_response_code = APDU_RESPONSE_CONDITION_NOT_SATISFIED; return false; } - if (set_struct_field_typesize(data, &data_idx, length) == false) { + if (set_struct_field_typesize(new_field, data, &data_idx, length) == false) { return false; } - } else if ((*typedesc_ptr & TYPE_MASK) == TYPE_CUSTOM) { - if (set_struct_field_custom_typename(data, &data_idx, length) == false) { + } else if (new_field->type == TYPE_CUSTOM) { + if (set_struct_field_custom_typename(new_field, data, &data_idx, length) == false) { return false; } } - if (*typedesc_ptr & ARRAY_MASK) { - if (set_struct_field_array(data, &data_idx, length) == false) { + if (new_field->type_is_array) { + if (set_struct_field_array(new_field, data, &data_idx, length) == false) { return false; } } - if (set_struct_field_keyname(data, &data_idx, length) == false) { + if (set_struct_field_keyname(new_field, data, &data_idx, length) == false) { return false; } @@ -740,5 +338,13 @@ bool set_struct_field(uint8_t length, const uint8_t *const data) { apdu_response_code = APDU_RESPONSE_INVALID_DATA; return false; } + + // get last struct + s_struct_712 *s; + for (s = g_structs; (s_struct_712 *) ((s_flist_node *) s)->next != NULL; + s = (s_struct_712 *) ((s_flist_node *) s)->next) + ; + + flist_push_back((s_flist_node **) &s->fields, (s_flist_node *) new_field); return true; } diff --git a/src_features/signMessageEIP712/typed_data.h b/src_features/signMessageEIP712/typed_data.h index 9feebd47c6..b6642cde13 100644 --- a/src_features/signMessageEIP712/typed_data.h +++ b/src_features/signMessageEIP712/typed_data.h @@ -2,6 +2,7 @@ #include #include +#include "list.h" // TypeDesc masks #define TYPE_MASK (0xF) @@ -26,32 +27,43 @@ typedef enum { } e_type; typedef struct { - uint8_t *structs_array; - uint8_t *current_struct_fields_array; -} s_typed_data; + e_array_type type; + uint8_t size; +} s_struct_712_field_array_level; -typedef uint8_t typedesc_t; -typedef uint8_t typesize_t; +typedef struct struct_712_field { + s_flist_node _list; + // TypeDesc + bool type_is_array : 1; + bool type_has_size : 1; + e_type type : 4; + // TypeNameLength + // TypeName + char *type_name; + // TypeSize + uint8_t type_size; + // ArrayLevelCount + uint8_t array_level_count; + // ArrayLevels + s_struct_712_field_array_level *array_levels; + // KeyNameLength + // KeyName + char *key_name; +} s_struct_712_field; + +typedef struct struct_712 { + s_flist_node _list; + char *name; + s_struct_712_field *fields; +} s_struct_712; const void *get_array_in_mem(const void *ptr, uint8_t *const array_size); const char *get_string_in_mem(const uint8_t *ptr, uint8_t *const string_length); -bool struct_field_is_array(const uint8_t *ptr); -bool struct_field_has_typesize(const uint8_t *ptr); -e_type struct_field_type(const uint8_t *ptr); -uint8_t get_struct_field_typesize(const uint8_t *ptr); -const char *get_struct_field_custom_typename(const uint8_t *ptr, uint8_t *const length); -const char *get_struct_field_typename(const uint8_t *ptr, uint8_t *const length); +const char *get_struct_field_custom_typename(const s_struct_712_field *field_ptr); +const char *get_struct_field_typename(const s_struct_712_field *ptr); e_array_type struct_field_array_depth(const uint8_t *ptr, uint8_t *const array_size); -const uint8_t *get_next_struct_field_array_lvl(const uint8_t *const ptr); -const uint8_t *struct_field_half_skip(const uint8_t *ptr); -const uint8_t *get_struct_field_array_lvls_array(const uint8_t *const ptr, uint8_t *const length); -const char *get_struct_field_keyname(const uint8_t *ptr, uint8_t *const length); -const uint8_t *get_next_struct_field(const void *ptr); -const char *get_struct_name(const uint8_t *ptr, uint8_t *const length); -const uint8_t *get_struct_fields_array(const uint8_t *ptr, uint8_t *const length); -const uint8_t *get_next_struct(const uint8_t *ptr); -const uint8_t *get_structs_array(uint8_t *const length); -const uint8_t *get_structn(const char *const name_ptr, const uint8_t name_length); +const s_struct_712 *get_struct_list(void); +const s_struct_712 *get_structn(const char *name_ptr, uint8_t name_length); bool set_struct_name(uint8_t length, const uint8_t *const name); bool set_struct_field(uint8_t length, const uint8_t *const data); bool typed_data_init(void); diff --git a/src_features/signMessageEIP712/ui_logic.c b/src_features/signMessageEIP712/ui_logic.c index 389e8319d3..05a8e75297 100644 --- a/src_features/signMessageEIP712/ui_logic.c +++ b/src_features/signMessageEIP712/ui_logic.c @@ -13,18 +13,21 @@ #include "filtering.h" #include "network.h" #include "time_format.h" +#include "list.h" -#define AMOUNT_JOIN_FLAG_TOKEN (1 << 0) -#define AMOUNT_JOIN_FLAG_VALUE (1 << 1) +#define AMOUNT_JOIN_FLAG_TOKEN (1 << 0) +#define AMOUNT_JOIN_FLAG_VALUE (1 << 1) +#define AMOUNT_JOIN_NAME_LENGTH 25 -typedef struct { - // display name, not NULL-terminated - char name[25]; - uint8_t name_length; - uint8_t value[INT256_LENGTH]; - uint8_t value_length; +typedef struct amount_join { + s_flist_node _list; + // display name, NULL-terminated + char name[AMOUNT_JOIN_NAME_LENGTH + 1]; // indicates the steps the token join has gone through uint8_t flags; + uint8_t token_idx; + uint8_t value_length; + uint8_t value[INT256_LENGTH]; } s_amount_join; typedef enum { @@ -39,11 +42,16 @@ typedef enum { #define UI_712_TRUSTED_NAME (1 << 4) typedef struct { - s_amount_join joins[MAX_ASSETS]; + s_amount_join *joins; uint8_t idx; e_amount_join_state state; } s_amount_context; +typedef struct filter_crc { + s_flist_node _list; + uint32_t value; +} s_filter_crc; + typedef struct { bool shown; bool end_reached; @@ -52,15 +60,13 @@ typedef struct { uint8_t field_flags; uint8_t structs_to_review; s_amount_context amount; - uint8_t filters_received; - uint32_t filters_crc[MAX_FILTERS]; - uint8_t discarded_path_length; - char discarded_path[255]; + s_filter_crc *filters_crc; + char *discarded_path; uint8_t tn_type_count; uint8_t tn_source_count; e_name_type tn_types[TN_TYPE_COUNT]; e_name_source tn_sources[TN_SOURCE_COUNT]; - char ui_pairs_buffer[(SHARED_CTX_FIELD_1_SIZE + SHARED_CTX_FIELD_2_SIZE) * 2]; + s_ui_712_pair *ui_pairs; } t_ui_context; static t_ui_context *ui_ctx = NULL; @@ -207,9 +213,8 @@ e_eip712_nfs ui_712_next_field(void) { * @param[in] struct_ptr pointer to the structure to be shown * @return whether it was successful or not */ -bool ui_712_review_struct(const void *struct_ptr) { +bool ui_712_review_struct(const s_struct_712 *struct_ptr) { const char *struct_name; - uint8_t struct_name_length; const char *title = "Review struct"; if (ui_ctx == NULL) { @@ -217,8 +222,8 @@ bool ui_712_review_struct(const void *struct_ptr) { } ui_712_set_title(title, strlen(title)); - if ((struct_name = get_struct_name(struct_ptr, &struct_name_length)) != NULL) { - ui_712_set_value(struct_name, struct_name_length); + if ((struct_name = struct_ptr->name) != NULL) { + ui_712_set_value(struct_name, strlen(struct_name)); } return ui_712_redraw_generic_step(); } @@ -352,7 +357,7 @@ static bool ui_712_format_bytes(const uint8_t *data, uint8_t length, bool first, static bool ui_712_format_int(const uint8_t *data, uint8_t length, bool first, - const void *field_ptr) { + const s_struct_712_field *field_ptr) { uint256_t value256; uint128_t value128; int32_t value32; @@ -362,7 +367,7 @@ static bool ui_712_format_int(const uint8_t *data, if (!first) { return false; } - switch (get_struct_field_typesize(field_ptr) * 8) { + switch (field_ptr->type_size * 8) { case 256: convertUint256BE(data, length, &value256); tostring256_signed(&value256, 10, strings.tmp.tmp, sizeof(strings.tmp.tmp)); @@ -426,6 +431,27 @@ static bool ui_712_format_uint(const uint8_t *data, uint8_t length, bool first) return true; } +static s_amount_join *get_amount_join(uint8_t token_idx) { + s_amount_join *tmp; + s_amount_join *new; + + for (tmp = ui_ctx->amount.joins; tmp != NULL; + tmp = (s_amount_join *) ((s_flist_node *) tmp)->next) { + if (tmp->token_idx == token_idx) break; + } + if (tmp != NULL) return tmp; + + // does not exist, create it + if ((new = app_mem_alloc(sizeof(*new))) == NULL) { + return NULL; + } + explicit_bzero(new, sizeof(*new)); + new->token_idx = token_idx; + + flist_push_back((s_flist_node **) &ui_ctx->amount.joins, (s_flist_node *) new); + return new; +} + /** * Format given data as an amount with its ticker and value with correct decimals * @@ -433,20 +459,23 @@ static bool ui_712_format_uint(const uint8_t *data, uint8_t length, bool first) */ static bool ui_712_format_amount_join(void) { const tokenDefinition_t *token = NULL; + s_amount_join *amount_join; if (tmpCtx.transactionContext.assetSet[ui_ctx->amount.idx]) { token = &tmpCtx.transactionContext.extraInfo[ui_ctx->amount.idx].token; } - if ((ui_ctx->amount.joins[ui_ctx->amount.idx].value_length == INT256_LENGTH) && - ismaxint(ui_ctx->amount.joins[ui_ctx->amount.idx].value, - ui_ctx->amount.joins[ui_ctx->amount.idx].value_length)) { + if ((amount_join = get_amount_join(ui_ctx->amount.idx)) == NULL) { + return false; + } + if ((amount_join->value_length == INT256_LENGTH) && + ismaxint(amount_join->value, amount_join->value_length)) { strlcpy(strings.tmp.tmp, "Unlimited ", sizeof(strings.tmp.tmp)); strlcat(strings.tmp.tmp, (token != NULL) ? token->ticker : g_unknown_ticker, sizeof(strings.tmp.tmp)); } else { - if (!amountToString(ui_ctx->amount.joins[ui_ctx->amount.idx].value, - ui_ctx->amount.joins[ui_ctx->amount.idx].value_length, + if (!amountToString(amount_join->value, + amount_join->value_length, (token != NULL) ? token->decimals : 0, (token != NULL) ? token->ticker : g_unknown_ticker, strings.tmp.tmp, @@ -455,18 +484,20 @@ static bool ui_712_format_amount_join(void) { } } ui_ctx->field_flags |= UI_712_FIELD_SHOWN; - ui_712_set_title(ui_ctx->amount.joins[ui_ctx->amount.idx].name, - ui_ctx->amount.joins[ui_ctx->amount.idx].name_length); - explicit_bzero(&ui_ctx->amount.joins[ui_ctx->amount.idx], - sizeof(ui_ctx->amount.joins[ui_ctx->amount.idx])); + ui_712_set_title(amount_join->name, strlen(amount_join->name)); + explicit_bzero(amount_join, sizeof(*amount_join)); return true; } /** * Simply mark the current amount-join's token address as received */ -void amount_join_set_token_received(void) { - ui_ctx->amount.joins[ui_ctx->amount.idx].flags |= AMOUNT_JOIN_FLAG_TOKEN; +bool amount_join_set_token_received(void) { + s_amount_join *amount_join = get_amount_join(ui_ctx->amount.idx); + + if (amount_join == NULL) return false; + amount_join->flags |= AMOUNT_JOIN_FLAG_TOKEN; + return true; } /** @@ -478,6 +509,7 @@ void amount_join_set_token_received(void) { */ static bool update_amount_join(const uint8_t *data, uint8_t length) { const tokenDefinition_t *token = NULL; + s_amount_join *amount_join; if (tmpCtx.transactionContext.assetSet[ui_ctx->amount.idx]) { token = &tmpCtx.transactionContext.extraInfo[ui_ctx->amount.idx].token; @@ -495,13 +527,18 @@ static bool update_amount_join(const uint8_t *data, uint8_t length) { return false; } } - amount_join_set_token_received(); + if (!amount_join_set_token_received()) { + return false; + } break; case AMOUNT_JOIN_STATE_VALUE: - memcpy(ui_ctx->amount.joins[ui_ctx->amount.idx].value, data, length); - ui_ctx->amount.joins[ui_ctx->amount.idx].value_length = length; - ui_ctx->amount.joins[ui_ctx->amount.idx].flags |= AMOUNT_JOIN_FLAG_VALUE; + if ((amount_join = get_amount_join(ui_ctx->amount.idx)) == NULL) { + return false; + } + memcpy(amount_join->value, data, length); + amount_join->value_length = length; + amount_join->flags |= AMOUNT_JOIN_FLAG_VALUE; break; default: @@ -542,10 +579,12 @@ static bool ui_712_format_trusted_name(const uint8_t *data, uint8_t length) { * @param[in] field_ptr pointer to the new struct field * @return whether it was successful or not */ -static bool ui_712_format_datetime(const uint8_t *data, uint8_t length, const void *field_ptr) { +static bool ui_712_format_datetime(const uint8_t *data, + uint8_t length, + const s_struct_712_field *field_ptr) { time_t timestamp; - if ((length >= get_struct_field_typesize(field_ptr)) && ismaxint((uint8_t *) data, length)) { + if ((length >= field_ptr->type_size) && ismaxint((uint8_t *) data, length)) { snprintf(strings.tmp.tmp, sizeof(strings.tmp.tmp), "Unlimited"); return true; } @@ -562,7 +601,7 @@ static bool ui_712_format_datetime(const uint8_t *data, uint8_t length, const vo * @param[in] first if this is the first chunk * @param[in] last if this is the last chunk */ -bool ui_712_feed_to_display(const void *field_ptr, +bool ui_712_feed_to_display(const s_struct_712_field *field_ptr, const uint8_t *data, uint8_t length, bool first, @@ -577,7 +616,7 @@ bool ui_712_feed_to_display(const void *field_ptr, } // Value if (ui_712_field_shown()) { - switch (struct_field_type(field_ptr)) { + switch (field_ptr->type) { case TYPE_SOL_STRING: ui_712_format_str(data, length, last); break; @@ -618,8 +657,11 @@ bool ui_712_feed_to_display(const void *field_ptr, return false; } - if (ui_ctx->amount.joins[ui_ctx->amount.idx].flags == - (AMOUNT_JOIN_FLAG_TOKEN | AMOUNT_JOIN_FLAG_VALUE)) { + s_amount_join *amount_join = get_amount_join(ui_ctx->amount.idx); + if (amount_join == NULL) { + return false; + } + if (amount_join->flags == (AMOUNT_JOIN_FLAG_TOKEN | AMOUNT_JOIN_FLAG_VALUE)) { if (!ui_712_format_amount_join()) { return false; } @@ -669,7 +711,12 @@ void ui_712_end_sign(void) { * Initializes the UI context structure in memory */ bool ui_712_init(void) { - if ((ui_ctx = MEM_ALLOC_AND_ALIGN_TYPE(*ui_ctx))) { + if (ui_ctx != NULL) { + ui_712_deinit(); + return false; + } + + if ((ui_ctx = app_mem_alloc(sizeof(*ui_ctx)))) { explicit_bzero(ui_ctx, sizeof(*ui_ctx)); ui_ctx->filtering_mode = EIP712_FILTERING_BASIC; explicit_bzero(&strings, sizeof(strings)); @@ -775,7 +822,12 @@ void ui_712_set_filters_count(uint8_t count) { * @return number of filters */ uint8_t ui_712_remaining_filters(void) { - return ui_ctx->filters_to_process - ui_ctx->filters_received; + uint8_t filter_count = 0; + + for (const s_filter_crc *tmp = ui_ctx->filters_crc; tmp != NULL; + tmp = (s_filter_crc *) ((s_flist_node *) tmp)->next) + filter_count += 1; + return ui_ctx->filters_to_process - filter_count; } /** @@ -800,31 +852,24 @@ void ui_712_queue_struct_to_review(void) { } } -/** - * Increment the filters counter - * - * @return if the counter could be incremented - */ -bool ui_712_filters_counter_incr(void) { - if (ui_ctx->filters_received > ui_ctx->filters_to_process) { - return false; - } - ui_ctx->filters_received += 1; - return true; -} - void ui_712_token_join_prepare_addr_check(uint8_t index) { ui_ctx->amount.idx = index; ui_ctx->amount.state = AMOUNT_JOIN_STATE_TOKEN; } -void ui_712_token_join_prepare_amount(uint8_t index, const char *name, uint8_t name_length) { - uint8_t cpy_len = MIN(sizeof(ui_ctx->amount.joins[index].name), name_length); +bool ui_712_token_join_prepare_amount(uint8_t index, const char *name, uint8_t name_length) { + s_amount_join *amount_join = get_amount_join(index); + uint8_t cpy_len; + if (amount_join == NULL) { + return false; + } + cpy_len = MIN(sizeof(amount_join->name) - 1, name_length); ui_ctx->amount.idx = index; ui_ctx->amount.state = AMOUNT_JOIN_STATE_VALUE; - memcpy(ui_ctx->amount.joins[index].name, name, cpy_len); - ui_ctx->amount.joins[index].name_length = cpy_len; + memcpy(amount_join->name, name, cpy_len); + amount_join->name[cpy_len] = '\0'; + return true; } /** @@ -833,16 +878,15 @@ void ui_712_token_join_prepare_amount(uint8_t index, const char *name, uint8_t n * @param[in] field_ptr pointer to the field * @return whether it was successful or not */ -bool ui_712_show_raw_key(const void *field_ptr) { +bool ui_712_show_raw_key(const s_struct_712_field *field_ptr) { const char *key; - uint8_t key_len; - if ((key = get_struct_field_keyname(field_ptr, &key_len)) == NULL) { + if ((key = field_ptr->key_name) == NULL) { return false; } if (ui_712_field_shown() && !(ui_ctx->field_flags & UI_712_FIELD_NAME_PROVIDED)) { - ui_712_set_title(key, key_len); + ui_712_set_title(key, strlen(key)); } return true; } @@ -851,18 +895,37 @@ bool ui_712_show_raw_key(const void *field_ptr) { * Push a new filter path * * @param[in] path_crc CRC of the filter path - * @return if the path was pushed or not (in case it was already present) + * @return whether it was successful or not */ bool ui_712_push_new_filter_path(uint32_t path_crc) { + s_filter_crc *tmp; + s_filter_crc *new_crc; + uint8_t filter_count = 0; + // check if already present - for (int i = 0; i < ui_ctx->filters_received; ++i) { - if (ui_ctx->filters_crc[i] == path_crc) { - PRINTF("EIP-712 path CRC (%x) already found at index %u!\n", path_crc, i); - return false; + for (tmp = ui_ctx->filters_crc; tmp != NULL; + tmp = (s_filter_crc *) ((s_flist_node *) tmp)->next) { + if (tmp->value == path_crc) { + PRINTF("EIP-712 path CRC (%x) already found!\n", path_crc); + return true; } + filter_count += 1; + } + + if (filter_count >= ui_ctx->filters_to_process) { + apdu_response_code = APDU_RESPONSE_INVALID_DATA; + return false; } - PRINTF("Pushing new EIP-712 path CRC (%x) at index %u\n", path_crc, ui_ctx->filters_received); - ui_ctx->filters_crc[ui_ctx->filters_received] = path_crc; + // allocate it + if ((new_crc = app_mem_alloc(sizeof(*new_crc))) == NULL) { + apdu_response_code = APDU_RESPONSE_INSUFFICIENT_MEMORY; + return false; + } + explicit_bzero(new_crc, sizeof(*new_crc)); + new_crc->value = path_crc; + + PRINTF("Pushing new EIP-712 path CRC (%x)\n", path_crc); + flist_push_back((s_flist_node **) &ui_ctx->filters_crc, (s_flist_node *) new_crc); return true; } @@ -871,23 +934,36 @@ bool ui_712_push_new_filter_path(uint32_t path_crc) { * * @param[in] path the given filter path * @param[in] length the path length + * @return whether it was successful or not */ -void ui_712_set_discarded_path(const char *path, uint8_t length) { +bool ui_712_set_discarded_path(const char *path, uint8_t length) { + if (ui_ctx->discarded_path != NULL) { + return false; + } + if ((ui_ctx->discarded_path = app_mem_alloc(length + 1)) == NULL) { + return false; + } memcpy(ui_ctx->discarded_path, path, length); - ui_ctx->discarded_path_length = length; + ui_ctx->discarded_path[length] = '\0'; + return true; } /** * Get the discarded filter path * - * @param[out] length the path length * @return filter path */ -const char *ui_712_get_discarded_path(uint8_t *length) { - *length = ui_ctx->discarded_path_length; +const char *ui_712_get_discarded_path(void) { return ui_ctx->discarded_path; } +void ui_712_clear_discarded_path(void) { + if (ui_ctx->discarded_path != NULL) { + app_mem_free(ui_ctx->discarded_path); + ui_ctx->discarded_path = NULL; + } +} + void ui_712_set_trusted_name_requirements(uint8_t type_count, const e_name_type *types, uint8_t source_count, @@ -898,13 +974,39 @@ void ui_712_set_trusted_name_requirements(uint8_t type_count, memcpy(ui_ctx->tn_sources, sources, source_count); } -/* - * Get UI pairs buffer - * - * @param[out] size buffer size - * @return pointer to the buffer - */ -char *get_ui_pairs_buffer(size_t *size) { - *size = sizeof(ui_ctx->ui_pairs_buffer); - return ui_ctx->ui_pairs_buffer; +const s_ui_712_pair *ui_712_get_pairs(void) { + return ui_ctx->ui_pairs; +} + +bool ui_712_push_new_pair(const char *key, const char *value) { + s_ui_712_pair *new_pair; + + // allocate pair + if ((new_pair = app_mem_alloc(sizeof(*new_pair))) == NULL) { + return false; + } + explicit_bzero(new_pair, sizeof(*new_pair)); + + flist_push_back((s_flist_node **) &ui_ctx->ui_pairs, (s_flist_node *) new_pair); + + if ((new_pair->key = app_mem_strdup(key)) == NULL) { + return false; + } + + if ((new_pair->value = app_mem_strdup(value)) == NULL) { + return false; + } + return true; +} + +void ui_712_delete_pairs(size_t keep) { + size_t size; + + size = flist_size((s_flist_node **) &ui_ctx->ui_pairs); + if (size > 0) { + while (size > keep) { + flist_pop_front((s_flist_node **) &ui_ctx->ui_pairs, NULL); + size -= 1; + } + } } diff --git a/src_features/signMessageEIP712/ui_logic.h b/src_features/signMessageEIP712/ui_logic.h index 6a87a1af50..01722dabd2 100644 --- a/src_features/signMessageEIP712/ui_logic.h +++ b/src_features/signMessageEIP712/ui_logic.h @@ -1,9 +1,12 @@ #pragma once +#include #include #include "ux.h" #include "uint256.h" +#include "typed_data.h" #include "trusted_name.h" +#include "list.h" typedef enum { EIP712_FILTERING_BASIC, EIP712_FILTERING_FULL } e_eip712_filtering_mode; typedef enum { @@ -12,11 +15,17 @@ typedef enum { EIP712_NO_MORE_FIELD } e_eip712_nfs; // next field state +typedef struct ui_712_pair { + s_flist_node _list; + char *key; + char *value; +} s_ui_712_pair; + bool ui_712_init(void); void ui_712_deinit(void); e_eip712_nfs ui_712_next_field(void); -bool ui_712_review_struct(const void *const struct_ptr); -bool ui_712_feed_to_display(const void *field_ptr, +bool ui_712_review_struct(const s_struct_712 *struct_ptr); +bool ui_712_feed_to_display(const s_struct_712_field *field_ptr, const uint8_t *data, uint8_t length, bool first, @@ -40,16 +49,18 @@ e_eip712_filtering_mode ui_712_get_filtering_mode(void); void ui_712_set_filters_count(uint8_t count); uint8_t ui_712_remaining_filters(void); void ui_712_queue_struct_to_review(void); -bool ui_712_filters_counter_incr(void); void ui_712_token_join_prepare_addr_check(uint8_t index); -void ui_712_token_join_prepare_amount(uint8_t index, const char *name, uint8_t name_length); -void amount_join_set_token_received(void); -bool ui_712_show_raw_key(const void *field_ptr); +bool ui_712_token_join_prepare_amount(uint8_t index, const char *name, uint8_t name_length); +bool amount_join_set_token_received(void); +bool ui_712_show_raw_key(const s_struct_712_field *field_ptr); bool ui_712_push_new_filter_path(uint32_t path_crc); -void ui_712_set_discarded_path(const char *path, uint8_t length); -const char *ui_712_get_discarded_path(uint8_t *length); +bool ui_712_set_discarded_path(const char *path, uint8_t length); +const char *ui_712_get_discarded_path(void); +void ui_712_clear_discarded_path(void); void ui_712_set_trusted_name_requirements(uint8_t type_count, const e_name_type *types, uint8_t source_count, const e_name_source *sources); -char *get_ui_pairs_buffer(size_t *size); +const s_ui_712_pair *ui_712_get_pairs(void); +bool ui_712_push_new_pair(const char *key, const char *value); +void ui_712_delete_pairs(size_t keep); diff --git a/src_nbgl/ui_gcs.c b/src_nbgl/ui_gcs.c index 8557e78b47..39fc4e4d26 100644 --- a/src_nbgl/ui_gcs.c +++ b/src_nbgl/ui_gcs.c @@ -24,16 +24,6 @@ static void review_choice(bool confirm) { } } -static char *_strdup(const char *src) { - char *dst; - size_t length = strlen(src) + 1; - - if ((dst = app_mem_alloc(length)) != NULL) { - memmove(dst, src, length); - } - return dst; -} - static void free_pair_extension_infolist_elem(const struct nbgl_contentInfoList_s *infolist, int idx) { if (infolist->infoTypes[idx] != NULL) { @@ -130,7 +120,7 @@ static bool prepare_infos(nbgl_contentInfoList_t *infos) { "Contract owner" #endif ); - if ((keys[count] = _strdup(tmp_buf)) == NULL) { + if ((keys[count] = app_mem_strdup(tmp_buf)) == NULL) { return false; } snprintf(tmp_buf, tmp_buf_size, "%s", value); @@ -138,7 +128,7 @@ static bool prepare_infos(nbgl_contentInfoList_t *infos) { off = strlen(tmp_buf); snprintf(tmp_buf + off, tmp_buf_size - off, "\n%s", value); } - if ((values[count] = _strdup(tmp_buf)) == NULL) { + if ((values[count] = app_mem_strdup(tmp_buf)) == NULL) { return false; } count += 1; @@ -153,11 +143,11 @@ static bool prepare_infos(nbgl_contentInfoList_t *infos) { "Contract" #endif ); - if ((keys[count] = _strdup(tmp_buf)) == NULL) { + if ((keys[count] = app_mem_strdup(tmp_buf)) == NULL) { return false; } snprintf(tmp_buf, tmp_buf_size, "%s", value); - if ((values[count] = _strdup(tmp_buf)) == NULL) { + if ((values[count] = app_mem_strdup(tmp_buf)) == NULL) { return false; } #ifdef SCREEN_SIZE_WALLET @@ -173,10 +163,10 @@ static bool prepare_infos(nbgl_contentInfoList_t *infos) { chainConfig->chainId)) { return false; } - if ((keys[count] = _strdup("Contract address")) == NULL) { + if ((keys[count] = app_mem_strdup("Contract address")) == NULL) { return false; } - if ((values[count] = _strdup(tmp_buf)) == NULL) { + if ((values[count] = app_mem_strdup(tmp_buf)) == NULL) { return false; } count += 1; @@ -184,11 +174,11 @@ static bool prepare_infos(nbgl_contentInfoList_t *infos) { if ((value = get_deploy_date()) != NULL) { snprintf(tmp_buf, tmp_buf_size, "Deployed on"); - if ((keys[count] = _strdup(tmp_buf)) == NULL) { + if ((keys[count] = app_mem_strdup(tmp_buf)) == NULL) { return false; } snprintf(tmp_buf, tmp_buf_size, "%s", value); - if ((values[count] = _strdup(tmp_buf)) == NULL) { + if ((values[count] = app_mem_strdup(tmp_buf)) == NULL) { return false; } count += 1; @@ -209,20 +199,20 @@ static bool prepare_infos(nbgl_contentInfoList_t *infos) { chainConfig->chainId)) { return false; } - if ((extensions[contract_idx].title = _strdup(tmp_buf)) == NULL) { + if ((extensions[contract_idx].title = app_mem_strdup(tmp_buf)) == NULL) { return false; } // Etherscan only for mainnet if (get_tx_chain_id() == ETHEREUM_MAINNET_CHAINID) { - if ((extensions[contract_idx].explanation = _strdup("Scan to view on Etherscan")) == - NULL) { + if ((extensions[contract_idx].explanation = + app_mem_strdup("Scan to view on Etherscan")) == NULL) { return false; } snprintf(tmp_buf, tmp_buf_size, "https://etherscan.io/address/%s", extensions[contract_idx].title); - if ((extensions[contract_idx].fullValue = _strdup(tmp_buf)) == NULL) { + if ((extensions[contract_idx].fullValue = app_mem_strdup(tmp_buf)) == NULL) { return false; } } else { @@ -272,7 +262,7 @@ bool ui_gcs(void) { #endif snprintf(tmp_buf, tmp_buf_size, "Review transaction to %s", get_operation_type()); - if ((g_review_title = _strdup(tmp_buf)) == NULL) { + if ((g_review_title = app_mem_strdup(tmp_buf)) == NULL) { ui_gcs_cleanup(); return false; } @@ -285,7 +275,7 @@ bool ui_gcs(void) { #else snprintf(tmp_buf, tmp_buf_size, "%s transaction", ui_tx_simulation_finish_str()); #endif - if ((g_sign_title = _strdup(tmp_buf)) == NULL) { + if ((g_sign_title = app_mem_strdup(tmp_buf)) == NULL) { ui_gcs_cleanup(); return false; } @@ -314,13 +304,13 @@ bool ui_gcs(void) { explicit_bzero(pairs, sizeof(*pairs) * g_pair_list->nbPairs); g_pair_list->pairs = pairs; - pairs[0].item = _strdup("Interaction with"); + pairs[0].item = app_mem_strdup("Interaction with"); pairs[0].value = get_creator_name(); if (pairs[0].value == NULL) { // not great, but this cannot be NULL - pairs[0].value = _strdup("a smart contract"); + pairs[0].value = app_mem_strdup("a smart contract"); } else { - pairs[0].value = _strdup(pairs[0].value); + pairs[0].value = app_mem_strdup(pairs[0].value); } if ((ext = app_mem_alloc(sizeof(*ext))) == NULL) { ui_gcs_cleanup(); @@ -342,9 +332,9 @@ bool ui_gcs(void) { } ext->aliasType = INFO_LIST_ALIAS; if ((ext->backText = get_creator_name()) == NULL) { - ext->backText = _strdup("Smart contract information"); + ext->backText = app_mem_strdup("Smart contract information"); } else { - ext->backText = _strdup(ext->backText); + ext->backText = app_mem_strdup(ext->backText); } pairs[0].aliasValue = 1; @@ -358,22 +348,22 @@ bool ui_gcs(void) { } if (show_network) { - pairs[g_pair_list->nbPairs - 2].item = _strdup("Network"); + pairs[g_pair_list->nbPairs - 2].item = app_mem_strdup("Network"); if (get_network_as_string(tmp_buf, tmp_buf_size) != APDU_RESPONSE_OK) { ui_gcs_cleanup(); return false; } - pairs[g_pair_list->nbPairs - 2].value = _strdup(tmp_buf); + pairs[g_pair_list->nbPairs - 2].value = app_mem_strdup(tmp_buf); } - pairs[g_pair_list->nbPairs - 1].item = _strdup("Max fees"); + pairs[g_pair_list->nbPairs - 1].item = app_mem_strdup("Max fees"); if (max_transaction_fee_to_string(&tmpContent.txContent.gasprice, &tmpContent.txContent.startgas, tmp_buf, tmp_buf_size) == false) { PRINTF("Error: Could not format the max fees!\n"); } - pairs[g_pair_list->nbPairs - 1].value = _strdup(tmp_buf); + pairs[g_pair_list->nbPairs - 1].value = app_mem_strdup(tmp_buf); nbgl_useCaseAdvancedReview(TYPE_TRANSACTION, g_pair_list, diff --git a/src_nbgl/ui_sign_712.c b/src_nbgl/ui_sign_712.c index 3b1b3ed61e..3e13dc5627 100644 --- a/src_nbgl/ui_sign_712.c +++ b/src_nbgl/ui_sign_712.c @@ -6,31 +6,36 @@ #include "cmd_get_tx_simulation.h" #include "utils.h" -static nbgl_contentTagValue_t pairs[7]; +#ifdef SCREEN_SIZE_WALLET +#define PAIR_COUNT 7 +#else +#define PAIR_COUNT 2 +#endif + +static nbgl_contentTagValue_t pairs[PAIR_COUNT]; static nbgl_contentTagValueList_t pairs_list; static uint8_t pair_idx; -static size_t buf_idx; static bool review_skipped; static bool hash_displayed; -nbgl_callback_t skip_callback = NULL; +static nbgl_callback_t skip_callback = NULL; static void message_progress(bool confirm) { - char *buf; - size_t buf_size; - size_t shift_off; - if (!review_skipped) { +#ifdef SCREEN_SIZE_WALLET if (pairs_list.nbPairs < pair_idx) { - buf = get_ui_pairs_buffer(&buf_size); - memmove(&pairs[0], &pairs[pairs_list.nbPairs], sizeof(pairs[0])); - memmove(buf, pairs[0].item, (buf + buf_idx) - pairs[0].item); - shift_off = pairs[0].item - buf; - buf_idx -= shift_off; - pairs[0].value -= shift_off; - pairs[0].item = buf; - pair_idx = 1; + ui_712_delete_pairs(pair_idx - pairs_list.nbPairs); + const s_ui_712_pair *tmp = ui_712_get_pairs(); + if (tmp != NULL) { + pairs[0].item = tmp->key; + pairs[0].value = tmp->value; + } + pair_idx = pair_idx - pairs_list.nbPairs; } +#else + ui_712_delete_pairs(0); + pair_idx = 0; +#endif } if (confirm) { if (ui_712_next_field() == EIP712_NO_MORE_FIELD) { @@ -49,29 +54,30 @@ static void review_skip(void) { #endif // SCREEN_SIZE_WALLET static void message_update(bool confirm) { - char *buf; - size_t buf_size; - size_t buf_off; bool flag; bool skippable; - buf = get_ui_pairs_buffer(&buf_size); if (confirm) { if (!review_skipped) { - buf_off = strlen(strings.tmp.tmp2) + 1; - LEDGER_ASSERT((buf_idx + buf_off) < buf_size, "UI pairs buffer overflow"); - pairs[pair_idx].item = memmove(buf + buf_idx, strings.tmp.tmp2, buf_off); - buf_idx += buf_off; - buf_off = strlen(strings.tmp.tmp) + 1; - LEDGER_ASSERT((buf_idx + buf_off) < buf_size, "UI pairs buffer overflow"); - pairs[pair_idx].value = memmove(buf + buf_idx, strings.tmp.tmp, buf_off); - buf_idx += buf_off; - pair_idx += 1; + LEDGER_ASSERT(ui_712_push_new_pair(strings.tmp.tmp2, strings.tmp.tmp), "Out of memory"); + const s_ui_712_pair *tmp; + for (tmp = ui_712_get_pairs(); (s_ui_712_pair *) ((s_flist_node *) tmp)->next != NULL; + tmp = (s_ui_712_pair *) ((s_flist_node *) tmp)->next) + ; + if (tmp != NULL) { + pairs[pair_idx].item = tmp->key; + pairs[pair_idx].value = tmp->value; + pair_idx += 1; + } skippable = warning.predefinedSet & SET_BIT(BLIND_SIGNING_WARN); pairs_list.nbPairs = nbgl_useCaseGetNbTagValuesInPageExt(pair_idx, &pairs_list, 0, skippable, &flag); } +#ifdef SCREEN_SIZE_WALLET if (!review_skipped && ((pair_idx == ARRAYLEN(pairs)) || (pairs_list.nbPairs < pair_idx))) { +#else + if (!review_skipped) { +#endif nbgl_useCaseReviewStreamingContinueExt(&pairs_list, message_progress, skip_callback); } else { message_progress(true); @@ -86,7 +92,6 @@ static void ui_712_start_common(void) { explicit_bzero(&pairs_list, sizeof(pairs_list)); pairs_list.pairs = pairs; pair_idx = 0; - buf_idx = 0; review_skipped = false; hash_displayed = false; #ifdef SCREEN_SIZE_WALLET From 98d418b69d34c58d6b51527e77bb2808ae78dff1 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Thu, 19 Jun 2025 15:05:00 +0200 Subject: [PATCH 4/6] Removed const-qualifier on pointers arguments in function --- src_features/signMessageEIP712/encode_field.c | 12 ++++++------ src_features/signMessageEIP712/encode_field.h | 10 +++++----- src_features/signMessageEIP712/field_hash.c | 6 +++--- src_features/signMessageEIP712/path.c | 6 +++--- src_features/signMessageEIP712/path.h | 2 +- src_features/signMessageEIP712/type_hash.c | 2 +- src_features/signMessageEIP712/type_hash.h | 2 +- src_features/signMessageEIP712/typed_data.c | 14 +++++++------- src_features/signMessageEIP712/typed_data.h | 10 +++++----- 9 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src_features/signMessageEIP712/encode_field.c b/src_features/signMessageEIP712/encode_field.c index 15e34b5827..d4ccc6bd2c 100644 --- a/src_features/signMessageEIP712/encode_field.c +++ b/src_features/signMessageEIP712/encode_field.c @@ -13,7 +13,7 @@ typedef enum { MSB, LSB } e_padding_type; * @param[in] pval value used for padding * @return encoded field value */ -static void *field_encode(const uint8_t *const value, +static void *field_encode(const uint8_t *value, uint8_t length, e_padding_type ptype, uint8_t pval) { @@ -53,7 +53,7 @@ static void *field_encode(const uint8_t *const value, * @param[in] length its byte-length * @return the encoded value */ -void *encode_uint(const uint8_t *const value, uint8_t length) { +void *encode_uint(const uint8_t *value, uint8_t length) { // no length check here since it will be checked by field_encode return field_encode(value, length, MSB, 0x00); } @@ -66,7 +66,7 @@ void *encode_uint(const uint8_t *const value, uint8_t length) { * @param[in] typesize the type size in bytes * @return the encoded value */ -void *encode_int(const uint8_t *const value, uint8_t length, uint8_t typesize) { +void *encode_int(const uint8_t *value, uint8_t length, uint8_t typesize) { uint8_t padding_value; if (length < 1) { @@ -91,7 +91,7 @@ void *encode_int(const uint8_t *const value, uint8_t length, uint8_t typesize) { * @param[in] length its byte-length * @return the encoded value */ -void *encode_bytes(const uint8_t *const value, uint8_t length) { +void *encode_bytes(const uint8_t *value, uint8_t length) { // no length check here since it will be checked by field_encode return field_encode(value, length, LSB, 0x00); } @@ -103,7 +103,7 @@ void *encode_bytes(const uint8_t *const value, uint8_t length) { * @param[in] length its byte-length * @return the encoded value */ -void *encode_boolean(const bool *const value, uint8_t length) { +void *encode_boolean(const bool *value, uint8_t length) { if (length != 1) // sanity check { apdu_response_code = APDU_RESPONSE_INVALID_DATA; @@ -119,7 +119,7 @@ void *encode_boolean(const bool *const value, uint8_t length) { * @param[in] length its byte-length * @return the encoded value */ -void *encode_address(const uint8_t *const value, uint8_t length) { +void *encode_address(const uint8_t *value, uint8_t length) { if (length != ADDRESS_LENGTH) // sanity check { apdu_response_code = APDU_RESPONSE_INVALID_DATA; diff --git a/src_features/signMessageEIP712/encode_field.h b/src_features/signMessageEIP712/encode_field.h index 648157c788..9fcfbebf44 100644 --- a/src_features/signMessageEIP712/encode_field.h +++ b/src_features/signMessageEIP712/encode_field.h @@ -5,8 +5,8 @@ #define EIP_712_ENCODED_FIELD_LENGTH 32 -void *encode_uint(const uint8_t *const value, uint8_t length); -void *encode_int(const uint8_t *const value, uint8_t length, uint8_t typesize); -void *encode_boolean(const bool *const value, uint8_t length); -void *encode_address(const uint8_t *const value, uint8_t length); -void *encode_bytes(const uint8_t *const value, uint8_t length); +void *encode_uint(const uint8_t *value, uint8_t length); +void *encode_int(const uint8_t *value, uint8_t length, uint8_t typesize); +void *encode_boolean(const bool *value, uint8_t length); +void *encode_address(const uint8_t *value, uint8_t length); +void *encode_bytes(const uint8_t *value, uint8_t length); diff --git a/src_features/signMessageEIP712/field_hash.c b/src_features/signMessageEIP712/field_hash.c index 09bf4f1b2e..12902a2a9c 100644 --- a/src_features/signMessageEIP712/field_hash.c +++ b/src_features/signMessageEIP712/field_hash.c @@ -77,7 +77,7 @@ static const uint8_t *field_hash_prepare(const s_struct_712_field *field_ptr, * @return pointer to the encoded value */ static const uint8_t *field_hash_finalize_static(const s_struct_712_field *field_ptr, - const uint8_t *const data, + const uint8_t *data, uint8_t data_length) { uint8_t *value = NULL; @@ -167,7 +167,7 @@ static void field_hash_feed_parent(e_type field_type, const uint8_t *hash) { * @return whether an error occurred or not */ static bool field_hash_domain_special_fields(const s_struct_712_field *field_ptr, - const uint8_t *const data, + const uint8_t *data, uint8_t data_length) { const char *key; const char *ethermint_vc = "cosmos"; @@ -215,7 +215,7 @@ static bool field_hash_domain_special_fields(const s_struct_712_field *field_ptr * @return whether an error occurred or not */ static bool field_hash_finalize(const s_struct_712_field *field_ptr, - const uint8_t *const data, + const uint8_t *data, uint8_t data_length) { const uint8_t *value = NULL; diff --git a/src_features/signMessageEIP712/path.c b/src_features/signMessageEIP712/path.c index a3470d21e3..0a968bd3bf 100644 --- a/src_features/signMessageEIP712/path.c +++ b/src_features/signMessageEIP712/path.c @@ -79,7 +79,7 @@ static const void *get_nth_field(uint8_t *fields_count_ptr, uint8_t n) { * @param[out] the number of fields in the depth of the returned field * @return the field which the path points to */ -static inline const void *get_field(uint8_t *const fields_count) { +static inline const void *get_field(uint8_t *fields_count) { return get_nth_field(fields_count, path_struct->depth_count); } @@ -187,7 +187,7 @@ static bool finalize_hash_depth(uint8_t *hash) { * * @param[in] hash pointer to given hash */ -static bool feed_last_hash_depth(const uint8_t *const hash) { +static bool feed_last_hash_depth(const uint8_t *hash) { const cx_sha3_t *hash_ctx; hash_ctx = get_last_hash_ctx(); @@ -386,7 +386,7 @@ static bool path_update(bool skip_if_array, bool stop_at_array, bool do_typehash * @param[in] name_length the root struct name length * @return boolean indicating if it was successful or not */ -bool path_set_root(const char *const struct_name, uint8_t name_length) { +bool path_set_root(const char *struct_name, uint8_t name_length) { uint8_t hash[KECCAK256_HASH_BYTESIZE]; if (path_struct == NULL) { diff --git a/src_features/signMessageEIP712/path.h b/src_features/signMessageEIP712/path.h index fa6df60dff..394939edec 100644 --- a/src_features/signMessageEIP712/path.h +++ b/src_features/signMessageEIP712/path.h @@ -24,7 +24,7 @@ typedef struct { e_root_type root_type; } s_path; -bool path_set_root(const char *const struct_name, uint8_t length); +bool path_set_root(const char *struct_name, uint8_t length); const void *path_get_field(void); bool path_advance(bool do_typehash); bool path_init(void); diff --git a/src_features/signMessageEIP712/type_hash.c b/src_features/signMessageEIP712/type_hash.c index 8268a97bf9..ca4763d9ca 100644 --- a/src_features/signMessageEIP712/type_hash.c +++ b/src_features/signMessageEIP712/type_hash.c @@ -147,7 +147,7 @@ static bool compare_struct_deps(const s_struct_dep *a, const s_struct_dep *b) { * @param[out] hash_buf buffer containing the resulting type_hash * @return whether the type_hash was successful or not */ -bool type_hash(const char *const struct_name, const uint8_t struct_name_length, uint8_t *hash_buf) { +bool type_hash(const char *struct_name, const uint8_t struct_name_length, uint8_t *hash_buf) { const void *struct_ptr; s_struct_dep *deps; cx_err_t error = CX_INTERNAL_ERROR; diff --git a/src_features/signMessageEIP712/type_hash.h b/src_features/signMessageEIP712/type_hash.h index 955fe1f1cd..94499ee139 100644 --- a/src_features/signMessageEIP712/type_hash.h +++ b/src_features/signMessageEIP712/type_hash.h @@ -3,4 +3,4 @@ #include #include -bool type_hash(const char *const struct_name, const uint8_t struct_name_length, uint8_t *hash_buf); +bool type_hash(const char *struct_name, const uint8_t struct_name_length, uint8_t *hash_buf); diff --git a/src_features/signMessageEIP712/typed_data.c b/src_features/signMessageEIP712/typed_data.c index 802f6cf368..5fabc3b1d0 100644 --- a/src_features/signMessageEIP712/typed_data.c +++ b/src_features/signMessageEIP712/typed_data.c @@ -78,7 +78,7 @@ const s_struct_712 *get_structn(const char *name, uint8_t length) { * @param[in] name name * @return whether it was successful */ -bool set_struct_name(uint8_t length, const uint8_t *const name) { +bool set_struct_name(uint8_t length, const uint8_t *name) { s_struct_712 *new_struct; if (name == NULL) { @@ -112,7 +112,7 @@ bool set_struct_name(uint8_t length, const uint8_t *const name) { * @return whether it was successful or not */ static bool set_struct_field_typedesc(s_struct_712_field *field, - const uint8_t *const data, + const uint8_t *data, uint8_t *data_idx, uint8_t length) { uint8_t typedesc; @@ -138,7 +138,7 @@ static bool set_struct_field_typedesc(s_struct_712_field *field, * @return whether it was successful */ static bool set_struct_field_custom_typename(s_struct_712_field *field, - const uint8_t *const data, + const uint8_t *data, uint8_t *data_idx, uint8_t length) { uint8_t typename_len; @@ -176,7 +176,7 @@ static bool set_struct_field_custom_typename(s_struct_712_field *field, * @return whether it was successful */ static bool set_struct_field_array(s_struct_712_field *field, - const uint8_t *const data, + const uint8_t *data, uint8_t *data_idx, uint8_t length) { if ((*data_idx + sizeof(field->array_level_count)) > length) // check buffer bound @@ -225,7 +225,7 @@ static bool set_struct_field_array(s_struct_712_field *field, * @return whether it was successful */ static bool set_struct_field_typesize(s_struct_712_field *field, - const uint8_t *const data, + const uint8_t *data, uint8_t *data_idx, uint8_t length) { // copy TypeSize @@ -246,7 +246,7 @@ static bool set_struct_field_typesize(s_struct_712_field *field, * @return whether it was successful */ static bool set_struct_field_keyname(s_struct_712_field *field, - const uint8_t *const data, + const uint8_t *data, uint8_t *data_idx, uint8_t length) { uint8_t keyname_len; @@ -283,7 +283,7 @@ static bool set_struct_field_keyname(s_struct_712_field *field, * @param[in] data the field data * @return whether it was successful */ -bool set_struct_field(uint8_t length, const uint8_t *const data) { +bool set_struct_field(uint8_t length, const uint8_t *data) { uint8_t data_idx = 0; if ((data == NULL) || (length == 0)) { diff --git a/src_features/signMessageEIP712/typed_data.h b/src_features/signMessageEIP712/typed_data.h index b6642cde13..bbb4d2c461 100644 --- a/src_features/signMessageEIP712/typed_data.h +++ b/src_features/signMessageEIP712/typed_data.h @@ -57,14 +57,14 @@ typedef struct struct_712 { s_struct_712_field *fields; } s_struct_712; -const void *get_array_in_mem(const void *ptr, uint8_t *const array_size); -const char *get_string_in_mem(const uint8_t *ptr, uint8_t *const string_length); +const void *get_array_in_mem(const void *ptr, uint8_t *array_size); +const char *get_string_in_mem(const uint8_t *ptr, uint8_t *string_length); const char *get_struct_field_custom_typename(const s_struct_712_field *field_ptr); const char *get_struct_field_typename(const s_struct_712_field *ptr); -e_array_type struct_field_array_depth(const uint8_t *ptr, uint8_t *const array_size); +e_array_type struct_field_array_depth(const uint8_t *ptr, uint8_t *array_size); const s_struct_712 *get_struct_list(void); const s_struct_712 *get_structn(const char *name_ptr, uint8_t name_length); -bool set_struct_name(uint8_t length, const uint8_t *const name); -bool set_struct_field(uint8_t length, const uint8_t *const data); +bool set_struct_name(uint8_t length, const uint8_t *name); +bool set_struct_field(uint8_t length, const uint8_t *data); bool typed_data_init(void); void typed_data_deinit(void); From f47666aa9bde20c09bfa2451ca78035fd4c1ebc2 Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Thu, 19 Jun 2025 15:47:05 +0200 Subject: [PATCH 5/6] Added EIP-712 memory allocation cleanup --- src_features/signMessageEIP712/context_712.c | 2 ++ src_features/signMessageEIP712/field_hash.c | 5 ++- src_features/signMessageEIP712/path.c | 18 ++++++++-- .../signMessageEIP712/sol_typenames.c | 12 ++++++- .../signMessageEIP712/sol_typenames.h | 1 + src_features/signMessageEIP712/type_hash.c | 6 ++++ src_features/signMessageEIP712/typed_data.c | 18 +++++++++- src_features/signMessageEIP712/ui_logic.c | 36 +++++++++++++++++-- 8 files changed, 90 insertions(+), 8 deletions(-) diff --git a/src_features/signMessageEIP712/context_712.c b/src_features/signMessageEIP712/context_712.c index 02dbcbcca2..c45cc2e076 100644 --- a/src_features/signMessageEIP712/context_712.c +++ b/src_features/signMessageEIP712/context_712.c @@ -66,6 +66,8 @@ void eip712_context_deinit(void) { path_deinit(); field_hash_deinit(); ui_712_deinit(); + sol_typenames_deinit(); + app_mem_free(eip712_context); eip712_context = NULL; reset_app_context(); } diff --git a/src_features/signMessageEIP712/field_hash.c b/src_features/signMessageEIP712/field_hash.c index 12902a2a9c..38b366bddb 100644 --- a/src_features/signMessageEIP712/field_hash.c +++ b/src_features/signMessageEIP712/field_hash.c @@ -38,7 +38,10 @@ bool field_hash_init(void) { * Deinitialize the field hash context */ void field_hash_deinit(void) { - fh = NULL; + if (fh != NULL) { + app_mem_free(fh); + fh = NULL; + } } /** diff --git a/src_features/signMessageEIP712/path.c b/src_features/signMessageEIP712/path.c index 0a968bd3bf..f2b22b317d 100644 --- a/src_features/signMessageEIP712/path.c +++ b/src_features/signMessageEIP712/path.c @@ -156,8 +156,13 @@ cx_sha3_t *get_last_hash_ctx(void) { return &((s_hash_ctx *) hash_ctx)->hash; } +// to be used as a \ref f_list_node_del +static void delete_hash_ctx(s_hash_ctx *ctx) { + app_mem_free(ctx); +} + static void remove_last_hash_ctx(void) { - flist_pop_back((s_flist_node **) &g_hash_ctxs, NULL); + flist_pop_back((s_flist_node **) &g_hash_ctxs, (f_list_node_del) &delete_hash_ctx); } /** @@ -221,6 +226,7 @@ static bool push_new_hash_depth(bool init) { flist_push_back((s_flist_node **) &g_hash_ctxs, (s_flist_node *) hash_ctx); return true; end: + app_mem_free(hash_ctx); return false; } @@ -788,5 +794,13 @@ bool path_init(void) { * De-initialize the path context */ void path_deinit(void) { - path_struct = NULL; + if (path_struct != NULL) { + app_mem_free(path_struct); + path_struct = NULL; + } + if (path_backup != NULL) { + app_mem_free(path_backup); + path_backup = NULL; + } + flist_clear((s_flist_node **) &g_hash_ctxs, (f_list_node_del) &delete_hash_ctx); } diff --git a/src_features/signMessageEIP712/sol_typenames.c b/src_features/signMessageEIP712/sol_typenames.c index 098354ad68..5e25145e3c 100644 --- a/src_features/signMessageEIP712/sol_typenames.c +++ b/src_features/signMessageEIP712/sol_typenames.c @@ -22,7 +22,7 @@ bool sol_typenames_init(void) { uint8_t count = TYPES_COUNT - 1; // because 0 is custom (so not solidity) if (g_sol_types != NULL) { - g_sol_types = NULL; + sol_typenames_deinit(); return false; } if ((g_sol_types = app_mem_alloc(sizeof(*g_sol_types) * count)) == NULL) { @@ -63,6 +63,16 @@ bool sol_typenames_init(void) { return true; } +void sol_typenames_deinit(void) { + if (g_sol_types != NULL) { + for (int i = 0; i < (TYPES_COUNT - 1); ++i) { + app_mem_free(g_sol_types[i].name); + } + app_mem_free(g_sol_types); + g_sol_types = NULL; + } +} + /** * Get typename from a given field * diff --git a/src_features/signMessageEIP712/sol_typenames.h b/src_features/signMessageEIP712/sol_typenames.h index c5ad460d08..453c600130 100644 --- a/src_features/signMessageEIP712/sol_typenames.h +++ b/src_features/signMessageEIP712/sol_typenames.h @@ -5,4 +5,5 @@ #include "typed_data.h" bool sol_typenames_init(void); +void sol_typenames_deinit(void); const char *get_struct_field_sol_typename(const s_struct_712_field *field_ptr); diff --git a/src_features/signMessageEIP712/type_hash.c b/src_features/signMessageEIP712/type_hash.c index ca4763d9ca..487c6f5096 100644 --- a/src_features/signMessageEIP712/type_hash.c +++ b/src_features/signMessageEIP712/type_hash.c @@ -139,6 +139,11 @@ static bool compare_struct_deps(const s_struct_dep *a, const s_struct_dep *b) { return true; } +// to be used as a \ref f_list_node_del +static void delete_struct_dep(s_struct_dep *sdep) { + app_mem_free(sdep); +} + /** * Encode the structure's type and hash it * @@ -175,6 +180,7 @@ bool type_hash(const char *struct_name, const uint8_t struct_name_length, uint8_ } } + flist_clear((s_flist_node **) &deps, (f_list_node_del) &delete_struct_dep); // copy hash into memory CX_CHECK(cx_hash_no_throw((cx_hash_t *) &global_sha3, CX_LAST, diff --git a/src_features/signMessageEIP712/typed_data.c b/src_features/signMessageEIP712/typed_data.c index 5fabc3b1d0..b391cb3147 100644 --- a/src_features/signMessageEIP712/typed_data.c +++ b/src_features/signMessageEIP712/typed_data.c @@ -20,8 +20,24 @@ bool typed_data_init(void) { return true; } +// to be used as a \ref f_list_node_del +static void delete_field(s_struct_712_field *f) { + if (f->type_name != NULL) app_mem_free(f->type_name); + if (f->array_levels != NULL) app_mem_free(f->array_levels); + if (f->key_name != NULL) app_mem_free(f->key_name); + app_mem_free(f); +} + +// to be used as a \ref f_list_node_del +static void delete_struct(s_struct_712 *s) { + if (s->name != NULL) app_mem_free(s->name); + if (s->fields != NULL) + flist_clear((s_flist_node **) &s->fields, (f_list_node_del) &delete_field); + app_mem_free(s); +} + void typed_data_deinit(void) { - g_structs = NULL; + flist_clear((s_flist_node **) &g_structs, (f_list_node_del) &delete_struct); } /** diff --git a/src_features/signMessageEIP712/ui_logic.c b/src_features/signMessageEIP712/ui_logic.c index 05a8e75297..d8e8278749 100644 --- a/src_features/signMessageEIP712/ui_logic.c +++ b/src_features/signMessageEIP712/ui_logic.c @@ -71,6 +71,23 @@ typedef struct { static t_ui_context *ui_ctx = NULL; +// to be used as a \ref f_list_node_del +static void delete_filter_crc(s_filter_crc *fcrc) { + app_mem_free(fcrc); +} + +// to be used as a \ref f_list_node_del +static void delete_ui_pair(s_ui_712_pair *pair) { + if (pair->key != NULL) app_mem_free(pair->key); + if (pair->value != NULL) app_mem_free(pair->value); + app_mem_free(pair); +} + +// to be used as a \ref f_list_node_del +static void delete_amount_join(s_amount_join *join) { + app_mem_free(join); +} + /** * Checks on the UI context to determine if the next EIP 712 field should be shown * @@ -485,7 +502,9 @@ static bool ui_712_format_amount_join(void) { } ui_ctx->field_flags |= UI_712_FIELD_SHOWN; ui_712_set_title(amount_join->name, strlen(amount_join->name)); - explicit_bzero(amount_join, sizeof(*amount_join)); + flist_remove((s_flist_node **) &ui_ctx->amount.joins, + (s_flist_node *) amount_join, + (f_list_node_del) delete_amount_join); return true; } @@ -730,7 +749,18 @@ bool ui_712_init(void) { * Deinit function that simply unsets the struct pointer to NULL */ void ui_712_deinit(void) { - ui_ctx = NULL; + if (ui_ctx != NULL) { + app_mem_free(ui_ctx); + if (ui_ctx->filters_crc != NULL) + flist_clear((s_flist_node **) &ui_ctx->filters_crc, + (f_list_node_del) &delete_filter_crc); + if (ui_ctx->ui_pairs != NULL) + flist_clear((s_flist_node **) &ui_ctx->ui_pairs, (f_list_node_del) &delete_ui_pair); + if (ui_ctx->amount.joins != NULL) + flist_clear((s_flist_node **) &ui_ctx->amount.joins, + (f_list_node_del) &delete_amount_join); + ui_ctx = NULL; + } } /** @@ -1005,7 +1035,7 @@ void ui_712_delete_pairs(size_t keep) { size = flist_size((s_flist_node **) &ui_ctx->ui_pairs); if (size > 0) { while (size > keep) { - flist_pop_front((s_flist_node **) &ui_ctx->ui_pairs, NULL); + flist_pop_front((s_flist_node **) &ui_ctx->ui_pairs, (f_list_node_del) &delete_ui_pair); size -= 1; } } From 37e3c9c63afb14695eaa4ed5db0d104766aecb6b Mon Sep 17 00:00:00 2001 From: Alexandre Paillier Date: Tue, 10 Jun 2025 17:40:32 +0200 Subject: [PATCH 6/6] Removed legacy memory allocator --- src/mem.c | 61 +------------------------------------------------ src/mem.h | 5 ---- src/mem_utils.c | 30 ------------------------ src/mem_utils.h | 4 ---- 4 files changed, 1 insertion(+), 99 deletions(-) diff --git a/src/mem.c b/src/mem.c index 1f10b61d61..8942a6fa8b 100644 --- a/src/mem.c +++ b/src/mem.c @@ -11,12 +11,9 @@ #include "mem_alloc.h" #include "os_print.h" -#define SIZE_MEM_BUFFER_MAIN 10240 -#define SIZE_MEM_BUFFER_ALT 2048 -#define SIZE_MEM_BUFFER (SIZE_MEM_BUFFER_MAIN + SIZE_MEM_BUFFER_ALT) +#define SIZE_MEM_BUFFER (1024 * 12) static uint8_t mem_buffer[SIZE_MEM_BUFFER] __attribute__((aligned(sizeof(intmax_t)))); -static uint16_t mem_legacy_idx; static mem_ctx_t mem_ctx = NULL; #ifdef HAVE_MEMORY_PROFILING @@ -55,59 +52,3 @@ void app_mem_free_impl(void *ptr, const char *file, int line) { #endif mem_free(mem_ctx, ptr); } - -/** - * Initializes the memory buffer index - */ -void mem_legacy_init(void) { - mem_legacy_idx = 0; - // initialize the new allocator to still be able to use it, just in case - mem_ctx = mem_init(mem_buffer + SIZE_MEM_BUFFER_MAIN, SIZE_MEM_BUFFER_ALT); -} - -/** - * Resets the memory buffer index - */ -void mem_legacy_reset(void) { - mem_legacy_init(); -} - -/** - * Allocates (push) a chunk of the memory buffer of a given size. - * - * Checks to see if there are enough space left in the memory buffer, returns - * the current location in the memory buffer and moves the index accordingly. - * - * @param[in] size Requested allocation size in bytes - * @return Allocated memory pointer; \ref NULL if not enough space left. - */ -void *mem_legacy_alloc(size_t size) { - size_t new_idx; - - if (__builtin_add_overflow((size_t) mem_legacy_idx, size, &new_idx)) { - PRINTF("Error: overflow detected!\n"); - return NULL; - } - // Buffer exceeded - if (new_idx > SIZE_MEM_BUFFER_MAIN) { - PRINTF("Error: mem_alloc(%u) failed!\n", size); - return NULL; - } - mem_legacy_idx += size; - return &mem_buffer[mem_legacy_idx - size]; -} - -/** - * De-allocates (pop) a chunk of memory buffer by a given size. - * - * @param[in] size Requested deallocation size in bytes - */ -void mem_legacy_dealloc(size_t size) { - // More than is already allocated - if (size > mem_legacy_idx) { - PRINTF("Warning: mem_dealloc(%u) with a value larger than allocated!\n", size); - mem_legacy_idx = 0; - } else { - mem_legacy_idx -= size; - } -} diff --git a/src/mem.h b/src/mem.h index ce65c2e310..b4a56cbcc2 100644 --- a/src/mem.h +++ b/src/mem.h @@ -16,8 +16,3 @@ bool app_mem_init(void); void *app_mem_alloc_impl(size_t size, const char *file, int line); void app_mem_free_impl(void *ptr, const char *file, int line); - -void mem_legacy_init(void); -void mem_legacy_reset(void); -void *mem_legacy_alloc(size_t size); -void mem_legacy_dealloc(size_t size); diff --git a/src/mem_utils.c b/src/mem_utils.c index a405153a60..cf39a448a5 100644 --- a/src/mem_utils.c +++ b/src/mem_utils.c @@ -28,36 +28,6 @@ const char *mem_alloc_and_format_uint(uint32_t value) { return mem_ptr; } -/** - * Align memory by a given value - * - * @param[in] alignment given alignment value - * @return size of the padding required for proper alignment - */ -uint8_t mem_legacy_align(size_t alignment) { - uint8_t diff = (uintptr_t) mem_legacy_alloc(0) % alignment; - - if (diff > 0) { - diff = alignment - diff; - mem_legacy_alloc(diff); - } - return diff; -} - -/** - * Allocate and align, required when dealing with pointers of multi-bytes data - * like structures that will be dereferenced at runtime. - * - * @param[in] size the size of the data we want to allocate in memory - * @param[in] alignment the byte alignment needed - * - * @return pointer to the memory area, \ref NULL if the allocation failed - */ -void *mem_legacy_alloc_and_align(size_t size, size_t alignment) { - mem_legacy_align(alignment); - return mem_legacy_alloc(size); -} - char *app_mem_strdup(const char *src) { char *dst; size_t length = strlen(src) + 1; diff --git a/src/mem_utils.h b/src/mem_utils.h index 1a03ab2a95..7e2ce6f0f0 100644 --- a/src/mem_utils.h +++ b/src/mem_utils.h @@ -2,9 +2,5 @@ #include -#define MEM_ALLOC_AND_ALIGN_TYPE(type) mem_legacy_alloc_and_align(sizeof(type), __alignof__(type)) - const char *mem_alloc_and_format_uint(uint32_t value); -uint8_t mem_legacy_align(size_t alignment); -void *mem_legacy_alloc_and_align(size_t size, size_t alignment); char *app_mem_strdup(const char *s);