1d75efeb7Sdjm /*
2*ab19a69eSdjm * Copyright (c) 2018-2022 Yubico AB. All rights reserved.
3d75efeb7Sdjm * Use of this source code is governed by a BSD-style
4d75efeb7Sdjm * license that can be found in the LICENSE file.
5d75efeb7Sdjm */
6d75efeb7Sdjm
7d75efeb7Sdjm #include "fido.h"
8d75efeb7Sdjm
932a20e26Sdjm #ifndef TLS
1032a20e26Sdjm #define TLS
1132a20e26Sdjm #endif
1232a20e26Sdjm
13c4a807edSdjm static TLS bool disable_u2f_fallback;
1432a20e26Sdjm
15739189a3Sdjm #ifdef FIDO_FUZZ
16739189a3Sdjm static void
set_random_report_len(fido_dev_t * dev)17739189a3Sdjm set_random_report_len(fido_dev_t *dev)
18739189a3Sdjm {
19739189a3Sdjm dev->rx_len = CTAP_MIN_REPORT_LEN +
20739189a3Sdjm uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1);
21739189a3Sdjm dev->tx_len = CTAP_MIN_REPORT_LEN +
22739189a3Sdjm uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1);
23739189a3Sdjm }
24739189a3Sdjm #endif
25739189a3Sdjm
26739189a3Sdjm static void
fido_dev_set_extension_flags(fido_dev_t * dev,const fido_cbor_info_t * info)27c4a807edSdjm fido_dev_set_extension_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
28739189a3Sdjm {
29c4a807edSdjm char * const *ptr = fido_cbor_info_extensions_ptr(info);
30c4a807edSdjm size_t len = fido_cbor_info_extensions_len(info);
31739189a3Sdjm
328b51a2b1Sdjm for (size_t i = 0; i < len; i++)
338b51a2b1Sdjm if (strcmp(ptr[i], "credProtect") == 0)
348b51a2b1Sdjm dev->flags |= FIDO_DEV_CRED_PROT;
35c4a807edSdjm }
36739189a3Sdjm
37c4a807edSdjm static void
fido_dev_set_option_flags(fido_dev_t * dev,const fido_cbor_info_t * info)38c4a807edSdjm fido_dev_set_option_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
39c4a807edSdjm {
40c4a807edSdjm char * const *ptr = fido_cbor_info_options_name_ptr(info);
41c4a807edSdjm const bool *val = fido_cbor_info_options_value_ptr(info);
42c4a807edSdjm size_t len = fido_cbor_info_options_len(info);
43739189a3Sdjm
448b51a2b1Sdjm for (size_t i = 0; i < len; i++)
458b51a2b1Sdjm if (strcmp(ptr[i], "clientPin") == 0) {
46*ab19a69eSdjm dev->flags |= val[i] ?
47*ab19a69eSdjm FIDO_DEV_PIN_SET : FIDO_DEV_PIN_UNSET;
48c4a807edSdjm } else if (strcmp(ptr[i], "credMgmt") == 0 ||
49c4a807edSdjm strcmp(ptr[i], "credentialMgmtPreview") == 0) {
50c4a807edSdjm if (val[i])
51c4a807edSdjm dev->flags |= FIDO_DEV_CREDMAN;
52c4a807edSdjm } else if (strcmp(ptr[i], "uv") == 0) {
53*ab19a69eSdjm dev->flags |= val[i] ?
54*ab19a69eSdjm FIDO_DEV_UV_SET : FIDO_DEV_UV_UNSET;
55c4a807edSdjm } else if (strcmp(ptr[i], "pinUvAuthToken") == 0) {
56c4a807edSdjm if (val[i])
57c4a807edSdjm dev->flags |= FIDO_DEV_TOKEN_PERMS;
58739189a3Sdjm }
59739189a3Sdjm }
60739189a3Sdjm
61c4a807edSdjm static void
fido_dev_set_protocol_flags(fido_dev_t * dev,const fido_cbor_info_t * info)62c4a807edSdjm fido_dev_set_protocol_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
63c4a807edSdjm {
64c4a807edSdjm const uint8_t *ptr = fido_cbor_info_protocols_ptr(info);
65c4a807edSdjm size_t len = fido_cbor_info_protocols_len(info);
66c4a807edSdjm
67c4a807edSdjm for (size_t i = 0; i < len; i++)
68c4a807edSdjm switch (ptr[i]) {
69c4a807edSdjm case CTAP_PIN_PROTOCOL1:
70c4a807edSdjm dev->flags |= FIDO_DEV_PIN_PROTOCOL1;
71c4a807edSdjm break;
72c4a807edSdjm case CTAP_PIN_PROTOCOL2:
73c4a807edSdjm dev->flags |= FIDO_DEV_PIN_PROTOCOL2;
74c4a807edSdjm break;
75c4a807edSdjm default:
76c4a807edSdjm fido_log_debug("%s: unknown protocol %u", __func__,
77c4a807edSdjm ptr[i]);
78c4a807edSdjm break;
79c4a807edSdjm }
80c4a807edSdjm }
81c4a807edSdjm
82c4a807edSdjm static void
fido_dev_set_flags(fido_dev_t * dev,const fido_cbor_info_t * info)83c4a807edSdjm fido_dev_set_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
84c4a807edSdjm {
85c4a807edSdjm fido_dev_set_extension_flags(dev, info);
86c4a807edSdjm fido_dev_set_option_flags(dev, info);
87c4a807edSdjm fido_dev_set_protocol_flags(dev, info);
88c4a807edSdjm }
89c4a807edSdjm
90d75efeb7Sdjm static int
fido_dev_open_tx(fido_dev_t * dev,const char * path,int * ms)91*ab19a69eSdjm fido_dev_open_tx(fido_dev_t *dev, const char *path, int *ms)
92d75efeb7Sdjm {
93739189a3Sdjm int r;
94d75efeb7Sdjm
95d75efeb7Sdjm if (dev->io_handle != NULL) {
9632a20e26Sdjm fido_log_debug("%s: handle=%p", __func__, dev->io_handle);
97d75efeb7Sdjm return (FIDO_ERR_INVALID_ARGUMENT);
98d75efeb7Sdjm }
99d75efeb7Sdjm
100d75efeb7Sdjm if (dev->io.open == NULL || dev->io.close == NULL) {
10132a20e26Sdjm fido_log_debug("%s: NULL open/close", __func__);
102d75efeb7Sdjm return (FIDO_ERR_INVALID_ARGUMENT);
103d75efeb7Sdjm }
104d75efeb7Sdjm
105c4a807edSdjm if (dev->cid != CTAP_CID_BROADCAST) {
106c4a807edSdjm fido_log_debug("%s: cid=0x%x", __func__, dev->cid);
107c4a807edSdjm return (FIDO_ERR_INVALID_ARGUMENT);
108c4a807edSdjm }
109c4a807edSdjm
110c4a807edSdjm if (fido_get_random(&dev->nonce, sizeof(dev->nonce)) < 0) {
111c4a807edSdjm fido_log_debug("%s: fido_get_random", __func__);
112d75efeb7Sdjm return (FIDO_ERR_INTERNAL);
113d75efeb7Sdjm }
114d75efeb7Sdjm
115d75efeb7Sdjm if ((dev->io_handle = dev->io.open(path)) == NULL) {
11632a20e26Sdjm fido_log_debug("%s: dev->io.open", __func__);
117d75efeb7Sdjm return (FIDO_ERR_INTERNAL);
118d75efeb7Sdjm }
119d75efeb7Sdjm
120739189a3Sdjm if (dev->io_own) {
121739189a3Sdjm dev->rx_len = CTAP_MAX_REPORT_LEN;
122739189a3Sdjm dev->tx_len = CTAP_MAX_REPORT_LEN;
123739189a3Sdjm } else {
124739189a3Sdjm dev->rx_len = fido_hid_report_in_len(dev->io_handle);
125739189a3Sdjm dev->tx_len = fido_hid_report_out_len(dev->io_handle);
126739189a3Sdjm }
127739189a3Sdjm
128739189a3Sdjm #ifdef FIDO_FUZZ
129739189a3Sdjm set_random_report_len(dev);
130739189a3Sdjm #endif
131739189a3Sdjm
132739189a3Sdjm if (dev->rx_len < CTAP_MIN_REPORT_LEN ||
133739189a3Sdjm dev->rx_len > CTAP_MAX_REPORT_LEN) {
134739189a3Sdjm fido_log_debug("%s: invalid rx_len %zu", __func__, dev->rx_len);
135739189a3Sdjm r = FIDO_ERR_RX;
136739189a3Sdjm goto fail;
137739189a3Sdjm }
138739189a3Sdjm
139739189a3Sdjm if (dev->tx_len < CTAP_MIN_REPORT_LEN ||
140739189a3Sdjm dev->tx_len > CTAP_MAX_REPORT_LEN) {
141739189a3Sdjm fido_log_debug("%s: invalid tx_len %zu", __func__, dev->tx_len);
142739189a3Sdjm r = FIDO_ERR_TX;
143739189a3Sdjm goto fail;
144739189a3Sdjm }
145739189a3Sdjm
146*ab19a69eSdjm if (fido_tx(dev, CTAP_CMD_INIT, &dev->nonce, sizeof(dev->nonce),
147*ab19a69eSdjm ms) < 0) {
14832a20e26Sdjm fido_log_debug("%s: fido_tx", __func__);
149739189a3Sdjm r = FIDO_ERR_TX;
150739189a3Sdjm goto fail;
151d75efeb7Sdjm }
152d75efeb7Sdjm
153d75efeb7Sdjm return (FIDO_OK);
154739189a3Sdjm fail:
155739189a3Sdjm dev->io.close(dev->io_handle);
156739189a3Sdjm dev->io_handle = NULL;
157739189a3Sdjm
158739189a3Sdjm return (r);
159d75efeb7Sdjm }
160d75efeb7Sdjm
161d75efeb7Sdjm static int
fido_dev_open_rx(fido_dev_t * dev,int * ms)162*ab19a69eSdjm fido_dev_open_rx(fido_dev_t *dev, int *ms)
163d75efeb7Sdjm {
16432a20e26Sdjm fido_cbor_info_t *info = NULL;
16532a20e26Sdjm int reply_len;
16632a20e26Sdjm int r;
167d75efeb7Sdjm
16832a20e26Sdjm if ((reply_len = fido_rx(dev, CTAP_CMD_INIT, &dev->attr,
16932a20e26Sdjm sizeof(dev->attr), ms)) < 0) {
17032a20e26Sdjm fido_log_debug("%s: fido_rx", __func__);
17132a20e26Sdjm r = FIDO_ERR_RX;
172d75efeb7Sdjm goto fail;
173d75efeb7Sdjm }
174d75efeb7Sdjm
175d75efeb7Sdjm #ifdef FIDO_FUZZ
176d75efeb7Sdjm dev->attr.nonce = dev->nonce;
177d75efeb7Sdjm #endif
178d75efeb7Sdjm
17932a20e26Sdjm if ((size_t)reply_len != sizeof(dev->attr) ||
18032a20e26Sdjm dev->attr.nonce != dev->nonce) {
18132a20e26Sdjm fido_log_debug("%s: invalid nonce", __func__);
18232a20e26Sdjm r = FIDO_ERR_RX;
183d75efeb7Sdjm goto fail;
184d75efeb7Sdjm }
185d75efeb7Sdjm
186739189a3Sdjm dev->flags = 0;
187d75efeb7Sdjm dev->cid = dev->attr.cid;
188d75efeb7Sdjm
18932a20e26Sdjm if (fido_dev_is_fido2(dev)) {
19032a20e26Sdjm if ((info = fido_cbor_info_new()) == NULL) {
19132a20e26Sdjm fido_log_debug("%s: fido_cbor_info_new", __func__);
19232a20e26Sdjm r = FIDO_ERR_INTERNAL;
19332a20e26Sdjm goto fail;
19432a20e26Sdjm }
195c4a807edSdjm if ((r = fido_dev_get_cbor_info_wait(dev, info,
196c4a807edSdjm ms)) != FIDO_OK) {
197c4a807edSdjm fido_log_debug("%s: fido_dev_cbor_info_wait: %d",
198c4a807edSdjm __func__, r);
199c4a807edSdjm if (disable_u2f_fallback)
200c4a807edSdjm goto fail;
20132a20e26Sdjm fido_log_debug("%s: falling back to u2f", __func__);
20232a20e26Sdjm fido_dev_force_u2f(dev);
203739189a3Sdjm } else {
204739189a3Sdjm fido_dev_set_flags(dev, info);
20532a20e26Sdjm }
20632a20e26Sdjm }
20732a20e26Sdjm
20832a20e26Sdjm if (fido_dev_is_fido2(dev) && info != NULL) {
209c4a807edSdjm dev->maxmsgsize = fido_cbor_info_maxmsgsiz(info);
21032a20e26Sdjm fido_log_debug("%s: FIDO_MAXMSG=%d, maxmsgsiz=%lu", __func__,
211c4a807edSdjm FIDO_MAXMSG, (unsigned long)dev->maxmsgsize);
21232a20e26Sdjm }
21332a20e26Sdjm
21432a20e26Sdjm r = FIDO_OK;
215d75efeb7Sdjm fail:
21632a20e26Sdjm fido_cbor_info_free(&info);
21732a20e26Sdjm
21832a20e26Sdjm if (r != FIDO_OK) {
219d75efeb7Sdjm dev->io.close(dev->io_handle);
220d75efeb7Sdjm dev->io_handle = NULL;
22132a20e26Sdjm }
222d75efeb7Sdjm
22332a20e26Sdjm return (r);
224d75efeb7Sdjm }
225d75efeb7Sdjm
226d75efeb7Sdjm static int
fido_dev_open_wait(fido_dev_t * dev,const char * path,int * ms)227*ab19a69eSdjm fido_dev_open_wait(fido_dev_t *dev, const char *path, int *ms)
228d75efeb7Sdjm {
229d75efeb7Sdjm int r;
230d75efeb7Sdjm
231c4a807edSdjm #ifdef USE_WINHELLO
232c4a807edSdjm if (strcmp(path, FIDO_WINHELLO_PATH) == 0)
233c4a807edSdjm return (fido_winhello_open(dev));
234c4a807edSdjm #endif
235*ab19a69eSdjm if ((r = fido_dev_open_tx(dev, path, ms)) != FIDO_OK ||
236d75efeb7Sdjm (r = fido_dev_open_rx(dev, ms)) != FIDO_OK)
237d75efeb7Sdjm return (r);
238d75efeb7Sdjm
239d75efeb7Sdjm return (FIDO_OK);
240d75efeb7Sdjm }
241d75efeb7Sdjm
242*ab19a69eSdjm 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 *))243*ab19a69eSdjm run_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen,
244*ab19a69eSdjm const char *type, int (*manifest)(fido_dev_info_t *, size_t, size_t *))
24532a20e26Sdjm {
246*ab19a69eSdjm size_t ndevs = 0;
247*ab19a69eSdjm int r;
24832a20e26Sdjm
249*ab19a69eSdjm if (*olen >= ilen) {
250*ab19a69eSdjm fido_log_debug("%s: skipping %s", __func__, type);
25132a20e26Sdjm return;
252*ab19a69eSdjm }
253*ab19a69eSdjm if ((r = manifest(devlist + *olen, ilen - *olen, &ndevs)) != FIDO_OK)
254*ab19a69eSdjm fido_log_debug("%s: %s: 0x%x", __func__, type, r);
255*ab19a69eSdjm fido_log_debug("%s: found %zu %s device%s", __func__, ndevs, type,
256*ab19a69eSdjm ndevs == 1 ? "" : "s");
257*ab19a69eSdjm *olen += ndevs;
25832a20e26Sdjm }
25932a20e26Sdjm
26032a20e26Sdjm int
fido_dev_info_manifest(fido_dev_info_t * devlist,size_t ilen,size_t * olen)26132a20e26Sdjm fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
26232a20e26Sdjm {
26332a20e26Sdjm *olen = 0;
26432a20e26Sdjm
265*ab19a69eSdjm run_manifest(devlist, ilen, olen, "hid", fido_hid_manifest);
266*ab19a69eSdjm #ifdef USE_NFC
267*ab19a69eSdjm run_manifest(devlist, ilen, olen, "nfc", fido_nfc_manifest);
268*ab19a69eSdjm #endif
269*ab19a69eSdjm #ifdef USE_PCSC
270*ab19a69eSdjm run_manifest(devlist, ilen, olen, "pcsc", fido_pcsc_manifest);
271c4a807edSdjm #endif
272c4a807edSdjm #ifdef USE_WINHELLO
273*ab19a69eSdjm run_manifest(devlist, ilen, olen, "winhello", fido_winhello_manifest);
274c4a807edSdjm #endif
27532a20e26Sdjm
27632a20e26Sdjm return (FIDO_OK);
27732a20e26Sdjm }
27832a20e26Sdjm
27932a20e26Sdjm int
fido_dev_open_with_info(fido_dev_t * dev)28032a20e26Sdjm fido_dev_open_with_info(fido_dev_t *dev)
28132a20e26Sdjm {
282*ab19a69eSdjm int ms = dev->timeout_ms;
283*ab19a69eSdjm
28432a20e26Sdjm if (dev->path == NULL)
28532a20e26Sdjm return (FIDO_ERR_INVALID_ARGUMENT);
28632a20e26Sdjm
287*ab19a69eSdjm return (fido_dev_open_wait(dev, dev->path, &ms));
28832a20e26Sdjm }
28932a20e26Sdjm
29032a20e26Sdjm int
fido_dev_open(fido_dev_t * dev,const char * path)291d75efeb7Sdjm fido_dev_open(fido_dev_t *dev, const char *path)
292d75efeb7Sdjm {
293*ab19a69eSdjm int ms = dev->timeout_ms;
294*ab19a69eSdjm
295*ab19a69eSdjm #ifdef USE_NFC
296*ab19a69eSdjm if (fido_is_nfc(path) && fido_dev_set_nfc(dev) < 0) {
297*ab19a69eSdjm fido_log_debug("%s: fido_dev_set_nfc", __func__);
298*ab19a69eSdjm return FIDO_ERR_INTERNAL;
299*ab19a69eSdjm }
300*ab19a69eSdjm #endif
301*ab19a69eSdjm #ifdef USE_PCSC
302*ab19a69eSdjm if (fido_is_pcsc(path) && fido_dev_set_pcsc(dev) < 0) {
303*ab19a69eSdjm fido_log_debug("%s: fido_dev_set_pcsc", __func__);
304*ab19a69eSdjm return FIDO_ERR_INTERNAL;
305c4a807edSdjm }
306c4a807edSdjm #endif
307c4a807edSdjm
308*ab19a69eSdjm return (fido_dev_open_wait(dev, path, &ms));
309d75efeb7Sdjm }
310d75efeb7Sdjm
311d75efeb7Sdjm int
fido_dev_close(fido_dev_t * dev)312d75efeb7Sdjm fido_dev_close(fido_dev_t *dev)
313d75efeb7Sdjm {
314c4a807edSdjm #ifdef USE_WINHELLO
315c4a807edSdjm if (dev->flags & FIDO_DEV_WINHELLO)
316c4a807edSdjm return (fido_winhello_close(dev));
317c4a807edSdjm #endif
318d75efeb7Sdjm if (dev->io_handle == NULL || dev->io.close == NULL)
319d75efeb7Sdjm return (FIDO_ERR_INVALID_ARGUMENT);
320d75efeb7Sdjm
321d75efeb7Sdjm dev->io.close(dev->io_handle);
322d75efeb7Sdjm dev->io_handle = NULL;
323c4a807edSdjm dev->cid = CTAP_CID_BROADCAST;
324d75efeb7Sdjm
325d75efeb7Sdjm return (FIDO_OK);
326d75efeb7Sdjm }
327d75efeb7Sdjm
328d75efeb7Sdjm int
fido_dev_set_sigmask(fido_dev_t * dev,const fido_sigset_t * sigmask)329c4a807edSdjm fido_dev_set_sigmask(fido_dev_t *dev, const fido_sigset_t *sigmask)
330d75efeb7Sdjm {
331*ab19a69eSdjm if (dev->io_handle == NULL || sigmask == NULL)
332739189a3Sdjm return (FIDO_ERR_INVALID_ARGUMENT);
333739189a3Sdjm
334*ab19a69eSdjm #ifdef USE_NFC
335*ab19a69eSdjm if (dev->transport.rx == fido_nfc_rx && dev->io.read == fido_nfc_read)
336c4a807edSdjm return (fido_nfc_set_sigmask(dev->io_handle, sigmask));
337c4a807edSdjm #endif
338*ab19a69eSdjm if (dev->transport.rx == NULL && dev->io.read == fido_hid_read)
339c4a807edSdjm return (fido_hid_set_sigmask(dev->io_handle, sigmask));
340*ab19a69eSdjm
341*ab19a69eSdjm return (FIDO_ERR_INVALID_ARGUMENT);
342c4a807edSdjm }
343c4a807edSdjm
344c4a807edSdjm int
fido_dev_cancel(fido_dev_t * dev)345c4a807edSdjm fido_dev_cancel(fido_dev_t *dev)
346c4a807edSdjm {
347*ab19a69eSdjm int ms = dev->timeout_ms;
348*ab19a69eSdjm
349c4a807edSdjm #ifdef USE_WINHELLO
350c4a807edSdjm if (dev->flags & FIDO_DEV_WINHELLO)
351c4a807edSdjm return (fido_winhello_cancel(dev));
352c4a807edSdjm #endif
353c4a807edSdjm if (fido_dev_is_fido2(dev) == false)
354c4a807edSdjm return (FIDO_ERR_INVALID_ARGUMENT);
355*ab19a69eSdjm if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0, &ms) < 0)
356d75efeb7Sdjm return (FIDO_ERR_TX);
357d75efeb7Sdjm
358d75efeb7Sdjm return (FIDO_OK);
359d75efeb7Sdjm }
360d75efeb7Sdjm
361d75efeb7Sdjm int
fido_dev_set_io_functions(fido_dev_t * dev,const fido_dev_io_t * io)362d75efeb7Sdjm fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io)
363d75efeb7Sdjm {
364d75efeb7Sdjm if (dev->io_handle != NULL) {
365739189a3Sdjm fido_log_debug("%s: non-NULL handle", __func__);
366d75efeb7Sdjm return (FIDO_ERR_INVALID_ARGUMENT);
367d75efeb7Sdjm }
368d75efeb7Sdjm
369d75efeb7Sdjm if (io == NULL || io->open == NULL || io->close == NULL ||
370d75efeb7Sdjm io->read == NULL || io->write == NULL) {
37132a20e26Sdjm fido_log_debug("%s: NULL function", __func__);
372d75efeb7Sdjm return (FIDO_ERR_INVALID_ARGUMENT);
373d75efeb7Sdjm }
374d75efeb7Sdjm
37532a20e26Sdjm dev->io = *io;
376739189a3Sdjm dev->io_own = true;
377739189a3Sdjm
378739189a3Sdjm return (FIDO_OK);
379739189a3Sdjm }
380739189a3Sdjm
381739189a3Sdjm int
fido_dev_set_transport_functions(fido_dev_t * dev,const fido_dev_transport_t * t)382739189a3Sdjm fido_dev_set_transport_functions(fido_dev_t *dev, const fido_dev_transport_t *t)
383739189a3Sdjm {
384739189a3Sdjm if (dev->io_handle != NULL) {
385739189a3Sdjm fido_log_debug("%s: non-NULL handle", __func__);
386739189a3Sdjm return (FIDO_ERR_INVALID_ARGUMENT);
387739189a3Sdjm }
388739189a3Sdjm
389739189a3Sdjm dev->transport = *t;
390739189a3Sdjm dev->io_own = true;
391d75efeb7Sdjm
392d75efeb7Sdjm return (FIDO_OK);
393d75efeb7Sdjm }
394d75efeb7Sdjm
395*ab19a69eSdjm void *
fido_dev_io_handle(const fido_dev_t * dev)396*ab19a69eSdjm fido_dev_io_handle(const fido_dev_t *dev)
397*ab19a69eSdjm {
398*ab19a69eSdjm
399*ab19a69eSdjm return (dev->io_handle);
400*ab19a69eSdjm }
401*ab19a69eSdjm
402d75efeb7Sdjm void
fido_init(int flags)403d75efeb7Sdjm fido_init(int flags)
404d75efeb7Sdjm {
405d75efeb7Sdjm if (flags & FIDO_DEBUG || getenv("FIDO_DEBUG") != NULL)
40632a20e26Sdjm fido_log_init();
407c4a807edSdjm
408c4a807edSdjm disable_u2f_fallback = (flags & FIDO_DISABLE_U2F_FALLBACK);
409d75efeb7Sdjm }
410d75efeb7Sdjm
411d75efeb7Sdjm fido_dev_t *
fido_dev_new(void)412d75efeb7Sdjm fido_dev_new(void)
413d75efeb7Sdjm {
414d75efeb7Sdjm fido_dev_t *dev;
41532a20e26Sdjm
41632a20e26Sdjm if ((dev = calloc(1, sizeof(*dev))) == NULL)
41732a20e26Sdjm return (NULL);
41832a20e26Sdjm
41932a20e26Sdjm dev->cid = CTAP_CID_BROADCAST;
420*ab19a69eSdjm dev->timeout_ms = -1;
42132a20e26Sdjm dev->io = (fido_dev_io_t) {
42232a20e26Sdjm &fido_hid_open,
42332a20e26Sdjm &fido_hid_close,
42432a20e26Sdjm &fido_hid_read,
42532a20e26Sdjm &fido_hid_write,
42632a20e26Sdjm };
42732a20e26Sdjm
42832a20e26Sdjm return (dev);
42932a20e26Sdjm }
43032a20e26Sdjm
43132a20e26Sdjm fido_dev_t *
fido_dev_new_with_info(const fido_dev_info_t * di)43232a20e26Sdjm fido_dev_new_with_info(const fido_dev_info_t *di)
43332a20e26Sdjm {
43432a20e26Sdjm fido_dev_t *dev;
435d75efeb7Sdjm
436d75efeb7Sdjm if ((dev = calloc(1, sizeof(*dev))) == NULL)
437d75efeb7Sdjm return (NULL);
438d75efeb7Sdjm
439c4a807edSdjm #if 0
44032a20e26Sdjm if (di->io.open == NULL || di->io.close == NULL ||
44132a20e26Sdjm di->io.read == NULL || di->io.write == NULL) {
44232a20e26Sdjm fido_log_debug("%s: NULL function", __func__);
44332a20e26Sdjm fido_dev_free(&dev);
44432a20e26Sdjm return (NULL);
44532a20e26Sdjm }
446c4a807edSdjm #endif
447d75efeb7Sdjm
44832a20e26Sdjm dev->io = di->io;
449c4a807edSdjm dev->io_own = di->transport.tx != NULL || di->transport.rx != NULL;
450739189a3Sdjm dev->transport = di->transport;
451c4a807edSdjm dev->cid = CTAP_CID_BROADCAST;
452*ab19a69eSdjm dev->timeout_ms = -1;
453739189a3Sdjm
45432a20e26Sdjm if ((dev->path = strdup(di->path)) == NULL) {
45532a20e26Sdjm fido_log_debug("%s: strdup", __func__);
456d75efeb7Sdjm fido_dev_free(&dev);
457d75efeb7Sdjm return (NULL);
458d75efeb7Sdjm }
459d75efeb7Sdjm
460d75efeb7Sdjm return (dev);
461d75efeb7Sdjm }
462d75efeb7Sdjm
463d75efeb7Sdjm void
fido_dev_free(fido_dev_t ** dev_p)464d75efeb7Sdjm fido_dev_free(fido_dev_t **dev_p)
465d75efeb7Sdjm {
466d75efeb7Sdjm fido_dev_t *dev;
467d75efeb7Sdjm
468d75efeb7Sdjm if (dev_p == NULL || (dev = *dev_p) == NULL)
469d75efeb7Sdjm return;
470d75efeb7Sdjm
47132a20e26Sdjm free(dev->path);
472d75efeb7Sdjm free(dev);
473d75efeb7Sdjm
474d75efeb7Sdjm *dev_p = NULL;
475d75efeb7Sdjm }
476d75efeb7Sdjm
477d75efeb7Sdjm uint8_t
fido_dev_protocol(const fido_dev_t * dev)478d75efeb7Sdjm fido_dev_protocol(const fido_dev_t *dev)
479d75efeb7Sdjm {
480d75efeb7Sdjm return (dev->attr.protocol);
481d75efeb7Sdjm }
482d75efeb7Sdjm
483d75efeb7Sdjm uint8_t
fido_dev_major(const fido_dev_t * dev)484d75efeb7Sdjm fido_dev_major(const fido_dev_t *dev)
485d75efeb7Sdjm {
486d75efeb7Sdjm return (dev->attr.major);
487d75efeb7Sdjm }
488d75efeb7Sdjm
489d75efeb7Sdjm uint8_t
fido_dev_minor(const fido_dev_t * dev)490d75efeb7Sdjm fido_dev_minor(const fido_dev_t *dev)
491d75efeb7Sdjm {
492d75efeb7Sdjm return (dev->attr.minor);
493d75efeb7Sdjm }
494d75efeb7Sdjm
495d75efeb7Sdjm uint8_t
fido_dev_build(const fido_dev_t * dev)496d75efeb7Sdjm fido_dev_build(const fido_dev_t *dev)
497d75efeb7Sdjm {
498d75efeb7Sdjm return (dev->attr.build);
499d75efeb7Sdjm }
500d75efeb7Sdjm
501d75efeb7Sdjm uint8_t
fido_dev_flags(const fido_dev_t * dev)502d75efeb7Sdjm fido_dev_flags(const fido_dev_t *dev)
503d75efeb7Sdjm {
504d75efeb7Sdjm return (dev->attr.flags);
505d75efeb7Sdjm }
506d75efeb7Sdjm
507d75efeb7Sdjm bool
fido_dev_is_fido2(const fido_dev_t * dev)508d75efeb7Sdjm fido_dev_is_fido2(const fido_dev_t *dev)
509d75efeb7Sdjm {
510d75efeb7Sdjm return (dev->attr.flags & FIDO_CAP_CBOR);
511d75efeb7Sdjm }
512d75efeb7Sdjm
513739189a3Sdjm bool
fido_dev_is_winhello(const fido_dev_t * dev)514c4a807edSdjm fido_dev_is_winhello(const fido_dev_t *dev)
515c4a807edSdjm {
516c4a807edSdjm return (dev->flags & FIDO_DEV_WINHELLO);
517c4a807edSdjm }
518c4a807edSdjm
519c4a807edSdjm bool
fido_dev_supports_pin(const fido_dev_t * dev)520739189a3Sdjm fido_dev_supports_pin(const fido_dev_t *dev)
521739189a3Sdjm {
5228b51a2b1Sdjm return (dev->flags & (FIDO_DEV_PIN_SET|FIDO_DEV_PIN_UNSET));
5238b51a2b1Sdjm }
5248b51a2b1Sdjm
5258b51a2b1Sdjm bool
fido_dev_has_pin(const fido_dev_t * dev)5268b51a2b1Sdjm fido_dev_has_pin(const fido_dev_t *dev)
5278b51a2b1Sdjm {
5288b51a2b1Sdjm return (dev->flags & FIDO_DEV_PIN_SET);
529739189a3Sdjm }
530739189a3Sdjm
531739189a3Sdjm bool
fido_dev_supports_cred_prot(const fido_dev_t * dev)532739189a3Sdjm fido_dev_supports_cred_prot(const fido_dev_t *dev)
533739189a3Sdjm {
5348b51a2b1Sdjm return (dev->flags & FIDO_DEV_CRED_PROT);
535739189a3Sdjm }
536739189a3Sdjm
537c4a807edSdjm bool
fido_dev_supports_credman(const fido_dev_t * dev)538c4a807edSdjm fido_dev_supports_credman(const fido_dev_t *dev)
539c4a807edSdjm {
540c4a807edSdjm return (dev->flags & FIDO_DEV_CREDMAN);
541c4a807edSdjm }
542c4a807edSdjm
543c4a807edSdjm bool
fido_dev_supports_uv(const fido_dev_t * dev)544c4a807edSdjm fido_dev_supports_uv(const fido_dev_t *dev)
545c4a807edSdjm {
546c4a807edSdjm return (dev->flags & (FIDO_DEV_UV_SET|FIDO_DEV_UV_UNSET));
547c4a807edSdjm }
548c4a807edSdjm
549c4a807edSdjm bool
fido_dev_has_uv(const fido_dev_t * dev)550c4a807edSdjm fido_dev_has_uv(const fido_dev_t *dev)
551c4a807edSdjm {
552c4a807edSdjm return (dev->flags & FIDO_DEV_UV_SET);
553c4a807edSdjm }
554c4a807edSdjm
555c4a807edSdjm bool
fido_dev_supports_permissions(const fido_dev_t * dev)556c4a807edSdjm fido_dev_supports_permissions(const fido_dev_t *dev)
557c4a807edSdjm {
558c4a807edSdjm return (dev->flags & FIDO_DEV_TOKEN_PERMS);
559c4a807edSdjm }
560c4a807edSdjm
561d75efeb7Sdjm void
fido_dev_force_u2f(fido_dev_t * dev)562d75efeb7Sdjm fido_dev_force_u2f(fido_dev_t *dev)
563d75efeb7Sdjm {
564739189a3Sdjm dev->attr.flags &= (uint8_t)~FIDO_CAP_CBOR;
565739189a3Sdjm dev->flags = 0;
566d75efeb7Sdjm }
567d75efeb7Sdjm
568d75efeb7Sdjm void
fido_dev_force_fido2(fido_dev_t * dev)569d75efeb7Sdjm fido_dev_force_fido2(fido_dev_t *dev)
570d75efeb7Sdjm {
571d75efeb7Sdjm dev->attr.flags |= FIDO_CAP_CBOR;
572d75efeb7Sdjm }
573c4a807edSdjm
574c4a807edSdjm uint8_t
fido_dev_get_pin_protocol(const fido_dev_t * dev)575c4a807edSdjm fido_dev_get_pin_protocol(const fido_dev_t *dev)
576c4a807edSdjm {
577c4a807edSdjm if (dev->flags & FIDO_DEV_PIN_PROTOCOL2)
578c4a807edSdjm return (CTAP_PIN_PROTOCOL2);
579c4a807edSdjm else if (dev->flags & FIDO_DEV_PIN_PROTOCOL1)
580c4a807edSdjm return (CTAP_PIN_PROTOCOL1);
581c4a807edSdjm
582c4a807edSdjm return (0);
583c4a807edSdjm }
584c4a807edSdjm
585c4a807edSdjm uint64_t
fido_dev_maxmsgsize(const fido_dev_t * dev)586c4a807edSdjm fido_dev_maxmsgsize(const fido_dev_t *dev)
587c4a807edSdjm {
588c4a807edSdjm return (dev->maxmsgsize);
589c4a807edSdjm }
590*ab19a69eSdjm
591*ab19a69eSdjm int
fido_dev_set_timeout(fido_dev_t * dev,int ms)592*ab19a69eSdjm fido_dev_set_timeout(fido_dev_t *dev, int ms)
593*ab19a69eSdjm {
594*ab19a69eSdjm if (ms < -1)
595*ab19a69eSdjm return (FIDO_ERR_INVALID_ARGUMENT);
596*ab19a69eSdjm
597*ab19a69eSdjm dev->timeout_ms = ms;
598*ab19a69eSdjm
599*ab19a69eSdjm return (FIDO_OK);
600*ab19a69eSdjm }
601