Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion deps/crypto/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ set(sources
trezor-firmware/crypto/aes/aestab.c)

# Pallas/Orchard curve arithmetic (~2.4k LOC) -- only the Zcash shielded engine
# uses it. Excluded from the bitcoin-only image.
# uses it. Excluded from the default and bitcoin-only images.
if(${KK_ZCASH_PRIVACY})
list(APPEND sources
trezor-firmware/crypto/pallas.c
Expand Down
61 changes: 33 additions & 28 deletions lib/firmware/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,57 @@ set(sources
app_confirm.c
app_layout.c
authenticator.c
binance.c
bip85.c
coins.c
crypto.c
eip712.c
eos.c
eos-contracts/eosio.system.c
eos-contracts/eosio.token.c
ethereum.c
ethereum_contracts.c
ethereum_contracts/makerdao.c
ethereum_contracts/saproxy.c
ethereum_contracts/zxappliquid.c
ethereum_contracts/thortx.c
ethereum_contracts/zxliquidtx.c
ethereum_contracts/zxtransERC20.c
ethereum_contracts/zxswap.c
ethereum_tokens.c
dice_input.c
fsm.c
hive.c
home_sm.c
mayachain.c
nano.c
osmosis.c
passphrase_sm.c
pin_sm.c
policy.c
recovery_cipher.c
reset.c
ripple.c
ripple_base58.c
signed_metadata.c
signing.c
signtx_tendermint.c
solana.c
storage.c
tron.c
ton.c
tendermint.c
thorchain.c
tiny-json.c
transaction.c
txin_check.c
u2f.c)

# Non-Bitcoin coin families -- excluded from the bitcoin-only image.
if(NOT ${KK_BITCOIN_ONLY})
list(APPEND sources
binance.c
eip712.c
eos.c
eos-contracts/eosio.system.c
eos-contracts/eosio.token.c
ethereum.c
ethereum_contracts.c
ethereum_contracts/makerdao.c
ethereum_contracts/saproxy.c
ethereum_contracts/zxappliquid.c
ethereum_contracts/thortx.c
ethereum_contracts/zxliquidtx.c
ethereum_contracts/zxtransERC20.c
ethereum_contracts/zxswap.c
ethereum_tokens.c
signed_metadata.c
mayachain.c
nano.c
osmosis.c
ripple.c
ripple_base58.c
signtx_tendermint.c
solana.c
hive.c
tron.c
ton.c
tendermint.c
thorchain.c)
endif()

# Zcash shielded/Orchard engine -- transparent Zcash needs none of this.
if(${KK_ZCASH_PRIVACY})
list(APPEND sources zcash.c)
Expand Down
29 changes: 26 additions & 3 deletions lib/firmware/fsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,15 @@ static uint8_t msg_resp[MAX_FRAME_SIZE] __attribute__((aligned(4)));
return; \
}

#define CHECK_NOT_BTC_ONLY_LOCKED \
if (storage_isBitcoinOnlyLocked()) { \
fsm_sendFailure(FailureType_Failure_Other, \
"Device holds a bitcoin-only wallet. Wipe the " \
"device to use multi-chain firmware."); \
layoutHome(); \
return; \
}

#define CHECK_PIN \
if (!pin_protect_cached()) { \
layoutHome(); \
Expand Down Expand Up @@ -283,13 +292,16 @@ void fsm_msgClearSession(ClearSession* msg) {
fsm_sendSuccess("Session cleared");
}

// Always-on handlers: Bitcoin/common (fsm_msg_coin), CipherKeyValue/identity
// (fsm_msg_crypto), debug-link, and BIP85 -- none are coin engines.
#include "fsm_msg_common.h"
#include "fsm_msg_coin.h"
#include "fsm_msg_ethereum.h"
#include "fsm_msg_nano.h"
#include "fsm_msg_crypto.h"
#include "fsm_msg_debug.h"
#include "fsm_msg_bip85.h"
#if !BITCOIN_ONLY
#include "fsm_msg_ethereum.h"
#include "fsm_msg_nano.h"
#include "fsm_msg_eos.h"
#include "fsm_msg_cosmos.h"
#include "fsm_msg_osmosis.h"
Expand All @@ -304,11 +316,22 @@ void fsm_msgClearSession(ClearSession* msg) {
#include "fsm_msg_hive.h"
/* After fsm_msg_solana.h: reuses its base58 helper and the KKSOLSC1 parser. */
#include "fsm_msg_clearsign_attestor.h"
#else
// Bitcoin-only: the coin engines above are compiled out, but the always-on
// Initialize/ClearSession/Cancel handlers still call their *_abort() hooks,
// and factory-reset calls signed_metadata_clear_signers() (EVM clearsign).
// With no state to reset, no-ops are correct.
void ethereum_signing_abort(void) {}
void tendermint_signAbort(void) {}
void eos_signingAbort(void) {}
void signed_metadata_clear_signers(void) {}
#endif // !BITCOIN_ONLY
#if ZCASH_PRIVACY
#include "fsm_msg_zcash.h"
#else
// Zcash shielded/Orchard engine compiled out. The always-on
// Initialize/ClearSession/Cancel handlers still call zcash_signing_abort();
// with no privacy state to reset, a no-op is correct.
// with no privacy state to reset, a no-op is correct. (Bitcoin-only forces
// privacy off, so this stub also covers the bitcoin-only image.)
void zcash_signing_abort(void) {}
#endif
24 changes: 20 additions & 4 deletions lib/firmware/fsm_msg_coin.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,21 @@ static bool path_mismatched(const CoinType* coin, const GetAddress* msg) {
return mismatch;
}

// m/86' : BIP86 Taproot
// m / purpose' / bip44_account_path' / account' / change / address_index
if (msg->address_n[0] == (0x80000000 + 86)) {
mismatch |= (msg->script_type != InputScriptType_SPENDTAPROOT);
mismatch |= !coin->has_segwit || !coin->segwit;
mismatch |= !coin->has_bech32_prefix;
mismatch |= !coin->has_taproot || !coin->taproot;
mismatch |= (msg->address_n_count != 5);
mismatch |= (msg->address_n[1] != coin->bip44_account_path);
mismatch |= (msg->address_n[2] & 0x80000000) == 0;
mismatch |= (msg->address_n[3] & 0x80000000) == 0x80000000;
mismatch |= (msg->address_n[4] & 0x80000000) == 0x80000000;
return mismatch;
}

return false;
}

Expand Down Expand Up @@ -270,8 +285,8 @@ void fsm_msgSignMessage(SignMessage* msg) {

CHECK_INITIALIZED

if (!confirm(ButtonRequestType_ButtonRequest_SignMessage, "Sign Message",
"%s", (char*)msg->message.bytes)) {
if (!confirm_bytes(ButtonRequestType_ButtonRequest_SignMessage,
"Sign Message", msg->message.bytes, msg->message.size)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled,
"Sign message cancelled");
layoutHome();
Expand Down Expand Up @@ -325,8 +340,9 @@ void fsm_msgVerifyMessage(VerifyMessage* msg) {
layoutHome();
return;
}
if (!review(ButtonRequestType_ButtonRequest_Other, "Message Verified", "%s",
(char*)msg->message.bytes)) {
if (!confirm_bytes(ButtonRequestType_ButtonRequest_Other,
"Message Verified", msg->message.bytes,
msg->message.size)) {
fsm_sendFailure(FailureType_Failure_ActionCancelled,
_("Action cancelled by user"));
layoutHome();
Expand Down
70 changes: 68 additions & 2 deletions lib/firmware/fsm_msg_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,53 @@ void fsm_msgGetFeatures(GetFeatures* msg) {

/* Variant Name */
resp->has_firmware_variant = true;
strlcpy(resp->firmware_variant, variant_getName(),
sizeof(resp->firmware_variant));
#if BITCOIN_ONLY
/* Bitcoin-only build. Uses the established KeepKeyBTC / EmulatorBTC names so
existing clients (python-keepkey requires_fullFeature, etc.) skip
multi-chain-only behaviour and never offer multi-chain firmware. The lock
sentinel is reachable here too: a NEWER bitcoin-only wallet than this
firmware understands refuses to load (storage_isBitcoinOnlyLocked), and
hosts need the same signal the other builds emit. */
if (storage_isBitcoinOnlyLocked()) {
strlcpy(resp->firmware_variant, "bitcoin-only-locked",
sizeof(resp->firmware_variant));
} else {
#ifdef EMULATOR
strlcpy(resp->firmware_variant, "EmulatorBTC",
sizeof(resp->firmware_variant));
#else
strlcpy(resp->firmware_variant, "KeepKeyBTC",
sizeof(resp->firmware_variant));
#endif
}
#elif ZCASH_PRIVACY
/* Zcash/Orchard privacy build. Distinct variant name so hosts can gate
variant-partitioned features — the clearsign session icon cache is
compiled out of this build to fit SRAM (identities still work; persistent
identity icons still render from storage). */
if (storage_isBitcoinOnlyLocked()) {
strlcpy(resp->firmware_variant, "bitcoin-only-locked",
sizeof(resp->firmware_variant));
} else {
#ifdef EMULATOR
strlcpy(resp->firmware_variant, "EmulatorZcash",
sizeof(resp->firmware_variant));
#else
strlcpy(resp->firmware_variant, "KeepKeyZcash",
sizeof(resp->firmware_variant));
#endif
}
#else
if (storage_isBitcoinOnlyLocked()) {
/* Multi-chain firmware refusing to touch a bitcoin-only wallet; a wipe
is required before this device can be used. */
strlcpy(resp->firmware_variant, "bitcoin-only-locked",
sizeof(resp->firmware_variant));
} else {
strlcpy(resp->firmware_variant, variant_getName(),
sizeof(resp->firmware_variant));
}
#endif

/* Security settings */
resp->has_pin_protection = true;
Expand Down Expand Up @@ -157,8 +202,10 @@ void fsm_msgGetCoinTable(GetCoinTable* msg) {
for (size_t i = 0; i < msg->end - msg->start; i++) {
if (msg->start + i < COINS_COUNT) {
resp->table[i] = coins[msg->start + i];
#if !BITCOIN_ONLY
} else if (msg->start + i - COINS_COUNT < TOKENS_COUNT) {
coinFromToken(&resp->table[i], &tokens[msg->start + i - COINS_COUNT]);
#endif
}
}
}
Expand Down Expand Up @@ -334,6 +381,7 @@ void fsm_msgPing(Ping* msg) {
}

void fsm_msgChangePin(ChangePin* msg) {
CHECK_NOT_BTC_ONLY_LOCKED
bool removal = msg->has_remove && msg->remove;
bool confirmed = false;

Expand Down Expand Up @@ -384,6 +432,7 @@ void fsm_msgChangePin(ChangePin* msg) {
}

void fsm_msgChangeWipeCode(ChangeWipeCode* msg) {
CHECK_NOT_BTC_ONLY_LOCKED
bool removal = msg->has_remove && msg->remove;
bool confirmed = false;

Expand Down Expand Up @@ -616,6 +665,7 @@ void fsm_msgGetEntropy(GetEntropy* msg) {
}

void fsm_msgLoadDevice(LoadDevice* msg) {
CHECK_NOT_BTC_ONLY_LOCKED
CHECK_NOT_INITIALIZED

if (!confirm_load_device(msg->has_node)) {
Expand Down Expand Up @@ -644,6 +694,7 @@ void fsm_msgLoadDevice(LoadDevice* msg) {
}

void fsm_msgResetDevice(ResetDevice* msg) {
CHECK_NOT_BTC_ONLY_LOCKED
CHECK_NOT_INITIALIZED

// display_random remains in the wire schema for host compatibility, but is
Expand Down Expand Up @@ -676,10 +727,12 @@ void fsm_msgCancel(Cancel* msg) {
ethereum_signing_abort();
tendermint_signAbort();
eos_signingAbort();
zcash_signing_abort();
fsm_sendFailure(FailureType_Failure_ActionCancelled, "Aborted");
}

void fsm_msgApplySettings(ApplySettings* msg) {
CHECK_NOT_BTC_ONLY_LOCKED
if (msg->has_label) {
if (!confirm(ButtonRequestType_ButtonRequest_ChangeLabel, "Change Label",
"Do you want to change the label to \"%s\"?", msg->label)) {
Expand Down Expand Up @@ -770,6 +823,7 @@ void fsm_msgApplySettings(ApplySettings* msg) {
}

void fsm_msgRecoveryDevice(RecoveryDevice* msg) {
CHECK_NOT_BTC_ONLY_LOCKED
if (msg->has_dry_run && msg->dry_run) {
CHECK_INITIALIZED
} else {
Expand Down Expand Up @@ -800,6 +854,7 @@ void fsm_msgCharacterAck(CharacterAck* msg) {
}

void fsm_msgApplyPolicies(ApplyPolicies* msg) {
CHECK_NOT_BTC_ONLY_LOCKED
CHECK_PARAM(msg->policy_count > 0, "No policies provided");

for (size_t i = 0; i < msg->policy_count; ++i) {
Expand Down Expand Up @@ -851,6 +906,17 @@ void fsm_msgApplyPolicies(ApplyPolicies* msg) {

storage_commit();

/* Runtime clearsign identities are an AdvancedMode capability. Revoking the
* policy also revokes every RAM-only signer immediately, so toggling the
* policy off cannot leave a previously approved trust anchor active. */
for (size_t i = 0; i < msg->policy_count; ++i) {
if (strcmp(msg->policy[i].policy_name, "AdvancedMode") == 0 &&
!msg->policy[i].enabled) {
signed_metadata_clear_signers();
break;
}
}

fsm_sendSuccess("Policies applied");
layoutHome();
}
Loading
Loading