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