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
get_key_len(uint8_t tag,uint8_t * key,size_t * key_len)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
get_key_val(const void * body,size_t key_len,uint32_t * val)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
fido_hid_get_usage(const uint8_t * report_ptr,size_t report_len,uint32_t * usage_page)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
fido_hid_get_report_len(const uint8_t * report_ptr,size_t report_len,size_t * report_in_len,size_t * report_out_len)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 *
fido_dev_info_new(size_t n)119 fido_dev_info_new(size_t n)
120 {
121 return (calloc(n, sizeof(fido_dev_info_t)));
122 }
123
124 static void
fido_dev_info_reset(fido_dev_info_t * di)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
fido_dev_info_free(fido_dev_info_t ** devlist_p,size_t n)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 *
fido_dev_info_ptr(const fido_dev_info_t * devlist,size_t i)150 fido_dev_info_ptr(const fido_dev_info_t *devlist, size_t i)
151 {
152 return (&devlist[i]);
153 }
154
155 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)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 *
fido_dev_info_path(const fido_dev_info_t * di)194 fido_dev_info_path(const fido_dev_info_t *di)
195 {
196 return (di->path);
197 }
198
199 int16_t
fido_dev_info_vendor(const fido_dev_info_t * di)200 fido_dev_info_vendor(const fido_dev_info_t *di)
201 {
202 return (di->vendor_id);
203 }
204
205 int16_t
fido_dev_info_product(const fido_dev_info_t * di)206 fido_dev_info_product(const fido_dev_info_t *di)
207 {
208 return (di->product_id);
209 }
210
211 const char *
fido_dev_info_manufacturer_string(const fido_dev_info_t * di)212 fido_dev_info_manufacturer_string(const fido_dev_info_t *di)
213 {
214 return (di->manufacturer);
215 }
216
217 const char *
fido_dev_info_product_string(const fido_dev_info_t * di)218 fido_dev_info_product_string(const fido_dev_info_t *di)
219 {
220 return (di->product);
221 }
222