You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/firmware/fsm_msg_common.h

391 lines
12 KiB

/*
* This file is part of the TREZOR project, https://trezor.io/
*
* Copyright (C) 2018 Pavol Rusnak <stick@satoshilabs.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
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));
}
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);
}
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();
}