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