From 173bfbf7886608a4a7abbfac6a42ac4bf4a3432d Mon Sep 17 00:00:00 2001 From: Colin Watson Date: Sun, 20 Sep 2020 16:14:20 +0100 Subject: New upstream version 1.5.0 --- examples/CMakeLists.txt | 16 ++++ examples/README.adoc | 9 ++ examples/assert.c | 15 ++-- examples/cred.c | 15 ++-- examples/extern.h | 1 + examples/info.c | 31 ++++++- examples/manifest.c | 5 +- examples/reset.c | 9 +- examples/retries.c | 5 +- examples/select.c | 215 ++++++++++++++++++++++++++++++++++++++++++++++++ examples/setpin.c | 5 +- examples/util.c | 3 +- 12 files changed, 289 insertions(+), 40 deletions(-) create mode 100644 examples/select.c (limited to 'examples') diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 1203592..7228860 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -3,6 +3,7 @@ # license that can be found in the LICENSE file. list(APPEND COMPAT_SOURCES + ../openbsd-compat/clock_gettime.c ../openbsd-compat/getopt_long.c ../openbsd-compat/strlcat.c ../openbsd-compat/strlcpy.c @@ -15,6 +16,13 @@ endif() # drop -rdynamic set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +# enable -Wconversion -Wsign-conversion +if(NOT MSVC) + set_source_files_properties(assert.c cred.c info.c manifest.c reset.c + retries.c setpin.c util.c PROPERTIES COMPILE_FLAGS + "-Wconversion -Wsign-conversion") +endif() + # manifest add_executable(manifest manifest.c ${COMPAT_SOURCES}) target_link_libraries(manifest fido2) @@ -42,3 +50,11 @@ target_link_libraries(setpin fido2) # retries add_executable(retries retries.c ${COMPAT_SOURCES}) target_link_libraries(retries fido2) + +# select +add_executable(select select.c ${COMPAT_SOURCES}) +target_link_libraries(select fido2) +if(MINGW) + # needed for nanosleep() in mingw + target_link_libraries(select winpthread) +endif() diff --git a/examples/README.adoc b/examples/README.adoc index 091c6bc..b7b73d8 100644 --- a/examples/README.adoc +++ b/examples/README.adoc @@ -77,5 +77,14 @@ The following examples are provided: - retries Get the number of PIN attempts left on before lockout. +- select + + Enumerates available FIDO devices and, if more than one is present, + simultaneously requests touch on all of them, printing information + about the device touched. + Debugging is possible through the use of the FIDO_DEBUG environment variable. If set, libfido2 will produce a log of its transactions with the authenticator. + +Additionally, an example of a WebAuthn client using libfido2 is available at +https://github.com/martelletto/fido2-webauthn-client. diff --git a/examples/assert.c b/examples/assert.c index a421a51..a18d8af 100644 --- a/examples/assert.c +++ b/examples/assert.c @@ -14,17 +14,12 @@ #include #endif -#include "../openbsd-compat/openbsd-compat.h" - #include "fido.h" #include "fido/es256.h" #include "fido/rs256.h" #include "fido/eddsa.h" #include "extern.h" - -#ifdef SIGNAL_EXAMPLE -extern volatile sig_atomic_t got_signal; -#endif +#include "../openbsd-compat/openbsd-compat.h" static const unsigned char cdh[32] = { 0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7, @@ -188,13 +183,15 @@ main(int argc, char **argv) break; case 'T': #ifndef SIGNAL_EXAMPLE + (void)seconds; errx(1, "-T not supported"); -#endif +#else if (base10(optarg, &seconds) < 0) errx(1, "base10: %s", optarg); if (seconds <= 0 || seconds > 30) errx(1, "-T: %s must be in (0,30]", optarg); break; +#endif case 'a': if (read_blob(optarg, &body, &len) < 0) errx(1, "read_blob: %s", optarg); @@ -312,6 +309,10 @@ main(int argc, char **argv) errx(1, "fido_assert_count: %d signatures returned", (int)fido_assert_count(assert)); + /* when verifying, pin implies uv */ + if (pin) + uv = true; + verify_assert(type, fido_assert_authdata_ptr(assert, 0), fido_assert_authdata_len(assert, 0), fido_assert_sig_ptr(assert, 0), fido_assert_sig_len(assert, 0), up, uv, ext, argv[0]); diff --git a/examples/cred.c b/examples/cred.c index 3e0a30f..6bd0faf 100644 --- a/examples/cred.c +++ b/examples/cred.c @@ -16,14 +16,9 @@ #include #endif -#include "../openbsd-compat/openbsd-compat.h" - #include "fido.h" #include "extern.h" - -#ifdef SIGNAL_EXAMPLE -extern volatile sig_atomic_t got_signal; -#endif +#include "../openbsd-compat/openbsd-compat.h" static const unsigned char cdh[32] = { 0xf9, 0x64, 0x57, 0xe7, 0x2d, 0x97, 0xf6, 0xbb, @@ -192,13 +187,15 @@ main(int argc, char **argv) break; case 'T': #ifndef SIGNAL_EXAMPLE + (void)seconds; errx(1, "-T not supported"); -#endif +#else if (base10(optarg, &seconds) < 0) errx(1, "base10: %s", optarg); if (seconds <= 0 || seconds > 30) errx(1, "-T: %s must be in (0,30]", optarg); break; +#endif case 'e': if (read_blob(optarg, &body, &len) < 0) errx(1, "read_blob: %s", optarg); @@ -318,6 +315,10 @@ main(int argc, char **argv) fido_dev_free(&dev); + /* when verifying, pin implies uv */ + if (pin) + uv = true; + verify_cred(type, fido_cred_fmt(cred), fido_cred_authdata_ptr(cred), fido_cred_authdata_len(cred), fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred), fido_cred_sig_ptr(cred), diff --git a/examples/extern.h b/examples/extern.h index 578b8c4..0ea68c4 100644 --- a/examples/extern.h +++ b/examples/extern.h @@ -27,6 +27,7 @@ int write_rsa_pubkey(const char *, const void *, size_t); int write_eddsa_pubkey(const char *, const void *, size_t); #ifdef SIGNAL_EXAMPLE void prepare_signal_handler(int); +extern volatile sig_atomic_t got_signal; #endif #endif /* _EXTERN_H_ */ diff --git a/examples/info.c b/examples/info.c index ef0d97e..d81de85 100644 --- a/examples/info.c +++ b/examples/info.c @@ -4,17 +4,14 @@ * license that can be found in the LICENSE file. */ -#include - #include #include #include #include #include -#include "../openbsd-compat/openbsd-compat.h" - #include "fido.h" +#include "../openbsd-compat/openbsd-compat.h" /* * Pretty-print a device's capabilities flags and return the result. @@ -130,6 +127,26 @@ print_maxmsgsiz(uint64_t maxmsgsiz) printf("maxmsgsiz: %d\n", (int)maxmsgsiz); } +/* + * Auxiliary function to print an authenticator's maximum number of credentials + * in a credential list on stdout. + */ +static void +print_maxcredcntlst(uint64_t maxcredcntlst) +{ + printf("maxcredcntlst: %d\n", (int)maxcredcntlst); +} + +/* + * Auxiliary function to print an authenticator's maximum credential ID length + * on stdout. + */ +static void +print_maxcredidlen(uint64_t maxcredidlen) +{ + printf("maxcredlen: %d\n", (int)maxcredidlen); +} + /* * Auxiliary function to print an authenticator's firmware version on stdout. */ @@ -199,6 +216,12 @@ getinfo(const char *path) /* print maximum message size */ print_maxmsgsiz(fido_cbor_info_maxmsgsiz(ci)); + /* print maximum number of credentials allowed in credential lists */ + print_maxcredcntlst(fido_cbor_info_maxcredcntlst(ci)); + + /* print maximum length of a credential ID */ + print_maxcredidlen(fido_cbor_info_maxcredidlen(ci)); + /* print firmware version */ print_fwversion(fido_cbor_info_fwversion(ci)); diff --git a/examples/manifest.c b/examples/manifest.c index 895447a..d5ebda2 100644 --- a/examples/manifest.c +++ b/examples/manifest.c @@ -4,15 +4,12 @@ * license that can be found in the LICENSE file. */ -#include - #include #include #include -#include "../openbsd-compat/openbsd-compat.h" - #include "fido.h" +#include "../openbsd-compat/openbsd-compat.h" int main(void) diff --git a/examples/reset.c b/examples/reset.c index 36a7de2..3e715c4 100644 --- a/examples/reset.c +++ b/examples/reset.c @@ -8,21 +8,14 @@ * Perform a factory reset on a given authenticator. */ -#include - #include #include #include #include -#include "../openbsd-compat/openbsd-compat.h" - #include "fido.h" #include "extern.h" - -#ifdef SIGNAL_EXAMPLE -extern volatile sig_atomic_t got_signal; -#endif +#include "../openbsd-compat/openbsd-compat.h" int main(int argc, char **argv) diff --git a/examples/retries.c b/examples/retries.c index 3ed7558..5cc116c 100644 --- a/examples/retries.c +++ b/examples/retries.c @@ -8,15 +8,12 @@ * Get an authenticator's number of PIN attempts left. */ -#include - #include #include #include -#include "../openbsd-compat/openbsd-compat.h" - #include "fido.h" +#include "../openbsd-compat/openbsd-compat.h" int main(int argc, char **argv) diff --git a/examples/select.c b/examples/select.c new file mode 100644 index 0000000..1fb2960 --- /dev/null +++ b/examples/select.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2020 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 "fido.h" +#include "../openbsd-compat/openbsd-compat.h" + +#define FIDO_POLL_MS 50 + +#if defined(_MSC_VER) +static int +nanosleep(const struct timespec *rqtp, struct timespec *rmtp) +{ + if (rmtp != NULL) { + errno = EINVAL; + return (-1); + } + + Sleep(rqtp->tv_nsec / 1000000); + + return (0); +} +#endif + +static fido_dev_t * +open_dev(const fido_dev_info_t *di) +{ + fido_dev_t *dev; + int r; + + if ((dev = fido_dev_new()) == NULL) { + warnx("%s: fido_dev_new", __func__); + return (NULL); + } + + if ((r = fido_dev_open(dev, fido_dev_info_path(di))) != FIDO_OK) { + warnx("%s: fido_dev_open %s: %s", __func__, + fido_dev_info_path(di), fido_strerr(r)); + fido_dev_free(&dev); + return (NULL); + } + + printf("%s (0x%04x:0x%04x) is %s\n", fido_dev_info_path(di), + fido_dev_info_vendor(di), fido_dev_info_product(di), + fido_dev_is_fido2(dev) ? "fido2" : "u2f"); + + return (dev); +} + +static int +select_dev(const fido_dev_info_t *devlist, size_t ndevs, fido_dev_t **dev, + size_t *idx, int secs) +{ + const fido_dev_info_t *di; + fido_dev_t **devtab; + struct timespec ts_start; + struct timespec ts_now; + struct timespec ts_delta; + struct timespec ts_pause; + size_t nopen = 0; + int touched; + int r; + long ms_remain; + + *dev = NULL; + *idx = 0; + + printf("%u authenticator(s) detected\n", (unsigned)ndevs); + + if (ndevs == 0) + return (0); /* nothing to do */ + + if ((devtab = calloc(ndevs, sizeof(*devtab))) == NULL) { + warn("%s: calloc", __func__); + return (-1); + } + + for (size_t i = 0; i < ndevs; i++) { + di = fido_dev_info_ptr(devlist, i); + if ((devtab[i] = open_dev(di)) != NULL) { + *idx = i; + nopen++; + } + } + + printf("%u authenticator(s) opened\n", (unsigned)nopen); + + if (nopen < 2) { + if (nopen == 1) + *dev = devtab[*idx]; /* single candidate */ + r = 0; + goto out; + } + + for (size_t i = 0; i < ndevs; i++) { + di = fido_dev_info_ptr(devlist, i); + if (devtab[i] == NULL) + continue; /* failed to open */ + if ((r = fido_dev_get_touch_begin(devtab[i])) != FIDO_OK) { + warnx("%s: fido_dev_get_touch_begin %s: %s", __func__, + fido_dev_info_path(di), fido_strerr(r)); + r = -1; + goto out; + } + } + + if (clock_gettime(CLOCK_MONOTONIC, &ts_start) != 0) { + warn("%s: clock_gettime", __func__); + r = -1; + goto out; + } + + ts_pause.tv_sec = 0; + ts_pause.tv_nsec = 200000000; /* 200ms */ + + do { + nanosleep(&ts_pause, NULL); + + for (size_t i = 0; i < ndevs; i++) { + di = fido_dev_info_ptr(devlist, i); + if (devtab[i] == NULL) { + /* failed to open or discarded */ + continue; + } + if ((r = fido_dev_get_touch_status(devtab[i], &touched, + FIDO_POLL_MS)) != FIDO_OK) { + warnx("%s: fido_dev_get_touch_status %s: %s", + __func__, fido_dev_info_path(di), + fido_strerr(r)); + fido_dev_close(devtab[i]); + fido_dev_free(&devtab[i]); + continue; /* discard */ + } + if (touched) { + *dev = devtab[i]; + *idx = i; + r = 0; + goto out; + } + } + + if (clock_gettime(CLOCK_MONOTONIC, &ts_now) != 0) { + warn("%s: clock_gettime", __func__); + r = -1; + goto out; + } + + timespecsub(&ts_now, &ts_start, &ts_delta); + ms_remain = (secs * 1000) - ((long)ts_delta.tv_sec * 1000) + + ((long)ts_delta.tv_nsec / 1000000); + } while (ms_remain > FIDO_POLL_MS); + + printf("timeout after %d seconds\n", secs); + r = -1; +out: + if (r != 0) { + *dev = NULL; + *idx = 0; + } + + for (size_t i = 0; i < ndevs; i++) { + if (devtab[i] && devtab[i] != *dev) { + fido_dev_cancel(devtab[i]); + fido_dev_close(devtab[i]); + fido_dev_free(&devtab[i]); + } + } + + free(devtab); + + return (r); +} + +int +main(void) +{ + const fido_dev_info_t *di; + fido_dev_info_t *devlist; + fido_dev_t *dev; + size_t idx; + size_t ndevs; + int r; + + fido_init(0); + + if ((devlist = fido_dev_info_new(64)) == NULL) + errx(1, "fido_dev_info_new"); + + if ((r = fido_dev_info_manifest(devlist, 64, &ndevs)) != FIDO_OK) + errx(1, "fido_dev_info_manifest: %s (0x%x)", fido_strerr(r), r); + if (select_dev(devlist, ndevs, &dev, &idx, 15) != 0) + errx(1, "select_dev"); + if (dev == NULL) + errx(1, "no authenticator found"); + + di = fido_dev_info_ptr(devlist, idx); + printf("%s: %s by %s (PIN %sset)\n", fido_dev_info_path(di), + fido_dev_info_product_string(di), + fido_dev_info_manufacturer_string(di), + fido_dev_has_pin(dev) ? "" : "un"); + + fido_dev_close(dev); + fido_dev_free(&dev); + fido_dev_info_free(&devlist, ndevs); + + exit(0); +} diff --git a/examples/setpin.c b/examples/setpin.c index 75d3d4a..5413bf9 100644 --- a/examples/setpin.c +++ b/examples/setpin.c @@ -8,16 +8,13 @@ * Configure a PIN on a given authenticator. */ -#include - #include #include #include #include -#include "../openbsd-compat/openbsd-compat.h" - #include "fido.h" +#include "../openbsd-compat/openbsd-compat.h" static void setpin(const char *path, const char *pin, const char *oldpin) diff --git a/examples/util.c b/examples/util.c index 2f6a845..5291cd8 100644 --- a/examples/util.c +++ b/examples/util.c @@ -27,13 +27,12 @@ #include "../openbsd-compat/posix_win.h" #endif -#include "../openbsd-compat/openbsd-compat.h" - #include "fido.h" #include "fido/es256.h" #include "fido/rs256.h" #include "fido/eddsa.h" #include "extern.h" +#include "../openbsd-compat/openbsd-compat.h" #ifdef SIGNAL_EXAMPLE volatile sig_atomic_t got_signal = 0; -- cgit v1.2.3