Path: blob/main/contrib/libfido2/src/hid_hidapi.c
104186 views
/*1* Copyright (c) 2019 Google LLC. All rights reserved.2* Use of this source code is governed by a BSD-style3* license that can be found in the LICENSE file.4* SPDX-License-Identifier: BSD-2-Clause5*/67#ifdef __linux__8#include <sys/ioctl.h>9#include <linux/hidraw.h>10#include <linux/input.h>11#include <fcntl.h>12#endif1314#include <errno.h>15#include <hidapi.h>16#include <wchar.h>1718#include "fido.h"1920struct hid_hidapi {21void *handle;22size_t report_in_len;23size_t report_out_len;24};2526static size_t27fido_wcslen(const wchar_t *wcs)28{29size_t l = 0;30while (*wcs++ != L'\0')31l++;32return l;33}3435static char *36wcs_to_cs(const wchar_t *wcs)37{38char *cs;39size_t i;4041if (wcs == NULL || (cs = calloc(fido_wcslen(wcs) + 1, 1)) == NULL)42return NULL;4344for (i = 0; i < fido_wcslen(wcs); i++) {45if (wcs[i] >= 128) {46/* give up on parsing non-ASCII text */47free(cs);48return strdup("hidapi device");49}50cs[i] = (char)wcs[i];51}5253return cs;54}5556static int57copy_info(fido_dev_info_t *di, const struct hid_device_info *d)58{59memset(di, 0, sizeof(*di));6061if (d->path != NULL)62di->path = strdup(d->path);63else64di->path = strdup("");6566if (d->manufacturer_string != NULL)67di->manufacturer = wcs_to_cs(d->manufacturer_string);68else69di->manufacturer = strdup("");7071if (d->product_string != NULL)72di->product = wcs_to_cs(d->product_string);73else74di->product = strdup("");7576if (di->path == NULL ||77di->manufacturer == NULL ||78di->product == NULL) {79free(di->path);80free(di->manufacturer);81free(di->product);82explicit_bzero(di, sizeof(*di));83return -1;84}8586di->product_id = (int16_t)d->product_id;87di->vendor_id = (int16_t)d->vendor_id;88di->io = (fido_dev_io_t) {89&fido_hid_open,90&fido_hid_close,91&fido_hid_read,92&fido_hid_write,93};9495return 0;96}9798#ifdef __linux__99static int100get_report_descriptor(const char *path, struct hidraw_report_descriptor *hrd)101{102int fd;103int s = -1;104int ok = -1;105106if ((fd = fido_hid_unix_open(path)) == -1) {107fido_log_debug("%s: fido_hid_unix_open", __func__);108return -1;109}110111if (ioctl(fd, IOCTL_REQ(HIDIOCGRDESCSIZE), &s) < 0 || s < 0 ||112(unsigned)s > HID_MAX_DESCRIPTOR_SIZE) {113fido_log_error(errno, "%s: ioctl HIDIOCGRDESCSIZE", __func__);114goto fail;115}116117hrd->size = (unsigned)s;118119if (ioctl(fd, IOCTL_REQ(HIDIOCGRDESC), hrd) < 0) {120fido_log_error(errno, "%s: ioctl HIDIOCGRDESC", __func__);121goto fail;122}123124ok = 0;125fail:126if (fd != -1)127close(fd);128129return ok;130}131132static bool133is_fido(const struct hid_device_info *hdi)134{135uint32_t usage_page = 0;136struct hidraw_report_descriptor *hrd;137138if ((hrd = calloc(1, sizeof(*hrd))) == NULL ||139get_report_descriptor(hdi->path, hrd) < 0 ||140fido_hid_get_usage(hrd->value, hrd->size, &usage_page) < 0)141usage_page = 0;142143free(hrd);144145return usage_page == 0xf1d0;146}147#elif defined(_WIN32) || defined(__APPLE__)148static bool149is_fido(const struct hid_device_info *hdi)150{151return hdi->usage_page == 0xf1d0;152}153#else154static bool155is_fido(const struct hid_device_info *hdi)156{157(void)hdi;158fido_log_debug("%s: assuming FIDO HID", __func__);159return true;160}161#endif162163void *164fido_hid_open(const char *path)165{166struct hid_hidapi *ctx;167168if ((ctx = calloc(1, sizeof(*ctx))) == NULL) {169return (NULL);170}171172if ((ctx->handle = hid_open_path(path)) == NULL) {173free(ctx);174return (NULL);175}176177ctx->report_in_len = ctx->report_out_len = CTAP_MAX_REPORT_LEN;178179return ctx;180}181182void183fido_hid_close(void *handle)184{185struct hid_hidapi *ctx = handle;186187hid_close(ctx->handle);188free(ctx);189}190191int192fido_hid_set_sigmask(void *handle, const fido_sigset_t *sigmask)193{194(void)handle;195(void)sigmask;196197return (FIDO_ERR_INTERNAL);198}199200int201fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms)202{203struct hid_hidapi *ctx = handle;204205if (len != ctx->report_in_len) {206fido_log_debug("%s: len %zu", __func__, len);207return -1;208}209210return hid_read_timeout(ctx->handle, buf, len, ms);211}212213int214fido_hid_write(void *handle, const unsigned char *buf, size_t len)215{216struct hid_hidapi *ctx = handle;217218if (len != ctx->report_out_len + 1) {219fido_log_debug("%s: len %zu", __func__, len);220return -1;221}222223return hid_write(ctx->handle, buf, len);224}225226int227fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)228{229struct hid_device_info *hdi;230231*olen = 0;232233if (ilen == 0)234return FIDO_OK; /* nothing to do */235if (devlist == NULL)236return FIDO_ERR_INVALID_ARGUMENT;237if ((hdi = hid_enumerate(0, 0)) == NULL)238return FIDO_OK; /* nothing to do */239240for (struct hid_device_info *d = hdi; d != NULL; d = d->next) {241if (is_fido(d) == false)242continue;243if (copy_info(&devlist[*olen], d) == 0) {244if (++(*olen) == ilen)245break;246}247}248249hid_free_enumeration(hdi);250251return FIDO_OK;252}253254size_t255fido_hid_report_in_len(void *handle)256{257struct hid_hidapi *ctx = handle;258259return (ctx->report_in_len);260}261262size_t263fido_hid_report_out_len(void *handle)264{265struct hid_hidapi *ctx = handle;266267return (ctx->report_out_len);268}269270271