diff --git a/src_features/signMessageEIP712/context.h b/src_features/signMessageEIP712/context.h index 455e270..3386a6f 100644 --- a/src_features/signMessageEIP712/context.h +++ b/src_features/signMessageEIP712/context.h @@ -12,6 +12,7 @@ typedef struct uint8_t *structs_array; uint8_t *current_struct_fields_array; uint8_t contract_addr[ADDRESS_LENGTH]; + uint8_t schema_hash[224 / 8]; } s_eip712_context; extern s_eip712_context *eip712_context; diff --git a/src_features/signMessageEIP712/entrypoint.c b/src_features/signMessageEIP712/entrypoint.c index ada54a4..2bf6f18 100644 --- a/src_features/signMessageEIP712/entrypoint.c +++ b/src_features/signMessageEIP712/entrypoint.c @@ -732,6 +732,66 @@ bool provide_field_name(const uint8_t *const payload, uint8_t length) return ret; } +#include "hash_bytes.h" +#include "format_hash_field_type.h" + +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; + cx_sha256_t hash_ctx; // sha224 + + cx_sha224_init(&hash_ctx); + + struct_ptr = get_structs_array(eip712_context->structs_array, &structs_count); + hash_byte('{', (cx_hash_t*)&hash_ctx); + while (structs_count-- > 0) + { + name = get_struct_name(struct_ptr, &name_length); + hash_byte('"', (cx_hash_t*)&hash_ctx); + hash_nbytes((uint8_t*)name, name_length, (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) + { + 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*)"\",\"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) + { + hash_byte(',', (cx_hash_t*)&hash_ctx); + } + field_ptr = get_next_struct_field(field_ptr); + } + hash_byte(']', (cx_hash_t*)&hash_ctx); + if (structs_count > 0) + { + hash_byte(',', (cx_hash_t*)&hash_ctx); + } + struct_ptr = get_next_struct(struct_ptr); + } + hash_byte('}', (cx_hash_t*)&hash_ctx); + + // copy hash into context struct + cx_hash((cx_hash_t*)&hash_ctx, + CX_LAST, + NULL, + 0, + eip712_context->schema_hash, + sizeof(eip712_context->schema_hash)); + return true; +} + bool handle_eip712_filtering(const uint8_t *const apdu_buf) { bool ret = true; @@ -743,6 +803,7 @@ bool handle_eip712_filtering(const uint8_t *const apdu_buf) if (!N_storage.verbose_eip712) { ui_712_set_filtering_mode(EIP712_FILTERING_FULL); + ret = compute_schema_hash(); } break; case P1_CONTRACT_NAME: