xref: /freebsd/contrib/libfido2/src/cbor.c (revision 2ccfa855b2fc331819953e3de1b1c15ce5b95a7e)
10afa8e06SEd Maste /*
2*2ccfa855SEd Maste  * Copyright (c) 2018-2022 Yubico AB. All rights reserved.
30afa8e06SEd Maste  * Use of this source code is governed by a BSD-style
40afa8e06SEd Maste  * license that can be found in the LICENSE file.
5*2ccfa855SEd Maste  * SPDX-License-Identifier: BSD-2-Clause
60afa8e06SEd Maste  */
70afa8e06SEd Maste 
80afa8e06SEd Maste #include <openssl/hmac.h>
90afa8e06SEd Maste #include <openssl/sha.h>
100afa8e06SEd Maste #include "fido.h"
110afa8e06SEd Maste 
120afa8e06SEd Maste static int
check_key_type(cbor_item_t * item)130afa8e06SEd Maste check_key_type(cbor_item_t *item)
140afa8e06SEd Maste {
150afa8e06SEd Maste 	if (item->type == CBOR_TYPE_UINT || item->type == CBOR_TYPE_NEGINT ||
160afa8e06SEd Maste 	    item->type == CBOR_TYPE_STRING)
170afa8e06SEd Maste 		return (0);
180afa8e06SEd Maste 
190afa8e06SEd Maste 	fido_log_debug("%s: invalid type: %d", __func__, item->type);
200afa8e06SEd Maste 
210afa8e06SEd Maste 	return (-1);
220afa8e06SEd Maste }
230afa8e06SEd Maste 
240afa8e06SEd Maste /*
250afa8e06SEd Maste  * Validate CTAP2 canonical CBOR encoding rules for maps.
260afa8e06SEd Maste  */
270afa8e06SEd Maste static int
ctap_check_cbor(cbor_item_t * prev,cbor_item_t * curr)280afa8e06SEd Maste ctap_check_cbor(cbor_item_t *prev, cbor_item_t *curr)
290afa8e06SEd Maste {
300afa8e06SEd Maste 	size_t	curr_len;
310afa8e06SEd Maste 	size_t	prev_len;
320afa8e06SEd Maste 
330afa8e06SEd Maste 	if (check_key_type(prev) < 0 || check_key_type(curr) < 0)
340afa8e06SEd Maste 		return (-1);
350afa8e06SEd Maste 
360afa8e06SEd Maste 	if (prev->type != curr->type) {
370afa8e06SEd Maste 		if (prev->type < curr->type)
380afa8e06SEd Maste 			return (0);
390afa8e06SEd Maste 		fido_log_debug("%s: unsorted types", __func__);
400afa8e06SEd Maste 		return (-1);
410afa8e06SEd Maste 	}
420afa8e06SEd Maste 
430afa8e06SEd Maste 	if (curr->type == CBOR_TYPE_UINT || curr->type == CBOR_TYPE_NEGINT) {
440afa8e06SEd Maste 		if (cbor_int_get_width(curr) >= cbor_int_get_width(prev) &&
450afa8e06SEd Maste 		    cbor_get_int(curr) > cbor_get_int(prev))
460afa8e06SEd Maste 			return (0);
470afa8e06SEd Maste 	} else {
480afa8e06SEd Maste 		curr_len = cbor_string_length(curr);
490afa8e06SEd Maste 		prev_len = cbor_string_length(prev);
500afa8e06SEd Maste 
510afa8e06SEd Maste 		if (curr_len > prev_len || (curr_len == prev_len &&
520afa8e06SEd Maste 		    memcmp(cbor_string_handle(prev), cbor_string_handle(curr),
530afa8e06SEd Maste 		    curr_len) < 0))
540afa8e06SEd Maste 			return (0);
550afa8e06SEd Maste 	}
560afa8e06SEd Maste 
570afa8e06SEd Maste 	fido_log_debug("%s: invalid cbor", __func__);
580afa8e06SEd Maste 
590afa8e06SEd Maste 	return (-1);
600afa8e06SEd Maste }
610afa8e06SEd Maste 
620afa8e06SEd Maste int
cbor_map_iter(const cbor_item_t * item,void * arg,int (* f)(const cbor_item_t *,const cbor_item_t *,void *))630afa8e06SEd Maste cbor_map_iter(const cbor_item_t *item, void *arg, int(*f)(const cbor_item_t *,
640afa8e06SEd Maste     const cbor_item_t *, void *))
650afa8e06SEd Maste {
660afa8e06SEd Maste 	struct cbor_pair	*v;
670afa8e06SEd Maste 	size_t			 n;
680afa8e06SEd Maste 
690afa8e06SEd Maste 	if ((v = cbor_map_handle(item)) == NULL) {
700afa8e06SEd Maste 		fido_log_debug("%s: cbor_map_handle", __func__);
710afa8e06SEd Maste 		return (-1);
720afa8e06SEd Maste 	}
730afa8e06SEd Maste 
740afa8e06SEd Maste 	n = cbor_map_size(item);
750afa8e06SEd Maste 
760afa8e06SEd Maste 	for (size_t i = 0; i < n; i++) {
770afa8e06SEd Maste 		if (v[i].key == NULL || v[i].value == NULL) {
780afa8e06SEd Maste 			fido_log_debug("%s: key=%p, value=%p for i=%zu",
790afa8e06SEd Maste 			    __func__, (void *)v[i].key, (void *)v[i].value, i);
800afa8e06SEd Maste 			return (-1);
810afa8e06SEd Maste 		}
820afa8e06SEd Maste 		if (i && ctap_check_cbor(v[i - 1].key, v[i].key) < 0) {
830afa8e06SEd Maste 			fido_log_debug("%s: ctap_check_cbor", __func__);
840afa8e06SEd Maste 			return (-1);
850afa8e06SEd Maste 		}
860afa8e06SEd Maste 		if (f(v[i].key, v[i].value, arg) < 0) {
870afa8e06SEd Maste 			fido_log_debug("%s: iterator < 0 on i=%zu", __func__,
880afa8e06SEd Maste 			    i);
890afa8e06SEd Maste 			return (-1);
900afa8e06SEd Maste 		}
910afa8e06SEd Maste 	}
920afa8e06SEd Maste 
930afa8e06SEd Maste 	return (0);
940afa8e06SEd Maste }
950afa8e06SEd Maste 
960afa8e06SEd Maste int
cbor_array_iter(const cbor_item_t * item,void * arg,int (* f)(const cbor_item_t *,void *))970afa8e06SEd Maste cbor_array_iter(const cbor_item_t *item, void *arg, int(*f)(const cbor_item_t *,
980afa8e06SEd Maste     void *))
990afa8e06SEd Maste {
1000afa8e06SEd Maste 	cbor_item_t	**v;
1010afa8e06SEd Maste 	size_t		  n;
1020afa8e06SEd Maste 
1030afa8e06SEd Maste 	if ((v = cbor_array_handle(item)) == NULL) {
1040afa8e06SEd Maste 		fido_log_debug("%s: cbor_array_handle", __func__);
1050afa8e06SEd Maste 		return (-1);
1060afa8e06SEd Maste 	}
1070afa8e06SEd Maste 
1080afa8e06SEd Maste 	n = cbor_array_size(item);
1090afa8e06SEd Maste 
1100afa8e06SEd Maste 	for (size_t i = 0; i < n; i++)
1110afa8e06SEd Maste 		if (v[i] == NULL || f(v[i], arg) < 0) {
1120afa8e06SEd Maste 			fido_log_debug("%s: iterator < 0 on i=%zu,%p",
1130afa8e06SEd Maste 			    __func__, i, (void *)v[i]);
1140afa8e06SEd Maste 			return (-1);
1150afa8e06SEd Maste 		}
1160afa8e06SEd Maste 
1170afa8e06SEd Maste 	return (0);
1180afa8e06SEd Maste }
1190afa8e06SEd Maste 
1200afa8e06SEd Maste int
cbor_parse_reply(const unsigned char * blob,size_t blob_len,void * arg,int (* parser)(const cbor_item_t *,const cbor_item_t *,void *))1210afa8e06SEd Maste cbor_parse_reply(const unsigned char *blob, size_t blob_len, void *arg,
1220afa8e06SEd Maste     int(*parser)(const cbor_item_t *, const cbor_item_t *, void *))
1230afa8e06SEd Maste {
1240afa8e06SEd Maste 	cbor_item_t		*item = NULL;
1250afa8e06SEd Maste 	struct cbor_load_result	 cbor;
1260afa8e06SEd Maste 	int			 r;
1270afa8e06SEd Maste 
1280afa8e06SEd Maste 	if (blob_len < 1) {
1290afa8e06SEd Maste 		fido_log_debug("%s: blob_len=%zu", __func__, blob_len);
1300afa8e06SEd Maste 		r = FIDO_ERR_RX;
1310afa8e06SEd Maste 		goto fail;
1320afa8e06SEd Maste 	}
1330afa8e06SEd Maste 
1340afa8e06SEd Maste 	if (blob[0] != FIDO_OK) {
1350afa8e06SEd Maste 		fido_log_debug("%s: blob[0]=0x%02x", __func__, blob[0]);
1360afa8e06SEd Maste 		r = blob[0];
1370afa8e06SEd Maste 		goto fail;
1380afa8e06SEd Maste 	}
1390afa8e06SEd Maste 
1400afa8e06SEd Maste 	if ((item = cbor_load(blob + 1, blob_len - 1, &cbor)) == NULL) {
1410afa8e06SEd Maste 		fido_log_debug("%s: cbor_load", __func__);
1420afa8e06SEd Maste 		r = FIDO_ERR_RX_NOT_CBOR;
1430afa8e06SEd Maste 		goto fail;
1440afa8e06SEd Maste 	}
1450afa8e06SEd Maste 
1460afa8e06SEd Maste 	if (cbor_isa_map(item) == false ||
1470afa8e06SEd Maste 	    cbor_map_is_definite(item) == false) {
1480afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
1490afa8e06SEd Maste 		r = FIDO_ERR_RX_INVALID_CBOR;
1500afa8e06SEd Maste 		goto fail;
1510afa8e06SEd Maste 	}
1520afa8e06SEd Maste 
1530afa8e06SEd Maste 	if (cbor_map_iter(item, arg, parser) < 0) {
1540afa8e06SEd Maste 		fido_log_debug("%s: cbor_map_iter", __func__);
1550afa8e06SEd Maste 		r = FIDO_ERR_RX_INVALID_CBOR;
1560afa8e06SEd Maste 		goto fail;
1570afa8e06SEd Maste 	}
1580afa8e06SEd Maste 
1590afa8e06SEd Maste 	r = FIDO_OK;
1600afa8e06SEd Maste fail:
1610afa8e06SEd Maste 	if (item != NULL)
1620afa8e06SEd Maste 		cbor_decref(&item);
1630afa8e06SEd Maste 
1640afa8e06SEd Maste 	return (r);
1650afa8e06SEd Maste }
1660afa8e06SEd Maste 
1670afa8e06SEd Maste void
cbor_vector_free(cbor_item_t ** item,size_t len)1680afa8e06SEd Maste cbor_vector_free(cbor_item_t **item, size_t len)
1690afa8e06SEd Maste {
1700afa8e06SEd Maste 	for (size_t i = 0; i < len; i++)
1710afa8e06SEd Maste 		if (item[i] != NULL)
1720afa8e06SEd Maste 			cbor_decref(&item[i]);
1730afa8e06SEd Maste }
1740afa8e06SEd Maste 
1750afa8e06SEd Maste int
cbor_bytestring_copy(const cbor_item_t * item,unsigned char ** buf,size_t * len)1760afa8e06SEd Maste cbor_bytestring_copy(const cbor_item_t *item, unsigned char **buf, size_t *len)
1770afa8e06SEd Maste {
1780afa8e06SEd Maste 	if (*buf != NULL || *len != 0) {
1790afa8e06SEd Maste 		fido_log_debug("%s: dup", __func__);
1800afa8e06SEd Maste 		return (-1);
1810afa8e06SEd Maste 	}
1820afa8e06SEd Maste 
1830afa8e06SEd Maste 	if (cbor_isa_bytestring(item) == false ||
1840afa8e06SEd Maste 	    cbor_bytestring_is_definite(item) == false) {
1850afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
1860afa8e06SEd Maste 		return (-1);
1870afa8e06SEd Maste 	}
1880afa8e06SEd Maste 
1890afa8e06SEd Maste 	*len = cbor_bytestring_length(item);
1900afa8e06SEd Maste 	if ((*buf = malloc(*len)) == NULL) {
1910afa8e06SEd Maste 		*len = 0;
1920afa8e06SEd Maste 		return (-1);
1930afa8e06SEd Maste 	}
1940afa8e06SEd Maste 
1950afa8e06SEd Maste 	memcpy(*buf, cbor_bytestring_handle(item), *len);
1960afa8e06SEd Maste 
1970afa8e06SEd Maste 	return (0);
1980afa8e06SEd Maste }
1990afa8e06SEd Maste 
2000afa8e06SEd Maste int
cbor_string_copy(const cbor_item_t * item,char ** str)2010afa8e06SEd Maste cbor_string_copy(const cbor_item_t *item, char **str)
2020afa8e06SEd Maste {
2030afa8e06SEd Maste 	size_t len;
2040afa8e06SEd Maste 
2050afa8e06SEd Maste 	if (*str != NULL) {
2060afa8e06SEd Maste 		fido_log_debug("%s: dup", __func__);
2070afa8e06SEd Maste 		return (-1);
2080afa8e06SEd Maste 	}
2090afa8e06SEd Maste 
2100afa8e06SEd Maste 	if (cbor_isa_string(item) == false ||
2110afa8e06SEd Maste 	    cbor_string_is_definite(item) == false) {
2120afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
2130afa8e06SEd Maste 		return (-1);
2140afa8e06SEd Maste 	}
2150afa8e06SEd Maste 
2160afa8e06SEd Maste 	if ((len = cbor_string_length(item)) == SIZE_MAX ||
2170afa8e06SEd Maste 	    (*str = malloc(len + 1)) == NULL)
2180afa8e06SEd Maste 		return (-1);
2190afa8e06SEd Maste 
2200afa8e06SEd Maste 	memcpy(*str, cbor_string_handle(item), len);
2210afa8e06SEd Maste 	(*str)[len] = '\0';
2220afa8e06SEd Maste 
2230afa8e06SEd Maste 	return (0);
2240afa8e06SEd Maste }
2250afa8e06SEd Maste 
2260afa8e06SEd Maste int
cbor_add_bytestring(cbor_item_t * item,const char * key,const unsigned char * value,size_t value_len)2270afa8e06SEd Maste cbor_add_bytestring(cbor_item_t *item, const char *key,
2280afa8e06SEd Maste     const unsigned char *value, size_t value_len)
2290afa8e06SEd Maste {
2300afa8e06SEd Maste 	struct cbor_pair pair;
2310afa8e06SEd Maste 	int ok = -1;
2320afa8e06SEd Maste 
2330afa8e06SEd Maste 	memset(&pair, 0, sizeof(pair));
2340afa8e06SEd Maste 
2350afa8e06SEd Maste 	if ((pair.key = cbor_build_string(key)) == NULL ||
2360afa8e06SEd Maste 	    (pair.value = cbor_build_bytestring(value, value_len)) == NULL) {
2370afa8e06SEd Maste 		fido_log_debug("%s: cbor_build", __func__);
2380afa8e06SEd Maste 		goto fail;
2390afa8e06SEd Maste 	}
2400afa8e06SEd Maste 
2410afa8e06SEd Maste 	if (!cbor_map_add(item, pair)) {
2420afa8e06SEd Maste 		fido_log_debug("%s: cbor_map_add", __func__);
2430afa8e06SEd Maste 		goto fail;
2440afa8e06SEd Maste 	}
2450afa8e06SEd Maste 
2460afa8e06SEd Maste 	ok = 0;
2470afa8e06SEd Maste fail:
2480afa8e06SEd Maste 	if (pair.key)
2490afa8e06SEd Maste 		cbor_decref(&pair.key);
2500afa8e06SEd Maste 	if (pair.value)
2510afa8e06SEd Maste 		cbor_decref(&pair.value);
2520afa8e06SEd Maste 
2530afa8e06SEd Maste 	return (ok);
2540afa8e06SEd Maste }
2550afa8e06SEd Maste 
2560afa8e06SEd Maste int
cbor_add_string(cbor_item_t * item,const char * key,const char * value)2570afa8e06SEd Maste cbor_add_string(cbor_item_t *item, const char *key, const char *value)
2580afa8e06SEd Maste {
2590afa8e06SEd Maste 	struct cbor_pair pair;
2600afa8e06SEd Maste 	int ok = -1;
2610afa8e06SEd Maste 
2620afa8e06SEd Maste 	memset(&pair, 0, sizeof(pair));
2630afa8e06SEd Maste 
2640afa8e06SEd Maste 	if ((pair.key = cbor_build_string(key)) == NULL ||
2650afa8e06SEd Maste 	    (pair.value = cbor_build_string(value)) == NULL) {
2660afa8e06SEd Maste 		fido_log_debug("%s: cbor_build", __func__);
2670afa8e06SEd Maste 		goto fail;
2680afa8e06SEd Maste 	}
2690afa8e06SEd Maste 
2700afa8e06SEd Maste 	if (!cbor_map_add(item, pair)) {
2710afa8e06SEd Maste 		fido_log_debug("%s: cbor_map_add", __func__);
2720afa8e06SEd Maste 		goto fail;
2730afa8e06SEd Maste 	}
2740afa8e06SEd Maste 
2750afa8e06SEd Maste 	ok = 0;
2760afa8e06SEd Maste fail:
2770afa8e06SEd Maste 	if (pair.key)
2780afa8e06SEd Maste 		cbor_decref(&pair.key);
2790afa8e06SEd Maste 	if (pair.value)
2800afa8e06SEd Maste 		cbor_decref(&pair.value);
2810afa8e06SEd Maste 
2820afa8e06SEd Maste 	return (ok);
2830afa8e06SEd Maste }
2840afa8e06SEd Maste 
2850afa8e06SEd Maste int
cbor_add_bool(cbor_item_t * item,const char * key,fido_opt_t value)2860afa8e06SEd Maste cbor_add_bool(cbor_item_t *item, const char *key, fido_opt_t value)
2870afa8e06SEd Maste {
2880afa8e06SEd Maste 	struct cbor_pair pair;
2890afa8e06SEd Maste 	int ok = -1;
2900afa8e06SEd Maste 
2910afa8e06SEd Maste 	memset(&pair, 0, sizeof(pair));
2920afa8e06SEd Maste 
2930afa8e06SEd Maste 	if ((pair.key = cbor_build_string(key)) == NULL ||
2940afa8e06SEd Maste 	    (pair.value = cbor_build_bool(value == FIDO_OPT_TRUE)) == NULL) {
2950afa8e06SEd Maste 		fido_log_debug("%s: cbor_build", __func__);
2960afa8e06SEd Maste 		goto fail;
2970afa8e06SEd Maste 	}
2980afa8e06SEd Maste 
2990afa8e06SEd Maste 	if (!cbor_map_add(item, pair)) {
3000afa8e06SEd Maste 		fido_log_debug("%s: cbor_map_add", __func__);
3010afa8e06SEd Maste 		goto fail;
3020afa8e06SEd Maste 	}
3030afa8e06SEd Maste 
3040afa8e06SEd Maste 	ok = 0;
3050afa8e06SEd Maste fail:
3060afa8e06SEd Maste 	if (pair.key)
3070afa8e06SEd Maste 		cbor_decref(&pair.key);
3080afa8e06SEd Maste 	if (pair.value)
3090afa8e06SEd Maste 		cbor_decref(&pair.value);
3100afa8e06SEd Maste 
3110afa8e06SEd Maste 	return (ok);
3120afa8e06SEd Maste }
3130afa8e06SEd Maste 
3140afa8e06SEd Maste static int
cbor_add_uint8(cbor_item_t * item,const char * key,uint8_t value)3150afa8e06SEd Maste cbor_add_uint8(cbor_item_t *item, const char *key, uint8_t value)
3160afa8e06SEd Maste {
3170afa8e06SEd Maste 	struct cbor_pair pair;
3180afa8e06SEd Maste 	int ok = -1;
3190afa8e06SEd Maste 
3200afa8e06SEd Maste 	memset(&pair, 0, sizeof(pair));
3210afa8e06SEd Maste 
3220afa8e06SEd Maste 	if ((pair.key = cbor_build_string(key)) == NULL ||
3230afa8e06SEd Maste 	    (pair.value = cbor_build_uint8(value)) == NULL) {
3240afa8e06SEd Maste 		fido_log_debug("%s: cbor_build", __func__);
3250afa8e06SEd Maste 		goto fail;
3260afa8e06SEd Maste 	}
3270afa8e06SEd Maste 
3280afa8e06SEd Maste 	if (!cbor_map_add(item, pair)) {
3290afa8e06SEd Maste 		fido_log_debug("%s: cbor_map_add", __func__);
3300afa8e06SEd Maste 		goto fail;
3310afa8e06SEd Maste 	}
3320afa8e06SEd Maste 
3330afa8e06SEd Maste 	ok = 0;
3340afa8e06SEd Maste fail:
3350afa8e06SEd Maste 	if (pair.key)
3360afa8e06SEd Maste 		cbor_decref(&pair.key);
3370afa8e06SEd Maste 	if (pair.value)
3380afa8e06SEd Maste 		cbor_decref(&pair.value);
3390afa8e06SEd Maste 
3400afa8e06SEd Maste 	return (ok);
3410afa8e06SEd Maste }
3420afa8e06SEd Maste 
3430afa8e06SEd Maste static int
cbor_add_arg(cbor_item_t * item,uint8_t n,cbor_item_t * arg)3440afa8e06SEd Maste cbor_add_arg(cbor_item_t *item, uint8_t n, cbor_item_t *arg)
3450afa8e06SEd Maste {
3460afa8e06SEd Maste 	struct cbor_pair pair;
3470afa8e06SEd Maste 	int ok = -1;
3480afa8e06SEd Maste 
3490afa8e06SEd Maste 	memset(&pair, 0, sizeof(pair));
3500afa8e06SEd Maste 
3510afa8e06SEd Maste 	if (arg == NULL)
3520afa8e06SEd Maste 		return (0); /* empty argument */
3530afa8e06SEd Maste 
3540afa8e06SEd Maste 	if ((pair.key = cbor_build_uint8(n)) == NULL) {
3550afa8e06SEd Maste 		fido_log_debug("%s: cbor_build", __func__);
3560afa8e06SEd Maste 		goto fail;
3570afa8e06SEd Maste 	}
3580afa8e06SEd Maste 
3590afa8e06SEd Maste 	pair.value = arg;
3600afa8e06SEd Maste 
3610afa8e06SEd Maste 	if (!cbor_map_add(item, pair)) {
3620afa8e06SEd Maste 		fido_log_debug("%s: cbor_map_add", __func__);
3630afa8e06SEd Maste 		goto fail;
3640afa8e06SEd Maste 	}
3650afa8e06SEd Maste 
3660afa8e06SEd Maste 	ok = 0;
3670afa8e06SEd Maste fail:
3680afa8e06SEd Maste 	if (pair.key)
3690afa8e06SEd Maste 		cbor_decref(&pair.key);
3700afa8e06SEd Maste 
3710afa8e06SEd Maste 	return (ok);
3720afa8e06SEd Maste }
3730afa8e06SEd Maste 
3740afa8e06SEd Maste cbor_item_t *
cbor_flatten_vector(cbor_item_t * argv[],size_t argc)3750afa8e06SEd Maste cbor_flatten_vector(cbor_item_t *argv[], size_t argc)
3760afa8e06SEd Maste {
3770afa8e06SEd Maste 	cbor_item_t	*map;
3780afa8e06SEd Maste 	uint8_t		 i;
3790afa8e06SEd Maste 
3800afa8e06SEd Maste 	if (argc > UINT8_MAX - 1)
3810afa8e06SEd Maste 		return (NULL);
3820afa8e06SEd Maste 
3830afa8e06SEd Maste 	if ((map = cbor_new_definite_map(argc)) == NULL)
3840afa8e06SEd Maste 		return (NULL);
3850afa8e06SEd Maste 
3860afa8e06SEd Maste 	for (i = 0; i < argc; i++)
3870afa8e06SEd Maste 		if (cbor_add_arg(map, (uint8_t)(i + 1), argv[i]) < 0)
3880afa8e06SEd Maste 			break;
3890afa8e06SEd Maste 
3900afa8e06SEd Maste 	if (i != argc) {
3910afa8e06SEd Maste 		cbor_decref(&map);
3920afa8e06SEd Maste 		map = NULL;
3930afa8e06SEd Maste 	}
3940afa8e06SEd Maste 
3950afa8e06SEd Maste 	return (map);
3960afa8e06SEd Maste }
3970afa8e06SEd Maste 
3980afa8e06SEd Maste int
cbor_build_frame(uint8_t cmd,cbor_item_t * argv[],size_t argc,fido_blob_t * f)3990afa8e06SEd Maste cbor_build_frame(uint8_t cmd, cbor_item_t *argv[], size_t argc, fido_blob_t *f)
4000afa8e06SEd Maste {
4010afa8e06SEd Maste 	cbor_item_t	*flat = NULL;
4020afa8e06SEd Maste 	unsigned char	*cbor = NULL;
4030afa8e06SEd Maste 	size_t		 cbor_len;
4040afa8e06SEd Maste 	size_t		 cbor_alloc_len;
4050afa8e06SEd Maste 	int		 ok = -1;
4060afa8e06SEd Maste 
4070afa8e06SEd Maste 	if ((flat = cbor_flatten_vector(argv, argc)) == NULL)
4080afa8e06SEd Maste 		goto fail;
4090afa8e06SEd Maste 
4100afa8e06SEd Maste 	cbor_len = cbor_serialize_alloc(flat, &cbor, &cbor_alloc_len);
4110afa8e06SEd Maste 	if (cbor_len == 0 || cbor_len == SIZE_MAX) {
4120afa8e06SEd Maste 		fido_log_debug("%s: cbor_len=%zu", __func__, cbor_len);
4130afa8e06SEd Maste 		goto fail;
4140afa8e06SEd Maste 	}
4150afa8e06SEd Maste 
4160afa8e06SEd Maste 	if ((f->ptr = malloc(cbor_len + 1)) == NULL)
4170afa8e06SEd Maste 		goto fail;
4180afa8e06SEd Maste 
4190afa8e06SEd Maste 	f->len = cbor_len + 1;
4200afa8e06SEd Maste 	f->ptr[0] = cmd;
4210afa8e06SEd Maste 	memcpy(f->ptr + 1, cbor, f->len - 1);
4220afa8e06SEd Maste 
4230afa8e06SEd Maste 	ok = 0;
4240afa8e06SEd Maste fail:
4250afa8e06SEd Maste 	if (flat != NULL)
4260afa8e06SEd Maste 		cbor_decref(&flat);
4270afa8e06SEd Maste 
4280afa8e06SEd Maste 	free(cbor);
4290afa8e06SEd Maste 
4300afa8e06SEd Maste 	return (ok);
4310afa8e06SEd Maste }
4320afa8e06SEd Maste 
4330afa8e06SEd Maste cbor_item_t *
cbor_encode_rp_entity(const fido_rp_t * rp)4340afa8e06SEd Maste cbor_encode_rp_entity(const fido_rp_t *rp)
4350afa8e06SEd Maste {
4360afa8e06SEd Maste 	cbor_item_t *item = NULL;
4370afa8e06SEd Maste 
4380afa8e06SEd Maste 	if ((item = cbor_new_definite_map(2)) == NULL)
4390afa8e06SEd Maste 		return (NULL);
4400afa8e06SEd Maste 
4410afa8e06SEd Maste 	if ((rp->id && cbor_add_string(item, "id", rp->id) < 0) ||
4420afa8e06SEd Maste 	    (rp->name && cbor_add_string(item, "name", rp->name) < 0)) {
4430afa8e06SEd Maste 		cbor_decref(&item);
4440afa8e06SEd Maste 		return (NULL);
4450afa8e06SEd Maste 	}
4460afa8e06SEd Maste 
4470afa8e06SEd Maste 	return (item);
4480afa8e06SEd Maste }
4490afa8e06SEd Maste 
4500afa8e06SEd Maste cbor_item_t *
cbor_encode_user_entity(const fido_user_t * user)4510afa8e06SEd Maste cbor_encode_user_entity(const fido_user_t *user)
4520afa8e06SEd Maste {
4530afa8e06SEd Maste 	cbor_item_t		*item = NULL;
4540afa8e06SEd Maste 	const fido_blob_t	*id = &user->id;
4550afa8e06SEd Maste 	const char		*display = user->display_name;
4560afa8e06SEd Maste 
4570afa8e06SEd Maste 	if ((item = cbor_new_definite_map(4)) == NULL)
4580afa8e06SEd Maste 		return (NULL);
4590afa8e06SEd Maste 
4600afa8e06SEd Maste 	if ((id->ptr && cbor_add_bytestring(item, "id", id->ptr, id->len) < 0) ||
4610afa8e06SEd Maste 	    (user->icon && cbor_add_string(item, "icon", user->icon) < 0) ||
4620afa8e06SEd Maste 	    (user->name && cbor_add_string(item, "name", user->name) < 0) ||
4630afa8e06SEd Maste 	    (display && cbor_add_string(item, "displayName", display) < 0)) {
4640afa8e06SEd Maste 		cbor_decref(&item);
4650afa8e06SEd Maste 		return (NULL);
4660afa8e06SEd Maste 	}
4670afa8e06SEd Maste 
4680afa8e06SEd Maste 	return (item);
4690afa8e06SEd Maste }
4700afa8e06SEd Maste 
4710afa8e06SEd Maste cbor_item_t *
cbor_encode_pubkey_param(int cose_alg)4720afa8e06SEd Maste cbor_encode_pubkey_param(int cose_alg)
4730afa8e06SEd Maste {
4740afa8e06SEd Maste 	cbor_item_t		*item = NULL;
4750afa8e06SEd Maste 	cbor_item_t		*body = NULL;
4760afa8e06SEd Maste 	struct cbor_pair	 alg;
4770afa8e06SEd Maste 	int			 ok = -1;
4780afa8e06SEd Maste 
4790afa8e06SEd Maste 	memset(&alg, 0, sizeof(alg));
4800afa8e06SEd Maste 
4810afa8e06SEd Maste 	if ((item = cbor_new_definite_array(1)) == NULL ||
4820afa8e06SEd Maste 	    (body = cbor_new_definite_map(2)) == NULL ||
4830afa8e06SEd Maste 	    cose_alg > -1 || cose_alg < INT16_MIN)
4840afa8e06SEd Maste 		goto fail;
4850afa8e06SEd Maste 
4860afa8e06SEd Maste 	alg.key = cbor_build_string("alg");
4870afa8e06SEd Maste 
4880afa8e06SEd Maste 	if (-cose_alg - 1 > UINT8_MAX)
4890afa8e06SEd Maste 		alg.value = cbor_build_negint16((uint16_t)(-cose_alg - 1));
4900afa8e06SEd Maste 	else
4910afa8e06SEd Maste 		alg.value = cbor_build_negint8((uint8_t)(-cose_alg - 1));
4920afa8e06SEd Maste 
4930afa8e06SEd Maste 	if (alg.key == NULL || alg.value == NULL) {
4940afa8e06SEd Maste 		fido_log_debug("%s: cbor_build", __func__);
4950afa8e06SEd Maste 		goto fail;
4960afa8e06SEd Maste 	}
4970afa8e06SEd Maste 
4980afa8e06SEd Maste 	if (cbor_map_add(body, alg) == false ||
4990afa8e06SEd Maste 	    cbor_add_string(body, "type", "public-key") < 0 ||
5000afa8e06SEd Maste 	    cbor_array_push(item, body) == false)
5010afa8e06SEd Maste 		goto fail;
5020afa8e06SEd Maste 
5030afa8e06SEd Maste 	ok  = 0;
5040afa8e06SEd Maste fail:
5050afa8e06SEd Maste 	if (ok < 0) {
5060afa8e06SEd Maste 		if (item != NULL) {
5070afa8e06SEd Maste 			cbor_decref(&item);
5080afa8e06SEd Maste 			item = NULL;
5090afa8e06SEd Maste 		}
5100afa8e06SEd Maste 	}
5110afa8e06SEd Maste 
5120afa8e06SEd Maste 	if (body != NULL)
5130afa8e06SEd Maste 		cbor_decref(&body);
5140afa8e06SEd Maste 	if (alg.key != NULL)
5150afa8e06SEd Maste 		cbor_decref(&alg.key);
5160afa8e06SEd Maste 	if (alg.value != NULL)
5170afa8e06SEd Maste 		cbor_decref(&alg.value);
5180afa8e06SEd Maste 
5190afa8e06SEd Maste 	return (item);
5200afa8e06SEd Maste }
5210afa8e06SEd Maste 
5220afa8e06SEd Maste cbor_item_t *
cbor_encode_pubkey(const fido_blob_t * pubkey)5230afa8e06SEd Maste cbor_encode_pubkey(const fido_blob_t *pubkey)
5240afa8e06SEd Maste {
5250afa8e06SEd Maste 	cbor_item_t *cbor_key = NULL;
5260afa8e06SEd Maste 
5270afa8e06SEd Maste 	if ((cbor_key = cbor_new_definite_map(2)) == NULL ||
5280afa8e06SEd Maste 	    cbor_add_bytestring(cbor_key, "id", pubkey->ptr, pubkey->len) < 0 ||
5290afa8e06SEd Maste 	    cbor_add_string(cbor_key, "type", "public-key") < 0) {
5300afa8e06SEd Maste 		if (cbor_key)
5310afa8e06SEd Maste 			cbor_decref(&cbor_key);
5320afa8e06SEd Maste 		return (NULL);
5330afa8e06SEd Maste 	}
5340afa8e06SEd Maste 
5350afa8e06SEd Maste 	return (cbor_key);
5360afa8e06SEd Maste }
5370afa8e06SEd Maste 
5380afa8e06SEd Maste cbor_item_t *
cbor_encode_pubkey_list(const fido_blob_array_t * list)5390afa8e06SEd Maste cbor_encode_pubkey_list(const fido_blob_array_t *list)
5400afa8e06SEd Maste {
5410afa8e06SEd Maste 	cbor_item_t	*array = NULL;
5420afa8e06SEd Maste 	cbor_item_t	*key = NULL;
5430afa8e06SEd Maste 
5440afa8e06SEd Maste 	if ((array = cbor_new_definite_array(list->len)) == NULL)
5450afa8e06SEd Maste 		goto fail;
5460afa8e06SEd Maste 
5470afa8e06SEd Maste 	for (size_t i = 0; i < list->len; i++) {
5480afa8e06SEd Maste 		if ((key = cbor_encode_pubkey(&list->ptr[i])) == NULL ||
5490afa8e06SEd Maste 		    cbor_array_push(array, key) == false)
5500afa8e06SEd Maste 			goto fail;
5510afa8e06SEd Maste 		cbor_decref(&key);
5520afa8e06SEd Maste 	}
5530afa8e06SEd Maste 
5540afa8e06SEd Maste 	return (array);
5550afa8e06SEd Maste fail:
5560afa8e06SEd Maste 	if (key != NULL)
5570afa8e06SEd Maste 		cbor_decref(&key);
5580afa8e06SEd Maste 	if (array != NULL)
5590afa8e06SEd Maste 		cbor_decref(&array);
5600afa8e06SEd Maste 
5610afa8e06SEd Maste 	return (NULL);
5620afa8e06SEd Maste }
5630afa8e06SEd Maste 
564f540a430SEd Maste cbor_item_t *
cbor_encode_str_array(const fido_str_array_t * a)565f540a430SEd Maste cbor_encode_str_array(const fido_str_array_t *a)
566f540a430SEd Maste {
567f540a430SEd Maste 	cbor_item_t	*array = NULL;
568f540a430SEd Maste 	cbor_item_t	*entry = NULL;
569f540a430SEd Maste 
570f540a430SEd Maste 	if ((array = cbor_new_definite_array(a->len)) == NULL)
571f540a430SEd Maste 		goto fail;
572f540a430SEd Maste 
573f540a430SEd Maste 	for (size_t i = 0; i < a->len; i++) {
574f540a430SEd Maste 		if ((entry = cbor_build_string(a->ptr[i])) == NULL ||
575f540a430SEd Maste 		    cbor_array_push(array, entry) == false)
576f540a430SEd Maste 			goto fail;
577f540a430SEd Maste 		cbor_decref(&entry);
578f540a430SEd Maste 	}
579f540a430SEd Maste 
580f540a430SEd Maste 	return (array);
581f540a430SEd Maste fail:
582f540a430SEd Maste 	if (entry != NULL)
583f540a430SEd Maste 		cbor_decref(&entry);
584f540a430SEd Maste 	if (array != NULL)
585f540a430SEd Maste 		cbor_decref(&array);
586f540a430SEd Maste 
587f540a430SEd Maste 	return (NULL);
588f540a430SEd Maste }
589f540a430SEd Maste 
5900afa8e06SEd Maste static int
cbor_encode_largeblob_key_ext(cbor_item_t * map)5910afa8e06SEd Maste cbor_encode_largeblob_key_ext(cbor_item_t *map)
5920afa8e06SEd Maste {
5930afa8e06SEd Maste 	if (map == NULL ||
5940afa8e06SEd Maste 	    cbor_add_bool(map, "largeBlobKey", FIDO_OPT_TRUE) < 0)
5950afa8e06SEd Maste 		return (-1);
5960afa8e06SEd Maste 
5970afa8e06SEd Maste 	return (0);
5980afa8e06SEd Maste }
5990afa8e06SEd Maste 
6000afa8e06SEd Maste cbor_item_t *
cbor_encode_cred_ext(const fido_cred_ext_t * ext,const fido_blob_t * blob)6010afa8e06SEd Maste cbor_encode_cred_ext(const fido_cred_ext_t *ext, const fido_blob_t *blob)
6020afa8e06SEd Maste {
6030afa8e06SEd Maste 	cbor_item_t *item = NULL;
6040afa8e06SEd Maste 	size_t size = 0;
6050afa8e06SEd Maste 
6060afa8e06SEd Maste 	if (ext->mask & FIDO_EXT_CRED_BLOB)
6070afa8e06SEd Maste 		size++;
6080afa8e06SEd Maste 	if (ext->mask & FIDO_EXT_HMAC_SECRET)
6090afa8e06SEd Maste 		size++;
6100afa8e06SEd Maste 	if (ext->mask & FIDO_EXT_CRED_PROTECT)
6110afa8e06SEd Maste 		size++;
6120afa8e06SEd Maste 	if (ext->mask & FIDO_EXT_LARGEBLOB_KEY)
6130afa8e06SEd Maste 		size++;
614f540a430SEd Maste 	if (ext->mask & FIDO_EXT_MINPINLEN)
615f540a430SEd Maste 		size++;
6160afa8e06SEd Maste 
6170afa8e06SEd Maste 	if (size == 0 || (item = cbor_new_definite_map(size)) == NULL)
6180afa8e06SEd Maste 		return (NULL);
6190afa8e06SEd Maste 
6200afa8e06SEd Maste 	if (ext->mask & FIDO_EXT_CRED_BLOB) {
6210afa8e06SEd Maste 		if (cbor_add_bytestring(item, "credBlob", blob->ptr,
6220afa8e06SEd Maste 		    blob->len) < 0) {
6230afa8e06SEd Maste 			cbor_decref(&item);
6240afa8e06SEd Maste 			return (NULL);
6250afa8e06SEd Maste 		}
6260afa8e06SEd Maste 	}
6270afa8e06SEd Maste 	if (ext->mask & FIDO_EXT_CRED_PROTECT) {
6280afa8e06SEd Maste 		if (ext->prot < 0 || ext->prot > UINT8_MAX ||
6290afa8e06SEd Maste 		    cbor_add_uint8(item, "credProtect",
6300afa8e06SEd Maste 		    (uint8_t)ext->prot) < 0) {
6310afa8e06SEd Maste 			cbor_decref(&item);
6320afa8e06SEd Maste 			return (NULL);
6330afa8e06SEd Maste 		}
6340afa8e06SEd Maste 	}
6350afa8e06SEd Maste 	if (ext->mask & FIDO_EXT_HMAC_SECRET) {
6360afa8e06SEd Maste 		if (cbor_add_bool(item, "hmac-secret", FIDO_OPT_TRUE) < 0) {
6370afa8e06SEd Maste 			cbor_decref(&item);
6380afa8e06SEd Maste 			return (NULL);
6390afa8e06SEd Maste 		}
6400afa8e06SEd Maste 	}
6410afa8e06SEd Maste 	if (ext->mask & FIDO_EXT_LARGEBLOB_KEY) {
6420afa8e06SEd Maste 		if (cbor_encode_largeblob_key_ext(item) < 0) {
6430afa8e06SEd Maste 			cbor_decref(&item);
6440afa8e06SEd Maste 			return (NULL);
6450afa8e06SEd Maste 		}
6460afa8e06SEd Maste 	}
647f540a430SEd Maste 	if (ext->mask & FIDO_EXT_MINPINLEN) {
648f540a430SEd Maste 		if (cbor_add_bool(item, "minPinLength", FIDO_OPT_TRUE) < 0) {
649f540a430SEd Maste 			cbor_decref(&item);
650f540a430SEd Maste 			return (NULL);
651f540a430SEd Maste 		}
652f540a430SEd Maste 	}
6530afa8e06SEd Maste 
6540afa8e06SEd Maste 	return (item);
6550afa8e06SEd Maste }
6560afa8e06SEd Maste 
6570afa8e06SEd Maste cbor_item_t *
cbor_encode_cred_opt(fido_opt_t rk,fido_opt_t uv)6580afa8e06SEd Maste cbor_encode_cred_opt(fido_opt_t rk, fido_opt_t uv)
6590afa8e06SEd Maste {
6600afa8e06SEd Maste 	cbor_item_t *item = NULL;
6610afa8e06SEd Maste 
6620afa8e06SEd Maste 	if ((item = cbor_new_definite_map(2)) == NULL)
6630afa8e06SEd Maste 		return (NULL);
6640afa8e06SEd Maste 	if ((rk != FIDO_OPT_OMIT && cbor_add_bool(item, "rk", rk) < 0) ||
6650afa8e06SEd Maste 	    (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) {
6660afa8e06SEd Maste 		cbor_decref(&item);
6670afa8e06SEd Maste 		return (NULL);
6680afa8e06SEd Maste 	}
6690afa8e06SEd Maste 
6700afa8e06SEd Maste 	return (item);
6710afa8e06SEd Maste }
6720afa8e06SEd Maste 
6730afa8e06SEd Maste cbor_item_t *
cbor_encode_assert_opt(fido_opt_t up,fido_opt_t uv)6740afa8e06SEd Maste cbor_encode_assert_opt(fido_opt_t up, fido_opt_t uv)
6750afa8e06SEd Maste {
6760afa8e06SEd Maste 	cbor_item_t *item = NULL;
6770afa8e06SEd Maste 
6780afa8e06SEd Maste 	if ((item = cbor_new_definite_map(2)) == NULL)
6790afa8e06SEd Maste 		return (NULL);
6800afa8e06SEd Maste 	if ((up != FIDO_OPT_OMIT && cbor_add_bool(item, "up", up) < 0) ||
6810afa8e06SEd Maste 	    (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) {
6820afa8e06SEd Maste 		cbor_decref(&item);
6830afa8e06SEd Maste 		return (NULL);
6840afa8e06SEd Maste 	}
6850afa8e06SEd Maste 
6860afa8e06SEd Maste 	return (item);
6870afa8e06SEd Maste }
6880afa8e06SEd Maste 
6890afa8e06SEd Maste cbor_item_t *
cbor_encode_pin_auth(const fido_dev_t * dev,const fido_blob_t * secret,const fido_blob_t * data)6900afa8e06SEd Maste cbor_encode_pin_auth(const fido_dev_t *dev, const fido_blob_t *secret,
6910afa8e06SEd Maste     const fido_blob_t *data)
6920afa8e06SEd Maste {
6930afa8e06SEd Maste 	const EVP_MD	*md = NULL;
6940afa8e06SEd Maste 	unsigned char	 dgst[SHA256_DIGEST_LENGTH];
6950afa8e06SEd Maste 	unsigned int	 dgst_len;
6960afa8e06SEd Maste 	size_t		 outlen;
6970afa8e06SEd Maste 	uint8_t		 prot;
6980afa8e06SEd Maste 	fido_blob_t	 key;
6990afa8e06SEd Maste 
7000afa8e06SEd Maste 	key.ptr = secret->ptr;
7010afa8e06SEd Maste 	key.len = secret->len;
7020afa8e06SEd Maste 
7030afa8e06SEd Maste 	if ((prot = fido_dev_get_pin_protocol(dev)) == 0) {
7040afa8e06SEd Maste 		fido_log_debug("%s: fido_dev_get_pin_protocol", __func__);
7050afa8e06SEd Maste 		return (NULL);
7060afa8e06SEd Maste 	}
7070afa8e06SEd Maste 
7080afa8e06SEd Maste 	/* select hmac portion of the shared secret */
7090afa8e06SEd Maste 	if (prot == CTAP_PIN_PROTOCOL2 && key.len > 32)
7100afa8e06SEd Maste 		key.len = 32;
7110afa8e06SEd Maste 
7120afa8e06SEd Maste 	if ((md = EVP_sha256()) == NULL || HMAC(md, key.ptr,
7130afa8e06SEd Maste 	    (int)key.len, data->ptr, data->len, dgst,
7140afa8e06SEd Maste 	    &dgst_len) == NULL || dgst_len != SHA256_DIGEST_LENGTH)
7150afa8e06SEd Maste 		return (NULL);
7160afa8e06SEd Maste 
7170afa8e06SEd Maste 	outlen = (prot == CTAP_PIN_PROTOCOL1) ? 16 : dgst_len;
7180afa8e06SEd Maste 
7190afa8e06SEd Maste 	return (cbor_build_bytestring(dgst, outlen));
7200afa8e06SEd Maste }
7210afa8e06SEd Maste 
7220afa8e06SEd Maste cbor_item_t *
cbor_encode_pin_opt(const fido_dev_t * dev)7230afa8e06SEd Maste cbor_encode_pin_opt(const fido_dev_t *dev)
7240afa8e06SEd Maste {
7250afa8e06SEd Maste 	uint8_t	    prot;
7260afa8e06SEd Maste 
7270afa8e06SEd Maste 	if ((prot = fido_dev_get_pin_protocol(dev)) == 0) {
7280afa8e06SEd Maste 		fido_log_debug("%s: fido_dev_get_pin_protocol", __func__);
7290afa8e06SEd Maste 		return (NULL);
7300afa8e06SEd Maste 	}
7310afa8e06SEd Maste 
7320afa8e06SEd Maste 	return (cbor_build_uint8(prot));
7330afa8e06SEd Maste }
7340afa8e06SEd Maste 
7350afa8e06SEd Maste cbor_item_t *
cbor_encode_change_pin_auth(const fido_dev_t * dev,const fido_blob_t * secret,const fido_blob_t * new_pin_enc,const fido_blob_t * pin_hash_enc)7360afa8e06SEd Maste cbor_encode_change_pin_auth(const fido_dev_t *dev, const fido_blob_t *secret,
7370afa8e06SEd Maste     const fido_blob_t *new_pin_enc, const fido_blob_t *pin_hash_enc)
7380afa8e06SEd Maste {
7390afa8e06SEd Maste 	unsigned char	 dgst[SHA256_DIGEST_LENGTH];
7400afa8e06SEd Maste 	unsigned int	 dgst_len;
7410afa8e06SEd Maste 	cbor_item_t	*item = NULL;
7420afa8e06SEd Maste 	const EVP_MD	*md = NULL;
7430afa8e06SEd Maste 	HMAC_CTX	*ctx = NULL;
7440afa8e06SEd Maste 	fido_blob_t	 key;
7450afa8e06SEd Maste 	uint8_t		 prot;
7460afa8e06SEd Maste 	size_t		 outlen;
7470afa8e06SEd Maste 
7480afa8e06SEd Maste 	key.ptr = secret->ptr;
7490afa8e06SEd Maste 	key.len = secret->len;
7500afa8e06SEd Maste 
7510afa8e06SEd Maste 	if ((prot = fido_dev_get_pin_protocol(dev)) == 0) {
7520afa8e06SEd Maste 		fido_log_debug("%s: fido_dev_get_pin_protocol", __func__);
7530afa8e06SEd Maste 		goto fail;
7540afa8e06SEd Maste 	}
7550afa8e06SEd Maste 
7560afa8e06SEd Maste 	if (prot == CTAP_PIN_PROTOCOL2 && key.len > 32)
7570afa8e06SEd Maste 		key.len = 32;
7580afa8e06SEd Maste 
7590afa8e06SEd Maste 	if ((ctx = HMAC_CTX_new()) == NULL ||
7600afa8e06SEd Maste 	    (md = EVP_sha256())  == NULL ||
7610afa8e06SEd Maste 	    HMAC_Init_ex(ctx, key.ptr, (int)key.len, md, NULL) == 0 ||
7620afa8e06SEd Maste 	    HMAC_Update(ctx, new_pin_enc->ptr, new_pin_enc->len) == 0 ||
7630afa8e06SEd Maste 	    HMAC_Update(ctx, pin_hash_enc->ptr, pin_hash_enc->len) == 0 ||
7640afa8e06SEd Maste 	    HMAC_Final(ctx, dgst, &dgst_len) == 0 ||
7650afa8e06SEd Maste 	    dgst_len != SHA256_DIGEST_LENGTH) {
7660afa8e06SEd Maste 		fido_log_debug("%s: HMAC", __func__);
7670afa8e06SEd Maste 		goto fail;
7680afa8e06SEd Maste 	}
7690afa8e06SEd Maste 
7700afa8e06SEd Maste 	outlen = (prot == CTAP_PIN_PROTOCOL1) ? 16 : dgst_len;
7710afa8e06SEd Maste 
7720afa8e06SEd Maste 	if ((item = cbor_build_bytestring(dgst, outlen)) == NULL) {
7730afa8e06SEd Maste 		fido_log_debug("%s: cbor_build_bytestring", __func__);
7740afa8e06SEd Maste 		goto fail;
7750afa8e06SEd Maste 	}
7760afa8e06SEd Maste 
7770afa8e06SEd Maste fail:
7780afa8e06SEd Maste 	HMAC_CTX_free(ctx);
7790afa8e06SEd Maste 
7800afa8e06SEd Maste 	return (item);
7810afa8e06SEd Maste }
7820afa8e06SEd Maste 
7830afa8e06SEd Maste static int
cbor_encode_hmac_secret_param(const fido_dev_t * dev,cbor_item_t * item,const fido_blob_t * ecdh,const es256_pk_t * pk,const fido_blob_t * salt)7840afa8e06SEd Maste cbor_encode_hmac_secret_param(const fido_dev_t *dev, cbor_item_t *item,
7850afa8e06SEd Maste     const fido_blob_t *ecdh, const es256_pk_t *pk, const fido_blob_t *salt)
7860afa8e06SEd Maste {
7870afa8e06SEd Maste 	cbor_item_t		*param = NULL;
7880afa8e06SEd Maste 	cbor_item_t		*argv[4];
7890afa8e06SEd Maste 	struct cbor_pair	 pair;
7900afa8e06SEd Maste 	fido_blob_t		*enc = NULL;
791f540a430SEd Maste 	uint8_t			 prot;
7920afa8e06SEd Maste 	int			 r;
7930afa8e06SEd Maste 
7940afa8e06SEd Maste 	memset(argv, 0, sizeof(argv));
7950afa8e06SEd Maste 	memset(&pair, 0, sizeof(pair));
7960afa8e06SEd Maste 
7970afa8e06SEd Maste 	if (item == NULL || ecdh == NULL || pk == NULL || salt->ptr == NULL) {
7980afa8e06SEd Maste 		fido_log_debug("%s: ecdh=%p, pk=%p, salt->ptr=%p", __func__,
7990afa8e06SEd Maste 		    (const void *)ecdh, (const void *)pk,
8000afa8e06SEd Maste 		    (const void *)salt->ptr);
8010afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
8020afa8e06SEd Maste 		goto fail;
8030afa8e06SEd Maste 	}
8040afa8e06SEd Maste 
8050afa8e06SEd Maste 	if (salt->len != 32 && salt->len != 64) {
8060afa8e06SEd Maste 		fido_log_debug("%s: salt->len=%zu", __func__, salt->len);
8070afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
8080afa8e06SEd Maste 		goto fail;
8090afa8e06SEd Maste 	}
8100afa8e06SEd Maste 
8110afa8e06SEd Maste 	if ((enc = fido_blob_new()) == NULL ||
8120afa8e06SEd Maste 	    aes256_cbc_enc(dev, ecdh, salt, enc) < 0) {
8130afa8e06SEd Maste 		fido_log_debug("%s: aes256_cbc_enc", __func__);
8140afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
8150afa8e06SEd Maste 		goto fail;
8160afa8e06SEd Maste 	}
8170afa8e06SEd Maste 
818f540a430SEd Maste 	if ((prot = fido_dev_get_pin_protocol(dev)) == 0) {
819f540a430SEd Maste 		fido_log_debug("%s: fido_dev_get_pin_protocol", __func__);
820f540a430SEd Maste 		r = FIDO_ERR_INTERNAL;
821f540a430SEd Maste 		goto fail;
822f540a430SEd Maste 	}
823f540a430SEd Maste 
8240afa8e06SEd Maste 	/* XXX not pin, but salt */
8250afa8e06SEd Maste 	if ((argv[0] = es256_pk_encode(pk, 1)) == NULL ||
8260afa8e06SEd Maste 	    (argv[1] = fido_blob_encode(enc)) == NULL ||
8270afa8e06SEd Maste 	    (argv[2] = cbor_encode_pin_auth(dev, ecdh, enc)) == NULL ||
828f540a430SEd Maste 	    (prot != 1 && (argv[3] = cbor_build_uint8(prot)) == NULL)) {
8290afa8e06SEd Maste 		fido_log_debug("%s: cbor encode", __func__);
8300afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
8310afa8e06SEd Maste 		goto fail;
8320afa8e06SEd Maste 	}
8330afa8e06SEd Maste 
8340afa8e06SEd Maste 	if ((param = cbor_flatten_vector(argv, nitems(argv))) == NULL) {
8350afa8e06SEd Maste 		fido_log_debug("%s: cbor_flatten_vector", __func__);
8360afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
8370afa8e06SEd Maste 		goto fail;
8380afa8e06SEd Maste 	}
8390afa8e06SEd Maste 
8400afa8e06SEd Maste 	if ((pair.key = cbor_build_string("hmac-secret")) == NULL) {
8410afa8e06SEd Maste 		fido_log_debug("%s: cbor_build", __func__);
8420afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
8430afa8e06SEd Maste 		goto fail;
8440afa8e06SEd Maste 	}
8450afa8e06SEd Maste 
8460afa8e06SEd Maste 	pair.value = param;
8470afa8e06SEd Maste 
8480afa8e06SEd Maste 	if (!cbor_map_add(item, pair)) {
8490afa8e06SEd Maste 		fido_log_debug("%s: cbor_map_add", __func__);
8500afa8e06SEd Maste 		r = FIDO_ERR_INTERNAL;
8510afa8e06SEd Maste 		goto fail;
8520afa8e06SEd Maste 	}
8530afa8e06SEd Maste 
8540afa8e06SEd Maste 	r = FIDO_OK;
8550afa8e06SEd Maste 
8560afa8e06SEd Maste fail:
8570afa8e06SEd Maste 	cbor_vector_free(argv, nitems(argv));
8580afa8e06SEd Maste 
8590afa8e06SEd Maste 	if (param != NULL)
8600afa8e06SEd Maste 		cbor_decref(&param);
8610afa8e06SEd Maste 	if (pair.key != NULL)
8620afa8e06SEd Maste 		cbor_decref(&pair.key);
8630afa8e06SEd Maste 
8640afa8e06SEd Maste 	fido_blob_free(&enc);
8650afa8e06SEd Maste 
8660afa8e06SEd Maste 	return (r);
8670afa8e06SEd Maste }
8680afa8e06SEd Maste 
8690afa8e06SEd Maste cbor_item_t *
cbor_encode_assert_ext(fido_dev_t * dev,const fido_assert_ext_t * ext,const fido_blob_t * ecdh,const es256_pk_t * pk)8700afa8e06SEd Maste cbor_encode_assert_ext(fido_dev_t *dev, const fido_assert_ext_t *ext,
8710afa8e06SEd Maste     const fido_blob_t *ecdh, const es256_pk_t *pk)
8720afa8e06SEd Maste {
8730afa8e06SEd Maste 	cbor_item_t *item = NULL;
8740afa8e06SEd Maste 	size_t size = 0;
8750afa8e06SEd Maste 
8760afa8e06SEd Maste 	if (ext->mask & FIDO_EXT_CRED_BLOB)
8770afa8e06SEd Maste 		size++;
8780afa8e06SEd Maste 	if (ext->mask & FIDO_EXT_HMAC_SECRET)
8790afa8e06SEd Maste 		size++;
8800afa8e06SEd Maste 	if (ext->mask & FIDO_EXT_LARGEBLOB_KEY)
8810afa8e06SEd Maste 		size++;
8820afa8e06SEd Maste 	if (size == 0 || (item = cbor_new_definite_map(size)) == NULL)
8830afa8e06SEd Maste 		return (NULL);
8840afa8e06SEd Maste 
8850afa8e06SEd Maste 	if (ext->mask & FIDO_EXT_CRED_BLOB) {
8860afa8e06SEd Maste 		if (cbor_add_bool(item, "credBlob", FIDO_OPT_TRUE) < 0) {
8870afa8e06SEd Maste 			cbor_decref(&item);
8880afa8e06SEd Maste 			return (NULL);
8890afa8e06SEd Maste 		}
8900afa8e06SEd Maste 	}
8910afa8e06SEd Maste 	if (ext->mask & FIDO_EXT_HMAC_SECRET) {
8920afa8e06SEd Maste 		if (cbor_encode_hmac_secret_param(dev, item, ecdh, pk,
8930afa8e06SEd Maste 		    &ext->hmac_salt) < 0) {
8940afa8e06SEd Maste 			cbor_decref(&item);
8950afa8e06SEd Maste 			return (NULL);
8960afa8e06SEd Maste 		}
8970afa8e06SEd Maste 	}
8980afa8e06SEd Maste 	if (ext->mask & FIDO_EXT_LARGEBLOB_KEY) {
8990afa8e06SEd Maste 		if (cbor_encode_largeblob_key_ext(item) < 0) {
9000afa8e06SEd Maste 			cbor_decref(&item);
9010afa8e06SEd Maste 			return (NULL);
9020afa8e06SEd Maste 		}
9030afa8e06SEd Maste 	}
9040afa8e06SEd Maste 
9050afa8e06SEd Maste 	return (item);
9060afa8e06SEd Maste }
9070afa8e06SEd Maste 
9080afa8e06SEd Maste int
cbor_decode_fmt(const cbor_item_t * item,char ** fmt)9090afa8e06SEd Maste cbor_decode_fmt(const cbor_item_t *item, char **fmt)
9100afa8e06SEd Maste {
9110afa8e06SEd Maste 	char	*type = NULL;
9120afa8e06SEd Maste 
9130afa8e06SEd Maste 	if (cbor_string_copy(item, &type) < 0) {
9140afa8e06SEd Maste 		fido_log_debug("%s: cbor_string_copy", __func__);
9150afa8e06SEd Maste 		return (-1);
9160afa8e06SEd Maste 	}
9170afa8e06SEd Maste 
9180afa8e06SEd Maste 	if (strcmp(type, "packed") && strcmp(type, "fido-u2f") &&
919f540a430SEd Maste 	    strcmp(type, "none") && strcmp(type, "tpm")) {
9200afa8e06SEd Maste 		fido_log_debug("%s: type=%s", __func__, type);
9210afa8e06SEd Maste 		free(type);
9220afa8e06SEd Maste 		return (-1);
9230afa8e06SEd Maste 	}
9240afa8e06SEd Maste 
9250afa8e06SEd Maste 	*fmt = type;
9260afa8e06SEd Maste 
9270afa8e06SEd Maste 	return (0);
9280afa8e06SEd Maste }
9290afa8e06SEd Maste 
9300afa8e06SEd Maste struct cose_key {
9310afa8e06SEd Maste 	int kty;
9320afa8e06SEd Maste 	int alg;
9330afa8e06SEd Maste 	int crv;
9340afa8e06SEd Maste };
9350afa8e06SEd Maste 
9360afa8e06SEd Maste static int
find_cose_alg(const cbor_item_t * key,const cbor_item_t * val,void * arg)9370afa8e06SEd Maste find_cose_alg(const cbor_item_t *key, const cbor_item_t *val, void *arg)
9380afa8e06SEd Maste {
9390afa8e06SEd Maste 	struct cose_key *cose_key = arg;
9400afa8e06SEd Maste 
9410afa8e06SEd Maste 	if (cbor_isa_uint(key) == true &&
9420afa8e06SEd Maste 	    cbor_int_get_width(key) == CBOR_INT_8) {
9430afa8e06SEd Maste 		switch (cbor_get_uint8(key)) {
9440afa8e06SEd Maste 		case 1:
9450afa8e06SEd Maste 			if (cbor_isa_uint(val) == false ||
9460afa8e06SEd Maste 			    cbor_get_int(val) > INT_MAX || cose_key->kty != 0) {
9470afa8e06SEd Maste 				fido_log_debug("%s: kty", __func__);
9480afa8e06SEd Maste 				return (-1);
9490afa8e06SEd Maste 			}
9500afa8e06SEd Maste 
9510afa8e06SEd Maste 			cose_key->kty = (int)cbor_get_int(val);
9520afa8e06SEd Maste 
9530afa8e06SEd Maste 			break;
9540afa8e06SEd Maste 		case 3:
9550afa8e06SEd Maste 			if (cbor_isa_negint(val) == false ||
9560afa8e06SEd Maste 			    cbor_get_int(val) > INT_MAX || cose_key->alg != 0) {
9570afa8e06SEd Maste 				fido_log_debug("%s: alg", __func__);
9580afa8e06SEd Maste 				return (-1);
9590afa8e06SEd Maste 			}
9600afa8e06SEd Maste 
9610afa8e06SEd Maste 			cose_key->alg = -(int)cbor_get_int(val) - 1;
9620afa8e06SEd Maste 
9630afa8e06SEd Maste 			break;
9640afa8e06SEd Maste 		}
9650afa8e06SEd Maste 	} else if (cbor_isa_negint(key) == true &&
9660afa8e06SEd Maste 	    cbor_int_get_width(key) == CBOR_INT_8) {
9670afa8e06SEd Maste 		if (cbor_get_uint8(key) == 0) {
9680afa8e06SEd Maste 			/* get crv if not rsa, otherwise ignore */
9690afa8e06SEd Maste 			if (cbor_isa_uint(val) == true &&
9700afa8e06SEd Maste 			    cbor_get_int(val) <= INT_MAX &&
9710afa8e06SEd Maste 			    cose_key->crv == 0)
9720afa8e06SEd Maste 				cose_key->crv = (int)cbor_get_int(val);
9730afa8e06SEd Maste 		}
9740afa8e06SEd Maste 	}
9750afa8e06SEd Maste 
9760afa8e06SEd Maste 	return (0);
9770afa8e06SEd Maste }
9780afa8e06SEd Maste 
9790afa8e06SEd Maste static int
get_cose_alg(const cbor_item_t * item,int * cose_alg)9800afa8e06SEd Maste get_cose_alg(const cbor_item_t *item, int *cose_alg)
9810afa8e06SEd Maste {
9820afa8e06SEd Maste 	struct cose_key cose_key;
9830afa8e06SEd Maste 
9840afa8e06SEd Maste 	memset(&cose_key, 0, sizeof(cose_key));
9850afa8e06SEd Maste 
9860afa8e06SEd Maste 	*cose_alg = 0;
9870afa8e06SEd Maste 
9880afa8e06SEd Maste 	if (cbor_isa_map(item) == false ||
9890afa8e06SEd Maste 	    cbor_map_is_definite(item) == false ||
9900afa8e06SEd Maste 	    cbor_map_iter(item, &cose_key, find_cose_alg) < 0) {
9910afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
9920afa8e06SEd Maste 		return (-1);
9930afa8e06SEd Maste 	}
9940afa8e06SEd Maste 
9950afa8e06SEd Maste 	switch (cose_key.alg) {
9960afa8e06SEd Maste 	case COSE_ES256:
9970afa8e06SEd Maste 		if (cose_key.kty != COSE_KTY_EC2 ||
9980afa8e06SEd Maste 		    cose_key.crv != COSE_P256) {
9990afa8e06SEd Maste 			fido_log_debug("%s: invalid kty/crv", __func__);
10000afa8e06SEd Maste 			return (-1);
10010afa8e06SEd Maste 		}
1002*2ccfa855SEd Maste 		break;
1003*2ccfa855SEd Maste 	case COSE_ES384:
1004*2ccfa855SEd Maste 		if (cose_key.kty != COSE_KTY_EC2 ||
1005*2ccfa855SEd Maste 		    cose_key.crv != COSE_P384) {
1006*2ccfa855SEd Maste 			fido_log_debug("%s: invalid kty/crv", __func__);
1007*2ccfa855SEd Maste 			return (-1);
1008*2ccfa855SEd Maste 		}
10090afa8e06SEd Maste 		break;
10100afa8e06SEd Maste 	case COSE_EDDSA:
10110afa8e06SEd Maste 		if (cose_key.kty != COSE_KTY_OKP ||
10120afa8e06SEd Maste 		    cose_key.crv != COSE_ED25519) {
10130afa8e06SEd Maste 			fido_log_debug("%s: invalid kty/crv", __func__);
10140afa8e06SEd Maste 			return (-1);
10150afa8e06SEd Maste 		}
10160afa8e06SEd Maste 		break;
10170afa8e06SEd Maste 	case COSE_RS256:
10180afa8e06SEd Maste 		if (cose_key.kty != COSE_KTY_RSA) {
10190afa8e06SEd Maste 			fido_log_debug("%s: invalid kty/crv", __func__);
10200afa8e06SEd Maste 			return (-1);
10210afa8e06SEd Maste 		}
10220afa8e06SEd Maste 		break;
10230afa8e06SEd Maste 	default:
10240afa8e06SEd Maste 		fido_log_debug("%s: unknown alg %d", __func__, cose_key.alg);
10250afa8e06SEd Maste 
10260afa8e06SEd Maste 		return (-1);
10270afa8e06SEd Maste 	}
10280afa8e06SEd Maste 
10290afa8e06SEd Maste 	*cose_alg = cose_key.alg;
10300afa8e06SEd Maste 
10310afa8e06SEd Maste 	return (0);
10320afa8e06SEd Maste }
10330afa8e06SEd Maste 
10340afa8e06SEd Maste int
cbor_decode_pubkey(const cbor_item_t * item,int * type,void * key)10350afa8e06SEd Maste cbor_decode_pubkey(const cbor_item_t *item, int *type, void *key)
10360afa8e06SEd Maste {
10370afa8e06SEd Maste 	if (get_cose_alg(item, type) < 0) {
10380afa8e06SEd Maste 		fido_log_debug("%s: get_cose_alg", __func__);
10390afa8e06SEd Maste 		return (-1);
10400afa8e06SEd Maste 	}
10410afa8e06SEd Maste 
10420afa8e06SEd Maste 	switch (*type) {
10430afa8e06SEd Maste 	case COSE_ES256:
10440afa8e06SEd Maste 		if (es256_pk_decode(item, key) < 0) {
10450afa8e06SEd Maste 			fido_log_debug("%s: es256_pk_decode", __func__);
10460afa8e06SEd Maste 			return (-1);
10470afa8e06SEd Maste 		}
10480afa8e06SEd Maste 		break;
1049*2ccfa855SEd Maste 	case COSE_ES384:
1050*2ccfa855SEd Maste 		if (es384_pk_decode(item, key) < 0) {
1051*2ccfa855SEd Maste 			fido_log_debug("%s: es384_pk_decode", __func__);
1052*2ccfa855SEd Maste 			return (-1);
1053*2ccfa855SEd Maste 		}
1054*2ccfa855SEd Maste 		break;
10550afa8e06SEd Maste 	case COSE_RS256:
10560afa8e06SEd Maste 		if (rs256_pk_decode(item, key) < 0) {
10570afa8e06SEd Maste 			fido_log_debug("%s: rs256_pk_decode", __func__);
10580afa8e06SEd Maste 			return (-1);
10590afa8e06SEd Maste 		}
10600afa8e06SEd Maste 		break;
10610afa8e06SEd Maste 	case COSE_EDDSA:
10620afa8e06SEd Maste 		if (eddsa_pk_decode(item, key) < 0) {
10630afa8e06SEd Maste 			fido_log_debug("%s: eddsa_pk_decode", __func__);
10640afa8e06SEd Maste 			return (-1);
10650afa8e06SEd Maste 		}
10660afa8e06SEd Maste 		break;
10670afa8e06SEd Maste 	default:
10680afa8e06SEd Maste 		fido_log_debug("%s: invalid cose_alg %d", __func__, *type);
10690afa8e06SEd Maste 		return (-1);
10700afa8e06SEd Maste 	}
10710afa8e06SEd Maste 
10720afa8e06SEd Maste 	return (0);
10730afa8e06SEd Maste }
10740afa8e06SEd Maste 
10750afa8e06SEd Maste static int
decode_attcred(const unsigned char ** buf,size_t * len,int cose_alg,fido_attcred_t * attcred)10760afa8e06SEd Maste decode_attcred(const unsigned char **buf, size_t *len, int cose_alg,
10770afa8e06SEd Maste     fido_attcred_t *attcred)
10780afa8e06SEd Maste {
10790afa8e06SEd Maste 	cbor_item_t		*item = NULL;
10800afa8e06SEd Maste 	struct cbor_load_result	 cbor;
10810afa8e06SEd Maste 	uint16_t		 id_len;
10820afa8e06SEd Maste 	int			 ok = -1;
10830afa8e06SEd Maste 
10840afa8e06SEd Maste 	fido_log_xxd(*buf, *len, "%s", __func__);
10850afa8e06SEd Maste 
10860afa8e06SEd Maste 	if (fido_buf_read(buf, len, &attcred->aaguid,
10870afa8e06SEd Maste 	    sizeof(attcred->aaguid)) < 0) {
10880afa8e06SEd Maste 		fido_log_debug("%s: fido_buf_read aaguid", __func__);
10890afa8e06SEd Maste 		return (-1);
10900afa8e06SEd Maste 	}
10910afa8e06SEd Maste 
10920afa8e06SEd Maste 	if (fido_buf_read(buf, len, &id_len, sizeof(id_len)) < 0) {
10930afa8e06SEd Maste 		fido_log_debug("%s: fido_buf_read id_len", __func__);
10940afa8e06SEd Maste 		return (-1);
10950afa8e06SEd Maste 	}
10960afa8e06SEd Maste 
10970afa8e06SEd Maste 	attcred->id.len = (size_t)be16toh(id_len);
10980afa8e06SEd Maste 	if ((attcred->id.ptr = malloc(attcred->id.len)) == NULL)
10990afa8e06SEd Maste 		return (-1);
11000afa8e06SEd Maste 
11010afa8e06SEd Maste 	fido_log_debug("%s: attcred->id.len=%zu", __func__, attcred->id.len);
11020afa8e06SEd Maste 
11030afa8e06SEd Maste 	if (fido_buf_read(buf, len, attcred->id.ptr, attcred->id.len) < 0) {
11040afa8e06SEd Maste 		fido_log_debug("%s: fido_buf_read id", __func__);
11050afa8e06SEd Maste 		return (-1);
11060afa8e06SEd Maste 	}
11070afa8e06SEd Maste 
11080afa8e06SEd Maste 	if ((item = cbor_load(*buf, *len, &cbor)) == NULL) {
11090afa8e06SEd Maste 		fido_log_debug("%s: cbor_load", __func__);
11100afa8e06SEd Maste 		goto fail;
11110afa8e06SEd Maste 	}
11120afa8e06SEd Maste 
11130afa8e06SEd Maste 	if (cbor_decode_pubkey(item, &attcred->type, &attcred->pubkey) < 0) {
11140afa8e06SEd Maste 		fido_log_debug("%s: cbor_decode_pubkey", __func__);
11150afa8e06SEd Maste 		goto fail;
11160afa8e06SEd Maste 	}
11170afa8e06SEd Maste 
11180afa8e06SEd Maste 	if (attcred->type != cose_alg) {
11190afa8e06SEd Maste 		fido_log_debug("%s: cose_alg mismatch (%d != %d)", __func__,
11200afa8e06SEd Maste 		    attcred->type, cose_alg);
11210afa8e06SEd Maste 		goto fail;
11220afa8e06SEd Maste 	}
11230afa8e06SEd Maste 
11240afa8e06SEd Maste 	*buf += cbor.read;
11250afa8e06SEd Maste 	*len -= cbor.read;
11260afa8e06SEd Maste 
11270afa8e06SEd Maste 	ok = 0;
11280afa8e06SEd Maste fail:
11290afa8e06SEd Maste 	if (item != NULL)
11300afa8e06SEd Maste 		cbor_decref(&item);
11310afa8e06SEd Maste 
11320afa8e06SEd Maste 	return (ok);
11330afa8e06SEd Maste }
11340afa8e06SEd Maste 
11350afa8e06SEd Maste static int
decode_cred_extension(const cbor_item_t * key,const cbor_item_t * val,void * arg)11360afa8e06SEd Maste decode_cred_extension(const cbor_item_t *key, const cbor_item_t *val, void *arg)
11370afa8e06SEd Maste {
11380afa8e06SEd Maste 	fido_cred_ext_t	*authdata_ext = arg;
11390afa8e06SEd Maste 	char		*type = NULL;
11400afa8e06SEd Maste 	int		 ok = -1;
11410afa8e06SEd Maste 
11420afa8e06SEd Maste 	if (cbor_string_copy(key, &type) < 0) {
11430afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
11440afa8e06SEd Maste 		ok = 0; /* ignore */
11450afa8e06SEd Maste 		goto out;
11460afa8e06SEd Maste 	}
11470afa8e06SEd Maste 
11480afa8e06SEd Maste 	if (strcmp(type, "hmac-secret") == 0) {
1149*2ccfa855SEd Maste 		if (cbor_decode_bool(val, NULL) < 0) {
1150*2ccfa855SEd Maste 			fido_log_debug("%s: cbor_decode_bool", __func__);
11510afa8e06SEd Maste 			goto out;
11520afa8e06SEd Maste 		}
11530afa8e06SEd Maste 		if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE)
11540afa8e06SEd Maste 			authdata_ext->mask |= FIDO_EXT_HMAC_SECRET;
11550afa8e06SEd Maste 	} else if (strcmp(type, "credProtect") == 0) {
11560afa8e06SEd Maste 		if (cbor_isa_uint(val) == false ||
11570afa8e06SEd Maste 		    cbor_int_get_width(val) != CBOR_INT_8) {
11580afa8e06SEd Maste 			fido_log_debug("%s: cbor type", __func__);
11590afa8e06SEd Maste 			goto out;
11600afa8e06SEd Maste 		}
11610afa8e06SEd Maste 		authdata_ext->mask |= FIDO_EXT_CRED_PROTECT;
11620afa8e06SEd Maste 		authdata_ext->prot = cbor_get_uint8(val);
11630afa8e06SEd Maste 	} else if (strcmp(type, "credBlob") == 0) {
1164*2ccfa855SEd Maste 		if (cbor_decode_bool(val, NULL) < 0) {
1165*2ccfa855SEd Maste 			fido_log_debug("%s: cbor_decode_bool", __func__);
11660afa8e06SEd Maste 			goto out;
11670afa8e06SEd Maste 		}
11680afa8e06SEd Maste 		if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE)
11690afa8e06SEd Maste 			authdata_ext->mask |= FIDO_EXT_CRED_BLOB;
1170f540a430SEd Maste 	} else if (strcmp(type, "minPinLength") == 0) {
1171f540a430SEd Maste 		if (cbor_isa_uint(val) == false ||
1172f540a430SEd Maste 		    cbor_int_get_width(val) != CBOR_INT_8) {
1173f540a430SEd Maste 			fido_log_debug("%s: cbor type", __func__);
1174f540a430SEd Maste 			goto out;
1175f540a430SEd Maste 		}
1176f540a430SEd Maste 		authdata_ext->mask |= FIDO_EXT_MINPINLEN;
1177f540a430SEd Maste 		authdata_ext->minpinlen = cbor_get_uint8(val);
11780afa8e06SEd Maste 	}
11790afa8e06SEd Maste 
11800afa8e06SEd Maste 	ok = 0;
11810afa8e06SEd Maste out:
11820afa8e06SEd Maste 	free(type);
11830afa8e06SEd Maste 
11840afa8e06SEd Maste 	return (ok);
11850afa8e06SEd Maste }
11860afa8e06SEd Maste 
11870afa8e06SEd Maste static int
decode_cred_extensions(const unsigned char ** buf,size_t * len,fido_cred_ext_t * authdata_ext)11880afa8e06SEd Maste decode_cred_extensions(const unsigned char **buf, size_t *len,
11890afa8e06SEd Maste     fido_cred_ext_t *authdata_ext)
11900afa8e06SEd Maste {
11910afa8e06SEd Maste 	cbor_item_t		*item = NULL;
11920afa8e06SEd Maste 	struct cbor_load_result	 cbor;
11930afa8e06SEd Maste 	int			 ok = -1;
11940afa8e06SEd Maste 
11950afa8e06SEd Maste 	memset(authdata_ext, 0, sizeof(*authdata_ext));
11960afa8e06SEd Maste 
11970afa8e06SEd Maste 	fido_log_xxd(*buf, *len, "%s", __func__);
11980afa8e06SEd Maste 
11990afa8e06SEd Maste 	if ((item = cbor_load(*buf, *len, &cbor)) == NULL) {
12000afa8e06SEd Maste 		fido_log_debug("%s: cbor_load", __func__);
12010afa8e06SEd Maste 		goto fail;
12020afa8e06SEd Maste 	}
12030afa8e06SEd Maste 
12040afa8e06SEd Maste 	if (cbor_isa_map(item) == false ||
12050afa8e06SEd Maste 	    cbor_map_is_definite(item) == false ||
12060afa8e06SEd Maste 	    cbor_map_iter(item, authdata_ext, decode_cred_extension) < 0) {
12070afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
12080afa8e06SEd Maste 		goto fail;
12090afa8e06SEd Maste 	}
12100afa8e06SEd Maste 
12110afa8e06SEd Maste 	*buf += cbor.read;
12120afa8e06SEd Maste 	*len -= cbor.read;
12130afa8e06SEd Maste 
12140afa8e06SEd Maste 	ok = 0;
12150afa8e06SEd Maste fail:
12160afa8e06SEd Maste 	if (item != NULL)
12170afa8e06SEd Maste 		cbor_decref(&item);
12180afa8e06SEd Maste 
12190afa8e06SEd Maste 	return (ok);
12200afa8e06SEd Maste }
12210afa8e06SEd Maste 
12220afa8e06SEd Maste static int
decode_assert_extension(const cbor_item_t * key,const cbor_item_t * val,void * arg)12230afa8e06SEd Maste decode_assert_extension(const cbor_item_t *key, const cbor_item_t *val,
12240afa8e06SEd Maste     void *arg)
12250afa8e06SEd Maste {
12260afa8e06SEd Maste 	fido_assert_extattr_t	*authdata_ext = arg;
12270afa8e06SEd Maste 	char			*type = NULL;
12280afa8e06SEd Maste 	int			 ok = -1;
12290afa8e06SEd Maste 
12300afa8e06SEd Maste 	if (cbor_string_copy(key, &type) < 0) {
12310afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
12320afa8e06SEd Maste 		ok = 0; /* ignore */
12330afa8e06SEd Maste 		goto out;
12340afa8e06SEd Maste 	}
12350afa8e06SEd Maste 
12360afa8e06SEd Maste 	if (strcmp(type, "hmac-secret") == 0) {
12370afa8e06SEd Maste 		if (fido_blob_decode(val, &authdata_ext->hmac_secret_enc) < 0) {
12380afa8e06SEd Maste 			fido_log_debug("%s: fido_blob_decode", __func__);
12390afa8e06SEd Maste 			goto out;
12400afa8e06SEd Maste 		}
12410afa8e06SEd Maste 		authdata_ext->mask |= FIDO_EXT_HMAC_SECRET;
12420afa8e06SEd Maste 	} else if (strcmp(type, "credBlob") == 0) {
12430afa8e06SEd Maste 		if (fido_blob_decode(val, &authdata_ext->blob) < 0) {
12440afa8e06SEd Maste 			fido_log_debug("%s: fido_blob_decode", __func__);
12450afa8e06SEd Maste 			goto out;
12460afa8e06SEd Maste 		}
12470afa8e06SEd Maste 		authdata_ext->mask |= FIDO_EXT_CRED_BLOB;
12480afa8e06SEd Maste 	}
12490afa8e06SEd Maste 
12500afa8e06SEd Maste 	ok = 0;
12510afa8e06SEd Maste out:
12520afa8e06SEd Maste 	free(type);
12530afa8e06SEd Maste 
12540afa8e06SEd Maste 	return (ok);
12550afa8e06SEd Maste }
12560afa8e06SEd Maste 
12570afa8e06SEd Maste static int
decode_assert_extensions(const unsigned char ** buf,size_t * len,fido_assert_extattr_t * authdata_ext)12580afa8e06SEd Maste decode_assert_extensions(const unsigned char **buf, size_t *len,
12590afa8e06SEd Maste     fido_assert_extattr_t *authdata_ext)
12600afa8e06SEd Maste {
12610afa8e06SEd Maste 	cbor_item_t		*item = NULL;
12620afa8e06SEd Maste 	struct cbor_load_result	 cbor;
12630afa8e06SEd Maste 	int			 ok = -1;
12640afa8e06SEd Maste 
12650afa8e06SEd Maste 	fido_log_xxd(*buf, *len, "%s", __func__);
12660afa8e06SEd Maste 
12670afa8e06SEd Maste 	if ((item = cbor_load(*buf, *len, &cbor)) == NULL) {
12680afa8e06SEd Maste 		fido_log_debug("%s: cbor_load", __func__);
12690afa8e06SEd Maste 		goto fail;
12700afa8e06SEd Maste 	}
12710afa8e06SEd Maste 
12720afa8e06SEd Maste 	if (cbor_isa_map(item) == false ||
12730afa8e06SEd Maste 	    cbor_map_is_definite(item) == false ||
12740afa8e06SEd Maste 	    cbor_map_iter(item, authdata_ext, decode_assert_extension) < 0) {
12750afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
12760afa8e06SEd Maste 		goto fail;
12770afa8e06SEd Maste 	}
12780afa8e06SEd Maste 
12790afa8e06SEd Maste 	*buf += cbor.read;
12800afa8e06SEd Maste 	*len -= cbor.read;
12810afa8e06SEd Maste 
12820afa8e06SEd Maste 	ok = 0;
12830afa8e06SEd Maste fail:
12840afa8e06SEd Maste 	if (item != NULL)
12850afa8e06SEd Maste 		cbor_decref(&item);
12860afa8e06SEd Maste 
12870afa8e06SEd Maste 	return (ok);
12880afa8e06SEd Maste }
12890afa8e06SEd Maste 
12900afa8e06SEd Maste int
cbor_decode_cred_authdata(const cbor_item_t * item,int cose_alg,fido_blob_t * authdata_cbor,fido_authdata_t * authdata,fido_attcred_t * attcred,fido_cred_ext_t * authdata_ext)12910afa8e06SEd Maste cbor_decode_cred_authdata(const cbor_item_t *item, int cose_alg,
12920afa8e06SEd Maste     fido_blob_t *authdata_cbor, fido_authdata_t *authdata,
12930afa8e06SEd Maste     fido_attcred_t *attcred, fido_cred_ext_t *authdata_ext)
12940afa8e06SEd Maste {
12950afa8e06SEd Maste 	const unsigned char	*buf = NULL;
12960afa8e06SEd Maste 	size_t			 len;
12970afa8e06SEd Maste 	size_t			 alloc_len;
12980afa8e06SEd Maste 
12990afa8e06SEd Maste 	if (cbor_isa_bytestring(item) == false ||
13000afa8e06SEd Maste 	    cbor_bytestring_is_definite(item) == false) {
13010afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
13020afa8e06SEd Maste 		return (-1);
13030afa8e06SEd Maste 	}
13040afa8e06SEd Maste 
13050afa8e06SEd Maste 	if (authdata_cbor->ptr != NULL ||
13060afa8e06SEd Maste 	    (authdata_cbor->len = cbor_serialize_alloc(item,
13070afa8e06SEd Maste 	    &authdata_cbor->ptr, &alloc_len)) == 0) {
13080afa8e06SEd Maste 		fido_log_debug("%s: cbor_serialize_alloc", __func__);
13090afa8e06SEd Maste 		return (-1);
13100afa8e06SEd Maste 	}
13110afa8e06SEd Maste 
13120afa8e06SEd Maste 	buf = cbor_bytestring_handle(item);
13130afa8e06SEd Maste 	len = cbor_bytestring_length(item);
13140afa8e06SEd Maste 	fido_log_xxd(buf, len, "%s", __func__);
13150afa8e06SEd Maste 
13160afa8e06SEd Maste 	if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) {
13170afa8e06SEd Maste 		fido_log_debug("%s: fido_buf_read", __func__);
13180afa8e06SEd Maste 		return (-1);
13190afa8e06SEd Maste 	}
13200afa8e06SEd Maste 
13210afa8e06SEd Maste 	authdata->sigcount = be32toh(authdata->sigcount);
13220afa8e06SEd Maste 
13230afa8e06SEd Maste 	if (attcred != NULL) {
13240afa8e06SEd Maste 		if ((authdata->flags & CTAP_AUTHDATA_ATT_CRED) == 0 ||
13250afa8e06SEd Maste 		    decode_attcred(&buf, &len, cose_alg, attcred) < 0)
13260afa8e06SEd Maste 			return (-1);
13270afa8e06SEd Maste 	}
13280afa8e06SEd Maste 
13290afa8e06SEd Maste 	if (authdata_ext != NULL) {
13300afa8e06SEd Maste 		if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0 &&
13310afa8e06SEd Maste 		    decode_cred_extensions(&buf, &len, authdata_ext) < 0)
13320afa8e06SEd Maste 			return (-1);
13330afa8e06SEd Maste 	}
13340afa8e06SEd Maste 
13350afa8e06SEd Maste 	/* XXX we should probably ensure that len == 0 at this point */
13360afa8e06SEd Maste 
13370afa8e06SEd Maste 	return (FIDO_OK);
13380afa8e06SEd Maste }
13390afa8e06SEd Maste 
13400afa8e06SEd Maste int
cbor_decode_assert_authdata(const cbor_item_t * item,fido_blob_t * authdata_cbor,fido_authdata_t * authdata,fido_assert_extattr_t * authdata_ext)13410afa8e06SEd Maste cbor_decode_assert_authdata(const cbor_item_t *item, fido_blob_t *authdata_cbor,
13420afa8e06SEd Maste     fido_authdata_t *authdata, fido_assert_extattr_t *authdata_ext)
13430afa8e06SEd Maste {
13440afa8e06SEd Maste 	const unsigned char	*buf = NULL;
13450afa8e06SEd Maste 	size_t			 len;
13460afa8e06SEd Maste 	size_t			 alloc_len;
13470afa8e06SEd Maste 
13480afa8e06SEd Maste 	if (cbor_isa_bytestring(item) == false ||
13490afa8e06SEd Maste 	    cbor_bytestring_is_definite(item) == false) {
13500afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
13510afa8e06SEd Maste 		return (-1);
13520afa8e06SEd Maste 	}
13530afa8e06SEd Maste 
13540afa8e06SEd Maste 	if (authdata_cbor->ptr != NULL ||
13550afa8e06SEd Maste 	    (authdata_cbor->len = cbor_serialize_alloc(item,
13560afa8e06SEd Maste 	    &authdata_cbor->ptr, &alloc_len)) == 0) {
13570afa8e06SEd Maste 		fido_log_debug("%s: cbor_serialize_alloc", __func__);
13580afa8e06SEd Maste 		return (-1);
13590afa8e06SEd Maste 	}
13600afa8e06SEd Maste 
13610afa8e06SEd Maste 	buf = cbor_bytestring_handle(item);
13620afa8e06SEd Maste 	len = cbor_bytestring_length(item);
13630afa8e06SEd Maste 
13640afa8e06SEd Maste 	fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)buf, len);
13650afa8e06SEd Maste 
13660afa8e06SEd Maste 	if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) {
13670afa8e06SEd Maste 		fido_log_debug("%s: fido_buf_read", __func__);
13680afa8e06SEd Maste 		return (-1);
13690afa8e06SEd Maste 	}
13700afa8e06SEd Maste 
13710afa8e06SEd Maste 	authdata->sigcount = be32toh(authdata->sigcount);
13720afa8e06SEd Maste 
13730afa8e06SEd Maste 	if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0) {
13740afa8e06SEd Maste 		if (decode_assert_extensions(&buf, &len, authdata_ext) < 0) {
13750afa8e06SEd Maste 			fido_log_debug("%s: decode_assert_extensions",
13760afa8e06SEd Maste 			    __func__);
13770afa8e06SEd Maste 			return (-1);
13780afa8e06SEd Maste 		}
13790afa8e06SEd Maste 	}
13800afa8e06SEd Maste 
13810afa8e06SEd Maste 	/* XXX we should probably ensure that len == 0 at this point */
13820afa8e06SEd Maste 
13830afa8e06SEd Maste 	return (FIDO_OK);
13840afa8e06SEd Maste }
13850afa8e06SEd Maste 
13860afa8e06SEd Maste static int
decode_x5c(const cbor_item_t * item,void * arg)13870afa8e06SEd Maste decode_x5c(const cbor_item_t *item, void *arg)
13880afa8e06SEd Maste {
13890afa8e06SEd Maste 	fido_blob_t *x5c = arg;
13900afa8e06SEd Maste 
13910afa8e06SEd Maste 	if (x5c->len)
13920afa8e06SEd Maste 		return (0); /* ignore */
13930afa8e06SEd Maste 
13940afa8e06SEd Maste 	return (fido_blob_decode(item, x5c));
13950afa8e06SEd Maste }
13960afa8e06SEd Maste 
13970afa8e06SEd Maste static int
decode_attstmt_entry(const cbor_item_t * key,const cbor_item_t * val,void * arg)13980afa8e06SEd Maste decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
13990afa8e06SEd Maste {
14000afa8e06SEd Maste 	fido_attstmt_t	*attstmt = arg;
14010afa8e06SEd Maste 	char		*name = NULL;
14020afa8e06SEd Maste 	int		 ok = -1;
14030afa8e06SEd Maste 
14040afa8e06SEd Maste 	if (cbor_string_copy(key, &name) < 0) {
14050afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
14060afa8e06SEd Maste 		ok = 0; /* ignore */
14070afa8e06SEd Maste 		goto out;
14080afa8e06SEd Maste 	}
14090afa8e06SEd Maste 
14100afa8e06SEd Maste 	if (!strcmp(name, "alg")) {
14110afa8e06SEd Maste 		if (cbor_isa_negint(val) == false ||
14120afa8e06SEd Maste 		    cbor_get_int(val) > UINT16_MAX) {
14130afa8e06SEd Maste 			fido_log_debug("%s: alg", __func__);
14140afa8e06SEd Maste 			goto out;
14150afa8e06SEd Maste 		}
1416f540a430SEd Maste 		attstmt->alg = -(int)cbor_get_int(val) - 1;
1417*2ccfa855SEd Maste 		if (attstmt->alg != COSE_ES256 && attstmt->alg != COSE_ES384 &&
1418*2ccfa855SEd Maste 		    attstmt->alg != COSE_RS256 && attstmt->alg != COSE_EDDSA &&
1419*2ccfa855SEd Maste 		    attstmt->alg != COSE_RS1) {
1420f540a430SEd Maste 			fido_log_debug("%s: unsupported attstmt->alg=%d",
1421f540a430SEd Maste 			    __func__, attstmt->alg);
14220afa8e06SEd Maste 			goto out;
14230afa8e06SEd Maste 		}
14240afa8e06SEd Maste 	} else if (!strcmp(name, "sig")) {
14250afa8e06SEd Maste 		if (fido_blob_decode(val, &attstmt->sig) < 0) {
14260afa8e06SEd Maste 			fido_log_debug("%s: sig", __func__);
14270afa8e06SEd Maste 			goto out;
14280afa8e06SEd Maste 		}
14290afa8e06SEd Maste 	} else if (!strcmp(name, "x5c")) {
14300afa8e06SEd Maste 		if (cbor_isa_array(val) == false ||
14310afa8e06SEd Maste 		    cbor_array_is_definite(val) == false ||
14320afa8e06SEd Maste 		    cbor_array_iter(val, &attstmt->x5c, decode_x5c) < 0) {
14330afa8e06SEd Maste 			fido_log_debug("%s: x5c", __func__);
14340afa8e06SEd Maste 			goto out;
14350afa8e06SEd Maste 		}
1436f540a430SEd Maste 	} else if (!strcmp(name, "certInfo")) {
1437f540a430SEd Maste 		if (fido_blob_decode(val, &attstmt->certinfo) < 0) {
1438f540a430SEd Maste 			fido_log_debug("%s: certinfo", __func__);
1439f540a430SEd Maste 			goto out;
1440f540a430SEd Maste 		}
1441f540a430SEd Maste 	} else if (!strcmp(name, "pubArea")) {
1442f540a430SEd Maste 		if (fido_blob_decode(val, &attstmt->pubarea) < 0) {
1443f540a430SEd Maste 			fido_log_debug("%s: pubarea", __func__);
1444f540a430SEd Maste 			goto out;
1445f540a430SEd Maste 		}
14460afa8e06SEd Maste 	}
14470afa8e06SEd Maste 
14480afa8e06SEd Maste 	ok = 0;
14490afa8e06SEd Maste out:
14500afa8e06SEd Maste 	free(name);
14510afa8e06SEd Maste 
14520afa8e06SEd Maste 	return (ok);
14530afa8e06SEd Maste }
14540afa8e06SEd Maste 
14550afa8e06SEd Maste int
cbor_decode_attstmt(const cbor_item_t * item,fido_attstmt_t * attstmt)14560afa8e06SEd Maste cbor_decode_attstmt(const cbor_item_t *item, fido_attstmt_t *attstmt)
14570afa8e06SEd Maste {
1458f540a430SEd Maste 	size_t alloc_len;
1459f540a430SEd Maste 
14600afa8e06SEd Maste 	if (cbor_isa_map(item) == false ||
14610afa8e06SEd Maste 	    cbor_map_is_definite(item) == false ||
14620afa8e06SEd Maste 	    cbor_map_iter(item, attstmt, decode_attstmt_entry) < 0) {
14630afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
14640afa8e06SEd Maste 		return (-1);
14650afa8e06SEd Maste 	}
14660afa8e06SEd Maste 
1467f540a430SEd Maste 	if (attstmt->cbor.ptr != NULL ||
1468f540a430SEd Maste 	    (attstmt->cbor.len = cbor_serialize_alloc(item,
1469f540a430SEd Maste 	    &attstmt->cbor.ptr, &alloc_len)) == 0) {
1470f540a430SEd Maste 		fido_log_debug("%s: cbor_serialize_alloc", __func__);
1471f540a430SEd Maste 		return (-1);
1472f540a430SEd Maste 	}
1473f540a430SEd Maste 
14740afa8e06SEd Maste 	return (0);
14750afa8e06SEd Maste }
14760afa8e06SEd Maste 
14770afa8e06SEd Maste int
cbor_decode_uint64(const cbor_item_t * item,uint64_t * n)14780afa8e06SEd Maste cbor_decode_uint64(const cbor_item_t *item, uint64_t *n)
14790afa8e06SEd Maste {
14800afa8e06SEd Maste 	if (cbor_isa_uint(item) == false) {
14810afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
14820afa8e06SEd Maste 		return (-1);
14830afa8e06SEd Maste 	}
14840afa8e06SEd Maste 
14850afa8e06SEd Maste 	*n = cbor_get_int(item);
14860afa8e06SEd Maste 
14870afa8e06SEd Maste 	return (0);
14880afa8e06SEd Maste }
14890afa8e06SEd Maste 
14900afa8e06SEd Maste static int
decode_cred_id_entry(const cbor_item_t * key,const cbor_item_t * val,void * arg)14910afa8e06SEd Maste decode_cred_id_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
14920afa8e06SEd Maste {
14930afa8e06SEd Maste 	fido_blob_t	*id = arg;
14940afa8e06SEd Maste 	char		*name = NULL;
14950afa8e06SEd Maste 	int		 ok = -1;
14960afa8e06SEd Maste 
14970afa8e06SEd Maste 	if (cbor_string_copy(key, &name) < 0) {
14980afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
14990afa8e06SEd Maste 		ok = 0; /* ignore */
15000afa8e06SEd Maste 		goto out;
15010afa8e06SEd Maste 	}
15020afa8e06SEd Maste 
15030afa8e06SEd Maste 	if (!strcmp(name, "id"))
15040afa8e06SEd Maste 		if (fido_blob_decode(val, id) < 0) {
15050afa8e06SEd Maste 			fido_log_debug("%s: cbor_bytestring_copy", __func__);
15060afa8e06SEd Maste 			goto out;
15070afa8e06SEd Maste 		}
15080afa8e06SEd Maste 
15090afa8e06SEd Maste 	ok = 0;
15100afa8e06SEd Maste out:
15110afa8e06SEd Maste 	free(name);
15120afa8e06SEd Maste 
15130afa8e06SEd Maste 	return (ok);
15140afa8e06SEd Maste }
15150afa8e06SEd Maste 
15160afa8e06SEd Maste int
cbor_decode_cred_id(const cbor_item_t * item,fido_blob_t * id)15170afa8e06SEd Maste cbor_decode_cred_id(const cbor_item_t *item, fido_blob_t *id)
15180afa8e06SEd Maste {
15190afa8e06SEd Maste 	if (cbor_isa_map(item) == false ||
15200afa8e06SEd Maste 	    cbor_map_is_definite(item) == false ||
15210afa8e06SEd Maste 	    cbor_map_iter(item, id, decode_cred_id_entry) < 0) {
15220afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
15230afa8e06SEd Maste 		return (-1);
15240afa8e06SEd Maste 	}
15250afa8e06SEd Maste 
15260afa8e06SEd Maste 	return (0);
15270afa8e06SEd Maste }
15280afa8e06SEd Maste 
15290afa8e06SEd Maste static int
decode_user_entry(const cbor_item_t * key,const cbor_item_t * val,void * arg)15300afa8e06SEd Maste decode_user_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
15310afa8e06SEd Maste {
15320afa8e06SEd Maste 	fido_user_t	*user = arg;
15330afa8e06SEd Maste 	char		*name = NULL;
15340afa8e06SEd Maste 	int		 ok = -1;
15350afa8e06SEd Maste 
15360afa8e06SEd Maste 	if (cbor_string_copy(key, &name) < 0) {
15370afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
15380afa8e06SEd Maste 		ok = 0; /* ignore */
15390afa8e06SEd Maste 		goto out;
15400afa8e06SEd Maste 	}
15410afa8e06SEd Maste 
15420afa8e06SEd Maste 	if (!strcmp(name, "icon")) {
15430afa8e06SEd Maste 		if (cbor_string_copy(val, &user->icon) < 0) {
15440afa8e06SEd Maste 			fido_log_debug("%s: icon", __func__);
15450afa8e06SEd Maste 			goto out;
15460afa8e06SEd Maste 		}
15470afa8e06SEd Maste 	} else if (!strcmp(name, "name")) {
15480afa8e06SEd Maste 		if (cbor_string_copy(val, &user->name) < 0) {
15490afa8e06SEd Maste 			fido_log_debug("%s: name", __func__);
15500afa8e06SEd Maste 			goto out;
15510afa8e06SEd Maste 		}
15520afa8e06SEd Maste 	} else if (!strcmp(name, "displayName")) {
15530afa8e06SEd Maste 		if (cbor_string_copy(val, &user->display_name) < 0) {
15540afa8e06SEd Maste 			fido_log_debug("%s: display_name", __func__);
15550afa8e06SEd Maste 			goto out;
15560afa8e06SEd Maste 		}
15570afa8e06SEd Maste 	} else if (!strcmp(name, "id")) {
15580afa8e06SEd Maste 		if (fido_blob_decode(val, &user->id) < 0) {
15590afa8e06SEd Maste 			fido_log_debug("%s: id", __func__);
15600afa8e06SEd Maste 			goto out;
15610afa8e06SEd Maste 		}
15620afa8e06SEd Maste 	}
15630afa8e06SEd Maste 
15640afa8e06SEd Maste 	ok = 0;
15650afa8e06SEd Maste out:
15660afa8e06SEd Maste 	free(name);
15670afa8e06SEd Maste 
15680afa8e06SEd Maste 	return (ok);
15690afa8e06SEd Maste }
15700afa8e06SEd Maste 
15710afa8e06SEd Maste int
cbor_decode_user(const cbor_item_t * item,fido_user_t * user)15720afa8e06SEd Maste cbor_decode_user(const cbor_item_t *item, fido_user_t *user)
15730afa8e06SEd Maste {
15740afa8e06SEd Maste 	if (cbor_isa_map(item) == false ||
15750afa8e06SEd Maste 	    cbor_map_is_definite(item) == false ||
15760afa8e06SEd Maste 	    cbor_map_iter(item, user, decode_user_entry) < 0) {
15770afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
15780afa8e06SEd Maste 		return (-1);
15790afa8e06SEd Maste 	}
15800afa8e06SEd Maste 
15810afa8e06SEd Maste 	return (0);
15820afa8e06SEd Maste }
15830afa8e06SEd Maste 
15840afa8e06SEd Maste static int
decode_rp_entity_entry(const cbor_item_t * key,const cbor_item_t * val,void * arg)15850afa8e06SEd Maste decode_rp_entity_entry(const cbor_item_t *key, const cbor_item_t *val,
15860afa8e06SEd Maste     void *arg)
15870afa8e06SEd Maste {
15880afa8e06SEd Maste 	fido_rp_t	*rp = arg;
15890afa8e06SEd Maste 	char		*name = NULL;
15900afa8e06SEd Maste 	int		 ok = -1;
15910afa8e06SEd Maste 
15920afa8e06SEd Maste 	if (cbor_string_copy(key, &name) < 0) {
15930afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
15940afa8e06SEd Maste 		ok = 0; /* ignore */
15950afa8e06SEd Maste 		goto out;
15960afa8e06SEd Maste 	}
15970afa8e06SEd Maste 
15980afa8e06SEd Maste 	if (!strcmp(name, "id")) {
15990afa8e06SEd Maste 		if (cbor_string_copy(val, &rp->id) < 0) {
16000afa8e06SEd Maste 			fido_log_debug("%s: id", __func__);
16010afa8e06SEd Maste 			goto out;
16020afa8e06SEd Maste 		}
16030afa8e06SEd Maste 	} else if (!strcmp(name, "name")) {
16040afa8e06SEd Maste 		if (cbor_string_copy(val, &rp->name) < 0) {
16050afa8e06SEd Maste 			fido_log_debug("%s: name", __func__);
16060afa8e06SEd Maste 			goto out;
16070afa8e06SEd Maste 		}
16080afa8e06SEd Maste 	}
16090afa8e06SEd Maste 
16100afa8e06SEd Maste 	ok = 0;
16110afa8e06SEd Maste out:
16120afa8e06SEd Maste 	free(name);
16130afa8e06SEd Maste 
16140afa8e06SEd Maste 	return (ok);
16150afa8e06SEd Maste }
16160afa8e06SEd Maste 
16170afa8e06SEd Maste int
cbor_decode_rp_entity(const cbor_item_t * item,fido_rp_t * rp)16180afa8e06SEd Maste cbor_decode_rp_entity(const cbor_item_t *item, fido_rp_t *rp)
16190afa8e06SEd Maste {
16200afa8e06SEd Maste 	if (cbor_isa_map(item) == false ||
16210afa8e06SEd Maste 	    cbor_map_is_definite(item) == false ||
16220afa8e06SEd Maste 	    cbor_map_iter(item, rp, decode_rp_entity_entry) < 0) {
16230afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
16240afa8e06SEd Maste 		return (-1);
16250afa8e06SEd Maste 	}
16260afa8e06SEd Maste 
16270afa8e06SEd Maste 	return (0);
16280afa8e06SEd Maste }
16290afa8e06SEd Maste 
1630*2ccfa855SEd Maste int
cbor_decode_bool(const cbor_item_t * item,bool * v)1631*2ccfa855SEd Maste cbor_decode_bool(const cbor_item_t *item, bool *v)
1632*2ccfa855SEd Maste {
1633*2ccfa855SEd Maste 	if (cbor_isa_float_ctrl(item) == false ||
1634*2ccfa855SEd Maste 	    cbor_float_get_width(item) != CBOR_FLOAT_0 ||
1635*2ccfa855SEd Maste 	    cbor_is_bool(item) == false) {
1636*2ccfa855SEd Maste 		fido_log_debug("%s: cbor type", __func__);
1637*2ccfa855SEd Maste 		return (-1);
1638*2ccfa855SEd Maste 	}
1639*2ccfa855SEd Maste 
1640*2ccfa855SEd Maste 	if (v != NULL)
1641*2ccfa855SEd Maste 		*v = cbor_ctrl_value(item) == CBOR_CTRL_TRUE;
1642*2ccfa855SEd Maste 
1643*2ccfa855SEd Maste 	return (0);
1644*2ccfa855SEd Maste }
1645*2ccfa855SEd Maste 
16460afa8e06SEd Maste cbor_item_t *
cbor_build_uint(const uint64_t value)16470afa8e06SEd Maste cbor_build_uint(const uint64_t value)
16480afa8e06SEd Maste {
16490afa8e06SEd Maste 	if (value <= UINT8_MAX)
16500afa8e06SEd Maste 		return cbor_build_uint8((uint8_t)value);
16510afa8e06SEd Maste 	else if (value <= UINT16_MAX)
16520afa8e06SEd Maste 		return cbor_build_uint16((uint16_t)value);
16530afa8e06SEd Maste 	else if (value <= UINT32_MAX)
16540afa8e06SEd Maste 		return cbor_build_uint32((uint32_t)value);
16550afa8e06SEd Maste 
16560afa8e06SEd Maste 	return cbor_build_uint64(value);
16570afa8e06SEd Maste }
16580afa8e06SEd Maste 
16590afa8e06SEd Maste int
cbor_array_append(cbor_item_t ** array,cbor_item_t * item)16600afa8e06SEd Maste cbor_array_append(cbor_item_t **array, cbor_item_t *item)
16610afa8e06SEd Maste {
16620afa8e06SEd Maste 	cbor_item_t **v, *ret;
16630afa8e06SEd Maste 	size_t n;
16640afa8e06SEd Maste 
16650afa8e06SEd Maste 	if ((v = cbor_array_handle(*array)) == NULL ||
16660afa8e06SEd Maste 	    (n = cbor_array_size(*array)) == SIZE_MAX ||
16670afa8e06SEd Maste 	    (ret = cbor_new_definite_array(n + 1)) == NULL)
16680afa8e06SEd Maste 		return -1;
16690afa8e06SEd Maste 	for (size_t i = 0; i < n; i++) {
16700afa8e06SEd Maste 		if (cbor_array_push(ret, v[i]) == 0) {
16710afa8e06SEd Maste 			cbor_decref(&ret);
16720afa8e06SEd Maste 			return -1;
16730afa8e06SEd Maste 		}
16740afa8e06SEd Maste 	}
16750afa8e06SEd Maste 	if (cbor_array_push(ret, item) == 0) {
16760afa8e06SEd Maste 		cbor_decref(&ret);
16770afa8e06SEd Maste 		return -1;
16780afa8e06SEd Maste 	}
16790afa8e06SEd Maste 	cbor_decref(array);
16800afa8e06SEd Maste 	*array = ret;
16810afa8e06SEd Maste 
16820afa8e06SEd Maste 	return 0;
16830afa8e06SEd Maste }
16840afa8e06SEd Maste 
16850afa8e06SEd Maste int
cbor_array_drop(cbor_item_t ** array,size_t idx)16860afa8e06SEd Maste cbor_array_drop(cbor_item_t **array, size_t idx)
16870afa8e06SEd Maste {
16880afa8e06SEd Maste 	cbor_item_t **v, *ret;
16890afa8e06SEd Maste 	size_t n;
16900afa8e06SEd Maste 
16910afa8e06SEd Maste 	if ((v = cbor_array_handle(*array)) == NULL ||
16920afa8e06SEd Maste 	    (n = cbor_array_size(*array)) == 0 || idx >= n ||
16930afa8e06SEd Maste 	    (ret = cbor_new_definite_array(n - 1)) == NULL)
16940afa8e06SEd Maste 		return -1;
16950afa8e06SEd Maste 	for (size_t i = 0; i < n; i++) {
16960afa8e06SEd Maste 		if (i != idx && cbor_array_push(ret, v[i]) == 0) {
16970afa8e06SEd Maste 			cbor_decref(&ret);
16980afa8e06SEd Maste 			return -1;
16990afa8e06SEd Maste 		}
17000afa8e06SEd Maste 	}
17010afa8e06SEd Maste 	cbor_decref(array);
17020afa8e06SEd Maste 	*array = ret;
17030afa8e06SEd Maste 
17040afa8e06SEd Maste 	return 0;
17050afa8e06SEd Maste }
1706