Coverage Report

Created: 2021-07-20 18:14

/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
40.4k
{
12
40.4k
        fido_str_array_t        *a = arg;
13
40.4k
        const size_t             i = a->len;
14
40.4k
15
40.4k
        /* keep ptr[x] and len consistent */
16
40.4k
        if (cbor_string_copy(item, &a->ptr[i]) < 0) {
17
106
                fido_log_debug("%s: cbor_string_copy", __func__);
18
106
                return (-1);
19
106
        }
20
40.3k
21
40.3k
        a->len++;
22
40.3k
23
40.3k
        return (0);
24
40.3k
}
25
26
static int
27
decode_string_array(const cbor_item_t *item, fido_str_array_t *v)
28
16.2k
{
29
16.2k
        v->ptr = NULL;
30
16.2k
        v->len = 0;
31
16.2k
32
16.2k
        if (cbor_isa_array(item) == false ||
33
16.2k
            cbor_array_is_definite(item) == false) {
34
78
                fido_log_debug("%s: cbor type", __func__);
35
78
                return (-1);
36
78
        }
37
16.2k
38
16.2k
        v->ptr = calloc(cbor_array_size(item), sizeof(char *));
39
16.2k
        if (v->ptr == NULL)
40
16.2k
                return (-1);
41
16.1k
42
16.1k
        if (cbor_array_iter(item, v, decode_string) < 0) {
43
121
                fido_log_debug("%s: decode_string", __func__);
44
121
                return (-1);
45
121
        }
46
16.0k
47
16.0k
        return (0);
48
16.0k
}
49
50
static int
51
decode_aaguid(const cbor_item_t *item, unsigned char *aaguid, size_t aaguid_len)
52
7.50k
{
53
7.50k
        if (cbor_isa_bytestring(item) == false ||
54
7.50k
            cbor_bytestring_is_definite(item) == false ||
55
7.50k
            cbor_bytestring_length(item) != aaguid_len) {
56
126
                fido_log_debug("%s: cbor type", __func__);
57
126
                return (-1);
58
126
        }
59
7.37k
60
7.37k
        memcpy(aaguid, cbor_bytestring_handle(item), aaguid_len);
61
7.37k
62
7.37k
        return (0);
63
7.37k
}
64
65
static int
66
decode_option(const cbor_item_t *key, const cbor_item_t *val, void *arg)
67
41.1k
{
68
41.1k
        fido_opt_array_t        *o = arg;
69
41.1k
        const size_t             i = o->len;
70
41.1k
71
41.1k
        if (cbor_isa_float_ctrl(val) == false ||
72
41.1k
            cbor_float_get_width(val) != CBOR_FLOAT_0 ||
73
41.1k
            cbor_is_bool(val) == false) {
74
2.34k
                fido_log_debug("%s: cbor type", __func__);
75
2.34k
                return (0); /* ignore */
76
2.34k
        }
77
38.8k
78
38.8k
        if (cbor_string_copy(key, &o->name[i]) < 0) {
79
204
                fido_log_debug("%s: cbor_string_copy", __func__);
80
204
                return (0); /* ignore */
81
204
        }
82
38.6k
83
38.6k
        /* keep name/value and len consistent */
84
38.6k
        o->value[i] = cbor_ctrl_value(val) == CBOR_CTRL_TRUE;
85
38.6k
        o->len++;
86
38.6k
87
38.6k
        return (0);
88
38.6k
}
89
90
static int
91
decode_options(const cbor_item_t *item, fido_opt_array_t *o)
92
7.22k
{
93
7.22k
        o->name = NULL;
94
7.22k
        o->value = NULL;
95
7.22k
        o->len = 0;
96
7.22k
97
7.22k
        if (cbor_isa_map(item) == false ||
98
7.22k
            cbor_map_is_definite(item) == false) {
99
41
                fido_log_debug("%s: cbor type", __func__);
100
41
                return (-1);
101
41
        }
102
7.18k
103
7.18k
        o->name = calloc(cbor_map_size(item), sizeof(char *));
104
7.18k
        o->value = calloc(cbor_map_size(item), sizeof(bool));
105
7.18k
        if (o->name == NULL || o->value == NULL)
106
7.18k
                return (-1);
107
7.15k
108
7.15k
        return (cbor_map_iter(item, o, decode_option));
109
7.15k
}
110
111
static int
112
decode_protocol(const cbor_item_t *item, void *arg)
113
8.98k
{
114
8.98k
        fido_byte_array_t       *p = arg;
115
8.98k
        const size_t             i = p->len;
116
8.98k
117
8.98k
        if (cbor_isa_uint(item) == false ||
118
8.98k
            cbor_int_get_width(item) != CBOR_INT_8) {
119
87
                fido_log_debug("%s: cbor type", __func__);
120
87
                return (-1);
121
87
        }
122
8.89k
123
8.89k
        /* keep ptr[x] and len consistent */
124
8.89k
        p->ptr[i] = cbor_get_uint8(item);
125
8.89k
        p->len++;
126
8.89k
127
8.89k
        return (0);
128
8.89k
}
129
130
static int
131
decode_protocols(const cbor_item_t *item, fido_byte_array_t *p)
132
7.02k
{
133
7.02k
        p->ptr = NULL;
134
7.02k
        p->len = 0;
135
7.02k
136
7.02k
        if (cbor_isa_array(item) == false ||
137
7.02k
            cbor_array_is_definite(item) == false) {
138
48
                fido_log_debug("%s: cbor type", __func__);
139
48
                return (-1);
140
48
        }
141
6.97k
142
6.97k
        p->ptr = calloc(cbor_array_size(item), sizeof(uint8_t));
143
6.97k
        if (p->ptr == NULL)
144
6.97k
                return (-1);
145
6.96k
146
6.96k
        if (cbor_array_iter(item, p, decode_protocol) < 0) {
147
94
                fido_log_debug("%s: decode_protocol", __func__);
148
94
                return (-1);
149
94
        }
150
6.86k
151
6.86k
        return (0);
152
6.86k
}
153
154
static int
155
decode_algorithm_entry(const cbor_item_t *key, const cbor_item_t *val,
156
    void *arg)
157
19.5k
{
158
19.5k
        fido_algo_t *alg = arg;
159
19.5k
        char *name = NULL;
160
19.5k
        int ok = -1;
161
19.5k
162
19.5k
        if (cbor_string_copy(key, &name) < 0) {
163
127
                fido_log_debug("%s: cbor type", __func__);
164
127
                ok = 0; /* ignore */
165
127
                goto out;
166
127
        }
167
19.3k
168
19.3k
        if (!strcmp(name, "alg")) {
169
8.75k
                if (cbor_isa_negint(val) == false ||
170
8.75k
                    cbor_get_int(val) > INT_MAX || alg->cose != 0) {
171
388
                        fido_log_debug("%s: alg", __func__);
172
388
                        goto out;
173
388
                }
174
8.37k
                alg->cose = -(int)cbor_get_int(val) - 1;
175
10.6k
        } else if (!strcmp(name, "type")) {
176
7.30k
                if (cbor_string_copy(val, &alg->type) < 0) {
177
32
                        fido_log_debug("%s: type", __func__);
178
32
                        goto out;
179
32
                }
180
18.9k
        }
181
18.9k
182
18.9k
        ok = 0;
183
19.5k
out:
184
19.5k
        free(name);
185
19.5k
186
19.5k
        return (ok);
187
18.9k
}
188
189
static void
190
free_algo(fido_algo_t *a)
191
10.3k
{
192
10.3k
        free(a->type);
193
10.3k
        a->type = NULL;
194
10.3k
        a->cose = 0;
195
10.3k
}
196
197
static int
198
decode_algorithm(const cbor_item_t *item, void *arg)
199
10.4k
{
200
10.4k
        fido_algo_array_t *aa = arg;
201
10.4k
        const size_t i = aa->len;
202
10.4k
203
10.4k
        if (cbor_isa_map(item) == false ||
204
10.4k
            cbor_map_is_definite(item) == false) {
205
112
                fido_log_debug("%s: cbor type", __func__);
206
112
                return (-1);
207
112
        }
208
10.3k
209
10.3k
        memset(&aa->ptr[i], 0, sizeof(aa->ptr[i]));
210
10.3k
211
10.3k
        if (cbor_map_iter(item, &aa->ptr[i], decode_algorithm_entry) < 0) {
212
655
                fido_log_debug("%s: decode_algorithm_entry", __func__);
213
655
                free_algo(&aa->ptr[i]);
214
655
                return (-1);
215
655
        }
216
9.66k
217
9.66k
        /* keep ptr[x] and len consistent */
218
9.66k
        aa->len++;
219
9.66k
220
9.66k
        return (0);
221
9.66k
}
222
223
static int
224
decode_algorithms(const cbor_item_t *item, fido_algo_array_t *aa)
225
5.37k
{
226
5.37k
        aa->ptr = NULL;
227
5.37k
        aa->len = 0;
228
5.37k
229
5.37k
        if (cbor_isa_array(item) == false ||
230
5.37k
            cbor_array_is_definite(item) == false) {
231
52
                fido_log_debug("%s: cbor type", __func__);
232
52
                return (-1);
233
52
        }
234
5.32k
235
5.32k
        aa->ptr = calloc(cbor_array_size(item), sizeof(fido_algo_t));
236
5.32k
        if (aa->ptr == NULL)
237
5.32k
                return (-1);
238
5.30k
239
5.30k
        if (cbor_array_iter(item, aa, decode_algorithm) < 0) {
240
768
                fido_log_debug("%s: decode_algorithm", __func__);
241
768
                return (-1);
242
768
        }
243
4.54k
244
4.54k
        return (0);
245
4.54k
}
246
247
static int
248
parse_reply_element(const cbor_item_t *key, const cbor_item_t *val, void *arg)
249
73.0k
{
250
73.0k
        fido_cbor_info_t *ci = arg;
251
73.0k
252
73.0k
        if (cbor_isa_uint(key) == false ||
253
73.0k
            cbor_int_get_width(key) != CBOR_INT_8) {
254
2.95k
                fido_log_debug("%s: cbor type", __func__);
255
2.95k
                return (0); /* ignore */
256
2.95k
        }
257
70.0k
258
70.0k
        switch (cbor_get_uint8(key)) {
259
7.52k
        case 1: /* versions */
260
7.52k
                return (decode_string_array(val, &ci->versions));
261
8.14k
        case 2: /* extensions */
262
8.14k
                return (decode_string_array(val, &ci->extensions));
263
7.50k
        case 3: /* aaguid */
264
7.50k
                return (decode_aaguid(val, ci->aaguid, sizeof(ci->aaguid)));
265
7.22k
        case 4: /* options */
266
7.22k
                return (decode_options(val, &ci->options));
267
7.32k
        case 5: /* maxMsgSize */
268
7.32k
                return (cbor_decode_uint64(val, &ci->maxmsgsiz));
269
7.02k
        case 6: /* pinProtocols */
270
7.02k
                return (decode_protocols(val, &ci->protocols));
271
6.67k
        case 7: /* maxCredentialCountInList */
272
6.67k
                return (cbor_decode_uint64(val, &ci->maxcredcntlst));
273
6.62k
        case 8: /* maxCredentialIdLength */
274
6.62k
                return (cbor_decode_uint64(val, &ci->maxcredidlen));
275
629
        case 9: /* transports */
276
629
                return (decode_string_array(val, &ci->transports));
277
5.37k
        case 10: /* algorithms */
278
5.37k
                return (decode_algorithms(val, &ci->algorithms));
279
553
        case 14: /* fwVersion */
280
553
                return (cbor_decode_uint64(val, &ci->fwversion));
281
528
        case 15: /* maxCredBlobLen */
282
528
                return (cbor_decode_uint64(val, &ci->maxcredbloblen));
283
4.96k
        default: /* ignore */
284
4.96k
                fido_log_debug("%s: cbor type", __func__);
285
4.96k
                return (0);
286
70.0k
        }
287
70.0k
}
288
289
static int
290
fido_dev_get_cbor_info_tx(fido_dev_t *dev)
291
16.7k
{
292
16.7k
        const unsigned char cbor[] = { CTAP_CBOR_GETINFO };
293
16.7k
294
16.7k
        fido_log_debug("%s: dev=%p", __func__, (void *)dev);
295
16.7k
296
16.7k
        if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor)) < 0) {
297
155
                fido_log_debug("%s: fido_tx", __func__);
298
155
                return (FIDO_ERR_TX);
299
155
        }
300
16.6k
301
16.6k
        return (FIDO_OK);
302
16.6k
}
303
304
static int
305
fido_dev_get_cbor_info_rx(fido_dev_t *dev, fido_cbor_info_t *ci, int ms)
306
16.6k
{
307
16.6k
        unsigned char   reply[FIDO_MAXMSG];
308
16.6k
        int             reply_len;
309
16.6k
310
16.6k
        fido_log_debug("%s: dev=%p, ci=%p, ms=%d", __func__, (void *)dev,
311
16.6k
            (void *)ci, ms);
312
16.6k
313
16.6k
        fido_cbor_info_reset(ci);
314
16.6k
315
16.6k
        if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
316
16.6k
            ms)) < 0) {
317
3.65k
                fido_log_debug("%s: fido_rx", __func__);
318
3.65k
                return (FIDO_ERR_RX);
319
3.65k
        }
320
12.9k
321
12.9k
        return (cbor_parse_reply(reply, (size_t)reply_len, ci,
322
12.9k
            parse_reply_element));
323
12.9k
}
324
325
int
326
fido_dev_get_cbor_info_wait(fido_dev_t *dev, fido_cbor_info_t *ci, int ms)
327
16.7k
{
328
16.7k
        int r;
329
16.7k
330
#ifdef USE_WINHELLO
331
        if (dev->flags & FIDO_DEV_WINHELLO)
332
                return (fido_winhello_get_cbor_info(dev, ci));
333
#endif
334
16.7k
        if ((r = fido_dev_get_cbor_info_tx(dev)) != FIDO_OK ||
335
16.7k
            (r = fido_dev_get_cbor_info_rx(dev, ci, ms)) != FIDO_OK)
336
16.7k
                return (r);
337
7.04k
338
7.04k
        return (FIDO_OK);
339
7.04k
}
340
341
int
342
fido_dev_get_cbor_info(fido_dev_t *dev, fido_cbor_info_t *ci)
343
305
{
344
305
        return (fido_dev_get_cbor_info_wait(dev, ci, -1));
345
305
}
346
347
/*
348
 * get/set functions for fido_cbor_info_t; always at the end of the file
349
 */
350
351
fido_cbor_info_t *
352
fido_cbor_info_new(void)
353
16.8k
{
354
16.8k
        return (calloc(1, sizeof(fido_cbor_info_t)));
355
16.8k
}
356
357
static void
358
free_str_array(fido_str_array_t *sa)
359
100k
{
360
140k
        for (size_t i = 0; i < sa->len; i++)
361
40.3k
                free(sa->ptr[i]);
362
100k
363
100k
        free(sa->ptr);
364
100k
        sa->ptr = NULL;
365
100k
        sa->len = 0;
366
100k
}
367
368
static void
369
free_opt_array(fido_opt_array_t *oa)
370
33.4k
{
371
72.0k
        for (size_t i = 0; i < oa->len; i++)
372
38.6k
                free(oa->name[i]);
373
33.4k
374
33.4k
        free(oa->name);
375
33.4k
        free(oa->value);
376
33.4k
        oa->name = NULL;
377
33.4k
        oa->value = NULL;
378
33.4k
}
379
380
static void
381
free_byte_array(fido_byte_array_t *ba)
382
33.4k
{
383
33.4k
        free(ba->ptr);
384
33.4k
385
33.4k
        ba->ptr = NULL;
386
33.4k
        ba->len = 0;
387
33.4k
}
388
389
static void
390
free_algo_array(fido_algo_array_t *aa)
391
33.4k
{
392
43.0k
        for (size_t i = 0; i < aa->len; i++)
393
9.66k
                free_algo(&aa->ptr[i]);
394
33.4k
395
33.4k
        free(aa->ptr);
396
33.4k
        aa->ptr = NULL;
397
33.4k
        aa->len = 0;
398
33.4k
}
399
400
void
401
fido_cbor_info_reset(fido_cbor_info_t *ci)
402
33.4k
{
403
33.4k
        free_str_array(&ci->versions);
404
33.4k
        free_str_array(&ci->extensions);
405
33.4k
        free_str_array(&ci->transports);
406
33.4k
        free_opt_array(&ci->options);
407
33.4k
        free_byte_array(&ci->protocols);
408
33.4k
        free_algo_array(&ci->algorithms);
409
33.4k
}
410
411
void
412
fido_cbor_info_free(fido_cbor_info_t **ci_p)
413
53.6k
{
414
53.6k
        fido_cbor_info_t *ci;
415
53.6k
416
53.6k
        if (ci_p == NULL || (ci = *ci_p) ==  NULL)
417
53.6k
                return;
418
16.7k
        fido_cbor_info_reset(ci);
419
16.7k
        free(ci);
420
16.7k
        *ci_p = NULL;
421
16.7k
}
422
423
char **
424
fido_cbor_info_versions_ptr(const fido_cbor_info_t *ci)
425
374
{
426
374
        return (ci->versions.ptr);
427
374
}
428
429
size_t
430
fido_cbor_info_versions_len(const fido_cbor_info_t *ci)
431
679
{
432
679
        return (ci->versions.len);
433
679
}
434
435
char **
436
fido_cbor_info_extensions_ptr(const fido_cbor_info_t *ci)
437
7.15k
{
438
7.15k
        return (ci->extensions.ptr);
439
7.15k
}
440
441
size_t
442
fido_cbor_info_extensions_len(const fido_cbor_info_t *ci)
443
7.46k
{
444
7.46k
        return (ci->extensions.len);
445
7.46k
}
446
447
char **
448
fido_cbor_info_transports_ptr(const fido_cbor_info_t *ci)
449
84
{
450
84
        return (ci->transports.ptr);
451
84
}
452
453
size_t
454
fido_cbor_info_transports_len(const fido_cbor_info_t *ci)
455
389
{
456
389
        return (ci->transports.len);
457
389
}
458
459
const unsigned char *
460
fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *ci)
461
305
{
462
305
        return (ci->aaguid);
463
305
}
464
465
size_t
466
fido_cbor_info_aaguid_len(const fido_cbor_info_t *ci)
467
305
{
468
305
        return (sizeof(ci->aaguid));
469
305
}
470
471
char **
472
fido_cbor_info_options_name_ptr(const fido_cbor_info_t *ci)
473
7.18k
{
474
7.18k
        return (ci->options.name);
475
7.18k
}
476
477
const bool *
478
fido_cbor_info_options_value_ptr(const fido_cbor_info_t *ci)
479
7.18k
{
480
7.18k
        return (ci->options.value);
481
7.18k
}
482
483
size_t
484
fido_cbor_info_options_len(const fido_cbor_info_t *ci)
485
7.49k
{
486
7.49k
        return (ci->options.len);
487
7.49k
}
488
489
uint64_t
490
fido_cbor_info_maxcredbloblen(const fido_cbor_info_t *ci)
491
305
{
492
305
        return (ci->maxcredbloblen);
493
305
}
494
495
uint64_t
496
fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *ci)
497
7.33k
{
498
7.33k
        return (ci->maxmsgsiz);
499
7.33k
}
500
501
uint64_t
502
fido_cbor_info_maxcredcntlst(const fido_cbor_info_t *ci)
503
305
{
504
305
        return (ci->maxcredcntlst);
505
305
}
506
507
uint64_t
508
fido_cbor_info_maxcredidlen(const fido_cbor_info_t *ci)
509
305
{
510
305
        return (ci->maxcredidlen);
511
305
}
512
513
uint64_t
514
fido_cbor_info_fwversion(const fido_cbor_info_t *ci)
515
305
{
516
305
        return (ci->fwversion);
517
305
}
518
519
const uint8_t *
520
fido_cbor_info_protocols_ptr(const fido_cbor_info_t *ci)
521
7.33k
{
522
7.33k
        return (ci->protocols.ptr);
523
7.33k
}
524
525
size_t
526
fido_cbor_info_protocols_len(const fido_cbor_info_t *ci)
527
7.33k
{
528
7.33k
        return (ci->protocols.len);
529
7.33k
}
530
531
size_t
532
fido_cbor_info_algorithm_count(const fido_cbor_info_t *ci)
533
633
{
534
633
        return (ci->algorithms.len);
535
633
}
536
537
const char *
538
fido_cbor_info_algorithm_type(const fido_cbor_info_t *ci, size_t idx)
539
328
{
540
328
        if (idx >= ci->algorithms.len)
541
305
                return (NULL);
542
23
543
23
        return (ci->algorithms.ptr[idx].type);
544
23
}
545
546
int
547
fido_cbor_info_algorithm_cose(const fido_cbor_info_t *ci, size_t idx)
548
328
{
549
328
        if (idx >= ci->algorithms.len)
550
305
                return (0);
551
23
552
23
        return (ci->algorithms.ptr[idx].cose);
553
23
}