Coverage Report

Created: 2021-10-21 13:35

/libfido2/src/info.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2018-2021 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
10
decode_string(const cbor_item_t *item, void *arg)
11
45.8k
{
12
45.8k
        fido_str_array_t        *a = arg;
13
45.8k
        const size_t             i = a->len;
14
15
        /* keep ptr[x] and len consistent */
16
45.8k
        if (cbor_string_copy(item, &a->ptr[i]) < 0) {
17
77
                fido_log_debug("%s: cbor_string_copy", __func__);
18
77
                return (-1);
19
77
        }
20
21
45.7k
        a->len++;
22
23
45.7k
        return (0);
24
45.7k
}
25
26
static int
27
decode_string_array(const cbor_item_t *item, fido_str_array_t *v)
28
18.3k
{
29
18.3k
        v->ptr = NULL;
30
18.3k
        v->len = 0;
31
32
18.3k
        if (cbor_isa_array(item) == false ||
33
18.3k
            cbor_array_is_definite(item) == false) {
34
51
                fido_log_debug("%s: cbor type", __func__);
35
51
                return (-1);
36
51
        }
37
38
18.3k
        v->ptr = calloc(cbor_array_size(item), sizeof(char *));
39
18.3k
        if (v->ptr == NULL)
40
18.3k
                return (-1);
41
42
18.2k
        if (cbor_array_iter(item, v, decode_string) < 0) {
43
85
                fido_log_debug("%s: decode_string", __func__);
44
85
                return (-1);
45
85
        }
46
47
18.1k
        return (0);
48
18.1k
}
49
50
static int
51
decode_aaguid(const cbor_item_t *item, unsigned char *aaguid, size_t aaguid_len)
52
8.44k
{
53
8.44k
        if (cbor_isa_bytestring(item) == false ||
54
8.44k
            cbor_bytestring_is_definite(item) == false ||
55
8.44k
            cbor_bytestring_length(item) != aaguid_len) {
56
102
                fido_log_debug("%s: cbor type", __func__);
57
102
                return (-1);
58
102
        }
59
60
8.34k
        memcpy(aaguid, cbor_bytestring_handle(item), aaguid_len);
61
62
8.34k
        return (0);
63
8.34k
}
64
65
static int
66
decode_option(const cbor_item_t *key, const cbor_item_t *val, void *arg)
67
46.4k
{
68
46.4k
        fido_opt_array_t        *o = arg;
69
46.4k
        const size_t             i = o->len;
70
71
46.4k
        if (cbor_isa_float_ctrl(val) == false ||
72
46.4k
            cbor_float_get_width(val) != CBOR_FLOAT_0 ||
73
46.4k
            cbor_is_bool(val) == false) {
74
2.31k
                fido_log_debug("%s: cbor type", __func__);
75
2.31k
                return (0); /* ignore */
76
2.31k
        }
77
78
44.1k
        if (cbor_string_copy(key, &o->name[i]) < 0) {
79
249
                fido_log_debug("%s: cbor_string_copy", __func__);
80
249
                return (0); /* ignore */
81
249
        }
82
83
        /* keep name/value and len consistent */
84
43.9k
        o->value[i] = cbor_ctrl_value(val) == CBOR_CTRL_TRUE;
85
43.9k
        o->len++;
86
87
43.9k
        return (0);
88
43.9k
}
89
90
static int
91
decode_options(const cbor_item_t *item, fido_opt_array_t *o)
92
8.15k
{
93
8.15k
        o->name = NULL;
94
8.15k
        o->value = NULL;
95
8.15k
        o->len = 0;
96
97
8.15k
        if (cbor_isa_map(item) == false ||
98
8.15k
            cbor_map_is_definite(item) == false) {
99
37
                fido_log_debug("%s: cbor type", __func__);
100
37
                return (-1);
101
37
        }
102
103
8.11k
        o->name = calloc(cbor_map_size(item), sizeof(char *));
104
8.11k
        o->value = calloc(cbor_map_size(item), sizeof(bool));
105
8.11k
        if (o->name == NULL || o->value == NULL)
106
8.11k
                return (-1);
107
108
8.09k
        return (cbor_map_iter(item, o, decode_option));
109
8.09k
}
110
111
static int
112
decode_protocol(const cbor_item_t *item, void *arg)
113
10.2k
{
114
10.2k
        fido_byte_array_t       *p = arg;
115
10.2k
        const size_t             i = p->len;
116
117
10.2k
        if (cbor_isa_uint(item) == false ||
118
10.2k
            cbor_int_get_width(item) != CBOR_INT_8) {
119
59
                fido_log_debug("%s: cbor type", __func__);
120
59
                return (-1);
121
59
        }
122
123
        /* keep ptr[x] and len consistent */
124
10.1k
        p->ptr[i] = cbor_get_uint8(item);
125
10.1k
        p->len++;
126
127
10.1k
        return (0);
128
10.1k
}
129
130
static int
131
decode_protocols(const cbor_item_t *item, fido_byte_array_t *p)
132
7.98k
{
133
7.98k
        p->ptr = NULL;
134
7.98k
        p->len = 0;
135
136
7.98k
        if (cbor_isa_array(item) == false ||
137
7.98k
            cbor_array_is_definite(item) == false) {
138
41
                fido_log_debug("%s: cbor type", __func__);
139
41
                return (-1);
140
41
        }
141
142
7.94k
        p->ptr = calloc(cbor_array_size(item), sizeof(uint8_t));
143
7.94k
        if (p->ptr == NULL)
144
7.94k
                return (-1);
145
146
7.93k
        if (cbor_array_iter(item, p, decode_protocol) < 0) {
147
63
                fido_log_debug("%s: decode_protocol", __func__);
148
63
                return (-1);
149
63
        }
150
151
7.86k
        return (0);
152
7.86k
}
153
154
static int
155
decode_algorithm_entry(const cbor_item_t *key, const cbor_item_t *val,
156
    void *arg)
157
23.8k
{
158
23.8k
        fido_algo_t *alg = arg;
159
23.8k
        char *name = NULL;
160
23.8k
        int ok = -1;
161
162
23.8k
        if (cbor_string_copy(key, &name) < 0) {
163
180
                fido_log_debug("%s: cbor type", __func__);
164
180
                ok = 0; /* ignore */
165
180
                goto out;
166
180
        }
167
168
23.7k
        if (!strcmp(name, "alg")) {
169
10.5k
                if (cbor_isa_negint(val) == false ||
170
10.5k
                    cbor_get_int(val) > INT_MAX || alg->cose != 0) {
171
391
                        fido_log_debug("%s: alg", __func__);
172
391
                        goto out;
173
391
                }
174
10.1k
                alg->cose = -(int)cbor_get_int(val) - 1;
175
13.2k
        } else if (!strcmp(name, "type")) {
176
9.11k
                if (cbor_string_copy(val, &alg->type) < 0) {
177
43
                        fido_log_debug("%s: type", __func__);
178
43
                        goto out;
179
43
                }
180
23.2k
        }
181
182
23.2k
        ok = 0;
183
23.8k
out:
184
23.8k
        free(name);
185
186
23.8k
        return (ok);
187
23.2k
}
188
189
static int
190
decode_algorithm(const cbor_item_t *item, void *arg)
191
12.6k
{
192
12.6k
        fido_algo_array_t *aa = arg;
193
12.6k
        const size_t i = aa->len;
194
195
12.6k
        if (cbor_isa_map(item) == false ||
196
12.6k
            cbor_map_is_definite(item) == false) {
197
96
                fido_log_debug("%s: cbor type", __func__);
198
96
                return (-1);
199
96
        }
200
201
12.5k
        memset(&aa->ptr[i], 0, sizeof(aa->ptr[i]));
202
203
12.5k
        if (cbor_map_iter(item, &aa->ptr[i], decode_algorithm_entry) < 0) {
204
681
                fido_log_debug("%s: decode_algorithm_entry", __func__);
205
681
                fido_algo_free(&aa->ptr[i]);
206
681
                return (-1);
207
681
        }
208
209
        /* keep ptr[x] and len consistent */
210
11.9k
        aa->len++;
211
212
11.9k
        return (0);
213
11.9k
}
214
215
static int
216
decode_algorithms(const cbor_item_t *item, fido_algo_array_t *aa)
217
6.45k
{
218
6.45k
        aa->ptr = NULL;
219
6.45k
        aa->len = 0;
220
221
6.45k
        if (cbor_isa_array(item) == false ||
222
6.45k
            cbor_array_is_definite(item) == false) {
223
45
                fido_log_debug("%s: cbor type", __func__);
224
45
                return (-1);
225
45
        }
226
227
6.41k
        aa->ptr = calloc(cbor_array_size(item), sizeof(fido_algo_t));
228
6.41k
        if (aa->ptr == NULL)
229
6.41k
                return (-1);
230
231
6.40k
        if (cbor_array_iter(item, aa, decode_algorithm) < 0) {
232
784
                fido_log_debug("%s: decode_algorithm", __func__);
233
784
                return (-1);
234
784
        }
235
236
5.61k
        return (0);
237
5.61k
}
238
239
static int
240
parse_reply_element(const cbor_item_t *key, const cbor_item_t *val, void *arg)
241
82.0k
{
242
82.0k
        fido_cbor_info_t *ci = arg;
243
244
82.0k
        if (cbor_isa_uint(key) == false ||
245
82.0k
            cbor_int_get_width(key) != CBOR_INT_8) {
246
2.93k
                fido_log_debug("%s: cbor type", __func__);
247
2.93k
                return (0); /* ignore */
248
2.93k
        }
249
250
79.0k
        switch (cbor_get_uint8(key)) {
251
8.58k
        case 1: /* versions */
252
8.58k
                return (decode_string_array(val, &ci->versions));
253
9.02k
        case 2: /* extensions */
254
9.02k
                return (decode_string_array(val, &ci->extensions));
255
8.44k
        case 3: /* aaguid */
256
8.44k
                return (decode_aaguid(val, ci->aaguid, sizeof(ci->aaguid)));
257
8.15k
        case 4: /* options */
258
8.15k
                return (decode_options(val, &ci->options));
259
8.24k
        case 5: /* maxMsgSize */
260
8.24k
                return (cbor_decode_uint64(val, &ci->maxmsgsiz));
261
7.98k
        case 6: /* pinProtocols */
262
7.98k
                return (decode_protocols(val, &ci->protocols));
263
7.66k
        case 7: /* maxCredentialCountInList */
264
7.66k
                return (cbor_decode_uint64(val, &ci->maxcredcntlst));
265
7.63k
        case 8: /* maxCredentialIdLength */
266
7.63k
                return (cbor_decode_uint64(val, &ci->maxcredidlen));
267
750
        case 9: /* transports */
268
750
                return (decode_string_array(val, &ci->transports));
269
6.45k
        case 10: /* algorithms */
270
6.45k
                return (decode_algorithms(val, &ci->algorithms));
271
587
        case 14: /* fwVersion */
272
587
                return (cbor_decode_uint64(val, &ci->fwversion));
273
563
        case 15: /* maxCredBlobLen */
274
563
                return (cbor_decode_uint64(val, &ci->maxcredbloblen));
275
4.99k
        default: /* ignore */
276
4.99k
                fido_log_debug("%s: cbor type", __func__);
277
4.99k
                return (0);
278
79.0k
        }
279
79.0k
}
280
281
static int
282
fido_dev_get_cbor_info_tx(fido_dev_t *dev, int *ms)
283
21.5k
{
284
21.5k
        const unsigned char cbor[] = { CTAP_CBOR_GETINFO };
285
286
21.5k
        fido_log_debug("%s: dev=%p", __func__, (void *)dev);
287
288
21.5k
        if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor), ms) < 0) {
289
281
                fido_log_debug("%s: fido_tx", __func__);
290
281
                return (FIDO_ERR_TX);
291
281
        }
292
293
21.3k
        return (FIDO_OK);
294
21.3k
}
295
296
static int
297
fido_dev_get_cbor_info_rx(fido_dev_t *dev, fido_cbor_info_t *ci, int *ms)
298
21.3k
{
299
21.3k
        unsigned char   reply[FIDO_MAXMSG];
300
21.3k
        int             reply_len;
301
302
21.3k
        fido_log_debug("%s: dev=%p, ci=%p, ms=%d", __func__, (void *)dev,
303
21.3k
            (void *)ci, *ms);
304
305
21.3k
        fido_cbor_info_reset(ci);
306
307
21.3k
        if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
308
21.3k
            ms)) < 0) {
309
5.54k
                fido_log_debug("%s: fido_rx", __func__);
310
5.54k
                return (FIDO_ERR_RX);
311
5.54k
        }
312
313
15.7k
        return (cbor_parse_reply(reply, (size_t)reply_len, ci,
314
15.7k
            parse_reply_element));
315
15.7k
}
316
317
int
318
fido_dev_get_cbor_info_wait(fido_dev_t *dev, fido_cbor_info_t *ci, int *ms)
319
21.5k
{
320
21.5k
        int r;
321
322
#ifdef USE_WINHELLO
323
        if (dev->flags & FIDO_DEV_WINHELLO)
324
                return (fido_winhello_get_cbor_info(dev, ci));
325
#endif
326
21.5k
        if ((r = fido_dev_get_cbor_info_tx(dev, ms)) != FIDO_OK ||
327
21.5k
            (r = fido_dev_get_cbor_info_rx(dev, ci, ms)) != FIDO_OK)
328
21.5k
                return (r);
329
330
7.89k
        return (FIDO_OK);
331
7.89k
}
332
333
int
334
fido_dev_get_cbor_info(fido_dev_t *dev, fido_cbor_info_t *ci)
335
426
{
336
426
        int ms = dev->timeout_ms;
337
338
426
        return (fido_dev_get_cbor_info_wait(dev, ci, &ms));
339
426
}
340
341
/*
342
 * get/set functions for fido_cbor_info_t; always at the end of the file
343
 */
344
345
fido_cbor_info_t *
346
fido_cbor_info_new(void)
347
21.6k
{
348
21.6k
        return (calloc(1, sizeof(fido_cbor_info_t)));
349
21.6k
}
350
351
void
352
fido_cbor_info_reset(fido_cbor_info_t *ci)
353
42.9k
{
354
42.9k
        fido_str_array_free(&ci->versions);
355
42.9k
        fido_str_array_free(&ci->extensions);
356
42.9k
        fido_str_array_free(&ci->transports);
357
42.9k
        fido_opt_array_free(&ci->options);
358
42.9k
        fido_byte_array_free(&ci->protocols);
359
42.9k
        fido_algo_array_free(&ci->algorithms);
360
42.9k
}
361
362
void
363
fido_cbor_info_free(fido_cbor_info_t **ci_p)
364
63.5k
{
365
63.5k
        fido_cbor_info_t *ci;
366
367
63.5k
        if (ci_p == NULL || (ci = *ci_p) ==  NULL)
368
63.5k
                return;
369
21.5k
        fido_cbor_info_reset(ci);
370
21.5k
        free(ci);
371
21.5k
        *ci_p = NULL;
372
21.5k
}
373
374
char **
375
fido_cbor_info_versions_ptr(const fido_cbor_info_t *ci)
376
339
{
377
339
        return (ci->versions.ptr);
378
339
}
379
380
size_t
381
fido_cbor_info_versions_len(const fido_cbor_info_t *ci)
382
765
{
383
765
        return (ci->versions.len);
384
765
}
385
386
char **
387
fido_cbor_info_extensions_ptr(const fido_cbor_info_t *ci)
388
7.98k
{
389
7.98k
        return (ci->extensions.ptr);
390
7.98k
}
391
392
size_t
393
fido_cbor_info_extensions_len(const fido_cbor_info_t *ci)
394
8.41k
{
395
8.41k
        return (ci->extensions.len);
396
8.41k
}
397
398
char **
399
fido_cbor_info_transports_ptr(const fido_cbor_info_t *ci)
400
48
{
401
48
        return (ci->transports.ptr);
402
48
}
403
404
size_t
405
fido_cbor_info_transports_len(const fido_cbor_info_t *ci)
406
474
{
407
474
        return (ci->transports.len);
408
474
}
409
410
const unsigned char *
411
fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *ci)
412
426
{
413
426
        return (ci->aaguid);
414
426
}
415
416
size_t
417
fido_cbor_info_aaguid_len(const fido_cbor_info_t *ci)
418
426
{
419
426
        return (sizeof(ci->aaguid));
420
426
}
421
422
char **
423
fido_cbor_info_options_name_ptr(const fido_cbor_info_t *ci)
424
8.04k
{
425
8.04k
        return (ci->options.name);
426
8.04k
}
427
428
const bool *
429
fido_cbor_info_options_value_ptr(const fido_cbor_info_t *ci)
430
8.04k
{
431
8.04k
        return (ci->options.value);
432
8.04k
}
433
434
size_t
435
fido_cbor_info_options_len(const fido_cbor_info_t *ci)
436
8.47k
{
437
8.47k
        return (ci->options.len);
438
8.47k
}
439
440
uint64_t
441
fido_cbor_info_maxcredbloblen(const fido_cbor_info_t *ci)
442
426
{
443
426
        return (ci->maxcredbloblen);
444
426
}
445
446
uint64_t
447
fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *ci)
448
8.30k
{
449
8.30k
        return (ci->maxmsgsiz);
450
8.30k
}
451
452
uint64_t
453
fido_cbor_info_maxcredcntlst(const fido_cbor_info_t *ci)
454
426
{
455
426
        return (ci->maxcredcntlst);
456
426
}
457
458
uint64_t
459
fido_cbor_info_maxcredidlen(const fido_cbor_info_t *ci)
460
426
{
461
426
        return (ci->maxcredidlen);
462
426
}
463
464
uint64_t
465
fido_cbor_info_fwversion(const fido_cbor_info_t *ci)
466
426
{
467
426
        return (ci->fwversion);
468
426
}
469
470
const uint8_t *
471
fido_cbor_info_protocols_ptr(const fido_cbor_info_t *ci)
472
8.30k
{
473
8.30k
        return (ci->protocols.ptr);
474
8.30k
}
475
476
size_t
477
fido_cbor_info_protocols_len(const fido_cbor_info_t *ci)
478
8.30k
{
479
8.30k
        return (ci->protocols.len);
480
8.30k
}
481
482
size_t
483
fido_cbor_info_algorithm_count(const fido_cbor_info_t *ci)
484
896
{
485
896
        return (ci->algorithms.len);
486
896
}
487
488
const char *
489
fido_cbor_info_algorithm_type(const fido_cbor_info_t *ci, size_t idx)
490
470
{
491
470
        if (idx >= ci->algorithms.len)
492
426
                return (NULL);
493
494
44
        return (ci->algorithms.ptr[idx].type);
495
44
}
496
497
int
498
fido_cbor_info_algorithm_cose(const fido_cbor_info_t *ci, size_t idx)
499
470
{
500
470
        if (idx >= ci->algorithms.len)
501
426
                return (0);
502
503
44
        return (ci->algorithms.ptr[idx].cose);
504
44
}