]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/libfido2/src/bio.c
zfs: merge openzfs/zfs@ad0a55461
[FreeBSD/FreeBSD.git] / contrib / libfido2 / src / bio.c
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
19 static int
20 bio_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;
53 fail:
54         free(cbor);
55
56         return (ok);
57 }
58
59 static int
60 bio_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;
119 fail:
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
129 static void
130 bio_reset_template(fido_bio_template_t *t)
131 {
132         free(t->name);
133         t->name = NULL;
134         fido_blob_reset(&t->id);
135 }
136
137 static void
138 bio_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
148 static int
149 decode_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
169 static int
170 decode_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
195 static int
196 bio_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
233 static int
234 bio_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
257 static int
258 bio_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
270 int
271 fido_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
282 static int
283 bio_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;
305 fail:
306         cbor_vector_free(argv, nitems(argv));
307
308         return (r);
309 }
310
311 int
312 fido_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
323 static void
324 bio_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
333 static int
334 bio_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
368 static int
369 bio_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
384 static int
385 bio_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
417 static int
418 bio_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;
439 fail:
440         cbor_vector_free(argv, nitems(argv));
441
442         return (r);
443 }
444
445 int
446 fido_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;
476 fail:
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
487 static int
488 bio_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
512 static int
513 bio_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;
535 fail:
536         cbor_vector_free(argv, nitems(argv));
537
538         return (r);
539 }
540
541 int
542 fido_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
553 static int
554 bio_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
568 int
569 fido_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
576 static int
577 bio_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;
598 fail:
599         cbor_vector_free(argv, nitems(argv));
600
601         return (r);
602 }
603
604 int
605 fido_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
613 static void
614 bio_reset_info(fido_bio_info_t *i)
615 {
616         i->type = 0;
617         i->max_samples = 0;
618 }
619
620 static int
621 bio_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
654 static int
655 bio_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
678 static int
679 bio_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
693 int
694 fido_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
701 const char *
702 fido_bio_template_name(const fido_bio_template_t *t)
703 {
704         return (t->name);
705 }
706
707 const unsigned char *
708 fido_bio_template_id_ptr(const fido_bio_template_t *t)
709 {
710         return (t->id.ptr);
711 }
712
713 size_t
714 fido_bio_template_id_len(const fido_bio_template_t *t)
715 {
716         return (t->id.len);
717 }
718
719 size_t
720 fido_bio_template_array_count(const fido_bio_template_array_t *ta)
721 {
722         return (ta->n_rx);
723 }
724
725 fido_bio_template_array_t *
726 fido_bio_template_array_new(void)
727 {
728         return (calloc(1, sizeof(fido_bio_template_array_t)));
729 }
730
731 fido_bio_template_t *
732 fido_bio_template_new(void)
733 {
734         return (calloc(1, sizeof(fido_bio_template_t)));
735 }
736
737 void
738 fido_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
750 void
751 fido_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
763 int
764 fido_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
775 int
776 fido_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
787 const fido_bio_template_t *
788 fido_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
796 fido_bio_enroll_t *
797 fido_bio_enroll_new(void)
798 {
799         return (calloc(1, sizeof(fido_bio_enroll_t)));
800 }
801
802 fido_bio_info_t *
803 fido_bio_info_new(void)
804 {
805         return (calloc(1, sizeof(fido_bio_info_t)));
806 }
807
808 uint8_t
809 fido_bio_info_type(const fido_bio_info_t *i)
810 {
811         return (i->type);
812 }
813
814 uint8_t
815 fido_bio_info_max_samples(const fido_bio_info_t *i)
816 {
817         return (i->max_samples);
818 }
819
820 void
821 fido_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
834 void
835 fido_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
846 uint8_t
847 fido_bio_enroll_remaining_samples(const fido_bio_enroll_t *e)
848 {
849         return (e->remaining_samples);
850 }
851
852 uint8_t
853 fido_bio_enroll_last_status(const fido_bio_enroll_t *e)
854 {
855         return (e->last_status);
856 }