1 /* 2 * Copyright (c) 2019 Yubico AB. All rights reserved. 3 * Use of this source code is governed by a BSD-style 4 * license that can be found in the LICENSE file. 5 */ 6 7 #include <sys/types.h> 8 9 #include <sys/ioctl.h> 10 #include <linux/hidraw.h> 11 #include <linux/input.h> 12 13 #include <errno.h> 14 #include <fcntl.h> 15 #include <libudev.h> 16 #include <poll.h> 17 #include <string.h> 18 #include <unistd.h> 19 20 #include "fido.h" 21 22 struct hid_linux { 23 int fd; 24 size_t report_in_len; 25 size_t report_out_len; 26 }; 27 28 static int 29 get_key_len(uint8_t tag, uint8_t *key, size_t *key_len) 30 { 31 *key = tag & 0xfc; 32 if ((*key & 0xf0) == 0xf0) { 33 fido_log_debug("%s: *key=0x%02x", __func__, *key); 34 return (-1); 35 } 36 37 *key_len = tag & 0x3; 38 if (*key_len == 3) { 39 *key_len = 4; 40 } 41 42 return (0); 43 } 44 45 static int 46 get_key_val(const void *body, size_t key_len, uint32_t *val) 47 { 48 const uint8_t *ptr = body; 49 50 switch (key_len) { 51 case 0: 52 *val = 0; 53 break; 54 case 1: 55 *val = ptr[0]; 56 break; 57 case 2: 58 *val = (uint32_t)((ptr[1] << 8) | ptr[0]); 59 break; 60 default: 61 fido_log_debug("%s: key_len=%zu", __func__, key_len); 62 return (-1); 63 } 64 65 return (0); 66 } 67 68 static int 69 get_usage_info(const struct hidraw_report_descriptor *hrd, uint32_t *usage_page, 70 uint32_t *usage) 71 { 72 const uint8_t *ptr = hrd->value; 73 size_t len = hrd->size; 74 75 while (len > 0) { 76 const uint8_t tag = ptr[0]; 77 ptr++; 78 len--; 79 80 uint8_t key; 81 size_t key_len; 82 uint32_t key_val; 83 84 if (get_key_len(tag, &key, &key_len) < 0 || key_len > len || 85 get_key_val(ptr, key_len, &key_val) < 0) { 86 return (-1); 87 } 88 89 if (key == 0x4) { 90 *usage_page = key_val; 91 } else if (key == 0x8) { 92 *usage = key_val; 93 } 94 95 ptr += key_len; 96 len -= key_len; 97 } 98 99 return (0); 100 } 101 102 static int 103 get_report_sizes(const struct hidraw_report_descriptor *hrd, 104 size_t *report_in_len, size_t *report_out_len) 105 { 106 const uint8_t *ptr = hrd->value; 107 size_t len = hrd->size; 108 uint32_t report_size = 0; 109 110 while (len > 0) { 111 const uint8_t tag = ptr[0]; 112 ptr++; 113 len--; 114 115 uint8_t key; 116 size_t key_len; 117 uint32_t key_val; 118 119 if (get_key_len(tag, &key, &key_len) < 0 || key_len > len || 120 get_key_val(ptr, key_len, &key_val) < 0) { 121 return (-1); 122 } 123 124 if (key == 0x94) { 125 report_size = key_val; 126 } else if (key == 0x80) { 127 *report_in_len = (size_t)report_size; 128 } else if (key == 0x90) { 129 *report_out_len = (size_t)report_size; 130 } 131 132 ptr += key_len; 133 len -= key_len; 134 } 135 136 return (0); 137 } 138 139 static int 140 get_report_descriptor(int fd, struct hidraw_report_descriptor *hrd) 141 { 142 int s = -1; 143 144 if (ioctl(fd, HIDIOCGRDESCSIZE, &s) < 0 || s < 0 || 145 (unsigned)s > HID_MAX_DESCRIPTOR_SIZE) { 146 fido_log_debug("%s: ioctl HIDIOCGRDESCSIZE", __func__); 147 return (-1); 148 } 149 150 hrd->size = (unsigned)s; 151 152 if (ioctl(fd, HIDIOCGRDESC, hrd) < 0) { 153 fido_log_debug("%s: ioctl HIDIOCGRDESC", __func__); 154 return (-1); 155 } 156 157 return (0); 158 } 159 160 static bool 161 is_fido(const char *path) 162 { 163 int fd; 164 uint32_t usage = 0; 165 uint32_t usage_page = 0; 166 struct hidraw_report_descriptor hrd; 167 168 memset(&hrd, 0, sizeof(hrd)); 169 170 if ((fd = open(path, O_RDONLY)) == -1) { 171 fido_log_debug("%s: open", __func__); 172 return (false); 173 } 174 175 if (get_report_descriptor(fd, &hrd) < 0 || 176 get_usage_info(&hrd, &usage_page, &usage) < 0) { 177 close(fd); 178 return (false); 179 } 180 181 close(fd); 182 183 return (usage_page == 0xf1d0); 184 } 185 186 static int 187 parse_uevent(const char *uevent, int *bus, int16_t *vendor_id, 188 int16_t *product_id) 189 { 190 char *cp; 191 char *p; 192 char *s; 193 int ok = -1; 194 short unsigned int x; 195 short unsigned int y; 196 short unsigned int z; 197 198 if ((s = cp = strdup(uevent)) == NULL) 199 return (-1); 200 201 while ((p = strsep(&cp, "\n")) != NULL && *p != '\0') { 202 if (strncmp(p, "HID_ID=", 7) == 0) { 203 if (sscanf(p + 7, "%hx:%hx:%hx", &x, &y, &z) == 3) { 204 *bus = (int)x; 205 *vendor_id = (int16_t)y; 206 *product_id = (int16_t)z; 207 ok = 0; 208 break; 209 } 210 } 211 } 212 213 free(s); 214 215 return (ok); 216 } 217 218 static char * 219 get_parent_attr(struct udev_device *dev, const char *subsystem, 220 const char *devtype, const char *attr) 221 { 222 struct udev_device *parent; 223 const char *value; 224 225 if ((parent = udev_device_get_parent_with_subsystem_devtype(dev, 226 subsystem, devtype)) == NULL || (value = 227 udev_device_get_sysattr_value(parent, attr)) == NULL) 228 return (NULL); 229 230 return (strdup(value)); 231 } 232 233 static char * 234 get_usb_attr(struct udev_device *dev, const char *attr) 235 { 236 return (get_parent_attr(dev, "usb", "usb_device", attr)); 237 } 238 239 static int 240 copy_info(fido_dev_info_t *di, struct udev *udev, 241 struct udev_list_entry *udev_entry) 242 { 243 const char *name; 244 const char *path; 245 char *uevent = NULL; 246 struct udev_device *dev = NULL; 247 int bus = 0; 248 int ok = -1; 249 250 memset(di, 0, sizeof(*di)); 251 252 if ((name = udev_list_entry_get_name(udev_entry)) == NULL || 253 (dev = udev_device_new_from_syspath(udev, name)) == NULL || 254 (path = udev_device_get_devnode(dev)) == NULL || 255 is_fido(path) == 0) 256 goto fail; 257 258 if ((uevent = get_parent_attr(dev, "hid", NULL, "uevent")) == NULL || 259 parse_uevent(uevent, &bus, &di->vendor_id, &di->product_id) < 0) { 260 fido_log_debug("%s: uevent", __func__); 261 goto fail; 262 } 263 264 #ifndef FIDO_HID_ANY 265 if (bus != BUS_USB) { 266 fido_log_debug("%s: bus", __func__); 267 goto fail; 268 } 269 #endif 270 271 di->path = strdup(path); 272 di->manufacturer = get_usb_attr(dev, "manufacturer"); 273 di->product = get_usb_attr(dev, "product"); 274 275 if (di->path == NULL || di->manufacturer == NULL || di->product == NULL) 276 goto fail; 277 278 ok = 0; 279 fail: 280 if (dev != NULL) 281 udev_device_unref(dev); 282 283 free(uevent); 284 285 if (ok < 0) { 286 free(di->path); 287 free(di->manufacturer); 288 free(di->product); 289 explicit_bzero(di, sizeof(*di)); 290 } 291 292 return (ok); 293 } 294 295 int 296 fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) 297 { 298 struct udev *udev = NULL; 299 struct udev_enumerate *udev_enum = NULL; 300 struct udev_list_entry *udev_list; 301 struct udev_list_entry *udev_entry; 302 int r = FIDO_ERR_INTERNAL; 303 304 *olen = 0; 305 306 if (ilen == 0) 307 return (FIDO_OK); /* nothing to do */ 308 309 if (devlist == NULL) 310 return (FIDO_ERR_INVALID_ARGUMENT); 311 312 if ((udev = udev_new()) == NULL || 313 (udev_enum = udev_enumerate_new(udev)) == NULL) 314 goto fail; 315 316 if (udev_enumerate_add_match_subsystem(udev_enum, "hidraw") < 0 || 317 udev_enumerate_scan_devices(udev_enum) < 0) 318 goto fail; 319 320 if ((udev_list = udev_enumerate_get_list_entry(udev_enum)) == NULL) { 321 r = FIDO_OK; /* zero hidraw devices */ 322 goto fail; 323 } 324 325 udev_list_entry_foreach(udev_entry, udev_list) { 326 if (copy_info(&devlist[*olen], udev, udev_entry) == 0) { 327 devlist[*olen].io = (fido_dev_io_t) { 328 fido_hid_open, 329 fido_hid_close, 330 fido_hid_read, 331 fido_hid_write, 332 }; 333 if (++(*olen) == ilen) 334 break; 335 } 336 } 337 338 r = FIDO_OK; 339 fail: 340 if (udev_enum != NULL) 341 udev_enumerate_unref(udev_enum); 342 if (udev != NULL) 343 udev_unref(udev); 344 345 return (r); 346 } 347 348 void * 349 fido_hid_open(const char *path) 350 { 351 struct hid_linux *ctx; 352 struct hidraw_report_descriptor hrd; 353 354 if ((ctx = calloc(1, sizeof(*ctx))) == NULL) 355 return (NULL); 356 357 if ((ctx->fd = open(path, O_RDWR)) < 0) { 358 free(ctx); 359 return (NULL); 360 } 361 362 if (get_report_descriptor(ctx->fd, &hrd) < 0 || get_report_sizes(&hrd, 363 &ctx->report_in_len, &ctx->report_out_len) < 0 || 364 ctx->report_in_len == 0 || ctx->report_out_len == 0) { 365 fido_log_debug("%s: using default report sizes", __func__); 366 ctx->report_in_len = CTAP_MAX_REPORT_LEN; 367 ctx->report_out_len = CTAP_MAX_REPORT_LEN; 368 } 369 370 return (ctx); 371 } 372 373 void 374 fido_hid_close(void *handle) 375 { 376 struct hid_linux *ctx = handle; 377 378 close(ctx->fd); 379 free(ctx); 380 } 381 382 static int 383 timespec_to_ms(const struct timespec *ts, int upper_bound) 384 { 385 int64_t x; 386 int64_t y; 387 388 if (ts->tv_sec < 0 || ts->tv_sec > INT64_MAX / 1000LL || 389 ts->tv_nsec < 0 || ts->tv_nsec / 1000000LL > INT64_MAX) 390 return (upper_bound); 391 392 x = ts->tv_sec * 1000LL; 393 y = ts->tv_nsec / 1000000LL; 394 395 if (INT64_MAX - x < y || x + y > upper_bound) 396 return (upper_bound); 397 398 return (int)(x + y); 399 } 400 401 static int 402 waitfd(int fd, int ms) 403 { 404 struct timespec ts_start; 405 struct timespec ts_now; 406 struct timespec ts_delta; 407 struct pollfd pfd; 408 int ms_remain; 409 int r; 410 411 if (ms < 0) 412 return (0); 413 414 memset(&pfd, 0, sizeof(pfd)); 415 pfd.events = POLLIN; 416 pfd.fd = fd; 417 418 if (clock_gettime(CLOCK_MONOTONIC, &ts_start) != 0) { 419 fido_log_debug("%s: clock_gettime: %s", __func__, 420 strerror(errno)); 421 return (-1); 422 } 423 424 for (ms_remain = ms; ms_remain > 0;) { 425 if ((r = poll(&pfd, 1, ms_remain)) > 0) 426 return (0); 427 else if (r == 0) 428 break; 429 else if (errno != EINTR) { 430 fido_log_debug("%s: poll: %s", __func__, 431 strerror(errno)); 432 return (-1); 433 } 434 /* poll interrupted - subtract time already waited */ 435 if (clock_gettime(CLOCK_MONOTONIC, &ts_now) != 0) { 436 fido_log_debug("%s: clock_gettime: %s", __func__, 437 strerror(errno)); 438 return (-1); 439 } 440 timespecsub(&ts_now, &ts_start, &ts_delta); 441 ms_remain = ms - timespec_to_ms(&ts_delta, ms); 442 } 443 444 return (-1); 445 } 446 447 int 448 fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) 449 { 450 struct hid_linux *ctx = handle; 451 ssize_t r; 452 453 if (len != ctx->report_in_len) { 454 fido_log_debug("%s: len %zu", __func__, len); 455 return (-1); 456 } 457 458 if (waitfd(ctx->fd, ms) < 0) { 459 fido_log_debug("%s: fd not ready", __func__); 460 return (-1); 461 } 462 463 if ((r = read(ctx->fd, buf, len)) < 0 || (size_t)r != len) { 464 fido_log_debug("%s: read", __func__); 465 return (-1); 466 } 467 468 return ((int)r); 469 } 470 471 int 472 fido_hid_write(void *handle, const unsigned char *buf, size_t len) 473 { 474 struct hid_linux *ctx = handle; 475 ssize_t r; 476 477 if (len != ctx->report_out_len + 1) { 478 fido_log_debug("%s: len %zu", __func__, len); 479 return (-1); 480 } 481 482 if ((r = write(ctx->fd, buf, len)) < 0 || (size_t)r != len) { 483 fido_log_debug("%s: write", __func__); 484 return (-1); 485 } 486 487 return ((int)r); 488 } 489 490 size_t 491 fido_hid_report_in_len(void *handle) 492 { 493 struct hid_linux *ctx = handle; 494 495 return (ctx->report_in_len); 496 } 497 498 size_t 499 fido_hid_report_out_len(void *handle) 500 { 501 struct hid_linux *ctx = handle; 502 503 return (ctx->report_out_len); 504 } 505