mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-18 13:38:12 +00:00
core/webauthn: Fix handling of interleaving frames to comply with the U2F HID specification.
This commit is contained in:
parent
e6d884b145
commit
25a39ea729
@ -41,6 +41,7 @@ _HID_RPT_SIZE = const(64)
|
|||||||
_FRAME_INIT_SIZE = const(57)
|
_FRAME_INIT_SIZE = const(57)
|
||||||
_FRAME_CONT_SIZE = const(59)
|
_FRAME_CONT_SIZE = const(59)
|
||||||
_MAX_U2FHID_MSG_PAYLOAD_LEN = const(_FRAME_INIT_SIZE + 128 * _FRAME_CONT_SIZE)
|
_MAX_U2FHID_MSG_PAYLOAD_LEN = const(_FRAME_INIT_SIZE + 128 * _FRAME_CONT_SIZE)
|
||||||
|
_CMD_INIT_NONCE_SIZE = const(8)
|
||||||
|
|
||||||
# types of cmd
|
# types of cmd
|
||||||
_CMD_PING = const(0x81) # echo data through local processor only
|
_CMD_PING = const(0x81) # echo data through local processor only
|
||||||
@ -418,20 +419,53 @@ async def read_cmd(iface: io.HID) -> Optional[Cmd]:
|
|||||||
while datalen < bcnt:
|
while datalen < bcnt:
|
||||||
buf = await loop.race(read, loop.sleep(_CTAP_HID_TIMEOUT_MS * 1000))
|
buf = await loop.race(read, loop.sleep(_CTAP_HID_TIMEOUT_MS * 1000))
|
||||||
if not isinstance(buf, bytes):
|
if not isinstance(buf, bytes):
|
||||||
|
if __debug__:
|
||||||
|
log.warning(__name__, "_ERR_MSG_TIMEOUT")
|
||||||
await send_cmd(cmd_error(ifrm.cid, _ERR_MSG_TIMEOUT), iface)
|
await send_cmd(cmd_error(ifrm.cid, _ERR_MSG_TIMEOUT), iface)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
cfrm = overlay_struct(bytearray(buf), desc_cont)
|
cfrm = overlay_struct(bytearray(buf), desc_cont)
|
||||||
|
|
||||||
if cfrm.seq == _CMD_INIT:
|
if cfrm.seq == _CMD_INIT:
|
||||||
# _CMD_INIT frame, cancels current channel
|
if cfrm.cid == ifrm.cid:
|
||||||
break
|
# _CMD_INIT command on current channel, abort current transaction.
|
||||||
|
if __debug__:
|
||||||
|
log.warning(
|
||||||
|
__name__,
|
||||||
|
"U2FHID: received CMD_INIT command during active tran, aborting",
|
||||||
|
)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
# _CMD_INIT command on different channel, return synchronization response, but continue on current CID.
|
||||||
|
if __debug__:
|
||||||
|
log.info(
|
||||||
|
__name__,
|
||||||
|
"U2FHID: received CMD_INIT command for different CID",
|
||||||
|
)
|
||||||
|
cfrm = overlay_struct(bytearray(buf), desc_init)
|
||||||
|
await send_cmd(
|
||||||
|
cmd_init(
|
||||||
|
Cmd(cfrm.cid, cfrm.cmd, bytes(cfrm.data[: cfrm.bcnt]))
|
||||||
|
),
|
||||||
|
iface,
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
if cfrm.cid != ifrm.cid:
|
if cfrm.cid != ifrm.cid:
|
||||||
# cont frame for a different channel, reply with BUSY and abort
|
# Frame for a different channel, continue waiting for next frame on the active CID.
|
||||||
if __debug__:
|
# For init frames reply with BUSY. Ignore continuation frames.
|
||||||
log.warning(__name__, "_ERR_CHANNEL_BUSY")
|
if cfrm.seq & _TYPE_MASK == _TYPE_INIT:
|
||||||
await send_cmd(cmd_error(cfrm.cid, _ERR_CHANNEL_BUSY), iface)
|
if __debug__:
|
||||||
|
log.warning(
|
||||||
|
__name__,
|
||||||
|
"U2FHID: received init frame for different CID, _ERR_CHANNEL_BUSY",
|
||||||
|
)
|
||||||
|
await send_cmd(cmd_error(cfrm.cid, _ERR_CHANNEL_BUSY), iface)
|
||||||
|
else:
|
||||||
|
if __debug__:
|
||||||
|
log.warning(
|
||||||
|
__name__, "U2FHID: received cont frame for different CID"
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if cfrm.seq != seq:
|
if cfrm.seq != seq:
|
||||||
@ -1099,6 +1133,9 @@ def cmd_init(req: Cmd) -> Cmd:
|
|||||||
else:
|
else:
|
||||||
resp_cid = req.cid
|
resp_cid = req.cid
|
||||||
|
|
||||||
|
if len(req.data) != _CMD_INIT_NONCE_SIZE:
|
||||||
|
return cmd_error(req.cid, _ERR_INVALID_LEN)
|
||||||
|
|
||||||
buf, resp = make_struct(resp_cmd_init())
|
buf, resp = make_struct(resp_cmd_init())
|
||||||
utils.memcpy(resp.nonce, 0, req.data, 0, len(req.data))
|
utils.memcpy(resp.nonce, 0, req.data, 0, len(req.data))
|
||||||
resp.cid = resp_cid
|
resp.cid = resp_cid
|
||||||
|
Loading…
Reference in New Issue
Block a user