refactor(python): don't return SEQ bit for irrelevant THP messages
What changed, and why it matters
This is a small code cleanup in Trezor's Python library for a newer transport protocol (THP). It changes a helper function so it returns 'no sequence bit' for message types that don't carry one, and adds an assertion to catch any unexpected case. The change is labeled a refactor with no changelog and appears defensive rather than a fix for an active security bug.
Treat as a low-risk hardening/refactoring commit. Reviewers may want to confirm that all callers of `get_seq_bit()` handle `None` correctly, and that the `0xE0` mask accurately covers all message types that lack a SEQ bit in the THP specification. No urgent action is indicated by the commit itself.
Security signals we found
Defensive assertion added to enforce expected control-byte semantics
Refactor of protocol control-byte parsing to avoid returning sequence bits for non-sequenced message types
No changelog and no explicit security framing by the vendor
Evidence from the diff
The commit modifies control_byte.get_seq_bit() to return None when the upper three bits of the control byte are set (i.e., ctrl_byte & 0xE0), indicating the message type does not contain a SEQ bit. Callers in protocol_v2.py now assert the result is not None before using it. This prevents the function from returning a misleading sequence-bit value for irrelevant THP messages and makes the protocol handling more explicit. There is no direct evidence in the diff of a vulnerability being exploited; it reads as a hardening/refactoring change.
Changed components
python/src/trezorlib/transport/thp/control_byte.pypython/src/trezorlib/transport/thp/protocol_v2.pyInspect captured patch +11 / −3
diff --git a/python/src/trezorlib/transport/thp/control_byte.py b/python/src/trezorlib/transport/thp/control_byte.py
index 01d9ad07..59bc0ea8 100644
--- a/python/src/trezorlib/transport/thp/control_byte.py
+++ b/python/src/trezorlib/transport/thp/control_byte.py
@@ -14,6 +14,8 @@
# 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>.
+from typing import Optional
+
CODEC_V1 = 0x3F
CONTINUATION_PACKET = 0x80
HANDSHAKE_INIT_REQ = 0x00
@@ -51,7 +53,11 @@ def add_ack_bit_to_ctrl_byte(ctrl_byte: int, ack_bit: int) -> int:
raise Exception("Unexpected acknowledgement bit")
-def get_seq_bit(ctrl_byte: int) -> int:
+def get_seq_bit(ctrl_byte: int) -> Optional[int]:
+ if ctrl_byte & 0xE0:
+ # not all message types contain SEQ bit
+ return None
+
return (ctrl_byte & 0x10) >> 4
diff --git a/python/src/trezorlib/transport/thp/protocol_v2.py b/python/src/trezorlib/transport/thp/protocol_v2.py
index 6573d697..c1c44695 100644
--- a/python/src/trezorlib/transport/thp/protocol_v2.py
+++ b/python/src/trezorlib/transport/thp/protocol_v2.py
@@ -350,13 +350,15 @@ class ProtocolV2Channel(Channel):
+ ")"
)
+ seq_bit = control_byte.get_seq_bit(header.ctrl_byte)
+ assert seq_bit is not None
LOG.debug(
"--> Get sequence bit %d %s %s",
- control_byte.get_seq_bit(header.ctrl_byte),
+ seq_bit,
"from control byte",
hexlify(header.ctrl_byte.to_bytes(1, "big")).decode(),
)
- self._send_ack_bit(bit=control_byte.get_seq_bit(header.ctrl_byte))
+ self._send_ack_bit(bit=seq_bit)
message = self._noise.decrypt(bytes(raw_payload))
session_id = message[0]
Why this scored 17/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.