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 void 125 fido_dev_info_free(fido_dev_info_t **devlist_p, size_t n) 126 { 127 fido_dev_info_t *devlist; 128 129 if (devlist_p == NULL || (devlist = *devlist_p) == NULL) 130 return; 131 132 for (size_t i = 0; i < n; i++) { 133 const fido_dev_info_t *di; 134 di = &devlist[i]; 135 free(di->path); 136 free(di->manufacturer); 137 free(di->product); 138 } 139 140 free(devlist); 141 142 *devlist_p = NULL; 143 } 144 145 const fido_dev_info_t * 146 fido_dev_info_ptr(const fido_dev_info_t *devlist, size_t i) 147 { 148 return (&devlist[i]); 149 } 150 151 const char * 152 fido_dev_info_path(const fido_dev_info_t *di) 153 { 154 return (di->path); 155 } 156 157 int16_t 158 fido_dev_info_vendor(const fido_dev_info_t *di) 159 { 160 return (di->vendor_id); 161 } 162 163 int16_t 164 fido_dev_info_product(const fido_dev_info_t *di) 165 { 166 return (di->product_id); 167 } 168 169 const char * 170 fido_dev_info_manufacturer_string(const fido_dev_info_t *di) 171 { 172 return (di->manufacturer); 173 } 174 175 const char * 176 fido_dev_info_product_string(const fido_dev_info_t *di) 177 { 178 return (di->product); 179 } 180