summaryrefslogtreecommitdiff
path: root/lib/libfido2
diff options
context:
space:
mode:
authorMarcus Glocker <mglocker@cvs.openbsd.org>2021-02-15 11:26:01 +0000
committerMarcus Glocker <mglocker@cvs.openbsd.org>2021-02-15 11:26:01 +0000
commit2b4d4942980e01a6b33e439ad18f42f5d4b2cb8a (patch)
tree0604bcc0a35dffe74103414b5abdeed47d3c1631 /lib/libfido2
parentcc5bfd032586e5e7455c2cb598c3527fd8055b39 (diff)
Back-out USB data toggle fix for HID devices, since we received multiple
reports about broken devices, e.g. for ukbd(4) and fido(4). ok mpi@
Diffstat (limited to 'lib/libfido2')
-rw-r--r--lib/libfido2/src/hid_openbsd.c66
1 files changed, 66 insertions, 0 deletions
diff --git a/lib/libfido2/src/hid_openbsd.c b/lib/libfido2/src/hid_openbsd.c
index 38edc41d4c6..58b8c3e9475 100644
--- a/lib/libfido2/src/hid_openbsd.c
+++ b/lib/libfido2/src/hid_openbsd.c
@@ -88,6 +88,62 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
return FIDO_OK;
}
+/*
+ * Workaround for OpenBSD <=6.6-current (as of 201910) bug that loses
+ * sync of DATA0/DATA1 sequence bit across uhid open/close.
+ * Send pings until we get a response - early pings with incorrect
+ * sequence bits will be ignored as duplicate packets by the device.
+ */
+static int
+terrible_ping_kludge(struct hid_openbsd *ctx)
+{
+ u_char data[256];
+ int i, n;
+ struct pollfd pfd;
+
+ if (sizeof(data) < ctx->report_out_len + 1)
+ return -1;
+ for (i = 0; i < 4; i++) {
+ memset(data, 0, sizeof(data));
+ /* broadcast channel ID */
+ data[1] = 0xff;
+ data[2] = 0xff;
+ data[3] = 0xff;
+ data[4] = 0xff;
+ /* Ping command */
+ data[5] = 0x81;
+ /* One byte ping only, Vasili */
+ data[6] = 0;
+ data[7] = 1;
+ fido_log_debug("%s: send ping %d", __func__, i);
+ if (fido_hid_write(ctx, data, ctx->report_out_len + 1) == -1)
+ return -1;
+ fido_log_debug("%s: wait reply", __func__);
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = ctx->fd;
+ pfd.events = POLLIN;
+ if ((n = poll(&pfd, 1, 100)) == -1) {
+ fido_log_debug("%s: poll: %s", __func__, strerror(errno));
+ return -1;
+ } else if (n == 0) {
+ fido_log_debug("%s: timed out", __func__);
+ continue;
+ }
+ if (fido_hid_read(ctx, data, ctx->report_out_len, 250) == -1)
+ return -1;
+ /*
+ * Ping isn't always supported on the broadcast channel,
+ * so we might get an error, but we don't care - we're
+ * synched now.
+ */
+ fido_log_debug("%s: got reply", __func__);
+ fido_log_xxd(data, ctx->report_out_len);
+ return 0;
+ }
+ fido_log_debug("%s: no response", __func__);
+ return -1;
+}
+
void *
fido_hid_open(const char *path)
{
@@ -102,6 +158,16 @@ fido_hid_open(const char *path)
fido_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
+ * track of the DATA0/DATA1 sequence toggle across uhid device
+ * open and close. This is a terrible hack to work around it.
+ */
+ if (terrible_ping_kludge(ret) != 0) {
+ fido_hid_close(ret);
+ return NULL;
+ }
+
return (ret);
}