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 10 static int 11 get_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 27 static int 28 get_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 50 int 51 fido_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 82 int 83 fido_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 119 fido_dev_info_t * 120 fido_dev_info_new(size_t n) 121 { 122 return (calloc(n, sizeof(fido_dev_info_t))); 123 } 124 125 static void 126 fido_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 134 void 135 fido_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 150 const fido_dev_info_t * 151 fido_dev_info_ptr(const fido_dev_info_t *devlist, size_t i) 152 { 153 return (&devlist[i]); 154 } 155 156 int 157 fido_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; 185 out: 186 if (r != FIDO_OK) { 187 free(prod_copy); 188 free(manu_copy); 189 free(path_copy); 190 } 191 return (r); 192 } 193 194 const char * 195 fido_dev_info_path(const fido_dev_info_t *di) 196 { 197 return (di->path); 198 } 199 200 int16_t 201 fido_dev_info_vendor(const fido_dev_info_t *di) 202 { 203 return (di->vendor_id); 204 } 205 206 int16_t 207 fido_dev_info_product(const fido_dev_info_t *di) 208 { 209 return (di->product_id); 210 } 211 212 const char * 213 fido_dev_info_manufacturer_string(const fido_dev_info_t *di) 214 { 215 return (di->manufacturer); 216 } 217 218 const char * 219 fido_dev_info_product_string(const fido_dev_info_t *di) 220 { 221 return (di->product); 222 } 223