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