From 77a6718f7656c8aa19ebe4855cd063cfe3ea8d98 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Fri, 25 Jan 2019 17:35:16 +0100 Subject: [PATCH] ethereum: address in messages is now string --- firmware/ethereum.c | 86 ++++++++++++++++++----- firmware/ethereum.h | 1 + firmware/fsm_msg_ethereum.h | 43 +++++++----- firmware/protob/messages-ethereum.options | 8 +-- vendor/trezor-common | 2 +- 5 files changed, 100 insertions(+), 40 deletions(-) diff --git a/firmware/ethereum.c b/firmware/ethereum.c index 29168d5740..500102c398 100644 --- a/firmware/ethereum.c +++ b/firmware/ethereum.c @@ -421,19 +421,21 @@ static void layoutEthereumFee(const uint8_t *value, uint32_t value_len, * - data (0 ..) */ -static bool ethereum_signing_check(EthereumSignTx *msg) +static bool ethereum_signing_check(const EthereumSignTx *msg) { if (!msg->has_gas_price || !msg->has_gas_limit) { return false; } - if (msg->to.size != 20 && msg->to.size != 0) { + size_t tolen = msg->has_to ? strlen(msg->to) : 0; + + if (tolen != 42 && tolen != 40 && tolen != 0) { /* Address has wrong length */ return false; } // sending transaction to address 0 (contract creation) without a data field - if (msg->to.size == 0 && (!msg->has_data_length || msg->data_length == 0)) { + if (tolen == 0 && (!msg->has_data_length || msg->data_length == 0)) { return false; } @@ -456,8 +458,15 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) msg->value.size = 0; if (!msg->has_data_initial_chunk) msg->data_initial_chunk.size = 0; - if (!msg->has_to) - msg->to.size = 0; + bool toset; + uint8_t pubkeyhash[20]; + if (msg->has_to && ethereum_parse(msg->to, pubkeyhash)) { + toset = true; + } else { + msg->to[0] = 0; + toset = false; + memzero(pubkeyhash, sizeof(pubkeyhash)); + } if (!msg->has_nonce) msg->nonce.size = 0; @@ -520,15 +529,15 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) const TokenType *token = NULL; // detect ERC-20 token - if (msg->to.size == 20 && msg->value.size == 0 && data_total == 68 && msg->data_initial_chunk.size == 68 + if (toset && msg->value.size == 0 && data_total == 68 && msg->data_initial_chunk.size == 68 && memcmp(msg->data_initial_chunk.bytes, "\xa9\x05\x9c\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16) == 0) { - token = tokenByChainAddress(chain_id, msg->to.bytes); + token = tokenByChainAddress(chain_id, pubkeyhash); } if (token != NULL) { layoutEthereumConfirmTx(msg->data_initial_chunk.bytes + 16, 20, msg->data_initial_chunk.bytes + 36, 32, token); } else { - layoutEthereumConfirmTx(msg->to.bytes, msg->to.size, msg->value.bytes, msg->value.size, NULL); + layoutEthereumConfirmTx(pubkeyhash, 20, msg->value.bytes, msg->value.size, NULL); } if (!protectButton(ButtonRequestType_ButtonRequest_SignTx, false)) { @@ -563,7 +572,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) rlp_length += rlp_calculate_length(msg->nonce.size, msg->nonce.bytes[0]); rlp_length += rlp_calculate_length(msg->gas_price.size, msg->gas_price.bytes[0]); rlp_length += rlp_calculate_length(msg->gas_limit.size, msg->gas_limit.bytes[0]); - rlp_length += rlp_calculate_length(msg->to.size, msg->to.bytes[0]); + rlp_length += rlp_calculate_length(toset ? 20 : 0, pubkeyhash[0]); rlp_length += rlp_calculate_length(msg->value.size, msg->value.bytes[0]); rlp_length += rlp_calculate_length(data_total, msg->data_initial_chunk.bytes[0]); if (tx_type) { @@ -586,7 +595,7 @@ void ethereum_signing_init(EthereumSignTx *msg, const HDNode *node) hash_rlp_field(msg->nonce.bytes, msg->nonce.size); hash_rlp_field(msg->gas_price.bytes, msg->gas_price.size); hash_rlp_field(msg->gas_limit.bytes, msg->gas_limit.size); - hash_rlp_field(msg->to.bytes, msg->to.size); + hash_rlp_field(pubkeyhash, toset ? 20 : 0); hash_rlp_field(msg->value.bytes, msg->value.size); hash_rlp_length(data_total, msg->data_initial_chunk.bytes[0]); hash_data(msg->data_initial_chunk.bytes, msg->data_initial_chunk.size); @@ -663,13 +672,18 @@ static void ethereum_message_hash(const uint8_t *message, size_t message_len, ui void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node, EthereumMessageSignature *resp) { - uint8_t hash[32]; - - if (!hdnode_get_ethereum_pubkeyhash(node, resp->address.bytes)) { + uint8_t pubkeyhash[20]; + if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash)) { return; } + resp->has_address = true; - resp->address.size = 20; + resp->address[0] = '0'; + resp->address[1] = 'x'; + ethereum_address_checksum(pubkeyhash, resp->address + 2, false, 0); + // ethereum_address_checksum adds trailing zero + + uint8_t hash[32]; ethereum_message_hash(msg->message.bytes, msg->message.size, hash); uint8_t v; @@ -686,8 +700,14 @@ void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node, E int ethereum_message_verify(const EthereumVerifyMessage *msg) { - if (msg->signature.size != 65 || msg->address.size != 20) { - fsm_sendFailure(FailureType_Failure_DataError, _("Malformed data")); + if (msg->signature.size != 65) { + fsm_sendFailure(FailureType_Failure_DataError, _("Malformed signature")); + return 1; + } + + uint8_t pubkeyhash[20]; + if (!ethereum_parse(msg->address, pubkeyhash)) { + fsm_sendFailure(FailureType_Failure_DataError, _("Malformed address")); return 1; } @@ -714,8 +734,40 @@ int ethereum_message_verify(const EthereumVerifyMessage *msg) keccak_Final(&ctx, hash); /* result are the least significant 160 bits */ - if (memcmp(msg->address.bytes, hash + 12, 20) != 0) { + if (memcmp(pubkeyhash, hash + 12, 20) != 0) { return 2; } return 0; } + +bool ethereum_parse(const char *address, uint8_t pubkeyhash[20]) +{ + memzero(pubkeyhash, 20); + size_t len = strlen(address); + if (len == 40) { + // do nothing + } else + if (len == 42) { + // check for "0x" prefix and strip it when required + if (address[0] != '0') return false; + if (address[1] != 'x' && address[1] != 'X') return false; + address += 2; + len -= 2; + } else { + return false; + } + for (size_t i = 0; i < len; i++) { + if (address[i] >= '0' && address[i] <= '9') { + pubkeyhash[i / 2] |= (address[i] - '0') << ((1 - (i % 2)) * 4); + } else + if (address[i] >= 'a' && address[i] <= 'f') { + pubkeyhash[i / 2] |= ((address[i] - 'a') + 10) << ((1 - (i % 2)) * 4); + } else + if (address[i] >= 'A' && address[i] <= 'F') { + pubkeyhash[i / 2] |= ((address[i] - 'A') + 10) << ((1 - (i % 2)) * 4); + } else { + return false; + } + } + return true; +} diff --git a/firmware/ethereum.h b/firmware/ethereum.h index f36b4e34ff..0bcc006273 100644 --- a/firmware/ethereum.h +++ b/firmware/ethereum.h @@ -31,5 +31,6 @@ void ethereum_signing_txack(const EthereumTxAck *msg); void ethereum_message_sign(const EthereumSignMessage *msg, const HDNode *node, EthereumMessageSignature *resp); int ethereum_message_verify(const EthereumVerifyMessage *msg); +bool ethereum_parse(const char *address, uint8_t pubkeyhash[20]); #endif diff --git a/firmware/fsm_msg_ethereum.h b/firmware/fsm_msg_ethereum.h index 1ae7efa800..bc32f46f98 100644 --- a/firmware/fsm_msg_ethereum.h +++ b/firmware/fsm_msg_ethereum.h @@ -89,28 +89,31 @@ void fsm_msgEthereumGetAddress(const EthereumGetAddress *msg) const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); if (!node) return; - resp->address.size = 20; + uint8_t pubkeyhash[20]; - if (!hdnode_get_ethereum_pubkeyhash(node, resp->address.bytes)) + if (!hdnode_get_ethereum_pubkeyhash(node, pubkeyhash)) return; + uint32_t slip44 = (msg->address_n_count > 1) ? (msg->address_n[1] & 0x7fffffff) : 0; + bool rskip60 = false; + uint32_t chain_id = 0; + // constants from trezor-common/defs/ethereum/networks.json + switch (slip44) { + case 137: rskip60 = true; chain_id = 30; break; + case 37310: rskip60 = true; chain_id = 31; break; + } + + resp->has_address = true; + resp->address[0] = '0'; + resp->address[1] = 'x'; + ethereum_address_checksum(pubkeyhash, resp->address + 2, rskip60, chain_id); + // ethereum_address_checksum adds trailing zero + if (msg->has_show_display && msg->show_display) { char desc[16]; strlcpy(desc, "Address:", sizeof(desc)); - uint32_t slip44 = msg->address_n[1] & 0x7fffffff; - bool rskip60 = false; - uint32_t chain_id = 0; - // constants from trezor-common/defs/ethereum/networks.json - switch (slip44) { - case 137: rskip60 = true; chain_id = 30; break; - case 37310: rskip60 = true; chain_id = 31; break; - } - - char address[43] = { '0', 'x' }; - ethereum_address_checksum(resp->address.bytes, address + 2, rskip60, chain_id); - - if (!fsm_layoutAddress(address, desc, false, 0, msg->address_n, msg->address_n_count, true)) { + if (!fsm_layoutAddress(resp->address, desc, false, 0, msg->address_n, msg->address_n_count, true)) { return; } } @@ -151,9 +154,13 @@ void fsm_msgEthereumVerifyMessage(const EthereumVerifyMessage *msg) return; } - char address[43] = { '0', 'x' }; - ethereum_address_checksum(msg->address.bytes, address + 2, false, 0); - layoutVerifyAddress(NULL, address); + uint8_t pubkeyhash[20]; + if (!ethereum_parse(msg->address, pubkeyhash)) { + fsm_sendFailure(FailureType_Failure_DataError, _("Invalid address")); + return; + } + + layoutVerifyAddress(NULL, msg->address); if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); diff --git a/firmware/protob/messages-ethereum.options b/firmware/protob/messages-ethereum.options index 07b148c97b..12f658f068 100644 --- a/firmware/protob/messages-ethereum.options +++ b/firmware/protob/messages-ethereum.options @@ -2,7 +2,7 @@ EthereumSignTx.address_n max_count:8 EthereumSignTx.nonce max_size:32 EthereumSignTx.gas_price max_size:32 EthereumSignTx.gas_limit max_size:32 -EthereumSignTx.to max_size:20 +EthereumSignTx.to max_size:43 EthereumSignTx.value max_size:32 EthereumSignTx.data_initial_chunk max_size:1024 @@ -14,15 +14,15 @@ EthereumTxAck.data_chunk max_size:1024 EthereumSignMessage.address_n max_count:8 EthereumSignMessage.message max_size:1024 -EthereumVerifyMessage.address max_size:20 +EthereumVerifyMessage.address max_size:43 EthereumVerifyMessage.signature max_size:65 EthereumVerifyMessage.message max_size:1024 -EthereumMessageSignature.address max_size:20 +EthereumMessageSignature.address max_size:43 EthereumMessageSignature.signature max_size:65 EthereumGetAddress.address_n max_count:8 EthereumGetPublicKey.address_n max_count:8 -EthereumAddress.address max_size:20 +EthereumAddress.address max_size:43 EthereumPublicKey.xpub max_size:113 diff --git a/vendor/trezor-common b/vendor/trezor-common index 78e232cf30..495b35e212 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit 78e232cf30d5d30ec1c7f06a740bbc990cc648e9 +Subproject commit 495b35e212f48ea2ac9e356febd5a49c3ee5254b