Coverage Report

Created: 2025-03-01 02:43

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