xref: /freebsd/contrib/libfido2/src/cbor.c (revision 8ddb146abcdf061be9f2c0db7e391697dafad85c)
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 }
1636