Skip to content

Commit

Permalink
Merge #554: trezor: Update trezorlib Dec 2021
Browse files Browse the repository at this point in the history
8d2ae5e trezor, keepkey: Passthrough model and _init_device in TrezorClientDebugLink (Andrew Chow)
25c36c9 trezorlib: add dataclasses as a dependency for python 3.6 (Andrew Chow)
b912fbe trezorlib: Document modifications (Andrew Chow)
fa97e3b trezor, keepkey: Update to work with new trezorlib (Andrew Chow)
aac439a keepkey: Update messages to new message definition (Andrew Chow)
292be0a trezor: trezorlib modifications (Andrew Chow)
051b9c1 trezor: Update Trezorlib (Andrew Chow)

Pull request description:

  Updates trezorlib. This update in particular pulls in components needed for Taproot support as well as various upstream changes that reduce our need to make custom modifications.

Top commit has no ACKs.

Tree-SHA512: 038c94bd304c5c9b0f073dafec957f48060db164b9f20310551cb8a638b350b6fc329c881ccbb846f85c9a6444af0b23d7115b5ae9d4596c109cd7627eff2f80
  • Loading branch information
achow101 committed Dec 22, 2021
2 parents 84842b5 + 8d2ae5e commit 6871946
Show file tree
Hide file tree
Showing 111 changed files with 3,448 additions and 3,846 deletions.
140 changes: 73 additions & 67 deletions hwilib/devices/keepkey.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,20 @@
common_err_msgs,
handle_errors,
)
from .trezorlib import protobuf as p
from .trezorlib import protobuf
from .trezorlib.transport import (
hid,
udp,
webusb,
)
from .trezor import TrezorClient, HID_IDS, WEBUSB_IDS
from .trezorlib.mapping import DEFAULT_MAPPING
from .trezorlib.messages import (
DebugLinkState,
Features,
HDNodeType,
ResetDevice,
)
from .trezorlib.models import TrezorModel

from typing import (
Any,
Expand All @@ -41,44 +42,58 @@


class KeepkeyFeatures(Features): # type: ignore
MESSAGE_WIRE_TYPE = 17
FIELDS = {
1: protobuf.Field("vendor", "string", repeated=False, required=False),
2: protobuf.Field("major_version", "uint32", repeated=False, required=True),
3: protobuf.Field("minor_version", "uint32", repeated=False, required=True),
4: protobuf.Field("patch_version", "uint32", repeated=False, required=True),
5: protobuf.Field("bootloader_mode", "bool", repeated=False, required=False),
6: protobuf.Field("device_id", "string", repeated=False, required=False),
7: protobuf.Field("pin_protection", "bool", repeated=False, required=False),
8: protobuf.Field("passphrase_protection", "bool", repeated=False, required=False),
9: protobuf.Field("language", "string", repeated=False, required=False),
10: protobuf.Field("label", "string", repeated=False, required=False),
12: protobuf.Field("initialized", "bool", repeated=False, required=False),
13: protobuf.Field("revision", "bytes", repeated=False, required=False),
14: protobuf.Field("bootloader_hash", "bytes", repeated=False, required=False),
15: protobuf.Field("imported", "bool", repeated=False, required=False),
16: protobuf.Field("unlocked", "bool", repeated=False, required=False),
17: protobuf.Field("passphrase_cached", "bool", repeated=False, required=False),
21: protobuf.Field("model", "string", repeated=False, required=False),
22: protobuf.Field("firmware_variant", "string", repeated=False, required=False),
23: protobuf.Field("firmware_hash", "bytes", repeated=False, required=False),
24: protobuf.Field("no_backup", "bool", repeated=False, required=False),
}

def __init__(
self,
*,
firmware_variant: Optional[str] = None,
firmware_hash: Optional[bytes] = None,
passphrase_cached: Optional[bool] = None,
**kwargs: Any,
) -> None:
super().__init__(**kwargs)
self.passphrase_cached = passphrase_cached
self.firmware_variant = firmware_variant
self.firmware_hash = firmware_hash

@classmethod
def get_fields(cls) -> Dict[int, p.FieldInfo]:
return {
1: ('vendor', p.UnicodeType, None),
2: ('major_version', p.UVarintType, None),
3: ('minor_version', p.UVarintType, None),
4: ('patch_version', p.UVarintType, None),
5: ('bootloader_mode', p.BoolType, None),
6: ('device_id', p.UnicodeType, None),
7: ('pin_protection', p.BoolType, None),
8: ('passphrase_protection', p.BoolType, None),
9: ('language', p.UnicodeType, None),
10: ('label', p.UnicodeType, None),
12: ('initialized', p.BoolType, None),
13: ('revision', p.BytesType, None),
14: ('bootloader_hash', p.BytesType, None),
15: ('imported', p.BoolType, None),
16: ('unlocked', p.BoolType, None),
21: ('model', p.UnicodeType, None),
22: ('firmware_variant', p.UnicodeType, None),
23: ('firmware_hash', p.BytesType, None),
24: ('no_backup', p.BoolType, None),
25: ('wipe_code_protection', p.BoolType, None),
}


class KeepkeyResetDevice(ResetDevice): # type: ignore
MESSAGE_WIRE_TYPE = 14
FIELDS = {
1: protobuf.Field("display_random", "bool", repeated=False, required=False),
2: protobuf.Field("strength", "uint32", repeated=False, required=False),
3: protobuf.Field("passphrase_protection", "bool", repeated=False, required=False),
4: protobuf.Field("pin_protection", "bool", repeated=False, required=False),
5: protobuf.Field("language", "string", repeated=False, required=False),
6: protobuf.Field("label", "string", repeated=False, required=False),
7: protobuf.Field("no_backup", "bool", repeated=False, required=False),
8: protobuf.Field("auto_lock_delay_ms", "uint32", repeated=False, required=False),
9: protobuf.Field("u2f_counter", "uint32", repeated=False, required=False),
}

def __init__(
self,
*,
Expand All @@ -88,22 +103,26 @@ def __init__(
super().__init__(**kwargs)
self.auto_lock_delay_ms = auto_lock_delay_ms

@classmethod
def get_fields(cls) -> Dict[int, p.FieldInfo]:
return {
1: ('display_random', p.BoolType, None),
2: ('strength', p.UVarintType, 256), # default=256
3: ('passphrase_protection', p.BoolType, None),
4: ('pin_protection', p.BoolType, None),
5: ('language', p.UnicodeType, "en-US"), # default=en-US
6: ('label', p.UnicodeType, None),
7: ('no_backup', p.BoolType, None),
8: ('auto_lock_delay_ms', p.UVarintType, None),
9: ('u2f_counter', p.UVarintType, None),
}


class KeepkeyDebugLinkState(DebugLinkState): # type: ignore
MESSAGE_WIRE_TYPE = 102
FIELDS = {
1: protobuf.Field("layout", "bytes", repeated=False, required=False),
2: protobuf.Field("pin", "string", repeated=False, required=False),
3: protobuf.Field("matrix", "string", repeated=False, required=False),
4: protobuf.Field("mnemonic_secret", "bytes", repeated=False, required=False),
5: protobuf.Field("node", "HDNodeType", repeated=False, required=False),
6: protobuf.Field("passphrase_protection", "bool", repeated=False, required=False),
7: protobuf.Field("reset_word", "string", repeated=False, required=False),
8: protobuf.Field("reset_entropy", "bytes", repeated=False, required=False),
9: protobuf.Field("recovery_fake_word", "string", repeated=False, required=False),
10: protobuf.Field("recovery_word_pos", "uint32", repeated=False, required=False),
11: protobuf.Field("recovery_cipher", "string", repeated=False, required=False),
12: protobuf.Field("recovery_auto_completed_word", "string", repeated=False, required=False),
13: protobuf.Field("firmware_hash", "bytes", repeated=False, required=False),
14: protobuf.Field("storage_hash", "bytes", repeated=False, required=False),
}

def __init__(
self,
*,
Expand All @@ -119,25 +138,6 @@ def __init__(
self.firmware_hash = firmware_hash
self.storage_hash = storage_hash

@classmethod
def get_fields(cls) -> Dict[int, p.FieldType]:
return {
1: ('layout', p.BytesType, None),
2: ('pin', p.UnicodeType, None),
3: ('matrix', p.UnicodeType, None),
4: ('mnemonic_secret', p.BytesType, None),
5: ('node', HDNodeType, None),
6: ('passphrase_protection', p.BoolType, None),
7: ('reset_word', p.UnicodeType, None),
8: ('reset_entropy', p.BytesType, None),
9: ('recovery_fake_word', p.UnicodeType, None),
10: ('recovery_word_pos', p.UVarintType, None),
11: ('recovery_cipher', p.UnicodeType, None),
12: ('recovery_auto_completed_word', p.UnicodeType, None),
13: ('firmware_hash', p.BytesType, None),
14: ('storage_hash', p.BytesType, None),
}


class KeepkeyClient(TrezorClient):
def __init__(self, path: str, password: str = "", expert: bool = False) -> None:
Expand All @@ -146,14 +146,20 @@ def __init__(self, path: str, password: str = "", expert: bool = False) -> None:
As Keepkeys are clones of the Trezor 1, please refer to `TrezorClient` for documentation.
"""
super(KeepkeyClient, self).__init__(path, password, expert, KEEPKEY_HID_IDS, KEEPKEY_WEBUSB_IDS, KEEPKEY_SIMULATOR_PATH)
model = TrezorModel(
name="K1-14M",
minimum_version=(0, 0, 0),
vendors=("keepkey.com"),
usb_ids=(), # unused
default_mapping=DEFAULT_MAPPING,
)
model.default_mapping.register(KeepkeyFeatures)
model.default_mapping.register(KeepkeyResetDevice)
if path.startswith("udp"):
model.default_mapping.register(KeepkeyDebugLinkState)

super(KeepkeyClient, self).__init__(path, password, expert, KEEPKEY_HID_IDS, KEEPKEY_WEBUSB_IDS, KEEPKEY_SIMULATOR_PATH, model)
self.type = 'Keepkey'
self.client.vendors = ("keepkey.com")
self.client.minimum_versions = {"K1-14AM": (0, 0, 0)}
self.client.map_type_to_class_override[KeepkeyFeatures.MESSAGE_WIRE_TYPE] = KeepkeyFeatures
self.client.map_type_to_class_override[KeepkeyResetDevice.MESSAGE_WIRE_TYPE] = KeepkeyResetDevice
if self.simulator:
self.client.debug.map_type_to_class_override[KeepkeyDebugLinkState.MESSAGE_WIRE_TYPE] = KeepkeyDebugLinkState

def can_sign_taproot(self) -> bool:
"""
Expand Down
8 changes: 5 additions & 3 deletions hwilib/devices/trezor.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from .trezorlib.client import TrezorClient as Trezor, PASSPHRASE_ON_DEVICE
from .trezorlib.debuglink import TrezorClientDebugLink
from .trezorlib.exceptions import Cancelled, TrezorFailure
from .trezorlib.models import TrezorModel
from .trezorlib.transport import (
DEV_TREZOR1,
TREZORS,
Expand Down Expand Up @@ -273,18 +274,19 @@ def __init__(
expert: bool = False,
hid_ids: Set[Tuple[int, int]] = HID_IDS,
webusb_ids: Set[Tuple[int, int]] = WEBUSB_IDS,
sim_path: str = SIMULATOR_PATH
sim_path: str = SIMULATOR_PATH,
model: Optional[TrezorModel] = None
) -> None:
super(TrezorClient, self).__init__(path, password, expert)
self.simulator = False
transport = get_path_transport(path, hid_ids, webusb_ids, sim_path)
if path.startswith('udp'):
logging.debug('Simulator found, using DebugLink')
self.client = TrezorClientDebugLink(transport=transport)
self.client = TrezorClientDebugLink(transport=transport, model=model, _init_device=False)
self.simulator = True
self.client.use_passphrase(password)
else:
self.client = Trezor(transport=transport, ui=PassphraseUI(password))
self.client = Trezor(transport=transport, ui=PassphraseUI(password), model=model, _init_device=False)

# if it wasn't able to find a client, throw an error
if not self.client:
Expand Down
8 changes: 4 additions & 4 deletions hwilib/devices/trezorlib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

This is a stripped down version of the official [python-trezor](https://github.com/trezor/trezor-firmware/tree/master/python) library.

This stripped down version was made at commit [e4c406822c00695aaf7cd420634643236de17849](https://github.com/trezor/trezor-firmware/commit/e4c406822c00695aaf7cd420634643236de17849).
This stripped down version was made at commit [3ed92a72bb2f4c923bd826ffc959e2f1660e75cd](https://github.com/trezor/trezor-firmware/commit/3ed92a72bb2f4c923bd826ffc959e2f1660e75cd).

## Changes

- Removed altcoin support
- Removed functions that HWI does not use or plan to use
- Changed `TrezorClient` from calling `init_device()` (HWI needs this behavior and doing it in the library makes this simpler)
- Add Keepkey support. Some fields of some messages had to be removed to support both the Keepkey and the Trezor in the same library
- Optionally disable firmware version check in `TrezorClient.call`
- Remove `_MessageTypeMeta` init override

See commits 4f480e49ffb772b585aba96ba310687cb8f2f91d and 0de1b627b3e4a7b6d9c85e3b49eea5c2d5b28541 for the modifications made.
See commit 83d17621d9c61636ccfe8cbf026ba2ed180fac86 for the modifications made.
23 changes: 16 additions & 7 deletions hwilib/devices/trezorlib/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
__version__ = "0.13.0"
# This file is part of the Trezor project.
#
# Copyright (C) 2012-2022 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>.

# fmt: off
MINIMUM_FIRMWARE_VERSION = {
"1": (1, 8, 0),
"T": (2, 1, 0),
}
# fmt: on
__version__ = "0.13.1"

0 comments on commit 6871946

Please sign in to comment.