diff --git a/legacy/firmware/ethereum.c b/legacy/firmware/ethereum.c index 1332f7e23..e13d6ffe7 100644 --- a/legacy/firmware/ethereum.c +++ b/legacy/firmware/ethereum.c @@ -51,6 +51,12 @@ static uint64_t chain_id; static bool eip1559; struct SHA3_CTX keccak_ctx = {0}; +static uint32_t signing_access_list_count; +static EthereumAccessList signing_access_list[8]; +_Static_assert(sizeof(signing_access_list) == + sizeof(((EthereumSignTxEIP1559 *)NULL)->access_list), + "access_list buffer size mismatch"); + struct signing_params { bool pubkeyhash_set; uint8_t pubkeyhash[20]; @@ -192,6 +198,29 @@ static int rlp_calculate_number_length(uint64_t number) { return length; } +static uint32_t rlp_calculate_access_list_keys_length( + const EthereumAccessList_storage_keys_t *keys, uint32_t keys_count) { + uint32_t keys_length = 0; + for (size_t i = 0; i < keys_count; i++) { + keys_length += rlp_calculate_length(keys[i].size, keys[i].bytes[0]); + } + return keys_length; +} + +static uint32_t rlp_calculate_access_list_length( + const EthereumAccessList access_list[8], uint32_t access_list_count) { + uint32_t length = 0; + for (size_t i = 0; i < access_list_count; i++) { + uint32_t address_length = rlp_calculate_length(20, 0xff); + uint32_t keys_length = rlp_calculate_access_list_keys_length( + access_list[i].storage_keys, access_list[i].storage_keys_count); + length += rlp_calculate_length( + address_length + rlp_calculate_length(keys_length, 0xff), 0xff); + } + + return length; +} + static void send_request_chunk(void) { int progress = 1000 - (data_total > 1000000 ? data_left / (data_total / 800) : data_left * 800 / data_total); @@ -212,7 +241,31 @@ static void send_signature(void) { layoutProgress(_("Signing"), 1000); if (eip1559) { - hash_rlp_list_length(0); + hash_rlp_list_length(rlp_calculate_access_list_length( + signing_access_list, signing_access_list_count)); + for (size_t i = 0; i < signing_access_list_count; i++) { + uint8_t address[20] = {0}; + if (!ethereum_parse(signing_access_list[i].address, address)) { + fsm_sendFailure(FailureType_Failure_DataError, _("Malformed address")); + ethereum_signing_abort(); + return; + } + + uint32_t address_length = + rlp_calculate_length(sizeof(address), address[0]); + uint32_t keys_length = rlp_calculate_access_list_keys_length( + signing_access_list[i].storage_keys, + signing_access_list[i].storage_keys_count); + + hash_rlp_list_length(address_length + + rlp_calculate_length(keys_length, 0xff)); + hash_rlp_field(address, sizeof(address)); + hash_rlp_list_length(keys_length); + for (size_t j = 0; j < signing_access_list[i].storage_keys_count; j++) { + hash_rlp_field(signing_access_list[i].storage_keys[j].bytes, + signing_access_list[i].storage_keys[j].size); + } + } } else { /* eip-155 replay protection */ /* hash v=chain_id, r=0, s=0 */ @@ -444,6 +497,8 @@ static bool ethereum_signing_init_common(struct signing_params *params) { chain_id = 0; memzero(&msg_tx_request, sizeof(EthereumTxRequest)); + memzero(signing_access_list, sizeof(signing_access_list)); + signing_access_list_count = 0; /* eip-155 chain id */ if (params->chain_id < 1) { @@ -725,7 +780,10 @@ void ethereum_signing_init_eip1559(const EthereumSignTxEIP1559 *msg, rlp_length += rlp_calculate_length(data_total, params.data_initial_chunk_bytes[0]); - rlp_length += rlp_calculate_length(0, 0xff); + rlp_length += + rlp_calculate_length(rlp_calculate_access_list_length( + msg->access_list, msg->access_list_count), + 0xff); /* Stage 2: Store header fields */ hash_rlp_number(EIP1559_TX_TYPE); @@ -744,6 +802,10 @@ void ethereum_signing_init_eip1559(const EthereumSignTxEIP1559 *msg, hash_data(params.data_initial_chunk_bytes, params.data_initial_chunk_size); data_left = data_total - params.data_initial_chunk_size; + /* make a copy of access_list, hash it after data is processed */ + memcpy(signing_access_list, msg->access_list, sizeof(signing_access_list)); + signing_access_list_count = msg->access_list_count; + memcpy(privkey, node->private_key, 32); if (data_left > 0) { diff --git a/legacy/firmware/protob/messages-ethereum.options b/legacy/firmware/protob/messages-ethereum.options index 89138a470..ead566378 100644 --- a/legacy/firmware/protob/messages-ethereum.options +++ b/legacy/firmware/protob/messages-ethereum.options @@ -16,7 +16,7 @@ EthereumSignTxEIP1559.value max_size:32 EthereumSignTxEIP1559.data_initial_chunk max_size:1024 EthereumSignTxEIP1559.access_list max_count:8 -EthereumAccessList.address max_size:32 +EthereumAccessList.address max_size:43 EthereumAccessList.storage_keys max_count:8 max_size:32 EthereumTxRequest.signature_r max_size:32 diff --git a/tests/device_tests/ethereum/test_signtx.py b/tests/device_tests/ethereum/test_signtx.py index eaf2e3d19..39ffccab5 100644 --- a/tests/device_tests/ethereum/test_signtx.py +++ b/tests/device_tests/ethereum/test_signtx.py @@ -172,7 +172,6 @@ def test_data_streaming(client): ) -@pytest.mark.skip_t1 def test_signtx_eip1559_access_list(client): with client: