diff --git a/legacy/firmware/.changelog.d/1627.added b/legacy/firmware/.changelog.d/1627.added new file mode 100644 index 000000000..a353447ff --- /dev/null +++ b/legacy/firmware/.changelog.d/1627.added @@ -0,0 +1 @@ +Safety checks setting in T1. diff --git a/legacy/firmware/config.c b/legacy/firmware/config.c index b8b7cf4bb..570f7f005 100644 --- a/legacy/firmware/config.c +++ b/legacy/firmware/config.c @@ -143,6 +143,8 @@ static uint32_t sessionUseCounter = 0; static secbool autoLockDelayMsCached = secfalse; static uint32_t autoLockDelayMs = autoLockDelayMsDefault; +static SafetyCheckLevel safetyCheckLevel = SafetyCheckLevel_Strict; + static const uint32_t CONFIG_VERSION = 11; static const uint8_t FALSE_BYTE = '\x00'; @@ -949,6 +951,12 @@ void config_setAutoLockDelayMs(uint32_t auto_lock_delay_ms) { } } +SafetyCheckLevel config_getSafetyCheckLevel(void) { return safetyCheckLevel; } + +void config_setSafetyCheckLevel(SafetyCheckLevel safety_check_level) { + safetyCheckLevel = safety_check_level; +} + void config_wipe(void) { char oldTiny = usbTiny(1); storage_wipe(); @@ -959,6 +967,7 @@ void config_wipe(void) { random_buffer((uint8_t *)config_uuid, sizeof(config_uuid)); data2hex((const uint8_t *)config_uuid, sizeof(config_uuid), config_uuid_str); autoLockDelayMsCached = secfalse; + safetyCheckLevel = SafetyCheckLevel_Strict; storage_set(KEY_UUID, config_uuid, sizeof(config_uuid)); storage_set(KEY_VERSION, &CONFIG_VERSION, sizeof(CONFIG_VERSION)); session_clear(false); diff --git a/legacy/firmware/config.h b/legacy/firmware/config.h index ee33064b8..94fa5b0e5 100644 --- a/legacy/firmware/config.h +++ b/legacy/firmware/config.h @@ -162,6 +162,9 @@ bool config_getFlags(uint32_t *flags); uint32_t config_getAutoLockDelayMs(void); void config_setAutoLockDelayMs(uint32_t auto_lock_delay_ms); +SafetyCheckLevel config_getSafetyCheckLevel(void); +void config_setSafetyCheckLevel(SafetyCheckLevel safety_check_level); + void config_wipe(void); extern char config_uuid_str[2 * UUID_SIZE + 1]; diff --git a/legacy/firmware/fsm_msg_coin.h b/legacy/firmware/fsm_msg_coin.h index 477f02ea0..96687b8fa 100644 --- a/legacy/firmware/fsm_msg_coin.h +++ b/legacy/firmware/fsm_msg_coin.h @@ -185,10 +185,17 @@ void fsm_msgGetAddress(const GetAddress *msg) { if (!coin_known_path_check(coin, msg->script_type, msg->address_n_count, msg->address_n, true)) { + if (config_getSafetyCheckLevel() == SafetyCheckLevel_Strict) { + fsm_sendFailure(FailureType_Failure_DataError, _("Forbidden key path")); + layoutHome(); + return; + } + layoutDialogSwipe(&bmp_icon_warning, _("Abort"), _("Continue"), NULL, _("Wrong address path"), _("for selected coin."), NULL, _("Continue at your"), _("own risk!"), NULL); - if (!protectButton(ButtonRequestType_ButtonRequest_Other, false)) { + if (!protectButton(ButtonRequestType_ButtonRequest_UnknownDerivationPath, + false)) { fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); layoutHome(); return; diff --git a/legacy/firmware/fsm_msg_common.h b/legacy/firmware/fsm_msg_common.h index 42249077b..f29eb3b33 100644 --- a/legacy/firmware/fsm_msg_common.h +++ b/legacy/firmware/fsm_msg_common.h @@ -56,6 +56,8 @@ bool get_features(Features *resp) { resp->has_flags = config_getFlags(&(resp->flags)); resp->has_model = true; strlcpy(resp->model, "1", sizeof(resp->model)); + resp->has_safety_checks = true; + resp->safety_checks = config_getSafetyCheckLevel(); if (session_isUnlocked()) { resp->has_wipe_code_protection = true; resp->wipe_code_protection = config_hasWipeCode(); @@ -363,7 +365,8 @@ void fsm_msgApplySettings(const ApplySettings *msg) { _("This firmware is incapable of passphrase entry on the device.")); CHECK_PARAM(msg->has_label || msg->has_language || msg->has_use_passphrase || - msg->has_homescreen || msg->has_auto_lock_delay_ms, + msg->has_homescreen || msg->has_auto_lock_delay_ms || + msg->has_safety_checks, _("No setting provided")); CHECK_PIN @@ -432,6 +435,23 @@ void fsm_msgApplySettings(const ApplySettings *msg) { } } + if (msg->has_safety_checks) { + if (msg->safety_checks == SafetyCheckLevel_Strict || + msg->safety_checks == SafetyCheckLevel_PromptTemporarily) { + layoutConfirmSafetyChecks(msg->safety_checks); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + } else { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("Unsupported safety-checks setting")); + layoutHome(); + return; + } + } + if (msg->has_label) { config_setLabel(msg->label); } @@ -447,6 +467,9 @@ void fsm_msgApplySettings(const ApplySettings *msg) { if (msg->has_auto_lock_delay_ms) { config_setAutoLockDelayMs(msg->auto_lock_delay_ms); } + if (msg->has_safety_checks) { + config_setSafetyCheckLevel(msg->safety_checks); + } fsm_sendSuccess(_("Settings applied")); layoutHome(); } diff --git a/legacy/firmware/layout2.c b/legacy/firmware/layout2.c index 89e130699..da07bff27 100644 --- a/legacy/firmware/layout2.c +++ b/legacy/firmware/layout2.c @@ -1245,3 +1245,18 @@ void layoutConfirmAutoLockDelay(uint32_t delay_ms) { _("Do you really want to"), _("auto-lock your device"), line, NULL, NULL, NULL); } + +void layoutConfirmSafetyChecks(SafetyCheckLevel safety_ckeck_level) { + if (safety_ckeck_level == SafetyCheckLevel_Strict) { + // Disallow unsafe actions. This is the default. + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you really want to"), _("enforce strict safety"), + _("checks?"), _("(Recommended.)"), NULL, NULL); + } else if (safety_ckeck_level == SafetyCheckLevel_PromptTemporarily) { + // Ask user before unsafe action. Reverts to Strict after reboot. + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you really want to"), _("be temporarily able"), + _("to approve some"), _("actions which might"), + _("be unsafe?"), NULL); + } +} diff --git a/legacy/firmware/layout2.h b/legacy/firmware/layout2.h index df7abeeba..52427b764 100644 --- a/legacy/firmware/layout2.h +++ b/legacy/firmware/layout2.h @@ -28,6 +28,7 @@ #include "messages-bitcoin.pb.h" #include "messages-crypto.pb.h" +#include "messages-management.pb.h" #include "messages-nem.pb.h" extern void *layoutLast; @@ -104,6 +105,7 @@ void layoutCosiCommitSign(const uint32_t *address_n, size_t address_n_count, const uint8_t *data, uint32_t len, bool final_sign); void layoutConfirmAutoLockDelay(uint32_t delay_ms); +void layoutConfirmSafetyChecks(SafetyCheckLevel safety_checks_level); const char **split_message(const uint8_t *msg, uint32_t len, uint32_t rowlen); const char **split_message_hex(const uint8_t *msg, uint32_t len); diff --git a/legacy/firmware/signing.c b/legacy/firmware/signing.c index 762e3b1a5..008e8d4c9 100644 --- a/legacy/firmware/signing.c +++ b/legacy/firmware/signing.c @@ -18,6 +18,7 @@ */ #include "signing.h" +#include "config.h" #include "crypto.h" #include "ecdsa.h" #include "fsm.h" @@ -686,7 +687,19 @@ bool compile_input_script_sig(TxInputType *tinput) { } if (!coin_known_path_check(coin, tinput->script_type, tinput->address_n_count, tinput->address_n, false)) { - return false; + if (config_getSafetyCheckLevel() == SafetyCheckLevel_Strict) { + return false; + } + + layoutDialogSwipe(&bmp_icon_warning, _("Abort"), _("Continue"), NULL, + _("Wrong address path"), _("for selected coin."), NULL, + _("Continue at your"), _("own risk!"), NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_UnknownDerivationPath, + false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return false; + } } return fill_input_script_sig(tinput); }