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