1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-10-20 23:09:13 +00:00
trezor-firmware/tests/upgrade_tests/test_firmware_upgrades.py
matejcik a4bcc95deb feat(python): introduce Trezor models
This keeps information about vendors and USB IDs in one place, and
allows us to extend with model-specific information later.

By default, this should be backwards-compatible -- TrezorClient can
optionally accept model information, and if not, it will try to guess
based on Features.

It is possible to specify which models to look for in transport
enumeration. Bridge and UDP transports ignore the parameter, because
they can't know what model is on the other side.

supersedes #1448 and #1449
2021-12-07 16:55:58 +01:00

368 lines
12 KiB
Python

# 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 <https://www.gnu.org/licenses/lgpl-3.0.html>.
import dataclasses
import pytest
from trezorlib import btc, debuglink, device, exceptions, fido, models
from trezorlib.messages import BackupType
from trezorlib.tools import H_
from ..click_tests import recovery
from ..common import MNEMONIC_SLIP39_BASIC_20_3of6, MNEMONIC_SLIP39_BASIC_20_3of6_SECRET
from ..device_handler import BackgroundDeviceHandler
from ..emulators import ALL_TAGS, EmulatorWrapper
from . import for_all, for_tags
models.TREZOR_ONE = dataclasses.replace(models.TREZOR_ONE, minimum_version=(1, 0, 0))
models.TREZOR_T = dataclasses.replace(models.TREZOR_T, minimum_version=(2, 0, 0))
models.TREZORS = {models.TREZOR_ONE, models.TREZOR_T}
# **** COMMON DEFINITIONS ****
MNEMONIC = " ".join(["all"] * 12)
PATH = [H_(44), H_(0), H_(0), 0, 0]
ADDRESS = "1JAd7XCBzGudGpJQSDSfpmJhiygtLQWaGL"
LABEL = "test"
LANGUAGE = "en-US"
STRENGTH = 128
@for_all()
def test_upgrade_load(gen, tag):
def asserts(client):
assert not client.features.pin_protection
assert not client.features.passphrase_protection
assert client.features.initialized
assert client.features.label == LABEL
assert btc.get_address(client, "Bitcoin", PATH) == ADDRESS
with EmulatorWrapper(gen, tag) as emu:
debuglink.load_device_by_mnemonic(
emu.client,
mnemonic=MNEMONIC,
pin="",
passphrase_protection=False,
label=LABEL,
language=LANGUAGE,
)
device_id = emu.client.features.device_id
asserts(emu.client)
storage = emu.get_storage()
with EmulatorWrapper(gen, storage=storage) as emu:
assert device_id == emu.client.features.device_id
asserts(emu.client)
assert emu.client.features.language == LANGUAGE
@for_all("legacy")
def test_upgrade_load_pin(gen, tag):
PIN = "1234"
def asserts(client):
assert client.features.pin_protection
assert not client.features.passphrase_protection
assert client.features.initialized
assert client.features.label == LABEL
client.use_pin_sequence([PIN])
assert btc.get_address(client, "Bitcoin", PATH) == ADDRESS
with EmulatorWrapper(gen, tag) as emu:
debuglink.load_device_by_mnemonic(
emu.client,
mnemonic=MNEMONIC,
pin=PIN,
passphrase_protection=False,
label=LABEL,
language=LANGUAGE,
)
device_id = emu.client.features.device_id
asserts(emu.client)
storage = emu.get_storage()
with EmulatorWrapper(gen, storage=storage) as emu:
assert device_id == emu.client.features.device_id
asserts(emu.client)
assert emu.client.features.language == LANGUAGE
# Test progressive upgrade of storage versions without unlocking in between.
# Legacy storage: until legacy-v1.7.3 (pre-norcow)
# Storage Version 0: until core-v2.0.9 (basic norcow)
# Storage Version 1: since legacy-v1.8.0 and core-v2.1.0 (encryption)
# Storage Version 2: since legacy-v1.9.0 and core-v2.3.0 (wipe code)
# Storage Version 3: since legacy-v1.10.0 and core-v2.4.0 (long PIN)
@for_tags(
("legacy", ["v1.7.0", "v1.8.0", "v1.9.0"]),
("legacy", ["v1.7.0", "v1.8.0"]),
("legacy", ["v1.7.0", "v1.9.0"]),
("legacy", ["v1.8.0", "v1.9.0"]),
)
def test_storage_upgrade_progressive(gen, tags):
PIN = "1234"
def asserts(client):
assert client.features.pin_protection
assert not client.features.passphrase_protection
assert client.features.initialized
assert client.features.label == LABEL
client.use_pin_sequence([PIN])
assert btc.get_address(client, "Bitcoin", PATH) == ADDRESS
with EmulatorWrapper(gen, tags[0]) as emu:
debuglink.load_device_by_mnemonic(
emu.client,
mnemonic=MNEMONIC,
pin=PIN,
passphrase_protection=False,
label=LABEL,
language=LANGUAGE,
)
device_id = emu.client.features.device_id
asserts(emu.client)
storage = emu.get_storage()
for tag in tags[1:]:
with EmulatorWrapper(gen, tag, storage=storage) as emu:
storage = emu.get_storage()
with EmulatorWrapper(gen, storage=storage) as emu:
assert device_id == emu.client.features.device_id
asserts(emu.client)
assert emu.client.features.language == LANGUAGE
@for_all("legacy", legacy_minimum_version=(1, 9, 0))
def test_upgrade_wipe_code(gen, tag):
PIN = "1234"
WIPE_CODE = "4321"
def asserts(client):
assert client.features.pin_protection
assert not client.features.passphrase_protection
assert client.features.initialized
assert client.features.label == LABEL
client.use_pin_sequence([PIN])
assert btc.get_address(client, "Bitcoin", PATH) == ADDRESS
with EmulatorWrapper(gen, tag) as emu:
debuglink.load_device_by_mnemonic(
emu.client,
mnemonic=MNEMONIC,
pin=PIN,
passphrase_protection=False,
label=LABEL,
language=LANGUAGE,
)
# Set wipe code.
emu.client.use_pin_sequence([PIN, WIPE_CODE, WIPE_CODE])
device.change_wipe_code(emu.client)
device_id = emu.client.features.device_id
asserts(emu.client)
storage = emu.get_storage()
with EmulatorWrapper(gen, storage=storage) as emu:
assert device_id == emu.client.features.device_id
asserts(emu.client)
assert emu.client.features.language == LANGUAGE
# Check that wipe code is set by changing the PIN to it.
emu.client.use_pin_sequence([PIN, WIPE_CODE, WIPE_CODE])
with pytest.raises(
exceptions.TrezorFailure,
match="The new PIN must be different from your wipe code",
):
return device.change_pin(emu.client)
@for_all("legacy")
def test_upgrade_reset(gen, tag):
def asserts(client):
assert not client.features.pin_protection
assert not client.features.passphrase_protection
assert client.features.initialized
assert client.features.label == LABEL
assert not client.features.needs_backup
assert not client.features.unfinished_backup
assert not client.features.no_backup
with EmulatorWrapper(gen, tag) as emu:
device.reset(
emu.client,
display_random=False,
strength=STRENGTH,
passphrase_protection=False,
pin_protection=False,
label=LABEL,
language=LANGUAGE,
)
device_id = emu.client.features.device_id
asserts(emu.client)
address = btc.get_address(emu.client, "Bitcoin", PATH)
storage = emu.get_storage()
with EmulatorWrapper(gen, storage=storage) as emu:
assert device_id == emu.client.features.device_id
asserts(emu.client)
assert emu.client.features.language == LANGUAGE
assert btc.get_address(emu.client, "Bitcoin", PATH) == address
@for_all()
def test_upgrade_reset_skip_backup(gen, tag):
def asserts(client):
assert not client.features.pin_protection
assert not client.features.passphrase_protection
assert client.features.initialized
assert client.features.label == LABEL
assert client.features.needs_backup
assert not client.features.unfinished_backup
assert not client.features.no_backup
with EmulatorWrapper(gen, tag) as emu:
device.reset(
emu.client,
display_random=False,
strength=STRENGTH,
passphrase_protection=False,
pin_protection=False,
label=LABEL,
language=LANGUAGE,
skip_backup=True,
)
device_id = emu.client.features.device_id
asserts(emu.client)
address = btc.get_address(emu.client, "Bitcoin", PATH)
storage = emu.get_storage()
with EmulatorWrapper(gen, storage=storage) as emu:
assert device_id == emu.client.features.device_id
asserts(emu.client)
assert emu.client.features.language == LANGUAGE
assert btc.get_address(emu.client, "Bitcoin", PATH) == address
@for_all(legacy_minimum_version=(1, 7, 2))
def test_upgrade_reset_no_backup(gen, tag):
def asserts(client):
assert not client.features.pin_protection
assert not client.features.passphrase_protection
assert client.features.initialized
assert client.features.label == LABEL
assert not client.features.needs_backup
assert not client.features.unfinished_backup
assert client.features.no_backup
with EmulatorWrapper(gen, tag) as emu:
device.reset(
emu.client,
display_random=False,
strength=STRENGTH,
passphrase_protection=False,
pin_protection=False,
label=LABEL,
language=LANGUAGE,
no_backup=True,
)
device_id = emu.client.features.device_id
asserts(emu.client)
address = btc.get_address(emu.client, "Bitcoin", PATH)
storage = emu.get_storage()
with EmulatorWrapper(gen, storage=storage) as emu:
assert device_id == emu.client.features.device_id
asserts(emu.client)
assert emu.client.features.language == LANGUAGE
assert btc.get_address(emu.client, "Bitcoin", PATH) == address
# Although Shamir was introduced in 2.1.2 already, the debug instrumentation was not present until 2.1.9.
@for_all("core", core_minimum_version=(2, 1, 9))
def test_upgrade_shamir_recovery(gen, tag):
with EmulatorWrapper(gen, tag) as emu, BackgroundDeviceHandler(
emu.client
) as device_handler:
assert emu.client.features.recovery_mode is False
emu.client.watch_layout(True)
debug = device_handler.debuglink()
device_handler.run(device.recover, pin_protection=False)
recovery.confirm_recovery(debug)
recovery.select_number_of_words(debug)
layout = recovery.enter_share(debug, MNEMONIC_SLIP39_BASIC_20_3of6[0])
assert "2 more shares" in layout.text
device_id = emu.client.features.device_id
storage = emu.get_storage()
device_handler.check_finalize()
with EmulatorWrapper(gen, storage=storage) as emu:
assert device_id == emu.client.features.device_id
assert emu.client.features.recovery_mode
debug = emu.client.debug
emu.client.watch_layout(True)
# second share
layout = recovery.enter_share(debug, MNEMONIC_SLIP39_BASIC_20_3of6[2])
assert "1 more share" in layout.text
# last one
layout = recovery.enter_share(debug, MNEMONIC_SLIP39_BASIC_20_3of6[1])
assert "You have successfully" in layout.text
# Check the result
state = debug.state()
assert state.mnemonic_secret.hex() == MNEMONIC_SLIP39_BASIC_20_3of6_SECRET
assert state.mnemonic_type == BackupType.Slip39_Basic
@for_all(legacy_minimum_version=(1, 8, 4), core_minimum_version=(2, 1, 9))
def test_upgrade_u2f(gen, tag):
"""Check U2F counter stayed the same after an upgrade."""
with EmulatorWrapper(gen, tag) as emu:
debuglink.load_device_by_mnemonic(
emu.client,
mnemonic=MNEMONIC,
pin="",
passphrase_protection=False,
label=LABEL,
)
success = fido.set_counter(emu.client, 10)
assert "U2F counter set" in success
counter = fido.get_next_counter(emu.client)
assert counter == 11
storage = emu.get_storage()
with EmulatorWrapper(gen, storage=storage) as emu:
counter = fido.get_next_counter(emu.client)
assert counter == 12
if __name__ == "__main__":
if not ALL_TAGS:
print("No versions found. Remember to run download_emulators.sh")
for k, v in ALL_TAGS.items():
print(f"Found versions for {k}: {v}")
print()
print(f"Use `pytest {__file__}` to run tests")