From 173bfbf7886608a4a7abbfac6a42ac4bf4a3432d Mon Sep 17 00:00:00 2001 From: Colin Watson Date: Sun, 20 Sep 2020 16:14:20 +0100 Subject: New upstream version 1.5.0 --- src/hid_hidapi.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 212 insertions(+), 14 deletions(-) (limited to 'src/hid_hidapi.c') diff --git a/src/hid_hidapi.c b/src/hid_hidapi.c index 915621f..898fd9e 100644 --- a/src/hid_hidapi.c +++ b/src/hid_hidapi.c @@ -4,14 +4,26 @@ * license that can be found in the LICENSE file. */ -#include +#ifdef __linux__ +#include +#include +#include +#include +#endif +#include #include #include #include #include "fido.h" +struct hid_hidapi { + void *handle; + size_t report_in_len; + size_t report_out_len; +}; + static size_t fido_wcslen(const wchar_t *wcs) { @@ -27,7 +39,7 @@ wcs_to_cs(const wchar_t *wcs) char *cs; size_t i; - if (wcs == NULL || (cs = calloc(fido_wcslen(wcs) + 1, 1)) == NULL) + if (wcs == NULL || (cs = calloc(fido_wcslen(wcs) + 1, 1)) == NULL) return NULL; for (i = 0; i < fido_wcslen(wcs); i++) { @@ -68,11 +80,12 @@ copy_info(fido_dev_info_t *di, const struct hid_device_info *d) free(di->path); free(di->manufacturer); free(di->product); + explicit_bzero(di, sizeof(*di)); return -1; } - di->product_id = d->product_id; - di->vendor_id = d->vendor_id; + di->product_id = (int16_t)d->product_id; + di->vendor_id = (int16_t)d->vendor_id; di->io = (fido_dev_io_t) { &fido_hid_open, &fido_hid_close, @@ -83,28 +96,199 @@ copy_info(fido_dev_info_t *di, const struct hid_device_info *d) return 0; } +#ifdef __linux__ +static int +get_key_len(uint8_t tag, uint8_t *key, size_t *key_len) +{ + *key = tag & 0xfc; + if ((*key & 0xf0) == 0xf0) { + fido_log_debug("%s: *key=0x%02x", __func__, *key); + return -1; + } + + *key_len = tag & 0x3; + if (*key_len == 3) { + *key_len = 4; + } + + return 0; +} + +static int +get_key_val(const void *body, size_t key_len, uint32_t *val) +{ + const uint8_t *ptr = body; + + switch (key_len) { + case 0: + *val = 0; + break; + case 1: + *val = ptr[0]; + break; + case 2: + *val = (uint32_t)((ptr[1] << 8) | ptr[0]); + break; + default: + fido_log_debug("%s: key_len=%zu", __func__, key_len); + return -1; + } + + return 0; +} + +static int +get_usage_info(const struct hidraw_report_descriptor *hrd, uint32_t *usage_page, + uint32_t *usage) +{ + const uint8_t *ptr = hrd->value; + size_t len = hrd->size; + + while (len > 0) { + const uint8_t tag = ptr[0]; + + ptr++; + len--; + + uint8_t key; + size_t key_len; + uint32_t key_val; + + if (get_key_len(tag, &key, &key_len) < 0 || key_len > len || + get_key_val(ptr, key_len, &key_val) < 0) { + return -1; + } + + if (key == 0x4) { + *usage_page = key_val; + } else if (key == 0x8) { + *usage = key_val; + } + + ptr += key_len; + len -= key_len; + } + + return 0; +} + +static int +get_report_descriptor(const char *path, struct hidraw_report_descriptor *hrd) +{ + int fd; + int s = -1; + int ok = -1; + + if ((fd = open(path, O_RDONLY)) < 0) { + fido_log_debug("%s: open", __func__); + return -1; + } + + if (ioctl(fd, HIDIOCGRDESCSIZE, &s) < 0 || s < 0 || + (unsigned)s > HID_MAX_DESCRIPTOR_SIZE) { + fido_log_debug("%s: ioctl HIDIOCGRDESCSIZE", __func__); + goto fail; + } + + hrd->size = (unsigned)s; + + if (ioctl(fd, HIDIOCGRDESC, hrd) < 0) { + fido_log_debug("%s: ioctl HIDIOCGRDESC", __func__); + goto fail; + } + + ok = 0; +fail: + if (fd != -1) + close(fd); + + return ok; +} + +static bool +is_fido(const struct hid_device_info *hdi) +{ + uint32_t usage = 0; + uint32_t usage_page = 0; + struct hidraw_report_descriptor hrd; + + memset(&hrd, 0, sizeof(hrd)); + + if (get_report_descriptor(hdi->path, &hrd) < 0 || + get_usage_info(&hrd, &usage_page, &usage) < 0) { + return false; + } + + return usage_page == 0xf1d0; +} +#elif defined(_WIN32) || defined(__APPLE__) +static bool +is_fido(const struct hid_device_info *hdi) +{ + return hdi->usage_page == 0xf1d0; +} +#else +static bool +is_fido(const struct hid_device_info *hdi) +{ + (void)hdi; + fido_log_debug("%s: assuming FIDO HID", __func__); + return true; +} +#endif + void * fido_hid_open(const char *path) { - return hid_open_path(path); + struct hid_hidapi *ctx; + + if ((ctx = calloc(1, sizeof(*ctx))) == NULL) { + return (NULL); + } + + if ((ctx->handle = hid_open_path(path)) == NULL) { + free(ctx); + return (NULL); + } + + ctx->report_in_len = ctx->report_out_len = CTAP_MAX_REPORT_LEN; + + return ctx; } void -fido_hid_close(void *hid_dev_handle) +fido_hid_close(void *handle) { - hid_close(hid_dev_handle); + struct hid_hidapi *ctx = handle; + + hid_close(ctx->handle); + free(ctx); } int -fido_hid_read(void *hid_dev_handle, unsigned char *buf, size_t len, int ms) +fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) { - return hid_read_timeout(hid_dev_handle, buf, len, ms); + struct hid_hidapi *ctx = handle; + + if (len != ctx->report_in_len) { + fido_log_debug("%s: len %zu", __func__, len); + return -1; + } + + return hid_read_timeout(ctx->handle, buf, len, ms); } int -fido_hid_write(void *hid_dev_handle, const unsigned char *buf, size_t len) +fido_hid_write(void *handle, const unsigned char *buf, size_t len) { - return hid_write(hid_dev_handle, buf, len); + struct hid_hidapi *ctx = handle; + + if (len != ctx->report_out_len + 1) { + fido_log_debug("%s: len %zu", __func__, len); + return -1; + } + + return hid_write(ctx->handle, buf, len); } int @@ -122,10 +306,8 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) return FIDO_OK; /* nothing to do */ for (struct hid_device_info *d = hdi; d != NULL; d = d->next) { -#if defined(_WIN32) || defined(__APPLE__) - if (d->usage_page != 0xf1d0) + if (is_fido(d) == false) continue; -#endif if (copy_info(&devlist[*olen], d) == 0) { if (++(*olen) == ilen) break; @@ -136,3 +318,19 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) return FIDO_OK; } + +size_t +fido_hid_report_in_len(void *handle) +{ + struct hid_hidapi *ctx = handle; + + return (ctx->report_in_len); +} + +size_t +fido_hid_report_out_len(void *handle) +{ + struct hid_hidapi *ctx = handle; + + return (ctx->report_out_len); +} -- cgit v1.2.3