Coverage Report

Created: 2021-03-26 11:35

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