2018-04-19 08:51:38 +02:00
|
|
|
/*
|
2022-02-23 15:27:44 +01:00
|
|
|
* Copyright (c) 2018-2022 Yubico AB. All rights reserved.
|
2018-04-19 08:51:38 +02:00
|
|
|
* Use of this source code is governed by a BSD-style
|
|
|
|
|
* license that can be found in the LICENSE file.
|
2022-08-02 10:59:49 +02:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2018-04-19 08:51:38 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "fido.h"
|
|
|
|
|
|
2019-12-09 10:58:33 +01:00
|
|
|
#ifndef TLS
|
|
|
|
|
#define TLS
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-03-03 16:55:26 +01:00
|
|
|
static TLS bool disable_u2f_fallback;
|
2019-11-18 18:41:21 -08:00
|
|
|
|
2020-05-10 11:59:13 +02:00
|
|
|
#ifdef FIDO_FUZZ
|
|
|
|
|
static void
|
|
|
|
|
set_random_report_len(fido_dev_t *dev)
|
|
|
|
|
{
|
2020-05-23 13:00:34 +02:00
|
|
|
dev->rx_len = CTAP_MIN_REPORT_LEN +
|
2020-05-10 11:59:13 +02:00
|
|
|
uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1);
|
2020-05-23 13:00:34 +02:00
|
|
|
dev->tx_len = CTAP_MIN_REPORT_LEN +
|
2020-05-10 11:59:13 +02:00
|
|
|
uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-08-07 11:43:17 +02:00
|
|
|
static void
|
2020-10-05 15:26:20 +02:00
|
|
|
fido_dev_set_extension_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
|
2020-08-07 11:43:17 +02:00
|
|
|
{
|
2020-10-05 15:26:20 +02:00
|
|
|
char * const *ptr = fido_cbor_info_extensions_ptr(info);
|
|
|
|
|
size_t len = fido_cbor_info_extensions_len(info);
|
2020-08-07 11:43:17 +02:00
|
|
|
|
2020-08-15 12:43:01 +02:00
|
|
|
for (size_t i = 0; i < len; i++)
|
|
|
|
|
if (strcmp(ptr[i], "credProtect") == 0)
|
|
|
|
|
dev->flags |= FIDO_DEV_CRED_PROT;
|
2020-10-05 15:26:20 +02:00
|
|
|
}
|
2020-08-07 11:43:17 +02:00
|
|
|
|
2020-10-05 15:26:20 +02:00
|
|
|
static void
|
|
|
|
|
fido_dev_set_option_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
|
|
|
|
|
{
|
|
|
|
|
char * const *ptr = fido_cbor_info_options_name_ptr(info);
|
|
|
|
|
const bool *val = fido_cbor_info_options_value_ptr(info);
|
|
|
|
|
size_t len = fido_cbor_info_options_len(info);
|
2020-08-07 11:43:17 +02:00
|
|
|
|
2020-08-15 12:43:01 +02:00
|
|
|
for (size_t i = 0; i < len; i++)
|
2020-08-15 13:48:05 +02:00
|
|
|
if (strcmp(ptr[i], "clientPin") == 0) {
|
2022-03-29 12:39:55 +02:00
|
|
|
dev->flags |= val[i] ?
|
|
|
|
|
FIDO_DEV_PIN_SET : FIDO_DEV_PIN_UNSET;
|
2023-11-21 09:23:08 +01:00
|
|
|
} else if (strcmp(ptr[i], "credMgmt") == 0) {
|
2020-10-05 15:26:20 +02:00
|
|
|
if (val[i])
|
2020-11-06 11:02:09 +01:00
|
|
|
dev->flags |= FIDO_DEV_CREDMAN;
|
2023-11-21 09:23:08 +01:00
|
|
|
} else if (strcmp(ptr[i], "credentialMgmtPreview") == 0) {
|
|
|
|
|
if (val[i])
|
|
|
|
|
dev->flags |= FIDO_DEV_CREDMAN_PRE;
|
2020-10-05 15:26:20 +02:00
|
|
|
} else if (strcmp(ptr[i], "uv") == 0) {
|
2022-03-29 12:39:55 +02:00
|
|
|
dev->flags |= val[i] ?
|
|
|
|
|
FIDO_DEV_UV_SET : FIDO_DEV_UV_UNSET;
|
2020-10-05 15:26:20 +02:00
|
|
|
} else if (strcmp(ptr[i], "pinUvAuthToken") == 0) {
|
|
|
|
|
if (val[i])
|
|
|
|
|
dev->flags |= FIDO_DEV_TOKEN_PERMS;
|
2023-11-21 09:33:20 +01:00
|
|
|
} else if (strcmp(ptr[i], "bioEnroll") == 0) {
|
|
|
|
|
dev->flags |= val[i] ?
|
|
|
|
|
FIDO_DEV_BIO_SET : FIDO_DEV_BIO_UNSET;
|
2020-08-15 13:48:05 +02:00
|
|
|
}
|
2020-08-07 11:43:17 +02:00
|
|
|
}
|
|
|
|
|
|
2020-10-05 15:26:20 +02:00
|
|
|
static void
|
|
|
|
|
fido_dev_set_protocol_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
|
|
|
|
|
{
|
|
|
|
|
const uint8_t *ptr = fido_cbor_info_protocols_ptr(info);
|
|
|
|
|
size_t len = fido_cbor_info_protocols_len(info);
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < len; i++)
|
|
|
|
|
switch (ptr[i]) {
|
|
|
|
|
case CTAP_PIN_PROTOCOL1:
|
|
|
|
|
dev->flags |= FIDO_DEV_PIN_PROTOCOL1;
|
|
|
|
|
break;
|
|
|
|
|
case CTAP_PIN_PROTOCOL2:
|
|
|
|
|
dev->flags |= FIDO_DEV_PIN_PROTOCOL2;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
fido_log_debug("%s: unknown protocol %u", __func__,
|
|
|
|
|
ptr[i]);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
fido_dev_set_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
|
|
|
|
|
{
|
|
|
|
|
fido_dev_set_extension_flags(dev, info);
|
|
|
|
|
fido_dev_set_option_flags(dev, info);
|
|
|
|
|
fido_dev_set_protocol_flags(dev, info);
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-19 08:51:38 +02:00
|
|
|
static int
|
2021-09-27 09:45:40 +02:00
|
|
|
fido_dev_open_tx(fido_dev_t *dev, const char *path, int *ms)
|
2018-04-19 08:51:38 +02:00
|
|
|
{
|
2021-06-08 17:16:20 +02:00
|
|
|
int r;
|
2018-04-19 08:51:38 +02:00
|
|
|
|
2018-04-26 16:13:19 +02:00
|
|
|
if (dev->io_handle != NULL) {
|
2019-11-18 12:07:54 +01:00
|
|
|
fido_log_debug("%s: handle=%p", __func__, dev->io_handle);
|
2018-04-19 08:51:38 +02:00
|
|
|
return (FIDO_ERR_INVALID_ARGUMENT);
|
2018-04-26 16:13:19 +02:00
|
|
|
}
|
2018-04-19 08:51:38 +02:00
|
|
|
|
2019-12-12 08:29:37 +01:00
|
|
|
if (dev->io.open == NULL || dev->io.close == NULL) {
|
2019-11-18 12:07:54 +01:00
|
|
|
fido_log_debug("%s: NULL open/close", __func__);
|
2018-04-26 16:13:19 +02:00
|
|
|
return (FIDO_ERR_INVALID_ARGUMENT);
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-10 13:43:28 +02:00
|
|
|
if (dev->cid != CTAP_CID_BROADCAST) {
|
|
|
|
|
fido_log_debug("%s: cid=0x%x", __func__, dev->cid);
|
|
|
|
|
return (FIDO_ERR_INVALID_ARGUMENT);
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-28 09:03:11 +02:00
|
|
|
if (fido_get_random(&dev->nonce, sizeof(dev->nonce)) < 0) {
|
|
|
|
|
fido_log_debug("%s: fido_get_random", __func__);
|
2018-04-19 08:51:38 +02:00
|
|
|
return (FIDO_ERR_INTERNAL);
|
2018-04-26 16:13:19 +02:00
|
|
|
}
|
|
|
|
|
|
2019-12-12 08:29:37 +01:00
|
|
|
if ((dev->io_handle = dev->io.open(path)) == NULL) {
|
2019-11-18 12:07:54 +01:00
|
|
|
fido_log_debug("%s: dev->io.open", __func__);
|
2018-04-26 16:13:19 +02:00
|
|
|
return (FIDO_ERR_INTERNAL);
|
|
|
|
|
}
|
2018-04-19 08:51:38 +02:00
|
|
|
|
2020-05-23 13:00:34 +02:00
|
|
|
if (dev->io_own) {
|
|
|
|
|
dev->rx_len = CTAP_MAX_REPORT_LEN;
|
|
|
|
|
dev->tx_len = CTAP_MAX_REPORT_LEN;
|
2020-05-04 15:24:06 +02:00
|
|
|
} else {
|
2020-05-23 13:00:34 +02:00
|
|
|
dev->rx_len = fido_hid_report_in_len(dev->io_handle);
|
|
|
|
|
dev->tx_len = fido_hid_report_out_len(dev->io_handle);
|
2020-05-04 15:24:06 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-25 07:56:32 +02:00
|
|
|
#ifdef FIDO_FUZZ
|
|
|
|
|
set_random_report_len(dev);
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-05-23 13:00:34 +02:00
|
|
|
if (dev->rx_len < CTAP_MIN_REPORT_LEN ||
|
|
|
|
|
dev->rx_len > CTAP_MAX_REPORT_LEN) {
|
|
|
|
|
fido_log_debug("%s: invalid rx_len %zu", __func__, dev->rx_len);
|
2020-05-25 07:56:32 +02:00
|
|
|
r = FIDO_ERR_RX;
|
|
|
|
|
goto fail;
|
2020-05-04 15:24:06 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-23 13:00:34 +02:00
|
|
|
if (dev->tx_len < CTAP_MIN_REPORT_LEN ||
|
|
|
|
|
dev->tx_len > CTAP_MAX_REPORT_LEN) {
|
|
|
|
|
fido_log_debug("%s: invalid tx_len %zu", __func__, dev->tx_len);
|
2020-05-25 07:56:32 +02:00
|
|
|
r = FIDO_ERR_TX;
|
|
|
|
|
goto fail;
|
2020-05-04 15:24:06 +02:00
|
|
|
}
|
|
|
|
|
|
2021-09-27 09:45:40 +02:00
|
|
|
if (fido_tx(dev, CTAP_CMD_INIT, &dev->nonce, sizeof(dev->nonce),
|
|
|
|
|
ms) < 0) {
|
2019-11-18 12:07:54 +01:00
|
|
|
fido_log_debug("%s: fido_tx", __func__);
|
2020-05-25 07:56:32 +02:00
|
|
|
r = FIDO_ERR_TX;
|
|
|
|
|
goto fail;
|
2018-04-19 08:51:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (FIDO_OK);
|
2020-05-25 07:56:32 +02:00
|
|
|
fail:
|
|
|
|
|
dev->io.close(dev->io_handle);
|
|
|
|
|
dev->io_handle = NULL;
|
|
|
|
|
|
|
|
|
|
return (r);
|
2018-04-19 08:51:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
2021-09-22 15:13:00 +02:00
|
|
|
fido_dev_open_rx(fido_dev_t *dev, int *ms)
|
2018-04-19 08:51:38 +02:00
|
|
|
{
|
2020-01-15 12:02:45 +01:00
|
|
|
fido_cbor_info_t *info = NULL;
|
|
|
|
|
int reply_len;
|
|
|
|
|
int r;
|
2018-04-19 08:51:38 +02:00
|
|
|
|
2020-01-15 12:02:45 +01:00
|
|
|
if ((reply_len = fido_rx(dev, CTAP_CMD_INIT, &dev->attr,
|
|
|
|
|
sizeof(dev->attr), ms)) < 0) {
|
2019-11-18 12:07:54 +01:00
|
|
|
fido_log_debug("%s: fido_rx", __func__);
|
2020-01-15 12:02:45 +01:00
|
|
|
r = FIDO_ERR_RX;
|
2019-09-17 14:09:04 +02:00
|
|
|
goto fail;
|
2018-04-26 16:13:19 +02:00
|
|
|
}
|
|
|
|
|
|
2018-07-11 09:38:26 +02:00
|
|
|
#ifdef FIDO_FUZZ
|
|
|
|
|
dev->attr.nonce = dev->nonce;
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-01-15 12:02:45 +01:00
|
|
|
if ((size_t)reply_len != sizeof(dev->attr) ||
|
|
|
|
|
dev->attr.nonce != dev->nonce) {
|
2019-11-18 12:07:54 +01:00
|
|
|
fido_log_debug("%s: invalid nonce", __func__);
|
2020-01-15 12:02:45 +01:00
|
|
|
r = FIDO_ERR_RX;
|
2019-09-17 14:09:04 +02:00
|
|
|
goto fail;
|
2018-04-26 16:13:19 +02:00
|
|
|
}
|
2018-04-19 08:51:38 +02:00
|
|
|
|
2020-08-07 11:43:17 +02:00
|
|
|
dev->flags = 0;
|
2018-04-19 08:51:38 +02:00
|
|
|
dev->cid = dev->attr.cid;
|
|
|
|
|
|
2019-12-16 13:39:22 +01:00
|
|
|
if (fido_dev_is_fido2(dev)) {
|
2020-01-15 12:02:45 +01:00
|
|
|
if ((info = fido_cbor_info_new()) == NULL) {
|
|
|
|
|
fido_log_debug("%s: fido_cbor_info_new", __func__);
|
|
|
|
|
r = FIDO_ERR_INTERNAL;
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
2021-03-03 16:55:26 +01:00
|
|
|
if ((r = fido_dev_get_cbor_info_wait(dev, info,
|
|
|
|
|
ms)) != FIDO_OK) {
|
|
|
|
|
fido_log_debug("%s: fido_dev_cbor_info_wait: %d",
|
|
|
|
|
__func__, r);
|
2021-03-03 16:51:28 +02:00
|
|
|
if (disable_u2f_fallback)
|
2021-03-03 16:55:26 +01:00
|
|
|
goto fail;
|
|
|
|
|
fido_log_debug("%s: falling back to u2f", __func__);
|
|
|
|
|
fido_dev_force_u2f(dev);
|
2020-08-07 11:43:17 +02:00
|
|
|
} else {
|
|
|
|
|
fido_dev_set_flags(dev, info);
|
2019-12-16 13:39:22 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-15 12:02:45 +01:00
|
|
|
if (fido_dev_is_fido2(dev) && info != NULL) {
|
2021-01-28 10:57:47 +01:00
|
|
|
dev->maxmsgsize = fido_cbor_info_maxmsgsiz(info);
|
2020-01-15 12:02:45 +01:00
|
|
|
fido_log_debug("%s: FIDO_MAXMSG=%d, maxmsgsiz=%lu", __func__,
|
2021-01-28 10:57:47 +01:00
|
|
|
FIDO_MAXMSG, (unsigned long)dev->maxmsgsize);
|
2020-01-15 12:02:45 +01:00
|
|
|
}
|
2019-09-17 14:09:04 +02:00
|
|
|
|
2020-01-15 12:02:45 +01:00
|
|
|
r = FIDO_OK;
|
|
|
|
|
fail:
|
|
|
|
|
fido_cbor_info_free(&info);
|
|
|
|
|
|
|
|
|
|
if (r != FIDO_OK) {
|
|
|
|
|
dev->io.close(dev->io_handle);
|
|
|
|
|
dev->io_handle = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (r);
|
2018-04-19 08:51:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
2021-09-22 15:13:00 +02:00
|
|
|
fido_dev_open_wait(fido_dev_t *dev, const char *path, int *ms)
|
2018-04-19 08:51:38 +02:00
|
|
|
{
|
|
|
|
|
int r;
|
|
|
|
|
|
2021-06-09 16:28:07 +02:00
|
|
|
#ifdef USE_WINHELLO
|
|
|
|
|
if (strcmp(path, FIDO_WINHELLO_PATH) == 0)
|
|
|
|
|
return (fido_winhello_open(dev));
|
|
|
|
|
#endif
|
2021-09-27 09:45:40 +02:00
|
|
|
if ((r = fido_dev_open_tx(dev, path, ms)) != FIDO_OK ||
|
2018-04-20 17:11:27 +02:00
|
|
|
(r = fido_dev_open_rx(dev, ms)) != FIDO_OK)
|
2018-04-19 08:51:38 +02:00
|
|
|
return (r);
|
|
|
|
|
|
|
|
|
|
return (FIDO_OK);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-28 16:21:17 +02:00
|
|
|
static void
|
|
|
|
|
run_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen,
|
2022-03-29 13:47:41 +02:00
|
|
|
const char *type, int (*manifest)(fido_dev_info_t *, size_t, size_t *))
|
2022-03-28 16:21:17 +02:00
|
|
|
{
|
|
|
|
|
size_t ndevs = 0;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
if (*olen >= ilen) {
|
|
|
|
|
fido_log_debug("%s: skipping %s", __func__, type);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if ((r = manifest(devlist + *olen, ilen - *olen, &ndevs)) != FIDO_OK)
|
|
|
|
|
fido_log_debug("%s: %s: 0x%x", __func__, type, r);
|
|
|
|
|
fido_log_debug("%s: found %zu %s device%s", __func__, ndevs, type,
|
|
|
|
|
ndevs == 1 ? "" : "s");
|
|
|
|
|
*olen += ndevs;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-18 18:41:21 -08:00
|
|
|
int
|
|
|
|
|
fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
|
|
|
|
|
{
|
|
|
|
|
*olen = 0;
|
2019-12-11 10:21:35 +01:00
|
|
|
|
2022-03-28 16:21:17 +02:00
|
|
|
run_manifest(devlist, ilen, olen, "hid", fido_hid_manifest);
|
2022-02-23 14:42:19 +01:00
|
|
|
#ifdef USE_NFC
|
2022-03-28 16:21:17 +02:00
|
|
|
run_manifest(devlist, ilen, olen, "nfc", fido_nfc_manifest);
|
2021-06-09 16:28:07 +02:00
|
|
|
#endif
|
2022-02-24 14:13:23 +01:00
|
|
|
#ifdef USE_PCSC
|
2022-03-28 16:21:17 +02:00
|
|
|
run_manifest(devlist, ilen, olen, "pcsc", fido_pcsc_manifest);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef USE_WINHELLO
|
|
|
|
|
run_manifest(devlist, ilen, olen, "winhello", fido_winhello_manifest);
|
2022-02-24 14:13:23 +01:00
|
|
|
#endif
|
2020-12-22 12:24:17 +01:00
|
|
|
|
2019-11-18 18:41:21 -08:00
|
|
|
return (FIDO_OK);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
fido_dev_open_with_info(fido_dev_t *dev)
|
|
|
|
|
{
|
2021-09-22 15:13:00 +02:00
|
|
|
int ms = dev->timeout_ms;
|
|
|
|
|
|
2019-12-12 08:29:37 +01:00
|
|
|
if (dev->path == NULL)
|
|
|
|
|
return (FIDO_ERR_INVALID_ARGUMENT);
|
|
|
|
|
|
2021-09-22 15:13:00 +02:00
|
|
|
return (fido_dev_open_wait(dev, dev->path, &ms));
|
2019-11-18 18:41:21 -08:00
|
|
|
}
|
|
|
|
|
|
2018-04-19 08:51:38 +02:00
|
|
|
int
|
|
|
|
|
fido_dev_open(fido_dev_t *dev, const char *path)
|
|
|
|
|
{
|
2021-09-22 15:13:00 +02:00
|
|
|
int ms = dev->timeout_ms;
|
|
|
|
|
|
2022-02-23 14:42:19 +01:00
|
|
|
#ifdef USE_NFC
|
2022-02-23 15:27:44 +01:00
|
|
|
if (fido_is_nfc(path) && fido_dev_set_nfc(dev) < 0) {
|
|
|
|
|
fido_log_debug("%s: fido_dev_set_nfc", __func__);
|
|
|
|
|
return FIDO_ERR_INTERNAL;
|
2020-12-22 12:24:17 +01:00
|
|
|
}
|
|
|
|
|
#endif
|
2022-02-24 14:13:23 +01:00
|
|
|
#ifdef USE_PCSC
|
|
|
|
|
if (fido_is_pcsc(path) && fido_dev_set_pcsc(dev) < 0) {
|
|
|
|
|
fido_log_debug("%s: fido_dev_set_pcsc", __func__);
|
|
|
|
|
return FIDO_ERR_INTERNAL;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2021-06-09 16:28:07 +02:00
|
|
|
|
2021-09-22 15:13:00 +02:00
|
|
|
return (fido_dev_open_wait(dev, path, &ms));
|
2018-04-19 08:51:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
fido_dev_close(fido_dev_t *dev)
|
|
|
|
|
{
|
2021-06-09 16:28:07 +02:00
|
|
|
#ifdef USE_WINHELLO
|
|
|
|
|
if (dev->flags & FIDO_DEV_WINHELLO)
|
|
|
|
|
return (fido_winhello_close(dev));
|
|
|
|
|
#endif
|
2019-12-12 08:29:37 +01:00
|
|
|
if (dev->io_handle == NULL || dev->io.close == NULL)
|
2018-04-19 08:51:38 +02:00
|
|
|
return (FIDO_ERR_INVALID_ARGUMENT);
|
|
|
|
|
|
2019-12-12 08:29:37 +01:00
|
|
|
dev->io.close(dev->io_handle);
|
2018-04-24 10:53:31 +02:00
|
|
|
dev->io_handle = NULL;
|
2020-10-10 13:43:28 +02:00
|
|
|
dev->cid = CTAP_CID_BROADCAST;
|
2018-04-24 10:53:31 +02:00
|
|
|
|
|
|
|
|
return (FIDO_OK);
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-22 16:11:47 +00:00
|
|
|
int
|
|
|
|
|
fido_dev_set_sigmask(fido_dev_t *dev, const fido_sigset_t *sigmask)
|
|
|
|
|
{
|
2021-09-13 09:41:28 +02:00
|
|
|
if (dev->io_handle == NULL || sigmask == NULL)
|
2020-12-22 16:11:47 +00:00
|
|
|
return (FIDO_ERR_INVALID_ARGUMENT);
|
|
|
|
|
|
2022-02-23 14:42:19 +01:00
|
|
|
#ifdef USE_NFC
|
2021-09-13 09:41:28 +02:00
|
|
|
if (dev->transport.rx == fido_nfc_rx && dev->io.read == fido_nfc_read)
|
2020-12-24 11:46:11 +01:00
|
|
|
return (fido_nfc_set_sigmask(dev->io_handle, sigmask));
|
|
|
|
|
#endif
|
2021-09-13 09:41:28 +02:00
|
|
|
if (dev->transport.rx == NULL && dev->io.read == fido_hid_read)
|
|
|
|
|
return (fido_hid_set_sigmask(dev->io_handle, sigmask));
|
|
|
|
|
|
|
|
|
|
return (FIDO_ERR_INVALID_ARGUMENT);
|
2020-12-22 16:11:47 +00:00
|
|
|
}
|
|
|
|
|
|
2019-09-17 12:50:44 +02:00
|
|
|
int
|
|
|
|
|
fido_dev_cancel(fido_dev_t *dev)
|
|
|
|
|
{
|
2021-09-27 09:45:40 +02:00
|
|
|
int ms = dev->timeout_ms;
|
|
|
|
|
|
2021-06-09 16:28:07 +02:00
|
|
|
#ifdef USE_WINHELLO
|
|
|
|
|
if (dev->flags & FIDO_DEV_WINHELLO)
|
|
|
|
|
return (fido_winhello_cancel(dev));
|
|
|
|
|
#endif
|
2020-08-07 11:44:31 +02:00
|
|
|
if (fido_dev_is_fido2(dev) == false)
|
|
|
|
|
return (FIDO_ERR_INVALID_ARGUMENT);
|
2021-09-27 09:45:40 +02:00
|
|
|
if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0, &ms) < 0)
|
2019-09-17 12:50:44 +02:00
|
|
|
return (FIDO_ERR_TX);
|
|
|
|
|
|
|
|
|
|
return (FIDO_OK);
|
|
|
|
|
}
|
2020-08-07 11:44:31 +02:00
|
|
|
|
2018-04-24 10:53:31 +02:00
|
|
|
int
|
|
|
|
|
fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io)
|
|
|
|
|
{
|
2018-04-26 16:13:19 +02:00
|
|
|
if (dev->io_handle != NULL) {
|
2020-02-22 10:41:52 +01:00
|
|
|
fido_log_debug("%s: non-NULL handle", __func__);
|
2018-04-24 10:53:31 +02:00
|
|
|
return (FIDO_ERR_INVALID_ARGUMENT);
|
2018-04-26 16:13:19 +02:00
|
|
|
}
|
2018-04-24 10:53:31 +02:00
|
|
|
|
2019-04-17 14:24:22 +02:00
|
|
|
if (io == NULL || io->open == NULL || io->close == NULL ||
|
2019-12-03 09:25:08 -08:00
|
|
|
io->read == NULL || io->write == NULL) {
|
2019-11-18 12:07:54 +01:00
|
|
|
fido_log_debug("%s: NULL function", __func__);
|
2018-04-24 10:53:31 +02:00
|
|
|
return (FIDO_ERR_INVALID_ARGUMENT);
|
2018-04-26 16:13:19 +02:00
|
|
|
}
|
2018-04-24 10:53:31 +02:00
|
|
|
|
2019-12-12 08:29:37 +01:00
|
|
|
dev->io = *io;
|
2020-05-23 13:00:34 +02:00
|
|
|
dev->io_own = true;
|
2018-04-19 08:51:38 +02:00
|
|
|
|
|
|
|
|
return (FIDO_OK);
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-22 10:41:52 +01:00
|
|
|
int
|
|
|
|
|
fido_dev_set_transport_functions(fido_dev_t *dev, const fido_dev_transport_t *t)
|
|
|
|
|
{
|
|
|
|
|
if (dev->io_handle != NULL) {
|
|
|
|
|
fido_log_debug("%s: non-NULL handle", __func__);
|
|
|
|
|
return (FIDO_ERR_INVALID_ARGUMENT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dev->transport = *t;
|
2020-05-23 13:00:34 +02:00
|
|
|
dev->io_own = true;
|
2020-02-22 10:41:52 +01:00
|
|
|
|
|
|
|
|
return (FIDO_OK);
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-04 21:58:03 +00:00
|
|
|
void *
|
|
|
|
|
fido_dev_io_handle(const fido_dev_t *dev)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
return (dev->io_handle);
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-19 08:51:38 +02:00
|
|
|
void
|
2018-04-27 13:04:14 +02:00
|
|
|
fido_init(int flags)
|
2018-04-19 08:51:38 +02:00
|
|
|
{
|
2018-04-27 13:04:14 +02:00
|
|
|
if (flags & FIDO_DEBUG || getenv("FIDO_DEBUG") != NULL)
|
2019-12-20 13:16:30 +01:00
|
|
|
fido_log_init();
|
2021-03-03 16:51:28 +02:00
|
|
|
|
|
|
|
|
disable_u2f_fallback = (flags & FIDO_DISABLE_U2F_FALLBACK);
|
2019-11-18 18:41:21 -08:00
|
|
|
}
|
|
|
|
|
|
2018-04-19 08:51:38 +02:00
|
|
|
fido_dev_t *
|
2019-12-09 10:58:33 +01:00
|
|
|
fido_dev_new(void)
|
2018-04-19 08:51:38 +02:00
|
|
|
{
|
2019-12-09 10:58:33 +01:00
|
|
|
fido_dev_t *dev;
|
2018-04-19 08:51:38 +02:00
|
|
|
|
|
|
|
|
if ((dev = calloc(1, sizeof(*dev))) == NULL)
|
|
|
|
|
return (NULL);
|
|
|
|
|
|
|
|
|
|
dev->cid = CTAP_CID_BROADCAST;
|
2021-09-22 15:08:46 +02:00
|
|
|
dev->timeout_ms = -1;
|
2019-12-12 08:29:37 +01:00
|
|
|
dev->io = (fido_dev_io_t) {
|
2019-11-18 18:41:21 -08:00
|
|
|
&fido_hid_open,
|
|
|
|
|
&fido_hid_close,
|
|
|
|
|
&fido_hid_read,
|
2019-12-02 17:00:24 -08:00
|
|
|
&fido_hid_write,
|
2019-11-18 18:41:21 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (dev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fido_dev_t *
|
2019-12-12 08:29:37 +01:00
|
|
|
fido_dev_new_with_info(const fido_dev_info_t *di)
|
2019-11-18 18:41:21 -08:00
|
|
|
{
|
2019-12-09 10:58:33 +01:00
|
|
|
fido_dev_t *dev;
|
2019-11-18 18:41:21 -08:00
|
|
|
|
|
|
|
|
if ((dev = calloc(1, sizeof(*dev))) == NULL)
|
|
|
|
|
return (NULL);
|
|
|
|
|
|
2021-06-09 16:28:07 +02:00
|
|
|
#if 0
|
2019-12-12 08:29:37 +01:00
|
|
|
if (di->io.open == NULL || di->io.close == NULL ||
|
|
|
|
|
di->io.read == NULL || di->io.write == NULL) {
|
2019-11-18 18:41:21 -08:00
|
|
|
fido_log_debug("%s: NULL function", __func__);
|
|
|
|
|
fido_dev_free(&dev);
|
|
|
|
|
return (NULL);
|
|
|
|
|
}
|
2021-06-09 16:28:07 +02:00
|
|
|
#endif
|
2019-11-18 18:41:21 -08:00
|
|
|
|
2019-12-12 08:29:37 +01:00
|
|
|
dev->io = di->io;
|
2020-09-23 09:25:51 +02:00
|
|
|
dev->io_own = di->transport.tx != NULL || di->transport.rx != NULL;
|
2020-02-22 10:41:52 +01:00
|
|
|
dev->transport = di->transport;
|
2020-10-10 13:43:28 +02:00
|
|
|
dev->cid = CTAP_CID_BROADCAST;
|
2021-09-22 15:08:46 +02:00
|
|
|
dev->timeout_ms = -1;
|
2020-02-22 10:41:52 +01:00
|
|
|
|
2019-12-12 08:29:37 +01:00
|
|
|
if ((dev->path = strdup(di->path)) == NULL) {
|
|
|
|
|
fido_log_debug("%s: strdup", __func__);
|
2018-04-24 10:53:31 +02:00
|
|
|
fido_dev_free(&dev);
|
|
|
|
|
return (NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-19 08:51:38 +02:00
|
|
|
return (dev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
fido_dev_free(fido_dev_t **dev_p)
|
|
|
|
|
{
|
|
|
|
|
fido_dev_t *dev;
|
|
|
|
|
|
|
|
|
|
if (dev_p == NULL || (dev = *dev_p) == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
2019-12-12 08:29:37 +01:00
|
|
|
free(dev->path);
|
2018-04-19 08:51:38 +02:00
|
|
|
free(dev);
|
|
|
|
|
|
|
|
|
|
*dev_p = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t
|
|
|
|
|
fido_dev_protocol(const fido_dev_t *dev)
|
|
|
|
|
{
|
|
|
|
|
return (dev->attr.protocol);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t
|
|
|
|
|
fido_dev_major(const fido_dev_t *dev)
|
|
|
|
|
{
|
|
|
|
|
return (dev->attr.major);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t
|
|
|
|
|
fido_dev_minor(const fido_dev_t *dev)
|
|
|
|
|
{
|
|
|
|
|
return (dev->attr.minor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t
|
|
|
|
|
fido_dev_build(const fido_dev_t *dev)
|
|
|
|
|
{
|
|
|
|
|
return (dev->attr.build);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t
|
|
|
|
|
fido_dev_flags(const fido_dev_t *dev)
|
|
|
|
|
{
|
|
|
|
|
return (dev->attr.flags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
fido_dev_is_fido2(const fido_dev_t *dev)
|
|
|
|
|
{
|
|
|
|
|
return (dev->attr.flags & FIDO_CAP_CBOR);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-15 15:50:24 +02:00
|
|
|
bool
|
|
|
|
|
fido_dev_is_winhello(const fido_dev_t *dev)
|
|
|
|
|
{
|
|
|
|
|
return (dev->flags & FIDO_DEV_WINHELLO);
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-07 11:43:17 +02:00
|
|
|
bool
|
|
|
|
|
fido_dev_supports_pin(const fido_dev_t *dev)
|
|
|
|
|
{
|
2020-08-15 12:43:01 +02:00
|
|
|
return (dev->flags & (FIDO_DEV_PIN_SET|FIDO_DEV_PIN_UNSET));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
fido_dev_has_pin(const fido_dev_t *dev)
|
|
|
|
|
{
|
|
|
|
|
return (dev->flags & FIDO_DEV_PIN_SET);
|
2020-08-07 11:43:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
fido_dev_supports_cred_prot(const fido_dev_t *dev)
|
|
|
|
|
{
|
2020-08-15 12:43:01 +02:00
|
|
|
return (dev->flags & FIDO_DEV_CRED_PROT);
|
2020-08-07 11:43:17 +02:00
|
|
|
}
|
|
|
|
|
|
2020-11-06 11:02:09 +01:00
|
|
|
bool
|
|
|
|
|
fido_dev_supports_credman(const fido_dev_t *dev)
|
|
|
|
|
{
|
2023-11-21 09:23:08 +01:00
|
|
|
return (dev->flags & (FIDO_DEV_CREDMAN|FIDO_DEV_CREDMAN_PRE));
|
2020-11-06 11:02:09 +01:00
|
|
|
}
|
|
|
|
|
|
2020-10-05 15:26:20 +02:00
|
|
|
bool
|
|
|
|
|
fido_dev_supports_uv(const fido_dev_t *dev)
|
|
|
|
|
{
|
|
|
|
|
return (dev->flags & (FIDO_DEV_UV_SET|FIDO_DEV_UV_UNSET));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
fido_dev_has_uv(const fido_dev_t *dev)
|
|
|
|
|
{
|
|
|
|
|
return (dev->flags & FIDO_DEV_UV_SET);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
fido_dev_supports_permissions(const fido_dev_t *dev)
|
|
|
|
|
{
|
|
|
|
|
return (dev->flags & FIDO_DEV_TOKEN_PERMS);
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-19 08:51:38 +02:00
|
|
|
void
|
|
|
|
|
fido_dev_force_u2f(fido_dev_t *dev)
|
|
|
|
|
{
|
2020-06-28 11:11:18 +02:00
|
|
|
dev->attr.flags &= (uint8_t)~FIDO_CAP_CBOR;
|
2020-08-07 11:43:17 +02:00
|
|
|
dev->flags = 0;
|
2018-04-19 08:51:38 +02:00
|
|
|
}
|
2018-07-13 08:46:31 +02:00
|
|
|
|
|
|
|
|
void
|
|
|
|
|
fido_dev_force_fido2(fido_dev_t *dev)
|
|
|
|
|
{
|
|
|
|
|
dev->attr.flags |= FIDO_CAP_CBOR;
|
|
|
|
|
}
|
2020-10-05 15:26:20 +02:00
|
|
|
|
|
|
|
|
uint8_t
|
|
|
|
|
fido_dev_get_pin_protocol(const fido_dev_t *dev)
|
|
|
|
|
{
|
|
|
|
|
if (dev->flags & FIDO_DEV_PIN_PROTOCOL2)
|
|
|
|
|
return (CTAP_PIN_PROTOCOL2);
|
|
|
|
|
else if (dev->flags & FIDO_DEV_PIN_PROTOCOL1)
|
|
|
|
|
return (CTAP_PIN_PROTOCOL1);
|
|
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
|
}
|
2021-01-28 10:57:47 +01:00
|
|
|
|
|
|
|
|
uint64_t
|
|
|
|
|
fido_dev_maxmsgsize(const fido_dev_t *dev)
|
|
|
|
|
{
|
|
|
|
|
return (dev->maxmsgsize);
|
|
|
|
|
}
|
2021-09-28 13:03:29 +02:00
|
|
|
|
|
|
|
|
int
|
|
|
|
|
fido_dev_set_timeout(fido_dev_t *dev, int ms)
|
|
|
|
|
{
|
|
|
|
|
if (ms < -1)
|
|
|
|
|
return (FIDO_ERR_INVALID_ARGUMENT);
|
|
|
|
|
|
|
|
|
|
dev->timeout_ms = ms;
|
|
|
|
|
|
|
|
|
|
return (FIDO_OK);
|
|
|
|
|
}
|