10afa8e06SEd Maste /*
2*2ccfa855SEd Maste * Copyright (c) 2019-2022 Yubico AB. All rights reserved.
30afa8e06SEd Maste * Use of this source code is governed by a BSD-style
40afa8e06SEd Maste * license that can be found in the LICENSE file.
5*2ccfa855SEd Maste * SPDX-License-Identifier: BSD-2-Clause
60afa8e06SEd Maste */
70afa8e06SEd Maste
80afa8e06SEd Maste #include "fido.h"
90afa8e06SEd Maste #include "fido/bio.h"
100afa8e06SEd Maste #include "fido/es256.h"
110afa8e06SEd Maste
120afa8e06SEd Maste #define CMD_ENROLL_BEGIN 0x01
130afa8e06SEd Maste #define CMD_ENROLL_NEXT 0x02
140afa8e06SEd Maste #define CMD_ENROLL_CANCEL 0x03
150afa8e06SEd Maste #define CMD_ENUM 0x04
160afa8e06SEd Maste #define CMD_SET_NAME 0x05
170afa8e06SEd Maste #define CMD_ENROLL_REMOVE 0x06
180afa8e06SEd Maste #define CMD_GET_INFO 0x07
190afa8e06SEd Maste
200afa8e06SEd Maste static int
bio_prepare_hmac(uint8_t cmd,cbor_item_t ** argv,size_t argc,cbor_item_t ** param,fido_blob_t * hmac_data)210afa8e06SEd Maste bio_prepare_hmac(uint8_t cmd, cbor_item_t **argv, size_t argc,
220afa8e06SEd Maste cbor_item_t **param, fido_blob_t *hmac_data)
230afa8e06SEd Maste {
240afa8e06SEd Maste const uint8_t prefix[2] = { 0x01 /* modality */, cmd };
250afa8e06SEd Maste int ok = -1;
260afa8e06SEd Maste size_t cbor_alloc_len;
270afa8e06SEd Maste size_t cbor_len;
280afa8e06SEd Maste unsigned char *cbor = NULL;
290afa8e06SEd Maste
300afa8e06SEd Maste if (argv == NULL || param == NULL)
310afa8e06SEd Maste return (fido_blob_set(hmac_data, prefix, sizeof(prefix)));
320afa8e06SEd Maste
330afa8e06SEd Maste if ((*param = cbor_flatten_vector(argv, argc)) == NULL) {
340afa8e06SEd Maste fido_log_debug("%s: cbor_flatten_vector", __func__);
350afa8e06SEd Maste goto fail;
360afa8e06SEd Maste }
370afa8e06SEd Maste
380afa8e06SEd Maste if ((cbor_len = cbor_serialize_alloc(*param, &cbor,
390afa8e06SEd Maste &cbor_alloc_len)) == 0 || cbor_len > SIZE_MAX - sizeof(prefix)) {
400afa8e06SEd Maste fido_log_debug("%s: cbor_serialize_alloc", __func__);
410afa8e06SEd Maste goto fail;
420afa8e06SEd Maste }
430afa8e06SEd Maste
440afa8e06SEd Maste if ((hmac_data->ptr = malloc(cbor_len + sizeof(prefix))) == NULL) {
450afa8e06SEd Maste fido_log_debug("%s: malloc", __func__);
460afa8e06SEd Maste goto fail;
470afa8e06SEd Maste }
480afa8e06SEd Maste
490afa8e06SEd Maste memcpy(hmac_data->ptr, prefix, sizeof(prefix));
500afa8e06SEd Maste memcpy(hmac_data->ptr + sizeof(prefix), cbor, cbor_len);
510afa8e06SEd Maste hmac_data->len = cbor_len + sizeof(prefix);
520afa8e06SEd Maste
530afa8e06SEd Maste ok = 0;
540afa8e06SEd Maste fail:
550afa8e06SEd Maste free(cbor);
560afa8e06SEd Maste
570afa8e06SEd Maste return (ok);
580afa8e06SEd Maste }
590afa8e06SEd Maste
600afa8e06SEd Maste static int
bio_tx(fido_dev_t * dev,uint8_t subcmd,cbor_item_t ** sub_argv,size_t sub_argc,const char * pin,const fido_blob_t * token,int * ms)610afa8e06SEd Maste bio_tx(fido_dev_t *dev, uint8_t subcmd, cbor_item_t **sub_argv, size_t sub_argc,
62f540a430SEd Maste const char *pin, const fido_blob_t *token, int *ms)
630afa8e06SEd Maste {
640afa8e06SEd Maste cbor_item_t *argv[5];
650afa8e06SEd Maste es256_pk_t *pk = NULL;
660afa8e06SEd Maste fido_blob_t *ecdh = NULL;
670afa8e06SEd Maste fido_blob_t f;
680afa8e06SEd Maste fido_blob_t hmac;
690afa8e06SEd Maste const uint8_t cmd = CTAP_CBOR_BIO_ENROLL_PRE;
700afa8e06SEd Maste int r = FIDO_ERR_INTERNAL;
710afa8e06SEd Maste
720afa8e06SEd Maste memset(&f, 0, sizeof(f));
730afa8e06SEd Maste memset(&hmac, 0, sizeof(hmac));
740afa8e06SEd Maste memset(&argv, 0, sizeof(argv));
750afa8e06SEd Maste
760afa8e06SEd Maste /* modality, subCommand */
770afa8e06SEd Maste if ((argv[0] = cbor_build_uint8(1)) == NULL ||
780afa8e06SEd Maste (argv[1] = cbor_build_uint8(subcmd)) == NULL) {
790afa8e06SEd Maste fido_log_debug("%s: cbor encode", __func__);
800afa8e06SEd Maste goto fail;
810afa8e06SEd Maste }
820afa8e06SEd Maste
830afa8e06SEd Maste /* subParams */
840afa8e06SEd Maste if (pin || token) {
850afa8e06SEd Maste if (bio_prepare_hmac(subcmd, sub_argv, sub_argc, &argv[2],
860afa8e06SEd Maste &hmac) < 0) {
870afa8e06SEd Maste fido_log_debug("%s: bio_prepare_hmac", __func__);
880afa8e06SEd Maste goto fail;
890afa8e06SEd Maste }
900afa8e06SEd Maste }
910afa8e06SEd Maste
920afa8e06SEd Maste /* pinProtocol, pinAuth */
930afa8e06SEd Maste if (pin) {
94f540a430SEd Maste if ((r = fido_do_ecdh(dev, &pk, &ecdh, ms)) != FIDO_OK) {
950afa8e06SEd Maste fido_log_debug("%s: fido_do_ecdh", __func__);
960afa8e06SEd Maste goto fail;
970afa8e06SEd Maste }
980afa8e06SEd Maste if ((r = cbor_add_uv_params(dev, cmd, &hmac, pk, ecdh, pin,
99f540a430SEd Maste NULL, &argv[4], &argv[3], ms)) != FIDO_OK) {
1000afa8e06SEd Maste fido_log_debug("%s: cbor_add_uv_params", __func__);
1010afa8e06SEd Maste goto fail;
1020afa8e06SEd Maste }
1030afa8e06SEd Maste } else if (token) {
1040afa8e06SEd Maste if ((argv[3] = cbor_encode_pin_opt(dev)) == NULL ||
1050afa8e06SEd Maste (argv[4] = cbor_encode_pin_auth(dev, token, &hmac)) == NULL) {
1060afa8e06SEd Maste fido_log_debug("%s: encode pin", __func__);
1070afa8e06SEd Maste goto fail;
1080afa8e06SEd Maste }
1090afa8e06SEd Maste }
1100afa8e06SEd Maste
1110afa8e06SEd Maste /* framing and transmission */
1120afa8e06SEd Maste if (cbor_build_frame(cmd, argv, nitems(argv), &f) < 0 ||
113f540a430SEd Maste fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, ms) < 0) {
1140afa8e06SEd Maste fido_log_debug("%s: fido_tx", __func__);
1150afa8e06SEd Maste r = FIDO_ERR_TX;
1160afa8e06SEd Maste goto fail;
1170afa8e06SEd Maste }
1180afa8e06SEd Maste
1190afa8e06SEd Maste r = FIDO_OK;
1200afa8e06SEd Maste fail:
1210afa8e06SEd Maste cbor_vector_free(argv, nitems(argv));
1220afa8e06SEd Maste es256_pk_free(&pk);
1230afa8e06SEd Maste fido_blob_free(&ecdh);
1240afa8e06SEd Maste free(f.ptr);
1250afa8e06SEd Maste free(hmac.ptr);
1260afa8e06SEd Maste
1270afa8e06SEd Maste return (r);
1280afa8e06SEd Maste }
1290afa8e06SEd Maste
1300afa8e06SEd Maste static void
bio_reset_template(fido_bio_template_t * t)1310afa8e06SEd Maste bio_reset_template(fido_bio_template_t *t)
1320afa8e06SEd Maste {
1330afa8e06SEd Maste free(t->name);
1340afa8e06SEd Maste t->name = NULL;
1350afa8e06SEd Maste fido_blob_reset(&t->id);
1360afa8e06SEd Maste }
1370afa8e06SEd Maste
1380afa8e06SEd Maste static void
bio_reset_template_array(fido_bio_template_array_t * ta)1390afa8e06SEd Maste bio_reset_template_array(fido_bio_template_array_t *ta)
1400afa8e06SEd Maste {
1410afa8e06SEd Maste for (size_t i = 0; i < ta->n_alloc; i++)
1420afa8e06SEd Maste bio_reset_template(&ta->ptr[i]);
1430afa8e06SEd Maste
1440afa8e06SEd Maste free(ta->ptr);
1450afa8e06SEd Maste ta->ptr = NULL;
1460afa8e06SEd Maste memset(ta, 0, sizeof(*ta));
1470afa8e06SEd Maste }
1480afa8e06SEd Maste
1490afa8e06SEd Maste static int
decode_template(const cbor_item_t * key,const cbor_item_t * val,void * arg)1500afa8e06SEd Maste decode_template(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1510afa8e06SEd Maste {
1520afa8e06SEd Maste fido_bio_template_t *t = arg;
1530afa8e06SEd Maste
1540afa8e06SEd Maste if (cbor_isa_uint(key) == false ||
1550afa8e06SEd Maste cbor_int_get_width(key) != CBOR_INT_8) {
1560afa8e06SEd Maste fido_log_debug("%s: cbor type", __func__);
1570afa8e06SEd Maste return (0); /* ignore */
1580afa8e06SEd Maste }
1590afa8e06SEd Maste
1600afa8e06SEd Maste switch (cbor_get_uint8(key)) {
1610afa8e06SEd Maste case 1: /* id */
1620afa8e06SEd Maste return (fido_blob_decode(val, &t->id));
1630afa8e06SEd Maste case 2: /* name */
1640afa8e06SEd Maste return (cbor_string_copy(val, &t->name));
1650afa8e06SEd Maste }
1660afa8e06SEd Maste
1670afa8e06SEd Maste return (0); /* ignore */
1680afa8e06SEd Maste }
1690afa8e06SEd Maste
1700afa8e06SEd Maste static int
decode_template_array(const cbor_item_t * item,void * arg)1710afa8e06SEd Maste decode_template_array(const cbor_item_t *item, void *arg)
1720afa8e06SEd Maste {
1730afa8e06SEd Maste fido_bio_template_array_t *ta = arg;
1740afa8e06SEd Maste
1750afa8e06SEd Maste if (cbor_isa_map(item) == false ||
1760afa8e06SEd Maste cbor_map_is_definite(item) == false) {
1770afa8e06SEd Maste fido_log_debug("%s: cbor type", __func__);
1780afa8e06SEd Maste return (-1);
1790afa8e06SEd Maste }
1800afa8e06SEd Maste
1810afa8e06SEd Maste if (ta->n_rx >= ta->n_alloc) {
1820afa8e06SEd Maste fido_log_debug("%s: n_rx >= n_alloc", __func__);
1830afa8e06SEd Maste return (-1);
1840afa8e06SEd Maste }
1850afa8e06SEd Maste
1860afa8e06SEd Maste if (cbor_map_iter(item, &ta->ptr[ta->n_rx], decode_template) < 0) {
1870afa8e06SEd Maste fido_log_debug("%s: decode_template", __func__);
1880afa8e06SEd Maste return (-1);
1890afa8e06SEd Maste }
1900afa8e06SEd Maste
1910afa8e06SEd Maste ta->n_rx++;
1920afa8e06SEd Maste
1930afa8e06SEd Maste return (0);
1940afa8e06SEd Maste }
1950afa8e06SEd Maste
1960afa8e06SEd Maste static int
bio_parse_template_array(const cbor_item_t * key,const cbor_item_t * val,void * arg)1970afa8e06SEd Maste bio_parse_template_array(const cbor_item_t *key, const cbor_item_t *val,
1980afa8e06SEd Maste void *arg)
1990afa8e06SEd Maste {
2000afa8e06SEd Maste fido_bio_template_array_t *ta = arg;
2010afa8e06SEd Maste
2020afa8e06SEd Maste if (cbor_isa_uint(key) == false ||
2030afa8e06SEd Maste cbor_int_get_width(key) != CBOR_INT_8 ||
2040afa8e06SEd Maste cbor_get_uint8(key) != 7) {
2050afa8e06SEd Maste fido_log_debug("%s: cbor type", __func__);
2060afa8e06SEd Maste return (0); /* ignore */
2070afa8e06SEd Maste }
2080afa8e06SEd Maste
2090afa8e06SEd Maste if (cbor_isa_array(val) == false ||
2100afa8e06SEd Maste cbor_array_is_definite(val) == false) {
2110afa8e06SEd Maste fido_log_debug("%s: cbor type", __func__);
2120afa8e06SEd Maste return (-1);
2130afa8e06SEd Maste }
2140afa8e06SEd Maste
2150afa8e06SEd Maste if (ta->ptr != NULL || ta->n_alloc != 0 || ta->n_rx != 0) {
2160afa8e06SEd Maste fido_log_debug("%s: ptr != NULL || n_alloc != 0 || n_rx != 0",
2170afa8e06SEd Maste __func__);
2180afa8e06SEd Maste return (-1);
2190afa8e06SEd Maste }
2200afa8e06SEd Maste
2210afa8e06SEd Maste if ((ta->ptr = calloc(cbor_array_size(val), sizeof(*ta->ptr))) == NULL)
2220afa8e06SEd Maste return (-1);
2230afa8e06SEd Maste
2240afa8e06SEd Maste ta->n_alloc = cbor_array_size(val);
2250afa8e06SEd Maste
2260afa8e06SEd Maste if (cbor_array_iter(val, ta, decode_template_array) < 0) {
2270afa8e06SEd Maste fido_log_debug("%s: decode_template_array", __func__);
2280afa8e06SEd Maste return (-1);
2290afa8e06SEd Maste }
2300afa8e06SEd Maste
2310afa8e06SEd Maste return (0);
2320afa8e06SEd Maste }
2330afa8e06SEd Maste
2340afa8e06SEd Maste static int
bio_rx_template_array(fido_dev_t * dev,fido_bio_template_array_t * ta,int * ms)235f540a430SEd Maste bio_rx_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta, int *ms)
2360afa8e06SEd Maste {
237*2ccfa855SEd Maste unsigned char *msg;
238*2ccfa855SEd Maste int msglen;
2390afa8e06SEd Maste int r;
2400afa8e06SEd Maste
2410afa8e06SEd Maste bio_reset_template_array(ta);
2420afa8e06SEd Maste
243*2ccfa855SEd Maste if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
244*2ccfa855SEd Maste r = FIDO_ERR_INTERNAL;
245*2ccfa855SEd Maste goto out;
2460afa8e06SEd Maste }
2470afa8e06SEd Maste
248*2ccfa855SEd Maste if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
249*2ccfa855SEd Maste fido_log_debug("%s: fido_rx", __func__);
250*2ccfa855SEd Maste r = FIDO_ERR_RX;
251*2ccfa855SEd Maste goto out;
252*2ccfa855SEd Maste }
253*2ccfa855SEd Maste
254*2ccfa855SEd Maste if ((r = cbor_parse_reply(msg, (size_t)msglen, ta,
2550afa8e06SEd Maste bio_parse_template_array)) != FIDO_OK) {
2560afa8e06SEd Maste fido_log_debug("%s: bio_parse_template_array" , __func__);
257*2ccfa855SEd Maste goto out;
2580afa8e06SEd Maste }
2590afa8e06SEd Maste
260*2ccfa855SEd Maste r = FIDO_OK;
261*2ccfa855SEd Maste out:
262*2ccfa855SEd Maste freezero(msg, FIDO_MAXMSG);
263*2ccfa855SEd Maste
264*2ccfa855SEd Maste return (r);
2650afa8e06SEd Maste }
2660afa8e06SEd Maste
2670afa8e06SEd Maste static int
bio_get_template_array_wait(fido_dev_t * dev,fido_bio_template_array_t * ta,const char * pin,int * ms)2680afa8e06SEd Maste bio_get_template_array_wait(fido_dev_t *dev, fido_bio_template_array_t *ta,
269f540a430SEd Maste const char *pin, int *ms)
2700afa8e06SEd Maste {
2710afa8e06SEd Maste int r;
2720afa8e06SEd Maste
273f540a430SEd Maste if ((r = bio_tx(dev, CMD_ENUM, NULL, 0, pin, NULL, ms)) != FIDO_OK ||
2740afa8e06SEd Maste (r = bio_rx_template_array(dev, ta, ms)) != FIDO_OK)
2750afa8e06SEd Maste return (r);
2760afa8e06SEd Maste
2770afa8e06SEd Maste return (FIDO_OK);
2780afa8e06SEd Maste }
2790afa8e06SEd Maste
2800afa8e06SEd Maste int
fido_bio_dev_get_template_array(fido_dev_t * dev,fido_bio_template_array_t * ta,const char * pin)2810afa8e06SEd Maste fido_bio_dev_get_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta,
2820afa8e06SEd Maste const char *pin)
2830afa8e06SEd Maste {
284f540a430SEd Maste int ms = dev->timeout_ms;
285f540a430SEd Maste
2860afa8e06SEd Maste if (pin == NULL)
2870afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT);
2880afa8e06SEd Maste
289f540a430SEd Maste return (bio_get_template_array_wait(dev, ta, pin, &ms));
2900afa8e06SEd Maste }
2910afa8e06SEd Maste
2920afa8e06SEd Maste static int
bio_set_template_name_wait(fido_dev_t * dev,const fido_bio_template_t * t,const char * pin,int * ms)2930afa8e06SEd Maste bio_set_template_name_wait(fido_dev_t *dev, const fido_bio_template_t *t,
294f540a430SEd Maste const char *pin, int *ms)
2950afa8e06SEd Maste {
2960afa8e06SEd Maste cbor_item_t *argv[2];
2970afa8e06SEd Maste int r = FIDO_ERR_INTERNAL;
2980afa8e06SEd Maste
2990afa8e06SEd Maste memset(&argv, 0, sizeof(argv));
3000afa8e06SEd Maste
3010afa8e06SEd Maste if ((argv[0] = fido_blob_encode(&t->id)) == NULL ||
3020afa8e06SEd Maste (argv[1] = cbor_build_string(t->name)) == NULL) {
3030afa8e06SEd Maste fido_log_debug("%s: cbor encode", __func__);
3040afa8e06SEd Maste goto fail;
3050afa8e06SEd Maste }
3060afa8e06SEd Maste
307f540a430SEd Maste if ((r = bio_tx(dev, CMD_SET_NAME, argv, 2, pin, NULL,
308f540a430SEd Maste ms)) != FIDO_OK ||
3090afa8e06SEd Maste (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
3100afa8e06SEd Maste fido_log_debug("%s: tx/rx", __func__);
3110afa8e06SEd Maste goto fail;
3120afa8e06SEd Maste }
3130afa8e06SEd Maste
3140afa8e06SEd Maste r = FIDO_OK;
3150afa8e06SEd Maste fail:
3160afa8e06SEd Maste cbor_vector_free(argv, nitems(argv));
3170afa8e06SEd Maste
3180afa8e06SEd Maste return (r);
3190afa8e06SEd Maste }
3200afa8e06SEd Maste
3210afa8e06SEd Maste int
fido_bio_dev_set_template_name(fido_dev_t * dev,const fido_bio_template_t * t,const char * pin)3220afa8e06SEd Maste fido_bio_dev_set_template_name(fido_dev_t *dev, const fido_bio_template_t *t,
3230afa8e06SEd Maste const char *pin)
3240afa8e06SEd Maste {
325f540a430SEd Maste int ms = dev->timeout_ms;
326f540a430SEd Maste
3270afa8e06SEd Maste if (pin == NULL || t->name == NULL)
3280afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT);
3290afa8e06SEd Maste
330f540a430SEd Maste return (bio_set_template_name_wait(dev, t, pin, &ms));
3310afa8e06SEd Maste }
3320afa8e06SEd Maste
3330afa8e06SEd Maste static void
bio_reset_enroll(fido_bio_enroll_t * e)3340afa8e06SEd Maste bio_reset_enroll(fido_bio_enroll_t *e)
3350afa8e06SEd Maste {
3360afa8e06SEd Maste e->remaining_samples = 0;
3370afa8e06SEd Maste e->last_status = 0;
3380afa8e06SEd Maste
3390afa8e06SEd Maste if (e->token)
3400afa8e06SEd Maste fido_blob_free(&e->token);
3410afa8e06SEd Maste }
3420afa8e06SEd Maste
3430afa8e06SEd Maste static int
bio_parse_enroll_status(const cbor_item_t * key,const cbor_item_t * val,void * arg)3440afa8e06SEd Maste bio_parse_enroll_status(const cbor_item_t *key, const cbor_item_t *val,
3450afa8e06SEd Maste void *arg)
3460afa8e06SEd Maste {
3470afa8e06SEd Maste fido_bio_enroll_t *e = arg;
3480afa8e06SEd Maste uint64_t x;
3490afa8e06SEd Maste
3500afa8e06SEd Maste if (cbor_isa_uint(key) == false ||
3510afa8e06SEd Maste cbor_int_get_width(key) != CBOR_INT_8) {
3520afa8e06SEd Maste fido_log_debug("%s: cbor type", __func__);
3530afa8e06SEd Maste return (0); /* ignore */
3540afa8e06SEd Maste }
3550afa8e06SEd Maste
3560afa8e06SEd Maste switch (cbor_get_uint8(key)) {
3570afa8e06SEd Maste case 5:
3580afa8e06SEd Maste if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) {
3590afa8e06SEd Maste fido_log_debug("%s: cbor_decode_uint64", __func__);
3600afa8e06SEd Maste return (-1);
3610afa8e06SEd Maste }
3620afa8e06SEd Maste e->last_status = (uint8_t)x;
3630afa8e06SEd Maste break;
3640afa8e06SEd Maste case 6:
3650afa8e06SEd Maste if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) {
3660afa8e06SEd Maste fido_log_debug("%s: cbor_decode_uint64", __func__);
3670afa8e06SEd Maste return (-1);
3680afa8e06SEd Maste }
3690afa8e06SEd Maste e->remaining_samples = (uint8_t)x;
3700afa8e06SEd Maste break;
3710afa8e06SEd Maste default:
3720afa8e06SEd Maste return (0); /* ignore */
3730afa8e06SEd Maste }
3740afa8e06SEd Maste
3750afa8e06SEd Maste return (0);
3760afa8e06SEd Maste }
3770afa8e06SEd Maste
3780afa8e06SEd Maste static int
bio_parse_template_id(const cbor_item_t * key,const cbor_item_t * val,void * arg)3790afa8e06SEd Maste bio_parse_template_id(const cbor_item_t *key, const cbor_item_t *val,
3800afa8e06SEd Maste void *arg)
3810afa8e06SEd Maste {
3820afa8e06SEd Maste fido_blob_t *id = arg;
3830afa8e06SEd Maste
3840afa8e06SEd Maste if (cbor_isa_uint(key) == false ||
3850afa8e06SEd Maste cbor_int_get_width(key) != CBOR_INT_8 ||
3860afa8e06SEd Maste cbor_get_uint8(key) != 4) {
3870afa8e06SEd Maste fido_log_debug("%s: cbor type", __func__);
3880afa8e06SEd Maste return (0); /* ignore */
3890afa8e06SEd Maste }
3900afa8e06SEd Maste
3910afa8e06SEd Maste return (fido_blob_decode(val, id));
3920afa8e06SEd Maste }
3930afa8e06SEd Maste
3940afa8e06SEd Maste static int
bio_rx_enroll_begin(fido_dev_t * dev,fido_bio_template_t * t,fido_bio_enroll_t * e,int * ms)3950afa8e06SEd Maste bio_rx_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t,
396f540a430SEd Maste fido_bio_enroll_t *e, int *ms)
3970afa8e06SEd Maste {
398*2ccfa855SEd Maste unsigned char *msg;
399*2ccfa855SEd Maste int msglen;
4000afa8e06SEd Maste int r;
4010afa8e06SEd Maste
4020afa8e06SEd Maste bio_reset_template(t);
4030afa8e06SEd Maste
4040afa8e06SEd Maste e->remaining_samples = 0;
4050afa8e06SEd Maste e->last_status = 0;
4060afa8e06SEd Maste
407*2ccfa855SEd Maste if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
408*2ccfa855SEd Maste r = FIDO_ERR_INTERNAL;
409*2ccfa855SEd Maste goto out;
4100afa8e06SEd Maste }
4110afa8e06SEd Maste
412*2ccfa855SEd Maste if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
413*2ccfa855SEd Maste fido_log_debug("%s: fido_rx", __func__);
414*2ccfa855SEd Maste r = FIDO_ERR_RX;
415*2ccfa855SEd Maste goto out;
416*2ccfa855SEd Maste }
417*2ccfa855SEd Maste
418*2ccfa855SEd Maste if ((r = cbor_parse_reply(msg, (size_t)msglen, e,
4190afa8e06SEd Maste bio_parse_enroll_status)) != FIDO_OK) {
4200afa8e06SEd Maste fido_log_debug("%s: bio_parse_enroll_status", __func__);
421*2ccfa855SEd Maste goto out;
4220afa8e06SEd Maste }
4230afa8e06SEd Maste
424*2ccfa855SEd Maste if ((r = cbor_parse_reply(msg, (size_t)msglen, &t->id,
425*2ccfa855SEd Maste bio_parse_template_id)) != FIDO_OK) {
426*2ccfa855SEd Maste fido_log_debug("%s: bio_parse_template_id", __func__);
427*2ccfa855SEd Maste goto out;
428*2ccfa855SEd Maste }
429*2ccfa855SEd Maste
430*2ccfa855SEd Maste r = FIDO_OK;
431*2ccfa855SEd Maste out:
432*2ccfa855SEd Maste freezero(msg, FIDO_MAXMSG);
433*2ccfa855SEd Maste
434*2ccfa855SEd Maste return (r);
4350afa8e06SEd Maste }
4360afa8e06SEd Maste
4370afa8e06SEd Maste static int
bio_enroll_begin_wait(fido_dev_t * dev,fido_bio_template_t * t,fido_bio_enroll_t * e,uint32_t timo_ms,int * ms)4380afa8e06SEd Maste bio_enroll_begin_wait(fido_dev_t *dev, fido_bio_template_t *t,
439f540a430SEd Maste fido_bio_enroll_t *e, uint32_t timo_ms, int *ms)
4400afa8e06SEd Maste {
4410afa8e06SEd Maste cbor_item_t *argv[3];
4420afa8e06SEd Maste const uint8_t cmd = CMD_ENROLL_BEGIN;
4430afa8e06SEd Maste int r = FIDO_ERR_INTERNAL;
4440afa8e06SEd Maste
4450afa8e06SEd Maste memset(&argv, 0, sizeof(argv));
4460afa8e06SEd Maste
4473e696dfbSEd Maste if ((argv[2] = cbor_build_uint(timo_ms)) == NULL) {
4480afa8e06SEd Maste fido_log_debug("%s: cbor encode", __func__);
4490afa8e06SEd Maste goto fail;
4500afa8e06SEd Maste }
4510afa8e06SEd Maste
452f540a430SEd Maste if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token, ms)) != FIDO_OK ||
4530afa8e06SEd Maste (r = bio_rx_enroll_begin(dev, t, e, ms)) != FIDO_OK) {
4540afa8e06SEd Maste fido_log_debug("%s: tx/rx", __func__);
4550afa8e06SEd Maste goto fail;
4560afa8e06SEd Maste }
4570afa8e06SEd Maste
4580afa8e06SEd Maste r = FIDO_OK;
4590afa8e06SEd Maste fail:
4600afa8e06SEd Maste cbor_vector_free(argv, nitems(argv));
4610afa8e06SEd Maste
4620afa8e06SEd Maste return (r);
4630afa8e06SEd Maste }
4640afa8e06SEd Maste
4650afa8e06SEd Maste int
fido_bio_dev_enroll_begin(fido_dev_t * dev,fido_bio_template_t * t,fido_bio_enroll_t * e,uint32_t timo_ms,const char * pin)4660afa8e06SEd Maste fido_bio_dev_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t,
4670afa8e06SEd Maste fido_bio_enroll_t *e, uint32_t timo_ms, const char *pin)
4680afa8e06SEd Maste {
4690afa8e06SEd Maste es256_pk_t *pk = NULL;
4700afa8e06SEd Maste fido_blob_t *ecdh = NULL;
4710afa8e06SEd Maste fido_blob_t *token = NULL;
472f540a430SEd Maste int ms = dev->timeout_ms;
4730afa8e06SEd Maste int r;
4740afa8e06SEd Maste
4750afa8e06SEd Maste if (pin == NULL || e->token != NULL)
4760afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT);
4770afa8e06SEd Maste
4780afa8e06SEd Maste if ((token = fido_blob_new()) == NULL) {
4790afa8e06SEd Maste r = FIDO_ERR_INTERNAL;
4800afa8e06SEd Maste goto fail;
4810afa8e06SEd Maste }
4820afa8e06SEd Maste
483f540a430SEd Maste if ((r = fido_do_ecdh(dev, &pk, &ecdh, &ms)) != FIDO_OK) {
4840afa8e06SEd Maste fido_log_debug("%s: fido_do_ecdh", __func__);
4850afa8e06SEd Maste goto fail;
4860afa8e06SEd Maste }
4870afa8e06SEd Maste
4880afa8e06SEd Maste if ((r = fido_dev_get_uv_token(dev, CTAP_CBOR_BIO_ENROLL_PRE, pin, ecdh,
489f540a430SEd Maste pk, NULL, token, &ms)) != FIDO_OK) {
4900afa8e06SEd Maste fido_log_debug("%s: fido_dev_get_uv_token", __func__);
4910afa8e06SEd Maste goto fail;
4920afa8e06SEd Maste }
4930afa8e06SEd Maste
4940afa8e06SEd Maste e->token = token;
4950afa8e06SEd Maste token = NULL;
4960afa8e06SEd Maste fail:
4970afa8e06SEd Maste es256_pk_free(&pk);
4980afa8e06SEd Maste fido_blob_free(&ecdh);
4990afa8e06SEd Maste fido_blob_free(&token);
5000afa8e06SEd Maste
5010afa8e06SEd Maste if (r != FIDO_OK)
5020afa8e06SEd Maste return (r);
5030afa8e06SEd Maste
504f540a430SEd Maste return (bio_enroll_begin_wait(dev, t, e, timo_ms, &ms));
5050afa8e06SEd Maste }
5060afa8e06SEd Maste
5070afa8e06SEd Maste static int
bio_rx_enroll_continue(fido_dev_t * dev,fido_bio_enroll_t * e,int * ms)508f540a430SEd Maste bio_rx_enroll_continue(fido_dev_t *dev, fido_bio_enroll_t *e, int *ms)
5090afa8e06SEd Maste {
510*2ccfa855SEd Maste unsigned char *msg;
511*2ccfa855SEd Maste int msglen;
5120afa8e06SEd Maste int r;
5130afa8e06SEd Maste
5140afa8e06SEd Maste e->remaining_samples = 0;
5150afa8e06SEd Maste e->last_status = 0;
5160afa8e06SEd Maste
517*2ccfa855SEd Maste if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
518*2ccfa855SEd Maste r = FIDO_ERR_INTERNAL;
519*2ccfa855SEd Maste goto out;
5200afa8e06SEd Maste }
5210afa8e06SEd Maste
522*2ccfa855SEd Maste if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
523*2ccfa855SEd Maste fido_log_debug("%s: fido_rx", __func__);
524*2ccfa855SEd Maste r = FIDO_ERR_RX;
525*2ccfa855SEd Maste goto out;
526*2ccfa855SEd Maste }
527*2ccfa855SEd Maste
528*2ccfa855SEd Maste if ((r = cbor_parse_reply(msg, (size_t)msglen, e,
5290afa8e06SEd Maste bio_parse_enroll_status)) != FIDO_OK) {
5300afa8e06SEd Maste fido_log_debug("%s: bio_parse_enroll_status", __func__);
531*2ccfa855SEd Maste goto out;
5320afa8e06SEd Maste }
5330afa8e06SEd Maste
534*2ccfa855SEd Maste r = FIDO_OK;
535*2ccfa855SEd Maste out:
536*2ccfa855SEd Maste freezero(msg, FIDO_MAXMSG);
537*2ccfa855SEd Maste
538*2ccfa855SEd Maste return (r);
5390afa8e06SEd Maste }
5400afa8e06SEd Maste
5410afa8e06SEd Maste static int
bio_enroll_continue_wait(fido_dev_t * dev,const fido_bio_template_t * t,fido_bio_enroll_t * e,uint32_t timo_ms,int * ms)5420afa8e06SEd Maste bio_enroll_continue_wait(fido_dev_t *dev, const fido_bio_template_t *t,
543f540a430SEd Maste fido_bio_enroll_t *e, uint32_t timo_ms, int *ms)
5440afa8e06SEd Maste {
5450afa8e06SEd Maste cbor_item_t *argv[3];
5460afa8e06SEd Maste const uint8_t cmd = CMD_ENROLL_NEXT;
5470afa8e06SEd Maste int r = FIDO_ERR_INTERNAL;
5480afa8e06SEd Maste
5490afa8e06SEd Maste memset(&argv, 0, sizeof(argv));
5500afa8e06SEd Maste
5510afa8e06SEd Maste if ((argv[0] = fido_blob_encode(&t->id)) == NULL ||
5523e696dfbSEd Maste (argv[2] = cbor_build_uint(timo_ms)) == NULL) {
5530afa8e06SEd Maste fido_log_debug("%s: cbor encode", __func__);
5540afa8e06SEd Maste goto fail;
5550afa8e06SEd Maste }
5560afa8e06SEd Maste
557f540a430SEd Maste if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token, ms)) != FIDO_OK ||
5580afa8e06SEd Maste (r = bio_rx_enroll_continue(dev, e, ms)) != FIDO_OK) {
5590afa8e06SEd Maste fido_log_debug("%s: tx/rx", __func__);
5600afa8e06SEd Maste goto fail;
5610afa8e06SEd Maste }
5620afa8e06SEd Maste
5630afa8e06SEd Maste r = FIDO_OK;
5640afa8e06SEd Maste fail:
5650afa8e06SEd Maste cbor_vector_free(argv, nitems(argv));
5660afa8e06SEd Maste
5670afa8e06SEd Maste return (r);
5680afa8e06SEd Maste }
5690afa8e06SEd Maste
5700afa8e06SEd Maste int
fido_bio_dev_enroll_continue(fido_dev_t * dev,const fido_bio_template_t * t,fido_bio_enroll_t * e,uint32_t timo_ms)5710afa8e06SEd Maste fido_bio_dev_enroll_continue(fido_dev_t *dev, const fido_bio_template_t *t,
5720afa8e06SEd Maste fido_bio_enroll_t *e, uint32_t timo_ms)
5730afa8e06SEd Maste {
574f540a430SEd Maste int ms = dev->timeout_ms;
575f540a430SEd Maste
5760afa8e06SEd Maste if (e->token == NULL)
5770afa8e06SEd Maste return (FIDO_ERR_INVALID_ARGUMENT);
5780afa8e06SEd Maste
579f540a430SEd Maste return (bio_enroll_continue_wait(dev, t, e, timo_ms, &ms));
5800afa8e06SEd Maste }
5810afa8e06SEd Maste
5820afa8e06SEd Maste static int
bio_enroll_cancel_wait(fido_dev_t * dev,int * ms)583f540a430SEd Maste bio_enroll_cancel_wait(fido_dev_t *dev, int *ms)
5840afa8e06SEd Maste {
5850afa8e06SEd Maste const uint8_t cmd = CMD_ENROLL_CANCEL;
5860afa8e06SEd Maste int r;
5870afa8e06SEd Maste
588f540a430SEd Maste if ((r = bio_tx(dev, cmd, NULL, 0, NULL, NULL, ms)) != FIDO_OK ||
5890afa8e06SEd Maste (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
5900afa8e06SEd Maste fido_log_debug("%s: tx/rx", __func__);
5910afa8e06SEd Maste return (r);
5920afa8e06SEd Maste }
5930afa8e06SEd Maste
5940afa8e06SEd Maste return (FIDO_OK);
5950afa8e06SEd Maste }
5960afa8e06SEd Maste
5970afa8e06SEd Maste int
fido_bio_dev_enroll_cancel(fido_dev_t * dev)5980afa8e06SEd Maste fido_bio_dev_enroll_cancel(fido_dev_t *dev)
5990afa8e06SEd Maste {
600f540a430SEd Maste int ms = dev->timeout_ms;
601f540a430SEd Maste
602f540a430SEd Maste return (bio_enroll_cancel_wait(dev, &ms));
6030afa8e06SEd Maste }
6040afa8e06SEd Maste
6050afa8e06SEd Maste static int
bio_enroll_remove_wait(fido_dev_t * dev,const fido_bio_template_t * t,const char * pin,int * ms)6060afa8e06SEd Maste bio_enroll_remove_wait(fido_dev_t *dev, const fido_bio_template_t *t,
607f540a430SEd Maste const char *pin, int *ms)
6080afa8e06SEd Maste {
6090afa8e06SEd Maste cbor_item_t *argv[1];
6100afa8e06SEd Maste const uint8_t cmd = CMD_ENROLL_REMOVE;
6110afa8e06SEd Maste int r = FIDO_ERR_INTERNAL;
6120afa8e06SEd Maste
6130afa8e06SEd Maste memset(&argv, 0, sizeof(argv));
6140afa8e06SEd Maste
6150afa8e06SEd Maste if ((argv[0] = fido_blob_encode(&t->id)) == NULL) {
6160afa8e06SEd Maste fido_log_debug("%s: cbor encode", __func__);
6170afa8e06SEd Maste goto fail;
6180afa8e06SEd Maste }
6190afa8e06SEd Maste
620f540a430SEd Maste if ((r = bio_tx(dev, cmd, argv, 1, pin, NULL, ms)) != FIDO_OK ||
6210afa8e06SEd Maste (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
6220afa8e06SEd Maste fido_log_debug("%s: tx/rx", __func__);
6230afa8e06SEd Maste goto fail;
6240afa8e06SEd Maste }
6250afa8e06SEd Maste
6260afa8e06SEd Maste r = FIDO_OK;
6270afa8e06SEd Maste fail:
6280afa8e06SEd Maste cbor_vector_free(argv, nitems(argv));
6290afa8e06SEd Maste
6300afa8e06SEd Maste return (r);
6310afa8e06SEd Maste }
6320afa8e06SEd Maste
6330afa8e06SEd Maste int
fido_bio_dev_enroll_remove(fido_dev_t * dev,const fido_bio_template_t * t,const char * pin)6340afa8e06SEd Maste fido_bio_dev_enroll_remove(fido_dev_t *dev, const fido_bio_template_t *t,
6350afa8e06SEd Maste const char *pin)
6360afa8e06SEd Maste {
637f540a430SEd Maste int ms = dev->timeout_ms;
638f540a430SEd Maste
639f540a430SEd Maste return (bio_enroll_remove_wait(dev, t, pin, &ms));
6400afa8e06SEd Maste }
6410afa8e06SEd Maste
6420afa8e06SEd Maste static void
bio_reset_info(fido_bio_info_t * i)6430afa8e06SEd Maste bio_reset_info(fido_bio_info_t *i)
6440afa8e06SEd Maste {
6450afa8e06SEd Maste i->type = 0;
6460afa8e06SEd Maste i->max_samples = 0;
6470afa8e06SEd Maste }
6480afa8e06SEd Maste
6490afa8e06SEd Maste static int
bio_parse_info(const cbor_item_t * key,const cbor_item_t * val,void * arg)6500afa8e06SEd Maste bio_parse_info(const cbor_item_t *key, const cbor_item_t *val, void *arg)
6510afa8e06SEd Maste {
6520afa8e06SEd Maste fido_bio_info_t *i = arg;
6530afa8e06SEd Maste uint64_t x;
6540afa8e06SEd Maste
6550afa8e06SEd Maste if (cbor_isa_uint(key) == false ||
6560afa8e06SEd Maste cbor_int_get_width(key) != CBOR_INT_8) {
6570afa8e06SEd Maste fido_log_debug("%s: cbor type", __func__);
6580afa8e06SEd Maste return (0); /* ignore */
6590afa8e06SEd Maste }
6600afa8e06SEd Maste
6610afa8e06SEd Maste switch (cbor_get_uint8(key)) {
6620afa8e06SEd Maste case 2:
6630afa8e06SEd Maste if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) {
6640afa8e06SEd Maste fido_log_debug("%s: cbor_decode_uint64", __func__);
6650afa8e06SEd Maste return (-1);
6660afa8e06SEd Maste }
6670afa8e06SEd Maste i->type = (uint8_t)x;
6680afa8e06SEd Maste break;
6690afa8e06SEd Maste case 3:
6700afa8e06SEd Maste if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) {
6710afa8e06SEd Maste fido_log_debug("%s: cbor_decode_uint64", __func__);
6720afa8e06SEd Maste return (-1);
6730afa8e06SEd Maste }
6740afa8e06SEd Maste i->max_samples = (uint8_t)x;
6750afa8e06SEd Maste break;
6760afa8e06SEd Maste default:
6770afa8e06SEd Maste return (0); /* ignore */
6780afa8e06SEd Maste }
6790afa8e06SEd Maste
6800afa8e06SEd Maste return (0);
6810afa8e06SEd Maste }
6820afa8e06SEd Maste
6830afa8e06SEd Maste static int
bio_rx_info(fido_dev_t * dev,fido_bio_info_t * i,int * ms)684f540a430SEd Maste bio_rx_info(fido_dev_t *dev, fido_bio_info_t *i, int *ms)
6850afa8e06SEd Maste {
686*2ccfa855SEd Maste unsigned char *msg;
687*2ccfa855SEd Maste int msglen;
6880afa8e06SEd Maste int r;
6890afa8e06SEd Maste
6900afa8e06SEd Maste bio_reset_info(i);
6910afa8e06SEd Maste
692*2ccfa855SEd Maste if ((msg = malloc(FIDO_MAXMSG)) == NULL) {
693*2ccfa855SEd Maste r = FIDO_ERR_INTERNAL;
694*2ccfa855SEd Maste goto out;
6950afa8e06SEd Maste }
6960afa8e06SEd Maste
697*2ccfa855SEd Maste if ((msglen = fido_rx(dev, CTAP_CMD_CBOR, msg, FIDO_MAXMSG, ms)) < 0) {
698*2ccfa855SEd Maste fido_log_debug("%s: fido_rx", __func__);
699*2ccfa855SEd Maste r = FIDO_ERR_RX;
700*2ccfa855SEd Maste goto out;
701*2ccfa855SEd Maste }
702*2ccfa855SEd Maste
703*2ccfa855SEd Maste if ((r = cbor_parse_reply(msg, (size_t)msglen, i,
7040afa8e06SEd Maste bio_parse_info)) != FIDO_OK) {
7050afa8e06SEd Maste fido_log_debug("%s: bio_parse_info" , __func__);
706*2ccfa855SEd Maste goto out;
7070afa8e06SEd Maste }
7080afa8e06SEd Maste
709*2ccfa855SEd Maste r = FIDO_OK;
710*2ccfa855SEd Maste out:
711*2ccfa855SEd Maste freezero(msg, FIDO_MAXMSG);
712*2ccfa855SEd Maste
713*2ccfa855SEd Maste return (r);
7140afa8e06SEd Maste }
7150afa8e06SEd Maste
7160afa8e06SEd Maste static int
bio_get_info_wait(fido_dev_t * dev,fido_bio_info_t * i,int * ms)717f540a430SEd Maste bio_get_info_wait(fido_dev_t *dev, fido_bio_info_t *i, int *ms)
7180afa8e06SEd Maste {
7190afa8e06SEd Maste int r;
7200afa8e06SEd Maste
721f540a430SEd Maste if ((r = bio_tx(dev, CMD_GET_INFO, NULL, 0, NULL, NULL,
722f540a430SEd Maste ms)) != FIDO_OK ||
7230afa8e06SEd Maste (r = bio_rx_info(dev, i, ms)) != FIDO_OK) {
7240afa8e06SEd Maste fido_log_debug("%s: tx/rx", __func__);
7250afa8e06SEd Maste return (r);
7260afa8e06SEd Maste }
7270afa8e06SEd Maste
7280afa8e06SEd Maste return (FIDO_OK);
7290afa8e06SEd Maste }
7300afa8e06SEd Maste
7310afa8e06SEd Maste int
fido_bio_dev_get_info(fido_dev_t * dev,fido_bio_info_t * i)7320afa8e06SEd Maste fido_bio_dev_get_info(fido_dev_t *dev, fido_bio_info_t *i)
7330afa8e06SEd Maste {
734f540a430SEd Maste int ms = dev->timeout_ms;
735f540a430SEd Maste
736f540a430SEd Maste return (bio_get_info_wait(dev, i, &ms));
7370afa8e06SEd Maste }
7380afa8e06SEd Maste
7390afa8e06SEd Maste const char *
fido_bio_template_name(const fido_bio_template_t * t)7400afa8e06SEd Maste fido_bio_template_name(const fido_bio_template_t *t)
7410afa8e06SEd Maste {
7420afa8e06SEd Maste return (t->name);
7430afa8e06SEd Maste }
7440afa8e06SEd Maste
7450afa8e06SEd Maste const unsigned char *
fido_bio_template_id_ptr(const fido_bio_template_t * t)7460afa8e06SEd Maste fido_bio_template_id_ptr(const fido_bio_template_t *t)
7470afa8e06SEd Maste {
7480afa8e06SEd Maste return (t->id.ptr);
7490afa8e06SEd Maste }
7500afa8e06SEd Maste
7510afa8e06SEd Maste size_t
fido_bio_template_id_len(const fido_bio_template_t * t)7520afa8e06SEd Maste fido_bio_template_id_len(const fido_bio_template_t *t)
7530afa8e06SEd Maste {
7540afa8e06SEd Maste return (t->id.len);
7550afa8e06SEd Maste }
7560afa8e06SEd Maste
7570afa8e06SEd Maste size_t
fido_bio_template_array_count(const fido_bio_template_array_t * ta)7580afa8e06SEd Maste fido_bio_template_array_count(const fido_bio_template_array_t *ta)
7590afa8e06SEd Maste {
7600afa8e06SEd Maste return (ta->n_rx);
7610afa8e06SEd Maste }
7620afa8e06SEd Maste
7630afa8e06SEd Maste fido_bio_template_array_t *
fido_bio_template_array_new(void)7640afa8e06SEd Maste fido_bio_template_array_new(void)
7650afa8e06SEd Maste {
7660afa8e06SEd Maste return (calloc(1, sizeof(fido_bio_template_array_t)));
7670afa8e06SEd Maste }
7680afa8e06SEd Maste
7690afa8e06SEd Maste fido_bio_template_t *
fido_bio_template_new(void)7700afa8e06SEd Maste fido_bio_template_new(void)
7710afa8e06SEd Maste {
7720afa8e06SEd Maste return (calloc(1, sizeof(fido_bio_template_t)));
7730afa8e06SEd Maste }
7740afa8e06SEd Maste
7750afa8e06SEd Maste void
fido_bio_template_array_free(fido_bio_template_array_t ** tap)7760afa8e06SEd Maste fido_bio_template_array_free(fido_bio_template_array_t **tap)
7770afa8e06SEd Maste {
7780afa8e06SEd Maste fido_bio_template_array_t *ta;
7790afa8e06SEd Maste
7800afa8e06SEd Maste if (tap == NULL || (ta = *tap) == NULL)
7810afa8e06SEd Maste return;
7820afa8e06SEd Maste
7830afa8e06SEd Maste bio_reset_template_array(ta);
7840afa8e06SEd Maste free(ta);
7850afa8e06SEd Maste *tap = NULL;
7860afa8e06SEd Maste }
7870afa8e06SEd Maste
7880afa8e06SEd Maste void
fido_bio_template_free(fido_bio_template_t ** tp)7890afa8e06SEd Maste fido_bio_template_free(fido_bio_template_t **tp)
7900afa8e06SEd Maste {
7910afa8e06SEd Maste fido_bio_template_t *t;
7920afa8e06SEd Maste
7930afa8e06SEd Maste if (tp == NULL || (t = *tp) == NULL)
7940afa8e06SEd Maste return;
7950afa8e06SEd Maste
7960afa8e06SEd Maste bio_reset_template(t);
7970afa8e06SEd Maste free(t);
7980afa8e06SEd Maste *tp = NULL;
7990afa8e06SEd Maste }
8000afa8e06SEd Maste
8010afa8e06SEd Maste int
fido_bio_template_set_name(fido_bio_template_t * t,const char * name)8020afa8e06SEd Maste fido_bio_template_set_name(fido_bio_template_t *t, const char *name)
8030afa8e06SEd Maste {
8040afa8e06SEd Maste free(t->name);
8050afa8e06SEd Maste t->name = NULL;
8060afa8e06SEd Maste
8070afa8e06SEd Maste if (name && (t->name = strdup(name)) == NULL)
8080afa8e06SEd Maste return (FIDO_ERR_INTERNAL);
8090afa8e06SEd Maste
8100afa8e06SEd Maste return (FIDO_OK);
8110afa8e06SEd Maste }
8120afa8e06SEd Maste
8130afa8e06SEd Maste int
fido_bio_template_set_id(fido_bio_template_t * t,const unsigned char * ptr,size_t len)8140afa8e06SEd Maste fido_bio_template_set_id(fido_bio_template_t *t, const unsigned char *ptr,
8150afa8e06SEd Maste size_t len)
8160afa8e06SEd Maste {
8170afa8e06SEd Maste fido_blob_reset(&t->id);
8180afa8e06SEd Maste
8190afa8e06SEd Maste if (ptr && fido_blob_set(&t->id, ptr, len) < 0)
8200afa8e06SEd Maste return (FIDO_ERR_INTERNAL);
8210afa8e06SEd Maste
8220afa8e06SEd Maste return (FIDO_OK);
8230afa8e06SEd Maste }
8240afa8e06SEd Maste
8250afa8e06SEd Maste const fido_bio_template_t *
fido_bio_template(const fido_bio_template_array_t * ta,size_t idx)8260afa8e06SEd Maste fido_bio_template(const fido_bio_template_array_t *ta, size_t idx)
8270afa8e06SEd Maste {
8280afa8e06SEd Maste if (idx >= ta->n_alloc)
8290afa8e06SEd Maste return (NULL);
8300afa8e06SEd Maste
8310afa8e06SEd Maste return (&ta->ptr[idx]);
8320afa8e06SEd Maste }
8330afa8e06SEd Maste
8340afa8e06SEd Maste fido_bio_enroll_t *
fido_bio_enroll_new(void)8350afa8e06SEd Maste fido_bio_enroll_new(void)
8360afa8e06SEd Maste {
8370afa8e06SEd Maste return (calloc(1, sizeof(fido_bio_enroll_t)));
8380afa8e06SEd Maste }
8390afa8e06SEd Maste
8400afa8e06SEd Maste fido_bio_info_t *
fido_bio_info_new(void)8410afa8e06SEd Maste fido_bio_info_new(void)
8420afa8e06SEd Maste {
8430afa8e06SEd Maste return (calloc(1, sizeof(fido_bio_info_t)));
8440afa8e06SEd Maste }
8450afa8e06SEd Maste
8460afa8e06SEd Maste uint8_t
fido_bio_info_type(const fido_bio_info_t * i)8470afa8e06SEd Maste fido_bio_info_type(const fido_bio_info_t *i)
8480afa8e06SEd Maste {
8490afa8e06SEd Maste return (i->type);
8500afa8e06SEd Maste }
8510afa8e06SEd Maste
8520afa8e06SEd Maste uint8_t
fido_bio_info_max_samples(const fido_bio_info_t * i)8530afa8e06SEd Maste fido_bio_info_max_samples(const fido_bio_info_t *i)
8540afa8e06SEd Maste {
8550afa8e06SEd Maste return (i->max_samples);
8560afa8e06SEd Maste }
8570afa8e06SEd Maste
8580afa8e06SEd Maste void
fido_bio_enroll_free(fido_bio_enroll_t ** ep)8590afa8e06SEd Maste fido_bio_enroll_free(fido_bio_enroll_t **ep)
8600afa8e06SEd Maste {
8610afa8e06SEd Maste fido_bio_enroll_t *e;
8620afa8e06SEd Maste
8630afa8e06SEd Maste if (ep == NULL || (e = *ep) == NULL)
8640afa8e06SEd Maste return;
8650afa8e06SEd Maste
8660afa8e06SEd Maste bio_reset_enroll(e);
8670afa8e06SEd Maste
8680afa8e06SEd Maste free(e);
8690afa8e06SEd Maste *ep = NULL;
8700afa8e06SEd Maste }
8710afa8e06SEd Maste
8720afa8e06SEd Maste void
fido_bio_info_free(fido_bio_info_t ** ip)8730afa8e06SEd Maste fido_bio_info_free(fido_bio_info_t **ip)
8740afa8e06SEd Maste {
8750afa8e06SEd Maste fido_bio_info_t *i;
8760afa8e06SEd Maste
8770afa8e06SEd Maste if (ip == NULL || (i = *ip) == NULL)
8780afa8e06SEd Maste return;
8790afa8e06SEd Maste
8800afa8e06SEd Maste free(i);
8810afa8e06SEd Maste *ip = NULL;
8820afa8e06SEd Maste }
8830afa8e06SEd Maste
8840afa8e06SEd Maste uint8_t
fido_bio_enroll_remaining_samples(const fido_bio_enroll_t * e)8850afa8e06SEd Maste fido_bio_enroll_remaining_samples(const fido_bio_enroll_t *e)
8860afa8e06SEd Maste {
8870afa8e06SEd Maste return (e->remaining_samples);
8880afa8e06SEd Maste }
8890afa8e06SEd Maste
8900afa8e06SEd Maste uint8_t
fido_bio_enroll_last_status(const fido_bio_enroll_t * e)8910afa8e06SEd Maste fido_bio_enroll_last_status(const fido_bio_enroll_t *e)
8920afa8e06SEd Maste {
8930afa8e06SEd Maste return (e->last_status);
8940afa8e06SEd Maste }
895