diff --git a/common/protob/messages-common.proto b/common/protob/messages-common.proto index 607784078..aefa0f08d 100644 --- a/common/protob/messages-common.proto +++ b/common/protob/messages-common.proto @@ -120,7 +120,7 @@ message PassphraseRequest { */ message PassphraseAck { optional string passphrase = 1; - optional bytes _state = 2 [deprecated=true]; // <2.3.0 + // optional bytes state = 2; DEPRECATED since 2.3.0 optional bool on_device = 3; // user wants to enter passphrase on the device } diff --git a/core/src/trezor/messages/PassphraseAck.py b/core/src/trezor/messages/PassphraseAck.py index 84d134c93..791d6c54f 100644 --- a/core/src/trezor/messages/PassphraseAck.py +++ b/core/src/trezor/messages/PassphraseAck.py @@ -16,17 +16,14 @@ class PassphraseAck(p.MessageType): def __init__( self, passphrase: str = None, - _state: bytes = None, on_device: bool = None, ) -> None: self.passphrase = passphrase - self._state = _state self.on_device = on_device @classmethod def get_fields(cls) -> Dict: return { 1: ('passphrase', p.UnicodeType, 0), - 2: ('_state', p.BytesType, 0), 3: ('on_device', p.BoolType, 0), } diff --git a/legacy/firmware/protob/messages-common.options b/legacy/firmware/protob/messages-common.options index 51ecb6ad2..c31f9fb7e 100644 --- a/legacy/firmware/protob/messages-common.options +++ b/legacy/firmware/protob/messages-common.options @@ -5,7 +5,6 @@ Failure.message max_size:256 PinMatrixAck.pin max_size:10 PassphraseAck.passphrase max_size:51 -PassphraseAck._state max_size:32 Deprecated_PassphraseStateRequest.state max_size:1 diff --git a/python/src/trezorlib/client.py b/python/src/trezorlib/client.py index cfb624393..9a7888d2a 100644 --- a/python/src/trezorlib/client.py +++ b/python/src/trezorlib/client.py @@ -187,9 +187,7 @@ class TrezorClient: available_on_device = Capability.PassphraseEntry in self.features.capabilities def send_passphrase(passphrase=None, on_device=None): - msg = messages.PassphraseAck( - _state=self.session_id, passphrase=passphrase, on_device=on_device - ) + msg = messages.PassphraseAck(passphrase=passphrase, on_device=on_device) resp = self.call_raw(msg) if isinstance(resp, messages.Deprecated_PassphraseStateRequest): self.session_id = resp.state diff --git a/python/src/trezorlib/messages/PassphraseAck.py b/python/src/trezorlib/messages/PassphraseAck.py index ef00fa78e..bc5f94c2d 100644 --- a/python/src/trezorlib/messages/PassphraseAck.py +++ b/python/src/trezorlib/messages/PassphraseAck.py @@ -16,17 +16,14 @@ class PassphraseAck(p.MessageType): def __init__( self, passphrase: str = None, - _state: bytes = None, on_device: bool = None, ) -> None: self.passphrase = passphrase - self._state = _state self.on_device = on_device @classmethod def get_fields(cls) -> Dict: return { 1: ('passphrase', p.UnicodeType, 0), - 2: ('_state', p.BytesType, 0), 3: ('on_device', p.BoolType, 0), } diff --git a/tests/upgrade_tests/test_passphrase_consistency.py b/tests/upgrade_tests/test_passphrase_consistency.py new file mode 100644 index 000000000..d8c46c5f1 --- /dev/null +++ b/tests/upgrade_tests/test_passphrase_consistency.py @@ -0,0 +1,116 @@ +# This file is part of the Trezor project. +# +# Copyright (C) 2012-2019 SatoshiLabs and contributors +# +# This library is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# as published by the Free Software Foundation. +# +# 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 License along with this library. +# If not, see . + +import pytest + +from trezorlib import MINIMUM_FIRMWARE_VERSION, btc, device, mapping, messages, protobuf +from trezorlib.tools import parse_path + +from ..emulators import EmulatorWrapper +from . import for_all + +SOURCE_ASK = 0 +SOURCE_DEVICE = 1 +SOURCE_HOST = 2 + + +class ApplySettingsCompat(protobuf.MessageType): + MESSAGE_WIRE_TYPE = 25 + + @classmethod + def get_fields(cls): + return { + 3: ("use_passphrase", protobuf.BoolType, 0), + 5: ("passphrase_source", protobuf.UVarintType, 0), + } + + +mapping.map_class_to_type[ApplySettingsCompat] = ApplySettingsCompat.MESSAGE_WIRE_TYPE + + +@pytest.fixture +def emulator(gen, tag): + with EmulatorWrapper(gen, tag) as emu: + # set up a passphrase-protected device + device.reset( + emu.client, pin_protection=False, skip_backup=True, + ) + resp = emu.client.call( + ApplySettingsCompat(use_passphrase=True, passphrase_source=SOURCE_HOST) + ) + assert isinstance(resp, messages.Success) + + yield emu + + +@for_all( + core_minimum_version=MINIMUM_FIRMWARE_VERSION["T"], + legacy_minimum_version=MINIMUM_FIRMWARE_VERSION["1"], +) +def test_passphrase_works(emulator): + """Check that passphrase handling in trezorlib works correctly in all versions.""" + if emulator.client.features.model == "T" and emulator.client.version < (2, 3, 0): + expected_responses = [ + messages.PassphraseRequest(), + messages.Deprecated_PassphraseStateRequest(), + messages.Address(), + ] + else: + expected_responses = [ + messages.PassphraseRequest(), + messages.Address(), + ] + + with emulator.client: + emulator.client.use_passphrase("TREZOR") + emulator.client.set_expected_responses(expected_responses) + btc.get_address(emulator.client, "Testnet", parse_path("44h/1h/0h/0/0")) + + +@for_all( + core_minimum_version=MINIMUM_FIRMWARE_VERSION["T"], + legacy_minimum_version=(1, 9, 0), +) +def test_init_device(emulator): + """Check that passphrase caching and session_id retaining works correctly across + supported versions. + """ + if emulator.client.features.model == "T" and emulator.client.version < (2, 3, 0): + expected_responses = [ + messages.PassphraseRequest(), + messages.Deprecated_PassphraseStateRequest(), + messages.Address(), + messages.Features(), + messages.Address(), + ] + else: + expected_responses = [ + messages.PassphraseRequest(), + messages.Address(), + messages.Features(), + messages.Address(), + ] + + with emulator.client: + emulator.client.use_passphrase("TREZOR") + emulator.client.set_expected_responses(expected_responses) + + btc.get_address(emulator.client, "Testnet", parse_path("44h/1h/0h/0/0")) + # in TT < 2.3.0 session_id will only be available after PassphraseStateRequest + session_id = emulator.client.session_id + emulator.client.init_device() + btc.get_address(emulator.client, "Testnet", parse_path("44h/1h/0h/0/0")) + assert session_id == emulator.client.session_id