diff options
Diffstat (limited to 'src/info.c')
-rw-r--r-- | src/info.c | 410 |
1 files changed, 410 insertions, 0 deletions
diff --git a/src/info.c b/src/info.c new file mode 100644 index 0000000..e896503 --- /dev/null +++ b/src/info.c | |||
@@ -0,0 +1,410 @@ | |||
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 <string.h> | ||
8 | #include "fido.h" | ||
9 | |||
10 | static int | ||
11 | decode_version(const cbor_item_t *item, void *arg) | ||
12 | { | ||
13 | fido_str_array_t *v = arg; | ||
14 | const size_t i = v->len; | ||
15 | |||
16 | /* keep ptr[x] and len consistent */ | ||
17 | if (cbor_string_copy(item, &v->ptr[i]) < 0) { | ||
18 | fido_log_debug("%s: cbor_string_copy", __func__); | ||
19 | return (-1); | ||
20 | } | ||
21 | |||
22 | v->len++; | ||
23 | |||
24 | return (0); | ||
25 | } | ||
26 | |||
27 | static int | ||
28 | decode_versions(const cbor_item_t *item, fido_str_array_t *v) | ||
29 | { | ||
30 | v->ptr = NULL; | ||
31 | v->len = 0; | ||
32 | |||
33 | if (cbor_isa_array(item) == false || | ||
34 | cbor_array_is_definite(item) == false) { | ||
35 | fido_log_debug("%s: cbor type", __func__); | ||
36 | return (-1); | ||
37 | } | ||
38 | |||
39 | v->ptr = calloc(cbor_array_size(item), sizeof(char *)); | ||
40 | if (v->ptr == NULL) | ||
41 | return (-1); | ||
42 | |||
43 | if (cbor_array_iter(item, v, decode_version) < 0) { | ||
44 | fido_log_debug("%s: decode_version", __func__); | ||
45 | return (-1); | ||
46 | } | ||
47 | |||
48 | return (0); | ||
49 | } | ||
50 | |||
51 | static int | ||
52 | decode_extension(const cbor_item_t *item, void *arg) | ||
53 | { | ||
54 | fido_str_array_t *e = arg; | ||
55 | const size_t i = e->len; | ||
56 | |||
57 | /* keep ptr[x] and len consistent */ | ||
58 | if (cbor_string_copy(item, &e->ptr[i]) < 0) { | ||
59 | fido_log_debug("%s: cbor_string_copy", __func__); | ||
60 | return (-1); | ||
61 | } | ||
62 | |||
63 | e->len++; | ||
64 | |||
65 | return (0); | ||
66 | } | ||
67 | |||
68 | static int | ||
69 | decode_extensions(const cbor_item_t *item, fido_str_array_t *e) | ||
70 | { | ||
71 | e->ptr = NULL; | ||
72 | e->len = 0; | ||
73 | |||
74 | if (cbor_isa_array(item) == false || | ||
75 | cbor_array_is_definite(item) == false) { | ||
76 | fido_log_debug("%s: cbor type", __func__); | ||
77 | return (-1); | ||
78 | } | ||
79 | |||
80 | e->ptr = calloc(cbor_array_size(item), sizeof(char *)); | ||
81 | if (e->ptr == NULL) | ||
82 | return (-1); | ||
83 | |||
84 | if (cbor_array_iter(item, e, decode_extension) < 0) { | ||
85 | fido_log_debug("%s: decode_extension", __func__); | ||
86 | return (-1); | ||
87 | } | ||
88 | |||
89 | return (0); | ||
90 | } | ||
91 | |||
92 | static int | ||
93 | decode_aaguid(const cbor_item_t *item, unsigned char *aaguid, size_t aaguid_len) | ||
94 | { | ||
95 | if (cbor_isa_bytestring(item) == false || | ||
96 | cbor_bytestring_is_definite(item) == false || | ||
97 | cbor_bytestring_length(item) != aaguid_len) { | ||
98 | fido_log_debug("%s: cbor type", __func__); | ||
99 | return (-1); | ||
100 | } | ||
101 | |||
102 | memcpy(aaguid, cbor_bytestring_handle(item), aaguid_len); | ||
103 | |||
104 | return (0); | ||
105 | } | ||
106 | |||
107 | static int | ||
108 | decode_option(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
109 | { | ||
110 | fido_opt_array_t *o = arg; | ||
111 | const size_t i = o->len; | ||
112 | |||
113 | if (cbor_isa_float_ctrl(val) == false || | ||
114 | cbor_float_get_width(val) != CBOR_FLOAT_0 || | ||
115 | cbor_is_bool(val) == false) { | ||
116 | fido_log_debug("%s: cbor type", __func__); | ||
117 | return (0); /* ignore */ | ||
118 | } | ||
119 | |||
120 | if (cbor_string_copy(key, &o->name[i]) < 0) { | ||
121 | fido_log_debug("%s: cbor_string_copy", __func__); | ||
122 | return (0); /* ignore */ | ||
123 | } | ||
124 | |||
125 | /* keep name/value and len consistent */ | ||
126 | o->value[i] = cbor_ctrl_value(val) == CBOR_CTRL_TRUE; | ||
127 | o->len++; | ||
128 | |||
129 | return (0); | ||
130 | } | ||
131 | |||
132 | static int | ||
133 | decode_options(const cbor_item_t *item, fido_opt_array_t *o) | ||
134 | { | ||
135 | o->name = NULL; | ||
136 | o->value = NULL; | ||
137 | o->len = 0; | ||
138 | |||
139 | if (cbor_isa_map(item) == false || | ||
140 | cbor_map_is_definite(item) == false) { | ||
141 | fido_log_debug("%s: cbor type", __func__); | ||
142 | return (-1); | ||
143 | } | ||
144 | |||
145 | o->name = calloc(cbor_map_size(item), sizeof(char *)); | ||
146 | o->value = calloc(cbor_map_size(item), sizeof(bool)); | ||
147 | if (o->name == NULL || o->value == NULL) | ||
148 | return (-1); | ||
149 | |||
150 | return (cbor_map_iter(item, o, decode_option)); | ||
151 | } | ||
152 | |||
153 | static int | ||
154 | decode_protocol(const cbor_item_t *item, void *arg) | ||
155 | { | ||
156 | fido_byte_array_t *p = arg; | ||
157 | const size_t i = p->len; | ||
158 | |||
159 | if (cbor_isa_uint(item) == false || | ||
160 | cbor_int_get_width(item) != CBOR_INT_8) { | ||
161 | fido_log_debug("%s: cbor type", __func__); | ||
162 | return (-1); | ||
163 | } | ||
164 | |||
165 | /* keep ptr[x] and len consistent */ | ||
166 | p->ptr[i] = cbor_get_uint8(item); | ||
167 | p->len++; | ||
168 | |||
169 | return (0); | ||
170 | } | ||
171 | |||
172 | static int | ||
173 | decode_protocols(const cbor_item_t *item, fido_byte_array_t *p) | ||
174 | { | ||
175 | p->ptr = NULL; | ||
176 | p->len = 0; | ||
177 | |||
178 | if (cbor_isa_array(item) == false || | ||
179 | cbor_array_is_definite(item) == false) { | ||
180 | fido_log_debug("%s: cbor type", __func__); | ||
181 | return (-1); | ||
182 | } | ||
183 | |||
184 | p->ptr = calloc(cbor_array_size(item), sizeof(uint8_t)); | ||
185 | if (p->ptr == NULL) | ||
186 | return (-1); | ||
187 | |||
188 | if (cbor_array_iter(item, p, decode_protocol) < 0) { | ||
189 | fido_log_debug("%s: decode_protocol", __func__); | ||
190 | return (-1); | ||
191 | } | ||
192 | |||
193 | return (0); | ||
194 | } | ||
195 | |||
196 | static int | ||
197 | parse_reply_element(const cbor_item_t *key, const cbor_item_t *val, void *arg) | ||
198 | { | ||
199 | fido_cbor_info_t *ci = arg; | ||
200 | |||
201 | if (cbor_isa_uint(key) == false || | ||
202 | cbor_int_get_width(key) != CBOR_INT_8) { | ||
203 | fido_log_debug("%s: cbor type", __func__); | ||
204 | return (0); /* ignore */ | ||
205 | } | ||
206 | |||
207 | switch (cbor_get_uint8(key)) { | ||
208 | case 1: /* versions */ | ||
209 | return (decode_versions(val, &ci->versions)); | ||
210 | case 2: /* extensions */ | ||
211 | return (decode_extensions(val, &ci->extensions)); | ||
212 | case 3: /* aaguid */ | ||
213 | return (decode_aaguid(val, ci->aaguid, sizeof(ci->aaguid))); | ||
214 | case 4: /* options */ | ||
215 | return (decode_options(val, &ci->options)); | ||
216 | case 5: /* maxMsgSize */ | ||
217 | return (cbor_decode_uint64(val, &ci->maxmsgsiz)); | ||
218 | case 6: /* pinProtocols */ | ||
219 | return (decode_protocols(val, &ci->protocols)); | ||
220 | default: /* ignore */ | ||
221 | fido_log_debug("%s: cbor type", __func__); | ||
222 | return (0); | ||
223 | } | ||
224 | } | ||
225 | |||
226 | static int | ||
227 | fido_dev_get_cbor_info_tx(fido_dev_t *dev) | ||
228 | { | ||
229 | const unsigned char cbor[] = { CTAP_CBOR_GETINFO }; | ||
230 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
231 | |||
232 | fido_log_debug("%s: dev=%p", __func__, (void *)dev); | ||
233 | |||
234 | if (fido_tx(dev, cmd, cbor, sizeof(cbor)) < 0) { | ||
235 | fido_log_debug("%s: fido_tx", __func__); | ||
236 | return (FIDO_ERR_TX); | ||
237 | } | ||
238 | |||
239 | return (FIDO_OK); | ||
240 | } | ||
241 | |||
242 | static int | ||
243 | fido_dev_get_cbor_info_rx(fido_dev_t *dev, fido_cbor_info_t *ci, int ms) | ||
244 | { | ||
245 | const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR; | ||
246 | unsigned char reply[512]; | ||
247 | int reply_len; | ||
248 | |||
249 | fido_log_debug("%s: dev=%p, ci=%p, ms=%d", __func__, (void *)dev, | ||
250 | (void *)ci, ms); | ||
251 | |||
252 | memset(ci, 0, sizeof(*ci)); | ||
253 | |||
254 | if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) { | ||
255 | fido_log_debug("%s: fido_rx", __func__); | ||
256 | return (FIDO_ERR_RX); | ||
257 | } | ||
258 | |||
259 | return (cbor_parse_reply(reply, (size_t)reply_len, ci, | ||
260 | parse_reply_element)); | ||
261 | } | ||
262 | |||
263 | static int | ||
264 | fido_dev_get_cbor_info_wait(fido_dev_t *dev, fido_cbor_info_t *ci, int ms) | ||
265 | { | ||
266 | int r; | ||
267 | |||
268 | if ((r = fido_dev_get_cbor_info_tx(dev)) != FIDO_OK || | ||
269 | (r = fido_dev_get_cbor_info_rx(dev, ci, ms)) != FIDO_OK) | ||
270 | return (r); | ||
271 | |||
272 | return (FIDO_OK); | ||
273 | } | ||
274 | |||
275 | int | ||
276 | fido_dev_get_cbor_info(fido_dev_t *dev, fido_cbor_info_t *ci) | ||
277 | { | ||
278 | return (fido_dev_get_cbor_info_wait(dev, ci, -1)); | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | * get/set functions for fido_cbor_info_t; always at the end of the file | ||
283 | */ | ||
284 | |||
285 | fido_cbor_info_t * | ||
286 | fido_cbor_info_new(void) | ||
287 | { | ||
288 | return (calloc(1, sizeof(fido_cbor_info_t))); | ||
289 | } | ||
290 | |||
291 | static void | ||
292 | free_str_array(fido_str_array_t *sa) | ||
293 | { | ||
294 | for (size_t i = 0; i < sa->len; i++) | ||
295 | free(sa->ptr[i]); | ||
296 | |||
297 | free(sa->ptr); | ||
298 | sa->ptr = NULL; | ||
299 | sa->len = 0; | ||
300 | } | ||
301 | |||
302 | static void | ||
303 | free_opt_array(fido_opt_array_t *oa) | ||
304 | { | ||
305 | for (size_t i = 0; i < oa->len; i++) | ||
306 | free(oa->name[i]); | ||
307 | |||
308 | free(oa->name); | ||
309 | free(oa->value); | ||
310 | oa->name = NULL; | ||
311 | oa->value = NULL; | ||
312 | } | ||
313 | |||
314 | static void | ||
315 | free_byte_array(fido_byte_array_t *ba) | ||
316 | { | ||
317 | free(ba->ptr); | ||
318 | |||
319 | ba->ptr = NULL; | ||
320 | ba->len = 0; | ||
321 | } | ||
322 | |||
323 | void | ||
324 | fido_cbor_info_free(fido_cbor_info_t **ci_p) | ||
325 | { | ||
326 | fido_cbor_info_t *ci; | ||
327 | |||
328 | if (ci_p == NULL || (ci = *ci_p) == NULL) | ||
329 | return; | ||
330 | |||
331 | free_str_array(&ci->versions); | ||
332 | free_str_array(&ci->extensions); | ||
333 | free_opt_array(&ci->options); | ||
334 | free_byte_array(&ci->protocols); | ||
335 | free(ci); | ||
336 | |||
337 | *ci_p = NULL; | ||
338 | } | ||
339 | |||
340 | char ** | ||
341 | fido_cbor_info_versions_ptr(const fido_cbor_info_t *ci) | ||
342 | { | ||
343 | return (ci->versions.ptr); | ||
344 | } | ||
345 | |||
346 | size_t | ||
347 | fido_cbor_info_versions_len(const fido_cbor_info_t *ci) | ||
348 | { | ||
349 | return (ci->versions.len); | ||
350 | } | ||
351 | |||
352 | char ** | ||
353 | fido_cbor_info_extensions_ptr(const fido_cbor_info_t *ci) | ||
354 | { | ||
355 | return (ci->extensions.ptr); | ||
356 | } | ||
357 | |||
358 | size_t | ||
359 | fido_cbor_info_extensions_len(const fido_cbor_info_t *ci) | ||
360 | { | ||
361 | return (ci->extensions.len); | ||
362 | } | ||
363 | |||
364 | const unsigned char * | ||
365 | fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *ci) | ||
366 | { | ||
367 | return (ci->aaguid); | ||
368 | } | ||
369 | |||
370 | size_t | ||
371 | fido_cbor_info_aaguid_len(const fido_cbor_info_t *ci) | ||
372 | { | ||
373 | return (sizeof(ci->aaguid)); | ||
374 | } | ||
375 | |||
376 | char ** | ||
377 | fido_cbor_info_options_name_ptr(const fido_cbor_info_t *ci) | ||
378 | { | ||
379 | return (ci->options.name); | ||
380 | } | ||
381 | |||
382 | const bool * | ||
383 | fido_cbor_info_options_value_ptr(const fido_cbor_info_t *ci) | ||
384 | { | ||
385 | return (ci->options.value); | ||
386 | } | ||
387 | |||
388 | size_t | ||
389 | fido_cbor_info_options_len(const fido_cbor_info_t *ci) | ||
390 | { | ||
391 | return (ci->options.len); | ||
392 | } | ||
393 | |||
394 | uint64_t | ||
395 | fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *ci) | ||
396 | { | ||
397 | return (ci->maxmsgsiz); | ||
398 | } | ||
399 | |||
400 | const uint8_t * | ||
401 | fido_cbor_info_protocols_ptr(const fido_cbor_info_t *ci) | ||
402 | { | ||
403 | return (ci->protocols.ptr); | ||
404 | } | ||
405 | |||
406 | size_t | ||
407 | fido_cbor_info_protocols_len(const fido_cbor_info_t *ci) | ||
408 | { | ||
409 | return (ci->protocols.len); | ||
410 | } | ||