aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEd Maste <emaste@FreeBSD.org>2023-04-26 16:39:46 +0000
committerEd Maste <emaste@FreeBSD.org>2023-04-26 16:39:46 +0000
commitcd0b1b947d7afe02b6deaa176ae6767f25818f1b (patch)
treecfc2c6c9daa1dc46c9393a8cd25e4d619e327145
parent3a9b77fea28092bb3b06ed5f5f6e832511c36f96 (diff)
Vendor import of libfido2 1.11.0vendor/libfido2/1.11.0
-rw-r--r--CMakeLists.txt65
-rw-r--r--NEWS11
-rw-r--r--README.adoc115
-rw-r--r--examples/CMakeLists.txt11
-rw-r--r--examples/info.c15
-rw-r--r--examples/select.c4
-rw-r--r--examples/setpin.c2
-rw-r--r--fuzz/CMakeLists.txt6
-rw-r--r--fuzz/Dockerfile16
-rw-r--r--fuzz/Makefile25
-rw-r--r--fuzz/dummy.h4
-rw-r--r--fuzz/export.gnu14
-rw-r--r--fuzz/functions.txt242
-rw-r--r--fuzz/fuzz_mgmt.c5
-rw-r--r--fuzz/fuzz_pcsc.c266
-rw-r--r--fuzz/mutator_aux.c9
-rw-r--r--fuzz/mutator_aux.h12
-rw-r--r--fuzz/pcsc.c152
-rw-r--r--fuzz/report.tgzbin323706 -> 341098 bytes
-rw-r--r--fuzz/summary.txt64
-rw-r--r--fuzz/wiredata_fido2.h76
-rw-r--r--fuzz/wrap.c51
-rw-r--r--fuzz/wrapped.sym9
-rw-r--r--man/CMakeLists.txt27
-rw-r--r--man/fido2-token.124
-rw-r--r--man/fido_assert_new.36
-rw-r--r--man/fido_assert_set_authdata.36
-rw-r--r--man/fido_cbor_info_new.313
-rw-r--r--man/fido_dev_enable_entattest.34
-rw-r--r--man/fido_dev_info_manifest.34
-rw-r--r--openbsd-compat/bsd-asprintf.c88
-rw-r--r--openbsd-compat/openbsd-compat.h4
-rw-r--r--regress/CMakeLists.txt39
-rw-r--r--regress/assert.c13
-rw-r--r--regress/compress.c267
-rw-r--r--regress/cred.c14
-rw-r--r--regress/dev.c42
-rw-r--r--regress/eddsa.c158
-rw-r--r--regress/es256.c198
-rw-r--r--regress/rs256.c200
-rw-r--r--src/CMakeLists.txt22
-rw-r--r--src/compress.c144
-rw-r--r--src/dev.c228
-rw-r--r--src/eddsa.c11
-rw-r--r--src/es256.c65
-rw-r--r--src/export.gnu3
-rw-r--r--src/export.llvm3
-rw-r--r--src/export.msvc3
-rw-r--r--src/extern.h22
-rw-r--r--src/fido.h5
-rw-r--r--src/fido/types.h31
-rw-r--r--src/hid_freebsd.c8
-rw-r--r--src/hid_openbsd.c100
-rw-r--r--src/hid_osx.c25
-rw-r--r--src/info.c8
-rw-r--r--src/nfc.c320
-rw-r--r--src/nfc_linux.c374
-rw-r--r--src/pcsc.c389
-rw-r--r--src/rs1.c2
-rw-r--r--src/rs256.c28
-rw-r--r--src/touch.c108
-rw-r--r--src/util.c30
-rw-r--r--src/webauthn.h75
-rw-r--r--src/winhello.c90
-rw-r--r--tools/CMakeLists.txt7
-rw-r--r--tools/token.c9
-rw-r--r--udev/70-u2f.rules3
-rw-r--r--udev/fidodevs1
-rw-r--r--windows/build.ps126
-rw-r--r--windows/const.ps16
-rwxr-xr-xwindows/cygwin.ps11
-rw-r--r--windows/release.ps120
72 files changed, 3462 insertions, 986 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 11a51ac5a645..2f10727d40e9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2018-2021 Yubico AB. All rights reserved.
+# Copyright (c) 2018-2022 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.
@@ -28,18 +28,19 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_COLOR_MAKEFILE OFF)
set(CMAKE_VERBOSE_MAKEFILE ON)
set(FIDO_MAJOR "1")
-set(FIDO_MINOR "10")
+set(FIDO_MINOR "11")
set(FIDO_PATCH "0")
set(FIDO_VERSION ${FIDO_MAJOR}.${FIDO_MINOR}.${FIDO_PATCH})
option(BUILD_EXAMPLES "Build example programs" ON)
option(BUILD_MANPAGES "Build man pages" ON)
-option(BUILD_SHARED_LIBS "Build the shared library" ON)
-option(BUILD_STATIC_LIBS "Build the static library" ON)
+option(BUILD_SHARED_LIBS "Build a shared library" ON)
+option(BUILD_STATIC_LIBS "Build a static library" ON)
option(BUILD_TOOLS "Build tool programs" ON)
option(FUZZ "Enable fuzzing instrumentation" OFF)
option(LIBFUZZER "Build libfuzzer harnesses" OFF)
option(USE_HIDAPI "Use hidapi as the HID backend" OFF)
+option(USE_PCSC "Enable experimental PCSC support" OFF)
option(USE_WINHELLO "Abstract Windows Hello as a FIDO device" ON)
option(NFC_LINUX "Enable NFC support on Linux" ON)
@@ -91,6 +92,7 @@ check_include_files(sys/random.h HAVE_SYS_RANDOM_H)
check_include_files(unistd.h HAVE_UNISTD_H)
check_symbol_exists(arc4random_buf stdlib.h HAVE_ARC4RANDOM_BUF)
+check_symbol_exists(asprintf stdio.h HAVE_ASPRINTF)
check_symbol_exists(clock_gettime time.h HAVE_CLOCK_GETTIME)
check_symbol_exists(explicit_bzero string.h HAVE_EXPLICIT_BZERO)
check_symbol_exists(freezero stdlib.h HAVE_FREEZERO)
@@ -116,6 +118,7 @@ try_compile(HAVE_POSIX_IOCTL
list(APPEND CHECK_VARIABLES
HAVE_ARC4RANDOM_BUF
+ HAVE_ASPRINTF
HAVE_CBOR_H
HAVE_CLOCK_GETTIME
HAVE_ENDIAN_H
@@ -166,8 +169,8 @@ if(MSVC)
"building under msvc")
endif()
set(CBOR_LIBRARIES cbor)
- set(ZLIB_LIBRARIES zlib)
- set(CRYPTO_LIBRARIES crypto-47)
+ set(ZLIB_LIBRARIES zlib1)
+ set(CRYPTO_LIBRARIES crypto-49)
set(MSVC_DISABLED_WARNINGS_LIST
"C4152" # nonstandard extension used: function/data pointer
# conversion in expression;
@@ -237,6 +240,17 @@ else()
add_compile_options(-Wno-unused-parameter)
endif()
+ if(FUZZ)
+ set(USE_PCSC ON)
+ add_definitions(-DFIDO_FUZZ)
+ endif()
+
+ # If building with PCSC, look for pcsc-lite.
+ if(USE_PCSC AND NOT (APPLE OR CYGWIN OR MSYS OR MINGW))
+ pkg_search_module(PCSC libpcsclite REQUIRED)
+ set(PCSC_LIBRARIES pcsclite)
+ endif()
+
if(USE_HIDAPI)
add_definitions(-DUSE_HIDAPI)
pkg_search_module(HIDAPI hidapi${HIDAPI_SUFFIX} REQUIRED)
@@ -244,7 +258,7 @@ else()
endif()
if(NFC_LINUX)
- add_definitions(-DNFC_LINUX)
+ add_definitions(-DUSE_NFC)
endif()
if(WIN32)
@@ -285,10 +299,6 @@ else()
add_definitions(-DOPENSSL_API_COMPAT=0x10100000L)
endif()
- if(FUZZ)
- add_definitions(-DFIDO_FUZZ)
- endif()
-
if(LIBFUZZER)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=fuzzer-no-link")
endif()
@@ -309,6 +319,10 @@ elseif(WIN32)
endif()
add_definitions(-DTLS=${TLS})
+if(USE_PCSC)
+ add_definitions(-DUSE_PCSC)
+endif()
+
# export list
if(APPLE AND (CMAKE_C_COMPILER_ID STREQUAL "Clang" OR
CMAKE_C_COMPILER_ID STREQUAL "AppleClang"))
@@ -345,16 +359,18 @@ else()
" /def:\"${CMAKE_CURRENT_SOURCE_DIR}/src/export.msvc\"")
endif()
-include_directories(${CMAKE_SOURCE_DIR}/src)
+include_directories(${PROJECT_SOURCE_DIR}/src)
include_directories(${CBOR_INCLUDE_DIRS})
include_directories(${CRYPTO_INCLUDE_DIRS})
include_directories(${HIDAPI_INCLUDE_DIRS})
+include_directories(${PCSC_INCLUDE_DIRS})
include_directories(${UDEV_INCLUDE_DIRS})
include_directories(${ZLIB_INCLUDE_DIRS})
link_directories(${CBOR_LIBRARY_DIRS})
link_directories(${CRYPTO_LIBRARY_DIRS})
link_directories(${HIDAPI_LIBRARY_DIRS})
+link_directories(${PCSC_LIBRARY_DIRS})
link_directories(${UDEV_LIBRARY_DIRS})
link_directories(${ZLIB_LIBRARY_DIRS})
@@ -372,9 +388,14 @@ message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
message(STATUS "CMAKE_C_COMPILER: ${CMAKE_C_COMPILER}")
message(STATUS "CMAKE_C_COMPILER_ID: ${CMAKE_C_COMPILER_ID}")
message(STATUS "CMAKE_C_FLAGS: ${CMAKE_C_FLAGS}")
+message(STATUS "CMAKE_CROSSCOMPILING: ${CMAKE_CROSSCOMPILING}")
+message(STATUS "CMAKE_GENERATOR_PLATFORM: ${CMAKE_GENERATOR_PLATFORM}")
+message(STATUS "CMAKE_HOST_SYSTEM_NAME: ${CMAKE_HOST_SYSTEM_NAME}")
+message(STATUS "CMAKE_HOST_SYSTEM_PROCESSOR: ${CMAKE_HOST_SYSTEM_PROCESSOR}")
message(STATUS "CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR}")
message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}")
message(STATUS "CMAKE_SYSTEM_NAME: ${CMAKE_SYSTEM_NAME}")
+message(STATUS "CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}")
message(STATUS "CMAKE_SYSTEM_VERSION: ${CMAKE_SYSTEM_VERSION}")
message(STATUS "CRYPTO_INCLUDE_DIRS: ${CRYPTO_INCLUDE_DIRS}")
message(STATUS "CRYPTO_LIBRARIES: ${CRYPTO_LIBRARIES}")
@@ -392,6 +413,10 @@ if(USE_HIDAPI)
message(STATUS "HIDAPI_LIBRARY_DIRS: ${HIDAPI_LIBRARY_DIRS}")
message(STATUS "HIDAPI_VERSION: ${HIDAPI_VERSION}")
endif()
+message(STATUS "PCSC_INCLUDE_DIRS: ${PCSC_INCLUDE_DIRS}")
+message(STATUS "PCSC_LIBRARIES: ${PCSC_LIBRARIES}")
+message(STATUS "PCSC_LIBRARY_DIRS: ${PCSC_LIBRARY_DIRS}")
+message(STATUS "PCSC_VERSION: ${PCSC_VERSION}")
message(STATUS "LIBFUZZER: ${LIBFUZZER}")
message(STATUS "TLS: ${TLS}")
message(STATUS "UDEV_INCLUDE_DIRS: ${UDEV_INCLUDE_DIRS}")
@@ -400,10 +425,22 @@ message(STATUS "UDEV_LIBRARY_DIRS: ${UDEV_LIBRARY_DIRS}")
message(STATUS "UDEV_RULES_DIR: ${UDEV_RULES_DIR}")
message(STATUS "UDEV_VERSION: ${UDEV_VERSION}")
message(STATUS "USE_HIDAPI: ${USE_HIDAPI}")
+message(STATUS "USE_PCSC: ${USE_PCSC}")
message(STATUS "USE_WINHELLO: ${USE_WINHELLO}")
message(STATUS "NFC_LINUX: ${NFC_LINUX}")
+if(BUILD_SHARED_LIBS)
+ set(_FIDO2_LIBRARY fido2_shared)
+elseif(BUILD_STATIC_LIBS)
+ set(_FIDO2_LIBRARY fido2)
+else()
+ message(FATAL_ERROR "Nothing to build (BUILD_*_LIBS=OFF)")
+endif()
+
+enable_testing()
+
subdirs(src)
+subdirs(regress)
if(BUILD_EXAMPLES)
subdirs(examples)
endif()
@@ -415,10 +452,6 @@ if(BUILD_MANPAGES)
endif()
if(NOT WIN32)
- if(CMAKE_BUILD_TYPE STREQUAL "Debug" AND NOT FUZZ)
- enable_testing()
- subdirs(regress)
- endif()
if(FUZZ)
subdirs(fuzz)
endif()
diff --git a/NEWS b/NEWS
index a48b685156c1..f5bd414297dd 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,14 @@
+* Version 1.11.0 (2022-05-03)
+ ** Experimental PCSC support; enable with -DUSE_PCSC.
+ ** Improved OpenSSL 3.0 compatibility.
+ ** Use RFC1951 raw deflate to compress CTAP 2.1 largeBlobs.
+ ** winhello: advertise "uv" instead of "clientPin".
+ ** winhello: support hmac-secret in fido_dev_get_assert().
+ ** New API calls:
+ - fido_cbor_info_maxlargeblob.
+ ** Documentation and reliability fixes.
+ ** Separate build and regress targets.
+
* Version 1.10.0 (2022-01-17)
** hid_osx: handle devices with paths > 511 bytes; gh#462.
** bio: fix CTAP2 canonical CBOR encoding in fido_bio_dev_enroll_*(); gh#480.
diff --git a/README.adoc b/README.adoc
index 114cc5eed762..c9cdafb5fea8 100644
--- a/README.adoc
+++ b/README.adoc
@@ -7,7 +7,7 @@ image:https://github.com/yubico/libfido2/workflows/fuzzer/badge.svg["Fuzz Status
image:https://oss-fuzz-build-logs.storage.googleapis.com/badges/libfido2.svg["Fuzz Status (oss-fuzz)", link="https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:libfido2"]
*libfido2* provides library functionality and command-line tools to
-communicate with a FIDO device over USB, and to verify attestation and
+communicate with a FIDO device over USB or NFC, and to verify attestation and
assertion signatures.
*libfido2* supports the FIDO U2F (CTAP 1) and FIDO2 (CTAP 2) protocols.
@@ -23,8 +23,6 @@ file for the full license text.
*libfido2* is known to work on Linux, macOS, Windows, OpenBSD, and FreeBSD.
-NFC support is available on Linux and Windows.
-
=== Documentation
Documentation is available in troff and HTML formats. An
@@ -38,19 +36,29 @@ is also available.
* Perl: https://github.com/jacquesg/p5-FIDO-Raw[p5-FIDO-Raw]
* Rust: https://github.com/PvdBerg1998/libfido2[libfido2]
+=== Releases
+
+The current release of *libfido2* is 1.11.0. Signed release tarballs are
+available at Yubico's
+https://developers.yubico.com/libfido2/Releases[release page].
+
+=== Dependencies
+
+*libfido2* depends on https://github.com/pjk/libcbor[libcbor],
+https://www.openssl.org[OpenSSL] 1.1 or newer, and https://zlib.net[zlib].
+On Linux, libudev
+(part of https://www.freedesktop.org/wiki/Software/systemd[systemd]) is also
+required.
+
=== Installation
-==== Releases
+==== Fedora 35 and 34
-The current release of *libfido2* is 1.10.0. Please consult Yubico's
-https://developers.yubico.com/libfido2/Releases[release page] for source
-and binary releases.
+ $ sudo dnf install libfido2 libfido2-devel fido2-tools
-==== Ubuntu 20.04 (Focal)
+==== Ubuntu 22.04 (Jammy) and 20.04 (Focal)
- $ sudo apt install libfido2-1
- $ sudo apt install libfido2-dev
- $ sudo apt install libfido2-doc
+ $ sudo apt install libfido2-1 libfido2-dev libfido2-doc fido2-tools
Alternatively, newer versions of *libfido2* are available in Yubico's PPA.
Follow the instructions for Ubuntu 18.04 (Bionic) below.
@@ -60,13 +68,31 @@ Follow the instructions for Ubuntu 18.04 (Bionic) below.
$ sudo apt install software-properties-common
$ sudo apt-add-repository ppa:yubico/stable
$ sudo apt update
- $ sudo apt install libfido2-dev
+ $ sudo apt install libfido2-1 libfido2-dev libfido2-doc fido2-tools
+
+On Linux, you may need to add a udev rule to be able to access the FIDO
+device. For example, the udev rule may contain the following:
+
+----
+#udev rule for allowing HID access to Yubico devices for FIDO support.
+
+KERNEL=="hidraw*", SUBSYSTEM=="hidraw", \
+ MODE="0664", GROUP="plugdev", ATTRS{idVendor}=="1050"
+----
==== macOS
$ brew install libfido2
-Or from source, on UNIX-like systems:
+==== Windows
+
+Please consult Yubico's
+https://developers.yubico.com/libfido2/Releases[release page] for ARM, ARM64,
+Win32, and Win64 artefacts.
+
+=== Building from source
+
+On UNIX-like systems:
$ cmake -B build
$ make -C build
@@ -74,23 +100,46 @@ Or from source, on UNIX-like systems:
Depending on the platform,
https://www.freedesktop.org/wiki/Software/pkg-config/[pkg-config] may need to
-be installed, or the PKG_CONFIG_PATH environment variable set.
-
-*libfido2* depends on https://github.com/pjk/libcbor[libcbor],
-https://www.openssl.org[OpenSSL] 1.1 or newer, and https://zlib.net[zlib].
-On Linux, libudev
-(part of https://www.freedesktop.org/wiki/Software/systemd[systemd]) is also
-required.
-
-For complete, OS-specific installation instructions, please refer to the
-`.actions/` (Linux, macOS) and `windows/` directories.
-
-On Linux, you will need to add a udev rule to be able to access the FIDO
-device, or run as root. For example, the udev rule may contain the following:
-
-----
-#udev rule for allowing HID access to Yubico devices for FIDO support.
-
-KERNEL=="hidraw*", SUBSYSTEM=="hidraw", \
- MODE="0664", GROUP="plugdev", ATTRS{idVendor}=="1050"
-----
+be installed, or the PKG_CONFIG_PATH environment variable set. For complete,
+OS-specific build instructions, please refer to the `.actions/`
+(Linux, macOS, BSD) and `windows/` directories.
+
+=== Build-time Customisation
+
+*libfido2* supports a number of CMake options. Some of the options require
+additional dependencies. Options that are disabled by default are not
+officially supported.
+
+[%autowidth.stretch]
+|===
+|*Option* |*Description* |*Default*
+| BUILD_EXAMPLES | Build example programs | ON
+| BUILD_MANPAGES | Build man pages | ON
+| BUILD_SHARED_LIBS | Build a shared library | ON
+| BUILD_STATIC_LIBS | Build a static library | ON
+| BUILD_TOOLS | Build auxiliary tools | ON
+| FUZZ | Enable fuzzing instrumentation | OFF
+| LIBFUZZER | Build libfuzzer harnesses | OFF
+| NFC_LINUX | Enable netlink NFC support on Linux | ON
+| USE_HIDAPI | Use hidapi as the HID backend | OFF
+| USE_PCSC | Enable experimental PCSC support | OFF
+| USE_WINHELLO | Abstract Windows Hello as a FIDO device | ON
+|===
+
+The USE_HIDAPI option requires https://github.com/libusb/hidapi[hidapi]. The
+USE_PCSC option requires https://github.com/LudovicRousseau/PCSC[pcsc-lite] on
+Linux.
+
+=== Development
+
+Please use https://github.com/Yubico/libfido2/discussions[GitHub Discussions]
+to ask questions and suggest features, and
+https://github.com/Yubico/libfido2/pulls[GitHub pull-requests] for code
+contributions.
+
+=== Reporting bugs
+
+Please use https://github.com/Yubico/libfido2/issues[GitHub Issues] to report
+bugs. To report security issues, please contact security@yubico.com. A PGP
+public key can be found at
+https://www.yubico.com/support/security-advisories/issue-rating-system/.
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index ad3d44faad6b..e558b620fd6e 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -13,17 +13,6 @@ if(WIN32 AND BUILD_SHARED_LIBS AND NOT CYGWIN AND NOT MSYS)
list(APPEND COMPAT_SOURCES ../openbsd-compat/posix_win.c)
endif()
-# set the library to link against
-if(BUILD_STATIC_LIBS)
- # drop -rdynamic
- set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
- set(_FIDO2_LIBRARY fido2)
-elseif(BUILD_SHARED_LIBS)
- set(_FIDO2_LIBRARY fido2_shared)
-else()
- set(_FIDO2_LIBRARY ${CRYPTO_LIBRARIES} fido2)
-endif()
-
# enable -Wconversion -Wsign-conversion
if(NOT MSVC)
set_source_files_properties(assert.c cred.c info.c manifest.c reset.c
diff --git a/examples/info.c b/examples/info.c
index 72b786a8bd83..1098580eec6f 100644
--- a/examples/info.c
+++ b/examples/info.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018 Yubico AB. All rights reserved.
+ * Copyright (c) 2018-2022 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.
*/
@@ -183,6 +183,16 @@ print_maxcredidlen(uint64_t maxcredidlen)
}
/*
+ * Auxiliary function to print the maximum size of an authenticator's
+ * serialized largeBlob array.
+ */
+static void
+print_maxlargeblob(uint64_t maxlargeblob)
+{
+ printf("maxlargeblob: %d\n", (int)maxlargeblob);
+}
+
+/*
* Auxiliary function to print an authenticator's firmware version on stdout.
*/
static void
@@ -264,6 +274,9 @@ getinfo(const char *path)
/* print maximum length of a credential ID */
print_maxcredidlen(fido_cbor_info_maxcredidlen(ci));
+ /* print maximum length of largeBlob array */
+ print_maxlargeblob(fido_cbor_info_maxlargeblob(ci));
+
/* print firmware version */
print_fwversion(fido_cbor_info_fwversion(ci));
diff --git a/examples/select.c b/examples/select.c
index 6ede9b490a95..05f6a331fd4c 100644
--- a/examples/select.c
+++ b/examples/select.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Yubico AB. All rights reserved.
+ * Copyright (c) 2020-2022 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.
*/
@@ -23,7 +23,7 @@ nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
return (-1);
}
- Sleep(rqtp->tv_nsec / 1000000);
+ Sleep((DWORD)(rqtp->tv_sec * 1000) + (DWORD)(rqtp->tv_nsec / 1000000));
return (0);
}
diff --git a/examples/setpin.c b/examples/setpin.c
index 4b9e792769d9..7fa0dcc764f3 100644
--- a/examples/setpin.c
+++ b/examples/setpin.c
@@ -29,7 +29,7 @@ setpin(const char *path, const char *pin, const char *oldpin)
errx(1, "fido_dev_open: %s (0x%x)", fido_strerr(r), r);
if ((r = fido_dev_set_pin(dev, pin, oldpin)) != FIDO_OK)
- errx(1, "fido_setpin: %s (0x%x)", fido_strerr(r), r);
+ errx(1, "fido_dev_set_pin: %s (0x%x)", fido_strerr(r), r);
if ((r = fido_dev_close(dev)) != FIDO_OK)
errx(1, "fido_dev_close: %s (0x%x)", fido_strerr(r), r);
diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt
index b1eebd55481b..4b6fdfbfca4f 100644
--- a/fuzz/CMakeLists.txt
+++ b/fuzz/CMakeLists.txt
@@ -61,3 +61,9 @@ add_executable(fuzz_largeblob fuzz_largeblob.c ${COMMON_SOURCES} ${COMPAT_SOURCE
target_compile_options(fuzz_largeblob PRIVATE ${FUZZ_LDFLAGS})
set_target_properties(fuzz_largeblob PROPERTIES LINK_FLAGS ${FUZZ_LDFLAGS})
target_link_libraries(fuzz_largeblob fido2_shared)
+
+# fuzz_pcsc
+add_executable(fuzz_pcsc fuzz_pcsc.c ${COMMON_SOURCES} ${COMPAT_SOURCES})
+target_compile_options(fuzz_pcsc PRIVATE ${FUZZ_LDFLAGS})
+set_target_properties(fuzz_pcsc PROPERTIES LINK_FLAGS ${FUZZ_LDFLAGS})
+target_link_libraries(fuzz_pcsc fido2_shared)
diff --git a/fuzz/Dockerfile b/fuzz/Dockerfile
index aefe1980ada4..a899df2c3ddd 100644
--- a/fuzz/Dockerfile
+++ b/fuzz/Dockerfile
@@ -1,12 +1,16 @@
-# Copyright (c) 2019-2021 Yubico AB. All rights reserved.
+# Copyright (c) 2019-2022 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.
FROM ubuntu:focal
ENV DEBIAN_FRONTEND=noninteractive
+ENV CC=clang-14
+ENV CXX=clang++-14
RUN apt-get update
-RUN apt-get install -y clang-12 cmake git libssl-dev libudev-dev make pkg-config
-RUN apt-get install -y zlib1g-dev
-RUN git clone --branch v0.9.0 https://github.com/PJK/libcbor
-RUN git clone https://github.com/yubico/libfido2
-RUN CC=clang-12 CXX=clang++-12 /libfido2/fuzz/build-coverage /libcbor /libfido2
+RUN apt-get install -y cmake git libssl-dev libudev-dev make pkg-config
+RUN apt-get install -y libpcsclite-dev zlib1g-dev software-properties-common
+RUN git clone --branch v0.9.0 --depth=1 https://github.com/PJK/libcbor
+RUN git clone --depth=1 https://github.com/yubico/libfido2
+WORKDIR /libfido2
+RUN ./.actions/setup_clang "${CC}"
+RUN ./fuzz/build-coverage /libcbor /libfido2
diff --git a/fuzz/Makefile b/fuzz/Makefile
index ce3fee73c69c..6abf59c3e69d 100644
--- a/fuzz/Makefile
+++ b/fuzz/Makefile
@@ -1,13 +1,13 @@
-# Copyright (c) 2019-2021 Yubico AB. All rights reserved.
+# Copyright (c) 2019-2022 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.
-IMAGE := libfido2-coverage:1.10.0
+IMAGE := libfido2-coverage:1.11.2
RUNNER := libfido2-runner
-PROFDATA := llvm-profdata-12
-COV := llvm-cov-12
+PROFDATA := llvm-profdata-14
+COV := llvm-cov-14
TARGETS := fuzz_assert fuzz_bio fuzz_cred fuzz_credman fuzz_hid \
- fuzz_largeblob fuzz_netlink fuzz_mgmt
+ fuzz_largeblob fuzz_netlink fuzz_mgmt fuzz_pcsc
CORPORA := $(foreach f,${TARGETS},${f}/corpus)
MINIFY := $(foreach f,${TARGETS},/minify/${f}/corpus)
REMOTE := gs://libfido2-corpus.clusterfuzz-external.appspot.com
@@ -24,7 +24,7 @@ run: build
sync: run
tar Ccf .. - src fuzz | docker exec -i ${RUNNER} tar Cxf /libfido2 -
- docker exec ${RUNNER} make -C libfido2/build
+ docker exec ${RUNNER} make -C /libfido2/build
corpus: sync
docker exec ${RUNNER} /bin/sh -c 'cd /libfido2/fuzz && rm -rf ${TARGETS}'
@@ -45,23 +45,24 @@ corpus.tgz-: ${MINIFY}
profdata: run
docker exec ${RUNNER} /bin/sh -c 'rm -f /$@ && ${PROFDATA} \
- merge -sparse profraw/* -o $@'
+ merge -sparse /profraw/* -o /$@'
report.tgz: profdata
docker exec ${RUNNER} /bin/sh -c 'rm -rf /report && mkdir /report && \
${COV} show -format=html -tab-size=8 -instr-profile=/$< \
- --show-branch-summary=false -output-dir=/report \
- /libfido2/build/src/libfido2.so'
+ -ignore-filename-regex=pcsclite.h --show-branch-summary=false \
+ -output-dir=/report /libfido2/build/src/libfido2.so'
docker exec -i ${RUNNER} tar Czcf / - report > $@
summary.txt: profdata
docker exec ${RUNNER} ${COV} report -use-color=false \
- --show-branch-summary=false /libfido2/build/src/libfido2.so \
- -instr-profile=/$< > $@
+ -ignore-filename-regex=pcsclite.h --show-branch-summary=false \
+ /libfido2/build/src/libfido2.so -instr-profile=/$< > $@
functions.txt: profdata
docker exec ${RUNNER} /bin/sh -c '${COV} report -use-color=false \
- -show-functions --show-branch-summary=false -instr-profile=/$< \
+ -ignore-filename-regex=pcsclite.h -show-functions \
+ --show-branch-summary=false -instr-profile=/$< \
/libfido2/build/src/libfido2.so /libfido2/src/*.[ch]' > $@
clean: run
diff --git a/fuzz/dummy.h b/fuzz/dummy.h
index 95744eba634b..b0225440e5da 100644
--- a/fuzz/dummy.h
+++ b/fuzz/dummy.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Yubico AB. All rights reserved.
+ * Copyright (c) 2020-2022 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.
*/
@@ -18,6 +18,8 @@ const char dummy_rp_name[] = "sweet home localhost";
const char dummy_user_icon[] = "an icon";
const char dummy_user_name[] = "john smith";
const char dummy_user_nick[] = "jsmith";
+const char dummy_pcsc_list[] = "reader1\0reader2\0reader3\0\0";
+const char dummy_pcsc_path[] = "pcsc://slot7";
const uint8_t dummy_id[] = { 0x5e, 0xd2 };
const uint8_t dummy_user_id[] = {
diff --git a/fuzz/export.gnu b/fuzz/export.gnu
index cac142ae970e..0ce72434fbd8 100644
--- a/fuzz/export.gnu
+++ b/fuzz/export.gnu
@@ -85,10 +85,11 @@
fido_cbor_info_extensions_len;
fido_cbor_info_extensions_ptr;
fido_cbor_info_free;
- fido_cbor_info_maxmsgsiz;
fido_cbor_info_maxcredbloblen;
fido_cbor_info_maxcredcntlst;
fido_cbor_info_maxcredidlen;
+ fido_cbor_info_maxlargeblob;
+ fido_cbor_info_maxmsgsiz;
fido_cbor_info_fwversion;
fido_cbor_info_new;
fido_cbor_info_options_len;
@@ -212,6 +213,7 @@
fido_dev_protocol;
fido_dev_reset;
fido_dev_set_io_functions;
+ fido_dev_set_pcsc;
fido_dev_set_pin;
fido_dev_set_pin_minlen;
fido_dev_set_pin_minlen_rpid;
@@ -237,6 +239,13 @@
fido_nl_get_nfc_target;
fido_nl_new;
fido_nl_power_nfc;
+ fido_pcsc_close;
+ fido_pcsc_manifest;
+ fido_pcsc_open;
+ fido_pcsc_read;
+ fido_pcsc_rx;
+ fido_pcsc_tx;
+ fido_pcsc_write;
fido_set_log_handler;
fido_strerr;
rs256_pk_free;
@@ -246,8 +255,11 @@
rs256_pk_new;
rs256_pk_to_EVP_PKEY;
prng_init;
+ prng_up;
fuzz_clock_reset;
set_netlink_io_functions;
+ set_pcsc_parameters;
+ set_pcsc_io_functions;
set_udev_parameters;
uniform_random;
local:
diff --git a/fuzz/functions.txt b/fuzz/functions.txt
index 946682d07d00..9c1a03cffb0b 100644
--- a/fuzz/functions.txt
+++ b/fuzz/functions.txt
@@ -1,16 +1,16 @@
File '/libfido2/src/aes256.c':
Name Regions Miss Cover Lines Miss Cover
--------------------------------------------------------------------------------------------------------
-aes256_cbc_enc 3 0 100.00% 4 0 100.00%
-aes256_cbc_dec 3 0 100.00% 4 0 100.00%
+aes256_cbc_enc 4 0 100.00% 4 0 100.00%
+aes256_cbc_dec 4 0 100.00% 4 0 100.00%
aes256_gcm_enc 1 0 100.00% 3 0 100.00%
aes256_gcm_dec 1 0 100.00% 3 0 100.00%
aes256.c:aes256_cbc_fips 26 2 92.31% 42 7 83.33%
aes256.c:aes256_cbc 29 1 96.55% 36 3 91.67%
aes256.c:aes256_cbc_proto1 1 0 100.00% 5 0 100.00%
-aes256.c:aes256_gcm 51 1 98.04% 60 4 93.33%
+aes256.c:aes256_gcm 52 1 98.08% 60 4 93.33%
--------------------------------------------------------------------------------------------------------
-TOTAL 115 4 96.52% 157 14 91.08%
+TOTAL 118 4 96.61% 157 14 91.08%
File '/libfido2/src/assert.c':
Name Regions Miss Cover Lines Miss Cover
@@ -18,7 +18,7 @@ Name Regions Miss Cover Lines Miss
fido_dev_get_assert 40 0 100.00% 35 0 100.00%
fido_check_flags 13 0 100.00% 15 0 100.00%
fido_get_signed_hash 36 0 100.00% 46 0 100.00%
-fido_assert_verify 48 4 91.67% 67 5 92.54%
+fido_assert_verify 48 4 91.67% 67 7 89.55%
fido_assert_set_clientdata 12 12 0.00% 11 11 0.00%
fido_assert_set_clientdata_hash 8 0 100.00% 6 0 100.00%
fido_assert_set_hmac_salt 10 0 100.00% 6 0 100.00%
@@ -26,7 +26,7 @@ fido_assert_set_hmac_secret 12 12 0.00% 7 7
fido_assert_set_rp 12 0 100.00% 11 0 100.00%
fido_assert_allow_cred 13 2 84.62% 22 3 86.36%
fido_assert_set_extensions 14 0 100.00% 10 0 100.00%
-fido_assert_set_options 6 6 0.00% 5 5 0.00%
+fido_assert_set_options 8 8 0.00% 5 5 0.00%
fido_assert_set_up 2 0 100.00% 4 0 100.00%
fido_assert_set_uv 2 0 100.00% 4 0 100.00%
fido_assert_clientdata_hash_ptr 1 0 100.00% 3 0 100.00%
@@ -72,7 +72,7 @@ assert.c:check_extensions 5 0 100.00% 9 0
assert.c:fido_assert_reset_extattr 1 0 100.00% 5 0 100.00%
assert.c:fido_assert_clean_authdata 1 0 100.00% 5 0 100.00%
-----------------------------------------------------------------------------------------------------------------
-TOTAL 563 40 92.90% 694 40 94.24%
+TOTAL 565 42 92.57% 694 42 93.95%
File '/libfido2/src/authkey.c':
Name Regions Miss Cover Lines Miss Cover
@@ -88,10 +88,10 @@ TOTAL 44 0 100.00% 59 0
File '/libfido2/src/bio.c':
Name Regions Miss Cover Lines Miss Cover
-----------------------------------------------------------------------------------------------------------------
-fido_bio_dev_get_template_array 5 2 60.00% 6 0 100.00%
+fido_bio_dev_get_template_array 5 2 60.00% 6 1 83.33%
fido_bio_dev_set_template_name 7 0 100.00% 6 0 100.00%
-fido_bio_dev_enroll_begin 25 2 92.00% 31 0 100.00%
-fido_bio_dev_enroll_continue 5 2 60.00% 6 0 100.00%
+fido_bio_dev_enroll_begin 25 2 92.00% 31 1 96.77%
+fido_bio_dev_enroll_continue 5 2 60.00% 6 1 83.33%
fido_bio_dev_enroll_cancel 1 1 0.00% 4 4 0.00%
fido_bio_dev_enroll_remove 1 0 100.00% 4 0 100.00%
fido_bio_dev_get_info 1 0 100.00% 4 0 100.00%
@@ -138,7 +138,7 @@ bio.c:bio_reset_template_array 4 0 100.00% 7 0
bio.c:bio_reset_template 1 0 100.00% 5 0 100.00%
bio.c:bio_reset_enroll 3 0 100.00% 6 0 100.00%
-----------------------------------------------------------------------------------------------------------------
-TOTAL 419 20 95.23% 559 21 96.24%
+TOTAL 419 20 95.23% 559 24 95.71%
File '/libfido2/src/blob.c':
Name Regions Miss Cover Lines Miss Cover
@@ -187,9 +187,9 @@ cbor_encode_str_array 18 0 100.00% 19 0
cbor_encode_cred_ext 55 0 100.00% 50 0 100.00%
cbor_encode_cred_opt 13 0 100.00% 11 0 100.00%
cbor_encode_assert_opt 13 0 100.00% 11 0 100.00%
-cbor_encode_pin_auth 20 1 95.00% 22 3 86.36%
+cbor_encode_pin_auth 21 1 95.24% 22 3 86.36%
cbor_encode_pin_opt 4 0 100.00% 8 0 100.00%
-cbor_encode_change_pin_auth 31 1 96.77% 36 3 91.67%
+cbor_encode_change_pin_auth 32 1 96.88% 36 3 91.67%
cbor_encode_assert_ext 33 0 100.00% 32 0 100.00%
cbor_decode_fmt 13 0 100.00% 15 0 100.00%
cbor_decode_pubkey 21 1 95.24% 30 2 93.33%
@@ -200,7 +200,7 @@ cbor_decode_uint64 4 0 100.00% 8 0
cbor_decode_cred_id 8 0 100.00% 9 0 100.00%
cbor_decode_user 8 0 100.00% 9 0 100.00%
cbor_decode_rp_entity 8 0 100.00% 9 0 100.00%
-cbor_build_uint 10 1 90.00% 9 2 77.78%
+cbor_build_uint 10 1 90.00% 9 1 88.89%
cbor_array_append 17 0 100.00% 21 0 100.00%
cbor_array_drop 18 2 88.89% 17 3 82.35%
cbor.c:ctap_check_cbor 28 0 100.00% 26 0 100.00%
@@ -222,16 +222,18 @@ cbor.c:decode_cred_id_entry 10 0 100.00% 19 0
cbor.c:decode_user_entry 25 0 100.00% 35 0 100.00%
cbor.c:decode_rp_entity_entry 15 0 100.00% 25 0 100.00%
------------------------------------------------------------------------------------------------------------------
-TOTAL 1047 23 97.80% 1237 46 96.28%
+TOTAL 1049 23 97.81% 1237 45 96.36%
File '/libfido2/src/compress.c':
Name Regions Miss Cover Lines Miss Cover
------------------------------------------------------------------------------------------------------------------
fido_compress 1 0 100.00% 3 0 100.00%
-fido_uncompress 1 0 100.00% 3 0 100.00%
-compress.c:do_compress 32 4 87.50% 22 3 86.36%
+fido_uncompress 6 0 100.00% 5 0 100.00%
+compress.c:rfc1951_deflate 33 2 93.94% 47 3 93.62%
+compress.c:rfc1950_inflate 27 2 92.59% 22 4 81.82%
+compress.c:rfc1951_inflate 38 10 73.68% 45 17 62.22%
------------------------------------------------------------------------------------------------------------------
-TOTAL 34 4 88.24% 28 3 89.29%
+TOTAL 105 14 86.67% 122 24 80.33%
File '/libfido2/src/config.c':
Name Regions Miss Cover Lines Miss Cover
@@ -255,8 +257,8 @@ Name Regions Miss Cover Lines Mis
-------------------------------------------------------------------------------------------------------------------
fido_dev_make_cred 12 0 100.00% 10 0 100.00%
fido_check_rp_id 4 0 100.00% 11 0 100.00%
-fido_cred_verify 56 2 96.43% 72 5 93.06%
-fido_cred_verify_self 58 4 93.10% 83 5 93.98%
+fido_cred_verify 56 2 96.43% 72 4 94.44%
+fido_cred_verify_self 58 4 93.10% 83 7 91.57%
fido_cred_new 1 0 100.00% 3 0 100.00%
fido_cred_reset_tx 1 0 100.00% 19 0 100.00%
fido_cred_reset_rx 1 0 100.00% 7 0 100.00%
@@ -273,13 +275,13 @@ fido_cred_set_clientdata_hash 8 0 100.00% 6
fido_cred_set_rp 18 0 100.00% 22 0 100.00%
fido_cred_set_user 32 0 100.00% 41 0 100.00%
fido_cred_set_extensions 16 0 100.00% 10 0 100.00%
-fido_cred_set_options 6 6 0.00% 5 5 0.00%
+fido_cred_set_options 8 8 0.00% 5 5 0.00%
fido_cred_set_rk 2 0 100.00% 4 0 100.00%
fido_cred_set_uv 2 0 100.00% 4 0 100.00%
fido_cred_set_prot 21 0 100.00% 14 0 100.00%
fido_cred_set_pin_minlen 7 0 100.00% 8 0 100.00%
fido_cred_set_blob 13 2 84.62% 8 1 87.50%
-fido_cred_set_fmt 20 4 80.00% 12 1 91.67%
+fido_cred_set_fmt 20 4 80.00% 12 2 83.33%
fido_cred_set_type 17 0 100.00% 7 0 100.00%
fido_cred_type 1 0 100.00% 3 0 100.00%
fido_cred_flags 1 0 100.00% 3 0 100.00%
@@ -319,11 +321,11 @@ cred.c:fido_dev_make_cred_rx 29 0 100.00% 32
cred.c:parse_makecred_reply 14 0 100.00% 27 0 100.00%
cred.c:check_extensions 2 0 100.00% 6 0 100.00%
cred.c:get_signed_hash_u2f 27 0 100.00% 26 0 100.00%
-cred.c:verify_attstmt 23 2 91.30% 40 5 87.50%
+cred.c:verify_attstmt 23 2 91.30% 40 6 85.00%
cred.c:fido_cred_clean_authdata 1 0 100.00% 8 0 100.00%
cred.c:fido_cred_clean_attstmt 1 0 100.00% 8 0 100.00%
-------------------------------------------------------------------------------------------------------------------
-TOTAL 632 34 94.62% 830 36 95.66%
+TOTAL 634 36 94.32% 830 39 95.30%
File '/libfido2/src/credman.c':
Name Regions Miss Cover Lines Miss Cover
@@ -334,15 +336,15 @@ fido_credman_del_dev_rk 1 0 100.00% 4
fido_credman_get_dev_rp 1 0 100.00% 4 0 100.00%
fido_credman_set_dev_rk 1 0 100.00% 4 0 100.00%
fido_credman_rk_new 1 0 100.00% 3 0 100.00%
-fido_credman_rk_free 6 1 83.33% 8 0 100.00%
+fido_credman_rk_free 6 1 83.33% 8 1 87.50%
fido_credman_rk_count 1 0 100.00% 3 0 100.00%
fido_credman_rk 4 0 100.00% 5 0 100.00%
fido_credman_metadata_new 1 0 100.00% 3 0 100.00%
-fido_credman_metadata_free 6 1 83.33% 7 0 100.00%
+fido_credman_metadata_free 6 1 83.33% 7 1 85.71%
fido_credman_rk_existing 1 0 100.00% 3 0 100.00%
fido_credman_rk_remaining 1 0 100.00% 3 0 100.00%
fido_credman_rp_new 1 0 100.00% 3 0 100.00%
-fido_credman_rp_free 6 1 83.33% 8 0 100.00%
+fido_credman_rp_free 6 1 83.33% 8 1 87.50%
fido_credman_rp_count 1 0 100.00% 3 0 100.00%
fido_credman_rp_id 4 0 100.00% 5 0 100.00%
fido_credman_rp_name 4 0 100.00% 5 0 100.00%
@@ -369,21 +371,17 @@ credman.c:credman_set_dev_rk_wait 11 0 100.00% 8
credman.c:credman_reset_rk 4 0 100.00% 9 0 100.00%
credman.c:credman_reset_rp 4 0 100.00% 12 0 100.00%
-------------------------------------------------------------------------------------------------------------------
-TOTAL 382 10 97.38% 518 15 97.10%
+TOTAL 382 10 97.38% 518 18 96.53%
File '/libfido2/src/dev.c':
Name Regions Miss Cover Lines Miss Cover
-------------------------------------------------------------------------------------------------------------------
-fido_dev_register_manifest_func 10 2 80.00% 14 3 78.57%
-fido_dev_unregister_manifest_func 7 7 0.00% 11 11 0.00%
-fido_dev_info_manifest 22 4 81.82% 24 0 100.00%
+fido_dev_info_manifest 2 0 100.00% 11 0 100.00%
fido_dev_open_with_info 5 5 0.00% 6 6 0.00%
-fido_dev_open 5 1 80.00% 19 12 36.84%
-fido_dev_close 9 2 77.78% 8 0 100.00%
+fido_dev_open 13 6 53.85% 16 6 62.50%
+fido_dev_close 9 2 77.78% 8 1 87.50%
fido_dev_set_sigmask 18 18 0.00% 11 11 0.00%
fido_dev_cancel 11 0 100.00% 8 0 100.00%
-fido_dev_get_touch_begin 50 0 100.00% 59 0 100.00%
-fido_dev_get_touch_status 17 0 100.00% 20 0 100.00%
fido_dev_set_io_functions 18 4 77.78% 14 6 57.14%
fido_dev_set_transport_functions 6 2 66.67% 9 3 66.67%
fido_dev_io_handle 1 1 0.00% 3 3 0.00%
@@ -410,17 +408,17 @@ fido_dev_force_fido2 2 2 0.00% 3
fido_dev_get_pin_protocol 11 0 100.00% 7 0 100.00%
fido_dev_maxmsgsize 1 0 100.00% 3 0 100.00%
fido_dev_set_timeout 6 2 66.67% 6 1 83.33%
-dev.c:find_manifest_func_node 5 0 100.00% 8 0 100.00%
+dev.c:run_manifest 10 0 100.00% 13 0 100.00%
dev.c:fido_dev_open_wait 10 0 100.00% 7 0 100.00%
dev.c:fido_dev_open_tx 56 15 73.21% 56 26 53.57%
dev.c:set_random_report_len 11 0 100.00% 6 0 100.00%
dev.c:fido_dev_open_rx 36 1 97.22% 53 1 98.11%
dev.c:fido_dev_set_flags 1 0 100.00% 5 0 100.00%
dev.c:fido_dev_set_extension_flags 7 0 100.00% 7 0 100.00%
-dev.c:fido_dev_set_option_flags 29 0 100.00% 18 0 100.00%
+dev.c:fido_dev_set_option_flags 31 0 100.00% 20 0 100.00%
dev.c:fido_dev_set_protocol_flags 11 0 100.00% 17 0 100.00%
-------------------------------------------------------------------------------------------------------------------
-TOTAL 421 79 81.24% 491 105 78.62%
+TOTAL 332 71 78.61% 378 86 77.25%
File '/libfido2/src/ecdh.c':
Name Regions Miss Cover Lines Miss Cover
@@ -438,15 +436,15 @@ Name Regions Miss Cover Lines Mis
eddsa_pk_decode 8 0 100.00% 9 0 100.00%
eddsa_pk_new 1 0 100.00% 3 0 100.00%
eddsa_pk_free 6 0 100.00% 7 0 100.00%
-eddsa_pk_from_ptr 6 0 100.00% 6 0 100.00%
+eddsa_pk_from_ptr 10 0 100.00% 12 0 100.00%
eddsa_pk_to_EVP_PKEY 3 0 100.00% 7 0 100.00%
-eddsa_pk_from_EVP_PKEY 14 0 100.00% 10 0 100.00%
+eddsa_pk_from_EVP_PKEY 18 2 88.89% 12 1 91.67%
eddsa_verify_sig 19 2 89.47% 30 6 80.00%
eddsa_pk_verify_sig 7 1 85.71% 13 2 84.62%
eddsa.c:decode_pubkey_point 8 0 100.00% 11 0 100.00%
eddsa.c:decode_coord 8 0 100.00% 10 0 100.00%
-------------------------------------------------------------------------------------------------------------------
-TOTAL 80 3 96.25% 106 8 92.45%
+TOTAL 88 5 94.32% 114 9 92.11%
File '/libfido2/src/err.c':
Name Regions Miss Cover Lines Miss Cover
@@ -464,21 +462,21 @@ es256_sk_new 1 0 100.00% 3
es256_sk_free 6 0 100.00% 7 0 100.00%
es256_pk_new 1 0 100.00% 3 0 100.00%
es256_pk_free 6 0 100.00% 7 0 100.00%
-es256_pk_from_ptr 11 0 100.00% 10 0 100.00%
+es256_pk_from_ptr 15 0 100.00% 17 0 100.00%
es256_pk_set_x 1 0 100.00% 4 0 100.00%
es256_pk_set_y 1 0 100.00% 4 0 100.00%
-es256_sk_create 39 0 100.00% 41 0 100.00%
-es256_pk_to_EVP_PKEY 42 0 100.00% 54 0 100.00%
-es256_pk_from_EC_KEY 38 0 100.00% 36 0 100.00%
-es256_pk_from_EVP_PKEY 7 2 71.43% 7 0 100.00%
-es256_sk_to_EVP_PKEY 28 0 100.00% 40 0 100.00%
-es256_derive_pk 25 0 100.00% 30 0 100.00%
+es256_sk_create 39 0 100.00% 40 0 100.00%
+es256_pk_to_EVP_PKEY 42 0 100.00% 53 0 100.00%
+es256_pk_from_EC_KEY 42 2 95.24% 47 4 91.49%
+es256_pk_from_EVP_PKEY 8 2 75.00% 7 1 85.71%
+es256_sk_to_EVP_PKEY 28 0 100.00% 39 0 100.00%
+es256_derive_pk 25 0 100.00% 29 0 100.00%
es256_verify_sig 12 2 83.33% 19 5 73.68%
es256_pk_verify_sig 7 1 85.71% 13 2 84.62%
es256.c:decode_pubkey_point 9 0 100.00% 13 0 100.00%
es256.c:decode_coord 8 0 100.00% 10 0 100.00%
-------------------------------------------------------------------------------------------------------------------
-TOTAL 306 5 98.37% 358 7 98.04%
+TOTAL 315 7 97.78% 372 12 96.77%
File '/libfido2/src/extern.h':
Name Regions Miss Cover Lines Miss Cover
@@ -511,7 +509,7 @@ TOTAL 87 2 97.70% 145
File '/libfido2/src/hid_linux.c':
Name Regions Miss Cover Lines Miss Cover
-------------------------------------------------------------------------------------------------------------------
-fido_hid_manifest 35 4 88.57% 41 1 97.56%
+fido_hid_manifest 35 4 88.57% 41 2 95.12%
fido_hid_open 27 27 0.00% 40 40 0.00%
fido_hid_close 3 3 0.00% 6 6 0.00%
fido_hid_set_sigmask 2 2 0.00% 6 6 0.00%
@@ -526,15 +524,15 @@ hid_linux.c:parse_uevent 12 0 100.00% 24
hid_linux.c:get_usb_attr 1 0 100.00% 3 0 100.00%
hid_linux.c:get_report_descriptor 14 1 92.86% 17 3 82.35%
-------------------------------------------------------------------------------------------------------------------
-TOTAL 173 68 60.69% 250 104 58.40%
+TOTAL 173 68 60.69% 250 105 58.00%
File '/libfido2/src/hid_unix.c':
Name Regions Miss Cover Lines Miss Cover
-------------------------------------------------------------------------------------------------------------------
fido_hid_unix_open 18 11 38.89% 22 14 36.36%
-fido_hid_unix_wait 10 9 10.00% 21 10 52.38%
+fido_hid_unix_wait 11 10 9.09% 21 12 42.86%
-------------------------------------------------------------------------------------------------------------------
-TOTAL 28 20 28.57% 43 24 44.19%
+TOTAL 29 21 27.59% 43 26 39.53%
File '/libfido2/src/info.c':
Name Regions Miss Cover Lines Miss Cover
@@ -559,6 +557,7 @@ fido_cbor_info_maxcredbloblen 1 0 100.00% 3
fido_cbor_info_maxmsgsiz 1 0 100.00% 3 0 100.00%
fido_cbor_info_maxcredcntlst 1 0 100.00% 3 0 100.00%
fido_cbor_info_maxcredidlen 1 0 100.00% 3 0 100.00%
+fido_cbor_info_maxlargeblob 1 0 100.00% 3 0 100.00%
fido_cbor_info_fwversion 1 0 100.00% 3 0 100.00%
fido_cbor_info_protocols_ptr 1 0 100.00% 3 0 100.00%
fido_cbor_info_protocols_len 1 0 100.00% 3 0 100.00%
@@ -567,7 +566,7 @@ fido_cbor_info_algorithm_type 4 0 100.00% 5
fido_cbor_info_algorithm_cose 4 0 100.00% 5 0 100.00%
info.c:fido_dev_get_cbor_info_tx 8 0 100.00% 9 0 100.00%
info.c:fido_dev_get_cbor_info_rx 6 0 100.00% 14 0 100.00%
-info.c:parse_reply_element 19 0 100.00% 37 0 100.00%
+info.c:parse_reply_element 20 0 100.00% 39 0 100.00%
info.c:decode_string_array 12 0 100.00% 17 0 100.00%
info.c:decode_string 4 0 100.00% 10 0 100.00%
info.c:decode_aaguid 8 0 100.00% 10 0 100.00%
@@ -579,37 +578,37 @@ info.c:decode_algorithms 12 0 100.00% 17
info.c:decode_algorithm 9 0 100.00% 17 0 100.00%
info.c:decode_algorithm_entry 20 0 100.00% 27 0 100.00%
-------------------------------------------------------------------------------------------------------------------
-TOTAL 184 0 100.00% 316 0 100.00%
+TOTAL 186 0 100.00% 321 0 100.00%
File '/libfido2/src/io.c':
Name Regions Miss Cover Lines Miss Cover
-------------------------------------------------------------------------------------------------------------------
-fido_tx 13 0 100.00% 11 0 100.00%
+fido_tx 14 0 100.00% 11 0 100.00%
fido_rx 13 1 92.31% 14 3 78.57%
fido_rx_cbor_status 8 0 100.00% 10 0 100.00%
io.c:transport_tx 7 0 100.00% 10 0 100.00%
io.c:tx_empty 9 0 100.00% 14 0 100.00%
io.c:tx_pkt 7 0 100.00% 10 0 100.00%
io.c:tx 13 0 100.00% 19 0 100.00%
-io.c:tx_preamble 16 1 93.75% 20 1 95.00%
-io.c:tx_frame 15 1 93.33% 18 1 94.44%
+io.c:tx_preamble 17 1 94.12% 20 1 95.00%
+io.c:tx_frame 16 1 93.75% 18 1 94.44%
io.c:transport_rx 7 0 100.00% 10 0 100.00%
-io.c:rx 40 2 95.00% 52 1 98.08%
+io.c:rx 40 2 95.00% 52 2 96.15%
io.c:rx_preamble 23 2 91.30% 22 5 77.27%
io.c:rx_frame 11 0 100.00% 11 0 100.00%
-------------------------------------------------------------------------------------------------------------------
-TOTAL 182 7 96.15% 221 11 95.02%
+TOTAL 185 7 96.22% 221 12 94.57%
File '/libfido2/src/iso7816.c':
Name Regions Miss Cover Lines Miss Cover
-------------------------------------------------------------------------------------------------------------------
iso7816_new 4 0 100.00% 16 0 100.00%
iso7816_free 6 0 100.00% 7 0 100.00%
-iso7816_add 6 1 83.33% 8 0 100.00%
+iso7816_add 6 1 83.33% 8 1 87.50%
iso7816_ptr 1 0 100.00% 3 0 100.00%
iso7816_len 1 0 100.00% 4 0 100.00%
-------------------------------------------------------------------------------------------------------------------
-TOTAL 18 1 94.44% 38 0 100.00%
+TOTAL 18 1 94.44% 38 1 97.37%
File '/libfido2/src/largeblob.c':
Name Regions Miss Cover Lines Miss Cover
@@ -620,7 +619,7 @@ fido_dev_largeblob_remove 12 0 100.00% 18
fido_dev_largeblob_get_array 15 2 86.67% 27 4 85.19%
fido_dev_largeblob_set_array 14 0 100.00% 19 0 100.00%
largeblob.c:largeblob_get_array 32 0 100.00% 36 0 100.00%
-largeblob.c:get_chunklen 9 1 88.89% 9 0 100.00%
+largeblob.c:get_chunklen 10 1 90.00% 9 1 88.89%
largeblob.c:largeblob_get_tx 19 0 100.00% 24 0 100.00%
largeblob.c:largeblob_get_rx 15 0 100.00% 21 0 100.00%
largeblob.c:parse_largeblob_reply 8 0 100.00% 9 0 100.00%
@@ -629,7 +628,7 @@ largeblob.c:largeblob_array_digest 10 0 100.00% 9
largeblob.c:largeblob_array_load 14 2 85.71% 19 7 63.16%
largeblob.c:largeblob_array_lookup 25 0 100.00% 33 0 100.00%
largeblob.c:largeblob_decode 16 2 87.50% 16 6 62.50%
-largeblob.c:largeblob_do_decode 27 3 88.89% 30 5 83.33%
+largeblob.c:largeblob_do_decode 27 3 88.89% 30 7 76.67%
largeblob.c:largeblob_decrypt 15 0 100.00% 24 0 100.00%
largeblob.c:largeblob_aad 1 0 100.00% 10 0 100.00%
largeblob.c:largeblob_reset 1 0 100.00% 5 0 100.00%
@@ -645,34 +644,34 @@ largeblob.c:largeblob_get_uv_token 19 0 100.00% 23
largeblob.c:largeblob_set_tx 35 0 100.00% 36 0 100.00%
largeblob.c:prepare_hmac 13 2 84.62% 23 7 69.57%
-------------------------------------------------------------------------------------------------------------------
-TOTAL 513 19 96.30% 684 43 93.71%
+TOTAL 514 19 96.30% 684 46 93.27%
File '/libfido2/src/log.c':
Name Regions Miss Cover Lines Miss Cover
-------------------------------------------------------------------------------------------------------------------
fido_log_init 1 0 100.00% 4 0 100.00%
-fido_log_debug 6 1 83.33% 8 0 100.00%
-fido_log_xxd 16 1 93.75% 24 0 100.00%
-fido_log_error 8 2 75.00% 11 1 90.91%
+fido_log_debug 6 1 83.33% 8 1 87.50%
+fido_log_xxd 16 1 93.75% 24 1 95.83%
+fido_log_error 8 2 75.00% 11 2 81.82%
fido_set_log_handler 3 0 100.00% 4 0 100.00%
log.c:log_on_stderr 1 1 0.00% 3 3 0.00%
log.c:do_log 4 0 100.00% 9 0 100.00%
-------------------------------------------------------------------------------------------------------------------
-TOTAL 39 5 87.18% 63 4 93.65%
+TOTAL 39 5 87.18% 63 7 88.89%
File '/libfido2/src/netlink.c':
Name Regions Miss Cover Lines Miss Cover
-------------------------------------------------------------------------------------------------------------------
fido_nl_power_nfc 18 1 94.44% 24 3 87.50%
fido_nl_get_nfc_target 17 1 94.12% 31 3 90.32%
-fido_nl_free 10 2 80.00% 9 1 88.89%
+fido_nl_free 10 2 80.00% 9 2 77.78%
fido_nl_new 16 1 93.75% 26 3 88.46%
set_netlink_io_functions 1 0 100.00% 4 0 100.00%
netlink.c:nlmsg_new 8 0 100.00% 15 0 100.00%
netlink.c:nlmsg_set_genl 1 0 100.00% 7 0 100.00%
netlink.c:nlmsg_write 6 1 83.33% 7 1 85.71%
netlink.c:nlmsg_set_u32 1 0 100.00% 3 0 100.00%
-netlink.c:nlmsg_setattr 14 1 92.86% 17 0 100.00%
+netlink.c:nlmsg_setattr 15 1 93.33% 17 0 100.00%
netlink.c:nlmsg_tx 10 1 90.00% 13 3 76.92%
netlink.c:nlmsg_ptr 1 0 100.00% 3 0 100.00%
netlink.c:nlmsg_len 1 0 100.00% 3 0 100.00%
@@ -704,36 +703,62 @@ netlink.c:parse_mcastgrps 1 0 100.00% 3
netlink.c:parse_mcastgrp 15 0 100.00% 24 0 100.00%
netlink.c:nla_get_str 10 0 100.00% 11 0 100.00%
-------------------------------------------------------------------------------------------------------------------
-TOTAL 328 14 95.73% 498 32 93.57%
+TOTAL 329 14 95.74% 498 33 93.37%
-File '/libfido2/src/nfc_linux.c':
+File '/libfido2/src/nfc.c':
Name Regions Miss Cover Lines Miss Cover
-------------------------------------------------------------------------------------------------------------------
fido_nfc_tx 28 0 100.00% 43 0 100.00%
-fido_nfc_rx 8 1 87.50% 13 3 76.92%
-fido_nfc_manifest 35 5 85.71% 45 13 71.11%
-fido_nfc_open 20 3 85.00% 23 5 78.26%
+fido_nfc_rx 8 0 100.00% 13 0 100.00%
+fido_is_nfc 3 0 100.00% 3 0 100.00%
+fido_dev_set_nfc 4 4 0.00% 18 18 0.00%
+nfc.c:nfc_do_tx 20 0 100.00% 25 0 100.00%
+nfc.c:tx_short_apdu 14 0 100.00% 32 0 100.00%
+nfc.c:rx_init 25 0 100.00% 27 0 100.00%
+nfc.c:rx_cbor 4 0 100.00% 6 0 100.00%
+nfc.c:rx_msg 18 2 88.89% 23 6 73.91%
+nfc.c:rx_apdu 14 1 92.86% 22 3 86.36%
+nfc.c:tx_get_response 4 0 100.00% 11 0 100.00%
+-------------------------------------------------------------------------------------------------------------------
+TOTAL 142 7 95.07% 223 27 87.89%
+
+File '/libfido2/src/nfc_linux.c':
+Name Regions Miss Cover Lines Miss Cover
+-------------------------------------------------------------------------------------------------------------------
+fido_nfc_manifest 35 7 80.00% 45 15 66.67%
+fido_nfc_open 20 3 85.00% 23 4 82.61%
fido_nfc_close 1 1 0.00% 4 4 0.00%
fido_nfc_set_sigmask 2 2 0.00% 6 6 0.00%
fido_nfc_read 14 14 0.00% 30 30 0.00%
fido_nfc_write 12 12 0.00% 18 18 0.00%
-nfc_linux.c:nfc_do_tx 20 2 90.00% 25 6 76.00%
-nfc_linux.c:tx_short_apdu 14 0 100.00% 32 0 100.00%
-nfc_linux.c:rx_init 25 6 76.00% 27 5 81.48%
-nfc_linux.c:rx_cbor 4 0 100.00% 6 0 100.00%
-nfc_linux.c:rx_msg 18 2 88.89% 23 6 73.91%
-nfc_linux.c:rx_apdu 14 1 92.86% 22 3 86.36%
-nfc_linux.c:tx_get_response 4 0 100.00% 11 0 100.00%
-nfc_linux.c:copy_info 41 9 78.05% 44 3 93.18%
+nfc_linux.c:copy_info 41 8 80.49% 47 5 89.36%
nfc_linux.c:get_usb_attr 1 0 100.00% 3 0 100.00%
nfc_linux.c:get_parent_attr 6 0 100.00% 9 0 100.00%
-nfc_linux.c:to_int 21 6 71.43% 14 1 92.86%
-nfc_linux.c:sysnum_from_syspath 12 0 100.00% 17 0 100.00%
+nfc_linux.c:sysnum_from_syspath 15 0 100.00% 17 0 100.00%
nfc_linux.c:nfc_new 6 0 100.00% 11 0 100.00%
nfc_linux.c:nfc_target_connect 9 9 0.00% 21 21 0.00%
nfc_linux.c:nfc_free 12 0 100.00% 11 0 100.00%
-------------------------------------------------------------------------------------------------------------------
-TOTAL 327 73 77.68% 458 124 72.93%
+TOTAL 174 56 67.82% 245 103 57.96%
+
+File '/libfido2/src/pcsc.c':
+Name Regions Miss Cover Lines Miss Cover
+-------------------------------------------------------------------------------------------------------------------
+fido_pcsc_manifest 51 0 100.00% 55 0 100.00%
+fido_pcsc_open 32 0 100.00% 43 0 100.00%
+fido_pcsc_close 6 0 100.00% 9 0 100.00%
+fido_pcsc_read 8 0 100.00% 16 0 100.00%
+fido_pcsc_write 8 0 100.00% 22 0 100.00%
+fido_pcsc_tx 1 0 100.00% 3 0 100.00%
+fido_pcsc_rx 1 0 100.00% 3 0 100.00%
+fido_is_pcsc 3 0 100.00% 3 0 100.00%
+fido_dev_set_pcsc 4 1 75.00% 18 3 83.33%
+pcsc.c:list_readers 24 0 100.00% 24 0 100.00%
+pcsc.c:copy_info 27 0 100.00% 37 0 100.00%
+pcsc.c:get_reader 25 0 100.00% 28 0 100.00%
+pcsc.c:prepare_io_request 11 0 100.00% 17 0 100.00%
+-------------------------------------------------------------------------------------------------------------------
+TOTAL 201 1 99.50% 278 3 98.92%
File '/libfido2/src/pin.c':
Name Regions Miss Cover Lines Miss Cover
@@ -744,7 +769,7 @@ fido_dev_set_pin 1 0 100.00% 4
fido_dev_get_retry_count 1 0 100.00% 4 0 100.00%
fido_dev_get_uv_retry_count 1 0 100.00% 4 0 100.00%
cbor_add_uv_params 17 0 100.00% 23 0 100.00%
-pin.c:uv_token_wait 14 2 85.71% 12 0 100.00%
+pin.c:uv_token_wait 14 2 85.71% 12 1 91.67%
pin.c:ctap21_uv_token_tx 49 0 100.00% 53 0 100.00%
pin.c:pin_sha256_enc 19 0 100.00% 24 0 100.00%
pin.c:encode_uv_permission 20 1 95.00% 19 3 84.21%
@@ -765,7 +790,7 @@ pin.c:fido_dev_get_uv_retry_count_wait 10 0 100.00% 7
pin.c:fido_dev_get_uv_retry_count_rx 11 0 100.00% 17 0 100.00%
pin.c:parse_uv_retry_count 1 0 100.00% 3 0 100.00%
---------------------------------------------------------------------------------------------------------------------
-TOTAL 403 3 99.26% 495 3 99.39%
+TOTAL 403 3 99.26% 495 4 99.19%
File '/libfido2/src/random.c':
Name Regions Miss Cover Lines Miss Cover
@@ -786,11 +811,11 @@ TOTAL 24 0 100.00% 23
File '/libfido2/src/rs1.c':
Name Regions Miss Cover Lines Miss Cover
---------------------------------------------------------------------------------------------------------------------
-rs1_verify_sig 20 0 100.00% 30 0 100.00%
-rs1.c:rs1_get_EVP_MD 4 0 100.00% 6 0 100.00%
+rs1_verify_sig 20 1 95.00% 30 3 90.00%
+rs1.c:rs1_get_EVP_MD 4 1 75.00% 6 1 83.33%
rs1.c:rs1_free_EVP_MD 1 0 100.00% 3 0 100.00%
---------------------------------------------------------------------------------------------------------------------
-TOTAL 25 0 100.00% 39 0 100.00%
+TOTAL 25 2 92.00% 39 4 89.74%
File '/libfido2/src/rs256.c':
Name Regions Miss Cover Lines Miss Cover
@@ -801,7 +826,7 @@ rs256_pk_free 6 0 100.00% 7
rs256_pk_from_ptr 6 0 100.00% 6 0 100.00%
rs256_pk_to_EVP_PKEY 32 0 100.00% 39 0 100.00%
rs256_pk_from_RSA 32 4 87.50% 26 6 76.92%
-rs256_pk_from_EVP_PKEY 7 2 71.43% 7 0 100.00%
+rs256_pk_from_EVP_PKEY 7 2 71.43% 7 1 85.71%
rs256_verify_sig 20 1 95.00% 30 2 93.33%
rs256_pk_verify_sig 7 1 85.71% 13 2 84.62%
rs256.c:decode_rsa_pubkey 9 0 100.00% 13 0 100.00%
@@ -809,31 +834,39 @@ rs256.c:decode_bignum 8 0 100.00% 10
rs256.c:rs256_get_EVP_MD 4 0 100.00% 6 0 100.00%
rs256.c:rs256_free_EVP_MD 1 0 100.00% 3 0 100.00%
---------------------------------------------------------------------------------------------------------------------
-TOTAL 141 8 94.33% 172 10 94.19%
+TOTAL 141 8 94.33% 172 11 93.60%
File '/libfido2/src/time.c':
Name Regions Miss Cover Lines Miss Cover
---------------------------------------------------------------------------------------------------------------------
fido_time_now 4 0 100.00% 7 0 100.00%
fido_time_delta 23 1 95.65% 23 0 100.00%
-time.c:timespec_to_ms 16 2 87.50% 13 1 92.31%
+time.c:timespec_to_ms 16 2 87.50% 13 2 84.62%
---------------------------------------------------------------------------------------------------------------------
-TOTAL 43 3 93.02% 43 1 97.67%
+TOTAL 43 3 93.02% 43 2 95.35%
+
+File '/libfido2/src/touch.c':
+Name Regions Miss Cover Lines Miss Cover
+---------------------------------------------------------------------------------------------------------------------
+fido_dev_get_touch_begin 50 0 100.00% 59 0 100.00%
+fido_dev_get_touch_status 17 0 100.00% 20 0 100.00%
+---------------------------------------------------------------------------------------------------------------------
+TOTAL 67 0 100.00% 79 0 100.00%
File '/libfido2/src/tpm.c':
Name Regions Miss Cover Lines Miss Cover
---------------------------------------------------------------------------------------------------------------------
-fido_get_signed_hash_tpm 25 0 100.00% 39 0 100.00%
-tpm.c:check_es256_pubarea 18 0 100.00% 30 0 100.00%
+fido_get_signed_hash_tpm 25 1 96.00% 39 3 92.31%
+tpm.c:check_es256_pubarea 19 1 94.74% 30 3 90.00%
tpm.c:bswap_es256_pubarea 1 0 100.00% 12 0 100.00%
-tpm.c:check_rs256_pubarea 16 0 100.00% 28 0 100.00%
+tpm.c:check_rs256_pubarea 17 1 94.12% 28 3 89.29%
tpm.c:bswap_rs256_pubarea 1 0 100.00% 10 0 100.00%
-tpm.c:check_sha1_certinfo 14 0 100.00% 38 0 100.00%
+tpm.c:check_sha1_certinfo 15 0 100.00% 38 0 100.00%
tpm.c:get_signed_sha1 17 0 100.00% 19 0 100.00%
tpm.c:get_signed_name 7 0 100.00% 10 0 100.00%
tpm.c:bswap_sha1_certinfo 1 0 100.00% 8 0 100.00%
---------------------------------------------------------------------------------------------------------------------
-TOTAL 100 0 100.00% 194 0 100.00%
+TOTAL 103 3 97.09% 194 9 95.36%
File '/libfido2/src/types.c':
Name Regions Miss Cover Lines Miss Cover
@@ -869,3 +902,10 @@ u2f.c:parse_auth_reply 23 0 100.00% 23
u2f.c:authdata_fake 12 0 100.00% 27 0 100.00%
---------------------------------------------------------------------------------------------------------------------
TOTAL 528 4 99.24% 685 12 98.25%
+
+File '/libfido2/src/util.c':
+Name Regions Miss Cover Lines Miss Cover
+---------------------------------------------------------------------------------------------------------------------
+fido_to_uint64 14 1 92.86% 14 1 92.86%
+---------------------------------------------------------------------------------------------------------------------
+TOTAL 14 1 92.86% 14 1 92.86%
diff --git a/fuzz/fuzz_mgmt.c b/fuzz/fuzz_mgmt.c
index 7c28979fb624..41077e23766c 100644
--- a/fuzz/fuzz_mgmt.c
+++ b/fuzz/fuzz_mgmt.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019 Yubico AB. All rights reserved.
+ * Copyright (c) 2019-2022 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.
*/
@@ -288,6 +288,9 @@ dev_get_cbor_info(const struct param *p)
n = fido_cbor_info_maxcredidlen(ci);
consume(&n, sizeof(n));
+ n = fido_cbor_info_maxlargeblob(ci);
+ consume(&n, sizeof(n));
+
n = fido_cbor_info_fwversion(ci);
consume(&n, sizeof(n));
diff --git a/fuzz/fuzz_pcsc.c b/fuzz/fuzz_pcsc.c
new file mode 100644
index 000000000000..4a066ec32e1f
--- /dev/null
+++ b/fuzz/fuzz_pcsc.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2022 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.
+ */
+
+#define _FIDO_INTERNAL
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <winscard.h>
+
+#include "mutator_aux.h"
+#include "wiredata_fido2.h"
+#include "dummy.h"
+
+#include "../src/extern.h"
+
+struct param {
+ int seed;
+ char path[MAXSTR];
+ struct blob pcsc_list;
+ struct blob tx_apdu;
+ struct blob wiredata_init;
+ struct blob wiredata_msg;
+};
+
+static const uint8_t dummy_tx_apdu[] = { WIREDATA_CTAP_EXTENDED_APDU };
+static const uint8_t dummy_wiredata_init[] = { WIREDATA_CTAP_NFC_INIT };
+static const uint8_t dummy_wiredata_msg[] = { WIREDATA_CTAP_NFC_MSG };
+
+struct param *
+unpack(const uint8_t *ptr, size_t len)
+{
+ cbor_item_t *item = NULL, **v;
+ struct cbor_load_result cbor;
+ struct param *p;
+ int ok = -1;
+
+ if ((p = calloc(1, sizeof(*p))) == NULL ||
+ (item = cbor_load(ptr, len, &cbor)) == NULL ||
+ cbor.read != len ||
+ cbor_isa_array(item) == false ||
+ cbor_array_is_definite(item) == false ||
+ cbor_array_size(item) != 6 ||
+ (v = cbor_array_handle(item)) == NULL)
+ goto fail;
+
+ if (unpack_int(v[0], &p->seed) < 0 ||
+ unpack_string(v[1], p->path) < 0 ||
+ unpack_blob(v[2], &p->pcsc_list) < 0 ||
+ unpack_blob(v[3], &p->tx_apdu) < 0 ||
+ unpack_blob(v[4], &p->wiredata_init) < 0 ||
+ unpack_blob(v[5], &p->wiredata_msg) < 0)
+ goto fail;
+
+ ok = 0;
+fail:
+ if (ok < 0) {
+ free(p);
+ p = NULL;
+ }
+
+ if (item)
+ cbor_decref(&item);
+
+ return p;
+}
+
+size_t
+pack(uint8_t *ptr, size_t len, const struct param *p)
+{
+ cbor_item_t *argv[6], *array = NULL;
+ size_t cbor_alloc_len, cbor_len = 0;
+ unsigned char *cbor = NULL;
+
+ memset(argv, 0, sizeof(argv));
+
+ if ((array = cbor_new_definite_array(6)) == NULL ||
+ (argv[0] = pack_int(p->seed)) == NULL ||
+ (argv[1] = pack_string(p->path)) == NULL ||
+ (argv[2] = pack_blob(&p->pcsc_list)) == NULL ||
+ (argv[3] = pack_blob(&p->tx_apdu)) == NULL ||
+ (argv[4] = pack_blob(&p->wiredata_init)) == NULL ||
+ (argv[5] = pack_blob(&p->wiredata_msg)) == NULL)
+ goto fail;
+
+ for (size_t i = 0; i < 6; i++)
+ if (cbor_array_push(array, argv[i]) == false)
+ goto fail;
+
+ if ((cbor_len = cbor_serialize_alloc(array, &cbor,
+ &cbor_alloc_len)) > len) {
+ cbor_len = 0;
+ goto fail;
+ }
+
+ memcpy(ptr, cbor, cbor_len);
+fail:
+ for (size_t i = 0; i < 6; i++)
+ if (argv[i])
+ cbor_decref(&argv[i]);
+
+ if (array)
+ cbor_decref(&array);
+
+ free(cbor);
+
+ return cbor_len;
+}
+
+size_t
+pack_dummy(uint8_t *ptr, size_t len)
+{
+ struct param dummy;
+ uint8_t blob[4096];
+ size_t blob_len;
+
+ memset(&dummy, 0, sizeof(dummy));
+
+ strlcpy(dummy.path, dummy_pcsc_path, sizeof(dummy.path));
+
+ dummy.pcsc_list.len = sizeof(dummy_pcsc_list);
+ memcpy(&dummy.pcsc_list.body, &dummy_pcsc_list, dummy.pcsc_list.len);
+
+ dummy.tx_apdu.len = sizeof(dummy_tx_apdu);
+ memcpy(&dummy.tx_apdu.body, &dummy_tx_apdu, dummy.tx_apdu.len);
+
+ dummy.wiredata_init.len = sizeof(dummy_wiredata_init);
+ memcpy(&dummy.wiredata_init.body, &dummy_wiredata_init,
+ dummy.wiredata_init.len);
+
+ dummy.wiredata_msg.len = sizeof(dummy_wiredata_msg);
+ memcpy(&dummy.wiredata_msg.body, &dummy_wiredata_msg,
+ dummy.wiredata_msg.len);
+
+ assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
+
+ if (blob_len > len) {
+ memcpy(ptr, blob, len);
+ return len;
+ }
+
+ memcpy(ptr, blob, blob_len);
+
+ return blob_len;
+}
+
+static void
+test_manifest(void)
+{
+ size_t ndevs, nfound;
+ fido_dev_info_t *devlist = NULL;
+ int16_t vendor_id, product_id;
+ int r;
+
+ r = fido_pcsc_manifest(NULL, 0, &nfound);
+ assert(r == FIDO_OK && nfound == 0);
+ r = fido_pcsc_manifest(NULL, 1, &nfound);
+ assert(r == FIDO_ERR_INVALID_ARGUMENT);
+
+ ndevs = uniform_random(64);
+ if ((devlist = fido_dev_info_new(ndevs)) == NULL ||
+ fido_pcsc_manifest(devlist, ndevs, &nfound) != FIDO_OK)
+ goto out;
+
+ for (size_t i = 0; i < nfound; i++) {
+ const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i);
+ consume_str(fido_dev_info_path(di));
+ consume_str(fido_dev_info_manufacturer_string(di));
+ consume_str(fido_dev_info_product_string(di));
+ vendor_id = fido_dev_info_vendor(di);
+ product_id = fido_dev_info_product(di);
+ consume(&vendor_id, sizeof(vendor_id));
+ consume(&product_id, sizeof(product_id));
+ }
+
+out:
+ fido_dev_info_free(&devlist, ndevs);
+}
+
+static void
+test_tx(const char *path, const struct blob *apdu, uint8_t cmd, u_char *rx_buf,
+ size_t rx_len)
+{
+ fido_dev_t dev;
+ const u_char *tx_ptr = NULL;
+ size_t tx_len = 0;
+ int n;
+
+ memset(&dev, 0, sizeof(dev));
+
+ if (fido_dev_set_pcsc(&dev) < 0)
+ return;
+ if ((dev.io_handle = fido_pcsc_open(path)) == NULL)
+ return;
+
+ if (apdu) {
+ tx_ptr = apdu->body;
+ tx_len = apdu->len;
+ }
+
+ fido_pcsc_tx(&dev, cmd, tx_ptr, tx_len);
+
+ if ((n = fido_pcsc_rx(&dev, cmd, rx_buf, rx_len, -1)) >= 0)
+ consume(rx_buf, n);
+
+ fido_pcsc_close(dev.io_handle);
+}
+
+static void
+test_misc(void)
+{
+ assert(fido_pcsc_open(NULL) == NULL);
+ assert(fido_pcsc_write(NULL, NULL, INT_MAX + 1LL) == -1);
+}
+
+void
+test(const struct param *p)
+{
+ u_char buf[512];
+
+ prng_init((unsigned int)p->seed);
+ fuzz_clock_reset();
+ fido_init(FIDO_DEBUG);
+ fido_set_log_handler(consume_str);
+
+ set_pcsc_parameters(&p->pcsc_list);
+ set_pcsc_io_functions(nfc_read, nfc_write, consume);
+
+ test_manifest();
+ test_misc();
+
+ set_wire_data(p->wiredata_init.body, p->wiredata_init.len);
+ test_tx(p->path, NULL, CTAP_CMD_INIT, buf, uniform_random(20));
+
+ set_wire_data(p->wiredata_msg.body, p->wiredata_msg.len);
+ test_tx(p->path, &p->tx_apdu, CTAP_CMD_MSG, buf, sizeof(buf));
+
+ set_wire_data(p->wiredata_msg.body, p->wiredata_msg.len);
+ test_tx(p->path, &p->tx_apdu, CTAP_CMD_CBOR, buf, sizeof(buf));
+
+ set_wire_data(p->wiredata_msg.body, p->wiredata_msg.len);
+ test_tx(p->path, &p->tx_apdu, CTAP_CMD_LOCK, buf, sizeof(buf));
+}
+
+void
+mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
+{
+ if (flags & MUTATE_SEED)
+ p->seed = (int)seed;
+
+ if (flags & MUTATE_PARAM) {
+ mutate_string(p->path);
+ mutate_blob(&p->pcsc_list);
+ mutate_blob(&p->tx_apdu);
+ }
+
+ if (flags & MUTATE_WIREDATA) {
+ mutate_blob(&p->wiredata_init);
+ mutate_blob(&p->wiredata_msg);
+ }
+}
diff --git a/fuzz/mutator_aux.c b/fuzz/mutator_aux.c
index 92a67be78106..660fbe4e67e7 100644
--- a/fuzz/mutator_aux.c
+++ b/fuzz/mutator_aux.c
@@ -15,9 +15,6 @@
#include "mutator_aux.h"
-#define HID_DEV_HANDLE 0x68696421
-#define NFC_DEV_HANDLE 0x6e666321
-
int fido_nfc_rx(fido_dev_t *, uint8_t, unsigned char *, size_t, int);
int fido_nfc_tx(fido_dev_t *, uint8_t, const unsigned char *, size_t);
size_t LLVMFuzzerMutate(uint8_t *, size_t, size_t);
@@ -241,16 +238,16 @@ nfc_close(void *handle)
assert(handle == (void *)NFC_DEV_HANDLE);
}
-static int
+int
nfc_read(void *handle, unsigned char *ptr, size_t len, int ms)
{
assert(handle == (void *)NFC_DEV_HANDLE);
- assert(len > 0 && len <= 256 + 2);
+ assert(len > 0 && len <= 264);
return buf_read(ptr, len, ms);
}
-static int
+int
nfc_write(void *handle, const unsigned char *ptr, size_t len)
{
assert(handle == (void *)NFC_DEV_HANDLE);
diff --git a/fuzz/mutator_aux.h b/fuzz/mutator_aux.h
index a9bebe232bae..730f58635b16 100644
--- a/fuzz/mutator_aux.h
+++ b/fuzz/mutator_aux.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2021 Yubico AB. All rights reserved.
+ * Copyright (c) 2019-2022 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.
*/
@@ -51,6 +51,9 @@
#define MAXSTR 1024
#define MAXBLOB 3600
+#define HID_DEV_HANDLE 0x68696421
+#define NFC_DEV_HANDLE 0x6e666321
+
struct blob {
uint8_t body[MAXBLOB];
size_t len;
@@ -85,6 +88,9 @@ void mutate_string(char *);
ssize_t fd_read(int, void *, size_t);
ssize_t fd_write(int, const void *, size_t);
+int nfc_read(void *, unsigned char *, size_t, int);
+int nfc_write(void *, const unsigned char *, size_t);
+
fido_dev_t *open_dev(int);
void set_wire_data(const uint8_t *, size_t);
@@ -94,4 +100,8 @@ unsigned long prng_uint32(void);
uint32_t uniform_random(uint32_t);
+void set_pcsc_parameters(const struct blob *);
+void set_pcsc_io_functions(int (*)(void *, u_char *, size_t, int),
+ int (*)(void *, const u_char *, size_t), void (*)(const void *, size_t));
+
#endif /* !_MUTATOR_AUX_H */
diff --git a/fuzz/pcsc.c b/fuzz/pcsc.c
new file mode 100644
index 000000000000..f8400a5e766d
--- /dev/null
+++ b/fuzz/pcsc.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2022 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 <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <winscard.h>
+
+#include "mutator_aux.h"
+
+static const struct blob *reader_list;
+static int (*xread)(void *, u_char *, size_t, int);
+static int (*xwrite)(void *, const u_char *, size_t);
+static void (*xconsume)(const void *, size_t);
+
+LONG __wrap_SCardEstablishContext(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT);
+LONG __wrap_SCardListReaders(SCARDCONTEXT, LPCSTR, LPSTR, LPDWORD);
+LONG __wrap_SCardReleaseContext(SCARDCONTEXT);
+LONG __wrap_SCardConnect(SCARDCONTEXT, LPCSTR, DWORD, DWORD, LPSCARDHANDLE,
+ LPDWORD);
+LONG __wrap_SCardDisconnect(SCARDHANDLE, DWORD);
+LONG __wrap_SCardTransmit(SCARDHANDLE, const SCARD_IO_REQUEST *, LPCBYTE,
+ DWORD, SCARD_IO_REQUEST *, LPBYTE, LPDWORD);
+
+LONG
+__wrap_SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
+ LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
+{
+ assert(dwScope == SCARD_SCOPE_SYSTEM);
+ assert(pvReserved1 == NULL);
+ assert(pvReserved2 == NULL);
+
+ *phContext = 1;
+
+ if (uniform_random(400) < 1)
+ return SCARD_E_NO_SERVICE;
+ if (uniform_random(400) < 1)
+ return SCARD_E_NO_SMARTCARD;
+ if (uniform_random(400) < 1)
+ return SCARD_E_NO_MEMORY;
+ if (uniform_random(400) < 1)
+ *phContext = 0;
+
+ return SCARD_S_SUCCESS;
+}
+
+LONG
+__wrap_SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups,
+ LPSTR mszReaders, LPDWORD pcchReaders)
+{
+ assert(hContext == 1);
+ assert(mszGroups == NULL);
+ assert(mszReaders != NULL);
+ assert(pcchReaders != 0);
+
+ if (reader_list == NULL || uniform_random(400) < 1)
+ return SCARD_E_NO_READERS_AVAILABLE;
+ if (uniform_random(400) < 1)
+ return SCARD_E_NO_MEMORY;
+
+ memcpy(mszReaders, reader_list->body, reader_list->len > *pcchReaders ?
+ *pcchReaders : reader_list->len);
+ *pcchReaders = (DWORD)reader_list->len; /* on purpose */
+
+ return SCARD_S_SUCCESS;
+}
+
+LONG
+__wrap_SCardReleaseContext(SCARDCONTEXT hContext)
+{
+ assert(hContext == 1);
+
+ return SCARD_S_SUCCESS;
+}
+
+LONG
+__wrap_SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode,
+ DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
+{
+ uint32_t r;
+
+ assert(hContext == 1);
+ xconsume(szReader, strlen(szReader) + 1);
+ assert(dwShareMode == SCARD_SHARE_SHARED);
+ assert(dwPreferredProtocols == SCARD_PROTOCOL_ANY);
+ assert(phCard != NULL);
+ assert(pdwActiveProtocol != NULL);
+
+ if ((r = uniform_random(400)) < 1)
+ return SCARD_E_UNEXPECTED;
+
+ *phCard = 1;
+ *pdwActiveProtocol = (r & 1) ? SCARD_PROTOCOL_T0 : SCARD_PROTOCOL_T1;
+
+ if (uniform_random(400) < 1)
+ *pdwActiveProtocol = SCARD_PROTOCOL_RAW;
+
+ return SCARD_S_SUCCESS;
+}
+
+LONG
+__wrap_SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
+{
+ assert(hCard == 1);
+ assert(dwDisposition == SCARD_LEAVE_CARD);
+
+ return SCARD_S_SUCCESS;
+}
+
+extern void consume(const void *body, size_t len);
+
+LONG
+__wrap_SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci,
+ LPCBYTE pbSendBuffer, DWORD cbSendLength, SCARD_IO_REQUEST *pioRecvPci,
+ LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength)
+{
+ void *ioh = (void *)NFC_DEV_HANDLE;
+ int n;
+
+ assert(hCard == 1);
+ xconsume(pioSendPci, sizeof(*pioSendPci));
+ xwrite(ioh, pbSendBuffer, cbSendLength);
+ assert(pioRecvPci == NULL);
+
+ if (uniform_random(400) < 1 ||
+ (n = xread(ioh, pbRecvBuffer, *pcbRecvLength, -1)) == -1)
+ return SCARD_E_UNEXPECTED;
+ *pcbRecvLength = (DWORD)n;
+
+ return SCARD_S_SUCCESS;
+}
+
+void
+set_pcsc_parameters(const struct blob *reader_list_ptr)
+{
+ reader_list = reader_list_ptr;
+}
+
+void
+set_pcsc_io_functions(int (*read_f)(void *, u_char *, size_t, int),
+ int (*write_f)(void *, const u_char *, size_t),
+ void (*consume_f)(const void *, size_t))
+{
+ xread = read_f;
+ xwrite = write_f;
+ xconsume = consume_f;
+}
diff --git a/fuzz/report.tgz b/fuzz/report.tgz
index d78f4628de59..1b44addb6982 100644
--- a/fuzz/report.tgz
+++ b/fuzz/report.tgz
Binary files differ
diff --git a/fuzz/summary.txt b/fuzz/summary.txt
index 05c000aa7757..305cb0d84c45 100644
--- a/fuzz/summary.txt
+++ b/fuzz/summary.txt
@@ -1,52 +1,58 @@
Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-fuzz/clock.c 24 1 95.83% 4 0 100.00% 35 0 100.00%
-fuzz/prng.c 31 0 100.00% 2 0 100.00% 35 0 100.00%
-fuzz/udev.c 103 1 99.03% 17 0 100.00% 126 3 97.62%
+fuzz/clock.c 24 1 95.83% 4 0 100.00% 35 1 97.14%
+fuzz/pcsc.c 59 0 100.00% 8 0 100.00% 75 12 84.00%
+fuzz/prng.c 31 0 100.00% 2 0 100.00% 35 1 97.14%
+fuzz/udev.c 109 1 99.08% 17 0 100.00% 126 11 91.27%
fuzz/uniform_random.c 7 1 85.71% 1 0 100.00% 12 1 91.67%
-fuzz/wrap.c 6 0 100.00% 1 0 100.00% 7 0 100.00%
+fuzz/wrap.c 17 0 100.00% 3 0 100.00% 29 0 100.00%
openbsd-compat/explicit_bzero.c 4 0 100.00% 1 0 100.00% 7 0 100.00%
openbsd-compat/freezero.c 4 0 100.00% 1 0 100.00% 6 0 100.00%
openbsd-compat/recallocarray.c 41 7 82.93% 1 0 100.00% 36 7 80.56%
openbsd-compat/strlcat.c 12 1 91.67% 1 0 100.00% 21 1 95.24%
openbsd-compat/timingsafe_bcmp.c 4 0 100.00% 1 0 100.00% 7 0 100.00%
-src/aes256.c 115 4 96.52% 8 0 100.00% 157 14 91.08%
-src/assert.c 563 40 92.90% 56 3 94.64% 694 40 94.24%
+src/aes256.c 118 4 96.61% 8 0 100.00% 157 14 91.08%
+src/assert.c 565 42 92.57% 56 3 94.64% 694 42 93.95%
src/authkey.c 44 0 100.00% 5 0 100.00% 59 0 100.00%
-src/bio.c 419 20 95.23% 49 2 95.92% 559 21 96.24%
+src/bio.c 419 20 95.23% 49 2 95.92% 559 24 95.71%
src/blob.c 53 2 96.23% 10 0 100.00% 83 4 95.18%
src/buf.c 8 1 87.50% 2 0 100.00% 16 1 93.75%
-src/cbor.c 1047 23 97.80% 54 0 100.00% 1237 46 96.28%
-src/compress.c 34 4 88.24% 3 0 100.00% 28 3 89.29%
+src/cbor.c 1049 23 97.81% 54 0 100.00% 1237 45 96.36%
+src/compress.c 105 14 86.67% 5 0 100.00% 122 24 80.33%
src/config.c 108 0 100.00% 11 0 100.00% 151 0 100.00%
-src/cred.c 632 34 94.62% 69 2 97.10% 830 36 95.66%
-src/credman.c 382 10 97.38% 40 0 100.00% 518 15 97.10%
-src/dev.c 421 79 81.24% 45 7 84.44% 491 105 78.62%
+src/cred.c 634 36 94.32% 69 2 97.10% 830 39 95.30%
+src/credman.c 382 10 97.38% 40 0 100.00% 518 18 96.53%
+src/dev.c 332 71 78.61% 41 6 85.37% 378 86 77.25%
src/ecdh.c 117 2 98.29% 4 0 100.00% 146 5 96.58%
-src/eddsa.c 80 3 96.25% 10 0 100.00% 106 8 92.45%
+src/eddsa.c 88 5 94.32% 10 0 100.00% 114 9 92.11%
src/err.c 122 10 91.80% 1 0 100.00% 126 10 92.06%
-src/es256.c 306 5 98.37% 19 0 100.00% 358 7 98.04%
+src/es256.c 315 7 97.78% 19 0 100.00% 372 12 96.77%
src/hid.c 87 2 97.70% 14 0 100.00% 145 3 97.93%
-src/hid_linux.c 173 68 60.69% 14 7 50.00% 250 104 58.40%
-src/hid_unix.c 28 20 28.57% 2 0 100.00% 43 24 44.19%
-src/info.c 184 0 100.00% 39 0 100.00% 316 0 100.00%
-src/io.c 182 7 96.15% 13 0 100.00% 221 11 95.02%
-src/iso7816.c 18 1 94.44% 5 0 100.00% 38 0 100.00%
-src/largeblob.c 513 19 96.30% 30 0 100.00% 684 43 93.71%
-src/log.c 39 5 87.18% 7 1 85.71% 63 4 93.65%
-src/netlink.c 328 14 95.73% 40 0 100.00% 498 32 93.57%
-src/nfc_linux.c 327 73 77.68% 23 5 78.26% 458 124 72.93%
-src/pin.c 403 3 99.26% 26 0 100.00% 495 3 99.39%
+src/hid_linux.c 173 68 60.69% 14 7 50.00% 250 105 58.00%
+src/hid_unix.c 29 21 27.59% 2 0 100.00% 43 26 39.53%
+src/info.c 186 0 100.00% 40 0 100.00% 321 0 100.00%
+src/io.c 185 7 96.22% 13 0 100.00% 221 12 94.57%
+src/iso7816.c 18 1 94.44% 5 0 100.00% 38 1 97.37%
+src/largeblob.c 514 19 96.30% 30 0 100.00% 684 46 93.27%
+src/log.c 39 5 87.18% 7 1 85.71% 63 7 88.89%
+src/netlink.c 329 14 95.74% 40 0 100.00% 498 33 93.37%
+src/nfc.c 142 7 95.07% 11 1 90.91% 223 27 87.89%
+src/nfc_linux.c 174 56 67.82% 13 5 61.54% 245 103 57.96%
+src/pcsc.c 201 1 99.50% 13 0 100.00% 278 3 98.92%
+src/pin.c 403 3 99.26% 26 0 100.00% 495 4 99.19%
src/random.c 6 1 83.33% 1 0 100.00% 6 1 83.33%
src/reset.c 24 0 100.00% 3 0 100.00% 23 0 100.00%
-src/rs1.c 25 0 100.00% 3 0 100.00% 39 0 100.00%
-src/rs256.c 141 8 94.33% 13 0 100.00% 172 10 94.19%
-src/time.c 43 3 93.02% 3 0 100.00% 43 1 97.67%
-src/tpm.c 100 0 100.00% 9 0 100.00% 194 0 100.00%
+src/rs1.c 25 2 92.00% 3 0 100.00% 39 4 89.74%
+src/rs256.c 141 8 94.33% 13 0 100.00% 172 11 93.60%
+src/time.c 43 3 93.02% 3 0 100.00% 43 2 95.35%
+src/touch.c 67 0 100.00% 2 0 100.00% 79 0 100.00%
+src/tpm.c 103 3 97.09% 9 0 100.00% 194 9 95.36%
src/types.c 25 0 100.00% 6 0 100.00% 46 0 100.00%
src/u2f.c 528 4 99.24% 17 0 100.00% 685 12 98.25%
+src/util.c 14 1 92.86% 1 0 100.00% 14 1 92.86%
Files which contain no functions:
+fuzz/mutator_aux.h 0 0 - 0 0 - 0 0 -
openbsd-compat/openbsd-compat.h 0 0 - 0 0 - 0 0 -
openbsd-compat/time.h 0 0 - 0 0 - 0 0 -
src/extern.h 0 0 - 0 0 - 0 0 -
@@ -54,4 +60,4 @@ src/fido.h 0 0 -
src/fido/err.h 0 0 - 0 0 - 0 0 -
src/fido/param.h 0 0 - 0 0 - 0 0 -
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-TOTAL 7861 476 93.94% 684 27 96.05% 10270 699 93.19%
+TOTAL 8227 484 94.12% 710 27 96.20% 10756 777 92.78%
diff --git a/fuzz/wiredata_fido2.h b/fuzz/wiredata_fido2.h
index da905516f92a..68504325450e 100644
--- a/fuzz/wiredata_fido2.h
+++ b/fuzz/wiredata_fido2.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Yubico AB. All rights reserved.
+ * Copyright (c) 2020-2022 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.
*/
@@ -630,4 +630,78 @@
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+#define WIREDATA_CTAP_NFC_INIT \
+ 0x55, 0x32, 0x46, 0x5f, 0x56, 0x32, 0x90, 0x00
+
+#define WIREDATA_CTAP_NFC_MSG \
+ 0x90, 0x00, 0x90, 0x00, 0x90, 0x00, 0x90, 0x00
+
+#define WIREDATA_CTAP_EXTENDED_APDU \
+ 0x00, 0xa4, 0x04, 0x00, 0x00, 0x02, 0x00, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, \
+ 0x00
+
#endif /* _WIREDATA_FIDO2_H */
diff --git a/fuzz/wrap.c b/fuzz/wrap.c
index 8d7be6bb6247..4d6ac77a98bb 100644
--- a/fuzz/wrap.c
+++ b/fuzz/wrap.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2021 Yubico AB. All rights reserved.
+ * Copyright (c) 2019-2022 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.
*/
@@ -16,6 +16,7 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
+#include <zlib.h>
#include "mutator_aux.h"
@@ -635,3 +636,51 @@ WRAP(int,
(sockfd, addr, addrlen),
1
)
+
+WRAP(int,
+ deflateInit2_,
+ (z_streamp strm, int level, int method, int windowBits, int memLevel,
+ int strategy, const char *version, int stream_size),
+ Z_STREAM_ERROR,
+ (strm, level, method, windowBits, memLevel, strategy, version,
+ stream_size),
+ 1
+)
+
+int __wrap_deflate(z_streamp, int);
+int __real_deflate(z_streamp, int);
+
+int
+__wrap_deflate(z_streamp strm, int flush)
+{
+ if (uniform_random(400) < 1) {
+ return Z_BUF_ERROR;
+ }
+ /* should never happen, but we check for it */
+ if (uniform_random(400) < 1) {
+ strm->avail_out = UINT_MAX;
+ return Z_STREAM_END;
+ }
+
+ return __real_deflate(strm, flush);
+}
+
+int __wrap_asprintf(char **, const char *, ...);
+
+int
+__wrap_asprintf(char **strp, const char *fmt, ...)
+{
+ va_list ap;
+ int r;
+
+ if (uniform_random(400) < 1) {
+ *strp = (void *)0xdeadbeef;
+ return -1;
+ }
+
+ va_start(ap, fmt);
+ r = vasprintf(strp, fmt, ap);
+ va_end(ap);
+
+ return r;
+}
diff --git a/fuzz/wrapped.sym b/fuzz/wrapped.sym
index 0e9d34627f86..59224565ee0a 100644
--- a/fuzz/wrapped.sym
+++ b/fuzz/wrapped.sym
@@ -1,3 +1,4 @@
+asprintf
bind
BN_bin2bn
BN_bn2bin
@@ -24,6 +25,8 @@ cbor_new_definite_bytestring
cbor_new_definite_map
cbor_serialize_alloc
clock_gettime
+deflate
+deflateInit2_
EC_KEY_get0_group
EC_KEY_get0_private_key
EC_KEY_new_by_curve_name
@@ -71,6 +74,12 @@ realloc
RSA_new
RSA_pkey_ctx_ctrl
RSA_set0_key
+SCardConnect
+SCardDisconnect
+SCardEstablishContext
+SCardListReaders
+SCardReleaseContext
+SCardTransmit
SHA1
SHA256
strdup
diff --git a/man/CMakeLists.txt b/man/CMakeLists.txt
index 5ce2fc7b83ed..910ee684e9fb 100644
--- a/man/CMakeLists.txt
+++ b/man/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2018 Yubico AB. All rights reserved.
+# Copyright (c) 2018-2022 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.
@@ -117,10 +117,11 @@ list(APPEND MAN_ALIAS
fido_cbor_info_new fido_cbor_info_extensions_len
fido_cbor_info_new fido_cbor_info_extensions_ptr
fido_cbor_info_new fido_cbor_info_free
- fido_cbor_info_new fido_cbor_info_maxmsgsiz
fido_cbor_info_new fido_cbor_info_maxcredbloblen
fido_cbor_info_new fido_cbor_info_maxcredcntlst
fido_cbor_info_new fido_cbor_info_maxcredidlen
+ fido_cbor_info_new fido_cbor_info_maxlargeblob
+ fido_cbor_info_new fido_cbor_info_maxmsgsiz
fido_cbor_info_new fido_cbor_info_fwversion
fido_cbor_info_new fido_cbor_info_options_len
fido_cbor_info_new fido_cbor_info_options_name_ptr
@@ -263,7 +264,7 @@ math(EXPR MAN_ALIAS_MAX "${MAN_ALIAS_LEN} - 2")
# man_copy
foreach(f ${MAN_SOURCES})
add_custom_command(OUTPUT ${f}
- COMMAND cp -f ${CMAKE_SOURCE_DIR}/man/${f} .
+ COMMAND cp -f ${PROJECT_SOURCE_DIR}/man/${f} .
DEPENDS ${f})
list(APPEND COPY_FILES ${f})
endforeach()
@@ -289,7 +290,7 @@ endforeach()
foreach(f ${MAN_SOURCES})
string(REGEX REPLACE ".[13]" "" g ${f})
add_custom_command(OUTPUT ${g}.partial
- COMMAND cat ${CMAKE_SOURCE_DIR}/man/dyc.css > ${g}.partial
+ COMMAND cat ${PROJECT_SOURCE_DIR}/man/dyc.css > ${g}.partial
COMMAND mandoc -T html -O man="%N.html",fragment ${f} >> ${g}.partial
DEPENDS ${f})
list(APPEND HTML_PARTIAL_FILES ${g}.partial)
@@ -337,17 +338,17 @@ add_custom_target(man ALL)
if(MANDOC_PATH)
add_dependencies(man man_symlink_html)
add_dependencies(man_gzip man_lint)
- install(FILES ${CMAKE_SOURCE_DIR}/man/style.css
+ install(FILES ${PROJECT_SOURCE_DIR}/man/style.css
DESTINATION "${CMAKE_INSTALL_DOCDIR}/html")
foreach(f ${MAN_SOURCES})
string(REGEX REPLACE ".[13]" "" f ${f})
- install(FILES ${CMAKE_BINARY_DIR}/man/${f}.html
+ install(FILES ${PROJECT_BINARY_DIR}/man/${f}.html
DESTINATION "${CMAKE_INSTALL_DOCDIR}/html")
endforeach()
foreach(i RANGE 0 ${MAN_ALIAS_MAX} 2)
math(EXPR j "${i} + 1")
list(GET MAN_ALIAS ${j} DST)
- install(FILES ${CMAKE_BINARY_DIR}/man/${DST}.html
+ install(FILES ${PROJECT_BINARY_DIR}/man/${DST}.html
DESTINATION "${CMAKE_INSTALL_DOCDIR}/html")
endforeach()
endif()
@@ -358,34 +359,34 @@ if(GZIP_PATH)
add_dependencies(man man_symlink_gzip)
foreach(f ${MAN_SOURCES})
if (${f} MATCHES ".1$")
- install(FILES ${CMAKE_BINARY_DIR}/man/${f}.gz
+ install(FILES ${PROJECT_BINARY_DIR}/man/${f}.gz
DESTINATION "${CMAKE_INSTALL_MANDIR}/man1")
elseif(${f} MATCHES ".3$")
- install(FILES ${CMAKE_BINARY_DIR}/man/${f}.gz
+ install(FILES ${PROJECT_BINARY_DIR}/man/${f}.gz
DESTINATION "${CMAKE_INSTALL_MANDIR}/man3")
endif()
endforeach()
foreach(i RANGE 0 ${MAN_ALIAS_MAX} 2)
math(EXPR j "${i} + 1")
list(GET MAN_ALIAS ${j} DST)
- install(FILES ${CMAKE_BINARY_DIR}/man/${DST}.3.gz
+ install(FILES ${PROJECT_BINARY_DIR}/man/${DST}.3.gz
DESTINATION "${CMAKE_INSTALL_MANDIR}/man3")
endforeach()
elseif(NOT MSVC)
add_dependencies(man man_symlink)
foreach(f ${MAN_SOURCES})
if (${f} MATCHES ".1$")
- install(FILES ${CMAKE_BINARY_DIR}/man/${f}
+ install(FILES ${PROJECT_BINARY_DIR}/man/${f}
DESTINATION "${CMAKE_INSTALL_MANDIR}/man1")
elseif(${f} MATCHES ".3$")
- install(FILES ${CMAKE_BINARY_DIR}/man/${f}
+ install(FILES ${PROJECT_BINARY_DIR}/man/${f}
DESTINATION "${CMAKE_INSTALL_MANDIR}/man3")
endif()
endforeach()
foreach(i RANGE 0 ${MAN_ALIAS_MAX} 2)
math(EXPR j "${i} + 1")
list(GET MAN_ALIAS ${j} DST)
- install(FILES ${CMAKE_BINARY_DIR}/man/${DST}.3
+ install(FILES ${PROJECT_BINARY_DIR}/man/${DST}.3
DESTINATION "${CMAKE_INSTALL_MANDIR}/man3")
endforeach()
endif()
diff --git a/man/fido2-token.1 b/man/fido2-token.1
index 1aa2feb86859..4f8b8d08efe6 100644
--- a/man/fido2-token.1
+++ b/man/fido2-token.1
@@ -1,8 +1,8 @@
-.\" Copyright (c) 2018-2021 Yubico AB. All rights reserved.
+.\" Copyright (c) 2018-2022 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.
.\"
-.Dd $Mdocdate: September 13 2019 $
+.Dd $Mdocdate: April 11 2022 $
.Dt FIDO2-TOKEN 1
.Os
.Sh NAME
@@ -147,7 +147,7 @@ from
.Ar device ,
where
.Ar key_path
-must hold the blob's base64-encoded encryption key.
+holds the blob's base64-encoded 32-byte AES-256 GCM encryption key.
A PIN or equivalent user-verification gesture is required.
.It Fl D Fl b Fl n Ar rp_id Oo Fl i Ar cred_id Oc Ar device
Deletes a
@@ -189,7 +189,7 @@ from
.Ar device ,
where
.Ar key_path
-must hold the blob's base64-encoded encryption key.
+holds the blob's base64-encoded 32-byte AES-256 GCM encryption key.
The blob is written to
.Ar blob_path .
A PIN or equivalent user-verification gesture is required.
@@ -267,29 +267,27 @@ The user will be prompted for the PIN.
Enables CTAP 2.1 Enterprise Attestation on
.Ar device .
.It Fl S Fl b Fl k Ar key_path Ar blob_path Ar device
-Sets
-.Ar blob_path
-as a CTAP 2.1
+Sets a CTAP 2.1
.Dq largeBlob
encrypted with
.Ar key_path
on
.Ar device ,
where
-.Ar blob_path
-holds the blob's plaintext, and
.Ar key_path
-the blob's base64-encoded encryption.
+holds the blob's base64-encoded 32-byte AES-256 GCM encryption key.
+The blob is read from
+.Fa blob_path .
A PIN or equivalent user-verification gesture is required.
.It Fl S Fl b Fl n Ar rp_id Oo Fl i Ar cred_id Oc Ar blob_path Ar device
-Sets
-.Ar blob_path
-as a CTAP 2.1
+Sets a CTAP 2.1
.Dq largeBlob
associated with
.Ar rp_id
on
.Ar device .
+The blob is read from
+.Fa blob_path .
If
.Ar rp_id
has multiple credentials enrolled on
diff --git a/man/fido_assert_new.3 b/man/fido_assert_new.3
index a1a3c101ba33..413b7a7ba2ef 100644
--- a/man/fido_assert_new.3
+++ b/man/fido_assert_new.3
@@ -1,8 +1,8 @@
-.\" Copyright (c) 2018 Yubico AB. All rights reserved.
+.\" Copyright (c) 2018-2022 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.
.\"
-.Dd $Mdocdate: October 22 2019 $
+.Dd $Mdocdate: April 27 2022 $
.Dt FIDO_ASSERT_NEW 3
.Os
.Sh NAME
@@ -180,6 +180,8 @@ in
The HMAC Secret Extension
.Pq hmac-secret
is a CTAP 2.0 extension.
+Note that the resulting hmac-secret varies according to whether
+user verification was performed by the authenticator.
.Pp
The
.Fn fido_assert_blob_ptr
diff --git a/man/fido_assert_set_authdata.3 b/man/fido_assert_set_authdata.3
index 51cdcc97c292..0d512b655012 100644
--- a/man/fido_assert_set_authdata.3
+++ b/man/fido_assert_set_authdata.3
@@ -1,8 +1,8 @@
-.\" Copyright (c) 2018 Yubico AB. All rights reserved.
+.\" Copyright (c) 2018-2022 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.
.\"
-.Dd $Mdocdate: May 23 2018 $
+.Dd $Mdocdate: April 27 2022 $
.Dt FIDO_ASSERT_SET_AUTHDATA 3
.Os
.Sh NAME
@@ -182,6 +182,8 @@ is made, and no references to the passed pointer are kept.
The HMAC Secret
.Pq hmac-secret
Extension is a CTAP 2.0 extension.
+Note that the resulting hmac-secret varies according to whether
+user verification was performed by the authenticator.
The
.Fn fido_assert_set_hmac_secret
function is normally only useful when writing tests.
diff --git a/man/fido_cbor_info_new.3 b/man/fido_cbor_info_new.3
index 86f2a887f99a..45c143f5df62 100644
--- a/man/fido_cbor_info_new.3
+++ b/man/fido_cbor_info_new.3
@@ -1,8 +1,8 @@
-.\" Copyright (c) 2018 Yubico AB. All rights reserved.
+.\" Copyright (c) 2018-2022 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.
.\"
-.Dd $Mdocdate: May 24 2018 $
+.Dd $Mdocdate: April 22 2022 $
.Dt FIDO_CBOR_INFO_NEW 3
.Os
.Sh NAME
@@ -29,6 +29,7 @@
.Nm fido_cbor_info_maxcredbloblen ,
.Nm fido_cbor_info_maxcredcntlst ,
.Nm fido_cbor_info_maxcredidlen ,
+.Nm fido_cbor_info_maxlargeblob ,
.Nm fido_cbor_info_fwversion
.Nd FIDO2 CBOR Info API
.Sh SYNOPSIS
@@ -80,6 +81,8 @@
.Ft uint64_t
.Fn fido_cbor_info_maxcredidlen "const fido_cbor_info_t *ci"
.Ft uint64_t
+.Fn fido_cbor_info_maxlargeblob "const fido_cbor_info_t *ci"
+.Ft uint64_t
.Fn fido_cbor_info_fwversion "const fido_cbor_info_t *ci"
.Sh DESCRIPTION
The
@@ -201,6 +204,12 @@ as reported in
.Fa ci .
.Pp
The
+.Fn fido_cbor_info_maxlargeblob
+function returns the maximum length in bytes of an authenticator's
+serialized largeBlob array as reported in
+.Fa ci .
+.Pp
+The
.Fn fido_cbor_info_fwversion
function returns the firmware version attribute of
.Fa ci .
diff --git a/man/fido_dev_enable_entattest.3 b/man/fido_dev_enable_entattest.3
index bfc1b2834e55..a06746b61317 100644
--- a/man/fido_dev_enable_entattest.3
+++ b/man/fido_dev_enable_entattest.3
@@ -2,7 +2,7 @@
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: September 22 2020 $
+.Dd $Mdocdate: March 30 2022 $
.Dt FIDO_DEV_ENABLE_ENTATTEST 3
.Os
.Sh NAME
@@ -65,7 +65,7 @@ does not have a PIN set.
.Pp
The
.Fn fido_dev_force_pin_change
-instructs
+function instructs
.Fa dev
to require a PIN change.
Subsequent PIN authentication attempts against
diff --git a/man/fido_dev_info_manifest.3 b/man/fido_dev_info_manifest.3
index 9539a0dda7c5..4be7e3a60490 100644
--- a/man/fido_dev_info_manifest.3
+++ b/man/fido_dev_info_manifest.3
@@ -2,7 +2,7 @@
.\" Use of this source code is governed by a BSD-style
.\" license that can be found in the LICENSE file.
.\"
-.Dd $Mdocdate: May 25 2018 $
+.Dd $Mdocdate: March 30 2022 $
.Dt FIDO_DEV_INFO_MANIFEST 3
.Os
.Sh NAME
@@ -97,7 +97,7 @@ Please note that the first slot has index 0.
.Pp
The
.Fn fido_dev_info_path
-returns the filesystem path or subsystem-specific identification
+function returns the filesystem path or subsystem-specific identification
string of
.Fa di .
.Pp
diff --git a/openbsd-compat/bsd-asprintf.c b/openbsd-compat/bsd-asprintf.c
new file mode 100644
index 000000000000..fbcb8679258f
--- /dev/null
+++ b/openbsd-compat/bsd-asprintf.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2004 Darren Tucker.
+ *
+ * Based originally on asprintf.c from OpenBSD:
+ * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "openbsd-compat.h"
+
+#ifndef HAVE_ASPRINTF
+
+#include <errno.h>
+#include <limits.h> /* for INT_MAX */
+#include <stdarg.h>
+#include <stdio.h> /* for vsnprintf */
+#include <stdlib.h>
+
+#define VA_COPY(dest, src) va_copy(dest, src)
+
+#define INIT_SZ 128
+
+int
+vasprintf(char **str, const char *fmt, va_list ap)
+{
+ int ret;
+ va_list ap2;
+ char *string, *newstr;
+ size_t len;
+
+ if ((string = malloc(INIT_SZ)) == NULL)
+ goto fail;
+
+ VA_COPY(ap2, ap);
+ ret = vsnprintf(string, INIT_SZ, fmt, ap2);
+ va_end(ap2);
+ if (ret >= 0 && ret < INIT_SZ) { /* succeeded with initial alloc */
+ *str = string;
+ } else if (ret == INT_MAX || ret < 0) { /* Bad length */
+ free(string);
+ goto fail;
+ } else { /* bigger than initial, realloc allowing for nul */
+ len = (size_t)ret + 1;
+ if ((newstr = realloc(string, len)) == NULL) {
+ free(string);
+ goto fail;
+ }
+ VA_COPY(ap2, ap);
+ ret = vsnprintf(newstr, len, fmt, ap2);
+ va_end(ap2);
+ if (ret < 0 || (size_t)ret >= len) { /* failed with realloc'ed string */
+ free(newstr);
+ goto fail;
+ }
+ *str = newstr;
+ }
+ return (ret);
+
+fail:
+ *str = NULL;
+ errno = ENOMEM;
+ return (-1);
+}
+
+int asprintf(char **str, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ *str = NULL;
+ va_start(ap, fmt);
+ ret = vasprintf(str, fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
+#endif
diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h
index dc9acec4c0a8..1518ff755b97 100644
--- a/openbsd-compat/openbsd-compat.h
+++ b/openbsd-compat/openbsd-compat.h
@@ -115,4 +115,8 @@ ssize_t getline(char **, size_t *, FILE *);
#define IOCTL_REQ(x) ((int)(x))
#endif
+#if !defined(HAVE_ASPRINTF)
+int asprintf(char **, const char *, ...);
+#endif
+
#endif /* !_OPENBSD_COMPAT_H */
diff --git a/regress/CMakeLists.txt b/regress/CMakeLists.txt
index c550b3141822..87482ef35362 100644
--- a/regress/CMakeLists.txt
+++ b/regress/CMakeLists.txt
@@ -1,20 +1,45 @@
-# Copyright (c) 2018-2021 Yubico AB. All rights reserved.
+# Copyright (c) 2018-2022 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.
-add_custom_target(regress ALL)
+add_custom_target(regress)
macro(add_regress_test NAME SOURCES)
add_executable(${NAME} ${SOURCES})
- target_link_libraries(${NAME} fido2_shared)
+ target_link_libraries(${NAME} fido2)
add_test(${NAME} ${NAME})
add_dependencies(regress ${NAME})
endmacro()
-add_custom_command(TARGET regress POST_BUILD
- COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure
- WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
+if(MSVC AND BUILD_SHARED_LIBS)
+ add_custom_command(TARGET regress POST_BUILD
+ COMMAND "${CMAKE_COMMAND}" -E copy
+ "${CBOR_BIN_DIRS}/${CBOR_LIBRARIES}.dll"
+ "${CRYPTO_BIN_DIRS}/${CRYPTO_LIBRARIES}.dll"
+ "${ZLIB_BIN_DIRS}/${ZLIB_LIBRARIES}.dll"
+ "${CMAKE_CURRENT_BINARY_DIR}")
+endif()
+
+if(CMAKE_CROSSCOMPILING OR (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64" AND
+ CMAKE_GENERATOR_PLATFORM MATCHES "^ARM.*$"))
+ add_custom_command(TARGET regress POST_BUILD
+ COMMAND "${CMAKE_COMMAND}" -E echo
+ "Cross-compilation detected. Skipping regress tests.")
+else()
+ add_custom_command(TARGET regress POST_BUILD
+ COMMAND "${CMAKE_CTEST_COMMAND}" --output-on-failure
+ WORKING_DIRECTORY ${PROJECT_BINARY_DIR})
+endif()
-add_regress_test(regress_cred cred.c)
add_regress_test(regress_assert assert.c)
+add_regress_test(regress_compress compress.c)
+add_regress_test(regress_cred cred.c)
add_regress_test(regress_dev dev.c)
+add_regress_test(regress_eddsa eddsa.c)
+add_regress_test(regress_es256 es256.c)
+add_regress_test(regress_rs256 rs256.c)
+
+if(MINGW)
+ # needed for nanosleep() in mingw
+ target_link_libraries(regress_dev winpthread)
+endif()
diff --git a/regress/assert.c b/regress/assert.c
index 23d666a61173..695a3b78edcc 100644
--- a/regress/assert.c
+++ b/regress/assert.c
@@ -4,16 +4,19 @@
* license that can be found in the LICENSE file.
*/
-#define _FIDO_INTERNAL
+#undef NDEBUG
#include <assert.h>
+#include <string.h>
+
+#define _FIDO_INTERNAL
+
#include <fido.h>
#include <fido/es256.h>
#include <fido/rs256.h>
#include <fido/eddsa.h>
-#include <string.h>
-#define FAKE_DEV_HANDLE ((void *)0xdeadbeef)
+static int fake_dev_handle;
static const unsigned char es256_pk[64] = {
0x34, 0xeb, 0x99, 0x77, 0x02, 0x9c, 0x36, 0x38,
@@ -94,13 +97,13 @@ dummy_open(const char *path)
{
(void)path;
- return (FAKE_DEV_HANDLE);
+ return (&fake_dev_handle);
}
static void
dummy_close(void *handle)
{
- assert(handle == FAKE_DEV_HANDLE);
+ assert(handle == &fake_dev_handle);
}
static int
diff --git a/regress/compress.c b/regress/compress.c
new file mode 100644
index 000000000000..5d537838bdeb
--- /dev/null
+++ b/regress/compress.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2022 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.
+ */
+
+#undef NDEBUG
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/sha.h>
+
+#define _FIDO_INTERNAL
+
+#include <fido.h>
+
+/*
+ * zlib compressed data (RFC1950); see https://www.ietf.org/rfc/rfc6713.txt
+ */
+static /* const */ unsigned char rfc1950_blob[694] = {
+ 0x78, 0x9c, 0xb5, 0x52, 0x3b, 0x6f, 0xdb, 0x30,
+ 0x10, 0xde, 0xf5, 0x2b, 0x0e, 0x99, 0x12, 0x40,
+ 0x75, 0x13, 0x4f, 0x45, 0x3b, 0xd1, 0x12, 0x6d,
+ 0x1d, 0x20, 0x8b, 0x2a, 0x49, 0xd9, 0xf5, 0x28,
+ 0x4b, 0x4c, 0x42, 0xc0, 0x12, 0x03, 0x3d, 0x12,
+ 0xe4, 0xdf, 0xf7, 0xc8, 0x3a, 0x88, 0xd3, 0x0c,
+ 0x9d, 0xea, 0xc1, 0x3e, 0xf3, 0x8e, 0xdf, 0xeb,
+ 0x98, 0xb8, 0xa7, 0xd7, 0xc1, 0x3e, 0x3c, 0x4e,
+ 0x70, 0xdd, 0xdc, 0xc0, 0xf2, 0xf6, 0xee, 0xdb,
+ 0x97, 0xe5, 0xed, 0x72, 0x09, 0x87, 0xf9, 0x68,
+ 0x1b, 0x07, 0x6c, 0xb5, 0x00, 0x76, 0x3a, 0x41,
+ 0x18, 0x19, 0x61, 0x30, 0xa3, 0x19, 0x9e, 0x4d,
+ 0xbb, 0x88, 0x22, 0x69, 0x5a, 0x3b, 0x4e, 0x83,
+ 0x3d, 0xce, 0x93, 0x75, 0x3d, 0xd4, 0x7d, 0x0b,
+ 0xf3, 0x68, 0xc0, 0xf6, 0x30, 0xba, 0x79, 0x68,
+ 0x4c, 0x38, 0x39, 0xda, 0xbe, 0x1e, 0x5e, 0xe1,
+ 0xde, 0x0d, 0xdd, 0x18, 0xc3, 0x8b, 0x9d, 0x1e,
+ 0xc1, 0x0d, 0xe1, 0xd7, 0xcd, 0x53, 0xd4, 0xb9,
+ 0xd6, 0xde, 0xdb, 0xa6, 0xf6, 0x00, 0x31, 0xd4,
+ 0x83, 0x81, 0x27, 0x33, 0x74, 0x76, 0x9a, 0x4c,
+ 0x0b, 0x4f, 0x83, 0x7b, 0xb6, 0x2d, 0x15, 0xd3,
+ 0x63, 0x3d, 0xd1, 0x97, 0x21, 0x90, 0xd3, 0xc9,
+ 0xbd, 0xd8, 0xfe, 0x01, 0x1a, 0xd7, 0xb7, 0xd6,
+ 0x5f, 0x1a, 0xfd, 0xa5, 0xa8, 0x33, 0xd3, 0xf7,
+ 0x28, 0x02, 0x80, 0xbb, 0x05, 0x7c, 0x54, 0x35,
+ 0x82, 0xbb, 0x7f, 0x93, 0xd3, 0xb8, 0xd6, 0x40,
+ 0x37, 0x8f, 0x13, 0x99, 0x98, 0x6a, 0x92, 0xe9,
+ 0x31, 0xeb, 0xa3, 0x7b, 0xf6, 0xad, 0x73, 0x06,
+ 0x1e, 0x84, 0x3e, 0xbd, 0x9b, 0x6c, 0x63, 0x62,
+ 0x9a, 0xb0, 0x23, 0x9c, 0x08, 0xcf, 0xc3, 0x5c,
+ 0x92, 0xf6, 0xed, 0x5f, 0x8a, 0x88, 0xb4, 0x39,
+ 0xd5, 0xb6, 0x33, 0xc3, 0xc2, 0x63, 0x2c, 0x3f,
+ 0x0b, 0x21, 0xc2, 0x8b, 0x30, 0xde, 0x84, 0x90,
+ 0xcb, 0x76, 0x26, 0x71, 0xff, 0x47, 0x0b, 0x91,
+ 0x9e, 0x51, 0xfc, 0x44, 0xeb, 0x9a, 0xb9, 0x33,
+ 0xfd, 0x54, 0xbf, 0xed, 0xeb, 0x2b, 0xad, 0xc2,
+ 0x51, 0x67, 0x80, 0xae, 0x9e, 0xcc, 0x60, 0xeb,
+ 0xd3, 0xf8, 0x1e, 0x7b, 0xd8, 0x15, 0x35, 0xcf,
+ 0x00, 0x97, 0x66, 0x68, 0xf9, 0x3a, 0x43, 0x05,
+ 0x4a, 0xac, 0xf5, 0x9e, 0x49, 0x0e, 0x54, 0x97,
+ 0x52, 0xec, 0x30, 0xe5, 0x29, 0xac, 0x0e, 0xa0,
+ 0x33, 0x0e, 0x89, 0x28, 0x0f, 0x12, 0x37, 0x99,
+ 0x86, 0x4c, 0xe4, 0x29, 0x97, 0x0a, 0x58, 0x91,
+ 0xd2, 0x69, 0xa1, 0x25, 0xae, 0x2a, 0x2d, 0xa4,
+ 0x8a, 0xae, 0x98, 0xa2, 0x9b, 0x57, 0xa1, 0xc1,
+ 0x8a, 0x03, 0xf0, 0x5f, 0xa5, 0xe4, 0x4a, 0x81,
+ 0x90, 0x80, 0xdb, 0x32, 0x47, 0x02, 0x23, 0x74,
+ 0xc9, 0x0a, 0x8d, 0x5c, 0xc5, 0x80, 0x45, 0x92,
+ 0x57, 0x29, 0x16, 0x9b, 0x18, 0x08, 0x00, 0x0a,
+ 0xa1, 0xa3, 0x1c, 0xb7, 0xa8, 0x69, 0x4c, 0x8b,
+ 0x38, 0x90, 0x7e, 0xbe, 0x06, 0x62, 0x0d, 0x5b,
+ 0x2e, 0x93, 0x8c, 0xfe, 0xb2, 0x15, 0xe6, 0xa8,
+ 0x0f, 0x81, 0x6f, 0x8d, 0xba, 0xf0, 0x5c, 0x6b,
+ 0x21, 0x23, 0x06, 0x25, 0x93, 0x1a, 0x93, 0x2a,
+ 0x67, 0x12, 0xca, 0x4a, 0x96, 0x42, 0x71, 0xf0,
+ 0xb6, 0x52, 0x54, 0x49, 0xce, 0x70, 0xcb, 0xd3,
+ 0x05, 0xb1, 0x13, 0x23, 0xf0, 0x1d, 0x2f, 0x34,
+ 0xa8, 0x8c, 0xe5, 0xf9, 0x47, 0x97, 0xd1, 0x1f,
+ 0x97, 0x5e, 0xfb, 0xa5, 0x47, 0x58, 0x71, 0xc8,
+ 0x91, 0xad, 0x72, 0xee, 0x99, 0x82, 0xcb, 0x14,
+ 0x25, 0x4f, 0xb4, 0xb7, 0xf3, 0x5e, 0x25, 0x94,
+ 0x1c, 0xe9, 0xcb, 0xe3, 0x48, 0x95, 0x3c, 0x41,
+ 0x2a, 0x28, 0x0c, 0x4e, 0x66, 0x98, 0x3c, 0xc4,
+ 0x67, 0x4c, 0xc5, 0x7f, 0x56, 0x34, 0x44, 0x4d,
+ 0x48, 0xd9, 0x96, 0x6d, 0xc8, 0xdb, 0xf5, 0x3f,
+ 0x22, 0xa1, 0x9d, 0x24, 0x95, 0xe4, 0x5b, 0xaf,
+ 0x99, 0x72, 0x50, 0xd5, 0x4a, 0x69, 0xd4, 0x95,
+ 0xe6, 0xb0, 0x11, 0x22, 0x0d, 0x41, 0x2b, 0x2e,
+ 0x77, 0x98, 0x70, 0xf5, 0x03, 0x72, 0xa1, 0x42,
+ 0x5a, 0x95, 0xe2, 0x71, 0x94, 0x32, 0xcd, 0x02,
+ 0x31, 0x41, 0x50, 0x54, 0xd4, 0xa6, 0x7a, 0x55,
+ 0x29, 0x0c, 0xa1, 0x61, 0xa1, 0xb9, 0x94, 0x55,
+ 0xa9, 0x51, 0x14, 0x37, 0xb4, 0xdf, 0x3d, 0xc5,
+ 0x42, 0x1a, 0x19, 0x5d, 0x4d, 0x43, 0xba, 0xa2,
+ 0xf0, 0x56, 0xe9, 0x91, 0x70, 0x21, 0x0f, 0x1e,
+ 0xd4, 0x67, 0x10, 0xc2, 0x8f, 0x61, 0x9f, 0x71,
+ 0x3a, 0x97, 0x3e, 0xd0, 0x90, 0x14, 0xf3, 0x11,
+ 0x28, 0x4a, 0x2c, 0xd1, 0x97, 0x63, 0xc4, 0x47,
+ 0x01, 0xea, 0xe8, 0xdd, 0x23, 0x14, 0x7c, 0x93,
+ 0xe3, 0x86, 0x17, 0x09, 0xf7, 0x5d, 0xe1, 0x51,
+ 0xf6, 0xa8, 0xf8, 0x0d, 0xed, 0x0a, 0x95, 0x1f,
+ 0xc0, 0x40, 0x4b, 0xdb, 0x27, 0xce, 0x2a, 0x58,
+ 0xf6, 0x3b, 0x22, 0x55, 0x51, 0x28, 0x2f, 0x5e,
+ 0x6c, 0x1c, 0x36, 0x09, 0xb8, 0x06, 0x96, 0xee,
+ 0xd0, 0xcb, 0x3e, 0x0f, 0xd3, 0xee, 0x15, 0x9e,
+ 0xdf, 0x49, 0x88, 0x2c, 0xc9, 0xce, 0x71, 0x2f,
+ 0xa2, 0xdf, 0xdf, 0xd7, 0x8e, 0x9c,
+};
+
+/*
+ * expected sha256 of rfc1950_blob after decompression
+ */
+static const unsigned char rfc1950_blob_hash[SHA256_DIGEST_LENGTH] = {
+ 0x61, 0xc0, 0x4e, 0x14, 0x01, 0xb6, 0xc5, 0x2d,
+ 0xba, 0x15, 0xf6, 0x27, 0x4c, 0xa1, 0xcc, 0xfc,
+ 0x39, 0xed, 0xd7, 0x12, 0xb6, 0x02, 0x3d, 0xb6,
+ 0xd9, 0x85, 0xd0, 0x10, 0x9f, 0xe9, 0x3e, 0x75,
+
+};
+
+static const size_t rfc1950_blob_origsiz = 1322;
+
+static /* const */ unsigned char random_words[515] = {
+ 0x61, 0x74, 0x68, 0x69, 0x72, 0x73, 0x74, 0x20,
+ 0x54, 0x68, 0x6f, 0x20, 0x63, 0x6f, 0x74, 0x20,
+ 0x73, 0x70, 0x6f, 0x66, 0x66, 0x79, 0x20, 0x4a,
+ 0x61, 0x76, 0x61, 0x6e, 0x20, 0x62, 0x72, 0x65,
+ 0x64, 0x65, 0x73, 0x20, 0x4c, 0x41, 0x4d, 0x20,
+ 0x6d, 0x69, 0x73, 0x2d, 0x68, 0x75, 0x6d, 0x69,
+ 0x6c, 0x69, 0x74, 0x79, 0x20, 0x73, 0x70, 0x69,
+ 0x67, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x76, 0x6f,
+ 0x6c, 0x74, 0x69, 0x6e, 0x67, 0x6c, 0x79, 0x20,
+ 0x49, 0x6f, 0x64, 0x61, 0x6d, 0x6f, 0x65, 0x62,
+ 0x61, 0x20, 0x68, 0x79, 0x70, 0x6f, 0x68, 0x79,
+ 0x64, 0x72, 0x6f, 0x63, 0x68, 0x6c, 0x6f, 0x72,
+ 0x69, 0x61, 0x20, 0x76, 0x6f, 0x6c, 0x75, 0x6d,
+ 0x65, 0x74, 0x74, 0x65, 0x20, 0x61, 0x63, 0x72,
+ 0x69, 0x64, 0x69, 0x6e, 0x65, 0x20, 0x68, 0x6f,
+ 0x77, 0x6c, 0x20, 0x45, 0x75, 0x72, 0x79, 0x67,
+ 0x61, 0x65, 0x61, 0x6e, 0x20, 0x63, 0x6f, 0x6e,
+ 0x63, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x69, 0x73,
+ 0x74, 0x20, 0x74, 0x65, 0x74, 0x72, 0x61, 0x70,
+ 0x6c, 0x6f, 0x69, 0x64, 0x20, 0x61, 0x75, 0x78,
+ 0x65, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x72,
+ 0x69, 0x70, 0x65, 0x2d, 0x67, 0x72, 0x6f, 0x77,
+ 0x6e, 0x20, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72,
+ 0x72, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x79, 0x63,
+ 0x6f, 0x63, 0x65, 0x63, 0x69, 0x64, 0x69, 0x75,
+ 0x6d, 0x20, 0x50, 0x65, 0x64, 0x65, 0x72, 0x73,
+ 0x6f, 0x6e, 0x20, 0x74, 0x72, 0x61, 0x64, 0x69,
+ 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x62, 0x6f, 0x75,
+ 0x6e, 0x64, 0x20, 0x4c, 0x65, 0x6e, 0x67, 0x6c,
+ 0x65, 0x6e, 0x20, 0x70, 0x72, 0x65, 0x73, 0x62,
+ 0x79, 0x74, 0x65, 0x72, 0x61, 0x74, 0x65, 0x20,
+ 0x6c, 0x65, 0x63, 0x79, 0x74, 0x68, 0x69, 0x73,
+ 0x20, 0x63, 0x68, 0x61, 0x72, 0x61, 0x64, 0x72,
+ 0x69, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x61,
+ 0x6c, 0x6c, 0x6f, 0x6b, 0x75, 0x72, 0x74, 0x69,
+ 0x63, 0x20, 0x75, 0x6e, 0x64, 0x69, 0x76, 0x69,
+ 0x73, 0x69, 0x76, 0x65, 0x6c, 0x79, 0x20, 0x70,
+ 0x73, 0x79, 0x63, 0x68, 0x6f, 0x6b, 0x79, 0x6d,
+ 0x65, 0x20, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x73,
+ 0x74, 0x61, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65,
+ 0x6e, 0x65, 0x73, 0x73, 0x20, 0x63, 0x75, 0x6c,
+ 0x74, 0x69, 0x73, 0x68, 0x20, 0x52, 0x65, 0x69,
+ 0x63, 0x68, 0x73, 0x74, 0x61, 0x67, 0x20, 0x75,
+ 0x6e, 0x63, 0x68, 0x6c, 0x6f, 0x72, 0x69, 0x6e,
+ 0x61, 0x74, 0x65, 0x64, 0x20, 0x6c, 0x6f, 0x67,
+ 0x6f, 0x67, 0x72, 0x61, 0x70, 0x68, 0x65, 0x72,
+ 0x20, 0x4c, 0x61, 0x69, 0x74, 0x68, 0x20, 0x74,
+ 0x77, 0x6f, 0x2d, 0x66, 0x61, 0x63, 0x65, 0x20,
+ 0x4d, 0x75, 0x70, 0x68, 0x72, 0x69, 0x64, 0x20,
+ 0x70, 0x72, 0x6f, 0x72, 0x65, 0x63, 0x69, 0x70,
+ 0x72, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
+ 0x20, 0x6c, 0x69, 0x62, 0x72, 0x65, 0x74, 0x74,
+ 0x69, 0x73, 0x74, 0x20, 0x49, 0x62, 0x69, 0x62,
+ 0x69, 0x6f, 0x20, 0x72, 0x65, 0x67, 0x72, 0x65,
+ 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x63,
+ 0x6f, 0x6e, 0x64, 0x69, 0x67, 0x6e, 0x6e, 0x65,
+ 0x73, 0x73, 0x20, 0x77, 0x68, 0x69, 0x74, 0x65,
+ 0x2d, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x65,
+ 0x64, 0x20, 0x73, 0x79, 0x6e, 0x61, 0x70, 0x74,
+ 0x65, 0x6e, 0x65, 0x20, 0x68, 0x6f, 0x6c, 0x6f,
+ 0x6d, 0x6f, 0x72, 0x70, 0x68, 0x20, 0x6d, 0x6f,
+ 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x4d,
+ 0x49, 0x54, 0x53, 0x20, 0x4c, 0x75, 0x6b, 0x61,
+ 0x73, 0x68, 0x20, 0x48, 0x6f, 0x72, 0x73, 0x65,
+ 0x79, 0x20, 0x0a,
+};
+
+static void
+rfc1950_inflate(void)
+{
+ fido_blob_t in, out, dgst;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ memset(&dgst, 0, sizeof(dgst));
+ in.ptr = rfc1950_blob;
+ in.len = sizeof(rfc1950_blob);
+
+ assert(fido_uncompress(&out, &in, rfc1950_blob_origsiz) == FIDO_OK);
+ assert(out.len == rfc1950_blob_origsiz);
+ assert(fido_sha256(&dgst, out.ptr, out.len) == 0);
+ assert(dgst.len == sizeof(rfc1950_blob_hash));
+ assert(memcmp(rfc1950_blob_hash, dgst.ptr, dgst.len) == 0);
+
+ free(out.ptr);
+ free(dgst.ptr);
+}
+
+static void
+rfc1951_inflate(void)
+{
+ fido_blob_t in, out, dgst;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ memset(&dgst, 0, sizeof(dgst));
+ in.ptr = rfc1950_blob + 2; /* trim header */
+ in.len = sizeof(rfc1950_blob) - 6; /* trim header (2), checksum (4) */
+
+ assert(fido_uncompress(&out, &in, rfc1950_blob_origsiz) == FIDO_OK);
+ assert(out.len == rfc1950_blob_origsiz);
+ assert(fido_sha256(&dgst, out.ptr, out.len) == 0);
+ assert(dgst.len == sizeof(rfc1950_blob_hash));
+ assert(memcmp(rfc1950_blob_hash, dgst.ptr, dgst.len) == 0);
+
+ free(out.ptr);
+ free(dgst.ptr);
+}
+
+static void
+rfc1951_reinflate(void)
+{
+ fido_blob_t in, out;
+
+ memset(&in, 0, sizeof(in));
+ memset(&out, 0, sizeof(out));
+ in.ptr = random_words;
+ in.len = sizeof(random_words);
+
+ assert(fido_compress(&out, &in) == FIDO_OK);
+
+ in.ptr = out.ptr;
+ in.len = out.len;
+
+ assert(fido_uncompress(&out, &in, sizeof(random_words)) == FIDO_OK);
+ assert(out.len == sizeof(random_words));
+ assert(memcmp(out.ptr, random_words, out.len) == 0);
+
+ free(in.ptr);
+ free(out.ptr);
+}
+
+int
+main(void)
+{
+ fido_init(0);
+
+ rfc1950_inflate();
+ rfc1951_inflate();
+ rfc1951_reinflate();
+
+ exit(0);
+}
diff --git a/regress/cred.c b/regress/cred.c
index 07a2ca0c0237..c62ff8e4dcb4 100644
--- a/regress/cred.c
+++ b/regress/cred.c
@@ -4,12 +4,16 @@
* license that can be found in the LICENSE file.
*/
+#undef NDEBUG
+
#include <assert.h>
-#include <cbor.h>
-#include <fido.h>
#include <string.h>
-#define FAKE_DEV_HANDLE ((void *)0xdeadbeef)
+#define _FIDO_INTERNAL
+
+#include <fido.h>
+
+static int fake_dev_handle;
static const unsigned char cdh[32] = {
0xf9, 0x64, 0x57, 0xe7, 0x2d, 0x97, 0xf6, 0xbb,
@@ -1384,13 +1388,13 @@ dummy_open(const char *path)
{
(void)path;
- return (FAKE_DEV_HANDLE);
+ return (&fake_dev_handle);
}
static void
dummy_close(void *handle)
{
- assert(handle == FAKE_DEV_HANDLE);
+ assert(handle == &fake_dev_handle);
}
static int
diff --git a/regress/dev.c b/regress/dev.c
index a5dc8d6e4529..92031e17066c 100644
--- a/regress/dev.c
+++ b/regress/dev.c
@@ -1,38 +1,57 @@
/*
- * Copyright (c) 2019-2021 Yubico AB. All rights reserved.
+ * Copyright (c) 2019-2022 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.
*/
+#undef NDEBUG
+
#include <assert.h>
-#include <err.h>
-#include <fido.h>
#include <string.h>
#include <time.h>
+#define _FIDO_INTERNAL
+
+#include <fido.h>
+
#include "../fuzz/wiredata_fido2.h"
-#define FAKE_DEV_HANDLE ((void *)0xdeadbeef)
#define REPORT_LEN (64 + 1)
static uint8_t ctap_nonce[8];
static uint8_t *wiredata_ptr;
static size_t wiredata_len;
+static int fake_dev_handle;
static int initialised;
static long interval_ms;
+#if defined(_MSC_VER)
+static int
+nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
+{
+ if (rmtp != NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ Sleep((DWORD)(rqtp->tv_sec * 1000) + (DWORD)(rqtp->tv_nsec / 1000000));
+
+ return (0);
+}
+#endif
+
static void *
dummy_open(const char *path)
{
(void)path;
- return (FAKE_DEV_HANDLE);
+ return (&fake_dev_handle);
}
static void
dummy_close(void *handle)
{
- assert(handle == FAKE_DEV_HANDLE);
+ assert(handle == &fake_dev_handle);
}
static int
@@ -42,7 +61,7 @@ dummy_read(void *handle, unsigned char *ptr, size_t len, int ms)
size_t n;
long d;
- assert(handle == FAKE_DEV_HANDLE);
+ assert(handle == &fake_dev_handle);
assert(ptr != NULL);
assert(len == REPORT_LEN - 1);
@@ -87,7 +106,7 @@ dummy_write(void *handle, const unsigned char *ptr, size_t len)
{
struct timespec tv;
- assert(handle == FAKE_DEV_HANDLE);
+ assert(handle == &fake_dev_handle);
assert(ptr != NULL);
assert(len == REPORT_LEN);
@@ -113,7 +132,14 @@ wiredata_setup(const uint8_t *data, size_t len)
assert(SIZE_MAX - len > sizeof(ctap_init_data));
assert((wiredata_ptr = malloc(sizeof(ctap_init_data) + len)) != NULL);
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:6386)
+#endif
memcpy(wiredata_ptr, ctap_init_data, sizeof(ctap_init_data));
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
if (len)
memcpy(wiredata_ptr + sizeof(ctap_init_data), data, len);
diff --git a/regress/eddsa.c b/regress/eddsa.c
new file mode 100644
index 000000000000..42236ea58adf
--- /dev/null
+++ b/regress/eddsa.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2022 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.
+ */
+
+#undef NDEBUG
+
+#include <assert.h>
+#include <string.h>
+
+#define _FIDO_INTERNAL
+
+#include <fido.h>
+#include <fido/eddsa.h>
+
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+
+#define ASSERT_NOT_NULL(e) assert((e) != NULL)
+#define ASSERT_NULL(e) assert((e) == NULL)
+#define ASSERT_INVAL(e) assert((e) == FIDO_ERR_INVALID_ARGUMENT)
+#define ASSERT_OK(e) assert((e) == FIDO_OK)
+
+static const char ecdsa[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOwiq14c80b7C1Jzsx5w1zMvk2GgW\n"
+"5kfGMOKXjwF/U+51ZfBDKehs3ivdeXAJBkxIh7E3iA32s+HyNqk+ntl9fg==\n"
+"-----END PUBLIC KEY-----\n";
+
+static const char eddsa[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MCowBQYDK2VwAyEADt/RHErAxAHxH9FUmsjOhQ2ALl6Y8nE0m3zQxkEE2iM=\n"
+"-----END PUBLIC KEY-----\n";
+
+static const unsigned char eddsa_raw[] = {
+ 0x0e, 0xdf, 0xd1, 0x1c, 0x4a, 0xc0, 0xc4, 0x01,
+ 0xf1, 0x1f, 0xd1, 0x54, 0x9a, 0xc8, 0xce, 0x85,
+ 0x0d, 0x80, 0x2e, 0x5e, 0x98, 0xf2, 0x71, 0x34,
+ 0x9b, 0x7c, 0xd0, 0xc6, 0x41, 0x04, 0xda, 0x23,
+};
+
+static EVP_PKEY *
+EVP_PKEY_from_PEM(const char *ptr, size_t len)
+{
+ BIO *bio = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ if ((bio = BIO_new(BIO_s_mem())) == NULL) {
+ warnx("BIO_new");
+ goto out;
+ }
+ if (len > INT_MAX || BIO_write(bio, ptr, (int)len) != (int)len) {
+ warnx("BIO_write");
+ goto out;
+ }
+ if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL)
+ warnx("PEM_read_bio_PUBKEY");
+out:
+ BIO_free(bio);
+
+ return pkey;
+}
+
+static int
+eddsa_pk_cmp(const char *ptr, size_t len)
+{
+ EVP_PKEY *pkA = NULL;
+ EVP_PKEY *pkB = NULL;
+ eddsa_pk_t *k = NULL;
+ int r, ok = -1;
+
+ if ((pkA = EVP_PKEY_from_PEM(ptr, len)) == NULL) {
+ warnx("EVP_PKEY_from_PEM");
+ goto out;
+ }
+ if ((k = eddsa_pk_new()) == NULL) {
+ warnx("eddsa_pk_new");
+ goto out;
+ }
+ if ((r = eddsa_pk_from_EVP_PKEY(k, pkA)) != FIDO_OK) {
+ warnx("eddsa_pk_from_EVP_PKEY: 0x%x", r);
+ goto out;
+ }
+ if ((pkB = eddsa_pk_to_EVP_PKEY(k)) == NULL) {
+ warnx("eddsa_pk_to_EVP_PKEY");
+ goto out;
+ }
+ if ((r = EVP_PKEY_cmp(pkA, pkB)) != 1) {
+ warnx("EVP_PKEY_cmp: %d", r);
+ goto out;
+ }
+
+ ok = 0;
+out:
+ EVP_PKEY_free(pkA);
+ EVP_PKEY_free(pkB);
+ eddsa_pk_free(&k);
+
+ return ok;
+}
+
+static void
+invalid_key(void)
+{
+ EVP_PKEY *pkey;
+ eddsa_pk_t *pk;
+
+ ASSERT_NOT_NULL((pkey = EVP_PKEY_from_PEM(ecdsa, sizeof(ecdsa))));
+ ASSERT_NOT_NULL((pk = eddsa_pk_new()));
+ ASSERT_INVAL(eddsa_pk_from_EVP_PKEY(pk, pkey));
+
+ EVP_PKEY_free(pkey);
+ eddsa_pk_free(&pk);
+}
+
+static void
+valid_key(void)
+{
+ EVP_PKEY *pkeyA = NULL;
+ EVP_PKEY *pkeyB = NULL;
+ eddsa_pk_t *pkA = NULL;
+ eddsa_pk_t *pkB = NULL;
+
+#if defined(LIBRESSL_VERSION_NUMBER)
+ /* incomplete support; test what we can */
+ ASSERT_NULL(EVP_PKEY_from_PEM(eddsa, sizeof(eddsa)));
+ ASSERT_NOT_NULL((pkB = eddsa_pk_new()));
+ ASSERT_INVAL(eddsa_pk_from_ptr(pkB, eddsa_raw, sizeof(eddsa_raw)));
+ ASSERT_NULL(eddsa_pk_to_EVP_PKEY((const eddsa_pk_t *)eddsa_raw));
+ assert(eddsa_pk_cmp(eddsa, sizeof(eddsa)) < 0);
+#else
+ ASSERT_NOT_NULL((pkeyA = EVP_PKEY_from_PEM(eddsa, sizeof(eddsa))));
+ ASSERT_NOT_NULL((pkA = eddsa_pk_new()));
+ ASSERT_NOT_NULL((pkB = eddsa_pk_new()));
+ ASSERT_OK(eddsa_pk_from_EVP_PKEY(pkA, pkeyA));
+ ASSERT_OK(eddsa_pk_from_ptr(pkB, eddsa_raw, sizeof(eddsa_raw)));
+ ASSERT_NOT_NULL((pkeyB = eddsa_pk_to_EVP_PKEY((const eddsa_pk_t *)eddsa_raw)));
+ assert(EVP_PKEY_cmp(pkeyA, pkeyB) == 1);
+ assert(eddsa_pk_cmp(eddsa, sizeof(eddsa)) == 0);
+#endif
+
+ EVP_PKEY_free(pkeyA);
+ EVP_PKEY_free(pkeyB);
+ eddsa_pk_free(&pkA);
+ eddsa_pk_free(&pkB);
+}
+
+int
+main(void)
+{
+ fido_init(0);
+
+ invalid_key();
+ valid_key();
+
+ exit(0);
+}
diff --git a/regress/es256.c b/regress/es256.c
new file mode 100644
index 000000000000..17ef27fd4c98
--- /dev/null
+++ b/regress/es256.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2022 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.
+ */
+
+#undef NDEBUG
+
+#include <assert.h>
+#include <string.h>
+
+#define _FIDO_INTERNAL
+
+#include <fido.h>
+#include <fido/es256.h>
+
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+
+#define ASSERT_NOT_NULL(e) assert((e) != NULL)
+#define ASSERT_NULL(e) assert((e) == NULL)
+#define ASSERT_INVAL(e) assert((e) == FIDO_ERR_INVALID_ARGUMENT)
+#define ASSERT_OK(e) assert((e) == FIDO_OK)
+
+static const char short_x[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAAeeHTZj4LEbt7Czs+u5gEZJfnGE\n"
+"6Z+YLe4AYu7SoGY7IH/2jKifsA7w+lkURL4DL63oEjd3f8foH9bX4eaVug==\n"
+"-----END PUBLIC KEY-----";
+
+static const char short_y[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEL8CWUP1r0tpJ5QmkzLc69O74C/Ti\n"
+"83hTiys/JFNVkp0ArW3pKt5jNRrgWSZYE4S/D3AMtpqifFXz/FLCzJqojQ==\n"
+"-----END PUBLIC KEY-----\n";
+
+static const char p256k1[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEU1y8c0Jg9FGr3vYChpEo9c4dpkijriYM\n"
+"QzU/DeskC89hZjLNH1Sj8ra2MsBlVGGJTNPCZSyx8Jo7ERapxdN7UQ==\n"
+"-----END PUBLIC KEY-----\n";
+
+static const char p256v1[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOwiq14c80b7C1Jzsx5w1zMvk2GgW\n"
+"5kfGMOKXjwF/U+51ZfBDKehs3ivdeXAJBkxIh7E3iA32s+HyNqk+ntl9fg==\n"
+"-----END PUBLIC KEY-----\n";
+
+static const unsigned char p256k1_raw[] = {
+ 0x04, 0x53, 0x5c, 0xbc, 0x73, 0x42, 0x60, 0xf4,
+ 0x51, 0xab, 0xde, 0xf6, 0x02, 0x86, 0x91, 0x28,
+ 0xf5, 0xce, 0x1d, 0xa6, 0x48, 0xa3, 0xae, 0x26,
+ 0x0c, 0x43, 0x35, 0x3f, 0x0d, 0xeb, 0x24, 0x0b,
+ 0xcf, 0x61, 0x66, 0x32, 0xcd, 0x1f, 0x54, 0xa3,
+ 0xf2, 0xb6, 0xb6, 0x32, 0xc0, 0x65, 0x54, 0x61,
+ 0x89, 0x4c, 0xd3, 0xc2, 0x65, 0x2c, 0xb1, 0xf0,
+ 0x9a, 0x3b, 0x11, 0x16, 0xa9, 0xc5, 0xd3, 0x7b,
+ 0x51,
+};
+
+static const unsigned char p256v1_raw[] = {
+ 0x04, 0x3b, 0x08, 0xaa, 0xd7, 0x87, 0x3c, 0xd1,
+ 0xbe, 0xc2, 0xd4, 0x9c, 0xec, 0xc7, 0x9c, 0x35,
+ 0xcc, 0xcb, 0xe4, 0xd8, 0x68, 0x16, 0xe6, 0x47,
+ 0xc6, 0x30, 0xe2, 0x97, 0x8f, 0x01, 0x7f, 0x53,
+ 0xee, 0x75, 0x65, 0xf0, 0x43, 0x29, 0xe8, 0x6c,
+ 0xde, 0x2b, 0xdd, 0x79, 0x70, 0x09, 0x06, 0x4c,
+ 0x48, 0x87, 0xb1, 0x37, 0x88, 0x0d, 0xf6, 0xb3,
+ 0xe1, 0xf2, 0x36, 0xa9, 0x3e, 0x9e, 0xd9, 0x7d,
+ 0x7e,
+};
+
+static EVP_PKEY *
+EVP_PKEY_from_PEM(const char *ptr, size_t len)
+{
+ BIO *bio = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ if ((bio = BIO_new(BIO_s_mem())) == NULL) {
+ warnx("BIO_new");
+ goto out;
+ }
+ if (len > INT_MAX || BIO_write(bio, ptr, (int)len) != (int)len) {
+ warnx("BIO_write");
+ goto out;
+ }
+ if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL)
+ warnx("PEM_read_bio_PUBKEY");
+out:
+ BIO_free(bio);
+
+ return pkey;
+}
+
+static int
+es256_pk_cmp(const char *ptr, size_t len)
+{
+ EVP_PKEY *pkA = NULL;
+ EVP_PKEY *pkB = NULL;
+ es256_pk_t *k = NULL;
+ int r, ok = -1;
+
+ if ((pkA = EVP_PKEY_from_PEM(ptr, len)) == NULL) {
+ warnx("EVP_PKEY_from_PEM");
+ goto out;
+ }
+ if ((k = es256_pk_new()) == NULL) {
+ warnx("es256_pk_new");
+ goto out;
+ }
+ if ((r = es256_pk_from_EVP_PKEY(k, pkA)) != FIDO_OK) {
+ warnx("es256_pk_from_EVP_PKEY: 0x%x", r);
+ goto out;
+ }
+ if ((pkB = es256_pk_to_EVP_PKEY(k)) == NULL) {
+ warnx("es256_pk_to_EVP_PKEY");
+ goto out;
+ }
+ if ((r = EVP_PKEY_cmp(pkA, pkB)) != 1) {
+ warnx("EVP_PKEY_cmp: %d", r);
+ goto out;
+ }
+
+ ok = 0;
+out:
+ EVP_PKEY_free(pkA);
+ EVP_PKEY_free(pkB);
+ es256_pk_free(&k);
+
+ return ok;
+}
+
+static void
+short_coord(void)
+{
+ assert(es256_pk_cmp(short_x, sizeof(short_x)) == 0);
+ assert(es256_pk_cmp(short_y, sizeof(short_y)) == 0);
+}
+
+static void
+invalid_curve(const unsigned char *raw, size_t raw_len)
+{
+ EVP_PKEY *pkey;
+ es256_pk_t *pk;
+
+ ASSERT_NOT_NULL((pkey = EVP_PKEY_from_PEM(p256k1, sizeof(p256k1))));
+ ASSERT_NOT_NULL((pk = es256_pk_new()));
+ ASSERT_INVAL(es256_pk_from_EVP_PKEY(pk, pkey));
+ ASSERT_INVAL(es256_pk_from_ptr(pk, raw, raw_len));
+ ASSERT_NULL(es256_pk_to_EVP_PKEY((const es256_pk_t *)raw));
+
+ EVP_PKEY_free(pkey);
+ es256_pk_free(&pk);
+}
+
+static void
+full_coord(void)
+{
+ assert(es256_pk_cmp(p256v1, sizeof(p256v1)) == 0);
+}
+
+static void
+valid_curve(const unsigned char *raw, size_t raw_len)
+{
+ EVP_PKEY *pkeyA;
+ EVP_PKEY *pkeyB;
+ es256_pk_t *pkA;
+ es256_pk_t *pkB;
+
+ ASSERT_NOT_NULL((pkeyA = EVP_PKEY_from_PEM(p256v1, sizeof(p256v1))));
+ ASSERT_NOT_NULL((pkA = es256_pk_new()));
+ ASSERT_NOT_NULL((pkB = es256_pk_new()));
+ ASSERT_OK(es256_pk_from_EVP_PKEY(pkA, pkeyA));
+ ASSERT_OK(es256_pk_from_ptr(pkB, raw, raw_len));
+ ASSERT_NOT_NULL((pkeyB = es256_pk_to_EVP_PKEY(pkB)));
+ assert(EVP_PKEY_cmp(pkeyA, pkeyB) == 1);
+
+ EVP_PKEY_free(pkeyA);
+ EVP_PKEY_free(pkeyB);
+ es256_pk_free(&pkA);
+ es256_pk_free(&pkB);
+}
+
+int
+main(void)
+{
+ fido_init(0);
+
+ short_coord();
+ full_coord();
+
+ invalid_curve(p256k1_raw, sizeof(p256k1_raw)); /* uncompressed */
+ invalid_curve(p256k1_raw + 1, sizeof(p256k1_raw) - 1); /* libfido2 */
+ valid_curve(p256v1_raw, sizeof(p256v1_raw)); /* uncompressed */
+ valid_curve(p256v1_raw + 1, sizeof(p256v1_raw) - 1); /* libfido2 */
+
+ exit(0);
+}
diff --git a/regress/rs256.c b/regress/rs256.c
new file mode 100644
index 000000000000..f6e685a11da8
--- /dev/null
+++ b/regress/rs256.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2022 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.
+ */
+
+#undef NDEBUG
+
+#include <assert.h>
+#include <string.h>
+
+#define _FIDO_INTERNAL
+
+#include <fido.h>
+#include <fido/rs256.h>
+
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+
+#define ASSERT_NOT_NULL(e) assert((e) != NULL)
+#define ASSERT_NULL(e) assert((e) == NULL)
+#define ASSERT_INVAL(e) assert((e) == FIDO_ERR_INVALID_ARGUMENT)
+#define ASSERT_OK(e) assert((e) == FIDO_OK)
+
+static char rsa1024[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCw92gn9Ku/bEfFj1AutaZyltpf\n"
+"zzXrg70kQFymNq+spMt/HlxKiImw8TZU08zWW4ZLE/Ch4JYjMW6ETAdQFhSC63Ih\n"
+"Wecui0JJ1f+2CsUVg+h7lO1877LZYUpdNiJrbqMb5Yc4N3FPtvdl3NoLIIQsF76H\n"
+"VRvpjQgkWipRfZ97JQIDAQAB\n"
+"-----END PUBLIC KEY-----";
+
+static char rsa2048[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApvIq/55ZodBIxzo/8BnE\n"
+"UQN1fo1hmJ6V20hQHSzJq5tHyxRCcvKikuJ1ZvR4RdZlEzdTdbEfMBdZ8sxve0/U\n"
+"yYEjH92CG0vgTCYuUaFLJTaWZSvWa96G8Lw+V4VyNFDRCM7sflOaSVH5pAsz8OEc\n"
+"TLZfM4NhnDsJAM+mQ6X7Tza0sczPchgDA+9KByXo/VIqyuBQs17rlKC2reMa8NkY\n"
+"rBRQZJLNzi68d5/BHH1flGWE1l8wJ9dr1Ex93H/KdzX+7/28TWUC98nneUo8RfRx\n"
+"FwUt/EInDMHOORCaCHSs28U/9IUyMjqLB1rxKhIp09yGXMiTrrT+p+Pcn8dO01HT\n"
+"vQIDAQAB\n"
+"-----END PUBLIC KEY-----";
+
+static char rsa3072[] = \
+"-----BEGIN PUBLIC KEY-----\n"
+"MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAwZunKrMs/o92AniLPNTF\n"
+"Ta4EYfhy5NDmMvQvRFT/eTYItLrOTPmYMap68KLyZYmgz/AdaxAL/992QWre7XTY\n"
+"gqLwtZT+WsSu7xPHWKTTXrlVohKBeLHQ0I7Zy0NSMUxhlJEMrBAjSyFAS86zWm5w\n"
+"ctC3pNCqfUKugA07BVj+d5Mv5fziwgMR86kuhkVuMYfsR4IYwX4+va0pyLzxx624\n"
+"s9nJ107g+A+3MUk4bAto3lruFeeZPUI2AFzFQbGg5By6VtvVi3gKQ7lUNtAr0Onu\n"
+"I6Fb+yz8sbFcvDpJcu5CXW20GrKMVP4KY5pn2LCajWuZjBl/dXWayPfm4UX5Y2O4\n"
+"73tzPpUBNwnEdz79His0v80Vmvjwn5IuF2jAoimrBNPJFFwCCuVNy8kgj2vllk1l\n"
+"RvLOG6hf8VnlDb40QZS3QAQ09xFfF+xlVLb8cHH6wllaAGEM230TrmawpC7xpz4Z\n"
+"sTuwJwI0AWEi//noMsRz2BuF2fCp//aORYJQU2S8kYk3AgMBAAE=\n"
+"-----END PUBLIC KEY-----";
+
+static const unsigned char rsa2048_raw[] = {
+ 0xa6, 0xf2, 0x2a, 0xff, 0x9e, 0x59, 0xa1, 0xd0,
+ 0x48, 0xc7, 0x3a, 0x3f, 0xf0, 0x19, 0xc4, 0x51,
+ 0x03, 0x75, 0x7e, 0x8d, 0x61, 0x98, 0x9e, 0x95,
+ 0xdb, 0x48, 0x50, 0x1d, 0x2c, 0xc9, 0xab, 0x9b,
+ 0x47, 0xcb, 0x14, 0x42, 0x72, 0xf2, 0xa2, 0x92,
+ 0xe2, 0x75, 0x66, 0xf4, 0x78, 0x45, 0xd6, 0x65,
+ 0x13, 0x37, 0x53, 0x75, 0xb1, 0x1f, 0x30, 0x17,
+ 0x59, 0xf2, 0xcc, 0x6f, 0x7b, 0x4f, 0xd4, 0xc9,
+ 0x81, 0x23, 0x1f, 0xdd, 0x82, 0x1b, 0x4b, 0xe0,
+ 0x4c, 0x26, 0x2e, 0x51, 0xa1, 0x4b, 0x25, 0x36,
+ 0x96, 0x65, 0x2b, 0xd6, 0x6b, 0xde, 0x86, 0xf0,
+ 0xbc, 0x3e, 0x57, 0x85, 0x72, 0x34, 0x50, 0xd1,
+ 0x08, 0xce, 0xec, 0x7e, 0x53, 0x9a, 0x49, 0x51,
+ 0xf9, 0xa4, 0x0b, 0x33, 0xf0, 0xe1, 0x1c, 0x4c,
+ 0xb6, 0x5f, 0x33, 0x83, 0x61, 0x9c, 0x3b, 0x09,
+ 0x00, 0xcf, 0xa6, 0x43, 0xa5, 0xfb, 0x4f, 0x36,
+ 0xb4, 0xb1, 0xcc, 0xcf, 0x72, 0x18, 0x03, 0x03,
+ 0xef, 0x4a, 0x07, 0x25, 0xe8, 0xfd, 0x52, 0x2a,
+ 0xca, 0xe0, 0x50, 0xb3, 0x5e, 0xeb, 0x94, 0xa0,
+ 0xb6, 0xad, 0xe3, 0x1a, 0xf0, 0xd9, 0x18, 0xac,
+ 0x14, 0x50, 0x64, 0x92, 0xcd, 0xce, 0x2e, 0xbc,
+ 0x77, 0x9f, 0xc1, 0x1c, 0x7d, 0x5f, 0x94, 0x65,
+ 0x84, 0xd6, 0x5f, 0x30, 0x27, 0xd7, 0x6b, 0xd4,
+ 0x4c, 0x7d, 0xdc, 0x7f, 0xca, 0x77, 0x35, 0xfe,
+ 0xef, 0xfd, 0xbc, 0x4d, 0x65, 0x02, 0xf7, 0xc9,
+ 0xe7, 0x79, 0x4a, 0x3c, 0x45, 0xf4, 0x71, 0x17,
+ 0x05, 0x2d, 0xfc, 0x42, 0x27, 0x0c, 0xc1, 0xce,
+ 0x39, 0x10, 0x9a, 0x08, 0x74, 0xac, 0xdb, 0xc5,
+ 0x3f, 0xf4, 0x85, 0x32, 0x32, 0x3a, 0x8b, 0x07,
+ 0x5a, 0xf1, 0x2a, 0x12, 0x29, 0xd3, 0xdc, 0x86,
+ 0x5c, 0xc8, 0x93, 0xae, 0xb4, 0xfe, 0xa7, 0xe3,
+ 0xdc, 0x9f, 0xc7, 0x4e, 0xd3, 0x51, 0xd3, 0xbd,
+ 0x01, 0x00, 0x01,
+};
+
+static EVP_PKEY *
+EVP_PKEY_from_PEM(const char *ptr, size_t len)
+{
+ BIO *bio = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ if ((bio = BIO_new(BIO_s_mem())) == NULL) {
+ warnx("BIO_new");
+ goto out;
+ }
+ if (len > INT_MAX || BIO_write(bio, ptr, (int)len) != (int)len) {
+ warnx("BIO_write");
+ goto out;
+ }
+ if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)) == NULL)
+ warnx("PEM_read_bio_PUBKEY");
+out:
+ BIO_free(bio);
+
+ return pkey;
+}
+
+static int
+rs256_pk_cmp(const char *ptr, size_t len)
+{
+ EVP_PKEY *pkA = NULL;
+ EVP_PKEY *pkB = NULL;
+ rs256_pk_t *k = NULL;
+ int r, ok = -1;
+
+ if ((pkA = EVP_PKEY_from_PEM(ptr, len)) == NULL) {
+ warnx("EVP_PKEY_from_PEM");
+ goto out;
+ }
+ if ((k = rs256_pk_new()) == NULL) {
+ warnx("rs256_pk_new");
+ goto out;
+ }
+ if ((r = rs256_pk_from_EVP_PKEY(k, pkA)) != FIDO_OK) {
+ warnx("rs256_pk_from_EVP_PKEY: 0x%x", r);
+ goto out;
+ }
+ if ((pkB = rs256_pk_to_EVP_PKEY(k)) == NULL) {
+ warnx("rs256_pk_to_EVP_PKEY");
+ goto out;
+ }
+ if ((r = EVP_PKEY_cmp(pkA, pkB)) != 1) {
+ warnx("EVP_PKEY_cmp: %d", r);
+ goto out;
+ }
+
+ ok = 0;
+out:
+ EVP_PKEY_free(pkA);
+ EVP_PKEY_free(pkB);
+ rs256_pk_free(&k);
+
+ return ok;
+}
+
+static void
+invalid_size(const char *pem)
+{
+ EVP_PKEY *pkey;
+ rs256_pk_t *pk;
+
+ ASSERT_NOT_NULL((pkey = EVP_PKEY_from_PEM(pem, strlen(pem))));
+ ASSERT_NOT_NULL((pk = rs256_pk_new()));
+ ASSERT_INVAL(rs256_pk_from_EVP_PKEY(pk, pkey));
+
+ EVP_PKEY_free(pkey);
+ rs256_pk_free(&pk);
+}
+
+static void
+valid_size(const char *pem, const unsigned char *raw, size_t raw_len)
+{
+ EVP_PKEY *pkeyA;
+ EVP_PKEY *pkeyB;
+ rs256_pk_t *pkA;
+ rs256_pk_t *pkB;
+
+ ASSERT_NOT_NULL((pkeyA = EVP_PKEY_from_PEM(pem, strlen(pem))));
+ ASSERT_NOT_NULL((pkA = rs256_pk_new()));
+ ASSERT_NOT_NULL((pkB = rs256_pk_new()));
+ ASSERT_OK(rs256_pk_from_EVP_PKEY(pkA, pkeyA));
+ ASSERT_OK(rs256_pk_from_ptr(pkB, raw, raw_len));
+ ASSERT_NOT_NULL((pkeyB = rs256_pk_to_EVP_PKEY(pkB)));
+ assert(EVP_PKEY_cmp(pkeyA, pkeyB) == 1);
+ assert(rs256_pk_cmp(pem, strlen(pem)) == 0);
+
+ EVP_PKEY_free(pkeyA);
+ EVP_PKEY_free(pkeyB);
+ rs256_pk_free(&pkA);
+ rs256_pk_free(&pkB);
+}
+
+int
+main(void)
+{
+ fido_init(0);
+
+ invalid_size(rsa1024);
+ invalid_size(rsa3072);
+ valid_size(rsa2048, rsa2048_raw, sizeof(rsa2048_raw));
+
+ exit(0);
+}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 796ec69a9dbe..44a87282869e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -33,20 +33,28 @@ list(APPEND FIDO_SOURCES
rs1.c
rs256.c
time.c
+ touch.c
tpm.c
types.c
u2f.c
+ util.c
)
if(FUZZ)
list(APPEND FIDO_SOURCES ../fuzz/clock.c)
+ list(APPEND FIDO_SOURCES ../fuzz/pcsc.c)
list(APPEND FIDO_SOURCES ../fuzz/prng.c)
- list(APPEND FIDO_SOURCES ../fuzz/uniform_random.c)
list(APPEND FIDO_SOURCES ../fuzz/udev.c)
+ list(APPEND FIDO_SOURCES ../fuzz/uniform_random.c)
list(APPEND FIDO_SOURCES ../fuzz/wrap.c)
endif()
+
if(NFC_LINUX)
- list(APPEND FIDO_SOURCES netlink.c nfc_linux.c)
+ list(APPEND FIDO_SOURCES netlink.c nfc.c nfc_linux.c)
+endif()
+
+if(USE_PCSC)
+ list(APPEND FIDO_SOURCES nfc.c pcsc.c)
endif()
if(USE_HIDAPI)
@@ -93,8 +101,15 @@ list(APPEND COMPAT_SOURCES
if(WIN32)
list(APPEND BASE_LIBRARIES wsock32 ws2_32 bcrypt setupapi hid)
+ if(USE_PCSC)
+ list(APPEND BASE_LIBRARIES winscard)
+ endif()
elseif(APPLE)
- list(APPEND BASE_LIBRARIES "-framework CoreFoundation" "-framework IOKit")
+ list(APPEND BASE_LIBRARIES "-framework CoreFoundation"
+ "-framework IOKit")
+ if(USE_PCSC)
+ list(APPEND BASE_LIBRARIES "-framework PCSC")
+ endif()
endif()
list(APPEND TARGET_LIBRARIES
@@ -104,6 +119,7 @@ list(APPEND TARGET_LIBRARIES
${BASE_LIBRARIES}
${HIDAPI_LIBRARIES}
${ZLIB_LIBRARIES}
+ ${PCSC_LIBRARIES}
)
# static library
diff --git a/src/compress.c b/src/compress.c
index ee5501b4a4a1..074bca876489 100644
--- a/src/compress.c
+++ b/src/compress.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Yubico AB. All rights reserved.
+ * Copyright (c) 2020-2022 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.
*/
@@ -9,41 +9,159 @@
#define BOUND (1024UL * 1024UL)
+/* zlib inflate (raw + headers) */
static int
-do_compress(fido_blob_t *out, const fido_blob_t *in, size_t origsiz, int decomp)
+rfc1950_inflate(fido_blob_t *out, const fido_blob_t *in, size_t origsiz)
{
u_long ilen, olen;
- int r;
+ int z;
memset(out, 0, sizeof(*out));
+
if (in->len > ULONG_MAX || (ilen = (u_long)in->len) > BOUND ||
- origsiz > ULONG_MAX || (olen = decomp ? (u_long)origsiz :
- compressBound(ilen)) > BOUND)
+ origsiz > ULONG_MAX || (olen = (u_long)origsiz) > BOUND) {
+ fido_log_debug("%s: in->len=%zu, origsiz=%zu", __func__,
+ in->len, origsiz);
return FIDO_ERR_INVALID_ARGUMENT;
+ }
+
if ((out->ptr = calloc(1, olen)) == NULL)
return FIDO_ERR_INTERNAL;
out->len = olen;
- if (decomp)
- r = uncompress(out->ptr, &olen, in->ptr, ilen);
- else
- r = compress(out->ptr, &olen, in->ptr, ilen);
- if (r != Z_OK || olen > SIZE_MAX || olen > out->len) {
+
+ if ((z = uncompress(out->ptr, &olen, in->ptr, ilen)) != Z_OK ||
+ olen > SIZE_MAX || olen != out->len) {
+ fido_log_debug("%s: uncompress: %d, olen=%lu, out->len=%zu",
+ __func__, z, olen, out->len);
fido_blob_reset(out);
return FIDO_ERR_COMPRESS;
}
- out->len = olen;
return FIDO_OK;
}
+/* raw inflate */
+static int
+rfc1951_inflate(fido_blob_t *out, const fido_blob_t *in, size_t origsiz)
+{
+ z_stream zs;
+ u_int ilen, olen;
+ int r, z;
+
+ memset(&zs, 0, sizeof(zs));
+ memset(out, 0, sizeof(*out));
+
+ if (in->len > UINT_MAX || (ilen = (u_int)in->len) > BOUND ||
+ origsiz > UINT_MAX || (olen = (u_int)origsiz) > BOUND) {
+ fido_log_debug("%s: in->len=%zu, origsiz=%zu", __func__,
+ in->len, origsiz);
+ return FIDO_ERR_INVALID_ARGUMENT;
+ }
+ if ((z = inflateInit2(&zs, -MAX_WBITS)) != Z_OK) {
+ fido_log_debug("%s: inflateInit2: %d", __func__, z);
+ return FIDO_ERR_COMPRESS;
+ }
+
+ if ((out->ptr = calloc(1, olen)) == NULL) {
+ r = FIDO_ERR_INTERNAL;
+ goto fail;
+ }
+ out->len = olen;
+ zs.next_in = in->ptr;
+ zs.avail_in = ilen;
+ zs.next_out = out->ptr;
+ zs.avail_out = olen;
+
+ if ((z = inflate(&zs, Z_FINISH)) != Z_STREAM_END) {
+ fido_log_debug("%s: inflate: %d", __func__, z);
+ r = FIDO_ERR_COMPRESS;
+ goto fail;
+ }
+ if (zs.avail_out != 0) {
+ fido_log_debug("%s: %u != 0", __func__, zs.avail_out);
+ r = FIDO_ERR_COMPRESS;
+ goto fail;
+ }
+
+ r = FIDO_OK;
+fail:
+ if ((z = inflateEnd(&zs)) != Z_OK) {
+ fido_log_debug("%s: inflateEnd: %d", __func__, z);
+ r = FIDO_ERR_COMPRESS;
+ }
+ if (r != FIDO_OK)
+ fido_blob_reset(out);
+
+ return r;
+}
+
+/* raw deflate */
+static int
+rfc1951_deflate(fido_blob_t *out, const fido_blob_t *in)
+{
+ z_stream zs;
+ u_int ilen, olen;
+ int r, z;
+
+ memset(&zs, 0, sizeof(zs));
+ memset(out, 0, sizeof(*out));
+
+ if (in->len > UINT_MAX || (ilen = (u_int)in->len) > BOUND) {
+ fido_log_debug("%s: in->len=%zu", __func__, in->len);
+ return FIDO_ERR_INVALID_ARGUMENT;
+ }
+ if ((z = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
+ -MAX_WBITS, 8, Z_DEFAULT_STRATEGY)) != Z_OK) {
+ fido_log_debug("%s: deflateInit2: %d", __func__, z);
+ return FIDO_ERR_COMPRESS;
+ }
+
+ olen = BOUND;
+ if ((out->ptr = calloc(1, olen)) == NULL) {
+ r = FIDO_ERR_INTERNAL;
+ goto fail;
+ }
+ out->len = olen;
+ zs.next_in = in->ptr;
+ zs.avail_in = ilen;
+ zs.next_out = out->ptr;
+ zs.avail_out = olen;
+
+ if ((z = deflate(&zs, Z_FINISH)) != Z_STREAM_END) {
+ fido_log_debug("%s: inflate: %d", __func__, z);
+ r = FIDO_ERR_COMPRESS;
+ goto fail;
+ }
+ if (zs.avail_out >= out->len) {
+ fido_log_debug("%s: %u > %zu", __func__, zs.avail_out,
+ out->len);
+ r = FIDO_ERR_COMPRESS;
+ goto fail;
+ }
+ out->len -= zs.avail_out;
+
+ r = FIDO_OK;
+fail:
+ if ((z = deflateEnd(&zs)) != Z_OK) {
+ fido_log_debug("%s: deflateEnd: %d", __func__, z);
+ r = FIDO_ERR_COMPRESS;
+ }
+ if (r != FIDO_OK)
+ fido_blob_reset(out);
+
+ return r;
+}
+
int
fido_compress(fido_blob_t *out, const fido_blob_t *in)
{
- return do_compress(out, in, 0, 0);
+ return rfc1951_deflate(out, in);
}
int
fido_uncompress(fido_blob_t *out, const fido_blob_t *in, size_t origsiz)
{
- return do_compress(out, in, origsiz, 1);
+ if (rfc1950_inflate(out, in, origsiz) == FIDO_OK)
+ return FIDO_OK; /* backwards compat with libfido2 < 1.11 */
+ return rfc1951_inflate(out, in, origsiz);
}
diff --git a/src/dev.c b/src/dev.c
index fb8faba0a06c..635e41714759 100644
--- a/src/dev.c
+++ b/src/dev.c
@@ -1,37 +1,17 @@
/*
- * Copyright (c) 2018 Yubico AB. All rights reserved.
+ * Copyright (c) 2018-2022 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 <openssl/sha.h>
#include "fido.h"
#ifndef TLS
#define TLS
#endif
-typedef struct dev_manifest_func_node {
- dev_manifest_func_t manifest_func;
- struct dev_manifest_func_node *next;
-} dev_manifest_func_node_t;
-
-static TLS dev_manifest_func_node_t *manifest_funcs = NULL;
static TLS bool disable_u2f_fallback;
-static void
-find_manifest_func_node(dev_manifest_func_t f, dev_manifest_func_node_t **curr,
- dev_manifest_func_node_t **prev)
-{
- *prev = NULL;
- *curr = manifest_funcs;
-
- while (*curr != NULL && (*curr)->manifest_func != f) {
- *prev = *curr;
- *curr = (*curr)->next;
- }
-}
-
#ifdef FIDO_FUZZ
static void
set_random_report_len(fido_dev_t *dev)
@@ -63,13 +43,15 @@ fido_dev_set_option_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
for (size_t i = 0; i < len; i++)
if (strcmp(ptr[i], "clientPin") == 0) {
- dev->flags |= val[i] ? FIDO_DEV_PIN_SET : FIDO_DEV_PIN_UNSET;
+ dev->flags |= val[i] ?
+ FIDO_DEV_PIN_SET : FIDO_DEV_PIN_UNSET;
} else if (strcmp(ptr[i], "credMgmt") == 0 ||
strcmp(ptr[i], "credentialMgmtPreview") == 0) {
if (val[i])
dev->flags |= FIDO_DEV_CREDMAN;
} else if (strcmp(ptr[i], "uv") == 0) {
- dev->flags |= val[i] ? FIDO_DEV_UV_SET : FIDO_DEV_UV_UNSET;
+ dev->flags |= val[i] ?
+ FIDO_DEV_UV_SET : FIDO_DEV_UV_UNSET;
} else if (strcmp(ptr[i], "pinUvAuthToken") == 0) {
if (val[i])
dev->flags |= FIDO_DEV_TOKEN_PERMS;
@@ -257,75 +239,40 @@ fido_dev_open_wait(fido_dev_t *dev, const char *path, int *ms)
return (FIDO_OK);
}
-int
-fido_dev_register_manifest_func(const dev_manifest_func_t f)
-{
- dev_manifest_func_node_t *prev, *curr, *n;
-
- find_manifest_func_node(f, &curr, &prev);
- if (curr != NULL)
- return (FIDO_OK);
-
- if ((n = calloc(1, sizeof(*n))) == NULL) {
- fido_log_debug("%s: calloc", __func__);
- return (FIDO_ERR_INTERNAL);
- }
-
- n->manifest_func = f;
- n->next = manifest_funcs;
- manifest_funcs = n;
-
- return (FIDO_OK);
-}
-
-void
-fido_dev_unregister_manifest_func(const dev_manifest_func_t f)
+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 *))
{
- dev_manifest_func_node_t *prev, *curr;
+ size_t ndevs = 0;
+ int r;
- find_manifest_func_node(f, &curr, &prev);
- if (curr == NULL)
+ if (*olen >= ilen) {
+ fido_log_debug("%s: skipping %s", __func__, type);
return;
- if (prev != NULL)
- prev->next = curr->next;
- else
- manifest_funcs = curr->next;
-
- free(curr);
+ }
+ 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;
}
int
fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
{
- dev_manifest_func_node_t *curr = NULL;
- dev_manifest_func_t m_func;
- size_t curr_olen;
- int r;
-
*olen = 0;
- if (fido_dev_register_manifest_func(fido_hid_manifest) != FIDO_OK)
- return (FIDO_ERR_INTERNAL);
-#ifdef NFC_LINUX
- if (fido_dev_register_manifest_func(fido_nfc_manifest) != FIDO_OK)
- return (FIDO_ERR_INTERNAL);
+ run_manifest(devlist, ilen, olen, "hid", fido_hid_manifest);
+#ifdef USE_NFC
+ run_manifest(devlist, ilen, olen, "nfc", fido_nfc_manifest);
+#endif
+#ifdef USE_PCSC
+ run_manifest(devlist, ilen, olen, "pcsc", fido_pcsc_manifest);
#endif
#ifdef USE_WINHELLO
- if (fido_dev_register_manifest_func(fido_winhello_manifest) != FIDO_OK)
- return (FIDO_ERR_INTERNAL);
+ run_manifest(devlist, ilen, olen, "winhello", fido_winhello_manifest);
#endif
- for (curr = manifest_funcs; curr != NULL; curr = curr->next) {
- curr_olen = 0;
- m_func = curr->manifest_func;
- r = m_func(devlist + *olen, ilen - *olen, &curr_olen);
- if (r != FIDO_OK)
- return (r);
- *olen += curr_olen;
- if (*olen == ilen)
- break;
- }
-
return (FIDO_OK);
}
@@ -345,19 +292,16 @@ fido_dev_open(fido_dev_t *dev, const char *path)
{
int ms = dev->timeout_ms;
-#ifdef NFC_LINUX
- if (strncmp(path, FIDO_NFC_PREFIX, strlen(FIDO_NFC_PREFIX)) == 0) {
- dev->io_own = true;
- dev->io = (fido_dev_io_t) {
- fido_nfc_open,
- fido_nfc_close,
- fido_nfc_read,
- fido_nfc_write,
- };
- dev->transport = (fido_dev_transport_t) {
- fido_nfc_rx,
- fido_nfc_tx,
- };
+#ifdef USE_NFC
+ if (fido_is_nfc(path) && fido_dev_set_nfc(dev) < 0) {
+ fido_log_debug("%s: fido_dev_set_nfc", __func__);
+ return FIDO_ERR_INTERNAL;
+ }
+#endif
+#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
@@ -387,7 +331,7 @@ fido_dev_set_sigmask(fido_dev_t *dev, const fido_sigset_t *sigmask)
if (dev->io_handle == NULL || sigmask == NULL)
return (FIDO_ERR_INVALID_ARGUMENT);
-#ifdef NFC_LINUX
+#ifdef USE_NFC
if (dev->transport.rx == fido_nfc_rx && dev->io.read == fido_nfc_read)
return (fido_nfc_set_sigmask(dev->io_handle, sigmask));
#endif
@@ -415,106 +359,6 @@ fido_dev_cancel(fido_dev_t *dev)
}
int
-fido_dev_get_touch_begin(fido_dev_t *dev)
-{
- fido_blob_t f;
- cbor_item_t *argv[9];
- const char *clientdata = FIDO_DUMMY_CLIENTDATA;
- const uint8_t user_id = FIDO_DUMMY_USER_ID;
- unsigned char cdh[SHA256_DIGEST_LENGTH];
- fido_rp_t rp;
- fido_user_t user;
- int ms = dev->timeout_ms;
- int r = FIDO_ERR_INTERNAL;
-
- memset(&f, 0, sizeof(f));
- memset(argv, 0, sizeof(argv));
- memset(cdh, 0, sizeof(cdh));
- memset(&rp, 0, sizeof(rp));
- memset(&user, 0, sizeof(user));
-
- if (fido_dev_is_fido2(dev) == false)
- return (u2f_get_touch_begin(dev, &ms));
-
- if (SHA256((const void *)clientdata, strlen(clientdata), cdh) != cdh) {
- fido_log_debug("%s: sha256", __func__);
- return (FIDO_ERR_INTERNAL);
- }
-
- if ((rp.id = strdup(FIDO_DUMMY_RP_ID)) == NULL ||
- (user.name = strdup(FIDO_DUMMY_USER_NAME)) == NULL) {
- fido_log_debug("%s: strdup", __func__);
- goto fail;
- }
-
- if (fido_blob_set(&user.id, &user_id, sizeof(user_id)) < 0) {
- fido_log_debug("%s: fido_blob_set", __func__);
- goto fail;
- }
-
- if ((argv[0] = cbor_build_bytestring(cdh, sizeof(cdh))) == NULL ||
- (argv[1] = cbor_encode_rp_entity(&rp)) == NULL ||
- (argv[2] = cbor_encode_user_entity(&user)) == NULL ||
- (argv[3] = cbor_encode_pubkey_param(COSE_ES256)) == NULL) {
- fido_log_debug("%s: cbor encode", __func__);
- goto fail;
- }
-
- if (fido_dev_supports_pin(dev)) {
- if ((argv[7] = cbor_new_definite_bytestring()) == NULL ||
- (argv[8] = cbor_encode_pin_opt(dev)) == NULL) {
- fido_log_debug("%s: cbor encode", __func__);
- goto fail;
- }
- }
-
- if (cbor_build_frame(CTAP_CBOR_MAKECRED, argv, nitems(argv), &f) < 0 ||
- fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, &ms) < 0) {
- fido_log_debug("%s: fido_tx", __func__);
- r = FIDO_ERR_TX;
- goto fail;
- }
-
- r = FIDO_OK;
-fail:
- cbor_vector_free(argv, nitems(argv));
- free(f.ptr);
- free(rp.id);
- free(user.name);
- free(user.id.ptr);
-
- return (r);
-}
-
-int
-fido_dev_get_touch_status(fido_dev_t *dev, int *touched, int ms)
-{
- int r;
-
- *touched = 0;
-
- if (fido_dev_is_fido2(dev) == false)
- return (u2f_get_touch_status(dev, touched, &ms));
-
- switch ((r = fido_rx_cbor_status(dev, &ms))) {
- case FIDO_ERR_PIN_AUTH_INVALID:
- case FIDO_ERR_PIN_INVALID:
- case FIDO_ERR_PIN_NOT_SET:
- case FIDO_ERR_SUCCESS:
- *touched = 1;
- break;
- case FIDO_ERR_RX:
- /* ignore */
- break;
- default:
- fido_log_debug("%s: fido_rx_cbor_status", __func__);
- return (r);
- }
-
- return (FIDO_OK);
-}
-
-int
fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io)
{
if (dev->io_handle != NULL) {
diff --git a/src/eddsa.c b/src/eddsa.c
index a7b4f4f900ce..a94ae3023917 100644
--- a/src/eddsa.c
+++ b/src/eddsa.c
@@ -122,11 +122,20 @@ eddsa_pk_free(eddsa_pk_t **pkp)
int
eddsa_pk_from_ptr(eddsa_pk_t *pk, const void *ptr, size_t len)
{
+ EVP_PKEY *pkey;
+
if (len < sizeof(*pk))
return (FIDO_ERR_INVALID_ARGUMENT);
memcpy(pk, ptr, sizeof(*pk));
+ if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) {
+ fido_log_debug("%s: eddsa_pk_to_EVP_PKEY", __func__);
+ return (FIDO_ERR_INVALID_ARGUMENT);
+ }
+
+ EVP_PKEY_free(pkey);
+
return (FIDO_OK);
}
@@ -147,6 +156,8 @@ eddsa_pk_from_EVP_PKEY(eddsa_pk_t *pk, const EVP_PKEY *pkey)
{
size_t len = 0;
+ if (EVP_PKEY_base_id(pkey) != EVP_PKEY_ED25519)
+ return (FIDO_ERR_INVALID_ARGUMENT);
if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1 ||
len != sizeof(pk->x))
return (FIDO_ERR_INTERNAL);
diff --git a/src/es256.c b/src/es256.c
index eb4cc63525aa..4d6e86f8a26d 100644
--- a/src/es256.c
+++ b/src/es256.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2021 Yubico AB. All rights reserved.
+ * Copyright (c) 2018-2022 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.
*/
@@ -11,6 +11,14 @@
#include "fido.h"
#include "fido/es256.h"
+#if OPENSSL_VERSION_NUMBER >= 0x30000000
+#define get0_EC_KEY(x) EVP_PKEY_get0_EC_KEY((x))
+#else
+#define get0_EC_KEY(x) EVP_PKEY_get0((x))
+#endif
+
+static const int es256_nid = NID_X9_62_prime256v1;
+
static int
decode_coord(const cbor_item_t *item, void *xy, size_t xy_len)
{
@@ -170,7 +178,8 @@ es256_pk_free(es256_pk_t **pkp)
int
es256_pk_from_ptr(es256_pk_t *pk, const void *ptr, size_t len)
{
- const uint8_t *p = ptr;
+ const uint8_t *p = ptr;
+ EVP_PKEY *pkey;
if (len < sizeof(*pk))
return (FIDO_ERR_INVALID_ARGUMENT);
@@ -180,6 +189,14 @@ es256_pk_from_ptr(es256_pk_t *pk, const void *ptr, size_t len)
else
memcpy(pk, ptr, sizeof(*pk)); /* libfido2 x||y format */
+ if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) {
+ fido_log_debug("%s: es256_pk_to_EVP_PKEY", __func__);
+ explicit_bzero(pk, sizeof(*pk));
+ return (FIDO_ERR_INVALID_ARGUMENT);
+ }
+
+ EVP_PKEY_free(pkey);
+
return (FIDO_OK);
}
@@ -208,13 +225,12 @@ es256_sk_create(es256_sk_t *key)
EVP_PKEY *k = NULL;
const EC_KEY *ec;
const BIGNUM *d;
- const int nid = NID_X9_62_prime256v1;
int n;
int ok = -1;
if ((pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL ||
EVP_PKEY_paramgen_init(pctx) <= 0 ||
- EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) <= 0 ||
+ EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, es256_nid) <= 0 ||
EVP_PKEY_paramgen(pctx, &p) <= 0) {
fido_log_debug("%s: EVP_PKEY_paramgen", __func__);
goto fail;
@@ -258,7 +274,6 @@ es256_pk_to_EVP_PKEY(const es256_pk_t *k)
BIGNUM *x = NULL;
BIGNUM *y = NULL;
const EC_GROUP *g = NULL;
- const int nid = NID_X9_62_prime256v1;
int ok = -1;
if ((bnctx = BN_CTX_new()) == NULL)
@@ -276,7 +291,7 @@ es256_pk_to_EVP_PKEY(const es256_pk_t *k)
goto fail;
}
- if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL ||
+ if ((ec = EC_KEY_new_by_curve_name(es256_nid)) == NULL ||
(g = EC_KEY_get0_group(ec)) == NULL) {
fido_log_debug("%s: EC_KEY init", __func__);
goto fail;
@@ -324,12 +339,15 @@ es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec)
BIGNUM *x = NULL;
BIGNUM *y = NULL;
const EC_POINT *q = NULL;
- const EC_GROUP *g = NULL;
+ EC_GROUP *g = NULL;
+ size_t dx;
+ size_t dy;
int ok = FIDO_ERR_INTERNAL;
- int n;
+ int nx;
+ int ny;
if ((q = EC_KEY_get0_public_key(ec)) == NULL ||
- (g = EC_KEY_get0_group(ec)) == NULL ||
+ (g = EC_GROUP_new_by_curve_name(es256_nid)) == NULL ||
(bnctx = BN_CTX_new()) == NULL)
goto fail;
@@ -339,22 +357,33 @@ es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec)
(y = BN_CTX_get(bnctx)) == NULL)
goto fail;
+ if (EC_POINT_is_on_curve(g, q, bnctx) != 1) {
+ fido_log_debug("%s: EC_POINT_is_on_curve", __func__);
+ ok = FIDO_ERR_INVALID_ARGUMENT;
+ goto fail;
+ }
+
if (EC_POINT_get_affine_coordinates_GFp(g, q, x, y, bnctx) == 0 ||
- (n = BN_num_bytes(x)) < 0 || (size_t)n > sizeof(pk->x) ||
- (n = BN_num_bytes(y)) < 0 || (size_t)n > sizeof(pk->y)) {
+ (nx = BN_num_bytes(x)) < 0 || (size_t)nx > sizeof(pk->x) ||
+ (ny = BN_num_bytes(y)) < 0 || (size_t)ny > sizeof(pk->y)) {
fido_log_debug("%s: EC_POINT_get_affine_coordinates_GFp",
__func__);
goto fail;
}
- if ((n = BN_bn2bin(x, pk->x)) < 0 || (size_t)n > sizeof(pk->x) ||
- (n = BN_bn2bin(y, pk->y)) < 0 || (size_t)n > sizeof(pk->y)) {
+ dx = sizeof(pk->x) - (size_t)nx;
+ dy = sizeof(pk->y) - (size_t)ny;
+
+ if ((nx = BN_bn2bin(x, pk->x + dx)) < 0 || (size_t)nx > sizeof(pk->x) ||
+ (ny = BN_bn2bin(y, pk->y + dy)) < 0 || (size_t)ny > sizeof(pk->y)) {
fido_log_debug("%s: BN_bn2bin", __func__);
goto fail;
}
ok = FIDO_OK;
fail:
+ EC_GROUP_free(g);
+
if (bnctx != NULL) {
BN_CTX_end(bnctx);
BN_CTX_free(bnctx);
@@ -366,10 +395,10 @@ fail:
int
es256_pk_from_EVP_PKEY(es256_pk_t *pk, const EVP_PKEY *pkey)
{
- EC_KEY *ec;
+ const EC_KEY *ec;
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC ||
- (ec = EVP_PKEY_get0(pkey)) == NULL)
+ (ec = get0_EC_KEY(pkey)) == NULL)
return (FIDO_ERR_INVALID_ARGUMENT);
return (es256_pk_from_EC_KEY(pk, ec));
@@ -382,7 +411,6 @@ es256_sk_to_EVP_PKEY(const es256_sk_t *k)
EC_KEY *ec = NULL;
EVP_PKEY *pkey = NULL;
BIGNUM *d = NULL;
- const int nid = NID_X9_62_prime256v1;
int ok = -1;
if ((bnctx = BN_CTX_new()) == NULL)
@@ -396,7 +424,7 @@ es256_sk_to_EVP_PKEY(const es256_sk_t *k)
goto fail;
}
- if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL ||
+ if ((ec = EC_KEY_new_by_curve_name(es256_nid)) == NULL ||
EC_KEY_set_private_key(ec, d) == 0) {
fido_log_debug("%s: EC_KEY_set_private_key", __func__);
goto fail;
@@ -435,11 +463,10 @@ es256_derive_pk(const es256_sk_t *sk, es256_pk_t *pk)
EC_KEY *ec = NULL;
EC_POINT *q = NULL;
const EC_GROUP *g = NULL;
- const int nid = NID_X9_62_prime256v1;
int ok = -1;
if ((d = BN_bin2bn(sk->d, (int)sizeof(sk->d), NULL)) == NULL ||
- (ec = EC_KEY_new_by_curve_name(nid)) == NULL ||
+ (ec = EC_KEY_new_by_curve_name(es256_nid)) == NULL ||
(g = EC_KEY_get0_group(ec)) == NULL ||
(q = EC_POINT_new(g)) == NULL) {
fido_log_debug("%s: get", __func__);
diff --git a/src/export.gnu b/src/export.gnu
index 0a8d46a20fad..8fc94af31c92 100644
--- a/src/export.gnu
+++ b/src/export.gnu
@@ -85,10 +85,11 @@
fido_cbor_info_extensions_len;
fido_cbor_info_extensions_ptr;
fido_cbor_info_free;
- fido_cbor_info_maxmsgsiz;
fido_cbor_info_maxcredbloblen;
fido_cbor_info_maxcredcntlst;
fido_cbor_info_maxcredidlen;
+ fido_cbor_info_maxlargeblob;
+ fido_cbor_info_maxmsgsiz;
fido_cbor_info_fwversion;
fido_cbor_info_new;
fido_cbor_info_options_len;
diff --git a/src/export.llvm b/src/export.llvm
index 80507346edee..df9a667f7477 100644
--- a/src/export.llvm
+++ b/src/export.llvm
@@ -83,10 +83,11 @@ _fido_cbor_info_algorithm_type
_fido_cbor_info_extensions_len
_fido_cbor_info_extensions_ptr
_fido_cbor_info_free
-_fido_cbor_info_maxmsgsiz
_fido_cbor_info_maxcredbloblen
_fido_cbor_info_maxcredcntlst
_fido_cbor_info_maxcredidlen
+_fido_cbor_info_maxlargeblob
+_fido_cbor_info_maxmsgsiz
_fido_cbor_info_fwversion
_fido_cbor_info_new
_fido_cbor_info_options_len
diff --git a/src/export.msvc b/src/export.msvc
index 14602164fd45..a9082152f5cc 100644
--- a/src/export.msvc
+++ b/src/export.msvc
@@ -84,10 +84,11 @@ fido_cbor_info_algorithm_type
fido_cbor_info_extensions_len
fido_cbor_info_extensions_ptr
fido_cbor_info_free
-fido_cbor_info_maxmsgsiz
fido_cbor_info_maxcredbloblen
fido_cbor_info_maxcredcntlst
fido_cbor_info_maxcredidlen
+fido_cbor_info_maxlargeblob
+fido_cbor_info_maxmsgsiz
fido_cbor_info_fwversion
fido_cbor_info_new
fido_cbor_info_options_len
diff --git a/src/extern.h b/src/extern.h
index 6f86d7642950..84536d58b6f8 100644
--- a/src/extern.h
+++ b/src/extern.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2021 Yubico AB. All rights reserved.
+ * Copyright (c) 2018-2022 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.
*/
@@ -118,6 +118,7 @@ size_t fido_hid_report_in_len(void *);
size_t fido_hid_report_out_len(void *);
/* nfc i/o */
+bool fido_is_nfc(const char *);
void *fido_nfc_open(const char *);
void fido_nfc_close(void *);
int fido_nfc_read(void *, unsigned char *, size_t, int);
@@ -125,6 +126,17 @@ int fido_nfc_write(void *, const unsigned char *, size_t);
int fido_nfc_rx(fido_dev_t *, uint8_t, unsigned char *, size_t, int);
int fido_nfc_tx(fido_dev_t *, uint8_t, const unsigned char *, size_t);
int fido_nfc_set_sigmask(void *, const fido_sigset_t *);
+int fido_dev_set_nfc(fido_dev_t *);
+
+/* pcsc i/o */
+bool fido_is_pcsc(const char *);
+void *fido_pcsc_open(const char *);
+void fido_pcsc_close(void *);
+int fido_pcsc_read(void *, unsigned char *, size_t, int);
+int fido_pcsc_write(void *, const unsigned char *, size_t);
+int fido_pcsc_rx(fido_dev_t *, uint8_t, unsigned char *, size_t, int);
+int fido_pcsc_tx(fido_dev_t *, uint8_t, const unsigned char *, size_t);
+int fido_dev_set_pcsc(fido_dev_t *);
/* windows hello */
int fido_winhello_manifest(fido_dev_info_t *, size_t, size_t *);
@@ -200,6 +212,7 @@ int fido_get_random(void *, size_t);
int fido_sha256(fido_blob_t *, const u_char *, size_t);
int fido_time_now(struct timespec *);
int fido_time_delta(const struct timespec *, int *);
+int fido_to_uint64(const char *, int, uint64_t *);
/* crypto */
int es256_verify_sig(const fido_blob_t *, EVP_PKEY *, const fido_blob_t *);
@@ -220,11 +233,7 @@ int fido_get_signed_hash_tpm(fido_blob_t *, const fido_blob_t *,
/* device manifest functions */
int fido_hid_manifest(fido_dev_info_t *, size_t, size_t *);
int fido_nfc_manifest(fido_dev_info_t *, size_t, size_t *);
-
-/* device manifest registration */
-typedef int (*dev_manifest_func_t)(fido_dev_info_t *, size_t, size_t *);
-int fido_dev_register_manifest_func(const dev_manifest_func_t);
-void fido_dev_unregister_manifest_func(const dev_manifest_func_t);
+int fido_pcsc_manifest(fido_dev_info_t *, size_t, size_t *);
/* fuzzing instrumentation */
#ifdef FIDO_FUZZ
@@ -250,6 +259,7 @@ uint32_t uniform_random(uint32_t);
#define FIDO_DUMMY_USER_ID 1
#define FIDO_WINHELLO_PATH "windows://hello"
#define FIDO_NFC_PREFIX "nfc:"
+#define FIDO_PCSC_PREFIX "pcsc:"
#ifdef __cplusplus
} /* extern "C" */
diff --git a/src/fido.h b/src/fido.h
index 4bd2aeebfccb..63d6de87b5aa 100644
--- a/src/fido.h
+++ b/src/fido.h
@@ -144,7 +144,9 @@ int fido_cred_set_user(fido_cred_t *, const unsigned char *, size_t,
int fido_cred_set_x509(fido_cred_t *, const unsigned char *, size_t);
int fido_cred_verify(const fido_cred_t *);
int fido_cred_verify_self(const fido_cred_t *);
+#ifdef _FIDO_SIGSET_DEFINED
int fido_dev_set_sigmask(fido_dev_t *, const fido_sigset_t *);
+#endif
int fido_dev_cancel(fido_dev_t *);
int fido_dev_close(fido_dev_t *);
int fido_dev_get_assert(fido_dev_t *, fido_assert_t *, const char *);
@@ -205,10 +207,11 @@ uint8_t fido_dev_build(const fido_dev_t *);
uint8_t fido_dev_flags(const fido_dev_t *);
int16_t fido_dev_info_vendor(const fido_dev_info_t *);
int16_t fido_dev_info_product(const fido_dev_info_t *);
-uint64_t fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *);
uint64_t fido_cbor_info_maxcredbloblen(const fido_cbor_info_t *);
uint64_t fido_cbor_info_maxcredcntlst(const fido_cbor_info_t *);
uint64_t fido_cbor_info_maxcredidlen(const fido_cbor_info_t *);
+uint64_t fido_cbor_info_maxlargeblob(const fido_cbor_info_t *);
+uint64_t fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *);
uint64_t fido_cbor_info_fwversion(const fido_cbor_info_t *);
bool fido_dev_has_pin(const fido_dev_t *);
diff --git a/src/fido/types.h b/src/fido/types.h
index 4a216b4b9786..593a6a6b4813 100644
--- a/src/fido/types.h
+++ b/src/fido/types.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018 Yubico AB. All rights reserved.
+ * Copyright (c) 2018-2022 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.
*/
@@ -48,10 +48,14 @@ typedef enum {
typedef void fido_log_handler_t(const char *);
+#undef _FIDO_SIGSET_DEFINED
+#define _FIDO_SIGSET_DEFINED
#ifdef _WIN32
typedef int fido_sigset_t;
-#else
+#elif defined(SIG_BLOCK)
typedef sigset_t fido_sigset_t;
+#else
+#undef _FIDO_SIGSET_DEFINED
#endif
#ifdef _FIDO_INTERNAL
@@ -216,18 +220,19 @@ typedef struct fido_algo_array {
} fido_algo_array_t;
typedef struct fido_cbor_info {
- fido_str_array_t versions; /* supported versions: fido2|u2f */
- fido_str_array_t extensions; /* list of supported extensions */
- fido_str_array_t transports; /* list of supported transports */
- unsigned char aaguid[16]; /* aaguid */
- fido_opt_array_t options; /* list of supported options */
- uint64_t maxmsgsiz; /* maximum message size */
- fido_byte_array_t protocols; /* supported pin protocols */
- fido_algo_array_t algorithms; /* list of supported algorithms */
- uint64_t maxcredcntlst; /* max number of credentials in list */
- uint64_t maxcredidlen; /* max credential ID length */
- uint64_t fwversion; /* firmware version */
+ fido_str_array_t versions; /* supported versions: fido2|u2f */
+ fido_str_array_t extensions; /* list of supported extensions */
+ fido_str_array_t transports; /* list of supported transports */
+ unsigned char aaguid[16]; /* aaguid */
+ fido_opt_array_t options; /* list of supported options */
+ uint64_t maxmsgsiz; /* maximum message size */
+ fido_byte_array_t protocols; /* supported pin protocols */
+ fido_algo_array_t algorithms; /* list of supported algorithms */
+ uint64_t maxcredcntlst; /* max credentials in list */
+ uint64_t maxcredidlen; /* max credential ID length */
+ uint64_t fwversion; /* firmware version */
uint64_t maxcredbloblen; /* max credBlob length */
+ uint64_t maxlargeblob; /* max largeBlob array length */
} fido_cbor_info_t;
typedef struct fido_dev_info {
diff --git a/src/hid_freebsd.c b/src/hid_freebsd.c
index 5aefe69c1bec..21e408ffd53f 100644
--- a/src/hid_freebsd.c
+++ b/src/hid_freebsd.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Yubico AB. All rights reserved.
+ * Copyright (c) 2020-2022 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.
*/
@@ -87,8 +87,8 @@ copy_info(fido_dev_info_t *di, const char *path)
ok = 0;
fail:
- if (fd != -1)
- close(fd);
+ if (fd != -1 && close(fd) == -1)
+ fido_log_error(errno, "%s: close %s", __func__, path);
if (ok < 0) {
free(di->path);
@@ -106,8 +106,6 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
char path[64];
size_t i;
- *olen = 0;
-
if (ilen == 0)
return (FIDO_OK); /* nothing to do */
diff --git a/src/hid_openbsd.c b/src/hid_openbsd.c
index d3d3bff0fc8b..2993d10dad9d 100644
--- a/src/hid_openbsd.c
+++ b/src/hid_openbsd.c
@@ -27,14 +27,58 @@ struct hid_openbsd {
const sigset_t *sigmaskp;
};
+static int
+copy_info(fido_dev_info_t *di, const char *path)
+{
+ int fd = -1, ok = -1;
+ struct usb_device_info udi;
+
+ memset(di, 0, sizeof(*di));
+ memset(&udi, 0, sizeof(udi));
+
+ if ((fd = fido_hid_unix_open(path)) == -1)
+ goto fail;
+ if (ioctl(fd, IOCTL_REQ(USB_GET_DEVICEINFO), &udi) == -1) {
+ fido_log_error(errno, "%s: ioctl %s", __func__, path);
+ goto fail;
+ }
+
+ fido_log_debug("%s: %s: bus = 0x%02x, addr = 0x%02x", __func__, path,
+ udi.udi_bus, udi.udi_addr);
+ fido_log_debug("%s: %s: vendor = \"%s\", product = \"%s\"", __func__,
+ path, udi.udi_vendor, udi.udi_product);
+ fido_log_debug("%s: %s: productNo = 0x%04x, vendorNo = 0x%04x, "
+ "releaseNo = 0x%04x", __func__, path, udi.udi_productNo,
+ udi.udi_vendorNo, udi.udi_releaseNo);
+
+ if ((di->path = strdup(path)) == NULL ||
+ (di->manufacturer = strdup(udi.udi_vendor)) == NULL ||
+ (di->product = strdup(udi.udi_product)) == NULL)
+ goto fail;
+
+ di->vendor_id = (int16_t)udi.udi_vendorNo;
+ di->product_id = (int16_t)udi.udi_productNo;
+
+ ok = 0;
+fail:
+ if (fd != -1 && close(fd) == -1)
+ fido_log_error(errno, "%s: close %s", __func__, path);
+
+ if (ok < 0) {
+ free(di->path);
+ free(di->manufacturer);
+ free(di->product);
+ explicit_bzero(di, sizeof(*di));
+ }
+
+ return (ok);
+}
+
int
fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
{
size_t i;
char path[64];
- int fd;
- struct usb_device_info udi;
- fido_dev_info_t *di;
if (ilen == 0)
return (FIDO_OK); /* nothing to do */
@@ -44,50 +88,18 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
for (i = *olen = 0; i < MAX_UHID && *olen < ilen; i++) {
snprintf(path, sizeof(path), "/dev/fido/%zu", i);
- if ((fd = fido_hid_unix_open(path)) == -1)
- continue;
- memset(&udi, 0, sizeof(udi));
- if (ioctl(fd, IOCTL_REQ(USB_GET_DEVICEINFO), &udi) == -1) {
- fido_log_error(errno, "%s: get device info %s",
- __func__, path);
- if (close(fd) == -1)
- fido_log_error(errno, "%s: close", __func__);
- continue;
+ if (copy_info(&devlist[*olen], path) == 0) {
+ devlist[*olen].io = (fido_dev_io_t) {
+ fido_hid_open,
+ fido_hid_close,
+ fido_hid_read,
+ fido_hid_write,
+ };
+ ++(*olen);
}
- if (close(fd) == -1)
- fido_log_error(errno, "%s: close", __func__);
-
- fido_log_debug("%s: %s: bus = 0x%02x, addr = 0x%02x",
- __func__, path, udi.udi_bus, udi.udi_addr);
- fido_log_debug("%s: %s: vendor = \"%s\", product = \"%s\"",
- __func__, path, udi.udi_vendor, udi.udi_product);
- fido_log_debug("%s: %s: productNo = 0x%04x, vendorNo = 0x%04x, "
- "releaseNo = 0x%04x", __func__, path, udi.udi_productNo,
- udi.udi_vendorNo, udi.udi_releaseNo);
-
- di = &devlist[*olen];
- memset(di, 0, sizeof(*di));
- di->io = (fido_dev_io_t) {
- fido_hid_open,
- fido_hid_close,
- fido_hid_read,
- fido_hid_write,
- };
- if ((di->path = strdup(path)) == NULL ||
- (di->manufacturer = strdup(udi.udi_vendor)) == NULL ||
- (di->product = strdup(udi.udi_product)) == NULL) {
- free(di->path);
- free(di->manufacturer);
- free(di->product);
- explicit_bzero(di, sizeof(*di));
- return FIDO_ERR_INTERNAL;
- }
- di->vendor_id = (int16_t)udi.udi_vendorNo;
- di->product_id = (int16_t)udi.udi_productNo;
- (*olen)++;
}
- return FIDO_OK;
+ return (FIDO_OK);
}
/*
diff --git a/src/hid_osx.c b/src/hid_osx.c
index 7f3652e39620..a5fa8281f81e 100644
--- a/src/hid_osx.c
+++ b/src/hid_osx.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2021 Yubico AB. All rights reserved.
+ * Copyright (c) 2019-2022 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.
*/
@@ -374,25 +374,6 @@ disable_sigpipe(int fd)
return (0);
}
-static int
-to_uint64(const char *str, uint64_t *out)
-{
- char *ep;
- unsigned long long ull;
-
- errno = 0;
- ull = strtoull(str, &ep, 10);
- if (str == ep || *ep != '\0')
- return (-1);
- else if (ull == ULLONG_MAX && errno == ERANGE)
- return (-1);
- else if (ull > UINT64_MAX)
- return (-1);
- *out = (uint64_t)ull;
-
- return (0);
-}
-
static io_registry_entry_t
get_ioreg_entry(const char *path)
{
@@ -401,8 +382,8 @@ get_ioreg_entry(const char *path)
if (strncmp(path, IOREG, strlen(IOREG)) != 0)
return (IORegistryEntryFromPath(kIOMainPortDefault, path));
- if (to_uint64(path + strlen(IOREG), &id) == -1) {
- fido_log_debug("%s: to_uint64", __func__);
+ if (fido_to_uint64(path + strlen(IOREG), 10, &id) == -1) {
+ fido_log_debug("%s: fido_to_uint64", __func__);
return (MACH_PORT_NULL);
}
diff --git a/src/info.c b/src/info.c
index 167a1d30ecaa..ea26f22297a6 100644
--- a/src/info.c
+++ b/src/info.c
@@ -268,6 +268,8 @@ parse_reply_element(const cbor_item_t *key, const cbor_item_t *val, void *arg)
return (decode_string_array(val, &ci->transports));
case 10: /* algorithms */
return (decode_algorithms(val, &ci->algorithms));
+ case 11: /* maxSerializedLargeBlobArray */
+ return (cbor_decode_uint64(val, &ci->maxlargeblob));
case 14: /* fwVersion */
return (cbor_decode_uint64(val, &ci->fwversion));
case 15: /* maxCredBlobLen */
@@ -462,6 +464,12 @@ fido_cbor_info_maxcredidlen(const fido_cbor_info_t *ci)
}
uint64_t
+fido_cbor_info_maxlargeblob(const fido_cbor_info_t *ci)
+{
+ return (ci->maxlargeblob);
+}
+
+uint64_t
fido_cbor_info_fwversion(const fido_cbor_info_t *ci)
{
return (ci->fwversion);
diff --git a/src/nfc.c b/src/nfc.c
new file mode 100644
index 000000000000..8e1221bb5057
--- /dev/null
+++ b/src/nfc.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2020-2022 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 <stdio.h>
+#include <string.h>
+
+#include "fido.h"
+#include "fido/param.h"
+#include "iso7816.h"
+
+#define TX_CHUNK_SIZE 240
+
+static const uint8_t aid[] = { 0xa0, 0x00, 0x00, 0x06, 0x47, 0x2f, 0x00, 0x01 };
+static const uint8_t v_u2f[] = { 'U', '2', 'F', '_', 'V', '2' };
+static const uint8_t v_fido[] = { 'F', 'I', 'D', 'O', '_', '2', '_', '0' };
+
+static int
+tx_short_apdu(fido_dev_t *d, const iso7816_header_t *h, const uint8_t *payload,
+ uint8_t payload_len, uint8_t cla_flags)
+{
+ uint8_t apdu[5 + UINT8_MAX + 1];
+ uint8_t sw[2];
+ size_t apdu_len;
+ int ok = -1;
+
+ memset(&apdu, 0, sizeof(apdu));
+ apdu[0] = h->cla | cla_flags;
+ apdu[1] = h->ins;
+ apdu[2] = h->p1;
+ apdu[3] = h->p2;
+ apdu[4] = payload_len;
+ memcpy(&apdu[5], payload, payload_len);
+ apdu_len = (size_t)(5 + payload_len + 1);
+
+ if (d->io.write(d->io_handle, apdu, apdu_len) < 0) {
+ fido_log_debug("%s: write", __func__);
+ goto fail;
+ }
+
+ if (cla_flags & 0x10) {
+ if (d->io.read(d->io_handle, sw, sizeof(sw), -1) != 2) {
+ fido_log_debug("%s: read", __func__);
+ goto fail;
+ }
+ if ((sw[0] << 8 | sw[1]) != SW_NO_ERROR) {
+ fido_log_debug("%s: unexpected sw", __func__);
+ goto fail;
+ }
+ }
+
+ ok = 0;
+fail:
+ explicit_bzero(apdu, sizeof(apdu));
+
+ return ok;
+}
+
+static int
+nfc_do_tx(fido_dev_t *d, const uint8_t *apdu_ptr, size_t apdu_len)
+{
+ iso7816_header_t h;
+
+ if (fido_buf_read(&apdu_ptr, &apdu_len, &h, sizeof(h)) < 0) {
+ fido_log_debug("%s: header", __func__);
+ return -1;
+ }
+ if (apdu_len < 2) {
+ fido_log_debug("%s: apdu_len %zu", __func__, apdu_len);
+ return -1;
+ }
+
+ apdu_len -= 2; /* trim le1 le2 */
+
+ while (apdu_len > TX_CHUNK_SIZE) {
+ if (tx_short_apdu(d, &h, apdu_ptr, TX_CHUNK_SIZE, 0x10) < 0) {
+ fido_log_debug("%s: chain", __func__);
+ return -1;
+ }
+ apdu_ptr += TX_CHUNK_SIZE;
+ apdu_len -= TX_CHUNK_SIZE;
+ }
+
+ if (tx_short_apdu(d, &h, apdu_ptr, (uint8_t)apdu_len, 0) < 0) {
+ fido_log_debug("%s: tx_short_apdu", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+fido_nfc_tx(fido_dev_t *d, uint8_t cmd, const unsigned char *buf, size_t count)
+{
+ iso7816_apdu_t *apdu = NULL;
+ const uint8_t *ptr;
+ size_t len;
+ int ok = -1;
+
+ switch (cmd) {
+ case CTAP_CMD_INIT: /* select */
+ if ((apdu = iso7816_new(0, 0xa4, 0x04, sizeof(aid))) == NULL ||
+ iso7816_add(apdu, aid, sizeof(aid)) < 0) {
+ fido_log_debug("%s: iso7816", __func__);
+ goto fail;
+ }
+ break;
+ case CTAP_CMD_CBOR: /* wrap cbor */
+ if (count > UINT16_MAX || (apdu = iso7816_new(0x80, 0x10, 0x00,
+ (uint16_t)count)) == NULL ||
+ iso7816_add(apdu, buf, count) < 0) {
+ fido_log_debug("%s: iso7816", __func__);
+ goto fail;
+ }
+ break;
+ case CTAP_CMD_MSG: /* already an apdu */
+ break;
+ default:
+ fido_log_debug("%s: cmd=%02x", __func__, cmd);
+ goto fail;
+ }
+
+ if (apdu != NULL) {
+ ptr = iso7816_ptr(apdu);
+ len = iso7816_len(apdu);
+ } else {
+ ptr = buf;
+ len = count;
+ }
+
+ if (nfc_do_tx(d, ptr, len) < 0) {
+ fido_log_debug("%s: nfc_do_tx", __func__);
+ goto fail;
+ }
+
+ ok = 0;
+fail:
+ iso7816_free(&apdu);
+
+ return ok;
+}
+
+static int
+rx_init(fido_dev_t *d, unsigned char *buf, size_t count, int ms)
+{
+ fido_ctap_info_t *attr = (fido_ctap_info_t *)buf;
+ uint8_t f[64];
+ int n;
+
+ if (count != sizeof(*attr)) {
+ fido_log_debug("%s: count=%zu", __func__, count);
+ return -1;
+ }
+
+ memset(attr, 0, sizeof(*attr));
+
+ if ((n = d->io.read(d->io_handle, f, sizeof(f), ms)) < 2 ||
+ (f[n - 2] << 8 | f[n - 1]) != SW_NO_ERROR) {
+ fido_log_debug("%s: read", __func__);
+ return -1;
+ }
+
+ n -= 2;
+
+ if (n == sizeof(v_u2f) && memcmp(f, v_u2f, sizeof(v_u2f)) == 0)
+ attr->flags = FIDO_CAP_CBOR;
+ else if (n == sizeof(v_fido) && memcmp(f, v_fido, sizeof(v_fido)) == 0)
+ attr->flags = FIDO_CAP_CBOR | FIDO_CAP_NMSG;
+ else {
+ fido_log_debug("%s: unknown version string", __func__);
+#ifdef FIDO_FUZZ
+ attr->flags = FIDO_CAP_CBOR | FIDO_CAP_NMSG;
+#else
+ return -1;
+#endif
+ }
+
+ memcpy(&attr->nonce, &d->nonce, sizeof(attr->nonce)); /* XXX */
+
+ return (int)count;
+}
+
+static int
+tx_get_response(fido_dev_t *d, uint8_t count)
+{
+ uint8_t apdu[5];
+
+ memset(apdu, 0, sizeof(apdu));
+ apdu[1] = 0xc0; /* GET_RESPONSE */
+ apdu[4] = count;
+
+ if (d->io.write(d->io_handle, apdu, sizeof(apdu)) < 0) {
+ fido_log_debug("%s: write", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+rx_apdu(fido_dev_t *d, uint8_t sw[2], unsigned char **buf, size_t *count, int *ms)
+{
+ uint8_t f[256 + 2];
+ struct timespec ts;
+ int n, ok = -1;
+
+ if (fido_time_now(&ts) != 0)
+ goto fail;
+
+ if ((n = d->io.read(d->io_handle, f, sizeof(f), *ms)) < 2) {
+ fido_log_debug("%s: read", __func__);
+ goto fail;
+ }
+
+ if (fido_time_delta(&ts, ms) != 0)
+ goto fail;
+
+ if (fido_buf_write(buf, count, f, (size_t)(n - 2)) < 0) {
+ fido_log_debug("%s: fido_buf_write", __func__);
+ goto fail;
+ }
+
+ memcpy(sw, f + n - 2, 2);
+
+ ok = 0;
+fail:
+ explicit_bzero(f, sizeof(f));
+
+ return ok;
+}
+
+static int
+rx_msg(fido_dev_t *d, unsigned char *buf, size_t count, int ms)
+{
+ uint8_t sw[2];
+ const size_t bufsiz = count;
+
+ if (rx_apdu(d, sw, &buf, &count, &ms) < 0) {
+ fido_log_debug("%s: preamble", __func__);
+ return -1;
+ }
+
+ while (sw[0] == SW1_MORE_DATA)
+ if (tx_get_response(d, sw[1]) < 0 ||
+ rx_apdu(d, sw, &buf, &count, &ms) < 0) {
+ fido_log_debug("%s: chain", __func__);
+ return -1;
+ }
+
+ if (fido_buf_write(&buf, &count, sw, sizeof(sw)) < 0) {
+ fido_log_debug("%s: sw", __func__);
+ return -1;
+ }
+
+ if (bufsiz - count > INT_MAX) {
+ fido_log_debug("%s: bufsiz", __func__);
+ return -1;
+ }
+
+ return (int)(bufsiz - count);
+}
+
+static int
+rx_cbor(fido_dev_t *d, unsigned char *buf, size_t count, int ms)
+{
+ int r;
+
+ if ((r = rx_msg(d, buf, count, ms)) < 2)
+ return -1;
+
+ return r - 2;
+}
+
+int
+fido_nfc_rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms)
+{
+ switch (cmd) {
+ case CTAP_CMD_INIT:
+ return rx_init(d, buf, count, ms);
+ case CTAP_CMD_CBOR:
+ return rx_cbor(d, buf, count, ms);
+ case CTAP_CMD_MSG:
+ return rx_msg(d, buf, count, ms);
+ default:
+ fido_log_debug("%s: cmd=%02x", __func__, cmd);
+ return -1;
+ }
+}
+
+#ifdef USE_NFC
+bool
+fido_is_nfc(const char *path)
+{
+ return strncmp(path, FIDO_NFC_PREFIX, strlen(FIDO_NFC_PREFIX)) == 0;
+}
+
+int
+fido_dev_set_nfc(fido_dev_t *d)
+{
+ if (d->io_handle != NULL) {
+ fido_log_debug("%s: device open", __func__);
+ return -1;
+ }
+ d->io_own = true;
+ d->io = (fido_dev_io_t) {
+ fido_nfc_open,
+ fido_nfc_close,
+ fido_nfc_read,
+ fido_nfc_write,
+ };
+ d->transport = (fido_dev_transport_t) {
+ fido_nfc_rx,
+ fido_nfc_tx,
+ };
+
+ return 0;
+}
+#endif /* USE_NFC */
diff --git a/src/nfc_linux.c b/src/nfc_linux.c
index d5f9ec048052..4673dc2b7d18 100644
--- a/src/nfc_linux.c
+++ b/src/nfc_linux.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 Yubico AB. All rights reserved.
+ * Copyright (c) 2020-2022 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.
*/
@@ -22,12 +22,6 @@
#include "netlink.h"
#include "iso7816.h"
-#define TX_CHUNK_SIZE 240
-
-static const uint8_t aid[] = { 0xa0, 0x00, 0x00, 0x06, 0x47, 0x2f, 0x00, 0x01 };
-static const uint8_t v_u2f[] = { 'U', '2', 'F', '_', 'V', '2' };
-static const uint8_t v_fido[] = { 'F', 'I', 'D', 'O', '_', '2', '_', '0' };
-
struct nfc_linux {
int fd;
uint32_t dev;
@@ -37,278 +31,6 @@ struct nfc_linux {
struct fido_nl *nl;
};
-static int
-tx_short_apdu(fido_dev_t *d, const iso7816_header_t *h, const uint8_t *payload,
- uint8_t payload_len, uint8_t cla_flags)
-{
- uint8_t apdu[5 + UINT8_MAX + 1];
- uint8_t sw[2];
- size_t apdu_len;
- int ok = -1;
-
- memset(&apdu, 0, sizeof(apdu));
- apdu[0] = h->cla | cla_flags;
- apdu[1] = h->ins;
- apdu[2] = h->p1;
- apdu[3] = h->p2;
- apdu[4] = payload_len;
- memcpy(&apdu[5], payload, payload_len);
- apdu_len = (size_t)(5 + payload_len + 1);
-
- if (d->io.write(d->io_handle, apdu, apdu_len) < 0) {
- fido_log_debug("%s: write", __func__);
- goto fail;
- }
-
- if (cla_flags & 0x10) {
- if (d->io.read(d->io_handle, sw, sizeof(sw), -1) != 2) {
- fido_log_debug("%s: read", __func__);
- goto fail;
- }
- if ((sw[0] << 8 | sw[1]) != SW_NO_ERROR) {
- fido_log_debug("%s: unexpected sw", __func__);
- goto fail;
- }
- }
-
- ok = 0;
-fail:
- explicit_bzero(apdu, sizeof(apdu));
-
- return (ok);
-}
-
-static int
-nfc_do_tx(fido_dev_t *d, const uint8_t *apdu_ptr, size_t apdu_len)
-{
- iso7816_header_t h;
-
- if (fido_buf_read(&apdu_ptr, &apdu_len, &h, sizeof(h)) < 0) {
- fido_log_debug("%s: header", __func__);
- return (-1);
- }
- if (apdu_len < 2) {
- fido_log_debug("%s: apdu_len %zu", __func__, apdu_len);
- return (-1);
- }
-
- apdu_len -= 2; /* trim le1 le2 */
-
- while (apdu_len > TX_CHUNK_SIZE) {
- if (tx_short_apdu(d, &h, apdu_ptr, TX_CHUNK_SIZE, 0x10) < 0) {
- fido_log_debug("%s: chain", __func__);
- return (-1);
- }
- apdu_ptr += TX_CHUNK_SIZE;
- apdu_len -= TX_CHUNK_SIZE;
- }
-
- if (tx_short_apdu(d, &h, apdu_ptr, (uint8_t)apdu_len, 0) < 0) {
- fido_log_debug("%s: tx_short_apdu", __func__);
- return (-1);
- }
-
- return (0);
-}
-
-int
-fido_nfc_tx(fido_dev_t *d, uint8_t cmd, const unsigned char *buf, size_t count)
-{
- iso7816_apdu_t *apdu = NULL;
- const uint8_t *ptr;
- size_t len;
- int ok = -1;
-
- switch (cmd) {
- case CTAP_CMD_INIT: /* select */
- if ((apdu = iso7816_new(0, 0xa4, 0x04, sizeof(aid))) == NULL ||
- iso7816_add(apdu, aid, sizeof(aid)) < 0) {
- fido_log_debug("%s: iso7816", __func__);
- goto fail;
- }
- break;
- case CTAP_CMD_CBOR: /* wrap cbor */
- if (count > UINT16_MAX || (apdu = iso7816_new(0x80, 0x10, 0x80,
- (uint16_t)count)) == NULL ||
- iso7816_add(apdu, buf, count) < 0) {
- fido_log_debug("%s: iso7816", __func__);
- goto fail;
- }
- break;
- case CTAP_CMD_MSG: /* already an apdu */
- break;
- default:
- fido_log_debug("%s: cmd=%02x", __func__, cmd);
- goto fail;
- }
-
- if (apdu != NULL) {
- ptr = iso7816_ptr(apdu);
- len = iso7816_len(apdu);
- } else {
- ptr = buf;
- len = count;
- }
-
- if (nfc_do_tx(d, ptr, len) < 0) {
- fido_log_debug("%s: nfc_do_tx", __func__);
- goto fail;
- }
-
- ok = 0;
-fail:
- iso7816_free(&apdu);
-
- return (ok);
-}
-
-static int
-rx_init(fido_dev_t *d, unsigned char *buf, size_t count, int ms)
-{
- fido_ctap_info_t *attr = (fido_ctap_info_t *)buf;
- uint8_t f[64];
- int n;
-
- if (count != sizeof(*attr)) {
- fido_log_debug("%s: count=%zu", __func__, count);
- return (-1);
- }
-
- memset(attr, 0, sizeof(*attr));
-
- if ((n = d->io.read(d->io_handle, f, sizeof(f), ms)) < 2 ||
- (f[n - 2] << 8 | f[n - 1]) != SW_NO_ERROR) {
- fido_log_debug("%s: read", __func__);
- return (-1);
- }
-
- n -= 2;
-
- if (n == sizeof(v_u2f) && memcmp(f, v_u2f, sizeof(v_u2f)) == 0)
- attr->flags = FIDO_CAP_CBOR;
- else if (n == sizeof(v_fido) && memcmp(f, v_fido, sizeof(v_fido)) == 0)
- attr->flags = FIDO_CAP_CBOR | FIDO_CAP_NMSG;
- else {
- fido_log_debug("%s: unknown version string", __func__);
-#ifdef FIDO_FUZZ
- attr->flags = FIDO_CAP_CBOR | FIDO_CAP_NMSG;
-#else
- return (-1);
-#endif
- }
-
- memcpy(&attr->nonce, &d->nonce, sizeof(attr->nonce)); /* XXX */
-
- return ((int)count);
-}
-
-static int
-tx_get_response(fido_dev_t *d, uint8_t count)
-{
- uint8_t apdu[5];
-
- memset(apdu, 0, sizeof(apdu));
- apdu[1] = 0xc0; /* GET_RESPONSE */
- apdu[4] = count;
-
- if (d->io.write(d->io_handle, apdu, sizeof(apdu)) < 0) {
- fido_log_debug("%s: write", __func__);
- return (-1);
- }
-
- return (0);
-}
-
-static int
-rx_apdu(fido_dev_t *d, uint8_t sw[2], unsigned char **buf, size_t *count, int *ms)
-{
- uint8_t f[256 + 2];
- struct timespec ts;
- int n, ok = -1;
-
- if (fido_time_now(&ts) != 0)
- goto fail;
-
- if ((n = d->io.read(d->io_handle, f, sizeof(f), *ms)) < 2) {
- fido_log_debug("%s: read", __func__);
- goto fail;
- }
-
- if (fido_time_delta(&ts, ms) != 0)
- goto fail;
-
- if (fido_buf_write(buf, count, f, (size_t)(n - 2)) < 0) {
- fido_log_debug("%s: fido_buf_write", __func__);
- goto fail;
- }
-
- memcpy(sw, f + n - 2, 2);
-
- ok = 0;
-fail:
- explicit_bzero(f, sizeof(f));
-
- return (ok);
-}
-
-static int
-rx_msg(fido_dev_t *d, unsigned char *buf, size_t count, int ms)
-{
- uint8_t sw[2];
- const size_t bufsiz = count;
-
- if (rx_apdu(d, sw, &buf, &count, &ms) < 0) {
- fido_log_debug("%s: preamble", __func__);
- return (-1);
- }
-
- while (sw[0] == SW1_MORE_DATA)
- if (tx_get_response(d, sw[1]) < 0 ||
- rx_apdu(d, sw, &buf, &count, &ms) < 0) {
- fido_log_debug("%s: chain", __func__);
- return (-1);
- }
-
- if (fido_buf_write(&buf, &count, sw, sizeof(sw)) < 0) {
- fido_log_debug("%s: sw", __func__);
- return (-1);
- }
-
- if (bufsiz - count > INT_MAX) {
- fido_log_debug("%s: bufsiz", __func__);
- return (-1);
- }
-
- return ((int)(bufsiz - count));
-}
-
-static int
-rx_cbor(fido_dev_t *d, unsigned char *buf, size_t count, int ms)
-{
- int r;
-
- if ((r = rx_msg(d, buf, count, ms)) < 2)
- return (-1);
-
- return (r - 2);
-}
-
-int
-fido_nfc_rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms)
-{
- switch (cmd) {
- case CTAP_CMD_INIT:
- return (rx_init(d, buf, count, ms));
- case CTAP_CMD_CBOR:
- return (rx_cbor(d, buf, count, ms));
- case CTAP_CMD_MSG:
- return (rx_msg(d, buf, count, ms));
- default:
- fido_log_debug("%s: cmd=%02x", __func__, cmd);
- return (-1);
- }
-}
-
static char *
get_parent_attr(struct udev_device *dev, const char *subsystem,
const char *devtype, const char *attr)
@@ -319,34 +41,15 @@ get_parent_attr(struct udev_device *dev, const char *subsystem,
if ((parent = udev_device_get_parent_with_subsystem_devtype(dev,
subsystem, devtype)) == NULL || (value =
udev_device_get_sysattr_value(parent, attr)) == NULL)
- return (NULL);
+ return NULL;
- return (strdup(value));
+ return strdup(value);
}
static char *
get_usb_attr(struct udev_device *dev, const char *attr)
{
- return (get_parent_attr(dev, "usb", "usb_device", attr));
-}
-
-static int
-to_int(const char *str, int base)
-{
- char *ep;
- long long ll;
-
- ll = strtoll(str, &ep, base);
- if (str == ep || *ep != '\0')
- return (-1);
- else if (ll == LLONG_MIN && errno == ERANGE)
- return (-1);
- else if (ll == LLONG_MAX && errno == ERANGE)
- return (-1);
- else if (ll < 0 || ll > INT_MAX)
- return (-1);
-
- return ((int)ll);
+ return get_parent_attr(dev, "usb", "usb_device", attr);
}
static int
@@ -357,15 +60,18 @@ copy_info(fido_dev_info_t *di, struct udev *udev,
char *str;
struct udev_device *dev = NULL;
void *ctx = NULL;
- int id, ok = -1;
+ uint64_t id;
+ int ok = -1;
memset(di, 0, sizeof(*di));
if ((name = udev_list_entry_get_name(udev_entry)) == NULL ||
(dev = udev_device_new_from_syspath(udev, name)) == NULL)
goto fail;
- if (asprintf(&di->path, "%s/%s", FIDO_NFC_PREFIX, name) == -1)
+ if (asprintf(&di->path, "%s/%s", FIDO_NFC_PREFIX, name) == -1) {
+ di->path = NULL;
goto fail;
+ }
if ((di->manufacturer = get_usb_attr(dev, "manufacturer")) == NULL)
di->manufacturer = strdup("");
if ((di->product = get_usb_attr(dev, "product")) == NULL)
@@ -374,11 +80,11 @@ copy_info(fido_dev_info_t *di, struct udev *udev,
goto fail;
/* XXX assumes USB for vendor/product info */
if ((str = get_usb_attr(dev, "idVendor")) != NULL &&
- (id = to_int(str, 16)) > 0 && id <= UINT16_MAX)
+ fido_to_uint64(str, 16, &id) == 0 && id <= UINT16_MAX)
di->vendor_id = (int16_t)id;
free(str);
if ((str = get_usb_attr(dev, "idProduct")) != NULL &&
- (id = to_int(str, 16)) > 0 && id <= UINT16_MAX)
+ fido_to_uint64(str, 16, &id) == 0 && id <= UINT16_MAX)
di->product_id = (int16_t)id;
free(str);
@@ -401,7 +107,7 @@ fail:
explicit_bzero(di, sizeof(*di));
}
- return (ok);
+ return ok;
}
static int
@@ -410,21 +116,21 @@ sysnum_from_syspath(const char *path)
struct udev *udev = NULL;
struct udev_device *dev = NULL;
const char *str;
- int idx;
+ uint64_t idx64;
+ int idx = -1;
- if ((udev = udev_new()) == NULL ||
- (dev = udev_device_new_from_syspath(udev, path)) == NULL ||
- (str = udev_device_get_sysnum(dev)) == NULL)
- idx = -1;
- else
- idx = to_int(str, 10);
+ if ((udev = udev_new()) != NULL &&
+ (dev = udev_device_new_from_syspath(udev, path)) != NULL &&
+ (str = udev_device_get_sysnum(dev)) != NULL &&
+ fido_to_uint64(str, 10, &idx64) == 0 && idx64 < INT_MAX)
+ idx = (int)idx64;
if (dev != NULL)
udev_device_unref(dev);
if (udev != NULL)
udev_unref(udev);
- return (idx);
+ return idx;
}
int
@@ -439,10 +145,10 @@ fido_nfc_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
*olen = 0;
if (ilen == 0)
- return (FIDO_OK);
+ return FIDO_OK;
if (devlist == NULL)
- return (FIDO_ERR_INVALID_ARGUMENT);
+ return FIDO_ERR_INVALID_ARGUMENT;
if ((udev = udev_new()) == NULL ||
(udev_enum = udev_enumerate_new(udev)) == NULL)
@@ -481,7 +187,7 @@ fail:
if (udev != NULL)
udev_unref(udev);
- return (r);
+ return r;
}
static int
@@ -498,17 +204,17 @@ nfc_target_connect(struct nfc_linux *ctx)
if ((ctx->fd = socket(AF_NFC, SOCK_SEQPACKET | SOCK_CLOEXEC,
NFC_SOCKPROTO_RAW)) == -1) {
fido_log_error(errno, "%s: socket", __func__);
- return (-1);
+ return -1;
}
if (connect(ctx->fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
fido_log_error(errno, "%s: connect", __func__);
if (close(ctx->fd) == -1)
fido_log_error(errno, "%s: close", __func__);
ctx->fd = -1;
- return (-1);
+ return -1;
}
- return (0);
+ return 0;
}
static void
@@ -535,13 +241,13 @@ nfc_new(uint32_t dev)
if ((ctx = calloc(1, sizeof(*ctx))) == NULL ||
(ctx->nl = fido_nl_new()) == NULL) {
nfc_free(&ctx);
- return (NULL);
+ return NULL;
}
ctx->fd = -1;
ctx->dev = dev;
- return (ctx);
+ return ctx;
}
void *
@@ -566,10 +272,10 @@ fido_nfc_open(const char *path)
goto fail;
}
- return (ctx);
+ return ctx;
fail:
nfc_free(&ctx);
- return (NULL);
+ return NULL;
}
void
@@ -588,7 +294,7 @@ fido_nfc_set_sigmask(void *handle, const fido_sigset_t *sigmask)
ctx->sigmask = *sigmask;
ctx->sigmaskp = &ctx->sigmask;
- return (FIDO_OK);
+ return FIDO_OK;
}
int
@@ -607,25 +313,25 @@ fido_nfc_read(void *handle, unsigned char *buf, size_t len, int ms)
if (fido_hid_unix_wait(ctx->fd, ms, ctx->sigmaskp) < 0) {
fido_log_debug("%s: fido_hid_unix_wait", __func__);
- return (-1);
+ return -1;
}
if ((r = readv(ctx->fd, iov, nitems(iov))) == -1) {
fido_log_error(errno, "%s: read", __func__);
- return (-1);
+ return -1;
}
if (r < 1) {
fido_log_debug("%s: %zd < 1", __func__, r);
- return (-1);
+ return -1;
}
if (preamble != 0x00) {
fido_log_debug("%s: preamble", __func__);
- return (-1);
+ return -1;
}
r--;
fido_log_xxd(buf, (size_t)r, "%s", __func__);
- return ((int)r);
+ return (int)r;
}
int
@@ -638,16 +344,16 @@ fido_nfc_write(void *handle, const unsigned char *buf, size_t len)
if (len > INT_MAX) {
fido_log_debug("%s: len", __func__);
- return (-1);
+ return -1;
}
if ((r = write(ctx->fd, buf, len)) == -1) {
fido_log_error(errno, "%s: write", __func__);
- return (-1);
+ return -1;
}
if (r < 0 || (size_t)r != len) {
fido_log_debug("%s: %zd != %zu", __func__, r, len);
- return (-1);
+ return -1;
}
- return ((int)r);
+ return (int)r;
}
diff --git a/src/pcsc.c b/src/pcsc.c
new file mode 100644
index 000000000000..c02251e9bfe1
--- /dev/null
+++ b/src/pcsc.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2022 Micro Focus or one of its affiliates.
+ * Copyright (c) 2022 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.
+ */
+
+#if __APPLE__
+#include <PCSC/wintypes.h>
+#include <PCSC/winscard.h>
+#else
+#include <winscard.h>
+#endif /* __APPLE__ */
+
+#include <errno.h>
+
+#include "fido.h"
+#include "fido/param.h"
+#include "iso7816.h"
+
+#if defined(_WIN32) && !defined(__MINGW32__)
+#define SCardConnect SCardConnectA
+#define SCardListReaders SCardListReadersA
+#endif
+
+#ifndef SCARD_PROTOCOL_Tx
+#define SCARD_PROTOCOL_Tx SCARD_PROTOCOL_ANY
+#endif
+
+#define BUFSIZE 1024 /* in bytes; passed to SCardListReaders() */
+#define APDULEN 264 /* 261 rounded up to the nearest multiple of 8 */
+#define READERS 8 /* maximum number of readers */
+
+struct pcsc {
+ SCARDCONTEXT ctx;
+ SCARDHANDLE h;
+ SCARD_IO_REQUEST req;
+ uint8_t rx_buf[APDULEN];
+ size_t rx_len;
+};
+
+static LONG
+list_readers(SCARDCONTEXT ctx, char **buf)
+{
+ LONG s;
+ DWORD len;
+
+ len = BUFSIZE;
+ if ((*buf = calloc(1, len)) == NULL)
+ goto fail;
+ if ((s = SCardListReaders(ctx, NULL, *buf, &len)) != SCARD_S_SUCCESS) {
+ fido_log_debug("%s: SCardListReaders 0x%lx", __func__, (long)s);
+ goto fail;
+ }
+ /* sanity check "multi-string" */
+ if (len > BUFSIZE || len < 2) {
+ fido_log_debug("%s: bogus len=%u", __func__, (unsigned)len);
+ goto fail;
+ }
+ if ((*buf)[len - 1] != 0 || (*buf)[len - 2] != '\0') {
+ fido_log_debug("%s: bogus buf", __func__);
+ goto fail;
+ }
+ return (LONG)SCARD_S_SUCCESS;
+fail:
+ free(*buf);
+ *buf = NULL;
+
+ return (LONG)SCARD_E_NO_READERS_AVAILABLE;
+}
+
+static char *
+get_reader(SCARDCONTEXT ctx, const char *path)
+{
+ char *reader = NULL, *buf = NULL;
+ const char prefix[] = FIDO_PCSC_PREFIX "//slot";
+ uint64_t n;
+
+ if (path == NULL)
+ goto out;
+ if (strncmp(path, prefix, strlen(prefix)) != 0 ||
+ fido_to_uint64(path + strlen(prefix), 10, &n) < 0 ||
+ n > READERS - 1) {
+ fido_log_debug("%s: invalid path %s", __func__, path);
+ goto out;
+ }
+ if (list_readers(ctx, &buf) != SCARD_S_SUCCESS) {
+ fido_log_debug("%s: list_readers", __func__);
+ goto out;
+ }
+ for (const char *name = buf; *name != 0; name += strlen(name) + 1) {
+ if (n == 0) {
+ reader = strdup(name);
+ goto out;
+ }
+ n--;
+ }
+ fido_log_debug("%s: failed to find reader %s", __func__, path);
+out:
+ free(buf);
+
+ return reader;
+}
+
+static int
+prepare_io_request(DWORD prot, SCARD_IO_REQUEST *req)
+{
+ switch (prot) {
+ case SCARD_PROTOCOL_T0:
+ req->dwProtocol = SCARD_PCI_T0->dwProtocol;
+ req->cbPciLength = SCARD_PCI_T0->cbPciLength;
+ break;
+ case SCARD_PROTOCOL_T1:
+ req->dwProtocol = SCARD_PCI_T1->dwProtocol;
+ req->cbPciLength = SCARD_PCI_T1->cbPciLength;
+ break;
+ default:
+ fido_log_debug("%s: unknown protocol %lu", __func__,
+ (u_long)prot);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+copy_info(fido_dev_info_t *di, SCARDCONTEXT ctx, const char *reader, size_t idx)
+{
+ SCARDHANDLE h = 0;
+ SCARD_IO_REQUEST req;
+ DWORD prot = 0;
+ LONG s;
+ int ok = -1;
+
+ memset(di, 0, sizeof(*di));
+ memset(&req, 0, sizeof(req));
+
+ if ((s = SCardConnect(ctx, reader, SCARD_SHARE_SHARED,
+ SCARD_PROTOCOL_Tx, &h, &prot)) != SCARD_S_SUCCESS) {
+ fido_log_debug("%s: SCardConnect 0x%lx", __func__, (long)s);
+ goto fail;
+ }
+ if (prepare_io_request(prot, &req) < 0) {
+ fido_log_debug("%s: prepare_io_request", __func__);
+ goto fail;
+ }
+ if (asprintf(&di->path, "%s//slot%zu", FIDO_PCSC_PREFIX, idx) == -1) {
+ di->path = NULL;
+ fido_log_debug("%s: asprintf", __func__);
+ goto fail;
+ }
+ if ((di->manufacturer = strdup("PC/SC")) == NULL ||
+ (di->product = strdup(reader)) == NULL)
+ goto fail;
+
+ ok = 0;
+fail:
+ if (h != 0)
+ SCardDisconnect(h, SCARD_LEAVE_CARD);
+ if (ok < 0) {
+ free(di->path);
+ free(di->manufacturer);
+ free(di->product);
+ explicit_bzero(di, sizeof(*di));
+ }
+
+ return ok;
+}
+
+int
+fido_pcsc_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
+{
+ SCARDCONTEXT ctx = 0;
+ char *buf = NULL;
+ LONG s;
+ size_t idx = 0;
+ int r = FIDO_ERR_INTERNAL;
+
+ *olen = 0;
+
+ if (ilen == 0)
+ return FIDO_OK;
+ if (devlist == NULL)
+ return FIDO_ERR_INVALID_ARGUMENT;
+
+ if ((s = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL,
+ &ctx)) != SCARD_S_SUCCESS || ctx == 0) {
+ fido_log_debug("%s: SCardEstablishContext 0x%lx", __func__,
+ (long)s);
+ if (s == (LONG)SCARD_E_NO_SERVICE ||
+ s == (LONG)SCARD_E_NO_SMARTCARD)
+ r = FIDO_OK; /* suppress error */
+ goto out;
+ }
+ if ((s = list_readers(ctx, &buf)) != SCARD_S_SUCCESS) {
+ fido_log_debug("%s: list_readers 0x%lx", __func__, (long)s);
+ if (s == (LONG)SCARD_E_NO_READERS_AVAILABLE)
+ r = FIDO_OK; /* suppress error */
+ goto out;
+ }
+
+ for (const char *name = buf; *name != 0; name += strlen(name) + 1) {
+ if (idx == READERS) {
+ fido_log_debug("%s: stopping at %zu readers", __func__,
+ idx);
+ r = FIDO_OK;
+ goto out;
+ }
+ if (copy_info(&devlist[*olen], ctx, name, idx++) == 0) {
+ devlist[*olen].io = (fido_dev_io_t) {
+ fido_pcsc_open,
+ fido_pcsc_close,
+ fido_pcsc_read,
+ fido_pcsc_write,
+ };
+ devlist[*olen].transport = (fido_dev_transport_t) {
+ fido_pcsc_rx,
+ fido_pcsc_tx,
+ };
+ if (++(*olen) == ilen)
+ break;
+ }
+ }
+
+ r = FIDO_OK;
+out:
+ free(buf);
+ if (ctx != 0)
+ SCardReleaseContext(ctx);
+
+ return r;
+}
+
+void *
+fido_pcsc_open(const char *path)
+{
+ char *reader = NULL;
+ struct pcsc *dev = NULL;
+ SCARDCONTEXT ctx = 0;
+ SCARDHANDLE h = 0;
+ SCARD_IO_REQUEST req;
+ DWORD prot = 0;
+ LONG s;
+
+ memset(&req, 0, sizeof(req));
+
+ if ((s = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL,
+ &ctx)) != SCARD_S_SUCCESS || ctx == 0) {
+ fido_log_debug("%s: SCardEstablishContext 0x%lx", __func__,
+ (long)s);
+ goto fail;
+
+ }
+ if ((reader = get_reader(ctx, path)) == NULL) {
+ fido_log_debug("%s: get_reader(%s)", __func__, path);
+ goto fail;
+ }
+ if ((s = SCardConnect(ctx, reader, SCARD_SHARE_SHARED,
+ SCARD_PROTOCOL_Tx, &h, &prot)) != SCARD_S_SUCCESS) {
+ fido_log_debug("%s: SCardConnect 0x%lx", __func__, (long)s);
+ goto fail;
+ }
+ if (prepare_io_request(prot, &req) < 0) {
+ fido_log_debug("%s: prepare_io_request", __func__);
+ goto fail;
+ }
+ if ((dev = calloc(1, sizeof(*dev))) == NULL)
+ goto fail;
+
+ dev->ctx = ctx;
+ dev->h = h;
+ dev->req = req;
+ ctx = 0;
+ h = 0;
+fail:
+ if (h != 0)
+ SCardDisconnect(h, SCARD_LEAVE_CARD);
+ if (ctx != 0)
+ SCardReleaseContext(ctx);
+ free(reader);
+
+ return dev;
+}
+
+void
+fido_pcsc_close(void *handle)
+{
+ struct pcsc *dev = handle;
+
+ if (dev->h != 0)
+ SCardDisconnect(dev->h, SCARD_LEAVE_CARD);
+ if (dev->ctx != 0)
+ SCardReleaseContext(dev->ctx);
+
+ explicit_bzero(dev->rx_buf, sizeof(dev->rx_buf));
+ free(dev);
+}
+
+int
+fido_pcsc_read(void *handle, unsigned char *buf, size_t len, int ms)
+{
+ struct pcsc *dev = handle;
+ int r;
+
+ (void)ms;
+ if (dev->rx_len == 0 || dev->rx_len > len ||
+ dev->rx_len > sizeof(dev->rx_buf)) {
+ fido_log_debug("%s: rx_len", __func__);
+ return -1;
+ }
+ fido_log_xxd(dev->rx_buf, dev->rx_len, "%s: reading", __func__);
+ memcpy(buf, dev->rx_buf, dev->rx_len);
+ explicit_bzero(dev->rx_buf, sizeof(dev->rx_buf));
+ r = (int)dev->rx_len;
+ dev->rx_len = 0;
+
+ return r;
+}
+
+int
+fido_pcsc_write(void *handle, const unsigned char *buf, size_t len)
+{
+ struct pcsc *dev = handle;
+ DWORD n;
+ LONG s;
+
+ if (len > INT_MAX) {
+ fido_log_debug("%s: len", __func__);
+ return -1;
+ }
+
+ explicit_bzero(dev->rx_buf, sizeof(dev->rx_buf));
+ dev->rx_len = 0;
+ n = (DWORD)sizeof(dev->rx_buf);
+
+ fido_log_xxd(buf, len, "%s: writing", __func__);
+
+ if ((s = SCardTransmit(dev->h, &dev->req, buf, (DWORD)len, NULL,
+ dev->rx_buf, &n)) != SCARD_S_SUCCESS) {
+ fido_log_debug("%s: SCardTransmit 0x%lx", __func__, (long)s);
+ explicit_bzero(dev->rx_buf, sizeof(dev->rx_buf));
+ return -1;
+ }
+ dev->rx_len = (size_t)n;
+
+ fido_log_xxd(dev->rx_buf, dev->rx_len, "%s: read", __func__);
+
+ return (int)len;
+}
+
+int
+fido_pcsc_tx(fido_dev_t *d, uint8_t cmd, const u_char *buf, size_t count)
+{
+ return fido_nfc_tx(d, cmd, buf, count);
+}
+
+int
+fido_pcsc_rx(fido_dev_t *d, uint8_t cmd, u_char *buf, size_t count, int ms)
+{
+ return fido_nfc_rx(d, cmd, buf, count, ms);
+}
+
+bool
+fido_is_pcsc(const char *path)
+{
+ return strncmp(path, FIDO_PCSC_PREFIX, strlen(FIDO_PCSC_PREFIX)) == 0;
+}
+
+int
+fido_dev_set_pcsc(fido_dev_t *d)
+{
+ if (d->io_handle != NULL) {
+ fido_log_debug("%s: device open", __func__);
+ return -1;
+ }
+ d->io_own = true;
+ d->io = (fido_dev_io_t) {
+ fido_pcsc_open,
+ fido_pcsc_close,
+ fido_pcsc_read,
+ fido_pcsc_write,
+ };
+ d->transport = (fido_dev_transport_t) {
+ fido_pcsc_rx,
+ fido_pcsc_tx,
+ };
+
+ return 0;
+}
diff --git a/src/rs1.c b/src/rs1.c
index 37aa9f073bed..134068b16747 100644
--- a/src/rs1.c
+++ b/src/rs1.c
@@ -9,7 +9,7 @@
#include "fido.h"
-#if defined(LIBRESSL_VERSION_NUMBER)
+#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3050200fL
static EVP_MD *
rs1_get_EVP_MD(void)
{
diff --git a/src/rs256.c b/src/rs256.c
index 29fcedbdee20..95bae167a177 100644
--- a/src/rs256.c
+++ b/src/rs256.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2021 Yubico AB. All rights reserved.
+ * Copyright (c) 2018-2022 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.
*/
@@ -11,7 +11,13 @@
#include "fido.h"
#include "fido/rs256.h"
-#if defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= 0x30000000
+#define get0_RSA(x) EVP_PKEY_get0_RSA((x))
+#else
+#define get0_RSA(x) EVP_PKEY_get0((x))
+#endif
+
+#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3050200fL
static EVP_MD *
rs256_get_EVP_MD(void)
{
@@ -128,11 +134,20 @@ rs256_pk_free(rs256_pk_t **pkp)
int
rs256_pk_from_ptr(rs256_pk_t *pk, const void *ptr, size_t len)
{
+ EVP_PKEY *pkey;
+
if (len < sizeof(*pk))
return (FIDO_ERR_INVALID_ARGUMENT);
memcpy(pk, ptr, sizeof(*pk));
+ if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) {
+ fido_log_debug("%s: rs256_pk_to_EVP_PKEY", __func__);
+ return (FIDO_ERR_INVALID_ARGUMENT);
+ }
+
+ EVP_PKEY_free(pkey);
+
return (FIDO_OK);
}
@@ -163,6 +178,11 @@ rs256_pk_to_EVP_PKEY(const rs256_pk_t *k)
n = NULL;
e = NULL;
+ if (RSA_bits(rsa) != 2048) {
+ fido_log_debug("%s: invalid key length", __func__);
+ goto fail;
+ }
+
if ((pkey = EVP_PKEY_new()) == NULL ||
EVP_PKEY_assign_RSA(pkey, rsa) == 0) {
fido_log_debug("%s: EVP_PKEY_assign_RSA", __func__);
@@ -225,10 +245,10 @@ rs256_pk_from_RSA(rs256_pk_t *pk, const RSA *rsa)
int
rs256_pk_from_EVP_PKEY(rs256_pk_t *pk, const EVP_PKEY *pkey)
{
- RSA *rsa;
+ const RSA *rsa;
if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA ||
- (rsa = EVP_PKEY_get0(pkey)) == NULL)
+ (rsa = get0_RSA(pkey)) == NULL)
return (FIDO_ERR_INVALID_ARGUMENT);
return (rs256_pk_from_RSA(pk, rsa));
diff --git a/src/touch.c b/src/touch.c
new file mode 100644
index 000000000000..66b1c3478c0a
--- /dev/null
+++ b/src/touch.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2018-2022 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 <openssl/sha.h>
+#include "fido.h"
+
+int
+fido_dev_get_touch_begin(fido_dev_t *dev)
+{
+ fido_blob_t f;
+ cbor_item_t *argv[9];
+ const char *clientdata = FIDO_DUMMY_CLIENTDATA;
+ const uint8_t user_id = FIDO_DUMMY_USER_ID;
+ unsigned char cdh[SHA256_DIGEST_LENGTH];
+ fido_rp_t rp;
+ fido_user_t user;
+ int ms = dev->timeout_ms;
+ int r = FIDO_ERR_INTERNAL;
+
+ memset(&f, 0, sizeof(f));
+ memset(argv, 0, sizeof(argv));
+ memset(cdh, 0, sizeof(cdh));
+ memset(&rp, 0, sizeof(rp));
+ memset(&user, 0, sizeof(user));
+
+ if (fido_dev_is_fido2(dev) == false)
+ return (u2f_get_touch_begin(dev, &ms));
+
+ if (SHA256((const void *)clientdata, strlen(clientdata), cdh) != cdh) {
+ fido_log_debug("%s: sha256", __func__);
+ return (FIDO_ERR_INTERNAL);
+ }
+
+ if ((rp.id = strdup(FIDO_DUMMY_RP_ID)) == NULL ||
+ (user.name = strdup(FIDO_DUMMY_USER_NAME)) == NULL) {
+ fido_log_debug("%s: strdup", __func__);
+ goto fail;
+ }
+
+ if (fido_blob_set(&user.id, &user_id, sizeof(user_id)) < 0) {
+ fido_log_debug("%s: fido_blob_set", __func__);
+ goto fail;
+ }
+
+ if ((argv[0] = cbor_build_bytestring(cdh, sizeof(cdh))) == NULL ||
+ (argv[1] = cbor_encode_rp_entity(&rp)) == NULL ||
+ (argv[2] = cbor_encode_user_entity(&user)) == NULL ||
+ (argv[3] = cbor_encode_pubkey_param(COSE_ES256)) == NULL) {
+ fido_log_debug("%s: cbor encode", __func__);
+ goto fail;
+ }
+
+ if (fido_dev_supports_pin(dev)) {
+ if ((argv[7] = cbor_new_definite_bytestring()) == NULL ||
+ (argv[8] = cbor_encode_pin_opt(dev)) == NULL) {
+ fido_log_debug("%s: cbor encode", __func__);
+ goto fail;
+ }
+ }
+
+ if (cbor_build_frame(CTAP_CBOR_MAKECRED, argv, nitems(argv), &f) < 0 ||
+ fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len, &ms) < 0) {
+ fido_log_debug("%s: fido_tx", __func__);
+ r = FIDO_ERR_TX;
+ goto fail;
+ }
+
+ r = FIDO_OK;
+fail:
+ cbor_vector_free(argv, nitems(argv));
+ free(f.ptr);
+ free(rp.id);
+ free(user.name);
+ free(user.id.ptr);
+
+ return (r);
+}
+
+int
+fido_dev_get_touch_status(fido_dev_t *dev, int *touched, int ms)
+{
+ int r;
+
+ *touched = 0;
+
+ if (fido_dev_is_fido2(dev) == false)
+ return (u2f_get_touch_status(dev, touched, &ms));
+
+ switch ((r = fido_rx_cbor_status(dev, &ms))) {
+ case FIDO_ERR_PIN_AUTH_INVALID:
+ case FIDO_ERR_PIN_INVALID:
+ case FIDO_ERR_PIN_NOT_SET:
+ case FIDO_ERR_SUCCESS:
+ *touched = 1;
+ break;
+ case FIDO_ERR_RX:
+ /* ignore */
+ break;
+ default:
+ fido_log_debug("%s: fido_rx_cbor_status", __func__);
+ return (r);
+ }
+
+ return (FIDO_OK);
+}
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 000000000000..61e120cfd06c
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2022 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 <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "fido.h"
+
+int
+fido_to_uint64(const char *str, int base, uint64_t *out)
+{
+ char *ep;
+ unsigned long long ull;
+
+ errno = 0;
+ ull = strtoull(str, &ep, base);
+ if (str == ep || *ep != '\0')
+ return -1;
+ else if (ull == ULLONG_MAX && errno == ERANGE)
+ return -1;
+ else if (ull > UINT64_MAX)
+ return -1;
+ *out = (uint64_t)ull;
+
+ return 0;
+}
diff --git a/src/webauthn.h b/src/webauthn.h
index 22bf6e346a73..e64236a0f6fe 100644
--- a/src/webauthn.h
+++ b/src/webauthn.h
@@ -92,6 +92,9 @@ extern "C" {
// - WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS : 5
// - WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS : 6
// - WEBAUTHN_ASSERTION : 3
+// APIs:
+// - WebAuthNGetPlatformCredentialList
+// - WebAuthNFreePlatformCredentialList
//
#define WEBAUTHN_API_CURRENT_VERSION WEBAUTHN_API_VERSION_4
@@ -283,11 +286,64 @@ typedef struct _WEBAUTHN_CREDENTIAL_LIST {
typedef const WEBAUTHN_CREDENTIAL_LIST *PCWEBAUTHN_CREDENTIAL_LIST;
//+------------------------------------------------------------------------------------------
+// Credential Information for WebAuthNGetPlatformCredentialList API
+//-------------------------------------------------------------------------------------------
+
+#define WEBAUTHN_CREDENTIAL_DETAILS_VERSION_1 1
+#define WEBAUTHN_CREDENTIAL_DETAILS_CURRENT_VERSION WEBAUTHN_CREDENTIAL_DETAILS_VERSION_1
+
+typedef struct _WEBAUTHN_CREDENTIAL_DETAILS {
+ // Version of this structure, to allow for modifications in the future.
+ DWORD dwVersion;
+
+ // Size of pbCredentialID.
+ DWORD cbCredentialID;
+ _Field_size_bytes_(cbCredentialID)
+ PBYTE pbCredentialID;
+
+ // RP Info
+ PWEBAUTHN_RP_ENTITY_INFORMATION pRpInformation;
+
+ // User Info
+ PWEBAUTHN_USER_ENTITY_INFORMATION pUserInformation;
+} WEBAUTHN_CREDENTIAL_DETAILS, *PWEBAUTHN_CREDENTIAL_DETAILS;
+typedef const WEBAUTHN_CREDENTIAL_DETAILS *PCWEBAUTHN_CREDENTIAL_DETAILS;
+
+typedef struct _WEBAUTHN_CREDENTIAL_DETAILS_LIST {
+ DWORD cCredentialDetails;
+ _Field_size_(cCredentialDetails)
+ PWEBAUTHN_CREDENTIAL_DETAILS *ppCredentialDetails;
+} WEBAUTHN_CREDENTIAL_DETAILS_LIST, *PWEBAUTHN_CREDENTIAL_DETAILS_LIST;
+typedef const WEBAUTHN_CREDENTIAL_DETAILS_LIST *PCWEBAUTHN_CREDENTIAL_DETAILS_LIST;
+
+#define WEBAUTHN_GET_CREDENTIALS_OPTIONS_VERSION_1 1
+#define WEBAUTHN_GET_CREDENTIALS_OPTIONS_CURRENT_VERSION WEBAUTHN_GET_CREDENTIALS_OPTIONS_VERSION_1
+
+typedef struct _WEBAUTHN_GET_CREDENTIALS_OPTIONS {
+ // Version of this structure, to allow for modifications in the future.
+ DWORD dwVersion;
+
+ // RPID
+ LPCWSTR pwszRpId;
+
+ // Optional. BrowserInPrivate Mode. Defaulting to FALSE.
+ BOOL bBrowserInPrivateMode;
+} WEBAUTHN_GET_CREDENTIALS_OPTIONS, *PWEBAUTHN_GET_CREDENTIALS_OPTIONS;
+typedef const WEBAUTHN_GET_CREDENTIALS_OPTIONS *PCWEBAUTHN_GET_CREDENTIALS_OPTIONS;
+
+//+------------------------------------------------------------------------------------------
// PRF values.
//-------------------------------------------------------------------------------------------
#define WEBAUTHN_CTAP_ONE_HMAC_SECRET_LENGTH 32
+// SALT values below by default are converted into RAW Hmac-Secret values as per PRF extension.
+// - SHA-256(UTF8Encode("WebAuthn PRF") || 0x00 || Value)
+//
+// Set WEBAUTHN_CTAP_HMAC_SECRET_VALUES_FLAG in dwFlags in WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS,
+// if caller wants to provide RAW Hmac-Secret SALT values directly. In that case,
+// values if provided MUST be of WEBAUTHN_CTAP_ONE_HMAC_SECRET_LENGTH size.
+
typedef struct _WEBAUTHN_HMAC_SECRET_SALT {
// Size of pbFirst.
DWORD cbFirst;
@@ -545,6 +601,12 @@ typedef const WEBAUTHN_AUTHENTICATOR_MAKE_CREDENTIAL_OPTIONS *PCWEBAUTHN_AUTHENT
#define WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_6 6
#define WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_CURRENT_VERSION WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_6
+/*
+ Information about flags.
+*/
+
+#define WEBAUTHN_AUTHENTICATOR_HMAC_SECRET_VALUES_FLAG 0x00100000
+
typedef struct _WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS {
// Version of this structure, to allow for modifications in the future.
DWORD dwVersion;
@@ -565,7 +627,7 @@ typedef struct _WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS {
// User Verification Requirement.
DWORD dwUserVerificationRequirement;
- // Reserved for future Use
+ // Flags
DWORD dwFlags;
//
@@ -879,6 +941,17 @@ WINAPI
WebAuthNCancelCurrentOperation(
_In_ const GUID* pCancellationId);
+HRESULT
+WINAPI
+WebAuthNGetPlatformCredentialList(
+ _In_ PCWEBAUTHN_GET_CREDENTIALS_OPTIONS pGetCredentialsOptions,
+ _Outptr_result_maybenull_ PWEBAUTHN_CREDENTIAL_DETAILS_LIST *ppCredentialDetailsList);
+
+void
+WINAPI
+WebAuthNFreePlatformCredentialList(
+ _In_ PWEBAUTHN_CREDENTIAL_DETAILS_LIST pCredentialDetailsList);
+
//
// Returns the following Error Names:
// L"Success" - S_OK
diff --git a/src/winhello.c b/src/winhello.c
index 9de6c6c9b983..f9ab6061fd60 100644
--- a/src/winhello.c
+++ b/src/winhello.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 Yubico AB. All rights reserved.
+ * Copyright (c) 2021-2022 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.
*/
@@ -428,6 +428,42 @@ pack_cred_ext(WEBAUTHN_EXTENSIONS *out, const fido_cred_ext_t *in)
}
static int
+pack_assert_ext(WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS *out,
+ const fido_assert_ext_t *in)
+{
+ WEBAUTHN_HMAC_SECRET_SALT_VALUES *v;
+ WEBAUTHN_HMAC_SECRET_SALT *s;
+
+ if (in->mask == 0) {
+ return 0; /* nothing to do */
+ }
+ if (in->mask != FIDO_EXT_HMAC_SECRET) {
+ fido_log_debug("%s: mask 0x%x", __func__, in->mask);
+ return -1;
+ }
+ if (in->hmac_salt.ptr == NULL ||
+ in->hmac_salt.len != WEBAUTHN_CTAP_ONE_HMAC_SECRET_LENGTH) {
+ fido_log_debug("%s: salt %p/%zu", __func__,
+ (const void *)in->hmac_salt.ptr, in->hmac_salt.len);
+ return -1;
+ }
+ if ((v = calloc(1, sizeof(*v))) == NULL ||
+ (s = calloc(1, sizeof(*s))) == NULL) {
+ free(v);
+ fido_log_debug("%s: calloc", __func__);
+ return -1;
+ }
+ s->cbFirst = (DWORD)in->hmac_salt.len;
+ s->pbFirst = in->hmac_salt.ptr;
+ v->pGlobalHmacSalt = s;
+ out->pHmacSecretSaltValues = v;
+ out->dwFlags |= WEBAUTHN_AUTHENTICATOR_HMAC_SECRET_VALUES_FLAG;
+ out->dwVersion = WEBAUTHN_AUTHENTICATOR_GET_ASSERTION_OPTIONS_VERSION_6;
+
+ return 0;
+}
+
+static int
unpack_assert_authdata(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa)
{
int r;
@@ -500,6 +536,39 @@ unpack_user_id(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa)
}
static int
+unpack_hmac_secret(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa)
+{
+ if (wa->dwVersion != WEBAUTHN_ASSERTION_VERSION_3) {
+ fido_log_debug("%s: dwVersion %u", __func__,
+ (unsigned)wa->dwVersion);
+ return 0; /* proceed without hmac-secret */
+ }
+ if (wa->pHmacSecret == NULL ||
+ wa->pHmacSecret->cbFirst == 0 ||
+ wa->pHmacSecret->cbFirst > SIZE_MAX ||
+ wa->pHmacSecret->pbFirst == NULL) {
+ fido_log_debug("%s: hmac-secret absent", __func__);
+ return 0; /* proceed without hmac-secret */
+ }
+ if (wa->pHmacSecret->cbSecond != 0 ||
+ wa->pHmacSecret->pbSecond != NULL) {
+ fido_log_debug("%s: 64-byte hmac-secret", __func__);
+ return 0; /* proceed without hmac-secret */
+ }
+ if (!fido_blob_is_empty(&assert->stmt[0].hmac_secret)) {
+ fido_log_debug("%s: fido_blob_is_empty", __func__);
+ return -1;
+ }
+ if (fido_blob_set(&assert->stmt[0].hmac_secret,
+ wa->pHmacSecret->pbFirst, (size_t)wa->pHmacSecret->cbFirst) < 0) {
+ fido_log_debug("%s: fido_blob_set", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
translate_fido_assert(struct winhello_assert *ctx, const fido_assert_t *assert,
const char *pin, int ms)
{
@@ -510,11 +579,6 @@ translate_fido_assert(struct winhello_assert *ctx, const fido_assert_t *assert,
fido_log_debug("%s: up %d", __func__, assert->up);
return FIDO_ERR_UNSUPPORTED_OPTION;
}
- /* not implemented */
- if (assert->ext.mask) {
- fido_log_debug("%s: ext 0x%x", __func__, assert->ext.mask);
- return FIDO_ERR_UNSUPPORTED_EXTENSION;
- }
if ((ctx->rp_id = to_utf16(assert->rp_id)) == NULL) {
fido_log_debug("%s: rp_id", __func__);
return FIDO_ERR_INTERNAL;
@@ -531,6 +595,10 @@ translate_fido_assert(struct winhello_assert *ctx, const fido_assert_t *assert,
fido_log_debug("%s: pack_credlist", __func__);
return FIDO_ERR_INTERNAL;
}
+ if (pack_assert_ext(opt, &assert->ext) < 0) {
+ fido_log_debug("%s: pack_assert_ext", __func__);
+ return FIDO_ERR_UNSUPPORTED_EXTENSION;
+ }
if (set_assert_uv(&opt->dwUserVerificationRequirement, assert->uv,
pin) < 0) {
fido_log_debug("%s: set_assert_uv", __func__);
@@ -570,6 +638,11 @@ translate_winhello_assert(fido_assert_t *assert, const WEBAUTHN_ASSERTION *wa)
fido_log_debug("%s: unpack_user_id", __func__);
return FIDO_ERR_INTERNAL;
}
+ if (assert->ext.mask & FIDO_EXT_HMAC_SECRET &&
+ unpack_hmac_secret(assert, wa) < 0) {
+ fido_log_debug("%s: unpack_hmac_secret", __func__);
+ return FIDO_ERR_INTERNAL;
+ }
return FIDO_OK;
}
@@ -742,6 +815,9 @@ winhello_assert_free(struct winhello_assert *ctx)
free(ctx->rp_id);
free(ctx->opt.CredentialList.pCredentials);
+ if (ctx->opt.pHmacSecretSaltValues != NULL)
+ free(ctx->opt.pHmacSecretSaltValues->pGlobalHmacSalt);
+ free(ctx->opt.pHmacSecretSaltValues);
free(ctx);
}
@@ -883,7 +959,7 @@ fido_winhello_get_cbor_info(fido_dev_t *dev, fido_cbor_info_t *ci)
const char *v[3] = { "U2F_V2", "FIDO_2_0", "FIDO_2_1_PRE" };
const char *e[2] = { "credProtect", "hmac-secret" };
const char *t[2] = { "nfc", "usb" };
- const char *o[4] = { "rk", "up", "plat", "clientPin" };
+ const char *o[4] = { "rk", "up", "uv", "plat" };
(void)dev;
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index f37aa1d87c97..c81397f41fb9 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -65,13 +65,6 @@ add_executable(fido2-token
${COMPAT_SOURCES}
)
-# set the library to link against
-if(BUILD_SHARED_LIBS)
- set(_FIDO2_LIBRARY fido2_shared)
-else()
- set(_FIDO2_LIBRARY fido2)
-endif()
-
target_link_libraries(fido2-cred ${CRYPTO_LIBRARIES} ${_FIDO2_LIBRARY})
target_link_libraries(fido2-assert ${CRYPTO_LIBRARIES} ${_FIDO2_LIBRARY})
target_link_libraries(fido2-token ${CRYPTO_LIBRARIES} ${_FIDO2_LIBRARY})
diff --git a/tools/token.c b/tools/token.c
index 3d165623fdbf..9124e7b7fd29 100644
--- a/tools/token.c
+++ b/tools/token.c
@@ -156,6 +156,12 @@ print_maxcredidlen(uint64_t maxcredidlen)
}
static void
+print_maxlargeblob(uint64_t maxlargeblob)
+{
+ printf("maxlargeblob: %d\n", (int)maxlargeblob);
+}
+
+static void
print_fwversion(uint64_t fwversion)
{
printf("fwversion: 0x%x\n", (int)fwversion);
@@ -259,6 +265,9 @@ token_info(int argc, char **argv, char *path)
/* print maximum length of a credential ID */
print_maxcredidlen(fido_cbor_info_maxcredidlen(ci));
+ /* print maximum length of serialized largeBlob array */
+ print_maxlargeblob(fido_cbor_info_maxlargeblob(ci));
+
/* print firmware version */
print_fwversion(fido_cbor_info_fwversion(ci));
diff --git a/udev/70-u2f.rules b/udev/70-u2f.rules
index 0dfc3e276c7a..6e1f88bbd042 100644
--- a/udev/70-u2f.rules
+++ b/udev/70-u2f.rules
@@ -106,6 +106,9 @@ KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct
# SatoshiLabs TREZOR by pid.codes
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="53c1", TAG+="uaccess", GROUP="plugdev", MODE="0660"
+# SoloKeys v2 by pid.codes
+KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="beee", TAG+="uaccess", GROUP="plugdev", MODE="0660"
+
# Google Titan U2F by Google Inc.
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="5026", TAG+="uaccess", GROUP="plugdev", MODE="0660"
diff --git a/udev/fidodevs b/udev/fidodevs
index cea60a0be9fb..d519acd2ca73 100644
--- a/udev/fidodevs
+++ b/udev/fidodevs
@@ -72,6 +72,7 @@ product SILICON 0x8acf U2F Zero
product PIDCODES 0x5070 SoloKeys SoloHacker
product PIDCODES 0x50b0 SoloKeys SoloBoot
product PIDCODES 0x53c1 SatoshiLabs TREZOR
+product PIDCODES 0xbeee SoloKeys v2
product GOOGLE 0x5026 Google Titan U2F
diff --git a/windows/build.ps1 b/windows/build.ps1
index 56302444c80b..bd63c7f21095 100644
--- a/windows/build.ps1
+++ b/windows/build.ps1
@@ -1,4 +1,4 @@
-# Copyright (c) 2021 Yubico AB. All rights reserved.
+# Copyright (c) 2021-2022 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.
@@ -187,17 +187,15 @@ try {
& $CMake --build . --config ${Config} --verbose; ExitOnError
& $CMake --build . --config ${Config} --target install --verbose; `
ExitOnError
- # Patch up zlib's resulting names when built with --config Debug.
- if ("${Config}" -eq "Debug") {
- if ("${Type}" -eq "Dynamic") {
- Copy-Item "${PREFIX}/lib/zlibd.lib" `
- -Destination "${PREFIX}/lib/zlib.lib" -Force
- Copy-Item "${PREFIX}/bin/zlibd1.dll" `
- -Destination "${PREFIX}/bin/zlib1.dll" -Force
- } else {
- Copy-Item "${PREFIX}/lib/zlibstaticd.lib" `
- -Destination "${PREFIX}/lib/zlib.lib" -Force
- }
+ # Patch up zlib's various names.
+ if ("${Type}" -eq "Dynamic") {
+ ((Get-ChildItem -Path "${PREFIX}/lib") -Match "zlib[d]?.lib") |
+ Copy-Item -Destination "${PREFIX}/lib/zlib1.lib" -Force
+ ((Get-ChildItem -Path "${PREFIX}/bin") -Match "zlibd1.dll") |
+ Copy-Item -Destination "${PREFIX}/bin/zlib1.dll" -Force
+ } else {
+ ((Get-ChildItem -Path "${PREFIX}/lib") -Match "zlibstatic[d]?.lib") |
+ Copy-item -Destination "${PREFIX}/lib/zlib1.lib" -Force
}
} catch {
throw "Failed to build zlib"
@@ -225,11 +223,13 @@ try {
-DCMAKE_INSTALL_PREFIX="${PREFIX}" "${CMAKE_SYSTEM_VERSION}"; `
ExitOnError
& $CMake --build . --config ${Config} --verbose; ExitOnError
+ & $CMake --build . --config ${Config} --target regress --verbose; `
+ ExitOnError
& $CMake --build . --config ${Config} --target install --verbose; `
ExitOnError
# Copy DLLs.
if ("${SHARED}" -eq "ON") {
- "cbor.dll", "crypto-47.dll", "zlib1.dll" | `
+ "cbor.dll", "crypto-49.dll", "zlib1.dll" | `
%{ Copy-Item "${PREFIX}\bin\$_" `
-Destination "examples\${Config}" }
}
diff --git a/windows/const.ps1 b/windows/const.ps1
index 4aac8bb2853e..8acc2b2e829a 100644
--- a/windows/const.ps1
+++ b/windows/const.ps1
@@ -6,7 +6,7 @@
New-Variable -Name 'LIBRESSL_URL' `
-Value 'https://fastly.cdn.openbsd.org/pub/OpenBSD/LibreSSL' `
-Option Constant
-New-Variable -Name 'LIBRESSL' -Value 'libressl-3.4.2' -Option Constant
+New-Variable -Name 'LIBRESSL' -Value 'libressl-3.5.2' -Option Constant
# libcbor coordinates.
New-Variable -Name 'LIBCBOR' -Value 'libcbor-0.9.0' -Option Constant
@@ -15,8 +15,8 @@ New-Variable -Name 'LIBCBOR_GIT' -Value 'https://github.com/pjk/libcbor' `
-Option Constant
# zlib coordinates.
-New-Variable -Name 'ZLIB' -Value 'zlib-1.2.11' -Option Constant
-New-Variable -Name 'ZLIB_BRANCH' -Value 'v1.2.11' -Option Constant
+New-Variable -Name 'ZLIB' -Value 'zlib-1.2.12' -Option Constant
+New-Variable -Name 'ZLIB_BRANCH' -Value 'v1.2.12' -Option Constant
New-Variable -Name 'ZLIB_GIT' -Value 'https://github.com/madler/zlib' `
-Option Constant
diff --git a/windows/cygwin.ps1 b/windows/cygwin.ps1
index aada60b6f06f..6e602b6d9474 100755
--- a/windows/cygwin.ps1
+++ b/windows/cygwin.ps1
@@ -66,3 +66,4 @@ Start-Process "${Cygwin}\${Setup}" -Wait -NoNewWindow `
$Env:PATH = "${Root}\bin\;" + $Env:PATH
cmake "-DCMAKE_BUILD_TYPE=${Config}" -B "build-${Config}"
make -C "build-${Config}"
+make -C "build-${Config}" regress
diff --git a/windows/release.ps1 b/windows/release.ps1
index 9221bcaa3413..6f3f4e9600df 100644
--- a/windows/release.ps1
+++ b/windows/release.ps1
@@ -1,4 +1,4 @@
-# Copyright (c) 2021 Yubico AB. All rights reserved.
+# Copyright (c) 2021-2022 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.
@@ -7,7 +7,7 @@ $Architectures = @('x64', 'Win32', 'ARM64', 'ARM')
$InstallPrefixes = @('Win64', 'Win32', 'ARM64', 'ARM')
$Types = @('dynamic', 'static')
$Config = 'Release'
-$LibCrypto = '47'
+$LibCrypto = '49'
$SDK = '143'
. "$PSScriptRoot\const.ps1"
@@ -34,7 +34,7 @@ Function Package-Dynamic(${SRC}, ${DEST}) {
Copy-Item "${SRC}\bin\cbor.dll" "${DEST}"
Copy-Item "${SRC}\lib\cbor.lib" "${DEST}"
Copy-Item "${SRC}\bin\zlib1.dll" "${DEST}"
- Copy-Item "${SRC}\lib\zlib.lib" "${DEST}"
+ Copy-Item "${SRC}\lib\zlib1.lib" "${DEST}"
Copy-Item "${SRC}\bin\crypto-${LibCrypto}.dll" "${DEST}"
Copy-Item "${SRC}\lib\crypto-${LibCrypto}.lib" "${DEST}"
Copy-Item "${SRC}\bin\fido2.dll" "${DEST}"
@@ -43,7 +43,7 @@ Function Package-Dynamic(${SRC}, ${DEST}) {
Function Package-Static(${SRC}, ${DEST}) {
Copy-Item "${SRC}/lib/cbor.lib" "${DEST}"
- Copy-Item "${SRC}/lib/zlib.lib" "${DEST}"
+ Copy-Item "${SRC}/lib/zlib1.lib" "${DEST}"
Copy-Item "${SRC}/lib/crypto-${LibCrypto}.lib" "${DEST}"
Copy-Item "${SRC}/lib/fido2_static.lib" "${DEST}/fido2.lib"
}
@@ -54,19 +54,19 @@ Function Package-PDBs(${SRC}, ${DEST}) {
Copy-Item "${SRC}\${LIBCBOR}\src\cbor.dir\${Config}\vc${SDK}.pdb" `
"${DEST}\cbor.pdb"
Copy-Item "${SRC}\${ZLIB}\zlib.dir\${Config}\vc${SDK}.pdb" `
- "${DEST}\zlib.pdb"
+ "${DEST}\zlib1.pdb"
Copy-Item "${SRC}\src\fido2_shared.dir\${Config}\vc${SDK}.pdb" `
"${DEST}\fido2.pdb"
}
Function Package-StaticPDBs(${SRC}, ${DEST}) {
- Copy-Item "${SRC}\${LIBRESSL}\crypto\Release\crypto-${LibCrypto}.pdb" `
+ Copy-Item "${SRC}\${LIBRESSL}\crypto\crypto_obj.dir\${Config}\crypto_obj.pdb" `
"${DEST}\crypto-${LibCrypto}.pdb"
- Copy-Item "${SRC}\${LIBCBOR}\src\Release\cbor.pdb" `
+ Copy-Item "${SRC}\${LIBCBOR}\src\${Config}\cbor.pdb" `
"${DEST}\cbor.pdb"
- Copy-Item "${SRC}\${ZLIB}\Release\zlibstatic.pdb" `
- "${DEST}\zlib.pdb"
- Copy-Item "${SRC}\src\Release\fido2_static.pdb" `
+ Copy-Item "${SRC}\${ZLIB}\${Config}\zlibstatic.pdb" `
+ "${DEST}\zlib1.pdb"
+ Copy-Item "${SRC}\src\${Config}\fido2_static.pdb" `
"${DEST}\fido2.pdb"
}