summaryrefslogtreecommitdiff
path: root/src/bio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/bio.c')
-rw-r--r--src/bio.c844
1 files changed, 844 insertions, 0 deletions
diff --git a/src/bio.c b/src/bio.c
new file mode 100644
index 0000000..74814b9
--- /dev/null
+++ b/src/bio.c
@@ -0,0 +1,844 @@
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 <string.h>
8
9#include "fido.h"
10#include "fido/bio.h"
11#include "fido/es256.h"
12
13#define CMD_ENROLL_BEGIN 0x01
14#define CMD_ENROLL_NEXT 0x02
15#define CMD_ENROLL_CANCEL 0x03
16#define CMD_ENUM 0x04
17#define CMD_SET_NAME 0x05
18#define CMD_ENROLL_REMOVE 0x06
19#define CMD_GET_INFO 0x07
20
21static int
22bio_prepare_hmac(uint8_t cmd, cbor_item_t **argv, size_t argc,
23 cbor_item_t **param, fido_blob_t *hmac_data)
24{
25 const uint8_t prefix[2] = { 0x01 /* modality */, cmd };
26 int ok = -1;
27 size_t cbor_alloc_len;
28 size_t cbor_len;
29 unsigned char *cbor = NULL;
30
31 if (argv == NULL || param == NULL)
32 return (fido_blob_set(hmac_data, prefix, sizeof(prefix)));
33
34 if ((*param = cbor_flatten_vector(argv, argc)) == NULL) {
35 fido_log_debug("%s: cbor_flatten_vector", __func__);
36 goto fail;
37 }
38
39 if ((cbor_len = cbor_serialize_alloc(*param, &cbor,
40 &cbor_alloc_len)) == 0 || cbor_len > SIZE_MAX - sizeof(prefix)) {
41 fido_log_debug("%s: cbor_serialize_alloc", __func__);
42 goto fail;
43 }
44
45 if ((hmac_data->ptr = malloc(cbor_len + sizeof(prefix))) == NULL) {
46 fido_log_debug("%s: malloc", __func__);
47 goto fail;
48 }
49
50 memcpy(hmac_data->ptr, prefix, sizeof(prefix));
51 memcpy(hmac_data->ptr + sizeof(prefix), cbor, cbor_len);
52 hmac_data->len = cbor_len + sizeof(prefix);
53
54 ok = 0;
55fail:
56 free(cbor);
57
58 return (ok);
59}
60
61static int
62bio_tx(fido_dev_t *dev, uint8_t cmd, cbor_item_t **sub_argv, size_t sub_argc,
63 const char *pin, const fido_blob_t *token)
64{
65 cbor_item_t *argv[5];
66 es256_pk_t *pk = NULL;
67 fido_blob_t *ecdh = NULL;
68 fido_blob_t f;
69 fido_blob_t hmac;
70 int r = FIDO_ERR_INTERNAL;
71
72 memset(&f, 0, sizeof(f));
73 memset(&hmac, 0, sizeof(hmac));
74 memset(&argv, 0, sizeof(argv));
75
76 /* modality, subCommand */
77 if ((argv[0] = cbor_build_uint8(1)) == NULL ||
78 (argv[1] = cbor_build_uint8(cmd)) == NULL) {
79 fido_log_debug("%s: cbor encode", __func__);
80 goto fail;
81 }
82
83 /* subParams */
84 if (pin || token) {
85 if (bio_prepare_hmac(cmd, sub_argv, sub_argc, &argv[2],
86 &hmac) < 0) {
87 fido_log_debug("%s: bio_prepare_hmac", __func__);
88 goto fail;
89 }
90 }
91
92 /* pinProtocol, pinAuth */
93 if (pin) {
94 if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
95 fido_log_debug("%s: fido_do_ecdh", __func__);
96 goto fail;
97 }
98 if ((r = cbor_add_pin_params(dev, &hmac, pk, ecdh, pin,
99 &argv[4], &argv[3])) != FIDO_OK) {
100 fido_log_debug("%s: cbor_add_pin_params", __func__);
101 goto fail;
102 }
103 } else if (token) {
104 if ((argv[3] = cbor_encode_pin_opt()) == NULL ||
105 (argv[4] = cbor_encode_pin_auth(token, &hmac)) == NULL) {
106 fido_log_debug("%s: encode pin", __func__);
107 goto fail;
108 }
109 }
110
111 /* framing and transmission */
112 if (cbor_build_frame(CTAP_CBOR_BIO_ENROLL_PRE, argv, 5, &f) < 0 ||
113 fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
114 fido_log_debug("%s: fido_tx", __func__);
115 r = FIDO_ERR_TX;
116 goto fail;
117 }
118
119 r = FIDO_OK;
120fail:
121 cbor_vector_free(argv, nitems(argv));
122 es256_pk_free(&pk);
123 fido_blob_free(&ecdh);
124 free(f.ptr);
125 free(hmac.ptr);
126
127 return (r);
128}
129
130static void
131bio_reset_template(fido_bio_template_t *t)
132{
133 free(t->name);
134 free(t->id.ptr);
135 t->name = NULL;
136 memset(&t->id, 0, sizeof(t->id));
137}
138
139static void
140bio_reset_template_array(fido_bio_template_array_t *ta)
141{
142 for (size_t i = 0; i < ta->n_alloc; i++)
143 bio_reset_template(&ta->ptr[i]);
144
145 free(ta->ptr);
146 ta->ptr = NULL;
147 memset(ta, 0, sizeof(*ta));
148}
149
150static int
151decode_template(const cbor_item_t *key, const cbor_item_t *val, void *arg)
152{
153 fido_bio_template_t *t = arg;
154
155 if (cbor_isa_uint(key) == false ||
156 cbor_int_get_width(key) != CBOR_INT_8) {
157 fido_log_debug("%s: cbor type", __func__);
158 return (0); /* ignore */
159 }
160
161 switch (cbor_get_uint8(key)) {
162 case 1: /* id */
163 return (fido_blob_decode(val, &t->id));
164 case 2: /* name */
165 return (cbor_string_copy(val, &t->name));
166 }
167
168 return (0); /* ignore */
169}
170
171static int
172decode_template_array(const cbor_item_t *item, void *arg)
173{
174 fido_bio_template_array_t *ta = arg;
175
176 if (cbor_isa_map(item) == false ||
177 cbor_map_is_definite(item) == false) {
178 fido_log_debug("%s: cbor type", __func__);
179 return (-1);
180 }
181
182 if (ta->n_rx >= ta->n_alloc) {
183 fido_log_debug("%s: n_rx >= n_alloc", __func__);
184 return (-1);
185 }
186
187 if (cbor_map_iter(item, &ta->ptr[ta->n_rx], decode_template) < 0) {
188 fido_log_debug("%s: decode_template", __func__);
189 return (-1);
190 }
191
192 ta->n_rx++;
193
194 return (0);
195}
196
197static int
198bio_parse_template_array(const cbor_item_t *key, const cbor_item_t *val,
199 void *arg)
200{
201 fido_bio_template_array_t *ta = arg;
202
203 if (cbor_isa_uint(key) == false ||
204 cbor_int_get_width(key) != CBOR_INT_8 ||
205 cbor_get_uint8(key) != 7) {
206 fido_log_debug("%s: cbor type", __func__);
207 return (0); /* ignore */
208 }
209
210 if (cbor_isa_array(val) == false ||
211 cbor_array_is_definite(val) == false) {
212 fido_log_debug("%s: cbor type", __func__);
213 return (-1);
214 }
215
216 if (ta->ptr != NULL || ta->n_alloc != 0 || ta->n_rx != 0) {
217 fido_log_debug("%s: ptr != NULL || n_alloc != 0 || n_rx != 0",
218 __func__);
219 return (-1);
220 }
221
222 if ((ta->ptr = calloc(cbor_array_size(val), sizeof(*ta->ptr))) == NULL)
223 return (-1);
224
225 ta->n_alloc = cbor_array_size(val);
226
227 if (cbor_array_iter(val, ta, decode_template_array) < 0) {
228 fido_log_debug("%s: decode_template_array", __func__);
229 return (-1);
230 }
231
232 return (0);
233}
234
235static int
236bio_rx_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta, int ms)
237{
238 const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
239 unsigned char reply[2048];
240 int reply_len;
241 int r;
242
243 bio_reset_template_array(ta);
244
245 if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) {
246 fido_log_debug("%s: fido_rx", __func__);
247 return (FIDO_ERR_RX);
248 }
249
250 if ((r = cbor_parse_reply(reply, (size_t)reply_len, ta,
251 bio_parse_template_array)) != FIDO_OK) {
252 fido_log_debug("%s: bio_parse_template_array" , __func__);
253 return (r);
254 }
255
256 return (FIDO_OK);
257}
258
259static int
260bio_get_template_array_wait(fido_dev_t *dev, fido_bio_template_array_t *ta,
261 const char *pin, int ms)
262{
263 int r;
264
265 if ((r = bio_tx(dev, CMD_ENUM, NULL, 0, pin, NULL)) != FIDO_OK ||
266 (r = bio_rx_template_array(dev, ta, ms)) != FIDO_OK)
267 return (r);
268
269 return (FIDO_OK);
270}
271
272int
273fido_bio_dev_get_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta,
274 const char *pin)
275{
276 if (pin == NULL)
277 return (FIDO_ERR_INVALID_ARGUMENT);
278
279 return (bio_get_template_array_wait(dev, ta, pin, -1));
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)) != FIDO_OK ||
298 (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
299 fido_log_debug("%s: tx/rx", __func__);
300 goto fail;
301 }
302
303 r = FIDO_OK;
304fail:
305 cbor_vector_free(argv, nitems(argv));
306
307 return (r);
308}
309
310int
311fido_bio_dev_set_template_name(fido_dev_t *dev, const fido_bio_template_t *t,
312 const char *pin)
313{
314 if (pin == NULL || t->name == NULL)
315 return (FIDO_ERR_INVALID_ARGUMENT);
316
317 return (bio_set_template_name_wait(dev, t, pin, -1));
318}
319
320static void
321bio_reset_enroll(fido_bio_enroll_t *e)
322{
323 e->remaining_samples = 0;
324 e->last_status = 0;
325
326 if (e->token)
327 fido_blob_free(&e->token);
328}
329
330static int
331bio_parse_enroll_status(const cbor_item_t *key, const cbor_item_t *val,
332 void *arg)
333{
334 fido_bio_enroll_t *e = arg;
335 uint64_t x;
336
337 if (cbor_isa_uint(key) == false ||
338 cbor_int_get_width(key) != CBOR_INT_8) {
339 fido_log_debug("%s: cbor type", __func__);
340 return (0); /* ignore */
341 }
342
343 switch (cbor_get_uint8(key)) {
344 case 5:
345 if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) {
346 fido_log_debug("%s: cbor_decode_uint64", __func__);
347 return (-1);
348 }
349 e->last_status = (uint8_t)x;
350 break;
351 case 6:
352 if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) {
353 fido_log_debug("%s: cbor_decode_uint64", __func__);
354 return (-1);
355 }
356 e->remaining_samples = (uint8_t)x;
357 break;
358 default:
359 return (0); /* ignore */
360 }
361
362 return (0);
363}
364
365static int
366bio_parse_template_id(const cbor_item_t *key, const cbor_item_t *val,
367 void *arg)
368{
369 fido_blob_t *id = arg;
370
371 if (cbor_isa_uint(key) == false ||
372 cbor_int_get_width(key) != CBOR_INT_8 ||
373 cbor_get_uint8(key) != 4) {
374 fido_log_debug("%s: cbor type", __func__);
375 return (0); /* ignore */
376 }
377
378 return (fido_blob_decode(val, id));
379}
380
381static int
382bio_rx_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t,
383 fido_bio_enroll_t *e, int ms)
384{
385 const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
386 unsigned char reply[2048];
387 int reply_len;
388 int r;
389
390 bio_reset_template(t);
391
392 e->remaining_samples = 0;
393 e->last_status = 0;
394
395 if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) {
396 fido_log_debug("%s: fido_rx", __func__);
397 return (FIDO_ERR_RX);
398 }
399
400 if ((r = cbor_parse_reply(reply, (size_t)reply_len, e,
401 bio_parse_enroll_status)) != FIDO_OK) {
402 fido_log_debug("%s: bio_parse_enroll_status", __func__);
403 return (r);
404 }
405 if ((r = cbor_parse_reply(reply, (size_t)reply_len, &t->id,
406 bio_parse_template_id)) != FIDO_OK) {
407 fido_log_debug("%s: bio_parse_template_id", __func__);
408 return (r);
409 }
410
411 return (FIDO_OK);
412}
413
414static int
415bio_enroll_begin_wait(fido_dev_t *dev, fido_bio_template_t *t,
416 fido_bio_enroll_t *e, uint32_t timo_ms, int ms)
417{
418 cbor_item_t *argv[3];
419 const uint8_t cmd = CMD_ENROLL_BEGIN;
420 int r = FIDO_ERR_INTERNAL;
421
422 memset(&argv, 0, sizeof(argv));
423
424 if ((argv[2] = cbor_build_uint32(timo_ms)) == NULL) {
425 fido_log_debug("%s: cbor encode", __func__);
426 goto fail;
427 }
428
429 if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token)) != FIDO_OK ||
430 (r = bio_rx_enroll_begin(dev, t, e, ms)) != FIDO_OK) {
431 fido_log_debug("%s: tx/rx", __func__);
432 goto fail;
433 }
434
435 r = FIDO_OK;
436fail:
437 cbor_vector_free(argv, nitems(argv));
438
439 return (r);
440}
441
442int
443fido_bio_dev_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t,
444 fido_bio_enroll_t *e, uint32_t timo_ms, const char *pin)
445{
446 es256_pk_t *pk = NULL;
447 fido_blob_t *ecdh = NULL;
448 fido_blob_t *token = NULL;
449 int r;
450
451 if (pin == NULL || e->token != NULL)
452 return (FIDO_ERR_INVALID_ARGUMENT);
453
454 if ((token = fido_blob_new()) == NULL) {
455 r = FIDO_ERR_INTERNAL;
456 goto fail;
457 }
458
459 if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
460 fido_log_debug("%s: fido_do_ecdh", __func__);
461 goto fail;
462 }
463
464 if ((r = fido_dev_get_pin_token(dev, pin, ecdh, pk, token)) != FIDO_OK) {
465 fido_log_debug("%s: fido_dev_get_pin_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 const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
486 unsigned char reply[2048];
487 int reply_len;
488 int r;
489
490 e->remaining_samples = 0;
491 e->last_status = 0;
492
493 if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), 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 const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
647 unsigned char reply[2048];
648 int reply_len;
649 int r;
650
651 bio_reset_info(i);
652
653 if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), 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}