From abb5ab74e30616280dcb421ecbae0b84b1aeb73e Mon Sep 17 00:00:00 2001 From: Andrew Kozlik Date: Sat, 29 Jan 2022 16:18:12 +0100 Subject: [PATCH] feat(legacy): Strict path validation for NEM. --- legacy/firmware/fsm_msg_nem.h | 36 +++++++++++++++++++++++++++++- legacy/firmware/nem2.c | 42 +++++++++++++++++++++++++++++++++++ legacy/firmware/nem2.h | 3 +++ 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/legacy/firmware/fsm_msg_nem.h b/legacy/firmware/fsm_msg_nem.h index 40ebc6aae..c17b68a58 100644 --- a/legacy/firmware/fsm_msg_nem.h +++ b/legacy/firmware/fsm_msg_nem.h @@ -17,6 +17,21 @@ * along with this library. If not, see . */ +static bool fsm_nemCheckPath(uint32_t address_n_count, + const uint32_t *address_n, uint8_t network) { + if (nem_path_check(address_n_count, address_n, network, true)) { + return true; + } + + if (config_getSafetyCheckLevel() == SafetyCheckLevel_Strict && + !nem_path_check(address_n_count, address_n, network, false)) { + fsm_sendFailure(FailureType_Failure_DataError, _("Forbidden key path")); + return false; + } + + return fsm_layoutPathWarning(); +} + void fsm_msgNEMGetAddress(NEMGetAddress *msg) { if (!msg->has_network) { msg->network = NEM_NETWORK_MAINNET; @@ -31,11 +46,19 @@ void fsm_msgNEMGetAddress(NEMGetAddress *msg) { RESP_INIT(NEMAddress); + if (!fsm_nemCheckPath(msg->address_n_count, msg->address_n, msg->network)) { + layoutHome(); + return; + } + HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n, msg->address_n_count, NULL); if (!node) return; - if (!hdnode_get_nem_address(node, msg->network, resp->address)) return; + if (!hdnode_get_nem_address(node, msg->network, resp->address)) { + layoutHome(); + return; + } if (msg->has_show_display && msg->show_display) { char desc[16]; @@ -116,6 +139,12 @@ void fsm_msgNEMSignTx(NEMSignTx *msg) { RESP_INIT(NEMSignedTx); + if (!fsm_nemCheckPath(msg->transaction.address_n_count, + msg->transaction.address_n, msg->transaction.network)) { + layoutHome(); + return; + } + HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->transaction.address_n, msg->transaction.address_n_count, NULL); @@ -317,6 +346,11 @@ void fsm_msgNEMDecryptMessage(NEMDecryptMessage *msg) { CHECK_PIN + if (!fsm_nemCheckPath(msg->address_n_count, msg->address_n, msg->network)) { + layoutHome(); + return; + } + const HDNode *node = fsm_getDerivedNode(ED25519_KECCAK_NAME, msg->address_n, msg->address_n_count, NULL); if (!node) return; diff --git a/legacy/firmware/nem2.c b/legacy/firmware/nem2.c index 6372e9007..f95ff2aef 100644 --- a/legacy/firmware/nem2.c +++ b/legacy/firmware/nem2.c @@ -20,6 +20,7 @@ #include "nem2.h" #include "aes/aes.h" +#include "crypto.h" #include "fsm.h" #include "gettext.h" #include "layout2.h" @@ -741,3 +742,44 @@ bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, return false; } } + +bool nem_path_check(uint32_t address_n_count, const uint32_t *address_n, + uint8_t network, bool check_coin_type) { + bool valid = (address_n_count >= 3); + valid = valid && (address_n[0] == (PATH_HARDENED | 44)); + valid = valid && (address_n[1] == (PATH_HARDENED | 43) || + address_n[1] == (PATH_HARDENED | 1)); + valid = valid && (address_n[2] & PATH_HARDENED); + valid = valid && ((address_n[2] & PATH_UNHARDEN_MASK) <= PATH_MAX_ACCOUNT); + + if (address_n_count == 3) { + // SEP-0005 for non-UTXO-based currencies, defined by Stellar: + // https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0005.md + // m/44'/coin_type'/account' + // No further checks required. + } else if (address_n_count == 5) { + // NanoWallet compatibility path + // "m/44'/coin_type'/account'/0'/0'" + valid = valid && (address_n[3] == (PATH_HARDENED | 0)); + valid = valid && (address_n[4] == (PATH_HARDENED | 0)); + } else { + return false; + } + + if (check_coin_type) { + // Check that the appropriate coin_type is set for the given network. + switch (network) { + case NEM_NETWORK_MAINNET: + case NEM_NETWORK_MIJIN: + valid = valid && (address_n[1] == (PATH_HARDENED | 43)); + break; + case NEM_NETWORK_TESTNET: + valid = valid && (address_n[1] == (PATH_HARDENED | 1)); + break; + default: + return false; + } + } + + return valid; +} diff --git a/legacy/firmware/nem2.h b/legacy/firmware/nem2.h index 05592756d..2f3e89c91 100644 --- a/legacy/firmware/nem2.h +++ b/legacy/firmware/nem2.h @@ -100,6 +100,9 @@ bool nem_mosaicFormatLevy(const NEMMosaicDefinition *definition, uint64_t quantity, const bignum256 *multiplier, uint8_t network, char *str_out, size_t size); +bool nem_path_check(uint32_t address_n_count, const uint32_t *address_n, + uint8_t network, bool check_coin_type); + static inline void nem_mosaicFormatName(const char *namespace, const char *mosaic, char *str_out, size_t size) {