From c79050aa44b8836d836c5dd22a383a073c28b74b Mon Sep 17 00:00:00 2001 From: nicoo Date: Wed, 12 Feb 2020 13:42:22 +0100 Subject: Import upstream release 1.3.0 Closes: #951184 --- src/dev.c | 284 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 284 insertions(+) create mode 100644 src/dev.c (limited to 'src/dev.c') diff --git a/src/dev.c b/src/dev.c new file mode 100644 index 0000000..d0efac7 --- /dev/null +++ b/src/dev.c @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2018 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + +#include +#include + +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "fido.h" + +#if defined(_WIN32) +#include + +#include +#include +#include +#include +#include + +static int +obtain_nonce(uint64_t *nonce) +{ + NTSTATUS status; + + status = BCryptGenRandom(NULL, (unsigned char *)nonce, sizeof(*nonce), + BCRYPT_USE_SYSTEM_PREFERRED_RNG); + + if (!NT_SUCCESS(status)) + return (-1); + + return (0); +} +#elif defined(HAS_DEV_URANDOM) +static int +obtain_nonce(uint64_t *nonce) +{ + int fd = -1; + int ok = -1; + ssize_t r; + + if ((fd = open(FIDO_RANDOM_DEV, O_RDONLY)) < 0) + goto fail; + if ((r = read(fd, nonce, sizeof(*nonce))) < 0 || + (size_t)r != sizeof(*nonce)) + goto fail; + + ok = 0; +fail: + if (fd != -1) + close(fd); + + return (ok); +} +#else +#error "please provide an implementation of obtain_nonce() for your platform" +#endif /* _WIN32 */ + +static int +fido_dev_open_tx(fido_dev_t *dev, const char *path) +{ + const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_INIT; + + if (dev->io_handle != NULL) { + fido_log_debug("%s: handle=%p", __func__, dev->io_handle); + return (FIDO_ERR_INVALID_ARGUMENT); + } + + if (dev->io.open == NULL || dev->io.close == NULL) { + fido_log_debug("%s: NULL open/close", __func__); + return (FIDO_ERR_INVALID_ARGUMENT); + } + + if (obtain_nonce(&dev->nonce) < 0) { + fido_log_debug("%s: obtain_nonce", __func__); + return (FIDO_ERR_INTERNAL); + } + + if ((dev->io_handle = dev->io.open(path)) == NULL) { + fido_log_debug("%s: dev->io.open", __func__); + return (FIDO_ERR_INTERNAL); + } + + if (fido_tx(dev, cmd, &dev->nonce, sizeof(dev->nonce)) < 0) { + fido_log_debug("%s: fido_tx", __func__); + dev->io.close(dev->io_handle); + dev->io_handle = NULL; + return (FIDO_ERR_TX); + } + + return (FIDO_OK); +} + +static int +fido_dev_open_rx(fido_dev_t *dev, int ms) +{ + const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_INIT; + int n; + + if ((n = fido_rx(dev, cmd, &dev->attr, sizeof(dev->attr), ms)) < 0) { + fido_log_debug("%s: fido_rx", __func__); + goto fail; + } + +#ifdef FIDO_FUZZ + dev->attr.nonce = dev->nonce; +#endif + + if ((size_t)n != sizeof(dev->attr) || dev->attr.nonce != dev->nonce) { + fido_log_debug("%s: invalid nonce", __func__); + goto fail; + } + + dev->cid = dev->attr.cid; + + return (FIDO_OK); +fail: + dev->io.close(dev->io_handle); + dev->io_handle = NULL; + + return (FIDO_ERR_RX); +} + +static int +fido_dev_open_wait(fido_dev_t *dev, const char *path, int ms) +{ + int r; + + if ((r = fido_dev_open_tx(dev, path)) != FIDO_OK || + (r = fido_dev_open_rx(dev, ms)) != FIDO_OK) + return (r); + + return (FIDO_OK); +} + +int +fido_dev_open(fido_dev_t *dev, const char *path) +{ + return (fido_dev_open_wait(dev, path, -1)); +} + +int +fido_dev_close(fido_dev_t *dev) +{ + if (dev->io_handle == NULL || dev->io.close == NULL) + return (FIDO_ERR_INVALID_ARGUMENT); + + dev->io.close(dev->io_handle); + dev->io_handle = NULL; + + return (FIDO_OK); +} + +int +fido_dev_cancel(fido_dev_t *dev) +{ + if (fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CANCEL, NULL, 0) < 0) + return (FIDO_ERR_TX); + + return (FIDO_OK); +} + +int +fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io) +{ + if (dev->io_handle != NULL) { + fido_log_debug("%s: NULL handle", __func__); + return (FIDO_ERR_INVALID_ARGUMENT); + } + + if (io == NULL || io->open == NULL || io->close == NULL || + io->read == NULL || io->write == NULL) { + fido_log_debug("%s: NULL function", __func__); + return (FIDO_ERR_INVALID_ARGUMENT); + } + + dev->io.open = io->open; + dev->io.close = io->close; + dev->io.read = io->read; + dev->io.write = io->write; + + return (FIDO_OK); +} + +void +fido_init(int flags) +{ + if (flags & FIDO_DEBUG || getenv("FIDO_DEBUG") != NULL) + fido_log_init(); +} + +fido_dev_t * +fido_dev_new(void) +{ + fido_dev_t *dev; + fido_dev_io_t io; + + if ((dev = calloc(1, sizeof(*dev))) == NULL) + return (NULL); + + dev->cid = CTAP_CID_BROADCAST; + + io.open = fido_hid_open; + io.close = fido_hid_close; + io.read = fido_hid_read; + io.write = fido_hid_write; + + if (fido_dev_set_io_functions(dev, &io) != FIDO_OK) { + fido_log_debug("%s: fido_dev_set_io_functions", __func__); + fido_dev_free(&dev); + return (NULL); + } + + return (dev); +} + +void +fido_dev_free(fido_dev_t **dev_p) +{ + fido_dev_t *dev; + + if (dev_p == NULL || (dev = *dev_p) == NULL) + return; + + 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); +} + +void +fido_dev_force_u2f(fido_dev_t *dev) +{ + dev->attr.flags &= ~FIDO_CAP_CBOR; +} + +void +fido_dev_force_fido2(fido_dev_t *dev) +{ + dev->attr.flags |= FIDO_CAP_CBOR; +} -- cgit v1.2.3