summaryrefslogtreecommitdiff
path: root/src/info.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/info.c')
-rw-r--r--src/info.c410
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
10static int
11decode_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
27static int
28decode_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
51static int
52decode_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
68static int
69decode_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
92static int
93decode_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
107static int
108decode_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
132static int
133decode_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
153static int
154decode_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
172static int
173decode_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
196static int
197parse_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
226static int
227fido_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
242static int
243fido_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
263static int
264fido_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
275int
276fido_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
285fido_cbor_info_t *
286fido_cbor_info_new(void)
287{
288 return (calloc(1, sizeof(fido_cbor_info_t)));
289}
290
291static void
292free_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
302static void
303free_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
314static void
315free_byte_array(fido_byte_array_t *ba)
316{
317 free(ba->ptr);
318
319 ba->ptr = NULL;
320 ba->len = 0;
321}
322
323void
324fido_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
340char **
341fido_cbor_info_versions_ptr(const fido_cbor_info_t *ci)
342{
343 return (ci->versions.ptr);
344}
345
346size_t
347fido_cbor_info_versions_len(const fido_cbor_info_t *ci)
348{
349 return (ci->versions.len);
350}
351
352char **
353fido_cbor_info_extensions_ptr(const fido_cbor_info_t *ci)
354{
355 return (ci->extensions.ptr);
356}
357
358size_t
359fido_cbor_info_extensions_len(const fido_cbor_info_t *ci)
360{
361 return (ci->extensions.len);
362}
363
364const unsigned char *
365fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *ci)
366{
367 return (ci->aaguid);
368}
369
370size_t
371fido_cbor_info_aaguid_len(const fido_cbor_info_t *ci)
372{
373 return (sizeof(ci->aaguid));
374}
375
376char **
377fido_cbor_info_options_name_ptr(const fido_cbor_info_t *ci)
378{
379 return (ci->options.name);
380}
381
382const bool *
383fido_cbor_info_options_value_ptr(const fido_cbor_info_t *ci)
384{
385 return (ci->options.value);
386}
387
388size_t
389fido_cbor_info_options_len(const fido_cbor_info_t *ci)
390{
391 return (ci->options.len);
392}
393
394uint64_t
395fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *ci)
396{
397 return (ci->maxmsgsiz);
398}
399
400const uint8_t *
401fido_cbor_info_protocols_ptr(const fido_cbor_info_t *ci)
402{
403 return (ci->protocols.ptr);
404}
405
406size_t
407fido_cbor_info_protocols_len(const fido_cbor_info_t *ci)
408{
409 return (ci->protocols.len);
410}