Coverage Report

Created: 2021-07-20 18:14

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