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