diff --git a/legacy/firmware/fsm_msg_nem.h b/legacy/firmware/fsm_msg_nem.h index 40ebc6aaec..c17b68a587 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 6372e90071..f95ff2aef5 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 05592756da..2f3e89c91f 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) {