Skip to content

Commit 15b681b

Browse files
committed
fixup! WIP: switch THP to rust/trezor-thp
1 parent 8bde9b7 commit 15b681b

6 files changed

Lines changed: 43 additions & 37 deletions

File tree

core/embed/rust/src/crypto/mod.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,10 @@ impl From<Error> for crate::error::Error {
3535
}
3636
}
3737

38-
/// Constant time bytestring comparison. Panics if the parameters don't have the
39-
/// same length.
40-
pub fn consteq(a: &[u8], b: &[u8]) -> bool {
41-
ensure!(a.len() == b.len(), "Invalid paramter lengths");
38+
/// Constant time bytestring comparison for two arrays of the same length.
39+
pub fn consteq<const N: usize>(a: &[u8; N], b: &[u8; N]) -> bool {
4240
let mut diff: u8 = 0;
43-
for i in 0..a.len() {
41+
for i in 0..N {
4442
diff |= a[i] ^ b[i];
4543
}
4644
diff == 0

core/embed/rust/src/thp/crypto.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ impl Cipher for TrezorCryptoAesGcm {
132132
let mut full_nonce = [0u8; 12];
133133
full_nonce[4..].copy_from_slice(&nonce.to_be_bytes());
134134

135-
out.copy_from_slice(&ciphertext[..out.len()]);
136-
let tag = &ciphertext[out.len()..];
135+
let (ciphertext, tag) = unwrap!(ciphertext.split_last_chunk::<{ aesgcm::TAG_SIZE }>());
136+
out.copy_from_slice(ciphertext);
137137

138138
init_ctx!(aesgcm::AesGcm, ctx, key.as_slice(), &full_nonce);
139139
let mut ctx = unwrap!(ctx);
@@ -160,7 +160,8 @@ impl Cipher for TrezorCryptoAesGcm {
160160
let mut full_nonce = [0u8; 12];
161161
full_nonce[4..].copy_from_slice(&nonce.to_be_bytes());
162162

163-
let (in_out, tag) = in_out[..ciphertext_len].split_at_mut(ciphertext_len - 16);
163+
let in_out = &mut in_out[..ciphertext_len];
164+
let (in_out, tag) = unwrap!(in_out.split_last_chunk_mut::<{ aesgcm::TAG_SIZE }>());
164165

165166
init_ctx!(aesgcm::AesGcm, ctx, key.as_slice(), &full_nonce);
166167
let mut ctx = unwrap!(ctx);

core/embed/rust/src/thp/mod.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,13 @@ impl InterfaceContext {
405405
return Err(CHANNEL_NOT_FOUND);
406406
};
407407
match retry {
408+
None => {
409+
log::error!(
410+
"[{:04x}] Requested to retransmit but not currently sending.",
411+
channel_id
412+
);
413+
Ok(true)
414+
}
408415
Some(r) if r > MAX_RETRANSMISSION_COUNT => {
409416
log::warn!(
410417
"[{:04x}] Closing channel after too many retransmissions.",
@@ -413,15 +420,9 @@ impl InterfaceContext {
413420
self.channel_close(channel_id);
414421
Ok(false)
415422
}
416-
None => {
417-
log::error!(
418-
"[{:04x}] Requested to retransmit but not currently sending.",
419-
channel_id
420-
);
421-
Ok(true)
422-
}
423-
Some(r) => {
424-
// TODO explain
423+
Some(_) => {
424+
// Update last write so that we don't end up retransmitting too quickly if
425+
// writes are blocked for some reason.
425426
if let Some(t) = self.timing.get_mut(&channel_id) {
426427
t.update_last_write(Instant::now(), None);
427428
}

core/src/trezor/wire/thp/channel.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ def __init__(
8181
):
8282
self.credential = decode_credential(inner)
8383
except Exception as e:
84-
self._log(f"Cannot parse credential: {e}")
84+
if __debug__:
85+
self._log(f"cannot parse credential: {e}")
8586

8687
def channel_id_bytes(self) -> bytes:
8788
return self.channel_id.to_bytes(2, "big")
@@ -91,7 +92,11 @@ def iface(self) -> WireInterface:
9192
return self.iface_ctx._iface
9293

9394
def clear(self, exc: Exception | None = None) -> None:
94-
self._log(f"Closing channel (exception: {exc is not None})")
95+
if __debug__:
96+
if exc:
97+
self._log(f"closing channel (exception: {exc.__class__.__name__})")
98+
else:
99+
self._log("closing channel")
95100
clear_sessions_with_channel_id(self.channel_id_bytes())
96101
trezorthp.channel_close(self.iface.iface_num(), self.channel_id)
97102
self.expecting_message = False
@@ -126,7 +131,8 @@ def get_last_write(self) -> int | None:
126131
return None
127132

128133
def set_channel_state(self, state: ChannelState) -> None:
129-
self._log(f"set state {state}")
134+
if __debug__:
135+
self._log(f"set state {state}")
130136
self.state = state
131137

132138
def end_pairing_and_replace(self) -> None:
@@ -163,7 +169,8 @@ async def read(self) -> tuple[int, Message]:
163169
finally:
164170
# wake up write loop to send ACKs or DECRYPTION_FAILED
165171
self.iface_ctx.request_write()
166-
self._log("message is ready")
172+
if __debug__ and _TRACE:
173+
self._log("message is ready")
167174
message = Message(
168175
message_type,
169176
self.receive_buffer[3:][:message_bytes_len],
@@ -235,7 +242,7 @@ def write_packet(self, packet: AnyBuffer) -> bool:
235242
res = trezorthp.packet_out(
236243
self.iface.iface_num(), self.channel_id, buffer, packet
237244
)
238-
if res is False and self.send_buffer is not None:
245+
if self.send_buffer:
239246
self.expecting_ack = True
240247
self.iface_ctx.request_read()
241248
return res

core/src/trezor/wire/thp/interface_context.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,11 @@ def preempt_active_channel_if_stale(self) -> None:
6666
last_write_ms = self.active_channel.get_last_write()
6767
# TODO does not work well if we're stuck in retransmit loop
6868
if last_write_ms is None or last_write_ms > _PREEMPT_TIMEOUT_MS:
69-
log.error(
70-
__name__,
71-
f"Interrupting channel {hex(self.active_channel.channel_id)} after {last_write_ms} ms",
72-
)
69+
if __debug__:
70+
log.error(
71+
__name__,
72+
f"Interrupted channel {hex(self.active_channel.channel_id)[2:]} after {last_write_ms} ms",
73+
)
7374
self.active_channel.clear(exc=CHANNEL_PREEMPTED)
7475

7576
async def close(self) -> None:
@@ -189,7 +190,7 @@ def should_read(self) -> bool:
189190
"""
190191
We want to avoid thefollowing sequence of events:
191192
- workflow triggered by a message has finished,
192-
- message is reassembled before session.py restart,
193+
- next message is reassembled before session.py restarts,
193194
- session is restarted, receive buffer is lost,
194195
- host has to resend message after a delay.
195196
To avoid unnecessarry delay, interface is only awaited when:
@@ -395,13 +396,14 @@ def handle_handshake_key(self, try_to_unlock: bool) -> None:
395396
elif not try_to_unlock:
396397
trezorthp.handshake_key(self._iface.iface_num(), None)
397398
elif self._handshake_key_task is None:
398-
log.debug(
399-
__name__,
400-
"Static key needed but device is locked, spawning unlock dialog",
401-
iface=self._iface,
402-
)
399+
if __debug__:
400+
log.debug(
401+
__name__,
402+
"Static key needed but device is locked, spawning unlock dialog",
403+
iface=self._iface,
404+
)
403405
self._handshake_key_task = loop.spawn(self.handshake_unlock())
404-
else:
406+
elif __debug__:
405407
log.debug(__name__, "Unlock task already running", iface=self._iface)
406408

407409
async def handshake_unlock(self) -> None:

python/src/trezorlib/thp/channel.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ def should_back_off() -> bool:
420420
retries_left -= 1
421421
time.sleep(retry_backoff_time)
422422
retry_backoff_time *= 2
423-
print("RETRY")
423+
LOG.warning("RETRY %04x", self.channel_id)
424424
return True
425425

426426
while True:
@@ -476,9 +476,6 @@ def _read_ack(self, message: Message) -> None:
476476
# process ACK bit, return message in next _read
477477
self._next_message = message
478478
else:
479-
print(
480-
f"{self.is_ack_piggybacking_allowed} {expected_seq_bit} {message.ack_bit}"
481-
)
482479
LOG.error("Received message is not a valid ACK: %s", message)
483480
# data messages and their acks should have been handled by _read()
484481
continue

0 commit comments

Comments
 (0)