Coverage Report

Created: 2020-12-02 17:02

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