xref: /freebsd/contrib/libfido2/src/dev.c (revision 2ccfa855)
10afa8e06SEd Maste /*
2*2ccfa855SEd Maste  * Copyright (c) 2018-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 
100afa8e06SEd Maste #ifndef TLS
110afa8e06SEd Maste #define TLS
120afa8e06SEd Maste #endif
130afa8e06SEd Maste 
140afa8e06SEd Maste static TLS bool disable_u2f_fallback;
150afa8e06SEd Maste 
160afa8e06SEd Maste #ifdef FIDO_FUZZ
170afa8e06SEd Maste static void
set_random_report_len(fido_dev_t * dev)180afa8e06SEd Maste set_random_report_len(fido_dev_t *dev)
190afa8e06SEd Maste {
200afa8e06SEd Maste 	dev->rx_len = CTAP_MIN_REPORT_LEN +
210afa8e06SEd Maste 	    uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1);
220afa8e06SEd Maste 	dev->tx_len = CTAP_MIN_REPORT_LEN +
230afa8e06SEd Maste 	    uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1);
240afa8e06SEd Maste }
250afa8e06SEd Maste #endif
260afa8e06SEd Maste 
270afa8e06SEd Maste static void
fido_dev_set_extension_flags(fido_dev_t * dev,const fido_cbor_info_t * info)280afa8e06SEd Maste fido_dev_set_extension_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
290afa8e06SEd Maste {
300afa8e06SEd Maste 	char * const	*ptr = fido_cbor_info_extensions_ptr(info);
310afa8e06SEd Maste 	size_t		 len = fido_cbor_info_extensions_len(info);
320afa8e06SEd Maste 
330afa8e06SEd Maste 	for (size_t i = 0; i < len; i++)
340afa8e06SEd Maste 		if (strcmp(ptr[i], "credProtect") == 0)
350afa8e06SEd Maste 			dev->flags |= FIDO_DEV_CRED_PROT;
360afa8e06SEd Maste }
370afa8e06SEd Maste 
380afa8e06SEd Maste static void
fido_dev_set_option_flags(fido_dev_t * dev,const fido_cbor_info_t * info)390afa8e06SEd Maste fido_dev_set_option_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
400afa8e06SEd Maste {
410afa8e06SEd Maste 	char * const	*ptr = fido_cbor_info_options_name_ptr(info);
420afa8e06SEd Maste 	const bool	*val = fido_cbor_info_options_value_ptr(info);
430afa8e06SEd Maste 	size_t		 len = fido_cbor_info_options_len(info);
440afa8e06SEd Maste 
450afa8e06SEd Maste 	for (size_t i = 0; i < len; i++)
460afa8e06SEd Maste 		if (strcmp(ptr[i], "clientPin") == 0) {
47*2ccfa855SEd Maste 			dev->flags |= val[i] ?
48*2ccfa855SEd Maste 			    FIDO_DEV_PIN_SET : FIDO_DEV_PIN_UNSET;
490afa8e06SEd Maste 		} else if (strcmp(ptr[i], "credMgmt") == 0 ||
500afa8e06SEd Maste 			   strcmp(ptr[i], "credentialMgmtPreview") == 0) {
510afa8e06SEd Maste 			if (val[i])
520afa8e06SEd Maste 				dev->flags |= FIDO_DEV_CREDMAN;
530afa8e06SEd Maste 		} else if (strcmp(ptr[i], "uv") == 0) {
54*2ccfa855SEd Maste 			dev->flags |= val[i] ?
55*2ccfa855SEd Maste 			    FIDO_DEV_UV_SET : FIDO_DEV_UV_UNSET;
560afa8e06SEd Maste 		} else if (strcmp(ptr[i], "pinUvAuthToken") == 0) {
570afa8e06SEd Maste 			if (val[i])
580afa8e06SEd Maste 				dev->flags |= FIDO_DEV_TOKEN_PERMS;
590afa8e06SEd Maste 		}
600afa8e06SEd Maste }
610afa8e06SEd Maste 
620afa8e06SEd Maste static void
fido_dev_set_protocol_flags(fido_dev_t * dev,const fido_cbor_info_t * info)630afa8e06SEd Maste fido_dev_set_protocol_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
640afa8e06SEd Maste {
650afa8e06SEd Maste 	const uint8_t	*ptr = fido_cbor_info_protocols_ptr(info);
660afa8e06SEd Maste 	size_t		 len = fido_cbor_info_protocols_len(info);
670afa8e06SEd Maste 
680afa8e06SEd Maste 	for (size_t i = 0; i < len; i++)
690afa8e06SEd Maste 		switch (ptr[i]) {
700afa8e06SEd Maste 		case CTAP_PIN_PROTOCOL1:
710afa8e06SEd Maste 			dev->flags |= FIDO_DEV_PIN_PROTOCOL1;
720afa8e06SEd Maste 			break;
730afa8e06SEd Maste 		case CTAP_PIN_PROTOCOL2:
740afa8e06SEd Maste 			dev->flags |= FIDO_DEV_PIN_PROTOCOL2;
750afa8e06SEd Maste 			break;
760afa8e06SEd Maste 		default:
770afa8e06SEd Maste 			fido_log_debug("%s: unknown protocol %u", __func__,
780afa8e06SEd Maste 			    ptr[i]);
790afa8e06SEd Maste 			break;
800afa8e06SEd Maste 		}
810afa8e06SEd Maste }
820afa8e06SEd Maste 
830afa8e06SEd Maste static void
fido_dev_set_flags(fido_dev_t * dev,const fido_cbor_info_t * info)840afa8e06SEd Maste fido_dev_set_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
850afa8e06SEd Maste {
860afa8e06SEd Maste 	fido_dev_set_extension_flags(dev, info);
870afa8e06SEd Maste 	fido_dev_set_option_flags(dev, info);
880afa8e06SEd Maste 	fido_dev_set_protocol_flags(dev, info);
890afa8e06SEd Maste }
900afa8e06SEd Maste 
910afa8e06SEd Maste static int
fido_dev_open_tx(fido_dev_t * dev,const char * path,int * ms)92f540a430SEd Maste fido_dev_open_tx(fido_dev_t *dev, const char *path, int *ms)
930afa8e06SEd Maste {
940afa8e06SEd Maste 	int r;
950afa8e06SEd Maste 
960afa8e06SEd Maste 	if (dev->io_handle != NULL) {
970afa8e06SEd Maste 		fido_log_debug("%s: handle=%p", __func__, dev->io_handle);
980afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
990afa8e06SEd Maste 	}
1000afa8e06SEd Maste 
1010afa8e06SEd Maste 	if (dev->io.open == NULL || dev->io.close == NULL) {
1020afa8e06SEd Maste 		fido_log_debug("%s: NULL open/close", __func__);
1030afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
1040afa8e06SEd Maste 	}
1050afa8e06SEd Maste 
1060afa8e06SEd Maste 	if (dev->cid != CTAP_CID_BROADCAST) {
1070afa8e06SEd Maste 		fido_log_debug("%s: cid=0x%x", __func__, dev->cid);
1080afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
1090afa8e06SEd Maste 	}
1100afa8e06SEd Maste 
1110afa8e06SEd Maste 	if (fido_get_random(&dev->nonce, sizeof(dev->nonce)) < 0) {
1120afa8e06SEd Maste 		fido_log_debug("%s: fido_get_random", __func__);
1130afa8e06SEd Maste 		return (FIDO_ERR_INTERNAL);
1140afa8e06SEd Maste 	}
1150afa8e06SEd Maste 
1160afa8e06SEd Maste 	if ((dev->io_handle = dev->io.open(path)) == NULL) {
1170afa8e06SEd Maste 		fido_log_debug("%s: dev->io.open", __func__);
1180afa8e06SEd Maste 		return (FIDO_ERR_INTERNAL);
1190afa8e06SEd Maste 	}
1200afa8e06SEd Maste 
1210afa8e06SEd Maste 	if (dev->io_own) {
1220afa8e06SEd Maste 		dev->rx_len = CTAP_MAX_REPORT_LEN;
1230afa8e06SEd Maste 		dev->tx_len = CTAP_MAX_REPORT_LEN;
1240afa8e06SEd Maste 	} else {
1250afa8e06SEd Maste 		dev->rx_len = fido_hid_report_in_len(dev->io_handle);
1260afa8e06SEd Maste 		dev->tx_len = fido_hid_report_out_len(dev->io_handle);
1270afa8e06SEd Maste 	}
1280afa8e06SEd Maste 
1290afa8e06SEd Maste #ifdef FIDO_FUZZ
1300afa8e06SEd Maste 	set_random_report_len(dev);
1310afa8e06SEd Maste #endif
1320afa8e06SEd Maste 
1330afa8e06SEd Maste 	if (dev->rx_len < CTAP_MIN_REPORT_LEN ||
1340afa8e06SEd Maste 	    dev->rx_len > CTAP_MAX_REPORT_LEN) {
1350afa8e06SEd Maste 		fido_log_debug("%s: invalid rx_len %zu", __func__, dev->rx_len);
1360afa8e06SEd Maste 		r = FIDO_ERR_RX;
1370afa8e06SEd Maste 		goto fail;
1380afa8e06SEd Maste 	}
1390afa8e06SEd Maste 
1400afa8e06SEd Maste 	if (dev->tx_len < CTAP_MIN_REPORT_LEN ||
1410afa8e06SEd Maste 	    dev->tx_len > CTAP_MAX_REPORT_LEN) {
1420afa8e06SEd Maste 		fido_log_debug("%s: invalid tx_len %zu", __func__, dev->tx_len);
1430afa8e06SEd Maste 		r = FIDO_ERR_TX;
1440afa8e06SEd Maste 		goto fail;
1450afa8e06SEd Maste 	}
1460afa8e06SEd Maste 
147f540a430SEd Maste 	if (fido_tx(dev, CTAP_CMD_INIT, &dev->nonce, sizeof(dev->nonce),
148f540a430SEd Maste 	    ms) < 0) {
1490afa8e06SEd Maste 		fido_log_debug("%s: fido_tx", __func__);
1500afa8e06SEd Maste 		r = FIDO_ERR_TX;
1510afa8e06SEd Maste 		goto fail;
1520afa8e06SEd Maste 	}
1530afa8e06SEd Maste 
1540afa8e06SEd Maste 	return (FIDO_OK);
1550afa8e06SEd Maste fail:
1560afa8e06SEd Maste 	dev->io.close(dev->io_handle);
1570afa8e06SEd Maste 	dev->io_handle = NULL;
1580afa8e06SEd Maste 
1590afa8e06SEd Maste 	return (r);
1600afa8e06SEd Maste }
1610afa8e06SEd Maste 
1620afa8e06SEd Maste static int
fido_dev_open_rx(fido_dev_t * dev,int * ms)163f540a430SEd Maste fido_dev_open_rx(fido_dev_t *dev, int *ms)
1640afa8e06SEd Maste {
1650afa8e06SEd Maste 	fido_cbor_info_t	*info = NULL;
1660afa8e06SEd Maste 	int			 reply_len;
1670afa8e06SEd Maste 	int			 r;
1680afa8e06SEd Maste 
1690afa8e06SEd Maste 	if ((reply_len = fido_rx(dev, CTAP_CMD_INIT, &dev->attr,
1700afa8e06SEd Maste 	    sizeof(dev->attr), ms)) < 0) {
1710afa8e06SEd Maste 		fido_log_debug("%s: fido_rx", __func__);
1720afa8e06SEd Maste 		r = FIDO_ERR_RX;
1730afa8e06SEd Maste 		goto fail;
1740afa8e06SEd Maste 	}
1750afa8e06SEd Maste 
1760afa8e06SEd Maste #ifdef FIDO_FUZZ
1770afa8e06SEd Maste 	dev->attr.nonce = dev->nonce;
1780afa8e06SEd Maste #endif
1790afa8e06SEd Maste 
1800afa8e06SEd Maste 	if ((size_t)reply_len != sizeof(dev->attr) ||
1810afa8e06SEd Maste 	    dev->attr.nonce != dev->nonce) {
1820afa8e06SEd Maste 		fido_log_debug("%s: invalid nonce", __func__);
1830afa8e06SEd Maste 		r = FIDO_ERR_RX;
1840afa8e06SEd Maste 		goto fail;
1850afa8e06SEd Maste 	}
1860afa8e06SEd Maste 
1870afa8e06SEd Maste 	dev->flags = 0;
1880afa8e06SEd Maste 	dev->cid = dev->attr.cid;
1890afa8e06SEd Maste 
1900afa8e06SEd Maste 	if (fido_dev_is_fido2(dev)) {
1910afa8e06SEd Maste 		if ((info = fido_cbor_info_new()) == NULL) {
1920afa8e06SEd Maste 			fido_log_debug("%s: fido_cbor_info_new", __func__);
1930afa8e06SEd Maste 			r = FIDO_ERR_INTERNAL;
1940afa8e06SEd Maste 			goto fail;
1950afa8e06SEd Maste 		}
1960afa8e06SEd Maste 		if ((r = fido_dev_get_cbor_info_wait(dev, info,
1970afa8e06SEd Maste 		    ms)) != FIDO_OK) {
1980afa8e06SEd Maste 			fido_log_debug("%s: fido_dev_cbor_info_wait: %d",
1990afa8e06SEd Maste 			    __func__, r);
2000afa8e06SEd Maste 			if (disable_u2f_fallback)
2010afa8e06SEd Maste 				goto fail;
2020afa8e06SEd Maste 			fido_log_debug("%s: falling back to u2f", __func__);
2030afa8e06SEd Maste 			fido_dev_force_u2f(dev);
2040afa8e06SEd Maste 		} else {
2050afa8e06SEd Maste 			fido_dev_set_flags(dev, info);
2060afa8e06SEd Maste 		}
2070afa8e06SEd Maste 	}
2080afa8e06SEd Maste 
2090afa8e06SEd Maste 	if (fido_dev_is_fido2(dev) && info != NULL) {
2100afa8e06SEd Maste 		dev->maxmsgsize = fido_cbor_info_maxmsgsiz(info);
2110afa8e06SEd Maste 		fido_log_debug("%s: FIDO_MAXMSG=%d, maxmsgsiz=%lu", __func__,
2120afa8e06SEd Maste 		    FIDO_MAXMSG, (unsigned long)dev->maxmsgsize);
2130afa8e06SEd Maste 	}
2140afa8e06SEd Maste 
2150afa8e06SEd Maste 	r = FIDO_OK;
2160afa8e06SEd Maste fail:
2170afa8e06SEd Maste 	fido_cbor_info_free(&info);
2180afa8e06SEd Maste 
2190afa8e06SEd Maste 	if (r != FIDO_OK) {
2200afa8e06SEd Maste 		dev->io.close(dev->io_handle);
2210afa8e06SEd Maste 		dev->io_handle = NULL;
2220afa8e06SEd Maste 	}
2230afa8e06SEd Maste 
2240afa8e06SEd Maste 	return (r);
2250afa8e06SEd Maste }
2260afa8e06SEd Maste 
2270afa8e06SEd Maste static int
fido_dev_open_wait(fido_dev_t * dev,const char * path,int * ms)228f540a430SEd Maste fido_dev_open_wait(fido_dev_t *dev, const char *path, int *ms)
2290afa8e06SEd Maste {
2300afa8e06SEd Maste 	int r;
2310afa8e06SEd Maste 
2320afa8e06SEd Maste #ifdef USE_WINHELLO
2330afa8e06SEd Maste 	if (strcmp(path, FIDO_WINHELLO_PATH) == 0)
2340afa8e06SEd Maste 		return (fido_winhello_open(dev));
2350afa8e06SEd Maste #endif
236f540a430SEd Maste 	if ((r = fido_dev_open_tx(dev, path, ms)) != FIDO_OK ||
2370afa8e06SEd Maste 	    (r = fido_dev_open_rx(dev, ms)) != FIDO_OK)
2380afa8e06SEd Maste 		return (r);
2390afa8e06SEd Maste 
2400afa8e06SEd Maste 	return (FIDO_OK);
2410afa8e06SEd Maste }
2420afa8e06SEd Maste 
243*2ccfa855SEd Maste static void
run_manifest(fido_dev_info_t * devlist,size_t ilen,size_t * olen,const char * type,int (* manifest)(fido_dev_info_t *,size_t,size_t *))244*2ccfa855SEd Maste run_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen,
245*2ccfa855SEd Maste     const char *type, int (*manifest)(fido_dev_info_t *, size_t, size_t *))
2460afa8e06SEd Maste {
247*2ccfa855SEd Maste 	size_t ndevs = 0;
248*2ccfa855SEd Maste 	int r;
2490afa8e06SEd Maste 
250*2ccfa855SEd Maste 	if (*olen >= ilen) {
251*2ccfa855SEd Maste 		fido_log_debug("%s: skipping %s", __func__, type);
2520afa8e06SEd Maste 		return;
253*2ccfa855SEd Maste 	}
254*2ccfa855SEd Maste 	if ((r = manifest(devlist + *olen, ilen - *olen, &ndevs)) != FIDO_OK)
255*2ccfa855SEd Maste 		fido_log_debug("%s: %s: 0x%x", __func__, type, r);
256*2ccfa855SEd Maste 	fido_log_debug("%s: found %zu %s device%s", __func__, ndevs, type,
257*2ccfa855SEd Maste 	    ndevs == 1 ? "" : "s");
258*2ccfa855SEd Maste 	*olen += ndevs;
2590afa8e06SEd Maste }
2600afa8e06SEd Maste 
2610afa8e06SEd Maste int
fido_dev_info_manifest(fido_dev_info_t * devlist,size_t ilen,size_t * olen)2620afa8e06SEd Maste fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
2630afa8e06SEd Maste {
2640afa8e06SEd Maste 	*olen = 0;
2650afa8e06SEd Maste 
266*2ccfa855SEd Maste 	run_manifest(devlist, ilen, olen, "hid", fido_hid_manifest);
267*2ccfa855SEd Maste #ifdef USE_NFC
268*2ccfa855SEd Maste 	run_manifest(devlist, ilen, olen, "nfc", fido_nfc_manifest);
269*2ccfa855SEd Maste #endif
270*2ccfa855SEd Maste #ifdef USE_PCSC
271*2ccfa855SEd Maste 	run_manifest(devlist, ilen, olen, "pcsc", fido_pcsc_manifest);
2720afa8e06SEd Maste #endif
2730afa8e06SEd Maste #ifdef USE_WINHELLO
274*2ccfa855SEd Maste 	run_manifest(devlist, ilen, olen, "winhello", fido_winhello_manifest);
2750afa8e06SEd Maste #endif
2760afa8e06SEd Maste 
2770afa8e06SEd Maste 	return (FIDO_OK);
2780afa8e06SEd Maste }
2790afa8e06SEd Maste 
2800afa8e06SEd Maste int
fido_dev_open_with_info(fido_dev_t * dev)2810afa8e06SEd Maste fido_dev_open_with_info(fido_dev_t *dev)
2820afa8e06SEd Maste {
283f540a430SEd Maste 	int ms = dev->timeout_ms;
284f540a430SEd Maste 
2850afa8e06SEd Maste 	if (dev->path == NULL)
2860afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
2870afa8e06SEd Maste 
288f540a430SEd Maste 	return (fido_dev_open_wait(dev, dev->path, &ms));
2890afa8e06SEd Maste }
2900afa8e06SEd Maste 
2910afa8e06SEd Maste int
fido_dev_open(fido_dev_t * dev,const char * path)2920afa8e06SEd Maste fido_dev_open(fido_dev_t *dev, const char *path)
2930afa8e06SEd Maste {
294f540a430SEd Maste 	int ms = dev->timeout_ms;
295f540a430SEd Maste 
296*2ccfa855SEd Maste #ifdef USE_NFC
297*2ccfa855SEd Maste 	if (fido_is_nfc(path) && fido_dev_set_nfc(dev) < 0) {
298*2ccfa855SEd Maste 		fido_log_debug("%s: fido_dev_set_nfc", __func__);
299*2ccfa855SEd Maste 		return FIDO_ERR_INTERNAL;
300*2ccfa855SEd Maste 	}
301*2ccfa855SEd Maste #endif
302*2ccfa855SEd Maste #ifdef USE_PCSC
303*2ccfa855SEd Maste 	if (fido_is_pcsc(path) && fido_dev_set_pcsc(dev) < 0) {
304*2ccfa855SEd Maste 		fido_log_debug("%s: fido_dev_set_pcsc", __func__);
305*2ccfa855SEd Maste 		return FIDO_ERR_INTERNAL;
3060afa8e06SEd Maste 	}
3070afa8e06SEd Maste #endif
3080afa8e06SEd Maste 
309f540a430SEd Maste 	return (fido_dev_open_wait(dev, path, &ms));
3100afa8e06SEd Maste }
3110afa8e06SEd Maste 
3120afa8e06SEd Maste int
fido_dev_close(fido_dev_t * dev)3130afa8e06SEd Maste fido_dev_close(fido_dev_t *dev)
3140afa8e06SEd Maste {
3150afa8e06SEd Maste #ifdef USE_WINHELLO
3160afa8e06SEd Maste 	if (dev->flags & FIDO_DEV_WINHELLO)
3170afa8e06SEd Maste 		return (fido_winhello_close(dev));
3180afa8e06SEd Maste #endif
3190afa8e06SEd Maste 	if (dev->io_handle == NULL || dev->io.close == NULL)
3200afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
3210afa8e06SEd Maste 
3220afa8e06SEd Maste 	dev->io.close(dev->io_handle);
3230afa8e06SEd Maste 	dev->io_handle = NULL;
3240afa8e06SEd Maste 	dev->cid = CTAP_CID_BROADCAST;
3250afa8e06SEd Maste 
3260afa8e06SEd Maste 	return (FIDO_OK);
3270afa8e06SEd Maste }
3280afa8e06SEd Maste 
3290afa8e06SEd Maste int
fido_dev_set_sigmask(fido_dev_t * dev,const fido_sigset_t * sigmask)3300afa8e06SEd Maste fido_dev_set_sigmask(fido_dev_t *dev, const fido_sigset_t *sigmask)
3310afa8e06SEd Maste {
332f540a430SEd Maste 	if (dev->io_handle == NULL || sigmask == NULL)
3330afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
3340afa8e06SEd Maste 
335*2ccfa855SEd Maste #ifdef USE_NFC
336f540a430SEd Maste 	if (dev->transport.rx == fido_nfc_rx && dev->io.read == fido_nfc_read)
3370afa8e06SEd Maste 		return (fido_nfc_set_sigmask(dev->io_handle, sigmask));
3380afa8e06SEd Maste #endif
339f540a430SEd Maste 	if (dev->transport.rx == NULL && dev->io.read == fido_hid_read)
3400afa8e06SEd Maste 		return (fido_hid_set_sigmask(dev->io_handle, sigmask));
341f540a430SEd Maste 
342f540a430SEd Maste 	return (FIDO_ERR_INVALID_ARGUMENT);
3430afa8e06SEd Maste }
3440afa8e06SEd Maste 
3450afa8e06SEd Maste int
fido_dev_cancel(fido_dev_t * dev)3460afa8e06SEd Maste fido_dev_cancel(fido_dev_t *dev)
3470afa8e06SEd Maste {
348f540a430SEd Maste 	int ms = dev->timeout_ms;
349f540a430SEd Maste 
3500afa8e06SEd Maste #ifdef USE_WINHELLO
3510afa8e06SEd Maste 	if (dev->flags & FIDO_DEV_WINHELLO)
3520afa8e06SEd Maste 		return (fido_winhello_cancel(dev));
3530afa8e06SEd Maste #endif
3540afa8e06SEd Maste 	if (fido_dev_is_fido2(dev) == false)
3550afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
356f540a430SEd Maste 	if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0, &ms) < 0)
3570afa8e06SEd Maste 		return (FIDO_ERR_TX);
3580afa8e06SEd Maste 
3590afa8e06SEd Maste 	return (FIDO_OK);
3600afa8e06SEd Maste }
3610afa8e06SEd Maste 
3620afa8e06SEd Maste int
fido_dev_set_io_functions(fido_dev_t * dev,const fido_dev_io_t * io)3630afa8e06SEd Maste fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io)
3640afa8e06SEd Maste {
3650afa8e06SEd Maste 	if (dev->io_handle != NULL) {
3660afa8e06SEd Maste 		fido_log_debug("%s: non-NULL handle", __func__);
3670afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
3680afa8e06SEd Maste 	}
3690afa8e06SEd Maste 
3700afa8e06SEd Maste 	if (io == NULL || io->open == NULL || io->close == NULL ||
3710afa8e06SEd Maste 	    io->read == NULL || io->write == NULL) {
3720afa8e06SEd Maste 		fido_log_debug("%s: NULL function", __func__);
3730afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
3740afa8e06SEd Maste 	}
3750afa8e06SEd Maste 
3760afa8e06SEd Maste 	dev->io = *io;
3770afa8e06SEd Maste 	dev->io_own = true;
3780afa8e06SEd Maste 
3790afa8e06SEd Maste 	return (FIDO_OK);
3800afa8e06SEd Maste }
3810afa8e06SEd Maste 
3820afa8e06SEd Maste int
fido_dev_set_transport_functions(fido_dev_t * dev,const fido_dev_transport_t * t)3830afa8e06SEd Maste fido_dev_set_transport_functions(fido_dev_t *dev, const fido_dev_transport_t *t)
3840afa8e06SEd Maste {
3850afa8e06SEd Maste 	if (dev->io_handle != NULL) {
3860afa8e06SEd Maste 		fido_log_debug("%s: non-NULL handle", __func__);
3870afa8e06SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
3880afa8e06SEd Maste 	}
3890afa8e06SEd Maste 
3900afa8e06SEd Maste 	dev->transport = *t;
3910afa8e06SEd Maste 	dev->io_own = true;
3920afa8e06SEd Maste 
3930afa8e06SEd Maste 	return (FIDO_OK);
3940afa8e06SEd Maste }
3950afa8e06SEd Maste 
3963e696dfbSEd Maste void *
fido_dev_io_handle(const fido_dev_t * dev)3973e696dfbSEd Maste fido_dev_io_handle(const fido_dev_t *dev)
3983e696dfbSEd Maste {
3993e696dfbSEd Maste 
4003e696dfbSEd Maste 	return (dev->io_handle);
4013e696dfbSEd Maste }
4023e696dfbSEd Maste 
4030afa8e06SEd Maste void
fido_init(int flags)4040afa8e06SEd Maste fido_init(int flags)
4050afa8e06SEd Maste {
4060afa8e06SEd Maste 	if (flags & FIDO_DEBUG || getenv("FIDO_DEBUG") != NULL)
4070afa8e06SEd Maste 		fido_log_init();
4080afa8e06SEd Maste 
4090afa8e06SEd Maste 	disable_u2f_fallback = (flags & FIDO_DISABLE_U2F_FALLBACK);
4100afa8e06SEd Maste }
4110afa8e06SEd Maste 
4120afa8e06SEd Maste fido_dev_t *
fido_dev_new(void)4130afa8e06SEd Maste fido_dev_new(void)
4140afa8e06SEd Maste {
4150afa8e06SEd Maste 	fido_dev_t *dev;
4160afa8e06SEd Maste 
4170afa8e06SEd Maste 	if ((dev = calloc(1, sizeof(*dev))) == NULL)
4180afa8e06SEd Maste 		return (NULL);
4190afa8e06SEd Maste 
4200afa8e06SEd Maste 	dev->cid = CTAP_CID_BROADCAST;
421f540a430SEd Maste 	dev->timeout_ms = -1;
4220afa8e06SEd Maste 	dev->io = (fido_dev_io_t) {
4230afa8e06SEd Maste 		&fido_hid_open,
4240afa8e06SEd Maste 		&fido_hid_close,
4250afa8e06SEd Maste 		&fido_hid_read,
4260afa8e06SEd Maste 		&fido_hid_write,
4270afa8e06SEd Maste 	};
4280afa8e06SEd Maste 
4290afa8e06SEd Maste 	return (dev);
4300afa8e06SEd Maste }
4310afa8e06SEd Maste 
4320afa8e06SEd Maste fido_dev_t *
fido_dev_new_with_info(const fido_dev_info_t * di)4330afa8e06SEd Maste fido_dev_new_with_info(const fido_dev_info_t *di)
4340afa8e06SEd Maste {
4350afa8e06SEd Maste 	fido_dev_t *dev;
4360afa8e06SEd Maste 
4370afa8e06SEd Maste 	if ((dev = calloc(1, sizeof(*dev))) == NULL)
4380afa8e06SEd Maste 		return (NULL);
4390afa8e06SEd Maste 
4400afa8e06SEd Maste #if 0
4410afa8e06SEd Maste 	if (di->io.open == NULL || di->io.close == NULL ||
4420afa8e06SEd Maste 	    di->io.read == NULL || di->io.write == NULL) {
4430afa8e06SEd Maste 		fido_log_debug("%s: NULL function", __func__);
4440afa8e06SEd Maste 		fido_dev_free(&dev);
4450afa8e06SEd Maste 		return (NULL);
4460afa8e06SEd Maste 	}
4470afa8e06SEd Maste #endif
4480afa8e06SEd Maste 
4490afa8e06SEd Maste 	dev->io = di->io;
4500afa8e06SEd Maste 	dev->io_own = di->transport.tx != NULL || di->transport.rx != NULL;
4510afa8e06SEd Maste 	dev->transport = di->transport;
4520afa8e06SEd Maste 	dev->cid = CTAP_CID_BROADCAST;
453f540a430SEd Maste 	dev->timeout_ms = -1;
4540afa8e06SEd Maste 
4550afa8e06SEd Maste 	if ((dev->path = strdup(di->path)) == NULL) {
4560afa8e06SEd Maste 		fido_log_debug("%s: strdup", __func__);
4570afa8e06SEd Maste 		fido_dev_free(&dev);
4580afa8e06SEd Maste 		return (NULL);
4590afa8e06SEd Maste 	}
4600afa8e06SEd Maste 
4610afa8e06SEd Maste 	return (dev);
4620afa8e06SEd Maste }
4630afa8e06SEd Maste 
4640afa8e06SEd Maste void
fido_dev_free(fido_dev_t ** dev_p)4650afa8e06SEd Maste fido_dev_free(fido_dev_t **dev_p)
4660afa8e06SEd Maste {
4670afa8e06SEd Maste 	fido_dev_t *dev;
4680afa8e06SEd Maste 
4690afa8e06SEd Maste 	if (dev_p == NULL || (dev = *dev_p) == NULL)
4700afa8e06SEd Maste 		return;
4710afa8e06SEd Maste 
4720afa8e06SEd Maste 	free(dev->path);
4730afa8e06SEd Maste 	free(dev);
4740afa8e06SEd Maste 
4750afa8e06SEd Maste 	*dev_p = NULL;
4760afa8e06SEd Maste }
4770afa8e06SEd Maste 
4780afa8e06SEd Maste uint8_t
fido_dev_protocol(const fido_dev_t * dev)4790afa8e06SEd Maste fido_dev_protocol(const fido_dev_t *dev)
4800afa8e06SEd Maste {
4810afa8e06SEd Maste 	return (dev->attr.protocol);
4820afa8e06SEd Maste }
4830afa8e06SEd Maste 
4840afa8e06SEd Maste uint8_t
fido_dev_major(const fido_dev_t * dev)4850afa8e06SEd Maste fido_dev_major(const fido_dev_t *dev)
4860afa8e06SEd Maste {
4870afa8e06SEd Maste 	return (dev->attr.major);
4880afa8e06SEd Maste }
4890afa8e06SEd Maste 
4900afa8e06SEd Maste uint8_t
fido_dev_minor(const fido_dev_t * dev)4910afa8e06SEd Maste fido_dev_minor(const fido_dev_t *dev)
4920afa8e06SEd Maste {
4930afa8e06SEd Maste 	return (dev->attr.minor);
4940afa8e06SEd Maste }
4950afa8e06SEd Maste 
4960afa8e06SEd Maste uint8_t
fido_dev_build(const fido_dev_t * dev)4970afa8e06SEd Maste fido_dev_build(const fido_dev_t *dev)
4980afa8e06SEd Maste {
4990afa8e06SEd Maste 	return (dev->attr.build);
5000afa8e06SEd Maste }
5010afa8e06SEd Maste 
5020afa8e06SEd Maste uint8_t
fido_dev_flags(const fido_dev_t * dev)5030afa8e06SEd Maste fido_dev_flags(const fido_dev_t *dev)
5040afa8e06SEd Maste {
5050afa8e06SEd Maste 	return (dev->attr.flags);
5060afa8e06SEd Maste }
5070afa8e06SEd Maste 
5080afa8e06SEd Maste bool
fido_dev_is_fido2(const fido_dev_t * dev)5090afa8e06SEd Maste fido_dev_is_fido2(const fido_dev_t *dev)
5100afa8e06SEd Maste {
5110afa8e06SEd Maste 	return (dev->attr.flags & FIDO_CAP_CBOR);
5120afa8e06SEd Maste }
5130afa8e06SEd Maste 
5140afa8e06SEd Maste bool
fido_dev_is_winhello(const fido_dev_t * dev)5150afa8e06SEd Maste fido_dev_is_winhello(const fido_dev_t *dev)
5160afa8e06SEd Maste {
5170afa8e06SEd Maste 	return (dev->flags & FIDO_DEV_WINHELLO);
5180afa8e06SEd Maste }
5190afa8e06SEd Maste 
5200afa8e06SEd Maste bool
fido_dev_supports_pin(const fido_dev_t * dev)5210afa8e06SEd Maste fido_dev_supports_pin(const fido_dev_t *dev)
5220afa8e06SEd Maste {
5230afa8e06SEd Maste 	return (dev->flags & (FIDO_DEV_PIN_SET|FIDO_DEV_PIN_UNSET));
5240afa8e06SEd Maste }
5250afa8e06SEd Maste 
5260afa8e06SEd Maste bool
fido_dev_has_pin(const fido_dev_t * dev)5270afa8e06SEd Maste fido_dev_has_pin(const fido_dev_t *dev)
5280afa8e06SEd Maste {
5290afa8e06SEd Maste 	return (dev->flags & FIDO_DEV_PIN_SET);
5300afa8e06SEd Maste }
5310afa8e06SEd Maste 
5320afa8e06SEd Maste bool
fido_dev_supports_cred_prot(const fido_dev_t * dev)5330afa8e06SEd Maste fido_dev_supports_cred_prot(const fido_dev_t *dev)
5340afa8e06SEd Maste {
5350afa8e06SEd Maste 	return (dev->flags & FIDO_DEV_CRED_PROT);
5360afa8e06SEd Maste }
5370afa8e06SEd Maste 
5380afa8e06SEd Maste bool
fido_dev_supports_credman(const fido_dev_t * dev)5390afa8e06SEd Maste fido_dev_supports_credman(const fido_dev_t *dev)
5400afa8e06SEd Maste {
5410afa8e06SEd Maste 	return (dev->flags & FIDO_DEV_CREDMAN);
5420afa8e06SEd Maste }
5430afa8e06SEd Maste 
5440afa8e06SEd Maste bool
fido_dev_supports_uv(const fido_dev_t * dev)5450afa8e06SEd Maste fido_dev_supports_uv(const fido_dev_t *dev)
5460afa8e06SEd Maste {
5470afa8e06SEd Maste 	return (dev->flags & (FIDO_DEV_UV_SET|FIDO_DEV_UV_UNSET));
5480afa8e06SEd Maste }
5490afa8e06SEd Maste 
5500afa8e06SEd Maste bool
fido_dev_has_uv(const fido_dev_t * dev)5510afa8e06SEd Maste fido_dev_has_uv(const fido_dev_t *dev)
5520afa8e06SEd Maste {
5530afa8e06SEd Maste 	return (dev->flags & FIDO_DEV_UV_SET);
5540afa8e06SEd Maste }
5550afa8e06SEd Maste 
5560afa8e06SEd Maste bool
fido_dev_supports_permissions(const fido_dev_t * dev)5570afa8e06SEd Maste fido_dev_supports_permissions(const fido_dev_t *dev)
5580afa8e06SEd Maste {
5590afa8e06SEd Maste 	return (dev->flags & FIDO_DEV_TOKEN_PERMS);
5600afa8e06SEd Maste }
5610afa8e06SEd Maste 
5620afa8e06SEd Maste void
fido_dev_force_u2f(fido_dev_t * dev)5630afa8e06SEd Maste fido_dev_force_u2f(fido_dev_t *dev)
5640afa8e06SEd Maste {
5650afa8e06SEd Maste 	dev->attr.flags &= (uint8_t)~FIDO_CAP_CBOR;
5660afa8e06SEd Maste 	dev->flags = 0;
5670afa8e06SEd Maste }
5680afa8e06SEd Maste 
5690afa8e06SEd Maste void
fido_dev_force_fido2(fido_dev_t * dev)5700afa8e06SEd Maste fido_dev_force_fido2(fido_dev_t *dev)
5710afa8e06SEd Maste {
5720afa8e06SEd Maste 	dev->attr.flags |= FIDO_CAP_CBOR;
5730afa8e06SEd Maste }
5740afa8e06SEd Maste 
5750afa8e06SEd Maste uint8_t
fido_dev_get_pin_protocol(const fido_dev_t * dev)5760afa8e06SEd Maste fido_dev_get_pin_protocol(const fido_dev_t *dev)
5770afa8e06SEd Maste {
5780afa8e06SEd Maste 	if (dev->flags & FIDO_DEV_PIN_PROTOCOL2)
5790afa8e06SEd Maste 		return (CTAP_PIN_PROTOCOL2);
5800afa8e06SEd Maste 	else if (dev->flags & FIDO_DEV_PIN_PROTOCOL1)
5810afa8e06SEd Maste 		return (CTAP_PIN_PROTOCOL1);
5820afa8e06SEd Maste 
5830afa8e06SEd Maste 	return (0);
5840afa8e06SEd Maste }
5850afa8e06SEd Maste 
5860afa8e06SEd Maste uint64_t
fido_dev_maxmsgsize(const fido_dev_t * dev)5870afa8e06SEd Maste fido_dev_maxmsgsize(const fido_dev_t *dev)
5880afa8e06SEd Maste {
5890afa8e06SEd Maste 	return (dev->maxmsgsize);
5900afa8e06SEd Maste }
591f540a430SEd Maste 
592f540a430SEd Maste int
fido_dev_set_timeout(fido_dev_t * dev,int ms)593f540a430SEd Maste fido_dev_set_timeout(fido_dev_t *dev, int ms)
594f540a430SEd Maste {
595f540a430SEd Maste 	if (ms < -1)
596f540a430SEd Maste 		return (FIDO_ERR_INVALID_ARGUMENT);
597f540a430SEd Maste 
598f540a430SEd Maste 	dev->timeout_ms = ms;
599f540a430SEd Maste 
600f540a430SEd Maste 	return (FIDO_OK);
601f540a430SEd Maste }
602