xref: /freebsd/contrib/libfido2/src/credman.c (revision 2ccfa855b2fc331819953e3de1b1c15ce5b95a7e)
10afa8e06SEd Maste /*
2*2ccfa855SEd Maste  * Copyright (c) 2019-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/sha.h>
90afa8e06SEd Maste 
100afa8e06SEd Maste #include "fido.h"
110afa8e06SEd Maste #include "fido/credman.h"
120afa8e06SEd Maste #include "fido/es256.h"
130afa8e06SEd Maste 
140afa8e06SEd Maste #define CMD_CRED_METADATA	0x01
150afa8e06SEd Maste #define CMD_RP_BEGIN		0x02
160afa8e06SEd Maste #define CMD_RP_NEXT		0x03
170afa8e06SEd Maste #define CMD_RK_BEGIN		0x04
180afa8e06SEd Maste #define CMD_RK_NEXT		0x05
190afa8e06SEd Maste #define CMD_DELETE_CRED		0x06
200afa8e06SEd Maste #define CMD_UPDATE_CRED		0x07
210afa8e06SEd Maste 
220afa8e06SEd Maste static int
credman_grow_array(void ** ptr,size_t * n_alloc,const size_t * n_rx,size_t n,size_t size)23*2ccfa855SEd Maste credman_grow_array(void **ptr, size_t *n_alloc, const size_t *n_rx, size_t n,
240afa8e06SEd Maste     size_t size)
250afa8e06SEd Maste {
260afa8e06SEd Maste 	void *new_ptr;
270afa8e06SEd Maste 
280afa8e06SEd Maste #ifdef FIDO_FUZZ
290afa8e06SEd Maste 	if (n > UINT8_MAX) {
300afa8e06SEd Maste 		fido_log_debug("%s: n > UINT8_MAX", __func__);
310afa8e06SEd Maste 		return (-1);
320afa8e06SEd Maste 	}
330afa8e06SEd Maste #endif
340afa8e06SEd Maste 
350afa8e06SEd Maste 	if (n < *n_alloc)
360afa8e06SEd Maste 		return (0);
370afa8e06SEd Maste 
380afa8e06SEd Maste 	/* sanity check */
390afa8e06SEd Maste 	if (*n_rx > 0 || *n_rx > *n_alloc || n < *n_alloc) {
400afa8e06SEd Maste 		fido_log_debug("%s: n=%zu, n_rx=%zu, n_alloc=%zu", __func__, n,
410afa8e06SEd Maste 		    *n_rx, *n_alloc);
420afa8e06SEd Maste 		return (-1);
430afa8e06SEd Maste 	}
440afa8e06SEd Maste 
450afa8e06SEd Maste 	if ((new_ptr = recallocarray(*ptr, *n_alloc, n, size)) == NULL)
460afa8e06SEd Maste 		return (-1);
470afa8e06SEd Maste 
480afa8e06SEd Maste 	*ptr = new_ptr;
490afa8e06SEd Maste 	*n_alloc = n;
500afa8e06SEd Maste 
510afa8e06SEd Maste 	return (0);
520afa8e06SEd Maste }
530afa8e06SEd Maste 
540afa8e06SEd Maste static int
credman_prepare_hmac(uint8_t cmd,const void * body,cbor_item_t ** param,fido_blob_t * hmac_data)550afa8e06SEd Maste credman_prepare_hmac(uint8_t cmd, const void *body, cbor_item_t **param,
560afa8e06SEd Maste     fido_blob_t *hmac_data)
570afa8e06SEd Maste {
580afa8e06SEd Maste 	cbor_item_t *param_cbor[3];
590afa8e06SEd Maste 	const fido_cred_t *cred;
600afa8e06SEd Maste 	size_t n;
610afa8e06SEd Maste 	int ok = -1;
620afa8e06SEd Maste 
630afa8e06SEd Maste 	memset(&param_cbor, 0, sizeof(param_cbor));
640afa8e06SEd Maste 
650afa8e06SEd Maste 	if (body == NULL)
660afa8e06SEd Maste 		return (fido_blob_set(hmac_data, &cmd, sizeof(cmd)));
670afa8e06SEd Maste 
680afa8e06SEd Maste 	switch (cmd) {
690afa8e06SEd Maste 	case CMD_RK_BEGIN:
700afa8e06SEd Maste 		n = 1;
710afa8e06SEd Maste 		if ((param_cbor[0] = fido_blob_encode(body)) == NULL) {
720afa8e06SEd Maste 			fido_log_debug("%s: cbor encode", __func__);
730afa8e06SEd Maste 			goto fail;
740afa8e06SEd Maste 		}
750afa8e06SEd Maste 		break;
760afa8e06SEd Maste 	case CMD_DELETE_CRED:
770afa8e06SEd Maste 		n = 2;
780afa8e06SEd Maste 		if ((param_cbor[1] = cbor_encode_pubkey(body)) == NULL) {
790afa8e06SEd Maste 			fido_log_debug("%s: cbor encode", __func__);
800afa8e06SEd Maste 			goto fail;
810afa8e06SEd Maste 		}
820afa8e06SEd Maste 		break;
830afa8e06SEd Maste 	case CMD_UPDATE_CRED:
840afa8e06SEd Maste 		n = 3;
850afa8e06SEd Maste 		cred = body;
860afa8e06SEd Maste 		param_cbor[1] = cbor_encode_pubkey(&cred->attcred.id);
870afa8e06SEd Maste 		param_cbor[2] = cbor_encode_user_entity(&cred->user);
880afa8e06SEd Maste 		if (param_cbor[1] == NULL || param_cbor[2] == NULL) {
890afa8e06SEd Maste 			fido_log_debug("%s: cbor encode", __func__);
900afa8e06SEd Maste 			goto fail;
910afa8e06SEd Maste 		}
920afa8e06SEd Maste 		break;
930afa8e06SEd Maste 	default:
940afa8e06SEd Maste 		fido_log_debug("%s: unknown cmd=0x%02x", __func__, cmd);
950afa8e06SEd Maste 		return (-1);
960afa8e06SEd Maste 	}
970afa8e06SEd Maste 
980afa8e06SEd Maste 	if ((*param = cbor_flatten_vector(param_cbor, n)) == NULL) {
990afa8e06SEd Maste 		fido_log_debug("%s: cbor_flatten_vector", __func__);
1000afa8e06SEd Maste 		goto fail;
1010afa8e06SEd Maste 	}
1020afa8e06SEd Maste 	if (cbor_build_frame(cmd, param_cbor, n, hmac_data) < 0) {
1030afa8e06SEd Maste 		fido_log_debug("%s: cbor_build_frame", __func__);
1040afa8e06SEd Maste 		goto fail;
1050afa8e06SEd Maste 	}
1060afa8e06SEd Maste 
1070afa8e06SEd Maste 	ok = 0;
1080afa8e06SEd Maste fail:
1090afa8e06SEd Maste 	cbor_vector_free(param_cbor, nitems(param_cbor));
1100afa8e06SEd Maste 
1110afa8e06SEd Maste 	return (ok);
1120afa8e06SEd Maste }
1130afa8e06SEd Maste 
1140afa8e06SEd Maste static int
credman_tx(fido_dev_t * dev,uint8_t subcmd,const void * param,const char * pin,const char * rp_id,fido_opt_t uv,int * ms)1150afa8e06SEd Maste credman_tx(fido_dev_t *dev, uint8_t subcmd, const void *param, const char *pin,
116f540a430SEd Maste     const char *rp_id, fido_opt_t uv, int *ms)
1170afa8e06SEd Maste {
1180afa8e06SEd Maste 	fido_blob_t	 f;
1190afa8e06SEd Maste 	fido_blob_t	*ecdh = NULL;
1200afa8e06SEd Maste 	fido_blob_t	 hmac;
1210afa8e06SEd Maste 	es256_pk_t	*pk = NULL;
1220afa8e06SEd Maste 	cbor_item_t	*argv[4];
1230afa8e06SEd Maste 	const uint8_t	 cmd = CTAP_CBOR_CRED_MGMT_PRE;
1240afa8e06SEd Maste 	int		 r = FIDO_ERR_INTERNAL;
1250afa8e06SEd Maste 
1260afa8e06SEd Maste 	memset(&f, 0, sizeof(f));
1270afa8e06SEd Maste 	memset(&hmac, 0, sizeof(hmac));
1280afa8e06SEd Maste 	memset(&argv, 0, sizeof(argv));
1290afa8e06SEd Maste 
1300afa8e06SEd Maste 	if (fido_dev_is_fido2(dev) == false) {
1310afa8e06SEd Maste 		fido_log_debug("%s: fido_dev_is_fido2", __func__);
1320afa8e06SEd Maste 		r = FIDO_ERR_INVALID_COMMAND;
1330afa8e06SEd Maste 		goto fail;
1340afa8e06SEd Maste 	}
1350afa8e06SEd Maste 
1360afa8e06SEd Maste 	/* subCommand */
1370afa8e06SEd Maste 	if ((argv[0] = cbor_build_uint8(subcmd)) == NULL) {
1380afa8e06SEd Maste 		fido_log_debug("%s: cbor encode", __func__);
1390afa8e06SEd Maste 		goto fail;
1400afa8e06SEd Maste 	}
1410afa8e06SEd Maste 
1420afa8e06SEd Maste 	/* pinProtocol, pinAuth */
1430afa8e06SEd Maste 	if (pin != NULL || uv == FIDO_OPT_TRUE) {
1440afa8e06SEd Maste 		if (credman_prepare_hmac(subcmd, param, &argv[1], &hmac) < 0) {
1450afa8e06SEd Maste 			fido_log_debug("%s: credman_prepare_hmac", __func__);
1460afa8e06SEd Maste 			goto fail;
1470afa8e06SEd Maste 		}
148f540a430SEd Maste 		if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
1490afa8e06SEd Maste 			fido_log_debug("%s: fido_do_ecdh", __func__);
1500afa8e06SEd Maste 			goto fail;
1510afa8e06SEd Maste 		}
1520afa8e06SEd Maste 		if ((r = cbor_add_uv_params(dev, cmd, &hmac, pk, ecdh, pin,
153f540a430SEd Maste 		    rp_id, &argv[3], &argv[2], ms)) != FIDO_OK) {
1540afa8e06SEd Maste 			fido_log_debug("%s: cbor_add_uv_params", __func__);
1550afa8e06SEd Maste 			goto fail;
1560afa8e06SEd Maste 		}
1570afa8e06SEd Maste 	}
1580afa8e06SEd Maste 
1590afa8e06SEd Maste 	/* framing and transmission */
1600afa8e06SEd Maste 	if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
161f540a430SEd Maste 	    fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
1620afa8e06SEd Maste 		fido_log_debug("%s: fido_tx", __func__);
1630afa8e06SEd Maste 		r = FIDO_ERR_TX;
1640afa8e06SEd Maste 		goto fail;
1650afa8e06SEd Maste 	}
1660afa8e06SEd Maste 
1670afa8e06SEd Maste 	r = FIDO_OK;
1680afa8e06SEd Maste fail:
1690afa8e06SEd Maste 	es256_pk_free(&pk);
1700afa8e06SEd Maste 	fido_blob_free(&ecdh);
1710afa8e06SEd Maste 	cbor_vector_free(argv, nitems(argv));
1720afa8e06SEd Maste 	free(f.ptr);
1730afa8e06SEd Maste 	free(hmac.ptr);
1740afa8e06SEd Maste 
1750afa8e06SEd Maste 	return (r);
1760afa8e06SEd Maste }
1770afa8e06SEd Maste 
1780afa8e06SEd Maste static int
credman_parse_metadata(const cbor_item_t * key,const cbor_item_t * val,void * arg)1790afa8e06SEd Maste credman_parse_metadata(const cbor_item_t *key, const cbor_item_t *val,
1800afa8e06SEd Maste     void *arg)
1810afa8e06SEd Maste {
1820afa8e06SEd Maste 	fido_credman_metadata_t *metadata = arg;
1830afa8e06SEd Maste 
1840afa8e06SEd Maste 	if (cbor_isa_uint(key) == false ||
1850afa8e06SEd Maste 	    cbor_int_get_width(key) != CBOR_INT_8) {
1860afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
1870afa8e06SEd Maste 		return (0); /* ignore */
1880afa8e06SEd Maste 	}
1890afa8e06SEd Maste 
1900afa8e06SEd Maste 	switch (cbor_get_uint8(key)) {
1910afa8e06SEd Maste 	case 1:
1920afa8e06SEd Maste 		return (cbor_decode_uint64(val, &metadata->rk_existing));
1930afa8e06SEd Maste 	case 2:
1940afa8e06SEd Maste 		return (cbor_decode_uint64(val, &metadata->rk_remaining));
1950afa8e06SEd Maste 	default:
1960afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
1970afa8e06SEd Maste 		return (0); /* ignore */
1980afa8e06SEd Maste 	}
1990afa8e06SEd Maste }
2000afa8e06SEd Maste 
2010afa8e06SEd Maste static int
credman_rx_metadata(fido_dev_t * dev,fido_credman_metadata_t * metadata,int * ms)202f540a430SEd Maste credman_rx_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata, int *ms)
2030afa8e06SEd Maste {
204*2ccfa855SEd Maste 	unsigned char	*msg;
205*2ccfa855SEd Maste 	int		 msglen;
2060afa8e06SEd Maste 	int		 r;
2070afa8e06SEd Maste 
2080afa8e06SEd Maste 	memset(metadata, 0, sizeof(*metadata));
2090afa8e06SEd Maste 
210*2ccfa855SEd Maste 	if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
211*2ccfa855SEd Maste 		r = FIDO_ERR_INTERNAL;
212*2ccfa855SEd Maste 		goto out;
2130afa8e06SEd Maste 	}
2140afa8e06SEd Maste 
215*2ccfa855SEd Maste 	if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
216*2ccfa855SEd Maste 		fido_log_debug("%s: fido_rx", __func__);
217*2ccfa855SEd Maste 		r = FIDO_ERR_RX;
218*2ccfa855SEd Maste 		goto out;
219*2ccfa855SEd Maste 	}
220*2ccfa855SEd Maste 
221*2ccfa855SEd Maste 	if ((r = cbor_parse_reply(msg, (size_t)msglen, metadata,
2220afa8e06SEd Maste 	    credman_parse_metadata)) != FIDO_OK) {
2230afa8e06SEd Maste 		fido_log_debug("%s: credman_parse_metadata", __func__);
224*2ccfa855SEd Maste 		goto out;
2250afa8e06SEd Maste 	}
2260afa8e06SEd Maste 
227*2ccfa855SEd Maste 	r = FIDO_OK;
228*2ccfa855SEd Maste out:
229*2ccfa855SEd Maste 	freezero(msg, FIDO_MAXMSG);
230*2ccfa855SEd Maste 
231*2ccfa855SEd Maste 	return (r);
2320afa8e06SEd Maste }
2330afa8e06SEd Maste 
2340afa8e06SEd Maste static int
credman_get_metadata_wait(fido_dev_t * dev,fido_credman_metadata_t * metadata,const char * pin,int * ms)2350afa8e06SEd Maste credman_get_metadata_wait(fido_dev_t *dev, fido_credman_metadata_t *metadata,
236f540a430SEd Maste     const char *pin, int *ms)
2370afa8e06SEd Maste {
2380afa8e06SEd Maste 	int r;
2390afa8e06SEd Maste 
2400afa8e06SEd Maste 	if ((r = credman_tx(dev, CMD_CRED_METADATA, NULL, pin, NULL,
241f540a430SEd Maste 	    FIDO_OPT_TRUE, ms)) != FIDO_OK ||
2420afa8e06SEd Maste 	    (r = credman_rx_metadata(dev, metadata, ms)) != FIDO_OK)
2430afa8e06SEd Maste 		return (r);
2440afa8e06SEd Maste 
2450afa8e06SEd Maste 	return (FIDO_OK);
2460afa8e06SEd Maste }
2470afa8e06SEd Maste 
2480afa8e06SEd Maste int
fido_credman_get_dev_metadata(fido_dev_t * dev,fido_credman_metadata_t * metadata,const char * pin)2490afa8e06SEd Maste fido_credman_get_dev_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata,
2500afa8e06SEd Maste     const char *pin)
2510afa8e06SEd Maste {
252f540a430SEd Maste 	int ms = dev->timeout_ms;
253f540a430SEd Maste 
254f540a430SEd Maste 	return (credman_get_metadata_wait(dev, metadata, pin, &ms));
2550afa8e06SEd Maste }
2560afa8e06SEd Maste 
2570afa8e06SEd Maste static int
credman_parse_rk(const cbor_item_t * key,const cbor_item_t * val,void * arg)2580afa8e06SEd Maste credman_parse_rk(const cbor_item_t *key, const cbor_item_t *val, void *arg)
2590afa8e06SEd Maste {
2600afa8e06SEd Maste 	fido_cred_t	*cred = arg;
2610afa8e06SEd Maste 	uint64_t	 prot;
2620afa8e06SEd Maste 
2630afa8e06SEd Maste 	if (cbor_isa_uint(key) == false ||
2640afa8e06SEd Maste 	    cbor_int_get_width(key) != CBOR_INT_8) {
2650afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
2660afa8e06SEd Maste 		return (0); /* ignore */
2670afa8e06SEd Maste 	}
2680afa8e06SEd Maste 
2690afa8e06SEd Maste 	switch (cbor_get_uint8(key)) {
2700afa8e06SEd Maste 	case 6:
2710afa8e06SEd Maste 		return (cbor_decode_user(val, &cred->user));
2720afa8e06SEd Maste 	case 7:
2730afa8e06SEd Maste 		return (cbor_decode_cred_id(val, &cred->attcred.id));
2740afa8e06SEd Maste 	case 8:
2750afa8e06SEd Maste 		if (cbor_decode_pubkey(val, &cred->attcred.type,
2760afa8e06SEd Maste 		    &cred->attcred.pubkey) < 0)
2770afa8e06SEd Maste 			return (-1);
2780afa8e06SEd Maste 		cred->type = cred->attcred.type; /* XXX */
2790afa8e06SEd Maste 		return (0);
2800afa8e06SEd Maste 	case 10:
2810afa8e06SEd Maste 		if (cbor_decode_uint64(val, &prot) < 0 || prot > INT_MAX ||
2820afa8e06SEd Maste 		    fido_cred_set_prot(cred, (int)prot) != FIDO_OK)
2830afa8e06SEd Maste 			return (-1);
2840afa8e06SEd Maste 		return (0);
2850afa8e06SEd Maste 	case 11:
2860afa8e06SEd Maste 		return (fido_blob_decode(val, &cred->largeblob_key));
2870afa8e06SEd Maste 	default:
2880afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
2890afa8e06SEd Maste 		return (0); /* ignore */
2900afa8e06SEd Maste 	}
2910afa8e06SEd Maste }
2920afa8e06SEd Maste 
2930afa8e06SEd Maste static void
credman_reset_rk(fido_credman_rk_t * rk)2940afa8e06SEd Maste credman_reset_rk(fido_credman_rk_t *rk)
2950afa8e06SEd Maste {
2960afa8e06SEd Maste 	for (size_t i = 0; i < rk->n_alloc; i++) {
2970afa8e06SEd Maste 		fido_cred_reset_tx(&rk->ptr[i]);
2980afa8e06SEd Maste 		fido_cred_reset_rx(&rk->ptr[i]);
2990afa8e06SEd Maste 	}
3000afa8e06SEd Maste 
3010afa8e06SEd Maste 	free(rk->ptr);
3020afa8e06SEd Maste 	rk->ptr = NULL;
3030afa8e06SEd Maste 	memset(rk, 0, sizeof(*rk));
3040afa8e06SEd Maste }
3050afa8e06SEd Maste 
3060afa8e06SEd Maste static int
credman_parse_rk_count(const cbor_item_t * key,const cbor_item_t * val,void * arg)3070afa8e06SEd Maste credman_parse_rk_count(const cbor_item_t *key, const cbor_item_t *val,
3080afa8e06SEd Maste     void *arg)
3090afa8e06SEd Maste {
3100afa8e06SEd Maste 	fido_credman_rk_t *rk = arg;
3110afa8e06SEd Maste 	uint64_t n;
3120afa8e06SEd Maste 
3130afa8e06SEd Maste 	/* totalCredentials */
3140afa8e06SEd Maste 	if (cbor_isa_uint(key) == false ||
3150afa8e06SEd Maste 	    cbor_int_get_width(key) != CBOR_INT_8 ||
3160afa8e06SEd Maste 	    cbor_get_uint8(key) != 9) {
3170afa8e06SEd Maste 		fido_log_debug("%s: cbor_type", __func__);
3180afa8e06SEd Maste 		return (0); /* ignore */
3190afa8e06SEd Maste 	}
3200afa8e06SEd Maste 
3210afa8e06SEd Maste 	if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) {
3220afa8e06SEd Maste 		fido_log_debug("%s: cbor_decode_uint64", __func__);
3230afa8e06SEd Maste 		return (-1);
3240afa8e06SEd Maste 	}
3250afa8e06SEd Maste 
3260afa8e06SEd Maste 	if (credman_grow_array((void **)&rk->ptr, &rk->n_alloc, &rk->n_rx,
3270afa8e06SEd Maste 	    (size_t)n, sizeof(*rk->ptr)) < 0) {
3280afa8e06SEd Maste 		fido_log_debug("%s: credman_grow_array", __func__);
3290afa8e06SEd Maste 		return (-1);
3300afa8e06SEd Maste 	}
3310afa8e06SEd Maste 
3320afa8e06SEd Maste 	return (0);
3330afa8e06SEd Maste }
3340afa8e06SEd Maste 
3350afa8e06SEd Maste static int
credman_rx_rk(fido_dev_t * dev,fido_credman_rk_t * rk,int * ms)336f540a430SEd Maste credman_rx_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int *ms)
3370afa8e06SEd Maste {
338*2ccfa855SEd Maste 	unsigned char	*msg;
339*2ccfa855SEd Maste 	int		 msglen;
3400afa8e06SEd Maste 	int		 r;
3410afa8e06SEd Maste 
3420afa8e06SEd Maste 	credman_reset_rk(rk);
3430afa8e06SEd Maste 
344*2ccfa855SEd Maste 	if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
345*2ccfa855SEd Maste 		r = FIDO_ERR_INTERNAL;
346*2ccfa855SEd Maste 		goto out;
347*2ccfa855SEd Maste 	}
348*2ccfa855SEd Maste 
349*2ccfa855SEd Maste 	if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
3500afa8e06SEd Maste 		fido_log_debug("%s: fido_rx", __func__);
351*2ccfa855SEd Maste 		r = FIDO_ERR_RX;
352*2ccfa855SEd Maste 		goto out;
3530afa8e06SEd Maste 	}
3540afa8e06SEd Maste 
3550afa8e06SEd Maste 	/* adjust as needed */
356*2ccfa855SEd Maste 	if ((r = cbor_parse_reply(msg, (size_t)msglen, rk,
3570afa8e06SEd Maste 	    credman_parse_rk_count)) != FIDO_OK) {
3580afa8e06SEd Maste 		fido_log_debug("%s: credman_parse_rk_count", __func__);
359*2ccfa855SEd Maste 		goto out;
3600afa8e06SEd Maste 	}
3610afa8e06SEd Maste 
3620afa8e06SEd Maste 	if (rk->n_alloc == 0) {
3630afa8e06SEd Maste 		fido_log_debug("%s: n_alloc=0", __func__);
364*2ccfa855SEd Maste 		r = FIDO_OK;
365*2ccfa855SEd Maste 		goto out;
3660afa8e06SEd Maste 	}
3670afa8e06SEd Maste 
3680afa8e06SEd Maste 	/* parse the first rk */
369*2ccfa855SEd Maste 	if ((r = cbor_parse_reply(msg, (size_t)msglen, &rk->ptr[0],
3700afa8e06SEd Maste 	    credman_parse_rk)) != FIDO_OK) {
3710afa8e06SEd Maste 		fido_log_debug("%s: credman_parse_rk", __func__);
372*2ccfa855SEd Maste 		goto out;
3730afa8e06SEd Maste 	}
374*2ccfa855SEd Maste 	rk->n_rx = 1;
3750afa8e06SEd Maste 
376*2ccfa855SEd Maste 	r = FIDO_OK;
377*2ccfa855SEd Maste out:
378*2ccfa855SEd Maste 	freezero(msg, FIDO_MAXMSG);
3790afa8e06SEd Maste 
380*2ccfa855SEd Maste 	return (r);
3810afa8e06SEd Maste }
3820afa8e06SEd Maste 
3830afa8e06SEd Maste static int
credman_rx_next_rk(fido_dev_t * dev,fido_credman_rk_t * rk,int * ms)384f540a430SEd Maste credman_rx_next_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int *ms)
3850afa8e06SEd Maste {
386*2ccfa855SEd Maste 	unsigned char	*msg;
387*2ccfa855SEd Maste 	int		 msglen;
3880afa8e06SEd Maste 	int		 r;
3890afa8e06SEd Maste 
390*2ccfa855SEd Maste 	if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
391*2ccfa855SEd Maste 		r = FIDO_ERR_INTERNAL;
392*2ccfa855SEd Maste 		goto out;
393*2ccfa855SEd Maste 	}
394*2ccfa855SEd Maste 
395*2ccfa855SEd Maste 	if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
3960afa8e06SEd Maste 		fido_log_debug("%s: fido_rx", __func__);
397*2ccfa855SEd Maste 		r = FIDO_ERR_RX;
398*2ccfa855SEd Maste 		goto out;
3990afa8e06SEd Maste 	}
4000afa8e06SEd Maste 
4010afa8e06SEd Maste 	/* sanity check */
4020afa8e06SEd Maste 	if (rk->n_rx >= rk->n_alloc) {
4030afa8e06SEd Maste 		fido_log_debug("%s: n_rx=%zu, n_alloc=%zu", __func__, rk->n_rx,
4040afa8e06SEd Maste 		    rk->n_alloc);
405*2ccfa855SEd Maste 		r = FIDO_ERR_INTERNAL;
406*2ccfa855SEd Maste 		goto out;
4070afa8e06SEd Maste 	}
4080afa8e06SEd Maste 
409*2ccfa855SEd Maste 	if ((r = cbor_parse_reply(msg, (size_t)msglen, &rk->ptr[rk->n_rx],
4100afa8e06SEd Maste 	    credman_parse_rk)) != FIDO_OK) {
4110afa8e06SEd Maste 		fido_log_debug("%s: credman_parse_rk", __func__);
412*2ccfa855SEd Maste 		goto out;
4130afa8e06SEd Maste 	}
4140afa8e06SEd Maste 
415*2ccfa855SEd Maste 	r = FIDO_OK;
416*2ccfa855SEd Maste out:
417*2ccfa855SEd Maste 	freezero(msg, FIDO_MAXMSG);
418*2ccfa855SEd Maste 
419*2ccfa855SEd Maste 	return (r);
4200afa8e06SEd Maste }
4210afa8e06SEd Maste 
4220afa8e06SEd Maste static int
credman_get_rk_wait(fido_dev_t * dev,const char * rp_id,fido_credman_rk_t * rk,const char * pin,int * ms)4230afa8e06SEd Maste credman_get_rk_wait(fido_dev_t *dev, const char *rp_id, fido_credman_rk_t *rk,
424f540a430SEd Maste     const char *pin, int *ms)
4250afa8e06SEd Maste {
4260afa8e06SEd Maste 	fido_blob_t	rp_dgst;
4270afa8e06SEd Maste 	uint8_t		dgst[SHA256_DIGEST_LENGTH];
4280afa8e06SEd Maste 	int		r;
4290afa8e06SEd Maste 
4300afa8e06SEd Maste 	if (SHA256((const unsigned char *)rp_id, strlen(rp_id), dgst) != dgst) {
4310afa8e06SEd Maste 		fido_log_debug("%s: sha256", __func__);
4320afa8e06SEd Maste 		return (FIDO_ERR_INTERNAL);
4330afa8e06SEd Maste 	}
4340afa8e06SEd Maste 
4350afa8e06SEd Maste 	rp_dgst.ptr = dgst;
4360afa8e06SEd Maste 	rp_dgst.len = sizeof(dgst);
4370afa8e06SEd Maste 
4380afa8e06SEd Maste 	if ((r = credman_tx(dev, CMD_RK_BEGIN, &rp_dgst, pin, rp_id,
439f540a430SEd Maste 	    FIDO_OPT_TRUE, ms)) != FIDO_OK ||
4400afa8e06SEd Maste 	    (r = credman_rx_rk(dev, rk, ms)) != FIDO_OK)
4410afa8e06SEd Maste 		return (r);
4420afa8e06SEd Maste 
4430afa8e06SEd Maste 	while (rk->n_rx < rk->n_alloc) {
4440afa8e06SEd Maste 		if ((r = credman_tx(dev, CMD_RK_NEXT, NULL, NULL, NULL,
445f540a430SEd Maste 		    FIDO_OPT_FALSE, ms)) != FIDO_OK ||
4460afa8e06SEd Maste 		    (r = credman_rx_next_rk(dev, rk, ms)) != FIDO_OK)
4470afa8e06SEd Maste 			return (r);
4480afa8e06SEd Maste 		rk->n_rx++;
4490afa8e06SEd Maste 	}
4500afa8e06SEd Maste 
4510afa8e06SEd Maste 	return (FIDO_OK);
4520afa8e06SEd Maste }
4530afa8e06SEd Maste 
4540afa8e06SEd Maste int
fido_credman_get_dev_rk(fido_dev_t * dev,const char * rp_id,fido_credman_rk_t * rk,const char * pin)4550afa8e06SEd Maste fido_credman_get_dev_rk(fido_dev_t *dev, const char *rp_id,
4560afa8e06SEd Maste     fido_credman_rk_t *rk, const char *pin)
4570afa8e06SEd Maste {
458f540a430SEd Maste 	int ms = dev->timeout_ms;
459f540a430SEd Maste 
460f540a430SEd Maste 	return (credman_get_rk_wait(dev, rp_id, rk, pin, &ms));
4610afa8e06SEd Maste }
4620afa8e06SEd Maste 
4630afa8e06SEd Maste static int
credman_del_rk_wait(fido_dev_t * dev,const unsigned char * cred_id,size_t cred_id_len,const char * pin,int * ms)4640afa8e06SEd Maste credman_del_rk_wait(fido_dev_t *dev, const unsigned char *cred_id,
465f540a430SEd Maste     size_t cred_id_len, const char *pin, int *ms)
4660afa8e06SEd Maste {
4670afa8e06SEd Maste 	fido_blob_t cred;
4680afa8e06SEd Maste 	int r;
4690afa8e06SEd Maste 
4700afa8e06SEd Maste 	memset(&cred, 0, sizeof(cred));
4710afa8e06SEd Maste 
4720afa8e06SEd Maste 	if (fido_blob_set(&cred, cred_id, cred_id_len) < 0)
4730afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
4740afa8e06SEd Maste 
4750afa8e06SEd Maste 	if ((r = credman_tx(dev, CMD_DELETE_CRED, &cred, pin, NULL,
476f540a430SEd Maste 	    FIDO_OPT_TRUE, ms)) != FIDO_OK ||
4770afa8e06SEd Maste 	    (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK)
4780afa8e06SEd Maste 		goto fail;
4790afa8e06SEd Maste 
4800afa8e06SEd Maste 	r = FIDO_OK;
4810afa8e06SEd Maste fail:
4820afa8e06SEd Maste 	free(cred.ptr);
4830afa8e06SEd Maste 
4840afa8e06SEd Maste 	return (r);
4850afa8e06SEd Maste }
4860afa8e06SEd Maste 
4870afa8e06SEd Maste int
fido_credman_del_dev_rk(fido_dev_t * dev,const unsigned char * cred_id,size_t cred_id_len,const char * pin)4880afa8e06SEd Maste fido_credman_del_dev_rk(fido_dev_t *dev, const unsigned char *cred_id,
4890afa8e06SEd Maste     size_t cred_id_len, const char *pin)
4900afa8e06SEd Maste {
491f540a430SEd Maste 	int ms = dev->timeout_ms;
492f540a430SEd Maste 
493f540a430SEd Maste 	return (credman_del_rk_wait(dev, cred_id, cred_id_len, pin, &ms));
4940afa8e06SEd Maste }
4950afa8e06SEd Maste 
4960afa8e06SEd Maste static int
credman_parse_rp(const cbor_item_t * key,const cbor_item_t * val,void * arg)4970afa8e06SEd Maste credman_parse_rp(const cbor_item_t *key, const cbor_item_t *val, void *arg)
4980afa8e06SEd Maste {
4990afa8e06SEd Maste 	struct fido_credman_single_rp *rp = arg;
5000afa8e06SEd Maste 
5010afa8e06SEd Maste 	if (cbor_isa_uint(key) == false ||
5020afa8e06SEd Maste 	    cbor_int_get_width(key) != CBOR_INT_8) {
5030afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
5040afa8e06SEd Maste 		return (0); /* ignore */
5050afa8e06SEd Maste 	}
5060afa8e06SEd Maste 
5070afa8e06SEd Maste 	switch (cbor_get_uint8(key)) {
5080afa8e06SEd Maste 	case 3:
5090afa8e06SEd Maste 		return (cbor_decode_rp_entity(val, &rp->rp_entity));
5100afa8e06SEd Maste 	case 4:
5110afa8e06SEd Maste 		return (fido_blob_decode(val, &rp->rp_id_hash));
5120afa8e06SEd Maste 	default:
5130afa8e06SEd Maste 		fido_log_debug("%s: cbor type", __func__);
5140afa8e06SEd Maste 		return (0); /* ignore */
5150afa8e06SEd Maste 	}
5160afa8e06SEd Maste }
5170afa8e06SEd Maste 
5180afa8e06SEd Maste static void
credman_reset_rp(fido_credman_rp_t * rp)5190afa8e06SEd Maste credman_reset_rp(fido_credman_rp_t *rp)
5200afa8e06SEd Maste {
5210afa8e06SEd Maste 	for (size_t i = 0; i < rp->n_alloc; i++) {
5220afa8e06SEd Maste 		free(rp->ptr[i].rp_entity.id);
5230afa8e06SEd Maste 		free(rp->ptr[i].rp_entity.name);
5240afa8e06SEd Maste 		rp->ptr[i].rp_entity.id = NULL;
5250afa8e06SEd Maste 		rp->ptr[i].rp_entity.name = NULL;
5260afa8e06SEd Maste 		fido_blob_reset(&rp->ptr[i].rp_id_hash);
5270afa8e06SEd Maste 	}
5280afa8e06SEd Maste 
5290afa8e06SEd Maste 	free(rp->ptr);
5300afa8e06SEd Maste 	rp->ptr = NULL;
5310afa8e06SEd Maste 	memset(rp, 0, sizeof(*rp));
5320afa8e06SEd Maste }
5330afa8e06SEd Maste 
5340afa8e06SEd Maste static int
credman_parse_rp_count(const cbor_item_t * key,const cbor_item_t * val,void * arg)5350afa8e06SEd Maste credman_parse_rp_count(const cbor_item_t *key, const cbor_item_t *val,
5360afa8e06SEd Maste     void *arg)
5370afa8e06SEd Maste {
5380afa8e06SEd Maste 	fido_credman_rp_t *rp = arg;
5390afa8e06SEd Maste 	uint64_t n;
5400afa8e06SEd Maste 
5410afa8e06SEd Maste 	/* totalRPs */
5420afa8e06SEd Maste 	if (cbor_isa_uint(key) == false ||
5430afa8e06SEd Maste 	    cbor_int_get_width(key) != CBOR_INT_8 ||
5440afa8e06SEd Maste 	    cbor_get_uint8(key) != 5) {
5450afa8e06SEd Maste 		fido_log_debug("%s: cbor_type", __func__);
5460afa8e06SEd Maste 		return (0); /* ignore */
5470afa8e06SEd Maste 	}
5480afa8e06SEd Maste 
5490afa8e06SEd Maste 	if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) {
5500afa8e06SEd Maste 		fido_log_debug("%s: cbor_decode_uint64", __func__);
5510afa8e06SEd Maste 		return (-1);
5520afa8e06SEd Maste 	}
5530afa8e06SEd Maste 
5540afa8e06SEd Maste 	if (credman_grow_array((void **)&rp->ptr, &rp->n_alloc, &rp->n_rx,
5550afa8e06SEd Maste 	    (size_t)n, sizeof(*rp->ptr)) < 0) {
5560afa8e06SEd Maste 		fido_log_debug("%s: credman_grow_array", __func__);
5570afa8e06SEd Maste 		return (-1);
5580afa8e06SEd Maste 	}
5590afa8e06SEd Maste 
5600afa8e06SEd Maste 	return (0);
5610afa8e06SEd Maste }
5620afa8e06SEd Maste 
5630afa8e06SEd Maste static int
credman_rx_rp(fido_dev_t * dev,fido_credman_rp_t * rp,int * ms)564f540a430SEd Maste credman_rx_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int *ms)
5650afa8e06SEd Maste {
566*2ccfa855SEd Maste 	unsigned char	*msg;
567*2ccfa855SEd Maste 	int		 msglen;
5680afa8e06SEd Maste 	int		 r;
5690afa8e06SEd Maste 
5700afa8e06SEd Maste 	credman_reset_rp(rp);
5710afa8e06SEd Maste 
572*2ccfa855SEd Maste 	if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
573*2ccfa855SEd Maste 		r = FIDO_ERR_INTERNAL;
574*2ccfa855SEd Maste 		goto out;
575*2ccfa855SEd Maste 	}
576*2ccfa855SEd Maste 
577*2ccfa855SEd Maste 	if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
5780afa8e06SEd Maste 		fido_log_debug("%s: fido_rx", __func__);
579*2ccfa855SEd Maste 		r = FIDO_ERR_RX;
580*2ccfa855SEd Maste 		goto out;
5810afa8e06SEd Maste 	}
5820afa8e06SEd Maste 
5830afa8e06SEd Maste 	/* adjust as needed */
584*2ccfa855SEd Maste 	if ((r = cbor_parse_reply(msg, (size_t)msglen, rp,
5850afa8e06SEd Maste 	    credman_parse_rp_count)) != FIDO_OK) {
5860afa8e06SEd Maste 		fido_log_debug("%s: credman_parse_rp_count", __func__);
587*2ccfa855SEd Maste 		goto out;
5880afa8e06SEd Maste 	}
5890afa8e06SEd Maste 
5900afa8e06SEd Maste 	if (rp->n_alloc == 0) {
5910afa8e06SEd Maste 		fido_log_debug("%s: n_alloc=0", __func__);
592*2ccfa855SEd Maste 		r = FIDO_OK;
593*2ccfa855SEd Maste 		goto out;
5940afa8e06SEd Maste 	}
5950afa8e06SEd Maste 
5960afa8e06SEd Maste 	/* parse the first rp */
597*2ccfa855SEd Maste 	if ((r = cbor_parse_reply(msg, (size_t)msglen, &rp->ptr[0],
5980afa8e06SEd Maste 	    credman_parse_rp)) != FIDO_OK) {
5990afa8e06SEd Maste 		fido_log_debug("%s: credman_parse_rp", __func__);
600*2ccfa855SEd Maste 		goto out;
6010afa8e06SEd Maste 	}
602*2ccfa855SEd Maste 	rp->n_rx = 1;
6030afa8e06SEd Maste 
604*2ccfa855SEd Maste 	r = FIDO_OK;
605*2ccfa855SEd Maste out:
606*2ccfa855SEd Maste 	freezero(msg, FIDO_MAXMSG);
6070afa8e06SEd Maste 
608*2ccfa855SEd Maste 	return (r);
6090afa8e06SEd Maste }
6100afa8e06SEd Maste 
6110afa8e06SEd Maste static int
credman_rx_next_rp(fido_dev_t * dev,fido_credman_rp_t * rp,int * ms)612f540a430SEd Maste credman_rx_next_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int *ms)
6130afa8e06SEd Maste {
614*2ccfa855SEd Maste 	unsigned char	*msg;
615*2ccfa855SEd Maste 	int		 msglen;
6160afa8e06SEd Maste 	int		 r;
6170afa8e06SEd Maste 
618*2ccfa855SEd Maste 	if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
619*2ccfa855SEd Maste 		r = FIDO_ERR_INTERNAL;
620*2ccfa855SEd Maste 		goto out;
621*2ccfa855SEd Maste 	}
622*2ccfa855SEd Maste 
623*2ccfa855SEd Maste 	if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
6240afa8e06SEd Maste 		fido_log_debug("%s: fido_rx", __func__);
625*2ccfa855SEd Maste 		r = FIDO_ERR_RX;
626*2ccfa855SEd Maste 		goto out;
6270afa8e06SEd Maste 	}
6280afa8e06SEd Maste 
6290afa8e06SEd Maste 	/* sanity check */
6300afa8e06SEd Maste 	if (rp->n_rx >= rp->n_alloc) {
6310afa8e06SEd Maste 		fido_log_debug("%s: n_rx=%zu, n_alloc=%zu", __func__, rp->n_rx,
6320afa8e06SEd Maste 		    rp->n_alloc);
633*2ccfa855SEd Maste 		r = FIDO_ERR_INTERNAL;
634*2ccfa855SEd Maste 		goto out;
6350afa8e06SEd Maste 	}
6360afa8e06SEd Maste 
637*2ccfa855SEd Maste 	if ((r = cbor_parse_reply(msg, (size_t)msglen, &rp->ptr[rp->n_rx],
6380afa8e06SEd Maste 	    credman_parse_rp)) != FIDO_OK) {
6390afa8e06SEd Maste 		fido_log_debug("%s: credman_parse_rp", __func__);
640*2ccfa855SEd Maste 		goto out;
6410afa8e06SEd Maste 	}
6420afa8e06SEd Maste 
643*2ccfa855SEd Maste 	r = FIDO_OK;
644*2ccfa855SEd Maste out:
645*2ccfa855SEd Maste 	freezero(msg, FIDO_MAXMSG);
646*2ccfa855SEd Maste 
647*2ccfa855SEd Maste 	return (r);
6480afa8e06SEd Maste }
6490afa8e06SEd Maste 
6500afa8e06SEd Maste static int
credman_get_rp_wait(fido_dev_t * dev,fido_credman_rp_t * rp,const char * pin,int * ms)6510afa8e06SEd Maste credman_get_rp_wait(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin,
652f540a430SEd Maste     int *ms)
6530afa8e06SEd Maste {
6540afa8e06SEd Maste 	int r;
6550afa8e06SEd Maste 
6560afa8e06SEd Maste 	if ((r = credman_tx(dev, CMD_RP_BEGIN, NULL, pin, NULL,
657f540a430SEd Maste 	    FIDO_OPT_TRUE, ms)) != FIDO_OK ||
6580afa8e06SEd Maste 	    (r = credman_rx_rp(dev, rp, ms)) != FIDO_OK)
6590afa8e06SEd Maste 		return (r);
6600afa8e06SEd Maste 
6610afa8e06SEd Maste 	while (rp->n_rx < rp->n_alloc) {
6620afa8e06SEd Maste 		if ((r = credman_tx(dev, CMD_RP_NEXT, NULL, NULL, NULL,
663f540a430SEd Maste 		    FIDO_OPT_FALSE, ms)) != FIDO_OK ||
6640afa8e06SEd Maste 		    (r = credman_rx_next_rp(dev, rp, ms)) != FIDO_OK)
6650afa8e06SEd Maste 			return (r);
6660afa8e06SEd Maste 		rp->n_rx++;
6670afa8e06SEd Maste 	}
6680afa8e06SEd Maste 
6690afa8e06SEd Maste 	return (FIDO_OK);
6700afa8e06SEd Maste }
6710afa8e06SEd Maste 
6720afa8e06SEd Maste int
fido_credman_get_dev_rp(fido_dev_t * dev,fido_credman_rp_t * rp,const char * pin)6730afa8e06SEd Maste fido_credman_get_dev_rp(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin)
6740afa8e06SEd Maste {
675f540a430SEd Maste 	int ms = dev->timeout_ms;
676f540a430SEd Maste 
677f540a430SEd Maste 	return (credman_get_rp_wait(dev, rp, pin, &ms));
6780afa8e06SEd Maste }
6790afa8e06SEd Maste 
6800afa8e06SEd Maste static int
credman_set_dev_rk_wait(fido_dev_t * dev,fido_cred_t * cred,const char * pin,int * ms)6810afa8e06SEd Maste credman_set_dev_rk_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
682f540a430SEd Maste     int *ms)
6830afa8e06SEd Maste {
6840afa8e06SEd Maste 	int r;
6850afa8e06SEd Maste 
6860afa8e06SEd Maste 	if ((r = credman_tx(dev, CMD_UPDATE_CRED, cred, pin, NULL,
687f540a430SEd Maste 	    FIDO_OPT_TRUE, ms)) != FIDO_OK ||
6880afa8e06SEd Maste 	    (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK)
6890afa8e06SEd Maste 		return (r);
6900afa8e06SEd Maste 
6910afa8e06SEd Maste 	return (FIDO_OK);
6920afa8e06SEd Maste }
6930afa8e06SEd Maste 
6940afa8e06SEd Maste int
fido_credman_set_dev_rk(fido_dev_t * dev,fido_cred_t * cred,const char * pin)6950afa8e06SEd Maste fido_credman_set_dev_rk(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
6960afa8e06SEd Maste {
697f540a430SEd Maste 	int ms = dev->timeout_ms;
698f540a430SEd Maste 
699f540a430SEd Maste 	return (credman_set_dev_rk_wait(dev, cred, pin, &ms));
7000afa8e06SEd Maste }
7010afa8e06SEd Maste 
7020afa8e06SEd Maste fido_credman_rk_t *
fido_credman_rk_new(void)7030afa8e06SEd Maste fido_credman_rk_new(void)
7040afa8e06SEd Maste {
7050afa8e06SEd Maste 	return (calloc(1, sizeof(fido_credman_rk_t)));
7060afa8e06SEd Maste }
7070afa8e06SEd Maste 
7080afa8e06SEd Maste void
fido_credman_rk_free(fido_credman_rk_t ** rk_p)7090afa8e06SEd Maste fido_credman_rk_free(fido_credman_rk_t **rk_p)
7100afa8e06SEd Maste {
7110afa8e06SEd Maste 	fido_credman_rk_t *rk;
7120afa8e06SEd Maste 
7130afa8e06SEd Maste 	if (rk_p == NULL || (rk = *rk_p) == NULL)
7140afa8e06SEd Maste 		return;
7150afa8e06SEd Maste 
7160afa8e06SEd Maste 	credman_reset_rk(rk);
7170afa8e06SEd Maste 	free(rk);
7180afa8e06SEd Maste 	*rk_p = NULL;
7190afa8e06SEd Maste }
7200afa8e06SEd Maste 
7210afa8e06SEd Maste size_t
fido_credman_rk_count(const fido_credman_rk_t * rk)7220afa8e06SEd Maste fido_credman_rk_count(const fido_credman_rk_t *rk)
7230afa8e06SEd Maste {
7240afa8e06SEd Maste 	return (rk->n_rx);
7250afa8e06SEd Maste }
7260afa8e06SEd Maste 
7270afa8e06SEd Maste const fido_cred_t *
fido_credman_rk(const fido_credman_rk_t * rk,size_t idx)7280afa8e06SEd Maste fido_credman_rk(const fido_credman_rk_t *rk, size_t idx)
7290afa8e06SEd Maste {
7300afa8e06SEd Maste 	if (idx >= rk->n_alloc)
7310afa8e06SEd Maste 		return (NULL);
7320afa8e06SEd Maste 
7330afa8e06SEd Maste 	return (&rk->ptr[idx]);
7340afa8e06SEd Maste }
7350afa8e06SEd Maste 
7360afa8e06SEd Maste fido_credman_metadata_t *
fido_credman_metadata_new(void)7370afa8e06SEd Maste fido_credman_metadata_new(void)
7380afa8e06SEd Maste {
7390afa8e06SEd Maste 	return (calloc(1, sizeof(fido_credman_metadata_t)));
7400afa8e06SEd Maste }
7410afa8e06SEd Maste 
7420afa8e06SEd Maste void
fido_credman_metadata_free(fido_credman_metadata_t ** metadata_p)7430afa8e06SEd Maste fido_credman_metadata_free(fido_credman_metadata_t **metadata_p)
7440afa8e06SEd Maste {
7450afa8e06SEd Maste 	fido_credman_metadata_t *metadata;
7460afa8e06SEd Maste 
7470afa8e06SEd Maste 	if (metadata_p == NULL || (metadata = *metadata_p) == NULL)
7480afa8e06SEd Maste 		return;
7490afa8e06SEd Maste 
7500afa8e06SEd Maste 	free(metadata);
7510afa8e06SEd Maste 	*metadata_p = NULL;
7520afa8e06SEd Maste }
7530afa8e06SEd Maste 
7540afa8e06SEd Maste uint64_t
fido_credman_rk_existing(const fido_credman_metadata_t * metadata)7550afa8e06SEd Maste fido_credman_rk_existing(const fido_credman_metadata_t *metadata)
7560afa8e06SEd Maste {
7570afa8e06SEd Maste 	return (metadata->rk_existing);
7580afa8e06SEd Maste }
7590afa8e06SEd Maste 
7600afa8e06SEd Maste uint64_t
fido_credman_rk_remaining(const fido_credman_metadata_t * metadata)7610afa8e06SEd Maste fido_credman_rk_remaining(const fido_credman_metadata_t *metadata)
7620afa8e06SEd Maste {
7630afa8e06SEd Maste 	return (metadata->rk_remaining);
7640afa8e06SEd Maste }
7650afa8e06SEd Maste 
7660afa8e06SEd Maste fido_credman_rp_t *
fido_credman_rp_new(void)7670afa8e06SEd Maste fido_credman_rp_new(void)
7680afa8e06SEd Maste {
7690afa8e06SEd Maste 	return (calloc(1, sizeof(fido_credman_rp_t)));
7700afa8e06SEd Maste }
7710afa8e06SEd Maste 
7720afa8e06SEd Maste void
fido_credman_rp_free(fido_credman_rp_t ** rp_p)7730afa8e06SEd Maste fido_credman_rp_free(fido_credman_rp_t **rp_p)
7740afa8e06SEd Maste {
7750afa8e06SEd Maste 	fido_credman_rp_t *rp;
7760afa8e06SEd Maste 
7770afa8e06SEd Maste 	if (rp_p == NULL || (rp = *rp_p) == NULL)
7780afa8e06SEd Maste 		return;
7790afa8e06SEd Maste 
7800afa8e06SEd Maste 	credman_reset_rp(rp);
7810afa8e06SEd Maste 	free(rp);
7820afa8e06SEd Maste 	*rp_p = NULL;
7830afa8e06SEd Maste }
7840afa8e06SEd Maste 
7850afa8e06SEd Maste size_t
fido_credman_rp_count(const fido_credman_rp_t * rp)7860afa8e06SEd Maste fido_credman_rp_count(const fido_credman_rp_t *rp)
7870afa8e06SEd Maste {
7880afa8e06SEd Maste 	return (rp->n_rx);
7890afa8e06SEd Maste }
7900afa8e06SEd Maste 
7910afa8e06SEd Maste const char *
fido_credman_rp_id(const fido_credman_rp_t * rp,size_t idx)7920afa8e06SEd Maste fido_credman_rp_id(const fido_credman_rp_t *rp, size_t idx)
7930afa8e06SEd Maste {
7940afa8e06SEd Maste 	if (idx >= rp->n_alloc)
7950afa8e06SEd Maste 		return (NULL);
7960afa8e06SEd Maste 
7970afa8e06SEd Maste 	return (rp->ptr[idx].rp_entity.id);
7980afa8e06SEd Maste }
7990afa8e06SEd Maste 
8000afa8e06SEd Maste const char *
fido_credman_rp_name(const fido_credman_rp_t * rp,size_t idx)8010afa8e06SEd Maste fido_credman_rp_name(const fido_credman_rp_t *rp, size_t idx)
8020afa8e06SEd Maste {
8030afa8e06SEd Maste 	if (idx >= rp->n_alloc)
8040afa8e06SEd Maste 		return (NULL);
8050afa8e06SEd Maste 
8060afa8e06SEd Maste 	return (rp->ptr[idx].rp_entity.name);
8070afa8e06SEd Maste }
8080afa8e06SEd Maste 
8090afa8e06SEd Maste size_t
fido_credman_rp_id_hash_len(const fido_credman_rp_t * rp,size_t idx)8100afa8e06SEd Maste fido_credman_rp_id_hash_len(const fido_credman_rp_t *rp, size_t idx)
8110afa8e06SEd Maste {
8120afa8e06SEd Maste 	if (idx >= rp->n_alloc)
8130afa8e06SEd Maste 		return (0);
8140afa8e06SEd Maste 
8150afa8e06SEd Maste 	return (rp->ptr[idx].rp_id_hash.len);
8160afa8e06SEd Maste }
8170afa8e06SEd Maste 
8180afa8e06SEd Maste const unsigned char *
fido_credman_rp_id_hash_ptr(const fido_credman_rp_t * rp,size_t idx)8190afa8e06SEd Maste fido_credman_rp_id_hash_ptr(const fido_credman_rp_t *rp, size_t idx)
8200afa8e06SEd Maste {
8210afa8e06SEd Maste 	if (idx >= rp->n_alloc)
8220afa8e06SEd Maste 		return (NULL);
8230afa8e06SEd Maste 
8240afa8e06SEd Maste 	return (rp->ptr[idx].rp_id_hash.ptr);
8250afa8e06SEd Maste }
826