View | Details | Raw Unified | Return to bug 263916
Collapse All | Expand All

(-)b/security/py-yubikey-manager/Makefile (-1 / +4 lines)
Lines 1-5 Link Here
1
PORTNAME=	yubikey-manager
1
PORTNAME=	yubikey-manager
2
PORTVERSION=	4.0.8
2
PORTVERSION=	4.0.8
3
PORTREVISION=	1
3
CATEGORIES=	security python
4
CATEGORIES=	security python
4
MASTER_SITES=	CHEESESHOP
5
MASTER_SITES=	CHEESESHOP
5
PKGNAMEPREFIX=	${PYTHON_PKGNAMEPREFIX}
6
PKGNAMEPREFIX=	${PYTHON_PKGNAMEPREFIX}
Lines 22-30 RUN_DEPENDS= ${PYTHON_PKGNAMEPREFIX}click>0:devel/py-click@${PY_FLAVOR} \ Link Here
22
		u2f-host:security/libu2f-host \
23
		u2f-host:security/libu2f-host \
23
		ykpersonalize:security/ykpers
24
		ykpersonalize:security/ykpers
24
25
25
USES=		python:3.6+
26
USES=		dos2unix python:3.6+
26
USE_PYTHON=	autoplist concurrent distutils
27
USE_PYTHON=	autoplist concurrent distutils
27
28
29
DOS2UNIX_GLOB=	*.adoc *.py
30
28
NO_ARCH=	yes
31
NO_ARCH=	yes
29
32
30
.include <bsd.port.mk>
33
.include <bsd.port.mk>
(-)b/security/py-yubikey-manager/files/patch-README.adoc (+47 lines)
Added Link Here
1
See https://github.com/Yubico/yubikey-manager/commit/ecd7897b3f02054
2
--- README.adoc.orig	2022-05-27 13:02:44 UTC
3
+++ README.adoc
4
@@ -106,8 +106,43 @@ installed on FreeBSD. It's available via its ports tre
5
 Should you opt to install and use YubiKey Manager on this platform, please be aware
6
 that it's **NOT** maintained by Yubico.
7
 
8
+To install the binary package, use `pkg install pyXY-yubikey-manager`, with `pyXY`
9
+specifying the version of Python the package was built for, so in order to install
10
+YubiKey Manager for Python 3.8, use:
11
+
12
+  # pkg install py38-yubikey-manager
13
+
14
 For more information about how to install packages or ports on FreeBSD, please refer
15
 to its official documentation: https://docs.freebsd.org/en/books/handbook/ports[FreeBSD Handbook].
16
+
17
+In order to use `ykman otp` commands, you need to make sure the _uhid(4)_ driver
18
+attaches to the USB device:
19
+
20
+  # usbconfig ugenX.Y add_quirk UQ_KBD_IGNORE
21
+  # usbconfig ugenX.Y reset
22
+
23
+The correct device to operate on _(ugenX.Y)_ can be determined using
24
+`usbconfig list`.
25
+
26
+When using FreeBSD 13 or higher, you can switch to the more modern _hidraw(4)_
27
+driver. This allows YubiKey Manager to access OTP HID in a non-exclusive way,
28
+so that the key will still function as a USB keyboard:
29
+
30
+  # sysrc kld_list+="hidraw hkbd"
31
+  # cat >>/boot/loader.conf<<EOF
32
+  hw.usb.usbhid.enable="1"
33
+  hw.usb.quirk.0="0x1050 0x0010 0 0xffff UQ_KBD_IGNORE"  # YKS_OTP
34
+  hw.usb.quirk.1="0x1050 0x0110 0 0xffff UQ_KBD_IGNORE"  # NEO_OTP
35
+  hw.usb.quirk.2="0x1050 0x0111 0 0xffff UQ_KBD_IGNORE"  # NEO_OTP_CCID
36
+  hw.usb.quirk.3="0x1050 0x0114 0 0xffff UQ_KBD_IGNORE"  # NEO_OTP_FIDO
37
+  hw.usb.quirk.4="0x1050 0x0116 0 0xffff UQ_KBD_IGNORE"  # NEO_OTP_FIDO_CCID
38
+  hw.usb.quirk.5="0x1050 0x0401 0 0xffff UQ_KBD_IGNORE"  # YK4_OTP
39
+  hw.usb.quirk.6="0x1050 0x0403 0 0xffff UQ_KBD_IGNORE"  # YK4_OTP_FIDO
40
+  hw.usb.quirk.7="0x1050 0x0405 0 0xffff UQ_KBD_IGNORE"  # YK4_OTP_CCID
41
+  hw.usb.quirk.8="0x1050 0x0407 0 0xffff UQ_KBD_IGNORE"  # YK4_OTP_FIDO_CCID
42
+  hw.usb.quirk.9="0x1050 0x0410 0 0xffff UQ_KBD_IGNORE"  # YKP_OTP_FIDO
43
+  EOF
44
+  # reboot
45
 
46
 ==== Source
47
 To install from source, see the link:doc/Development.adoc[development]
(-)b/security/py-yubikey-manager/files/patch-ykman_hid_____init____.py (+20 lines)
Added Link Here
1
See https://github.com/Yubico/yubikey-manager/commit/ecd7897b3f02054
2
--- ykman/hid/__init__.py.orig	2022-05-27 13:02:44 UTC
3
+++ ykman/hid/__init__.py
4
@@ -41,6 +41,8 @@ elif sys.platform.startswith("win32"):
5
     from . import windows as backend
6
 elif sys.platform.startswith("darwin"):
7
     from . import macos as backend
8
+elif sys.platform.startswith("freebsd"):
9
+    from . import freebsd as backend
10
 else:
11
 
12
     class backend:
13
@@ -83,7 +85,6 @@ try:
14
                 except ValueError:
15
                     logger.debug(f"Unsupported Yubico device with PID: {desc.pid:02x}")
16
         return devs
17
-
18
 
19
 except Exception:
20
     # CTAP not supported on this platform
(-)b/security/py-yubikey-manager/files/patch-ykman_hid_freebsd.py (+301 lines)
Added Link Here
1
See https://github.com/Yubico/yubikey-manager/commit/ecd7897b3f02054
2
--- ykman/hid/freebsd.py.orig	2022-05-27 13:02:44 UTC
3
+++ ykman/hid/freebsd.py
4
@@ -0,0 +1,297 @@
5
+# Original work Copyright 2016 Google Inc. All Rights Reserved.
6
+#
7
+# Licensed under the Apache License, Version 2.0 (the "License");
8
+# you may not use this file except in compliance with the License.
9
+# You may obtain a copy of the License at
10
+#
11
+#    http://www.apache.org/licenses/LICENSE-2.0
12
+#
13
+# Unless required by applicable law or agreed to in writing, software
14
+# distributed under the License is distributed on an "AS IS" BASIS,
15
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+# See the License for the specific language governing permissions and
17
+# limitations under the License.
18
+#
19
+# Modified work Copyright 2022 Michael Gmelin. All Rights Reserved.
20
+# This file, with modifications, is licensed under the above Apache License.
21
+#
22
+# Modified work Copyright 2022 Yubico AB. All Rights Reserved.
23
+# This file, with modifications, is licensed under the above Apache License.
24
+
25
+# FreeBSD HID driver.
26
+#
27
+# There are two options to access UHID on FreeBSD:
28
+#
29
+# hidraw(4) - New method, not enabled by default
30
+#             on FreeBSD 13.x and earlier
31
+# uhid(4) - Classic method, default option on
32
+#           FreeBSD 13.x and earlier
33
+#
34
+# To avoid attaching the Yubikey as a keyboard, do:
35
+#
36
+#     usbconfig ugenX.Y add_quirk UQ_KBD_IGNORE
37
+#     usbconfig ugenX.Y reset
38
+#
39
+# The list of available devices is shown using `usbconfig list`
40
+# You can make these changes permanent by altering loader.conf.
41
+#
42
+# Starting from FreeBSD 13 hidraw(4) can be enabled using:
43
+#
44
+#     sysrc kld_list+="hidraw hkbd"
45
+#     cat >>/boot/loader.conf<<EOF
46
+#     hw.usb.usbhid.enable="1"
47
+#     hw.usb.quirk.0="0x1050 0x0010 0 0xffff UQ_KBD_IGNORE"  # YKS_OTP
48
+#     hw.usb.quirk.1="0x1050 0x0110 0 0xffff UQ_KBD_IGNORE"  # NEO_OTP
49
+#     hw.usb.quirk.2="0x1050 0x0111 0 0xffff UQ_KBD_IGNORE"  # NEO_OTP_CCID
50
+#     hw.usb.quirk.3="0x1050 0x0114 0 0xffff UQ_KBD_IGNORE"  # NEO_OTP_FIDO
51
+#     hw.usb.quirk.4="0x1050 0x0116 0 0xffff UQ_KBD_IGNORE"  # NEO_OTP_FIDO_CCID
52
+#     hw.usb.quirk.5="0x1050 0x0401 0 0xffff UQ_KBD_IGNORE"  # YK4_OTP
53
+#     hw.usb.quirk.6="0x1050 0x0403 0 0xffff UQ_KBD_IGNORE"  # YK4_OTP_FIDO
54
+#     hw.usb.quirk.7="0x1050 0x0405 0 0xffff UQ_KBD_IGNORE"  # YK4_OTP_CCID
55
+#     hw.usb.quirk.8="0x1050 0x0407 0 0xffff UQ_KBD_IGNORE"  # YK4_OTP_FIDO_CCID
56
+#     hw.usb.quirk.9="0x1050 0x0410 0 0xffff UQ_KBD_IGNORE"  # YKP_OTP_FIDO
57
+#     EOF
58
+#     reboot
59
+#
60
+from yubikit.core.otp import OtpConnection
61
+from .base import OtpYubiKeyDevice, YUBICO_VID, USAGE_OTP
62
+
63
+from ctypes.util import find_library
64
+import ctypes
65
+
66
+import glob
67
+import fcntl
68
+import os
69
+import re
70
+import struct
71
+import logging
72
+
73
+logger = logging.getLogger(__name__)
74
+
75
+devdir = "/dev/"
76
+
77
+# /usr/include/dev/ususb_ioctl.h
78
+USB_GET_REPORT = 0xC0205517
79
+USB_SET_REPORT = 0x80205518
80
+USB_GET_REPORT_DESC = 0xC0205515
81
+
82
+# /usr/include/dev/hid/hidraw.h>
83
+HIDIOCGRAWINFO = 0x40085520
84
+HIDIOCGRDESC = 0x2000551F
85
+HIDIOCGRDESCSIZE = 0x4004551E
86
+HIDIOCGFEATURE_9 = 0xC0095524
87
+HIDIOCSFEATURE_9 = 0x80095523
88
+
89
+
90
+class HidrawConnection(OtpConnection):
91
+    """
92
+    hidraw(4) is FreeBSD's modern raw access driver, based on usbhid(4).
93
+    It is available since FreeBSD 13 and can be activated by adding
94
+    `hw.usb.usbhid.enable="1"` to `/boot/loader.conf`. The actual kernel
95
+    module is loaded with `kldload hidraw`.
96
+    """
97
+
98
+    def __init__(self, path):
99
+        self.fd = os.open(path, os.O_RDWR)
100
+
101
+    def close(self):
102
+        os.close(self.fd)
103
+
104
+    def receive(self):
105
+        buf = bytearray(1 + 8)
106
+        fcntl.ioctl(self.fd, HIDIOCGFEATURE_9, buf, True)
107
+        return buf[1:]
108
+
109
+    def send(self, data):
110
+        buf = bytes([0]) + data
111
+        fcntl.ioctl(self.fd, HIDIOCSFEATURE_9, buf)
112
+
113
+    @staticmethod
114
+    def get_info(dev):
115
+        buf = bytearray(4 + 2 + 2)
116
+        fcntl.ioctl(dev, HIDIOCGRAWINFO, buf, True)
117
+        return struct.unpack("<IHH", buf)
118
+
119
+    @staticmethod
120
+    def get_descriptor(dev):
121
+        buf = bytearray(4)
122
+        fcntl.ioctl(dev, HIDIOCGRDESCSIZE, buf, True)
123
+        size = struct.unpack("<I", buf)[0]
124
+        buf += bytearray(size)
125
+        fcntl.ioctl(dev, HIDIOCGRDESC, buf, True)
126
+        return buf[4:]
127
+
128
+    @staticmethod
129
+    def get_usage(dev):
130
+        buf = HidrawConnection.get_descriptor(dev)
131
+        usage, usage_page = (None, None)
132
+        while buf:
133
+            head, buf = buf[0], buf[1:]
134
+            typ, size = 0xFC & head, 0x03 & head
135
+            value, buf = buf[:size], buf[size:]
136
+            if typ == 4:  # Usage page
137
+                usage_page = struct.unpack("<I", value.ljust(4, b"\0"))[0]
138
+                if usage is not None:
139
+                    return usage_page, usage
140
+            elif typ == 8:  # Usage
141
+                usage = struct.unpack("<I", value.ljust(4, b"\0"))[0]
142
+                if usage_page is not None:
143
+                    return usage_page, usage
144
+
145
+    @staticmethod
146
+    def list_devices():
147
+        devices = []
148
+        for hidraw in glob.glob(devdir + "hidraw?*"):
149
+            try:
150
+                with open(hidraw, "rb") as f:
151
+                    bustype, vid, pid = HidrawConnection.get_info(f)
152
+                    if vid == YUBICO_VID and HidrawConnection.get_usage(f) == USAGE_OTP:
153
+                        devices.append(OtpYubiKeyDevice(hidraw, pid, HidrawConnection))
154
+            except Exception as e:
155
+                logger.debug("Failed opening HID device", exc_info=e)
156
+                continue
157
+        return devices
158
+
159
+
160
+# For UhidConnection
161
+libc = ctypes.CDLL(find_library("c"))
162
+
163
+
164
+class usb_gen_descriptor(ctypes.Structure):
165
+    _fields_ = [
166
+        (
167
+            "ugd_data",
168
+            ctypes.c_void_p,
169
+        ),
170
+        ("ugd_lang_id", ctypes.c_uint16),
171
+        ("ugd_maxlen", ctypes.c_uint16),
172
+        ("ugd_actlen", ctypes.c_uint16),
173
+        ("ugd_offset", ctypes.c_uint16),
174
+        ("ugd_config_index", ctypes.c_uint8),
175
+        ("ugd_string_index", ctypes.c_uint8),
176
+        ("ugd_iface_index", ctypes.c_uint8),
177
+        ("ugd_altif_index", ctypes.c_uint8),
178
+        ("ugd_endpt_index", ctypes.c_uint8),
179
+        ("ugd_report_type", ctypes.c_uint8),
180
+        ("reserved", ctypes.c_uint8 * 8),
181
+    ]
182
+
183
+
184
+class UhidConnection(OtpConnection):
185
+    """
186
+    uhid(4) is FreeBSD's classic USB hid access driver and enabled
187
+    by default in FreeBSD 13.x and earlier.
188
+    """
189
+
190
+    def __init__(self, path):
191
+        self.fd = os.open(path, os.O_RDWR)
192
+
193
+    def close(self):
194
+        os.close(self.fd)
195
+
196
+    def receive(self):
197
+        buf = ctypes.create_string_buffer(9)
198
+        desc = usb_gen_descriptor(
199
+            ugd_data=ctypes.addressof(buf),
200
+            ugd_maxlen=ctypes.sizeof(buf),
201
+            ugd_report_type=3,
202
+        )
203
+        ret = libc.ioctl(self.fd, USB_GET_REPORT, ctypes.pointer(desc))
204
+        if ret != 0:
205
+            raise ValueError("ioctl failed: " + str(ret))
206
+        return buf[:-1]
207
+
208
+    def send(self, data):
209
+        buf = ctypes.create_string_buffer(8)
210
+        for i in range(0, len(data)):
211
+            buf[i] = data[i]
212
+
213
+        desc = usb_gen_descriptor(
214
+            ugd_data=ctypes.addressof(buf),
215
+            ugd_maxlen=len(buf),
216
+            ugd_report_type=0x3,
217
+        )
218
+        ret = libc.ioctl(self.fd, USB_SET_REPORT, ctypes.pointer(desc))
219
+        if ret != 0:
220
+            raise ValueError("ioctl failed: " + str(ret))
221
+
222
+    @staticmethod
223
+    def get_usage(dev):
224
+        c_data = ctypes.create_string_buffer(4096)
225
+        desc = usb_gen_descriptor(
226
+            ugd_data=ctypes.addressof(c_data),
227
+            ugd_maxlen=ctypes.sizeof(c_data),
228
+            ugd_report_type=3,
229
+        )
230
+        ret = libc.ioctl(dev, USB_GET_REPORT_DESC, ctypes.pointer(desc))
231
+        if ret != 0:
232
+            raise ValueError("ioctl failed")
233
+
234
+        REPORT_DESCRIPTOR_KEY_MASK = 0xFC
235
+        SIZE_MASK = ~REPORT_DESCRIPTOR_KEY_MASK
236
+        USAGE_PAGE = 0x04
237
+        USAGE = 0x08
238
+
239
+        data = c_data.raw
240
+        usage, usage_page = (None, None)
241
+        while data and not (usage and usage_page):
242
+            head, data = struct.unpack_from(">B", data)[0], data[1:]
243
+            key, size = REPORT_DESCRIPTOR_KEY_MASK & head, SIZE_MASK & head
244
+            value = struct.unpack_from("<I", data[:size].ljust(4, b"\0"))[0]
245
+            data = data[size:]
246
+            if key == USAGE_PAGE and not usage_page:
247
+                usage_page = value
248
+            elif key == USAGE and not usage:
249
+                usage = value
250
+
251
+        return (usage_page, usage)
252
+
253
+    @staticmethod
254
+    def get_info(index):
255
+        vendor_re = re.compile("vendor=(0x[0-9a-fA-F]+)")
256
+        product_re = re.compile("product=(0x[0-9a-fA-F]+)")
257
+        sernum_re = re.compile('sernum="([^"]+)')
258
+
259
+        pnpinfo = ("dev.uhid." + index + ".%pnpinfo").encode()
260
+
261
+        ovalue = ctypes.create_string_buffer(1024)
262
+        olen = ctypes.c_size_t(ctypes.sizeof(ovalue))
263
+        key = ctypes.c_char_p(pnpinfo)
264
+        retval = libc.sysctlbyname(key, ovalue, ctypes.byref(olen), None, None)
265
+        if retval != 0:
266
+            raise IOError("sysctlbyname failed")
267
+
268
+        value = ovalue.value[: olen.value].decode()
269
+        m = vendor_re.search(value)
270
+        vid = int(m.group(1), 16) if m else None
271
+        m = product_re.search(value)
272
+        pid = int(m.group(1), 16) if m else None
273
+        m = sernum_re.search(value)
274
+        serial = m.group(1) if m else None
275
+        return (vid, pid, serial)
276
+
277
+    @staticmethod
278
+    def list_devices():
279
+        devices = []
280
+        for uhid in glob.glob(devdir + "uhid?*"):
281
+            index = uhid[len(devdir) + len("uhid") :]
282
+            if not index.isdigit():
283
+                continue
284
+
285
+            try:
286
+                (vid, pid, serial) = UhidConnection.get_info(index)
287
+                if vid == YUBICO_VID:
288
+                    with open(uhid, "rb") as f:
289
+                        if UhidConnection.get_usage(f.fileno()) == USAGE_OTP:
290
+                            devices.append(OtpYubiKeyDevice(uhid, pid, UhidConnection))
291
+            except Exception as e:
292
+                logger.debug("Failed opening HID device", exc_info=e)
293
+                continue
294
+        return devices
295
+
296
+
297
+def list_devices():
298
+    devices = HidrawConnection.list_devices()
299
+    if not devices:
300
+        devices = UhidConnection.list_devices()
301
+    return devices
(-)b/security/py-yubikey-manager/pkg-message (-1 / +34 lines)
Added Link Here
0
- 
1
[
2
{ type: install
3
  message: <<EOM
4
In order to use `ykman otp` commands, you need to make sure the uhid(4)
5
driver attaches to the USB device:
6
7
  # usbconfig ugenX.Y add_quirk UQ_KBD_IGNORE
8
  # usbconfig ugenX.Y reset
9
10
The correct device to operate on (ugenX.Y) can be determined using
11
`usbconfig list`.
12
13
When using FreeBSD 13 or higher, you can switch to the more modern
14
hidraw(4) driver. This allows YubiKey Manager to access OTP HID in a
15
non-exclusive way, so that the key will still function as a USB keyboard:
16
17
  # sysrc kld_list+="hidraw hkbd"
18
  # cat >>/boot/loader.conf<<EOF
19
  hw.usb.usbhid.enable="1"
20
  hw.usb.quirk.0="0x1050 0x0010 0 0xffff UQ_KBD_IGNORE"  # YKS_OTP
21
  hw.usb.quirk.1="0x1050 0x0110 0 0xffff UQ_KBD_IGNORE"  # NEO_OTP
22
  hw.usb.quirk.2="0x1050 0x0111 0 0xffff UQ_KBD_IGNORE"  # NEO_OTP_CCID
23
  hw.usb.quirk.3="0x1050 0x0114 0 0xffff UQ_KBD_IGNORE"  # NEO_OTP_FIDO
24
  hw.usb.quirk.4="0x1050 0x0116 0 0xffff UQ_KBD_IGNORE"  # NEO_OTP_FIDO_CCID
25
  hw.usb.quirk.5="0x1050 0x0401 0 0xffff UQ_KBD_IGNORE"  # YK4_OTP
26
  hw.usb.quirk.6="0x1050 0x0403 0 0xffff UQ_KBD_IGNORE"  # YK4_OTP_FIDO
27
  hw.usb.quirk.7="0x1050 0x0405 0 0xffff UQ_KBD_IGNORE"  # YK4_OTP_CCID
28
  hw.usb.quirk.8="0x1050 0x0407 0 0xffff UQ_KBD_IGNORE"  # YK4_OTP_FIDO_CCID
29
  hw.usb.quirk.9="0x1050 0x0410 0 0xffff UQ_KBD_IGNORE"  # YKP_OTP_FIDO
30
  EOF
31
  # reboot
32
EOM
33
}
34
]

Return to bug 263916