Coverage Report

Created: 2022-04-27 14:33

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