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