1/* 2 * Copyright (c) 2018 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 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include "fido.h" 9 10static int 11get_key_len(uint8_t tag, uint8_t *key, size_t *key_len) 12{ 13 *key = tag & 0xfc; 14 if ((*key & 0xf0) == 0xf0) { 15 fido_log_debug("%s: *key=0x%02x", __func__, *key); 16 return (-1); 17 } 18 19 *key_len = tag & 0x3; 20 if (*key_len == 3) { 21 *key_len = 4; 22 } 23 24 return (0); 25} 26 27static int 28get_key_val(const void *body, size_t key_len, uint32_t *val) 29{ 30 const uint8_t *ptr = body; 31 32 switch (key_len) { 33 case 0: 34 *val = 0; 35 break; 36 case 1: 37 *val = ptr[0]; 38 break; 39 case 2: 40 *val = (uint32_t)((ptr[1] << 8) | ptr[0]); 41 break; 42 default: 43 fido_log_debug("%s: key_len=%zu", __func__, key_len); 44 return (-1); 45 } 46 47 return (0); 48} 49 50int 51fido_hid_get_usage(const uint8_t *report_ptr, size_t report_len, 52 uint32_t *usage_page) 53{ 54 const uint8_t *ptr = report_ptr; 55 size_t len = report_len; 56 57 while (len > 0) { 58 const uint8_t tag = ptr[0]; 59 ptr++; 60 len--; 61 62 uint8_t key; 63 size_t key_len; 64 uint32_t key_val; 65 66 if (get_key_len(tag, &key, &key_len) < 0 || key_len > len || 67 get_key_val(ptr, key_len, &key_val) < 0) { 68 return (-1); 69 } 70 71 if (key == 0x4) { 72 *usage_page = key_val; 73 } 74 75 ptr += key_len; 76 len -= key_len; 77 } 78 79 return (0); 80} 81 82int 83fido_hid_get_report_len(const uint8_t *report_ptr, size_t report_len, 84 size_t *report_in_len, size_t *report_out_len) 85{ 86 const uint8_t *ptr = report_ptr; 87 size_t len = report_len; 88 uint32_t report_size = 0; 89 90 while (len > 0) { 91 const uint8_t tag = ptr[0]; 92 ptr++; 93 len--; 94 95 uint8_t key; 96 size_t key_len; 97 uint32_t key_val; 98 99 if (get_key_len(tag, &key, &key_len) < 0 || key_len > len || 100 get_key_val(ptr, key_len, &key_val) < 0) { 101 return (-1); 102 } 103 104 if (key == 0x94) { 105 report_size = key_val; 106 } else if (key == 0x80) { 107 *report_in_len = (size_t)report_size; 108 } else if (key == 0x90) { 109 *report_out_len = (size_t)report_size; 110 } 111 112 ptr += key_len; 113 len -= key_len; 114 } 115 116 return (0); 117} 118 119fido_dev_info_t * 120fido_dev_info_new(size_t n) 121{ 122 return (calloc(n, sizeof(fido_dev_info_t))); 123} 124 125static void 126fido_dev_info_reset(fido_dev_info_t *di) 127{ 128 free(di->path); 129 free(di->manufacturer); 130 free(di->product); 131 memset(di, 0, sizeof(*di)); 132} 133 134void 135fido_dev_info_free(fido_dev_info_t **devlist_p, size_t n) 136{ 137 fido_dev_info_t *devlist; 138 139 if (devlist_p == NULL || (devlist = *devlist_p) == NULL) 140 return; 141 142 for (size_t i = 0; i < n; i++) 143 fido_dev_info_reset(&devlist[i]); 144 145 free(devlist); 146 147 *devlist_p = NULL; 148} 149 150const fido_dev_info_t * 151fido_dev_info_ptr(const fido_dev_info_t *devlist, size_t i) 152{ 153 return (&devlist[i]); 154} 155 156int 157fido_dev_info_set(fido_dev_info_t *devlist, size_t i, 158 const char *path, const char *manufacturer, const char *product, 159 const fido_dev_io_t *io, const fido_dev_transport_t *transport) 160{ 161 char *path_copy = NULL, *manu_copy = NULL, *prod_copy = NULL; 162 int r; 163 164 if (path == NULL || manufacturer == NULL || product == NULL || 165 io == NULL) { 166 r = FIDO_ERR_INVALID_ARGUMENT; 167 goto out; 168 } 169 170 if ((path_copy = strdup(path)) == NULL || 171 (manu_copy = strdup(manufacturer)) == NULL || 172 (prod_copy = strdup(product)) == NULL) { 173 r = FIDO_ERR_INTERNAL; 174 goto out; 175 } 176 177 fido_dev_info_reset(&devlist[i]); 178 devlist[i].path = path_copy; 179 devlist[i].manufacturer = manu_copy; 180 devlist[i].product = prod_copy; 181 devlist[i].io = *io; 182 if (transport) 183 devlist[i].transport = *transport; 184 r = FIDO_OK; 185out: 186 if (r != FIDO_OK) { 187 free(prod_copy); 188 free(manu_copy); 189 free(path_copy); 190 } 191 return (r); 192} 193 194const char * 195fido_dev_info_path(const fido_dev_info_t *di) 196{ 197 return (di->path); 198} 199 200int16_t 201fido_dev_info_vendor(const fido_dev_info_t *di) 202{ 203 return (di->vendor_id); 204} 205 206int16_t 207fido_dev_info_product(const fido_dev_info_t *di) 208{ 209 return (di->product_id); 210} 211 212const char * 213fido_dev_info_manufacturer_string(const fido_dev_info_t *di) 214{ 215 return (di->manufacturer); 216} 217 218const char * 219fido_dev_info_product_string(const fido_dev_info_t *di) 220{ 221 return (di->product); 222} 223