summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2019-12-17 13:08:57 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2019-12-17 13:08:57 +0000
commit93c5a80cd9505a17528ed97b6fc75b8a12a2adc6 (patch)
treeb744b8472950e501afef29498928e14ae3b24652 /lib
parent3a713a9a6753ac8aa6d5e955f64f8b47b79e516a (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/Makefile3
-rw-r--r--lib/libfido2/src/hid_openbsd.c84
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