bio.c revision 1.1.1.2
1/* 2 * Copyright (c) 2019 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 "fido.h" 8#include "fido/bio.h" 9#include "fido/es256.h" 10 11#define CMD_ENROLL_BEGIN 0x01 12#define CMD_ENROLL_NEXT 0x02 13#define CMD_ENROLL_CANCEL 0x03 14#define CMD_ENUM 0x04 15#define CMD_SET_NAME 0x05 16#define CMD_ENROLL_REMOVE 0x06 17#define CMD_GET_INFO 0x07 18 19static int 20bio_prepare_hmac(uint8_t cmd, cbor_item_t **argv, size_t argc, 21 cbor_item_t **param, fido_blob_t *hmac_data) 22{ 23 const uint8_t prefix[2] = { 0x01 /* modality */, cmd }; 24 int ok = -1; 25 size_t cbor_alloc_len; 26 size_t cbor_len; 27 unsigned char *cbor = NULL; 28 29 if (argv == NULL || param == NULL) 30 return (fido_blob_set(hmac_data, prefix, sizeof(prefix))); 31 32 if ((*param = cbor_flatten_vector(argv, argc)) == NULL) { 33 fido_log_debug("%s: cbor_flatten_vector", __func__); 34 goto fail; 35 } 36 37 if ((cbor_len = cbor_serialize_alloc(*param, &cbor, 38 &cbor_alloc_len)) == 0 || cbor_len > SIZE_MAX - sizeof(prefix)) { 39 fido_log_debug("%s: cbor_serialize_alloc", __func__); 40 goto fail; 41 } 42 43 if ((hmac_data->ptr = malloc(cbor_len + sizeof(prefix))) == NULL) { 44 fido_log_debug("%s: malloc", __func__); 45 goto fail; 46 } 47 48 memcpy(hmac_data->ptr, prefix, sizeof(prefix)); 49 memcpy(hmac_data->ptr + sizeof(prefix), cbor, cbor_len); 50 hmac_data->len = cbor_len + sizeof(prefix); 51 52 ok = 0; 53fail: 54 free(cbor); 55 56 return (ok); 57} 58 59static int 60bio_tx(fido_dev_t *dev, uint8_t subcmd, cbor_item_t **sub_argv, size_t sub_argc, 61 const char *pin, const fido_blob_t *token) 62{ 63 cbor_item_t *argv[5]; 64 es256_pk_t *pk = NULL; 65 fido_blob_t *ecdh = NULL; 66 fido_blob_t f; 67 fido_blob_t hmac; 68 const uint8_t cmd = CTAP_CBOR_BIO_ENROLL_PRE; 69 int r = FIDO_ERR_INTERNAL; 70 71 memset(&f, 0, sizeof(f)); 72 memset(&hmac, 0, sizeof(hmac)); 73 memset(&argv, 0, sizeof(argv)); 74 75 /* modality, subCommand */ 76 if ((argv[0] = cbor_build_uint8(1)) == NULL || 77 (argv[1] = cbor_build_uint8(subcmd)) == NULL) { 78 fido_log_debug("%s: cbor encode", __func__); 79 goto fail; 80 } 81 82 /* subParams */ 83 if (pin || token) { 84 if (bio_prepare_hmac(subcmd, sub_argv, sub_argc, &argv[2], 85 &hmac) < 0) { 86 fido_log_debug("%s: bio_prepare_hmac", __func__); 87 goto fail; 88 } 89 } 90 91 /* pinProtocol, pinAuth */ 92 if (pin) { 93 if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { 94 fido_log_debug("%s: fido_do_ecdh", __func__); 95 goto fail; 96 } 97 if ((r = cbor_add_uv_params(dev, cmd, &hmac, pk, ecdh, pin, 98 NULL, &argv[4], &argv[3])) != FIDO_OK) { 99 fido_log_debug("%s: cbor_add_uv_params", __func__); 100 goto fail; 101 } 102 } else if (token) { 103 if ((argv[3] = cbor_encode_pin_opt(dev)) == NULL || 104 (argv[4] = cbor_encode_pin_auth(dev, token, &hmac)) == NULL) { 105 fido_log_debug("%s: encode pin", __func__); 106 goto fail; 107 } 108 } 109 110 /* framing and transmission */ 111 if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 || 112 fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) { 113 fido_log_debug("%s: fido_tx", __func__); 114 r = FIDO_ERR_TX; 115 goto fail; 116 } 117 118 r = FIDO_OK; 119fail: 120 cbor_vector_free(argv, nitems(argv)); 121 es256_pk_free(&pk); 122 fido_blob_free(&ecdh); 123 free(f.ptr); 124 free(hmac.ptr); 125 126 return (r); 127} 128 129static void 130bio_reset_template(fido_bio_template_t *t) 131{ 132 free(t->name); 133 free(t->id.ptr); 134 t->name = NULL; 135 memset(&t->id, 0, sizeof(t->id)); 136} 137 138static void 139bio_reset_template_array(fido_bio_template_array_t *ta) 140{ 141 for (size_t i = 0; i < ta->n_alloc; i++) 142 bio_reset_template(&ta->ptr[i]); 143 144 free(ta->ptr); 145 ta->ptr = NULL; 146 memset(ta, 0, sizeof(*ta)); 147} 148 149static int 150decode_template(const cbor_item_t *key, const cbor_item_t *val, void *arg) 151{ 152 fido_bio_template_t *t = arg; 153 154 if (cbor_isa_uint(key) == false || 155 cbor_int_get_width(key) != CBOR_INT_8) { 156 fido_log_debug("%s: cbor type", __func__); 157 return (0); /* ignore */ 158 } 159 160 switch (cbor_get_uint8(key)) { 161 case 1: /* id */ 162 return (fido_blob_decode(val, &t->id)); 163 case 2: /* name */ 164 return (cbor_string_copy(val, &t->name)); 165 } 166 167 return (0); /* ignore */ 168} 169 170static int 171decode_template_array(const cbor_item_t *item, void *arg) 172{ 173 fido_bio_template_array_t *ta = arg; 174 175 if (cbor_isa_map(item) == false || 176 cbor_map_is_definite(item) == false) { 177 fido_log_debug("%s: cbor type", __func__); 178 return (-1); 179 } 180 181 if (ta->n_rx >= ta->n_alloc) { 182 fido_log_debug("%s: n_rx >= n_alloc", __func__); 183 return (-1); 184 } 185 186 if (cbor_map_iter(item, &ta->ptr[ta->n_rx], decode_template) < 0) { 187 fido_log_debug("%s: decode_template", __func__); 188 return (-1); 189 } 190 191 ta->n_rx++; 192 193 return (0); 194} 195 196static int 197bio_parse_template_array(const cbor_item_t *key, const cbor_item_t *val, 198 void *arg) 199{ 200 fido_bio_template_array_t *ta = arg; 201 202 if (cbor_isa_uint(key) == false || 203 cbor_int_get_width(key) != CBOR_INT_8 || 204 cbor_get_uint8(key) != 7) { 205 fido_log_debug("%s: cbor type", __func__); 206 return (0); /* ignore */ 207 } 208 209 if (cbor_isa_array(val) == false || 210 cbor_array_is_definite(val) == false) { 211 fido_log_debug("%s: cbor type", __func__); 212 return (-1); 213 } 214 215 if (ta->ptr != NULL || ta->n_alloc != 0 || ta->n_rx != 0) { 216 fido_log_debug("%s: ptr != NULL || n_alloc != 0 || n_rx != 0", 217 __func__); 218 return (-1); 219 } 220 221 if ((ta->ptr = calloc(cbor_array_size(val), sizeof(*ta->ptr))) == NULL) 222 return (-1); 223 224 ta->n_alloc = cbor_array_size(val); 225 226 if (cbor_array_iter(val, ta, decode_template_array) < 0) { 227 fido_log_debug("%s: decode_template_array", __func__); 228 return (-1); 229 } 230 231 return (0); 232} 233 234static int 235bio_rx_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta, int ms) 236{ 237 unsigned char reply[FIDO_MAXMSG]; 238 int reply_len; 239 int r; 240 241 bio_reset_template_array(ta); 242 243 if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), 244 ms)) < 0) { 245 fido_log_debug("%s: fido_rx", __func__); 246 return (FIDO_ERR_RX); 247 } 248 249 if ((r = cbor_parse_reply(reply, (size_t)reply_len, ta, 250 bio_parse_template_array)) != FIDO_OK) { 251 fido_log_debug("%s: bio_parse_template_array" , __func__); 252 return (r); 253 } 254 255 return (FIDO_OK); 256} 257 258static int 259bio_get_template_array_wait(fido_dev_t *dev, fido_bio_template_array_t *ta, 260 const char *pin, int ms) 261{ 262 int r; 263 264 if ((r = bio_tx(dev, CMD_ENUM, NULL, 0, pin, NULL)) != FIDO_OK || 265 (r = bio_rx_template_array(dev, ta, ms)) != FIDO_OK) 266 return (r); 267 268 return (FIDO_OK); 269} 270 271int 272fido_bio_dev_get_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta, 273 const char *pin) 274{ 275 if (pin == NULL) 276 return (FIDO_ERR_INVALID_ARGUMENT); 277 278 return (bio_get_template_array_wait(dev, ta, pin, -1)); 279} 280 281static int 282bio_set_template_name_wait(fido_dev_t *dev, const fido_bio_template_t *t, 283 const char *pin, int ms) 284{ 285 cbor_item_t *argv[2]; 286 int r = FIDO_ERR_INTERNAL; 287 288 memset(&argv, 0, sizeof(argv)); 289 290 if ((argv[0] = fido_blob_encode(&t->id)) == NULL || 291 (argv[1] = cbor_build_string(t->name)) == NULL) { 292 fido_log_debug("%s: cbor encode", __func__); 293 goto fail; 294 } 295 296 if ((r = bio_tx(dev, CMD_SET_NAME, argv, 2, pin, NULL)) != FIDO_OK || 297 (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) { 298 fido_log_debug("%s: tx/rx", __func__); 299 goto fail; 300 } 301 302 r = FIDO_OK; 303fail: 304 cbor_vector_free(argv, nitems(argv)); 305 306 return (r); 307} 308 309int 310fido_bio_dev_set_template_name(fido_dev_t *dev, const fido_bio_template_t *t, 311 const char *pin) 312{ 313 if (pin == NULL || t->name == NULL) 314 return (FIDO_ERR_INVALID_ARGUMENT); 315 316 return (bio_set_template_name_wait(dev, t, pin, -1)); 317} 318 319static void 320bio_reset_enroll(fido_bio_enroll_t *e) 321{ 322 e->remaining_samples = 0; 323 e->last_status = 0; 324 325 if (e->token) 326 fido_blob_free(&e->token); 327} 328 329static int 330bio_parse_enroll_status(const cbor_item_t *key, const cbor_item_t *val, 331 void *arg) 332{ 333 fido_bio_enroll_t *e = arg; 334 uint64_t x; 335 336 if (cbor_isa_uint(key) == false || 337 cbor_int_get_width(key) != CBOR_INT_8) { 338 fido_log_debug("%s: cbor type", __func__); 339 return (0); /* ignore */ 340 } 341 342 switch (cbor_get_uint8(key)) { 343 case 5: 344 if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) { 345 fido_log_debug("%s: cbor_decode_uint64", __func__); 346 return (-1); 347 } 348 e->last_status = (uint8_t)x; 349 break; 350 case 6: 351 if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) { 352 fido_log_debug("%s: cbor_decode_uint64", __func__); 353 return (-1); 354 } 355 e->remaining_samples = (uint8_t)x; 356 break; 357 default: 358 return (0); /* ignore */ 359 } 360 361 return (0); 362} 363 364static int 365bio_parse_template_id(const cbor_item_t *key, const cbor_item_t *val, 366 void *arg) 367{ 368 fido_blob_t *id = arg; 369 370 if (cbor_isa_uint(key) == false || 371 cbor_int_get_width(key) != CBOR_INT_8 || 372 cbor_get_uint8(key) != 4) { 373 fido_log_debug("%s: cbor type", __func__); 374 return (0); /* ignore */ 375 } 376 377 return (fido_blob_decode(val, id)); 378} 379 380static int 381bio_rx_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t, 382 fido_bio_enroll_t *e, int ms) 383{ 384 unsigned char reply[FIDO_MAXMSG]; 385 int reply_len; 386 int r; 387 388 bio_reset_template(t); 389 390 e->remaining_samples = 0; 391 e->last_status = 0; 392 393 if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), 394 ms)) < 0) { 395 fido_log_debug("%s: fido_rx", __func__); 396 return (FIDO_ERR_RX); 397 } 398 399 if ((r = cbor_parse_reply(reply, (size_t)reply_len, e, 400 bio_parse_enroll_status)) != FIDO_OK) { 401 fido_log_debug("%s: bio_parse_enroll_status", __func__); 402 return (r); 403 } 404 if ((r = cbor_parse_reply(reply, (size_t)reply_len, &t->id, 405 bio_parse_template_id)) != FIDO_OK) { 406 fido_log_debug("%s: bio_parse_template_id", __func__); 407 return (r); 408 } 409 410 return (FIDO_OK); 411} 412 413static int 414bio_enroll_begin_wait(fido_dev_t *dev, fido_bio_template_t *t, 415 fido_bio_enroll_t *e, uint32_t timo_ms, int ms) 416{ 417 cbor_item_t *argv[3]; 418 const uint8_t cmd = CMD_ENROLL_BEGIN; 419 int r = FIDO_ERR_INTERNAL; 420 421 memset(&argv, 0, sizeof(argv)); 422 423 if ((argv[2] = cbor_build_uint32(timo_ms)) == NULL) { 424 fido_log_debug("%s: cbor encode", __func__); 425 goto fail; 426 } 427 428 if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token)) != FIDO_OK || 429 (r = bio_rx_enroll_begin(dev, t, e, ms)) != FIDO_OK) { 430 fido_log_debug("%s: tx/rx", __func__); 431 goto fail; 432 } 433 434 r = FIDO_OK; 435fail: 436 cbor_vector_free(argv, nitems(argv)); 437 438 return (r); 439} 440 441int 442fido_bio_dev_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t, 443 fido_bio_enroll_t *e, uint32_t timo_ms, const char *pin) 444{ 445 es256_pk_t *pk = NULL; 446 fido_blob_t *ecdh = NULL; 447 fido_blob_t *token = NULL; 448 int r; 449 450 if (pin == NULL || e->token != NULL) 451 return (FIDO_ERR_INVALID_ARGUMENT); 452 453 if ((token = fido_blob_new()) == NULL) { 454 r = FIDO_ERR_INTERNAL; 455 goto fail; 456 } 457 458 if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) { 459 fido_log_debug("%s: fido_do_ecdh", __func__); 460 goto fail; 461 } 462 463 if ((r = fido_dev_get_uv_token(dev, CTAP_CBOR_BIO_ENROLL_PRE, pin, ecdh, 464 pk, NULL, token)) != FIDO_OK) { 465 fido_log_debug("%s: fido_dev_get_uv_token", __func__); 466 goto fail; 467 } 468 469 e->token = token; 470 token = NULL; 471fail: 472 es256_pk_free(&pk); 473 fido_blob_free(&ecdh); 474 fido_blob_free(&token); 475 476 if (r != FIDO_OK) 477 return (r); 478 479 return (bio_enroll_begin_wait(dev, t, e, timo_ms, -1)); 480} 481 482static int 483bio_rx_enroll_continue(fido_dev_t *dev, fido_bio_enroll_t *e, int ms) 484{ 485 unsigned char reply[FIDO_MAXMSG]; 486 int reply_len; 487 int r; 488 489 e->remaining_samples = 0; 490 e->last_status = 0; 491 492 if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), 493 ms)) < 0) { 494 fido_log_debug("%s: fido_rx", __func__); 495 return (FIDO_ERR_RX); 496 } 497 498 if ((r = cbor_parse_reply(reply, (size_t)reply_len, e, 499 bio_parse_enroll_status)) != FIDO_OK) { 500 fido_log_debug("%s: bio_parse_enroll_status", __func__); 501 return (r); 502 } 503 504 return (FIDO_OK); 505} 506 507static int 508bio_enroll_continue_wait(fido_dev_t *dev, const fido_bio_template_t *t, 509 fido_bio_enroll_t *e, uint32_t timo_ms, int ms) 510{ 511 cbor_item_t *argv[3]; 512 const uint8_t cmd = CMD_ENROLL_NEXT; 513 int r = FIDO_ERR_INTERNAL; 514 515 memset(&argv, 0, sizeof(argv)); 516 517 if ((argv[0] = fido_blob_encode(&t->id)) == NULL || 518 (argv[2] = cbor_build_uint32(timo_ms)) == NULL) { 519 fido_log_debug("%s: cbor encode", __func__); 520 goto fail; 521 } 522 523 if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token)) != FIDO_OK || 524 (r = bio_rx_enroll_continue(dev, e, ms)) != FIDO_OK) { 525 fido_log_debug("%s: tx/rx", __func__); 526 goto fail; 527 } 528 529 r = FIDO_OK; 530fail: 531 cbor_vector_free(argv, nitems(argv)); 532 533 return (r); 534} 535 536int 537fido_bio_dev_enroll_continue(fido_dev_t *dev, const fido_bio_template_t *t, 538 fido_bio_enroll_t *e, uint32_t timo_ms) 539{ 540 if (e->token == NULL) 541 return (FIDO_ERR_INVALID_ARGUMENT); 542 543 return (bio_enroll_continue_wait(dev, t, e, timo_ms, -1)); 544} 545 546static int 547bio_enroll_cancel_wait(fido_dev_t *dev, int ms) 548{ 549 const uint8_t cmd = CMD_ENROLL_CANCEL; 550 int r; 551 552 if ((r = bio_tx(dev, cmd, NULL, 0, NULL, NULL)) != FIDO_OK || 553 (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) { 554 fido_log_debug("%s: tx/rx", __func__); 555 return (r); 556 } 557 558 return (FIDO_OK); 559} 560 561int 562fido_bio_dev_enroll_cancel(fido_dev_t *dev) 563{ 564 return (bio_enroll_cancel_wait(dev, -1)); 565} 566 567static int 568bio_enroll_remove_wait(fido_dev_t *dev, const fido_bio_template_t *t, 569 const char *pin, int ms) 570{ 571 cbor_item_t *argv[1]; 572 const uint8_t cmd = CMD_ENROLL_REMOVE; 573 int r = FIDO_ERR_INTERNAL; 574 575 memset(&argv, 0, sizeof(argv)); 576 577 if ((argv[0] = fido_blob_encode(&t->id)) == NULL) { 578 fido_log_debug("%s: cbor encode", __func__); 579 goto fail; 580 } 581 582 if ((r = bio_tx(dev, cmd, argv, 1, pin, NULL)) != FIDO_OK || 583 (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) { 584 fido_log_debug("%s: tx/rx", __func__); 585 goto fail; 586 } 587 588 r = FIDO_OK; 589fail: 590 cbor_vector_free(argv, nitems(argv)); 591 592 return (r); 593} 594 595int 596fido_bio_dev_enroll_remove(fido_dev_t *dev, const fido_bio_template_t *t, 597 const char *pin) 598{ 599 return (bio_enroll_remove_wait(dev, t, pin, -1)); 600} 601 602static void 603bio_reset_info(fido_bio_info_t *i) 604{ 605 i->type = 0; 606 i->max_samples = 0; 607} 608 609static int 610bio_parse_info(const cbor_item_t *key, const cbor_item_t *val, void *arg) 611{ 612 fido_bio_info_t *i = arg; 613 uint64_t x; 614 615 if (cbor_isa_uint(key) == false || 616 cbor_int_get_width(key) != CBOR_INT_8) { 617 fido_log_debug("%s: cbor type", __func__); 618 return (0); /* ignore */ 619 } 620 621 switch (cbor_get_uint8(key)) { 622 case 2: 623 if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) { 624 fido_log_debug("%s: cbor_decode_uint64", __func__); 625 return (-1); 626 } 627 i->type = (uint8_t)x; 628 break; 629 case 3: 630 if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) { 631 fido_log_debug("%s: cbor_decode_uint64", __func__); 632 return (-1); 633 } 634 i->max_samples = (uint8_t)x; 635 break; 636 default: 637 return (0); /* ignore */ 638 } 639 640 return (0); 641} 642 643static int 644bio_rx_info(fido_dev_t *dev, fido_bio_info_t *i, int ms) 645{ 646 unsigned char reply[FIDO_MAXMSG]; 647 int reply_len; 648 int r; 649 650 bio_reset_info(i); 651 652 if ((reply_len = fido_rx(dev, CTAP_CMD_CBOR, &reply, sizeof(reply), 653 ms)) < 0) { 654 fido_log_debug("%s: fido_rx", __func__); 655 return (FIDO_ERR_RX); 656 } 657 658 if ((r = cbor_parse_reply(reply, (size_t)reply_len, i, 659 bio_parse_info)) != FIDO_OK) { 660 fido_log_debug("%s: bio_parse_info" , __func__); 661 return (r); 662 } 663 664 return (FIDO_OK); 665} 666 667static int 668bio_get_info_wait(fido_dev_t *dev, fido_bio_info_t *i, int ms) 669{ 670 int r; 671 672 if ((r = bio_tx(dev, CMD_GET_INFO, NULL, 0, NULL, NULL)) != FIDO_OK || 673 (r = bio_rx_info(dev, i, ms)) != FIDO_OK) { 674 fido_log_debug("%s: tx/rx", __func__); 675 return (r); 676 } 677 678 return (FIDO_OK); 679} 680 681int 682fido_bio_dev_get_info(fido_dev_t *dev, fido_bio_info_t *i) 683{ 684 return (bio_get_info_wait(dev, i, -1)); 685} 686 687const char * 688fido_bio_template_name(const fido_bio_template_t *t) 689{ 690 return (t->name); 691} 692 693const unsigned char * 694fido_bio_template_id_ptr(const fido_bio_template_t *t) 695{ 696 return (t->id.ptr); 697} 698 699size_t 700fido_bio_template_id_len(const fido_bio_template_t *t) 701{ 702 return (t->id.len); 703} 704 705size_t 706fido_bio_template_array_count(const fido_bio_template_array_t *ta) 707{ 708 return (ta->n_rx); 709} 710 711fido_bio_template_array_t * 712fido_bio_template_array_new(void) 713{ 714 return (calloc(1, sizeof(fido_bio_template_array_t))); 715} 716 717fido_bio_template_t * 718fido_bio_template_new(void) 719{ 720 return (calloc(1, sizeof(fido_bio_template_t))); 721} 722 723void 724fido_bio_template_array_free(fido_bio_template_array_t **tap) 725{ 726 fido_bio_template_array_t *ta; 727 728 if (tap == NULL || (ta = *tap) == NULL) 729 return; 730 731 bio_reset_template_array(ta); 732 free(ta); 733 *tap = NULL; 734} 735 736void 737fido_bio_template_free(fido_bio_template_t **tp) 738{ 739 fido_bio_template_t *t; 740 741 if (tp == NULL || (t = *tp) == NULL) 742 return; 743 744 bio_reset_template(t); 745 free(t); 746 *tp = NULL; 747} 748 749int 750fido_bio_template_set_name(fido_bio_template_t *t, const char *name) 751{ 752 free(t->name); 753 t->name = NULL; 754 755 if (name && (t->name = strdup(name)) == NULL) 756 return (FIDO_ERR_INTERNAL); 757 758 return (FIDO_OK); 759} 760 761int 762fido_bio_template_set_id(fido_bio_template_t *t, const unsigned char *ptr, 763 size_t len) 764{ 765 free(t->id.ptr); 766 t->id.ptr = NULL; 767 t->id.len = 0; 768 769 if (ptr && fido_blob_set(&t->id, ptr, len) < 0) 770 return (FIDO_ERR_INTERNAL); 771 772 return (FIDO_OK); 773} 774 775const fido_bio_template_t * 776fido_bio_template(const fido_bio_template_array_t *ta, size_t idx) 777{ 778 if (idx >= ta->n_alloc) 779 return (NULL); 780 781 return (&ta->ptr[idx]); 782} 783 784fido_bio_enroll_t * 785fido_bio_enroll_new(void) 786{ 787 return (calloc(1, sizeof(fido_bio_enroll_t))); 788} 789 790fido_bio_info_t * 791fido_bio_info_new(void) 792{ 793 return (calloc(1, sizeof(fido_bio_info_t))); 794} 795 796uint8_t 797fido_bio_info_type(const fido_bio_info_t *i) 798{ 799 return (i->type); 800} 801 802uint8_t 803fido_bio_info_max_samples(const fido_bio_info_t *i) 804{ 805 return (i->max_samples); 806} 807 808void 809fido_bio_enroll_free(fido_bio_enroll_t **ep) 810{ 811 fido_bio_enroll_t *e; 812 813 if (ep == NULL || (e = *ep) == NULL) 814 return; 815 816 bio_reset_enroll(e); 817 818 free(e); 819 *ep = NULL; 820} 821 822void 823fido_bio_info_free(fido_bio_info_t **ip) 824{ 825 fido_bio_info_t *i; 826 827 if (ip == NULL || (i = *ip) == NULL) 828 return; 829 830 free(i); 831 *ip = NULL; 832} 833 834uint8_t 835fido_bio_enroll_remaining_samples(const fido_bio_enroll_t *e) 836{ 837 return (e->remaining_samples); 838} 839 840uint8_t 841fido_bio_enroll_last_status(const fido_bio_enroll_t *e) 842{ 843 return (e->last_status); 844} 845