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