Coverage Report

Created: 2022-01-17 10:46

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