1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-14 03:30:02 +00:00

feat(core): work on pairing, updated protobuf

note: crashes during build
This commit is contained in:
M1nd3r 2024-04-09 12:27:55 +02:00
parent 30fd1fe5c3
commit 2637ce299d
23 changed files with 3376 additions and 135 deletions

View File

@ -12,45 +12,170 @@ option java_outer_classname = "TrezorMessageThp";
* @embed
*/
enum ThpPairingMethod {
PairingMethod_NoMethod = 1; // Trust without MITM protection.
PairingMethod_CodeEntry = 2; // User types code diplayed on Trezor into the host application.
PairingMethod_QrCode = 3; // User scans code displayed on Trezor into host application.
PairingMethod_NFC_Unidirectional = 4; // Trezor transmits an authentication key to the host device via NFC.
PairingMethod_NoMethod = 1; // Trust without MITM protection.
PairingMethod_CodeEntry = 2; // User types code diplayed on Trezor into the host application.
PairingMethod_QrCode = 3; // User scans code displayed on Trezor into host application.
PairingMethod_NFC_Unidirectional = 4; // Trezor transmits an authentication key to the host device via NFC.
}
/**
* @embed
*/
message ThpDeviceProperties {
optional string internal_model = 1; // Internal model name e.g. "T2B1".
optional uint32 model_variant = 2; // Encodes the device properties such as color.
optional bool bootloader_mode = 3; // Indicates whether the device is in bootloader or firmware mode.
optional uint32 protocol_version = 4; // The communication protocol version supported by the firmware.
repeated ThpPairingMethod pairing_methods = 5; // The pairing methods supported by the Trezor.
optional string internal_model = 1; // Internal model name e.g. "T2B1".
optional uint32 model_variant = 2; // Encodes the device properties such as color.
optional bool bootloader_mode = 3; // Indicates whether the device is in bootloader or firmware mode.
optional uint32 protocol_version = 4; // The communication protocol version supported by the firmware.
repeated ThpPairingMethod pairing_methods = 5; // The pairing methods supported by the Trezor.
}
/**
* @embed
*/
message ThpHandshakeCompletionReqNoisePayload {
optional bytes host_pairing_credential = 1; // Host's pairing credential
repeated ThpPairingMethod pairing_methods = 2; // The pairing methods chosen by the host
optional bytes host_pairing_credential = 1; // Host's pairing credential
repeated ThpPairingMethod pairing_methods = 2; // The pairing methods chosen by the host
}
/**
* Request: Ask device for a new session with given passphrase
* Request: Ask device for a new session with given passphrase.
* @start
* @next ThpNewSession
*/
message ThpCreateNewSession{
optional string passphrase = 1;
optional bool on_device = 2; // user wants to enter passphrase on the device
optional bool on_device = 2; // User wants to enter passphrase on the device
}
/**
* Response: Contains session_id of the newly created session
* Response: Contains session_id of the newly created session.
* @end
*/
message ThpNewSession{
optional uint32 new_session_id = 1;
}
/**
* Request: Start pairing process.
* @start
* @next ThpCodeEntryCommitment
* @next ThpQrCodeTag // Sent by the Host
* @next ThpNfcUnidirectionalTag // Sent by the Host
*/
message ThpStartPairingRequest{
optional bytes host_name = 1; // Human-readable host name
}
/**
* Response: If Code Entry is an allowed pairing option, Trezor responds with a commitment.
* @next ThpCodeEntryChallenge
*/
message ThpCodeEntryCommitment {
optional bytes commitment = 1; // SHA-256 of Trezor's random 32-byte secret
}
/**
* Response: Host responds to Trezor's Code Entry commitment with a challenge.
* @next ThpCodeEntryCpaceHost // Sent by the Host
* @next ThpQrCodeTag // Sent by the Host
* @next ThpNfcUnidirectionalTag // Sent by the Host
*/
message ThpCodeEntryChallenge {
optional bytes challenge = 1; // host's random 32-byte challenge
}
/**
* Request: User selected Code Entry option in Host. Host starts CPACE protocol with Trezor.
* @next ThpCodeEntryCpaceTrezor
*/
message ThpCodeEntryCpaceHost {
optional bytes cpace_host_public_key = 1; // Host's ephemeral CPace public key
}
/**
* Response: Trezor continues with the CPACE protocol.
* @next ThpCodeEntryTag
*/
message ThpCodeEntryCpaceTrezor {
optional bytes cpace_trezor_public_key = 1; // Trezor's ephemeral CPace public key
}
/**
* Response: Host continues with the CPACE protocol.
* @next ThpCodeEntrySecret
*/
message ThpCodeEntryTag {
optional bytes tag = 2; // SHA-256 of shared secret
}
/**
* Response: Trezor finishes the CPACE protocol.
* @end
*/
message ThpCodeEntrySecret {
optional bytes secret = 1; // Trezor's secret
}
/**
* Request: User selected QR Code pairing option. Host sends a QR Tag.
* @next ThpQrCodeSecret
*/
message ThpQrCodeTag {
optional bytes tag = 1; // SHA-256 of shared secret
}
/**
* Response: Trezor sends the QR secret.
* @end
*/
message ThpQrCodeSecret {
optional bytes secret = 1; // Trezor's secret
}
/**
* Request: User selected Unidirectional NFC pairing option. Host sends an Unidirectional NFC Tag.
* @next ThpNfcUnideirectionalSecret
*/
message ThpNfcUnidirectionalTag {
optional bytes tag = 1; // SHA-256 of shared secret
}
/**
* Response: Trezor sends the Unidirectioal NFC secret.
* @end
*/
message ThpNfcUnideirectionalSecret {
optional bytes secret = 1; // Trezor's secret
}
/**
* Request: Host requests issuance of a new pairing credential.
* @start
* @next ThpCredentialResponse
*/
message ThpCredentialRequest {
optional bytes host_static_pubkey = 1; // Host's static public key used in the handshake.
}
/**
* Response: Trezor issues a new pairing credential.
* @next ThpCredentialRequest
* @next EndRequest
*/
message ThpCredentialResponse {
optional bytes trezor_static_pubkey = 1; // Trezor's static public key used in the handshake.
optional bytes credential = 2; // The pairing credential issued by the Trezor to the host.
}
/**
* Request: Host requests transition to the encrypted traffic phase.
* @start
* @next EndResponse
*/
message EndRequest {}
/**
* Response: Trezor approves transition to the encrypted traffic phase
* @end
*/
message EndResponse {}

View File

@ -385,5 +385,14 @@ enum MessageType {
MessageType_ThpEndResponse = 1005 [(bitcoin_only) = true, (wire_out) = true];
MessageType_ThpCreateNewSession = 1006[(bitcoin_only)=true,(wire_in)=true];
MessageType_ThpNewSession = 1007[(bitcoin_only)=true,(wire_out)=true];
MessageType_ThpCodeEntryCommitment = 1016[(bitcoin_only)=true,(wire_out)=true];
MessageType_ThpCodeEntryChallenge = 1017[(bitcoin_only)=true,(wire_in)=true];
MessageType_ThpCodeEntryCpaceHost = 1018[(bitcoin_only)=true,(wire_in)=true];
MessageType_ThpCodeEntryCpaceTrezor = 1019[(bitcoin_only)=true,(wire_out)=true];
MessageType_ThpCodeEntryTag = 1020[(bitcoin_only)=true,(wire_in)=true];
MessageType_ThpCodeEntrySecret = 1021[(bitcoin_only)=true,(wire_out)=true];
MessageType_ThpQrCodeTag = 1024[(bitcoin_only)=true,(wire_in)=true];
MessageType_ThpQrCodeSecret = 1025[(bitcoin_only)=true,(wire_out)=true];
MessageType_ThpNfcUnidirectionalTag = 1032[(bitcoin_only)=true,(wire_in)=true];
MessageType_ThpNfcUnideirectionalSecret = 1033[(bitcoin_only)=true,(wire_in)=true];
}

View File

@ -217,6 +217,8 @@ trezor.wire.thp.checksum
import trezor.wire.thp.checksum
trezor.wire.thp.crypto
import trezor.wire.thp.crypto
trezor.wire.thp.pairing_context
import trezor.wire.thp.pairing_context
trezor.wire.thp.session_context
import trezor.wire.thp.session_context
trezor.wire.thp.thp_messages
@ -397,6 +399,12 @@ apps.misc.get_firmware_hash
import apps.misc.get_firmware_hash
apps.misc.sign_identity
import apps.misc.sign_identity
apps.thp
import apps.thp
apps.thp.create_session
import apps.thp.create_session
apps.thp.pairing
import apps.thp.pairing
apps.workflow_handlers
import apps.workflow_handlers

View File

@ -270,7 +270,7 @@ async def handle_DoPreauthorized(msg: DoPreauthorized) -> protobuf.MessageType:
get_context().iface, req.MESSAGE_WIRE_TYPE
)
if handler is None:
return wire.unexpected_message()
return wire.message_handler.unexpected_message()
return await handler(req, authorization.get()) # type: ignore [Expected 1 positional argument]

View File

@ -29,7 +29,10 @@ async def recovery_process() -> Success:
import storage
from trezor.enums import MessageType
wire.AVOID_RESTARTING_FOR = (MessageType.Initialize, MessageType.GetFeatures)
wire.message_handler.AVOID_RESTARTING_FOR = (
MessageType.Initialize,
MessageType.GetFeatures,
)
try:
return await _continue_recovery_process()
except recover.RecoveryAborted:

View File

View File

@ -0,0 +1,13 @@
from typing import TYPE_CHECKING # pyright: ignore[reportShadowedImports]
from trezor.wire.thp.channel import Channel
if TYPE_CHECKING:
from trezor.messages import ThpCreateNewSession, ThpNewSession
async def create_new_session(
channel: Channel, message: ThpCreateNewSession
) -> ThpNewSession:
new_session_id: int = channel.create_new_session(message.passphrase)
return ThpNewSession(new_session_id=new_session_id)

View File

@ -0,0 +1,92 @@
from typing import TYPE_CHECKING # pyright: ignore[reportShadowedImports]
from trezor.wire.errors import UnexpectedMessage
from trezor.wire.thp import ChannelState
from trezor.wire.thp.channel import Channel
from trezor.wire.thp.thp_session import ThpError
if TYPE_CHECKING:
from trezor.enums import ThpPairingMethod
from trezor.messages import (
ThpCodeEntryChallenge,
ThpCodeEntryCommitment,
ThpCodeEntryCpaceHost,
ThpCodeEntryCpaceTrezor,
ThpCodeEntrySecret,
ThpCodeEntryTag,
ThpNfcUnideirectionalSecret,
ThpNfcUnidirectionalTag,
ThpQrCodeSecret,
ThpQrCodeTag,
ThpStartPairingRequest,
)
# TODO implement the following handlers
async def handle_pairing_request(
channel: Channel, message: ThpStartPairingRequest
) -> ThpCodeEntryCommitment | None:
_check_state(channel, ChannelState.TP1)
if _is_method_included(channel, ThpPairingMethod.PairingMethod_CodeEntry):
channel.set_channel_state(ChannelState.TP2)
return ThpCodeEntryCommitment()
channel.set_channel_state(ChannelState.TP3)
return None
async def handle_code_entry_challenge(
channel: Channel, message: ThpCodeEntryChallenge
) -> None:
_check_state(channel, ChannelState.TP2)
channel.set_channel_state(ChannelState.TP3)
async def handle_code_entry_cpace(
channel: Channel, message: ThpCodeEntryCpaceHost
) -> ThpCodeEntryCpaceTrezor:
_check_state(channel, ChannelState.TP3)
_check_method_is_allowed(channel, ThpPairingMethod.PairingMethod_CodeEntry)
channel.set_channel_state(ChannelState.TP4)
return ThpCodeEntryCpaceTrezor()
async def handle_code_entry_tag(
channel: Channel, message: ThpCodeEntryTag
) -> ThpCodeEntrySecret:
_check_state(channel, ChannelState.TP4)
channel.set_channel_state(ChannelState.TC1)
return ThpCodeEntrySecret()
async def handle_qr_code_tag(
channel: Channel, message: ThpQrCodeTag
) -> ThpQrCodeSecret:
_check_state(channel, ChannelState.TP3)
_check_method_is_allowed(channel, ThpPairingMethod.PairingMethod_QrCode)
channel.set_channel_state(ChannelState.TC1)
return ThpQrCodeSecret()
async def handle_nfc_unidirectional_tag(
channel: Channel, message: ThpNfcUnidirectionalTag
) -> ThpNfcUnideirectionalSecret:
_check_state(channel, ChannelState.TP3)
_check_method_is_allowed(channel, ThpPairingMethod.PairingMethod_NFC_Unidirectional)
channel.set_channel_state(ChannelState.TC1)
return ThpNfcUnideirectionalSecret()
def _check_state(channel: Channel, expected_state: ChannelState) -> None:
if expected_state is not channel.get_channel_state():
raise UnexpectedMessage("Unexpected message")
def _check_method_is_allowed(channel: Channel, method: ThpPairingMethod) -> None:
if not _is_method_included(channel, method):
raise ThpError("Unexpected pairing method")
def _is_method_included(channel: Channel, method: ThpPairingMethod) -> bool:
return method in channel.selected_pairing_methods

View File

@ -105,6 +105,16 @@ ThpEndRequest = 1004
ThpEndResponse = 1005
ThpCreateNewSession = 1006
ThpNewSession = 1007
ThpCodeEntryCommitment = 1016
ThpCodeEntryChallenge = 1017
ThpCodeEntryCpaceHost = 1018
ThpCodeEntryCpaceTrezor = 1019
ThpCodeEntryTag = 1020
ThpCodeEntrySecret = 1021
ThpQrCodeTag = 1024
ThpQrCodeSecret = 1025
ThpNfcUnidirectionalTag = 1032
ThpNfcUnideirectionalSecret = 1033
if not utils.BITCOIN_ONLY:
SetU2FCounter = 63
GetNextU2FCounter = 80

View File

@ -272,6 +272,16 @@ if TYPE_CHECKING:
ThpEndResponse = 1005
ThpCreateNewSession = 1006
ThpNewSession = 1007
ThpCodeEntryCommitment = 1016
ThpCodeEntryChallenge = 1017
ThpCodeEntryCpaceHost = 1018
ThpCodeEntryCpaceTrezor = 1019
ThpCodeEntryTag = 1020
ThpCodeEntrySecret = 1021
ThpQrCodeTag = 1024
ThpQrCodeSecret = 1025
ThpNfcUnidirectionalTag = 1032
ThpNfcUnideirectionalSecret = 1033
class FailureType(IntEnum):
UnexpectedMessage = 1

View File

@ -6166,6 +6166,202 @@ if TYPE_CHECKING:
def is_type_of(cls, msg: Any) -> TypeGuard["ThpNewSession"]:
return isinstance(msg, cls)
class ThpStartPairingRequest(protobuf.MessageType):
host_name: "bytes | None"
def __init__(
self,
*,
host_name: "bytes | None" = None,
) -> None:
pass
@classmethod
def is_type_of(cls, msg: Any) -> TypeGuard["ThpStartPairingRequest"]:
return isinstance(msg, cls)
class ThpCodeEntryCommitment(protobuf.MessageType):
commitment: "bytes | None"
def __init__(
self,
*,
commitment: "bytes | None" = None,
) -> None:
pass
@classmethod
def is_type_of(cls, msg: Any) -> TypeGuard["ThpCodeEntryCommitment"]:
return isinstance(msg, cls)
class ThpCodeEntryChallenge(protobuf.MessageType):
challenge: "bytes | None"
def __init__(
self,
*,
challenge: "bytes | None" = None,
) -> None:
pass
@classmethod
def is_type_of(cls, msg: Any) -> TypeGuard["ThpCodeEntryChallenge"]:
return isinstance(msg, cls)
class ThpCodeEntryCpaceHost(protobuf.MessageType):
cpace_host_public_key: "bytes | None"
def __init__(
self,
*,
cpace_host_public_key: "bytes | None" = None,
) -> None:
pass
@classmethod
def is_type_of(cls, msg: Any) -> TypeGuard["ThpCodeEntryCpaceHost"]:
return isinstance(msg, cls)
class ThpCodeEntryCpaceTrezor(protobuf.MessageType):
cpace_trezor_public_key: "bytes | None"
def __init__(
self,
*,
cpace_trezor_public_key: "bytes | None" = None,
) -> None:
pass
@classmethod
def is_type_of(cls, msg: Any) -> TypeGuard["ThpCodeEntryCpaceTrezor"]:
return isinstance(msg, cls)
class ThpCodeEntryTag(protobuf.MessageType):
tag: "bytes | None"
def __init__(
self,
*,
tag: "bytes | None" = None,
) -> None:
pass
@classmethod
def is_type_of(cls, msg: Any) -> TypeGuard["ThpCodeEntryTag"]:
return isinstance(msg, cls)
class ThpCodeEntrySecret(protobuf.MessageType):
secret: "bytes | None"
def __init__(
self,
*,
secret: "bytes | None" = None,
) -> None:
pass
@classmethod
def is_type_of(cls, msg: Any) -> TypeGuard["ThpCodeEntrySecret"]:
return isinstance(msg, cls)
class ThpQrCodeTag(protobuf.MessageType):
tag: "bytes | None"
def __init__(
self,
*,
tag: "bytes | None" = None,
) -> None:
pass
@classmethod
def is_type_of(cls, msg: Any) -> TypeGuard["ThpQrCodeTag"]:
return isinstance(msg, cls)
class ThpQrCodeSecret(protobuf.MessageType):
secret: "bytes | None"
def __init__(
self,
*,
secret: "bytes | None" = None,
) -> None:
pass
@classmethod
def is_type_of(cls, msg: Any) -> TypeGuard["ThpQrCodeSecret"]:
return isinstance(msg, cls)
class ThpNfcUnidirectionalTag(protobuf.MessageType):
tag: "bytes | None"
def __init__(
self,
*,
tag: "bytes | None" = None,
) -> None:
pass
@classmethod
def is_type_of(cls, msg: Any) -> TypeGuard["ThpNfcUnidirectionalTag"]:
return isinstance(msg, cls)
class ThpNfcUnideirectionalSecret(protobuf.MessageType):
secret: "bytes | None"
def __init__(
self,
*,
secret: "bytes | None" = None,
) -> None:
pass
@classmethod
def is_type_of(cls, msg: Any) -> TypeGuard["ThpNfcUnideirectionalSecret"]:
return isinstance(msg, cls)
class CredentialReq(protobuf.MessageType):
host_static_pubkey: "bytes | None"
def __init__(
self,
*,
host_static_pubkey: "bytes | None" = None,
) -> None:
pass
@classmethod
def is_type_of(cls, msg: Any) -> TypeGuard["CredentialReq"]:
return isinstance(msg, cls)
class CredentialResp(protobuf.MessageType):
trezor_static_pubkey: "bytes | None"
credential: "bytes | None"
def __init__(
self,
*,
trezor_static_pubkey: "bytes | None" = None,
credential: "bytes | None" = None,
) -> None:
pass
@classmethod
def is_type_of(cls, msg: Any) -> TypeGuard["CredentialResp"]:
return isinstance(msg, cls)
class EndReq(protobuf.MessageType):
@classmethod
def is_type_of(cls, msg: Any) -> TypeGuard["EndReq"]:
return isinstance(msg, cls)
class EndResp(protobuf.MessageType):
@classmethod
def is_type_of(cls, msg: Any) -> TypeGuard["EndResp"]:
return isinstance(msg, cls)
class WebAuthnListResidentCredentials(protobuf.MessageType):
@classmethod

View File

@ -23,15 +23,16 @@ reads the message's header. When the message type is known the first handler is
"""
from micropython import const
from typing import TYPE_CHECKING
from storage.cache_common import InvalidSessionError
from trezor import log, loop, protobuf, utils
from trezor.enums import FailureType
from trezor.messages import Failure
from trezor.wire import context, message_handler, protocol_common, thp_v1
from trezor.wire.errors import DataError, Error
from trezor.wire.message_handler import (
AVOID_RESTARTING_FOR,
WIRE_BUFFER,
WIRE_BUFFER_DEBUG,
failure,
)
# Import all errors into namespace, so that `wire.Error` is available from
# other packages.
@ -43,7 +44,6 @@ if TYPE_CHECKING:
from typing import (
Any,
Callable,
Container,
Coroutine,
TypeVar,
)
@ -66,35 +66,6 @@ def setup(iface: WireInterface, is_debug_session: bool = False) -> None:
loop.schedule(handle_session(iface, is_debug_session))
def wrap_protobuf_load(
buffer: bytes,
expected_type: type[LoadedMessageType],
) -> LoadedMessageType:
try:
msg = protobuf.decode(buffer, expected_type, EXPERIMENTAL_ENABLED)
if __debug__ and utils.EMULATOR:
log.debug(
__name__, "received message contents:\n%s", utils.dump_protobuf(msg)
)
return msg
except Exception as e:
if __debug__:
log.exception(__name__, e)
if e.args:
raise DataError("Failed to decode message: " + " ".join(e.args))
else:
raise DataError("Failed to decode message")
_PROTOBUF_BUFFER_SIZE = const(8192)
WIRE_BUFFER = bytearray(_PROTOBUF_BUFFER_SIZE)
if __debug__:
PROTOBUF_BUFFER_SIZE_DEBUG = 1024
WIRE_BUFFER_DEBUG = bytearray(PROTOBUF_BUFFER_SIZE_DEBUG)
async def handle_thp_session(iface: WireInterface, is_debug_session: bool = False):
if __debug__ and is_debug_session:
ctx_buffer = WIRE_BUFFER_DEBUG
@ -195,33 +166,3 @@ async def handle_session(iface: WireInterface, is_debug_session: bool = False) -
# loop.clear() above.
if __debug__:
log.exception(__name__, exc)
def _find_handler_placeholder(iface: WireInterface, msg_type: int) -> Handler | None:
"""Placeholder handler lookup before a proper one is registered."""
return None
find_handler = _find_handler_placeholder
AVOID_RESTARTING_FOR: Container[int] = ()
def failure(exc: BaseException) -> Failure:
if isinstance(exc, Error):
return Failure(code=exc.code, message=exc.message)
elif isinstance(exc, loop.TaskClosed):
return Failure(code=FailureType.ActionCancelled, message="Cancelled")
elif isinstance(exc, InvalidSessionError):
return Failure(code=FailureType.InvalidSession, message="Invalid session")
else:
# NOTE: when receiving generic `FirmwareError` on non-debug build,
# change the `if __debug__` to `if True` to get the full error message.
if __debug__:
message = str(exc)
else:
message = "Firmware error"
return Failure(code=FailureType.FirmwareError, message=message)
def unexpected_message() -> Failure:
return Failure(code=FailureType.UnexpectedMessage, message="Unexpected message")

View File

@ -125,7 +125,8 @@ class CodecContext(Context):
)
# look up the protobuf class and parse the message
from . import wrap_protobuf_load
from . import message_handler # noqa: F401
from .message_handler import wrap_protobuf_load
return wrap_protobuf_load(msg.data, expected_type)

View File

@ -86,15 +86,20 @@ async def handle_single_message(
msg_type = f"{msg.type} - unknown message type"
if ctx.channel_id is not None:
sid = int.from_bytes(ctx.channel_id, "big")
log.debug(
__name__,
"%s:%x receive: <%s>",
ctx.iface.iface_num(),
sid,
msg_type,
)
else:
sid = -1
log.debug(
__name__,
"%s:%x receive: <%s>",
ctx.iface.iface_num(),
sid,
msg_type,
)
log.debug(
__name__,
"%s:unknown_sid receive: <%s>",
ctx.iface.iface_num(),
msg_type,
)
res_msg: protobuf.MessageType | None = None

View File

@ -14,7 +14,7 @@ class ChannelState(IntEnum):
TP2 = 4
TP3 = 5
TP4 = 6
TP5 = 7
TC1 = 7
ENCRYPTED_TRANSPORT = 8

View File

@ -7,11 +7,7 @@ from storage import cache_thp
from storage.cache_thp import KEY_LENGTH, SESSION_ID_LENGTH, TAG_LENGTH, ChannelCache
from trezor import log, loop, protobuf, utils
from trezor.enums import FailureType, MessageType # , ThpPairingMethod
from trezor.messages import (
Failure,
ThpCreateNewSession,
ThpNewSession,
)
from trezor.messages import Failure, ThpCreateNewSession, ThpNewSession
from trezor.wire import message_handler
from trezor.wire.thp import ack_handler, thp_messages

View File

@ -0,0 +1,199 @@
from typing import TYPE_CHECKING # pyright: ignore[reportShadowedImports]
from trezor import log, loop, protobuf, workflow
from trezor.messages import ThpStartPairingRequest
from trezor.wire import message_handler, protocol_common
from trezor.wire.context import UnexpectedMessageWithId
from trezor.wire.errors import ActionCancelled
from trezor.wire.protocol_common import MessageWithType
from trezor.wire.thp.session_context import UnexpectedMessageWithType
from apps.thp.pairing import handle_pairing_request
from .channel import Channel
if TYPE_CHECKING:
from typing import Container # pyright:ignore[reportShadowedImports]
pass
class PairingContext:
def __init__(self, channel: Channel) -> None:
self.channel = channel
self.incoming_message = loop.chan()
async def handle(self, is_debug_session: bool = False) -> None:
if __debug__:
log.debug(__name__, "handle - start")
if is_debug_session:
import apps.debug
apps.debug.DEBUG_CONTEXT = self
take = self.incoming_message.take()
next_message: MessageWithType | None = None
# Take a mark of modules that are imported at this point, so we can
# roll back and un-import any others.
# TODO modules = utils.unimport_begin()
while True:
try:
if next_message is None:
# If the previous run did not keep an unprocessed message for us,
# wait for a new one.
try:
message: MessageWithType = await take
except protocol_common.WireError as e:
if __debug__:
log.exception(__name__, e)
await self.write(message_handler.failure(e))
continue
else:
# Process the message from previous run.
message = next_message
next_message = None
try:
next_message = await handle_pairing_message(
self, message, use_workflow=not is_debug_session
)
except Exception as exc:
# Log and ignore. The session handler can only exit explicitly in the
# following finally block.
if __debug__:
log.exception(__name__, exc)
finally:
if not __debug__ or not is_debug_session:
# Unload modules imported by the workflow. Should not raise.
# This is not done for the debug session because the snapshot taken
# in a debug session would clear modules which are in use by the
# workflow running on wire.
# TODO utils.unimport_end(modules)
if next_message is None:
# Shut down the loop if there is no next message waiting.
# Let the session be restarted from `main`.
loop.clear()
return # pylint: disable=lost-exception
except Exception as exc:
# Log and try again. The session handler can only exit explicitly via
# loop.clear() above.
if __debug__:
log.exception(__name__, exc)
async def read(
self,
expected_types: Container[int],
expected_type: type[protobuf.MessageType] | None = None,
) -> protobuf.MessageType:
if __debug__:
exp_type: str = str(expected_type)
if expected_type is not None:
exp_type = expected_type.MESSAGE_NAME
log.debug(
__name__,
"Read - with expected types %s and expected type %s",
str(expected_types),
exp_type,
)
message: MessageWithType = await self.incoming_message.take()
if message.type not in expected_types:
raise UnexpectedMessageWithType(message)
if expected_type is None:
expected_type = protobuf.type_for_wire(message.type)
return message_handler.wrap_protobuf_load(message.data, expected_type)
async def write(self, msg: protobuf.MessageType) -> None:
return await self.channel.write(msg)
async def handle_pairing_message(
ctx: PairingContext, msg: protocol_common.MessageWithType, use_workflow: bool
) -> protocol_common.MessageWithType | None:
res_msg: protobuf.MessageType | None = None
# We need to find a handler for this message type. Should not raise.
# TODO register handlers to dict
handler = get_handler(msg.type) # pylint: disable=assignment-from-none
if handler is None:
# If no handler is found, we can skip decoding and directly
# respond with failure.
await ctx.write(message_handler.unexpected_message())
return None
if msg.type in workflow.ALLOW_WHILE_LOCKED:
workflow.autolock_interrupts_workflow = False
# Here we make sure we always respond with a Failure response
# in case of any errors.
try:
# Find a protobuf.MessageType subclass that describes this
# message. Raises if the type is not found.
req_type = protobuf.type_for_wire(msg.type)
# Try to decode the message according to schema from
# `req_type`. Raises if the message is malformed.
req_msg = message_handler.wrap_protobuf_load(msg.data, req_type)
# Create the handler task.
if TYPE_CHECKING:
assert isinstance(req_msg, ThpStartPairingRequest) # TODO remove
task = handler(ctx.channel, req_msg)
# Run the workflow task. Workflow can do more on-the-wire
# communication inside, but it should eventually return a
# response message, or raise an exception (a rather common
# thing to do). Exceptions are handled in the code below.
if use_workflow:
# Spawn a workflow around the task. This ensures that concurrent
# workflows are shut down.
# res_msg = await workflow.spawn(context.with_context(ctx, task))
pass # TODO
else:
# For debug messages, ignore workflow processing and just await
# results of the handler.
res_msg = await task
except UnexpectedMessageWithId as exc:
# Workflow was trying to read a message from the wire, and
# something unexpected came in. See Context.read() for
# example, which expects some particular message and raises
# UnexpectedMessage if another one comes in.
# In order not to lose the message, we return it to the caller.
# TODO:
# We might handle only the few common cases here, like
# Initialize and Cancel.
return exc.msg
except BaseException as exc:
# Either:
# - the message had a type that has a registered handler, but does not have
# a protobuf class
# - the message was not valid protobuf
# - workflow raised some kind of an exception while running
# - something canceled the workflow from the outside
if __debug__:
if isinstance(exc, ActionCancelled):
log.debug(__name__, "cancelled: %s", exc.message)
elif isinstance(exc, loop.TaskClosed):
log.debug(__name__, "cancelled: loop task was closed")
else:
log.exception(__name__, exc)
res_msg = message_handler.failure(exc)
if res_msg is not None:
# perform the write outside the big try-except block, so that usb write
# problem bubbles up
await ctx.write(res_msg)
return None
def get_handler(messageType: int):
return handle_pairing_request

View File

@ -3,7 +3,8 @@ from typing import TYPE_CHECKING # pyright: ignore[reportShadowedImports]
from storage import cache_thp
from storage.cache_thp import SessionThpCache
from trezor import log, loop, protobuf
from trezor.wire import AVOID_RESTARTING_FOR, failure, message_handler, protocol_common
from trezor.wire import message_handler, protocol_common
from trezor.wire.message_handler import AVOID_RESTARTING_FOR, failure
from ..protocol_common import Context, MessageWithType
from . import SessionState
@ -34,7 +35,7 @@ class SessionContext(Context):
"The session has different channel id than the provided channel context!"
)
super().__init__(channel.iface, channel.channel_id)
self.channel_context = channel
self.channel = channel
self.session_cache = session_cache
self.session_id = int.from_bytes(session_cache.session_id, "big")
self.incoming_message = loop.chan()
@ -132,7 +133,7 @@ class SessionContext(Context):
return message_handler.wrap_protobuf_load(message.data, expected_type)
async def write(self, msg: protobuf.MessageType) -> None:
return await self.channel_context.write(msg, self.session_id)
return await self.channel.write(msg, self.session_id)
# ACCESS TO SESSION DATA

View File

@ -22,7 +22,7 @@ _MAX_CID_REQ_PAYLOAD_LENGTH = const(12) # TODO set to reasonable value
_BUFFER: bytearray
_BUFFER_LOCK = None
_CHANNEL_CONTEXTS: dict[int, Channel] = {}
CHANNELS: dict[int, Channel] = {}
def set_buffer(buffer):
@ -31,9 +31,9 @@ def set_buffer(buffer):
async def thp_main_loop(iface: WireInterface, is_debug_session=False):
global _CHANNEL_CONTEXTS
global CHANNELS
global _BUFFER
_CHANNEL_CONTEXTS = load_cached_channels(_BUFFER)
CHANNELS = load_cached_channels(_BUFFER)
read = loop.wait(iface.iface_num() | io.POLL_READ)
@ -55,8 +55,8 @@ async def thp_main_loop(iface: WireInterface, is_debug_session=False):
await _handle_broadcast(iface, ctrl_byte, packet)
continue
if cid in _CHANNEL_CONTEXTS:
channel = _CHANNEL_CONTEXTS[cid]
if cid in CHANNELS:
channel = CHANNELS[cid]
if channel is None:
# TODO send error message to wire
raise ThpError("Invalid state of a channel")
@ -94,7 +94,7 @@ async def _handle_broadcast(
new_context: Channel = Channel.create_new_channel(iface, _BUFFER)
cid = int.from_bytes(new_context.channel_id, "big")
_CHANNEL_CONTEXTS[cid] = new_context
CHANNELS[cid] = new_context
response_data = thp_messages.get_channel_allocation_response(
nonce, new_context.channel_id

View File

@ -280,6 +280,16 @@ class MessageType(IntEnum):
ThpEndResponse = 1005
ThpCreateNewSession = 1006
ThpNewSession = 1007
ThpCodeEntryCommitment = 1016
ThpCodeEntryChallenge = 1017
ThpCodeEntryCpaceHost = 1018
ThpCodeEntryCpaceTrezor = 1019
ThpCodeEntryTag = 1020
ThpCodeEntrySecret = 1021
ThpQrCodeTag = 1024
ThpQrCodeSecret = 1025
ThpNfcUnidirectionalTag = 1032
ThpNfcUnideirectionalSecret = 1033
class FailureType(IntEnum):
@ -7792,6 +7802,199 @@ class ThpNewSession(protobuf.MessageType):
self.new_session_id = new_session_id
class ThpStartPairingRequest(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 1000
FIELDS = {
1: protobuf.Field("host_name", "bytes", repeated=False, required=False, default=None),
}
def __init__(
self,
*,
host_name: Optional["bytes"] = None,
) -> None:
self.host_name = host_name
class ThpCodeEntryCommitment(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 1016
FIELDS = {
1: protobuf.Field("commitment", "bytes", repeated=False, required=False, default=None),
}
def __init__(
self,
*,
commitment: Optional["bytes"] = None,
) -> None:
self.commitment = commitment
class ThpCodeEntryChallenge(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 1017
FIELDS = {
1: protobuf.Field("challenge", "bytes", repeated=False, required=False, default=None),
}
def __init__(
self,
*,
challenge: Optional["bytes"] = None,
) -> None:
self.challenge = challenge
class ThpCodeEntryCpaceHost(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 1018
FIELDS = {
1: protobuf.Field("cpace_host_public_key", "bytes", repeated=False, required=False, default=None),
}
def __init__(
self,
*,
cpace_host_public_key: Optional["bytes"] = None,
) -> None:
self.cpace_host_public_key = cpace_host_public_key
class ThpCodeEntryCpaceTrezor(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 1019
FIELDS = {
1: protobuf.Field("cpace_trezor_public_key", "bytes", repeated=False, required=False, default=None),
}
def __init__(
self,
*,
cpace_trezor_public_key: Optional["bytes"] = None,
) -> None:
self.cpace_trezor_public_key = cpace_trezor_public_key
class ThpCodeEntryTag(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 1020
FIELDS = {
2: protobuf.Field("tag", "bytes", repeated=False, required=False, default=None),
}
def __init__(
self,
*,
tag: Optional["bytes"] = None,
) -> None:
self.tag = tag
class ThpCodeEntrySecret(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 1021
FIELDS = {
1: protobuf.Field("secret", "bytes", repeated=False, required=False, default=None),
}
def __init__(
self,
*,
secret: Optional["bytes"] = None,
) -> None:
self.secret = secret
class ThpQrCodeTag(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 1024
FIELDS = {
1: protobuf.Field("tag", "bytes", repeated=False, required=False, default=None),
}
def __init__(
self,
*,
tag: Optional["bytes"] = None,
) -> None:
self.tag = tag
class ThpQrCodeSecret(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 1025
FIELDS = {
1: protobuf.Field("secret", "bytes", repeated=False, required=False, default=None),
}
def __init__(
self,
*,
secret: Optional["bytes"] = None,
) -> None:
self.secret = secret
class ThpNfcUnidirectionalTag(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 1032
FIELDS = {
1: protobuf.Field("tag", "bytes", repeated=False, required=False, default=None),
}
def __init__(
self,
*,
tag: Optional["bytes"] = None,
) -> None:
self.tag = tag
class ThpNfcUnideirectionalSecret(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 1033
FIELDS = {
1: protobuf.Field("secret", "bytes", repeated=False, required=False, default=None),
}
def __init__(
self,
*,
secret: Optional["bytes"] = None,
) -> None:
self.secret = secret
class CredentialReq(protobuf.MessageType):
MESSAGE_WIRE_TYPE = None
FIELDS = {
1: protobuf.Field("host_static_pubkey", "bytes", repeated=False, required=False, default=None),
}
def __init__(
self,
*,
host_static_pubkey: Optional["bytes"] = None,
) -> None:
self.host_static_pubkey = host_static_pubkey
class CredentialResp(protobuf.MessageType):
MESSAGE_WIRE_TYPE = None
FIELDS = {
1: protobuf.Field("trezor_static_pubkey", "bytes", repeated=False, required=False, default=None),
2: protobuf.Field("credential", "bytes", repeated=False, required=False, default=None),
}
def __init__(
self,
*,
trezor_static_pubkey: Optional["bytes"] = None,
credential: Optional["bytes"] = None,
) -> None:
self.trezor_static_pubkey = trezor_static_pubkey
self.credential = credential
class EndReq(protobuf.MessageType):
MESSAGE_WIRE_TYPE = None
class EndResp(protobuf.MessageType):
MESSAGE_WIRE_TYPE = None
class WebAuthnListResidentCredentials(protobuf.MessageType):
MESSAGE_WIRE_TYPE = 800

View File

@ -90,6 +90,16 @@ trezor_message_impl! {
ThpEndResponse => MessageType_ThpEndResponse,
ThpCreateNewSession => MessageType_ThpCreateNewSession,
ThpNewSession => MessageType_ThpNewSession,
ThpCodeEntryCommitment => MessageType_ThpCodeEntryCommitment,
ThpCodeEntryChallenge => MessageType_ThpCodeEntryChallenge,
ThpCodeEntryCpaceHost => MessageType_ThpCodeEntryCpaceHost,
ThpCodeEntryCpaceTrezor => MessageType_ThpCodeEntryCpaceTrezor,
ThpCodeEntryTag => MessageType_ThpCodeEntryTag,
ThpCodeEntrySecret => MessageType_ThpCodeEntrySecret,
ThpQrCodeTag => MessageType_ThpQrCodeTag,
ThpQrCodeSecret => MessageType_ThpQrCodeSecret,
ThpNfcUnidirectionalTag => MessageType_ThpNfcUnidirectionalTag,
ThpNfcUnideirectionalSecret => MessageType_ThpNfcUnideirectionalSecret,
}
#[cfg(feature = "binance")]

View File

@ -530,6 +530,26 @@ pub enum MessageType {
MessageType_ThpCreateNewSession = 1006,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_ThpNewSession)
MessageType_ThpNewSession = 1007,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_ThpCodeEntryCommitment)
MessageType_ThpCodeEntryCommitment = 1016,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_ThpCodeEntryChallenge)
MessageType_ThpCodeEntryChallenge = 1017,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_ThpCodeEntryCpaceHost)
MessageType_ThpCodeEntryCpaceHost = 1018,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_ThpCodeEntryCpaceTrezor)
MessageType_ThpCodeEntryCpaceTrezor = 1019,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_ThpCodeEntryTag)
MessageType_ThpCodeEntryTag = 1020,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_ThpCodeEntrySecret)
MessageType_ThpCodeEntrySecret = 1021,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_ThpQrCodeTag)
MessageType_ThpQrCodeTag = 1024,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_ThpQrCodeSecret)
MessageType_ThpQrCodeSecret = 1025,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_ThpNfcUnidirectionalTag)
MessageType_ThpNfcUnidirectionalTag = 1032,
// @@protoc_insertion_point(enum_value:hw.trezor.messages.MessageType.MessageType_ThpNfcUnideirectionalSecret)
MessageType_ThpNfcUnideirectionalSecret = 1033,
}
impl ::protobuf::Enum for MessageType {
@ -792,6 +812,16 @@ impl ::protobuf::Enum for MessageType {
1005 => ::std::option::Option::Some(MessageType::MessageType_ThpEndResponse),
1006 => ::std::option::Option::Some(MessageType::MessageType_ThpCreateNewSession),
1007 => ::std::option::Option::Some(MessageType::MessageType_ThpNewSession),
1016 => ::std::option::Option::Some(MessageType::MessageType_ThpCodeEntryCommitment),
1017 => ::std::option::Option::Some(MessageType::MessageType_ThpCodeEntryChallenge),
1018 => ::std::option::Option::Some(MessageType::MessageType_ThpCodeEntryCpaceHost),
1019 => ::std::option::Option::Some(MessageType::MessageType_ThpCodeEntryCpaceTrezor),
1020 => ::std::option::Option::Some(MessageType::MessageType_ThpCodeEntryTag),
1021 => ::std::option::Option::Some(MessageType::MessageType_ThpCodeEntrySecret),
1024 => ::std::option::Option::Some(MessageType::MessageType_ThpQrCodeTag),
1025 => ::std::option::Option::Some(MessageType::MessageType_ThpQrCodeSecret),
1032 => ::std::option::Option::Some(MessageType::MessageType_ThpNfcUnidirectionalTag),
1033 => ::std::option::Option::Some(MessageType::MessageType_ThpNfcUnideirectionalSecret),
_ => ::std::option::Option::None
}
}
@ -1049,6 +1079,16 @@ impl ::protobuf::Enum for MessageType {
"MessageType_ThpEndResponse" => ::std::option::Option::Some(MessageType::MessageType_ThpEndResponse),
"MessageType_ThpCreateNewSession" => ::std::option::Option::Some(MessageType::MessageType_ThpCreateNewSession),
"MessageType_ThpNewSession" => ::std::option::Option::Some(MessageType::MessageType_ThpNewSession),
"MessageType_ThpCodeEntryCommitment" => ::std::option::Option::Some(MessageType::MessageType_ThpCodeEntryCommitment),
"MessageType_ThpCodeEntryChallenge" => ::std::option::Option::Some(MessageType::MessageType_ThpCodeEntryChallenge),
"MessageType_ThpCodeEntryCpaceHost" => ::std::option::Option::Some(MessageType::MessageType_ThpCodeEntryCpaceHost),
"MessageType_ThpCodeEntryCpaceTrezor" => ::std::option::Option::Some(MessageType::MessageType_ThpCodeEntryCpaceTrezor),
"MessageType_ThpCodeEntryTag" => ::std::option::Option::Some(MessageType::MessageType_ThpCodeEntryTag),
"MessageType_ThpCodeEntrySecret" => ::std::option::Option::Some(MessageType::MessageType_ThpCodeEntrySecret),
"MessageType_ThpQrCodeTag" => ::std::option::Option::Some(MessageType::MessageType_ThpQrCodeTag),
"MessageType_ThpQrCodeSecret" => ::std::option::Option::Some(MessageType::MessageType_ThpQrCodeSecret),
"MessageType_ThpNfcUnidirectionalTag" => ::std::option::Option::Some(MessageType::MessageType_ThpNfcUnidirectionalTag),
"MessageType_ThpNfcUnideirectionalSecret" => ::std::option::Option::Some(MessageType::MessageType_ThpNfcUnideirectionalSecret),
_ => ::std::option::Option::None
}
}
@ -1305,6 +1345,16 @@ impl ::protobuf::Enum for MessageType {
MessageType::MessageType_ThpEndResponse,
MessageType::MessageType_ThpCreateNewSession,
MessageType::MessageType_ThpNewSession,
MessageType::MessageType_ThpCodeEntryCommitment,
MessageType::MessageType_ThpCodeEntryChallenge,
MessageType::MessageType_ThpCodeEntryCpaceHost,
MessageType::MessageType_ThpCodeEntryCpaceTrezor,
MessageType::MessageType_ThpCodeEntryTag,
MessageType::MessageType_ThpCodeEntrySecret,
MessageType::MessageType_ThpQrCodeTag,
MessageType::MessageType_ThpQrCodeSecret,
MessageType::MessageType_ThpNfcUnidirectionalTag,
MessageType::MessageType_ThpNfcUnideirectionalSecret,
];
}
@ -1567,6 +1617,16 @@ impl ::protobuf::EnumFull for MessageType {
MessageType::MessageType_ThpEndResponse => 248,
MessageType::MessageType_ThpCreateNewSession => 249,
MessageType::MessageType_ThpNewSession => 250,
MessageType::MessageType_ThpCodeEntryCommitment => 251,
MessageType::MessageType_ThpCodeEntryChallenge => 252,
MessageType::MessageType_ThpCodeEntryCpaceHost => 253,
MessageType::MessageType_ThpCodeEntryCpaceTrezor => 254,
MessageType::MessageType_ThpCodeEntryTag => 255,
MessageType::MessageType_ThpCodeEntrySecret => 256,
MessageType::MessageType_ThpQrCodeTag => 257,
MessageType::MessageType_ThpQrCodeSecret => 258,
MessageType::MessageType_ThpNfcUnidirectionalTag => 259,
MessageType::MessageType_ThpNfcUnideirectionalSecret => 260,
};
Self::enum_descriptor().value_by_index(index)
}
@ -1616,7 +1676,7 @@ pub mod exts {
static file_descriptor_proto_data: &'static [u8] = b"\
\n\x0emessages.proto\x12\x12hw.trezor.messages\x1a\x20google/protobuf/de\
scriptor.proto*\x93W\n\x0bMessageType\x12(\n\x16MessageType_Initialize\
scriptor.proto*\xfaZ\n\x0bMessageType\x12(\n\x16MessageType_Initialize\
\x10\0\x1a\x0c\x80\xa6\x1d\x01\xb0\xb5\x18\x01\x90\xb5\x18\x01\x12\x1e\n\
\x10MessageType_Ping\x10\x01\x1a\x08\x80\xa6\x1d\x01\x90\xb5\x18\x01\x12\
%\n\x13MessageType_Success\x10\x02\x1a\x0c\x80\xa6\x1d\x01\xa8\xb5\x18\
@ -1901,30 +1961,43 @@ static file_descriptor_proto_data: &'static [u8] = b"\
\x12)\n\x1aMessageType_ThpEndResponse\x10\xed\x07\x1a\x08\x80\xa6\x1d\
\x01\x98\xb5\x18\x01\x12.\n\x1fMessageType_ThpCreateNewSession\x10\xee\
\x07\x1a\x08\x80\xa6\x1d\x01\x90\xb5\x18\x01\x12(\n\x19MessageType_ThpNe\
wSession\x10\xef\x07\x1a\x08\x80\xa6\x1d\x01\x98\xb5\x18\x01\x1a\x04\xc8\
\xf3\x18\x01\"\x04\x08Z\x10\\\"\x04\x08r\x10z\"\x06\x08\xdb\x01\x10\xdb\
\x01\"\x06\x08\xe0\x01\x10\xe0\x01\"\x06\x08\xac\x02\x10\xb0\x02\"\x06\
\x08\xb5\x02\x10\xb8\x02:<\n\x07wire_in\x18\xd2\x86\x03\x20\x01(\x08\x12\
!.google.protobuf.EnumValueOptionsR\x06wireIn:>\n\x08wire_out\x18\xd3\
\x86\x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptionsR\x07wireOut:\
G\n\rwire_debug_in\x18\xd4\x86\x03\x20\x01(\x08\x12!.google.protobuf.Enu\
mValueOptionsR\x0bwireDebugIn:I\n\x0ewire_debug_out\x18\xd5\x86\x03\x20\
\x01(\x08\x12!.google.protobuf.EnumValueOptionsR\x0cwireDebugOut:@\n\twi\
re_tiny\x18\xd6\x86\x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptio\
nsR\x08wireTiny:L\n\x0fwire_bootloader\x18\xd7\x86\x03\x20\x01(\x08\x12!\
.google.protobuf.EnumValueOptionsR\x0ewireBootloader:C\n\x0bwire_no_fsm\
\x18\xd8\x86\x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptionsR\twi\
reNoFsm:F\n\x0cbitcoin_only\x18\xe0\xd4\x03\x20\x01(\x08\x12!.google.pro\
tobuf.EnumValueOptionsR\x0bbitcoinOnly:U\n\x17has_bitcoin_only_values\
\x18\xb9\x8e\x03\x20\x01(\x08\x12\x1c.google.protobuf.EnumOptionsR\x14ha\
sBitcoinOnlyValues:T\n\x14experimental_message\x18\xa1\x96\x03\x20\x01(\
\x08\x12\x1f.google.protobuf.MessageOptionsR\x13experimentalMessage:>\n\
\twire_type\x18\xa2\x96\x03\x20\x01(\r\x12\x1f.google.protobuf.MessageOp\
tionsR\x08wireType:N\n\x12experimental_field\x18\x89\x9e\x03\x20\x01(\
\x08\x12\x1d.google.protobuf.FieldOptionsR\x11experimentalField:U\n\x17i\
nclude_in_bitcoin_only\x18\xe0\xd4\x03\x20\x01(\x08\x12\x1c.google.proto\
buf.FileOptionsR\x14includeInBitcoinOnlyB8\n#com.satoshilabs.trezor.lib.\
protobufB\rTrezorMessage\x80\xa6\x1d\x01\
wSession\x10\xef\x07\x1a\x08\x80\xa6\x1d\x01\x98\xb5\x18\x01\x121\n\"Mes\
sageType_ThpCodeEntryCommitment\x10\xf8\x07\x1a\x08\x80\xa6\x1d\x01\x98\
\xb5\x18\x01\x120\n!MessageType_ThpCodeEntryChallenge\x10\xf9\x07\x1a\
\x08\x80\xa6\x1d\x01\x90\xb5\x18\x01\x120\n!MessageType_ThpCodeEntryCpac\
eHost\x10\xfa\x07\x1a\x08\x80\xa6\x1d\x01\x90\xb5\x18\x01\x122\n#Message\
Type_ThpCodeEntryCpaceTrezor\x10\xfb\x07\x1a\x08\x80\xa6\x1d\x01\x98\xb5\
\x18\x01\x12*\n\x1bMessageType_ThpCodeEntryTag\x10\xfc\x07\x1a\x08\x80\
\xa6\x1d\x01\x90\xb5\x18\x01\x12-\n\x1eMessageType_ThpCodeEntrySecret\
\x10\xfd\x07\x1a\x08\x80\xa6\x1d\x01\x98\xb5\x18\x01\x12'\n\x18MessageTy\
pe_ThpQrCodeTag\x10\x80\x08\x1a\x08\x80\xa6\x1d\x01\x90\xb5\x18\x01\x12*\
\n\x1bMessageType_ThpQrCodeSecret\x10\x81\x08\x1a\x08\x80\xa6\x1d\x01\
\x98\xb5\x18\x01\x122\n#MessageType_ThpNfcUnidirectionalTag\x10\x88\x08\
\x1a\x08\x80\xa6\x1d\x01\x90\xb5\x18\x01\x126\n'MessageType_ThpNfcUnidei\
rectionalSecret\x10\x89\x08\x1a\x08\x80\xa6\x1d\x01\x90\xb5\x18\x01\x1a\
\x04\xc8\xf3\x18\x01\"\x04\x08Z\x10\\\"\x04\x08r\x10z\"\x06\x08\xdb\x01\
\x10\xdb\x01\"\x06\x08\xe0\x01\x10\xe0\x01\"\x06\x08\xac\x02\x10\xb0\x02\
\"\x06\x08\xb5\x02\x10\xb8\x02:<\n\x07wire_in\x18\xd2\x86\x03\x20\x01(\
\x08\x12!.google.protobuf.EnumValueOptionsR\x06wireIn:>\n\x08wire_out\
\x18\xd3\x86\x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptionsR\x07\
wireOut:G\n\rwire_debug_in\x18\xd4\x86\x03\x20\x01(\x08\x12!.google.prot\
obuf.EnumValueOptionsR\x0bwireDebugIn:I\n\x0ewire_debug_out\x18\xd5\x86\
\x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOptionsR\x0cwireDebugOut\
:@\n\twire_tiny\x18\xd6\x86\x03\x20\x01(\x08\x12!.google.protobuf.EnumVa\
lueOptionsR\x08wireTiny:L\n\x0fwire_bootloader\x18\xd7\x86\x03\x20\x01(\
\x08\x12!.google.protobuf.EnumValueOptionsR\x0ewireBootloader:C\n\x0bwir\
e_no_fsm\x18\xd8\x86\x03\x20\x01(\x08\x12!.google.protobuf.EnumValueOpti\
onsR\twireNoFsm:F\n\x0cbitcoin_only\x18\xe0\xd4\x03\x20\x01(\x08\x12!.go\
ogle.protobuf.EnumValueOptionsR\x0bbitcoinOnly:U\n\x17has_bitcoin_only_v\
alues\x18\xb9\x8e\x03\x20\x01(\x08\x12\x1c.google.protobuf.EnumOptionsR\
\x14hasBitcoinOnlyValues:T\n\x14experimental_message\x18\xa1\x96\x03\x20\
\x01(\x08\x12\x1f.google.protobuf.MessageOptionsR\x13experimentalMessage\
:>\n\twire_type\x18\xa2\x96\x03\x20\x01(\r\x12\x1f.google.protobuf.Messa\
geOptionsR\x08wireType:N\n\x12experimental_field\x18\x89\x9e\x03\x20\x01\
(\x08\x12\x1d.google.protobuf.FieldOptionsR\x11experimentalField:U\n\x17\
include_in_bitcoin_only\x18\xe0\xd4\x03\x20\x01(\x08\x12\x1c.google.prot\
obuf.FileOptionsR\x14includeInBitcoinOnlyB8\n#com.satoshilabs.trezor.lib\
.protobufB\rTrezorMessage\x80\xa6\x1d\x01\
";
/// `FileDescriptorProto` object which was a source for this generated file

File diff suppressed because it is too large Load Diff