1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-01-07 14:00:57 +00:00

chore(core): ensure dependency between PIN and wipe code

This commit is contained in:
Lukas Bielesch 2024-12-12 17:55:56 +01:00
parent 75ee4dc7a7
commit 99fd231a8b
10 changed files with 89 additions and 9 deletions

View File

@ -399,6 +399,8 @@ static void _librust_qstrs(void) {
MP_QSTR_pin__tries_left; MP_QSTR_pin__tries_left;
MP_QSTR_pin__turn_off; MP_QSTR_pin__turn_off;
MP_QSTR_pin__turn_on; MP_QSTR_pin__turn_on;
MP_QSTR_pin__wipe_code_exists_description;
MP_QSTR_pin__wipe_code_exists_title;
MP_QSTR_pin__wrong_pin; MP_QSTR_pin__wrong_pin;
MP_QSTR_plurals__contains_x_keys; MP_QSTR_plurals__contains_x_keys;
MP_QSTR_plurals__lock_after_x_hours; MP_QSTR_plurals__lock_after_x_hours;
@ -750,6 +752,7 @@ static void _librust_qstrs(void) {
MP_QSTR_wipe_code__info; MP_QSTR_wipe_code__info;
MP_QSTR_wipe_code__invalid; MP_QSTR_wipe_code__invalid;
MP_QSTR_wipe_code__mismatch; MP_QSTR_wipe_code__mismatch;
MP_QSTR_wipe_code__pin_not_set_description;
MP_QSTR_wipe_code__reenter; MP_QSTR_wipe_code__reenter;
MP_QSTR_wipe_code__reenter_to_confirm; MP_QSTR_wipe_code__reenter_to_confirm;
MP_QSTR_wipe_code__title_check; MP_QSTR_wipe_code__title_check;

View File

@ -1382,6 +1382,9 @@ pub enum TranslatedString {
misc__enable_labeling = 973, // "Enable labeling?" misc__enable_labeling = 973, // "Enable labeling?"
#[cfg(feature = "universal_fw")] #[cfg(feature = "universal_fw")]
ethereum__unknown_contract_address_short = 974, // "Unknown contract address." ethereum__unknown_contract_address_short = 974, // "Unknown contract address."
wipe_code__pin_not_set_description = 975, // "PIN must be set before enabling wipe code."
pin__wipe_code_exists_description = 976, // "Wipe code must be turned off before turnig off PIN protection."
pin__wipe_code_exists_title = 977, // "Wipe code set"
} }
impl TranslatedString { impl TranslatedString {
@ -2758,6 +2761,9 @@ impl TranslatedString {
Self::misc__enable_labeling => "Enable labeling?", Self::misc__enable_labeling => "Enable labeling?",
#[cfg(feature = "universal_fw")] #[cfg(feature = "universal_fw")]
Self::ethereum__unknown_contract_address_short => "Unknown contract address.", Self::ethereum__unknown_contract_address_short => "Unknown contract address.",
Self::wipe_code__pin_not_set_description => "PIN must be set before enabling wipe code.",
Self::pin__wipe_code_exists_description => "Wipe code must be turned off before turnig off PIN protection.",
Self::pin__wipe_code_exists_title => "Wipe code set",
} }
} }
@ -4135,6 +4141,9 @@ impl TranslatedString {
Qstr::MP_QSTR_misc__enable_labeling => Some(Self::misc__enable_labeling), Qstr::MP_QSTR_misc__enable_labeling => Some(Self::misc__enable_labeling),
#[cfg(feature = "universal_fw")] #[cfg(feature = "universal_fw")]
Qstr::MP_QSTR_ethereum__unknown_contract_address_short => Some(Self::ethereum__unknown_contract_address_short), Qstr::MP_QSTR_ethereum__unknown_contract_address_short => Some(Self::ethereum__unknown_contract_address_short),
Qstr::MP_QSTR_wipe_code__pin_not_set_description => Some(Self::wipe_code__pin_not_set_description),
Qstr::MP_QSTR_pin__wipe_code_exists_description => Some(Self::pin__wipe_code_exists_description),
Qstr::MP_QSTR_pin__wipe_code_exists_title => Some(Self::pin__wipe_code_exists_title),
_ => None, _ => None,
} }
} }

View File

@ -541,6 +541,8 @@ class TR:
pin__tries_left: str = "tries left" pin__tries_left: str = "tries left"
pin__turn_off: str = "Are you sure you want to turn off PIN protection?" pin__turn_off: str = "Are you sure you want to turn off PIN protection?"
pin__turn_on: str = "Turn on PIN protection?" pin__turn_on: str = "Turn on PIN protection?"
pin__wipe_code_exists_description: str = "Wipe code must be turned off before turnig off PIN protection."
pin__wipe_code_exists_title: str = "Wipe code set"
pin__wrong_pin: str = "Wrong PIN" pin__wrong_pin: str = "Wrong PIN"
plurals__contains_x_keys: str = "key|keys" plurals__contains_x_keys: str = "key|keys"
plurals__lock_after_x_hours: str = "hour|hours" plurals__lock_after_x_hours: str = "hour|hours"
@ -908,6 +910,7 @@ class TR:
wipe_code__info: str = "Wipe code can be used to erase all data from this device." wipe_code__info: str = "Wipe code can be used to erase all data from this device."
wipe_code__invalid: str = "Invalid wipe code" wipe_code__invalid: str = "Invalid wipe code"
wipe_code__mismatch: str = "The wipe codes you entered do not match." wipe_code__mismatch: str = "The wipe codes you entered do not match."
wipe_code__pin_not_set_description: str = "PIN must be set before enabling wipe code."
wipe_code__reenter: str = "Re-enter wipe code" wipe_code__reenter: str = "Re-enter wipe code"
wipe_code__reenter_to_confirm: str = "Please re-enter wipe code to confirm." wipe_code__reenter_to_confirm: str = "Please re-enter wipe code to confirm."
wipe_code__title_check: str = "Check wipe code" wipe_code__title_check: str = "Check wipe code"

View File

@ -147,3 +147,21 @@ async def error_pin_matches_wipe_code() -> NoReturn:
exc=wire.PinInvalid, exc=wire.PinInvalid,
) )
assert False assert False
async def error_pin_not_set() -> NoReturn:
await show_error_and_raise(
"warning_pin_not_set",
TR.wipe_code__pin_not_set_description,
TR.homescreen__title_pin_not_set,
exc=wire.ActionCancelled,
)
assert False
async def error_wipe_code_exists() -> NoReturn:
await show_error_and_raise(
"wipe_code_exists",
TR.pin__wipe_code_exists_description,
TR.pin__wipe_code_exists_title,
exc=wire.ActionCancelled,
)
assert False

View File

@ -16,6 +16,7 @@ async def change_pin(msg: ChangePin) -> Success:
from apps.common.request_pin import ( from apps.common.request_pin import (
error_pin_invalid, error_pin_invalid,
error_pin_matches_wipe_code, error_pin_matches_wipe_code,
error_wipe_code_exists,
request_pin_and_sd_salt, request_pin_and_sd_salt,
request_pin_confirm, request_pin_confirm,
) )
@ -26,6 +27,9 @@ async def change_pin(msg: ChangePin) -> Success:
# confirm that user wants to change the pin # confirm that user wants to change the pin
await _require_confirm_change_pin(msg) await _require_confirm_change_pin(msg)
if msg.remove and config.has_wipe_code():
await error_wipe_code_exists()
# get old pin # get old pin
curpin, salt = await request_pin_and_sd_salt(TR.pin__enter) curpin, salt = await request_pin_and_sd_salt(TR.pin__enter)

View File

@ -14,6 +14,7 @@ async def change_wipe_code(msg: ChangeWipeCode) -> Success:
from trezor.messages import Success from trezor.messages import Success
from trezor.ui.layouts import show_success from trezor.ui.layouts import show_success
from trezor.wire import NotInitialized from trezor.wire import NotInitialized
from apps.common.request_pin import error_pin_not_set
from apps.common.request_pin import error_pin_invalid, request_pin_and_sd_salt from apps.common.request_pin import error_pin_invalid, request_pin_and_sd_salt
@ -24,6 +25,10 @@ async def change_wipe_code(msg: ChangeWipeCode) -> Success:
has_wipe_code = config.has_wipe_code() has_wipe_code = config.has_wipe_code()
await _require_confirm_action(msg, has_wipe_code) await _require_confirm_action(msg, has_wipe_code)
if not config.has_pin():
await error_pin_not_set()
# Get the unlocking PIN. # Get the unlocking PIN.
pin, salt = await request_pin_and_sd_salt(TR.pin__enter) pin, salt = await request_pin_and_sd_salt(TR.pin__enter)
@ -59,10 +64,14 @@ async def change_wipe_code(msg: ChangeWipeCode) -> Success:
def _require_confirm_action( def _require_confirm_action(
msg: ChangeWipeCode, has_wipe_code: bool msg: ChangeWipeCode, has_wipe_code: bool
) -> Awaitable[None]: ) -> Awaitable[None]:
from trezor.ui.layouts import confirm_action, confirm_set_new_pin from trezor.ui.layouts import (
confirm_action,
confirm_set_new_pin,
show_error_and_raise,
)
from trezor.wire import ProcessError from trezor.wire import ProcessError
if msg.remove and has_wipe_code: if msg.remove and has_wipe_code: # removing wipe code
return confirm_action( return confirm_action(
"disable_wipe_code", "disable_wipe_code",
TR.wipe_code__title_settings, TR.wipe_code__title_settings,
@ -71,7 +80,7 @@ def _require_confirm_action(
prompt_screen=True, prompt_screen=True,
) )
if not msg.remove and has_wipe_code: if not msg.remove and has_wipe_code: # changing wipe code
return confirm_action( return confirm_action(
"change_wipe_code", "change_wipe_code",
TR.wipe_code__title_settings, TR.wipe_code__title_settings,
@ -79,7 +88,7 @@ def _require_confirm_action(
verb=TR.buttons__change, verb=TR.buttons__change,
) )
if not msg.remove and not has_wipe_code: if not msg.remove and not has_wipe_code: # setting new wipe code
return confirm_set_new_pin( return confirm_set_new_pin(
"set_wipe_code", "set_wipe_code",
TR.wipe_code__title_settings, TR.wipe_code__title_settings,

View File

@ -544,6 +544,8 @@
"pin__turn_off": "Are you sure you want to turn off PIN protection?", "pin__turn_off": "Are you sure you want to turn off PIN protection?",
"pin__turn_on": "Turn on PIN protection?", "pin__turn_on": "Turn on PIN protection?",
"pin__wrong_pin": "Wrong PIN", "pin__wrong_pin": "Wrong PIN",
"pin__wipe_code_exists_title": "Wipe code set",
"pin__wipe_code_exists_description": "Wipe code must be turned off before turnig off PIN protection.",
"plurals__contains_x_keys": "key|keys", "plurals__contains_x_keys": "key|keys",
"plurals__lock_after_x_hours": "hour|hours", "plurals__lock_after_x_hours": "hour|hours",
"plurals__lock_after_x_milliseconds": "millisecond|milliseconds", "plurals__lock_after_x_milliseconds": "millisecond|milliseconds",
@ -918,6 +920,7 @@
"wipe_code__turn_off": "Turn off wipe code protection?", "wipe_code__turn_off": "Turn off wipe code protection?",
"wipe_code__turn_on": "Turn on wipe code protection?", "wipe_code__turn_on": "Turn on wipe code protection?",
"wipe_code__wipe_code_mismatch": "Wipe code mismatch", "wipe_code__wipe_code_mismatch": "Wipe code mismatch",
"wipe_code__pin_not_set_description": "PIN must be set before enabling wipe code.",
"word_count__title": "Number of words", "word_count__title": "Number of words",
"words__account": "Account", "words__account": "Account",
"words__account_colon": "Account:", "words__account_colon": "Account:",

View File

@ -973,5 +973,8 @@
"971": "instructions__view_all_data", "971": "instructions__view_all_data",
"972": "ethereum__interaction_contract", "972": "ethereum__interaction_contract",
"973": "misc__enable_labeling", "973": "misc__enable_labeling",
"974": "ethereum__unknown_contract_address_short" "974": "ethereum__unknown_contract_address_short",
"975": "wipe_code__pin_not_set_description",
"976": "pin__wipe_code_exists_description",
"977": "pin__wipe_code_exists_title"
} }

View File

@ -1,8 +1,8 @@
{ {
"current": { "current": {
"merkle_root": "f8a7086deaa86c43ed4e1f1848fb6b24f88ab7910abd4f2ddca75eaa298e1631", "merkle_root": "aed3ba9931fccdba8734a127bb1ba50cb3b3188d82cb240af9bfa408aae4065f",
"datetime": "2024-12-08T15:56:14.564570", "datetime": "2024-12-12T19:05:16.917410",
"commit": "abd1f8c4dfa3d7874aa2e2aa0bbb1fd02265428f" "commit": "7b0557c9b98edc583830d66b5f2b9c07dc01b93b"
}, },
"history": [ "history": [
{ {

View File

@ -20,7 +20,7 @@ from trezorlib import btc, device, messages
from trezorlib.client import MAX_PIN_LENGTH, PASSPHRASE_TEST_PATH from trezorlib.client import MAX_PIN_LENGTH, PASSPHRASE_TEST_PATH
from trezorlib.debuglink import LayoutType from trezorlib.debuglink import LayoutType
from trezorlib.debuglink import TrezorClientDebugLink as Client from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.exceptions import TrezorFailure from trezorlib.exceptions import Cancelled, TrezorFailure
from ..input_flows import InputFlowNewCodeMismatch from ..input_flows import InputFlowNewCodeMismatch
@ -167,3 +167,31 @@ def test_set_pin_to_wipe_code(client: Client):
) )
client.use_pin_sequence([WIPE_CODE4, WIPE_CODE4]) client.use_pin_sequence([WIPE_CODE4, WIPE_CODE4])
device.change_pin(client) device.change_pin(client)
def test_set_wipe_code_without_pin(client: Client):
# Make sure the PIN is not set.
assert client.features.pin_protection is False
# Expect an error when trying to set the wipe code without a PIN.
with pytest.raises(Cancelled):
device.change_wipe_code(client)
@pytest.mark.setup_client(pin=PIN4)
def test_set_remove_pin_without_removing_wipe_code(client: Client):
_ensure_unlocked(client, PIN4)
assert client.features.wipe_code_protection is False
# Set wipe code
with client:
client.use_pin_sequence([PIN4, WIPE_CODE4, WIPE_CODE4])
device.change_wipe_code(client)
client.init_device()
assert client.features.wipe_code_protection is True
# Remove pin code without wipe code being removed.
with client:
# Expect an error when trying to remove PIN with enabled wipe code.
with pytest.raises(Cancelled):
device.change_pin(client, remove=True)