xref: /openbsd-src/lib/libfido2/src/credman.c (revision ab19a69ebe1d1275c01611de862453c36b3d15b9)
1d75efeb7Sdjm /*
2c4a807edSdjm  * Copyright (c) 2019-2021 Yubico AB. All rights reserved.
3d75efeb7Sdjm  * Use of this source code is governed by a BSD-style
4d75efeb7Sdjm  * license that can be found in the LICENSE file.
5d75efeb7Sdjm  */
6d75efeb7Sdjm 
7d75efeb7Sdjm #include <openssl/sha.h>
8d75efeb7Sdjm 
9d75efeb7Sdjm #include "fido.h"
10d75efeb7Sdjm #include "fido/credman.h"
11d75efeb7Sdjm #include "fido/es256.h"
12d75efeb7Sdjm 
13d75efeb7Sdjm #define CMD_CRED_METADATA	0x01
14d75efeb7Sdjm #define CMD_RP_BEGIN		0x02
15d75efeb7Sdjm #define CMD_RP_NEXT		0x03
16d75efeb7Sdjm #define CMD_RK_BEGIN		0x04
17d75efeb7Sdjm #define CMD_RK_NEXT		0x05
18d75efeb7Sdjm #define CMD_DELETE_CRED		0x06
19c4a807edSdjm #define CMD_UPDATE_CRED		0x07
20d75efeb7Sdjm 
21d75efeb7Sdjm static int
credman_grow_array(void ** ptr,size_t * n_alloc,size_t * n_rx,size_t n,size_t size)22d75efeb7Sdjm credman_grow_array(void **ptr, size_t *n_alloc, size_t *n_rx, size_t n,
23d75efeb7Sdjm     size_t size)
24d75efeb7Sdjm {
25d75efeb7Sdjm 	void *new_ptr;
26d75efeb7Sdjm 
27d75efeb7Sdjm #ifdef FIDO_FUZZ
28d75efeb7Sdjm 	if (n > UINT8_MAX) {
2932a20e26Sdjm 		fido_log_debug("%s: n > UINT8_MAX", __func__);
30d75efeb7Sdjm 		return (-1);
31d75efeb7Sdjm 	}
32d75efeb7Sdjm #endif
33d75efeb7Sdjm 
34d75efeb7Sdjm 	if (n < *n_alloc)
35d75efeb7Sdjm 		return (0);
36d75efeb7Sdjm 
37d75efeb7Sdjm 	/* sanity check */
38d75efeb7Sdjm 	if (*n_rx > 0 || *n_rx > *n_alloc || n < *n_alloc) {
3932a20e26Sdjm 		fido_log_debug("%s: n=%zu, n_rx=%zu, n_alloc=%zu", __func__, n,
40d75efeb7Sdjm 		    *n_rx, *n_alloc);
41d75efeb7Sdjm 		return (-1);
42d75efeb7Sdjm 	}
43d75efeb7Sdjm 
44d75efeb7Sdjm 	if ((new_ptr = recallocarray(*ptr, *n_alloc, n, size)) == NULL)
45d75efeb7Sdjm 		return (-1);
46d75efeb7Sdjm 
47d75efeb7Sdjm 	*ptr = new_ptr;
48d75efeb7Sdjm 	*n_alloc = n;
49d75efeb7Sdjm 
50d75efeb7Sdjm 	return (0);
51d75efeb7Sdjm }
52d75efeb7Sdjm 
53d75efeb7Sdjm static int
credman_prepare_hmac(uint8_t cmd,const void * body,cbor_item_t ** param,fido_blob_t * hmac_data)54c4a807edSdjm credman_prepare_hmac(uint8_t cmd, const void *body, cbor_item_t **param,
55d75efeb7Sdjm     fido_blob_t *hmac_data)
56d75efeb7Sdjm {
57c4a807edSdjm 	cbor_item_t *param_cbor[3];
58c4a807edSdjm 	const fido_cred_t *cred;
59d75efeb7Sdjm 	size_t n;
60d75efeb7Sdjm 	int ok = -1;
61d75efeb7Sdjm 
62d75efeb7Sdjm 	memset(&param_cbor, 0, sizeof(param_cbor));
63d75efeb7Sdjm 
64d75efeb7Sdjm 	if (body == NULL)
65d75efeb7Sdjm 		return (fido_blob_set(hmac_data, &cmd, sizeof(cmd)));
66d75efeb7Sdjm 
67d75efeb7Sdjm 	switch (cmd) {
68d75efeb7Sdjm 	case CMD_RK_BEGIN:
69d75efeb7Sdjm 		n = 1;
70c4a807edSdjm 		if ((param_cbor[0] = fido_blob_encode(body)) == NULL) {
71c4a807edSdjm 			fido_log_debug("%s: cbor encode", __func__);
72c4a807edSdjm 			goto fail;
73c4a807edSdjm 		}
74d75efeb7Sdjm 		break;
75d75efeb7Sdjm 	case CMD_DELETE_CRED:
76d75efeb7Sdjm 		n = 2;
77c4a807edSdjm 		if ((param_cbor[1] = cbor_encode_pubkey(body)) == NULL) {
78c4a807edSdjm 			fido_log_debug("%s: cbor encode", __func__);
79c4a807edSdjm 			goto fail;
80c4a807edSdjm 		}
81c4a807edSdjm 		break;
82c4a807edSdjm 	case CMD_UPDATE_CRED:
83c4a807edSdjm 		n = 3;
84c4a807edSdjm 		cred = body;
85c4a807edSdjm 		param_cbor[1] = cbor_encode_pubkey(&cred->attcred.id);
86c4a807edSdjm 		param_cbor[2] = cbor_encode_user_entity(&cred->user);
87c4a807edSdjm 		if (param_cbor[1] == NULL || param_cbor[2] == NULL) {
88c4a807edSdjm 			fido_log_debug("%s: cbor encode", __func__);
89c4a807edSdjm 			goto fail;
90c4a807edSdjm 		}
91d75efeb7Sdjm 		break;
92d75efeb7Sdjm 	default:
9332a20e26Sdjm 		fido_log_debug("%s: unknown cmd=0x%02x", __func__, cmd);
94d75efeb7Sdjm 		return (-1);
95d75efeb7Sdjm 	}
96d75efeb7Sdjm 
97d75efeb7Sdjm 	if ((*param = cbor_flatten_vector(param_cbor, n)) == NULL) {
9832a20e26Sdjm 		fido_log_debug("%s: cbor_flatten_vector", __func__);
99d75efeb7Sdjm 		goto fail;
100d75efeb7Sdjm 	}
101d75efeb7Sdjm 	if (cbor_build_frame(cmd, param_cbor, n, hmac_data) < 0) {
10232a20e26Sdjm 		fido_log_debug("%s: cbor_build_frame", __func__);
103d75efeb7Sdjm 		goto fail;
104d75efeb7Sdjm 	}
105d75efeb7Sdjm 
106d75efeb7Sdjm 	ok = 0;
107d75efeb7Sdjm fail:
108d75efeb7Sdjm 	cbor_vector_free(param_cbor, nitems(param_cbor));
109d75efeb7Sdjm 
110d75efeb7Sdjm 	return (ok);
111d75efeb7Sdjm }
112d75efeb7Sdjm 
113d75efeb7Sdjm 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)114c4a807edSdjm credman_tx(fido_dev_t *dev, uint8_t subcmd, const void *param, const char *pin,
115*ab19a69eSdjm     const char *rp_id, fido_opt_t uv, int *ms)
116d75efeb7Sdjm {
117d75efeb7Sdjm 	fido_blob_t	 f;
118d75efeb7Sdjm 	fido_blob_t	*ecdh = NULL;
119d75efeb7Sdjm 	fido_blob_t	 hmac;
120d75efeb7Sdjm 	es256_pk_t	*pk = NULL;
121d75efeb7Sdjm 	cbor_item_t	*argv[4];
122c4a807edSdjm 	const uint8_t	 cmd = CTAP_CBOR_CRED_MGMT_PRE;
123d75efeb7Sdjm 	int		 r = FIDO_ERR_INTERNAL;
124d75efeb7Sdjm 
125d75efeb7Sdjm 	memset(&f, 0, sizeof(f));
126d75efeb7Sdjm 	memset(&hmac, 0, sizeof(hmac));
127d75efeb7Sdjm 	memset(&argv, 0, sizeof(argv));
128d75efeb7Sdjm 
129c4a807edSdjm 	if (fido_dev_is_fido2(dev) == false) {
130c4a807edSdjm 		fido_log_debug("%s: fido_dev_is_fido2", __func__);
131c4a807edSdjm 		r = FIDO_ERR_INVALID_COMMAND;
132c4a807edSdjm 		goto fail;
133c4a807edSdjm 	}
134c4a807edSdjm 
135d75efeb7Sdjm 	/* subCommand */
136c4a807edSdjm 	if ((argv[0] = cbor_build_uint8(subcmd)) == NULL) {
13732a20e26Sdjm 		fido_log_debug("%s: cbor encode", __func__);
138d75efeb7Sdjm 		goto fail;
139d75efeb7Sdjm 	}
140d75efeb7Sdjm 
141d75efeb7Sdjm 	/* pinProtocol, pinAuth */
142c4a807edSdjm 	if (pin != NULL || uv == FIDO_OPT_TRUE) {
143c4a807edSdjm 		if (credman_prepare_hmac(subcmd, param, &argv[1], &hmac) < 0) {
14432a20e26Sdjm 			fido_log_debug("%s: credman_prepare_hmac", __func__);
145d75efeb7Sdjm 			goto fail;
146d75efeb7Sdjm 		}
147*ab19a69eSdjm 		if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
14832a20e26Sdjm 			fido_log_debug("%s: fido_do_ecdh", __func__);
149d75efeb7Sdjm 			goto fail;
150d75efeb7Sdjm 		}
151c4a807edSdjm 		if ((r = cbor_add_uv_params(dev, cmd, &hmac, pk, ecdh, pin,
152*ab19a69eSdjm 		    rp_id, &argv[3], &argv[2], ms)) != FIDO_OK) {
153c4a807edSdjm 			fido_log_debug("%s: cbor_add_uv_params", __func__);
154d75efeb7Sdjm 			goto fail;
155d75efeb7Sdjm 		}
156d75efeb7Sdjm 	}
157d75efeb7Sdjm 
158d75efeb7Sdjm 	/* framing and transmission */
159c4a807edSdjm 	if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
160*ab19a69eSdjm 	    fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
16132a20e26Sdjm 		fido_log_debug("%s: fido_tx", __func__);
162d75efeb7Sdjm 		r = FIDO_ERR_TX;
163d75efeb7Sdjm 		goto fail;
164d75efeb7Sdjm 	}
165d75efeb7Sdjm 
166d75efeb7Sdjm 	r = FIDO_OK;
167d75efeb7Sdjm fail:
168d75efeb7Sdjm 	es256_pk_free(&pk);
169d75efeb7Sdjm 	fido_blob_free(&ecdh);
170d75efeb7Sdjm 	cbor_vector_free(argv, nitems(argv));
171d75efeb7Sdjm 	free(f.ptr);
172d75efeb7Sdjm 	free(hmac.ptr);
173d75efeb7Sdjm 
174d75efeb7Sdjm 	return (r);
175d75efeb7Sdjm }
176d75efeb7Sdjm 
177d75efeb7Sdjm static int
credman_parse_metadata(const cbor_item_t * key,const cbor_item_t * val,void * arg)178d75efeb7Sdjm credman_parse_metadata(const cbor_item_t *key, const cbor_item_t *val,
179d75efeb7Sdjm     void *arg)
180d75efeb7Sdjm {
181d75efeb7Sdjm 	fido_credman_metadata_t *metadata = arg;
182d75efeb7Sdjm 
183d75efeb7Sdjm 	if (cbor_isa_uint(key) == false ||
184d75efeb7Sdjm 	    cbor_int_get_width(key) != CBOR_INT_8) {
18532a20e26Sdjm 		fido_log_debug("%s: cbor type", __func__);
186d75efeb7Sdjm 		return (0); /* ignore */
187d75efeb7Sdjm 	}
188d75efeb7Sdjm 
189d75efeb7Sdjm 	switch (cbor_get_uint8(key)) {
190d75efeb7Sdjm 	case 1:
19132a20e26Sdjm 		return (cbor_decode_uint64(val, &metadata->rk_existing));
192d75efeb7Sdjm 	case 2:
19332a20e26Sdjm 		return (cbor_decode_uint64(val, &metadata->rk_remaining));
194d75efeb7Sdjm 	default:
19532a20e26Sdjm 		fido_log_debug("%s: cbor type", __func__);
196d75efeb7Sdjm 		return (0); /* ignore */
197d75efeb7Sdjm 	}
198d75efeb7Sdjm }
199d75efeb7Sdjm 
200d75efeb7Sdjm static int
credman_rx_metadata(fido_dev_t * dev,fido_credman_metadata_t * metadata,int * ms)201*ab19a69eSdjm credman_rx_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata, int *ms)
202d75efeb7Sdjm {
20332a20e26Sdjm 	unsigned char	reply[FIDO_MAXMSG];
204d75efeb7Sdjm 	int		reply_len;
205d75efeb7Sdjm 	int		r;
206d75efeb7Sdjm 
207d75efeb7Sdjm 	memset(metadata, 0, sizeof(*metadata));
208d75efeb7Sdjm 
20932a20e26Sdjm 	if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
21032a20e26Sdjm 	    ms)) < 0) {
21132a20e26Sdjm 		fido_log_debug("%s: fido_rx", __func__);
212d75efeb7Sdjm 		return (FIDO_ERR_RX);
213d75efeb7Sdjm 	}
214d75efeb7Sdjm 
21532a20e26Sdjm 	if ((r = cbor_parse_reply(reply, (size_t)reply_len, metadata,
216d75efeb7Sdjm 	    credman_parse_metadata)) != FIDO_OK) {
21732a20e26Sdjm 		fido_log_debug("%s: credman_parse_metadata", __func__);
218d75efeb7Sdjm 		return (r);
219d75efeb7Sdjm 	}
220d75efeb7Sdjm 
221d75efeb7Sdjm 	return (FIDO_OK);
222d75efeb7Sdjm }
223d75efeb7Sdjm 
224d75efeb7Sdjm static int
credman_get_metadata_wait(fido_dev_t * dev,fido_credman_metadata_t * metadata,const char * pin,int * ms)225d75efeb7Sdjm credman_get_metadata_wait(fido_dev_t *dev, fido_credman_metadata_t *metadata,
226*ab19a69eSdjm     const char *pin, int *ms)
227d75efeb7Sdjm {
228d75efeb7Sdjm 	int r;
229d75efeb7Sdjm 
230c4a807edSdjm 	if ((r = credman_tx(dev, CMD_CRED_METADATA, NULL, pin, NULL,
231*ab19a69eSdjm 	    FIDO_OPT_TRUE, ms)) != FIDO_OK ||
232d75efeb7Sdjm 	    (r = credman_rx_metadata(dev, metadata, ms)) != FIDO_OK)
233d75efeb7Sdjm 		return (r);
234d75efeb7Sdjm 
235d75efeb7Sdjm 	return (FIDO_OK);
236d75efeb7Sdjm }
237d75efeb7Sdjm 
238d75efeb7Sdjm int
fido_credman_get_dev_metadata(fido_dev_t * dev,fido_credman_metadata_t * metadata,const char * pin)239d75efeb7Sdjm fido_credman_get_dev_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata,
240d75efeb7Sdjm     const char *pin)
241d75efeb7Sdjm {
242*ab19a69eSdjm 	int ms = dev->timeout_ms;
243*ab19a69eSdjm 
244*ab19a69eSdjm 	return (credman_get_metadata_wait(dev, metadata, pin, &ms));
245d75efeb7Sdjm }
246d75efeb7Sdjm 
247d75efeb7Sdjm static int
credman_parse_rk(const cbor_item_t * key,const cbor_item_t * val,void * arg)248d75efeb7Sdjm credman_parse_rk(const cbor_item_t *key, const cbor_item_t *val, void *arg)
249d75efeb7Sdjm {
250d75efeb7Sdjm 	fido_cred_t	*cred = arg;
251739189a3Sdjm 	uint64_t	 prot;
252d75efeb7Sdjm 
253d75efeb7Sdjm 	if (cbor_isa_uint(key) == false ||
254d75efeb7Sdjm 	    cbor_int_get_width(key) != CBOR_INT_8) {
25532a20e26Sdjm 		fido_log_debug("%s: cbor type", __func__);
256d75efeb7Sdjm 		return (0); /* ignore */
257d75efeb7Sdjm 	}
258d75efeb7Sdjm 
259d75efeb7Sdjm 	switch (cbor_get_uint8(key)) {
260c4a807edSdjm 	case 6:
26132a20e26Sdjm 		return (cbor_decode_user(val, &cred->user));
262d75efeb7Sdjm 	case 7:
26332a20e26Sdjm 		return (cbor_decode_cred_id(val, &cred->attcred.id));
264d75efeb7Sdjm 	case 8:
26532a20e26Sdjm 		if (cbor_decode_pubkey(val, &cred->attcred.type,
266d75efeb7Sdjm 		    &cred->attcred.pubkey) < 0)
267d75efeb7Sdjm 			return (-1);
268d75efeb7Sdjm 		cred->type = cred->attcred.type; /* XXX */
269d75efeb7Sdjm 		return (0);
270739189a3Sdjm 	case 10:
271739189a3Sdjm 		if (cbor_decode_uint64(val, &prot) < 0 || prot > INT_MAX ||
272739189a3Sdjm 		    fido_cred_set_prot(cred, (int)prot) != FIDO_OK)
273739189a3Sdjm 			return (-1);
274739189a3Sdjm 		return (0);
275c4a807edSdjm 	case 11:
276c4a807edSdjm 		return (fido_blob_decode(val, &cred->largeblob_key));
277d75efeb7Sdjm 	default:
27832a20e26Sdjm 		fido_log_debug("%s: cbor type", __func__);
279d75efeb7Sdjm 		return (0); /* ignore */
280d75efeb7Sdjm 	}
281d75efeb7Sdjm }
282d75efeb7Sdjm 
283d75efeb7Sdjm static void
credman_reset_rk(fido_credman_rk_t * rk)284d75efeb7Sdjm credman_reset_rk(fido_credman_rk_t *rk)
285d75efeb7Sdjm {
286d75efeb7Sdjm 	for (size_t i = 0; i < rk->n_alloc; i++) {
287d75efeb7Sdjm 		fido_cred_reset_tx(&rk->ptr[i]);
288d75efeb7Sdjm 		fido_cred_reset_rx(&rk->ptr[i]);
289d75efeb7Sdjm 	}
290d75efeb7Sdjm 
291d75efeb7Sdjm 	free(rk->ptr);
292d75efeb7Sdjm 	rk->ptr = NULL;
293d75efeb7Sdjm 	memset(rk, 0, sizeof(*rk));
294d75efeb7Sdjm }
295d75efeb7Sdjm 
296d75efeb7Sdjm static int
credman_parse_rk_count(const cbor_item_t * key,const cbor_item_t * val,void * arg)297d75efeb7Sdjm credman_parse_rk_count(const cbor_item_t *key, const cbor_item_t *val,
298d75efeb7Sdjm     void *arg)
299d75efeb7Sdjm {
300d75efeb7Sdjm 	fido_credman_rk_t *rk = arg;
301d75efeb7Sdjm 	uint64_t n;
302d75efeb7Sdjm 
303d75efeb7Sdjm 	/* totalCredentials */
304d75efeb7Sdjm 	if (cbor_isa_uint(key) == false ||
305d75efeb7Sdjm 	    cbor_int_get_width(key) != CBOR_INT_8 ||
306d75efeb7Sdjm 	    cbor_get_uint8(key) != 9) {
30732a20e26Sdjm 		fido_log_debug("%s: cbor_type", __func__);
308d75efeb7Sdjm 		return (0); /* ignore */
309d75efeb7Sdjm 	}
310d75efeb7Sdjm 
31132a20e26Sdjm 	if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) {
31232a20e26Sdjm 		fido_log_debug("%s: cbor_decode_uint64", __func__);
313d75efeb7Sdjm 		return (-1);
314d75efeb7Sdjm 	}
315d75efeb7Sdjm 
316d75efeb7Sdjm 	if (credman_grow_array((void **)&rk->ptr, &rk->n_alloc, &rk->n_rx,
317d75efeb7Sdjm 	    (size_t)n, sizeof(*rk->ptr)) < 0) {
31832a20e26Sdjm 		fido_log_debug("%s: credman_grow_array", __func__);
319d75efeb7Sdjm 		return (-1);
320d75efeb7Sdjm 	}
321d75efeb7Sdjm 
322d75efeb7Sdjm 	return (0);
323d75efeb7Sdjm }
324d75efeb7Sdjm 
325d75efeb7Sdjm static int
credman_rx_rk(fido_dev_t * dev,fido_credman_rk_t * rk,int * ms)326*ab19a69eSdjm credman_rx_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int *ms)
327d75efeb7Sdjm {
32832a20e26Sdjm 	unsigned char	reply[FIDO_MAXMSG];
329d75efeb7Sdjm 	int		reply_len;
330d75efeb7Sdjm 	int		r;
331d75efeb7Sdjm 
332d75efeb7Sdjm 	credman_reset_rk(rk);
333d75efeb7Sdjm 
33432a20e26Sdjm 	if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
33532a20e26Sdjm 	    ms)) < 0) {
33632a20e26Sdjm 		fido_log_debug("%s: fido_rx", __func__);
337d75efeb7Sdjm 		return (FIDO_ERR_RX);
338d75efeb7Sdjm 	}
339d75efeb7Sdjm 
340d75efeb7Sdjm 	/* adjust as needed */
34132a20e26Sdjm 	if ((r = cbor_parse_reply(reply, (size_t)reply_len, rk,
342d75efeb7Sdjm 	    credman_parse_rk_count)) != FIDO_OK) {
34332a20e26Sdjm 		fido_log_debug("%s: credman_parse_rk_count", __func__);
344d75efeb7Sdjm 		return (r);
345d75efeb7Sdjm 	}
346d75efeb7Sdjm 
347d75efeb7Sdjm 	if (rk->n_alloc == 0) {
34832a20e26Sdjm 		fido_log_debug("%s: n_alloc=0", __func__);
349d75efeb7Sdjm 		return (FIDO_OK);
350d75efeb7Sdjm 	}
351d75efeb7Sdjm 
352d75efeb7Sdjm 	/* parse the first rk */
35332a20e26Sdjm 	if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rk->ptr[0],
354d75efeb7Sdjm 	    credman_parse_rk)) != FIDO_OK) {
35532a20e26Sdjm 		fido_log_debug("%s: credman_parse_rk", __func__);
356d75efeb7Sdjm 		return (r);
357d75efeb7Sdjm 	}
358d75efeb7Sdjm 
359d75efeb7Sdjm 	rk->n_rx++;
360d75efeb7Sdjm 
361d75efeb7Sdjm 	return (FIDO_OK);
362d75efeb7Sdjm }
363d75efeb7Sdjm 
364d75efeb7Sdjm static int
credman_rx_next_rk(fido_dev_t * dev,fido_credman_rk_t * rk,int * ms)365*ab19a69eSdjm credman_rx_next_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int *ms)
366d75efeb7Sdjm {
36732a20e26Sdjm 	unsigned char	reply[FIDO_MAXMSG];
368d75efeb7Sdjm 	int		reply_len;
369d75efeb7Sdjm 	int		r;
370d75efeb7Sdjm 
37132a20e26Sdjm 	if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
37232a20e26Sdjm 	    ms)) < 0) {
37332a20e26Sdjm 		fido_log_debug("%s: fido_rx", __func__);
374d75efeb7Sdjm 		return (FIDO_ERR_RX);
375d75efeb7Sdjm 	}
376d75efeb7Sdjm 
377d75efeb7Sdjm 	/* sanity check */
378d75efeb7Sdjm 	if (rk->n_rx >= rk->n_alloc) {
37932a20e26Sdjm 		fido_log_debug("%s: n_rx=%zu, n_alloc=%zu", __func__, rk->n_rx,
380d75efeb7Sdjm 		    rk->n_alloc);
381d75efeb7Sdjm 		return (FIDO_ERR_INTERNAL);
382d75efeb7Sdjm 	}
383d75efeb7Sdjm 
38432a20e26Sdjm 	if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rk->ptr[rk->n_rx],
385d75efeb7Sdjm 	    credman_parse_rk)) != FIDO_OK) {
38632a20e26Sdjm 		fido_log_debug("%s: credman_parse_rk", __func__);
387d75efeb7Sdjm 		return (r);
388d75efeb7Sdjm 	}
389d75efeb7Sdjm 
390d75efeb7Sdjm 	return (FIDO_OK);
391d75efeb7Sdjm }
392d75efeb7Sdjm 
393d75efeb7Sdjm static int
credman_get_rk_wait(fido_dev_t * dev,const char * rp_id,fido_credman_rk_t * rk,const char * pin,int * ms)394d75efeb7Sdjm credman_get_rk_wait(fido_dev_t *dev, const char *rp_id, fido_credman_rk_t *rk,
395*ab19a69eSdjm     const char *pin, int *ms)
396d75efeb7Sdjm {
397d75efeb7Sdjm 	fido_blob_t	rp_dgst;
398d75efeb7Sdjm 	uint8_t		dgst[SHA256_DIGEST_LENGTH];
399d75efeb7Sdjm 	int		r;
400d75efeb7Sdjm 
401d75efeb7Sdjm 	if (SHA256((const unsigned char *)rp_id, strlen(rp_id), dgst) != dgst) {
40232a20e26Sdjm 		fido_log_debug("%s: sha256", __func__);
403d75efeb7Sdjm 		return (FIDO_ERR_INTERNAL);
404d75efeb7Sdjm 	}
405d75efeb7Sdjm 
406d75efeb7Sdjm 	rp_dgst.ptr = dgst;
407d75efeb7Sdjm 	rp_dgst.len = sizeof(dgst);
408d75efeb7Sdjm 
409c4a807edSdjm 	if ((r = credman_tx(dev, CMD_RK_BEGIN, &rp_dgst, pin, rp_id,
410*ab19a69eSdjm 	    FIDO_OPT_TRUE, ms)) != FIDO_OK ||
411d75efeb7Sdjm 	    (r = credman_rx_rk(dev, rk, ms)) != FIDO_OK)
412d75efeb7Sdjm 		return (r);
413d75efeb7Sdjm 
414d75efeb7Sdjm 	while (rk->n_rx < rk->n_alloc) {
415c4a807edSdjm 		if ((r = credman_tx(dev, CMD_RK_NEXT, NULL, NULL, NULL,
416*ab19a69eSdjm 		    FIDO_OPT_FALSE, ms)) != FIDO_OK ||
417d75efeb7Sdjm 		    (r = credman_rx_next_rk(dev, rk, ms)) != FIDO_OK)
418d75efeb7Sdjm 			return (r);
419d75efeb7Sdjm 		rk->n_rx++;
420d75efeb7Sdjm 	}
421d75efeb7Sdjm 
422d75efeb7Sdjm 	return (FIDO_OK);
423d75efeb7Sdjm }
424d75efeb7Sdjm 
425d75efeb7Sdjm int
fido_credman_get_dev_rk(fido_dev_t * dev,const char * rp_id,fido_credman_rk_t * rk,const char * pin)426d75efeb7Sdjm fido_credman_get_dev_rk(fido_dev_t *dev, const char *rp_id,
427d75efeb7Sdjm     fido_credman_rk_t *rk, const char *pin)
428d75efeb7Sdjm {
429*ab19a69eSdjm 	int ms = dev->timeout_ms;
430*ab19a69eSdjm 
431*ab19a69eSdjm 	return (credman_get_rk_wait(dev, rp_id, rk, pin, &ms));
432d75efeb7Sdjm }
433d75efeb7Sdjm 
434d75efeb7Sdjm 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)435d75efeb7Sdjm credman_del_rk_wait(fido_dev_t *dev, const unsigned char *cred_id,
436*ab19a69eSdjm     size_t cred_id_len, const char *pin, int *ms)
437d75efeb7Sdjm {
438d75efeb7Sdjm 	fido_blob_t cred;
439d75efeb7Sdjm 	int r;
440d75efeb7Sdjm 
441d75efeb7Sdjm 	memset(&cred, 0, sizeof(cred));
442d75efeb7Sdjm 
443d75efeb7Sdjm 	if (fido_blob_set(&cred, cred_id, cred_id_len) < 0)
444d75efeb7Sdjm 		return (FIDO_ERR_INVALID_ARGUMENT);
445d75efeb7Sdjm 
446c4a807edSdjm 	if ((r = credman_tx(dev, CMD_DELETE_CRED, &cred, pin, NULL,
447*ab19a69eSdjm 	    FIDO_OPT_TRUE, ms)) != FIDO_OK ||
44832a20e26Sdjm 	    (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK)
449d75efeb7Sdjm 		goto fail;
450d75efeb7Sdjm 
451d75efeb7Sdjm 	r = FIDO_OK;
452d75efeb7Sdjm fail:
453d75efeb7Sdjm 	free(cred.ptr);
454d75efeb7Sdjm 
455d75efeb7Sdjm 	return (r);
456d75efeb7Sdjm }
457d75efeb7Sdjm 
458d75efeb7Sdjm int
fido_credman_del_dev_rk(fido_dev_t * dev,const unsigned char * cred_id,size_t cred_id_len,const char * pin)459d75efeb7Sdjm fido_credman_del_dev_rk(fido_dev_t *dev, const unsigned char *cred_id,
460d75efeb7Sdjm     size_t cred_id_len, const char *pin)
461d75efeb7Sdjm {
462*ab19a69eSdjm 	int ms = dev->timeout_ms;
463*ab19a69eSdjm 
464*ab19a69eSdjm 	return (credman_del_rk_wait(dev, cred_id, cred_id_len, pin, &ms));
465d75efeb7Sdjm }
466d75efeb7Sdjm 
467d75efeb7Sdjm static int
credman_parse_rp(const cbor_item_t * key,const cbor_item_t * val,void * arg)468d75efeb7Sdjm credman_parse_rp(const cbor_item_t *key, const cbor_item_t *val, void *arg)
469d75efeb7Sdjm {
470d75efeb7Sdjm 	struct fido_credman_single_rp *rp = arg;
471d75efeb7Sdjm 
472d75efeb7Sdjm 	if (cbor_isa_uint(key) == false ||
473d75efeb7Sdjm 	    cbor_int_get_width(key) != CBOR_INT_8) {
47432a20e26Sdjm 		fido_log_debug("%s: cbor type", __func__);
475d75efeb7Sdjm 		return (0); /* ignore */
476d75efeb7Sdjm 	}
477d75efeb7Sdjm 
478d75efeb7Sdjm 	switch (cbor_get_uint8(key)) {
479d75efeb7Sdjm 	case 3:
48032a20e26Sdjm 		return (cbor_decode_rp_entity(val, &rp->rp_entity));
481d75efeb7Sdjm 	case 4:
482d75efeb7Sdjm 		return (fido_blob_decode(val, &rp->rp_id_hash));
483d75efeb7Sdjm 	default:
48432a20e26Sdjm 		fido_log_debug("%s: cbor type", __func__);
485d75efeb7Sdjm 		return (0); /* ignore */
486d75efeb7Sdjm 	}
487d75efeb7Sdjm }
488d75efeb7Sdjm 
489d75efeb7Sdjm static void
credman_reset_rp(fido_credman_rp_t * rp)490d75efeb7Sdjm credman_reset_rp(fido_credman_rp_t *rp)
491d75efeb7Sdjm {
492d75efeb7Sdjm 	for (size_t i = 0; i < rp->n_alloc; i++) {
493d75efeb7Sdjm 		free(rp->ptr[i].rp_entity.id);
494d75efeb7Sdjm 		free(rp->ptr[i].rp_entity.name);
495d75efeb7Sdjm 		rp->ptr[i].rp_entity.id = NULL;
496d75efeb7Sdjm 		rp->ptr[i].rp_entity.name = NULL;
497c4a807edSdjm 		fido_blob_reset(&rp->ptr[i].rp_id_hash);
498d75efeb7Sdjm 	}
499d75efeb7Sdjm 
500d75efeb7Sdjm 	free(rp->ptr);
501d75efeb7Sdjm 	rp->ptr = NULL;
502d75efeb7Sdjm 	memset(rp, 0, sizeof(*rp));
503d75efeb7Sdjm }
504d75efeb7Sdjm 
505d75efeb7Sdjm static int
credman_parse_rp_count(const cbor_item_t * key,const cbor_item_t * val,void * arg)506d75efeb7Sdjm credman_parse_rp_count(const cbor_item_t *key, const cbor_item_t *val,
507d75efeb7Sdjm     void *arg)
508d75efeb7Sdjm {
509d75efeb7Sdjm 	fido_credman_rp_t *rp = arg;
510d75efeb7Sdjm 	uint64_t n;
511d75efeb7Sdjm 
512d75efeb7Sdjm 	/* totalRPs */
513d75efeb7Sdjm 	if (cbor_isa_uint(key) == false ||
514d75efeb7Sdjm 	    cbor_int_get_width(key) != CBOR_INT_8 ||
515d75efeb7Sdjm 	    cbor_get_uint8(key) != 5) {
51632a20e26Sdjm 		fido_log_debug("%s: cbor_type", __func__);
517d75efeb7Sdjm 		return (0); /* ignore */
518d75efeb7Sdjm 	}
519d75efeb7Sdjm 
52032a20e26Sdjm 	if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) {
52132a20e26Sdjm 		fido_log_debug("%s: cbor_decode_uint64", __func__);
522d75efeb7Sdjm 		return (-1);
523d75efeb7Sdjm 	}
524d75efeb7Sdjm 
525d75efeb7Sdjm 	if (credman_grow_array((void **)&rp->ptr, &rp->n_alloc, &rp->n_rx,
526d75efeb7Sdjm 	    (size_t)n, sizeof(*rp->ptr)) < 0) {
52732a20e26Sdjm 		fido_log_debug("%s: credman_grow_array", __func__);
528d75efeb7Sdjm 		return (-1);
529d75efeb7Sdjm 	}
530d75efeb7Sdjm 
531d75efeb7Sdjm 	return (0);
532d75efeb7Sdjm }
533d75efeb7Sdjm 
534d75efeb7Sdjm static int
credman_rx_rp(fido_dev_t * dev,fido_credman_rp_t * rp,int * ms)535*ab19a69eSdjm credman_rx_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int *ms)
536d75efeb7Sdjm {
53732a20e26Sdjm 	unsigned char	reply[FIDO_MAXMSG];
538d75efeb7Sdjm 	int		reply_len;
539d75efeb7Sdjm 	int		r;
540d75efeb7Sdjm 
541d75efeb7Sdjm 	credman_reset_rp(rp);
542d75efeb7Sdjm 
54332a20e26Sdjm 	if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
54432a20e26Sdjm 	    ms)) < 0) {
54532a20e26Sdjm 		fido_log_debug("%s: fido_rx", __func__);
546d75efeb7Sdjm 		return (FIDO_ERR_RX);
547d75efeb7Sdjm 	}
548d75efeb7Sdjm 
549d75efeb7Sdjm 	/* adjust as needed */
55032a20e26Sdjm 	if ((r = cbor_parse_reply(reply, (size_t)reply_len, rp,
551d75efeb7Sdjm 	    credman_parse_rp_count)) != FIDO_OK) {
55232a20e26Sdjm 		fido_log_debug("%s: credman_parse_rp_count", __func__);
553d75efeb7Sdjm 		return (r);
554d75efeb7Sdjm 	}
555d75efeb7Sdjm 
556d75efeb7Sdjm 	if (rp->n_alloc == 0) {
55732a20e26Sdjm 		fido_log_debug("%s: n_alloc=0", __func__);
558d75efeb7Sdjm 		return (FIDO_OK);
559d75efeb7Sdjm 	}
560d75efeb7Sdjm 
561d75efeb7Sdjm 	/* parse the first rp */
56232a20e26Sdjm 	if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rp->ptr[0],
563d75efeb7Sdjm 	    credman_parse_rp)) != FIDO_OK) {
56432a20e26Sdjm 		fido_log_debug("%s: credman_parse_rp", __func__);
565d75efeb7Sdjm 		return (r);
566d75efeb7Sdjm 	}
567d75efeb7Sdjm 
568d75efeb7Sdjm 	rp->n_rx++;
569d75efeb7Sdjm 
570d75efeb7Sdjm 	return (FIDO_OK);
571d75efeb7Sdjm }
572d75efeb7Sdjm 
573d75efeb7Sdjm static int
credman_rx_next_rp(fido_dev_t * dev,fido_credman_rp_t * rp,int * ms)574*ab19a69eSdjm credman_rx_next_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int *ms)
575d75efeb7Sdjm {
57632a20e26Sdjm 	unsigned char	reply[FIDO_MAXMSG];
577d75efeb7Sdjm 	int		reply_len;
578d75efeb7Sdjm 	int		r;
579d75efeb7Sdjm 
58032a20e26Sdjm 	if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
58132a20e26Sdjm 	    ms)) < 0) {
58232a20e26Sdjm 		fido_log_debug("%s: fido_rx", __func__);
583d75efeb7Sdjm 		return (FIDO_ERR_RX);
584d75efeb7Sdjm 	}
585d75efeb7Sdjm 
586d75efeb7Sdjm 	/* sanity check */
587d75efeb7Sdjm 	if (rp->n_rx >= rp->n_alloc) {
58832a20e26Sdjm 		fido_log_debug("%s: n_rx=%zu, n_alloc=%zu", __func__, rp->n_rx,
589d75efeb7Sdjm 		    rp->n_alloc);
590d75efeb7Sdjm 		return (FIDO_ERR_INTERNAL);
591d75efeb7Sdjm 	}
592d75efeb7Sdjm 
59332a20e26Sdjm 	if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rp->ptr[rp->n_rx],
594d75efeb7Sdjm 	    credman_parse_rp)) != FIDO_OK) {
59532a20e26Sdjm 		fido_log_debug("%s: credman_parse_rp", __func__);
596d75efeb7Sdjm 		return (r);
597d75efeb7Sdjm 	}
598d75efeb7Sdjm 
599d75efeb7Sdjm 	return (FIDO_OK);
600d75efeb7Sdjm }
601d75efeb7Sdjm 
602d75efeb7Sdjm static int
credman_get_rp_wait(fido_dev_t * dev,fido_credman_rp_t * rp,const char * pin,int * ms)603d75efeb7Sdjm credman_get_rp_wait(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin,
604*ab19a69eSdjm     int *ms)
605d75efeb7Sdjm {
606d75efeb7Sdjm 	int r;
607d75efeb7Sdjm 
608c4a807edSdjm 	if ((r = credman_tx(dev, CMD_RP_BEGIN, NULL, pin, NULL,
609*ab19a69eSdjm 	    FIDO_OPT_TRUE, ms)) != FIDO_OK ||
610d75efeb7Sdjm 	    (r = credman_rx_rp(dev, rp, ms)) != FIDO_OK)
611d75efeb7Sdjm 		return (r);
612d75efeb7Sdjm 
613d75efeb7Sdjm 	while (rp->n_rx < rp->n_alloc) {
614c4a807edSdjm 		if ((r = credman_tx(dev, CMD_RP_NEXT, NULL, NULL, NULL,
615*ab19a69eSdjm 		    FIDO_OPT_FALSE, ms)) != FIDO_OK ||
616d75efeb7Sdjm 		    (r = credman_rx_next_rp(dev, rp, ms)) != FIDO_OK)
617d75efeb7Sdjm 			return (r);
618d75efeb7Sdjm 		rp->n_rx++;
619d75efeb7Sdjm 	}
620d75efeb7Sdjm 
621d75efeb7Sdjm 	return (FIDO_OK);
622d75efeb7Sdjm }
623d75efeb7Sdjm 
624d75efeb7Sdjm int
fido_credman_get_dev_rp(fido_dev_t * dev,fido_credman_rp_t * rp,const char * pin)625d75efeb7Sdjm fido_credman_get_dev_rp(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin)
626d75efeb7Sdjm {
627*ab19a69eSdjm 	int ms = dev->timeout_ms;
628*ab19a69eSdjm 
629*ab19a69eSdjm 	return (credman_get_rp_wait(dev, rp, pin, &ms));
630d75efeb7Sdjm }
631d75efeb7Sdjm 
632c4a807edSdjm static int
credman_set_dev_rk_wait(fido_dev_t * dev,fido_cred_t * cred,const char * pin,int * ms)633c4a807edSdjm credman_set_dev_rk_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
634*ab19a69eSdjm     int *ms)
635c4a807edSdjm {
636c4a807edSdjm 	int r;
637c4a807edSdjm 
638c4a807edSdjm 	if ((r = credman_tx(dev, CMD_UPDATE_CRED, cred, pin, NULL,
639*ab19a69eSdjm 	    FIDO_OPT_TRUE, ms)) != FIDO_OK ||
640c4a807edSdjm 	    (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK)
641c4a807edSdjm 		return (r);
642c4a807edSdjm 
643c4a807edSdjm 	return (FIDO_OK);
644c4a807edSdjm }
645c4a807edSdjm 
646c4a807edSdjm int
fido_credman_set_dev_rk(fido_dev_t * dev,fido_cred_t * cred,const char * pin)647c4a807edSdjm fido_credman_set_dev_rk(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
648c4a807edSdjm {
649*ab19a69eSdjm 	int ms = dev->timeout_ms;
650*ab19a69eSdjm 
651*ab19a69eSdjm 	return (credman_set_dev_rk_wait(dev, cred, pin, &ms));
652c4a807edSdjm }
653c4a807edSdjm 
654d75efeb7Sdjm fido_credman_rk_t *
fido_credman_rk_new(void)655d75efeb7Sdjm fido_credman_rk_new(void)
656d75efeb7Sdjm {
657d75efeb7Sdjm 	return (calloc(1, sizeof(fido_credman_rk_t)));
658d75efeb7Sdjm }
659d75efeb7Sdjm 
660d75efeb7Sdjm void
fido_credman_rk_free(fido_credman_rk_t ** rk_p)661d75efeb7Sdjm fido_credman_rk_free(fido_credman_rk_t **rk_p)
662d75efeb7Sdjm {
663d75efeb7Sdjm 	fido_credman_rk_t *rk;
664d75efeb7Sdjm 
665d75efeb7Sdjm 	if (rk_p == NULL || (rk = *rk_p) == NULL)
666d75efeb7Sdjm 		return;
667d75efeb7Sdjm 
668d75efeb7Sdjm 	credman_reset_rk(rk);
669d75efeb7Sdjm 	free(rk);
670d75efeb7Sdjm 	*rk_p = NULL;
671d75efeb7Sdjm }
672d75efeb7Sdjm 
673d75efeb7Sdjm size_t
fido_credman_rk_count(const fido_credman_rk_t * rk)674d75efeb7Sdjm fido_credman_rk_count(const fido_credman_rk_t *rk)
675d75efeb7Sdjm {
676d75efeb7Sdjm 	return (rk->n_rx);
677d75efeb7Sdjm }
678d75efeb7Sdjm 
679d75efeb7Sdjm const fido_cred_t *
fido_credman_rk(const fido_credman_rk_t * rk,size_t idx)680d75efeb7Sdjm fido_credman_rk(const fido_credman_rk_t *rk, size_t idx)
681d75efeb7Sdjm {
682d75efeb7Sdjm 	if (idx >= rk->n_alloc)
683d75efeb7Sdjm 		return (NULL);
684d75efeb7Sdjm 
685d75efeb7Sdjm 	return (&rk->ptr[idx]);
686d75efeb7Sdjm }
687d75efeb7Sdjm 
688d75efeb7Sdjm fido_credman_metadata_t *
fido_credman_metadata_new(void)689d75efeb7Sdjm fido_credman_metadata_new(void)
690d75efeb7Sdjm {
691d75efeb7Sdjm 	return (calloc(1, sizeof(fido_credman_metadata_t)));
692d75efeb7Sdjm }
693d75efeb7Sdjm 
694d75efeb7Sdjm void
fido_credman_metadata_free(fido_credman_metadata_t ** metadata_p)695d75efeb7Sdjm fido_credman_metadata_free(fido_credman_metadata_t **metadata_p)
696d75efeb7Sdjm {
697d75efeb7Sdjm 	fido_credman_metadata_t *metadata;
698d75efeb7Sdjm 
699d75efeb7Sdjm 	if (metadata_p == NULL || (metadata = *metadata_p) == NULL)
700d75efeb7Sdjm 		return;
701d75efeb7Sdjm 
702d75efeb7Sdjm 	free(metadata);
703d75efeb7Sdjm 	*metadata_p = NULL;
704d75efeb7Sdjm }
705d75efeb7Sdjm 
706d75efeb7Sdjm uint64_t
fido_credman_rk_existing(const fido_credman_metadata_t * metadata)707d75efeb7Sdjm fido_credman_rk_existing(const fido_credman_metadata_t *metadata)
708d75efeb7Sdjm {
709d75efeb7Sdjm 	return (metadata->rk_existing);
710d75efeb7Sdjm }
711d75efeb7Sdjm 
712d75efeb7Sdjm uint64_t
fido_credman_rk_remaining(const fido_credman_metadata_t * metadata)713d75efeb7Sdjm fido_credman_rk_remaining(const fido_credman_metadata_t *metadata)
714d75efeb7Sdjm {
715d75efeb7Sdjm 	return (metadata->rk_remaining);
716d75efeb7Sdjm }
717d75efeb7Sdjm 
718d75efeb7Sdjm fido_credman_rp_t *
fido_credman_rp_new(void)719d75efeb7Sdjm fido_credman_rp_new(void)
720d75efeb7Sdjm {
721d75efeb7Sdjm 	return (calloc(1, sizeof(fido_credman_rp_t)));
722d75efeb7Sdjm }
723d75efeb7Sdjm 
724d75efeb7Sdjm void
fido_credman_rp_free(fido_credman_rp_t ** rp_p)725d75efeb7Sdjm fido_credman_rp_free(fido_credman_rp_t **rp_p)
726d75efeb7Sdjm {
727d75efeb7Sdjm 	fido_credman_rp_t *rp;
728d75efeb7Sdjm 
729d75efeb7Sdjm 	if (rp_p == NULL || (rp = *rp_p) == NULL)
730d75efeb7Sdjm 		return;
731d75efeb7Sdjm 
732d75efeb7Sdjm 	credman_reset_rp(rp);
733d75efeb7Sdjm 	free(rp);
734d75efeb7Sdjm 	*rp_p = NULL;
735d75efeb7Sdjm }
736d75efeb7Sdjm 
737d75efeb7Sdjm size_t
fido_credman_rp_count(const fido_credman_rp_t * rp)738d75efeb7Sdjm fido_credman_rp_count(const fido_credman_rp_t *rp)
739d75efeb7Sdjm {
740d75efeb7Sdjm 	return (rp->n_rx);
741d75efeb7Sdjm }
742d75efeb7Sdjm 
743d75efeb7Sdjm const char *
fido_credman_rp_id(const fido_credman_rp_t * rp,size_t idx)744d75efeb7Sdjm fido_credman_rp_id(const fido_credman_rp_t *rp, size_t idx)
745d75efeb7Sdjm {
746d75efeb7Sdjm 	if (idx >= rp->n_alloc)
747d75efeb7Sdjm 		return (NULL);
748d75efeb7Sdjm 
749d75efeb7Sdjm 	return (rp->ptr[idx].rp_entity.id);
750d75efeb7Sdjm }
751d75efeb7Sdjm 
752d75efeb7Sdjm const char *
fido_credman_rp_name(const fido_credman_rp_t * rp,size_t idx)753d75efeb7Sdjm fido_credman_rp_name(const fido_credman_rp_t *rp, size_t idx)
754d75efeb7Sdjm {
755d75efeb7Sdjm 	if (idx >= rp->n_alloc)
756d75efeb7Sdjm 		return (NULL);
757d75efeb7Sdjm 
758d75efeb7Sdjm 	return (rp->ptr[idx].rp_entity.name);
759d75efeb7Sdjm }
760d75efeb7Sdjm 
761d75efeb7Sdjm size_t
fido_credman_rp_id_hash_len(const fido_credman_rp_t * rp,size_t idx)762d75efeb7Sdjm fido_credman_rp_id_hash_len(const fido_credman_rp_t *rp, size_t idx)
763d75efeb7Sdjm {
764d75efeb7Sdjm 	if (idx >= rp->n_alloc)
765d75efeb7Sdjm 		return (0);
766d75efeb7Sdjm 
767d75efeb7Sdjm 	return (rp->ptr[idx].rp_id_hash.len);
768d75efeb7Sdjm }
769d75efeb7Sdjm 
770d75efeb7Sdjm const unsigned char *
fido_credman_rp_id_hash_ptr(const fido_credman_rp_t * rp,size_t idx)771d75efeb7Sdjm fido_credman_rp_id_hash_ptr(const fido_credman_rp_t *rp, size_t idx)
772d75efeb7Sdjm {
773d75efeb7Sdjm 	if (idx >= rp->n_alloc)
774d75efeb7Sdjm 		return (NULL);
775d75efeb7Sdjm 
776d75efeb7Sdjm 	return (rp->ptr[idx].rp_id_hash.ptr);
777d75efeb7Sdjm }
778