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