diff --git a/legacy/firmware/config.c b/legacy/firmware/config.c index 918571c1e..98a1e907b 100644 --- a/legacy/firmware/config.c +++ b/legacy/firmware/config.c @@ -785,6 +785,22 @@ bool config_getPin(char *dest, uint16_t dest_size) { } #endif +bool config_hasWipeCode(void) { return sectrue == storage_has_wipe_code(); } + +bool config_changeWipeCode(const char *pin, const char *wipe_code) { + uint32_t wipe_code_int = pin_to_int(wipe_code); + if (wipe_code_int == 0) { + return false; + } + + char oldTiny = usbTiny(1); + secbool ret = storage_change_wipe_code(pin_to_int(pin), NULL, wipe_code_int); + usbTiny(oldTiny); + + memzero(&wipe_code_int, sizeof(wipe_code_int)); + return sectrue == ret; +} + void session_cachePassphrase(const char *passphrase) { strlcpy(sessionPassphrase, passphrase, sizeof(sessionPassphrase)); sessionPassphraseCached = sectrue; diff --git a/legacy/firmware/config.h b/legacy/firmware/config.h index 31c7f3c8b..d061dea71 100644 --- a/legacy/firmware/config.h +++ b/legacy/firmware/config.h @@ -129,6 +129,9 @@ bool config_hasPin(void); bool config_changePin(const char *old_pin, const char *new_pin); bool session_isUnlocked(void); +bool config_hasWipeCode(void); +bool config_changeWipeCode(const char *pin, const char *wipe_code); + uint32_t config_nextU2FCounter(void); void config_setU2FCounter(uint32_t u2fcounter); diff --git a/legacy/firmware/fsm.c b/legacy/firmware/fsm.c index 7b15fe6e0..4c82442b3 100644 --- a/legacy/firmware/fsm.c +++ b/legacy/firmware/fsm.c @@ -167,6 +167,9 @@ void fsm_sendFailure(FailureType code, const char *text) case FailureType_Failure_PinMismatch: text = _("PIN mismatch"); break; + case FailureType_Failure_WipeCodeMismatch: + text = _("Wipe code mismatch"); + break; case FailureType_Failure_FirmwareError: text = _("Firmware error"); break; diff --git a/legacy/firmware/fsm.h b/legacy/firmware/fsm.h index d66e1699e..23c4ffe47 100644 --- a/legacy/firmware/fsm.h +++ b/legacy/firmware/fsm.h @@ -52,6 +52,7 @@ void fsm_msgInitialize(const Initialize *msg); void fsm_msgGetFeatures(const GetFeatures *msg); void fsm_msgPing(const Ping *msg); void fsm_msgChangePin(const ChangePin *msg); +void fsm_msgChangeWipeCode(const ChangeWipeCode *msg); void fsm_msgWipeDevice(const WipeDevice *msg); void fsm_msgGetEntropy(const GetEntropy *msg); #if DEBUG_LINK diff --git a/legacy/firmware/fsm_msg_common.h b/legacy/firmware/fsm_msg_common.h index d84b47abb..9de5b2ec4 100644 --- a/legacy/firmware/fsm_msg_common.h +++ b/legacy/firmware/fsm_msg_common.h @@ -82,6 +82,10 @@ void fsm_msgGetFeatures(const GetFeatures *msg) { resp->has_flags = config_getFlags(&(resp->flags)); resp->has_model = true; strlcpy(resp->model, "1", sizeof(resp->model)); + if (session_isUnlocked()) { + resp->has_wipe_code_protection = true; + resp->wipe_code_protection = config_hasWipeCode(); + } #if BITCOIN_ONLY resp->capabilities_count = 2; @@ -176,6 +180,52 @@ void fsm_msgChangePin(const ChangePin *msg) { layoutHome(); } +void fsm_msgChangeWipeCode(const ChangeWipeCode *msg) { + CHECK_INITIALIZED + + bool removal = msg->has_remove && msg->remove; + bool has_wipe_code = config_hasWipeCode(); + + if (removal) { + // Note that if storage is locked, then config_hasWipeCode() returns false. + if (has_wipe_code || !session_isUnlocked()) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you really want to"), _("disable wipe code"), + _("protection?"), NULL, NULL, NULL); + } else { + fsm_sendSuccess(_("Wipe code removed")); + return; + } + } else { + if (has_wipe_code) { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you really want to"), _("change the current"), + _("wipe code?"), NULL, NULL, NULL); + } else { + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you really want to"), _("set a new wipe code?"), + NULL, NULL, NULL, NULL); + } + } + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + if (protectChangeWipeCode(removal)) { + if (removal) { + fsm_sendSuccess(_("Wipe code removed")); + } else if (has_wipe_code) { + fsm_sendSuccess(_("Wipe code changed")); + } else { + fsm_sendSuccess(_("Wipe code set")); + } + } + + layoutHome(); +} + void fsm_msgWipeDevice(const WipeDevice *msg) { (void)msg; layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, diff --git a/legacy/firmware/protect.c b/legacy/firmware/protect.c index 687d35aee..2b77b291d 100644 --- a/legacy/firmware/protect.c +++ b/legacy/firmware/protect.c @@ -270,6 +270,80 @@ bool protectChangePin(bool removal) { bool ret = config_changePin(old_pin, new_pin); memzero(old_pin, sizeof(old_pin)); memzero(new_pin, sizeof(new_pin)); + if (ret == false) { + if (removal) { + fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); + } else { + fsm_sendFailure(FailureType_Failure_ProcessError, + _("The new PIN must be different from your wipe code.")); + } + } + return ret; +} + +bool protectChangeWipeCode(bool removal) { + static CONFIDENTIAL char pin[MAX_PIN_LEN + 1] = ""; + static CONFIDENTIAL char wipe_code[MAX_PIN_LEN + 1] = ""; + const char *input = NULL; + + if (config_hasPin()) { + input = requestPin(PinMatrixRequestType_PinMatrixRequestType_Current, + _("Please enter your PIN:")); + if (input == NULL) { + fsm_sendFailure(FailureType_Failure_PinCancelled, NULL); + return false; + } + + // If removing, defer the check to config_changeWipeCode(). + if (!removal) { + usbTiny(1); + bool ret = config_unlock(input); + usbTiny(0); + if (ret == false) { + fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); + return false; + } + } + + strlcpy(pin, input, sizeof(pin)); + } + + if (!removal) { + input = requestPin(PinMatrixRequestType_PinMatrixRequestType_WipeCodeFirst, + _("Enter new wipe code:")); + if (input == NULL) { + memzero(pin, sizeof(pin)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + return false; + } + if (strncmp(pin, input, sizeof(pin)) == 0) { + memzero(pin, sizeof(pin)); + fsm_sendFailure(FailureType_Failure_ProcessError, + _("The wipe code must be different from your PIN.")); + return false; + } + strlcpy(wipe_code, input, sizeof(wipe_code)); + + input = requestPin(PinMatrixRequestType_PinMatrixRequestType_WipeCodeSecond, + _("Re-enter new wipe code:")); + if (input == NULL) { + memzero(pin, sizeof(pin)); + memzero(wipe_code, sizeof(wipe_code)); + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + return false; + } + + if (strncmp(wipe_code, input, sizeof(wipe_code)) != 0) { + memzero(pin, sizeof(pin)); + memzero(wipe_code, sizeof(wipe_code)); + fsm_sendFailure(FailureType_Failure_WipeCodeMismatch, NULL); + return false; + } + } + + bool ret = config_changeWipeCode(pin, wipe_code); + memzero(pin, sizeof(pin)); + memzero(wipe_code, sizeof(wipe_code)); if (ret == false) { fsm_sendFailure(FailureType_Failure_PinInvalid, NULL); } diff --git a/legacy/firmware/protect.h b/legacy/firmware/protect.h index dfae16934..4d9af7c6e 100644 --- a/legacy/firmware/protect.h +++ b/legacy/firmware/protect.h @@ -29,6 +29,7 @@ secbool protectPinUiCallback(uint32_t wait, uint32_t progress, const char* message); bool protectPin(bool use_cached); bool protectChangePin(bool removal); +bool protectChangeWipeCode(bool removal); bool protectPassphrase(void); extern bool protectAbortedByCancel; diff --git a/legacy/norcow_config.h b/legacy/norcow_config.h index 9fb4b20a4..59a2d79f3 100644 --- a/legacy/norcow_config.h +++ b/legacy/norcow_config.h @@ -36,6 +36,6 @@ /* * Current storage version. */ -#define NORCOW_VERSION ((uint32_t)0x00000001) +#define NORCOW_VERSION ((uint32_t)0x00000002) #endif