From 7d084d9856fdabf4cd7c87a833f3d5b3a2c9676a Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Sat, 9 Nov 2019 17:58:44 -0700 Subject: [PATCH 01/44] boil your plates --- include/keepkey/firmware/coins.def | 2 + include/keepkey/firmware/cosmos.h | 12 ++++++ include/keepkey/firmware/fsm.h | 3 ++ include/keepkey/transport/interface.h | 1 + lib/firmware/CMakeLists.txt | 1 + lib/firmware/cosmos.c | 23 +++++++++++ lib/firmware/fsm.c | 1 + lib/firmware/fsm_msg_cosmos.h | 57 +++++++++++++++++++++++++++ lib/firmware/messagemap.def | 12 ++++++ lib/transport/CMakeLists.txt | 9 +++++ unittests/firmware/coins.cpp | 8 +++- 11 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 include/keepkey/firmware/cosmos.h create mode 100644 lib/firmware/cosmos.c create mode 100644 lib/firmware/fsm_msg_cosmos.h diff --git a/include/keepkey/firmware/coins.def b/include/keepkey/firmware/coins.def index 2abed6a63..51dcbe187 100644 --- a/include/keepkey/firmware/coins.def +++ b/include/keepkey/firmware/coins.def @@ -1,5 +1,6 @@ #define NO_CONTRACT {0, {0}} //coin_name coin_shortcut address_type maxfee_kb p2sh signed_message_header bip44_account_path forkid/chain_id decimals contract_address xpub_magic segwit force_bip143 curve_name cashaddr_prefix bech32_prefix decred xpub_magic_segwit_p2sh xpub_mmagic_segwit_native nanoaddr_prefix +<<<<<<< HEAD X(true, "Bitcoin", true, "BTC", true, 0, true, 100000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x80000000, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "bc", false, false, true, 77429938, true, 78792518, false, "" ) X(true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, "\x18" "Bitcoin Signed Message:\n", true, 0x80000001, false, 0, true, 8, false, NO_CONTRACT, true, 70617039, true, true, true, false, true, SECP256K1_STRING, false, "", true, "tb", false, false, true, 71979618, true, 73342198, false, "" ) X(true, "BitcoinCash", true, "BCH", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x80000091, true, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, true, true, SECP256K1_STRING, true, "bitcoincash", false, "", false, false, false, 0, false, 0, false, "" ) @@ -34,5 +35,6 @@ X(true, "GRS Testnet", true, "tGRS", true, 111, true, 100000 , true, 19 X(true, "Megacoin", true, "MEC", true, 50, true, 1000000, true, 5, true, "\x19" "MegaCoin Signed Message:\n", true, 0x800000d9, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, true, 77429938, true, 78792518, false, "" ) X(true, "Terracoin", true, "TRC", true, 0, true, 100000, true, 5, true, "\x19" "DarkCoin Signed Message:\n", true, 0x80000053, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) X(true, "Qtum", true, "QTUM", true, 58, true, 40000000, true, 50, true, "\x15" "Qtum Signed Message:\n", true, 0x800008fd, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "qc", false, false, true, 77429938, true, 78792518, false, "" ) +X(true, "Cosmos", true, "ATOM", false, NA, false, NA, false, NA, false, {0}, true, 0x80000076, false, 0, true, 6, false, NO_CONTRACT, false, 0, false, false, false, false, true, SECP256K1_STRING, false, "", false, "cosmos", false, false, false, 0, false, 0, false, "" ) #undef X #undef NO_CONTRACT diff --git a/include/keepkey/firmware/cosmos.h b/include/keepkey/firmware/cosmos.h new file mode 100644 index 000000000..9d7e4a501 --- /dev/null +++ b/include/keepkey/firmware/cosmos.h @@ -0,0 +1,12 @@ +#ifndef __COSMOS_H__ +#define __COSMOS_H__ + +#include +#include +#include +#include "crypto.h" +#include "fsm.h" +#include "messages.pb.h" +#include "trezor/crypto/bip32.h" + +#endif \ No newline at end of file diff --git a/include/keepkey/firmware/fsm.h b/include/keepkey/firmware/fsm.h index 4311db0d1..7f11d6d6d 100644 --- a/include/keepkey/firmware/fsm.h +++ b/include/keepkey/firmware/fsm.h @@ -92,6 +92,9 @@ void fsm_msgEosGetPublicKey(const EosGetPublicKey *msg); void fsm_msgEosSignTx(const EosSignTx *msg); void fsm_msgEosTxActionAck(const EosTxActionAck *msg); +void fsm_msgCosmosGetAddress(const CosmosGetAddress *msg); +void fsm_msgCosmosSignTx(const CosmosSignTx *msg); + #if DEBUG_LINK //void fsm_msgDebugLinkDecision(DebugLinkDecision *msg); void fsm_msgDebugLinkGetState(DebugLinkGetState *msg); diff --git a/include/keepkey/transport/interface.h b/include/keepkey/transport/interface.h index f30cf1266..a0966729a 100644 --- a/include/keepkey/transport/interface.h +++ b/include/keepkey/transport/interface.h @@ -27,6 +27,7 @@ #undef delete #include "messages-eos.pb.h" +#include "messages-cosmos.pb.h" #include "types.pb.h" #include "trezor_transport.h" diff --git a/lib/firmware/CMakeLists.txt b/lib/firmware/CMakeLists.txt index 56e0178a3..55dd5085a 100644 --- a/lib/firmware/CMakeLists.txt +++ b/lib/firmware/CMakeLists.txt @@ -2,6 +2,7 @@ set(sources app_confirm.c app_layout.c coins.c + cosmos.c crypto.c eos.c eos-contracts/eosio.system.c diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c new file mode 100644 index 000000000..c0ad440dd --- /dev/null +++ b/lib/firmware/cosmos.c @@ -0,0 +1,23 @@ +#include "keepkey/firmware/cosmos.h" + +#include "keepkey/board/confirm_sm.h" +#include "keepkey/board/util.h" +#include "keepkey/firmware/home_sm.h" +#include "keepkey/firmware/storage.h" +#include "trezor/crypto/memzero.h" +#include +#include + +static bool stellar_signing = false; +static StellarTransaction stellar_activeTx; + +/* + * Starts the signing process and parses the transaction header + */ +bool cosmos_getAddress(const CosmosGetAddress *msg) +{ +} + +bool cosmos_signTx(const CosmosSignTx *msg) +{ +} \ No newline at end of file diff --git a/lib/firmware/fsm.c b/lib/firmware/fsm.c index 6d2c48ea0..b5ea531b1 100644 --- a/lib/firmware/fsm.c +++ b/lib/firmware/fsm.c @@ -67,6 +67,7 @@ #include "trezor/crypto/secp256k1.h" #include "messages.pb.h" +#include "messages-cosmos.pb.h" #include "messages-eos.pb.h" #include "messages-nano.pb.h" diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h new file mode 100644 index 000000000..c6eedd63f --- /dev/null +++ b/lib/firmware/fsm_msg_cosmos.h @@ -0,0 +1,57 @@ +#include "keepkey/firmware/stellar.h" + +void fsm_msgCosmosGetAddress(const CosmosGetAddress *msg) +{ + RESP_INIT(CosmosAddress); + + CHECK_INITIALIZED + + CHECK_PIN + + // const HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); + // if (!node) + // { + // fsm_sendFailure(FailureType_Failure_FirmwareError, + // _("Failed to derive private key")); + // return; + // } + + // stellar_publicAddressAsStr(node->public_key + 1, resp->address, + // sizeof(resp->address)); + // if (msg->has_show_display && msg->show_display) + // { + // if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Share public account ID?"), "%s", resp->address)) + // { + // fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + // layoutHome(); + // return; + // } + // } + + // resp->has_address = true; + + // layoutHome(); + // msg_write(MessageType_MessageType_StellarAddress, resp); +} + +void fsm_msgCosmosSignTx(const CosmosSignTx *msg) +{ + CHECK_INITIALIZED + CHECK_PIN + + // if (!stellar_signingInit(msg)) + // { + // fsm_sendFailure(FailureType_Failure_FirmwareError, + // _("Failed to derive private key")); + // layoutHome(); + // return; + // } + + // Confirm transaction basics + // stellar_layoutTransactionSummary(msg); + + // Respond with a request for the first operation + RESP_INIT(CosmosSignedTx); + + // msg_write(MessageType_MessageType_StellarTxOpRequest, resp); +} diff --git a/lib/firmware/messagemap.def b/lib/firmware/messagemap.def index 55cafec88..e252d6ac2 100644 --- a/lib/firmware/messagemap.def +++ b/lib/firmware/messagemap.def @@ -41,6 +41,9 @@ MSG_IN(MessageType_MessageType_NanoGetAddress, NanoGetAddress, fsm_msgNanoGetAddress) MSG_IN(MessageType_MessageType_NanoSignTx, NanoSignTx, fsm_msgNanoSignTx) + MSG_IN(MessageType_MessageType_CosmosGetAddress, CosmosGetAddress, fsm_msgCosmosGetAddress) + MSG_IN(MessageType_MessageType_CosmosSignTx, CosmosSignTx, fsm_msgCosmosSignTx) + MSG_IN(MessageType_MessageType_EosGetPublicKey, EosGetPublicKey, fsm_msgEosGetPublicKey) MSG_IN(MessageType_MessageType_EosSignTx, EosSignTx, fsm_msgEosSignTx) MSG_IN(MessageType_MessageType_EosTxActionAck, EosTxActionAck, fsm_msgEosTxActionAck) @@ -72,6 +75,15 @@ MSG_OUT(MessageType_MessageType_EthereumMessageSignature, EthereumMessageSignature, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_NanoAddress, NanoAddress, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_NanoSignedTx, NanoSignedTx, NO_PROCESS_FUNC) +<<<<<<< HEAD +======= + MSG_OUT(MessageType_MessageType_StellarAddress, StellarAddress, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_StellarSignedTx, StellarSignedTx, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_StellarTxOpRequest, StellarTxOpRequest, NO_PROCESS_FUNC) + + MSG_OUT(MessageType_MessageType_CosmosAddress, CosmosAddress, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_CosmosSignedTx, CosmosSignedTx, NO_PROCESS_FUNC) +>>>>>>> 2c99a843... boil your plates MSG_OUT(MessageType_MessageType_EosPublicKey, EosPublicKey, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_EosTxActionRequest, EosTxActionRequest, NO_PROCESS_FUNC) diff --git a/lib/transport/CMakeLists.txt b/lib/transport/CMakeLists.txt index 2b991ed81..e929785ee 100644 --- a/lib/transport/CMakeLists.txt +++ b/lib/transport/CMakeLists.txt @@ -7,6 +7,7 @@ set(protoc_pb_sources ${DEVICE_PROTOCOL}/exchange.proto ${DEVICE_PROTOCOL}/messages-eos.proto ${DEVICE_PROTOCOL}/messages-nano.proto + ${DEVICE_PROTOCOL}/messages-cosmos.proto ${DEVICE_PROTOCOL}/messages.proto) set(protoc_pb_options @@ -14,6 +15,7 @@ set(protoc_pb_options ${CMAKE_SOURCE_DIR}/include/keepkey/transport/exchange.options ${CMAKE_SOURCE_DIR}/include/keepkey/transport/messages-eos.options ${CMAKE_SOURCE_DIR}/include/keepkey/transport/messages-nano.options + ${CMAKE_SOURCE_DIR}/include/keepkey/transport/messages-cosmos.options ${CMAKE_SOURCE_DIR}/include/keepkey/transport/messages.options) set(protoc_c_sources @@ -21,6 +23,7 @@ set(protoc_c_sources ${CMAKE_BINARY_DIR}/lib/transport/exchange.pb.c ${CMAKE_BINARY_DIR}/lib/transport/messages-eos.pb.c ${CMAKE_BINARY_DIR}/lib/transport/messages-nano.pb.c + ${CMAKE_BINARY_DIR}/lib/transport/messages-cosmos.pb.c ${CMAKE_BINARY_DIR}/lib/transport/messages.pb.c) set(protoc_c_headers @@ -28,6 +31,7 @@ set(protoc_c_headers ${CMAKE_BINARY_DIR}/include/exchange.pb.h ${CMAKE_BINARY_DIR}/include/messages-eos.pb.h ${CMAKE_BINARY_DIR}/include/messages-nano.pb.h + ${CMAKE_BINARY_DIR}/include/messages-cosmos.pb.h ${CMAKE_BINARY_DIR}/include/messages.pb.h) set(protoc_pb_sources_moved @@ -35,6 +39,7 @@ set(protoc_pb_sources_moved ${CMAKE_BINARY_DIR}/lib/transport/exchange.proto ${CMAKE_BINARY_DIR}/lib/transport/messages-eos.proto ${CMAKE_BINARY_DIR}/lib/transport/messages-nano.proto + ${CMAKE_BINARY_DIR}/lib/transport/messages-cosmos.proto ${CMAKE_BINARY_DIR}/lib/transport/messages.proto) add_custom_command( @@ -72,6 +77,10 @@ add_custom_command( ${PROTOC_BINARY} -I. -I/usr/include --plugin=nanopb=${NANOPB_DIR}/generator/protoc-gen-nanopb "--nanopb_out=-f messages-nano.options:." messages-nano.proto + COMMAND + ${PROTOC_BINARY} -I. -I/usr/include + --plugin=nanopb=${NANOPB_DIR}/generator/protoc-gen-nanopb + "--nanopb_out=-f messages-cosmos.options:." messages-cosmos.proto COMMAND ${PROTOC_BINARY} -I. -I/usr/include --plugin=nanopb=${NANOPB_DIR}/generator/protoc-gen-nanopb diff --git a/unittests/firmware/coins.cpp b/unittests/firmware/coins.cpp index 508cb5b64..03b3e13bd 100644 --- a/unittests/firmware/coins.cpp +++ b/unittests/firmware/coins.cpp @@ -11,8 +11,7 @@ extern "C" { static const int MaxLength = 256; -template -static std::string arrayToStr(const uint32_t (&address_n)[size]) { +template static std::string arrayToStr(const uint32_t (&address_n)[size]) { std::string str; std::stringstream OS(str); OS << "{"; @@ -162,6 +161,11 @@ TEST(Coins, BIP32AccountName) { { 0x80000000|44, 0x80000000|194, 0x80000000|42, 0, 0 }, 5, true, "EOS Account #42" }, + { + "Cosmos" + { 0x80000000|44, 0x80000000|118, 0x80000000|9, 0, 0 }, + 5, true, "Cosmos Account #9" + } }; for (const auto &vec : vector) { From c8be2d28446fd0b19a89f1aa8edf0fd851972f24 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Sun, 10 Nov 2019 11:10:44 -0700 Subject: [PATCH 02/44] partial --- lib/firmware/cosmos.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index c0ad440dd..8b210f990 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -8,8 +8,7 @@ #include #include -static bool stellar_signing = false; -static StellarTransaction stellar_activeTx; +static char* signing_template = "{\"account_number\":\"%d\",\"chain_id\":\"%s\",\"fee\":{\"amount\":[{\"amount\":\"%d\",\"denom\":\"uatom\"}],\"gas\":\"%d\"},\"memo\":\"%s\",\"msgs\":[{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{\"amount\":[{\"amount\":\"%d\",\"denom\":\"uatom\"}],\"from_address\":\"%s\",\"to_address\":\"%s\"}}],\"sequence\":\"%d\"}"; /* * Starts the signing process and parses the transaction header From aa3c08217a4076359a65d70db68a8fb3b4cce3fc Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Sun, 10 Nov 2019 19:17:35 -0700 Subject: [PATCH 03/44] works on emulator --- .gitmodules | 4 +- include/keepkey/firmware/cosmos.h | 15 +++ .../keepkey/transport/messages-cosmos.options | 13 +++ lib/firmware/cosmos.c | 70 +++++++++++- lib/firmware/fsm.c | 1 + lib/firmware/fsm_msg_cosmos.h | 107 ++++++++++++------ unittests/firmware/CMakeLists.txt | 1 + unittests/firmware/coins.cpp | 2 +- unittests/firmware/cosmos.cpp | 23 ++++ 9 files changed, 193 insertions(+), 43 deletions(-) create mode 100644 include/keepkey/transport/messages-cosmos.options create mode 100644 unittests/firmware/cosmos.cpp diff --git a/.gitmodules b/.gitmodules index 30597ede5..b878441b5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "deps/device-protocol"] path = deps/device-protocol - url = https://github.com/keepkey/device-protocol.git + url = https://github.com/Start9Labs/device-protocol.git [submodule "deps/trezor-firmware"] path = deps/crypto/trezor-firmware url = https://github.com/keepkey/trezor-firmware.git @@ -12,7 +12,7 @@ url = https://github.com/keepkey/code-signing-keys.git [submodule "deps/python-keepkey"] path = deps/python-keepkey - url = https://github.com/keepkey/python-keepkey.git + url = https://github.com/Start9Labs/python-keepkey.git [submodule "deps/qrenc/QR-Code-generator"] path = deps/qrenc/QR-Code-generator url = https://github.com/keepkey/QR-Code-generator.git diff --git a/include/keepkey/firmware/cosmos.h b/include/keepkey/firmware/cosmos.h index 9d7e4a501..b3a561f51 100644 --- a/include/keepkey/firmware/cosmos.h +++ b/include/keepkey/firmware/cosmos.h @@ -9,4 +9,19 @@ #include "messages.pb.h" #include "trezor/crypto/bip32.h" +bool cosmos_getAddress(const uint8_t *public_key, char *address); +bool cosmos_signTx(const uint8_t* private_key, + const uint64_t account_number, + const char* chain_id, + const size_t chain_id_length, + const uint32_t fee_uatom_amount, + const uint32_t gas, + const char* memo, + const size_t memo_length, + const uint64_t amount, + const char* from_address, + const char* to_address, + const uint64_t sequence, + uint8_t* signature); + #endif \ No newline at end of file diff --git a/include/keepkey/transport/messages-cosmos.options b/include/keepkey/transport/messages-cosmos.options new file mode 100644 index 000000000..1bbbaf610 --- /dev/null +++ b/include/keepkey/transport/messages-cosmos.options @@ -0,0 +1,13 @@ +CosmosGetAddress.address_n max_count:10 + +CosmosAddress.address max_size:45 + +CosmosSignTx.address_n max_count:10 +CosmosSignTx.chain_id max_size:32 +CosmosSignTx.memo max_size:256 + +CosmosMsgSend.from_address max_size:45 +CosmosMsgSend.to_address max_size:45 + +CosmosSignedTx.public_key max_size:33 +CosmosSignedTx.signature max_size:64 \ No newline at end of file diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index 8b210f990..402779b94 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -4,19 +4,79 @@ #include "keepkey/board/util.h" #include "keepkey/firmware/home_sm.h" #include "keepkey/firmware/storage.h" -#include "trezor/crypto/memzero.h" +#include "trezor/crypto/segwit_addr.h" +#include "trezor/crypto/ecdsa.h" #include #include -static char* signing_template = "{\"account_number\":\"%d\",\"chain_id\":\"%s\",\"fee\":{\"amount\":[{\"amount\":\"%d\",\"denom\":\"uatom\"}],\"gas\":\"%d\"},\"memo\":\"%s\",\"msgs\":[{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{\"amount\":[{\"amount\":\"%d\",\"denom\":\"uatom\"}],\"from_address\":\"%s\",\"to_address\":\"%s\"}}],\"sequence\":\"%d\"}"; +/* This was inlined from the trezor firmware because it was not exported. + * Forking the repository to expose this function is an option but we will + * need guidance on the way you want to handle syncing the locked commit, + * keepkey@HEAD, and the new commit. + */ +static int convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, size_t inlen, int inbits, int pad) { + uint32_t val = 0; + int bits = 0; + uint32_t maxv = (((uint32_t)1) << outbits) - 1; + while (inlen--) { + val = (val << inbits) | *(in++); + bits += inbits; + while (bits >= outbits) { + bits -= outbits; + out[(*outlen)++] = (val >> bits) & maxv; + } + } + if (pad) { + if (bits) { + out[(*outlen)++] = (val << (outbits - bits)) & maxv; + } + } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) { + return 0; + } + return 1; +} /* - * Starts the signing process and parses the transaction header + * Gets the address + * + * public_key: 33 byte compressed secp256k1 key + * address: output buffer + * + * returns true if successful */ -bool cosmos_getAddress(const CosmosGetAddress *msg) +bool cosmos_getAddress(const uint8_t *public_key, char *address) { + uint8_t hash160Buf[RIPEMD160_DIGEST_LENGTH]; + ecdsa_get_pubkeyhash(public_key, HASHER_SHA2_RIPEMD, hash160Buf); + + uint8_t fiveBitExpanded[32]; // RIPEMD160_DIGEST_LENGTH * 8 / 5 + size_t len = 0; + convert_bits(fiveBitExpanded, &len, 5, hash160Buf, 20, 8, 1); + // bech32encode + return bech32_encode(address, "cosmos", fiveBitExpanded, len) == 1; } -bool cosmos_signTx(const CosmosSignTx *msg) +#define SIGNING_TEMPLATE "{\"account_number\":\"%"PRIu64"\",\"chain_id\":\"%s\",\"fee\":{\"amount\":[{\"amount\":\"%"PRIu32"\",\"denom\":\"uatom\"}],\"gas\":\"%"PRIu32"\"},\"memo\":\"%s\",\"msgs\":[{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{\"amount\":[{\"amount\":\"%"PRIu64"\",\"denom\":\"uatom\"}],\"from_address\":\"%s\",\"to_address\":\"%s\"}}],\"sequence\":\"%"PRIu64"\"}" + +// 411 + memo + chain_id + NULL terminator +bool cosmos_signTx(const uint8_t* private_key, + const uint64_t account_number, + const char* chain_id, + const size_t chain_id_length, + const uint32_t fee_uatom_amount, + const uint32_t gas, + const char* memo, + const size_t memo_length, + const uint64_t amount, + const char* from_address, + const char* to_address, + const uint64_t sequence, + uint8_t* signature) { + size_t len = 412 + memo_length + chain_id_length; + char signBytes[len]; + snprintf(signBytes, len, SIGNING_TEMPLATE, account_number, chain_id, fee_uatom_amount, gas, memo, amount, from_address, to_address, sequence); + uint8_t hash[SHA256_DIGEST_LENGTH]; + sha256_Raw((uint8_t*)signBytes, strlen(signBytes), hash); + return ecdsa_sign_digest(&secp256k1, private_key, hash, signature, NULL, NULL) == 0; } \ No newline at end of file diff --git a/lib/firmware/fsm.c b/lib/firmware/fsm.c index b5ea531b1..4991417b8 100644 --- a/lib/firmware/fsm.c +++ b/lib/firmware/fsm.c @@ -284,3 +284,4 @@ void fsm_msgClearSession(ClearSession *msg) #include "fsm_msg_crypto.h" #include "fsm_msg_debug.h" #include "fsm_msg_eos.h" +#include "fsm_msg_cosmos.h" diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h index c6eedd63f..eabf034a5 100644 --- a/lib/firmware/fsm_msg_cosmos.h +++ b/lib/firmware/fsm_msg_cosmos.h @@ -1,4 +1,4 @@ -#include "keepkey/firmware/stellar.h" +#include "keepkey/firmware/cosmos.h" void fsm_msgCosmosGetAddress(const CosmosGetAddress *msg) { @@ -8,30 +8,26 @@ void fsm_msgCosmosGetAddress(const CosmosGetAddress *msg) CHECK_PIN - // const HDNode *node = stellar_deriveNode(msg->address_n, msg->address_n_count); - // if (!node) - // { - // fsm_sendFailure(FailureType_Failure_FirmwareError, - // _("Failed to derive private key")); - // return; - // } - - // stellar_publicAddressAsStr(node->public_key + 1, resp->address, - // sizeof(resp->address)); - // if (msg->has_show_display && msg->show_display) - // { - // if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Share public account ID?"), "%s", resp->address)) - // { - // fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); - // layoutHome(); - // return; - // } - // } - - // resp->has_address = true; - - // layoutHome(); - // msg_write(MessageType_MessageType_StellarAddress, resp); + uint32_t fingerprint; + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, &fingerprint); + if (!node) { return; } + + cosmos_getAddress(node->public_key, resp->address); + + if (msg->has_show_display && msg->show_display) + { + if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Share public account ID?"), "%s", resp->address)) + { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } + + resp->has_address = true; + + layoutHome(); + msg_write(MessageType_MessageType_CosmosAddress, resp); } void fsm_msgCosmosSignTx(const CosmosSignTx *msg) @@ -39,19 +35,60 @@ void fsm_msgCosmosSignTx(const CosmosSignTx *msg) CHECK_INITIALIZED CHECK_PIN - // if (!stellar_signingInit(msg)) - // { - // fsm_sendFailure(FailureType_Failure_FirmwareError, - // _("Failed to derive private key")); - // layoutHome(); - // return; - // } + uint32_t fingerprint; + const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, &fingerprint); + if (!node) { return; } // Confirm transaction basics - // stellar_layoutTransactionSummary(msg); + if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Main Details"), "From: %s\nTo: %s\nAmount: %f ATOM", msg->msg.from_address, msg->msg.to_address, (float)msg->msg.amount * 1E-6)) + { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Fee Details"), "Fee: %"PRIu32" uATOM\nGas: %"PRIu32"", msg->fee.amount, msg->fee.gas)) + { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Aux Details"), "Memo: \"%s\"\nChain ID: %s\nAccount #: %"PRIu64"", msg->memo, msg->chain_id, msg->account_number)) + { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } - // Respond with a request for the first operation RESP_INIT(CosmosSignedTx); - // msg_write(MessageType_MessageType_StellarTxOpRequest, resp); + if (!cosmos_signTx(node->private_key, + msg->account_number, + msg->chain_id, + strlen(msg->chain_id), + msg->fee.amount, + msg->fee.gas, + msg->memo, + strlen(msg->memo), + msg->msg.amount, + msg->msg.from_address, + msg->msg.to_address, + msg->sequence, + resp->signature.bytes)) + { + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Failed to sign transaction")); + layoutHome(); + return; + } + resp->signature.size = 64; + resp->has_signature = true; + + memcpy(resp->public_key.bytes, node->public_key, 33); + resp->public_key.size = 33; + resp->has_public_key = true; + + layoutHome(); + msg_write(MessageType_MessageType_CosmosSignedTx, resp); } diff --git a/unittests/firmware/CMakeLists.txt b/unittests/firmware/CMakeLists.txt index 5cd46aafc..7d055b883 100644 --- a/unittests/firmware/CMakeLists.txt +++ b/unittests/firmware/CMakeLists.txt @@ -1,5 +1,6 @@ set(sources coins.cpp + cosmos.cpp eos.cpp ethereum.cpp nano.cpp diff --git a/unittests/firmware/coins.cpp b/unittests/firmware/coins.cpp index 03b3e13bd..70c781d17 100644 --- a/unittests/firmware/coins.cpp +++ b/unittests/firmware/coins.cpp @@ -164,7 +164,7 @@ TEST(Coins, BIP32AccountName) { { "Cosmos" { 0x80000000|44, 0x80000000|118, 0x80000000|9, 0, 0 }, - 5, true, "Cosmos Account #9" + 5, true, "Cosmos Account #9\nAddress #0" } }; diff --git a/unittests/firmware/cosmos.cpp b/unittests/firmware/cosmos.cpp new file mode 100644 index 000000000..2be8dd7ff --- /dev/null +++ b/unittests/firmware/cosmos.cpp @@ -0,0 +1,23 @@ +extern "C" { +#include "keepkey/firmware/coins.h" +#include "keepkey/firmware/cosmos.h" +} + +#include "gtest/gtest.h" +#include + + +TEST(Cosmos, CosmosGetAddress) { + const uint8_t* pubkey = (uint8_t *)"\x03\xb7\x32\x9f\x67\x8e\x0a\xc1\x21\x4b\x77\x23\x57\x54\x66\x21\x9c\x77\xfe\xdb\xdd\x95\x5c\x33\x29\x1a\x74\xf1\x8b\xf5\xc8\xa4\xe2"; + char addr[46]; + ASSERT_TRUE(cosmos_getAddress(pubkey, addr)); + EXPECT_EQ(std::string("cosmos1am058pdux3hyulcmfgj4m3hhrlfn8nzm88u80q"), addr); +} + +TEST(Cosmos, CosmosSignTx) { + const uint8_t* privkey = (uint8_t*)"\x04\xde\xc0\xcc\x01\x3c\xd8\xab\x70\x87\xca\x14\x96\x0b\x76\x8c\x3d\x83\x45\x24\x48\xaa\x00\x64\xda\xe6\xfb\x04\xb5\xd9\x34\x76"; + uint8_t signature[64]; + const uint8_t* expected = (uint8_t*)"\x41\x99\x66\x30\x08\xef\xea\x75\x93\x56\x35\xe6\x1a\x11\xdf\xa3\x3c\xeb\xeb\x91\xc1\xca\xed\xc6\x0e\x5e\xef\x3c\xa2\xc0\x1f\x83\x48\x08\x36\xe6\x21\x89\x51\x14\x36\x64\x7f\xac\x5a\xbd\xc2\x9f\x54\xae\x3d\x7e\x47\x56\x43\xca\x33\xc7\xad\x2c\x8a\x53\x2b\x39"; + ASSERT_TRUE(cosmos_signTx(privkey, 0, "cosmoshub-2", strlen("cosmoshub-2"), 5000, 200000, "", 0, 100000, "cosmos1am058pdux3hyulcmfgj4m3hhrlfn8nzm88u80q", "cosmos18vhdczjut44gpsy804crfhnd5nq003nz0nf20v", 0, signature)); + EXPECT_TRUE(memcmp(expected, signature, 64) == 0); +} From bbb31d97398e2216a05f26ee5b93b5c747de7bcc Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Sun, 10 Nov 2019 22:50:40 -0700 Subject: [PATCH 04/44] tests passing --- .../keepkey/transport/messages-cosmos.options | 6 ++--- lib/firmware/fsm_msg_cosmos.h | 22 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/keepkey/transport/messages-cosmos.options b/include/keepkey/transport/messages-cosmos.options index 1bbbaf610..d9b318830 100644 --- a/include/keepkey/transport/messages-cosmos.options +++ b/include/keepkey/transport/messages-cosmos.options @@ -1,13 +1,13 @@ CosmosGetAddress.address_n max_count:10 -CosmosAddress.address max_size:45 +CosmosAddress.address max_size:46 CosmosSignTx.address_n max_count:10 CosmosSignTx.chain_id max_size:32 +CosmosSignTx.from_address max_size:46 +CosmosSignTx.to_address max_size:46 CosmosSignTx.memo max_size:256 -CosmosMsgSend.from_address max_size:45 -CosmosMsgSend.to_address max_size:45 CosmosSignedTx.public_key max_size:33 CosmosSignedTx.signature max_size:64 \ No newline at end of file diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h index eabf034a5..8059e3a5b 100644 --- a/lib/firmware/fsm_msg_cosmos.h +++ b/lib/firmware/fsm_msg_cosmos.h @@ -8,9 +8,9 @@ void fsm_msgCosmosGetAddress(const CosmosGetAddress *msg) CHECK_PIN - uint32_t fingerprint; - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, &fingerprint); + HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); if (!node) { return; } + hdnode_fill_public_key(node); cosmos_getAddress(node->public_key, resp->address); @@ -35,19 +35,19 @@ void fsm_msgCosmosSignTx(const CosmosSignTx *msg) CHECK_INITIALIZED CHECK_PIN - uint32_t fingerprint; - const HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, &fingerprint); + HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); if (!node) { return; } + hdnode_fill_public_key(node); // Confirm transaction basics - if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Main Details"), "From: %s\nTo: %s\nAmount: %f ATOM", msg->msg.from_address, msg->msg.to_address, (float)msg->msg.amount * 1E-6)) + if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Main Details"), "From: %s\nTo: %s\nAmount: %f ATOM", msg->from_address, msg->to_address, (float)msg->amount * 1E-6)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } - if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Fee Details"), "Fee: %"PRIu32" uATOM\nGas: %"PRIu32"", msg->fee.amount, msg->fee.gas)) + if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Fee Details"), "Fee: %"PRIu32" uATOM\nGas: %"PRIu32"", msg->fee_amount, msg->gas)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); @@ -67,13 +67,13 @@ void fsm_msgCosmosSignTx(const CosmosSignTx *msg) msg->account_number, msg->chain_id, strlen(msg->chain_id), - msg->fee.amount, - msg->fee.gas, + msg->fee_amount, + msg->gas, msg->memo, strlen(msg->memo), - msg->msg.amount, - msg->msg.from_address, - msg->msg.to_address, + msg->amount, + msg->from_address, + msg->to_address, msg->sequence, resp->signature.bytes)) { From 6f7444778210cc18b4e105b4d2b0042c6d5f2210 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Mon, 11 Nov 2019 21:06:03 -0700 Subject: [PATCH 05/44] fixes submodule deps for pr --- .gitmodules | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index b878441b5..30597ede5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "deps/device-protocol"] path = deps/device-protocol - url = https://github.com/Start9Labs/device-protocol.git + url = https://github.com/keepkey/device-protocol.git [submodule "deps/trezor-firmware"] path = deps/crypto/trezor-firmware url = https://github.com/keepkey/trezor-firmware.git @@ -12,7 +12,7 @@ url = https://github.com/keepkey/code-signing-keys.git [submodule "deps/python-keepkey"] path = deps/python-keepkey - url = https://github.com/Start9Labs/python-keepkey.git + url = https://github.com/keepkey/python-keepkey.git [submodule "deps/qrenc/QR-Code-generator"] path = deps/qrenc/QR-Code-generator url = https://github.com/keepkey/QR-Code-generator.git From c8661128ee9afa05e3627fee4cb9f8e11f23e207 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Tue, 12 Nov 2019 19:32:05 -0700 Subject: [PATCH 06/44] missed conflict header in rebase --- include/keepkey/firmware/coins.def | 1 - 1 file changed, 1 deletion(-) diff --git a/include/keepkey/firmware/coins.def b/include/keepkey/firmware/coins.def index 51dcbe187..4b8d3e378 100644 --- a/include/keepkey/firmware/coins.def +++ b/include/keepkey/firmware/coins.def @@ -1,6 +1,5 @@ #define NO_CONTRACT {0, {0}} //coin_name coin_shortcut address_type maxfee_kb p2sh signed_message_header bip44_account_path forkid/chain_id decimals contract_address xpub_magic segwit force_bip143 curve_name cashaddr_prefix bech32_prefix decred xpub_magic_segwit_p2sh xpub_mmagic_segwit_native nanoaddr_prefix -<<<<<<< HEAD X(true, "Bitcoin", true, "BTC", true, 0, true, 100000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x80000000, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "bc", false, false, true, 77429938, true, 78792518, false, "" ) X(true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, "\x18" "Bitcoin Signed Message:\n", true, 0x80000001, false, 0, true, 8, false, NO_CONTRACT, true, 70617039, true, true, true, false, true, SECP256K1_STRING, false, "", true, "tb", false, false, true, 71979618, true, 73342198, false, "" ) X(true, "BitcoinCash", true, "BCH", true, 0, true, 500000, true, 5, true, "\x18" "Bitcoin Signed Message:\n", true, 0x80000091, true, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, true, true, SECP256K1_STRING, true, "bitcoincash", false, "", false, false, false, 0, false, 0, false, "" ) From 06a31e5e2ede84f324c1e1f44d72caef70e3031f Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Tue, 12 Nov 2019 19:35:28 -0700 Subject: [PATCH 07/44] Update lib/firmware/cosmos.c Co-Authored-By: keepkeyjon <35975617+keepkeyjon@users.noreply.github.com> --- lib/firmware/cosmos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index 402779b94..cac0a88c5 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -49,7 +49,7 @@ bool cosmos_getAddress(const uint8_t *public_key, char *address) uint8_t hash160Buf[RIPEMD160_DIGEST_LENGTH]; ecdsa_get_pubkeyhash(public_key, HASHER_SHA2_RIPEMD, hash160Buf); - uint8_t fiveBitExpanded[32]; // RIPEMD160_DIGEST_LENGTH * 8 / 5 + uint8_t fiveBitExpanded[RIPEMD160_DIGEST_LENGTH * 8 / 5]; size_t len = 0; convert_bits(fiveBitExpanded, &len, 5, hash160Buf, 20, 8, 1); // bech32encode @@ -79,4 +79,4 @@ bool cosmos_signTx(const uint8_t* private_key, uint8_t hash[SHA256_DIGEST_LENGTH]; sha256_Raw((uint8_t*)signBytes, strlen(signBytes), hash); return ecdsa_sign_digest(&secp256k1, private_key, hash, signature, NULL, NULL) == 0; -} \ No newline at end of file +} From 8c5f92e292dca0be7fefb02f018d24512bb37395 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Tue, 12 Nov 2019 19:37:26 -0700 Subject: [PATCH 08/44] moves import --- .gitmodules | 4 +- deps/device-protocol | 2 +- lib/firmware/fsm.c | 82 ++++++++++++++++++++--------------- lib/firmware/fsm_msg_cosmos.h | 15 ++++--- 4 files changed, 60 insertions(+), 43 deletions(-) diff --git a/.gitmodules b/.gitmodules index 30597ede5..b878441b5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "deps/device-protocol"] path = deps/device-protocol - url = https://github.com/keepkey/device-protocol.git + url = https://github.com/Start9Labs/device-protocol.git [submodule "deps/trezor-firmware"] path = deps/crypto/trezor-firmware url = https://github.com/keepkey/trezor-firmware.git @@ -12,7 +12,7 @@ url = https://github.com/keepkey/code-signing-keys.git [submodule "deps/python-keepkey"] path = deps/python-keepkey - url = https://github.com/keepkey/python-keepkey.git + url = https://github.com/Start9Labs/python-keepkey.git [submodule "deps/qrenc/QR-Code-generator"] path = deps/qrenc/QR-Code-generator url = https://github.com/keepkey/QR-Code-generator.git diff --git a/deps/device-protocol b/deps/device-protocol index 88e294107..a956b3c5e 160000 --- a/deps/device-protocol +++ b/deps/device-protocol @@ -1 +1 @@ -Subproject commit 88e29410753b26d27882ed66460e8bd61d6980c6 +Subproject commit a956b3c5e4eb3367746bf9499ce1efe409839300 diff --git a/lib/firmware/fsm.c b/lib/firmware/fsm.c index 4991417b8..d3888246f 100644 --- a/lib/firmware/fsm.c +++ b/lib/firmware/fsm.c @@ -35,6 +35,7 @@ #include "keepkey/firmware/app_confirm.h" #include "keepkey/firmware/app_layout.h" #include "keepkey/firmware/coins.h" +#include "keepkey/firmware/cosmos.h" #include "keepkey/firmware/crypto.h" #include "keepkey/firmware/eos.h" #include "keepkey/firmware/eos-contracts.h" @@ -77,35 +78,40 @@ static uint8_t msg_resp[MAX_FRAME_SIZE] __attribute__((aligned(4))); -#define CHECK_INITIALIZED \ - if (!storage_isInitialized()) { \ +#define CHECK_INITIALIZED \ + if (!storage_isInitialized()) \ + { \ fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized"); \ - return; \ + return; \ } -#define CHECK_NOT_INITIALIZED \ - if (storage_isInitialized()) { \ +#define CHECK_NOT_INITIALIZED \ + if (storage_isInitialized()) \ + { \ fsm_sendFailure(FailureType_Failure_UnexpectedMessage, "Device is already initialized. Use Wipe first."); \ - return; \ + return; \ } -#define CHECK_PIN \ - if (!pin_protect_cached()) { \ - layoutHome(); \ - return; \ +#define CHECK_PIN \ + if (!pin_protect_cached()) \ + { \ + layoutHome(); \ + return; \ } -#define CHECK_PIN_UNCACHED \ - if (!pin_protect_uncached()) { \ - layoutHome(); \ - return; \ +#define CHECK_PIN_UNCACHED \ + if (!pin_protect_uncached()) \ + { \ + layoutHome(); \ + return; \ } -#define CHECK_PARAM_RET(cond, errormsg, retval) \ - if (!(cond)) { \ +#define CHECK_PARAM_RET(cond, errormsg, retval) \ + if (!(cond)) \ + { \ fsm_sendFailure(FailureType_Failure_Other, (errormsg)); \ - layoutHome(); \ - return retval; \ + layoutHome(); \ + return retval; \ } #define CHECK_PARAM(cond, errormsg) \ @@ -117,18 +123,18 @@ static const MessagesMap_t MessagesMap[] = { #undef MSG_IN #define MSG_IN(ID, STRUCT_NAME, PROCESS_FUNC) \ - _Static_assert(sizeof(STRUCT_NAME) <= MAX_DECODE_SIZE, "Message too big"); + _Static_assert(sizeof(STRUCT_NAME) <= MAX_DECODE_SIZE, "Message too big"); #undef MSG_OUT #define MSG_OUT(ID, STRUCT_NAME, PROCESS_FUNC) #undef RAW_IN #define RAW_IN(ID, STRUCT_NAME, PROCESS_FUNC) \ - _Static_assert(sizeof(STRUCT_NAME) <= MAX_DECODE_SIZE, "Message too big"); + _Static_assert(sizeof(STRUCT_NAME) <= MAX_DECODE_SIZE, "Message too big"); #undef DEBUG_IN #define DEBUG_IN(ID, STRUCT_NAME, PROCESS_FUNC) \ - _Static_assert(sizeof(STRUCT_NAME) <= MAX_DECODE_SIZE, "Message too big"); + _Static_assert(sizeof(STRUCT_NAME) <= MAX_DECODE_SIZE, "Message too big"); #undef DEBUG_OUT #define DEBUG_OUT(ID, STRUCT_NAME, PROCESS_FUNC) @@ -140,12 +146,15 @@ extern bool reset_msg_stack; static const CoinType *fsm_getCoin(bool has_name, const char *name) { const CoinType *coin; - if (has_name) { + if (has_name) + { coin = coinByName(name); - } else { + } + else + { coin = coinByName("Bitcoin"); } - if(!coin) + if (!coin) { fsm_sendFailure(FailureType_Failure_Other, "Invalid coin name"); layoutHome(); @@ -158,17 +167,19 @@ static const CoinType *fsm_getCoin(bool has_name, const char *name) static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, size_t address_n_count, uint32_t *fingerprint) { static HDNode CONFIDENTIAL node; - if (fingerprint) { + if (fingerprint) + { *fingerprint = 0; } - if (!get_curve_by_name(curve)) { + if (!get_curve_by_name(curve)) + { fsm_sendFailure(FailureType_Failure_SyntaxError, "Unknown ecdsa curve"); layoutHome(); return 0; } - if(!storage_getRootNode(curve, true, &node)) + if (!storage_getRootNode(curve, true, &node)) { fsm_sendFailure(FailureType_Failure_NotInitialized, "Device not initialized or passphrase request cancelled"); @@ -176,12 +187,12 @@ static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, return 0; } - if(!address_n || address_n_count == 0) + if (!address_n || address_n_count == 0) { return &node; } - if(hdnode_private_ckd_cached(&node, address_n, address_n_count, fingerprint) == 0) + if (hdnode_private_ckd_cached(&node, address_n, address_n_count, fingerprint) == 0) { fsm_sendFailure(FailureType_Failure_Other, "Failed to derive private key"); layoutHome(); @@ -192,7 +203,8 @@ static HDNode *fsm_getDerivedNode(const char *curve, const uint32_t *address_n, } #if DEBUG_LINK -static void sendFailureWrapper(FailureType code, const char *text) { +static void sendFailureWrapper(FailureType code, const char *text) +{ fsm_sendFailure(code, text); } #endif @@ -218,7 +230,7 @@ void fsm_init(void) void fsm_sendSuccess(const char *text) { - if(reset_msg_stack) + if (reset_msg_stack) { fsm_msgInitialize((Initialize *)0); reset_msg_stack = false; @@ -227,7 +239,7 @@ void fsm_sendSuccess(const char *text) RESP_INIT(Success); - if(text) + if (text) { resp->has_message = true; strlcpy(resp->message, text, sizeof(resp->message)); @@ -242,7 +254,7 @@ void fsm_sendFailureDebug(FailureType code, const char *text, const char *source void fsm_sendFailure(FailureType code, const char *text) #endif { - if(reset_msg_stack) + if (reset_msg_stack) { fsm_msgInitialize((Initialize *)0); reset_msg_stack = false; @@ -256,7 +268,8 @@ void fsm_sendFailure(FailureType code, const char *text) #if DEBUG_LINK resp->has_message = true; strlcpy(resp->message, source, sizeof(resp->message)); - if (text) { + if (text) + { strlcat(resp->message, text, sizeof(resp->message)); } #else @@ -269,7 +282,6 @@ void fsm_sendFailure(FailureType code, const char *text) msg_write(MessageType_MessageType_Failure, resp); } - void fsm_msgClearSession(ClearSession *msg) { (void)msg; diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h index 8059e3a5b..94156a0b9 100644 --- a/lib/firmware/fsm_msg_cosmos.h +++ b/lib/firmware/fsm_msg_cosmos.h @@ -1,4 +1,3 @@ -#include "keepkey/firmware/cosmos.h" void fsm_msgCosmosGetAddress(const CosmosGetAddress *msg) { @@ -9,7 +8,10 @@ void fsm_msgCosmosGetAddress(const CosmosGetAddress *msg) CHECK_PIN HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) { return; } + if (!node) + { + return; + } hdnode_fill_public_key(node); cosmos_getAddress(node->public_key, resp->address); @@ -36,7 +38,10 @@ void fsm_msgCosmosSignTx(const CosmosSignTx *msg) CHECK_PIN HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) { return; } + if (!node) + { + return; + } hdnode_fill_public_key(node); // Confirm transaction basics @@ -47,14 +52,14 @@ void fsm_msgCosmosSignTx(const CosmosSignTx *msg) return; } - if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Fee Details"), "Fee: %"PRIu32" uATOM\nGas: %"PRIu32"", msg->fee_amount, msg->gas)) + if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Fee Details"), "Fee: %" PRIu32 " uATOM\nGas: %" PRIu32 "", msg->fee_amount, msg->gas)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } - if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Aux Details"), "Memo: \"%s\"\nChain ID: %s\nAccount #: %"PRIu64"", msg->memo, msg->chain_id, msg->account_number)) + if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Aux Details"), "Memo: \"%s\"\nChain ID: %s\nAccount #: %" PRIu64 "", msg->memo, msg->chain_id, msg->account_number)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); From 0f2fcb99c73349efb235a0975436b03c19907a2a Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Tue, 12 Nov 2019 19:44:55 -0700 Subject: [PATCH 09/44] puts responsibility on getAddress to fill pubkey --- lib/firmware/cosmos.c | 41 +++++++++++++++++++++-------------- lib/firmware/fsm_msg_cosmos.h | 3 +-- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index cac0a88c5..7a0aceae8 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -14,23 +14,30 @@ * need guidance on the way you want to handle syncing the locked commit, * keepkey@HEAD, and the new commit. */ -static int convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t* in, size_t inlen, int inbits, int pad) { +static int convert_bits(uint8_t *out, size_t *outlen, int outbits, const uint8_t *in, size_t inlen, int inbits, int pad) +{ uint32_t val = 0; int bits = 0; uint32_t maxv = (((uint32_t)1) << outbits) - 1; - while (inlen--) { + while (inlen--) + { val = (val << inbits) | *(in++); bits += inbits; - while (bits >= outbits) { + while (bits >= outbits) + { bits -= outbits; out[(*outlen)++] = (val >> bits) & maxv; } } - if (pad) { - if (bits) { + if (pad) + { + if (bits) + { out[(*outlen)++] = (val << (outbits - bits)) & maxv; } - } else if (((val << (outbits - bits)) & maxv) || bits >= inbits) { + } + else if (((val << (outbits - bits)) & maxv) || bits >= inbits) + { return 0; } return 1; @@ -44,10 +51,12 @@ static int convert_bits(uint8_t* out, size_t* outlen, int outbits, const uint8_t * * returns true if successful */ -bool cosmos_getAddress(const uint8_t *public_key, char *address) +bool cosmos_getAddress(const HDNode *node, char *address) { + hdnode_fill_public_key(node); + uint8_t hash160Buf[RIPEMD160_DIGEST_LENGTH]; - ecdsa_get_pubkeyhash(public_key, HASHER_SHA2_RIPEMD, hash160Buf); + ecdsa_get_pubkeyhash(node->public_key, HASHER_SHA2_RIPEMD, hash160Buf); uint8_t fiveBitExpanded[RIPEMD160_DIGEST_LENGTH * 8 / 5]; size_t len = 0; @@ -56,27 +65,27 @@ bool cosmos_getAddress(const uint8_t *public_key, char *address) return bech32_encode(address, "cosmos", fiveBitExpanded, len) == 1; } -#define SIGNING_TEMPLATE "{\"account_number\":\"%"PRIu64"\",\"chain_id\":\"%s\",\"fee\":{\"amount\":[{\"amount\":\"%"PRIu32"\",\"denom\":\"uatom\"}],\"gas\":\"%"PRIu32"\"},\"memo\":\"%s\",\"msgs\":[{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{\"amount\":[{\"amount\":\"%"PRIu64"\",\"denom\":\"uatom\"}],\"from_address\":\"%s\",\"to_address\":\"%s\"}}],\"sequence\":\"%"PRIu64"\"}" +#define SIGNING_TEMPLATE "{\"account_number\":\"%" PRIu64 "\",\"chain_id\":\"%s\",\"fee\":{\"amount\":[{\"amount\":\"%" PRIu32 "\",\"denom\":\"uatom\"}],\"gas\":\"%" PRIu32 "\"},\"memo\":\"%s\",\"msgs\":[{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{\"amount\":[{\"amount\":\"%" PRIu64 "\",\"denom\":\"uatom\"}],\"from_address\":\"%s\",\"to_address\":\"%s\"}}],\"sequence\":\"%" PRIu64 "\"}" // 411 + memo + chain_id + NULL terminator -bool cosmos_signTx(const uint8_t* private_key, +bool cosmos_signTx(const uint8_t *private_key, const uint64_t account_number, - const char* chain_id, + const char *chain_id, const size_t chain_id_length, const uint32_t fee_uatom_amount, const uint32_t gas, - const char* memo, + const char *memo, const size_t memo_length, const uint64_t amount, - const char* from_address, - const char* to_address, + const char *from_address, + const char *to_address, const uint64_t sequence, - uint8_t* signature) + uint8_t *signature) { size_t len = 412 + memo_length + chain_id_length; char signBytes[len]; snprintf(signBytes, len, SIGNING_TEMPLATE, account_number, chain_id, fee_uatom_amount, gas, memo, amount, from_address, to_address, sequence); uint8_t hash[SHA256_DIGEST_LENGTH]; - sha256_Raw((uint8_t*)signBytes, strlen(signBytes), hash); + sha256_Raw((uint8_t *)signBytes, strlen(signBytes), hash); return ecdsa_sign_digest(&secp256k1, private_key, hash, signature, NULL, NULL) == 0; } diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h index 94156a0b9..827a2f561 100644 --- a/lib/firmware/fsm_msg_cosmos.h +++ b/lib/firmware/fsm_msg_cosmos.h @@ -12,9 +12,8 @@ void fsm_msgCosmosGetAddress(const CosmosGetAddress *msg) { return; } - hdnode_fill_public_key(node); - cosmos_getAddress(node->public_key, resp->address); + cosmos_getAddress(node, resp->address); if (msg->has_show_display && msg->show_display) { From 702b185ab80aa8cc9bdc52e39941716ac9bb7100 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Tue, 12 Nov 2019 20:55:10 -0700 Subject: [PATCH 10/44] fixes confirmation dialogs --- lib/firmware/cosmos.c | 16 ++++++++++++++++ lib/firmware/fsm_msg_cosmos.h | 35 +++++++++++++++++++++++++++-------- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index 7a0aceae8..c8da9be79 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -9,6 +9,22 @@ #include #include +bool cosmos_path_mismatched(const CoinType *_coin, + const uint32_t *address_n, + const uint32_t address_n_count) +{ + // m/44' : BIP44-like path + // m / purpose' / bip44_account_path' / account' / x / y + bool mismatch = false; + mismatch |= address_n_count != 5; + mismatch |= address_n_count > 0 && (address_n[0] != (0x80000000 + 44)); + mismatch |= address_n_count > 1 && (address_n[1] != _coin->bip44_account_path); + mismatch |= address_n_count > 2 && (address_n[2] & 0x80000000) == 0; + mismatch |= address_n_count > 2 && (address_n[3] & 0x80000000) == 0; + mismatch |= address_n_count > 2 && (address_n[4] & 0x80000000) == 0; + return mismatch; +} + /* This was inlined from the trezor firmware because it was not exported. * Forking the repository to expose this function is an option but we will * need guidance on the way you want to handle syncing the locked commit, diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h index 827a2f561..9e7712523 100644 --- a/lib/firmware/fsm_msg_cosmos.h +++ b/lib/firmware/fsm_msg_cosmos.h @@ -7,19 +7,38 @@ void fsm_msgCosmosGetAddress(const CosmosGetAddress *msg) CHECK_PIN + const char *coin_name = msg->has_coin_name ? msg->coin_name : "Cosmos"; + const CoinType *coin = fsm_getCoin(true, coin_name); + if (!coin) { return; } HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) - { + if (!node) { return; } + + if (!cosmos_getAddress(node, resp->address) { + fsm_sendFailure(FailureType_Failure_Other, _("Can't encode address")); + layoutHome(); return; } - cosmos_getAddress(node, resp->address); + if (msg->has_show_display && msg->show_display) { + char node_str[NODE_STRING_LENGTH]; + if (!nano_bip32_to_string(node_str, sizeof(node_str), coin, msg->address_n, + msg->address_n_count) && + !bip32_path_to_string(node_str, sizeof(node_str), + msg->address_n, msg->address_n_count)) { + memset(node_str, 0, sizeof(node_str)); + } + bool mismatch = cosmos_path_mismatched(coin, msg->address_n, msg->address_n_count); + + if (mismatch) { + if (!confirm(ButtonRequestType_ButtonRequest_Other, "WARNING", "Wrong address path for selected coin. Continue at your own risk!")) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } - if (msg->has_show_display && msg->show_display) - { - if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Share public account ID?"), "%s", resp->address)) - { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + if(!confirm_address(node_str, address)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, "Show address cancelled"); layoutHome(); return; } From 720a7ba83afa567fd08034dbc206645d228d98b1 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Tue, 12 Nov 2019 21:16:17 -0700 Subject: [PATCH 11/44] displays node_str instead of from address --- lib/firmware/coins.c | 11 +++++++++-- lib/firmware/fsm_msg_cosmos.h | 16 +++++++++++++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/lib/firmware/coins.c b/lib/firmware/coins.c index 487973383..2504377be 100644 --- a/lib/firmware/coins.c +++ b/lib/firmware/coins.c @@ -432,6 +432,13 @@ static bool isEOS(const char *coin_name) { return false; } +static bool isAccountBased(const char* coin_name) +{ + if (strcmp(coin_name, "Cosmos") == 0) { return true; } + if (isEthereumLike(coin_name)) { return true; } + return false; +} + bool bip32_node_to_string(char *node_str, size_t len, const CoinType *coin, const uint32_t *address_n, size_t address_n_count, bool whole_account, bool show_addridx) @@ -448,7 +455,7 @@ bool bip32_node_to_string(char *node_str, size_t len, const CoinType *coin, return false; // Only 0/1 for internal/external are valid paths on UTXO coins. - if (!isEthereumLike(coin_name) && !isEOS(coin_name) && + if (!isEthereumLike(coin_name) && !isEOS(coin_name) && !isAccountBased(coin_name) address_n[3] != 0 && address_n[3] != 1) return false; } @@ -460,7 +467,7 @@ bool bip32_node_to_string(char *node_str, size_t len, const CoinType *coin, if (!prefix) return false; - if (whole_account || isEthereumLike(coin_name) || isEOS(coin_name) || !show_addridx) { + if (whole_account || isEthereumLike(coin_name) || isEOS(coin_name) || isAccountBased(coin_name) || !show_addridx) { snprintf(node_str, len, "%s%s Account #%" PRIu32, prefix, coin_name, address_n[2] & 0x7fffffff); } else { diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h index 9e7712523..9326f7086 100644 --- a/lib/firmware/fsm_msg_cosmos.h +++ b/lib/firmware/fsm_msg_cosmos.h @@ -21,8 +21,9 @@ void fsm_msgCosmosGetAddress(const CosmosGetAddress *msg) if (msg->has_show_display && msg->show_display) { char node_str[NODE_STRING_LENGTH]; - if (!nano_bip32_to_string(node_str, sizeof(node_str), coin, msg->address_n, - msg->address_n_count) && + if (!bip32_node_to_string(node_str, sizeof(node_str), coin, msg->address_n, + msg->address_n_count, /*whole_account=*/false, + /*show_addridx=*/true) && !bip32_path_to_string(node_str, sizeof(node_str), msg->address_n, msg->address_n_count)) { memset(node_str, 0, sizeof(node_str)); @@ -62,8 +63,17 @@ void fsm_msgCosmosSignTx(const CosmosSignTx *msg) } hdnode_fill_public_key(node); + char node_str[NODE_STRING_LENGTH]; + if (!bip32_node_to_string(node_str, sizeof(node_str), coin, msg->address_n, + msg->address_n_count, /*whole_account=*/false, + /*show_addridx=*/true) && + !bip32_path_to_string(node_str, sizeof(node_str), + msg->address_n, msg->address_n_count)) { + memset(node_str, 0, sizeof(node_str)); + } + // Confirm transaction basics - if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Main Details"), "From: %s\nTo: %s\nAmount: %f ATOM", msg->from_address, msg->to_address, (float)msg->amount * 1E-6)) + if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Main Details"), "From: %s\nTo: %s\nAmount: %f ATOM", node_str, msg->to_address, (float)msg->amount * 1E-6)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); From e3048b2a2b6db8db9a53ccf7e228a2af6fa926b9 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Tue, 12 Nov 2019 21:17:30 -0700 Subject: [PATCH 12/44] fixes committed conflict --- lib/firmware/messagemap.def | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/firmware/messagemap.def b/lib/firmware/messagemap.def index e252d6ac2..fd6a77c53 100644 --- a/lib/firmware/messagemap.def +++ b/lib/firmware/messagemap.def @@ -75,15 +75,9 @@ MSG_OUT(MessageType_MessageType_EthereumMessageSignature, EthereumMessageSignature, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_NanoAddress, NanoAddress, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_NanoSignedTx, NanoSignedTx, NO_PROCESS_FUNC) -<<<<<<< HEAD -======= - MSG_OUT(MessageType_MessageType_StellarAddress, StellarAddress, NO_PROCESS_FUNC) - MSG_OUT(MessageType_MessageType_StellarSignedTx, StellarSignedTx, NO_PROCESS_FUNC) - MSG_OUT(MessageType_MessageType_StellarTxOpRequest, StellarTxOpRequest, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_CosmosAddress, CosmosAddress, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_CosmosSignedTx, CosmosSignedTx, NO_PROCESS_FUNC) ->>>>>>> 2c99a843... boil your plates MSG_OUT(MessageType_MessageType_EosPublicKey, EosPublicKey, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_EosTxActionRequest, EosTxActionRequest, NO_PROCESS_FUNC) From 200efcd1d2b987a3c854905782c28b8d277e54e9 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 13 Nov 2019 09:45:48 -0700 Subject: [PATCH 13/44] fixes mismatch logic, adds EOS to account based calls --- lib/firmware/coins.c | 1 + lib/firmware/cosmos.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/firmware/coins.c b/lib/firmware/coins.c index 2504377be..3ffdfeb53 100644 --- a/lib/firmware/coins.c +++ b/lib/firmware/coins.c @@ -436,6 +436,7 @@ static bool isAccountBased(const char* coin_name) { if (strcmp(coin_name, "Cosmos") == 0) { return true; } if (isEthereumLike(coin_name)) { return true; } + if (isEOS(coin_name)) { return true; } return false; } diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index c8da9be79..d27af2769 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -20,8 +20,8 @@ bool cosmos_path_mismatched(const CoinType *_coin, mismatch |= address_n_count > 0 && (address_n[0] != (0x80000000 + 44)); mismatch |= address_n_count > 1 && (address_n[1] != _coin->bip44_account_path); mismatch |= address_n_count > 2 && (address_n[2] & 0x80000000) == 0; - mismatch |= address_n_count > 2 && (address_n[3] & 0x80000000) == 0; - mismatch |= address_n_count > 2 && (address_n[4] & 0x80000000) == 0; + mismatch |= address_n_count > 3 && (address_n[3] & 0x80000000) != 0; + mismatch |= address_n_count > 4 && (address_n[4] & 0x80000000) != 0; return mismatch; } From 1ad286c023f138fb247b83c764cb7223595d1945 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 13 Nov 2019 09:52:08 -0700 Subject: [PATCH 14/44] changes to rebased cosmos commit --- deps/device-protocol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/device-protocol b/deps/device-protocol index a956b3c5e..437e53a58 160000 --- a/deps/device-protocol +++ b/deps/device-protocol @@ -1 +1 @@ -Subproject commit a956b3c5e4eb3367746bf9499ce1efe409839300 +Subproject commit 437e53a58deb233c8ecc4f7374c145e6d071b636 From 30628560cbdb38190644a2218cf14b1c19d6a32c Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 13 Nov 2019 10:02:13 -0700 Subject: [PATCH 15/44] temp change to start9 fork of trezor firmware --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index b878441b5..9f7c8f29b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,7 +3,7 @@ url = https://github.com/Start9Labs/device-protocol.git [submodule "deps/trezor-firmware"] path = deps/crypto/trezor-firmware - url = https://github.com/keepkey/trezor-firmware.git + url = https://github.com/Start9Labs/trezor-firmware.git [submodule "googletest"] path = deps/googletest url = https://github.com/google/googletest.git From e22364d3ba7dcde31948881f5c122d33ab0f2ea2 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 13 Nov 2019 10:12:36 -0700 Subject: [PATCH 16/44] changes trezor-firmware commit to include base conversion functionality --- deps/crypto/trezor-firmware | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/crypto/trezor-firmware b/deps/crypto/trezor-firmware index 655661668..e9c6a3520 160000 --- a/deps/crypto/trezor-firmware +++ b/deps/crypto/trezor-firmware @@ -1 +1 @@ -Subproject commit 6556616681a4e2d7e18817e8692d4f6e041dee01 +Subproject commit e9c6a3520f2fbe494eb74d2e7214fe7f4af2dfda From c4063bfde07f02eaa1f11a28401e480f3085d878 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 13 Nov 2019 10:13:43 -0700 Subject: [PATCH 17/44] Update lib/firmware/coins.c Co-Authored-By: keepkeyjon <35975617+keepkeyjon@users.noreply.github.com> --- lib/firmware/coins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/firmware/coins.c b/lib/firmware/coins.c index 3ffdfeb53..ce2f9a11c 100644 --- a/lib/firmware/coins.c +++ b/lib/firmware/coins.c @@ -456,7 +456,7 @@ bool bip32_node_to_string(char *node_str, size_t len, const CoinType *coin, return false; // Only 0/1 for internal/external are valid paths on UTXO coins. - if (!isEthereumLike(coin_name) && !isEOS(coin_name) && !isAccountBased(coin_name) + if (!isAccountBased(coin_name) && address_n[3] != 0 && address_n[3] != 1) return false; } From f9e3a40cca00d7be0d6a05ac0ef93f008a8e838e Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 13 Nov 2019 10:13:56 -0700 Subject: [PATCH 18/44] Update lib/firmware/coins.c Co-Authored-By: keepkeyjon <35975617+keepkeyjon@users.noreply.github.com> --- lib/firmware/coins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/firmware/coins.c b/lib/firmware/coins.c index ce2f9a11c..0d93090e9 100644 --- a/lib/firmware/coins.c +++ b/lib/firmware/coins.c @@ -468,7 +468,7 @@ bool bip32_node_to_string(char *node_str, size_t len, const CoinType *coin, if (!prefix) return false; - if (whole_account || isEthereumLike(coin_name) || isEOS(coin_name) || isAccountBased(coin_name) || !show_addridx) { + if (whole_account || isAccountBased(coin_name) || !show_addridx) { snprintf(node_str, len, "%s%s Account #%" PRIu32, prefix, coin_name, address_n[2] & 0x7fffffff); } else { From 605c58716142e82dfba45fd58454752dec4439f5 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 13 Nov 2019 11:21:35 -0700 Subject: [PATCH 19/44] removes commented code --- lib/firmware/cosmos.c | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index 9fccb3718..2d432c77c 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -25,40 +25,6 @@ bool cosmos_path_mismatched(const CoinType *_coin, return mismatch; } -/* This was inlined from the trezor firmware because it was not exported. - * Forking the repository to expose this function is an option but we will - * need guidance on the way you want to handle syncing the locked commit, - * keepkey@HEAD, and the new commit. - */ -// static int convert_bits(uint8_t *out, size_t *outlen, int outbits, const uint8_t *in, size_t inlen, int inbits, int pad) -// { -// uint32_t val = 0; -// int bits = 0; -// uint32_t maxv = (((uint32_t)1) << outbits) - 1; -// while (inlen--) -// { -// val = (val << inbits) | *(in++); -// bits += inbits; -// while (bits >= outbits) -// { -// bits -= outbits; -// out[(*outlen)++] = (val >> bits) & maxv; -// } -// } -// if (pad) -// { -// if (bits) -// { -// out[(*outlen)++] = (val << (outbits - bits)) & maxv; -// } -// } -// else if (((val << (outbits - bits)) & maxv) || bits >= inbits) -// { -// return 0; -// } -// return 1; -// } - /* * Gets the address * From aa3826dda2a96a1c2778b7250ea7e11a5892f046 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 13 Nov 2019 11:23:10 -0700 Subject: [PATCH 20/44] changes back to keepkey remotes on submodules --- .gitmodules | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index 9f7c8f29b..30597ede5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,9 @@ [submodule "deps/device-protocol"] path = deps/device-protocol - url = https://github.com/Start9Labs/device-protocol.git + url = https://github.com/keepkey/device-protocol.git [submodule "deps/trezor-firmware"] path = deps/crypto/trezor-firmware - url = https://github.com/Start9Labs/trezor-firmware.git + url = https://github.com/keepkey/trezor-firmware.git [submodule "googletest"] path = deps/googletest url = https://github.com/google/googletest.git @@ -12,7 +12,7 @@ url = https://github.com/keepkey/code-signing-keys.git [submodule "deps/python-keepkey"] path = deps/python-keepkey - url = https://github.com/Start9Labs/python-keepkey.git + url = https://github.com/keepkey/python-keepkey.git [submodule "deps/qrenc/QR-Code-generator"] path = deps/qrenc/QR-Code-generator url = https://github.com/keepkey/QR-Code-generator.git From 2b3dac793f259f4c1e68e6b6e93d4183bade90ed Mon Sep 17 00:00:00 2001 From: Aiden McClelland Date: Wed, 13 Nov 2019 12:33:46 -0700 Subject: [PATCH 21/44] escaping --- lib/firmware/cosmos.c | 97 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 91 insertions(+), 6 deletions(-) diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index 9fccb3718..c8fb718eb 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -79,9 +79,47 @@ bool cosmos_getAddress(const HDNode *node, char *address) return bech32_encode(address, "cosmos", fiveBitExpanded, len) == 1; } -#define SIGNING_TEMPLATE "{\"account_number\":\"%" PRIu64 "\",\"chain_id\":\"%s\",\"fee\":{\"amount\":[{\"amount\":\"%" PRIu32 "\",\"denom\":\"uatom\"}],\"gas\":\"%" PRIu32 "\"},\"memo\":\"%s\",\"msgs\":[{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{\"amount\":[{\"amount\":\"%" PRIu64 "\",\"denom\":\"uatom\"}],\"from_address\":\"%s\",\"to_address\":\"%s\"}}],\"sequence\":\"%" PRIu64 "\"}" +// Each segment guaranteed to be less than 64 bytes +// 19 + ^20 + 14 = ^53 +#define SIGNING_TEMPLATE_SEG1 "{\"account_number\":\"%" PRIu64 "\",\"chain_id\":\"" +// +// 30 + ^10 + 24 = ^64 +#define SIGNING_TEMPLATE_SEG2 "\",\"fee\":{\"amount\":[{\"amount\":\"%" PRIu32 "\",\"denom\":\"uatom\"}],\"gas" +// 3 + ^10 + 11 = ^23 +#define SIGNING_TEMPLATE_SEG3 "\":\"%" PRIu32 "\"},\"memo\":\"" +// +// 64 +#define SIGNING_TEMPLATE_SEG4 "\",\"msgs\":[{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{\"amount\":[{\"amou" +// 5 + ^20 + 36 = ^61 +#define SIGNING_TEMPLATE_SEG5 "nt\":\"%" PRIu64 "\",\"denom\":\"uatom\"}],\"from_address\":\"" +// 45 + 16 = 61 +#define SIGNING_TEMPLATE_SEG6 "%s\",\"to_address\":\"" +// 45 + 17 = 62 +#define SIGNING_TEMPLATE_SEG7 "%s\"}}],\"sequence\":\"" +// ^20 + 2 = ^22 +#define SIGNING_TEMPLATE_SEG8 "%" PRIu64 "\"}" + +void sha256UpdateEscaped(SHA256_CTX *ctx, const char *s, size_t len) +{ + while (len > 0) + { + if (s[0] == '"') + { + sha256_Update(ctx, (uint8_t *)"\\\"", 2); + } + else if (s[0] == '\\') + { + sha256_Update(ctx, (uint8_t *)"\\\\", 2); + } + else + { + sha256_Update(ctx, (uint8_t *)&s[0], 1); + } + s = &s[1]; + len--; + } +} -// 411 + memo + chain_id + NULL terminator bool cosmos_signTx(const uint8_t *private_key, const uint64_t account_number, const char *chain_id, @@ -96,10 +134,57 @@ bool cosmos_signTx(const uint8_t *private_key, const uint64_t sequence, uint8_t *signature) { - size_t len = 412 + memo_length + chain_id_length; - char signBytes[len]; - snprintf(signBytes, len, SIGNING_TEMPLATE, account_number, chain_id, fee_uatom_amount, gas, memo, amount, from_address, to_address, sequence); + SHA256_CTX ctx; + int n; + sha256_Init(&ctx); + char buffer[SHA256_BLOCK_LENGTH + 1]; // NULL TERMINATOR NOT PART OF HASH + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG1, account_number); + if (n < 0) + { + return false; + } + sha256_Update(&ctx, (uint8_t *)buffer, n); + sha256UpdateEscaped(&ctx, chain_id, chain_id_length); + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG2, fee_uatom_amount); + if (n < 0) + { + return false; + } + sha256_Update(&ctx, (uint8_t *)buffer, n); + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG3, gas); + if (n < 0) + { + return false; + } + sha256_Update(&ctx, (uint8_t *)buffer, n); + sha256UpdateEscaped(&ctx, memo, memo_length); + sha256_Update(&ctx, (uint8_t *)SIGNING_TEMPLATE_SEG4, 64); // no interpolation needed + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG5, amount); + if (n < 0) + { + return false; + } + sha256_Update(&ctx, (uint8_t *)buffer, n); + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG6, from_address); + if (n < 0) + { + return false; + } + sha256_Update(&ctx, (uint8_t *)buffer, n); + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG7, to_address); + if (n < 0) + { + return false; + } + sha256_Update(&ctx, (uint8_t *)buffer, n); + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG8, sequence); + if (n < 0) + { + return false; + } + sha256_Update(&ctx, (uint8_t *)buffer, n); + uint8_t hash[SHA256_DIGEST_LENGTH]; - sha256_Raw((uint8_t *)signBytes, strlen(signBytes), hash); + sha256_Final(&ctx, hash); return ecdsa_sign_digest(&secp256k1, private_key, hash, signature, NULL, NULL) == 0; } From a21af263b7f9b3000b100e28292ede490b29e2aa Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 13 Nov 2019 14:41:59 -0700 Subject: [PATCH 22/44] tests pass again --- deps/device-protocol | 2 +- include/keepkey/firmware/coins.def | 76 +++++++++++++++--------------- lib/firmware/fsm_msg_cosmos.h | 10 ++-- unittests/firmware/coins.cpp | 4 +- unittests/firmware/cosmos.cpp | 31 +++++++----- 5 files changed, 65 insertions(+), 58 deletions(-) diff --git a/deps/device-protocol b/deps/device-protocol index 437e53a58..60a74a6c2 160000 --- a/deps/device-protocol +++ b/deps/device-protocol @@ -1 +1 @@ -Subproject commit 437e53a58deb233c8ecc4f7374c145e6d071b636 +Subproject commit 60a74a6c2769a91e3e67435a55fb4bad6fd2389a diff --git a/include/keepkey/firmware/coins.def b/include/keepkey/firmware/coins.def index debec698c..2afb6d4fe 100644 --- a/include/keepkey/firmware/coins.def +++ b/include/keepkey/firmware/coins.def @@ -1,42 +1,42 @@ #define NO_CONTRACT {0, {0}} //coin_name coin_shortcut address_type maxfee_kb p2sh signed_message_header bip44_account_path forkid/chain_id decimals contract_address xpub_magic segwit force_bip143 curve_name cashaddr_prefix bech32_prefix decred xpub_magic_segwit_p2sh xpub_mmagic_segwit_native nanoaddr_prefix -X(true, "Bitcoin", true, "BTC", true, 0, true, 100000, true, 5, true, "Bitcoin Signed Message:\n", true, 0x80000000, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "bc", false, false, true, 77429938, true, 78792518, false, "" ) -X(true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, "Bitcoin Signed Message:\n", true, 0x80000001, false, 0, true, 8, false, NO_CONTRACT, true, 70617039, true, true, true, false, true, SECP256K1_STRING, false, "", true, "tb", false, false, true, 71979618, true, 73342198, false, "" ) -X(true, "BitcoinCash", true, "BCH", true, 0, true, 500000, true, 5, true, "Bitcoin Signed Message:\n", true, 0x80000091, true, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, true, true, SECP256K1_STRING, true, "bitcoincash", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, true, "Namecoin Signed Message:\n", true, 0x80000007, false, 0, true, 8, false, NO_CONTRACT, true, 27108450, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 50, true, "Litecoin Signed Message:\n", true, 0x80000002, false, 0, true, 8, false, NO_CONTRACT, true, 27108450, true, true, true, false, true, SECP256K1_STRING, false, "", true, "ltc", false, false, false, 0, false, 0, false, "" ) -X(true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, true, "Dogecoin Signed Message:\n", true, 0x80000003, false, 0, true, 8, false, NO_CONTRACT, true, 49990397, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, true, "DarkCoin Signed Message:\n", true, 0x80000005, false, 0, true, 8, false, NO_CONTRACT, true, 50221772, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, ETHEREUM, true, "ETH", true, NA, true, 100000, true, NA, true, "Ethereum Signed Message:\n", true, 0x8000003c, true, 1, true, 18, false, NO_CONTRACT, false, 0, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, ETHEREUM_CLS, true, "ETC", true, NA, true, 100000, true, NA, true, "Ethereum Signed Message:\n", true, 0x8000003d, true, 62, true, 18, false, NO_CONTRACT, false, 0, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "BitcoinGold", true, "BTG", true, 38, true, 500000, true, 23, true, "Bitcoin Gold Signed Message:\n", true, 0x8000009c, true, 79, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, true, true, SECP256K1_STRING, false, "", true, "btg", false, false, true, 77429938, false, 0, false, "" ) -X(true, "Zcash", true, "ZEC", true, 7352, true, 1000000, true, 7357, true, "Zcash Signed Message:\n", true, 0x80000085, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, false, false, false, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Zcash Testnet",true, "TAZ", true, 7461, true, 10000000, true, 7354, true, "Zcash Signed Message:\n", true, 0x80000001, false, 0, true, 8, false, NO_CONTRACT, true, 70617039, false, false, false, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "DigiByte", true, "DGB", true, 30, true, 500000, true, 63, true, "DigiByte Signed Message:\n", true, 0x80000014, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, false, false, true, SECP256K1_STRING, false, "", true, "dgb", false, false, false, 0, false, 0, false, "" ) -X(true, "EOS", true, "EOS", false, NA, false, 0, false, NA, false, {0}, true, 0x800000c2, false, 0, false, 0, false, NO_CONTRACT, false, 0, false, false, false, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Axe", true, "AXE", true, 55, true, 100000, true, 16, true, "DarkCoin Signed Message:\n", true, 0x80001092, false, 0, true, 8, false, NO_CONTRACT, true, 50221772, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Bitcore", true, "BTX", true, 3, true, 100000, true, 125, true, "BitCore Signed Message:\n", true, 0x800000a0, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "btx", false, false, true, 77429938, true, 78792518, false, "" ) -X(true, "Fujicoin", true, "FJC", true, 36, true, 10000000, true, 16, true, "FujiCoin Signed Message:\n", true, 0x8000004b, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "fc", false, false, true, 77429938, true, 78792518, false, "" ) -X(true, "Denarius", true, "D", true, 30, true, 100000, true, 90, true, "Denarius Signed Message:\n", true, 0x80000074, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Bitsend", true, "BSD", true, 102, true, 1000000, true, 5, true, "Bitsend Signed Message:\n", true, 0x8000005b, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, true, 77429938, true, 78792518, false, "" ) -X(true, "Bitcloud", true, "BTDX", true, 25, true, 1000000, true, 5, true, "Diamond Signed Message:\n", true, 0x800000da, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "BitcoinSV", true, "BSV", true, 0, true, 500000, true, 5, true, "Bitcoin Signed Message:\n", true, 0x800000ec, true, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, true, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Komodo", true, "KMD", true, 60, true, 1000000, true, 85, true, "Komodo Signed Message:\n", true, 0x8000008d, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Ravencoin", true, "RVN", true, 60, true, 2000000, true, 122, true, "Ravencoin Signed Message:\n", true, 0x800000af, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Decred", true, "DCR", true,1855, true, 1000000, true,1818, true, "Decred Signed Message:\n", true, 0x8000002a, false, 0, true, 8, false, NO_CONTRACT, true, 50178342, true, false, true, false, true,"secp256k1-decred", false, "", false, "", true, true, false, 0, false, 0, false, "" ) -X(true, "Vertcoin", true, "VTC", true, 71, true, 40000000, true, 5, true, "Vertcoin Signed Message:\n", true, 0x8000001c, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "vtc", false, false, true, 77429938, false, 0, false, "" ) -X(true, "GameCredits", true, "GAME", true, 38, true, 5000000, true, 62, true, "GameCredits Signed Message:\n", true, 0x80000065, false, 0, true, 8, false, NO_CONTRACT, true, 27106558, true, true, true, false, true, SECP256K1_STRING, false, "", true, "game", false, false, true, 28471030, false, 0, false, "" ) -X(true, "Monacoin", true, "MONA", true, 50, true, 5000000, true, 55, true, "Monacoin Signed Message:\n", true, 0x80000016, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "mona", false, false, true, 77429938, false, 0, false, "" ) -X(true, "Electra", true, "ECA", true, 33, true, 10000, true, 40, true, "Electra very Signed Message:\n", true, 0x800000f9, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, false, false, false, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Nano", true, "NANO", true, NA, false, NA, false, NA, true, "Nano Signed Message:\n", true, 0x800000a5, false, 0, true, 30, false, NO_CONTRACT, false, 0, false, false, false, false, true, ED25519_BLAKE2B_NANO_STRING, false, "", false, "", false, false, false, 0, false, 0, true, "xrb_") -X(true, "Groestlcoin", true, "GRS", true, 36, true, 100000, true, 5, true, "GroestlCoin Signed Message:\n", true, 0x80000011, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true,"secp256k1-groestl", false, "", true, "grs", false, false, true, 77429938, true, 78792518, false, "" ) -X(true, "Megacoin", true, "MEC", true, 50, true, 1000000, true, 5, true, "MegaCoin Signed Message:\n", true, 0x800000d9, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, true, 77429938, true, 78792518, false, "" ) -X(true, "Terracoin", true, "TRC", true, 0, true, 100000, true, 5, true, "DarkCoin Signed Message:\n", true, 0x80000053, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Qtum", true, "QTUM", true, 58, true, 40000000, true, 50, true, "Qtum Signed Message:\n", true, 0x800008fd, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "qc", false, false, true, 77429938, true, 78792518, false, "" ) -X(true, "GRS Testnet", true, "tGRS", true, 111, true, 100000 , true, 196, true, "GroestlCoin Signed Message:\n", true, 0x80000001, false, 0, true, 8, false, NO_CONTRACT, true, 70617039, true, true, true, false, true,"secp256k1-groestl", false, "", true, "tgrs", false, false, true, 71979618, true, 73342198, false, "" ) -X(true, "BCH Testnet", true, "tBCH", true, 0, true, 500000, true, 5, true, "Bitcoin Signed Message:\n", true, 0x80000001, true, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, true, true, SECP256K1_STRING, true, "bitcoincash", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "LTC Testnet", true, "tLTC", true, 48, true, 1000000, true, 50, true, "Litecoin Signed Message:\n", true, 0x80000001, false, 0, true, 8, false, NO_CONTRACT, true, 27108450, true, true, true, false, true, SECP256K1_STRING, false, "", true, "ltc", false, false, false, 0, false, 0, false, "" ) -X(true, ETHEREUM_TST, true, "tETH", true, NA, true, 100000, true, NA, true, "Ethereum Signed Message:\n", true, 0x80000001, true, 1, true, 18, false, NO_CONTRACT, false, 0, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) -X(true, "Cosmos", true, "ATOM", false, NA, false, NA, false, NA, false, {0}, true, 0x80000076, false, 0, true, 6, false, NO_CONTRACT, false, 0, false, false, false, false, true, SECP256K1_STRING, false, "", false, "cosmos", false, false, false, 0, false, 0, false, "" ) +X(true, "Bitcoin", true, "BTC", true, 0, true, 100000, true, 5, true, "Bitcoin Signed Message:\n", true, 0x80000000, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "bc", false, false, true, 77429938, true, 78792518, false, "" ) +X(true, "Testnet", true, "TEST", true, 111, true, 10000000, true, 196, true, "Bitcoin Signed Message:\n", true, 0x80000001, false, 0, true, 8, false, NO_CONTRACT, true, 70617039, true, true, true, false, true, SECP256K1_STRING, false, "", true, "tb", false, false, true, 71979618, true, 73342198, false, "" ) +X(true, "BitcoinCash", true, "BCH", true, 0, true, 500000, true, 5, true, "Bitcoin Signed Message:\n", true, 0x80000091, true, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, true, true, SECP256K1_STRING, true, "bitcoincash", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Namecoin", true, "NMC", true, 52, true, 10000000, true, 5, true, "Namecoin Signed Message:\n", true, 0x80000007, false, 0, true, 8, false, NO_CONTRACT, true, 27108450, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Litecoin", true, "LTC", true, 48, true, 1000000, true, 50, true, "Litecoin Signed Message:\n", true, 0x80000002, false, 0, true, 8, false, NO_CONTRACT, true, 27108450, true, true, true, false, true, SECP256K1_STRING, false, "", true, "ltc", false, false, false, 0, false, 0, false, "" ) +X(true, "Dogecoin", true, "DOGE", true, 30, true, 1000000000, true, 22, true, "Dogecoin Signed Message:\n", true, 0x80000003, false, 0, true, 8, false, NO_CONTRACT, true, 49990397, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Dash", true, "DASH", true, 76, true, 100000, true, 16, true, "DarkCoin Signed Message:\n", true, 0x80000005, false, 0, true, 8, false, NO_CONTRACT, true, 50221772, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, ETHEREUM, true, "ETH", true, NA, true, 100000, true, NA, true, "Ethereum Signed Message:\n", true, 0x8000003c, true, 1, true, 18, false, NO_CONTRACT, false, 0, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, ETHEREUM_CLS, true, "ETC", true, NA, true, 100000, true, NA, true, "Ethereum Signed Message:\n", true, 0x8000003d, true, 62, true, 18, false, NO_CONTRACT, false, 0, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "BitcoinGold", true, "BTG", true, 38, true, 500000, true, 23, true, "Bitcoin Gold Signed Message:\n", true, 0x8000009c, true, 79, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, true, true, SECP256K1_STRING, false, "", true, "btg", false, false, true, 77429938, false, 0, false, "" ) +X(true, "Zcash", true, "ZEC", true, 7352, true, 1000000, true, 7357, true, "Zcash Signed Message:\n", true, 0x80000085, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, false, false, false, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Zcash Testnet",true, "TAZ", true, 7461, true, 10000000, true, 7354, true, "Zcash Signed Message:\n", true, 0x80000001, false, 0, true, 8, false, NO_CONTRACT, true, 70617039, false, false, false, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "DigiByte", true, "DGB", true, 30, true, 500000, true, 63, true, "DigiByte Signed Message:\n", true, 0x80000014, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, false, false, true, SECP256K1_STRING, false, "", true, "dgb", false, false, false, 0, false, 0, false, "" ) +X(true, "EOS", true, "EOS", false, NA, false, 0, false, NA, false, {0}, true, 0x800000c2, false, 0, false, 0, false, NO_CONTRACT, false, 0, false, false, false, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Axe", true, "AXE", true, 55, true, 100000, true, 16, true, "DarkCoin Signed Message:\n", true, 0x80001092, false, 0, true, 8, false, NO_CONTRACT, true, 50221772, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Bitcore", true, "BTX", true, 3, true, 100000, true, 125, true, "BitCore Signed Message:\n", true, 0x800000a0, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "btx", false, false, true, 77429938, true, 78792518, false, "" ) +X(true, "Fujicoin", true, "FJC", true, 36, true, 10000000, true, 16, true, "FujiCoin Signed Message:\n", true, 0x8000004b, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "fc", false, false, true, 77429938, true, 78792518, false, "" ) +X(true, "Denarius", true, "D", true, 30, true, 100000, true, 90, true, "Denarius Signed Message:\n", true, 0x80000074, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Bitsend", true, "BSD", true, 102, true, 1000000, true, 5, true, "Bitsend Signed Message:\n", true, 0x8000005b, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, true, 77429938, true, 78792518, false, "" ) +X(true, "Bitcloud", true, "BTDX", true, 25, true, 1000000, true, 5, true, "Diamond Signed Message:\n", true, 0x800000da, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "BitcoinSV", true, "BSV", true, 0, true, 500000, true, 5, true, "Bitcoin Signed Message:\n", true, 0x800000ec, true, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, true, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Komodo", true, "KMD", true, 60, true, 1000000, true, 85, true, "Komodo Signed Message:\n", true, 0x8000008d, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Ravencoin", true, "RVN", true, 60, true, 2000000, true, 122, true, "Ravencoin Signed Message:\n", true, 0x800000af, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Decred", true, "DCR", true,1855, true, 1000000, true,1818, true, "Decred Signed Message:\n", true, 0x8000002a, false, 0, true, 8, false, NO_CONTRACT, true, 50178342, true, false, true, false, true,"secp256k1-decred", false, "", false, "", true, true, false, 0, false, 0, false, "" ) +X(true, "Vertcoin", true, "VTC", true, 71, true, 40000000, true, 5, true, "Vertcoin Signed Message:\n", true, 0x8000001c, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "vtc", false, false, true, 77429938, false, 0, false, "" ) +X(true, "GameCredits", true, "GAME", true, 38, true, 5000000, true, 62, true, "GameCredits Signed Message:\n", true, 0x80000065, false, 0, true, 8, false, NO_CONTRACT, true, 27106558, true, true, true, false, true, SECP256K1_STRING, false, "", true, "game", false, false, true, 28471030, false, 0, false, "" ) +X(true, "Monacoin", true, "MONA", true, 50, true, 5000000, true, 55, true, "Monacoin Signed Message:\n", true, 0x80000016, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "mona", false, false, true, 77429938, false, 0, false, "" ) +X(true, "Electra", true, "ECA", true, 33, true, 10000, true, 40, true, "Electra very Signed Message:\n", true, 0x800000f9, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, false, false, false, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Nano", true, "NANO", true, NA, false, NA, false, NA, true, "Nano Signed Message:\n", true, 0x800000a5, false, 0, true, 30, false, NO_CONTRACT, false, 0, false, false, false, false, true, ED25519_BLAKE2B_NANO_STRING, false, "", false, "", false, false, false, 0, false, 0, true, "xrb_") +X(true, "Groestlcoin", true, "GRS", true, 36, true, 100000, true, 5, true, "GroestlCoin Signed Message:\n", true, 0x80000011, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true,"secp256k1-groestl", false, "", true, "grs", false, false, true, 77429938, true, 78792518, false, "" ) +X(true, "Megacoin", true, "MEC", true, 50, true, 1000000, true, 5, true, "MegaCoin Signed Message:\n", true, 0x800000d9, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, true, 77429938, true, 78792518, false, "" ) +X(true, "Terracoin", true, "TRC", true, 0, true, 100000, true, 5, true, "DarkCoin Signed Message:\n", true, 0x80000053, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Qtum", true, "QTUM", true, 58, true, 40000000, true, 50, true, "Qtum Signed Message:\n", true, 0x800008fd, false, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, true, true, false, true, SECP256K1_STRING, false, "", true, "qc", false, false, true, 77429938, true, 78792518, false, "" ) +X(true, "GRS Testnet", true, "tGRS", true, 111, true, 100000 , true, 196, true, "GroestlCoin Signed Message:\n", true, 0x80000001, false, 0, true, 8, false, NO_CONTRACT, true, 70617039, true, true, true, false, true,"secp256k1-groestl", false, "", true, "tgrs", false, false, true, 71979618, true, 73342198, false, "" ) +X(true, "BCH Testnet", true, "tBCH", true, 0, true, 500000, true, 5, true, "Bitcoin Signed Message:\n", true, 0x80000001, true, 0, true, 8, false, NO_CONTRACT, true, 76067358, true, false, true, true, true, SECP256K1_STRING, true, "bitcoincash", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "LTC Testnet", true, "tLTC", true, 48, true, 1000000, true, 50, true, "Litecoin Signed Message:\n", true, 0x80000001, false, 0, true, 8, false, NO_CONTRACT, true, 27108450, true, true, true, false, true, SECP256K1_STRING, false, "", true, "ltc", false, false, false, 0, false, 0, false, "" ) +X(true, ETHEREUM_TST, true, "tETH", true, NA, true, 100000, true, NA, true, "Ethereum Signed Message:\n", true, 0x80000001, true, 1, true, 18, false, NO_CONTRACT, false, 0, true, false, true, false, true, SECP256K1_STRING, false, "", false, "", false, false, false, 0, false, 0, false, "" ) +X(true, "Cosmos", true, "ATOM", false, NA, false, NA, false, NA, false, {0}, true, 0x80000076, false, 0, true, 6, false, NO_CONTRACT, false, 0, false, false, false, false, true, SECP256K1_STRING, false, "", false, "cosmos", false, false, false, 0, false, 0, false, "" ) #undef X #undef NO_CONTRACT diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h index 334871277..0fda053ff 100644 --- a/lib/firmware/fsm_msg_cosmos.h +++ b/lib/firmware/fsm_msg_cosmos.h @@ -24,8 +24,8 @@ void fsm_msgCosmosGetAddress(const CosmosGetAddress *msg) if (msg->has_show_display && msg->show_display) { char node_str[NODE_STRING_LENGTH]; if (!bip32_node_to_string(node_str, sizeof(node_str), coin, msg->address_n, - msg->address_n_count, /*whole_account=*/false, - /*show_addridx=*/true) && + msg->address_n_count, /*whole_account=*/true, + /*show_addridx=*/false) && !bip32_path_to_string(node_str, sizeof(node_str), msg->address_n, msg->address_n_count)) { memset(node_str, 0, sizeof(node_str)); @@ -62,10 +62,8 @@ void fsm_msgCosmosSignTx(const CosmosSignTx *msg) const CoinType *coin = fsm_getCoin(true, coin_name); if (!coin) { return; } HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); - if (!node) - { - return; - } + if (!node) { return; } + hdnode_fill_public_key(node); char node_str[NODE_STRING_LENGTH]; diff --git a/unittests/firmware/coins.cpp b/unittests/firmware/coins.cpp index 70c781d17..e1bbbe4cf 100644 --- a/unittests/firmware/coins.cpp +++ b/unittests/firmware/coins.cpp @@ -162,9 +162,9 @@ TEST(Coins, BIP32AccountName) { 5, true, "EOS Account #42" }, { - "Cosmos" + "Cosmos", { 0x80000000|44, 0x80000000|118, 0x80000000|9, 0, 0 }, - 5, true, "Cosmos Account #9\nAddress #0" + 5, true, "Cosmos Account #9" } }; diff --git a/unittests/firmware/cosmos.cpp b/unittests/firmware/cosmos.cpp index 2be8dd7ff..d26dbf78c 100644 --- a/unittests/firmware/cosmos.cpp +++ b/unittests/firmware/cosmos.cpp @@ -1,4 +1,5 @@ -extern "C" { +extern "C" +{ #include "keepkey/firmware/coins.h" #include "keepkey/firmware/cosmos.h" } @@ -6,18 +7,26 @@ extern "C" { #include "gtest/gtest.h" #include - -TEST(Cosmos, CosmosGetAddress) { - const uint8_t* pubkey = (uint8_t *)"\x03\xb7\x32\x9f\x67\x8e\x0a\xc1\x21\x4b\x77\x23\x57\x54\x66\x21\x9c\x77\xfe\xdb\xdd\x95\x5c\x33\x29\x1a\x74\xf1\x8b\xf5\xc8\xa4\xe2"; +TEST(Cosmos, CosmosGetAddress) +{ + HDNode node = { + 0, + 0, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0x03, 0xb7, 0x32, 0x9f, 0x67, 0x8e, 0x0a, 0xc1, 0x21, 0x4b, 0x77, 0x23, 0x57, 0x54, 0x66, 0x21, 0x9c, 0x77, 0xfe, 0xdb, 0xdd, 0x95, 0x5c, 0x33, 0x29, 0x1a, 0x74, 0xf1, 0x8b, 0xf5, 0xc8, 0xa4, 0xe2}, + &secp256k1_info}; char addr[46]; - ASSERT_TRUE(cosmos_getAddress(pubkey, addr)); + ASSERT_TRUE(cosmos_getAddress(&node, addr)); EXPECT_EQ(std::string("cosmos1am058pdux3hyulcmfgj4m3hhrlfn8nzm88u80q"), addr); } -TEST(Cosmos, CosmosSignTx) { - const uint8_t* privkey = (uint8_t*)"\x04\xde\xc0\xcc\x01\x3c\xd8\xab\x70\x87\xca\x14\x96\x0b\x76\x8c\x3d\x83\x45\x24\x48\xaa\x00\x64\xda\xe6\xfb\x04\xb5\xd9\x34\x76"; - uint8_t signature[64]; - const uint8_t* expected = (uint8_t*)"\x41\x99\x66\x30\x08\xef\xea\x75\x93\x56\x35\xe6\x1a\x11\xdf\xa3\x3c\xeb\xeb\x91\xc1\xca\xed\xc6\x0e\x5e\xef\x3c\xa2\xc0\x1f\x83\x48\x08\x36\xe6\x21\x89\x51\x14\x36\x64\x7f\xac\x5a\xbd\xc2\x9f\x54\xae\x3d\x7e\x47\x56\x43\xca\x33\xc7\xad\x2c\x8a\x53\x2b\x39"; - ASSERT_TRUE(cosmos_signTx(privkey, 0, "cosmoshub-2", strlen("cosmoshub-2"), 5000, 200000, "", 0, 100000, "cosmos1am058pdux3hyulcmfgj4m3hhrlfn8nzm88u80q", "cosmos18vhdczjut44gpsy804crfhnd5nq003nz0nf20v", 0, signature)); - EXPECT_TRUE(memcmp(expected, signature, 64) == 0); +TEST(Cosmos, CosmosSignTx) +{ + const uint8_t *privkey = (uint8_t *)"\x04\xde\xc0\xcc\x01\x3c\xd8\xab\x70\x87\xca\x14\x96\x0b\x76\x8c\x3d\x83\x45\x24\x48\xaa\x00\x64\xda\xe6\xfb\x04\xb5\xd9\x34\x76"; + uint8_t signature[64]; + const uint8_t *expected = (uint8_t *)"\x41\x99\x66\x30\x08\xef\xea\x75\x93\x56\x35\xe6\x1a\x11\xdf\xa3\x3c\xeb\xeb\x91\xc1\xca\xed\xc6\x0e\x5e\xef\x3c\xa2\xc0\x1f\x83\x48\x08\x36\xe6\x21\x89\x51\x14\x36\x64\x7f\xac\x5a\xbd\xc2\x9f\x54\xae\x3d\x7e\x47\x56\x43\xca\x33\xc7\xad\x2c\x8a\x53\x2b\x39"; + ASSERT_TRUE(cosmos_signTx(privkey, 0, "cosmoshub-2", strlen("cosmoshub-2"), 5000, 200000, "", 0, 100000, "cosmos1am058pdux3hyulcmfgj4m3hhrlfn8nzm88u80q", "cosmos18vhdczjut44gpsy804crfhnd5nq003nz0nf20v", 0, signature)); + EXPECT_TRUE(memcmp(expected, signature, 64) == 0); } From 5b3680acdab9cf4c2a35150e7cf4cee3c8ae5b23 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 13 Nov 2019 17:29:48 -0700 Subject: [PATCH 23/44] WIP: refactor message protocol for interactivity --- deps/device-protocol | 2 +- include/keepkey/firmware/cosmos.h | 17 ++ include/keepkey/firmware/fsm.h | 1 + .../keepkey/transport/messages-cosmos.options | 4 +- lib/firmware/cosmos.c | 268 +++++++++++++----- lib/firmware/fsm_msg_cosmos.h | 101 ++++--- lib/firmware/messagemap.def | 2 + 7 files changed, 287 insertions(+), 108 deletions(-) diff --git a/deps/device-protocol b/deps/device-protocol index 60a74a6c2..1b92e340f 160000 --- a/deps/device-protocol +++ b/deps/device-protocol @@ -1 +1 @@ -Subproject commit 60a74a6c2769a91e3e67435a55fb4bad6fd2389a +Subproject commit 1b92e340f952d33d1e2f02651bf85d1d64e1b183 diff --git a/include/keepkey/firmware/cosmos.h b/include/keepkey/firmware/cosmos.h index d6df303de..8f041f542 100644 --- a/include/keepkey/firmware/cosmos.h +++ b/include/keepkey/firmware/cosmos.h @@ -13,6 +13,23 @@ bool cosmos_path_mismatched(const CoinType *_coin, const uint32_t *address_n, const uint32_t address_n_count); bool cosmos_getAddress(const HDNode *node, char *address); +bool cosmos_signTxInit(const HDNode* _node, + const uint32_t _address_n[8], + const size_t _address_n_count, + const uint64_t account_number, + const char *chain_id, + const size_t chain_id_length, + const uint32_t fee_uatom_amount, + const uint32_t gas, + const char *memo, + const size_t memo_length, + const uint64_t _sequence, + const uint32_t msg_count); +bool cosmos_signingIsInited(); +bool cosmos_signingIsFinished(); +void cosmos_signAbort(void); +size_t cosmos_getAddressNCount(); +void cosmos_getAddressN(uint32_t* address_n); bool cosmos_signTx(const uint8_t* private_key, const uint64_t account_number, const char* chain_id, diff --git a/include/keepkey/firmware/fsm.h b/include/keepkey/firmware/fsm.h index 7f11d6d6d..c331afec2 100644 --- a/include/keepkey/firmware/fsm.h +++ b/include/keepkey/firmware/fsm.h @@ -94,6 +94,7 @@ void fsm_msgEosTxActionAck(const EosTxActionAck *msg); void fsm_msgCosmosGetAddress(const CosmosGetAddress *msg); void fsm_msgCosmosSignTx(const CosmosSignTx *msg); +void fsm_msgCosmosMsgAck(const CosmosMsgAck *msg); #if DEBUG_LINK //void fsm_msgDebugLinkDecision(DebugLinkDecision *msg); diff --git a/include/keepkey/transport/messages-cosmos.options b/include/keepkey/transport/messages-cosmos.options index d9b318830..08b2916a8 100644 --- a/include/keepkey/transport/messages-cosmos.options +++ b/include/keepkey/transport/messages-cosmos.options @@ -4,10 +4,10 @@ CosmosAddress.address max_size:46 CosmosSignTx.address_n max_count:10 CosmosSignTx.chain_id max_size:32 -CosmosSignTx.from_address max_size:46 -CosmosSignTx.to_address max_size:46 CosmosSignTx.memo max_size:256 +CosmosMsgSend.from_address max_size:46 +CosmosMsgSend.to_address max_size:46 CosmosSignedTx.public_key max_size:33 CosmosSignedTx.signature max_size:64 \ No newline at end of file diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index 2a02ee7d0..b88ee0bf0 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -4,11 +4,21 @@ #include "keepkey/board/util.h" #include "keepkey/firmware/home_sm.h" #include "keepkey/firmware/storage.h" -#include "trezor/crypto/segwit_addr.h" #include "trezor/crypto/ecdsa.h" +#include "trezor/crypto/memzero.h" +#include "trezor/crypto/segwit_addr.h" #include #include +static CONFIDENTIAL HDNode node; +static SHA256_CTX ctx; +static bool has_message; +static bool initialized; +static uint32_t address_n[8]; +static size_t address_n_count; +static uint32_t msgs_remaining; +static uint64_t sequence; + bool cosmos_path_mismatched(const CoinType *_coin, const uint32_t *address_n, const uint32_t address_n_count) @@ -45,25 +55,29 @@ bool cosmos_getAddress(const HDNode *node, char *address) return bech32_encode(address, "cosmos", fiveBitExpanded, len) == 1; } -// Each segment guaranteed to be less than 64 bytes +// Each segment guaranteed to be less than or equal to 64 bytes // 19 + ^20 + 14 = ^53 -#define SIGNING_TEMPLATE_SEG1 "{\"account_number\":\"%" PRIu64 "\",\"chain_id\":\"" +#define SIGNING_TEMPLATE_START_SEG1 "{\"account_number\":\"%" PRIu64 "\",\"chain_id\":\"" // // 30 + ^10 + 24 = ^64 -#define SIGNING_TEMPLATE_SEG2 "\",\"fee\":{\"amount\":[{\"amount\":\"%" PRIu32 "\",\"denom\":\"uatom\"}],\"gas" +#define SIGNING_TEMPLATE_START_SEG2 "\",\"fee\":{\"amount\":[{\"amount\":\"%" PRIu32 "\",\"denom\":\"uatom\"}],\"gas" // 3 + ^10 + 11 = ^23 -#define SIGNING_TEMPLATE_SEG3 "\":\"%" PRIu32 "\"},\"memo\":\"" +#define SIGNING_TEMPLATE_START_SEG3 "\":\"%" PRIu32 "\"},\"memo\":\"" // -// 64 -#define SIGNING_TEMPLATE_SEG4 "\",\"msgs\":[{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{\"amount\":[{\"amou" -// 5 + ^20 + 36 = ^61 -#define SIGNING_TEMPLATE_SEG5 "nt\":\"%" PRIu64 "\",\"denom\":\"uatom\"}],\"from_address\":\"" +// 10 +#define SIGNING_TEMPLATE_START_SEG4 "\",\"msgs\":[" + +// 59 +#define SIGNING_TEMPLATE_MSG_SEND_SEG1 "{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{\"amount\":[{\"amount\":\"" +// ^20 + 36 = ^56 +#define SIGNING_TEMPLATE_MSG_SEND_SEG2 "%" PRIu64 "\",\"denom\":\"uatom\"}],\"from_address\":\"" // 45 + 16 = 61 -#define SIGNING_TEMPLATE_SEG6 "%s\",\"to_address\":\"" -// 45 + 17 = 62 -#define SIGNING_TEMPLATE_SEG7 "%s\"}}],\"sequence\":\"" -// ^20 + 2 = ^22 -#define SIGNING_TEMPLATE_SEG8 "%" PRIu64 "\"}" +#define SIGNING_TEMPLATE_MSG_SEND_SEG3 "%s\",\"to_address\":\"" +// 45 + 3 = 48 +#define SIGNING_TEMPLATE_MSG_SEND_SEG4 "%s\"}}" + +// 16 + ^20 = ^36 +#define SIGNING_TEMPLATE_END_SEG1 "],\"sequence\":\"%" PRIu64 "\"}" void sha256UpdateEscaped(SHA256_CTX *ctx, const char *s, size_t len) { @@ -86,71 +100,191 @@ void sha256UpdateEscaped(SHA256_CTX *ctx, const char *s, size_t len) } } -bool cosmos_signTx(const uint8_t *private_key, - const uint64_t account_number, - const char *chain_id, - const size_t chain_id_length, - const uint32_t fee_uatom_amount, - const uint32_t gas, - const char *memo, - const size_t memo_length, - const uint64_t amount, - const char *from_address, - const char *to_address, - const uint64_t sequence, - uint8_t *signature) +bool cosmos_signTxInit(const HDNode* _node, + const uint32_t _address_n[8], + const size_t _address_n_count, + const uint64_t account_number, + const char *chain_id, + const size_t chain_id_length, + const uint32_t fee_uatom_amount, + const uint32_t gas, + const char *memo, + const size_t memo_length, + const uint64_t _sequence, + const uint32_t msg_count) { - SHA256_CTX ctx; + + msgs_remaining = msg_count; + has_message = false; + sequence = _sequence; + + memzero(&node, sizeof(node)); + memcpy(&node, _node, sizeof(node)); + memzero(address_n, sizeof(address_n)); + memcpy(address_n, _address_n, sizeof(address_n)); + address_n_count = _address_n_count; + int n; sha256_Init(&ctx); char buffer[SHA256_BLOCK_LENGTH + 1]; // NULL TERMINATOR NOT PART OF HASH - n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG1, account_number); - if (n < 0) - { - return false; - } + + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_START_SEG1, account_number); + if (n < 0) { return false; } sha256_Update(&ctx, (uint8_t *)buffer, n); + sha256UpdateEscaped(&ctx, chain_id, chain_id_length); - n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG2, fee_uatom_amount); - if (n < 0) - { - return false; - } + + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_START_SEG2, fee_uatom_amount); + if (n < 0) { return false; } sha256_Update(&ctx, (uint8_t *)buffer, n); - n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG3, gas); - if (n < 0) - { - return false; - } + + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_START_SEG3, gas); + if (n < 0) { return false; } sha256_Update(&ctx, (uint8_t *)buffer, n); + sha256UpdateEscaped(&ctx, memo, memo_length); - sha256_Update(&ctx, (uint8_t *)SIGNING_TEMPLATE_SEG4, 64); // no interpolation needed - n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG5, amount); - if (n < 0) - { - return false; - } - sha256_Update(&ctx, (uint8_t *)buffer, n); - n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG6, from_address); - if (n < 0) - { - return false; - } - sha256_Update(&ctx, (uint8_t *)buffer, n); - n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG7, to_address); - if (n < 0) - { - return false; - } - sha256_Update(&ctx, (uint8_t *)buffer, n); - n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG8, sequence); - if (n < 0) - { - return false; + + return true; +} + +bool cosmos_signTxUpdateMsgSend(const uint64_t amount, + const char *from_address, + const char *to_address) +{ + int n; + char buffer[SHA256_DIGEST_LENGTH + 1]; // NULL TERMINATOR NOT PART OF HASH + + size_t decoded_len; + uint8_t decoded[33]; + if (!bech32_decode("cosmos", decoded, &decoded_len, from_address)) { return false; } + if (!bech32_decode("cosmos", decoded, &decoded_len, to_address)) { return false; } + + char* start_ptr; + if (has_message) { + buffer[0] = ','; + start_ptr = buffer + 1; + } else { + start_ptr = buffer; } + + n = snprintf(start_ptr, SHA256_BLOCK_LENGTH + 1 - (start_ptr == buffer ? 0 : 1), SIGNING_TEMPLATE_MSG_SEND_SEG1); + if (n < 0) { return false; } sha256_Update(&ctx, (uint8_t *)buffer, n); + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_MSG_SEND_SEG2, amount); + if (n < 0) { return false; } + sha256_Update(&ctx, (uint8_t*)buffer, n); + + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_MSG_SEND_SEG3, from_address); + if (n < 0) { return false; } + sha256_Update(&ctx, (uint8_t*)buffer, n); + + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_MSG_SEND_SEG4, to_address); + if (n < 0) { return false; } + sha256_Update(&ctx, (uint8_t*)buffer, n); + + has_message = true; + msgs_remaining--; + return true; +} + +bool cosmos_signTxFinalize(uint8_t* signature) +{ + int n; + char buffer[SHA256_DIGEST_LENGTH + 1]; // NULL TERMINATOR NOT PART OF HASH + + n = snprintf(buffer, SHA256_DIGEST_LENGTH + 1, SIGNING_TEMPLATE_END_SEG1, sequence); + if (n < 0) { return false; } + sha256_Update(&ctx, (uint8_t*)buffer, n); + uint8_t hash[SHA256_DIGEST_LENGTH]; sha256_Final(&ctx, hash); - return ecdsa_sign_digest(&secp256k1, private_key, hash, signature, NULL, NULL) == 0; + return ecdsa_sign_digest(&secp256k1, node.private_key, hash, signature, NULL, NULL) == 0; +} + +bool cosmos_signingIsInited() { + return initialized; } + +bool cosmos_signingIsFinished() { + return msgs_remaining == 0; +} + +void cosmos_signAbort(void) { + initialized = false; + has_message = false; + memzero(&ctx, sizeof(ctx)); + memzero(&node, sizeof(node)); + memzero(&sequence, sizeof(sequence)); + msgs_remaining = 0; + sequence = 0; +} + +// bool cosmos_signTx(const uint8_t *private_key, +// const uint64_t account_number, +// const char *chain_id, +// const size_t chain_id_length, +// const uint32_t fee_uatom_amount, +// const uint32_t gas, +// const char *memo, +// const size_t memo_length, +// const uint64_t amount, +// const char *from_address, +// const char *to_address, +// const uint64_t sequence, +// uint8_t *signature) +// { +// SHA256_CTX ctx; +// int n; +// sha256_Init(&ctx); +// char buffer[SHA256_BLOCK_LENGTH + 1]; // NULL TERMINATOR NOT PART OF HASH +// n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG1, account_number); +// if (n < 0) +// { +// return false; +// } +// sha256_Update(&ctx, (uint8_t *)buffer, n); +// sha256UpdateEscaped(&ctx, chain_id, chain_id_length); +// n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG2, fee_uatom_amount); +// if (n < 0) +// { +// return false; +// } +// sha256_Update(&ctx, (uint8_t *)buffer, n); +// n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG3, gas); +// if (n < 0) +// { +// return false; +// } +// sha256_Update(&ctx, (uint8_t *)buffer, n); +// sha256UpdateEscaped(&ctx, memo, memo_length); +// sha256_Update(&ctx, (uint8_t *)SIGNING_TEMPLATE_SEG4, 64); // no interpolation needed +// n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG5, amount); +// if (n < 0) +// { +// return false; +// } +// sha256_Update(&ctx, (uint8_t *)buffer, n); +// n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG6, from_address); +// if (n < 0) +// { +// return false; +// } +// sha256_Update(&ctx, (uint8_t *)buffer, n); +// n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG7, to_address); +// if (n < 0) +// { +// return false; +// } +// sha256_Update(&ctx, (uint8_t *)buffer, n); +// n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG8, sequence); +// if (n < 0) +// { +// return false; +// } +// sha256_Update(&ctx, (uint8_t *)buffer, n); + +// uint8_t hash[SHA256_DIGEST_LENGTH]; +// sha256_Final(&ctx, hash); +// return ecdsa_sign_digest(&secp256k1, private_key, hash, signature, NULL, NULL) == 0; +// } diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h index 0fda053ff..cf4f3fb04 100644 --- a/lib/firmware/fsm_msg_cosmos.h +++ b/lib/firmware/fsm_msg_cosmos.h @@ -58,73 +58,98 @@ void fsm_msgCosmosSignTx(const CosmosSignTx *msg) CHECK_INITIALIZED CHECK_PIN - const char *coin_name = "Cosmos"; - const CoinType *coin = fsm_getCoin(true, coin_name); - if (!coin) { return; } + HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); if (!node) { return; } hdnode_fill_public_key(node); - char node_str[NODE_STRING_LENGTH]; - if (!bip32_node_to_string(node_str, sizeof(node_str), coin, msg->address_n, - msg->address_n_count, /*whole_account=*/false, - /*show_addridx=*/true) && - !bip32_path_to_string(node_str, sizeof(node_str), - msg->address_n, msg->address_n_count)) { - memset(node_str, 0, sizeof(node_str)); - } + - // Confirm transaction basics - if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Main Details"), "From: %s\nTo: %s\nAmount: %f ATOM", node_str, msg->to_address, (float)msg->amount * 1E-6)) + if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Fee Details"), "Fee: %" PRIu32 " uATOM\nGas: %" PRIu32 "", msg->fee_amount, msg->gas)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } - if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Fee Details"), "Fee: %" PRIu32 " uATOM\nGas: %" PRIu32 "", msg->fee_amount, msg->gas)) + if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Aux Details"), "Memo: \"%s\"\nChain ID: %s", msg->memo, msg->chain_id)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } - if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Aux Details"), "Memo: \"%s\"\nChain ID: %s\nAccount #: %" PRIu64 "", msg->memo, msg->chain_id, msg->account_number)) + RESP_INIT(CosmosMsgRequest); + + if (!cosmos_signTxInit(node, + msg->address_n, + msg->address_n_count, + msg->account_number, + msg->chain_id, + strlen(msg->chain_id), + msg->fee_amount, + msg->gas, + msg->memo, + strlen(msg->memo), + msg->sequence, + msg->msg_count)) { - fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + fsm_sendFailure(FailureType_Failure_FirmwareError, + _("Failed to initialize transaction signing")); layoutHome(); return; } - RESP_INIT(CosmosSignedTx); - if (!cosmos_signTx(node->private_key, - msg->account_number, - msg->chain_id, - strlen(msg->chain_id), - msg->fee_amount, - msg->gas, - msg->memo, - strlen(msg->memo), - msg->amount, - msg->from_address, - msg->to_address, - msg->sequence, - resp->signature.bytes)) - { + + layoutHome(); + msg_write(MessageType_MessageType_CosmosMsgRequest, resp); +} + +void fsm_msgCosmosMsgAck(const CosmosMsgAck* msg) { + // Confirm transaction basics + CHECK_PARAM(cosmos_signingIsInited(), "Must call CosmosSignTx to initiate signing"); + if (!msg->has_send) { + cosmos_signAbort(); fsm_sendFailure(FailureType_Failure_FirmwareError, - _("Failed to sign transaction")); + _("Invalid Cosmos Message Type")); + layoutHome(); + return; + } + + const char *coin_name = "Cosmos"; + const CoinType *coin = fsm_getCoin(true, coin_name); + if (!coin) { return; } + + uint32_t address_n[8]; + cosmos_getAddressN(address_n); + size_t address_n_count = cosmos_getAddressNCount(); + char node_str[NODE_STRING_LENGTH]; + if (!bip32_node_to_string(node_str, sizeof(node_str), coin, address_n, + address_n_count, /*whole_account=*/false, + /*show_addridx=*/true) && + !bip32_path_to_string(node_str, sizeof(node_str), + address_n, address_n_count)) { + memset(node_str, 0, sizeof(node_str)); + } + + if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Send Details"), "From: %s\nTo: %s\nAmount: %f ATOM", node_str, msg->send.to_address, (float)msg->send.amount * 1E-6)) + { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } - resp->signature.size = 64; - resp->has_signature = true; + + if (!cosmos_signingIsFinished()) { + RESP_INIT(CosmosMsgRequest); + msg_write(MessageType_MessageType_CosmosMsgRequest, resp); + return; + } + + RESP_INIT(CosmosSignedTx); memcpy(resp->public_key.bytes, node->public_key, 33); resp->public_key.size = 33; resp->has_public_key = true; - - layoutHome(); - msg_write(MessageType_MessageType_CosmosSignedTx, resp); -} +} \ No newline at end of file diff --git a/lib/firmware/messagemap.def b/lib/firmware/messagemap.def index fd6a77c53..a2f4c278c 100644 --- a/lib/firmware/messagemap.def +++ b/lib/firmware/messagemap.def @@ -43,6 +43,7 @@ MSG_IN(MessageType_MessageType_CosmosGetAddress, CosmosGetAddress, fsm_msgCosmosGetAddress) MSG_IN(MessageType_MessageType_CosmosSignTx, CosmosSignTx, fsm_msgCosmosSignTx) + MSG_IN(MessageType_MessageType_CosmosMsgAck, CosmosMsgAck, fsm_msgCosmosMsgAck) MSG_IN(MessageType_MessageType_EosGetPublicKey, EosGetPublicKey, fsm_msgEosGetPublicKey) MSG_IN(MessageType_MessageType_EosSignTx, EosSignTx, fsm_msgEosSignTx) @@ -77,6 +78,7 @@ MSG_OUT(MessageType_MessageType_NanoSignedTx, NanoSignedTx, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_CosmosAddress, CosmosAddress, NO_PROCESS_FUNC) + MSG_OUT(MessageType_MessageType_CosmosMsgRequest, CosmosMsgRequest, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_CosmosSignedTx, CosmosSignedTx, NO_PROCESS_FUNC) MSG_OUT(MessageType_MessageType_EosPublicKey, EosPublicKey, NO_PROCESS_FUNC) From 5fd3abb61021cc0c0079e4edf7e2c79b731bf6ae Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 13 Nov 2019 18:13:15 -0700 Subject: [PATCH 24/44] updates device protocol dependency --- deps/device-protocol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/device-protocol b/deps/device-protocol index 1b92e340f..97d4c7f6e 160000 --- a/deps/device-protocol +++ b/deps/device-protocol @@ -1 +1 @@ -Subproject commit 1b92e340f952d33d1e2f02651bf85d1d64e1b183 +Subproject commit 97d4c7f6ef3ae9ec0b5f129cbcc20f006d6f3441 From 59d535869cfc0073e1f65790db24bda6b1870526 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 13 Nov 2019 19:56:11 -0700 Subject: [PATCH 25/44] WIP: trying to get unit tests to pass with refactor --- include/keepkey/firmware/cosmos.h | 32 +++++++++++++++++-------------- lib/firmware/cosmos.c | 24 ++++++++++++++++++++--- lib/firmware/fsm_msg_cosmos.h | 24 +++++++++++++++++++++-- unittests/firmware/cosmos.cpp | 17 ++++++++++++++-- 4 files changed, 76 insertions(+), 21 deletions(-) diff --git a/include/keepkey/firmware/cosmos.h b/include/keepkey/firmware/cosmos.h index 8f041f542..1c619ad66 100644 --- a/include/keepkey/firmware/cosmos.h +++ b/include/keepkey/firmware/cosmos.h @@ -25,23 +25,27 @@ bool cosmos_signTxInit(const HDNode* _node, const size_t memo_length, const uint64_t _sequence, const uint32_t msg_count); +bool cosmos_signTxUpdateMsgSend(const uint64_t amount, + const char *from_address, + const char *to_address); +bool cosmos_signTxFinalize(uint8_t* public_key, uint8_t* signature); bool cosmos_signingIsInited(); bool cosmos_signingIsFinished(); void cosmos_signAbort(void); size_t cosmos_getAddressNCount(); -void cosmos_getAddressN(uint32_t* address_n); -bool cosmos_signTx(const uint8_t* private_key, - const uint64_t account_number, - const char* chain_id, - const size_t chain_id_length, - const uint32_t fee_uatom_amount, - const uint32_t gas, - const char* memo, - const size_t memo_length, - const uint64_t amount, - const char* from_address, - const char* to_address, - const uint64_t sequence, - uint8_t* signature); +bool cosmos_getAddressN(uint32_t* address_n, size_t address_n_count); +// bool cosmos_signTx(const uint8_t* private_key, +// const uint64_t account_number, +// const char* chain_id, +// const size_t chain_id_length, +// const uint32_t fee_uatom_amount, +// const uint32_t gas, +// const char* memo, +// const size_t memo_length, +// const uint64_t amount, +// const char* from_address, +// const char* to_address, +// const uint64_t sequence, +// uint8_t* signature); #endif \ No newline at end of file diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index b88ee0bf0..f062f2291 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -101,7 +101,7 @@ void sha256UpdateEscaped(SHA256_CTX *ctx, const char *s, size_t len) } bool cosmos_signTxInit(const HDNode* _node, - const uint32_t _address_n[8], + const uint32_t* _address_n, const size_t _address_n_count, const uint64_t account_number, const char *chain_id, @@ -155,10 +155,12 @@ bool cosmos_signTxUpdateMsgSend(const uint64_t amount, char buffer[SHA256_DIGEST_LENGTH + 1]; // NULL TERMINATOR NOT PART OF HASH size_t decoded_len; - uint8_t decoded[33]; + uint8_t decoded[38]; if (!bech32_decode("cosmos", decoded, &decoded_len, from_address)) { return false; } if (!bech32_decode("cosmos", decoded, &decoded_len, to_address)) { return false; } + return false; // TODO: REMOVE THIS + char* start_ptr; if (has_message) { buffer[0] = ','; @@ -188,7 +190,7 @@ bool cosmos_signTxUpdateMsgSend(const uint64_t amount, return true; } -bool cosmos_signTxFinalize(uint8_t* signature) +bool cosmos_signTxFinalize(uint8_t* public_key, uint8_t* signature) { int n; char buffer[SHA256_DIGEST_LENGTH + 1]; // NULL TERMINATOR NOT PART OF HASH @@ -197,6 +199,9 @@ bool cosmos_signTxFinalize(uint8_t* signature) if (n < 0) { return false; } sha256_Update(&ctx, (uint8_t*)buffer, n); + hdnode_fill_public_key(&node); + memcpy(public_key, node.public_key, 33); + uint8_t hash[SHA256_DIGEST_LENGTH]; sha256_Final(&ctx, hash); return ecdsa_sign_digest(&secp256k1, node.private_key, hash, signature, NULL, NULL) == 0; @@ -220,6 +225,19 @@ void cosmos_signAbort(void) { sequence = 0; } +size_t cosmos_getAddressNCount() { + return address_n_count; +} + +bool cosmos_getAddressN(uint32_t* _address_n, size_t _address_n_count) +{ + if (_address_n_count < address_n_count) { + return false; + } + memcpy(_address_n, address_n, sizeof(uint32_t) * address_n_count); + return true; +} + // bool cosmos_signTx(const uint8_t *private_key, // const uint64_t account_number, // const char *chain_id, diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h index cf4f3fb04..023cb989a 100644 --- a/lib/firmware/fsm_msg_cosmos.h +++ b/lib/firmware/fsm_msg_cosmos.h @@ -123,7 +123,11 @@ void fsm_msgCosmosMsgAck(const CosmosMsgAck* msg) { if (!coin) { return; } uint32_t address_n[8]; - cosmos_getAddressN(address_n); + if(!cosmos_getAddressN(address_n, 8)) { + cosmos_signAbort(); + fsm_sendFailure(FailureType_Failure_FirmwareError, "Failed to get derivation path"); + return; + } size_t address_n_count = cosmos_getAddressNCount(); char node_str[NODE_STRING_LENGTH]; if (!bip32_node_to_string(node_str, sizeof(node_str), coin, address_n, @@ -136,11 +140,18 @@ void fsm_msgCosmosMsgAck(const CosmosMsgAck* msg) { if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Send Details"), "From: %s\nTo: %s\nAmount: %f ATOM", node_str, msg->send.to_address, (float)msg->send.amount * 1E-6)) { + cosmos_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } + if(!cosmos_signTxUpdateMsgSend(msg->send.amount, msg->send.from_address, msg->send.to_address)) { + cosmos_signAbort(); + fsm_sendFailure(FailureType_Failure_FirmwareError, "Failed to include send message in transaction"); + return; + } + if (!cosmos_signingIsFinished()) { RESP_INIT(CosmosMsgRequest); msg_write(MessageType_MessageType_CosmosMsgRequest, resp); @@ -149,7 +160,16 @@ void fsm_msgCosmosMsgAck(const CosmosMsgAck* msg) { RESP_INIT(CosmosSignedTx); - memcpy(resp->public_key.bytes, node->public_key, 33); + if(!cosmos_signTxFinalize(resp->public_key.bytes, resp->signature.bytes)) { + fsm_sendFailure(FailureType_Failure_FirmwareError, "Failed to finalize signature"); + layoutHome(); + return; + } + resp->public_key.size = 33; resp->has_public_key = true; + resp->signature.size = 64; + resp->has_signature = true; + layoutHome(); + msg_write(MessageType_MessageType_CosmosSignedTx, resp); } \ No newline at end of file diff --git a/unittests/firmware/cosmos.cpp b/unittests/firmware/cosmos.cpp index d26dbf78c..18e44b9c3 100644 --- a/unittests/firmware/cosmos.cpp +++ b/unittests/firmware/cosmos.cpp @@ -24,9 +24,22 @@ TEST(Cosmos, CosmosGetAddress) TEST(Cosmos, CosmosSignTx) { + HDNode node = { + 0, + 0, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + { 0x04, 0xde, 0xc0, 0xcc, 0x01, 0x3c, 0xd8, 0xab, 0x70, 0x87, 0xca, 0x14, 0x96, 0x0b, 0x76, 0x8c, 0x3d, 0x83, 0x45, 0x24, 0x48, 0xaa, 0x00, 0x64, 0xda, 0xe6, 0xfb, 0x04, 0xb5, 0xd9, 0x34, 0x76 }, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + &secp256k1_info + }; const uint8_t *privkey = (uint8_t *)"\x04\xde\xc0\xcc\x01\x3c\xd8\xab\x70\x87\xca\x14\x96\x0b\x76\x8c\x3d\x83\x45\x24\x48\xaa\x00\x64\xda\xe6\xfb\x04\xb5\xd9\x34\x76"; uint8_t signature[64]; const uint8_t *expected = (uint8_t *)"\x41\x99\x66\x30\x08\xef\xea\x75\x93\x56\x35\xe6\x1a\x11\xdf\xa3\x3c\xeb\xeb\x91\xc1\xca\xed\xc6\x0e\x5e\xef\x3c\xa2\xc0\x1f\x83\x48\x08\x36\xe6\x21\x89\x51\x14\x36\x64\x7f\xac\x5a\xbd\xc2\x9f\x54\xae\x3d\x7e\x47\x56\x43\xca\x33\xc7\xad\x2c\x8a\x53\x2b\x39"; - ASSERT_TRUE(cosmos_signTx(privkey, 0, "cosmoshub-2", strlen("cosmoshub-2"), 5000, 200000, "", 0, 100000, "cosmos1am058pdux3hyulcmfgj4m3hhrlfn8nzm88u80q", "cosmos18vhdczjut44gpsy804crfhnd5nq003nz0nf20v", 0, signature)); - EXPECT_TRUE(memcmp(expected, signature, 64) == 0); + const uint32_t address_n[5] = {0x80000000|44, 0x80000000|118, 0x80000000, 0, 0}; + ASSERT_TRUE(cosmos_signTxInit(&node, address_n, 5, 0, "cosmoshub-2", strlen("cosmoshub-2"), 5000, 200000, "", 0, 0, 1)); + // vvv this is the part that is segfaulting right now, I think it's the bech32 decodes, hence the immediate return false afterwards vvv + ASSERT_TRUE(cosmos_signTxUpdateMsgSend(100000, "cosmos1am058pdux3hyulcmfgj4m3hhrlfn8nzm88u80q", "cosmos18vhdczjut44gpsy804crfhnd5nq003nz0nf20v")); + // ASSERT_TRUE(cosmos_signTxFinalize(privkey, 0, "cosmoshub-2", strlen("cosmoshub-2"), 5000, 200000, "", 0, 100000, "cosmos1am058pdux3hyulcmfgj4m3hhrlfn8nzm88u80q", "cosmos18vhdczjut44gpsy804crfhnd5nq003nz0nf20v", 0, signature)); + // EXPECT_TRUE(memcmp(expected, signature, 64) == 0); } From 17bd6915592e5f4608f8f438f671a9d0310f01ac Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 13 Nov 2019 22:34:11 -0700 Subject: [PATCH 26/44] WIP: phase 2 works? --- lib/firmware/cosmos.c | 14 +++++++------- unittests/firmware/cosmos.cpp | 1 - 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index f062f2291..93e9635ba 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -152,14 +152,13 @@ bool cosmos_signTxUpdateMsgSend(const uint64_t amount, const char *to_address) { int n; - char buffer[SHA256_DIGEST_LENGTH + 1]; // NULL TERMINATOR NOT PART OF HASH + char buffer[SHA256_BLOCK_LENGTH + 1]; // NULL TERMINATOR NOT PART OF HASH size_t decoded_len; + char hrp[7]; uint8_t decoded[38]; - if (!bech32_decode("cosmos", decoded, &decoded_len, from_address)) { return false; } - if (!bech32_decode("cosmos", decoded, &decoded_len, to_address)) { return false; } - - return false; // TODO: REMOVE THIS + if (!bech32_decode(hrp, decoded, &decoded_len, from_address)) { return false; } + if (!bech32_decode(hrp, decoded, &decoded_len, to_address)) { return false; } char* start_ptr; if (has_message) { @@ -169,9 +168,10 @@ bool cosmos_signTxUpdateMsgSend(const uint64_t amount, start_ptr = buffer; } - n = snprintf(start_ptr, SHA256_BLOCK_LENGTH + 1 - (start_ptr == buffer ? 0 : 1), SIGNING_TEMPLATE_MSG_SEND_SEG1); + n = snprintf(start_ptr, SHA256_BLOCK_LENGTH + 1 - has_message, SIGNING_TEMPLATE_MSG_SEND_SEG1); if (n < 0) { return false; } - sha256_Update(&ctx, (uint8_t *)buffer, n); + sha256_Update(&ctx, (uint8_t *)buffer, n + has_message); + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_MSG_SEND_SEG2, amount); if (n < 0) { return false; } diff --git a/unittests/firmware/cosmos.cpp b/unittests/firmware/cosmos.cpp index 18e44b9c3..0061f2203 100644 --- a/unittests/firmware/cosmos.cpp +++ b/unittests/firmware/cosmos.cpp @@ -38,7 +38,6 @@ TEST(Cosmos, CosmosSignTx) const uint8_t *expected = (uint8_t *)"\x41\x99\x66\x30\x08\xef\xea\x75\x93\x56\x35\xe6\x1a\x11\xdf\xa3\x3c\xeb\xeb\x91\xc1\xca\xed\xc6\x0e\x5e\xef\x3c\xa2\xc0\x1f\x83\x48\x08\x36\xe6\x21\x89\x51\x14\x36\x64\x7f\xac\x5a\xbd\xc2\x9f\x54\xae\x3d\x7e\x47\x56\x43\xca\x33\xc7\xad\x2c\x8a\x53\x2b\x39"; const uint32_t address_n[5] = {0x80000000|44, 0x80000000|118, 0x80000000, 0, 0}; ASSERT_TRUE(cosmos_signTxInit(&node, address_n, 5, 0, "cosmoshub-2", strlen("cosmoshub-2"), 5000, 200000, "", 0, 0, 1)); - // vvv this is the part that is segfaulting right now, I think it's the bech32 decodes, hence the immediate return false afterwards vvv ASSERT_TRUE(cosmos_signTxUpdateMsgSend(100000, "cosmos1am058pdux3hyulcmfgj4m3hhrlfn8nzm88u80q", "cosmos18vhdczjut44gpsy804crfhnd5nq003nz0nf20v")); // ASSERT_TRUE(cosmos_signTxFinalize(privkey, 0, "cosmoshub-2", strlen("cosmoshub-2"), 5000, 200000, "", 0, 100000, "cosmos1am058pdux3hyulcmfgj4m3hhrlfn8nzm88u80q", "cosmos18vhdczjut44gpsy804crfhnd5nq003nz0nf20v", 0, signature)); // EXPECT_TRUE(memcmp(expected, signature, 64) == 0); From 6e7c70193b0969aca5f5ed2fe11d450916cfd7fd Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 13 Nov 2019 23:03:28 -0700 Subject: [PATCH 27/44] =?UTF-8?q?Unit=20Tests=20Pass=20For=20Real=E2=84=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/firmware/cosmos.c | 12 +++++------- unittests/firmware/cosmos.cpp | 9 +++++---- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index 93e9635ba..cded8d0b3 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -144,6 +144,8 @@ bool cosmos_signTxInit(const HDNode* _node, sha256UpdateEscaped(&ctx, memo, memo_length); + sha256_Update(&ctx, SIGNING_TEMPLATE_START_SEG4, 10); + return true; } @@ -160,17 +162,13 @@ bool cosmos_signTxUpdateMsgSend(const uint64_t amount, if (!bech32_decode(hrp, decoded, &decoded_len, from_address)) { return false; } if (!bech32_decode(hrp, decoded, &decoded_len, to_address)) { return false; } - char* start_ptr; if (has_message) { - buffer[0] = ','; - start_ptr = buffer + 1; - } else { - start_ptr = buffer; + sha256_Update(&ctx, (uint8_t*)",", 1); } - n = snprintf(start_ptr, SHA256_BLOCK_LENGTH + 1 - has_message, SIGNING_TEMPLATE_MSG_SEND_SEG1); + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_MSG_SEND_SEG1); if (n < 0) { return false; } - sha256_Update(&ctx, (uint8_t *)buffer, n + has_message); + sha256_Update(&ctx, (uint8_t *)buffer, n); n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_MSG_SEND_SEG2, amount); diff --git a/unittests/firmware/cosmos.cpp b/unittests/firmware/cosmos.cpp index 0061f2203..babcaed70 100644 --- a/unittests/firmware/cosmos.cpp +++ b/unittests/firmware/cosmos.cpp @@ -34,11 +34,12 @@ TEST(Cosmos, CosmosSignTx) &secp256k1_info }; const uint8_t *privkey = (uint8_t *)"\x04\xde\xc0\xcc\x01\x3c\xd8\xab\x70\x87\xca\x14\x96\x0b\x76\x8c\x3d\x83\x45\x24\x48\xaa\x00\x64\xda\xe6\xfb\x04\xb5\xd9\x34\x76"; - uint8_t signature[64]; const uint8_t *expected = (uint8_t *)"\x41\x99\x66\x30\x08\xef\xea\x75\x93\x56\x35\xe6\x1a\x11\xdf\xa3\x3c\xeb\xeb\x91\xc1\xca\xed\xc6\x0e\x5e\xef\x3c\xa2\xc0\x1f\x83\x48\x08\x36\xe6\x21\x89\x51\x14\x36\x64\x7f\xac\x5a\xbd\xc2\x9f\x54\xae\x3d\x7e\x47\x56\x43\xca\x33\xc7\xad\x2c\x8a\x53\x2b\x39"; const uint32_t address_n[5] = {0x80000000|44, 0x80000000|118, 0x80000000, 0, 0}; ASSERT_TRUE(cosmos_signTxInit(&node, address_n, 5, 0, "cosmoshub-2", strlen("cosmoshub-2"), 5000, 200000, "", 0, 0, 1)); - ASSERT_TRUE(cosmos_signTxUpdateMsgSend(100000, "cosmos1am058pdux3hyulcmfgj4m3hhrlfn8nzm88u80q", "cosmos18vhdczjut44gpsy804crfhnd5nq003nz0nf20v")); - // ASSERT_TRUE(cosmos_signTxFinalize(privkey, 0, "cosmoshub-2", strlen("cosmoshub-2"), 5000, 200000, "", 0, 100000, "cosmos1am058pdux3hyulcmfgj4m3hhrlfn8nzm88u80q", "cosmos18vhdczjut44gpsy804crfhnd5nq003nz0nf20v", 0, signature)); - // EXPECT_TRUE(memcmp(expected, signature, 64) == 0); + ASSERT_TRUE(cosmos_signTxUpdateMsgSend(100000, "cosmos1am058pdux3hyulcmfgj4m3hhrlfn8nzm88u80q", "cosmos18vhdczjut44gpsy804crfhnd5nq003nz0nf20v")); + uint8_t public_key[33]; + uint8_t signature[64]; + ASSERT_TRUE(cosmos_signTxFinalize(public_key, signature)); + EXPECT_TRUE(memcmp(expected, signature, 64) == 0); } From fe51ffc045490858a6306507358f320d47776639 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 13 Nov 2019 23:07:38 -0700 Subject: [PATCH 28/44] switched to sizeof --- lib/firmware/cosmos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index cded8d0b3..b2a6272a6 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -144,7 +144,7 @@ bool cosmos_signTxInit(const HDNode* _node, sha256UpdateEscaped(&ctx, memo, memo_length); - sha256_Update(&ctx, SIGNING_TEMPLATE_START_SEG4, 10); + sha256_Update(&ctx, SIGNING_TEMPLATE_START_SEG4, sizeof(SIGNING_TEMPLATE_START_SEG4) - 1); return true; } From 5c2fa36222e80cce5290c99abf0cd01a65dc52b4 Mon Sep 17 00:00:00 2001 From: Aiden McClelland Date: Wed, 13 Nov 2019 23:49:57 -0700 Subject: [PATCH 29/44] fix optionals --- deps/python-keepkey | 2 +- include/keepkey/firmware/cosmos.h | 12 +++++----- lib/firmware/cosmos.c | 38 +++++++++++++++---------------- lib/firmware/fsm_msg_cosmos.h | 19 +++++++++++----- 4 files changed, 39 insertions(+), 32 deletions(-) diff --git a/deps/python-keepkey b/deps/python-keepkey index b4af5b4ba..e2047aa15 160000 --- a/deps/python-keepkey +++ b/deps/python-keepkey @@ -1 +1 @@ -Subproject commit b4af5b4bab81b5567490136d02a0681b9ac1a266 +Subproject commit e2047aa15ff1d2311b34a99de5bd8afca1a4d6a5 diff --git a/include/keepkey/firmware/cosmos.h b/include/keepkey/firmware/cosmos.h index 1c619ad66..9612bba9d 100644 --- a/include/keepkey/firmware/cosmos.h +++ b/include/keepkey/firmware/cosmos.h @@ -10,9 +10,9 @@ #include "trezor/crypto/bip32.h" bool cosmos_path_mismatched(const CoinType *_coin, - const uint32_t *address_n, - const uint32_t address_n_count); -bool cosmos_getAddress(const HDNode *node, char *address); + const uint32_t *_address_n, + const uint32_t _address_n_count); +bool cosmos_getAddress(const HDNode *_node, char *address); bool cosmos_signTxInit(const HDNode* _node, const uint32_t _address_n[8], const size_t _address_n_count, @@ -29,10 +29,10 @@ bool cosmos_signTxUpdateMsgSend(const uint64_t amount, const char *from_address, const char *to_address); bool cosmos_signTxFinalize(uint8_t* public_key, uint8_t* signature); -bool cosmos_signingIsInited(); -bool cosmos_signingIsFinished(); +bool cosmos_signingIsInited(void); +bool cosmos_signingIsFinished(void); void cosmos_signAbort(void); -size_t cosmos_getAddressNCount(); +size_t cosmos_getAddressNCount(void); bool cosmos_getAddressN(uint32_t* address_n, size_t address_n_count); // bool cosmos_signTx(const uint8_t* private_key, // const uint64_t account_number, diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index b2a6272a6..80e56442f 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -20,18 +20,18 @@ static uint32_t msgs_remaining; static uint64_t sequence; bool cosmos_path_mismatched(const CoinType *_coin, - const uint32_t *address_n, - const uint32_t address_n_count) + const uint32_t *_address_n, + const uint32_t _address_n_count) { // m/44' : BIP44-like path // m / purpose' / bip44_account_path' / account' / x / y bool mismatch = false; - mismatch |= address_n_count != 5; - mismatch |= address_n_count > 0 && (address_n[0] != (0x80000000 + 44)); - mismatch |= address_n_count > 1 && (address_n[1] != _coin->bip44_account_path); - mismatch |= address_n_count > 2 && (address_n[2] & 0x80000000) == 0; - mismatch |= address_n_count > 3 && (address_n[3] & 0x80000000) != 0; - mismatch |= address_n_count > 4 && (address_n[4] & 0x80000000) != 0; + mismatch |= _address_n_count != 5; + mismatch |= _address_n_count > 0 && (_address_n[0] != (0x80000000 + 44)); + mismatch |= _address_n_count > 1 && (_address_n[1] != _coin->bip44_account_path); + mismatch |= _address_n_count > 2 && (_address_n[2] & 0x80000000) == 0; + mismatch |= _address_n_count > 3 && (_address_n[3] & 0x80000000) != 0; + mismatch |= _address_n_count > 4 && (_address_n[4] & 0x80000000) != 0; return mismatch; } @@ -43,10 +43,10 @@ bool cosmos_path_mismatched(const CoinType *_coin, * * returns true if successful */ -bool cosmos_getAddress(const HDNode *node, char *address) +bool cosmos_getAddress(const HDNode *_node, char *address) { uint8_t hash160Buf[RIPEMD160_DIGEST_LENGTH]; - ecdsa_get_pubkeyhash(node->public_key, HASHER_SHA2_RIPEMD, hash160Buf); + ecdsa_get_pubkeyhash(_node->public_key, HASHER_SHA2_RIPEMD, hash160Buf); uint8_t fiveBitExpanded[RIPEMD160_DIGEST_LENGTH * 8 / 5]; size_t len = 0; @@ -79,21 +79,21 @@ bool cosmos_getAddress(const HDNode *node, char *address) // 16 + ^20 = ^36 #define SIGNING_TEMPLATE_END_SEG1 "],\"sequence\":\"%" PRIu64 "\"}" -void sha256UpdateEscaped(SHA256_CTX *ctx, const char *s, size_t len) +void sha256UpdateEscaped(SHA256_CTX *_ctx, const char *s, size_t len) { while (len > 0) { if (s[0] == '"') { - sha256_Update(ctx, (uint8_t *)"\\\"", 2); + sha256_Update(_ctx, (uint8_t *)"\\\"", 2); } else if (s[0] == '\\') { - sha256_Update(ctx, (uint8_t *)"\\\\", 2); + sha256_Update(_ctx, (uint8_t *)"\\\\", 2); } else { - sha256_Update(ctx, (uint8_t *)&s[0], 1); + sha256_Update(_ctx, (uint8_t *)&s[0], 1); } s = &s[1]; len--; @@ -144,7 +144,7 @@ bool cosmos_signTxInit(const HDNode* _node, sha256UpdateEscaped(&ctx, memo, memo_length); - sha256_Update(&ctx, SIGNING_TEMPLATE_START_SEG4, sizeof(SIGNING_TEMPLATE_START_SEG4) - 1); + sha256_Update(&ctx, (uint8_t *)SIGNING_TEMPLATE_START_SEG4, sizeof(SIGNING_TEMPLATE_START_SEG4) - 1); return true; } @@ -157,7 +157,7 @@ bool cosmos_signTxUpdateMsgSend(const uint64_t amount, char buffer[SHA256_BLOCK_LENGTH + 1]; // NULL TERMINATOR NOT PART OF HASH size_t decoded_len; - char hrp[7]; + char hrp[45]; uint8_t decoded[38]; if (!bech32_decode(hrp, decoded, &decoded_len, from_address)) { return false; } if (!bech32_decode(hrp, decoded, &decoded_len, to_address)) { return false; } @@ -205,11 +205,11 @@ bool cosmos_signTxFinalize(uint8_t* public_key, uint8_t* signature) return ecdsa_sign_digest(&secp256k1, node.private_key, hash, signature, NULL, NULL) == 0; } -bool cosmos_signingIsInited() { +bool cosmos_signingIsInited(void) { return initialized; } -bool cosmos_signingIsFinished() { +bool cosmos_signingIsFinished(void) { return msgs_remaining == 0; } @@ -223,7 +223,7 @@ void cosmos_signAbort(void) { sequence = 0; } -size_t cosmos_getAddressNCount() { +size_t cosmos_getAddressNCount(void) { return address_n_count; } diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h index 023cb989a..43321c8be 100644 --- a/lib/firmware/fsm_msg_cosmos.h +++ b/lib/firmware/fsm_msg_cosmos.h @@ -58,14 +58,21 @@ void fsm_msgCosmosSignTx(const CosmosSignTx *msg) CHECK_INITIALIZED CHECK_PIN - + if (!msg->has_account_number || + !msg->has_chain_id || + !msg->has_fee_amount || + !msg->has_gas || + !msg->has_sequence) { + fsm_sendFailure(FailureType_Failure_SyntaxError, "Missing Fields On Message"); + layoutHome(); + return; + } + HDNode *node = fsm_getDerivedNode(SECP256K1_NAME, msg->address_n, msg->address_n_count, NULL); if (!node) { return; } hdnode_fill_public_key(node); - - if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Fee Details"), "Fee: %" PRIu32 " uATOM\nGas: %" PRIu32 "", msg->fee_amount, msg->gas)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); @@ -90,8 +97,8 @@ void fsm_msgCosmosSignTx(const CosmosSignTx *msg) strlen(msg->chain_id), msg->fee_amount, msg->gas, - msg->memo, - strlen(msg->memo), + msg->has_memo ? msg->memo : "", + msg->has_memo ? strlen(msg->memo) : 0, msg->sequence, msg->msg_count)) { @@ -110,7 +117,7 @@ void fsm_msgCosmosSignTx(const CosmosSignTx *msg) void fsm_msgCosmosMsgAck(const CosmosMsgAck* msg) { // Confirm transaction basics CHECK_PARAM(cosmos_signingIsInited(), "Must call CosmosSignTx to initiate signing"); - if (!msg->has_send) { + if (!msg->has_send || !msg->send.has_from_address || !msg->send.has_to_address || !msg->send.has_amount) { cosmos_signAbort(); fsm_sendFailure(FailureType_Failure_FirmwareError, _("Invalid Cosmos Message Type")); From 12bcaa290c236244c8e40ce8a55b4269d15e71cf Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Thu, 14 Nov 2019 00:23:53 -0700 Subject: [PATCH 30/44] Integration tests work --- deps/python-keepkey | 2 +- lib/firmware/cosmos.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/deps/python-keepkey b/deps/python-keepkey index e2047aa15..0140bb456 160000 --- a/deps/python-keepkey +++ b/deps/python-keepkey @@ -1 +1 @@ -Subproject commit e2047aa15ff1d2311b34a99de5bd8afca1a4d6a5 +Subproject commit 0140bb4562db1d25b85c0ed43a5f0b38286ebe2e diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index 80e56442f..09bb7ec47 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -114,6 +114,7 @@ bool cosmos_signTxInit(const HDNode* _node, const uint32_t msg_count) { + initialized = true; msgs_remaining = msg_count; has_message = false; sequence = _sequence; From a10fa443a0151dc1746bcc4a152137ba2525a6a0 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 20 Nov 2019 20:29:18 -0700 Subject: [PATCH 31/44] Update lib/firmware/cosmos.c Co-Authored-By: keepkeyjon <35975617+keepkeyjon@users.noreply.github.com> --- lib/firmware/cosmos.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index 09bb7ec47..be9386efc 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -51,7 +51,6 @@ bool cosmos_getAddress(const HDNode *_node, char *address) uint8_t fiveBitExpanded[RIPEMD160_DIGEST_LENGTH * 8 / 5]; size_t len = 0; convert_bits(fiveBitExpanded, &len, 5, hash160Buf, 20, 8, 1); - // bech32encode return bech32_encode(address, "cosmos", fiveBitExpanded, len) == 1; } From e3c7686df8bdb00de8bb6f980703ed97b5537487 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 20 Nov 2019 20:43:23 -0700 Subject: [PATCH 32/44] Update lib/firmware/fsm_msg_cosmos.h Co-Authored-By: keepkeyjon <35975617+keepkeyjon@users.noreply.github.com> --- lib/firmware/fsm_msg_cosmos.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h index 43321c8be..6d623961f 100644 --- a/lib/firmware/fsm_msg_cosmos.h +++ b/lib/firmware/fsm_msg_cosmos.h @@ -80,7 +80,7 @@ void fsm_msgCosmosSignTx(const CosmosSignTx *msg) return; } - if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Aux Details"), "Memo: \"%s\"\nChain ID: %s", msg->memo, msg->chain_id)) + if (msg->has_memo && !confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Aux Details"), "Memo: \"%s\"\nChain ID: %s", msg->memo, msg->chain_id)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); @@ -179,4 +179,4 @@ void fsm_msgCosmosMsgAck(const CosmosMsgAck* msg) { resp->has_signature = true; layoutHome(); msg_write(MessageType_MessageType_CosmosSignedTx, resp); -} \ No newline at end of file +} From cf90b53373e0b79a70462d4b42dfe823b3789ec6 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 20 Nov 2019 21:06:54 -0700 Subject: [PATCH 33/44] dead code removal, macro inlining --- include/keepkey/firmware/cosmos.h | 15 +--- lib/firmware/cosmos.c | 125 ++++++------------------------ lib/firmware/fsm_msg_cosmos.h | 4 +- 3 files changed, 26 insertions(+), 118 deletions(-) diff --git a/include/keepkey/firmware/cosmos.h b/include/keepkey/firmware/cosmos.h index 9612bba9d..ff3640d21 100644 --- a/include/keepkey/firmware/cosmos.h +++ b/include/keepkey/firmware/cosmos.h @@ -14,7 +14,7 @@ bool cosmos_path_mismatched(const CoinType *_coin, const uint32_t _address_n_count); bool cosmos_getAddress(const HDNode *_node, char *address); bool cosmos_signTxInit(const HDNode* _node, - const uint32_t _address_n[8], + const uint32_t* _address_n, const size_t _address_n_count, const uint64_t account_number, const char *chain_id, @@ -34,18 +34,5 @@ bool cosmos_signingIsFinished(void); void cosmos_signAbort(void); size_t cosmos_getAddressNCount(void); bool cosmos_getAddressN(uint32_t* address_n, size_t address_n_count); -// bool cosmos_signTx(const uint8_t* private_key, -// const uint64_t account_number, -// const char* chain_id, -// const size_t chain_id_length, -// const uint32_t fee_uatom_amount, -// const uint32_t gas, -// const char* memo, -// const size_t memo_length, -// const uint64_t amount, -// const char* from_address, -// const char* to_address, -// const uint64_t sequence, -// uint8_t* signature); #endif \ No newline at end of file diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index 09bb7ec47..84d6eb6ff 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -30,7 +30,7 @@ bool cosmos_path_mismatched(const CoinType *_coin, mismatch |= _address_n_count > 0 && (_address_n[0] != (0x80000000 + 44)); mismatch |= _address_n_count > 1 && (_address_n[1] != _coin->bip44_account_path); mismatch |= _address_n_count > 2 && (_address_n[2] & 0x80000000) == 0; - mismatch |= _address_n_count > 3 && (_address_n[3] & 0x80000000) != 0; + mismatch |= _address_n_count > 3 && _address_n[3] != 0; mismatch |= _address_n_count > 4 && (_address_n[4] & 0x80000000) != 0; return mismatch; } @@ -55,30 +55,6 @@ bool cosmos_getAddress(const HDNode *_node, char *address) return bech32_encode(address, "cosmos", fiveBitExpanded, len) == 1; } -// Each segment guaranteed to be less than or equal to 64 bytes -// 19 + ^20 + 14 = ^53 -#define SIGNING_TEMPLATE_START_SEG1 "{\"account_number\":\"%" PRIu64 "\",\"chain_id\":\"" -// -// 30 + ^10 + 24 = ^64 -#define SIGNING_TEMPLATE_START_SEG2 "\",\"fee\":{\"amount\":[{\"amount\":\"%" PRIu32 "\",\"denom\":\"uatom\"}],\"gas" -// 3 + ^10 + 11 = ^23 -#define SIGNING_TEMPLATE_START_SEG3 "\":\"%" PRIu32 "\"},\"memo\":\"" -// -// 10 -#define SIGNING_TEMPLATE_START_SEG4 "\",\"msgs\":[" - -// 59 -#define SIGNING_TEMPLATE_MSG_SEND_SEG1 "{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{\"amount\":[{\"amount\":\"" -// ^20 + 36 = ^56 -#define SIGNING_TEMPLATE_MSG_SEND_SEG2 "%" PRIu64 "\",\"denom\":\"uatom\"}],\"from_address\":\"" -// 45 + 16 = 61 -#define SIGNING_TEMPLATE_MSG_SEND_SEG3 "%s\",\"to_address\":\"" -// 45 + 3 = 48 -#define SIGNING_TEMPLATE_MSG_SEND_SEG4 "%s\"}}" - -// 16 + ^20 = ^36 -#define SIGNING_TEMPLATE_END_SEG1 "],\"sequence\":\"%" PRIu64 "\"}" - void sha256UpdateEscaped(SHA256_CTX *_ctx, const char *s, size_t len) { while (len > 0) @@ -129,23 +105,30 @@ bool cosmos_signTxInit(const HDNode* _node, sha256_Init(&ctx); char buffer[SHA256_BLOCK_LENGTH + 1]; // NULL TERMINATOR NOT PART OF HASH - n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_START_SEG1, account_number); + // Each segment guaranteed to be less than or equal to 64 bytes + // 19 + ^20 + 14 = ^53 + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, "{\"account_number\":\"%" PRIu64 "\",\"chain_id\":\"", account_number); if (n < 0) { return false; } sha256_Update(&ctx, (uint8_t *)buffer, n); + // sha256UpdateEscaped(&ctx, chain_id, chain_id_length); - n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_START_SEG2, fee_uatom_amount); + // 30 + ^10 + 24 = ^64 + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, "\",\"fee\":{\"amount\":[{\"amount\":\"%" PRIu32 "\",\"denom\":\"uatom\"}],\"gas", fee_uatom_amount); if (n < 0) { return false; } sha256_Update(&ctx, (uint8_t *)buffer, n); - n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_START_SEG3, gas); + // 3 + ^10 + 11 = ^23 + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, "\":\"%" PRIu32 "\"},\"memo\":\"", gas); if (n < 0) { return false; } sha256_Update(&ctx, (uint8_t *)buffer, n); + // sha256UpdateEscaped(&ctx, memo, memo_length); - sha256_Update(&ctx, (uint8_t *)SIGNING_TEMPLATE_START_SEG4, sizeof(SIGNING_TEMPLATE_START_SEG4) - 1); + // 10 + sha256_Update(&ctx, (uint8_t *)"\",\"msgs\":[", 10); return true; } @@ -167,20 +150,24 @@ bool cosmos_signTxUpdateMsgSend(const uint64_t amount, sha256_Update(&ctx, (uint8_t*)",", 1); } - n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_MSG_SEND_SEG1); + // 59 + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, "{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{\"amount\":[{\"amount\":\""); if (n < 0) { return false; } sha256_Update(&ctx, (uint8_t *)buffer, n); - n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_MSG_SEND_SEG2, amount); + // ^20 + 36 = ^56 + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, "%" PRIu64 "\",\"denom\":\"uatom\"}],\"from_address\":\"", amount); if (n < 0) { return false; } sha256_Update(&ctx, (uint8_t*)buffer, n); - n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_MSG_SEND_SEG3, from_address); + // 45 + 16 = 61 + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, "%s\",\"to_address\":\"", from_address); if (n < 0) { return false; } sha256_Update(&ctx, (uint8_t*)buffer, n); - n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_MSG_SEND_SEG4, to_address); + // 45 + 3 = 48 + n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, "%s\"}}", to_address); if (n < 0) { return false; } sha256_Update(&ctx, (uint8_t*)buffer, n); @@ -194,7 +181,8 @@ bool cosmos_signTxFinalize(uint8_t* public_key, uint8_t* signature) int n; char buffer[SHA256_DIGEST_LENGTH + 1]; // NULL TERMINATOR NOT PART OF HASH - n = snprintf(buffer, SHA256_DIGEST_LENGTH + 1, SIGNING_TEMPLATE_END_SEG1, sequence); + // 16 + ^20 = ^36 + n = snprintf(buffer, SHA256_DIGEST_LENGTH + 1, "],\"sequence\":\"%" PRIu64 "\"}", sequence); if (n < 0) { return false; } sha256_Update(&ctx, (uint8_t*)buffer, n); @@ -236,72 +224,3 @@ bool cosmos_getAddressN(uint32_t* _address_n, size_t _address_n_count) memcpy(_address_n, address_n, sizeof(uint32_t) * address_n_count); return true; } - -// bool cosmos_signTx(const uint8_t *private_key, -// const uint64_t account_number, -// const char *chain_id, -// const size_t chain_id_length, -// const uint32_t fee_uatom_amount, -// const uint32_t gas, -// const char *memo, -// const size_t memo_length, -// const uint64_t amount, -// const char *from_address, -// const char *to_address, -// const uint64_t sequence, -// uint8_t *signature) -// { -// SHA256_CTX ctx; -// int n; -// sha256_Init(&ctx); -// char buffer[SHA256_BLOCK_LENGTH + 1]; // NULL TERMINATOR NOT PART OF HASH -// n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG1, account_number); -// if (n < 0) -// { -// return false; -// } -// sha256_Update(&ctx, (uint8_t *)buffer, n); -// sha256UpdateEscaped(&ctx, chain_id, chain_id_length); -// n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG2, fee_uatom_amount); -// if (n < 0) -// { -// return false; -// } -// sha256_Update(&ctx, (uint8_t *)buffer, n); -// n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG3, gas); -// if (n < 0) -// { -// return false; -// } -// sha256_Update(&ctx, (uint8_t *)buffer, n); -// sha256UpdateEscaped(&ctx, memo, memo_length); -// sha256_Update(&ctx, (uint8_t *)SIGNING_TEMPLATE_SEG4, 64); // no interpolation needed -// n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG5, amount); -// if (n < 0) -// { -// return false; -// } -// sha256_Update(&ctx, (uint8_t *)buffer, n); -// n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG6, from_address); -// if (n < 0) -// { -// return false; -// } -// sha256_Update(&ctx, (uint8_t *)buffer, n); -// n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG7, to_address); -// if (n < 0) -// { -// return false; -// } -// sha256_Update(&ctx, (uint8_t *)buffer, n); -// n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, SIGNING_TEMPLATE_SEG8, sequence); -// if (n < 0) -// { -// return false; -// } -// sha256_Update(&ctx, (uint8_t *)buffer, n); - -// uint8_t hash[SHA256_DIGEST_LENGTH]; -// sha256_Final(&ctx, hash); -// return ecdsa_sign_digest(&secp256k1, private_key, hash, signature, NULL, NULL) == 0; -// } diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h index 43321c8be..83332d037 100644 --- a/lib/firmware/fsm_msg_cosmos.h +++ b/lib/firmware/fsm_msg_cosmos.h @@ -16,7 +16,7 @@ void fsm_msgCosmosGetAddress(const CosmosGetAddress *msg) hdnode_fill_public_key(node); if (!cosmos_getAddress(node, resp->address)) { - fsm_sendFailure(FailureType_Failure_Other, _("Can't encode address")); + fsm_sendFailure(FailureType_Failure_FirmwareError, _("Can't encode address")); layoutHome(); return; } @@ -29,6 +29,8 @@ void fsm_msgCosmosGetAddress(const CosmosGetAddress *msg) !bip32_path_to_string(node_str, sizeof(node_str), msg->address_n, msg->address_n_count)) { memset(node_str, 0, sizeof(node_str)); + fsm_sendFailure(FailureType_Failure_FirmwareError, _("Can't create Bip32 Path String")); + layoutHome(); } bool mismatch = cosmos_path_mismatched(coin, msg->address_n, msg->address_n_count); From fa8473c341108a7dbcbf790ea17a2b57a64f8f31 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 20 Nov 2019 21:30:13 -0700 Subject: [PATCH 34/44] removes requirement of from_address, calculates it dynamically --- include/keepkey/firmware/cosmos.h | 1 - lib/firmware/cosmos.c | 6 +++--- lib/firmware/fsm_msg_cosmos.h | 2 +- unittests/firmware/cosmos.cpp | 3 ++- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/keepkey/firmware/cosmos.h b/include/keepkey/firmware/cosmos.h index ff3640d21..826cf6ed5 100644 --- a/include/keepkey/firmware/cosmos.h +++ b/include/keepkey/firmware/cosmos.h @@ -26,7 +26,6 @@ bool cosmos_signTxInit(const HDNode* _node, const uint64_t _sequence, const uint32_t msg_count); bool cosmos_signTxUpdateMsgSend(const uint64_t amount, - const char *from_address, const char *to_address); bool cosmos_signTxFinalize(uint8_t* public_key, uint8_t* signature); bool cosmos_signingIsInited(void); diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index aec9d3337..7af9fe69b 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -38,7 +38,7 @@ bool cosmos_path_mismatched(const CoinType *_coin, /* * Gets the address * - * public_key: 33 byte compressed secp256k1 key + * _node: HDNode from which the address is to be derived * address: output buffer * * returns true if successful @@ -133,7 +133,6 @@ bool cosmos_signTxInit(const HDNode* _node, } bool cosmos_signTxUpdateMsgSend(const uint64_t amount, - const char *from_address, const char *to_address) { int n; @@ -142,8 +141,9 @@ bool cosmos_signTxUpdateMsgSend(const uint64_t amount, size_t decoded_len; char hrp[45]; uint8_t decoded[38]; - if (!bech32_decode(hrp, decoded, &decoded_len, from_address)) { return false; } if (!bech32_decode(hrp, decoded, &decoded_len, to_address)) { return false; } + char from_address[46]; + if (!cosmos_getAddress(&node, from_address)) { return false; } if (has_message) { sha256_Update(&ctx, (uint8_t*)",", 1); diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h index 7f8e32be0..97f4738b6 100644 --- a/lib/firmware/fsm_msg_cosmos.h +++ b/lib/firmware/fsm_msg_cosmos.h @@ -155,7 +155,7 @@ void fsm_msgCosmosMsgAck(const CosmosMsgAck* msg) { return; } - if(!cosmos_signTxUpdateMsgSend(msg->send.amount, msg->send.from_address, msg->send.to_address)) { + if(!cosmos_signTxUpdateMsgSend(msg->send.amount, msg->send.to_address)) { cosmos_signAbort(); fsm_sendFailure(FailureType_Failure_FirmwareError, "Failed to include send message in transaction"); return; diff --git a/unittests/firmware/cosmos.cpp b/unittests/firmware/cosmos.cpp index babcaed70..41f404f51 100644 --- a/unittests/firmware/cosmos.cpp +++ b/unittests/firmware/cosmos.cpp @@ -33,11 +33,12 @@ TEST(Cosmos, CosmosSignTx) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, &secp256k1_info }; + hdnode_fill_public_key(&node); const uint8_t *privkey = (uint8_t *)"\x04\xde\xc0\xcc\x01\x3c\xd8\xab\x70\x87\xca\x14\x96\x0b\x76\x8c\x3d\x83\x45\x24\x48\xaa\x00\x64\xda\xe6\xfb\x04\xb5\xd9\x34\x76"; const uint8_t *expected = (uint8_t *)"\x41\x99\x66\x30\x08\xef\xea\x75\x93\x56\x35\xe6\x1a\x11\xdf\xa3\x3c\xeb\xeb\x91\xc1\xca\xed\xc6\x0e\x5e\xef\x3c\xa2\xc0\x1f\x83\x48\x08\x36\xe6\x21\x89\x51\x14\x36\x64\x7f\xac\x5a\xbd\xc2\x9f\x54\xae\x3d\x7e\x47\x56\x43\xca\x33\xc7\xad\x2c\x8a\x53\x2b\x39"; const uint32_t address_n[5] = {0x80000000|44, 0x80000000|118, 0x80000000, 0, 0}; ASSERT_TRUE(cosmos_signTxInit(&node, address_n, 5, 0, "cosmoshub-2", strlen("cosmoshub-2"), 5000, 200000, "", 0, 0, 1)); - ASSERT_TRUE(cosmos_signTxUpdateMsgSend(100000, "cosmos1am058pdux3hyulcmfgj4m3hhrlfn8nzm88u80q", "cosmos18vhdczjut44gpsy804crfhnd5nq003nz0nf20v")); + ASSERT_TRUE(cosmos_signTxUpdateMsgSend(100000, "cosmos18vhdczjut44gpsy804crfhnd5nq003nz0nf20v")); uint8_t public_key[33]; uint8_t signature[64]; ASSERT_TRUE(cosmos_signTxFinalize(public_key, signature)); From 291ac602f21b09dd4937b71d1798d6f1f3d84324 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Wed, 20 Nov 2019 21:33:45 -0700 Subject: [PATCH 35/44] removes has_from_address check --- lib/firmware/fsm_msg_cosmos.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h index 97f4738b6..56a457d18 100644 --- a/lib/firmware/fsm_msg_cosmos.h +++ b/lib/firmware/fsm_msg_cosmos.h @@ -119,7 +119,7 @@ void fsm_msgCosmosSignTx(const CosmosSignTx *msg) void fsm_msgCosmosMsgAck(const CosmosMsgAck* msg) { // Confirm transaction basics CHECK_PARAM(cosmos_signingIsInited(), "Must call CosmosSignTx to initiate signing"); - if (!msg->has_send || !msg->send.has_from_address || !msg->send.has_to_address || !msg->send.has_amount) { + if (!msg->has_send || !msg->send.has_to_address || !msg->send.has_amount) { cosmos_signAbort(); fsm_sendFailure(FailureType_Failure_FirmwareError, _("Invalid Cosmos Message Type")); From c96ff1f271dbf1bfeaab26477fc5f0d9bedcaa24 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Fri, 22 Nov 2019 10:56:03 -0700 Subject: [PATCH 36/44] fix for bip32 derivation --- lib/firmware/cosmos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index 7af9fe69b..b72aaeea9 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -31,7 +31,7 @@ bool cosmos_path_mismatched(const CoinType *_coin, mismatch |= _address_n_count > 1 && (_address_n[1] != _coin->bip44_account_path); mismatch |= _address_n_count > 2 && (_address_n[2] & 0x80000000) == 0; mismatch |= _address_n_count > 3 && _address_n[3] != 0; - mismatch |= _address_n_count > 4 && (_address_n[4] & 0x80000000) != 0; + mismatch |= _address_n_count > 4 && _address_n[4] != 0; return mismatch; } From 4ad5419dcb2833cf7568fb694acfc0c2c5ff7f84 Mon Sep 17 00:00:00 2001 From: keepkeyjon Date: Fri, 22 Nov 2019 13:23:24 -0700 Subject: [PATCH 37/44] Update trezor-firmware dep --- deps/crypto/trezor-firmware | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/crypto/trezor-firmware b/deps/crypto/trezor-firmware index 91fbbe305..d251f3e56 160000 --- a/deps/crypto/trezor-firmware +++ b/deps/crypto/trezor-firmware @@ -1 +1 @@ -Subproject commit 91fbbe3054f30f7432a3667a5289c5621cfd4223 +Subproject commit d251f3e5636ee3b9a31a2b3436f0ea651414d355 From f56d76c9dfff2c99b6cbbdcf854dfddea3fe808d Mon Sep 17 00:00:00 2001 From: keepkeyjon Date: Fri, 22 Nov 2019 14:02:36 -0700 Subject: [PATCH 38/44] cosmos: rearrange msg signing for clarity --- lib/firmware/cosmos.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index b72aaeea9..ac3344137 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -102,28 +102,32 @@ bool cosmos_signTxInit(const HDNode* _node, int n; sha256_Init(&ctx); - char buffer[SHA256_BLOCK_LENGTH + 1]; // NULL TERMINATOR NOT PART OF HASH + char buffer[64 + 1]; // Each segment guaranteed to be less than or equal to 64 bytes - // 19 + ^20 + 14 = ^53 - n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, "{\"account_number\":\"%" PRIu64 "\",\"chain_id\":\"", account_number); + // 19 + ^20 + 1 = ^40 + n = snprintf(buffer, sizeof(buffer), "{\"account_number\":\"%" PRIu64 "\"", account_number); if (n < 0) { return false; } sha256_Update(&ctx, (uint8_t *)buffer, n); // + const char *const chainid_prefix = ",\"chain_id\":\""; + sha256_Update(&ctx, (uint8_t *)chainid_prefix, strlen(chainid_prefix)); sha256UpdateEscaped(&ctx, chain_id, chain_id_length); - // 30 + ^10 + 24 = ^64 - n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, "\",\"fee\":{\"amount\":[{\"amount\":\"%" PRIu32 "\",\"denom\":\"uatom\"}],\"gas", fee_uatom_amount); + // 30 + ^10 + 19 = ^59 + n = snprintf(buffer, sizeof(buffer), "\",\"fee\":{\"amount\":[{\"amount\":\"%" PRIu32 "\",\"denom\":\"uatom\"}]", fee_uatom_amount); if (n < 0) { return false; } sha256_Update(&ctx, (uint8_t *)buffer, n); - // 3 + ^10 + 11 = ^23 - n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, "\":\"%" PRIu32 "\"},\"memo\":\"", gas); + // 8 + ^10 + 2 = ^20 + n = snprintf(buffer, sizeof(buffer), ",\"gas\":\"%" PRIu32 "\"}", gas); if (n < 0) { return false; } sha256_Update(&ctx, (uint8_t *)buffer, n); // + const char *const memo_prefix = ",\"memo\":\""; + sha256_Update(&ctx, (uint8_t *)memo_prefix, strlen(memo_prefix)); sha256UpdateEscaped(&ctx, memo, memo_length); // 10 @@ -136,12 +140,13 @@ bool cosmos_signTxUpdateMsgSend(const uint64_t amount, const char *to_address) { int n; - char buffer[SHA256_BLOCK_LENGTH + 1]; // NULL TERMINATOR NOT PART OF HASH + char buffer[64 + 1]; size_t decoded_len; char hrp[45]; uint8_t decoded[38]; if (!bech32_decode(hrp, decoded, &decoded_len, to_address)) { return false; } + char from_address[46]; if (!cosmos_getAddress(&node, from_address)) { return false; } @@ -149,24 +154,21 @@ bool cosmos_signTxUpdateMsgSend(const uint64_t amount, sha256_Update(&ctx, (uint8_t*)",", 1); } - // 59 - n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, "{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{\"amount\":[{\"amount\":\""); - if (n < 0) { return false; } - sha256_Update(&ctx, (uint8_t *)buffer, n); + const char *const prelude = "{\"type\":\"cosmos-sdk/MsgSend\",\"value\":{"; + sha256_Update(&ctx, (uint8_t *)prelude, strlen(prelude)); - - // ^20 + 36 = ^56 - n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, "%" PRIu64 "\",\"denom\":\"uatom\"}],\"from_address\":\"", amount); + // 21 + ^20 + 19 = ^60 + n = snprintf(buffer, sizeof(buffer), "\"amount\":[{\"amount\":\"%" PRIu64 "\",\"denom\":\"uatom\"}]", amount); if (n < 0) { return false; } sha256_Update(&ctx, (uint8_t*)buffer, n); - // 45 + 16 = 61 - n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, "%s\",\"to_address\":\"", from_address); + // 17 + 45 + 1 = 63 + n = snprintf(buffer, sizeof(buffer), ",\"from_address\":\"%s\"", from_address); if (n < 0) { return false; } sha256_Update(&ctx, (uint8_t*)buffer, n); - // 45 + 3 = 48 - n = snprintf(buffer, SHA256_BLOCK_LENGTH + 1, "%s\"}}", to_address); + // 15 + 45 + 3 = 63 + n = snprintf(buffer, sizeof(buffer), ",\"to_address\":\"%s\"}}", to_address); if (n < 0) { return false; } sha256_Update(&ctx, (uint8_t*)buffer, n); @@ -220,6 +222,7 @@ bool cosmos_getAddressN(uint32_t* _address_n, size_t _address_n_count) if (_address_n_count < address_n_count) { return false; } + memcpy(_address_n, address_n, sizeof(uint32_t) * address_n_count); return true; } From 223075ee511cd9ce9a8e056ef61407b6050a1801 Mon Sep 17 00:00:00 2001 From: keepkeyjon Date: Fri, 22 Nov 2019 14:03:29 -0700 Subject: [PATCH 39/44] cosmos: avoid UB in testcase --- unittests/firmware/cosmos.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unittests/firmware/cosmos.cpp b/unittests/firmware/cosmos.cpp index 41f404f51..d1f5c1b44 100644 --- a/unittests/firmware/cosmos.cpp +++ b/unittests/firmware/cosmos.cpp @@ -36,7 +36,7 @@ TEST(Cosmos, CosmosSignTx) hdnode_fill_public_key(&node); const uint8_t *privkey = (uint8_t *)"\x04\xde\xc0\xcc\x01\x3c\xd8\xab\x70\x87\xca\x14\x96\x0b\x76\x8c\x3d\x83\x45\x24\x48\xaa\x00\x64\xda\xe6\xfb\x04\xb5\xd9\x34\x76"; const uint8_t *expected = (uint8_t *)"\x41\x99\x66\x30\x08\xef\xea\x75\x93\x56\x35\xe6\x1a\x11\xdf\xa3\x3c\xeb\xeb\x91\xc1\xca\xed\xc6\x0e\x5e\xef\x3c\xa2\xc0\x1f\x83\x48\x08\x36\xe6\x21\x89\x51\x14\x36\x64\x7f\xac\x5a\xbd\xc2\x9f\x54\xae\x3d\x7e\x47\x56\x43\xca\x33\xc7\xad\x2c\x8a\x53\x2b\x39"; - const uint32_t address_n[5] = {0x80000000|44, 0x80000000|118, 0x80000000, 0, 0}; + const uint32_t address_n[8] = {0x80000000|44, 0x80000000|118, 0x80000000, 0, 0}; ASSERT_TRUE(cosmos_signTxInit(&node, address_n, 5, 0, "cosmoshub-2", strlen("cosmoshub-2"), 5000, 200000, "", 0, 0, 1)); ASSERT_TRUE(cosmos_signTxUpdateMsgSend(100000, "cosmos18vhdczjut44gpsy804crfhnd5nq003nz0nf20v")); uint8_t public_key[33]; From de09ac818f118f8dc64f3f85b1a31da1f00a6fe5 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Fri, 22 Nov 2019 14:03:42 -0700 Subject: [PATCH 40/44] fixes UB issue with copying --- lib/firmware/cosmos.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/firmware/cosmos.c b/lib/firmware/cosmos.c index b72aaeea9..767ef0bb3 100644 --- a/lib/firmware/cosmos.c +++ b/lib/firmware/cosmos.c @@ -97,7 +97,8 @@ bool cosmos_signTxInit(const HDNode* _node, memzero(&node, sizeof(node)); memcpy(&node, _node, sizeof(node)); memzero(address_n, sizeof(address_n)); - memcpy(address_n, _address_n, sizeof(address_n)); + if (_address_n_count > sizeof(address_n)/sizeof(address_n[0])) { return false; } + memcpy(address_n, _address_n, _address_n_count * sizeof(*address_n)); address_n_count = _address_n_count; int n; From ac9393c85c51cc23e934b62faa594c06498dea94 Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Fri, 22 Nov 2019 15:23:47 -0700 Subject: [PATCH 41/44] aborts and proper string formatting --- lib/firmware/fsm_msg_cosmos.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h index 56a457d18..1d8fcdb59 100644 --- a/lib/firmware/fsm_msg_cosmos.h +++ b/lib/firmware/fsm_msg_cosmos.h @@ -65,6 +65,7 @@ void fsm_msgCosmosSignTx(const CosmosSignTx *msg) !msg->has_fee_amount || !msg->has_gas || !msg->has_sequence) { + cosmos_signAbort(); fsm_sendFailure(FailureType_Failure_SyntaxError, "Missing Fields On Message"); layoutHome(); return; @@ -77,6 +78,7 @@ void fsm_msgCosmosSignTx(const CosmosSignTx *msg) if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Fee Details"), "Fee: %" PRIu32 " uATOM\nGas: %" PRIu32 "", msg->fee_amount, msg->gas)) { + cosmos_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; @@ -84,6 +86,7 @@ void fsm_msgCosmosSignTx(const CosmosSignTx *msg) if (msg->has_memo && !confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Aux Details"), "Memo: \"%s\"\nChain ID: %s", msg->memo, msg->chain_id)) { + cosmos_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; @@ -104,6 +107,7 @@ void fsm_msgCosmosSignTx(const CosmosSignTx *msg) msg->sequence, msg->msg_count)) { + cosmos_signAbort(); fsm_sendFailure(FailureType_Failure_FirmwareError, _("Failed to initialize transaction signing")); layoutHome(); @@ -135,6 +139,7 @@ void fsm_msgCosmosMsgAck(const CosmosMsgAck* msg) { if(!cosmos_getAddressN(address_n, 8)) { cosmos_signAbort(); fsm_sendFailure(FailureType_Failure_FirmwareError, "Failed to get derivation path"); + layoutHome(); return; } size_t address_n_count = cosmos_getAddressNCount(); @@ -147,7 +152,9 @@ void fsm_msgCosmosMsgAck(const CosmosMsgAck* msg) { memset(node_str, 0, sizeof(node_str)); } - if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Send Details"), "From: %s\nTo: %s\nAmount: %f ATOM", node_str, msg->send.to_address, (float)msg->send.amount * 1E-6)) + char canonicFormatAmount[32]; + bn_format_uint64(msg->send.amount, NULL, NULL, 6, 0, false, canonicFormatAmount, sizeof(canonicFormatAmount)); + if (!confirm(ButtonRequestType_ButtonRequest_ProtectCall, _("Confirm Send Details"), "From: %s\nTo: %s\nAmount: %s ATOM", node_str, msg->send.to_address, canonicFormatAmount)) { cosmos_signAbort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); @@ -158,6 +165,7 @@ void fsm_msgCosmosMsgAck(const CosmosMsgAck* msg) { if(!cosmos_signTxUpdateMsgSend(msg->send.amount, msg->send.to_address)) { cosmos_signAbort(); fsm_sendFailure(FailureType_Failure_FirmwareError, "Failed to include send message in transaction"); + layoutHome(); return; } @@ -170,6 +178,7 @@ void fsm_msgCosmosMsgAck(const CosmosMsgAck* msg) { RESP_INIT(CosmosSignedTx); if(!cosmos_signTxFinalize(resp->public_key.bytes, resp->signature.bytes)) { + cosmos_signAbort(); fsm_sendFailure(FailureType_Failure_FirmwareError, "Failed to finalize signature"); layoutHome(); return; From be49036440da1870e5ff6ed0a6fd8cc890947111 Mon Sep 17 00:00:00 2001 From: keepkeyjon Date: Fri, 22 Nov 2019 14:18:24 -0700 Subject: [PATCH 42/44] cosmos: whole_account = false ... sorry, I suggested the wrong thing. --- lib/firmware/fsm_msg_cosmos.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h index 1d8fcdb59..f55101ebc 100644 --- a/lib/firmware/fsm_msg_cosmos.h +++ b/lib/firmware/fsm_msg_cosmos.h @@ -24,7 +24,7 @@ void fsm_msgCosmosGetAddress(const CosmosGetAddress *msg) if (msg->has_show_display && msg->show_display) { char node_str[NODE_STRING_LENGTH]; if (!bip32_node_to_string(node_str, sizeof(node_str), coin, msg->address_n, - msg->address_n_count, /*whole_account=*/true, + msg->address_n_count, /*whole_account=*/false, /*show_addridx=*/false) && !bip32_path_to_string(node_str, sizeof(node_str), msg->address_n, msg->address_n_count)) { @@ -146,7 +146,7 @@ void fsm_msgCosmosMsgAck(const CosmosMsgAck* msg) { char node_str[NODE_STRING_LENGTH]; if (!bip32_node_to_string(node_str, sizeof(node_str), coin, address_n, address_n_count, /*whole_account=*/false, - /*show_addridx=*/true) && + /*show_addridx=*/false) && !bip32_path_to_string(node_str, sizeof(node_str), address_n, address_n_count)) { memset(node_str, 0, sizeof(node_str)); From ec716cf818c4927d37512d6f0e3142c58944b700 Mon Sep 17 00:00:00 2001 From: keepkeyjon Date: Fri, 22 Nov 2019 16:05:45 -0700 Subject: [PATCH 43/44] update device-protocol --- deps/device-protocol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/device-protocol b/deps/device-protocol index 97d4c7f6e..d1e2d52b9 160000 --- a/deps/device-protocol +++ b/deps/device-protocol @@ -1 +1 @@ -Subproject commit 97d4c7f6ef3ae9ec0b5f129cbcc20f006d6f3441 +Subproject commit d1e2d52b910aa939fc1eebf3d5e2b5c12ffd98f3 From 91dc4f4ad8e0cc0387a218d16983d7754e57aded Mon Sep 17 00:00:00 2001 From: Keagan McClelland Date: Tue, 26 Nov 2019 10:40:31 -0700 Subject: [PATCH 44/44] Update lib/firmware/fsm_msg_cosmos.h Co-Authored-By: keepkeyjon <35975617+keepkeyjon@users.noreply.github.com> --- lib/firmware/fsm_msg_cosmos.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/firmware/fsm_msg_cosmos.h b/lib/firmware/fsm_msg_cosmos.h index f55101ebc..ec4601a80 100644 --- a/lib/firmware/fsm_msg_cosmos.h +++ b/lib/firmware/fsm_msg_cosmos.h @@ -188,6 +188,7 @@ void fsm_msgCosmosMsgAck(const CosmosMsgAck* msg) { resp->has_public_key = true; resp->signature.size = 64; resp->has_signature = true; + cosmos_signAbort(); layoutHome(); msg_write(MessageType_MessageType_CosmosSignedTx, resp); }