Coverage Report

Created: 2020-03-07 10:10

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