Coverage Report

Created: 2020-09-01 07:05

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