Coverage Report

Created: 2020-03-07 10:10

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