From 78ecc38b1b1f5f3e547bcd95f3b33b1a1012a402 Mon Sep 17 00:00:00 2001 From: matejcik Date: Fri, 20 Sep 2019 17:11:24 +0200 Subject: [PATCH] core: fix BIP39 backup Refers to #550. Not marking fixed because we need more tests. --- .../apps/management/reset_device/__init__.py | 28 ++++------ tests/device_tests/test_msg_backup_device.py | 56 +++++++++++++++++++ 2 files changed, 68 insertions(+), 16 deletions(-) create mode 100644 tests/device_tests/test_msg_backup_device.py diff --git a/core/src/apps/management/reset_device/__init__.py b/core/src/apps/management/reset_device/__init__.py index 3158a6d1e5..daf8af1ba3 100644 --- a/core/src/apps/management/reset_device/__init__.py +++ b/core/src/apps/management/reset_device/__init__.py @@ -58,6 +58,17 @@ async def reset_device(ctx: wire.Context, msg: ResetDevice) -> Success: if perform_backup: perform_backup = await layout.confirm_backup(ctx) + # Check backup type, convert seed accordingly + if msg.backup_type == BackupType.Bip39: + # in BIP-39 we store mnemonic string instead of the secret + secret = bip39.from_data(secret).encode() + elif msg.backup_type not in (BackupType.Slip39_Basic, BackupType.Slip39_Advanced): + # Unknown backup type. + # This check might seem superfluous, because we are checking + # in `_validate_reset_device` already, however, this is critical part, + # so just to make sure. + raise RuntimeError + # generate and display backup information for the master secret if perform_backup: await backup_seed(ctx, msg.backup_type, secret) @@ -70,16 +81,6 @@ async def reset_device(ctx: wire.Context, msg: ResetDevice) -> Success: storage.device.load_settings( label=msg.label, use_passphrase=msg.passphrase_protection ) - if msg.backup_type == BackupType.Bip39: - # in BIP-39 we store mnemonic string instead of the secret - secret = bip39.from_data(secret).encode() - elif msg.backup_type not in (BackupType.Slip39_Basic, BackupType.Slip39_Advanced): - # Unknown backup type. - # This check might seem superfluous, because we are checking - # in `_validate_reset_device` already, however, this is critical part, - # so just to make sure. - raise RuntimeError - storage.device.store_mnemonic_secret( secret, # for SLIP-39, this is the EMS msg.backup_type, @@ -153,11 +154,6 @@ async def backup_slip39_advanced( await layout.slip39_advanced_show_and_confirm_shares(ctx, mnemonics) -async def backup_bip39(ctx: wire.Context, secret: bytes) -> None: - mnemonic = bip39.from_data(secret) - await layout.bip39_show_and_confirm_mnemonic(ctx, mnemonic) - - def _validate_reset_device(msg: ResetDevice) -> None: msg.backup_type = msg.backup_type or _DEFAULT_BACKUP_TYPE if msg.backup_type not in ( @@ -200,4 +196,4 @@ async def backup_seed( elif backup_type == BackupType.Slip39_Advanced: await backup_slip39_advanced(ctx, mnemonic_secret) else: - await backup_bip39(ctx, mnemonic_secret) + await layout.bip39_show_and_confirm_mnemonic(ctx, mnemonic_secret.decode()) diff --git a/tests/device_tests/test_msg_backup_device.py b/tests/device_tests/test_msg_backup_device.py new file mode 100644 index 0000000000..ce963204a5 --- /dev/null +++ b/tests/device_tests/test_msg_backup_device.py @@ -0,0 +1,56 @@ +# 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 device, messages +from trezorlib.messages import ButtonRequestType as B + +from ..common import MNEMONIC12, read_and_confirm_mnemonic + + +@pytest.mark.skip_t1 # TODO we want this for t1 too +@pytest.mark.setup_client(mnemonic=MNEMONIC12) +def test_backup(client): + assert client.features.needs_backup is True + mnemonic = None + + def input_flow(): + nonlocal mnemonic + yield # Confirm Backup + client.debug.press_yes() + yield # Mnemonic phrases + mnemonic = read_and_confirm_mnemonic(client.debug, words=12) + yield # Confirm success + client.debug.press_yes() + yield # Backup is done + client.debug.press_yes() + + with client: + client.set_input_flow(input_flow) + client.set_expected_responses( + [ + messages.ButtonRequest(code=B.ResetDevice), + messages.ButtonRequest(code=B.ResetDevice), + messages.ButtonRequest(code=B.Success), + messages.ButtonRequest(code=B.Success), + messages.Success(), + ] + ) + device.backup(client) + + assert mnemonic == MNEMONIC12