diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2019-12-17 13:08:57 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2019-12-17 13:08:57 +0000 |
commit | 93c5a80cd9505a17528ed97b6fc75b8a12a2adc6 (patch) | |
tree | b744b8472950e501afef29498928e14ae3b24652 /lib | |
parent | 3a713a9a6753ac8aa6d5e955f64f8b47b79e516a (diff) |
Add fido(4), a HID driver for FIDO/U2F security keys
While FIDO/U2F keys were already supported by the generic uhid(4)
driver, this driver adds the first step to tighten the security of
FIDO/U2F access. Specifically, users don't need read/write access to
all USB/HID devices anymore and the driver also improves integration
with pledge(2) and unveil(2): It is pledge-friendly because it doesn't
require any ioctls to discover the device and unveil-friendly because
it uses a single /dev/fido/* directory for its device nodes.
It also allows to support FIDO/U2F in firefox without further
weakening the "sandbox" of the browser. Firefox does not have a
proper privsep design and many operations, such as U2F access, are
handled directly by the main process. This means that the browser's
"fat" main process needs direct read/write access to all USB HID
devices, at least on other operating systems. With fido(4) we can
support security keys in Firefox under OpenBSD without such a
compromise.
With this change, libfido2 stops using the ioctl to query the device
vendor/product and just assumes "OpenBSD" "fido(4)" instead. The
ioctl is still supported but there was no benefit in obtaining the
vendor product or name; it also allows to use libfido2 under pledge.
With feedback from deraadt@ and many others
OK kettenis@ djm@ and jmc@ for the manpage bits
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libfido2/Makefile | 3 | ||||
-rw-r--r-- | lib/libfido2/src/hid_openbsd.c | 84 |
2 files changed, 11 insertions, 76 deletions
diff --git a/lib/libfido2/Makefile b/lib/libfido2/Makefile index afbbf158e84..d6fb7aef060 100644 --- a/lib/libfido2/Makefile +++ b/lib/libfido2/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.3 2019/11/15 03:19:40 deraadt Exp $ +# $OpenBSD: Makefile,v 1.4 2019/12/17 13:08:54 reyk Exp $ .PATH: ${.CURDIR}/man ${.CURDIR}/src @@ -9,7 +9,6 @@ CDIAGFLAGS+= -Wall -Wextra CDIAGFLAGS+= -Werror LDADD+= -L${BSDOBJDIR}/lib/libcbor -lcbor -LDADD+= -L${BSDOBJDIR}/lib/libusbhid -lusbhid SYMBOL_LIST= Symbols.list VERSION_SCRIPT= Symbols.map diff --git a/lib/libfido2/src/hid_openbsd.c b/lib/libfido2/src/hid_openbsd.c index 92b7c05b6f7..15af3ad5253 100644 --- a/lib/libfido2/src/hid_openbsd.c +++ b/lib/libfido2/src/hid_openbsd.c @@ -20,7 +20,7 @@ #include "fido.h" #define MAX_UHID 64 -#define MAX_REPORT_LEN (sizeof(((struct usb_ctl_report *)(NULL))->ucr_data)) +#define MAX_U2FHID_LEN 64 struct hid_openbsd { int fd; @@ -33,11 +33,8 @@ fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) { size_t i; char path[64]; - int is_fido, fd; + int fd; struct usb_device_info udi; - report_desc_t rdesc = NULL; - hid_data_t hdata = NULL; - hid_item_t hitem; fido_dev_info_t *di; if (ilen == 0) @@ -47,7 +44,7 @@ fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) return (FIDO_ERR_INVALID_ARGUMENT); for (i = *olen = 0; i < MAX_UHID && *olen < ilen; i++) { - snprintf(path, sizeof(path), "/dev/uhid%zu", i); + snprintf(path, sizeof(path), "/dev/fido/%zu", i); if ((fd = open(path, O_RDWR)) == -1) { if (errno != ENOENT && errno != ENXIO) { log_debug("%s: open %s: %s", __func__, path, @@ -55,49 +52,15 @@ fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) } continue; } - memset(&udi, 0, sizeof(udi)); - if (ioctl(fd, USB_GET_DEVICEINFO, &udi) != 0) { - log_debug("%s: get device info %s: %s", __func__, - path, strerror(errno)); - close(fd); - continue; - } - if ((rdesc = hid_get_report_desc(fd)) == NULL) { - log_debug("%s: failed to get report descriptor: %s", - __func__, path); - close(fd); - continue; - } - if ((hdata = hid_start_parse(rdesc, - 1<<hid_collection, -1)) == NULL) { - log_debug("%s: failed to parse report descriptor: %s", - __func__, path); - hid_dispose_report_desc(rdesc); - close(fd); - continue; - } - is_fido = 0; - for (is_fido = 0; !is_fido;) { - memset(&hitem, 0, sizeof(hitem)); - if (hid_get_item(hdata, &hitem) <= 0) - break; - if ((hitem._usage_page & 0xFFFF0000) == 0xf1d00000) - is_fido = 1; - } - hid_end_parse(hdata); - hid_dispose_report_desc(rdesc); close(fd); - if (!is_fido) - continue; + memset(&udi, 0, sizeof(udi)); + strlcpy(udi.udi_vendor, "OpenBSD", sizeof(udi.udi_vendor)); + strlcpy(udi.udi_product, "fido(4)", sizeof(udi.udi_product)); + udi.udi_vendorNo = 0x0b5d; /* stolen from PCI_VENDOR_OPENBSD */ - log_debug("%s: %s: bus = 0x%02x, addr = 0x%02x", - __func__, path, udi.udi_bus, udi.udi_addr); log_debug("%s: %s: vendor = \"%s\", product = \"%s\"", __func__, path, udi.udi_vendor, udi.udi_product); - log_debug("%s: %s: productNo = 0x%04x, vendorNo = 0x%04x, " - "releaseNo = 0x%04x", __func__, path, udi.udi_productNo, - udi.udi_vendorNo, udi.udi_releaseNo); di = &devlist[*olen]; memset(di, 0, sizeof(*di)); @@ -178,42 +141,15 @@ void * hid_open(const char *path) { struct hid_openbsd *ret = NULL; - report_desc_t rdesc = NULL; - int len, usb_report_id = 0; if ((ret = calloc(1, sizeof(*ret))) == NULL || (ret->fd = open(path, O_RDWR)) < 0) { free(ret); return (NULL); } - if (ioctl(ret->fd, USB_GET_REPORT_ID, &usb_report_id) != 0) { - log_debug("%s: failed to get report ID: %s", __func__, - strerror(errno)); - goto fail; - } - if ((rdesc = hid_get_report_desc(ret->fd)) == NULL) { - log_debug("%s: failed to get report descriptor", __func__); - goto fail; - } - if ((len = hid_report_size(rdesc, hid_input, usb_report_id)) <= 0 || - (size_t)len > MAX_REPORT_LEN) { - log_debug("%s: bad input report size %d", __func__, len); - goto fail; - } - ret->report_in_len = (size_t)len; - if ((len = hid_report_size(rdesc, hid_output, usb_report_id)) <= 0 || - (size_t)len > MAX_REPORT_LEN) { - log_debug("%s: bad output report size %d", __func__, len); - fail: - hid_dispose_report_desc(rdesc); - close(ret->fd); - free(ret); - return NULL; - } - ret->report_out_len = (size_t)len; - hid_dispose_report_desc(rdesc); - log_debug("%s: USB report ID %d, inlen = %zu outlen = %zu", __func__, - usb_report_id, ret->report_in_len, ret->report_out_len); + ret->report_in_len = ret->report_out_len = MAX_U2FHID_LEN; + log_debug("%s: inlen = %zu outlen = %zu", __func__, + ret->report_in_len, ret->report_out_len); /* * OpenBSD (as of 201910) has a bug that causes it to lose |