Coverage Report

Created: 2022-07-22 12:05

/libfido2/src/info.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2018-2022 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
21.3k
{
12
21.3k
        fido_str_array_t        *a = arg;
13
21.3k
        const size_t             i = a->len;
14
15
        /* keep ptr[x] and len consistent */
16
21.3k
        if (cbor_string_copy(item, &a->ptr[i]) < 0) {
17
61
                fido_log_debug("%s: cbor_string_copy", __func__);
18
61
                return (-1);
19
61
        }
20
21
21.2k
        a->len++;
22
23
21.2k
        return (0);
24
21.3k
}
25
26
static int
27
decode_string_array(const cbor_item_t *item, fido_str_array_t *v)
28
8.80k
{
29
8.80k
        v->ptr = NULL;
30
8.80k
        v->len = 0;
31
32
8.80k
        if (cbor_isa_array(item) == false ||
33
8.80k
            cbor_array_is_definite(item) == false) {
34
29
                fido_log_debug("%s: cbor type", __func__);
35
29
                return (-1);
36
29
        }
37
38
8.78k
        v->ptr = calloc(cbor_array_size(item), sizeof(char *));
39
8.78k
        if (v->ptr == NULL)
40
16
                return (-1);
41
42
8.76k
        if (cbor_array_iter(item, v, decode_string) < 0) {
43
68
                fido_log_debug("%s: decode_string", __func__);
44
68
                return (-1);
45
68
        }
46
47
8.69k
        return (0);
48
8.76k
}
49
50
static int
51
decode_aaguid(const cbor_item_t *item, unsigned char *aaguid, size_t aaguid_len)
52
3.72k
{
53
3.72k
        if (cbor_isa_bytestring(item) == false ||
54
3.72k
            cbor_bytestring_is_definite(item) == false ||
55
3.72k
            cbor_bytestring_length(item) != aaguid_len) {
56
65
                fido_log_debug("%s: cbor type", __func__);
57
65
                return (-1);
58
65
        }
59
60
3.65k
        memcpy(aaguid, cbor_bytestring_handle(item), aaguid_len);
61
62
3.65k
        return (0);
63
3.72k
}
64
65
static int
66
decode_option(const cbor_item_t *key, const cbor_item_t *val, void *arg)
67
20.2k
{
68
20.2k
        fido_opt_array_t        *o = arg;
69
20.2k
        const size_t             i = o->len;
70
71
20.2k
        if (cbor_decode_bool(val, NULL) < 0) {
72
806
                fido_log_debug("%s: cbor_decode_bool", __func__);
73
806
                return (0); /* ignore */
74
806
        }
75
76
19.4k
        if (cbor_string_copy(key, &o->name[i]) < 0) {
77
78
                fido_log_debug("%s: cbor_string_copy", __func__);
78
78
                return (0); /* ignore */
79
78
        }
80
81
        /* keep name/value and len consistent */
82
19.3k
        o->value[i] = cbor_ctrl_value(val) == CBOR_CTRL_TRUE;
83
19.3k
        o->len++;
84
85
19.3k
        return (0);
86
19.4k
}
87
88
static int
89
decode_options(const cbor_item_t *item, fido_opt_array_t *o)
90
3.60k
{
91
3.60k
        o->name = NULL;
92
3.60k
        o->value = NULL;
93
3.60k
        o->len = 0;
94
95
3.60k
        if (cbor_isa_map(item) == false ||
96
3.60k
            cbor_map_is_definite(item) == false) {
97
19
                fido_log_debug("%s: cbor type", __func__);
98
19
                return (-1);
99
19
        }
100
101
3.58k
        o->name = calloc(cbor_map_size(item), sizeof(char *));
102
3.58k
        o->value = calloc(cbor_map_size(item), sizeof(bool));
103
3.58k
        if (o->name == NULL || o->value == NULL)
104
16
                return (-1);
105
106
3.57k
        return (cbor_map_iter(item, o, decode_option));
107
3.58k
}
108
109
static int
110
decode_protocol(const cbor_item_t *item, void *arg)
111
5.89k
{
112
5.89k
        fido_byte_array_t       *p = arg;
113
5.89k
        const size_t             i = p->len;
114
115
5.89k
        if (cbor_isa_uint(item) == false ||
116
5.89k
            cbor_int_get_width(item) != CBOR_INT_8) {
117
43
                fido_log_debug("%s: cbor type", __func__);
118
43
                return (-1);
119
43
        }
120
121
        /* keep ptr[x] and len consistent */
122
5.85k
        p->ptr[i] = cbor_get_uint8(item);
123
5.85k
        p->len++;
124
125
5.85k
        return (0);
126
5.89k
}
127
128
static int
129
decode_protocols(const cbor_item_t *item, fido_byte_array_t *p)
130
3.61k
{
131
3.61k
        p->ptr = NULL;
132
3.61k
        p->len = 0;
133
134
3.61k
        if (cbor_isa_array(item) == false ||
135
3.61k
            cbor_array_is_definite(item) == false) {
136
23
                fido_log_debug("%s: cbor type", __func__);
137
23
                return (-1);
138
23
        }
139
140
3.59k
        p->ptr = calloc(cbor_array_size(item), sizeof(uint8_t));
141
3.59k
        if (p->ptr == NULL)
142
10
                return (-1);
143
144
3.58k
        if (cbor_array_iter(item, p, decode_protocol) < 0) {
145
49
                fido_log_debug("%s: decode_protocol", __func__);
146
49
                return (-1);
147
49
        }
148
149
3.53k
        return (0);
150
3.58k
}
151
152
static int
153
decode_algorithm_entry(const cbor_item_t *key, const cbor_item_t *val,
154
    void *arg)
155
11.6k
{
156
11.6k
        fido_algo_t *alg = arg;
157
11.6k
        char *name = NULL;
158
11.6k
        int ok = -1;
159
160
11.6k
        if (cbor_string_copy(key, &name) < 0) {
161
118
                fido_log_debug("%s: cbor type", __func__);
162
118
                ok = 0; /* ignore */
163
118
                goto out;
164
118
        }
165
166
11.5k
        if (!strcmp(name, "alg")) {
167
5.38k
                if (cbor_isa_negint(val) == false ||
168
5.38k
                    cbor_get_int(val) > INT_MAX || alg->cose != 0) {
169
110
                        fido_log_debug("%s: alg", __func__);
170
110
                        goto out;
171
110
                }
172
5.27k
                alg->cose = -(int)cbor_get_int(val) - 1;
173
6.18k
        } else if (!strcmp(name, "type")) {
174
5.06k
                if (cbor_string_copy(val, &alg->type) < 0) {
175
26
                        fido_log_debug("%s: type", __func__);
176
26
                        goto out;
177
26
                }
178
5.06k
        }
179
180
11.4k
        ok = 0;
181
11.6k
out:
182
11.6k
        free(name);
183
184
11.6k
        return (ok);
185
11.4k
}
186
187
static int
188
decode_algorithm(const cbor_item_t *item, void *arg)
189
6.27k
{
190
6.27k
        fido_algo_array_t *aa = arg;
191
6.27k
        const size_t i = aa->len;
192
193
6.27k
        if (cbor_isa_map(item) == false ||
194
6.27k
            cbor_map_is_definite(item) == false) {
195
33
                fido_log_debug("%s: cbor type", __func__);
196
33
                return (-1);
197
33
        }
198
199
6.24k
        memset(&aa->ptr[i], 0, sizeof(aa->ptr[i]));
200
201
6.24k
        if (cbor_map_iter(item, &aa->ptr[i], decode_algorithm_entry) < 0) {
202
222
                fido_log_debug("%s: decode_algorithm_entry", __func__);
203
222
                fido_algo_free(&aa->ptr[i]);
204
222
                return (-1);
205
222
        }
206
207
        /* keep ptr[x] and len consistent */
208
6.02k
        aa->len++;
209
210
6.02k
        return (0);
211
6.24k
}
212
213
static int
214
decode_algorithms(const cbor_item_t *item, fido_algo_array_t *aa)
215
3.10k
{
216
3.10k
        aa->ptr = NULL;
217
3.10k
        aa->len = 0;
218
219
3.10k
        if (cbor_isa_array(item) == false ||
220
3.10k
            cbor_array_is_definite(item) == false) {
221
22
                fido_log_debug("%s: cbor type", __func__);
222
22
                return (-1);
223
22
        }
224
225
3.08k
        aa->ptr = calloc(cbor_array_size(item), sizeof(fido_algo_t));
226
3.08k
        if (aa->ptr == NULL)
227
10
                return (-1);
228
229
3.07k
        if (cbor_array_iter(item, aa, decode_algorithm) < 0) {
230
262
                fido_log_debug("%s: decode_algorithm", __func__);
231
262
                return (-1);
232
262
        }
233
234
2.81k
        return (0);
235
3.07k
}
236
237
static int
238
decode_cert(const cbor_item_t *key, const cbor_item_t *val, void *arg)
239
1.23k
{
240
1.23k
        fido_cert_array_t       *c = arg;
241
1.23k
        const size_t             i = c->len;
242
243
1.23k
        if (cbor_is_int(val) == false) {
244
89
                fido_log_debug("%s: cbor_is_int", __func__);
245
89
                return (0); /* ignore */
246
89
        }
247
248
1.14k
        if (cbor_string_copy(key, &c->name[i]) < 0) {
249
70
                fido_log_debug("%s: cbor_string_copy", __func__);
250
70
                return (0); /* ignore */
251
70
        }
252
253
        /* keep name/value and len consistent */
254
1.07k
        c->value[i] = cbor_get_int(val);
255
1.07k
        c->len++;
256
257
1.07k
        return (0);
258
1.14k
}
259
260
static int
261
decode_certs(const cbor_item_t *item, fido_cert_array_t *c)
262
630
{
263
630
        c->name = NULL;
264
630
        c->value = NULL;
265
630
        c->len = 0;
266
267
630
        if (cbor_isa_map(item) == false ||
268
630
            cbor_map_is_definite(item) == false) {
269
18
                fido_log_debug("%s: cbor type", __func__);
270
18
                return (-1);
271
18
        }
272
273
612
        c->name = calloc(cbor_map_size(item), sizeof(char *));
274
612
        c->value = calloc(cbor_map_size(item), sizeof(uint64_t));
275
612
        if (c->name == NULL || c->value == NULL)
276
18
                return (-1);
277
278
594
        return (cbor_map_iter(item, c, decode_cert));
279
612
}
280
281
static int
282
parse_reply_element(const cbor_item_t *key, const cbor_item_t *val, void *arg)
283
38.7k
{
284
38.7k
        fido_cbor_info_t *ci = arg;
285
38.7k
        uint64_t x;
286
287
38.7k
        if (cbor_isa_uint(key) == false ||
288
38.7k
            cbor_int_get_width(key) != CBOR_INT_8) {
289
849
                fido_log_debug("%s: cbor type", __func__);
290
849
                return (0); /* ignore */
291
849
        }
292
293
37.9k
        switch (cbor_get_uint8(key)) {
294
3.76k
        case 1: /* versions */
295
3.76k
                return (decode_string_array(val, &ci->versions));
296
4.05k
        case 2: /* extensions */
297
4.05k
                return (decode_string_array(val, &ci->extensions));
298
3.72k
        case 3: /* aaguid */
299
3.72k
                return (decode_aaguid(val, ci->aaguid, sizeof(ci->aaguid)));
300
3.60k
        case 4: /* options */
301
3.60k
                return (decode_options(val, &ci->options));
302
3.64k
        case 5: /* maxMsgSize */
303
3.64k
                return (cbor_decode_uint64(val, &ci->maxmsgsiz));
304
3.61k
        case 6: /* pinProtocols */
305
3.61k
                return (decode_protocols(val, &ci->protocols));
306
3.33k
        case 7: /* maxCredentialCountInList */
307
3.33k
                return (cbor_decode_uint64(val, &ci->maxcredcntlst));
308
3.28k
        case 8: /* maxCredentialIdLength */
309
3.28k
                return (cbor_decode_uint64(val, &ci->maxcredidlen));
310
991
        case 9: /* transports */
311
991
                return (decode_string_array(val, &ci->transports));
312
3.10k
        case 10: /* algorithms */
313
3.10k
                return (decode_algorithms(val, &ci->algorithms));
314
246
        case 11: /* maxSerializedLargeBlobArray */
315
246
                return (cbor_decode_uint64(val, &ci->maxlargeblob));
316
239
        case 12: /* forcePINChange */
317
239
                return (cbor_decode_bool(val, &ci->new_pin_reqd));
318
832
        case 13: /* minPINLength */
319
832
                return (cbor_decode_uint64(val, &ci->minpinlen));
320
868
        case 14: /* fwVersion */
321
868
                return (cbor_decode_uint64(val, &ci->fwversion));
322
243
        case 15: /* maxCredBlobLen */
323
243
                return (cbor_decode_uint64(val, &ci->maxcredbloblen));
324
236
        case 16: /* maxRPIDsForSetMinPINLength */
325
236
                return (cbor_decode_uint64(val, &ci->maxrpid_minlen));
326
237
        case 17: /* preferredPlatformUvAttempts */
327
237
                return (cbor_decode_uint64(val, &ci->uv_attempts));
328
239
        case 18: /* uvModality */
329
239
                return (cbor_decode_uint64(val, &ci->uv_modality));
330
630
        case 19: /* certifications */
331
630
                return (decode_certs(val, &ci->certs));
332
456
        case 20: /* remainingDiscoverableCredentials */
333
456
                if (cbor_decode_uint64(val, &x) < 0 || x > INT64_MAX) {
334
29
                        fido_log_debug("%s: cbor_decode_uint64", __func__);
335
29
                        return (-1);
336
29
                }
337
427
                ci->rk_remaining = (int64_t)x;
338
427
                return (0);
339
579
        default: /* ignore */
340
579
                fido_log_debug("%s: cbor type: 0x%02x", __func__, cbor_get_uint8(key));
341
579
                return (0);
342
37.9k
        }
343
37.9k
}
344
345
static int
346
fido_dev_get_cbor_info_tx(fido_dev_t *dev, int *ms)
347
13.8k
{
348
13.8k
        const unsigned char cbor[] = { CTAP_CBOR_GETINFO };
349
350
13.8k
        fido_log_debug("%s: dev=%p", __func__, (void *)dev);
351
352
13.8k
        if (fido_tx(dev, CTAP_CMD_CBOR, cbor, sizeof(cbor), ms) < 0) {
353
247
                fido_log_debug("%s: fido_tx", __func__);
354
247
                return (FIDO_ERR_TX);
355
247
        }
356
357
13.5k
        return (FIDO_OK);
358
13.8k
}
359
360
static int
361
fido_dev_get_cbor_info_rx(fido_dev_t *dev, fido_cbor_info_t *ci, int *ms)
362
13.5k
{
363
13.5k
        unsigned char   *msg;
364
13.5k
        int              msglen;
365
13.5k
        int              r;
366
367
13.5k
        fido_log_debug("%s: dev=%p, ci=%p, ms=%d", __func__, (void *)dev,
368
13.5k
            (void *)ci, *ms);
369
370
13.5k
        fido_cbor_info_reset(ci);
371
372
13.5k
        if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
373
83
                r = FIDO_ERR_INTERNAL;
374
83
                goto out;
375
83
        }
376
377
13.5k
        if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
378
3.98k
                fido_log_debug("%s: fido_rx", __func__);
379
3.98k
                r = FIDO_ERR_RX;
380
3.98k
                goto out;
381
3.98k
        }
382
383
9.52k
        r = cbor_parse_reply(msg, (size_t)msglen, ci, parse_reply_element);
384
13.5k
out:
385
13.5k
        freezero(msg, FIDO_MAXMSG);
386
387
13.5k
        return (r);
388
9.52k
}
389
390
int
391
fido_dev_get_cbor_info_wait(fido_dev_t *dev, fido_cbor_info_t *ci, int *ms)
392
13.8k
{
393
13.8k
        int r;
394
395
#ifdef USE_WINHELLO
396
        if (dev->flags & FIDO_DEV_WINHELLO)
397
                return (fido_winhello_get_cbor_info(dev, ci));
398
#endif
399
13.8k
        if ((r = fido_dev_get_cbor_info_tx(dev, ms)) != FIDO_OK ||
400
13.8k
            (r = fido_dev_get_cbor_info_rx(dev, ci, ms)) != FIDO_OK)
401
10.3k
                return (r);
402
403
3.52k
        return (FIDO_OK);
404
13.8k
}
405
406
int
407
fido_dev_get_cbor_info(fido_dev_t *dev, fido_cbor_info_t *ci)
408
226
{
409
226
        int ms = dev->timeout_ms;
410
411
226
        return (fido_dev_get_cbor_info_wait(dev, ci, &ms));
412
226
}
413
414
/*
415
 * get/set functions for fido_cbor_info_t; always at the end of the file
416
 */
417
418
fido_cbor_info_t *
419
fido_cbor_info_new(void)
420
13.8k
{
421
13.8k
        fido_cbor_info_t *ci;
422
423
13.8k
        if ((ci = calloc(1, sizeof(fido_cbor_info_t))) == NULL)
424
49
                return (NULL);
425
426
13.8k
        fido_cbor_info_reset(ci);
427
428
13.8k
        return (ci);
429
13.8k
}
430
431
void
432
fido_cbor_info_reset(fido_cbor_info_t *ci)
433
41.2k
{
434
41.2k
        fido_str_array_free(&ci->versions);
435
41.2k
        fido_str_array_free(&ci->extensions);
436
41.2k
        fido_str_array_free(&ci->transports);
437
41.2k
        fido_opt_array_free(&ci->options);
438
41.2k
        fido_byte_array_free(&ci->protocols);
439
41.2k
        fido_algo_array_free(&ci->algorithms);
440
41.2k
        fido_cert_array_free(&ci->certs);
441
41.2k
        ci->rk_remaining = -1;
442
41.2k
}
443
444
void
445
fido_cbor_info_free(fido_cbor_info_t **ci_p)
446
37.8k
{
447
37.8k
        fido_cbor_info_t *ci;
448
449
37.8k
        if (ci_p == NULL || (ci = *ci_p) ==  NULL)
450
24.0k
                return;
451
13.8k
        fido_cbor_info_reset(ci);
452
13.8k
        free(ci);
453
13.8k
        *ci_p = NULL;
454
13.8k
}
455
456
char **
457
fido_cbor_info_versions_ptr(const fido_cbor_info_t *ci)
458
138
{
459
138
        return (ci->versions.ptr);
460
138
}
461
462
size_t
463
fido_cbor_info_versions_len(const fido_cbor_info_t *ci)
464
364
{
465
364
        return (ci->versions.len);
466
364
}
467
468
char **
469
fido_cbor_info_extensions_ptr(const fido_cbor_info_t *ci)
470
3.57k
{
471
3.57k
        return (ci->extensions.ptr);
472
3.57k
}
473
474
size_t
475
fido_cbor_info_extensions_len(const fido_cbor_info_t *ci)
476
3.79k
{
477
3.79k
        return (ci->extensions.len);
478
3.79k
}
479
480
char **
481
fido_cbor_info_transports_ptr(const fido_cbor_info_t *ci)
482
62
{
483
62
        return (ci->transports.ptr);
484
62
}
485
486
size_t
487
fido_cbor_info_transports_len(const fido_cbor_info_t *ci)
488
288
{
489
288
        return (ci->transports.len);
490
288
}
491
492
const unsigned char *
493
fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *ci)
494
226
{
495
226
        return (ci->aaguid);
496
226
}
497
498
size_t
499
fido_cbor_info_aaguid_len(const fido_cbor_info_t *ci)
500
226
{
501
226
        return (sizeof(ci->aaguid));
502
226
}
503
504
char **
505
fido_cbor_info_options_name_ptr(const fido_cbor_info_t *ci)
506
3.59k
{
507
3.59k
        return (ci->options.name);
508
3.59k
}
509
510
const bool *
511
fido_cbor_info_options_value_ptr(const fido_cbor_info_t *ci)
512
3.59k
{
513
3.59k
        return (ci->options.value);
514
3.59k
}
515
516
size_t
517
fido_cbor_info_options_len(const fido_cbor_info_t *ci)
518
3.82k
{
519
3.82k
        return (ci->options.len);
520
3.82k
}
521
522
uint64_t
523
fido_cbor_info_maxcredbloblen(const fido_cbor_info_t *ci)
524
226
{
525
226
        return (ci->maxcredbloblen);
526
226
}
527
528
uint64_t
529
fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *ci)
530
3.74k
{
531
3.74k
        return (ci->maxmsgsiz);
532
3.74k
}
533
534
uint64_t
535
fido_cbor_info_maxcredcntlst(const fido_cbor_info_t *ci)
536
226
{
537
226
        return (ci->maxcredcntlst);
538
226
}
539
540
uint64_t
541
fido_cbor_info_maxcredidlen(const fido_cbor_info_t *ci)
542
226
{
543
226
        return (ci->maxcredidlen);
544
226
}
545
546
uint64_t
547
fido_cbor_info_maxlargeblob(const fido_cbor_info_t *ci)
548
226
{
549
226
        return (ci->maxlargeblob);
550
226
}
551
552
uint64_t
553
fido_cbor_info_fwversion(const fido_cbor_info_t *ci)
554
226
{
555
226
        return (ci->fwversion);
556
226
}
557
558
uint64_t
559
fido_cbor_info_minpinlen(const fido_cbor_info_t *ci)
560
226
{
561
226
        return (ci->minpinlen);
562
226
}
563
564
uint64_t
565
fido_cbor_info_maxrpid_minpinlen(const fido_cbor_info_t *ci)
566
226
{
567
226
        return (ci->maxrpid_minlen);
568
226
}
569
570
uint64_t
571
fido_cbor_info_uv_attempts(const fido_cbor_info_t *ci)
572
226
{
573
226
        return (ci->uv_attempts);
574
226
}
575
576
uint64_t
577
fido_cbor_info_uv_modality(const fido_cbor_info_t *ci)
578
226
{
579
226
        return (ci->uv_modality);
580
226
}
581
582
int64_t
583
fido_cbor_info_rk_remaining(const fido_cbor_info_t *ci)
584
226
{
585
226
        return (ci->rk_remaining);
586
226
}
587
588
const uint8_t *
589
fido_cbor_info_protocols_ptr(const fido_cbor_info_t *ci)
590
3.74k
{
591
3.74k
        return (ci->protocols.ptr);
592
3.74k
}
593
594
size_t
595
fido_cbor_info_protocols_len(const fido_cbor_info_t *ci)
596
3.74k
{
597
3.74k
        return (ci->protocols.len);
598
3.74k
}
599
600
size_t
601
fido_cbor_info_algorithm_count(const fido_cbor_info_t *ci)
602
478
{
603
478
        return (ci->algorithms.len);
604
478
}
605
606
const char *
607
fido_cbor_info_algorithm_type(const fido_cbor_info_t *ci, size_t idx)
608
252
{
609
252
        if (idx >= ci->algorithms.len)
610
226
                return (NULL);
611
612
26
        return (ci->algorithms.ptr[idx].type);
613
252
}
614
615
int
616
fido_cbor_info_algorithm_cose(const fido_cbor_info_t *ci, size_t idx)
617
252
{
618
252
        if (idx >= ci->algorithms.len)
619
226
                return (0);
620
621
26
        return (ci->algorithms.ptr[idx].cose);
622
252
}
623
624
bool
625
fido_cbor_info_new_pin_required(const fido_cbor_info_t *ci)
626
226
{
627
226
        return (ci->new_pin_reqd);
628
226
}
629
630
char **
631
fido_cbor_info_certs_name_ptr(const fido_cbor_info_t *ci)
632
13
{
633
13
        return (ci->certs.name);
634
13
}
635
636
const uint64_t *
637
fido_cbor_info_certs_value_ptr(const fido_cbor_info_t *ci)
638
13
{
639
13
        return (ci->certs.value);
640
13
}
641
642
size_t
643
fido_cbor_info_certs_len(const fido_cbor_info_t *ci)
644
239
{
645
239
        return (ci->certs.len);
646
239
}