diff --git a/core/src/apps/webauthn/__init__.py b/core/src/apps/webauthn/__init__.py index 5a5a916f9..ee3f7a7dc 100644 --- a/core/src/apps/webauthn/__init__.py +++ b/core/src/apps/webauthn/__init__.py @@ -20,4 +20,5 @@ def boot() -> None: ) import usb - loop.schedule(handle_reports(usb.iface_webauthn)) + if usb.ENABLE_IFACE_WEBAUTHN: + loop.schedule(handle_reports(usb.iface_webauthn)) diff --git a/core/src/usb.py b/core/src/usb.py index a3eff5764..cb732e618 100644 --- a/core/src/usb.py +++ b/core/src/usb.py @@ -1,19 +1,57 @@ from storage.device import get_device_id from trezor import io, utils +_iface_iter = iter(range(5)) + +ENABLE_IFACE_DEBUG = __debug__ +# change to False to enable VCP, see below +ENABLE_IFACE_WEBAUTHN = not utils.BITCOIN_ONLY + +# We only have 10 available USB endpoints on real HW, of which 2 are taken up by the USB descriptor. +# iface_wire, iface_debug and iface_webauthn also consume 2 each, iface_vcp uses 3. +# That is a grand total of 11. That means that we can't enable everything at the same time. +# By default, iface_vcp is only enabled on bitcoin_only firmware, where iface_webauthn +# is disabled. Implementation-wise, we check if any of the previous ifaces is disabled +# in order to enable VCP. +ENABLE_IFACE_VCP = __debug__ and ( + utils.EMULATOR or not ENABLE_IFACE_DEBUG or not ENABLE_IFACE_WEBAUTHN +) + # interface used for trezor wire protocol -iface_wire = io.WebUSB(iface_num=0, ep_in=0x81, ep_out=0x01) +id_wire = next(_iface_iter) +iface_wire = io.WebUSB( + iface_num=id_wire, + ep_in=0x81 + id_wire, + ep_out=0x01 + id_wire, +) + +# XXXXXXXXXXXXXXXXXXX +# +# We want the following branches present only in their respective firmwares. To achieve +# that, we are taking advantage of the upy compiler static optimization: when an +# if-expression statically evaluates to False, the branch is excluded from the bytecode. +# This works magically for the __debug__ builtin, and `utils.BITCOIN_ONLY` is replaced +# by a literal True/False by us in the build step. +# +# Therefore, each of the following needs to include the respective static expression +# so that it can be correctly excluded from the resulting build. -if __debug__: +if __debug__ and ENABLE_IFACE_DEBUG: # interface used for debug messages with trezor wire protocol - iface_debug = io.WebUSB(iface_num=1, ep_in=0x82, ep_out=0x02) + id_debug = next(_iface_iter) + iface_debug = io.WebUSB( + iface_num=id_debug, + ep_in=0x81 + id_debug, + ep_out=0x01 + id_debug, + ) -if not utils.BITCOIN_ONLY: +if not utils.BITCOIN_ONLY and ENABLE_IFACE_WEBAUTHN: # interface used for FIDO/U2F and FIDO2/WebAuthn HID transport + id_webauthn = next(_iface_iter) iface_webauthn = io.HID( - iface_num=2 if __debug__ else 1, - ep_in=0x83 if __debug__ else 0x82, - ep_out=0x03 if __debug__ else 0x02, + iface_num=id_webauthn, + ep_in=0x81 + id_webauthn, + ep_out=0x01 + id_webauthn, # fmt: off report_desc=bytes([ 0x06, 0xd0, 0xf1, # USAGE_PAGE (FIDO Alliance) @@ -36,20 +74,17 @@ if not utils.BITCOIN_ONLY: # fmt: on ) -if __debug__: - # We cannot use this on real device simultaneously with the iface_webauthn - # interface, because we have only limited number of endpoints (10). - # We start this only for bitcoin-only firmware or for emulator. - ENABLE_VCP_IFACE = utils.EMULATOR or utils.BITCOIN_ONLY - if ENABLE_VCP_IFACE: - # interface used for cdc/vcp console emulation (debug messages) - iface_vcp = io.VCP( - iface_num=2 if utils.BITCOIN_ONLY else 3, - data_iface_num=3 if utils.BITCOIN_ONLY else 4, - ep_in=0x83 if utils.BITCOIN_ONLY else 0x84, - ep_out=0x03 if utils.BITCOIN_ONLY else 0x04, - ep_cmd=0x84 if utils.BITCOIN_ONLY else 0x85, - ) +if __debug__ and ENABLE_IFACE_VCP: + # interface used for cdc/vcp console emulation (debug messages) + id_vcp = next(_iface_iter) + id_vcp_data = next(_iface_iter) + iface_vcp = io.VCP( + iface_num=id_vcp, + data_iface_num=id_vcp_data, + ep_in=0x81 + id_vcp, + ep_out=0x01 + id_vcp, + ep_cmd=0x81 + id_vcp_data, + ) bus = io.USB( vendor_id=0x1209, @@ -62,10 +97,9 @@ bus = io.USB( usb21_landing=False, ) bus.add(iface_wire) -if __debug__: +if __debug__ and ENABLE_IFACE_DEBUG: bus.add(iface_debug) -if not utils.BITCOIN_ONLY: +if not utils.BITCOIN_ONLY and ENABLE_IFACE_WEBAUTHN: bus.add(iface_webauthn) -if __debug__: - if ENABLE_VCP_IFACE: - bus.add(iface_vcp) +if __debug__ and ENABLE_IFACE_VCP: + bus.add(iface_vcp)