Coverage Report

Created: 2022-07-22 12:05

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