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