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
credman_grow_array(void ** ptr,size_t * n_alloc,size_t * n_rx,size_t n,size_t size)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
credman_prepare_hmac(uint8_t cmd,const void * body,cbor_item_t ** param,fido_blob_t * hmac_data)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(¶m_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
credman_tx(fido_dev_t * dev,uint8_t subcmd,const void * param,const char * pin,const char * rp_id,fido_opt_t uv)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)
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)) != 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])) != 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) < 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
credman_parse_metadata(const cbor_item_t * key,const cbor_item_t * val,void * arg)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
credman_rx_metadata(fido_dev_t * dev,fido_credman_metadata_t * metadata,int ms)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
credman_get_metadata_wait(fido_dev_t * dev,fido_credman_metadata_t * metadata,const char * pin,int ms)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)) != FIDO_OK ||
232 (r = credman_rx_metadata(dev, metadata, ms)) != FIDO_OK)
233 return (r);
234
235 return (FIDO_OK);
236 }
237
238 int
fido_credman_get_dev_metadata(fido_dev_t * dev,fido_credman_metadata_t * metadata,const char * pin)239 fido_credman_get_dev_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata,
240 const char *pin)
241 {
242 return (credman_get_metadata_wait(dev, metadata, pin, -1));
243 }
244
245 static int
credman_parse_rk(const cbor_item_t * key,const cbor_item_t * val,void * arg)246 credman_parse_rk(const cbor_item_t *key, const cbor_item_t *val, void *arg)
247 {
248 fido_cred_t *cred = arg;
249 uint64_t prot;
250
251 if (cbor_isa_uint(key) == false ||
252 cbor_int_get_width(key) != CBOR_INT_8) {
253 fido_log_debug("%s: cbor type", __func__);
254 return (0); /* ignore */
255 }
256
257 switch (cbor_get_uint8(key)) {
258 case 6:
259 return (cbor_decode_user(val, &cred->user));
260 case 7:
261 return (cbor_decode_cred_id(val, &cred->attcred.id));
262 case 8:
263 if (cbor_decode_pubkey(val, &cred->attcred.type,
264 &cred->attcred.pubkey) < 0)
265 return (-1);
266 cred->type = cred->attcred.type; /* XXX */
267 return (0);
268 case 10:
269 if (cbor_decode_uint64(val, &prot) < 0 || prot > INT_MAX ||
270 fido_cred_set_prot(cred, (int)prot) != FIDO_OK)
271 return (-1);
272 return (0);
273 case 11:
274 return (fido_blob_decode(val, &cred->largeblob_key));
275 default:
276 fido_log_debug("%s: cbor type", __func__);
277 return (0); /* ignore */
278 }
279 }
280
281 static void
credman_reset_rk(fido_credman_rk_t * rk)282 credman_reset_rk(fido_credman_rk_t *rk)
283 {
284 for (size_t i = 0; i < rk->n_alloc; i++) {
285 fido_cred_reset_tx(&rk->ptr[i]);
286 fido_cred_reset_rx(&rk->ptr[i]);
287 }
288
289 free(rk->ptr);
290 rk->ptr = NULL;
291 memset(rk, 0, sizeof(*rk));
292 }
293
294 static int
credman_parse_rk_count(const cbor_item_t * key,const cbor_item_t * val,void * arg)295 credman_parse_rk_count(const cbor_item_t *key, const cbor_item_t *val,
296 void *arg)
297 {
298 fido_credman_rk_t *rk = arg;
299 uint64_t n;
300
301 /* totalCredentials */
302 if (cbor_isa_uint(key) == false ||
303 cbor_int_get_width(key) != CBOR_INT_8 ||
304 cbor_get_uint8(key) != 9) {
305 fido_log_debug("%s: cbor_type", __func__);
306 return (0); /* ignore */
307 }
308
309 if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) {
310 fido_log_debug("%s: cbor_decode_uint64", __func__);
311 return (-1);
312 }
313
314 if (credman_grow_array((void **)&rk->ptr, &rk->n_alloc, &rk->n_rx,
315 (size_t)n, sizeof(*rk->ptr)) < 0) {
316 fido_log_debug("%s: credman_grow_array", __func__);
317 return (-1);
318 }
319
320 return (0);
321 }
322
323 static int
credman_rx_rk(fido_dev_t * dev,fido_credman_rk_t * rk,int ms)324 credman_rx_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int ms)
325 {
326 unsigned char reply[FIDO_MAXMSG];
327 int reply_len;
328 int r;
329
330 credman_reset_rk(rk);
331
332 if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
333 ms)) < 0) {
334 fido_log_debug("%s: fido_rx", __func__);
335 return (FIDO_ERR_RX);
336 }
337
338 /* adjust as needed */
339 if ((r = cbor_parse_reply(reply, (size_t)reply_len, rk,
340 credman_parse_rk_count)) != FIDO_OK) {
341 fido_log_debug("%s: credman_parse_rk_count", __func__);
342 return (r);
343 }
344
345 if (rk->n_alloc == 0) {
346 fido_log_debug("%s: n_alloc=0", __func__);
347 return (FIDO_OK);
348 }
349
350 /* parse the first rk */
351 if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rk->ptr[0],
352 credman_parse_rk)) != FIDO_OK) {
353 fido_log_debug("%s: credman_parse_rk", __func__);
354 return (r);
355 }
356
357 rk->n_rx++;
358
359 return (FIDO_OK);
360 }
361
362 static int
credman_rx_next_rk(fido_dev_t * dev,fido_credman_rk_t * rk,int ms)363 credman_rx_next_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int ms)
364 {
365 unsigned char reply[FIDO_MAXMSG];
366 int reply_len;
367 int r;
368
369 if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
370 ms)) < 0) {
371 fido_log_debug("%s: fido_rx", __func__);
372 return (FIDO_ERR_RX);
373 }
374
375 /* sanity check */
376 if (rk->n_rx >= rk->n_alloc) {
377 fido_log_debug("%s: n_rx=%zu, n_alloc=%zu", __func__, rk->n_rx,
378 rk->n_alloc);
379 return (FIDO_ERR_INTERNAL);
380 }
381
382 if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rk->ptr[rk->n_rx],
383 credman_parse_rk)) != FIDO_OK) {
384 fido_log_debug("%s: credman_parse_rk", __func__);
385 return (r);
386 }
387
388 return (FIDO_OK);
389 }
390
391 static int
credman_get_rk_wait(fido_dev_t * dev,const char * rp_id,fido_credman_rk_t * rk,const char * pin,int ms)392 credman_get_rk_wait(fido_dev_t *dev, const char *rp_id, fido_credman_rk_t *rk,
393 const char *pin, int ms)
394 {
395 fido_blob_t rp_dgst;
396 uint8_t dgst[SHA256_DIGEST_LENGTH];
397 int r;
398
399 if (SHA256((const unsigned char *)rp_id, strlen(rp_id), dgst) != dgst) {
400 fido_log_debug("%s: sha256", __func__);
401 return (FIDO_ERR_INTERNAL);
402 }
403
404 rp_dgst.ptr = dgst;
405 rp_dgst.len = sizeof(dgst);
406
407 if ((r = credman_tx(dev, CMD_RK_BEGIN, &rp_dgst, pin, rp_id,
408 FIDO_OPT_TRUE)) != FIDO_OK ||
409 (r = credman_rx_rk(dev, rk, ms)) != FIDO_OK)
410 return (r);
411
412 while (rk->n_rx < rk->n_alloc) {
413 if ((r = credman_tx(dev, CMD_RK_NEXT, NULL, NULL, NULL,
414 FIDO_OPT_FALSE)) != FIDO_OK ||
415 (r = credman_rx_next_rk(dev, rk, ms)) != FIDO_OK)
416 return (r);
417 rk->n_rx++;
418 }
419
420 return (FIDO_OK);
421 }
422
423 int
fido_credman_get_dev_rk(fido_dev_t * dev,const char * rp_id,fido_credman_rk_t * rk,const char * pin)424 fido_credman_get_dev_rk(fido_dev_t *dev, const char *rp_id,
425 fido_credman_rk_t *rk, const char *pin)
426 {
427 return (credman_get_rk_wait(dev, rp_id, rk, pin, -1));
428 }
429
430 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)431 credman_del_rk_wait(fido_dev_t *dev, const unsigned char *cred_id,
432 size_t cred_id_len, const char *pin, int ms)
433 {
434 fido_blob_t cred;
435 int r;
436
437 memset(&cred, 0, sizeof(cred));
438
439 if (fido_blob_set(&cred, cred_id, cred_id_len) < 0)
440 return (FIDO_ERR_INVALID_ARGUMENT);
441
442 if ((r = credman_tx(dev, CMD_DELETE_CRED, &cred, pin, NULL,
443 FIDO_OPT_TRUE)) != FIDO_OK ||
444 (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK)
445 goto fail;
446
447 r = FIDO_OK;
448 fail:
449 free(cred.ptr);
450
451 return (r);
452 }
453
454 int
fido_credman_del_dev_rk(fido_dev_t * dev,const unsigned char * cred_id,size_t cred_id_len,const char * pin)455 fido_credman_del_dev_rk(fido_dev_t *dev, const unsigned char *cred_id,
456 size_t cred_id_len, const char *pin)
457 {
458 return (credman_del_rk_wait(dev, cred_id, cred_id_len, pin, -1));
459 }
460
461 static int
credman_parse_rp(const cbor_item_t * key,const cbor_item_t * val,void * arg)462 credman_parse_rp(const cbor_item_t *key, const cbor_item_t *val, void *arg)
463 {
464 struct fido_credman_single_rp *rp = arg;
465
466 if (cbor_isa_uint(key) == false ||
467 cbor_int_get_width(key) != CBOR_INT_8) {
468 fido_log_debug("%s: cbor type", __func__);
469 return (0); /* ignore */
470 }
471
472 switch (cbor_get_uint8(key)) {
473 case 3:
474 return (cbor_decode_rp_entity(val, &rp->rp_entity));
475 case 4:
476 return (fido_blob_decode(val, &rp->rp_id_hash));
477 default:
478 fido_log_debug("%s: cbor type", __func__);
479 return (0); /* ignore */
480 }
481 }
482
483 static void
credman_reset_rp(fido_credman_rp_t * rp)484 credman_reset_rp(fido_credman_rp_t *rp)
485 {
486 for (size_t i = 0; i < rp->n_alloc; i++) {
487 free(rp->ptr[i].rp_entity.id);
488 free(rp->ptr[i].rp_entity.name);
489 rp->ptr[i].rp_entity.id = NULL;
490 rp->ptr[i].rp_entity.name = NULL;
491 fido_blob_reset(&rp->ptr[i].rp_id_hash);
492 }
493
494 free(rp->ptr);
495 rp->ptr = NULL;
496 memset(rp, 0, sizeof(*rp));
497 }
498
499 static int
credman_parse_rp_count(const cbor_item_t * key,const cbor_item_t * val,void * arg)500 credman_parse_rp_count(const cbor_item_t *key, const cbor_item_t *val,
501 void *arg)
502 {
503 fido_credman_rp_t *rp = arg;
504 uint64_t n;
505
506 /* totalRPs */
507 if (cbor_isa_uint(key) == false ||
508 cbor_int_get_width(key) != CBOR_INT_8 ||
509 cbor_get_uint8(key) != 5) {
510 fido_log_debug("%s: cbor_type", __func__);
511 return (0); /* ignore */
512 }
513
514 if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) {
515 fido_log_debug("%s: cbor_decode_uint64", __func__);
516 return (-1);
517 }
518
519 if (credman_grow_array((void **)&rp->ptr, &rp->n_alloc, &rp->n_rx,
520 (size_t)n, sizeof(*rp->ptr)) < 0) {
521 fido_log_debug("%s: credman_grow_array", __func__);
522 return (-1);
523 }
524
525 return (0);
526 }
527
528 static int
credman_rx_rp(fido_dev_t * dev,fido_credman_rp_t * rp,int ms)529 credman_rx_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int ms)
530 {
531 unsigned char reply[FIDO_MAXMSG];
532 int reply_len;
533 int r;
534
535 credman_reset_rp(rp);
536
537 if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
538 ms)) < 0) {
539 fido_log_debug("%s: fido_rx", __func__);
540 return (FIDO_ERR_RX);
541 }
542
543 /* adjust as needed */
544 if ((r = cbor_parse_reply(reply, (size_t)reply_len, rp,
545 credman_parse_rp_count)) != FIDO_OK) {
546 fido_log_debug("%s: credman_parse_rp_count", __func__);
547 return (r);
548 }
549
550 if (rp->n_alloc == 0) {
551 fido_log_debug("%s: n_alloc=0", __func__);
552 return (FIDO_OK);
553 }
554
555 /* parse the first rp */
556 if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rp->ptr[0],
557 credman_parse_rp)) != FIDO_OK) {
558 fido_log_debug("%s: credman_parse_rp", __func__);
559 return (r);
560 }
561
562 rp->n_rx++;
563
564 return (FIDO_OK);
565 }
566
567 static int
credman_rx_next_rp(fido_dev_t * dev,fido_credman_rp_t * rp,int ms)568 credman_rx_next_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int ms)
569 {
570 unsigned char reply[FIDO_MAXMSG];
571 int reply_len;
572 int r;
573
574 if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply),
575 ms)) < 0) {
576 fido_log_debug("%s: fido_rx", __func__);
577 return (FIDO_ERR_RX);
578 }
579
580 /* sanity check */
581 if (rp->n_rx >= rp->n_alloc) {
582 fido_log_debug("%s: n_rx=%zu, n_alloc=%zu", __func__, rp->n_rx,
583 rp->n_alloc);
584 return (FIDO_ERR_INTERNAL);
585 }
586
587 if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rp->ptr[rp->n_rx],
588 credman_parse_rp)) != FIDO_OK) {
589 fido_log_debug("%s: credman_parse_rp", __func__);
590 return (r);
591 }
592
593 return (FIDO_OK);
594 }
595
596 static int
credman_get_rp_wait(fido_dev_t * dev,fido_credman_rp_t * rp,const char * pin,int ms)597 credman_get_rp_wait(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin,
598 int ms)
599 {
600 int r;
601
602 if ((r = credman_tx(dev, CMD_RP_BEGIN, NULL, pin, NULL,
603 FIDO_OPT_TRUE)) != FIDO_OK ||
604 (r = credman_rx_rp(dev, rp, ms)) != FIDO_OK)
605 return (r);
606
607 while (rp->n_rx < rp->n_alloc) {
608 if ((r = credman_tx(dev, CMD_RP_NEXT, NULL, NULL, NULL,
609 FIDO_OPT_FALSE)) != FIDO_OK ||
610 (r = credman_rx_next_rp(dev, rp, ms)) != FIDO_OK)
611 return (r);
612 rp->n_rx++;
613 }
614
615 return (FIDO_OK);
616 }
617
618 int
fido_credman_get_dev_rp(fido_dev_t * dev,fido_credman_rp_t * rp,const char * pin)619 fido_credman_get_dev_rp(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin)
620 {
621 return (credman_get_rp_wait(dev, rp, pin, -1));
622 }
623
624 static int
credman_set_dev_rk_wait(fido_dev_t * dev,fido_cred_t * cred,const char * pin,int ms)625 credman_set_dev_rk_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin,
626 int ms)
627 {
628 int r;
629
630 if ((r = credman_tx(dev, CMD_UPDATE_CRED, cred, pin, NULL,
631 FIDO_OPT_TRUE)) != FIDO_OK ||
632 (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK)
633 return (r);
634
635 return (FIDO_OK);
636 }
637
638 int
fido_credman_set_dev_rk(fido_dev_t * dev,fido_cred_t * cred,const char * pin)639 fido_credman_set_dev_rk(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
640 {
641 return (credman_set_dev_rk_wait(dev, cred, pin, -1));
642 }
643
644 fido_credman_rk_t *
fido_credman_rk_new(void)645 fido_credman_rk_new(void)
646 {
647 return (calloc(1, sizeof(fido_credman_rk_t)));
648 }
649
650 void
fido_credman_rk_free(fido_credman_rk_t ** rk_p)651 fido_credman_rk_free(fido_credman_rk_t **rk_p)
652 {
653 fido_credman_rk_t *rk;
654
655 if (rk_p == NULL || (rk = *rk_p) == NULL)
656 return;
657
658 credman_reset_rk(rk);
659 free(rk);
660 *rk_p = NULL;
661 }
662
663 size_t
fido_credman_rk_count(const fido_credman_rk_t * rk)664 fido_credman_rk_count(const fido_credman_rk_t *rk)
665 {
666 return (rk->n_rx);
667 }
668
669 const fido_cred_t *
fido_credman_rk(const fido_credman_rk_t * rk,size_t idx)670 fido_credman_rk(const fido_credman_rk_t *rk, size_t idx)
671 {
672 if (idx >= rk->n_alloc)
673 return (NULL);
674
675 return (&rk->ptr[idx]);
676 }
677
678 fido_credman_metadata_t *
fido_credman_metadata_new(void)679 fido_credman_metadata_new(void)
680 {
681 return (calloc(1, sizeof(fido_credman_metadata_t)));
682 }
683
684 void
fido_credman_metadata_free(fido_credman_metadata_t ** metadata_p)685 fido_credman_metadata_free(fido_credman_metadata_t **metadata_p)
686 {
687 fido_credman_metadata_t *metadata;
688
689 if (metadata_p == NULL || (metadata = *metadata_p) == NULL)
690 return;
691
692 free(metadata);
693 *metadata_p = NULL;
694 }
695
696 uint64_t
fido_credman_rk_existing(const fido_credman_metadata_t * metadata)697 fido_credman_rk_existing(const fido_credman_metadata_t *metadata)
698 {
699 return (metadata->rk_existing);
700 }
701
702 uint64_t
fido_credman_rk_remaining(const fido_credman_metadata_t * metadata)703 fido_credman_rk_remaining(const fido_credman_metadata_t *metadata)
704 {
705 return (metadata->rk_remaining);
706 }
707
708 fido_credman_rp_t *
fido_credman_rp_new(void)709 fido_credman_rp_new(void)
710 {
711 return (calloc(1, sizeof(fido_credman_rp_t)));
712 }
713
714 void
fido_credman_rp_free(fido_credman_rp_t ** rp_p)715 fido_credman_rp_free(fido_credman_rp_t **rp_p)
716 {
717 fido_credman_rp_t *rp;
718
719 if (rp_p == NULL || (rp = *rp_p) == NULL)
720 return;
721
722 credman_reset_rp(rp);
723 free(rp);
724 *rp_p = NULL;
725 }
726
727 size_t
fido_credman_rp_count(const fido_credman_rp_t * rp)728 fido_credman_rp_count(const fido_credman_rp_t *rp)
729 {
730 return (rp->n_rx);
731 }
732
733 const char *
fido_credman_rp_id(const fido_credman_rp_t * rp,size_t idx)734 fido_credman_rp_id(const fido_credman_rp_t *rp, size_t idx)
735 {
736 if (idx >= rp->n_alloc)
737 return (NULL);
738
739 return (rp->ptr[idx].rp_entity.id);
740 }
741
742 const char *
fido_credman_rp_name(const fido_credman_rp_t * rp,size_t idx)743 fido_credman_rp_name(const fido_credman_rp_t *rp, size_t idx)
744 {
745 if (idx >= rp->n_alloc)
746 return (NULL);
747
748 return (rp->ptr[idx].rp_entity.name);
749 }
750
751 size_t
fido_credman_rp_id_hash_len(const fido_credman_rp_t * rp,size_t idx)752 fido_credman_rp_id_hash_len(const fido_credman_rp_t *rp, size_t idx)
753 {
754 if (idx >= rp->n_alloc)
755 return (0);
756
757 return (rp->ptr[idx].rp_id_hash.len);
758 }
759
760 const unsigned char *
fido_credman_rp_id_hash_ptr(const fido_credman_rp_t * rp,size_t idx)761 fido_credman_rp_id_hash_ptr(const fido_credman_rp_t *rp, size_t idx)
762 {
763 if (idx >= rp->n_alloc)
764 return (NULL);
765
766 return (rp->ptr[idx].rp_id_hash.ptr);
767 }
768