void fsm_msgInitialize(Initialize *msg) { recovery_abort(); signing_abort(); if (msg && msg->has_state && msg->state.size == 64) { uint8_t i_state[64]; if (!session_getState(msg->state.bytes, i_state, NULL)) { session_clear(false); // do not clear PIN } else { if (0 != memcmp(msg->state.bytes, i_state, 64)) { session_clear(false); // do not clear PIN } } } else { session_clear(false); // do not clear PIN } layoutHome(); fsm_msgGetFeatures(0); } void fsm_msgGetFeatures(GetFeatures *msg) { (void)msg; RESP_INIT(Features); resp->has_vendor = true; strlcpy(resp->vendor, "bitcointrezor.com", sizeof(resp->vendor)); resp->has_major_version = true; resp->major_version = VERSION_MAJOR; resp->has_minor_version = true; resp->minor_version = VERSION_MINOR; resp->has_patch_version = true; resp->patch_version = VERSION_PATCH; resp->has_device_id = true; strlcpy(resp->device_id, storage_uuid_str, sizeof(resp->device_id)); resp->has_pin_protection = true; resp->pin_protection = storage_hasPin(); resp->has_passphrase_protection = true; resp->passphrase_protection = storage_hasPassphraseProtection(); #ifdef SCM_REVISION int len = sizeof(SCM_REVISION) - 1; resp->has_revision = true; memcpy(resp->revision.bytes, SCM_REVISION, len); resp->revision.size = len; #endif resp->has_bootloader_hash = true; resp->bootloader_hash.size = memory_bootloader_hash(resp->bootloader_hash.bytes); if (storage_getLanguage()) { resp->has_language = true; strlcpy(resp->language, storage_getLanguage(), sizeof(resp->language)); } if (storage_getLabel()) { resp->has_label = true; strlcpy(resp->label, storage_getLabel(), sizeof(resp->label)); } _Static_assert(pb_arraysize(Features, coins) >= COINS_COUNT, "Features.coins max_count not large enough"); resp->coins_count = COINS_COUNT; for (int i = 0; i < COINS_COUNT; i++) { if (coins[i].coin_name) { resp->coins[i].has_coin_name = true; strlcpy(resp->coins[i].coin_name, coins[i].coin_name, sizeof(resp->coins[i].coin_name)); } if (coins[i].coin_shortcut) { resp->coins[i].has_coin_shortcut = true; strlcpy(resp->coins[i].coin_shortcut, coins[i].coin_shortcut + 1, sizeof(resp->coins[i].coin_shortcut)); } resp->coins[i].has_address_type = coins[i].has_address_type; resp->coins[i].address_type = coins[i].address_type; resp->coins[i].has_maxfee_kb = true; resp->coins[i].maxfee_kb = coins[i].maxfee_kb; resp->coins[i].has_address_type_p2sh = coins[i].has_address_type_p2sh; resp->coins[i].address_type_p2sh = coins[i].address_type_p2sh; resp->coins[i].has_xpub_magic = coins[i].xpub_magic != 0; resp->coins[i].xpub_magic = coins[i].xpub_magic; resp->coins[i].has_xprv_magic = coins[i].xprv_magic != 0; resp->coins[i].xprv_magic = coins[i].xprv_magic; resp->coins[i].has_segwit = true; resp->coins[i].segwit = coins[i].has_segwit; resp->coins[i].has_forkid = coins[i].has_forkid; resp->coins[i].forkid = coins[i].forkid; resp->coins[i].has_force_bip143 = true; resp->coins[i].force_bip143 = coins[i].force_bip143; } resp->has_initialized = true; resp->initialized = storage_isInitialized(); resp->has_imported = true; resp->imported = storage_isImported(); resp->has_pin_cached = true; resp->pin_cached = session_isPinCached(); resp->has_passphrase_cached = true; resp->passphrase_cached = session_isPassphraseCached(); resp->has_needs_backup = true; resp->needs_backup = storage_needsBackup(); resp->unfinished_backup = true; resp->unfinished_backup = storage_unfinishedBackup(); resp->has_flags = true; resp->flags = storage_getFlags(); resp->has_model = true; strlcpy(resp->model, "1", sizeof(resp->model)); msg_write(MessageType_MessageType_Features, resp); } void fsm_msgPing(Ping *msg) { RESP_INIT(Success); if (msg->has_button_protection && msg->button_protection) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("answer to ping?"), NULL, NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } } if (msg->has_pin_protection && msg->pin_protection) { CHECK_PIN } if (msg->has_passphrase_protection && msg->passphrase_protection) { if (!protectPassphrase()) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); return; } } if (msg->has_message) { resp->has_message = true; memcpy(&(resp->message), &(msg->message), sizeof(resp->message)); } msg_write(MessageType_MessageType_Success, resp); layoutHome(); } void fsm_msgChangePin(ChangePin *msg) { bool removal = msg->has_remove && msg->remove; if (removal) { if (storage_hasPin()) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("remove current PIN?"), NULL, NULL, NULL, NULL); } else { fsm_sendSuccess(_("PIN removed")); return; } } else { if (storage_hasPin()) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change current PIN?"), NULL, NULL, NULL, NULL); } else { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("set new PIN?"), NULL, NULL, NULL, NULL); } } if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } CHECK_PIN_UNCACHED if (removal) { storage_setPin(""); storage_update(); fsm_sendSuccess(_("PIN removed")); } else { if (protectChangePin()) { fsm_sendSuccess(_("PIN changed")); } else { fsm_sendFailure(FailureType_Failure_PinMismatch, NULL); } } layoutHome(); } void fsm_msgWipeDevice(WipeDevice *msg) { (void)msg; layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("wipe the device?"), NULL, _("All data will be lost."), NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_WipeDevice, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } storage_wipe(); // the following does not work on Mac anyway :-/ Linux/Windows are fine, so it is not needed // usbReconnect(); // force re-enumeration because of the serial number change fsm_sendSuccess(_("Device wiped")); layoutHome(); } void fsm_msgGetEntropy(GetEntropy *msg) { #if !DEBUG_RNG layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("send entropy?"), NULL, NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } #endif RESP_INIT(Entropy); uint32_t len = msg->size; if (len > 1024) { len = 1024; } resp->entropy.size = len; random_buffer(resp->entropy.bytes, len); msg_write(MessageType_MessageType_Entropy, resp); layoutHome(); } void fsm_msgLoadDevice(LoadDevice *msg) { CHECK_NOT_INITIALIZED layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("I take the risk"), NULL, _("Loading private seed"), _("is not recommended."), _("Continue only if you"), _("know what you are"), _("doing!"), NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } if (msg->has_mnemonic && !(msg->has_skip_checksum && msg->skip_checksum) ) { if (!mnemonic_check(msg->mnemonic)) { fsm_sendFailure(FailureType_Failure_DataError, _("Mnemonic with wrong checksum provided")); layoutHome(); return; } } storage_loadDevice(msg); fsm_sendSuccess(_("Device loaded")); layoutHome(); } void fsm_msgResetDevice(ResetDevice *msg) { CHECK_NOT_INITIALIZED CHECK_PARAM(!msg->has_strength || msg->strength == 128 || msg->strength == 192 || msg->strength == 256, _("Invalid seed strength")); reset_init( msg->has_display_random && msg->display_random, msg->has_strength ? msg->strength : 128, msg->has_passphrase_protection && msg->passphrase_protection, msg->has_pin_protection && msg->pin_protection, msg->has_language ? msg->language : 0, msg->has_label ? msg->label : 0, msg->has_u2f_counter ? msg->u2f_counter : 0, msg->has_skip_backup ? msg->skip_backup : false ); } void fsm_msgEntropyAck(EntropyAck *msg) { if (msg->has_entropy) { reset_entropy(msg->entropy.bytes, msg->entropy.size); } else { reset_entropy(0, 0); } } void fsm_msgBackupDevice(BackupDevice *msg) { CHECK_INITIALIZED CHECK_PIN_UNCACHED (void)msg; reset_backup(true); } void fsm_msgCancel(Cancel *msg) { (void)msg; recovery_abort(); signing_abort(); ethereum_signing_abort(); fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); } void fsm_msgClearSession(ClearSession *msg) { (void)msg; session_clear(true); // clear PIN as well layoutScreensaver(); fsm_sendSuccess(_("Session cleared")); } void fsm_msgApplySettings(ApplySettings *msg) { CHECK_PARAM(msg->has_label || msg->has_language || msg->has_use_passphrase || msg->has_homescreen || msg->has_auto_lock_delay_ms, _("No setting provided")); CHECK_PIN if (msg->has_label) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change name to"), msg->label, "?", NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } } if (msg->has_language) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change language to"), msg->language, "?", NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } } if (msg->has_use_passphrase) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), msg->use_passphrase ? _("enable passphrase") : _("disable passphrase"), _("protection?"), NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } } if (msg->has_homescreen) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change the home"), _("screen?"), NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } } if (msg->has_auto_lock_delay_ms) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("change auto-lock"), _("delay?"), NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } } if (msg->has_label) { storage_setLabel(msg->label); } if (msg->has_language) { storage_setLanguage(msg->language); } if (msg->has_use_passphrase) { storage_setPassphraseProtection(msg->use_passphrase); } if (msg->has_homescreen) { storage_setHomescreen(msg->homescreen.bytes, msg->homescreen.size); } if (msg->has_auto_lock_delay_ms) { storage_setAutoLockDelayMs(msg->auto_lock_delay_ms); } storage_update(); fsm_sendSuccess(_("Settings applied")); layoutHome(); } void fsm_msgApplyFlags(ApplyFlags *msg) { if (msg->has_flags) { storage_applyFlags(msg->flags); storage_update(); } fsm_sendSuccess(_("Flags applied")); } void fsm_msgRecoveryDevice(RecoveryDevice *msg) { const bool dry_run = msg->has_dry_run ? msg->dry_run : false; if (dry_run) { CHECK_PIN } else { CHECK_NOT_INITIALIZED } CHECK_PARAM(!msg->has_word_count || msg->word_count == 12 || msg->word_count == 18 || msg->word_count == 24, _("Invalid word count")); if (!dry_run) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you really want to"), _("recover the device?"), NULL, NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } } recovery_init( msg->has_word_count ? msg->word_count : 12, msg->has_passphrase_protection && msg->passphrase_protection, msg->has_pin_protection && msg->pin_protection, msg->has_language ? msg->language : 0, msg->has_label ? msg->label : 0, msg->has_enforce_wordlist && msg->enforce_wordlist, msg->has_type ? msg->type : 0, msg->has_u2f_counter ? msg->u2f_counter : 0, dry_run ); } void fsm_msgWordAck(WordAck *msg) { recovery_word(msg->word); } void fsm_msgSetU2FCounter(SetU2FCounter *msg) { layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, _("Do you want to set"), _("the U2F counter?"), NULL, NULL, NULL, NULL); if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; } storage_setU2FCounter(msg->u2f_counter); storage_update(); fsm_sendSuccess(_("U2F counter set")); layoutHome(); }