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(¶m_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 } 826