Path: blob/main/contrib/libfido2/examples/select.c
39536 views
/*1* Copyright (c) 2020-2022 Yubico AB. All rights reserved.2* Use of this source code is governed by a BSD-style3* license that can be found in the LICENSE file.4* SPDX-License-Identifier: BSD-2-Clause5*/67#include <errno.h>8#include <fido.h>9#include <stdio.h>10#include <stdlib.h>11#include <time.h>1213#include "../openbsd-compat/openbsd-compat.h"1415#define FIDO_POLL_MS 501617#if defined(_MSC_VER)18static int19nanosleep(const struct timespec *rqtp, struct timespec *rmtp)20{21if (rmtp != NULL) {22errno = EINVAL;23return (-1);24}2526Sleep((DWORD)(rqtp->tv_sec * 1000) + (DWORD)(rqtp->tv_nsec / 1000000));2728return (0);29}30#endif3132static fido_dev_t *33open_dev(const fido_dev_info_t *di)34{35fido_dev_t *dev;36int r;3738if ((dev = fido_dev_new()) == NULL) {39warnx("%s: fido_dev_new", __func__);40return (NULL);41}4243if ((r = fido_dev_open(dev, fido_dev_info_path(di))) != FIDO_OK) {44warnx("%s: fido_dev_open %s: %s", __func__,45fido_dev_info_path(di), fido_strerr(r));46fido_dev_free(&dev);47return (NULL);48}4950printf("%s (0x%04x:0x%04x) is %s\n", fido_dev_info_path(di),51fido_dev_info_vendor(di), fido_dev_info_product(di),52fido_dev_is_fido2(dev) ? "fido2" : "u2f");5354return (dev);55}5657static int58select_dev(const fido_dev_info_t *devlist, size_t ndevs, fido_dev_t **dev,59size_t *idx, int secs)60{61const fido_dev_info_t *di;62fido_dev_t **devtab;63struct timespec ts_start;64struct timespec ts_now;65struct timespec ts_delta;66struct timespec ts_pause;67size_t nopen = 0;68int touched;69int r;70long ms_remain;7172*dev = NULL;73*idx = 0;7475printf("%u authenticator(s) detected\n", (unsigned)ndevs);7677if (ndevs == 0)78return (0); /* nothing to do */7980if ((devtab = calloc(ndevs, sizeof(*devtab))) == NULL) {81warn("%s: calloc", __func__);82return (-1);83}8485for (size_t i = 0; i < ndevs; i++) {86di = fido_dev_info_ptr(devlist, i);87if ((devtab[i] = open_dev(di)) != NULL) {88*idx = i;89nopen++;90}91}9293printf("%u authenticator(s) opened\n", (unsigned)nopen);9495if (nopen < 2) {96if (nopen == 1)97*dev = devtab[*idx]; /* single candidate */98r = 0;99goto out;100}101102for (size_t i = 0; i < ndevs; i++) {103di = fido_dev_info_ptr(devlist, i);104if (devtab[i] == NULL)105continue; /* failed to open */106if ((r = fido_dev_get_touch_begin(devtab[i])) != FIDO_OK) {107warnx("%s: fido_dev_get_touch_begin %s: %s", __func__,108fido_dev_info_path(di), fido_strerr(r));109r = -1;110goto out;111}112}113114if (clock_gettime(CLOCK_MONOTONIC, &ts_start) != 0) {115warn("%s: clock_gettime", __func__);116r = -1;117goto out;118}119120ts_pause.tv_sec = 0;121ts_pause.tv_nsec = 200000000; /* 200ms */122123do {124nanosleep(&ts_pause, NULL);125126for (size_t i = 0; i < ndevs; i++) {127di = fido_dev_info_ptr(devlist, i);128if (devtab[i] == NULL) {129/* failed to open or discarded */130continue;131}132if ((r = fido_dev_get_touch_status(devtab[i], &touched,133FIDO_POLL_MS)) != FIDO_OK) {134warnx("%s: fido_dev_get_touch_status %s: %s",135__func__, fido_dev_info_path(di),136fido_strerr(r));137fido_dev_close(devtab[i]);138fido_dev_free(&devtab[i]);139continue; /* discard */140}141if (touched) {142*dev = devtab[i];143*idx = i;144r = 0;145goto out;146}147}148149if (clock_gettime(CLOCK_MONOTONIC, &ts_now) != 0) {150warn("%s: clock_gettime", __func__);151r = -1;152goto out;153}154155timespecsub(&ts_now, &ts_start, &ts_delta);156ms_remain = (secs * 1000) - ((long)ts_delta.tv_sec * 1000) +157((long)ts_delta.tv_nsec / 1000000);158} while (ms_remain > FIDO_POLL_MS);159160printf("timeout after %d seconds\n", secs);161r = -1;162out:163if (r != 0) {164*dev = NULL;165*idx = 0;166}167168for (size_t i = 0; i < ndevs; i++) {169if (devtab[i] && devtab[i] != *dev) {170fido_dev_cancel(devtab[i]);171fido_dev_close(devtab[i]);172fido_dev_free(&devtab[i]);173}174}175176free(devtab);177178return (r);179}180181int182main(void)183{184const fido_dev_info_t *di;185fido_dev_info_t *devlist;186fido_dev_t *dev;187size_t idx;188size_t ndevs;189int r;190191fido_init(0);192193if ((devlist = fido_dev_info_new(64)) == NULL)194errx(1, "fido_dev_info_new");195196if ((r = fido_dev_info_manifest(devlist, 64, &ndevs)) != FIDO_OK)197errx(1, "fido_dev_info_manifest: %s (0x%x)", fido_strerr(r), r);198if (select_dev(devlist, ndevs, &dev, &idx, 15) != 0)199errx(1, "select_dev");200if (dev == NULL)201errx(1, "no authenticator found");202203di = fido_dev_info_ptr(devlist, idx);204printf("%s: %s by %s (PIN %sset)\n", fido_dev_info_path(di),205fido_dev_info_product_string(di),206fido_dev_info_manufacturer_string(di),207fido_dev_has_pin(dev) ? "" : "un");208209fido_dev_close(dev);210fido_dev_free(&dev);211fido_dev_info_free(&devlist, ndevs);212213exit(0);214}215216217