You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/core/tools/hid-bridge/hid_interface.py

108 lines
3.7 KiB

import os
import logger
import uhid
def random_bytes(length):
return os.urandom(length)
class HIDInterface:
uhid_device = "/dev/uhid"
def __init__(self):
self.file_descriptor = os.open(HIDInterface.uhid_device, os.O_RDWR)
self.create_device()
def __uhid_read(self, length):
data = os.read(self.file_descriptor, length)
logger.log_raw(f"{HIDInterface.uhid_device} >", data.hex())
return data
def __uhid_write(self, data):
bytes_written = os.write(self.file_descriptor, data)
assert bytes_written == len(data)
logger.log_raw(f"{HIDInterface.uhid_device} <", data.hex())
def create_device(self):
name = b"Virtual Trezor"
phys = b""
uniq = random_bytes(64)
bus = 0
vendor = 0x1209
product = 0x53C1
version = 0x0200
country = 0
# fmt: off
rd_data = bytes([
0x06, 0xD0, 0xF1, # USAGE_PAGE (FIDO Alliance)
0x09, 0x01, # USAGE (U2F HID Authenticator Device)
0xA1, 0x01, # COLLECTION (Application)
0x09, 0x20, # USAGE (Input Report Data)
0x15, 0x00, # LOGICAL_MINIMUM (0)
0x26, 0xFF, 0x00, # LOGICAL_MAXIMUM (255)
0x75, 0x08, # REPORT_SIZE (8)
0x95, 0x40, # REPORT_COUNT (64)
0x81, 0x02, # INPUT (Data,Var,Abs)
0x09, 0x21, # USAGE (Output Report Data)
0x15, 0x00, # LOGICAL_MINIMUM (0)
0x26, 0xFF, 0x00, # LOGICAL_MAXIMUM (255)
0x75, 0x08, # REPORT_SIZE (8)
0x95, 0x40, # REPORT_COUNT (64)
0x91, 0x02, # OUTPUT (Data,Var,Abs)
0xC0, # END_COLLECTION
])
# fmt: on
buf = uhid.create_create2_event(
name, phys, uniq, bus, vendor, product, version, country, rd_data
)
self.__uhid_write(buf)
logger.log_uhid_event(
"UHID_CREATE2",
f"name='{name.decode()}' "
f"phys='{phys.decode()}' "
f"uniq=0x{uniq.hex()} "
f"rd_size={len(rd_data)} "
f"bus=0x{bus:04x} "
f"vendor=0x{vendor:04x} "
f"product=0x{product:04x} "
f"version=0x{version:04x} "
f"country=0x{country:04x} "
f"rd_data=0x{rd_data.hex()}",
)
def write_data(self, data):
buf = uhid.create_input2_event(data)
self.__uhid_write(buf)
logger.log_uhid_event(
"UHID_INPUT2", f"data=0x{data.hex()} size={len(data)}"
)
logger.log_hid_packet("DEVICE_OUTPUT", f"0x{data.hex()}")
def process_event(self):
ev_type, request = uhid.parse_event(self.__uhid_read(uhid.EVENT_LENGTH))
if ev_type == uhid.EVENT_TYPE_START:
dev_flags, = request
logger.log_uhid_event("UHID_START", f"dev_flags=0b{dev_flags:08b}")
elif ev_type == uhid.EVENT_TYPE_STOP:
logger.log_uhid_event("UHID_STOP")
elif ev_type == uhid.EVENT_TYPE_OPEN:
logger.log_uhid_event("UHID_OPEN")
elif ev_type == uhid.EVENT_TYPE_CLOSE:
logger.log_uhid_event("UHID_CLOSE")
elif ev_type == uhid.EVENT_TYPE_OUTPUT:
data, size, rtype = request
logger.log_uhid_event(
"UHID_OUTPUT",
f"data=0x{data.hex()} size={size} rtype={rtype}",
)
logger.log_hid_packet("DEVICE_INPUT", f"0x{data[1:].hex()}")
return data[1:]
else:
logger.log_uhid_event(
"UNKNOWN_EVENT",
f"ev_type={ev_type} request=0x{request.hex()}",
)