mirror of https://github.com/Yubico/python-fido2
124 lines
3.6 KiB
Python
124 lines
3.6 KiB
Python
# Original work Copyright 2016 Google Inc. All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
#
|
|
# Modified work Copyright 2020 Yubico AB. All Rights Reserved.
|
|
# This file, with modifications, is licensed under the above Apache License.
|
|
|
|
|
|
import fcntl
|
|
import select
|
|
import os
|
|
import os.path
|
|
|
|
from ctypes import Structure, c_char, c_int, c_uint8, c_uint16, c_uint32
|
|
|
|
from .base import HidDescriptor, FileCtapHidConnection
|
|
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# /usr/include/dev/usb/usb.h
|
|
USB_GET_DEVICEINFO = 0x421C5570
|
|
USB_MAX_STRING_LEN = 127
|
|
USB_MAX_DEVNAMES = 4
|
|
USB_MAX_DEVNAMELEN = 16
|
|
|
|
FIDO_DEVS = "/dev/fido"
|
|
MAX_U2F_HIDLEN = 64
|
|
|
|
|
|
class UsbDeviceInfo(Structure):
|
|
_fields_ = [
|
|
("udi_bus", c_uint8),
|
|
("udi_addr", c_uint8),
|
|
("udi_product", c_char * USB_MAX_STRING_LEN),
|
|
("udi_vendor", c_char * USB_MAX_STRING_LEN),
|
|
("udi_release", c_char * 8),
|
|
("udi_productNo", c_uint16),
|
|
("udi_vendorNo", c_uint16),
|
|
("udi_releaseNo", c_uint16),
|
|
("udi_class", c_uint8),
|
|
("udi_subclass", c_uint8),
|
|
("udi_protocol", c_uint8),
|
|
("udi_config", c_uint8),
|
|
("udi_speed", c_uint8),
|
|
("udi_power", c_int),
|
|
("udi_nports", c_int),
|
|
("udi_devnames", c_char * USB_MAX_DEVNAMELEN * USB_MAX_DEVNAMES),
|
|
("udi_ports", c_uint32 * 16),
|
|
("udi_serial", c_char * USB_MAX_STRING_LEN),
|
|
]
|
|
|
|
|
|
class OpenBsdCtapHidConnection(FileCtapHidConnection):
|
|
def __init__(self, descriptor):
|
|
super(OpenBsdCtapHidConnection, self).__init__(descriptor)
|
|
try:
|
|
self._terrible_ping_kludge()
|
|
except Exception:
|
|
self.close()
|
|
raise
|
|
|
|
def _terrible_ping_kludge(self):
|
|
# This is pulled from
|
|
# https://github.com/Yubico/libfido2/blob/da24193aa901086960f8d31b60d930ebef21f7a2/src/hid_openbsd.c#L128
|
|
for _ in range(4):
|
|
# 1 byte ping
|
|
data = b"\xff\xff\xff\xff\x81\0\1".ljust(
|
|
self.descriptor.report_size_out, b"\0"
|
|
)
|
|
|
|
poll = select.poll()
|
|
poll.register(self.handle, select.POLLIN)
|
|
|
|
self.write_packet(data)
|
|
|
|
poll.poll(100)
|
|
data = self.read_packet()
|
|
|
|
|
|
def open_connection(descriptor):
|
|
return OpenBsdCtapHidConnection(descriptor)
|
|
|
|
|
|
def get_descriptor(path):
|
|
f = os.open(path, os.O_RDONLY)
|
|
|
|
dev_info = UsbDeviceInfo()
|
|
|
|
try:
|
|
fcntl.ioctl(f, USB_GET_DEVICEINFO, dev_info) # type: ignore
|
|
finally:
|
|
os.close(f)
|
|
|
|
vid = int(dev_info.udi_vendorNo)
|
|
pid = int(dev_info.udi_productNo)
|
|
name = dev_info.udi_product.decode("utf-8") or None
|
|
serial = dev_info.udi_serial.decode("utf-8") or None
|
|
|
|
return HidDescriptor(path, vid, pid, MAX_U2F_HIDLEN, MAX_U2F_HIDLEN, name, serial)
|
|
|
|
|
|
def list_descriptors():
|
|
descriptors = []
|
|
for dev in os.listdir(FIDO_DEVS):
|
|
path = os.path.join(FIDO_DEVS, dev)
|
|
try:
|
|
descriptors.append(get_descriptor(path))
|
|
logger.debug("Found CTAP device: %s", path)
|
|
except Exception as e:
|
|
logger.debug("Failed opening FIDO device", exc_info=e)
|
|
return descriptors
|