Coverage Report

Created: 2022-04-27 14:33

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