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