diff --git a/security/py-fido2/Makefile b/security/py-fido2/Makefile index b1c88628a94d..a2176170c194 100644 --- a/security/py-fido2/Makefile +++ b/security/py-fido2/Makefile @@ -1,22 +1,23 @@ PORTNAME= fido2 PORTVERSION= 0.9.3 +PORTREVISION= 1 CATEGORIES= security python MASTER_SITES= CHEESESHOP PKGNAMEPREFIX= ${PYTHON_PKGNAMEPREFIX} MAINTAINER= python@FreeBSD.org COMMENT= Provides library functionality for FIDO 2.0 LICENSE= BSD2CLAUSE LICENSE_FILE= ${WRKSRC}/COPYING RUN_DEPENDS= ${PYTHON_PKGNAMEPREFIX}cryptography>=1.5:security/py-cryptography@${PY_FLAVOR} \ ${PYTHON_PKGNAMEPREFIX}six>=0:devel/py-six@${PY_FLAVOR} TEST_DEPENDS= ${PYTHON_PKGNAMEPREFIX}mock>0:devel/py-mock@${PY_FLAVOR} USES= python:3.6+ USE_PYTHON= autoplist distutils unittest NO_ARCH= yes .include diff --git a/security/py-fido2/files/patch-fido2_hid_freebsd.py b/security/py-fido2/files/patch-fido2_hid_freebsd.py new file mode 100644 index 000000000000..78836b3c4d06 --- /dev/null +++ b/security/py-fido2/files/patch-fido2_hid_freebsd.py @@ -0,0 +1,222 @@ +See https://github.com/Yubico/python-fido2/commit/2a202d0e19fdb7be +--- fido2/hid/freebsd.py.orig 2022-05-27 09:25:33 UTC ++++ fido2/hid/freebsd.py +@@ -15,19 +15,39 @@ + # Modified work Copyright 2020 Yubico AB. All Rights Reserved. + # This file, with modifications, is licensed under the above Apache License. + ++# FreeBSD HID driver. ++# ++# There are two options to access UHID on FreeBSD: ++# ++# hidraw(4) - New method, not enabled by default ++# on FreeBSD 13.x and earlier ++# uhid(4) - Classic method, default option on ++# FreeBSD 13.x and earlier ++# ++# uhid is available since FreeBSD 13 and can be activated by adding ++# `hw.usb.usbhid.enable="1"` to `/boot/loader.conf`. The actual kernel ++# module is loaded with `kldload hidraw`. + +-from __future__ import absolute_import ++from __future__ import annotations + + from ctypes.util import find_library + import ctypes ++import fcntl + import glob + import re ++import struct + import os ++from array import array + + from .base import HidDescriptor, parse_report_descriptor, FileCtapHidConnection + + import logging ++import sys ++from typing import Dict, Optional, Set, Union + ++# Don't typecheck this file on Windows ++assert sys.platform != "win32" # nosec ++ + logger = logging.getLogger(__name__) + + +@@ -39,9 +59,17 @@ sernum_re = re.compile('sernum="([^"]+)') + + libc = ctypes.CDLL(find_library("c")) + ++# /usr/include/dev/usb/usb_ioctl.h + USB_GET_REPORT_DESC = 0xC0205515 + ++# /usr/include/dev/hid/hidraw.h> ++HIDIOCGRAWINFO = 0x40085520 ++HIDIOCGRDESC = 0x2000551F ++HIDIOCGRDESCSIZE = 0x4004551E ++HIDIOCGRAWNAME_128 = 0x40805521 ++HIDIOCGRAWUNIQ_64 = 0x40405525 + ++ + class usb_gen_descriptor(ctypes.Structure): + _fields_ = [ + ( +@@ -62,8 +90,17 @@ class usb_gen_descriptor(ctypes.Structure): + ] + + ++class HidrawCtapHidConnection(FileCtapHidConnection): ++ def write_packet(self, packet): ++ # Prepend the report ID ++ super(HidrawCtapHidConnection, self).write_packet(b"\0" + packet) ++ ++ + def open_connection(descriptor): +- return FileCtapHidConnection(descriptor) ++ if descriptor.path.find(devdir + "hidraw") == 0: ++ return HidrawCtapHidConnection(descriptor) ++ else: ++ return FileCtapHidConnection(descriptor) + + + def _get_report_data(fd, report_type): +@@ -71,7 +108,7 @@ def _get_report_data(fd, report_type): + desc = usb_gen_descriptor( + ugd_data=ctypes.addressof(data), + ugd_maxlen=ctypes.sizeof(data), +- report_type=report_type, ++ ugd_report_type=report_type, + ) + ret = libc.ioctl(fd, USB_GET_REPORT_DESC, ctypes.byref(desc)) + if ret != 0: +@@ -104,16 +141,16 @@ def _enumerate(): + if retval != 0: + continue + +- dev = {} ++ dev: Dict[str, Optional[Union[str, int]]] = {} + dev["name"] = uhid[len(devdir) :] + dev["path"] = uhid + + value = ovalue.value[: olen.value].decode() + m = vendor_re.search(value) +- dev["vendor_id"] = m.group(1) if m else None ++ dev["vendor_id"] = int(m.group(1), 16) if m else None + + m = product_re.search(value) +- dev["product_id"] = m.group(1) if m else None ++ dev["product_id"] = int(m.group(1), 16) if m else None + + m = sernum_re.search(value) + dev["serial_number"] = m.group(1) if m else None +@@ -126,7 +163,49 @@ def _enumerate(): + yield dev + + ++def get_hidraw_descriptor(path): ++ with open(path, "rb") as f: ++ # Read VID, PID ++ buf = array("B", [0] * (4 + 2 + 2)) ++ fcntl.ioctl(f, HIDIOCGRAWINFO, buf, True) ++ _, vid, pid = struct.unpack(" 1 else None ++ ++ # Read unique ID ++ try: ++ buf = array("B", [0] * 65) ++ fcntl.ioctl(f, HIDIOCGRAWUNIQ_64, buf, True) ++ length = buf.index(0) + 1 # emulate ioctl return value ++ serial = ( ++ bytearray(buf[: (length - 1)]).decode("utf-8") if length > 1 else None ++ ) ++ except OSError: ++ serial = None ++ ++ # Read report descriptor ++ buf = array("B", [0] * 4) ++ fcntl.ioctl(f, HIDIOCGRDESCSIZE, buf, True) ++ size = struct.unpack("