feat(core): ability to not show passphrase coming from host

[no changelog]
pull/2834/head
grdddj 1 year ago committed by Jiří Musil
parent afb5c55416
commit 20d280d7e0

@ -122,6 +122,7 @@ message Features {
optional bool experimental_features = 40; // are experimental message types enabled?
optional bool busy = 41; // is the device busy, showing "Do not disconnect"?
optional HomescreenFormat homescreen_format = 42; // format of the homescreen, 1 = TOIf 144x144, 2 = jpg 240x240
optional bool hide_passphrase_from_host = 43; // should we hide the passphrase when it comes from host?
}
/**
@ -168,6 +169,7 @@ message ApplySettings {
optional bool passphrase_always_on_device = 8; // do not prompt for passphrase, enforce device entry
optional SafetyCheckLevel safety_checks = 9; // Safety check level, set to Prompt to limit path namespace enforcement
optional bool experimental_features = 10; // enable experimental message types
optional bool hide_passphrase_from_host = 11; // do not show passphrase coming from host
}
/**

@ -128,6 +128,7 @@ def get_features() -> Features:
f.auto_lock_delay_ms = storage_device.get_autolock_delay_ms()
f.display_rotation = storage_device.get_rotation()
f.experimental_features = storage_device.get_experimental_features()
f.hide_passphrase_from_host = storage_device.get_hide_passphrase_from_host()
return f

@ -59,19 +59,29 @@ async def _request_on_host(ctx: Context) -> str:
if passphrase:
from trezor.ui.layouts import confirm_action, confirm_blob
await confirm_action(
ctx,
"passphrase_host1",
"Hidden wallet",
description="Access hidden wallet?\n\nNext screen will show the passphrase!",
)
await confirm_blob(
ctx,
"passphrase_host2",
"Hidden wallet",
passphrase,
"Use this passphrase?\n",
)
# We want to hide the passphrase, or show it, according to settings.
if storage_device.get_hide_passphrase_from_host():
explanation = "Passphrase provided by host will be used but will not be displayed due to the device settings."
await confirm_action(
ctx,
"passphrase_host1_hidden",
"Hidden wallet",
description=f"Access hidden wallet?\n\n{explanation}",
)
else:
await confirm_action(
ctx,
"passphrase_host1",
"Hidden wallet",
description="Access hidden wallet?\n\nNext screen will show the passphrase!",
)
await confirm_blob(
ctx,
"passphrase_host2",
"Hidden wallet",
passphrase,
"Use this passphrase?\n",
)
return passphrase

@ -58,6 +58,7 @@ async def apply_settings(ctx: Context, msg: ApplySettings) -> Success:
display_rotation = msg.display_rotation # local_cache_attribute
msg_safety_checks = msg.safety_checks # local_cache_attribute
experimental_features = msg.experimental_features # local_cache_attribute
hide_passphrase_from_host = msg.hide_passphrase_from_host # local_cache_attribute
if (
homescreen is None
@ -68,6 +69,7 @@ async def apply_settings(ctx: Context, msg: ApplySettings) -> Success:
and auto_lock_delay_ms is None
and msg_safety_checks is None
and experimental_features is None
and hide_passphrase_from_host is None
):
raise ProcessError("No setting provided")
@ -117,6 +119,12 @@ async def apply_settings(ctx: Context, msg: ApplySettings) -> Success:
await _require_confirm_experimental_features(ctx, experimental_features)
storage_device.set_experimental_features(experimental_features)
if hide_passphrase_from_host is not None:
if safety_checks.is_strict():
raise ProcessError("Safety checks are strict")
await _require_confirm_hide_passphrase_from_host(ctx, hide_passphrase_from_host)
storage_device.set_hide_passphrase_from_host(hide_passphrase_from_host)
reload_settings_from_storage()
return Success(message="Settings applied")
@ -269,3 +277,16 @@ async def _require_confirm_experimental_features(
reverse=True,
br_code=BRT_PROTECT_CALL,
)
async def _require_confirm_hide_passphrase_from_host(
ctx: GenericContext, enable: bool
) -> None:
if enable:
await confirm_action(
ctx,
"set_hide_passphrase_from_host",
"Hide passphrase",
description="Hide passphrase coming from host?",
br_code=BRT_PROTECT_CALL,
)

@ -34,6 +34,7 @@ _SD_SALT_AUTH_KEY = const(0x12) # bytes
INITIALIZED = const(0x13) # bool (0x01 or empty)
_SAFETY_CHECK_LEVEL = const(0x14) # int
_EXPERIMENTAL_FEATURES = const(0x15) # bool (0x01 or empty)
_HIDE_PASSPHRASE_FROM_HOST = const(0x16) # bool (0x01 or empty)
SAFETY_CHECK_LEVEL_STRICT : Literal[0] = const(0)
SAFETY_CHECK_LEVEL_PROMPT : Literal[1] = const(1)
@ -334,3 +335,17 @@ def set_experimental_features(enabled: bool) -> None:
cached_bytes = b"\x01" if enabled else b""
storage_cache.set(storage_cache.STORAGE_DEVICE_EXPERIMENTAL_FEATURES, cached_bytes)
common.set_true_or_delete(_NAMESPACE, _EXPERIMENTAL_FEATURES, enabled)
def set_hide_passphrase_from_host(hide: bool) -> None:
"""
Whether we should hide the passphrase from the host.
"""
common.set_bool(_NAMESPACE, _HIDE_PASSPHRASE_FROM_HOST, hide)
def get_hide_passphrase_from_host() -> bool:
"""
Whether we should hide the passphrase from the host.
"""
return common.get_bool(_NAMESPACE, _HIDE_PASSPHRASE_FROM_HOST)

@ -2104,6 +2104,7 @@ if TYPE_CHECKING:
experimental_features: "bool | None"
busy: "bool | None"
homescreen_format: "HomescreenFormat | None"
hide_passphrase_from_host: "bool | None"
def __init__(
self,
@ -2147,6 +2148,7 @@ if TYPE_CHECKING:
experimental_features: "bool | None" = None,
busy: "bool | None" = None,
homescreen_format: "HomescreenFormat | None" = None,
hide_passphrase_from_host: "bool | None" = None,
) -> None:
pass
@ -2190,6 +2192,7 @@ if TYPE_CHECKING:
passphrase_always_on_device: "bool | None"
safety_checks: "SafetyCheckLevel | None"
experimental_features: "bool | None"
hide_passphrase_from_host: "bool | None"
def __init__(
self,
@ -2203,6 +2206,7 @@ if TYPE_CHECKING:
passphrase_always_on_device: "bool | None" = None,
safety_checks: "SafetyCheckLevel | None" = None,
experimental_features: "bool | None" = None,
hide_passphrase_from_host: "bool | None" = None,
) -> None:
pass

@ -18,9 +18,10 @@ import random
import pytest
from trezorlib import exceptions, messages
from trezorlib import device, exceptions, messages
from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.messages import FailureType
from trezorlib.exceptions import TrezorFailure
from trezorlib.messages import FailureType, SafetyCheckLevel
from trezorlib.tools import parse_path
XPUB_PASSPHRASES = {
@ -375,6 +376,83 @@ def test_passphrase_length(client: Client):
call(passphrase="A" * 49 + "š", expected_result=False)
@pytest.mark.skip_t1
@pytest.mark.setup_client(passphrase=True)
def test_hide_passphrase_from_host(client: Client):
# Without safety checks, turning it on fails
with pytest.raises(TrezorFailure, match="Safety checks are strict"), client:
device.apply_settings(client, hide_passphrase_from_host=True)
device.apply_settings(client, safety_checks=SafetyCheckLevel.PromptTemporarily)
# Turning it on
device.apply_settings(client, hide_passphrase_from_host=True)
passphrase = "abc"
with client:
def input_flow():
yield
layout = client.debug.wait_layout()
assert (
"Passphrase provided by host will be used but will not be displayed due to the device settings."
in layout.get_content()
)
client.debug.press_yes()
client.watch_layout()
client.set_input_flow(input_flow)
client.set_expected_responses(
[
messages.PassphraseRequest,
messages.ButtonRequest,
messages.PublicKey,
]
)
client.use_passphrase(passphrase)
result = client.call(XPUB_REQUEST)
assert isinstance(result, messages.PublicKey)
xpub_hidden_passphrase = result.xpub
# Turning it off
device.apply_settings(client, hide_passphrase_from_host=False)
# Starting new session, otherwise the passphrase would be cached
_init_session(client)
with client:
def input_flow():
yield
layout = client.debug.wait_layout()
assert "Next screen will show the passphrase!" in layout.get_content()
client.debug.press_yes()
yield
layout = client.debug.wait_layout()
assert "Use this passphrase?" in layout.get_content()
assert passphrase in layout.get_content()
client.debug.press_yes()
client.watch_layout()
client.set_input_flow(input_flow)
client.set_expected_responses(
[
messages.PassphraseRequest,
messages.ButtonRequest,
messages.ButtonRequest,
messages.PublicKey,
]
)
client.use_passphrase(passphrase)
result = client.call(XPUB_REQUEST)
assert isinstance(result, messages.PublicKey)
xpub_shown_passphrase = result.xpub
assert xpub_hidden_passphrase == xpub_shown_passphrase
def _get_xpub_cardano(client: Client, passphrase):
msg = messages.CardanoGetPublicKey(
address_n=parse_path("m/44h/1815h/0h/0/0"),

@ -1705,6 +1705,7 @@
"TT_test_session.py::test_end_session_only_current": "bd83a31d0fc4c23953dfd0d138e4441984e34698ace96aad5308a4ae51b712ae",
"TT_test_session.py::test_session_recycling": "07f265234a3269c8c99172e2f67abf626e17a542e6f4c00b45c5b685d0e4c240",
"TT_test_session_id_and_passphrase.py::test_cardano_passphrase": "26e3b8bc6b1ba85fc89d5b237096685309a95f73350d2fca646720fb750d0e8f",
"TT_test_session_id_and_passphrase.py::test_hide_passphrase_from_host": "ccdb34cba3b759d91500b3c2b2ee5d427167d21b6aefa709b659aed298760605",
"TT_test_session_id_and_passphrase.py::test_max_sessions_with_passphrases": "5c85cb246fe4bb07076ed88f426e6133368f3417472cf2dfbef2daac32a088aa",
"TT_test_session_id_and_passphrase.py::test_multiple_passphrases": "12231bae2ea96b600c96ade946e5dda29d6625d128906cf14728869c1e697987",
"TT_test_session_id_and_passphrase.py::test_multiple_sessions": "bd83a31d0fc4c23953dfd0d138e4441984e34698ace96aad5308a4ae51b712ae",

Loading…
Cancel
Save