Coverage Report

Created: 2021-10-21 13:35

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