Coverage Report

Created: 2024-02-05 19:20

/libfido2/src/cbor.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
 * SPDX-License-Identifier: BSD-2-Clause
6
 */
7
8
#include <openssl/hmac.h>
9
#include <openssl/sha.h>
10
#include "fido.h"
11
12
static int
13
check_key_type(cbor_item_t *item)
14
6.69M
{
15
6.69M
        if (item->type == CBOR_TYPE_UINT || item->type == CBOR_TYPE_NEGINT ||
16
6.69M
            item->type == CBOR_TYPE_STRING)
17
6.68M
                return (0);
18
19
4.96k
        fido_log_debug("%s: invalid type: %d", __func__, item->type);
20
21
4.96k
        return (-1);
22
6.69M
}
23
24
/*
25
 * Validate CTAP2 canonical CBOR encoding rules for maps.
26
 */
27
static int
28
ctap_check_cbor(cbor_item_t *prev, cbor_item_t *curr)
29
3.34M
{
30
3.34M
        size_t  curr_len;
31
3.34M
        size_t  prev_len;
32
33
3.34M
        if (check_key_type(prev) < 0 || check_key_type(curr) < 0)
34
4.96k
                return (-1);
35
36
3.34M
        if (prev->type != curr->type) {
37
155k
                if (prev->type < curr->type)
38
145k
                        return (0);
39
10.3k
                fido_log_debug("%s: unsorted types", __func__);
40
10.3k
                return (-1);
41
155k
        }
42
43
3.18M
        if (curr->type == CBOR_TYPE_UINT || curr->type == CBOR_TYPE_NEGINT) {
44
1.95M
                if (cbor_int_get_width(curr) >= cbor_int_get_width(prev) &&
45
1.95M
                    cbor_get_int(curr) > cbor_get_int(prev))
46
1.95M
                        return (0);
47
1.95M
        } else {
48
1.22M
                curr_len = cbor_string_length(curr);
49
1.22M
                prev_len = cbor_string_length(prev);
50
51
1.22M
                if (curr_len > prev_len || (curr_len == prev_len &&
52
294k
                    memcmp(cbor_string_handle(prev), cbor_string_handle(curr),
53
293k
                    curr_len) < 0))
54
1.21M
                        return (0);
55
1.22M
        }
56
57
13.9k
        fido_log_debug("%s: invalid cbor", __func__);
58
59
13.9k
        return (-1);
60
3.18M
}
61
62
int
63
cbor_map_iter(const cbor_item_t *item, void *arg, int(*f)(const cbor_item_t *,
64
    const cbor_item_t *, void *))
65
1.00M
{
66
1.00M
        struct cbor_pair        *v;
67
1.00M
        size_t                   n;
68
69
1.00M
        if ((v = cbor_map_handle(item)) == NULL) {
70
1.26k
                fido_log_debug("%s: cbor_map_handle", __func__);
71
1.26k
                return (-1);
72
1.26k
        }
73
74
1.00M
        n = cbor_map_size(item);
75
76
5.25M
        for (size_t i = 0; i < n; i++) {
77
4.31M
                if (v[i].key == NULL || v[i].value == NULL) {
78
0
                        fido_log_debug("%s: key=%p, value=%p for i=%zu",
79
0
                            __func__, (void *)v[i].key, (void *)v[i].value, i);
80
0
                        return (-1);
81
0
                }
82
4.31M
                if (i && ctap_check_cbor(v[i - 1].key, v[i].key) < 0) {
83
29.2k
                        fido_log_debug("%s: ctap_check_cbor", __func__);
84
29.2k
                        return (-1);
85
29.2k
                }
86
4.28M
                if (f(v[i].key, v[i].value, arg) < 0) {
87
38.9k
                        fido_log_debug("%s: iterator < 0 on i=%zu", __func__,
88
38.9k
                            i);
89
38.9k
                        return (-1);
90
38.9k
                }
91
4.28M
        }
92
93
938k
        return (0);
94
1.00M
}
95
96
int
97
cbor_array_iter(const cbor_item_t *item, void *arg, int(*f)(const cbor_item_t *,
98
    void *))
99
655k
{
100
655k
        cbor_item_t     **v;
101
655k
        size_t            n;
102
103
655k
        if ((v = cbor_array_handle(item)) == NULL) {
104
341
                fido_log_debug("%s: cbor_array_handle", __func__);
105
341
                return (-1);
106
341
        }
107
108
655k
        n = cbor_array_size(item);
109
110
2.22M
        for (size_t i = 0; i < n; i++)
111
1.58M
                if (v[i] == NULL || f(v[i], arg) < 0) {
112
13.3k
                        fido_log_debug("%s: iterator < 0 on i=%zu,%p",
113
13.3k
                            __func__, i, (void *)v[i]);
114
13.3k
                        return (-1);
115
13.3k
                }
116
117
641k
        return (0);
118
655k
}
119
120
int
121
cbor_parse_reply(const unsigned char *blob, size_t blob_len, void *arg,
122
    int(*parser)(const cbor_item_t *, const cbor_item_t *, void *))
123
538k
{
124
538k
        cbor_item_t             *item = NULL;
125
538k
        struct cbor_load_result  cbor;
126
538k
        int                      r;
127
128
538k
        if (blob_len < 1) {
129
107k
                fido_log_debug("%s: blob_len=%zu", __func__, blob_len);
130
107k
                r = FIDO_ERR_RX;
131
107k
                goto fail;
132
107k
        }
133
134
431k
        if (blob[0] != FIDO_OK) {
135
19.5k
                fido_log_debug("%s: blob[0]=0x%02x", __func__, blob[0]);
136
19.5k
                r = blob[0];
137
19.5k
                goto fail;
138
19.5k
        }
139
140
411k
        if ((item = cbor_load(blob + 1, blob_len - 1, &cbor)) == NULL) {
141
16.5k
                fido_log_debug("%s: cbor_load", __func__);
142
16.5k
                r = FIDO_ERR_RX_NOT_CBOR;
143
16.5k
                goto fail;
144
16.5k
        }
145
146
395k
        if (cbor_isa_map(item) == false ||
147
395k
            cbor_map_is_definite(item) == false) {
148
11.4k
                fido_log_debug("%s: cbor type", __func__);
149
11.4k
                r = FIDO_ERR_RX_INVALID_CBOR;
150
11.4k
                goto fail;
151
11.4k
        }
152
153
383k
        if (cbor_map_iter(item, arg, parser) < 0) {
154
53.4k
                fido_log_debug("%s: cbor_map_iter", __func__);
155
53.4k
                r = FIDO_ERR_RX_INVALID_CBOR;
156
53.4k
                goto fail;
157
53.4k
        }
158
159
330k
        r = FIDO_OK;
160
538k
fail:
161
538k
        if (item != NULL)
162
395k
                cbor_decref(&item);
163
164
538k
        return (r);
165
330k
}
166
167
void
168
cbor_vector_free(cbor_item_t **item, size_t len)
169
866k
{
170
3.97M
        for (size_t i = 0; i < len; i++)
171
3.10M
                if (item[i] != NULL)
172
1.39M
                        cbor_decref(&item[i]);
173
866k
}
174
175
int
176
cbor_bytestring_copy(const cbor_item_t *item, unsigned char **buf, size_t *len)
177
117k
{
178
117k
        if (*buf != NULL || *len != 0) {
179
6
                fido_log_debug("%s: dup", __func__);
180
6
                return (-1);
181
6
        }
182
183
117k
        if (cbor_isa_bytestring(item) == false ||
184
117k
            cbor_bytestring_is_definite(item) == false) {
185
662
                fido_log_debug("%s: cbor type", __func__);
186
662
                return (-1);
187
662
        }
188
189
117k
        *len = cbor_bytestring_length(item);
190
117k
        if ((*buf = malloc(*len)) == NULL) {
191
616
                *len = 0;
192
616
                return (-1);
193
616
        }
194
195
116k
        memcpy(*buf, cbor_bytestring_handle(item), *len);
196
197
116k
        return (0);
198
117k
}
199
200
int
201
cbor_string_copy(const cbor_item_t *item, char **str)
202
2.70M
{
203
2.70M
        size_t len;
204
205
2.70M
        if (*str != NULL) {
206
1
                fido_log_debug("%s: dup", __func__);
207
1
                return (-1);
208
1
        }
209
210
2.70M
        if (cbor_isa_string(item) == false ||
211
2.70M
            cbor_string_is_definite(item) == false) {
212
17.5k
                fido_log_debug("%s: cbor type", __func__);
213
17.5k
                return (-1);
214
17.5k
        }
215
216
2.68M
        if ((len = cbor_string_length(item)) == SIZE_MAX ||
217
2.68M
            (*str = malloc(len + 1)) == NULL)
218
4.67k
                return (-1);
219
220
2.68M
        memcpy(*str, cbor_string_handle(item), len);
221
2.68M
        (*str)[len] = '\0';
222
223
2.68M
        return (0);
224
2.68M
}
225
226
int
227
cbor_add_bytestring(cbor_item_t *item, const char *key,
228
    const unsigned char *value, size_t value_len)
229
373k
{
230
373k
        struct cbor_pair pair;
231
373k
        int ok = -1;
232
233
373k
        memset(&pair, 0, sizeof(pair));
234
235
373k
        if ((pair.key = cbor_build_string(key)) == NULL ||
236
373k
            (pair.value = cbor_build_bytestring(value, value_len)) == NULL) {
237
167
                fido_log_debug("%s: cbor_build", __func__);
238
167
                goto fail;
239
167
        }
240
241
373k
        if (!cbor_map_add(item, pair)) {
242
139
                fido_log_debug("%s: cbor_map_add", __func__);
243
139
                goto fail;
244
139
        }
245
246
373k
        ok = 0;
247
373k
fail:
248
373k
        if (pair.key)
249
373k
                cbor_decref(&pair.key);
250
373k
        if (pair.value)
251
373k
                cbor_decref(&pair.value);
252
253
373k
        return (ok);
254
373k
}
255
256
int
257
cbor_add_string(cbor_item_t *item, const char *key, const char *value)
258
414k
{
259
414k
        struct cbor_pair pair;
260
414k
        int ok = -1;
261
262
414k
        memset(&pair, 0, sizeof(pair));
263
264
414k
        if ((pair.key = cbor_build_string(key)) == NULL ||
265
414k
            (pair.value = cbor_build_string(value)) == NULL) {
266
542
                fido_log_debug("%s: cbor_build", __func__);
267
542
                goto fail;
268
542
        }
269
270
414k
        if (!cbor_map_add(item, pair)) {
271
184
                fido_log_debug("%s: cbor_map_add", __func__);
272
184
                goto fail;
273
184
        }
274
275
414k
        ok = 0;
276
414k
fail:
277
414k
        if (pair.key)
278
414k
                cbor_decref(&pair.key);
279
414k
        if (pair.value)
280
414k
                cbor_decref(&pair.value);
281
282
414k
        return (ok);
283
414k
}
284
285
int
286
cbor_add_bool(cbor_item_t *item, const char *key, fido_opt_t value)
287
10.9k
{
288
10.9k
        struct cbor_pair pair;
289
10.9k
        int ok = -1;
290
291
10.9k
        memset(&pair, 0, sizeof(pair));
292
293
10.9k
        if ((pair.key = cbor_build_string(key)) == NULL ||
294
10.9k
            (pair.value = cbor_build_bool(value == FIDO_OPT_TRUE)) == NULL) {
295
19
                fido_log_debug("%s: cbor_build", __func__);
296
19
                goto fail;
297
19
        }
298
299
10.9k
        if (!cbor_map_add(item, pair)) {
300
10
                fido_log_debug("%s: cbor_map_add", __func__);
301
10
                goto fail;
302
10
        }
303
304
10.9k
        ok = 0;
305
10.9k
fail:
306
10.9k
        if (pair.key)
307
10.9k
                cbor_decref(&pair.key);
308
10.9k
        if (pair.value)
309
10.9k
                cbor_decref(&pair.value);
310
311
10.9k
        return (ok);
312
10.9k
}
313
314
static int
315
cbor_add_uint8(cbor_item_t *item, const char *key, uint8_t value)
316
4.36k
{
317
4.36k
        struct cbor_pair pair;
318
4.36k
        int ok = -1;
319
320
4.36k
        memset(&pair, 0, sizeof(pair));
321
322
4.36k
        if ((pair.key = cbor_build_string(key)) == NULL ||
323
4.36k
            (pair.value = cbor_build_uint8(value)) == NULL) {
324
60
                fido_log_debug("%s: cbor_build", __func__);
325
60
                goto fail;
326
60
        }
327
328
4.30k
        if (!cbor_map_add(item, pair)) {
329
1
                fido_log_debug("%s: cbor_map_add", __func__);
330
1
                goto fail;
331
1
        }
332
333
4.30k
        ok = 0;
334
4.36k
fail:
335
4.36k
        if (pair.key)
336
4.30k
                cbor_decref(&pair.key);
337
4.36k
        if (pair.value)
338
4.30k
                cbor_decref(&pair.value);
339
340
4.36k
        return (ok);
341
4.30k
}
342
343
static int
344
cbor_add_arg(cbor_item_t *item, uint8_t n, cbor_item_t *arg)
345
1.76M
{
346
1.76M
        struct cbor_pair pair;
347
1.76M
        int ok = -1;
348
349
1.76M
        memset(&pair, 0, sizeof(pair));
350
351
1.76M
        if (arg == NULL)
352
685k
                return (0); /* empty argument */
353
354
1.08M
        if ((pair.key = cbor_build_uint8(n)) == NULL) {
355
2.61k
                fido_log_debug("%s: cbor_build", __func__);
356
2.61k
                goto fail;
357
2.61k
        }
358
359
1.08M
        pair.value = arg;
360
361
1.08M
        if (!cbor_map_add(item, pair)) {
362
3.55k
                fido_log_debug("%s: cbor_map_add", __func__);
363
3.55k
                goto fail;
364
3.55k
        }
365
366
1.07M
        ok = 0;
367
1.08M
fail:
368
1.08M
        if (pair.key)
369
1.08M
                cbor_decref(&pair.key);
370
371
1.08M
        return (ok);
372
1.07M
}
373
374
cbor_item_t *
375
cbor_flatten_vector(cbor_item_t *argv[], size_t argc)
376
537k
{
377
537k
        cbor_item_t     *map;
378
537k
        uint8_t          i;
379
380
537k
        if (argc > UINT8_MAX - 1)
381
0
                return (NULL);
382
383
537k
        if ((map = cbor_new_definite_map(argc)) == NULL)
384
1.39k
                return (NULL);
385
386
2.29M
        for (i = 0; i < argc; i++)
387
1.76M
                if (cbor_add_arg(map, (uint8_t)(i + 1), argv[i]) < 0)
388
6.16k
                        break;
389
390
535k
        if (i != argc) {
391
6.16k
                cbor_decref(&map);
392
6.16k
                map = NULL;
393
6.16k
        }
394
395
535k
        return (map);
396
537k
}
397
398
int
399
cbor_build_frame(uint8_t cmd, cbor_item_t *argv[], size_t argc, fido_blob_t *f)
400
372k
{
401
372k
        cbor_item_t     *flat = NULL;
402
372k
        unsigned char   *cbor = NULL;
403
372k
        size_t           cbor_len;
404
372k
        size_t           cbor_alloc_len;
405
372k
        int              ok = -1;
406
407
372k
        if ((flat = cbor_flatten_vector(argv, argc)) == NULL)
408
4.95k
                goto fail;
409
410
367k
        cbor_len = cbor_serialize_alloc(flat, &cbor, &cbor_alloc_len);
411
367k
        if (cbor_len == 0 || cbor_len == SIZE_MAX) {
412
505
                fido_log_debug("%s: cbor_len=%zu", __func__, cbor_len);
413
505
                goto fail;
414
505
        }
415
416
366k
        if ((f->ptr = malloc(cbor_len + 1)) == NULL)
417
730
                goto fail;
418
419
366k
        f->len = cbor_len + 1;
420
366k
        f->ptr[0] = cmd;
421
366k
        memcpy(f->ptr + 1, cbor, f->len - 1);
422
423
366k
        ok = 0;
424
372k
fail:
425
372k
        if (flat != NULL)
426
367k
                cbor_decref(&flat);
427
428
372k
        free(cbor);
429
430
372k
        return (ok);
431
366k
}
432
433
cbor_item_t *
434
cbor_encode_rp_entity(const fido_rp_t *rp)
435
9.83k
{
436
9.83k
        cbor_item_t *item = NULL;
437
438
9.83k
        if ((item = cbor_new_definite_map(2)) == NULL)
439
22
                return (NULL);
440
441
9.81k
        if ((rp->id && cbor_add_string(item, "id", rp->id) < 0) ||
442
9.81k
            (rp->name && cbor_add_string(item, "name", rp->name) < 0)) {
443
44
                cbor_decref(&item);
444
44
                return (NULL);
445
44
        }
446
447
9.76k
        return (item);
448
9.81k
}
449
450
cbor_item_t *
451
cbor_encode_user_entity(const fido_user_t *user)
452
19.0k
{
453
19.0k
        cbor_item_t             *item = NULL;
454
19.0k
        const fido_blob_t       *id = &user->id;
455
19.0k
        const char              *display = user->display_name;
456
457
19.0k
        if ((item = cbor_new_definite_map(4)) == NULL)
458
56
                return (NULL);
459
460
18.9k
        if ((id->ptr && cbor_add_bytestring(item, "id", id->ptr, id->len) < 0) ||
461
18.9k
            (user->icon && cbor_add_string(item, "icon", user->icon) < 0) ||
462
18.9k
            (user->name && cbor_add_string(item, "name", user->name) < 0) ||
463
18.9k
            (display && cbor_add_string(item, "displayName", display) < 0)) {
464
353
                cbor_decref(&item);
465
353
                return (NULL);
466
353
        }
467
468
18.6k
        return (item);
469
18.9k
}
470
471
cbor_item_t *
472
cbor_encode_pubkey_param(int cose_alg)
473
9.53k
{
474
9.53k
        cbor_item_t             *item = NULL;
475
9.53k
        cbor_item_t             *body = NULL;
476
9.53k
        struct cbor_pair         alg;
477
9.53k
        int                      ok = -1;
478
479
9.53k
        memset(&alg, 0, sizeof(alg));
480
481
9.53k
        if ((item = cbor_new_definite_array(1)) == NULL ||
482
9.53k
            (body = cbor_new_definite_map(2)) == NULL ||
483
9.53k
            cose_alg > -1 || cose_alg < INT16_MIN)
484
103
                goto fail;
485
486
9.43k
        alg.key = cbor_build_string("alg");
487
488
9.43k
        if (-cose_alg - 1 > UINT8_MAX)
489
1.69k
                alg.value = cbor_build_negint16((uint16_t)(-cose_alg - 1));
490
7.73k
        else
491
7.73k
                alg.value = cbor_build_negint8((uint8_t)(-cose_alg - 1));
492
493
9.43k
        if (alg.key == NULL || alg.value == NULL) {
494
34
                fido_log_debug("%s: cbor_build", __func__);
495
34
                goto fail;
496
34
        }
497
498
9.40k
        if (cbor_map_add(body, alg) == false ||
499
9.40k
            cbor_add_string(body, "type", "public-key") < 0 ||
500
9.40k
            cbor_array_push(item, body) == false)
501
160
                goto fail;
502
503
9.24k
        ok  = 0;
504
9.53k
fail:
505
9.53k
        if (ok < 0) {
506
297
                if (item != NULL) {
507
215
                        cbor_decref(&item);
508
215
                        item = NULL;
509
215
                }
510
297
        }
511
512
9.53k
        if (body != NULL)
513
9.43k
                cbor_decref(&body);
514
9.53k
        if (alg.key != NULL)
515
9.41k
                cbor_decref(&alg.key);
516
9.53k
        if (alg.value != NULL)
517
9.42k
                cbor_decref(&alg.value);
518
519
9.53k
        return (item);
520
9.24k
}
521
522
cbor_item_t *
523
cbor_encode_pubkey(const fido_blob_t *pubkey)
524
352k
{
525
352k
        cbor_item_t *cbor_key = NULL;
526
527
352k
        if ((cbor_key = cbor_new_definite_map(2)) == NULL ||
528
352k
            cbor_add_bytestring(cbor_key, "id", pubkey->ptr, pubkey->len) < 0 ||
529
352k
            cbor_add_string(cbor_key, "type", "public-key") < 0) {
530
639
                if (cbor_key)
531
588
                        cbor_decref(&cbor_key);
532
639
                return (NULL);
533
639
        }
534
535
352k
        return (cbor_key);
536
352k
}
537
538
cbor_item_t *
539
cbor_encode_pubkey_list(const fido_blob_array_t *list)
540
6.51k
{
541
6.51k
        cbor_item_t     *array = NULL;
542
6.51k
        cbor_item_t     *key = NULL;
543
544
6.51k
        if ((array = cbor_new_definite_array(list->len)) == NULL)
545
4
                goto fail;
546
547
339k
        for (size_t i = 0; i < list->len; i++) {
548
333k
                if ((key = cbor_encode_pubkey(&list->ptr[i])) == NULL ||
549
333k
                    cbor_array_push(array, key) == false)
550
478
                        goto fail;
551
333k
                cbor_decref(&key);
552
333k
        }
553
554
6.02k
        return (array);
555
482
fail:
556
482
        if (key != NULL)
557
96
                cbor_decref(&key);
558
482
        if (array != NULL)
559
478
                cbor_decref(&array);
560
561
482
        return (NULL);
562
6.50k
}
563
564
cbor_item_t *
565
cbor_encode_str_array(const fido_str_array_t *a)
566
34.6k
{
567
34.6k
        cbor_item_t     *array = NULL;
568
34.6k
        cbor_item_t     *entry = NULL;
569
570
34.6k
        if ((array = cbor_new_definite_array(a->len)) == NULL)
571
22
                goto fail;
572
573
959k
        for (size_t i = 0; i < a->len; i++) {
574
928k
                if ((entry = cbor_build_string(a->ptr[i])) == NULL ||
575
928k
                    cbor_array_push(array, entry) == false)
576
3.92k
                        goto fail;
577
924k
                cbor_decref(&entry);
578
924k
        }
579
580
30.7k
        return (array);
581
3.94k
fail:
582
3.94k
        if (entry != NULL)
583
1.75k
                cbor_decref(&entry);
584
3.94k
        if (array != NULL)
585
3.92k
                cbor_decref(&array);
586
587
3.94k
        return (NULL);
588
34.6k
}
589
590
static int
591
cbor_encode_largeblob_key_ext(cbor_item_t *map)
592
2.83k
{
593
2.83k
        if (map == NULL ||
594
2.83k
            cbor_add_bool(map, "largeBlobKey", FIDO_OPT_TRUE) < 0)
595
2
                return (-1);
596
597
2.83k
        return (0);
598
2.83k
}
599
600
cbor_item_t *
601
cbor_encode_cred_ext(const fido_cred_ext_t *ext, const fido_blob_t *blob)
602
6.24k
{
603
6.24k
        cbor_item_t *item = NULL;
604
6.24k
        size_t size = 0;
605
606
6.24k
        if (ext->mask & FIDO_EXT_CRED_BLOB)
607
2.37k
                size++;
608
6.24k
        if (ext->mask & FIDO_EXT_HMAC_SECRET)
609
2.96k
                size++;
610
6.24k
        if (ext->mask & FIDO_EXT_CRED_PROTECT)
611
4.36k
                size++;
612
6.24k
        if (ext->mask & FIDO_EXT_LARGEBLOB_KEY)
613
2.60k
                size++;
614
6.24k
        if (ext->mask & FIDO_EXT_MINPINLEN)
615
1.46k
                size++;
616
617
6.24k
        if (size == 0 || (item = cbor_new_definite_map(size)) == NULL)
618
2
                return (NULL);
619
620
6.24k
        if (ext->mask & FIDO_EXT_CRED_BLOB) {
621
2.37k
                if (cbor_add_bytestring(item, "credBlob", blob->ptr,
622
2.37k
                    blob->len) < 0) {
623
8
                        cbor_decref(&item);
624
8
                        return (NULL);
625
8
                }
626
2.37k
        }
627
6.23k
        if (ext->mask & FIDO_EXT_CRED_PROTECT) {
628
4.36k
                if (ext->prot < 0 || ext->prot > UINT8_MAX ||
629
4.36k
                    cbor_add_uint8(item, "credProtect",
630
4.36k
                    (uint8_t)ext->prot) < 0) {
631
61
                        cbor_decref(&item);
632
61
                        return (NULL);
633
61
                }
634
4.36k
        }
635
6.17k
        if (ext->mask & FIDO_EXT_HMAC_SECRET) {
636
2.94k
                if (cbor_add_bool(item, "hmac-secret", FIDO_OPT_TRUE) < 0) {
637
3
                        cbor_decref(&item);
638
3
                        return (NULL);
639
3
                }
640
2.94k
        }
641
6.17k
        if (ext->mask & FIDO_EXT_LARGEBLOB_KEY) {
642
2.59k
                if (cbor_encode_largeblob_key_ext(item) < 0) {
643
1
                        cbor_decref(&item);
644
1
                        return (NULL);
645
1
                }
646
2.59k
        }
647
6.16k
        if (ext->mask & FIDO_EXT_MINPINLEN) {
648
1.45k
                if (cbor_add_bool(item, "minPinLength", FIDO_OPT_TRUE) < 0) {
649
2
                        cbor_decref(&item);
650
2
                        return (NULL);
651
2
                }
652
1.45k
        }
653
654
6.16k
        return (item);
655
6.16k
}
656
657
cbor_item_t *
658
cbor_encode_cred_opt(fido_opt_t rk, fido_opt_t uv)
659
2.61k
{
660
2.61k
        cbor_item_t *item = NULL;
661
662
2.61k
        if ((item = cbor_new_definite_map(2)) == NULL)
663
1
                return (NULL);
664
2.61k
        if ((rk != FIDO_OPT_OMIT && cbor_add_bool(item, "rk", rk) < 0) ||
665
2.61k
            (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) {
666
17
                cbor_decref(&item);
667
17
                return (NULL);
668
17
        }
669
670
2.59k
        return (item);
671
2.61k
}
672
673
cbor_item_t *
674
cbor_encode_assert_opt(fido_opt_t up, fido_opt_t uv)
675
319
{
676
319
        cbor_item_t *item = NULL;
677
678
319
        if ((item = cbor_new_definite_map(2)) == NULL)
679
1
                return (NULL);
680
318
        if ((up != FIDO_OPT_OMIT && cbor_add_bool(item, "up", up) < 0) ||
681
318
            (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) {
682
4
                cbor_decref(&item);
683
4
                return (NULL);
684
4
        }
685
686
314
        return (item);
687
318
}
688
689
cbor_item_t *
690
cbor_encode_pin_auth(const fido_dev_t *dev, const fido_blob_t *secret,
691
    const fido_blob_t *data)
692
31.8k
{
693
31.8k
        const EVP_MD    *md = NULL;
694
31.8k
        unsigned char    dgst[SHA256_DIGEST_LENGTH];
695
31.8k
        unsigned int     dgst_len;
696
31.8k
        size_t           outlen;
697
31.8k
        uint8_t          prot;
698
31.8k
        fido_blob_t      key;
699
700
31.8k
        key.ptr = secret->ptr;
701
31.8k
        key.len = secret->len;
702
703
31.8k
        if ((prot = fido_dev_get_pin_protocol(dev)) == 0) {
704
0
                fido_log_debug("%s: fido_dev_get_pin_protocol", __func__);
705
0
                return (NULL);
706
0
        }
707
708
        /* select hmac portion of the shared secret */
709
31.8k
        if (prot == CTAP_PIN_PROTOCOL2 && key.len > 32)
710
341
                key.len = 32;
711
712
31.8k
        if ((md = EVP_sha256()) == NULL || HMAC(md, key.ptr,
713
31.2k
            (int)key.len, data->ptr, data->len, dgst,
714
31.2k
            &dgst_len) == NULL || dgst_len != SHA256_DIGEST_LENGTH)
715
973
                return (NULL);
716
717
30.8k
        outlen = (prot == CTAP_PIN_PROTOCOL1) ? 16 : dgst_len;
718
719
30.8k
        return (cbor_build_bytestring(dgst, outlen));
720
31.8k
}
721
722
cbor_item_t *
723
cbor_encode_pin_opt(const fido_dev_t *dev)
724
294k
{
725
294k
        uint8_t     prot;
726
727
294k
        if ((prot = fido_dev_get_pin_protocol(dev)) == 0) {
728
94.3k
                fido_log_debug("%s: fido_dev_get_pin_protocol", __func__);
729
94.3k
                return (NULL);
730
94.3k
        }
731
732
199k
        return (cbor_build_uint8(prot));
733
294k
}
734
735
cbor_item_t *
736
cbor_encode_change_pin_auth(const fido_dev_t *dev, const fido_blob_t *secret,
737
    const fido_blob_t *new_pin_enc, const fido_blob_t *pin_hash_enc)
738
1.05k
{
739
1.05k
        unsigned char    dgst[SHA256_DIGEST_LENGTH];
740
1.05k
        unsigned int     dgst_len;
741
1.05k
        cbor_item_t     *item = NULL;
742
1.05k
        const EVP_MD    *md = NULL;
743
1.05k
        HMAC_CTX        *ctx = NULL;
744
1.05k
        fido_blob_t      key;
745
1.05k
        uint8_t          prot;
746
1.05k
        size_t           outlen;
747
748
1.05k
        key.ptr = secret->ptr;
749
1.05k
        key.len = secret->len;
750
751
1.05k
        if ((prot = fido_dev_get_pin_protocol(dev)) == 0) {
752
0
                fido_log_debug("%s: fido_dev_get_pin_protocol", __func__);
753
0
                goto fail;
754
0
        }
755
756
1.05k
        if (prot == CTAP_PIN_PROTOCOL2 && key.len > 32)
757
377
                key.len = 32;
758
759
1.05k
        if ((ctx = HMAC_CTX_new()) == NULL ||
760
1.05k
            (md = EVP_sha256())  == NULL ||
761
1.05k
            HMAC_Init_ex(ctx, key.ptr, (int)key.len, md, NULL) == 0 ||
762
1.05k
            HMAC_Update(ctx, new_pin_enc->ptr, new_pin_enc->len) == 0 ||
763
1.05k
            HMAC_Update(ctx, pin_hash_enc->ptr, pin_hash_enc->len) == 0 ||
764
1.05k
            HMAC_Final(ctx, dgst, &dgst_len) == 0 ||
765
1.05k
            dgst_len != SHA256_DIGEST_LENGTH) {
766
213
                fido_log_debug("%s: HMAC", __func__);
767
213
                goto fail;
768
213
        }
769
770
841
        outlen = (prot == CTAP_PIN_PROTOCOL1) ? 16 : dgst_len;
771
772
841
        if ((item = cbor_build_bytestring(dgst, outlen)) == NULL) {
773
21
                fido_log_debug("%s: cbor_build_bytestring", __func__);
774
21
                goto fail;
775
21
        }
776
777
1.05k
fail:
778
1.05k
        HMAC_CTX_free(ctx);
779
780
1.05k
        return (item);
781
841
}
782
783
static int
784
cbor_encode_hmac_secret_param(const fido_dev_t *dev, cbor_item_t *item,
785
    const fido_blob_t *ecdh, const es256_pk_t *pk, const fido_blob_t *salt)
786
133
{
787
133
        cbor_item_t             *param = NULL;
788
133
        cbor_item_t             *argv[4];
789
133
        struct cbor_pair         pair;
790
133
        fido_blob_t             *enc = NULL;
791
133
        uint8_t                  prot;
792
133
        int                      r;
793
794
133
        memset(argv, 0, sizeof(argv));
795
133
        memset(&pair, 0, sizeof(pair));
796
797
133
        if (item == NULL || ecdh == NULL || pk == NULL || salt->ptr == NULL) {
798
38
                fido_log_debug("%s: ecdh=%p, pk=%p, salt->ptr=%p", __func__,
799
38
                    (const void *)ecdh, (const void *)pk,
800
38
                    (const void *)salt->ptr);
801
38
                r = FIDO_ERR_INTERNAL;
802
38
                goto fail;
803
38
        }
804
805
95
        if (salt->len != 32 && salt->len != 64) {
806
0
                fido_log_debug("%s: salt->len=%zu", __func__, salt->len);
807
0
                r = FIDO_ERR_INTERNAL;
808
0
                goto fail;
809
0
        }
810
811
95
        if ((enc = fido_blob_new()) == NULL ||
812
95
            aes256_cbc_enc(dev, ecdh, salt, enc) < 0) {
813
3
                fido_log_debug("%s: aes256_cbc_enc", __func__);
814
3
                r = FIDO_ERR_INTERNAL;
815
3
                goto fail;
816
3
        }
817
818
92
        if ((prot = fido_dev_get_pin_protocol(dev)) == 0) {
819
0
                fido_log_debug("%s: fido_dev_get_pin_protocol", __func__);
820
0
                r = FIDO_ERR_INTERNAL;
821
0
                goto fail;
822
0
        }
823
824
        /* XXX not pin, but salt */
825
92
        if ((argv[0] = es256_pk_encode(pk, 1)) == NULL ||
826
92
            (argv[1] = fido_blob_encode(enc)) == NULL ||
827
92
            (argv[2] = cbor_encode_pin_auth(dev, ecdh, enc)) == NULL ||
828
92
            (prot != 1 && (argv[3] = cbor_build_uint8(prot)) == NULL)) {
829
10
                fido_log_debug("%s: cbor encode", __func__);
830
10
                r = FIDO_ERR_INTERNAL;
831
10
                goto fail;
832
10
        }
833
834
82
        if ((param = cbor_flatten_vector(argv, nitems(argv))) == NULL) {
835
1
                fido_log_debug("%s: cbor_flatten_vector", __func__);
836
1
                r = FIDO_ERR_INTERNAL;
837
1
                goto fail;
838
1
        }
839
840
81
        if ((pair.key = cbor_build_string("hmac-secret")) == NULL) {
841
1
                fido_log_debug("%s: cbor_build", __func__);
842
1
                r = FIDO_ERR_INTERNAL;
843
1
                goto fail;
844
1
        }
845
846
80
        pair.value = param;
847
848
80
        if (!cbor_map_add(item, pair)) {
849
1
                fido_log_debug("%s: cbor_map_add", __func__);
850
1
                r = FIDO_ERR_INTERNAL;
851
1
                goto fail;
852
1
        }
853
854
79
        r = FIDO_OK;
855
856
133
fail:
857
133
        cbor_vector_free(argv, nitems(argv));
858
859
133
        if (param != NULL)
860
81
                cbor_decref(&param);
861
133
        if (pair.key != NULL)
862
80
                cbor_decref(&pair.key);
863
864
133
        fido_blob_free(&enc);
865
866
133
        return (r);
867
79
}
868
869
cbor_item_t *
870
cbor_encode_assert_ext(fido_dev_t *dev, const fido_assert_ext_t *ext,
871
    const fido_blob_t *ecdh, const es256_pk_t *pk)
872
512
{
873
512
        cbor_item_t *item = NULL;
874
512
        size_t size = 0;
875
876
512
        if (ext->mask & FIDO_EXT_CRED_BLOB)
877
327
                size++;
878
512
        if (ext->mask & FIDO_EXT_HMAC_SECRET)
879
133
                size++;
880
512
        if (ext->mask & FIDO_EXT_LARGEBLOB_KEY)
881
270
                size++;
882
512
        if (size == 0 || (item = cbor_new_definite_map(size)) == NULL)
883
1
                return (NULL);
884
885
511
        if (ext->mask & FIDO_EXT_CRED_BLOB) {
886
326
                if (cbor_add_bool(item, "credBlob", FIDO_OPT_TRUE) < 0) {
887
1
                        cbor_decref(&item);
888
1
                        return (NULL);
889
1
                }
890
326
        }
891
510
        if (ext->mask & FIDO_EXT_HMAC_SECRET) {
892
133
                if (cbor_encode_hmac_secret_param(dev, item, ecdh, pk,
893
133
                    &ext->hmac_salt) < 0) {
894
54
                        cbor_decref(&item);
895
54
                        return (NULL);
896
54
                }
897
133
        }
898
456
        if (ext->mask & FIDO_EXT_LARGEBLOB_KEY) {
899
242
                if (cbor_encode_largeblob_key_ext(item) < 0) {
900
1
                        cbor_decref(&item);
901
1
                        return (NULL);
902
1
                }
903
242
        }
904
905
455
        return (item);
906
456
}
907
908
int
909
cbor_decode_fmt(const cbor_item_t *item, char **fmt)
910
3.80k
{
911
3.80k
        char    *type = NULL;
912
913
3.80k
        if (cbor_string_copy(item, &type) < 0) {
914
965
                fido_log_debug("%s: cbor_string_copy", __func__);
915
965
                return (-1);
916
965
        }
917
918
2.84k
        if (strcmp(type, "packed") && strcmp(type, "fido-u2f") &&
919
2.84k
            strcmp(type, "none") && strcmp(type, "tpm")) {
920
110
                fido_log_debug("%s: type=%s", __func__, type);
921
110
                free(type);
922
110
                return (-1);
923
110
        }
924
925
2.73k
        *fmt = type;
926
927
2.73k
        return (0);
928
2.84k
}
929
930
struct cose_key {
931
        int kty;
932
        int alg;
933
        int crv;
934
};
935
936
static int
937
find_cose_alg(const cbor_item_t *key, const cbor_item_t *val, void *arg)
938
92.0k
{
939
92.0k
        struct cose_key *cose_key = arg;
940
941
92.0k
        if (cbor_isa_uint(key) == true &&
942
92.0k
            cbor_int_get_width(key) == CBOR_INT_8) {
943
38.6k
                switch (cbor_get_uint8(key)) {
944
19.0k
                case 1:
945
19.0k
                        if (cbor_isa_uint(val) == false ||
946
19.0k
                            cbor_get_int(val) > INT_MAX || cose_key->kty != 0) {
947
88
                                fido_log_debug("%s: kty", __func__);
948
88
                                return (-1);
949
88
                        }
950
951
18.9k
                        cose_key->kty = (int)cbor_get_int(val);
952
953
18.9k
                        break;
954
19.0k
                case 3:
955
19.0k
                        if (cbor_isa_negint(val) == false ||
956
19.0k
                            cbor_get_int(val) > INT_MAX || cose_key->alg != 0) {
957
227
                                fido_log_debug("%s: alg", __func__);
958
227
                                return (-1);
959
227
                        }
960
961
18.8k
                        cose_key->alg = -(int)cbor_get_int(val) - 1;
962
963
18.8k
                        break;
964
38.6k
                }
965
53.4k
        } else if (cbor_isa_negint(key) == true &&
966
53.4k
            cbor_int_get_width(key) == CBOR_INT_8) {
967
52.4k
                if (cbor_get_uint8(key) == 0) {
968
                        /* get crv if not rsa, otherwise ignore */
969
18.0k
                        if (cbor_isa_uint(val) == true &&
970
18.0k
                            cbor_get_int(val) <= INT_MAX &&
971
18.0k
                            cose_key->crv == 0)
972
17.8k
                                cose_key->crv = (int)cbor_get_int(val);
973
18.0k
                }
974
52.4k
        }
975
976
91.7k
        return (0);
977
92.0k
}
978
979
static int
980
get_cose_alg(const cbor_item_t *item, int *cose_alg)
981
19.5k
{
982
19.5k
        struct cose_key cose_key;
983
984
19.5k
        memset(&cose_key, 0, sizeof(cose_key));
985
986
19.5k
        *cose_alg = 0;
987
988
19.5k
        if (cbor_isa_map(item) == false ||
989
19.5k
            cbor_map_is_definite(item) == false ||
990
19.5k
            cbor_map_iter(item, &cose_key, find_cose_alg) < 0) {
991
894
                fido_log_debug("%s: cbor type", __func__);
992
894
                return (-1);
993
894
        }
994
995
18.6k
        switch (cose_key.alg) {
996
15.9k
        case COSE_ES256:
997
15.9k
                if (cose_key.kty != COSE_KTY_EC2 ||
998
15.9k
                    cose_key.crv != COSE_P256) {
999
139
                        fido_log_debug("%s: invalid kty/crv", __func__);
1000
139
                        return (-1);
1001
139
                }
1002
15.7k
                break;
1003
15.7k
        case COSE_ES384:
1004
252
                if (cose_key.kty != COSE_KTY_EC2 ||
1005
252
                    cose_key.crv != COSE_P384) {
1006
14
                        fido_log_debug("%s: invalid kty/crv", __func__);
1007
14
                        return (-1);
1008
14
                }
1009
238
                break;
1010
1.57k
        case COSE_EDDSA:
1011
1.57k
                if (cose_key.kty != COSE_KTY_OKP ||
1012
1.57k
                    cose_key.crv != COSE_ED25519) {
1013
245
                        fido_log_debug("%s: invalid kty/crv", __func__);
1014
245
                        return (-1);
1015
245
                }
1016
1.33k
                break;
1017
1.33k
        case COSE_RS256:
1018
540
                if (cose_key.kty != COSE_KTY_RSA) {
1019
4
                        fido_log_debug("%s: invalid kty/crv", __func__);
1020
4
                        return (-1);
1021
4
                }
1022
536
                break;
1023
536
        default:
1024
316
                fido_log_debug("%s: unknown alg %d", __func__, cose_key.alg);
1025
1026
316
                return (-1);
1027
18.6k
        }
1028
1029
17.9k
        *cose_alg = cose_key.alg;
1030
1031
17.9k
        return (0);
1032
18.6k
}
1033
1034
int
1035
cbor_decode_pubkey(const cbor_item_t *item, int *type, void *key)
1036
19.5k
{
1037
19.5k
        if (get_cose_alg(item, type) < 0) {
1038
1.61k
                fido_log_debug("%s: get_cose_alg", __func__);
1039
1.61k
                return (-1);
1040
1.61k
        }
1041
1042
17.9k
        switch (*type) {
1043
15.7k
        case COSE_ES256:
1044
15.7k
                if (es256_pk_decode(item, key) < 0) {
1045
86
                        fido_log_debug("%s: es256_pk_decode", __func__);
1046
86
                        return (-1);
1047
86
                }
1048
15.7k
                break;
1049
15.7k
        case COSE_ES384:
1050
238
                if (es384_pk_decode(item, key) < 0) {
1051
24
                        fido_log_debug("%s: es384_pk_decode", __func__);
1052
24
                        return (-1);
1053
24
                }
1054
214
                break;
1055
536
        case COSE_RS256:
1056
536
                if (rs256_pk_decode(item, key) < 0) {
1057
40
                        fido_log_debug("%s: rs256_pk_decode", __func__);
1058
40
                        return (-1);
1059
40
                }
1060
496
                break;
1061
1.33k
        case COSE_EDDSA:
1062
1.33k
                if (eddsa_pk_decode(item, key) < 0) {
1063
108
                        fido_log_debug("%s: eddsa_pk_decode", __func__);
1064
108
                        return (-1);
1065
108
                }
1066
1.22k
                break;
1067
1.22k
        default:
1068
0
                fido_log_debug("%s: invalid cose_alg %d", __func__, *type);
1069
0
                return (-1);
1070
17.9k
        }
1071
1072
17.6k
        return (0);
1073
17.9k
}
1074
1075
static int
1076
decode_attcred(const unsigned char **buf, size_t *len, int cose_alg,
1077
    fido_attcred_t *attcred)
1078
9.34k
{
1079
9.34k
        cbor_item_t             *item = NULL;
1080
9.34k
        struct cbor_load_result  cbor;
1081
9.34k
        uint16_t                 id_len;
1082
9.34k
        int                      ok = -1;
1083
1084
9.34k
        fido_log_xxd(*buf, *len, "%s", __func__);
1085
1086
9.34k
        if (fido_buf_read(buf, len, &attcred->aaguid,
1087
9.34k
            sizeof(attcred->aaguid)) < 0) {
1088
1
                fido_log_debug("%s: fido_buf_read aaguid", __func__);
1089
1
                return (-1);
1090
1
        }
1091
1092
9.34k
        if (fido_buf_read(buf, len, &id_len, sizeof(id_len)) < 0) {
1093
1
                fido_log_debug("%s: fido_buf_read id_len", __func__);
1094
1
                return (-1);
1095
1
        }
1096
1097
9.34k
        attcred->id.len = (size_t)be16toh(id_len);
1098
9.34k
        if ((attcred->id.ptr = malloc(attcred->id.len)) == NULL)
1099
97
                return (-1);
1100
1101
9.25k
        fido_log_debug("%s: attcred->id.len=%zu", __func__, attcred->id.len);
1102
1103
9.25k
        if (fido_buf_read(buf, len, attcred->id.ptr, attcred->id.len) < 0) {
1104
32
                fido_log_debug("%s: fido_buf_read id", __func__);
1105
32
                return (-1);
1106
32
        }
1107
1108
9.21k
        if ((item = cbor_load(*buf, *len, &cbor)) == NULL) {
1109
64
                fido_log_debug("%s: cbor_load", __func__);
1110
64
                goto fail;
1111
64
        }
1112
1113
9.15k
        if (cbor_decode_pubkey(item, &attcred->type, &attcred->pubkey) < 0) {
1114
276
                fido_log_debug("%s: cbor_decode_pubkey", __func__);
1115
276
                goto fail;
1116
276
        }
1117
1118
8.87k
        if (attcred->type != cose_alg) {
1119
390
                fido_log_debug("%s: cose_alg mismatch (%d != %d)", __func__,
1120
390
                    attcred->type, cose_alg);
1121
390
                goto fail;
1122
390
        }
1123
1124
8.48k
        *buf += cbor.read;
1125
8.48k
        *len -= cbor.read;
1126
1127
8.48k
        ok = 0;
1128
9.21k
fail:
1129
9.21k
        if (item != NULL)
1130
9.15k
                cbor_decref(&item);
1131
1132
9.21k
        return (ok);
1133
8.48k
}
1134
1135
static int
1136
decode_cred_extension(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1137
149
{
1138
149
        fido_cred_ext_t *authdata_ext = arg;
1139
149
        char            *type = NULL;
1140
149
        int              ok = -1;
1141
1142
149
        if (cbor_string_copy(key, &type) < 0) {
1143
23
                fido_log_debug("%s: cbor type", __func__);
1144
23
                ok = 0; /* ignore */
1145
23
                goto out;
1146
23
        }
1147
1148
126
        if (strcmp(type, "hmac-secret") == 0) {
1149
39
                if (cbor_decode_bool(val, NULL) < 0) {
1150
7
                        fido_log_debug("%s: cbor_decode_bool", __func__);
1151
7
                        goto out;
1152
7
                }
1153
32
                if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE)
1154
25
                        authdata_ext->mask |= FIDO_EXT_HMAC_SECRET;
1155
87
        } else if (strcmp(type, "credProtect") == 0) {
1156
41
                if (cbor_isa_uint(val) == false ||
1157
41
                    cbor_int_get_width(val) != CBOR_INT_8) {
1158
4
                        fido_log_debug("%s: cbor type", __func__);
1159
4
                        goto out;
1160
4
                }
1161
37
                authdata_ext->mask |= FIDO_EXT_CRED_PROTECT;
1162
37
                authdata_ext->prot = cbor_get_uint8(val);
1163
46
        } else if (strcmp(type, "credBlob") == 0) {
1164
17
                if (cbor_decode_bool(val, NULL) < 0) {
1165
2
                        fido_log_debug("%s: cbor_decode_bool", __func__);
1166
2
                        goto out;
1167
2
                }
1168
15
                if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE)
1169
9
                        authdata_ext->mask |= FIDO_EXT_CRED_BLOB;
1170
29
        } else if (strcmp(type, "minPinLength") == 0) {
1171
16
                if (cbor_isa_uint(val) == false ||
1172
16
                    cbor_int_get_width(val) != CBOR_INT_8) {
1173
7
                        fido_log_debug("%s: cbor type", __func__);
1174
7
                        goto out;
1175
7
                }
1176
9
                authdata_ext->mask |= FIDO_EXT_MINPINLEN;
1177
9
                authdata_ext->minpinlen = cbor_get_uint8(val);
1178
9
        }
1179
1180
106
        ok = 0;
1181
149
out:
1182
149
        free(type);
1183
1184
149
        return (ok);
1185
106
}
1186
1187
static int
1188
decode_cred_extensions(const unsigned char **buf, size_t *len,
1189
    fido_cred_ext_t *authdata_ext)
1190
118
{
1191
118
        cbor_item_t             *item = NULL;
1192
118
        struct cbor_load_result  cbor;
1193
118
        int                      ok = -1;
1194
1195
118
        memset(authdata_ext, 0, sizeof(*authdata_ext));
1196
1197
118
        fido_log_xxd(*buf, *len, "%s", __func__);
1198
1199
118
        if ((item = cbor_load(*buf, *len, &cbor)) == NULL) {
1200
9
                fido_log_debug("%s: cbor_load", __func__);
1201
9
                goto fail;
1202
9
        }
1203
1204
109
        if (cbor_isa_map(item) == false ||
1205
109
            cbor_map_is_definite(item) == false ||
1206
109
            cbor_map_iter(item, authdata_ext, decode_cred_extension) < 0) {
1207
23
                fido_log_debug("%s: cbor type", __func__);
1208
23
                goto fail;
1209
23
        }
1210
1211
86
        *buf += cbor.read;
1212
86
        *len -= cbor.read;
1213
1214
86
        ok = 0;
1215
118
fail:
1216
118
        if (item != NULL)
1217
109
                cbor_decref(&item);
1218
1219
118
        return (ok);
1220
86
}
1221
1222
static int
1223
decode_assert_extension(const cbor_item_t *key, const cbor_item_t *val,
1224
    void *arg)
1225
524
{
1226
524
        fido_assert_extattr_t   *authdata_ext = arg;
1227
524
        char                    *type = NULL;
1228
524
        int                      ok = -1;
1229
1230
524
        if (cbor_string_copy(key, &type) < 0) {
1231
47
                fido_log_debug("%s: cbor type", __func__);
1232
47
                ok = 0; /* ignore */
1233
47
                goto out;
1234
47
        }
1235
1236
477
        if (strcmp(type, "hmac-secret") == 0) {
1237
288
                if (fido_blob_decode(val, &authdata_ext->hmac_secret_enc) < 0) {
1238
14
                        fido_log_debug("%s: fido_blob_decode", __func__);
1239
14
                        goto out;
1240
14
                }
1241
274
                authdata_ext->mask |= FIDO_EXT_HMAC_SECRET;
1242
274
        } else if (strcmp(type, "credBlob") == 0) {
1243
123
                if (fido_blob_decode(val, &authdata_ext->blob) < 0) {
1244
1
                        fido_log_debug("%s: fido_blob_decode", __func__);
1245
1
                        goto out;
1246
1
                }
1247
122
                authdata_ext->mask |= FIDO_EXT_CRED_BLOB;
1248
122
        }
1249
1250
462
        ok = 0;
1251
524
out:
1252
524
        free(type);
1253
1254
524
        return (ok);
1255
462
}
1256
1257
static int
1258
decode_assert_extensions(const unsigned char **buf, size_t *len,
1259
    fido_assert_extattr_t *authdata_ext)
1260
1.01k
{
1261
1.01k
        cbor_item_t             *item = NULL;
1262
1.01k
        struct cbor_load_result  cbor;
1263
1.01k
        int                      ok = -1;
1264
1265
1.01k
        fido_log_xxd(*buf, *len, "%s", __func__);
1266
1267
1.01k
        if ((item = cbor_load(*buf, *len, &cbor)) == NULL) {
1268
240
                fido_log_debug("%s: cbor_load", __func__);
1269
240
                goto fail;
1270
240
        }
1271
1272
774
        if (cbor_isa_map(item) == false ||
1273
774
            cbor_map_is_definite(item) == false ||
1274
774
            cbor_map_iter(item, authdata_ext, decode_assert_extension) < 0) {
1275
293
                fido_log_debug("%s: cbor type", __func__);
1276
293
                goto fail;
1277
293
        }
1278
1279
481
        *buf += cbor.read;
1280
481
        *len -= cbor.read;
1281
1282
481
        ok = 0;
1283
1.01k
fail:
1284
1.01k
        if (item != NULL)
1285
774
                cbor_decref(&item);
1286
1287
1.01k
        return (ok);
1288
481
}
1289
1290
int
1291
cbor_decode_cred_authdata(const cbor_item_t *item, int cose_alg,
1292
    fido_blob_t *authdata_cbor, fido_authdata_t *authdata,
1293
    fido_attcred_t *attcred, fido_cred_ext_t *authdata_ext)
1294
9.43k
{
1295
9.43k
        const unsigned char     *buf = NULL;
1296
9.43k
        size_t                   len;
1297
9.43k
        size_t                   alloc_len;
1298
1299
9.43k
        if (cbor_isa_bytestring(item) == false ||
1300
9.43k
            cbor_bytestring_is_definite(item) == false) {
1301
0
                fido_log_debug("%s: cbor type", __func__);
1302
0
                return (-1);
1303
0
        }
1304
1305
9.43k
        if (authdata_cbor->ptr != NULL ||
1306
9.43k
            (authdata_cbor->len = cbor_serialize_alloc(item,
1307
9.43k
            &authdata_cbor->ptr, &alloc_len)) == 0) {
1308
82
                fido_log_debug("%s: cbor_serialize_alloc", __func__);
1309
82
                return (-1);
1310
82
        }
1311
1312
9.35k
        buf = cbor_bytestring_handle(item);
1313
9.35k
        len = cbor_bytestring_length(item);
1314
9.35k
        fido_log_xxd(buf, len, "%s", __func__);
1315
1316
9.35k
        if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) {
1317
4
                fido_log_debug("%s: fido_buf_read", __func__);
1318
4
                return (-1);
1319
4
        }
1320
1321
9.35k
        authdata->sigcount = be32toh(authdata->sigcount);
1322
1323
9.35k
        if (attcred != NULL) {
1324
9.35k
                if ((authdata->flags & CTAP_AUTHDATA_ATT_CRED) == 0 ||
1325
9.35k
                    decode_attcred(&buf, &len, cose_alg, attcred) < 0)
1326
865
                        return (-1);
1327
9.35k
        }
1328
1329
8.48k
        if (authdata_ext != NULL) {
1330
8.48k
                if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0 &&
1331
8.48k
                    decode_cred_extensions(&buf, &len, authdata_ext) < 0)
1332
32
                        return (-1);
1333
8.48k
        }
1334
1335
        /* XXX we should probably ensure that len == 0 at this point */
1336
1337
8.45k
        return (FIDO_OK);
1338
8.48k
}
1339
1340
int
1341
cbor_decode_assert_authdata(const cbor_item_t *item, fido_blob_t *authdata_cbor,
1342
    fido_authdata_t *authdata, fido_assert_extattr_t *authdata_ext)
1343
4.06k
{
1344
4.06k
        const unsigned char     *buf = NULL;
1345
4.06k
        size_t                   len;
1346
4.06k
        size_t                   alloc_len;
1347
1348
4.06k
        if (cbor_isa_bytestring(item) == false ||
1349
4.06k
            cbor_bytestring_is_definite(item) == false) {
1350
0
                fido_log_debug("%s: cbor type", __func__);
1351
0
                return (-1);
1352
0
        }
1353
1354
4.06k
        if (authdata_cbor->ptr != NULL ||
1355
4.06k
            (authdata_cbor->len = cbor_serialize_alloc(item,
1356
4.06k
            &authdata_cbor->ptr, &alloc_len)) == 0) {
1357
25
                fido_log_debug("%s: cbor_serialize_alloc", __func__);
1358
25
                return (-1);
1359
25
        }
1360
1361
4.03k
        buf = cbor_bytestring_handle(item);
1362
4.03k
        len = cbor_bytestring_length(item);
1363
1364
4.03k
        fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)buf, len);
1365
1366
4.03k
        if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) {
1367
6
                fido_log_debug("%s: fido_buf_read", __func__);
1368
6
                return (-1);
1369
6
        }
1370
1371
4.03k
        authdata->sigcount = be32toh(authdata->sigcount);
1372
1373
4.03k
        if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0) {
1374
1.01k
                if (decode_assert_extensions(&buf, &len, authdata_ext) < 0) {
1375
533
                        fido_log_debug("%s: decode_assert_extensions",
1376
533
                            __func__);
1377
533
                        return (-1);
1378
533
                }
1379
1.01k
        }
1380
1381
        /* XXX we should probably ensure that len == 0 at this point */
1382
1383
3.49k
        return (FIDO_OK);
1384
4.03k
}
1385
1386
static int
1387
decode_x5c(const cbor_item_t *item, void *arg)
1388
10.8k
{
1389
10.8k
        fido_blob_t *x5c = arg;
1390
1391
10.8k
        if (x5c->len)
1392
3.49k
                return (0); /* ignore */
1393
1394
7.35k
        return (fido_blob_decode(item, x5c));
1395
10.8k
}
1396
1397
static int
1398
decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1399
26.6k
{
1400
26.6k
        fido_attstmt_t  *attstmt = arg;
1401
26.6k
        char            *name = NULL;
1402
26.6k
        int              ok = -1;
1403
1404
26.6k
        if (cbor_string_copy(key, &name) < 0) {
1405
277
                fido_log_debug("%s: cbor type", __func__);
1406
277
                ok = 0; /* ignore */
1407
277
                goto out;
1408
277
        }
1409
1410
26.3k
        if (!strcmp(name, "alg")) {
1411
8.15k
                if (cbor_isa_negint(val) == false ||
1412
8.15k
                    cbor_get_int(val) > UINT16_MAX) {
1413
17
                        fido_log_debug("%s: alg", __func__);
1414
17
                        goto out;
1415
17
                }
1416
8.13k
                attstmt->alg = -(int)cbor_get_int(val) - 1;
1417
8.13k
                if (attstmt->alg != COSE_ES256 && attstmt->alg != COSE_ES384 &&
1418
8.13k
                    attstmt->alg != COSE_RS256 && attstmt->alg != COSE_EDDSA &&
1419
8.13k
                    attstmt->alg != COSE_RS1) {
1420
28
                        fido_log_debug("%s: unsupported attstmt->alg=%d",
1421
28
                            __func__, attstmt->alg);
1422
28
                        goto out;
1423
28
                }
1424
18.2k
        } else if (!strcmp(name, "sig")) {
1425
8.08k
                if (fido_blob_decode(val, &attstmt->sig) < 0) {
1426
19
                        fido_log_debug("%s: sig", __func__);
1427
19
                        goto out;
1428
19
                }
1429
10.1k
        } else if (!strcmp(name, "x5c")) {
1430
7.37k
                if (cbor_isa_array(val) == false ||
1431
7.37k
                    cbor_array_is_definite(val) == false ||
1432
7.37k
                    cbor_array_iter(val, &attstmt->x5c, decode_x5c) < 0) {
1433
43
                        fido_log_debug("%s: x5c", __func__);
1434
43
                        goto out;
1435
43
                }
1436
7.37k
        } else if (!strcmp(name, "certInfo")) {
1437
656
                if (fido_blob_decode(val, &attstmt->certinfo) < 0) {
1438
1
                        fido_log_debug("%s: certinfo", __func__);
1439
1
                        goto out;
1440
1
                }
1441
2.10k
        } else if (!strcmp(name, "pubArea")) {
1442
672
                if (fido_blob_decode(val, &attstmt->pubarea) < 0) {
1443
3
                        fido_log_debug("%s: pubarea", __func__);
1444
3
                        goto out;
1445
3
                }
1446
672
        }
1447
1448
26.2k
        ok = 0;
1449
26.6k
out:
1450
26.6k
        free(name);
1451
1452
26.6k
        return (ok);
1453
26.2k
}
1454
1455
int
1456
cbor_decode_attstmt(const cbor_item_t *item, fido_attstmt_t *attstmt)
1457
8.43k
{
1458
8.43k
        size_t alloc_len;
1459
1460
8.43k
        if (cbor_isa_map(item) == false ||
1461
8.43k
            cbor_map_is_definite(item) == false ||
1462
8.43k
            cbor_map_iter(item, attstmt, decode_attstmt_entry) < 0) {
1463
219
                fido_log_debug("%s: cbor type", __func__);
1464
219
                return (-1);
1465
219
        }
1466
1467
8.21k
        if (attstmt->cbor.ptr != NULL ||
1468
8.21k
            (attstmt->cbor.len = cbor_serialize_alloc(item,
1469
8.21k
            &attstmt->cbor.ptr, &alloc_len)) == 0) {
1470
64
                fido_log_debug("%s: cbor_serialize_alloc", __func__);
1471
64
                return (-1);
1472
64
        }
1473
1474
8.15k
        return (0);
1475
8.21k
}
1476
1477
int
1478
cbor_decode_uint64(const cbor_item_t *item, uint64_t *n)
1479
677k
{
1480
677k
        if (cbor_isa_uint(item) == false) {
1481
632
                fido_log_debug("%s: cbor type", __func__);
1482
632
                return (-1);
1483
632
        }
1484
1485
677k
        *n = cbor_get_int(item);
1486
1487
677k
        return (0);
1488
677k
}
1489
1490
static int
1491
decode_cred_id_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1492
22.3k
{
1493
22.3k
        fido_blob_t     *id = arg;
1494
22.3k
        char            *name = NULL;
1495
22.3k
        int              ok = -1;
1496
1497
22.3k
        if (cbor_string_copy(key, &name) < 0) {
1498
393
                fido_log_debug("%s: cbor type", __func__);
1499
393
                ok = 0; /* ignore */
1500
393
                goto out;
1501
393
        }
1502
1503
21.9k
        if (!strcmp(name, "id"))
1504
5.68k
                if (fido_blob_decode(val, id) < 0) {
1505
33
                        fido_log_debug("%s: cbor_bytestring_copy", __func__);
1506
33
                        goto out;
1507
33
                }
1508
1509
21.9k
        ok = 0;
1510
22.3k
out:
1511
22.3k
        free(name);
1512
1513
22.3k
        return (ok);
1514
21.9k
}
1515
1516
int
1517
cbor_decode_cred_id(const cbor_item_t *item, fido_blob_t *id)
1518
11.1k
{
1519
11.1k
        if (cbor_isa_map(item) == false ||
1520
11.1k
            cbor_map_is_definite(item) == false ||
1521
11.1k
            cbor_map_iter(item, id, decode_cred_id_entry) < 0) {
1522
139
                fido_log_debug("%s: cbor type", __func__);
1523
139
                return (-1);
1524
139
        }
1525
1526
11.0k
        return (0);
1527
11.1k
}
1528
1529
static int
1530
decode_user_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1531
31.9k
{
1532
31.9k
        fido_user_t     *user = arg;
1533
31.9k
        char            *name = NULL;
1534
31.9k
        int              ok = -1;
1535
1536
31.9k
        if (cbor_string_copy(key, &name) < 0) {
1537
616
                fido_log_debug("%s: cbor type", __func__);
1538
616
                ok = 0; /* ignore */
1539
616
                goto out;
1540
616
        }
1541
1542
31.3k
        if (!strcmp(name, "icon")) {
1543
91
                if (cbor_string_copy(val, &user->icon) < 0) {
1544
8
                        fido_log_debug("%s: icon", __func__);
1545
8
                        goto out;
1546
8
                }
1547
31.2k
        } else if (!strcmp(name, "name")) {
1548
3.55k
                if (cbor_string_copy(val, &user->name) < 0) {
1549
2
                        fido_log_debug("%s: name", __func__);
1550
2
                        goto out;
1551
2
                }
1552
27.7k
        } else if (!strcmp(name, "displayName")) {
1553
1.99k
                if (cbor_string_copy(val, &user->display_name) < 0) {
1554
2
                        fido_log_debug("%s: display_name", __func__);
1555
2
                        goto out;
1556
2
                }
1557
25.7k
        } else if (!strcmp(name, "id")) {
1558
5.21k
                if (fido_blob_decode(val, &user->id) < 0) {
1559
8
                        fido_log_debug("%s: id", __func__);
1560
8
                        goto out;
1561
8
                }
1562
5.21k
        }
1563
1564
31.3k
        ok = 0;
1565
31.9k
out:
1566
31.9k
        free(name);
1567
1568
31.9k
        return (ok);
1569
31.3k
}
1570
1571
int
1572
cbor_decode_user(const cbor_item_t *item, fido_user_t *user)
1573
11.0k
{
1574
11.0k
        if (cbor_isa_map(item) == false ||
1575
11.0k
            cbor_map_is_definite(item) == false ||
1576
11.0k
            cbor_map_iter(item, user, decode_user_entry) < 0) {
1577
188
                fido_log_debug("%s: cbor type", __func__);
1578
188
                return (-1);
1579
188
        }
1580
1581
10.9k
        return (0);
1582
11.0k
}
1583
1584
static int
1585
decode_rp_entity_entry(const cbor_item_t *key, const cbor_item_t *val,
1586
    void *arg)
1587
8.36k
{
1588
8.36k
        fido_rp_t       *rp = arg;
1589
8.36k
        char            *name = NULL;
1590
8.36k
        int              ok = -1;
1591
1592
8.36k
        if (cbor_string_copy(key, &name) < 0) {
1593
226
                fido_log_debug("%s: cbor type", __func__);
1594
226
                ok = 0; /* ignore */
1595
226
                goto out;
1596
226
        }
1597
1598
8.13k
        if (!strcmp(name, "id")) {
1599
831
                if (cbor_string_copy(val, &rp->id) < 0) {
1600
3
                        fido_log_debug("%s: id", __func__);
1601
3
                        goto out;
1602
3
                }
1603
7.30k
        } else if (!strcmp(name, "name")) {
1604
6
                if (cbor_string_copy(val, &rp->name) < 0) {
1605
3
                        fido_log_debug("%s: name", __func__);
1606
3
                        goto out;
1607
3
                }
1608
6
        }
1609
1610
8.12k
        ok = 0;
1611
8.36k
out:
1612
8.36k
        free(name);
1613
1614
8.36k
        return (ok);
1615
8.12k
}
1616
1617
int
1618
cbor_decode_rp_entity(const cbor_item_t *item, fido_rp_t *rp)
1619
8.45k
{
1620
8.45k
        if (cbor_isa_map(item) == false ||
1621
8.45k
            cbor_map_is_definite(item) == false ||
1622
8.45k
            cbor_map_iter(item, rp, decode_rp_entity_entry) < 0) {
1623
78
                fido_log_debug("%s: cbor type", __func__);
1624
78
                return (-1);
1625
78
        }
1626
1627
8.37k
        return (0);
1628
8.45k
}
1629
1630
int
1631
cbor_decode_bool(const cbor_item_t *item, bool *v)
1632
1.03M
{
1633
1.03M
        if (cbor_isa_float_ctrl(item) == false ||
1634
1.03M
            cbor_float_get_width(item) != CBOR_FLOAT_0 ||
1635
1.03M
            cbor_is_bool(item) == false) {
1636
95.2k
                fido_log_debug("%s: cbor type", __func__);
1637
95.2k
                return (-1);
1638
95.2k
        }
1639
1640
938k
        if (v != NULL)
1641
23.9k
                *v = cbor_ctrl_value(item) == CBOR_CTRL_TRUE;
1642
1643
938k
        return (0);
1644
1.03M
}
1645
1646
cbor_item_t *
1647
cbor_build_uint(const uint64_t value)
1648
79.1k
{
1649
79.1k
        if (value <= UINT8_MAX)
1650
48.1k
                return cbor_build_uint8((uint8_t)value);
1651
31.0k
        else if (value <= UINT16_MAX)
1652
21.3k
                return cbor_build_uint16((uint16_t)value);
1653
9.62k
        else if (value <= UINT32_MAX)
1654
9.62k
                return cbor_build_uint32((uint32_t)value);
1655
1656
0
        return cbor_build_uint64(value);
1657
79.1k
}
1658
1659
int
1660
cbor_array_append(cbor_item_t **array, cbor_item_t *item)
1661
5.29k
{
1662
5.29k
        cbor_item_t **v, *ret;
1663
5.29k
        size_t n;
1664
1665
5.29k
        if ((v = cbor_array_handle(*array)) == NULL ||
1666
5.29k
            (n = cbor_array_size(*array)) == SIZE_MAX ||
1667
5.29k
            (ret = cbor_new_definite_array(n + 1)) == NULL)
1668
20
                return -1;
1669
8.61k
        for (size_t i = 0; i < n; i++) {
1670
3.37k
                if (cbor_array_push(ret, v[i]) == 0) {
1671
36
                        cbor_decref(&ret);
1672
36
                        return -1;
1673
36
                }
1674
3.37k
        }
1675
5.23k
        if (cbor_array_push(ret, item) == 0) {
1676
4
                cbor_decref(&ret);
1677
4
                return -1;
1678
4
        }
1679
5.23k
        cbor_decref(array);
1680
5.23k
        *array = ret;
1681
1682
5.23k
        return 0;
1683
5.23k
}
1684
1685
int
1686
cbor_array_drop(cbor_item_t **array, size_t idx)
1687
1.45k
{
1688
1.45k
        cbor_item_t **v, *ret;
1689
1.45k
        size_t n;
1690
1691
1.45k
        if ((v = cbor_array_handle(*array)) == NULL ||
1692
1.45k
            (n = cbor_array_size(*array)) == 0 || idx >= n ||
1693
1.45k
            (ret = cbor_new_definite_array(n - 1)) == NULL)
1694
3
                return -1;
1695
4.46k
        for (size_t i = 0; i < n; i++) {
1696
3.09k
                if (i != idx && cbor_array_push(ret, v[i]) == 0) {
1697
85
                        cbor_decref(&ret);
1698
85
                        return -1;
1699
85
                }
1700
3.09k
        }
1701
1.36k
        cbor_decref(array);
1702
1.36k
        *array = ret;
1703
1704
1.36k
        return 0;
1705
1.45k
}