/* * Copyright (c) 2018 Yubico AB. All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the LICENSE file. */ #include "fido.h" 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); } int fido_hid_get_usage(const uint8_t *report_ptr, size_t report_len, uint32_t *usage_page) { const uint8_t *ptr = report_ptr; size_t len = report_len; 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; } ptr += key_len; len -= key_len; } return (0); } int fido_hid_get_report_len(const uint8_t *report_ptr, size_t report_len, size_t *report_in_len, size_t *report_out_len) { const uint8_t *ptr = report_ptr; size_t len = report_len; uint32_t report_size = 0; 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 == 0x94) { report_size = key_val; } else if (key == 0x80) { *report_in_len = (size_t)report_size; } else if (key == 0x90) { *report_out_len = (size_t)report_size; } ptr += key_len; len -= key_len; } return (0); } fido_dev_info_t * fido_dev_info_new(size_t n) { return (calloc(n, sizeof(fido_dev_info_t))); } static void fido_dev_info_reset(fido_dev_info_t *di) { free(di->path); free(di->manufacturer); free(di->product); memset(di, 0, sizeof(*di)); } void fido_dev_info_free(fido_dev_info_t **devlist_p, size_t n) { fido_dev_info_t *devlist; if (devlist_p == NULL || (devlist = *devlist_p) == NULL) return; for (size_t i = 0; i < n; i++) fido_dev_info_reset(&devlist[i]); free(devlist); *devlist_p = NULL; } const fido_dev_info_t * fido_dev_info_ptr(const fido_dev_info_t *devlist, size_t i) { return (&devlist[i]); } int fido_dev_info_set(fido_dev_info_t *devlist, size_t i, const char *path, const char *manufacturer, const char *product, const fido_dev_io_t *io, const fido_dev_transport_t *transport) { char *path_copy = NULL, *manu_copy = NULL, *prod_copy = NULL; int r; if (path == NULL || manufacturer == NULL || product == NULL || io == NULL) { r = FIDO_ERR_INVALID_ARGUMENT; goto out; } if ((path_copy = strdup(path)) == NULL || (manu_copy = strdup(manufacturer)) == NULL || (prod_copy = strdup(product)) == NULL) { r = FIDO_ERR_INTERNAL; goto out; } fido_dev_info_reset(&devlist[i]); devlist[i].path = path_copy; devlist[i].manufacturer = manu_copy; devlist[i].product = prod_copy; devlist[i].io = *io; if (transport) devlist[i].transport = *transport; r = FIDO_OK; out: if (r != FIDO_OK) { free(prod_copy); free(manu_copy); free(path_copy); } return (r); } const char * fido_dev_info_path(const fido_dev_info_t *di) { return (di->path); } int16_t fido_dev_info_vendor(const fido_dev_info_t *di) { return (di->vendor_id); } int16_t fido_dev_info_product(const fido_dev_info_t *di) { return (di->product_id); } const char * fido_dev_info_manufacturer_string(const fido_dev_info_t *di) { return (di->manufacturer); } const char * fido_dev_info_product_string(const fido_dev_info_t *di) { return (di->product); }