From 173bfbf7886608a4a7abbfac6a42ac4bf4a3432d Mon Sep 17 00:00:00 2001 From: Colin Watson Date: Sun, 20 Sep 2020 16:14:20 +0100 Subject: New upstream version 1.5.0 --- .github/workflows/cifuzz_oss.yml | 23 -- .github/workflows/scan.yml | 36 --- .github/workflows/windows.yml | 14 -- .gitignore | 9 - .travis.yml | 86 -------- .travis/build-linux-clang | 22 -- .travis/build-linux-gcc | 19 -- .travis/build-linux-mingw | 47 ---- .travis/build-osx-clang | 24 -- .travis/fuzz-linux-asan | 59 ----- .travis/fuzz-linux-msan | 59 ----- CMakeLists.txt | 111 +++++----- NEWS | 18 ++ README.adoc | 27 ++- debian/changelog | 80 ------- debian/compat | 1 - debian/control | 53 ----- debian/copyright | 85 -------- debian/fido2-tools.install | 1 - debian/fido2-tools.manpages | 3 - debian/libfido2-1.install | 1 - debian/libfido2-1.symbols | 148 ------------- debian/libfido2-dev.install | 29 --- debian/libfido2-dev.links | 276 ----------------------- debian/libfido2-dev.manpages | 25 --- debian/libfido2-udev.install | 1 - debian/rules | 9 - debian/source/format | 1 - docker/bionic/Dockerfile | 14 -- examples/CMakeLists.txt | 16 ++ examples/README.adoc | 9 + examples/assert.c | 15 +- examples/cred.c | 15 +- examples/extern.h | 1 + examples/info.c | 31 ++- examples/manifest.c | 5 +- examples/reset.c | 9 +- examples/retries.c | 5 +- examples/select.c | 215 ++++++++++++++++++ examples/setpin.c | 5 +- examples/util.c | 3 +- fuzz/CMakeLists.txt | 1 + fuzz/Dockerfile | 9 +- fuzz/Makefile | 20 +- fuzz/README | 130 +---------- fuzz/build-coverage | 33 +-- fuzz/dummy.h | 4 +- fuzz/export.gnu | 10 + fuzz/functions.txt | 197 +++++++++-------- fuzz/fuzz_assert.c | 455 +++++++++++++++++++------------------- fuzz/fuzz_bio.c | 335 ++++++++++++++-------------- fuzz/fuzz_cred.c | 458 ++++++++++++++++++++++----------------- fuzz/fuzz_credman.c | 314 ++++++++++++++------------- fuzz/fuzz_mgmt.c | 321 +++++++++++++-------------- fuzz/libfuzzer.c | 174 +++++++++++++++ fuzz/mutator_aux.c | 253 ++++++--------------- fuzz/mutator_aux.h | 49 +++-- fuzz/prng.c | 3 +- fuzz/report.tgz | Bin 211709 -> 222723 bytes fuzz/summary.txt | 31 +-- man/CMakeLists.txt | 55 +++-- man/NOTES | 3 + man/fido2-assert.1 | 33 ++- man/fido2-cred.1 | 8 + man/fido_assert_new.3 | 35 ++- man/fido_cbor_info_new.3 | 22 +- man/fido_cred_new.3 | 65 +++++- man/fido_dev_get_touch_begin.3 | 73 +++++++ man/fido_dev_open.3 | 33 +++ openbsd-compat/clock_gettime.c | 32 +++ openbsd-compat/diff.sh | 24 -- openbsd-compat/openbsd-compat.h | 2 + openbsd-compat/time.h | 46 ++++ openbsd-compat/types.h | 7 - regress/assert.c | 16 +- regress/cred.c | 78 +++++++ src/CMakeLists.txt | 17 +- src/assert.c | 2 +- src/cbor.c | 25 +-- src/cred.c | 12 + src/credman.c | 8 +- src/dev.c | 207 +++++++++++++++++- src/diff_exports.sh | 29 +-- src/err.c | 4 + src/es256.c | 2 +- src/export.gnu | 9 + src/export.llvm | 9 + src/export.msvc | 9 + src/extern.h | 20 ++ src/fido.h | 23 +- src/fido/err.h | 2 + src/fido/param.h | 12 +- src/fido/types.h | 20 +- src/hid_hidapi.c | 226 +++++++++++++++++-- src/hid_linux.c | 308 +++++++++++++++++++------- src/hid_openbsd.c | 91 ++------ src/hid_osx.c | 323 +++++++++++++++++++-------- src/hid_win.c | 398 +++++++++++++++++++++++++--------- src/info.c | 16 ++ src/io.c | 94 ++++---- src/iso7816.c | 6 +- src/pin.c | 10 +- src/u2f.c | 100 ++++++++- tools/CMakeLists.txt | 7 + tools/assert_get.c | 94 ++++++-- tools/assert_verify.c | 12 +- tools/base64.c | 5 +- tools/cred_make.c | 26 ++- tools/cred_verify.c | 26 ++- tools/credman.c | 21 +- tools/extern.h | 6 +- tools/fido2-assert.c | 6 +- tools/fido2-attach.sh | 14 ++ tools/fido2-cred.c | 6 +- tools/fido2-detach.sh | 12 + tools/fido2-token.c | 6 +- tools/fido2-unprot.sh | 75 +++++++ tools/include_check.sh | 8 +- tools/macos_pkg.sh | 44 ---- tools/token.c | 18 ++ tools/util.c | 68 ++++++ udev/70-u2f.rules | 192 ++++++++++++---- udev/check.sh | 31 +++ udev/fidodevs | 110 ++++++++++ udev/genrules.awk | 55 +++++ windows/build.ps1 | 14 +- 126 files changed, 4474 insertions(+), 3303 deletions(-) delete mode 100644 .github/workflows/cifuzz_oss.yml delete mode 100644 .github/workflows/scan.yml delete mode 100644 .github/workflows/windows.yml delete mode 100644 .gitignore delete mode 100644 .travis.yml delete mode 100644 .travis/build-linux-clang delete mode 100644 .travis/build-linux-gcc delete mode 100644 .travis/build-linux-mingw delete mode 100644 .travis/build-osx-clang delete mode 100644 .travis/fuzz-linux-asan delete mode 100644 .travis/fuzz-linux-msan delete mode 100644 debian/changelog delete mode 100644 debian/compat delete mode 100644 debian/control delete mode 100644 debian/copyright delete mode 100644 debian/fido2-tools.install delete mode 100644 debian/fido2-tools.manpages delete mode 100644 debian/libfido2-1.install delete mode 100644 debian/libfido2-1.symbols delete mode 100644 debian/libfido2-dev.install delete mode 100644 debian/libfido2-dev.links delete mode 100644 debian/libfido2-dev.manpages delete mode 100644 debian/libfido2-udev.install delete mode 100755 debian/rules delete mode 100644 debian/source/format delete mode 100644 docker/bionic/Dockerfile create mode 100644 examples/select.c create mode 100644 fuzz/libfuzzer.c mode change 100755 => 100644 fuzz/prng.c create mode 100644 man/fido_dev_get_touch_begin.3 create mode 100644 openbsd-compat/clock_gettime.c delete mode 100755 openbsd-compat/diff.sh create mode 100644 openbsd-compat/time.h create mode 100755 tools/fido2-attach.sh create mode 100755 tools/fido2-detach.sh create mode 100755 tools/fido2-unprot.sh delete mode 100755 tools/macos_pkg.sh create mode 100755 udev/check.sh create mode 100644 udev/fidodevs create mode 100755 udev/genrules.awk diff --git a/.github/workflows/cifuzz_oss.yml b/.github/workflows/cifuzz_oss.yml deleted file mode 100644 index cbb334c..0000000 --- a/.github/workflows/cifuzz_oss.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: CIFuzz -on: [pull_request] -jobs: - Fuzzing: - runs-on: ubuntu-latest - steps: - - name: Build Fuzzers - uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master - with: - oss-fuzz-project-name: 'libfido2' - dry-run: false - - name: Run Fuzzers - uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master - with: - oss-fuzz-project-name: 'libfido2' - fuzz-seconds: 600 - dry-run: false - - name: Upload Crash - uses: actions/upload-artifact@v1 - if: failure() - with: - name: artifacts - path: ./out/artifacts diff --git a/.github/workflows/scan.yml b/.github/workflows/scan.yml deleted file mode 100644 index 008961b..0000000 --- a/.github/workflows/scan.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: static code analysis - -on: - push: - schedule: - - cron: '0 0 * * 1' - -env: - SCAN_IMG: - yes-docker-local.artifactory.in.yubico.org/static-code-analysis/c:v1 - SECRET: ${{ secrets.ARTIFACTORY_READER_TOKEN }} - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@master - - - name: Scan but do not fail on warnings - run: | - if [ "${SECRET}" != "" ]; then - docker login yes-docker-local.artifactory.in.yubico.org/ \ - -u svc-static-code-analysis-reader \ - -p ${{ secrets.ARTIFACTORY_READER_TOKEN }} - docker pull ${SCAN_IMG} - docker run -v${PWD}:/k -e COMPILE_DEPS="${COMPILE_DEPS}" \ - -e PROJECT_NAME=${GITHUB_REPOSITORY#Yubico/} -t ${SCAN_IMG} - fi - continue-on-error: true - - - uses: actions/upload-artifact@master - if: failure() - with: - name: suppression_files - path: suppression_files diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml deleted file mode 100644 index eb953db..0000000 --- a/.github/workflows/windows.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: windows - -on: [push] - -jobs: - build: - - runs-on: windows-latest - - steps: - - uses: actions/checkout@v1 - - name: build - run: .\windows\build.ps1 - diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 0915625..0000000 --- a/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -build/ -cscope.out -fuzz/build/ -fuzz/corpus.tgz- -fuzz/fuzz_*/ -fuzz/obj/ -fuzz/report -fuzz/*.so -output/ diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c2bff78..0000000 --- a/.travis.yml +++ /dev/null @@ -1,86 +0,0 @@ -language: c - -matrix: - include: - - os: linux - compiler: clang-7 - dist: xenial - sudo: required - addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-xenial-7 - packages: - - clang-7 - - cmake - - libssl-dev - - libudev-dev - script: /bin/sh -eux .travis/build-linux-clang - - os: linux - compiler: gcc-7 - dist: xenial - sudo: required - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - gcc-7 - - cmake - - libssl-dev - - libudev-dev - script: /bin/sh -eux .travis/build-linux-gcc - - os: linux - compiler: i686-w64-mingw32-gcc-4.8 - dist: xenial - sudo: required - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - binutils-mingw-w64-i686 - - gcc-mingw-w64 - - g++-mingw-w64 - - mingw-w64-i686-dev - - cmake - script: /bin/sh -eux .travis/build-linux-mingw - - os: osx - osx_image: xcode10.2 - compiler: clang - sudo: required - script: /bin/sh -eux .travis/build-osx-clang - - os: linux - compiler: clang-7 - dist: bionic - sudo: required - addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-xenial-7 - packages: - - clang-7 - - cmake - - libssl-dev - - libudev-dev - script: /bin/sh -eux .travis/fuzz-linux-asan - - os: linux - compiler: clang-7 - dist: bionic - sudo: required - addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-xenial-7 - packages: - - clang-7 - - cmake - - libssl-dev - - libudev-dev - script: /bin/sh -eux .travis/fuzz-linux-msan - -notifications: - email: false diff --git a/.travis/build-linux-clang b/.travis/build-linux-clang deleted file mode 100644 index 8938461..0000000 --- a/.travis/build-linux-clang +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh -eux - -${CC} --version - -# Check exports. -(cd src && ./diff_exports.sh) - -# Build and install libcbor. -git clone git://github.com/pjk/libcbor -cd libcbor -git checkout v0.5.0 -mkdir build -(cd build && cmake ..) -make -C build -sudo make -C build install -cd .. - -# Build, analyze, and install libfido2. -mkdir build -(cd build && scan-build cmake -DCMAKE_BUILD_TYPE=Debug ..) -scan-build --status-bugs make -C build -sudo make -C build install diff --git a/.travis/build-linux-gcc b/.travis/build-linux-gcc deleted file mode 100644 index be1e0a9..0000000 --- a/.travis/build-linux-gcc +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh -eux - -${CC} --version - -# Build and install libcbor. -git clone git://github.com/pjk/libcbor -cd libcbor -git checkout v0.5.0 -mkdir build -(cd build && cmake ..) -make -C build -sudo make -C build install -cd .. - -# Build and install libfido2. -mkdir build -(cd build && cmake -DCMAKE_BUILD_TYPE=Debug ..) -make -C build -sudo make -C build install diff --git a/.travis/build-linux-mingw b/.travis/build-linux-mingw deleted file mode 100644 index c88ddca..0000000 --- a/.travis/build-linux-mingw +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/sh -eux - -# XXX defining CC and cross-compiling confuses OpenSSL's build. -unset CC - -sudo mkdir /fakeroot -sudo chmod 755 /fakeroot - -cat << EOF > /tmp/mingw.cmake -SET(CMAKE_SYSTEM_NAME Windows) -SET(CMAKE_C_COMPILER i686-w64-mingw32-gcc) -SET(CMAKE_CXX_COMPILER i686-w64-mingw32-g++) -SET(CMAKE_RC_COMPILER i686-w64-mingw32-windres) -SET(CMAKE_FIND_ROOT_PATH /fakeroot) -SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) -SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -EOF - -# Build and install libcbor. -git clone git://github.com/pjk/libcbor -cd libcbor -git checkout v0.5.0 -mkdir build -(cd build && cmake -DCMAKE_TOOLCHAIN_FILE=/tmp/mingw.cmake \ - -DCMAKE_INSTALL_PREFIX=/fakeroot ..) -make -C build -sudo make -C build install -cd .. - -# Build and install OpenSSL 1.1.0j. -git clone git://github.com/openssl/openssl -cd openssl -git checkout OpenSSL_1_1_0j -./Configure mingw --prefix=/fakeroot --openssldir=/fakeroot/openssl \ - --cross-compile-prefix=i686-w64-mingw32- -make -sudo make install_sw -cd .. - -# Build and install libfido2. -export PKG_CONFIG_PATH=/fakeroot/lib/pkgconfig -mkdir build -(cd build && cmake -DCMAKE_TOOLCHAIN_FILE=/tmp/mingw.cmake \ - -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/fakeroot ..) -make -C build -sudo make -C build install diff --git a/.travis/build-osx-clang b/.travis/build-osx-clang deleted file mode 100644 index 69a784c..0000000 --- a/.travis/build-osx-clang +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -eux - -${CC} --version - -# Build and install libcbor. -git clone git://github.com/pjk/libcbor -cd libcbor -git checkout v0.5.0 -mkdir build -(cd build && cmake ..) -make -C build -sudo make -C build install -cd .. - -# Install mandoc from Homebrew. -brew install mandoc - -# Build and install libfido2. -export PKG_CONFIG_PATH=/usr/local/opt/openssl@1.1/lib/pkgconfig -mkdir build -(cd build && cmake -DCMAKE_BUILD_TYPE=Debug ..) -make -C build -make -C build man_symlink_html -sudo make -C build install diff --git a/.travis/fuzz-linux-asan b/.travis/fuzz-linux-asan deleted file mode 100644 index af8a08c..0000000 --- a/.travis/fuzz-linux-asan +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/sh -eux - -${CC} --version - -FAKEROOT=/fakeroot -sudo mkdir ${FAKEROOT} -sudo chmod 755 ${FAKEROOT} - -# Build and install libcbor. -git clone git://github.com/pjk/libcbor -cd libcbor -patch -p0 < ../fuzz/README -mkdir build -cd build -cmake -DCMAKE_C_FLAGS_DEBUG="-g2 -fno-omit-frame-pointer" \ - -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=Debug \ - -DCMAKE_INSTALL_PREFIX=${FAKEROOT} -DSANITIZE=ON \ - -DCMAKE_INSTALL_LIBDIR=lib .. -make -sudo make install -cd ../.. - -# Build and install OpenSSL 1.1.1b. -git clone git://github.com/openssl/openssl -cd openssl -git checkout OpenSSL_1_1_1b -./Configure linux-x86_64-clang enable-asan --prefix=${FAKEROOT} \ - --openssldir=${FAKEROOT}/openssl -make clean -make -sudo make install_sw -cd .. - -# Build libfido2. -mkdir build -cd build -export PKG_CONFIG_PATH=/fakeroot/lib/pkgconfig -cmake -DFUZZ=1 -DLIBFUZZER=1 -DASAN=1 -DUBSAN=1 -DCMAKE_C_COMPILER=clang \ - -DCRYPTO_INCLUDE_DIRS=${FAKEROOT}/include \ - -DCRYPTO_LIBRARY_DIRS=${FAKEROOT}/lib \ - -DCBOR_INCLUDE_DIRS=${FAKEROOT}/include \ - -DCBOR_LIBRARY_DIRS=${FAKEROOT}/lib \ - -DCMAKE_BUILD_TYPE=Debug .. -make - -# Fuzz with ASAN. -mkdir corpus -curl -s https://ambientworks.net/tmp/corpus.tgz > ../fuzz/corpus.tgz -tar -C corpus -zxf ../fuzz/corpus.tgz -fuzz/fuzz_cred -use_value_profile=1 -reload=30 -print_pcs=1 \ - -print_funcs=30 -timeout=10 -runs=1 corpus/fuzz_cred -fuzz/fuzz_assert -use_value_profile=1 -reload=30 -print_pcs=1 \ - -print_funcs=30 -timeout=10 -runs=1 corpus/fuzz_assert -fuzz/fuzz_credman -use_value_profile=1 -reload=30 -print_pcs=1 \ - -print_funcs=30 -timeout=10 -runs=1 corpus/fuzz_credman -fuzz/fuzz_mgmt -use_value_profile=1 -reload=30 -print_pcs=1 \ - -print_funcs=30 -timeout=10 -runs=1 corpus/fuzz_mgmt -fuzz/fuzz_bio -use_value_profile=1 -reload=30 -print_pcs=1 \ - -print_funcs=30 -timeout=10 -runs=1 corpus/fuzz_bio diff --git a/.travis/fuzz-linux-msan b/.travis/fuzz-linux-msan deleted file mode 100644 index e67ab22..0000000 --- a/.travis/fuzz-linux-msan +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/sh -eux - -${CC} --version - -FAKEROOT=/fakeroot -sudo mkdir ${FAKEROOT} -sudo chmod 755 ${FAKEROOT} - -# Build and install libcbor. -git clone git://github.com/pjk/libcbor -cd libcbor -patch -p0 < ../fuzz/README -mkdir build -cd build -cmake -DCMAKE_C_FLAGS_DEBUG="-fsanitize=memory,undefined -g2 -fno-omit-frame-pointer" \ - -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=Debug \ - -DCMAKE_INSTALL_PREFIX=${FAKEROOT} -DSANITIZE=OFF \ - -DCMAKE_INSTALL_LIBDIR=lib .. -make -sudo make install -cd ../.. - -# Build and install OpenSSL 1.1.1b. -git clone git://github.com/openssl/openssl -cd openssl -git checkout OpenSSL_1_1_1b -./Configure linux-x86_64-clang enable-msan --prefix=${FAKEROOT} \ - --openssldir=${FAKEROOT}/openssl -make clean -make -sudo make install_sw -cd .. - -# Build libfido2. -mkdir build -cd build -export PKG_CONFIG_PATH=/fakeroot/lib/pkgconfig -cmake -DFUZZ=1 -DLIBFUZZER=1 -DMSAN=1 -DUBSAN=1 -DCMAKE_C_COMPILER=clang \ - -DCRYPTO_INCLUDE_DIRS=${FAKEROOT}/include \ - -DCRYPTO_LIBRARY_DIRS=${FAKEROOT}/lib \ - -DCBOR_INCLUDE_DIRS=${FAKEROOT}/include \ - -DCBOR_LIBRARY_DIRS=${FAKEROOT}/lib \ - -DCMAKE_BUILD_TYPE=Debug .. -make - -# Fuzz with MSAN. -mkdir corpus -curl -s https://ambientworks.net/tmp/corpus.tgz > ../fuzz/corpus.tgz -tar -C corpus -zxf ../fuzz/corpus.tgz -fuzz/fuzz_cred -use_value_profile=1 -reload=30 -print_pcs=1 \ - -print_funcs=30 -timeout=10 -runs=1 corpus/fuzz_cred -fuzz/fuzz_assert -use_value_profile=1 -reload=30 -print_pcs=1 \ - -print_funcs=30 -timeout=10 -runs=1 corpus/fuzz_assert -fuzz/fuzz_credman -use_value_profile=1 -reload=30 -print_pcs=1 \ - -print_funcs=30 -timeout=10 -runs=1 corpus/fuzz_credman -fuzz/fuzz_mgmt -use_value_profile=1 -reload=30 -print_pcs=1 \ - -print_funcs=30 -timeout=10 -runs=1 corpus/fuzz_mgmt -fuzz/fuzz_bio -use_value_profile=1 -reload=30 -print_pcs=1 \ - -print_funcs=30 -timeout=10 -runs=1 corpus/fuzz_bio diff --git a/CMakeLists.txt b/CMakeLists.txt index 0bb2e87..dbd5fa5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,8 @@ cmake_minimum_required(VERSION 3.0) include(CheckCCompilerFlag) include(CheckFunctionExists) +include(CheckLibraryExists) +include(CheckSymbolExists) include(CheckIncludeFiles) include(CheckTypeSize) include(GNUInstallDirs) @@ -19,7 +21,7 @@ set(CMAKE_VERBOSE_MAKEFILE on) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(FIDO_MAJOR "1") -set(FIDO_MINOR "4") +set(FIDO_MINOR "5") set(FIDO_PATCH "0") set(FIDO_VERSION ${FIDO_MAJOR}.${FIDO_MINOR}.${FIDO_PATCH}) @@ -33,21 +35,12 @@ if(CYGWIN OR MSYS) endif() if(WIN32) - add_definitions(-DWIN32_LEAN_AND_MEAN) + add_definitions(-DWIN32_LEAN_AND_MEAN -D_WIN32_WINNT=0x0600) endif() if(APPLE) set(CMAKE_INSTALL_NAME_DIR - "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") -endif() - -# Observe OpenBSD's library versioning scheme. -if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") - set(LIB_VERSION ${FIDO_MAJOR}.${FIDO_MINOR}) - set(LIB_SOVERSION ${LIB_VERSION}) -else() - set(LIB_VERSION ${FIDO_VERSION}) - set(LIB_SOVERSION ${FIDO_MAJOR}) + "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") endif() if(MSVC) @@ -58,7 +51,7 @@ if(MSVC) "under msvc") endif() set(CBOR_LIBRARIES cbor) - set(CRYPTO_LIBRARIES crypto-45) + set(CRYPTO_LIBRARIES crypto-46) set(MSVC_DISABLED_WARNINGS_LIST "C4200" # nonstandard extension used: zero-sized array in # struct/union; @@ -71,9 +64,9 @@ if(MSVC) # The construction in the following 3 lines was taken from LibreSSL's # CMakeLists.txt. string(REPLACE "C" " -wd" MSVC_DISABLED_WARNINGS_STR - ${MSVC_DISABLED_WARNINGS_LIST}) + ${MSVC_DISABLED_WARNINGS_LIST}) string(REGEX REPLACE "[/-]W[1234][ ]?" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS}) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -MP -W4 ${MSVC_DISABLED_WARNINGS_STR}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -MP -W4 -WX ${MSVC_DISABLED_WARNINGS_STR}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Z7") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zi") else() @@ -102,13 +95,18 @@ else() if(CMAKE_SYSTEM_NAME STREQUAL "Linux") pkg_search_module(UDEV libudev REQUIRED) set(UDEV_NAME "udev") + include_directories(${UDEV_INCLUDE_DIRS}) + link_directories(${UDEV_LIBRARY_DIRS}) # Define be32toh(). add_definitions(-D_GNU_SOURCE) # If using hidapi, use hidapi-hidraw. set(HIDAPI_SUFFIX -hidraw) - elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR - CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") - set(BASE_LIBRARIES usbhid) + # Look for clock_gettime in librt. + check_library_exists(rt clock_gettime "time.h" HAVE_CLOCK_GETTIME) + if(HAVE_CLOCK_GETTIME) + set(BASE_LIBRARIES ${BASE_LIBRARIES} rt) + add_definitions(-DHAVE_CLOCK_GETTIME) + endif() endif() if(MINGW) @@ -122,6 +120,8 @@ else() add_definitions(-DUSE_HIDAPI) pkg_search_module(HIDAPI hidapi${HIDAPI_SUFFIX} REQUIRED) if(HIDAPI_FOUND) + include_directories(${HIDAPI_INCLUDE_DIRS}) + link_directories(${HIDAPI_LIBRARY_DIRS}) set(HIDAPI_LIBRARIES hidapi${HIDAPI_SUFFIX}) endif() endif() @@ -153,24 +153,6 @@ else() endif() add_definitions(-DFIDO_FUZZ) endif() - - if(ASAN) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address,leak") - endif() - - if(MSAN) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-memory-track-origins") - endif() - - if(UBSAN) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-trap=undefined") - endif() - - if(COVERAGE) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-instr-generate -fcoverage-mapping") - endif() endif() # Use -Wshorten-64-to-32 if available. @@ -333,6 +315,20 @@ if(UNIX) add_definitions(-DHAVE_DEV_URANDOM) endif() +# clock_gettime +if(NOT HAVE_CLOCK_GETTIME) + check_function_exists(clock_gettime HAVE_CLOCK_GETTIME) + if(HAVE_CLOCK_GETTIME) + add_definitions(-DHAVE_CLOCK_GETTIME) + endif() +endif() + +# timespecsub +check_symbol_exists(timespecsub sys/time.h HAVE_TIMESPECSUB) +if(HAVE_TIMESPECSUB) + add_definitions(-DHAVE_TIMESPECSUB) +endif() + # export list if(APPLE AND (CMAKE_C_COMPILER_ID STREQUAL "Clang" OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang")) @@ -366,7 +362,7 @@ elseif(NOT MSVC) endif() else() string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} - " /def:\"${CMAKE_CURRENT_SOURCE_DIR}/src/export.msvc\"") + " /def:\"${CMAKE_CURRENT_SOURCE_DIR}/src/export.msvc\"") endif() include_directories(${CMAKE_SOURCE_DIR}/src) @@ -376,38 +372,33 @@ include_directories(${CRYPTO_INCLUDE_DIRS}) link_directories(${CBOR_LIBRARY_DIRS}) link_directories(${CRYPTO_LIBRARY_DIRS}) +message(STATUS "BASE_LIBRARIES: ${BASE_LIBRARIES}") +message(STATUS "CBOR_INCLUDE_DIRS: ${CBOR_INCLUDE_DIRS}") +message(STATUS "CBOR_LIBRARIES: ${CBOR_LIBRARIES}") +message(STATUS "CBOR_LIBRARY_DIRS: ${CBOR_LIBRARY_DIRS}") +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_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}") message(STATUS "CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR}") -message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") -message(STATUS "CBOR_INCLUDE_DIRS: ${CBOR_INCLUDE_DIRS}") -message(STATUS "CBOR_LIBRARY_DIRS: ${CBOR_LIBRARY_DIRS}") -message(STATUS "CBOR_LIBRARIES: ${CBOR_LIBRARIES}") +message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}") message(STATUS "CRYPTO_INCLUDE_DIRS: ${CRYPTO_INCLUDE_DIRS}") -message(STATUS "CRYPTO_LIBRARY_DIRS: ${CRYPTO_LIBRARY_DIRS}") message(STATUS "CRYPTO_LIBRARIES: ${CRYPTO_LIBRARIES}") -message(STATUS "BASE_LIBRARIES: ${BASE_LIBRARIES}") -message(STATUS "HIDAPI_LIBRARIES: ${HIDAPI_LIBRARIES}") -message(STATUS "VERSION: ${FIDO_VERSION}") -message(STATUS "LIB_VERSION: ${LIB_VERSION}") -message(STATUS "LIB_SOVERSION: ${LIB_SOVERSION}") +message(STATUS "CRYPTO_LIBRARY_DIRS: ${CRYPTO_LIBRARY_DIRS}") +message(STATUS "FIDO_VERSION: ${FIDO_VERSION}") message(STATUS "FUZZ: ${FUZZ}") -message(STATUS "AFL: ${AFL}") +if(USE_HIDAPI) + message(STATUS "HIDAPI_INCLUDE_DIRS: ${HIDAPI_INCLUDE_DIRS}") + message(STATUS "HIDAPI_LIBRARIES: ${HIDAPI_LIBRARIES}") + message(STATUS "HIDAPI_LIBRARY_DIRS: ${HIDAPI_LIBRARY_DIRS}") +endif() message(STATUS "LIBFUZZER: ${LIBFUZZER}") -message(STATUS "ASAN: ${ASAN}") -message(STATUS "MSAN: ${MSAN}") -message(STATUS "COVERAGE: ${COVERAGE}") message(STATUS "TLS: ${TLS}") +message(STATUS "UDEV_INCLUDE_DIRS: ${UDEV_INCLUDE_DIRS}") +message(STATUS "UDEV_LIBRARIES: ${UDEV_LIBRARIES}") +message(STATUS "UDEV_LIBRARY_DIRS: ${UDEV_LIBRARY_DIRS}") +message(STATUS "UDEV_RULES_DIR: ${UDEV_RULES_DIR}") message(STATUS "USE_HIDAPI: ${USE_HIDAPI}") -if(CMAKE_SYSTEM_NAME STREQUAL "Linux") - message(STATUS "UDEV_INCLUDE_DIRS: ${UDEV_INCLUDE_DIRS}") - message(STATUS "UDEV_LIBRARY_DIRS: ${UDEV_LIBRARY_DIRS}") - message(STATUS "UDEV_LIBRARIES: ${UDEV_LIBRARIES}") - message(STATUS "UDEV_RULES_DIR: ${UDEV_RULES_DIR}") -endif() - subdirs(src) subdirs(examples) subdirs(tools) @@ -415,7 +406,7 @@ subdirs(man) if(NOT WIN32) if(CMAKE_BUILD_TYPE STREQUAL "Debug") - if(NOT MSAN AND NOT LIBFUZZER) + if(NOT LIBFUZZER AND NOT FUZZ) subdirs(regress) endif() endif() diff --git a/NEWS b/NEWS index 153ff71..b651ca0 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,21 @@ +* Version 1.5.0 (2020-09-01) + ** hid_linux: return FIDO_OK if no devices are found. + ** hid_osx: + - repair communication with U2F tokens, gh#166; + - reliability fixes. + ** fido2-{assert,cred}: new options to explicitly toggle UP, UV. + ** Support for configurable report lengths. + ** New API calls: + - fido_cbor_info_maxcredcntlst; + - fido_cbor_info_maxcredidlen; + - fido_cred_aaguid_len; + - fido_cred_aaguid_ptr; + - fido_dev_get_touch_begin; + - fido_dev_get_touch_status. + ** Use COSE_ECDH_ES256 with CTAP_CBOR_CLIENT_PIN; gh#154. + ** Allow CTAP messages up to 2048 bytes; gh#171. + ** Ensure we only list USB devices by default. + * Version 1.4.0 (2020-04-15) ** hid_hidapi: hidapi backend; enable with -DUSE_HIDAPI=1. ** Fall back to U2F if the key claims to, but does not support FIDO2. diff --git a/README.adoc b/README.adoc index f389a83..6fe0272 100644 --- a/README.adoc +++ b/README.adoc @@ -1,8 +1,10 @@ == libfido2 -image:https://api.travis-ci.org/Yubico/libfido2.svg?branch=master["Build Status (Travis)", link="https://travis-ci.org/Yubico/libfido2"] -image:https://github.com/yubico/libfido2/workflows/windows/badge.svg["windows build status (github actions)", link="https://github.com/Yubico/libfido2/actions"] -image:https://img.shields.io/badge/license-BSD-blue.svg["License", link="https://raw.githubusercontent.com/Yubico/libfido2/master/LICENSE"] +image:https://github.com/yubico/libfido2/workflows/linux/badge.svg["Linux Build Status (github actions)", link="https://github.com/Yubico/libfido2/actions"] +image:https://github.com/yubico/libfido2/workflows/macos/badge.svg["macOS Build Status (github actions)", link="https://github.com/Yubico/libfido2/actions"] +image:https://github.com/yubico/libfido2/workflows/windows/badge.svg["Windows Build Status (github actions)", link="https://github.com/Yubico/libfido2/actions"] +image:https://github.com/yubico/libfido2/workflows/fuzzer/badge.svg["Fuzz Status (github actions)", link="https://github.com/Yubico/libfido2/actions"] +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 @@ -14,7 +16,7 @@ For usage, see the `examples/` directory. === License -*libfido2* is licensed under the BSD 2-clause license. See the _LICENSE_ +*libfido2* is licensed under the BSD 2-clause license. See the LICENSE file for the full license text. === Supported Platforms @@ -31,11 +33,17 @@ is also available. ==== Releases -The current release of *libfido2* is 1.4.0. Please consult Yubico's +The current release of *libfido2* is 1.5.0. Please consult Yubico's https://developers.yubico.com/libfido2/Releases[release page] for source and binary releases. -==== Ubuntu +==== Ubuntu 20.04 (Focal) + + $ sudo apt install libfido2-1 + $ sudo apt install libfido2-dev + $ sudo apt install libfido2-doc + +==== Ubuntu 18.04 (Bionic) and 16.04 (Xenial) $ sudo apt install software-properties-common $ sudo apt-add-repository ppa:yubico/stable @@ -52,15 +60,16 @@ Or from source, on UNIX-like systems: $ make -C build $ sudo make -C build install -Depending on the platform, the PKG_CONFIG_PATH environment variable may need to -be set. +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] and https://www.openssl.org[OpenSSL]. 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 -`.travis/` (Linux, MacOS) and `windows/` directories. +`.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: diff --git a/debian/changelog b/debian/changelog deleted file mode 100644 index 7502d61..0000000 --- a/debian/changelog +++ /dev/null @@ -1,80 +0,0 @@ -libfido2 (1.2.0~ppa1~bionic1) bionic; urgency=low - - * Credential management support. - * New API reflecting FIDO's 3-state booleans (true, false, absent): - - fido_assert_set_up; - - fido_assert_set_uv; - - fido_cred_set_rk; - - fido_cred_set_uv. - * Command-line tools for Windows. - * Documentation and reliability fixes. - * fido_{assert,cred}_set_options() are now marked as deprecated. - - -- pedro martelletto Fri, 23 Aug 2019 12:08:02 +0000 - -libfido2 (1.1.0) bionic; urgency=low - - * MacOS: fix IOKit crash on HID read. - * Windows: fix contents of release file. - * EdDSA (Ed25519) support. - * fido_dev_make_cred: fix order of CBOR map keys. - * fido_dev_get_assert: plug memory leak when operating on U2F devices. - - -- pedro martelletto Tue, 07 May 2019 08:03:21 +0000 - -libfido2 (1.0.0) bionic; urgency=low - - * Native HID support on Linux, MacOS, and Windows. - * fido2-{assert,cred}: new -u option to force U2F on dual authenticators. - * fido2-assert: support for multiple resident keys with the same RP. - * Strict checks for CTAP2 compliance on received CBOR payloads. - * Better fuzzing harnesses. - * Documentation and reliability fixes. - - -- pedro martelletto Tue, 19 Mar 2019 07:38:36 +0000 - -libfido2 (0.4.0) bionic; urgency=low - - * fido2-assert: print the user id for resident credentials. - * Fix encoding of COSE algorithms when making a credential. - * Rework purpose of fido_cred_set_type; no ABI change. - * Minor documentation and code fixes. - - -- pedro martelletto Mon, 07 Jan 2019 08:22:01 +0000 - -libfido2 (0.3.0) bionic; urgency=low - - * Various reliability fixes. - * Merged fuzzing instrumentation. - * Added regress tests. - * Added support for FIDO 2's hmac-secret extension. - * New API calls: - - fido_assert_hmac_secret_len; - - fido_assert_hmac_secret_ptr; - - fido_assert_set_extensions; - - fido_assert_set_hmac_salt; - - fido_cred_set_extensions; - - fido_dev_force_fido2. - * Support for native builds with Microsoft Visual Studio 17. - - -- pedro martelletto Tue, 11 Sep 2018 09:05:32 +0000 - -libfido2 (0.2.0) bionic; urgency=low - - * Added command-line tools. - * Added a couple of missing get functions. - - -- pedro martelletto Mon, 18 Jun 2018 10:44:11 +0000 - -libfido2 (0.1.1~dev) bionic; urgency=low - - * Added documentation. - * Minor fixes. - - -- pedro martelletto Wed, 30 May 2018 13:16:28 +0000 - -libfido2 (0.1.0~dev) bionic; urgency=low - - * Initial release. - - -- pedro martelletto Fri, 18 May 2018 08:47:01 +0000 diff --git a/debian/compat b/debian/compat deleted file mode 100644 index ec63514..0000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/debian/control b/debian/control deleted file mode 100644 index 50b9482..0000000 --- a/debian/control +++ /dev/null @@ -1,53 +0,0 @@ -Source: libfido2 -Priority: optional -Maintainer: Yubico Open Source Maintainers -Uploaders: pedro martelletto -Standards-Version: 4.1.2 -Section: libs -Homepage: https://github.com/yubico/libfido2 -Build-Depends: debhelper (>= 9), - pkg-config, - cmake, - mandoc, - libcbor-dev, - libssl-dev, - libudev-dev - -Package: libfido2-1 -Architecture: any -Multi-Arch: same -Depends: libcbor0, libssl1.1, libudev1, ${shlibs:Depends}, ${misc:Depends} -Description: library for generating and verifying FIDO 2.0 objects - A library for communicating with a FIDO device over USB, and for verifying - attestation and assertion signatures. FIDO U2F (CTAP 1) and FIDO 2.0 (CTAP 2) - are supported. This package contains the runtime library. - -Package: libfido2-dev -Section: libdevel -Architecture: any -Multi-Arch: same -Depends: libfido2-1 (= ${binary:Version}), ${misc:Depends} -Suggests: libssl-dev -Description: library for generating and verifying FIDO 2.0 objects (development headers) - A library for communicating with a FIDO device over USB, and for verifying - attestation and assertion signatures. FIDO U2F (CTAP 1) and FIDO 2.0 (CTAP 2) - are supported. This package contains the development headers. - -Package: fido2-tools -Section: utils -Architecture: any -Multi-Arch: foreign -Depends: libfido2-1 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends} -Description: command-line tools to configure and use a FIDO 2 token - A set of tools to manage a FIDO 2 token, generate credentials and - assertions, and verify them. - -Package: libfido2-udev -Section: libs -Architecture: all -Multi-Arch: foreign -Depends: ${misc:Depends} -Conflicts: libu2f-udev -Description: udev rules for access to U2F and FIDO2 devices - A set of udev rules allowing unprivileged system-level access - to U2F and FIDO2 USB devices for logged-on users. diff --git a/debian/copyright b/debian/copyright deleted file mode 100644 index 3ba51ef..0000000 --- a/debian/copyright +++ /dev/null @@ -1,85 +0,0 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: libfido2 -Source: https://github.com/yubico/libfido2 - -Files: * -Copyright: Copyright (c) 2018 Yubico AB. All rights reserved. -License: BSD-2-clause - -Files: openbsd-compat/strlcpy.c openbsd-compat/strlcat.c -Copyright: Copyright (c) 1998 Todd C. Miller -License: ISC - -Files: src/compat/timingsafe_bcmp.c -Copyright: Copyright (c) 2010 Damien Miller. All rights reserved. -License: ISC - -Files: - openbsd-compat/bsd-getpagesize.c - openbsd-compat/err.h - openbsd-compat/explicit_bzero.c - openbsd-compat/explicit_bzero_win32.c - openbsd-compat/types.h -Copyright: Public domain -License: public-domain - -Files: openbsd-compat/recallocarray.c -Copyright: Copyright (c) 2008, 2017 Otto Moerbeek -License: ISC - -Files: openbsd-compat/readpassphrase.h -Copyright: Copyright (c) 2000, 2002 Todd C. Miller -License: ISC - -Files: openbsd-compat/readpassphrase.c -Copyright: Copyright (c) 2000-2002, 2007, 2010 Todd C. Miller -License: ISC - -Files: openbsd-compat/getopt.h -Copyright: Copyright (c) 2000 The NetBSD Foundation, Inc. All rights reserved. -License: BSD-2-clause - -Files: openbsd-compat/getopt_long.c -Copyright: Copyright (c) 2002 Todd C. Miller - Copyright (c) 2000 The NetBSD Foundation, Inc. All rights reserved. -License: ISC and BSD-2-clause - -License: BSD-2-clause - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - . - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - . - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -License: public-domain - Public domain. - -License: ISC - 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. diff --git a/debian/fido2-tools.install b/debian/fido2-tools.install deleted file mode 100644 index e772481..0000000 --- a/debian/fido2-tools.install +++ /dev/null @@ -1 +0,0 @@ -usr/bin diff --git a/debian/fido2-tools.manpages b/debian/fido2-tools.manpages deleted file mode 100644 index fc19867..0000000 --- a/debian/fido2-tools.manpages +++ /dev/null @@ -1,3 +0,0 @@ -man/fido2-assert.1 -man/fido2-cred.1 -man/fido2-token.1 diff --git a/debian/libfido2-1.install b/debian/libfido2-1.install deleted file mode 100644 index a080fbe..0000000 --- a/debian/libfido2-1.install +++ /dev/null @@ -1 +0,0 @@ -usr/lib/*/libfido2.so.* diff --git a/debian/libfido2-1.symbols b/debian/libfido2-1.symbols deleted file mode 100644 index afbf449..0000000 --- a/debian/libfido2-1.symbols +++ /dev/null @@ -1,148 +0,0 @@ -libfido2.so.1 libfido2-1 #MINVER# - eddsa_pk_free@Base 1.1.0 - eddsa_pk_from_EVP_PKEY@Base 1.1.0 - eddsa_pk_from_ptr@Base 1.1.0 - eddsa_pk_new@Base 1.1.0 - eddsa_pk_to_EVP_PKEY@Base 1.1.0 - es256_pk_free@Base 1.1.0 - es256_pk_from_EC_KEY@Base 1.1.0 - es256_pk_from_ptr@Base 1.1.0 - es256_pk_new@Base 1.1.0 - es256_pk_to_EVP_PKEY@Base 1.1.0 - fido_assert_allow_cred@Base 1.1.0 - fido_assert_authdata_len@Base 1.1.0 - fido_assert_authdata_ptr@Base 1.1.0 - fido_assert_clientdata_hash_len@Base 1.1.0 - fido_assert_clientdata_hash_ptr@Base 1.1.0 - fido_assert_count@Base 1.1.0 - fido_assert_flags@Base 1.1.0 - fido_assert_free@Base 1.1.0 - fido_assert_hmac_secret_len@Base 1.1.0 - fido_assert_hmac_secret_ptr@Base 1.1.0 - fido_assert_id_len@Base 1.1.0 - fido_assert_id_ptr@Base 1.1.0 - fido_assert_new@Base 1.1.0 - fido_assert_rp_id@Base 1.1.0 - fido_assert_set_authdata@Base 1.1.0 - fido_assert_set_clientdata_hash@Base 1.1.0 - fido_assert_set_count@Base 1.1.0 - fido_assert_set_extensions@Base 1.1.0 - fido_assert_set_hmac_salt@Base 1.1.0 - fido_assert_set_options@Base 1.1.0 - fido_assert_set_rp@Base 1.1.0 - fido_assert_set_sig@Base 1.1.0 - fido_assert_set_up@Base 1.2.0 - fido_assert_set_uv@Base 1.2.0 - fido_assert_sig_len@Base 1.1.0 - fido_assert_sig_ptr@Base 1.1.0 - fido_assert_user_display_name@Base 1.1.0 - fido_assert_user_icon@Base 1.1.0 - fido_assert_user_id_len@Base 1.1.0 - fido_assert_user_id_ptr@Base 1.1.0 - fido_assert_user_name@Base 1.1.0 - fido_assert_verify@Base 1.1.0 - fido_cbor_info_aaguid_len@Base 1.1.0 - fido_cbor_info_aaguid_ptr@Base 1.1.0 - fido_cbor_info_extensions_len@Base 1.1.0 - fido_cbor_info_extensions_ptr@Base 1.1.0 - fido_cbor_info_free@Base 1.1.0 - fido_cbor_info_maxmsgsiz@Base 1.1.0 - fido_cbor_info_new@Base 1.1.0 - fido_cbor_info_options_len@Base 1.1.0 - fido_cbor_info_options_name_ptr@Base 1.1.0 - fido_cbor_info_options_value_ptr@Base 1.1.0 - fido_cbor_info_protocols_len@Base 1.1.0 - fido_cbor_info_protocols_ptr@Base 1.1.0 - fido_cbor_info_versions_len@Base 1.1.0 - fido_cbor_info_versions_ptr@Base 1.1.0 - fido_cred_authdata_len@Base 1.1.0 - fido_cred_authdata_ptr@Base 1.1.0 - fido_cred_clientdata_hash_len@Base 1.1.0 - fido_cred_clientdata_hash_ptr@Base 1.1.0 - fido_cred_display_name@Base 1.2.0 - fido_cred_exclude@Base 1.1.0 - fido_cred_flags@Base 1.1.0 - fido_cred_fmt@Base 1.1.0 - fido_cred_free@Base 1.1.0 - fido_cred_id_len@Base 1.1.0 - fido_cred_id_ptr@Base 1.1.0 - fido_cred_new@Base 1.1.0 - fido_cred_pubkey_len@Base 1.1.0 - fido_cred_pubkey_ptr@Base 1.1.0 - fido_cred_rp_id@Base 1.1.0 - fido_cred_rp_name@Base 1.1.0 - fido_cred_set_authdata@Base 1.1.0 - fido_cred_set_clientdata_hash@Base 1.1.0 - fido_cred_set_extensions@Base 1.1.0 - fido_cred_set_fmt@Base 1.1.0 - fido_cred_set_options@Base 1.1.0 - fido_cred_set_rk@Base 1.2.0 - fido_cred_set_rp@Base 1.1.0 - fido_cred_set_sig@Base 1.1.0 - fido_cred_set_type@Base 1.1.0 - fido_cred_set_user@Base 1.1.0 - fido_cred_set_uv@Base 1.2.0 - fido_cred_set_x509@Base 1.1.0 - fido_cred_sig_len@Base 1.1.0 - fido_cred_sig_ptr@Base 1.1.0 - fido_cred_type@Base 1.2.0 - fido_cred_user_id_len@Base 1.2.0 - fido_cred_user_id_ptr@Base 1.2.0 - fido_cred_user_name@Base 1.2.0 - fido_cred_verify@Base 1.1.0 - fido_cred_x5c_len@Base 1.1.0 - fido_cred_x5c_ptr@Base 1.1.0 - fido_credman_del_dev_rk@Base 1.2.0 - fido_credman_get_dev_metadata@Base 1.2.0 - fido_credman_get_dev_rk@Base 1.2.0 - fido_credman_get_dev_rp@Base 1.2.0 - fido_credman_metadata_free@Base 1.2.0 - fido_credman_metadata_new@Base 1.2.0 - fido_credman_rk@Base 1.2.0 - fido_credman_rk_count@Base 1.2.0 - fido_credman_rk_existing@Base 1.2.0 - fido_credman_rk_free@Base 1.2.0 - fido_credman_rk_new@Base 1.2.0 - fido_credman_rk_remaining@Base 1.2.0 - fido_credman_rp_count@Base 1.2.0 - fido_credman_rp_free@Base 1.2.0 - fido_credman_rp_id@Base 1.2.0 - fido_credman_rp_id_hash_len@Base 1.2.0 - fido_credman_rp_id_hash_ptr@Base 1.2.0 - fido_credman_rp_name@Base 1.2.0 - fido_credman_rp_new@Base 1.2.0 - fido_dev_build@Base 1.1.0 - fido_dev_close@Base 1.1.0 - fido_dev_flags@Base 1.1.0 - fido_dev_force_fido2@Base 1.1.0 - fido_dev_force_u2f@Base 1.1.0 - fido_dev_free@Base 1.1.0 - fido_dev_get_assert@Base 1.1.0 - fido_dev_get_cbor_info@Base 1.1.0 - fido_dev_get_retry_count@Base 1.1.0 - fido_dev_info_free@Base 1.1.0 - fido_dev_info_manifest@Base 1.1.0 - fido_dev_info_manufacturer_string@Base 1.1.0 - fido_dev_info_new@Base 1.1.0 - fido_dev_info_path@Base 1.1.0 - fido_dev_info_product@Base 1.1.0 - fido_dev_info_product_string@Base 1.1.0 - fido_dev_info_ptr@Base 1.1.0 - fido_dev_info_vendor@Base 1.1.0 - fido_dev_is_fido2@Base 1.1.0 - fido_dev_major@Base 1.1.0 - fido_dev_make_cred@Base 1.1.0 - fido_dev_minor@Base 1.1.0 - fido_dev_new@Base 1.1.0 - fido_dev_open@Base 1.1.0 - fido_dev_protocol@Base 1.1.0 - fido_dev_reset@Base 1.1.0 - fido_dev_set_io_functions@Base 1.1.0 - fido_dev_set_pin@Base 1.1.0 - fido_init@Base 1.1.0 - fido_strerr@Base 1.1.0 - rs256_pk_free@Base 1.1.0 - rs256_pk_from_RSA@Base 1.1.0 - rs256_pk_from_ptr@Base 1.1.0 - rs256_pk_new@Base 1.1.0 - rs256_pk_to_EVP_PKEY@Base 1.1.0 diff --git a/debian/libfido2-dev.install b/debian/libfido2-dev.install deleted file mode 100644 index c1c34e7..0000000 --- a/debian/libfido2-dev.install +++ /dev/null @@ -1,29 +0,0 @@ -usr/include -usr/lib/*/*.so -usr/lib/*/pkgconfig/*.pc -usr/share/doc/libfido2/html/eddsa_pk_new.html -usr/share/doc/libfido2/html/es256_pk_new.html -usr/share/doc/libfido2/html/fido_init.html -usr/share/doc/libfido2/html/fido_assert_new.html -usr/share/doc/libfido2/html/fido_assert_allow_cred.html -usr/share/doc/libfido2/html/fido_assert_set_authdata.html -usr/share/doc/libfido2/html/fido_assert_verify.html -usr/share/doc/libfido2/html/fido_bio_dev_get_info.html -usr/share/doc/libfido2/html/fido_bio_enroll_new.html -usr/share/doc/libfido2/html/fido_bio_info_new.html -usr/share/doc/libfido2/html/fido_bio_template.html -usr/share/doc/libfido2/html/fido_cbor_info_new.html -usr/share/doc/libfido2/html/fido_cred_new.html -usr/share/doc/libfido2/html/fido_cred_exclude.html -usr/share/doc/libfido2/html/fido_credman_metadata_new.html -usr/share/doc/libfido2/html/fido_cred_set_authdata.html -usr/share/doc/libfido2/html/fido_cred_verify.html -usr/share/doc/libfido2/html/fido_dev_get_assert.html -usr/share/doc/libfido2/html/fido_dev_info_manifest.html -usr/share/doc/libfido2/html/fido_dev_make_cred.html -usr/share/doc/libfido2/html/fido_dev_open.html -usr/share/doc/libfido2/html/fido_dev_set_io_functions.html -usr/share/doc/libfido2/html/fido_dev_set_pin.html -usr/share/doc/libfido2/html/fido_strerr.html -usr/share/doc/libfido2/html/rs256_pk_new.html -usr/share/doc/libfido2/html/style.css diff --git a/debian/libfido2-dev.links b/debian/libfido2-dev.links deleted file mode 100644 index b23b8a0..0000000 --- a/debian/libfido2-dev.links +++ /dev/null @@ -1,276 +0,0 @@ -/usr/share/man/man3/eddsa_pk_new.3 /usr/share/man/man3/eddsa_pk_free.3 -/usr/share/man/man3/eddsa_pk_new.3 /usr/share/man/man3/eddsa_pk_from_ptr.3 -/usr/share/man/man3/eddsa_pk_new.3 /usr/share/man/man3/eddsa_pk_to_EVP_PKEY.3 -/usr/share/man/man3/es256_pk_new.3 /usr/share/man/man3/es256_pk_free.3 -/usr/share/man/man3/es256_pk_new.3 /usr/share/man/man3/es256_pk_from_EC_KEY.3 -/usr/share/man/man3/es256_pk_new.3 /usr/share/man/man3/es256_pk_from_ptr.3 -/usr/share/man/man3/es256_pk_new.3 /usr/share/man/man3/es256_pk_to_EVP_PKEY.3 -/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_authdata_len.3 -/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_authdata_ptr.3 -/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_clientdata_hash_len.3 -/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_clientdata_hash_ptr.3 -/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_count.3 -/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_free.3 -/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_hmac_secret_len.3 -/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_hmac_secret_ptr.3 -/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_sigcount.3 -/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_sig_len.3 -/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_sig_ptr.3 -/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_user_display_name.3 -/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_user_icon.3 -/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_user_id_len.3 -/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_user_id_ptr.3 -/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_user_name.3 -/usr/share/man/man3/fido_assert_set_authdata.3 /usr/share/man/man3/fido_assert_set_clientdata_hash.3 -/usr/share/man/man3/fido_assert_set_authdata.3 /usr/share/man/man3/fido_assert_set_count.3 -/usr/share/man/man3/fido_assert_set_authdata.3 /usr/share/man/man3/fido_assert_set_extensions.3 -/usr/share/man/man3/fido_assert_set_authdata.3 /usr/share/man/man3/fido_assert_set_hmac_salt.3 -/usr/share/man/man3/fido_assert_set_authdata.3 /usr/share/man/man3/fido_assert_set_rp.3 -/usr/share/man/man3/fido_assert_set_authdata.3 /usr/share/man/man3/fido_assert_set_sig.3 -/usr/share/man/man3/fido_assert_set_authdata.3 /usr/share/man/man3/fido_assert_set_up.3 -/usr/share/man/man3/fido_assert_set_authdata.3 /usr/share/man/man3/fido_assert_set_uv.3 -/usr/share/man/man3/fido_bio_dev_get_info.3 /usr/share/man/man3/fido_bio_dev_enroll_begin.3 -/usr/share/man/man3/fido_bio_dev_get_info.3 /usr/share/man/man3/fido_bio_dev_enroll_cancel.3 -/usr/share/man/man3/fido_bio_dev_get_info.3 /usr/share/man/man3/fido_bio_dev_enroll_continue.3 -/usr/share/man/man3/fido_bio_dev_get_info.3 /usr/share/man/man3/fido_bio_dev_enroll_remove.3 -/usr/share/man/man3/fido_bio_dev_get_info.3 /usr/share/man/man3/fido_bio_dev_get_template_array.3 -/usr/share/man/man3/fido_bio_dev_get_info.3 /usr/share/man/man3/fido_bio_dev_set_template_name.3 -/usr/share/man/man3/fido_bio_enroll_new.3 /usr/share/man/man3/fido_bio_enroll_free.3 -/usr/share/man/man3/fido_bio_enroll_new.3 /usr/share/man/man3/fido_bio_enroll_last_status.3 -/usr/share/man/man3/fido_bio_enroll_new.3 /usr/share/man/man3/fido_bio_enroll_remaining_samples.3 -/usr/share/man/man3/fido_bio_info_new.3 /usr/share/man/man3/fido_bio_info_free.3 -/usr/share/man/man3/fido_bio_info_new.3 /usr/share/man/man3/fido_bio_info_max_samples.3 -/usr/share/man/man3/fido_bio_info_new.3 /usr/share/man/man3/fido_bio_info_type.3 -/usr/share/man/man3/fido_bio_template.3 /usr/share/man/man3/fido_bio_template_array_count.3 -/usr/share/man/man3/fido_bio_template.3 /usr/share/man/man3/fido_bio_template_array_free.3 -/usr/share/man/man3/fido_bio_template.3 /usr/share/man/man3/fido_bio_template_array_new.3 -/usr/share/man/man3/fido_bio_template.3 /usr/share/man/man3/fido_bio_template_free.3 -/usr/share/man/man3/fido_bio_template.3 /usr/share/man/man3/fido_bio_template_id_len.3 -/usr/share/man/man3/fido_bio_template.3 /usr/share/man/man3/fido_bio_template_id_ptr.3 -/usr/share/man/man3/fido_bio_template.3 /usr/share/man/man3/fido_bio_template_name.3 -/usr/share/man/man3/fido_bio_template.3 /usr/share/man/man3/fido_bio_template_new.3 -/usr/share/man/man3/fido_bio_template.3 /usr/share/man/man3/fido_bio_template_set_id.3 -/usr/share/man/man3/fido_bio_template.3 /usr/share/man/man3/fido_bio_template_set_name.3 -/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_aaguid_len.3 -/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_aaguid_ptr.3 -/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_extensions_len.3 -/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_extensions_ptr.3 -/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_free.3 -/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_maxmsgsiz.3 -/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_options_len.3 -/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_options_name_ptr.3 -/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_options_value_ptr.3 -/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_protocols_len.3 -/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_protocols_ptr.3 -/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_versions_len.3 -/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_versions_ptr.3 -/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_dev_get_cbor_info.3 -/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_authdata_len.3 -/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_authdata_ptr.3 -/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_clientdata_hash_len.3 -/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_clientdata_hash_ptr.3 -/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_fmt.3 -/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_free.3 -/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_id_len.3 -/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_id_ptr.3 -/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_prot.3 -/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_pubkey_len.3 -/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_pubkey_ptr.3 -/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_sig_len.3 -/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_sig_ptr.3 -/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_x5c_len.3 -/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_x5c_ptr.3 -/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_del_dev_rk.3 -/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_get_dev_metadata.3 -/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_get_dev_rk.3 -/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_get_dev_rp.3 -/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_metadata_free.3 -/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rk.3 -/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rk_count.3 -/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rk_existing.3 -/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rk_free.3 -/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rk_new.3 -/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rk_remaining.3 -/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rp_count.3 -/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rp_free.3 -/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rp_id.3 -/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rp_id_hash_len.3 -/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rp_id_hash_ptr.3 -/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rp_name.3 -/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rp_new.3 -/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_authdata_raw.3 -/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_clientdata_hash.3 -/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_extensions.3 -/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_fmt.3 -/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_prot.3 -/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_rk.3 -/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_rp.3 -/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_sig.3 -/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_type.3 -/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_user.3 -/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_uv.3 -/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_x509.3 -/usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_free.3 -/usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_manufacturer_string.3 -/usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_new.3 -/usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_path.3 -/usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_product.3 -/usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_product_string.3 -/usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_ptr.3 -/usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_vendor.3 -/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_build.3 -/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_cancel.3 -/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_close.3 -/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_flags.3 -/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_force_fido2.3 -/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_force_u2f.3 -/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_free.3 -/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_is_fido2.3 -/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_major.3 -/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_minor.3 -/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_new.3 -/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_protocol.3 -/usr/share/man/man3/fido_dev_set_pin.3 /usr/share/man/man3/fido_dev_get_retry_count.3 -/usr/share/man/man3/fido_dev_set_pin.3 /usr/share/man/man3/fido_dev_reset.3 -/usr/share/man/man3/rs256_pk_new.3 /usr/share/man/man3/rs256_pk_free.3 -/usr/share/man/man3/rs256_pk_new.3 /usr/share/man/man3/rs256_pk_from_ptr.3 -/usr/share/man/man3/rs256_pk_new.3 /usr/share/man/man3/rs256_pk_from_RSA.3 -/usr/share/man/man3/rs256_pk_new.3 /usr/share/man/man3/rs256_pk_to_EVP_PKEY.3 -/usr/share/doc/libfido2/eddsa_pk_new.html /usr/share/doc/libfido2/eddsa_pk_free.html -/usr/share/doc/libfido2/eddsa_pk_new.html /usr/share/doc/libfido2/eddsa_pk_from_ptr.html -/usr/share/doc/libfido2/eddsa_pk_new.html /usr/share/doc/libfido2/eddsa_pk_to_EVP_PKEY.html -/usr/share/doc/libfido2/es256_pk_new.html /usr/share/doc/libfido2/es256_pk_free.html -/usr/share/doc/libfido2/es256_pk_new.html /usr/share/doc/libfido2/es256_pk_from_EC_KEY.html -/usr/share/doc/libfido2/es256_pk_new.html /usr/share/doc/libfido2/es256_pk_from_ptr.html -/usr/share/doc/libfido2/es256_pk_new.html /usr/share/doc/libfido2/es256_pk_to_EVP_PKEY.html -/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_authdata_len.html -/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_authdata_ptr.html -/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_clientdata_hash_len.html -/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_clientdata_hash_ptr.html -/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_count.html -/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_free.html -/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_hmac_secret_len.html -/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_hmac_secret_ptr.html -/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_sigcount.html -/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_sig_len.html -/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_sig_ptr.html -/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_user_display_name.html -/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_user_icon.html -/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_user_id_len.html -/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_user_id_ptr.html -/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_user_name.html -/usr/share/doc/libfido2/fido_assert_set_authdata.html /usr/share/doc/libfido2/fido_assert_set_clientdata_hash.html -/usr/share/doc/libfido2/fido_assert_set_authdata.html /usr/share/doc/libfido2/fido_assert_set_count.html -/usr/share/doc/libfido2/fido_assert_set_authdata.html /usr/share/doc/libfido2/fido_assert_set_extensions.html -/usr/share/doc/libfido2/fido_assert_set_authdata.html /usr/share/doc/libfido2/fido_assert_set_hmac_salt.html -/usr/share/doc/libfido2/fido_assert_set_authdata.html /usr/share/doc/libfido2/fido_assert_set_rp.html -/usr/share/doc/libfido2/fido_assert_set_authdata.html /usr/share/doc/libfido2/fido_assert_set_sig.html -/usr/share/doc/libfido2/fido_assert_set_authdata.html /usr/share/doc/libfido2/fido_assert_set_up.html -/usr/share/doc/libfido2/fido_assert_set_authdata.html /usr/share/doc/libfido2/fido_assert_set_uv.html -/usr/share/doc/libfido2/fido_bio_dev_get_info.html /usr/share/doc/libfido2/fido_bio_dev_enroll_begin.html -/usr/share/doc/libfido2/fido_bio_dev_get_info.html /usr/share/doc/libfido2/fido_bio_dev_enroll_cancel.html -/usr/share/doc/libfido2/fido_bio_dev_get_info.html /usr/share/doc/libfido2/fido_bio_dev_enroll_continue.html -/usr/share/doc/libfido2/fido_bio_dev_get_info.html /usr/share/doc/libfido2/fido_bio_dev_enroll_remove.html -/usr/share/doc/libfido2/fido_bio_dev_get_info.html /usr/share/doc/libfido2/fido_bio_dev_get_template_array.html -/usr/share/doc/libfido2/fido_bio_dev_get_info.html /usr/share/doc/libfido2/fido_bio_dev_set_template_name.html -/usr/share/doc/libfido2/fido_bio_enroll_new.html /usr/share/doc/libfido2/fido_bio_enroll_free.html -/usr/share/doc/libfido2/fido_bio_enroll_new.html /usr/share/doc/libfido2/fido_bio_enroll_last_status.html -/usr/share/doc/libfido2/fido_bio_enroll_new.html /usr/share/doc/libfido2/fido_bio_enroll_remaining_samples.html -/usr/share/doc/libfido2/fido_bio_info_new.html /usr/share/doc/libfido2/fido_bio_info_free.html -/usr/share/doc/libfido2/fido_bio_info_new.html /usr/share/doc/libfido2/fido_bio_info_max_samples.html -/usr/share/doc/libfido2/fido_bio_info_new.html /usr/share/doc/libfido2/fido_bio_info_type.html -/usr/share/doc/libfido2/fido_bio_template.html /usr/share/doc/libfido2/fido_bio_template_array_count.html -/usr/share/doc/libfido2/fido_bio_template.html /usr/share/doc/libfido2/fido_bio_template_array_free.html -/usr/share/doc/libfido2/fido_bio_template.html /usr/share/doc/libfido2/fido_bio_template_array_new.html -/usr/share/doc/libfido2/fido_bio_template.html /usr/share/doc/libfido2/fido_bio_template_free.html -/usr/share/doc/libfido2/fido_bio_template.html /usr/share/doc/libfido2/fido_bio_template_id_len.html -/usr/share/doc/libfido2/fido_bio_template.html /usr/share/doc/libfido2/fido_bio_template_id_ptr.html -/usr/share/doc/libfido2/fido_bio_template.html /usr/share/doc/libfido2/fido_bio_template_name.html -/usr/share/doc/libfido2/fido_bio_template.html /usr/share/doc/libfido2/fido_bio_template_new.html -/usr/share/doc/libfido2/fido_bio_template.html /usr/share/doc/libfido2/fido_bio_template_set_id.html -/usr/share/doc/libfido2/fido_bio_template.html /usr/share/doc/libfido2/fido_bio_template_set_name.html -/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_aaguid_len.html -/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_aaguid_ptr.html -/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_extensions_len.html -/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_extensions_ptr.html -/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_free.html -/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_maxmsgsiz.html -/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_options_len.html -/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_options_name_ptr.html -/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_options_value_ptr.html -/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_protocols_len.html -/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_protocols_ptr.html -/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_versions_len.html -/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_versions_ptr.html -/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_dev_get_cbor_info.html -/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_authdata_len.html -/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_authdata_ptr.html -/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_clientdata_hash_len.html -/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_clientdata_hash_ptr.html -/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_fmt.html -/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_free.html -/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_id_len.html -/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_id_ptr.html -/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_prot.html -/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_pubkey_len.html -/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_pubkey_ptr.html -/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_sig_len.html -/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_sig_ptr.html -/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_x5c_len.html -/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_x5c_ptr.html -/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_del_dev_rk.html -/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_get_dev_metadata.html -/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_get_dev_rk.html -/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_get_dev_rp.html -/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_metadata_free.html -/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rk.html -/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rk_count.html -/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rk_existing.html -/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rk_free.html -/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rk_new.html -/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rk_remaining.html -/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rp_count.html -/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rp_free.html -/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rp_id.html -/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rp_id_hash_len.html -/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rp_id_hash_ptr.html -/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rp_name.html -/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rp_new.html -/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_authdata_raw.html -/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_clientdata_hash.html -/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_extensions.html -/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_fmt.html -/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_prot.html -/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_rk.html -/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_rp.html -/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_sig.html -/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_type.html -/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_user.html -/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_uv.html -/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_x509.html -/usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_free.html -/usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_manufacturer_string.html -/usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_new.html -/usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_path.html -/usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_product.html -/usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_product_string.html -/usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_ptr.html -/usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_vendor.html -/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_build.html -/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_cancel.html -/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_close.html -/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_flags.html -/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_force_fido2.html -/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_force_u2f.html -/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_free.html -/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_is_fido2.html -/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_major.html -/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_minor.html -/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_new.html -/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_protocol.html -/usr/share/doc/libfido2/fido_dev_set_pin.html /usr/share/doc/libfido2/fido_dev_get_retry_count.html -/usr/share/doc/libfido2/fido_dev_set_pin.html /usr/share/doc/libfido2/fido_dev_reset.html -/usr/share/doc/libfido2/rs256_pk_new.html /usr/share/doc/libfido2/rs256_pk_free.html -/usr/share/doc/libfido2/rs256_pk_new.html /usr/share/doc/libfido2/rs256_pk_from_ptr.html -/usr/share/doc/libfido2/rs256_pk_new.html /usr/share/doc/libfido2/rs256_pk_from_RSA.html -/usr/share/doc/libfido2/rs256_pk_new.html /usr/share/doc/libfido2/rs256_pk_to_EVP_PKEY.html diff --git a/debian/libfido2-dev.manpages b/debian/libfido2-dev.manpages deleted file mode 100644 index 228a13e..0000000 --- a/debian/libfido2-dev.manpages +++ /dev/null @@ -1,25 +0,0 @@ -man/eddsa_pk_new.3 -man/es256_pk_new.3 -man/fido_init.3 -man/fido_assert_new.3 -man/fido_assert_allow_cred.3 -man/fido_assert_set_authdata.3 -man/fido_assert_verify.3 -man/fido_bio_dev_get_info.3 -man/fido_bio_enroll_new.3 -man/fido_bio_info_new.3 -man/fido_bio_template.3 -man/fido_cbor_info_new.3 -man/fido_cred_new.3 -man/fido_cred_exclude.3 -man/fido_credman_metadata_new.3 -man/fido_cred_set_authdata.3 -man/fido_cred_verify.3 -man/fido_dev_get_assert.3 -man/fido_dev_info_manifest.3 -man/fido_dev_make_cred.3 -man/fido_dev_open.3 -man/fido_dev_set_io_functions.3 -man/fido_dev_set_pin.3 -man/fido_strerr.3 -man/rs256_pk_new.3 diff --git a/debian/libfido2-udev.install b/debian/libfido2-udev.install deleted file mode 100644 index 528cb53..0000000 --- a/debian/libfido2-udev.install +++ /dev/null @@ -1 +0,0 @@ -lib/udev/rules.d diff --git a/debian/rules b/debian/rules deleted file mode 100755 index bb7acbc..0000000 --- a/debian/rules +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/make -f - -DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) - -%: - dh $@ - -override_dh_auto_configure: - dh_auto_configure -- -DUDEV_RULES_DIR=/lib/udev/rules.d diff --git a/debian/source/format b/debian/source/format deleted file mode 100644 index 89ae9db..0000000 --- a/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (native) diff --git a/docker/bionic/Dockerfile b/docker/bionic/Dockerfile deleted file mode 100644 index 9225ed8..0000000 --- a/docker/bionic/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -# unlock-yk -# docker run --rm --volume=/home/pedro/projects/libfido2:/workdir \ -# --volume=$(gpgconf --list-dirs socketdir):/root/.gnupg \ -# --volume=$(gpgconf --list-dirs homedir)/pubring.kbx:/root/.gnupg/pubring.kbx \ -# -it libfido2-staging --install-deps --ppa martelletto/ppa \ -# --key pedro@yubico.com -FROM ubuntu:bionic -ENV DEBIAN_FRONTEND noninteractive -RUN apt-get -qq update && apt-get -qq upgrade -RUN apt-get install -qq packaging-dev debian-keyring devscripts equivs gnupg python sudo -ADD https://raw.githubusercontent.com/dainnilsson/scripts/master/make-ppa /make-ppa -RUN chmod +x /make-ppa -WORKDIR /workdir -ENTRYPOINT ["/make-ppa"] diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 1203592..7228860 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -3,6 +3,7 @@ # license that can be found in the LICENSE file. list(APPEND COMPAT_SOURCES + ../openbsd-compat/clock_gettime.c ../openbsd-compat/getopt_long.c ../openbsd-compat/strlcat.c ../openbsd-compat/strlcpy.c @@ -15,6 +16,13 @@ endif() # drop -rdynamic set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") +# enable -Wconversion -Wsign-conversion +if(NOT MSVC) + set_source_files_properties(assert.c cred.c info.c manifest.c reset.c + retries.c setpin.c util.c PROPERTIES COMPILE_FLAGS + "-Wconversion -Wsign-conversion") +endif() + # manifest add_executable(manifest manifest.c ${COMPAT_SOURCES}) target_link_libraries(manifest fido2) @@ -42,3 +50,11 @@ target_link_libraries(setpin fido2) # retries add_executable(retries retries.c ${COMPAT_SOURCES}) target_link_libraries(retries fido2) + +# select +add_executable(select select.c ${COMPAT_SOURCES}) +target_link_libraries(select fido2) +if(MINGW) + # needed for nanosleep() in mingw + target_link_libraries(select winpthread) +endif() diff --git a/examples/README.adoc b/examples/README.adoc index 091c6bc..b7b73d8 100644 --- a/examples/README.adoc +++ b/examples/README.adoc @@ -77,5 +77,14 @@ The following examples are provided: - retries Get the number of PIN attempts left on before lockout. +- select + + Enumerates available FIDO devices and, if more than one is present, + simultaneously requests touch on all of them, printing information + about the device touched. + Debugging is possible through the use of the FIDO_DEBUG environment variable. If set, libfido2 will produce a log of its transactions with the authenticator. + +Additionally, an example of a WebAuthn client using libfido2 is available at +https://github.com/martelletto/fido2-webauthn-client. diff --git a/examples/assert.c b/examples/assert.c index a421a51..a18d8af 100644 --- a/examples/assert.c +++ b/examples/assert.c @@ -14,17 +14,12 @@ #include #endif -#include "../openbsd-compat/openbsd-compat.h" - #include "fido.h" #include "fido/es256.h" #include "fido/rs256.h" #include "fido/eddsa.h" #include "extern.h" - -#ifdef SIGNAL_EXAMPLE -extern volatile sig_atomic_t got_signal; -#endif +#include "../openbsd-compat/openbsd-compat.h" static const unsigned char cdh[32] = { 0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7, @@ -188,13 +183,15 @@ main(int argc, char **argv) break; case 'T': #ifndef SIGNAL_EXAMPLE + (void)seconds; errx(1, "-T not supported"); -#endif +#else if (base10(optarg, &seconds) < 0) errx(1, "base10: %s", optarg); if (seconds <= 0 || seconds > 30) errx(1, "-T: %s must be in (0,30]", optarg); break; +#endif case 'a': if (read_blob(optarg, &body, &len) < 0) errx(1, "read_blob: %s", optarg); @@ -312,6 +309,10 @@ main(int argc, char **argv) errx(1, "fido_assert_count: %d signatures returned", (int)fido_assert_count(assert)); + /* when verifying, pin implies uv */ + if (pin) + uv = true; + verify_assert(type, fido_assert_authdata_ptr(assert, 0), fido_assert_authdata_len(assert, 0), fido_assert_sig_ptr(assert, 0), fido_assert_sig_len(assert, 0), up, uv, ext, argv[0]); diff --git a/examples/cred.c b/examples/cred.c index 3e0a30f..6bd0faf 100644 --- a/examples/cred.c +++ b/examples/cred.c @@ -16,14 +16,9 @@ #include #endif -#include "../openbsd-compat/openbsd-compat.h" - #include "fido.h" #include "extern.h" - -#ifdef SIGNAL_EXAMPLE -extern volatile sig_atomic_t got_signal; -#endif +#include "../openbsd-compat/openbsd-compat.h" static const unsigned char cdh[32] = { 0xf9, 0x64, 0x57, 0xe7, 0x2d, 0x97, 0xf6, 0xbb, @@ -192,13 +187,15 @@ main(int argc, char **argv) break; case 'T': #ifndef SIGNAL_EXAMPLE + (void)seconds; errx(1, "-T not supported"); -#endif +#else if (base10(optarg, &seconds) < 0) errx(1, "base10: %s", optarg); if (seconds <= 0 || seconds > 30) errx(1, "-T: %s must be in (0,30]", optarg); break; +#endif case 'e': if (read_blob(optarg, &body, &len) < 0) errx(1, "read_blob: %s", optarg); @@ -318,6 +315,10 @@ main(int argc, char **argv) fido_dev_free(&dev); + /* when verifying, pin implies uv */ + if (pin) + uv = true; + verify_cred(type, fido_cred_fmt(cred), fido_cred_authdata_ptr(cred), fido_cred_authdata_len(cred), fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred), fido_cred_sig_ptr(cred), diff --git a/examples/extern.h b/examples/extern.h index 578b8c4..0ea68c4 100644 --- a/examples/extern.h +++ b/examples/extern.h @@ -27,6 +27,7 @@ int write_rsa_pubkey(const char *, const void *, size_t); int write_eddsa_pubkey(const char *, const void *, size_t); #ifdef SIGNAL_EXAMPLE void prepare_signal_handler(int); +extern volatile sig_atomic_t got_signal; #endif #endif /* _EXTERN_H_ */ diff --git a/examples/info.c b/examples/info.c index ef0d97e..d81de85 100644 --- a/examples/info.c +++ b/examples/info.c @@ -4,17 +4,14 @@ * license that can be found in the LICENSE file. */ -#include - #include #include #include #include #include -#include "../openbsd-compat/openbsd-compat.h" - #include "fido.h" +#include "../openbsd-compat/openbsd-compat.h" /* * Pretty-print a device's capabilities flags and return the result. @@ -130,6 +127,26 @@ print_maxmsgsiz(uint64_t maxmsgsiz) printf("maxmsgsiz: %d\n", (int)maxmsgsiz); } +/* + * Auxiliary function to print an authenticator's maximum number of credentials + * in a credential list on stdout. + */ +static void +print_maxcredcntlst(uint64_t maxcredcntlst) +{ + printf("maxcredcntlst: %d\n", (int)maxcredcntlst); +} + +/* + * Auxiliary function to print an authenticator's maximum credential ID length + * on stdout. + */ +static void +print_maxcredidlen(uint64_t maxcredidlen) +{ + printf("maxcredlen: %d\n", (int)maxcredidlen); +} + /* * Auxiliary function to print an authenticator's firmware version on stdout. */ @@ -199,6 +216,12 @@ getinfo(const char *path) /* print maximum message size */ print_maxmsgsiz(fido_cbor_info_maxmsgsiz(ci)); + /* print maximum number of credentials allowed in credential lists */ + print_maxcredcntlst(fido_cbor_info_maxcredcntlst(ci)); + + /* print maximum length of a credential ID */ + print_maxcredidlen(fido_cbor_info_maxcredidlen(ci)); + /* print firmware version */ print_fwversion(fido_cbor_info_fwversion(ci)); diff --git a/examples/manifest.c b/examples/manifest.c index 895447a..d5ebda2 100644 --- a/examples/manifest.c +++ b/examples/manifest.c @@ -4,15 +4,12 @@ * license that can be found in the LICENSE file. */ -#include - #include #include #include -#include "../openbsd-compat/openbsd-compat.h" - #include "fido.h" +#include "../openbsd-compat/openbsd-compat.h" int main(void) diff --git a/examples/reset.c b/examples/reset.c index 36a7de2..3e715c4 100644 --- a/examples/reset.c +++ b/examples/reset.c @@ -8,21 +8,14 @@ * Perform a factory reset on a given authenticator. */ -#include - #include #include #include #include -#include "../openbsd-compat/openbsd-compat.h" - #include "fido.h" #include "extern.h" - -#ifdef SIGNAL_EXAMPLE -extern volatile sig_atomic_t got_signal; -#endif +#include "../openbsd-compat/openbsd-compat.h" int main(int argc, char **argv) diff --git a/examples/retries.c b/examples/retries.c index 3ed7558..5cc116c 100644 --- a/examples/retries.c +++ b/examples/retries.c @@ -8,15 +8,12 @@ * Get an authenticator's number of PIN attempts left. */ -#include - #include #include #include -#include "../openbsd-compat/openbsd-compat.h" - #include "fido.h" +#include "../openbsd-compat/openbsd-compat.h" int main(int argc, char **argv) diff --git a/examples/select.c b/examples/select.c new file mode 100644 index 0000000..1fb2960 --- /dev/null +++ b/examples/select.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2020 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + +#include +#include +#include +#include +#include + +#include "fido.h" +#include "../openbsd-compat/openbsd-compat.h" + +#define FIDO_POLL_MS 50 + +#if defined(_MSC_VER) +static int +nanosleep(const struct timespec *rqtp, struct timespec *rmtp) +{ + if (rmtp != NULL) { + errno = EINVAL; + return (-1); + } + + Sleep(rqtp->tv_nsec / 1000000); + + return (0); +} +#endif + +static fido_dev_t * +open_dev(const fido_dev_info_t *di) +{ + fido_dev_t *dev; + int r; + + if ((dev = fido_dev_new()) == NULL) { + warnx("%s: fido_dev_new", __func__); + return (NULL); + } + + if ((r = fido_dev_open(dev, fido_dev_info_path(di))) != FIDO_OK) { + warnx("%s: fido_dev_open %s: %s", __func__, + fido_dev_info_path(di), fido_strerr(r)); + fido_dev_free(&dev); + return (NULL); + } + + printf("%s (0x%04x:0x%04x) is %s\n", fido_dev_info_path(di), + fido_dev_info_vendor(di), fido_dev_info_product(di), + fido_dev_is_fido2(dev) ? "fido2" : "u2f"); + + return (dev); +} + +static int +select_dev(const fido_dev_info_t *devlist, size_t ndevs, fido_dev_t **dev, + size_t *idx, int secs) +{ + const fido_dev_info_t *di; + fido_dev_t **devtab; + struct timespec ts_start; + struct timespec ts_now; + struct timespec ts_delta; + struct timespec ts_pause; + size_t nopen = 0; + int touched; + int r; + long ms_remain; + + *dev = NULL; + *idx = 0; + + printf("%u authenticator(s) detected\n", (unsigned)ndevs); + + if (ndevs == 0) + return (0); /* nothing to do */ + + if ((devtab = calloc(ndevs, sizeof(*devtab))) == NULL) { + warn("%s: calloc", __func__); + return (-1); + } + + for (size_t i = 0; i < ndevs; i++) { + di = fido_dev_info_ptr(devlist, i); + if ((devtab[i] = open_dev(di)) != NULL) { + *idx = i; + nopen++; + } + } + + printf("%u authenticator(s) opened\n", (unsigned)nopen); + + if (nopen < 2) { + if (nopen == 1) + *dev = devtab[*idx]; /* single candidate */ + r = 0; + goto out; + } + + for (size_t i = 0; i < ndevs; i++) { + di = fido_dev_info_ptr(devlist, i); + if (devtab[i] == NULL) + continue; /* failed to open */ + if ((r = fido_dev_get_touch_begin(devtab[i])) != FIDO_OK) { + warnx("%s: fido_dev_get_touch_begin %s: %s", __func__, + fido_dev_info_path(di), fido_strerr(r)); + r = -1; + goto out; + } + } + + if (clock_gettime(CLOCK_MONOTONIC, &ts_start) != 0) { + warn("%s: clock_gettime", __func__); + r = -1; + goto out; + } + + ts_pause.tv_sec = 0; + ts_pause.tv_nsec = 200000000; /* 200ms */ + + do { + nanosleep(&ts_pause, NULL); + + for (size_t i = 0; i < ndevs; i++) { + di = fido_dev_info_ptr(devlist, i); + if (devtab[i] == NULL) { + /* failed to open or discarded */ + continue; + } + if ((r = fido_dev_get_touch_status(devtab[i], &touched, + FIDO_POLL_MS)) != FIDO_OK) { + warnx("%s: fido_dev_get_touch_status %s: %s", + __func__, fido_dev_info_path(di), + fido_strerr(r)); + fido_dev_close(devtab[i]); + fido_dev_free(&devtab[i]); + continue; /* discard */ + } + if (touched) { + *dev = devtab[i]; + *idx = i; + r = 0; + goto out; + } + } + + if (clock_gettime(CLOCK_MONOTONIC, &ts_now) != 0) { + warn("%s: clock_gettime", __func__); + r = -1; + goto out; + } + + timespecsub(&ts_now, &ts_start, &ts_delta); + ms_remain = (secs * 1000) - ((long)ts_delta.tv_sec * 1000) + + ((long)ts_delta.tv_nsec / 1000000); + } while (ms_remain > FIDO_POLL_MS); + + printf("timeout after %d seconds\n", secs); + r = -1; +out: + if (r != 0) { + *dev = NULL; + *idx = 0; + } + + for (size_t i = 0; i < ndevs; i++) { + if (devtab[i] && devtab[i] != *dev) { + fido_dev_cancel(devtab[i]); + fido_dev_close(devtab[i]); + fido_dev_free(&devtab[i]); + } + } + + free(devtab); + + return (r); +} + +int +main(void) +{ + const fido_dev_info_t *di; + fido_dev_info_t *devlist; + fido_dev_t *dev; + size_t idx; + size_t ndevs; + int r; + + fido_init(0); + + if ((devlist = fido_dev_info_new(64)) == NULL) + errx(1, "fido_dev_info_new"); + + if ((r = fido_dev_info_manifest(devlist, 64, &ndevs)) != FIDO_OK) + errx(1, "fido_dev_info_manifest: %s (0x%x)", fido_strerr(r), r); + if (select_dev(devlist, ndevs, &dev, &idx, 15) != 0) + errx(1, "select_dev"); + if (dev == NULL) + errx(1, "no authenticator found"); + + di = fido_dev_info_ptr(devlist, idx); + printf("%s: %s by %s (PIN %sset)\n", fido_dev_info_path(di), + fido_dev_info_product_string(di), + fido_dev_info_manufacturer_string(di), + fido_dev_has_pin(dev) ? "" : "un"); + + fido_dev_close(dev); + fido_dev_free(&dev); + fido_dev_info_free(&devlist, ndevs); + + exit(0); +} diff --git a/examples/setpin.c b/examples/setpin.c index 75d3d4a..5413bf9 100644 --- a/examples/setpin.c +++ b/examples/setpin.c @@ -8,16 +8,13 @@ * Configure a PIN on a given authenticator. */ -#include - #include #include #include #include -#include "../openbsd-compat/openbsd-compat.h" - #include "fido.h" +#include "../openbsd-compat/openbsd-compat.h" static void setpin(const char *path, const char *pin, const char *oldpin) diff --git a/examples/util.c b/examples/util.c index 2f6a845..5291cd8 100644 --- a/examples/util.c +++ b/examples/util.c @@ -27,13 +27,12 @@ #include "../openbsd-compat/posix_win.h" #endif -#include "../openbsd-compat/openbsd-compat.h" - #include "fido.h" #include "fido/es256.h" #include "fido/rs256.h" #include "fido/eddsa.h" #include "extern.h" +#include "../openbsd-compat/openbsd-compat.h" #ifdef SIGNAL_EXAMPLE volatile sig_atomic_t got_signal = 0; diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt index 241cdc7..70c5eec 100644 --- a/fuzz/CMakeLists.txt +++ b/fuzz/CMakeLists.txt @@ -8,6 +8,7 @@ list(APPEND COMPAT_SOURCES ) list(APPEND COMMON_SOURCES + libfuzzer.c mutator_aux.c ) diff --git a/fuzz/Dockerfile b/fuzz/Dockerfile index 68afd99..f9152f8 100644 --- a/fuzz/Dockerfile +++ b/fuzz/Dockerfile @@ -2,9 +2,10 @@ # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. -FROM ubuntu:bionic +FROM ubuntu:focal +ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update -RUN apt-get install -y clang-9 cmake git libssl-dev libudev-dev make pkg-config -RUN git clone --branch v0.5.0 https://github.com/PJK/libcbor +RUN apt-get install -y clang-10 cmake git libssl-dev libudev-dev make pkg-config +RUN git clone --branch v0.7.0 https://github.com/PJK/libcbor RUN git clone https://github.com/yubico/libfido2 -RUN CC=clang-9 /libfido2/fuzz/build-coverage /libcbor /libfido2 +RUN CC=clang-10 CXX=clang++-10 /libfido2/fuzz/build-coverage /libcbor /libfido2 diff --git a/fuzz/Makefile b/fuzz/Makefile index c8fe0b8..77699ac 100644 --- a/fuzz/Makefile +++ b/fuzz/Makefile @@ -2,10 +2,10 @@ # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. -IMAGE := libfido2-coverage:1.3.0 +IMAGE := libfido2-coverage:1.5.0 RUNNER := libfido2-runner -PROFDATA := llvm-profdata-9 -COV := llvm-cov-9 +PROFDATA := llvm-profdata-10 +COV := llvm-cov-10 TARGETS := fuzz_assert fuzz_bio fuzz_cred fuzz_credman fuzz_mgmt CORPORA := $(foreach f,${TARGETS},${f}/corpus) MINIFY := $(foreach f,${TARGETS},/minify/${f}/corpus) @@ -26,16 +26,16 @@ sync: run docker exec ${RUNNER} make -C libfido2/build corpus: sync - docker exec ${RUNNER} /bin/bash -c 'cd /libfido2/fuzz && rm -rf ${TARGETS}' + docker exec ${RUNNER} /bin/sh -c 'cd /libfido2/fuzz && rm -rf ${TARGETS}' docker exec ${RUNNER} tar Czxf /libfido2/fuzz /libfido2/fuzz/corpus.tgz ${TARGETS}: corpus sync docker exec -e LLVM_PROFILE_FILE=/profraw/$@ ${RUNNER} \ - /bin/bash -c 'rm -f /profraw/$@ && /libfido2/build/fuzz/$@ \ + /bin/sh -c 'rm -f /profraw/$@ && /libfido2/build/fuzz/$@ \ -runs=1 /libfido2/fuzz/$@' ${MINIFY}: /minify/%/corpus: % - docker exec ${RUNNER} /bin/bash -c 'rm -rf $@ && mkdir -p $@ && \ + docker exec ${RUNNER} /bin/sh -c 'rm -rf $@ && mkdir -p $@ && \ /libfido2/build/fuzz/$< -use_value_profile=1 -merge=1 $@ \ /libfido2/fuzz/$ $@ profdata: run - docker exec ${RUNNER} /bin/bash -c 'rm -f /$@ && ${PROFDATA} \ + docker exec ${RUNNER} /bin/sh -c 'rm -f /$@ && ${PROFDATA} \ merge -sparse profraw/* -o $@' report.tgz: profdata - docker exec ${RUNNER} /bin/bash -c 'rm -rf /report && mkdir /report && \ + docker exec ${RUNNER} /bin/sh -c 'rm -rf /report && mkdir /report && \ ${COV} show -format=html -tab-size=8 -instr-profile=/$< \ -output-dir=/report /libfido2/build/src/libfido2.so' docker exec -i ${RUNNER} tar Czcf / - report > $@ @@ -57,12 +57,12 @@ summary.txt: profdata /libfido2/build/src/libfido2.so -instr-profile=/$< > $@ functions.txt: profdata - docker exec ${RUNNER} /bin/bash -c '${COV} report -use-color=false \ + docker exec ${RUNNER} /bin/sh -c '${COV} report -use-color=false \ -show-functions -instr-profile=/$< \ /libfido2/build/src/libfido2.so /libfido2/src/*.[ch]' > $@ clean: run - docker exec ${RUNNER} /bin/bash -c 'rm -rf /profraw /profdata && \ + docker exec ${RUNNER} /bin/sh -c 'rm -rf /profraw /profdata && \ make -C /libfido2/build clean' -docker stop ${RUNNER} rm -rf ${TARGETS} diff --git a/fuzz/README b/fuzz/README index 42646e4..03de9d0 100644 --- a/fuzz/README +++ b/fuzz/README @@ -3,10 +3,8 @@ ASAN/MSAN/UBSAN. AFL is more convenient when fuzzing the path from the authenticator to libfido2 in an existing application. To do so, use preload-snoop.c with a real -authenticator to obtain an initial corpus, rebuild libfido2 with -DFUZZ=1 --DAFL=1, and use preload-fuzz.c to read device data from stdin. Examples of -this approach can be found in the harnesses under fuzz/harnesses/ that fuzz -the standalone examples and tools bundled with libfido2. +authenticator to obtain an initial corpus, rebuild libfido2 with -DFUZZ=1, and +use preload-fuzz.c to read device data from stdin. libFuzzer is better suited for bespoke fuzzers; see fuzz_cred.c, fuzz_credman.c, fuzz_assert.c, and fuzz_mgmt.c for examples. To build these harnesses, @@ -15,129 +13,7 @@ use -DFUZZ=1 -DLIBFUZZER=1. To run under ASAN/MSAN/UBSAN, libfido2 needs to be linked against flavours of libcbor and OpenSSL built with the respective sanitiser. In order to keep memory utilisation at a manageable level, you can either enforce limits at -the OS level (e.g. cgroups on Linux) or, alternatively, patch libcbor with -the diff at the bottom of this file. - -1. Using ASAN + UBSAN - -- Make sure you have libcbor built with -fsanitize=address; -- Make sure you have OpenSSL built with -fsanitize=address; -- Rebuild libfido2 with -DASAN=1 -DUBSAN=1. - -1.1 Decide where your workspace will live - -$ export FAKEROOT=/home/pedro/fakeroot -$ mkdir -p ${FAKEROOT}/src - -1.2 Building libcbor with ASAN - -$ git clone https://github.com/pjk/libcbor ${FAKEROOT}/src/libcbor -$ cd ${FAKEROOT}/src/libcbor - -Assuming libfido2 is under ${FAKEROOT}/src/libfido2: - -$ patch -p0 < ${FAKEROOT}/src/libfido2/fuzz/README -$ mkdir build -$ cd build -$ cmake -DCMAKE_C_FLAGS_DEBUG="-g2 -fno-omit-frame-pointer" \ - -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=Debug \ - -DCMAKE_INSTALL_PREFIX=${FAKEROOT} -DSANITIZE=ON \ - -DCMAKE_INSTALL_LIBDIR=lib .. -$ make -$ make install - -1.3 Building OpenSSL with ASAN - -$ git clone https://github.com/openssl/openssl ${FAKEROOT}/src/openssl -$ cd ${FAKEROOT}/src/openssl -$ ./Configure linux-x86_64-clang enable-asan --prefix=${FAKEROOT} \ - --openssldir=${FAKEROOT}/openssl -$ make clean -$ make -$ make install_sw - -1.4 Building libfido2 with libFuzzer and ASAN + UBSAN - -$ cd ${FAKEROOT}/src/libfido2 -$ mkdir build -$ cd build -$ cmake -DFUZZ=1 -DLIBFUZZER=1 -DASAN=1 -DUBSAN=1 -DCMAKE_C_COMPILER=clang \ - -DCRYPTO_INCLUDE_DIRS=${FAKEROOT}/include \ - -DCRYPTO_LIBRARY_DIRS=${FAKEROOT}/lib \ - -DCBOR_INCLUDE_DIRS=${FAKEROOT}/include \ - -DCBOR_LIBRARY_DIRS=${FAKEROOT}/lib \ - -DCMAKE_BUILD_TYPE=Debug .. -$ make - -2. Using MSAN + UBSAN - -- Make sure you have libcbor built with -fsanitize=memory; -- Make sure you have OpenSSL built with -fsanitize=memory; -- Rebuild libfido2 with -DMSAN=1 -DUBSAN=1. - -2.1 Decide where your workspace will live - -$ export FAKEROOT=/home/pedro/fakeroot -$ mkdir -p ${FAKEROOT}/src - -2.2 Building libcbor with MSAN - -$ git clone https://github.com/pjk/libcbor ${FAKEROOT}/src/libcbor -$ cd ${FAKEROOT}/src/libcbor - -Assuming libfido2 is under ${FAKEROOT}/src/libfido2: - -$ patch -p0 < ${FAKEROOT}/src/libfido2/fuzz/README -$ mkdir build -$ cd build -$ cmake -DCMAKE_C_FLAGS_DEBUG="-fsanitize=memory,undefined -g2 -fno-omit-frame-pointer" \ - -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=Debug \ - -DCMAKE_INSTALL_PREFIX=${FAKEROOT} -DSANITIZE=OFF \ - -DCMAKE_INSTALL_LIBDIR=lib .. -$ make -$ make install - -2.2 Building OpenSSL with MSAN - -$ mkdir -p ${FAKEROOT}/src -$ git clone https://github.com/openssl/openssl ${FAKEROOT}/src/openssl -$ cd ${FAKEROOT}/src/openssl -$ ./Configure linux-x86_64-clang enable-msan --prefix=${FAKEROOT} \ - --openssldir=${FAKEROOT}/openssl -$ make clean -$ make -$ make install_sw - -2.3 Building libfido2 with libFuzzer and MSAN + UBSAN - -$ cd ${FAKEROOT}/src/libfido2 -$ mkdir build -$ cd build -$ cmake -DFUZZ=1 -DLIBFUZZER=1 -DMSAN=1 -DUBSAN=1 -DCMAKE_C_COMPILER=clang \ - -DCRYPTO_INCLUDE_DIRS=${FAKEROOT}/include \ - -DCRYPTO_LIBRARY_DIRS=${FAKEROOT}/lib \ - -DCBOR_INCLUDE_DIRS=${FAKEROOT}/include \ - -DCBOR_LIBRARY_DIRS=${FAKEROOT}/lib \ - -DCMAKE_BUILD_TYPE=Debug .. -$ make - -3. Running the libFuzzer harnesses - -When running under ASAN, you may want to set ASAN_OPTIONS to -'allocator_may_return_null=1:detect_stack_use_after_return=1'. - -The recommended way to run the harnesses is: - -$ fuzz_{assert,cred,credman,mgmt} -use_value_profile=1 -reload=30 \ - -print_pcs=1 -print_funcs=30 -timeout=10 CORPUS_DIR - -You may want to use -jobs or -workers depending on the number of logical -cores available for fuzzing. - -4. Auxiliary scripts - -A set of harnesses and auxiliary scripts can be found under harnesses/. To -compile coverage reports, adjust the harnesses to your setup and run 'report'. +the OS level (e.g. cgroups on Linux), or patch libcbor with the diff below. diff --git src/cbor/internal/memory_utils.c src/cbor/internal/memory_utils.c index aa049a2..e294b38 100644 diff --git a/fuzz/build-coverage b/fuzz/build-coverage index af9f8df..0f8310d 100755 --- a/fuzz/build-coverage +++ b/fuzz/build-coverage @@ -1,27 +1,30 @@ -#!/bin/bash -eux -# +#!/bin/sh -eux + # Copyright (c) 2019 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. -LIBCBOR=$1 -LIBFIDO2=$2 +LIBCBOR="$1" +LIBFIDO2="$2" -CC=${CC:-clang} -PKG_CONFIG_PATH=${PKG_CONFIG_PATH:-${LIBCBOR}/install/lib/pkgconfig} +CC="${CC:-clang}" +CXX="${CXX:-clang++}" +PKG_CONFIG_PATH="${PKG_CONFIG_PATH:-${LIBCBOR}/install/lib/pkgconfig}" export CC PKG_CONFIG_PATH # Clean up. -rm -rf ${LIBCBOR}/build ${LIBCBOR}/install ${LIBFIDO2}/build +rm -rf "${LIBCBOR}/build" "${LIBCBOR}/install" "${LIBFIDO2}/build" # Patch, build, and install libcbor. -(cd ${LIBCBOR} && patch -N -l -s -p0 < ${LIBFIDO2}/fuzz/README) || true -mkdir ${LIBCBOR}/build ${LIBCBOR}/install -(cd ${LIBCBOR}/build && cmake -DCMAKE_INSTALL_PREFIX=${LIBCBOR}/install ..) -make -C ${LIBCBOR}/build all install +(cd "${LIBCBOR}" && patch -N -l -s -p0 < "${LIBFIDO2}/fuzz/README") || true +mkdir "${LIBCBOR}/build" "${LIBCBOR}/install" +(cd "${LIBCBOR}/build" && cmake -DCMAKE_INSTALL_PREFIX="${LIBCBOR}/install" ..) +make -C "${LIBCBOR}/build" all install # Build libfido2. -mkdir -p ${LIBFIDO2}/build -(cd ${LIBFIDO2}/build && cmake -DFUZZ=1 -DLIBFUZZER=1 -DCOVERAGE=1 \ - -DCMAKE_BUILD_TYPE=Debug ..) -make -C ${LIBFIDO2}/build +mkdir -p "${LIBFIDO2}/build" +export CFLAGS="-fprofile-instr-generate -fcoverage-mapping" +export LDFLAGS="${CFLAGS}" +(cd "${LIBFIDO2}/build" && cmake -DFUZZ=1 -DLIBFUZZER=1 \ + -DCMAKE_BUILD_TYPE=Debug ..) +make -C "${LIBFIDO2}/build" diff --git a/fuzz/dummy.h b/fuzz/dummy.h index a899e4a..981ccee 100644 --- a/fuzz/dummy.h +++ b/fuzz/dummy.h @@ -10,6 +10,8 @@ #include const char dummy_name[] = "finger1"; +const char dummy_pin1[] = "skepp cg0u3;Y.."; +const char dummy_pin2[] = "bastilha 6rJrfQZI."; const char dummy_pin[] = "9}4gT:8d=A37Dh}U"; const char dummy_rp_id[] = "localhost"; const char dummy_rp_name[] = "sweet home localhost"; @@ -17,8 +19,6 @@ const char dummy_user_icon[] = "an icon"; const char dummy_user_name[] = "john smith"; const char dummy_user_nick[] = "jsmith"; const uint8_t dummy_id[] = { 0x5e, 0xd2 }; -const char dummy_pin1[] = "skepp cg0u3;Y.."; -const char dummy_pin2[] = "bastilha 6rJrfQZI."; const uint8_t dummy_user_id[] = { 0x78, 0x1c, 0x78, 0x60, 0xad, 0x88, 0xd2, 0x63, diff --git a/fuzz/export.gnu b/fuzz/export.gnu index 68463ff..80941e4 100644 --- a/fuzz/export.gnu +++ b/fuzz/export.gnu @@ -76,6 +76,8 @@ fido_cbor_info_extensions_ptr; fido_cbor_info_free; fido_cbor_info_maxmsgsiz; + fido_cbor_info_maxcredcntlst; + fido_cbor_info_maxcredidlen; fido_cbor_info_fwversion; fido_cbor_info_new; fido_cbor_info_options_len; @@ -96,6 +98,8 @@ fido_cred_free; fido_cred_id_len; fido_cred_id_ptr; + fido_cred_aaguid_len; + fido_cred_aaguid_ptr; fido_credman_del_dev_rk; fido_credman_get_dev_metadata; fido_credman_get_dev_rk; @@ -155,6 +159,9 @@ fido_dev_get_assert; fido_dev_get_cbor_info; fido_dev_get_retry_count; + fido_dev_get_touch_begin; + fido_dev_get_touch_status; + fido_dev_has_pin; fido_dev_info_free; fido_dev_info_manifest; fido_dev_info_manufacturer_string; @@ -174,6 +181,9 @@ fido_dev_reset; fido_dev_set_io_functions; fido_dev_set_pin; + fido_dev_set_transport_functions; + fido_dev_supports_cred_prot; + fido_dev_supports_pin; fido_init; fido_set_log_handler; fido_strerr; diff --git a/fuzz/functions.txt b/fuzz/functions.txt index 27a9608..90284dd 100644 --- a/fuzz/functions.txt +++ b/fuzz/functions.txt @@ -9,16 +9,16 @@ TOTAL 56 0 100.00% 82 0 100.00% File '/libfido2/src/assert.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- -fido_dev_get_assert 35 3 91.43% 38 4 89.47% +fido_dev_get_assert 35 0 100.00% 38 0 100.00% fido_check_flags 13 0 100.00% 18 0 100.00% fido_get_signed_hash 32 0 100.00% 46 0 100.00% fido_verify_sig_es256 17 2 88.24% 31 7 77.42% fido_verify_sig_rs256 17 2 88.24% 31 7 77.42% -fido_verify_sig_eddsa 23 4 82.61% 43 13 69.77% -fido_assert_verify 48 4 91.67% 79 4 94.94% +fido_verify_sig_eddsa 23 2 91.30% 43 7 83.72% +fido_assert_verify 48 4 91.67% 79 5 93.67% fido_assert_set_clientdata_hash 6 0 100.00% 6 0 100.00% fido_assert_set_hmac_salt 10 0 100.00% 7 0 100.00% -fido_assert_set_rp 12 1 91.67% 14 3 78.57% +fido_assert_set_rp 12 0 100.00% 14 0 100.00% fido_assert_allow_cred 13 2 84.62% 29 3 89.66% fido_assert_set_extensions 9 0 100.00% 8 0 100.00% fido_assert_set_options 6 6 0.00% 6 6 0.00% @@ -28,7 +28,7 @@ fido_assert_clientdata_hash_ptr 1 0 100.00% 3 0 fido_assert_clientdata_hash_len 1 0 100.00% 3 0 100.00% fido_assert_new 1 0 100.00% 3 0 100.00% fido_assert_reset_tx 1 0 100.00% 15 0 100.00% -fido_assert_reset_rx 6 1 83.33% 24 3 87.50% +fido_assert_reset_rx 6 0 100.00% 24 0 100.00% fido_assert_free 6 0 100.00% 13 0 100.00% fido_assert_count 1 0 100.00% 3 0 100.00% fido_assert_rp_id 1 0 100.00% 3 0 100.00% @@ -48,22 +48,22 @@ fido_assert_user_display_name 4 0 100.00% 6 0 fido_assert_hmac_secret_ptr 4 0 100.00% 6 0 100.00% fido_assert_hmac_secret_len 4 0 100.00% 6 0 100.00% fido_assert_set_authdata 24 0 100.00% 35 0 100.00% -fido_assert_set_authdata_raw 24 4 83.33% 34 7 79.41% +fido_assert_set_authdata_raw 24 0 100.00% 34 0 100.00% fido_assert_set_sig 14 0 100.00% 17 0 100.00% fido_assert_set_count 10 0 100.00% 21 0 100.00% -assert.c:fido_dev_get_assert_wait 21 1 95.24% 16 2 87.50% +assert.c:fido_dev_get_assert_wait 21 0 100.00% 16 0 100.00% assert.c:fido_dev_get_assert_tx 58 4 93.10% 84 11 86.90% assert.c:fido_dev_get_assert_rx 19 0 100.00% 38 0 100.00% assert.c:adjust_assert_count 24 0 100.00% 33 0 100.00% assert.c:parse_assert_reply 11 0 100.00% 25 0 100.00% -assert.c:fido_get_next_assert_tx 8 2 75.00% 10 3 70.00% -assert.c:fido_get_next_assert_rx 15 4 73.33% 26 7 73.08% -assert.c:decrypt_hmac_secrets 9 3 66.67% 15 7 53.33% +assert.c:fido_get_next_assert_tx 8 0 100.00% 10 0 100.00% +assert.c:fido_get_next_assert_rx 15 2 86.67% 26 4 84.62% +assert.c:decrypt_hmac_secrets 9 0 100.00% 15 0 100.00% assert.c:check_extensions 4 0 100.00% 9 0 100.00% assert.c:fido_assert_clean_authdata 1 0 100.00% 9 0 100.00% assert.c:fido_assert_clean_sig 1 0 100.00% 5 0 100.00% --------------------------------------------------------------------------------------- -TOTAL 566 43 92.40% 900 87 90.33% +TOTAL 566 24 95.76% 900 50 94.44% File '/libfido2/src/authkey.c': Name Regions Miss Cover Lines Miss Cover @@ -135,14 +135,14 @@ File '/libfido2/src/blob.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- fido_blob_new 1 0 100.00% 3 0 100.00% -fido_blob_set 11 1 90.91% 25 4 84.00% +fido_blob_set 11 0 100.00% 25 0 100.00% fido_blob_free 8 0 100.00% 16 0 100.00% fido_free_blob_array 9 0 100.00% 17 0 100.00% fido_blob_encode 6 0 100.00% 6 0 100.00% fido_blob_decode 1 0 100.00% 3 0 100.00% fido_blob_is_empty 3 0 100.00% 3 0 100.00% --------------------------------------------------------------------------------------- -TOTAL 39 1 97.44% 73 4 94.52% +TOTAL 39 0 100.00% 73 0 100.00% File '/libfido2/src/buf.c': Name Regions Miss Cover Lines Miss Cover @@ -155,7 +155,7 @@ TOTAL 8 1 87.50% 20 1 File '/libfido2/src/cbor.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- -cbor_map_iter 20 0 100.00% 30 0 100.00% +cbor_map_iter 20 1 95.00% 30 4 86.67% cbor_array_iter 12 0 100.00% 20 0 100.00% cbor_parse_reply 27 0 100.00% 43 0 100.00% cbor_vector_free 6 0 100.00% 5 0 100.00% @@ -168,23 +168,23 @@ cbor_flatten_vector 14 1 92.86% 21 1 cbor_build_frame 15 0 100.00% 32 0 100.00% cbor_encode_rp_entity 13 0 100.00% 14 0 100.00% cbor_encode_user_entity 21 0 100.00% 18 0 100.00% -cbor_encode_pubkey_param 36 1 97.22% 48 0 100.00% +cbor_encode_pubkey_param 36 0 100.00% 48 0 100.00% cbor_encode_pubkey 10 0 100.00% 13 0 100.00% -cbor_encode_pubkey_list 18 1 94.44% 23 0 100.00% -cbor_encode_extensions 24 2 91.67% 26 3 88.46% +cbor_encode_pubkey_list 18 0 100.00% 23 0 100.00% +cbor_encode_extensions 28 0 100.00% 28 0 100.00% cbor_encode_options 13 0 100.00% 14 0 100.00% cbor_encode_assert_options 13 0 100.00% 14 0 100.00% cbor_encode_pin_auth 8 0 100.00% 12 0 100.00% cbor_encode_pin_opt 1 0 100.00% 3 0 100.00% cbor_encode_pin_enc 4 0 100.00% 12 0 100.00% -cbor_encode_change_pin_auth 44 1 97.73% 69 3 95.65% +cbor_encode_change_pin_auth 39 0 100.00% 60 0 100.00% cbor_encode_set_pin_auth 17 0 100.00% 28 0 100.00% cbor_encode_pin_hash_enc 15 0 100.00% 27 0 100.00% -cbor_encode_hmac_secret_param 41 2 95.12% 66 9 86.36% +cbor_encode_hmac_secret_param 41 1 97.56% 66 4 93.94% cbor_decode_fmt 9 0 100.00% 18 0 100.00% -cbor_decode_pubkey 21 6 71.43% 32 7 78.12% +cbor_decode_pubkey 21 1 95.24% 32 2 93.75% cbor_decode_cred_authdata 31 0 100.00% 47 0 100.00% -cbor_decode_assert_authdata 23 2 91.30% 44 2 95.45% +cbor_decode_assert_authdata 23 0 100.00% 44 0 100.00% cbor_decode_attstmt 8 0 100.00% 10 0 100.00% cbor_decode_uint64 4 0 100.00% 10 0 100.00% cbor_decode_cred_id 8 0 100.00% 10 0 100.00% @@ -193,30 +193,30 @@ cbor_decode_rp_entity 8 0 100.00% 10 0 cbor.c:ctap_check_cbor 28 0 100.00% 32 0 100.00% cbor.c:check_key_type 8 0 100.00% 9 0 100.00% cbor.c:cbor_add_arg 13 0 100.00% 28 0 100.00% -cbor.c:cbor_add_uint8 14 1 92.86% 26 3 88.46% +cbor.c:cbor_add_uint8 14 0 100.00% 26 0 100.00% cbor.c:sha256 7 0 100.00% 15 0 100.00% -cbor.c:get_cose_alg 36 6 83.33% 48 6 87.50% +cbor.c:get_cose_alg 36 0 100.00% 48 0 100.00% cbor.c:find_cose_alg 35 0 100.00% 40 0 100.00% cbor.c:decode_attcred 25 0 100.00% 58 0 100.00% -cbor.c:decode_extensions 14 9 35.71% 34 13 61.76% -cbor.c:decode_extension 27 27 0.00% 36 36 0.00% -cbor.c:decode_hmac_secret 16 4 75.00% 32 6 81.25% -cbor.c:decode_hmac_secret_aux 7 7 0.00% 17 17 0.00% +cbor.c:decode_extensions 14 0 100.00% 34 0 100.00% +cbor.c:decode_extension 27 2 92.59% 36 6 83.33% +cbor.c:decode_hmac_secret 16 0 100.00% 32 0 100.00% +cbor.c:decode_hmac_secret_aux 7 0 100.00% 17 0 100.00% cbor.c:decode_attstmt_entry 38 0 100.00% 45 0 100.00% cbor.c:decode_x5c 4 0 100.00% 8 0 100.00% cbor.c:decode_cred_id_entry 10 0 100.00% 23 0 100.00% cbor.c:decode_user_entry 25 0 100.00% 39 0 100.00% cbor.c:decode_rp_entity_entry 15 0 100.00% 29 0 100.00% --------------------------------------------------------------------------------------- -TOTAL 884 70 92.08% 1371 106 92.27% +TOTAL 883 6 99.32% 1364 17 98.75% File '/libfido2/src/cred.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- fido_dev_make_cred 12 0 100.00% 10 0 100.00% fido_check_rp_id 4 0 100.00% 14 0 100.00% -fido_cred_verify 46 6 86.96% 71 11 84.51% -fido_cred_verify_self 54 14 74.07% 90 22 75.56% +fido_cred_verify 46 2 95.65% 71 3 95.77% +fido_cred_verify_self 54 4 92.59% 90 5 94.44% fido_cred_new 1 0 100.00% 3 0 100.00% fido_cred_reset_tx 1 0 100.00% 20 0 100.00% fido_cred_reset_rx 1 0 100.00% 8 0 100.00% @@ -227,15 +227,15 @@ fido_cred_set_x509 12 0 100.00% 16 0 fido_cred_set_sig 12 0 100.00% 16 0 100.00% fido_cred_exclude 14 2 85.71% 25 3 88.00% fido_cred_set_clientdata_hash 6 0 100.00% 6 0 100.00% -fido_cred_set_rp 18 2 88.89% 26 6 76.92% -fido_cred_set_user 33 4 87.88% 50 13 74.00% +fido_cred_set_rp 18 0 100.00% 26 0 100.00% +fido_cred_set_user 33 0 100.00% 50 0 100.00% fido_cred_set_extensions 15 0 100.00% 12 0 100.00% fido_cred_set_options 6 6 0.00% 6 6 0.00% fido_cred_set_rk 2 0 100.00% 5 0 100.00% fido_cred_set_uv 2 0 100.00% 5 0 100.00% -fido_cred_set_prot 21 2 90.48% 16 0 100.00% +fido_cred_set_prot 21 0 100.00% 16 0 100.00% fido_cred_set_fmt 16 4 75.00% 15 1 93.33% -fido_cred_set_type 17 2 88.24% 9 1 88.89% +fido_cred_set_type 17 0 100.00% 9 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% fido_cred_clientdata_hash_ptr 1 0 100.00% 3 0 100.00% @@ -246,10 +246,12 @@ fido_cred_sig_ptr 1 0 100.00% 3 0 fido_cred_sig_len 1 0 100.00% 3 0 100.00% fido_cred_authdata_ptr 1 0 100.00% 3 0 100.00% fido_cred_authdata_len 1 0 100.00% 3 0 100.00% -fido_cred_pubkey_ptr 9 2 77.78% 20 2 90.00% -fido_cred_pubkey_len 9 2 77.78% 20 2 90.00% +fido_cred_pubkey_ptr 9 0 100.00% 20 0 100.00% +fido_cred_pubkey_len 9 0 100.00% 20 0 100.00% fido_cred_id_ptr 1 0 100.00% 3 0 100.00% fido_cred_id_len 1 0 100.00% 3 0 100.00% +fido_cred_aaguid_ptr 1 0 100.00% 3 0 100.00% +fido_cred_aaguid_len 1 0 100.00% 3 0 100.00% fido_cred_prot 1 0 100.00% 3 0 100.00% fido_cred_fmt 1 0 100.00% 3 0 100.00% fido_cred_rp_id 1 0 100.00% 3 0 100.00% @@ -269,7 +271,7 @@ cred.c:fido_cred_clean_authdata 1 0 100.00% 9 0 cred.c:fido_cred_clean_x509 1 0 100.00% 5 0 100.00% cred.c:fido_cred_clean_sig 1 0 100.00% 5 0 100.00% --------------------------------------------------------------------------------------- -TOTAL 534 51 90.45% 830 78 90.60% +TOTAL 536 23 95.71% 836 29 96.53% File '/libfido2/src/credman.c': Name Regions Miss Cover Lines Miss Cover @@ -295,14 +297,14 @@ fido_credman_rp_id_hash_len 4 0 100.00% 6 0 fido_credman_rp_id_hash_ptr 4 0 100.00% 6 0 100.00% credman.c:credman_get_metadata_wait 11 0 100.00% 9 0 100.00% credman.c:credman_tx 30 0 100.00% 53 0 100.00% -credman.c:credman_prepare_hmac 21 1 95.24% 43 2 95.35% +credman.c:credman_prepare_hmac 21 1 95.24% 43 3 93.02% credman.c:credman_rx_metadata 11 0 100.00% 21 0 100.00% credman.c:credman_parse_metadata 9 0 100.00% 19 0 100.00% credman.c:credman_get_rk_wait 27 0 100.00% 26 0 100.00% credman.c:credman_rx_rk 19 0 100.00% 36 0 100.00% credman.c:credman_parse_rk_count 16 0 100.00% 25 0 100.00% credman.c:credman_grow_array 17 2 88.24% 28 5 82.14% -credman.c:credman_parse_rk 13 0 100.00% 25 0 100.00% +credman.c:credman_parse_rk 22 0 100.00% 31 0 100.00% credman.c:credman_rx_next_rk 15 2 86.67% 26 4 84.62% credman.c:credman_del_rk_wait 16 0 100.00% 19 0 100.00% credman.c:credman_get_rp_wait 23 0 100.00% 16 0 100.00% @@ -313,7 +315,7 @@ credman.c:credman_rx_next_rp 15 2 86.67% 26 4 credman.c:credman_reset_rk 4 0 100.00% 10 0 100.00% credman.c:credman_reset_rp 4 0 100.00% 15 0 100.00% --------------------------------------------------------------------------------------- -TOTAL 376 18 95.21% 589 15 97.45% +TOTAL 385 18 95.32% 595 16 97.31% File '/libfido2/src/dev.c': Name Regions Miss Cover Lines Miss Cover @@ -324,9 +326,11 @@ fido_dev_info_manifest 17 17 0.00% 24 24 fido_dev_open_with_info 5 5 0.00% 6 6 0.00% fido_dev_open 1 0 100.00% 3 0 100.00% fido_dev_close 8 2 75.00% 9 0 100.00% -fido_dev_cancel 7 0 100.00% 6 0 100.00% -fido_dev_set_io_functions 18 4 77.78% 16 6 62.50% -fido_dev_set_transport_functions 6 6 0.00% 10 10 0.00% +fido_dev_cancel 11 0 100.00% 9 0 100.00% +fido_dev_get_touch_begin 50 0 100.00% 68 0 100.00% +fido_dev_get_touch_status 17 0 100.00% 25 0 100.00% +fido_dev_set_io_functions 18 4 77.78% 17 6 64.71% +fido_dev_set_transport_functions 6 6 0.00% 11 11 0.00% fido_init 7 1 85.71% 4 0 100.00% fido_dev_new 5 0 100.00% 16 0 100.00% fido_dev_new_with_info 17 17 0.00% 26 26 0.00% @@ -337,15 +341,20 @@ fido_dev_minor 1 0 100.00% 3 0 fido_dev_build 1 0 100.00% 3 0 100.00% fido_dev_flags 1 0 100.00% 3 0 100.00% fido_dev_is_fido2 2 0 100.00% 3 0 100.00% -fido_dev_force_u2f 2 0 100.00% 3 0 100.00% +fido_dev_supports_pin 3 0 100.00% 3 0 100.00% +fido_dev_has_pin 2 0 100.00% 3 0 100.00% +fido_dev_supports_cred_prot 2 0 100.00% 3 0 100.00% +fido_dev_force_u2f 2 0 100.00% 4 0 100.00% fido_dev_force_fido2 2 2 0.00% 3 3 0.00% dev.c:find_manifest_func_node 5 5 0.00% 9 9 0.00% dev.c:fido_dev_open_wait 10 0 100.00% 9 0 100.00% -dev.c:fido_dev_open_tx 25 8 68.00% 32 12 62.50% +dev.c:fido_dev_open_tx 51 13 74.51% 63 23 63.49% dev.c:obtain_nonce 4 1 75.00% 5 1 80.00% -dev.c:fido_dev_open_rx 32 0 100.00% 53 0 100.00% +dev.c:set_random_report_len 11 0 100.00% 6 0 100.00% +dev.c:fido_dev_open_rx 33 0 100.00% 56 0 100.00% +dev.c:fido_dev_set_flags 17 0 100.00% 24 0 100.00% --------------------------------------------------------------------------------------- -TOTAL 201 85 57.71% 294 128 56.46% +TOTAL 334 90 73.05% 466 140 69.96% File '/libfido2/src/ecdh.c': Name Regions Miss Cover Lines Miss Cover @@ -372,9 +381,9 @@ TOTAL 54 0 100.00% 79 0 File '/libfido2/src/err.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- -fido_strerr 108 108 0.00% 112 112 0.00% +fido_strerr 112 8 92.86% 116 8 93.10% --------------------------------------------------------------------------------------- -TOTAL 108 108 0.00% 112 112 0.00% +TOTAL 112 8 92.86% 116 8 93.10% File '/libfido2/src/es256.c': Name Regions Miss Cover Lines Miss Cover @@ -389,14 +398,14 @@ es256_pk_from_ptr 11 0 100.00% 13 0 es256_pk_set_x 1 0 100.00% 5 0 100.00% es256_pk_set_y 1 0 100.00% 5 0 100.00% es256_sk_create 39 0 100.00% 46 0 100.00% -es256_pk_to_EVP_PKEY 41 0 100.00% 58 0 100.00% -es256_pk_from_EC_KEY 38 0 100.00% 39 0 100.00% -es256_sk_to_EVP_PKEY 27 0 100.00% 41 0 100.00% +es256_pk_to_EVP_PKEY 42 0 100.00% 66 0 100.00% +es256_pk_from_EC_KEY 38 0 100.00% 43 0 100.00% +es256_sk_to_EVP_PKEY 28 0 100.00% 50 0 100.00% es256_derive_pk 25 0 100.00% 34 0 100.00% es256.c:decode_pubkey_point 9 0 100.00% 16 0 100.00% es256.c:decode_coord 8 0 100.00% 12 0 100.00% --------------------------------------------------------------------------------------- -TOTAL 278 0 100.00% 377 0 100.00% +TOTAL 280 0 100.00% 398 0 100.00% File '/libfido2/src/extern.h': Name Regions Miss Cover Lines Miss Cover @@ -423,20 +432,27 @@ TOTAL 16 16 0.00% 38 38 File '/libfido2/src/hid_linux.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- -fido_hid_manifest 33 33 0.00% 46 46 0.00% -fido_hid_open 6 6 0.00% 11 11 0.00% +fido_hid_manifest 35 35 0.00% 50 50 0.00% +fido_hid_open 17 17 0.00% 22 22 0.00% fido_hid_close 1 1 0.00% 6 6 0.00% -fido_hid_read 12 12 0.00% 16 16 0.00% -fido_hid_write 12 12 0.00% 16 16 0.00% -hid_linux.c:copy_info 35 35 0.00% 56 56 0.00% -hid_linux.c:is_fido 6 6 0.00% 14 14 0.00% -hid_linux.c:get_report_descriptor 17 17 0.00% 30 30 0.00% -hid_linux.c:get_usage_info 16 16 0.00% 33 33 0.00% +fido_hid_read 12 12 0.00% 21 21 0.00% +fido_hid_write 9 9 0.00% 16 16 0.00% +fido_hid_report_in_len 1 1 0.00% 5 5 0.00% +fido_hid_report_out_len 1 1 0.00% 5 5 0.00% +hid_linux.c:copy_info 30 30 0.00% 52 52 0.00% +hid_linux.c:is_fido 9 9 0.00% 23 23 0.00% +hid_linux.c:get_usage_info 16 16 0.00% 30 30 0.00% hid_linux.c:get_key_len 6 6 0.00% 14 14 0.00% hid_linux.c:get_key_val 6 6 0.00% 20 20 0.00% -hid_linux.c:parse_uevent 16 16 0.00% 30 30 0.00% ---------------------------------------------------------------------------------------- -TOTAL 166 166 0.00% 292 292 0.00% +hid_linux.c:get_parent_attr 6 6 0.00% 11 11 0.00% +hid_linux.c:parse_uevent 12 12 0.00% 28 28 0.00% +hid_linux.c:get_usb_attr 1 1 0.00% 3 3 0.00% +hid_linux.c:get_report_descriptor 11 11 0.00% 18 18 0.00% +hid_linux.c:get_report_sizes 19 19 0.00% 33 33 0.00% +hid_linux.c:waitfd 28 28 0.00% 43 43 0.00% +hid_linux.c:timespec_to_ms 15 15 0.00% 16 16 0.00% +--------------------------------------------------------------------------------------- +TOTAL 235 235 0.00% 416 416 0.00% File '/libfido2/src/info.c': Name Regions Miss Cover Lines Miss Cover @@ -455,11 +471,14 @@ fido_cbor_info_options_name_ptr 1 0 100.00% 3 0 fido_cbor_info_options_value_ptr 1 0 100.00% 3 0 100.00% fido_cbor_info_options_len 1 0 100.00% 3 0 100.00% 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_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% info.c:fido_dev_get_cbor_info_tx 8 0 100.00% 12 0 100.00% info.c:fido_dev_get_cbor_info_rx 6 0 100.00% 18 0 100.00% -info.c:parse_reply_element 13 0 100.00% 27 0 100.00% +info.c:parse_reply_element 16 0 100.00% 33 0 100.00% info.c:decode_versions 12 0 100.00% 21 0 100.00% info.c:decode_version 4 0 100.00% 14 0 100.00% info.c:decode_extensions 12 0 100.00% 21 0 100.00% @@ -473,23 +492,23 @@ info.c:free_str_array 4 0 100.00% 8 0 info.c:free_opt_array 4 0 100.00% 9 0 100.00% info.c:free_byte_array 1 0 100.00% 6 0 100.00% --------------------------------------------------------------------------------------- -TOTAL 146 0 100.00% 304 0 100.00% +TOTAL 152 0 100.00% 319 0 100.00% File '/libfido2/src/io.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- -fido_tx 14 1 92.86% 18 0 100.00% -fido_rx 13 2 84.62% 21 3 85.71% +fido_tx 13 1 92.31% 14 0 100.00% +fido_rx 13 2 84.62% 19 3 84.21% fido_rx_cbor_status 8 0 100.00% 12 0 100.00% -io.c:tx_empty 7 0 100.00% 16 0 100.00% +io.c:tx_empty 9 0 100.00% 17 0 100.00% io.c:tx 13 0 100.00% 21 0 100.00% -io.c:tx_preamble 10 0 100.00% 20 0 100.00% -io.c:tx_frame 9 0 100.00% 18 0 100.00% -io.c:rx 25 1 96.00% 58 4 93.10% -io.c:rx_preamble 18 1 94.44% 25 4 84.00% -io.c:rx_frame 6 0 100.00% 9 0 100.00% +io.c:tx_preamble 16 1 93.75% 24 1 95.83% +io.c:tx_frame 15 1 93.33% 22 1 95.45% +io.c:rx 40 2 95.00% 68 1 98.53% +io.c:rx_preamble 21 2 90.48% 28 5 82.14% +io.c:rx_frame 8 0 100.00% 11 0 100.00% --------------------------------------------------------------------------------------- -TOTAL 123 5 95.93% 218 11 94.95% +TOTAL 156 9 94.23% 236 11 95.34% File '/libfido2/src/iso7816.c': Name Regions Miss Cover Lines Miss Cover @@ -547,32 +566,34 @@ TOTAL 19 0 100.00% 22 0 File '/libfido2/src/rs256.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- -rs256_pk_decode 8 8 0.00% 10 10 0.00% +rs256_pk_decode 8 0 100.00% 10 0 100.00% rs256_pk_new 1 0 100.00% 3 0 100.00% rs256_pk_free 6 0 100.00% 11 0 100.00% rs256_pk_from_ptr 6 0 100.00% 8 0 100.00% rs256_pk_to_EVP_PKEY 32 0 100.00% 48 0 100.00% rs256_pk_from_RSA 32 4 87.50% 32 6 81.25% -rs256.c:decode_rsa_pubkey 9 9 0.00% 16 16 0.00% -rs256.c:decode_bignum 8 8 0.00% 12 12 0.00% +rs256.c:decode_rsa_pubkey 9 1 88.89% 16 4 75.00% +rs256.c:decode_bignum 8 1 87.50% 12 3 75.00% --------------------------------------------------------------------------------------- -TOTAL 102 29 71.57% 140 44 68.57% +TOTAL 102 6 94.12% 140 13 90.71% File '/libfido2/src/u2f.c': Name Regions Miss Cover Lines Miss Cover --------------------------------------------------------------------------------------- -u2f_register 70 5 92.86% 88 7 92.05% -u2f_authenticate 32 4 87.50% 44 2 95.45% +u2f_register 70 1 98.57% 88 0 100.00% +u2f_authenticate 32 0 100.00% 44 0 100.00% +u2f_get_touch_begin 30 0 100.00% 46 0 100.00% +u2f_get_touch_status 18 0 100.00% 29 0 100.00% u2f.c:key_lookup 44 0 100.00% 69 0 100.00% -u2f.c:send_dummy_register 31 5 83.87% 49 8 83.67% +u2f.c:send_dummy_register 31 1 96.77% 49 0 100.00% u2f.c:parse_register_reply 57 0 100.00% 83 0 100.00% -u2f.c:x5c_get 21 2 90.48% 37 6 83.78% +u2f.c:x5c_get 21 1 95.24% 37 3 91.89% u2f.c:sig_get 8 1 87.50% 16 6 62.50% -u2f.c:encode_cred_authdata 37 3 91.89% 82 9 89.02% -u2f.c:cbor_blob_from_ec_point 22 1 95.45% 39 3 92.31% -u2f.c:u2f_authenticate_single 36 2 94.44% 58 4 93.10% -u2f.c:do_auth 50 3 94.00% 71 4 94.37% +u2f.c:encode_cred_authdata 37 2 94.59% 82 6 92.68% +u2f.c:cbor_blob_from_ec_point 22 0 100.00% 39 0 100.00% +u2f.c:u2f_authenticate_single 36 0 100.00% 58 0 100.00% +u2f.c:do_auth 50 1 98.00% 71 0 100.00% u2f.c:parse_auth_reply 23 2 91.30% 29 3 89.66% u2f.c:authdata_fake 12 0 100.00% 34 0 100.00% --------------------------------------------------------------------------------------- -TOTAL 443 28 93.68% 699 52 92.56% +TOTAL 491 9 98.17% 774 18 97.67% diff --git a/fuzz/fuzz_assert.c b/fuzz/fuzz_assert.c index 5b72658..3ae54eb 100644 --- a/fuzz/fuzz_assert.c +++ b/fuzz/fuzz_assert.c @@ -23,39 +23,23 @@ #include "../openbsd-compat/openbsd-compat.h" -#define TAG_U2F 0x01 -#define TAG_TYPE 0x02 -#define TAG_CDH 0x03 -#define TAG_RP_ID 0x04 -#define TAG_EXT 0x05 -#define TAG_SEED 0x06 -#define TAG_UP 0x07 -#define TAG_UV 0x08 -#define TAG_WIRE_DATA 0x09 -#define TAG_CRED_COUNT 0x0a -#define TAG_CRED 0x0b -#define TAG_ES256 0x0c -#define TAG_RS256 0x0d -#define TAG_PIN 0x0e -#define TAG_EDDSA 0x0f - /* Parameter set defining a FIDO2 get assertion operation. */ struct param { - char pin[MAXSTR]; - char rp_id[MAXSTR]; - int ext; - int seed; - struct blob cdh; - struct blob cred; - struct blob es256; - struct blob rs256; - struct blob eddsa; - struct blob wire_data; - uint8_t cred_count; - uint8_t type; - uint8_t u2f; - uint8_t up; - uint8_t uv; + char pin[MAXSTR]; + char rp_id[MAXSTR]; + int ext; + int seed; + struct blob cdh; + struct blob cred; + struct blob es256; + struct blob rs256; + struct blob eddsa; + struct blob wire_data; + uint8_t cred_count; + uint8_t type; + uint8_t u2f; + uint8_t up; + uint8_t uv; }; /* @@ -83,73 +67,153 @@ static const uint8_t dummy_wire_data_u2f[] = { WIREDATA_CTAP_U2F_AUTH, }; -int LLVMFuzzerTestOneInput(const uint8_t *, size_t); -size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); - -static int -unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN +struct param * +unpack(const uint8_t *ptr, size_t len) { - uint8_t **pp = (void *)&ptr; - - if (unpack_byte(TAG_UV, pp, &len, &p->uv) < 0 || - unpack_byte(TAG_UP, pp, &len, &p->up) < 0 || - unpack_byte(TAG_U2F, pp, &len, &p->u2f) < 0 || - unpack_byte(TAG_TYPE, pp, &len, &p->type) < 0 || - unpack_byte(TAG_CRED_COUNT, pp, &len, &p->cred_count) < 0 || - unpack_int(TAG_EXT, pp, &len, &p->ext) < 0 || - unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || - unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || - unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || - unpack_blob(TAG_WIRE_DATA, pp, &len, &p->wire_data) < 0 || - unpack_blob(TAG_RS256, pp, &len, &p->rs256) < 0 || - unpack_blob(TAG_ES256, pp, &len, &p->es256) < 0 || - unpack_blob(TAG_EDDSA, pp, &len, &p->eddsa) < 0 || - unpack_blob(TAG_CRED, pp, &len, &p->cred) < 0 || - unpack_blob(TAG_CDH, pp, &len, &p->cdh) < 0) - return (-1); - - return (0); + 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) != 15 || + (v = cbor_array_handle(item)) == NULL) + goto fail; + + if (unpack_byte(v[0], &p->uv) < 0 || + unpack_byte(v[1], &p->up) < 0 || + unpack_byte(v[2], &p->u2f) < 0 || + unpack_byte(v[3], &p->type) < 0 || + unpack_byte(v[4], &p->cred_count) < 0 || + unpack_int(v[5], &p->ext) < 0 || + unpack_int(v[6], &p->seed) < 0 || + unpack_string(v[7], p->rp_id) < 0 || + unpack_string(v[8], p->pin) < 0 || + unpack_blob(v[9], &p->wire_data) < 0 || + unpack_blob(v[10], &p->rs256) < 0 || + unpack_blob(v[11], &p->es256) < 0 || + unpack_blob(v[12], &p->eddsa) < 0 || + unpack_blob(v[13], &p->cred) < 0 || + unpack_blob(v[14], &p->cdh) < 0) + goto fail; + + ok = 0; +fail: + if (ok < 0) { + free(p); + p = NULL; + } + + if (item) + cbor_decref(&item); + + return p; } -static size_t +size_t pack(uint8_t *ptr, size_t len, const struct param *p) { - const size_t max = len; - - if (pack_byte(TAG_UV, &ptr, &len, p->uv) < 0 || - pack_byte(TAG_UP, &ptr, &len, p->up) < 0 || - pack_byte(TAG_U2F, &ptr, &len, p->u2f) < 0 || - pack_byte(TAG_TYPE, &ptr, &len, p->type) < 0 || - pack_byte(TAG_CRED_COUNT, &ptr, &len, p->cred_count) < 0 || - pack_int(TAG_EXT, &ptr, &len, p->ext) < 0 || - pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || - pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || - pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || - pack_blob(TAG_WIRE_DATA, &ptr, &len, &p->wire_data) < 0 || - pack_blob(TAG_RS256, &ptr, &len, &p->rs256) < 0 || - pack_blob(TAG_ES256, &ptr, &len, &p->es256) < 0 || - pack_blob(TAG_EDDSA, &ptr, &len, &p->eddsa) < 0 || - pack_blob(TAG_CRED, &ptr, &len, &p->cred) < 0 || - pack_blob(TAG_CDH, &ptr, &len, &p->cdh) < 0) - return (0); - - return (max - len); + cbor_item_t *argv[15], *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(15)) == NULL || + (argv[0] = pack_byte(p->uv)) == NULL || + (argv[1] = pack_byte(p->up)) == NULL || + (argv[2] = pack_byte(p->u2f)) == NULL || + (argv[3] = pack_byte(p->type)) == NULL || + (argv[4] = pack_byte(p->cred_count)) == NULL || + (argv[5] = pack_int(p->ext)) == NULL || + (argv[6] = pack_int(p->seed)) == NULL || + (argv[7] = pack_string(p->rp_id)) == NULL || + (argv[8] = pack_string(p->pin)) == NULL || + (argv[9] = pack_blob(&p->wire_data)) == NULL || + (argv[10] = pack_blob(&p->rs256)) == NULL || + (argv[11] = pack_blob(&p->es256)) == NULL || + (argv[12] = pack_blob(&p->eddsa)) == NULL || + (argv[13] = pack_blob(&p->cred)) == NULL || + (argv[14] = pack_blob(&p->cdh)) == NULL) + goto fail; + + for (size_t i = 0; i < 15; 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 < 15; i++) + if (argv[i]) + cbor_decref(&argv[i]); + + if (array) + cbor_decref(&array); + + free(cbor); + + return cbor_len; } -static size_t -input_len(int max) +size_t +pack_dummy(uint8_t *ptr, size_t len) { - return (5 * len_byte() + 2 * len_int() + 2 * len_string(max) + - 6 * len_blob(max)); + struct param dummy; + uint8_t blob[4096]; + size_t blob_len; + + memset(&dummy, 0, sizeof(dummy)); + + dummy.type = 1; /* rsa */ + dummy.ext = FIDO_EXT_HMAC_SECRET; + + strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); + strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); + + dummy.cred.len = sizeof(dummy_cdh); /* XXX */ + dummy.cdh.len = sizeof(dummy_cdh); + dummy.es256.len = sizeof(dummy_es256); + dummy.rs256.len = sizeof(dummy_rs256); + dummy.eddsa.len = sizeof(dummy_eddsa); + dummy.wire_data.len = sizeof(dummy_wire_data_fido); + + memcpy(&dummy.cred.body, &dummy_cdh, dummy.cred.len); /* XXX */ + memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len); + memcpy(&dummy.wire_data.body, &dummy_wire_data_fido, + dummy.wire_data.len); + memcpy(&dummy.es256.body, &dummy_es256, dummy.es256.len); + memcpy(&dummy.rs256.body, &dummy_rs256, dummy.rs256.len); + memcpy(&dummy.eddsa.body, &dummy_eddsa, dummy.eddsa.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 get_assert(fido_assert_t *assert, uint8_t u2f, const struct blob *cdh, const char *rp_id, int ext, uint8_t up, uint8_t uv, const char *pin, - uint8_t cred_count, struct blob *cred) + uint8_t cred_count, const struct blob *cred) { - fido_dev_t *dev; - fido_dev_io_t io; + fido_dev_t *dev; + fido_dev_io_t io; memset(&io, 0, sizeof(io)); @@ -166,21 +230,31 @@ get_assert(fido_assert_t *assert, uint8_t u2f, const struct blob *cdh, if (u2f & 1) fido_dev_force_u2f(dev); - - for (uint8_t i = 0; i < cred_count; i++) - fido_assert_allow_cred(assert, cred->body, cred->len); - - fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len); - fido_assert_set_rp(assert, rp_id); if (ext & 1) fido_assert_set_extensions(assert, FIDO_EXT_HMAC_SECRET); if (up & 1) fido_assert_set_up(assert, FIDO_OPT_TRUE); + else if (u2f &1) + fido_assert_set_up(assert, FIDO_OPT_FALSE); if (uv & 1) fido_assert_set_uv(assert, FIDO_OPT_TRUE); - /* XXX reuse cred as hmac salt to keep struct param small */ + + for (uint8_t i = 0; i < cred_count; i++) + fido_assert_allow_cred(assert, cred->body, cred->len); + + fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len); + fido_assert_set_rp(assert, rp_id); + /* XXX reuse cred as hmac salt */ fido_assert_set_hmac_salt(assert, cred->body, cred->len); + /* repeat memory operations to trigger reallocation paths */ + fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len); + fido_assert_set_rp(assert, rp_id); + fido_assert_set_hmac_salt(assert, cred->body, cred->len); + + if (strlen(pin) == 0) + pin = NULL; + fido_dev_get_assert(dev, assert, u2f & 1 ? NULL : pin); fido_dev_cancel(dev); @@ -194,7 +268,7 @@ verify_assert(int type, const unsigned char *cdh_ptr, size_t cdh_len, const unsigned char *sig_ptr, size_t sig_len, uint8_t up, uint8_t uv, int ext, void *pk) { - fido_assert_t *assert = NULL; + fido_assert_t *assert = NULL; if ((assert = fido_assert_new()) == NULL) return; @@ -202,16 +276,30 @@ verify_assert(int type, const unsigned char *cdh_ptr, size_t cdh_len, fido_assert_set_clientdata_hash(assert, cdh_ptr, cdh_len); fido_assert_set_rp(assert, rp_id); fido_assert_set_count(assert, 1); + if (fido_assert_set_authdata(assert, 0, authdata_ptr, authdata_len) != FIDO_OK) { fido_assert_set_authdata_raw(assert, 0, authdata_ptr, authdata_len); } + + if (up & 1) + fido_assert_set_up(assert, FIDO_OPT_TRUE); + if (uv & 1) + fido_assert_set_uv(assert, FIDO_OPT_TRUE); + fido_assert_set_extensions(assert, ext); - if (up & 1) fido_assert_set_up(assert, FIDO_OPT_TRUE); - if (uv & 1) fido_assert_set_uv(assert, FIDO_OPT_TRUE); fido_assert_set_sig(assert, 0, sig_ptr, sig_len); - fido_assert_verify(assert, 0, type, pk); + + /* repeat memory operations to trigger reallocation paths */ + if (fido_assert_set_authdata(assert, 0, authdata_ptr, + authdata_len) != FIDO_OK) { + fido_assert_set_authdata_raw(assert, 0, authdata_ptr, + authdata_len); + } + fido_assert_set_sig(assert, 0, sig_ptr, sig_len); + + assert(fido_assert_verify(assert, 0, type, pk) != FIDO_OK); fido_assert_free(&assert); } @@ -262,38 +350,30 @@ out: EVP_PKEY_free(pkey); } -int -LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +void +test(const struct param *p) { - struct param p; - fido_assert_t *assert = NULL; - es256_pk_t *es256_pk = NULL; - rs256_pk_t *rs256_pk = NULL; - eddsa_pk_t *eddsa_pk = NULL; - uint8_t flags; - uint32_t sigcount; - int cose_alg = 0; - void *pk; - - memset(&p, 0, sizeof(p)); - - if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) || - unpack(data, size, &p) < 0) - return (0); - - prng_init((unsigned int)p.seed); - + fido_assert_t *assert = NULL; + es256_pk_t *es256_pk = NULL; + rs256_pk_t *rs256_pk = NULL; + eddsa_pk_t *eddsa_pk = NULL; + uint8_t flags; + uint32_t sigcount; + int cose_alg = 0; + void *pk; + + prng_init((unsigned int)p->seed); fido_init(FIDO_DEBUG); fido_set_log_handler(consume_str); - switch (p.type & 3) { + switch (p->type & 3) { case 0: cose_alg = COSE_ES256; if ((es256_pk = es256_pk_new()) == NULL) - return (0); + return; - es256_pk_from_ptr(es256_pk, p.es256.body, p.es256.len); + es256_pk_from_ptr(es256_pk, p->es256.body, p->es256.len); pk = es256_pk; break; @@ -301,9 +381,9 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) cose_alg = COSE_RS256; if ((rs256_pk = rs256_pk_new()) == NULL) - return (0); + return; - rs256_pk_from_ptr(rs256_pk, p.rs256.body, p.rs256.len); + rs256_pk_from_ptr(rs256_pk, p->rs256.body, p->rs256.len); pk = rs256_pk; rs256_convert(pk); @@ -313,9 +393,9 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) cose_alg = COSE_EDDSA; if ((eddsa_pk = eddsa_pk_new()) == NULL) - return (0); + return; - eddsa_pk_from_ptr(eddsa_pk, p.eddsa.body, p.eddsa.len); + eddsa_pk_from_ptr(eddsa_pk, p->eddsa.body, p->eddsa.len); pk = eddsa_pk; eddsa_convert(pk); @@ -326,10 +406,10 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) if ((assert = fido_assert_new()) == NULL) goto out; - set_wire_data(p.wire_data.body, p.wire_data.len); + set_wire_data(p->wire_data.body, p->wire_data.len); - get_assert(assert, p.u2f, &p.cdh, p.rp_id, p.ext, p.up, p.uv, p.pin, - p.cred_count, &p.cred); + get_assert(assert, p->u2f, &p->cdh, p->rp_id, p->ext, p->up, p->uv, + p->pin, p->cred_count, &p->cred); /* XXX +1 on purpose */ for (size_t i = 0; i <= fido_assert_count(assert); i++) { @@ -340,7 +420,7 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) fido_assert_authdata_ptr(assert, i), fido_assert_authdata_len(assert, i), fido_assert_sig_ptr(assert, i), - fido_assert_sig_len(assert, i), p.up, p.uv, p.ext, pk); + fido_assert_sig_len(assert, i), p->up, p->uv, p->ext, pk); consume(fido_assert_id_ptr(assert, i), fido_assert_id_len(assert, i)); consume(fido_assert_user_id_ptr(assert, i), @@ -365,103 +445,40 @@ out: eddsa_pk_free(&eddsa_pk); fido_assert_free(&assert); - - return (0); } -static size_t -pack_dummy(uint8_t *ptr, size_t len) +void +mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN { - struct param dummy; - uint8_t blob[16384]; - size_t blob_len; - - memset(&dummy, 0, sizeof(dummy)); - - dummy.type = 1; /* rsa */ - dummy.ext = FIDO_EXT_HMAC_SECRET; - - strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); - strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); - - dummy.cred.len = sizeof(dummy_cdh); /* XXX */ - dummy.cdh.len = sizeof(dummy_cdh); - dummy.es256.len = sizeof(dummy_es256); - dummy.rs256.len = sizeof(dummy_rs256); - dummy.eddsa.len = sizeof(dummy_eddsa); - dummy.wire_data.len = sizeof(dummy_wire_data_fido); - - memcpy(&dummy.cred.body, &dummy_cdh, dummy.cred.len); /* XXX */ - memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len); - memcpy(&dummy.wire_data.body, &dummy_wire_data_fido, - dummy.wire_data.len); - memcpy(&dummy.es256.body, &dummy_es256, dummy.es256.len); - memcpy(&dummy.rs256.body, &dummy_rs256, dummy.rs256.len); - memcpy(&dummy.eddsa.body, &dummy_eddsa, dummy.eddsa.len); - - blob_len = pack(blob, sizeof(blob), &dummy); - assert(blob_len != 0); - - if (blob_len > len) { - memcpy(ptr, blob, len); - return (len); + if (flags & MUTATE_SEED) + p->seed = (int)seed; + + if (flags & MUTATE_PARAM) { + mutate_byte(&p->uv); + mutate_byte(&p->up); + mutate_byte(&p->u2f); + mutate_byte(&p->type); + mutate_byte(&p->cred_count); + mutate_int(&p->ext); + mutate_blob(&p->rs256); + mutate_blob(&p->es256); + mutate_blob(&p->eddsa); + mutate_blob(&p->cred); + mutate_blob(&p->cdh); + mutate_string(p->rp_id); + mutate_string(p->pin); } - memcpy(ptr, blob, blob_len); - - return (blob_len); -} - -size_t -LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, - unsigned int seed) NO_MSAN -{ - struct param p; - uint8_t blob[16384]; - size_t blob_len; - - (void)seed; - - memset(&p, 0, sizeof(p)); - - if (unpack(data, size, &p) < 0) - return (pack_dummy(data, maxsize)); - - mutate_byte(&p.uv); - mutate_byte(&p.up); - mutate_byte(&p.u2f); - mutate_byte(&p.type); - mutate_byte(&p.cred_count); - - mutate_int(&p.ext); - p.seed = (int)seed; - - if (p.u2f & 1) { - p.wire_data.len = sizeof(dummy_wire_data_u2f); - memcpy(&p.wire_data.body, &dummy_wire_data_u2f, - p.wire_data.len); - } else { - p.wire_data.len = sizeof(dummy_wire_data_fido); - memcpy(&p.wire_data.body, &dummy_wire_data_fido, - p.wire_data.len); + if (flags & MUTATE_WIREDATA) { + if (p->u2f & 1) { + p->wire_data.len = sizeof(dummy_wire_data_u2f); + memcpy(&p->wire_data.body, &dummy_wire_data_u2f, + p->wire_data.len); + } else { + p->wire_data.len = sizeof(dummy_wire_data_fido); + memcpy(&p->wire_data.body, &dummy_wire_data_fido, + p->wire_data.len); + } + mutate_blob(&p->wire_data); } - - mutate_blob(&p.wire_data); - mutate_blob(&p.rs256); - mutate_blob(&p.es256); - mutate_blob(&p.eddsa); - mutate_blob(&p.cred); - mutate_blob(&p.cdh); - - mutate_string(p.rp_id); - mutate_string(p.pin); - - blob_len = pack(blob, sizeof(blob), &p); - - if (blob_len == 0 || blob_len > maxsize) - return (0); - - memcpy(data, blob, blob_len); - - return (blob_len); } diff --git a/fuzz/fuzz_bio.c b/fuzz/fuzz_bio.c index 05f6ce3..5051a34 100644 --- a/fuzz/fuzz_bio.c +++ b/fuzz/fuzz_bio.c @@ -19,27 +19,17 @@ #include "../openbsd-compat/openbsd-compat.h" -#define TAG_PIN 0x01 -#define TAG_NAME 0x02 -#define TAG_SEED 0x03 -#define TAG_ID 0x04 -#define TAG_INFO_WIRE_DATA 0x05 -#define TAG_ENROLL_WIRE_DATA 0x06 -#define TAG_LIST_WIRE_DATA 0x07 -#define TAG_SET_NAME_WIRE_DATA 0x08 -#define TAG_REMOVE_WIRE_DATA 0x09 - /* Parameter set defining a FIDO2 credential management operation. */ struct param { - char pin[MAXSTR]; - char name[MAXSTR]; - int seed; - struct blob id; - struct blob info_wire_data; - struct blob enroll_wire_data; - struct blob list_wire_data; - struct blob set_name_wire_data; - struct blob remove_wire_data; + char pin[MAXSTR]; + char name[MAXSTR]; + int seed; + struct blob id; + struct blob info_wire_data; + struct blob enroll_wire_data; + struct blob list_wire_data; + struct blob set_name_wire_data; + struct blob remove_wire_data; }; /* @@ -100,58 +90,141 @@ static const uint8_t dummy_remove_wire_data[] = { WIREDATA_CTAP_CBOR_STATUS, }; -int LLVMFuzzerTestOneInput(const uint8_t *, size_t); -size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); - -static int -unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN +struct param * +unpack(const uint8_t *ptr, size_t len) { - uint8_t **pp = (void *)&ptr; - - if (unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || - unpack_string(TAG_NAME, pp, &len, p->name) < 0 || - unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || - unpack_blob(TAG_ID, pp, &len, &p->id) < 0 || - unpack_blob(TAG_INFO_WIRE_DATA, pp, &len, &p->info_wire_data) < 0 || - unpack_blob(TAG_ENROLL_WIRE_DATA, pp, &len, &p->enroll_wire_data) < 0 || - unpack_blob(TAG_LIST_WIRE_DATA, pp, &len, &p->list_wire_data) < 0 || - unpack_blob(TAG_SET_NAME_WIRE_DATA, pp, &len, &p->set_name_wire_data) < 0 || - unpack_blob(TAG_REMOVE_WIRE_DATA, pp, &len, &p->remove_wire_data) < 0) - return (-1); - - return (0); + 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) != 9 || + (v = cbor_array_handle(item)) == NULL) + goto fail; + + if (unpack_int(v[0], &p->seed) < 0 || + unpack_string(v[1], p->pin) < 0 || + unpack_string(v[2], p->name) < 0 || + unpack_blob(v[3], &p->id) < 0 || + unpack_blob(v[4], &p->info_wire_data) < 0 || + unpack_blob(v[5], &p->enroll_wire_data) < 0 || + unpack_blob(v[6], &p->list_wire_data) < 0 || + unpack_blob(v[7], &p->set_name_wire_data) < 0 || + unpack_blob(v[8], &p->remove_wire_data) < 0) + goto fail; + + ok = 0; +fail: + if (ok < 0) { + free(p); + p = NULL; + } + + if (item) + cbor_decref(&item); + + return p; } -static size_t +size_t pack(uint8_t *ptr, size_t len, const struct param *p) { - const size_t max = len; - - if (pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || - pack_string(TAG_NAME, &ptr, &len, p->name) < 0 || - pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || - pack_blob(TAG_ID, &ptr, &len, &p->id) < 0 || - pack_blob(TAG_INFO_WIRE_DATA, &ptr, &len, &p->info_wire_data) < 0 || - pack_blob(TAG_ENROLL_WIRE_DATA, &ptr, &len, &p->enroll_wire_data) < 0 || - pack_blob(TAG_LIST_WIRE_DATA, &ptr, &len, &p->list_wire_data) < 0 || - pack_blob(TAG_SET_NAME_WIRE_DATA, &ptr, &len, &p->set_name_wire_data) < 0 || - pack_blob(TAG_REMOVE_WIRE_DATA, &ptr, &len, &p->remove_wire_data) < 0) - return (0); - - return (max - len); + cbor_item_t *argv[9], *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(9)) == NULL || + (argv[0] = pack_int(p->seed)) == NULL || + (argv[1] = pack_string(p->pin)) == NULL || + (argv[2] = pack_string(p->name)) == NULL || + (argv[3] = pack_blob(&p->id)) == NULL || + (argv[4] = pack_blob(&p->info_wire_data)) == NULL || + (argv[5] = pack_blob(&p->enroll_wire_data)) == NULL || + (argv[6] = pack_blob(&p->list_wire_data)) == NULL || + (argv[7] = pack_blob(&p->set_name_wire_data)) == NULL || + (argv[8] = pack_blob(&p->remove_wire_data)) == NULL) + goto fail; + + for (size_t i = 0; i < 9; 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 < 9; i++) + if (argv[i]) + cbor_decref(&argv[i]); + + if (array) + cbor_decref(&array); + + free(cbor); + + return cbor_len; } -static size_t -input_len(int max) +size_t +pack_dummy(uint8_t *ptr, size_t len) { - return (2 * len_string(max) + len_int() + 6 * len_blob(max)); + struct param dummy; + uint8_t blob[4096]; + size_t blob_len; + + memset(&dummy, 0, sizeof(dummy)); + + strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); + strlcpy(dummy.name, dummy_name, sizeof(dummy.name)); + + dummy.info_wire_data.len = sizeof(dummy_info_wire_data); + dummy.enroll_wire_data.len = sizeof(dummy_enroll_wire_data); + dummy.list_wire_data.len = sizeof(dummy_list_wire_data); + dummy.set_name_wire_data.len = sizeof(dummy_set_name_wire_data); + dummy.remove_wire_data.len = sizeof(dummy_remove_wire_data); + dummy.id.len = sizeof(dummy_id); + + memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data, + dummy.info_wire_data.len); + memcpy(&dummy.enroll_wire_data.body, &dummy_enroll_wire_data, + dummy.enroll_wire_data.len); + memcpy(&dummy.list_wire_data.body, &dummy_list_wire_data, + dummy.list_wire_data.len); + memcpy(&dummy.set_name_wire_data.body, &dummy_set_name_wire_data, + dummy.set_name_wire_data.len); + memcpy(&dummy.remove_wire_data.body, &dummy_remove_wire_data, + dummy.remove_wire_data.len); + memcpy(&dummy.id.body, &dummy_id, dummy.id.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 fido_dev_t * -prepare_dev() +prepare_dev(void) { - fido_dev_t *dev; - fido_dev_io_t io; + fido_dev_t *dev; + fido_dev_io_t io; + bool x; memset(&io, 0, sizeof(io)); @@ -163,26 +236,35 @@ prepare_dev() if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { fido_dev_free(&dev); - return (NULL); + return NULL; } - return (dev); + x = fido_dev_is_fido2(dev); + consume(&x, sizeof(x)); + x = fido_dev_supports_pin(dev); + consume(&x, sizeof(x)); + x = fido_dev_has_pin(dev); + consume(&x, sizeof(x)); + + return dev; } static void -get_info(struct param *p) +get_info(const struct param *p) { fido_dev_t *dev = NULL; fido_bio_info_t *i = NULL; uint8_t type; uint8_t max_samples; + int r; set_wire_data(p->info_wire_data.body, p->info_wire_data.len); if ((dev = prepare_dev()) == NULL || (i = fido_bio_info_new()) == NULL) goto done; - fido_bio_dev_get_info(dev, i); + r = fido_bio_dev_get_info(dev, i); + consume_str(fido_strerr(r)); type = fido_bio_info_type(i); max_samples = fido_bio_info_max_samples(i); @@ -217,7 +299,7 @@ consume_enroll(fido_bio_enroll_t *e) } static void -enroll(struct param *p) +enroll(const struct param *p) { fido_dev_t *dev = NULL; fido_bio_template_t *t = NULL; @@ -252,7 +334,7 @@ done: } static void -list(struct param *p) +list(const struct param *p) { fido_dev_t *dev = NULL; fido_bio_template_array_t *ta = NULL; @@ -280,7 +362,7 @@ done: } static void -set_name(struct param *p) +set_name(const struct param *p) { fido_dev_t *dev = NULL; fido_bio_template_t *t = NULL; @@ -306,10 +388,11 @@ done: } static void -del(struct param *p) +del(const struct param *p) { fido_dev_t *dev = NULL; fido_bio_template_t *t = NULL; + int r; set_wire_data(p->remove_wire_data.body, p->remove_wire_data.len); @@ -317,8 +400,9 @@ del(struct param *p) (t = fido_bio_template_new()) == NULL) goto done; - fido_bio_template_set_id(t, p->id.body, p->id.len); + r = fido_bio_template_set_id(t, p->id.body, p->id.len); consume_template(t); + consume_str(fido_strerr(r)); fido_bio_dev_enroll_remove(dev, t, p->pin); @@ -330,106 +414,37 @@ done: fido_bio_template_free(&t); } -int -LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +void +test(const struct param *p) { - struct param p; - - memset(&p, 0, sizeof(p)); - - if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) || - unpack(data, size, &p) < 0) - return (0); - - prng_init((unsigned int)p.seed); - + prng_init((unsigned int)p->seed); fido_init(FIDO_DEBUG); fido_set_log_handler(consume_str); - get_info(&p); - enroll(&p); - list(&p); - set_name(&p); - del(&p); - - return (0); + get_info(p); + enroll(p); + list(p); + set_name(p); + del(p); } -static size_t -pack_dummy(uint8_t *ptr, size_t len) +void +mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN { - struct param dummy; - uint8_t blob[32768]; - size_t blob_len; - - memset(&dummy, 0, sizeof(dummy)); - - strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); - strlcpy(dummy.name, dummy_name, sizeof(dummy.name)); - - dummy.info_wire_data.len = sizeof(dummy_info_wire_data); - dummy.enroll_wire_data.len = sizeof(dummy_enroll_wire_data); - dummy.list_wire_data.len = sizeof(dummy_list_wire_data); - dummy.set_name_wire_data.len = sizeof(dummy_set_name_wire_data); - dummy.remove_wire_data.len = sizeof(dummy_remove_wire_data); - dummy.id.len = sizeof(dummy_id); - - memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data, - dummy.info_wire_data.len); - memcpy(&dummy.enroll_wire_data.body, &dummy_enroll_wire_data, - dummy.enroll_wire_data.len); - memcpy(&dummy.list_wire_data.body, &dummy_list_wire_data, - dummy.list_wire_data.len); - memcpy(&dummy.set_name_wire_data.body, &dummy_set_name_wire_data, - dummy.set_name_wire_data.len); - memcpy(&dummy.remove_wire_data.body, &dummy_remove_wire_data, - dummy.remove_wire_data.len); - memcpy(&dummy.id.body, &dummy_id, dummy.id.len); - - blob_len = pack(blob, sizeof(blob), &dummy); - assert(blob_len != 0); + if (flags & MUTATE_SEED) + p->seed = (int)seed; - if (blob_len > len) { - memcpy(ptr, blob, len); - return (len); + if (flags & MUTATE_PARAM) { + mutate_blob(&p->id); + mutate_string(p->pin); + mutate_string(p->name); } - memcpy(ptr, blob, blob_len); - - return (blob_len); -} - -size_t -LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, - unsigned int seed) NO_MSAN -{ - struct param p; - uint8_t blob[16384]; - size_t blob_len; - - memset(&p, 0, sizeof(p)); - - if (unpack(data, size, &p) < 0) - return (pack_dummy(data, maxsize)); - - p.seed = (int)seed; - - mutate_blob(&p.id); - mutate_blob(&p.info_wire_data); - mutate_blob(&p.enroll_wire_data); - mutate_blob(&p.list_wire_data); - mutate_blob(&p.set_name_wire_data); - mutate_blob(&p.remove_wire_data); - - mutate_string(p.pin); - mutate_string(p.name); - - blob_len = pack(blob, sizeof(blob), &p); - - if (blob_len == 0 || blob_len > maxsize) - return (0); - - memcpy(data, blob, blob_len); - - return (blob_len); + if (flags & MUTATE_WIREDATA) { + mutate_blob(&p->info_wire_data); + mutate_blob(&p->enroll_wire_data); + mutate_blob(&p->list_wire_data); + mutate_blob(&p->set_name_wire_data); + mutate_blob(&p->remove_wire_data); + } } diff --git a/fuzz/fuzz_cred.c b/fuzz/fuzz_cred.c index cc37903..87a877a 100644 --- a/fuzz/fuzz_cred.c +++ b/fuzz/fuzz_cred.c @@ -18,43 +18,25 @@ #include "../openbsd-compat/openbsd-compat.h" -#define TAG_U2F 0x01 -#define TAG_TYPE 0x02 -#define TAG_CDH 0x03 -#define TAG_RP_ID 0x04 -#define TAG_RP_NAME 0x05 -#define TAG_USER_ID 0x06 -#define TAG_USER_NAME 0x07 -#define TAG_USER_NICK 0x08 -#define TAG_USER_ICON 0x09 -#define TAG_EXT 0x0a -#define TAG_SEED 0x0b -#define TAG_RK 0x0c -#define TAG_UV 0x0d -#define TAG_PIN 0x0e -#define TAG_WIRE_DATA 0x0f -#define TAG_EXCL_COUNT 0x10 -#define TAG_EXCL_CRED 0x11 - /* Parameter set defining a FIDO2 make credential operation. */ struct param { - char pin[MAXSTR]; - char rp_id[MAXSTR]; - char rp_name[MAXSTR]; - char user_icon[MAXSTR]; - char user_name[MAXSTR]; - char user_nick[MAXSTR]; - int ext; - int seed; - struct blob cdh; - struct blob excl_cred; - struct blob user_id; - struct blob wire_data; - uint8_t excl_count; - uint8_t rk; - uint8_t type; - uint8_t u2f; - uint8_t uv; + char pin[MAXSTR]; + char rp_id[MAXSTR]; + char rp_name[MAXSTR]; + char user_icon[MAXSTR]; + char user_name[MAXSTR]; + char user_nick[MAXSTR]; + int ext; + int seed; + struct blob cdh; + struct blob excl_cred; + struct blob user_id; + struct blob wire_data; + uint8_t excl_count; + uint8_t rk; + uint8_t type; + uint8_t u2f; + uint8_t uv; }; /* @@ -86,79 +68,157 @@ static const uint8_t dummy_wire_data_u2f[] = { WIREDATA_CTAP_U2F_REGISTER, }; -int LLVMFuzzerTestOneInput(const uint8_t *, size_t); -size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); - -static int -unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN +struct param * +unpack(const uint8_t *ptr, size_t len) { - uint8_t **pp = (void *)&ptr; - - if (unpack_byte(TAG_RK, pp, &len, &p->rk) < 0 || - unpack_byte(TAG_TYPE, pp, &len, &p->type) < 0 || - unpack_byte(TAG_U2F, pp, &len, &p->u2f) < 0 || - unpack_byte(TAG_UV, pp, &len, &p->uv) < 0 || - unpack_byte(TAG_EXCL_COUNT, pp, &len, &p->excl_count) < 0 || - unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || - unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || - unpack_string(TAG_RP_NAME, pp, &len, p->rp_name) < 0 || - unpack_string(TAG_USER_ICON, pp, &len, p->user_icon) < 0 || - unpack_string(TAG_USER_NAME, pp, &len, p->user_name) < 0 || - unpack_string(TAG_USER_NICK, pp, &len, p->user_nick) < 0 || - unpack_int(TAG_EXT, pp, &len, &p->ext) < 0 || - unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || - unpack_blob(TAG_CDH, pp, &len, &p->cdh) < 0 || - unpack_blob(TAG_USER_ID, pp, &len, &p->user_id) < 0 || - unpack_blob(TAG_WIRE_DATA, pp, &len, &p->wire_data) < 0 || - unpack_blob(TAG_EXCL_CRED, pp, &len, &p->excl_cred) < 0) - return (-1); - - return (0); + 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) != 17 || + (v = cbor_array_handle(item)) == NULL) + goto fail; + + if (unpack_byte(v[0], &p->rk) < 0 || + unpack_byte(v[1], &p->type) < 0 || + unpack_byte(v[2], &p->u2f) < 0 || + unpack_byte(v[3], &p->uv) < 0 || + unpack_byte(v[4], &p->excl_count) < 0 || + unpack_int(v[5], &p->ext) < 0 || + unpack_int(v[6], &p->seed) < 0 || + unpack_string(v[7], p->pin) < 0 || + unpack_string(v[8], p->rp_id) < 0 || + unpack_string(v[9], p->rp_name) < 0 || + unpack_string(v[10], p->user_icon) < 0 || + unpack_string(v[11], p->user_name) < 0 || + unpack_string(v[12], p->user_nick) < 0 || + unpack_blob(v[13], &p->cdh) < 0 || + unpack_blob(v[14], &p->user_id) < 0 || + unpack_blob(v[15], &p->wire_data) < 0 || + unpack_blob(v[16], &p->excl_cred) < 0) + goto fail; + + ok = 0; +fail: + if (ok < 0) { + free(p); + p = NULL; + } + + if (item) + cbor_decref(&item); + + return p; } -static size_t +size_t pack(uint8_t *ptr, size_t len, const struct param *p) { - const size_t max = len; - - if (pack_byte(TAG_RK, &ptr, &len, p->rk) < 0 || - pack_byte(TAG_TYPE, &ptr, &len, p->type) < 0 || - pack_byte(TAG_U2F, &ptr, &len, p->u2f) < 0 || - pack_byte(TAG_UV, &ptr, &len, p->uv) < 0 || - pack_byte(TAG_EXCL_COUNT, &ptr, &len, p->excl_count) < 0 || - pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || - pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || - pack_string(TAG_RP_NAME, &ptr, &len, p->rp_name) < 0 || - pack_string(TAG_USER_ICON, &ptr, &len, p->user_icon) < 0 || - pack_string(TAG_USER_NAME, &ptr, &len, p->user_name) < 0 || - pack_string(TAG_USER_NICK, &ptr, &len, p->user_nick) < 0 || - pack_int(TAG_EXT, &ptr, &len, p->ext) < 0 || - pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || - pack_blob(TAG_CDH, &ptr, &len, &p->cdh) < 0 || - pack_blob(TAG_USER_ID, &ptr, &len, &p->user_id) < 0 || - pack_blob(TAG_WIRE_DATA, &ptr, &len, &p->wire_data) < 0 || - pack_blob(TAG_EXCL_CRED, &ptr, &len, &p->excl_cred) < 0) - return (0); - - return (max - len); + cbor_item_t *argv[17], *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(17)) == NULL || + (argv[0] = pack_byte(p->rk)) == NULL || + (argv[1] = pack_byte(p->type)) == NULL || + (argv[2] = pack_byte(p->u2f)) == NULL || + (argv[3] = pack_byte(p->uv)) == NULL || + (argv[4] = pack_byte(p->excl_count)) == NULL || + (argv[5] = pack_int(p->ext)) == NULL || + (argv[6] = pack_int(p->seed)) == NULL || + (argv[7] = pack_string(p->pin)) == NULL || + (argv[8] = pack_string(p->rp_id)) == NULL || + (argv[9] = pack_string(p->rp_name)) == NULL || + (argv[10] = pack_string(p->user_icon)) == NULL || + (argv[11] = pack_string(p->user_name)) == NULL || + (argv[12] = pack_string(p->user_nick)) == NULL || + (argv[13] = pack_blob(&p->cdh)) == NULL || + (argv[14] = pack_blob(&p->user_id)) == NULL || + (argv[15] = pack_blob(&p->wire_data)) == NULL || + (argv[16] = pack_blob(&p->excl_cred)) == NULL) + goto fail; + + for (size_t i = 0; i < 17; 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 < 17; i++) + if (argv[i]) + cbor_decref(&argv[i]); + + if (array) + cbor_decref(&array); + + free(cbor); + + return cbor_len; } -static size_t -input_len(int max) +size_t +pack_dummy(uint8_t *ptr, size_t len) { - return (5 * len_byte() + 6 * len_string(max) + 2 * len_int() + - 4 * len_blob(max)); + struct param dummy; + uint8_t blob[4096]; + size_t blob_len; + + memset(&dummy, 0, sizeof(dummy)); + + dummy.type = 1; + dummy.ext = FIDO_EXT_HMAC_SECRET; + + strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); + strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); + strlcpy(dummy.rp_name, dummy_rp_name, sizeof(dummy.rp_name)); + strlcpy(dummy.user_icon, dummy_user_icon, sizeof(dummy.user_icon)); + strlcpy(dummy.user_name, dummy_user_name, sizeof(dummy.user_name)); + strlcpy(dummy.user_nick, dummy_user_nick, sizeof(dummy.user_nick)); + + dummy.cdh.len = sizeof(dummy_cdh); + dummy.user_id.len = sizeof(dummy_user_id); + dummy.wire_data.len = sizeof(dummy_wire_data_fido); + + memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len); + memcpy(&dummy.user_id.body, &dummy_user_id, dummy.user_id.len); + memcpy(&dummy.wire_data.body, &dummy_wire_data_fido, + dummy.wire_data.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 make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh, - const char *rp_id, const char *rp_name, struct blob *user_id, + const char *rp_id, const char *rp_name, const struct blob *user_id, const char *user_name, const char *user_nick, const char *user_icon, int ext, uint8_t rk, uint8_t uv, const char *pin, uint8_t excl_count, - struct blob *excl_cred) + const struct blob *excl_cred) { - fido_dev_t *dev; - fido_dev_io_t io; + fido_dev_t *dev; + fido_dev_io_t io; memset(&io, 0, sizeof(io)); @@ -185,6 +245,7 @@ make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh, fido_cred_set_user(cred, user_id->body, user_id->len, user_name, user_nick, user_icon); fido_cred_set_extensions(cred, ext); + if (rk & 1) fido_cred_set_rk(cred, FIDO_OPT_TRUE); if (uv & 1) @@ -192,6 +253,16 @@ make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh, if (user_id->len) fido_cred_set_prot(cred, user_id->body[0] & 0x03); + /* repeat memory operations to trigger reallocation paths */ + fido_cred_set_type(cred, type); + fido_cred_set_clientdata_hash(cred, cdh->body, cdh->len); + fido_cred_set_rp(cred, rp_id, rp_name); + fido_cred_set_user(cred, user_id->body, user_id->len, user_name, + user_nick, user_icon); + + if (strlen(pin) == 0) + pin = NULL; + fido_dev_make_cred(dev, cred, u2f & 1 ? NULL : pin); fido_dev_cancel(dev); @@ -206,8 +277,8 @@ verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len, const unsigned char *x5c_ptr, size_t x5c_len, const unsigned char *sig_ptr, size_t sig_len, const char *fmt, int prot) { - fido_cred_t *cred; - uint8_t flags; + fido_cred_t *cred; + uint8_t flags; if ((cred = fido_cred_new()) == NULL) return; @@ -229,11 +300,18 @@ verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len, if (fmt) fido_cred_set_fmt(cred, fmt); - fido_cred_verify(cred); - fido_cred_verify_self(cred); + /* repeat memory operations to trigger reallocation paths */ + if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK) + fido_cred_set_authdata_raw(cred, authdata_ptr, authdata_len); + fido_cred_set_x509(cred, x5c_ptr, x5c_len); + fido_cred_set_sig(cred, sig_ptr, sig_len); + + assert(fido_cred_verify(cred) != FIDO_OK); + assert(fido_cred_verify_self(cred) != FIDO_OK); consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); + consume(fido_cred_aaguid_ptr(cred), fido_cred_aaguid_len(cred)); consume(fido_cred_user_id_ptr(cred), fido_cred_user_id_len(cred)); consume(fido_cred_user_name(cred), xstrlen(fido_cred_user_name(cred))); consume(fido_cred_display_name(cred), @@ -247,30 +325,16 @@ verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len, fido_cred_free(&cred); } -int -LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +static void +test_cred(const struct param *p) { - struct param p; - fido_cred_t *cred = NULL; - int cose_alg = 0; - - memset(&p, 0, sizeof(p)); - - if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) || - unpack(data, size, &p) < 0) - return (0); - - prng_init((unsigned int)p.seed); - - fido_init(FIDO_DEBUG); - fido_set_log_handler(consume_str); + fido_cred_t *cred = NULL; + int cose_alg = 0; if ((cred = fido_cred_new()) == NULL) - return (0); - - set_wire_data(p.wire_data.body, p.wire_data.len); + return; - switch (p.type & 3) { + switch (p->type & 3) { case 0: cose_alg = COSE_ES256; break; @@ -282,116 +346,106 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) break; } - make_cred(cred, p.u2f, cose_alg, &p.cdh, p.rp_id, p.rp_name, - &p.user_id, p.user_name, p.user_nick, p.user_icon, p.ext, p.rk, - p.uv, p.pin, p.excl_count, &p.excl_cred); + set_wire_data(p->wire_data.body, p->wire_data.len); + + make_cred(cred, p->u2f, cose_alg, &p->cdh, p->rp_id, p->rp_name, + &p->user_id, p->user_name, p->user_nick, p->user_icon, p->ext, + p->rk, p->uv, p->pin, p->excl_count, &p->excl_cred); verify_cred(cose_alg, fido_cred_clientdata_hash_ptr(cred), fido_cred_clientdata_hash_len(cred), fido_cred_rp_id(cred), fido_cred_rp_name(cred), fido_cred_authdata_ptr(cred), - fido_cred_authdata_len(cred), p.ext, p.rk, p.uv, + fido_cred_authdata_len(cred), p->ext, p->rk, p->uv, fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred), fido_cred_sig_ptr(cred), fido_cred_sig_len(cred), fido_cred_fmt(cred), fido_cred_prot(cred)); fido_cred_free(&cred); - - return (0); } -static size_t -pack_dummy(uint8_t *ptr, size_t len) +static void +test_touch(const struct param *p) { - struct param dummy; - uint8_t blob[16384]; - size_t blob_len; + fido_dev_t *dev; + fido_dev_io_t io; + int r; + int touched; - memset(&dummy, 0, sizeof(dummy)); + memset(&io, 0, sizeof(io)); - dummy.type = 1; - dummy.ext = FIDO_EXT_HMAC_SECRET; + io.open = dev_open; + io.close = dev_close; + io.read = dev_read; + io.write = dev_write; - strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); - strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); - strlcpy(dummy.rp_name, dummy_rp_name, sizeof(dummy.rp_name)); - strlcpy(dummy.user_icon, dummy_user_icon, sizeof(dummy.user_icon)); - strlcpy(dummy.user_name, dummy_user_name, sizeof(dummy.user_name)); - strlcpy(dummy.user_nick, dummy_user_nick, sizeof(dummy.user_nick)); + set_wire_data(p->wire_data.body, p->wire_data.len); - dummy.cdh.len = sizeof(dummy_cdh); - dummy.user_id.len = sizeof(dummy_user_id); - dummy.wire_data.len = sizeof(dummy_wire_data_fido); + if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, + &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { + fido_dev_free(&dev); + return; + } - memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len); - memcpy(&dummy.user_id.body, &dummy_user_id, dummy.user_id.len); - memcpy(&dummy.wire_data.body, &dummy_wire_data_fido, - dummy.wire_data.len); + if (p->u2f & 1) + fido_dev_force_u2f(dev); - blob_len = pack(blob, sizeof(blob), &dummy); - assert(blob_len != 0); + r = fido_dev_get_touch_begin(dev); + consume_str(fido_strerr(r)); + r = fido_dev_get_touch_status(dev, &touched, -1); + consume_str(fido_strerr(r)); + consume(&touched, sizeof(touched)); - if (blob_len > len) { - memcpy(ptr, blob, len); - return (len); - } + fido_dev_cancel(dev); + fido_dev_close(dev); + fido_dev_free(&dev); +} - memcpy(ptr, blob, blob_len); +void +test(const struct param *p) +{ + prng_init((unsigned int)p->seed); + fido_init(FIDO_DEBUG); + fido_set_log_handler(consume_str); - return (blob_len); + test_cred(p); + test_touch(p); } -size_t -LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, - unsigned int seed) NO_MSAN +void +mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN { - struct param p; - uint8_t blob[16384]; - size_t blob_len; - - memset(&p, 0, sizeof(p)); - - if (unpack(data, size, &p) < 0) - return (pack_dummy(data, maxsize)); - - mutate_byte(&p.rk); - mutate_byte(&p.type); - mutate_byte(&p.u2f); - mutate_byte(&p.uv); - mutate_byte(&p.excl_count); - - mutate_int(&p.ext); - p.seed = (int)seed; - - mutate_blob(&p.cdh); - mutate_blob(&p.user_id); - - if (p.u2f & 1) { - p.wire_data.len = sizeof(dummy_wire_data_u2f); - memcpy(&p.wire_data.body, &dummy_wire_data_u2f, - p.wire_data.len); - } else { - p.wire_data.len = sizeof(dummy_wire_data_fido); - memcpy(&p.wire_data.body, &dummy_wire_data_fido, - p.wire_data.len); + if (flags & MUTATE_SEED) + p->seed = (int)seed; + + if (flags & MUTATE_PARAM) { + mutate_byte(&p->rk); + mutate_byte(&p->type); + mutate_byte(&p->u2f); + mutate_byte(&p->uv); + mutate_byte(&p->excl_count); + mutate_int(&p->ext); + mutate_blob(&p->cdh); + mutate_blob(&p->user_id); + mutate_blob(&p->excl_cred); + mutate_string(p->pin); + mutate_string(p->user_icon); + mutate_string(p->user_name); + mutate_string(p->user_nick); + mutate_string(p->rp_id); + mutate_string(p->rp_name); } - mutate_blob(&p.wire_data); - mutate_blob(&p.excl_cred); - - mutate_string(p.pin); - mutate_string(p.user_icon); - mutate_string(p.user_name); - mutate_string(p.user_nick); - mutate_string(p.rp_id); - mutate_string(p.rp_name); - - blob_len = pack(blob, sizeof(blob), &p); - - if (blob_len == 0 || blob_len > maxsize) - return (0); - - memcpy(data, blob, blob_len); - - return (blob_len); + if (flags & MUTATE_WIREDATA) { + if (p->u2f & 1) { + p->wire_data.len = sizeof(dummy_wire_data_u2f); + memcpy(&p->wire_data.body, &dummy_wire_data_u2f, + p->wire_data.len); + } else { + p->wire_data.len = sizeof(dummy_wire_data_fido); + memcpy(&p->wire_data.body, &dummy_wire_data_fido, + p->wire_data.len); + } + mutate_blob(&p->wire_data); + } } diff --git a/fuzz/fuzz_credman.c b/fuzz/fuzz_credman.c index 323d0a9..db0dfb8 100644 --- a/fuzz/fuzz_credman.c +++ b/fuzz/fuzz_credman.c @@ -19,25 +19,16 @@ #include "../openbsd-compat/openbsd-compat.h" -#define TAG_META_WIRE_DATA 0x01 -#define TAG_RP_WIRE_DATA 0x02 -#define TAG_RK_WIRE_DATA 0x03 -#define TAG_DEL_WIRE_DATA 0x04 -#define TAG_CRED_ID 0x05 -#define TAG_PIN 0x06 -#define TAG_RP_ID 0x07 -#define TAG_SEED 0x08 - /* Parameter set defining a FIDO2 credential management operation. */ struct param { - char pin[MAXSTR]; - char rp_id[MAXSTR]; - int seed; - struct blob cred_id; - struct blob del_wire_data; - struct blob meta_wire_data; - struct blob rk_wire_data; - struct blob rp_wire_data; + char pin[MAXSTR]; + char rp_id[MAXSTR]; + int seed; + struct blob cred_id; + struct blob del_wire_data; + struct blob meta_wire_data; + struct blob rk_wire_data; + struct blob rp_wire_data; }; /* @@ -88,56 +79,136 @@ static const uint8_t dummy_del_wire_data[] = { WIREDATA_CTAP_CBOR_STATUS, }; -int LLVMFuzzerTestOneInput(const uint8_t *, size_t); -size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); - -static int -unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN +struct param * +unpack(const uint8_t *ptr, size_t len) { - uint8_t **pp = (void *)&ptr; - - if (unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || - unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || - unpack_blob(TAG_CRED_ID, pp, &len, &p->cred_id) < 0 || - unpack_blob(TAG_META_WIRE_DATA, pp, &len, &p->meta_wire_data) < 0 || - unpack_blob(TAG_RP_WIRE_DATA, pp, &len, &p->rp_wire_data) < 0 || - unpack_blob(TAG_RK_WIRE_DATA, pp, &len, &p->rk_wire_data) < 0 || - unpack_blob(TAG_DEL_WIRE_DATA, pp, &len, &p->del_wire_data) < 0 || - unpack_int(TAG_SEED, pp, &len, &p->seed) < 0) - return (-1); - - return (0); + 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) != 8 || + (v = cbor_array_handle(item)) == NULL) + goto fail; + + if (unpack_int(v[0], &p->seed) < 0 || + unpack_string(v[1], p->pin) < 0 || + unpack_string(v[2], p->rp_id) < 0 || + unpack_blob(v[3], &p->cred_id) < 0 || + unpack_blob(v[4], &p->meta_wire_data) < 0 || + unpack_blob(v[5], &p->rp_wire_data) < 0 || + unpack_blob(v[6], &p->rk_wire_data) < 0 || + unpack_blob(v[7], &p->del_wire_data) < 0) + goto fail; + + ok = 0; +fail: + if (ok < 0) { + free(p); + p = NULL; + } + + if (item) + cbor_decref(&item); + + return p; } -static size_t +size_t pack(uint8_t *ptr, size_t len, const struct param *p) { - const size_t max = len; - - if (pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || - pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || - pack_blob(TAG_CRED_ID, &ptr, &len, &p->cred_id) < 0 || - pack_blob(TAG_META_WIRE_DATA, &ptr, &len, &p->meta_wire_data) < 0 || - pack_blob(TAG_RP_WIRE_DATA, &ptr, &len, &p->rp_wire_data) < 0 || - pack_blob(TAG_RK_WIRE_DATA, &ptr, &len, &p->rk_wire_data) < 0 || - pack_blob(TAG_DEL_WIRE_DATA, &ptr, &len, &p->del_wire_data) < 0 || - pack_int(TAG_SEED, &ptr, &len, p->seed) < 0) - return (0); - - return (max - len); + cbor_item_t *argv[8], *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(8)) == NULL || + (argv[0] = pack_int(p->seed)) == NULL || + (argv[1] = pack_string(p->pin)) == NULL || + (argv[2] = pack_string(p->rp_id)) == NULL || + (argv[3] = pack_blob(&p->cred_id)) == NULL || + (argv[4] = pack_blob(&p->meta_wire_data)) == NULL || + (argv[5] = pack_blob(&p->rp_wire_data)) == NULL || + (argv[6] = pack_blob(&p->rk_wire_data)) == NULL || + (argv[7] = pack_blob(&p->del_wire_data)) == NULL) + goto fail; + + for (size_t i = 0; i < 8; 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 < 8; i++) + if (argv[i]) + cbor_decref(&argv[i]); + + if (array) + cbor_decref(&array); + + free(cbor); + + return cbor_len; } -static size_t -input_len(int max) +size_t +pack_dummy(uint8_t *ptr, size_t len) { - return (2 * len_string(max) + 5 * len_blob(max) + len_int()); + struct param dummy; + uint8_t blob[4096]; + size_t blob_len; + + memset(&dummy, 0, sizeof(dummy)); + + strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); + strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); + + dummy.meta_wire_data.len = sizeof(dummy_meta_wire_data); + dummy.rp_wire_data.len = sizeof(dummy_rp_wire_data); + dummy.rk_wire_data.len = sizeof(dummy_rk_wire_data); + dummy.del_wire_data.len = sizeof(dummy_del_wire_data); + dummy.cred_id.len = sizeof(dummy_cred_id); + + memcpy(&dummy.meta_wire_data.body, &dummy_meta_wire_data, + dummy.meta_wire_data.len); + memcpy(&dummy.rp_wire_data.body, &dummy_rp_wire_data, + dummy.rp_wire_data.len); + memcpy(&dummy.rk_wire_data.body, &dummy_rk_wire_data, + dummy.rk_wire_data.len); + memcpy(&dummy.del_wire_data.body, &dummy_del_wire_data, + dummy.del_wire_data.len); + memcpy(&dummy.cred_id.body, &dummy_cred_id, dummy.cred_id.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 fido_dev_t * -prepare_dev() +prepare_dev(void) { - fido_dev_t *dev; - fido_dev_io_t io; + fido_dev_t *dev; + fido_dev_io_t io; + bool x; memset(&io, 0, sizeof(io)); @@ -149,14 +220,19 @@ prepare_dev() if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { fido_dev_free(&dev); - return (NULL); + return NULL; } - return (dev); + x = fido_dev_is_fido2(dev); + consume(&x, sizeof(x)); + x = fido_dev_supports_cred_prot(dev); + consume(&x, sizeof(x)); + + return dev; } static void -get_metadata(struct param *p) +get_metadata(const struct param *p) { fido_dev_t *dev; fido_credman_metadata_t *metadata; @@ -187,7 +263,7 @@ get_metadata(struct param *p) } static void -get_rp_list(struct param *p) +get_rp_list(const struct param *p) { fido_dev_t *dev; fido_credman_rp_t *rp; @@ -221,12 +297,12 @@ get_rp_list(struct param *p) } static void -get_rk_list(struct param *p) +get_rk_list(const struct param *p) { fido_dev_t *dev; fido_credman_rk_t *rk; const fido_cred_t *cred; - int type; + int val; set_wire_data(p->rk_wire_data.body, p->rk_wire_data.len); @@ -247,8 +323,8 @@ get_rk_list(struct param *p) assert(i >= fido_credman_rk_count(rk)); continue; } - type = fido_cred_type(cred); - consume(&type, sizeof(type)); + val = fido_cred_type(cred); + consume(&val, sizeof(val)); consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); consume(fido_cred_user_id_ptr(cred), @@ -257,6 +333,8 @@ get_rk_list(struct param *p) xstrlen(fido_cred_user_name(cred))); consume(fido_cred_display_name(cred), xstrlen(fido_cred_display_name(cred))); + val = fido_cred_prot(cred); + consume(&val, sizeof(val)); } fido_credman_rk_free(&rk); @@ -265,7 +343,7 @@ get_rk_list(struct param *p) } static void -del_rk(struct param *p) +del_rk(const struct param *p) { fido_dev_t *dev; @@ -279,101 +357,35 @@ del_rk(struct param *p) fido_dev_free(&dev); } -int -LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +void +test(const struct param *p) { - struct param p; - - memset(&p, 0, sizeof(p)); - - if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) || - unpack(data, size, &p) < 0) - return (0); - - prng_init((unsigned int)p.seed); - + prng_init((unsigned int)p->seed); fido_init(FIDO_DEBUG); fido_set_log_handler(consume_str); - get_metadata(&p); - get_rp_list(&p); - get_rk_list(&p); - del_rk(&p); - - return (0); + get_metadata(p); + get_rp_list(p); + get_rk_list(p); + del_rk(p); } -static size_t -pack_dummy(uint8_t *ptr, size_t len) +void +mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN { - struct param dummy; - uint8_t blob[32768]; - size_t blob_len; - - memset(&dummy, 0, sizeof(dummy)); - - strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); - strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); + if (flags & MUTATE_SEED) + p->seed = (int)seed; - dummy.meta_wire_data.len = sizeof(dummy_meta_wire_data); - dummy.rp_wire_data.len = sizeof(dummy_rp_wire_data); - dummy.rk_wire_data.len = sizeof(dummy_rk_wire_data); - dummy.del_wire_data.len = sizeof(dummy_del_wire_data); - dummy.cred_id.len = sizeof(dummy_cred_id); - - memcpy(&dummy.meta_wire_data.body, &dummy_meta_wire_data, - dummy.meta_wire_data.len); - memcpy(&dummy.rp_wire_data.body, &dummy_rp_wire_data, - dummy.rp_wire_data.len); - memcpy(&dummy.rk_wire_data.body, &dummy_rk_wire_data, - dummy.rk_wire_data.len); - memcpy(&dummy.del_wire_data.body, &dummy_del_wire_data, - dummy.del_wire_data.len); - memcpy(&dummy.cred_id.body, &dummy_cred_id, dummy.cred_id.len); - - blob_len = pack(blob, sizeof(blob), &dummy); - assert(blob_len != 0); - - if (blob_len > len) { - memcpy(ptr, blob, len); - return (len); + if (flags & MUTATE_PARAM) { + mutate_blob(&p->cred_id); + mutate_string(p->pin); + mutate_string(p->rp_id); } - memcpy(ptr, blob, blob_len); - - return (blob_len); -} - -size_t -LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, - unsigned int seed) NO_MSAN -{ - struct param p; - uint8_t blob[16384]; - size_t blob_len; - - memset(&p, 0, sizeof(p)); - - if (unpack(data, size, &p) < 0) - return (pack_dummy(data, maxsize)); - - p.seed = (int)seed; - - mutate_blob(&p.cred_id); - mutate_blob(&p.meta_wire_data); - mutate_blob(&p.rp_wire_data); - mutate_blob(&p.rk_wire_data); - mutate_blob(&p.del_wire_data); - - mutate_string(p.pin); - mutate_string(p.rp_id); - - blob_len = pack(blob, sizeof(blob), &p); - - if (blob_len == 0 || blob_len > maxsize) - return (0); - - memcpy(data, blob, blob_len); - - return (blob_len); + if (flags & MUTATE_WIREDATA) { + mutate_blob(&p->meta_wire_data); + mutate_blob(&p->rp_wire_data); + mutate_blob(&p->rk_wire_data); + mutate_blob(&p->del_wire_data); + } } diff --git a/fuzz/fuzz_mgmt.c b/fuzz/fuzz_mgmt.c index d46daf6..0b6cf19 100644 --- a/fuzz/fuzz_mgmt.c +++ b/fuzz/fuzz_mgmt.c @@ -17,24 +17,15 @@ #include "../openbsd-compat/openbsd-compat.h" -#define TAG_PIN1 0x01 -#define TAG_PIN2 0x02 -#define TAG_RESET_WIRE_DATA 0x03 -#define TAG_INFO_WIRE_DATA 0x04 -#define TAG_SET_PIN_WIRE_DATA 0x05 -#define TAG_CHANGE_PIN_WIRE_DATA 0x06 -#define TAG_RETRY_WIRE_DATA 0x07 -#define TAG_SEED 0x08 - struct param { - char pin1[MAXSTR]; - char pin2[MAXSTR]; - struct blob reset_wire_data; - struct blob info_wire_data; - struct blob set_pin_wire_data; - struct blob change_pin_wire_data; - struct blob retry_wire_data; - int seed; + char pin1[MAXSTR]; + char pin2[MAXSTR]; + struct blob reset_wire_data; + struct blob info_wire_data; + struct blob set_pin_wire_data; + struct blob change_pin_wire_data; + struct blob retry_wire_data; + int seed; }; static const uint8_t dummy_reset_wire_data[] = { @@ -72,56 +63,136 @@ static const uint8_t dummy_retry_wire_data[] = { WIREDATA_CTAP_CBOR_RETRIES, }; -int LLVMFuzzerTestOneInput(const uint8_t *, size_t); -size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); - -static int -unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN +struct param * +unpack(const uint8_t *ptr, size_t len) { - uint8_t **pp = (void *)&ptr; - - if (unpack_string(TAG_PIN1, pp, &len, p->pin1) < 0 || - unpack_string(TAG_PIN2, pp, &len, p->pin2) < 0 || - unpack_blob(TAG_RESET_WIRE_DATA, pp, &len, &p->reset_wire_data) < 0 || - unpack_blob(TAG_INFO_WIRE_DATA, pp, &len, &p->info_wire_data) < 0 || - unpack_blob(TAG_SET_PIN_WIRE_DATA, pp, &len, &p->set_pin_wire_data) < 0 || - unpack_blob(TAG_CHANGE_PIN_WIRE_DATA, pp, &len, &p->change_pin_wire_data) < 0 || - unpack_blob(TAG_RETRY_WIRE_DATA, pp, &len, &p->retry_wire_data) < 0 || - unpack_int(TAG_SEED, pp, &len, &p->seed) < 0) - return (-1); - - return (0); + 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) != 8 || + (v = cbor_array_handle(item)) == NULL) + goto fail; + + if (unpack_int(v[0], &p->seed) < 0 || + unpack_string(v[1], p->pin1) < 0 || + unpack_string(v[2], p->pin2) < 0 || + unpack_blob(v[3], &p->reset_wire_data) < 0 || + unpack_blob(v[4], &p->info_wire_data) < 0 || + unpack_blob(v[5], &p->set_pin_wire_data) < 0 || + unpack_blob(v[6], &p->change_pin_wire_data) < 0 || + unpack_blob(v[7], &p->retry_wire_data) < 0) + goto fail; + + ok = 0; +fail: + if (ok < 0) { + free(p); + p = NULL; + } + + if (item) + cbor_decref(&item); + + return p; } -static size_t +size_t pack(uint8_t *ptr, size_t len, const struct param *p) { - const size_t max = len; - - if (pack_string(TAG_PIN1, &ptr, &len, p->pin1) < 0 || - pack_string(TAG_PIN2, &ptr, &len, p->pin2) < 0 || - pack_blob(TAG_RESET_WIRE_DATA, &ptr, &len, &p->reset_wire_data) < 0 || - pack_blob(TAG_INFO_WIRE_DATA, &ptr, &len, &p->info_wire_data) < 0 || - pack_blob(TAG_SET_PIN_WIRE_DATA, &ptr, &len, &p->set_pin_wire_data) < 0 || - pack_blob(TAG_CHANGE_PIN_WIRE_DATA, &ptr, &len, &p->change_pin_wire_data) < 0 || - pack_blob(TAG_RETRY_WIRE_DATA, &ptr, &len, &p->retry_wire_data) < 0 || - pack_int(TAG_SEED, &ptr, &len, p->seed) < 0) - return (0); - - return (max - len); + cbor_item_t *argv[8], *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(8)) == NULL || + (argv[0] = pack_int(p->seed)) == NULL || + (argv[1] = pack_string(p->pin1)) == NULL || + (argv[2] = pack_string(p->pin2)) == NULL || + (argv[3] = pack_blob(&p->reset_wire_data)) == NULL || + (argv[4] = pack_blob(&p->info_wire_data)) == NULL || + (argv[5] = pack_blob(&p->set_pin_wire_data)) == NULL || + (argv[6] = pack_blob(&p->change_pin_wire_data)) == NULL || + (argv[7] = pack_blob(&p->retry_wire_data)) == NULL) + goto fail; + + for (size_t i = 0; i < 8; 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 < 8; i++) + if (argv[i]) + cbor_decref(&argv[i]); + + if (array) + cbor_decref(&array); + + free(cbor); + + return cbor_len; } -static size_t -input_len(int max) +size_t +pack_dummy(uint8_t *ptr, size_t len) { - return (2 * len_string(max) + 5 * len_blob(max) + len_int()); + struct param dummy; + uint8_t blob[4096]; + size_t blob_len; + + memset(&dummy, 0, sizeof(dummy)); + + strlcpy(dummy.pin1, dummy_pin1, sizeof(dummy.pin1)); + strlcpy(dummy.pin2, dummy_pin2, sizeof(dummy.pin2)); + + dummy.reset_wire_data.len = sizeof(dummy_reset_wire_data); + dummy.info_wire_data.len = sizeof(dummy_info_wire_data); + dummy.set_pin_wire_data.len = sizeof(dummy_set_pin_wire_data); + dummy.change_pin_wire_data.len = sizeof(dummy_change_pin_wire_data); + dummy.retry_wire_data.len = sizeof(dummy_retry_wire_data); + + memcpy(&dummy.reset_wire_data.body, &dummy_reset_wire_data, + dummy.reset_wire_data.len); + memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data, + dummy.info_wire_data.len); + memcpy(&dummy.set_pin_wire_data.body, &dummy_set_pin_wire_data, + dummy.set_pin_wire_data.len); + memcpy(&dummy.change_pin_wire_data.body, &dummy_change_pin_wire_data, + dummy.change_pin_wire_data.len); + memcpy(&dummy.retry_wire_data.body, &dummy_retry_wire_data, + dummy.retry_wire_data.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 fido_dev_t * -prepare_dev() +prepare_dev(void) { - fido_dev_t *dev; - fido_dev_io_t io; + fido_dev_t *dev; + fido_dev_io_t io; memset(&io, 0, sizeof(io)); @@ -133,14 +204,14 @@ prepare_dev() if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { fido_dev_free(&dev); - return (NULL); + return NULL; } - return (dev); + return dev; } static void -dev_reset(struct param *p) +dev_reset(const struct param *p) { fido_dev_t *dev; @@ -155,16 +226,12 @@ dev_reset(struct param *p) } static void -dev_get_cbor_info(struct param *p) +dev_get_cbor_info(const struct param *p) { fido_dev_t *dev; fido_cbor_info_t *ci; uint64_t n; - uint8_t proto; - uint8_t major; - uint8_t minor; - uint8_t build; - uint8_t flags; + uint8_t proto, major, minor, build, flags; set_wire_data(p->info_wire_data.body, p->info_wire_data.len); @@ -192,6 +259,7 @@ dev_get_cbor_info(struct param *p) char * const *sa = fido_cbor_info_versions_ptr(ci); consume(sa[i], strlen(sa[i])); } + for (size_t i = 0; i < fido_cbor_info_extensions_len(ci); i++) { char * const *sa = fido_cbor_info_extensions_ptr(ci); consume(sa[i], strlen(sa[i])); @@ -207,6 +275,12 @@ dev_get_cbor_info(struct param *p) n = fido_cbor_info_maxmsgsiz(ci); consume(&n, sizeof(n)); + n = fido_cbor_info_maxcredcntlst(ci); + consume(&n, sizeof(n)); + + n = fido_cbor_info_maxcredidlen(ci); + consume(&n, sizeof(n)); + n = fido_cbor_info_fwversion(ci); consume(&n, sizeof(n)); @@ -222,7 +296,7 @@ out: } static void -dev_set_pin(struct param *p) +dev_set_pin(const struct param *p) { fido_dev_t *dev; @@ -237,7 +311,7 @@ dev_set_pin(struct param *p) } static void -dev_change_pin(struct param *p) +dev_change_pin(const struct param *p) { fido_dev_t *dev; @@ -252,10 +326,10 @@ dev_change_pin(struct param *p) } static void -dev_get_retry_count(struct param *p) +dev_get_retry_count(const struct param *p) { fido_dev_t *dev; - int n; + int n = 0; set_wire_data(p->retry_wire_data.body, p->retry_wire_data.len); @@ -268,103 +342,36 @@ dev_get_retry_count(struct param *p) fido_dev_free(&dev); } -int -LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +void +test(const struct param *p) { - struct param p; - - memset(&p, 0, sizeof(p)); - - if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) || - unpack(data, size, &p) < 0) - return (0); - - prng_init((unsigned int)p.seed); - + prng_init((unsigned int)p->seed); fido_init(FIDO_DEBUG); fido_set_log_handler(consume_str); - dev_reset(&p); - dev_get_cbor_info(&p); - dev_set_pin(&p); - dev_change_pin(&p); - dev_get_retry_count(&p); - - return (0); + dev_reset(p); + dev_get_cbor_info(p); + dev_set_pin(p); + dev_change_pin(p); + dev_get_retry_count(p); } -static size_t -pack_dummy(uint8_t *ptr, size_t len) +void +mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN { - struct param dummy; - uint8_t blob[16384]; - size_t blob_len; - - memset(&dummy, 0, sizeof(dummy)); - - strlcpy(dummy.pin1, dummy_pin1, sizeof(dummy.pin1)); - strlcpy(dummy.pin2, dummy_pin2, sizeof(dummy.pin2)); - - dummy.reset_wire_data.len = sizeof(dummy_reset_wire_data); - dummy.info_wire_data.len = sizeof(dummy_info_wire_data); - dummy.set_pin_wire_data.len = sizeof(dummy_set_pin_wire_data); - dummy.change_pin_wire_data.len = sizeof(dummy_change_pin_wire_data); - dummy.retry_wire_data.len = sizeof(dummy_retry_wire_data); - - memcpy(&dummy.reset_wire_data.body, &dummy_reset_wire_data, - dummy.reset_wire_data.len); - memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data, - dummy.info_wire_data.len); - memcpy(&dummy.set_pin_wire_data.body, &dummy_set_pin_wire_data, - dummy.set_pin_wire_data.len); - memcpy(&dummy.change_pin_wire_data.body, &dummy_change_pin_wire_data, - dummy.change_pin_wire_data.len); - memcpy(&dummy.retry_wire_data.body, &dummy_retry_wire_data, - dummy.retry_wire_data.len); - - blob_len = pack(blob, sizeof(blob), &dummy); - assert(blob_len != 0); + if (flags & MUTATE_SEED) + p->seed = (int)seed; - if (blob_len > len) { - memcpy(ptr, blob, len); - return (len); + if (flags & MUTATE_PARAM) { + mutate_string(p->pin1); + mutate_string(p->pin2); } - memcpy(ptr, blob, blob_len); - - return (blob_len); -} - -size_t -LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, - unsigned int seed) -{ - struct param p; - uint8_t blob[16384]; - size_t blob_len; - - memset(&p, 0, sizeof(p)); - - if (unpack(data, size, &p) < 0) - return (pack_dummy(data, maxsize)); - - p.seed = (int)seed; - - mutate_string(p.pin1); - mutate_string(p.pin2); - - mutate_blob(&p.reset_wire_data); - mutate_blob(&p.info_wire_data); - mutate_blob(&p.set_pin_wire_data); - mutate_blob(&p.change_pin_wire_data); - mutate_blob(&p.retry_wire_data); - - blob_len = pack(blob, sizeof(blob), &p); - - if (blob_len == 0 || blob_len > maxsize) - return (0); - - memcpy(data, blob, blob_len); - - return (blob_len); + if (flags & MUTATE_WIREDATA) { + mutate_blob(&p->reset_wire_data); + mutate_blob(&p->info_wire_data); + mutate_blob(&p->set_pin_wire_data); + mutate_blob(&p->change_pin_wire_data); + mutate_blob(&p->retry_wire_data); + } } diff --git a/fuzz/libfuzzer.c b/fuzz/libfuzzer.c new file mode 100644 index 0000000..ac9c798 --- /dev/null +++ b/fuzz/libfuzzer.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2019 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mutator_aux.h" + +static bool debug; +static unsigned int flags = MUTATE_ALL; +static unsigned long long test_fail; +static unsigned long long test_total; +static unsigned long long mutate_fail; +static unsigned long long mutate_total; + +int LLVMFuzzerInitialize(int *, char ***); +int LLVMFuzzerTestOneInput(const uint8_t *, size_t); +size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); + +static int +save_seed(const char *opt) +{ + const char *path; + int fd = -1, status = 1; + void *buf = NULL; + const size_t buflen = 4096; + size_t n; + struct param *p = NULL; + + if ((path = strchr(opt, '=')) == NULL || strlen(++path) == 0) { + warnx("usage: --fido-save-seed="); + goto fail; + } + + if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0644)) == -1) { + warn("open %s", path); + goto fail; + } + + if ((buf = malloc(buflen)) == NULL) { + warn("malloc"); + goto fail; + } + + n = pack_dummy(buf, buflen); + + if ((p = unpack(buf, n)) == NULL) { + warnx("unpack"); + goto fail; + } + + if (write(fd, buf, n) != (ssize_t)n) { + warn("write %s", path); + goto fail; + } + + status = 0; +fail: + if (fd != -1) + close(fd); + free(buf); + free(p); + + return status; +} + +static void +parse_mutate_flags(const char *opt, unsigned int *mutate_flags) +{ + const char *f; + + if ((f = strchr(opt, '=')) == NULL || strlen(++f) == 0) + errx(1, "usage: --fido-mutate="); + + if (strcmp(f, "seed") == 0) + *mutate_flags |= MUTATE_SEED; + else if (strcmp(f, "param") == 0) + *mutate_flags |= MUTATE_PARAM; + else if (strcmp(f, "wiredata") == 0) + *mutate_flags |= MUTATE_WIREDATA; + else + errx(1, "--fido-mutate: unknown flag '%s'", f); +} + +int +LLVMFuzzerInitialize(int *argc, char ***argv) +{ + unsigned int mutate_flags = 0; + + for (int i = 0; i < *argc; i++) + if (strcmp((*argv)[i], "--fido-debug") == 0) { + debug = 1; + } else if (strncmp((*argv)[i], "--fido-save-seed=", 17) == 0) { + exit(save_seed((*argv)[i])); + } else if (strncmp((*argv)[i], "--fido-mutate=", 14) == 0) { + parse_mutate_flags((*argv)[i], &mutate_flags); + } + + if (mutate_flags) + flags = mutate_flags; + + return 0; +} + +int +LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + struct param *p; + + if (++test_total % 100000 == 0 && debug) { + double r = (double)test_fail/(double)test_total * 100.0; + fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__, + test_fail, test_total, r); + } + + if (size > 4096 || (p = unpack(data, size)) == NULL) + test_fail++; + else { + test(p); + free(p); + } + + return 0; +} + +size_t +LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, + unsigned int seed) NO_MSAN +{ + struct param *p; + uint8_t blob[4096]; + size_t blob_len; + + memset(&p, 0, sizeof(p)); + +#ifdef WITH_MSAN + __msan_unpoison(data, maxsize); +#endif + + if (++mutate_total % 100000 == 0 && debug) { + double r = (double)mutate_fail/(double)mutate_total * 100.0; + fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__, + mutate_fail, mutate_total, r); + } + + if ((p = unpack(data, size)) == NULL) { + mutate_fail++; + return pack_dummy(data, maxsize); + } + + mutate(p, seed, flags); + + if ((blob_len = pack(blob, sizeof(blob), p)) == 0 || + blob_len > sizeof(blob) || blob_len > maxsize) { + mutate_fail++; + free(p); + return 0; + } + + free(p); + + memcpy(data, blob, blob_len); + + return blob_len; +} diff --git a/fuzz/mutator_aux.c b/fuzz/mutator_aux.c index fe09438..98815e8 100644 --- a/fuzz/mutator_aux.c +++ b/fuzz/mutator_aux.c @@ -5,26 +5,28 @@ */ #include +#include #include #include #include #include #include +#include "fido.h" #include "mutator_aux.h" size_t LLVMFuzzerMutate(uint8_t *, size_t, size_t); -static uint8_t *wire_data_ptr = NULL; -static size_t wire_data_len = 0; +static const uint8_t *wire_data_ptr = NULL; +static size_t wire_data_len = 0; size_t xstrlen(const char *s) { if (s == NULL) - return (0); + return 0; - return (strlen(s)); + return strlen(s); } void @@ -33,6 +35,10 @@ consume(const void *body, size_t len) const volatile uint8_t *ptr = body; volatile uint8_t x = 0; +#ifdef WITH_MSAN + __msan_check_mem_is_initialized(body, len); +#endif + while (len--) x ^= *ptr++; } @@ -44,217 +50,87 @@ consume_str(const char *str) } int -unpack_int(uint8_t t, uint8_t **ptr, size_t *len, int *v) NO_MSAN -{ - size_t l; - - if (*len < sizeof(t) || **ptr != t) - return (-1); - - *ptr += sizeof(t); - *len -= sizeof(t); - - if (*len < sizeof(l)) - return (-1); - - memcpy(&l, *ptr, sizeof(l)); - *ptr += sizeof(l); - *len -= sizeof(l); - - if (l != sizeof(*v) || *len < l) - return (-1); - - memcpy(v, *ptr, sizeof(*v)); - *ptr += sizeof(*v); - *len -= sizeof(*v); - - return (0); -} - -int -unpack_string(uint8_t t, uint8_t **ptr, size_t *len, char *v) NO_MSAN +unpack_int(cbor_item_t *item, int *v) { - size_t l; - - if (*len < sizeof(t) || **ptr != t) - return (-1); - - *ptr += sizeof(t); - *len -= sizeof(t); - - if (*len < sizeof(l)) - return (-1); - - memcpy(&l, *ptr, sizeof(l)); - *ptr += sizeof(l); - *len -= sizeof(l); + if (cbor_is_int(item) == false || + cbor_int_get_width(item) != CBOR_INT_64) + return -1; - if (*len < l || l >= MAXSTR) - return (-1); - - memcpy(v, *ptr, l); - v[l] = '\0'; - - *ptr += l; - *len -= l; - - return (0); -} - -int -unpack_byte(uint8_t t, uint8_t **ptr, size_t *len, uint8_t *v) NO_MSAN -{ - size_t l; - - if (*len < sizeof(t) || **ptr != t) - return (-1); - - *ptr += sizeof(t); - *len -= sizeof(t); - - if (*len < sizeof(l)) - return (-1); - - memcpy(&l, *ptr, sizeof(l)); - *ptr += sizeof(l); - *len -= sizeof(l); - - if (l != sizeof(*v) || *len < l) - return (-1); - - memcpy(v, *ptr, sizeof(*v)); - *ptr += sizeof(*v); - *len -= sizeof(*v); - - return (0); -} - -int -unpack_blob(uint8_t t, uint8_t **ptr, size_t *len, struct blob *v) NO_MSAN -{ - size_t l; - - v->len = 0; - - if (*len < sizeof(t) || **ptr != t) - return (-1); - - *ptr += sizeof(t); - *len -= sizeof(t); - - if (*len < sizeof(l)) - return (-1); - - memcpy(&l, *ptr, sizeof(l)); - *ptr += sizeof(l); - *len -= sizeof(l); - - if (*len < l || l > sizeof(v->body)) - return (-1); - - memcpy(v->body, *ptr, l); - *ptr += l; - *len -= l; - - v->len = l; + if (cbor_isa_uint(item)) + *v = (int)cbor_get_uint64(item); + else + *v = (int)(-cbor_get_uint64(item) - 1); - return (0); + return 0; } int -pack_int(uint8_t t, uint8_t **ptr, size_t *len, int v) NO_MSAN +unpack_string(cbor_item_t *item, char *v) { - const size_t l = sizeof(v); + size_t len; - if (*len < sizeof(t) + sizeof(l) + l) - return (-1); + if (cbor_isa_bytestring(item) == false || + (len = cbor_bytestring_length(item)) >= MAXSTR) + return -1; - (*ptr)[0] = t; - memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l)); - memcpy(&(*ptr)[sizeof(t) + sizeof(l)], &v, l); + memcpy(v, cbor_bytestring_handle(item), len); + v[len] = '\0'; - *ptr += sizeof(t) + sizeof(l) + l; - *len -= sizeof(t) + sizeof(l) + l; - - return (0); + return 0; } int -pack_string(uint8_t t, uint8_t **ptr, size_t *len, const char *v) NO_MSAN +unpack_byte(cbor_item_t *item, uint8_t *v) { - const size_t l = strlen(v); - - if (*len < sizeof(t) + sizeof(l) + l) - return (-1); - - (*ptr)[0] = t; - memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l)); - memcpy(&(*ptr)[sizeof(t) + sizeof(l)], v, l); + if (cbor_isa_uint(item) == false || + cbor_int_get_width(item) != CBOR_INT_8) + return -1; - *ptr += sizeof(t) + sizeof(l) + l; - *len -= sizeof(t) + sizeof(l) + l; + *v = cbor_get_uint8(item); - return (0); + return 0; } int -pack_byte(uint8_t t, uint8_t **ptr, size_t *len, uint8_t v) NO_MSAN +unpack_blob(cbor_item_t *item, struct blob *v) { - const size_t l = sizeof(v); + if (cbor_isa_bytestring(item) == false || + (v->len = cbor_bytestring_length(item)) > sizeof(v->body)) + return -1; - if (*len < sizeof(t) + sizeof(l) + l) - return (-1); + memcpy(v->body, cbor_bytestring_handle(item), v->len); - (*ptr)[0] = t; - memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l)); - memcpy(&(*ptr)[sizeof(t) + sizeof(l)], &v, l); - - *ptr += sizeof(t) + sizeof(l) + l; - *len -= sizeof(t) + sizeof(l) + l; - - return (0); + return 0; } -int -pack_blob(uint8_t t, uint8_t **ptr, size_t *len, const struct blob *v) NO_MSAN +cbor_item_t * +pack_int(int v) NO_MSAN { - const size_t l = v->len; - - if (*len < sizeof(t) + sizeof(l) + l) - return (-1); - - (*ptr)[0] = t; - memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l)); - memcpy(&(*ptr)[sizeof(t) + sizeof(l)], v->body, l); - - *ptr += sizeof(t) + sizeof(l) + l; - *len -= sizeof(t) + sizeof(l) + l; - - return (0); + if (v < 0) + return cbor_build_negint64((uint64_t)(-(int64_t)v - 1)); + else + return cbor_build_uint64((uint64_t)v); } -size_t -len_int(void) +cbor_item_t * +pack_string(const char *v) NO_MSAN { - return (sizeof(uint8_t) + sizeof(size_t) + sizeof(int)); -} + if (strlen(v) >= MAXSTR) + return NULL; -size_t -len_string(int max) -{ - return ((sizeof(uint8_t) + sizeof(size_t)) + (max ? MAXSTR - 1 : 0)); + return cbor_build_bytestring((const unsigned char *)v, strlen(v)); } -size_t -len_byte(void) +cbor_item_t * +pack_byte(uint8_t v) NO_MSAN { - return (sizeof(uint8_t) + sizeof(size_t) + sizeof(uint8_t)); + return cbor_build_uint8(v); } -size_t -len_blob(int max) +cbor_item_t * +pack_blob(const struct blob *v) NO_MSAN { - return (sizeof(uint8_t) + sizeof(size_t) + (max ? MAXBLOB : 0)); + return cbor_build_bytestring(v->body, v->len); } void @@ -284,13 +160,13 @@ mutate_string(char *s) n = LLVMFuzzerMutate((uint8_t *)s, strlen(s), MAXSTR - 1); s[n] = '\0'; } - + void * dev_open(const char *path) { (void)path; - return ((void *)0xdeadbeef); + return (void *)0xdeadbeef; } void @@ -307,7 +183,7 @@ dev_read(void *handle, unsigned char *ptr, size_t len, int ms) (void)ms; assert(handle == (void *)0xdeadbeef); - assert(len == 64); + assert(len >= CTAP_MIN_REPORT_LEN && len <= CTAP_MAX_REPORT_LEN); if (wire_data_len < len) n = wire_data_len; @@ -319,25 +195,26 @@ dev_read(void *handle, unsigned char *ptr, size_t len, int ms) wire_data_ptr += n; wire_data_len -= n; - return ((int)n); + return (int)n; } int dev_write(void *handle, const unsigned char *ptr, size_t len) { assert(handle == (void *)0xdeadbeef); - assert(len == 64 + 1); + assert(len >= CTAP_MIN_REPORT_LEN + 1 && + len <= CTAP_MAX_REPORT_LEN + 1); consume(ptr, len); if (uniform_random(400) < 1) - return (-1); + return -1; - return ((int)len); + return (int)len; } void -set_wire_data(uint8_t *ptr, size_t len) +set_wire_data(const uint8_t *ptr, size_t len) { wire_data_ptr = ptr; wire_data_len = len; diff --git a/fuzz/mutator_aux.h b/fuzz/mutator_aux.h index d14e177..4a7e647 100644 --- a/fuzz/mutator_aux.h +++ b/fuzz/mutator_aux.h @@ -9,9 +9,10 @@ #include #include +#include /* - * As of LLVM 7.0.1, MSAN support in libFuzzer was still experimental. + * As of LLVM 10.0.0, MSAN support in libFuzzer was still experimental. * We therefore have to be careful when using our custom mutator, or * MSAN will flag uninitialised reads on memory populated by libFuzzer. * Since there is no way to suppress MSAN without regenerating object @@ -22,6 +23,7 @@ #if defined(__has_feature) # if __has_feature(memory_sanitizer) +# include # define NO_MSAN __attribute__((no_sanitize("memory"))) # define WITH_MSAN 1 # endif @@ -31,44 +33,49 @@ # define NO_MSAN #endif +#define MUTATE_SEED 0x01 +#define MUTATE_PARAM 0x02 +#define MUTATE_WIREDATA 0x04 +#define MUTATE_ALL (MUTATE_SEED | MUTATE_PARAM | MUTATE_WIREDATA) + #define MAXSTR 1024 #define MAXBLOB 3072 -#define GETLEN_MIN 0 -#define GETLEN_MAX 1 - struct blob { - uint8_t body[MAXBLOB]; - size_t len; + uint8_t body[MAXBLOB]; + size_t len; }; +struct param; + +struct param *unpack(const uint8_t *, size_t); +size_t pack(uint8_t *, size_t, const struct param *); +size_t pack_dummy(uint8_t *, size_t); +void mutate(struct param *, unsigned int, unsigned int); +void test(const struct param *); + size_t xstrlen(const char *); void consume(const void *, size_t); void consume_str(const char *); -int unpack_blob(uint8_t, uint8_t **, size_t *, struct blob *); -int unpack_byte(uint8_t, uint8_t **, size_t *, uint8_t *); -int unpack_int(uint8_t, uint8_t **, size_t *, int *); -int unpack_string(uint8_t, uint8_t **, size_t *, char *); - -int pack_blob(uint8_t, uint8_t **, size_t *, const struct blob *); -int pack_byte(uint8_t, uint8_t **, size_t *, uint8_t); -int pack_int(uint8_t, uint8_t **, size_t *, int); -int pack_string(uint8_t, uint8_t **, size_t *, const char *); +int unpack_blob(cbor_item_t *, struct blob *); +int unpack_byte(cbor_item_t *, uint8_t *); +int unpack_int(cbor_item_t *, int *); +int unpack_string(cbor_item_t *, char *); -size_t len_int(void); -size_t len_string(int); -size_t len_byte(void); -size_t len_blob(int); +cbor_item_t *pack_blob(const struct blob *); +cbor_item_t *pack_byte(uint8_t); +cbor_item_t *pack_int(int); +cbor_item_t *pack_string(const char *); void mutate_byte(uint8_t *); void mutate_int(int *); void mutate_blob(struct blob *); void mutate_string(char *); -void * dev_open(const char *); +void *dev_open(const char *); void dev_close(void *); -void set_wire_data(uint8_t *, size_t); +void set_wire_data(const uint8_t *, size_t); int dev_read(void *, unsigned char *, size_t, int); int dev_write(void *, const unsigned char *, size_t); diff --git a/fuzz/prng.c b/fuzz/prng.c old mode 100755 new mode 100644 index fa6d4e4..61114ac --- a/fuzz/prng.c +++ b/fuzz/prng.c @@ -63,7 +63,8 @@ void init_genrand(unsigned long s) mt[0]= s & 0xffffffffUL; for (mti=1; mti> 30)) + mti); + (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + + (unsigned long)mti); /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ /* In the previous versions, MSBs of the seed affect */ /* only MSBs of the array mt[]. */ diff --git a/fuzz/report.tgz b/fuzz/report.tgz index 8a002f0..6f02fc5 100644 Binary files a/fuzz/report.tgz and b/fuzz/report.tgz differ diff --git a/fuzz/summary.txt b/fuzz/summary.txt index da9d165..3a1ac21 100644 --- a/fuzz/summary.txt +++ b/fuzz/summary.txt @@ -1,6 +1,6 @@ Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -fuzz/prng.c 31 0 100.00% 2 0 100.00% 48 0 100.00% +fuzz/prng.c 31 0 100.00% 2 0 100.00% 49 0 100.00% fuzz/uniform_random.c 7 1 85.71% 1 0 100.00% 23 1 95.65% fuzz/wrap.c 6 0 100.00% 1 0 100.00% 7 0 100.00% openbsd-compat/explicit_bzero.c 4 0 100.00% 1 0 100.00% 12 0 100.00% @@ -8,34 +8,35 @@ openbsd-compat/recallocarray.c 41 7 82.93% openbsd-compat/strlcat.c 12 1 91.67% 1 0 100.00% 25 1 96.00% openbsd-compat/timingsafe_bcmp.c 4 0 100.00% 1 0 100.00% 8 0 100.00% src/aes256.c 56 0 100.00% 2 0 100.00% 82 0 100.00% -src/assert.c 566 43 92.40% 53 1 98.11% 900 87 90.33% +src/assert.c 566 24 95.76% 53 1 98.11% 900 50 94.44% src/authkey.c 44 0 100.00% 5 0 100.00% 75 0 100.00% src/bio.c 418 20 95.22% 49 2 95.92% 661 22 96.67% -src/blob.c 39 1 97.44% 7 0 100.00% 73 4 94.52% +src/blob.c 39 0 100.00% 7 0 100.00% 73 0 100.00% src/buf.c 8 1 87.50% 2 0 100.00% 20 1 95.00% -src/cbor.c 884 70 92.08% 52 2 96.15% 1371 106 92.27% -src/cred.c 534 51 90.45% 55 1 98.18% 830 78 90.60% -src/credman.c 376 18 95.21% 38 0 100.00% 589 15 97.45% -src/dev.c 201 85 57.71% 26 8 69.23% 294 128 56.46% +src/cbor.c 883 6 99.32% 52 0 100.00% 1364 17 98.75% +src/cred.c 536 23 95.71% 57 1 98.25% 836 29 96.53% +src/credman.c 385 18 95.32% 38 0 100.00% 595 16 97.31% +src/dev.c 334 90 73.05% 33 8 75.76% 466 140 69.96% src/ecdh.c 68 0 100.00% 2 0 100.00% 104 0 100.00% src/eddsa.c 54 0 100.00% 8 0 100.00% 79 0 100.00% -src/err.c 108 108 0.00% 1 1 0.00% 112 112 0.00% -src/es256.c 278 0 100.00% 16 0 100.00% 377 0 100.00% +src/err.c 112 8 92.86% 1 0 100.00% 116 8 93.10% +src/es256.c 280 0 100.00% 16 0 100.00% 398 0 100.00% src/hid.c 16 16 0.00% 8 8 0.00% 38 38 0.00% -src/hid_linux.c 166 166 0.00% 12 12 0.00% 292 292 0.00% -src/info.c 146 0 100.00% 31 0 100.00% 304 0 100.00% -src/io.c 123 5 95.93% 10 0 100.00% 218 11 94.95% +src/hid_linux.c 235 235 0.00% 19 19 0.00% 416 416 0.00% +src/info.c 152 0 100.00% 34 0 100.00% 319 0 100.00% +src/io.c 156 9 94.23% 10 0 100.00% 236 11 95.34% src/iso7816.c 18 1 94.44% 5 0 100.00% 47 0 100.00% src/log.c 34 2 94.12% 5 1 80.00% 50 3 94.00% src/pin.c 248 0 100.00% 16 0 100.00% 365 0 100.00% src/reset.c 19 0 100.00% 3 0 100.00% 22 0 100.00% -src/rs256.c 102 29 71.57% 8 3 62.50% 140 44 68.57% -src/u2f.c 443 28 93.68% 13 0 100.00% 699 52 92.56% +src/rs256.c 102 6 94.12% 8 0 100.00% 140 13 90.71% +src/u2f.c 491 9 98.17% 15 0 100.00% 774 18 97.67% Files which contain no functions: +openbsd-compat/time.h 0 0 - 0 0 - 0 0 - src/extern.h 0 0 - 0 0 - 0 0 - src/fido.h 0 0 - 0 0 - 0 0 - src/fido/err.h 0 0 - 0 0 - 0 0 - src/fido/param.h 0 0 - 0 0 - 0 0 - -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -TOTAL 5054 653 87.08% 435 39 91.03% 7914 1002 87.34% +TOTAL 5359 477 91.10% 456 40 91.23% 8349 791 90.53% diff --git a/man/CMakeLists.txt b/man/CMakeLists.txt index 44e4a96..f0d9cb3 100644 --- a/man/CMakeLists.txt +++ b/man/CMakeLists.txt @@ -3,12 +3,10 @@ # license that can be found in the LICENSE file. find_program(MANDOC_PATH mandoc) -message(STATUS "MANDOC_PATH: ${MANDOC_PATH}") +find_program(GZIP_PATH gzip) -if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR CMAKE_SYSTEM_NAME STREQUAL "Linux") - find_program(GZIP_PATH gzip) - message(STATUS "GZIP_PATH: ${GZIP_PATH}") -endif() +message(STATUS "MANDOC_PATH: ${MANDOC_PATH}") +message(STATUS "GZIP_PATH: ${GZIP_PATH}") list(APPEND MAN_SOURCES eddsa_pk_new.3 @@ -32,6 +30,7 @@ list(APPEND MAN_SOURCES fido_cred_set_authdata.3 fido_cred_verify.3 fido_dev_get_assert.3 + fido_dev_get_touch_begin.3 fido_dev_info_manifest.3 fido_dev_make_cred.3 fido_dev_open.3 @@ -54,9 +53,13 @@ list(APPEND MAN_ALIAS fido_assert_new fido_assert_clientdata_hash_len fido_assert_new fido_assert_clientdata_hash_ptr fido_assert_new fido_assert_count + fido_assert_new fido_assert_flags fido_assert_new fido_assert_free fido_assert_new fido_assert_hmac_secret_len fido_assert_new fido_assert_hmac_secret_ptr + fido_assert_new fido_assert_id_len + fido_assert_new fido_assert_id_ptr + fido_assert_new fido_assert_rp_id fido_assert_new fido_assert_sigcount fido_assert_new fido_assert_sig_len fido_assert_new fido_assert_sig_ptr @@ -95,34 +98,46 @@ list(APPEND MAN_ALIAS fido_bio_template fido_bio_template_new fido_bio_template fido_bio_template_set_id fido_bio_template fido_bio_template_set_name - fido_cbor_info_new fido_cbor_info_aaguid_len - fido_cbor_info_new fido_cbor_info_aaguid_ptr - 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_aaguid_len + fido_cbor_info_new fido_cbor_info_aaguid_ptr + 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_maxcredcntlst; + fido_cbor_info_new fido_cbor_info_maxcredidlen; 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 - fido_cbor_info_new fido_cbor_info_options_value_ptr - fido_cbor_info_new fido_cbor_info_protocols_len - fido_cbor_info_new fido_cbor_info_protocols_ptr - fido_cbor_info_new fido_cbor_info_versions_len - fido_cbor_info_new fido_cbor_info_versions_ptr - fido_cbor_info_new fido_dev_get_cbor_info + fido_cbor_info_new fido_cbor_info_options_len + fido_cbor_info_new fido_cbor_info_options_name_ptr + fido_cbor_info_new fido_cbor_info_options_value_ptr + fido_cbor_info_new fido_cbor_info_protocols_len + fido_cbor_info_new fido_cbor_info_protocols_ptr + fido_cbor_info_new fido_cbor_info_versions_len + fido_cbor_info_new fido_cbor_info_versions_ptr + fido_cbor_info_new fido_dev_get_cbor_info fido_cred_new fido_cred_authdata_len fido_cred_new fido_cred_authdata_ptr fido_cred_new fido_cred_clientdata_hash_len fido_cred_new fido_cred_clientdata_hash_ptr + fido_cred_new fido_cred_display_name + fido_cred_new fido_cred_flags fido_cred_new fido_cred_fmt fido_cred_new fido_cred_free fido_cred_new fido_cred_id_len fido_cred_new fido_cred_id_ptr + fido_cred_new fido_cred_aaguid_len + fido_cred_new fido_cred_aaguid_ptr fido_cred_new fido_cred_prot fido_cred_new fido_cred_pubkey_len fido_cred_new fido_cred_pubkey_ptr + fido_cred_new fido_cred_rp_id + fido_cred_new fido_cred_rp_name fido_cred_new fido_cred_sig_len fido_cred_new fido_cred_sig_ptr + fido_cred_new fido_cred_type + fido_cred_new fido_cred_user_name + fido_cred_new fido_cred_user_id_len + fido_cred_new fido_cred_user_id_ptr fido_cred_new fido_cred_x5c_len fido_cred_new fido_cred_x5c_ptr fido_credman_metadata_new fido_credman_del_dev_rk @@ -171,6 +186,8 @@ list(APPEND MAN_ALIAS fido_dev_open fido_dev_force_u2f fido_dev_open fido_dev_free fido_dev_open fido_dev_is_fido2 + fido_dev_open fido_dev_supports_cred_prot + fido_dev_open fido_dev_supports_pin fido_dev_open fido_dev_major fido_dev_open fido_dev_minor fido_dev_open fido_dev_new @@ -224,7 +241,7 @@ endforeach() # man_gzip foreach(f ${MAN_SOURCES}) add_custom_command(OUTPUT ${f}.gz - COMMAND gzip -c ${f} > ${f}.gz + COMMAND gzip -cn ${f} > ${f}.gz DEPENDS ${f}) list(APPEND GZ_FILES ${f}.gz) endforeach() diff --git a/man/NOTES b/man/NOTES index 4a461ff..5cba436 100644 --- a/man/NOTES +++ b/man/NOTES @@ -2,3 +2,6 @@ To generate .partial files for https://developers.yubico.com/: $ make -C build man_symlink_html_partial $ (cd build/man && pax -p p -r -w *.partial /tmp/partial) + +Use mandoc 1.14.4. Otherwise, adjust dyc.css to mandoc's HTML +output. diff --git a/man/fido2-assert.1 b/man/fido2-assert.1 index 67883e2..e77e771 100644 --- a/man/fido2-assert.1 +++ b/man/fido2-assert.1 @@ -12,6 +12,7 @@ .Nm .Fl G .Op Fl dhpruv +.Op Fl t Ar option .Op Fl i Ar input_file .Op Fl o Ar output_file .Ar device @@ -110,6 +111,29 @@ is specified, .Nm will not expect a credential id in its input, and may output multiple assertions. +.It Fl t Ar option +Toggles a key/value +.Ar option , +where +.Ar option +is a string of the form +.Dq key=value . +The options supported at present are: +.Bl -tag -width Ds +.It Cm up Ns = Ns Ar true|false +Asks the authenticator for user presence to be enabled or disabled. +.It Cm uv Ns = Ns Ar true|false +Asks the authenticator for user verification to be enabled or +disabled. +.It Cm pin Ns = Ns Ar true|false +Tells +.Nm +whether to prompt for a PIN and request user verification. +.El +.Pp +The +.Fl t +option may be specified multiple times. .It Fl u Obtain an assertion using U2F. By default, @@ -119,6 +143,10 @@ U2F otherwise. .It Fl v If obtaining an assertion, prompt the user for a PIN and request user verification from the authenticator. +If verifying an assertion, check whether the user verification bit +was signed by the authenticator. +.El +.Pp If a .Em tty is available, @@ -127,9 +155,6 @@ will use it to obtain the PIN. Otherwise, .Em stdin is used. -If verifying an assertion, check whether the user verification bit -was signed by the authenticator. -.El .Sh INPUT FORMAT The input of .Nm @@ -140,7 +165,7 @@ When obtaining an assertion, .Nm expects its input to consist of: .Pp -.Bl -enum -offset indent -compact +.Bl -enum -offset indent -compact .It client data hash (base64 blob); .It diff --git a/man/fido2-cred.1 b/man/fido2-cred.1 index d9bf7d2..4132d26 100644 --- a/man/fido2-cred.1 +++ b/man/fido2-cred.1 @@ -12,6 +12,7 @@ .Nm .Fl M .Op Fl dhqruv +.Op Fl c Ar cred_protect .Op Fl i Ar input_file .Op Fl o Ar output_file .Ar device @@ -19,6 +20,7 @@ .Nm .Fl V .Op Fl dhv +.Op Fl c Ar cred_protect .Op Fl i Ar input_file .Op Fl o Ar output_file .Op Ar type @@ -89,6 +91,12 @@ to make a new credential on Tells .Nm to verify a credential. +.It Fl c Ar cred_protect +If making a credential, set the credential's protection level to +.Ar cred_protect . +If verifying a credential, check whether the credential's protection +level was signed by the authenticator as +.Ar cred_protect . .It Fl d Causes .Nm diff --git a/man/fido_assert_new.3 b/man/fido_assert_new.3 index 0c2f92f..b1b1f2f 100644 --- a/man/fido_assert_new.3 +++ b/man/fido_assert_new.3 @@ -9,6 +9,7 @@ .Nm fido_assert_new , .Nm fido_assert_free , .Nm fido_assert_count , +.Nm fido_assert_rp_id , .Nm fido_assert_user_display_name , .Nm fido_assert_user_icon , .Nm fido_assert_user_name , @@ -17,12 +18,15 @@ .Nm fido_assert_hmac_secret_ptr , .Nm fido_assert_user_id_ptr , .Nm fido_assert_sig_ptr , +.Nm fido_assert_id_ptr , .Nm fido_assert_authdata_len , .Nm fido_assert_clientdata_hash_len , .Nm fido_assert_hmac_secret_len , .Nm fido_assert_user_id_len , .Nm fido_assert_sig_len , -.Nm fido_assert_sigcount +.Nm fido_assert_id_len , +.Nm fido_assert_sigcount , +.Nm fido_assert_flags .Nd FIDO 2 assertion API .Sh SYNOPSIS .In fido.h @@ -33,6 +37,8 @@ .Ft size_t .Fn fido_assert_count "const fido_assert_t *assert" .Ft const char * +.Fn fido_assert_rp_id "const fido_assert_t *assert" +.Ft const char * .Fn fido_assert_user_display_name "const fido_assert_t *assert" "size_t idx" .Ft const char * .Fn fido_assert_user_icon "const fido_assert_t *assert" "size_t idx" @@ -48,6 +54,8 @@ .Fn fido_assert_user_id_ptr "const fido_assert_t *assert" "size_t idx" .Ft const unsigned char * .Fn fido_assert_sig_ptr "const fido_assert_t *assert" "size_t idx" +.Ft const unsigned char * +.Fn fido_assert_id_ptr "const fido_assert_t *assert" "size_t idx" .Ft size_t .Fn fido_assert_authdata_len "const fido_assert_t *assert" "size_t idx" .Ft size_t @@ -58,8 +66,12 @@ .Fn fido_assert_user_id_len "const fido_assert_t *assert" "size_t idx" .Ft size_t .Fn fido_assert_sig_len "const fido_assert_t *assert" "size_t idx" +.Ft size_t +.Fn fido_assert_id_len "const fido_assert_t *assert" "size_t idx" .Ft uint32_t .Fn fido_assert_sigcount "const fido_assert_t *assert" "size_t idx" +.Ft uint8_t +.Fn fido_assert_flags "const fido_assert_t *assert" "size_t idx" .Sh DESCRIPTION FIDO 2 assertions are abstracted in .Em libfido2 @@ -110,6 +122,12 @@ function returns the number of statements in .Fa assert . .Pp The +.Fn fido_assert_rp_id +function returns a pointer to a NUL-terminated string holding the +relying party ID of +.Fa assert . +.Pp +The .Fn fido_assert_user_display_name , .Fn fido_assert_user_icon , and @@ -126,10 +144,11 @@ The .Fn fido_assert_user_id_ptr , .Fn fido_assert_authdata_ptr , .Fn fido_assert_hmac_secret_ptr , +.Fn fido_assert_sig_ptr , and -.Fn fido_assert_sig_ptr +.Fn fido_assert_id_ptr functions return pointers to the user ID, authenticator data, -hmac-secret, and signature attributes of statement +hmac-secret, signature, and credential ID attributes of statement .Fa idx in .Fa assert . @@ -137,8 +156,9 @@ The .Fn fido_assert_user_id_len , .Fn fido_assert_authdata_len , .Fn fido_assert_hmac_secret_len , +.Fn fido_assert_sig_len , and -.Fn fido_assert_sig_len +.Fn fido_assert_id_len functions can be used to retrieve the corresponding length of a specific attribute. .Pp @@ -149,6 +169,13 @@ function can be used to obtain the signature counter of statement in .Fa assert . .Pp +The +.Fn fido_assert_flags +function returns the authenticator data flags of statement +.Fa idx +in +.Fa assert . +.Pp Please note that the first statement in .Fa assert has an diff --git a/man/fido_cbor_info_new.3 b/man/fido_cbor_info_new.3 index 3e7de1f..ee942e6 100644 --- a/man/fido_cbor_info_new.3 +++ b/man/fido_cbor_info_new.3 @@ -21,6 +21,8 @@ .Nm fido_cbor_info_versions_len , .Nm fido_cbor_info_options_len , .Nm fido_cbor_info_maxmsgsiz , +.Nm fido_cbor_info_maxcredcntlst , +.Nm fido_cbor_info_maxcredidlen , .Nm fido_cbor_info_fwversion .Nd FIDO 2 CBOR Info API .Sh SYNOPSIS @@ -56,6 +58,10 @@ .Ft uint64_t .Fn fido_cbor_info_maxmsgsiz "const fido_cbor_info_t *ci" .Ft uint64_t +.Fn fido_cbor_info_maxcredcntlst "const fido_cbor_info_t *ci" +.Ft uint64_t +.Fn fido_cbor_info_maxcredidlen "const fido_cbor_info_t *ci" +.Ft uint64_t .Fn fido_cbor_info_fwversion "const fido_cbor_info_t *ci" .Sh DESCRIPTION The @@ -103,8 +109,8 @@ The .Fn fido_cbor_info_protocols_ptr , and .Fn fido_cbor_info_versions_ptr -functions return pointers to the AAGUID, supported extensions, -PIN protocol and CTAP version strings of +functions return pointers to the authenticator attestation GUID, +supported extensions, PIN protocol and CTAP version strings of .Fa ci . The corresponding length of a given attribute can be obtained by @@ -131,6 +137,18 @@ function returns the maximum message size attribute of .Fa ci . .Pp The +.Fn fido_cbor_info_maxcredcntlst +function returns the maximum supported number of credentials in +a single credential ID list as reported in +.Fa ci . +.Pp +The +.Fn fido_cbor_info_maxcredidlen +function returns the maximum supported length of a credential ID +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_cred_new.3 b/man/fido_cred_new.3 index 22af60c..d2023eb 100644 --- a/man/fido_cred_new.3 +++ b/man/fido_cred_new.3 @@ -10,18 +10,28 @@ .Nm fido_cred_free , .Nm fido_cred_prot , .Nm fido_cred_fmt , +.Nm fido_cred_rp_id , +.Nm fido_cred_rp_name , +.Nm fido_cred_user_name , +.Nm fido_cred_display_name , .Nm fido_cred_authdata_ptr , .Nm fido_cred_clientdata_hash_ptr , .Nm fido_cred_id_ptr , +.Nm fido_cred_aaguid_ptr , .Nm fido_cred_pubkey_ptr , .Nm fido_cred_sig_ptr , +.Nm fido_cred_user_id_ptr , .Nm fido_cred_x5c_ptr , .Nm fido_cred_authdata_len , .Nm fido_cred_clientdata_hash_len , .Nm fido_cred_id_len , +.Nm fido_cred_aaguid_len , .Nm fido_cred_pubkey_len , .Nm fido_cred_sig_len , -.Nm fido_cred_x5c_len +.Nm fido_cred_user_id_len , +.Nm fido_cred_x5c_len , +.Nm fido_cred_type , +.Nm fido_cred_flags .Nd FIDO 2 credential API .Sh SYNOPSIS .In fido.h @@ -33,6 +43,14 @@ .Fn fido_cred_prot "fido_cred_t *cred" .Ft const char * .Fn fido_cred_fmt "const fido_cred_t *cred" +.Ft const char * +.Fn fido_cred_rp_id "const fido_cred_t *cred" +.Ft const char * +.Fn fido_cred_rp_name "const fido_cred_t *cred" +.Ft const char * +.Fn fido_cred_user_name "const fido_cred_t *cred" +.Ft const char * +.Fn fido_cred_display_name "const fido_cred_t *cred" .Ft const unsigned char * .Fn fido_cred_authdata_ptr "const fido_cred_t *cred" .Ft const unsigned char * @@ -40,10 +58,14 @@ .Ft const unsigned char * .Fn fido_cred_id_ptr "const fido_cred_t *cred" .Ft const unsigned char * +.Fn fido_cred_aaguid_ptr "const fido_cred_t *cred" +.Ft const unsigned char * .Fn fido_cred_pubkey_ptr "const fido_cred_t *cred" .Ft const unsigned char * .Fn fido_cred_sig_ptr "const fido_cred_t *cred" .Ft const unsigned char * +.Fn fido_cred_user_id_ptr "const fido_cred_t *cred" +.Ft const unsigned char * .Fn fido_cred_x5c_ptr "const fido_cred_t *cred" .Ft size_t .Fn fido_cred_authdata_len "const fido_cred_t *cred" @@ -52,11 +74,19 @@ .Ft size_t .Fn fido_cred_id_len "const fido_cred_t *cred" .Ft size_t +.Fn fido_cred_aaguid_len "const fido_cred_t *cred" +.Ft size_t .Fn fido_cred_pubkey_len "const fido_cred_t *cred" .Ft size_t .Fn fido_cred_sig_len "const fido_cred_t *cred" .Ft size_t +.Fn fido_cred_user_id_len "const fido_cred_t *cred" +.Ft size_t .Fn fido_cred_x5c_len "const fido_cred_t *cred" +.Ft int +.Fn fido_cred_type "const fido_cred_t *cred" +.Ft uint8_t +.Fn fido_cred_flags "const fido_cred_t *cred" .Sh DESCRIPTION FIDO 2 credentials are abstracted in .Em libfido2 @@ -120,15 +150,30 @@ or NULL if does not have a format set. .Pp The +.Fn fido_cred_rp_id , +.Fn fido_cred_rp_name , +.Fn fido_cred_user_name , +and +.Fn fido_cred_display_name +functions return pointers to NUL-terminated strings holding the +relying party ID, relying party name, user name, and user display +name attributes of +.Fa cred , +or NULL if the respective entry is not set. +.Pp +The .Fn fido_cred_authdata_ptr , .Fn fido_cred_clientdata_hash_ptr , .Fn fido_cred_id_ptr , +.Fn fido_cred_aaguid_ptr , .Fn fido_cred_pubkey_ptr , .Fn fido_cred_sig_ptr , +.Fn fido_cred_user_id_ptr , and .Fn fido_cred_x5c_ptr functions return pointers to the authenticator data, client data -hash, ID, public key, signature and x509 certificate parts of +hash, ID, authenticator attestation GUID, public key, signature, +user ID, and x509 certificate parts of .Fa cred , or NULL if the respective entry is not set. .Pp @@ -136,12 +181,25 @@ The corresponding length can be obtained by .Fn fido_cred_authdata_len , .Fn fido_cred_clientdata_hash_len , .Fn fido_cred_id_len , +.Fn fido_cred_aaguid_len , .Fn fido_cred_pubkey_len , +.Fn fido_cred_sig_len , +.Fn fido_cred_user_id_len , and -.Fn fido_cred_sig_len . +.Fn fido_cred_x5c_len . .Pp The authenticator data, x509 certificate, and signature parts of a credential are typically passed to a FIDO 2 server for verification. +.Pp +The +.Fn fido_cred_type +function returns the COSE algorithm of +.Fa cred . +.Pp +The +.Fn fido_cred_flags +function returns the authenticator data flags of +.Fa cred . .Sh RETURN VALUES The authenticator data returned by .Fn fido_cred_authdata_ptr @@ -152,6 +210,7 @@ If not NULL, pointers returned by .Fn fido_cred_authdata_ptr , .Fn fido_cred_clientdata_hash_ptr , .Fn fido_cred_id_ptr , +.Fn fido_cred_aaguid_ptr , .Fn fido_cred_pubkey_ptr , .Fn fido_cred_sig_ptr , and diff --git a/man/fido_dev_get_touch_begin.3 b/man/fido_dev_get_touch_begin.3 new file mode 100644 index 0000000..8372c6f --- /dev/null +++ b/man/fido_dev_get_touch_begin.3 @@ -0,0 +1,73 @@ +.\" Copyright (c) 2020 Yubico AB. All rights reserved. +.\" Use of this source code is governed by a BSD-style +.\" license that can be found in the LICENSE file. +.\" +.Dd $Mdocdate: August 5 2020 $ +.Dt FIDO_DEV_GET_TOUCH_BEGIN 3 +.Os +.Sh NAME +.Nm fido_dev_get_touch_begin , +.Nm fido_dev_get_touch_status +.Nd asynchronously wait for touch on a FIDO 2 authenticator +.Sh SYNOPSIS +.In fido.h +.Ft int +.Fn fido_dev_get_touch_begin "fido_dev_t *dev" +.Ft int +.Fn fido_dev_get_touch_status "fido_dev_t *dev" "int *touched" "int ms" +.Sh DESCRIPTION +The functions described in this page allow an application to +asynchronously wait for touch on a FIDO authenticator. +This is useful when multiple authenticators are present and +the application needs to know which one to use. +.Pp +The +.Fn fido_dev_get_touch_begin +function initiates a touch request on +.Fa dev . +.Pp +The +.Fn fido_dev_get_touch_status +function continues an ongoing touch request on +.Fa dev , +blocking up to +.Fa ms +milliseconds. +On success, +.Fa touched +will be updated to reflect the touch request status. +If +.Fa touched +is 1, the device was touched, and the touch request is +terminated. +If +.Fa touched +is 0, the application may call +.Fn fido_dev_get_touch_status +to continue the touch request, or +.Fn fido_dev_cancel +to terminate it. +.Sh RETURN VALUES +The error codes returned by +.Fn fido_dev_get_touch_begin +and +.Fn fido_dev_get_touch_status +are defined in +.In fido/err.h . +On success, +.Dv FIDO_OK +is returned. +.Sh EXAMPLES +Please refer to +.Em examples/select.c +in +.Em libfido2's +source tree. +.Sh SEE ALSO +.Xr fido_dev_cancel 3 +.Sh CAVEATS +The +.Fn fido_dev_get_touch_status +function will cause a command to be transmitted to U2F +authenticators. +These transmissions should not exceed a frequency of 5Hz. diff --git a/man/fido_dev_open.3 b/man/fido_dev_open.3 index 53e3a12..6c7489d 100644 --- a/man/fido_dev_open.3 +++ b/man/fido_dev_open.3 @@ -14,6 +14,9 @@ .Nm fido_dev_force_fido2 , .Nm fido_dev_force_u2f , .Nm fido_dev_is_fido2 , +.Nm fido_dev_supports_cred_prot , +.Nm fido_dev_supports_pin , +.Nm fido_dev_has_pin , .Nm fido_dev_protocol , .Nm fido_dev_build , .Nm fido_dev_flags , @@ -38,6 +41,12 @@ .Fn fido_dev_force_u2f "fido_dev_t *dev" .Ft bool .Fn fido_dev_is_fido2 "const fido_dev_t *dev" +.Ft bool +.Fn fido_dev_supports_cred_prot "const fido_dev_t *dev" +.Ft bool +.Fn fido_dev_supports_pin "const fido_dev_t *dev" +.Ft bool +.Fn fido_dev_has_pin "const fido_dev_t *dev" .Ft uint8_t .Fn fido_dev_protocol "const fido_dev_t *dev" .Ft uint8_t @@ -117,6 +126,30 @@ if is a FIDO 2 device. .Pp The +.Fn fido_dev_supports_cred_prot +function returns +.Dv true +if +.Fa dev +supports FIDO 2.1 Credential Protection. +.Pp +The +.Fn fido_dev_supports_pin +function returns +.Dv true +if +.Fa dev +supports FIDO 2.0 Client PINs. +.Pp +The +.Fn fido_dev_has_pin +function returns +.Dv true +if +.Fa dev +has a FIDO 2.0 Client PIN set. +.Pp +The .Fn fido_dev_protocol function returns the CTAPHID protocol version identifier of .Fa dev . diff --git a/openbsd-compat/clock_gettime.c b/openbsd-compat/clock_gettime.c new file mode 100644 index 0000000..ca261a6 --- /dev/null +++ b/openbsd-compat/clock_gettime.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 Yubico AB. All rights reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + +#include "openbsd-compat.h" + +#if !defined(HAVE_CLOCK_GETTIME) + +#if _WIN32 +int +clock_gettime(clockid_t clock_id, struct timespec *tp) +{ + ULONGLONG ms; + + if (clock_id != CLOCK_MONOTONIC) { + errno = EINVAL; + return (-1); + } + + ms = GetTickCount64(); + tp->tv_sec = ms / 1000L; + tp->tv_nsec = (ms % 1000L) * 1000000L; + + return (0); +} +#else +#error "please provide an implementation of clock_gettime() for your platform" +#endif /* _WIN32 */ + +#endif /* !defined(HAVE_CLOCK_GETTIME) */ diff --git a/openbsd-compat/diff.sh b/openbsd-compat/diff.sh deleted file mode 100755 index f21e7d8..0000000 --- a/openbsd-compat/diff.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash -u - -# Copyright (c) 2019 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. - -OPENSSH=$(realpath ../../openssh) -LIBRESSL=$(realpath ../../libressl-2.8.3) -[[ ! -d "${OPENSSH}" || ! -d "${LIBRESSL}" ]] && exit 1 - -diff -pu bsd-getpagesize.c ${OPENSSH}/openbsd-compat/bsd-getpagesize.c -diff -pu err.h ${LIBRESSL}/include/compat/err.h -diff -pu explicit_bzero.c ${OPENSSH}/openbsd-compat/explicit_bzero.c -diff -pu explicit_bzero_win32.c ${LIBRESSL}/crypto/compat/explicit_bzero_win.c -diff -pu getopt.h ${OPENSSH}/openbsd-compat/getopt.h -diff -pu getopt_long.c ${OPENSSH}/openbsd-compat/getopt_long.c -diff -pu posix_win.c ${LIBRESSL}/crypto/compat/posix_win.c -diff -pu readpassphrase.c ${OPENSSH}/openbsd-compat/readpassphrase.c -diff -pu readpassphrase.h ${OPENSSH}/openbsd-compat/readpassphrase.h -diff -pu recallocarray.c ${OPENSSH}/openbsd-compat/recallocarray.c -diff -pu strlcat.c ${OPENSSH}/openbsd-compat/strlcat.c -diff -pu strlcpy.c ${OPENSSH}/openbsd-compat/strlcpy.c -diff -pu timingsafe_bcmp.c ${OPENSSH}/openbsd-compat/timingsafe_bcmp.c -diff -pu types.h ${LIBRESSL}/include/compat/sys/types.h diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h index 30d80b3..4f847a5 100644 --- a/openbsd-compat/openbsd-compat.h +++ b/openbsd-compat/openbsd-compat.h @@ -90,4 +90,6 @@ int timingsafe_bcmp(const void *, const void *, size_t); ssize_t getline(char **, size_t *, FILE *); #endif +#include "time.h" + #endif /* !_OPENBSD_COMPAT_H */ diff --git a/openbsd-compat/time.h b/openbsd-compat/time.h new file mode 100644 index 0000000..23ac0fe --- /dev/null +++ b/openbsd-compat/time.h @@ -0,0 +1,46 @@ +/* + * Public domain + * sys/time.h compatibility shim + */ + +#if defined(_MSC_VER) && (_MSC_VER >= 1900) +#include <../ucrt/time.h> +#elif defined(_MSC_VER) && (_MSC_VER < 1900) +#include <../include/time.h> +#else +#include +#endif + +#ifndef _COMPAT_TIME_H +#define _COMPAT_TIME_H + +#ifndef CLOCK_MONOTONIC +#define CLOCK_MONOTONIC CLOCK_REALTIME +#endif + +#ifndef CLOCK_REALTIME +#define CLOCK_REALTIME 0 +#endif + +#ifndef HAVE_CLOCK_GETTIME +typedef int clockid_t; +int clock_gettime(clockid_t, struct timespec *); +#endif + +#ifdef HAVE_TIMESPECSUB +#include +#endif + +#ifndef HAVE_TIMESPECSUB +#define timespecsub(tsp, usp, vsp) \ + do { \ + (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \ + (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \ + if ((vsp)->tv_nsec < 0) { \ + (vsp)->tv_sec--; \ + (vsp)->tv_nsec += 1000000000L; \ + } \ + } while (0) +#endif + +#endif /* _COMPAT_TIME_H */ diff --git a/openbsd-compat/types.h b/openbsd-compat/types.h index cc1da66..e3aa6b5 100644 --- a/openbsd-compat/types.h +++ b/openbsd-compat/types.h @@ -23,13 +23,6 @@ typedef uint32_t uid_t; #endif #ifdef _MSC_VER -typedef unsigned char u_char; -typedef unsigned short u_short; -typedef unsigned int u_int; -typedef uint32_t in_addr_t; -typedef uint32_t mode_t; -typedef uint32_t uid_t; - #include typedef SSIZE_T ssize_t; diff --git a/regress/assert.c b/regress/assert.c index caa5725..3b75839 100644 --- a/regress/assert.c +++ b/regress/assert.c @@ -160,7 +160,7 @@ free_rs256_pk(rs256_pk_t *pk) } static void -empty_assert(fido_dev_t *d, fido_assert_t *a, int idx) +empty_assert(fido_dev_t *d, fido_assert_t *a, size_t idx) { es256_pk_t *es256; rs256_pk_t *rs256; @@ -187,21 +187,21 @@ empty_assert(fido_dev_t *d, fido_assert_t *a, int idx) fido_dev_force_u2f(d); assert(fido_dev_get_assert(d, a, NULL) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_dev_get_assert(d, a, "") == FIDO_ERR_INVALID_ARGUMENT); - assert(fido_assert_verify(a, COSE_ES256, idx, + assert(fido_assert_verify(a, idx, COSE_ES256, NULL) == FIDO_ERR_INVALID_ARGUMENT); - assert(fido_assert_verify(a, COSE_ES256, idx, + assert(fido_assert_verify(a, idx, COSE_ES256, es256) == FIDO_ERR_INVALID_ARGUMENT); - assert(fido_assert_verify(a, COSE_RS256, idx, + assert(fido_assert_verify(a, idx, COSE_RS256, rs256) == FIDO_ERR_INVALID_ARGUMENT); fido_dev_force_fido2(d); assert(fido_dev_get_assert(d, a, NULL) == FIDO_ERR_INVALID_ARGUMENT); assert(fido_dev_get_assert(d, a, "") == FIDO_ERR_INVALID_ARGUMENT); - assert(fido_assert_verify(a, COSE_ES256, idx, + assert(fido_assert_verify(a, idx, COSE_ES256, NULL) == FIDO_ERR_INVALID_ARGUMENT); - assert(fido_assert_verify(a, COSE_ES256, idx, + assert(fido_assert_verify(a, idx, COSE_ES256, es256) == FIDO_ERR_INVALID_ARGUMENT); - assert(fido_assert_verify(a, COSE_RS256, idx, + assert(fido_assert_verify(a, idx, COSE_RS256, rs256) == FIDO_ERR_INVALID_ARGUMENT); free_es256_pk(es256); @@ -214,7 +214,7 @@ empty_assert_tests(void) fido_assert_t *a; fido_dev_t *d; fido_dev_io_t io_f; - int i; + size_t i; memset(&io_f, 0, sizeof(io_f)); diff --git a/regress/cred.c b/regress/cred.c index f8c08a4..74236e3 100644 --- a/regress/cred.c +++ b/regress/cred.c @@ -231,6 +231,16 @@ const unsigned char id[64] = { 0x34, 0xe3, 0x83, 0xe7, 0xd1, 0xbd, 0x9f, 0x25, }; +/* + * Security Key By Yubico + * 5.1.X + * f8a011f3-8c0a-4d15-8006-17111f9edc7d +*/ +const unsigned char aaguid[16] = { + 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15, + 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d, +}; + const char rp_id[] = "localhost"; const char rp_name[] = "sweet home localhost"; @@ -323,6 +333,7 @@ empty_cred(void) assert(fido_cred_fmt(c) == NULL); assert(fido_cred_id_len(c) == 0); assert(fido_cred_id_ptr(c) == NULL); + assert(fido_cred_prot(c) == 0); assert(fido_cred_pubkey_len(c) == 0); assert(fido_cred_pubkey_ptr(c) == NULL); assert(fido_cred_rp_id(c) == NULL); @@ -374,10 +385,13 @@ valid_cred(void) assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); assert(fido_cred_verify(c) == FIDO_OK); + assert(fido_cred_prot(c) == 0); assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); + assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); + assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); } @@ -400,6 +414,8 @@ no_cdh(void) assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); + assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); + assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); } @@ -422,6 +438,8 @@ no_rp_id(void) assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); + assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); + assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); } @@ -445,6 +463,8 @@ no_rp_name(void) assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); + assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); + assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); } @@ -452,6 +472,10 @@ static void no_authdata(void) { fido_cred_t *c; + unsigned char *unset; + + unset = calloc(1, sizeof(aaguid)); + assert(unset != NULL); c = alloc_cred(); assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); @@ -467,7 +491,10 @@ no_authdata(void) assert(fido_cred_pubkey_ptr(c) == NULL); assert(fido_cred_id_len(c) == 0); assert(fido_cred_id_ptr(c) == NULL); + assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); + assert(memcmp(fido_cred_aaguid_ptr(c), unset, sizeof(aaguid)) == 0); free_cred(c); + free(unset); } static void @@ -489,6 +516,8 @@ no_x509(void) assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); + assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); + assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); } @@ -511,6 +540,8 @@ no_sig(void) assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); + assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); + assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); } @@ -533,6 +564,8 @@ no_fmt(void) assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); + assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); + assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); } @@ -556,6 +589,8 @@ wrong_options(void) assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); + assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); + assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); } @@ -585,6 +620,8 @@ junk_cdh(void) assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); + assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); + assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); free(junk); } @@ -609,6 +646,8 @@ junk_rp_id(void) assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); + assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); + assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); } @@ -632,6 +671,8 @@ junk_rp_name(void) assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); + assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); + assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); } @@ -640,12 +681,16 @@ junk_authdata(void) { fido_cred_t *c; unsigned char *junk; + unsigned char *unset; junk = malloc(sizeof(authdata)); assert(junk != NULL); memcpy(junk, authdata, sizeof(authdata)); junk[0] = ~junk[0]; + unset = calloc(1, sizeof(aaguid)); + assert(unset != NULL); + c = alloc_cred(); assert(fido_cred_set_authdata(c, junk, sizeof(authdata)) == FIDO_ERR_INVALID_ARGUMENT); @@ -663,9 +708,12 @@ junk_authdata(void) assert(fido_cred_sig_ptr(c) == NULL); assert(fido_cred_x5c_len(c) == 0); assert(fido_cred_x5c_ptr(c) == NULL); + assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); + assert(memcmp(fido_cred_aaguid_ptr(c), unset, sizeof(aaguid)) == 0); assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); free_cred(c); free(junk); + free(unset); } static void @@ -694,6 +742,8 @@ junk_sig(void) assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); + assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); + assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); free(junk); } @@ -724,6 +774,8 @@ junk_x509(void) assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); assert(fido_cred_id_len(c) == sizeof(id)); assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); + assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); + assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0); free_cred(c); free(junk); } @@ -733,6 +785,10 @@ static void invalid_type(void) { fido_cred_t *c; + unsigned char *unset; + + unset = calloc(1, sizeof(aaguid)); + assert(unset != NULL); c = alloc_cred(); assert(fido_cred_set_type(c, COSE_RS256) == FIDO_OK); @@ -749,7 +805,10 @@ invalid_type(void) assert(fido_cred_pubkey_ptr(c) == NULL); assert(fido_cred_id_len(c) == 0); assert(fido_cred_id_ptr(c) == NULL); + assert(fido_cred_aaguid_len(c) == sizeof(aaguid)); + assert(memcmp(fido_cred_aaguid_ptr(c), unset, sizeof(aaguid)) == 0); free_cred(c); + free(unset); } /* cbor_serialize_alloc misuse */ @@ -789,6 +848,24 @@ unsorted_keys(void) free_cred(c); } +static void +wrong_credprot(void) +{ + fido_cred_t *c; + + c = alloc_cred(); + assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); + assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK); + assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK); + assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK); + assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); + assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); + assert(fido_cred_set_prot(c, FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID) == FIDO_OK); + assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK); + assert(fido_cred_verify(c) == FIDO_ERR_INVALID_PARAM); + free_cred(c); +} + int main(void) { @@ -814,6 +891,7 @@ main(void) bad_cbor_serialize(); duplicate_keys(); unsorted_keys(); + wrong_credprot(); exit(0); } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3cf62e8..ad02524 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -37,19 +37,24 @@ if(FUZZ) endif() if(USE_HIDAPI) - list(APPEND COMPAT_SOURCES hid_hidapi.c) + list(APPEND FIDO_SOURCES hid_hidapi.c) elseif(WIN32) - list(APPEND COMPAT_SOURCES hid_win.c) + list(APPEND FIDO_SOURCES hid_win.c) elseif(APPLE) - list(APPEND COMPAT_SOURCES hid_osx.c) + list(APPEND FIDO_SOURCES hid_osx.c) elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") - list(APPEND COMPAT_SOURCES hid_linux.c) + list(APPEND FIDO_SOURCES hid_linux.c) elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") - list(APPEND COMPAT_SOURCES hid_openbsd.c) + list(APPEND FIDO_SOURCES hid_openbsd.c) else() message(FATAL_ERROR "please define a hid backend for your platform") endif() +if(NOT MSVC) + set_source_files_properties(${FIDO_SOURCES} PROPERTIES COMPILE_FLAGS + "-Wconversion -Wsign-conversion") +endif() + list(APPEND COMPAT_SOURCES ../openbsd-compat/bsd-getpagesize.c ../openbsd-compat/explicit_bzero.c @@ -94,7 +99,7 @@ elseif(APPLE) "-framework IOKit") endif() set_target_properties(fido2_shared PROPERTIES OUTPUT_NAME fido2 - VERSION ${LIB_VERSION} SOVERSION ${LIB_SOVERSION}) + VERSION ${FIDO_VERSION} SOVERSION ${FIDO_MAJOR}) install(TARGETS fido2_shared ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} diff --git a/src/assert.c b/src/assert.c index b71d00e..1746387 100644 --- a/src/assert.c +++ b/src/assert.c @@ -313,7 +313,7 @@ fido_dev_get_assert(fido_dev_t *dev, fido_assert_t *assert, const char *pin) goto fail; } } - + r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, -1); if (r == FIDO_OK && assert->ext & FIDO_EXT_HMAC_SECRET) if (decrypt_hmac_secrets(assert, ecdh) < 0) { diff --git a/src/cbor.c b/src/cbor.c index 3928325..b30da50 100644 --- a/src/cbor.c +++ b/src/cbor.c @@ -386,7 +386,7 @@ cbor_flatten_vector(cbor_item_t *argv[], size_t argc) return (NULL); for (i = 0; i < argc; i++) - if (cbor_add_arg(map, i + 1, argv[i]) < 0) + if (cbor_add_arg(map, (uint8_t)(i + 1), argv[i]) < 0) break; if (i != argc) { @@ -583,7 +583,9 @@ cbor_encode_extensions(const fido_cred_ext_t *ext) } } if (ext->mask & FIDO_EXT_CRED_PROTECT) { - if (cbor_add_uint8(item, "credProtect", ext->prot) < 0) { + if (ext->prot < 0 || ext->prot > UINT8_MAX || + cbor_add_uint8(item, "credProtect", + (uint8_t)ext->prot) < 0) { cbor_decref(&item); return (NULL); } @@ -634,7 +636,7 @@ cbor_encode_pin_auth(const fido_blob_t *hmac_key, const fido_blob_t *data) unsigned int dgst_len; if ((md = EVP_sha256()) == NULL || HMAC(md, hmac_key->ptr, - (int)hmac_key->len, data->ptr, (int)data->len, dgst, + (int)hmac_key->len, data->ptr, data->len, dgst, &dgst_len) == NULL || dgst_len != SHA256_DIGEST_LENGTH) return (NULL); @@ -696,7 +698,6 @@ cbor_encode_change_pin_auth(const fido_blob_t *key, const fido_blob_t *new_pin, fido_blob_t *npe = NULL; /* new pin, encrypted */ fido_blob_t *ph = NULL; /* pin hash */ fido_blob_t *phe = NULL; /* pin hash, encrypted */ - int ok = -1; if ((npe = fido_blob_new()) == NULL || (ph = fido_blob_new()) == NULL || @@ -735,8 +736,8 @@ cbor_encode_change_pin_auth(const fido_blob_t *key, const fido_blob_t *new_pin, if ((ctx = HMAC_CTX_new()) == NULL || (md = EVP_sha256()) == NULL || HMAC_Init_ex(ctx, key->ptr, (int)key->len, md, NULL) == 0 || - HMAC_Update(ctx, npe->ptr, (int)npe->len) == 0 || - HMAC_Update(ctx, phe->ptr, (int)phe->len) == 0 || + HMAC_Update(ctx, npe->ptr, npe->len) == 0 || + HMAC_Update(ctx, phe->ptr, phe->len) == 0 || HMAC_Final(ctx, dgst, &dgst_len) == 0 || dgst_len != 32) { fido_log_debug("%s: HMAC", __func__); goto fail; @@ -748,7 +749,6 @@ cbor_encode_change_pin_auth(const fido_blob_t *key, const fido_blob_t *new_pin, goto fail; } - ok = 0; fail: fido_blob_free(&npe); fido_blob_free(&ph); @@ -759,13 +759,6 @@ fail: HMAC_CTX_free(ctx); #endif - if (ok < 0) { - if (item != NULL) { - cbor_decref(&item); - item = NULL; - } - } - return (item); } @@ -787,7 +780,7 @@ cbor_encode_set_pin_auth(const fido_blob_t *key, const fido_blob_t *pin) } if ((md = EVP_sha256()) == NULL || key->len != 32 || HMAC(md, key->ptr, - (int)key->len, pe->ptr, (int)pe->len, dgst, &dgst_len) == NULL || + (int)key->len, pe->ptr, pe->len, dgst, &dgst_len) == NULL || dgst_len != SHA256_DIGEST_LENGTH) { fido_log_debug("%s: HMAC", __func__); goto fail; @@ -1292,7 +1285,7 @@ cbor_decode_cred_authdata(const cbor_item_t *item, int cose_alg, } if (authdata_ext != NULL) { - if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0 && + if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0 && decode_extensions(&buf, &len, authdata_ext) < 0) return (-1); } diff --git a/src/cred.c b/src/cred.c index 4ecbba8..9f902fa 100644 --- a/src/cred.c +++ b/src/cred.c @@ -967,6 +967,18 @@ fido_cred_id_len(const fido_cred_t *cred) return (cred->attcred.id.len); } +const unsigned char * +fido_cred_aaguid_ptr(const fido_cred_t *cred) +{ + return (cred->attcred.aaguid); +} + +size_t +fido_cred_aaguid_len(const fido_cred_t *cred) +{ + return (sizeof(cred->attcred.aaguid)); +} + int fido_cred_prot(const fido_cred_t *cred) { diff --git a/src/credman.c b/src/credman.c index a382185..4219807 100644 --- a/src/credman.c +++ b/src/credman.c @@ -230,7 +230,8 @@ fido_credman_get_dev_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata static int credman_parse_rk(const cbor_item_t *key, const cbor_item_t *val, void *arg) { - fido_cred_t *cred = arg; + fido_cred_t *cred = arg; + uint64_t prot; if (cbor_isa_uint(key) == false || cbor_int_get_width(key) != CBOR_INT_8) { @@ -249,6 +250,11 @@ credman_parse_rk(const cbor_item_t *key, const cbor_item_t *val, void *arg) return (-1); cred->type = cred->attcred.type; /* XXX */ return (0); + case 10: + if (cbor_decode_uint64(val, &prot) < 0 || prot > INT_MAX || + fido_cred_set_prot(cred, (int)prot) != FIDO_OK) + return (-1); + return (0); default: fido_log_debug("%s: cbor type", __func__); return (0); /* ignore */ diff --git a/src/dev.c b/src/dev.c index 51b9935..3463ae4 100644 --- a/src/dev.c +++ b/src/dev.c @@ -10,6 +10,8 @@ #include #endif +#include + #include #include #include @@ -106,10 +108,49 @@ find_manifest_func_node(dev_manifest_func_t f, dev_manifest_func_node_t **curr, } } +#ifdef FIDO_FUZZ +static void +set_random_report_len(fido_dev_t *dev) +{ + dev->rx_len = CTAP_MIN_REPORT_LEN + + uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1); + dev->tx_len = CTAP_MIN_REPORT_LEN + + uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1); +} +#endif + +static void +fido_dev_set_flags(fido_dev_t *dev, const fido_cbor_info_t *info) +{ + char * const *ptr; + const bool *val; + size_t len; + + ptr = fido_cbor_info_extensions_ptr(info); + len = fido_cbor_info_extensions_len(info); + + for (size_t i = 0; i < len; i++) + if (strcmp(ptr[i], "credProtect") == 0) + dev->flags |= FIDO_DEV_CRED_PROT; + + ptr = fido_cbor_info_options_name_ptr(info); + val = fido_cbor_info_options_value_ptr(info); + len = fido_cbor_info_options_len(info); + + for (size_t i = 0; i < len; i++) + if (strcmp(ptr[i], "clientPin") == 0) { + if (val[i] == true) + dev->flags |= FIDO_DEV_PIN_SET; + else + dev->flags |= FIDO_DEV_PIN_UNSET; + } +} + static int fido_dev_open_tx(fido_dev_t *dev, const char *path) { - const uint8_t cmd = CTAP_CMD_INIT; + const uint8_t cmd = CTAP_CMD_INIT; + int r; if (dev->io_handle != NULL) { fido_log_debug("%s: handle=%p", __func__, dev->io_handle); @@ -131,14 +172,44 @@ fido_dev_open_tx(fido_dev_t *dev, const char *path) return (FIDO_ERR_INTERNAL); } + if (dev->io_own) { + dev->rx_len = CTAP_MAX_REPORT_LEN; + dev->tx_len = CTAP_MAX_REPORT_LEN; + } else { + dev->rx_len = fido_hid_report_in_len(dev->io_handle); + dev->tx_len = fido_hid_report_out_len(dev->io_handle); + } + +#ifdef FIDO_FUZZ + set_random_report_len(dev); +#endif + + if (dev->rx_len < CTAP_MIN_REPORT_LEN || + dev->rx_len > CTAP_MAX_REPORT_LEN) { + fido_log_debug("%s: invalid rx_len %zu", __func__, dev->rx_len); + r = FIDO_ERR_RX; + goto fail; + } + + if (dev->tx_len < CTAP_MIN_REPORT_LEN || + dev->tx_len > CTAP_MAX_REPORT_LEN) { + fido_log_debug("%s: invalid tx_len %zu", __func__, dev->tx_len); + r = FIDO_ERR_TX; + goto fail; + } + if (fido_tx(dev, cmd, &dev->nonce, sizeof(dev->nonce)) < 0) { fido_log_debug("%s: fido_tx", __func__); - dev->io.close(dev->io_handle); - dev->io_handle = NULL; - return (FIDO_ERR_TX); + r = FIDO_ERR_TX; + goto fail; } return (FIDO_OK); +fail: + dev->io.close(dev->io_handle); + dev->io_handle = NULL; + + return (r); } static int @@ -166,6 +237,7 @@ fido_dev_open_rx(fido_dev_t *dev, int ms) goto fail; } + dev->flags = 0; dev->cid = dev->attr.cid; if (fido_dev_is_fido2(dev)) { @@ -177,6 +249,8 @@ fido_dev_open_rx(fido_dev_t *dev, int ms) if (fido_dev_get_cbor_info_wait(dev, info, ms) != FIDO_OK) { fido_log_debug("%s: falling back to u2f", __func__); fido_dev_force_u2f(dev); + } else { + fido_dev_set_flags(dev, info); } } @@ -303,12 +377,114 @@ fido_dev_close(fido_dev_t *dev) int fido_dev_cancel(fido_dev_t *dev) { + if (fido_dev_is_fido2(dev) == false) + return (FIDO_ERR_INVALID_ARGUMENT); + if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0) < 0) return (FIDO_ERR_TX); return (FIDO_OK); } +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 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)); + + 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()) == 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) < 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) { @@ -324,6 +500,7 @@ fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io) } dev->io = *io; + dev->io_own = true; return (FIDO_OK); } @@ -337,6 +514,7 @@ fido_dev_set_transport_functions(fido_dev_t *dev, const fido_dev_transport_t *t) } dev->transport = *t; + dev->io_own = true; return (FIDO_OK); } @@ -446,10 +624,29 @@ fido_dev_is_fido2(const fido_dev_t *dev) return (dev->attr.flags & FIDO_CAP_CBOR); } +bool +fido_dev_supports_pin(const fido_dev_t *dev) +{ + return (dev->flags & (FIDO_DEV_PIN_SET|FIDO_DEV_PIN_UNSET)); +} + +bool +fido_dev_has_pin(const fido_dev_t *dev) +{ + return (dev->flags & FIDO_DEV_PIN_SET); +} + +bool +fido_dev_supports_cred_prot(const fido_dev_t *dev) +{ + return (dev->flags & FIDO_DEV_CRED_PROT); +} + void fido_dev_force_u2f(fido_dev_t *dev) { - dev->attr.flags &= ~FIDO_CAP_CBOR; + dev->attr.flags &= (uint8_t)~FIDO_CAP_CBOR; + dev->flags = 0; } void diff --git a/src/diff_exports.sh b/src/diff_exports.sh index 7920f47..9cff009 100755 --- a/src/diff_exports.sh +++ b/src/diff_exports.sh @@ -1,23 +1,26 @@ -#!/bin/bash -u +#!/bin/sh -u # Copyright (c) 2018 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. -[[ ! -f export.gnu || ! -f export.llvm || ! -f export.msvc ]] && exit 1 +for f in export.gnu export.llvm export.msvc; do + if [ ! -f "${f}" ]; then + exit 1 + fi +done -TMPDIR=$(mktemp -d) -GNU=${TMPDIR}/gnu -LLVM=${TMPDIR}/llvm -MSVC=${TMPDIR}/msvc +TMPDIR="$(mktemp -d)" +GNU="${TMPDIR}/gnu" +LLVM="${TMPDIR}/llvm" +MSVC="${TMPDIR}/msvc" -egrep -o $'([^*{}\t]+);$' export.gnu | tr -d ';' | sort > ${GNU} -sed 's/^_//g' export.llvm | sort > ${LLVM} -egrep -v "^EXPORTS$" export.msvc | sort > ${MSVC} -diff -u ${GNU} ${LLVM} && diff -u ${MSVC} ${LLVM} +awk '/^[^*{}]+;$/' export.gnu | tr -d '\t;' | sort > "${GNU}" +sed 's/^_//' export.llvm | sort > "${LLVM}" +grep -v '^EXPORTS$' export.msvc | sort > "${MSVC}" +diff -u "${GNU}" "${LLVM}" && diff -u "${MSVC}" "${LLVM}" ERROR=$? - -rm ${GNU} ${LLVM} ${MSVC} -rmdir ${TMPDIR} +rm "${GNU}" "${LLVM}" "${MSVC}" +rmdir "${TMPDIR}" exit ${ERROR} diff --git a/src/err.c b/src/err.c index 6261bfc..19cda21 100644 --- a/src/err.c +++ b/src/err.c @@ -38,6 +38,8 @@ fido_strerr(int n) return "FIDO_ERR_LIMIT_EXCEEDED"; case FIDO_ERR_UNSUPPORTED_EXTENSION: return "FIDO_ERR_UNSUPPORTED_EXTENSION"; + case FIDO_ERR_FP_DATABASE_FULL: + return "FIDO_ERR_FP_DATABASE_FULL"; case FIDO_ERR_CREDENTIAL_EXCLUDED: return "FIDO_ERR_CREDENTIAL_EXCLUDED"; case FIDO_ERR_PROCESSING: @@ -94,6 +96,8 @@ fido_strerr(int n) return "FIDO_ERR_ACTION_TIMEOUT"; case FIDO_ERR_UP_REQUIRED: return "FIDO_ERR_UP_REQUIRED"; + case FIDO_ERR_UV_BLOCKED: + return "FIDO_ERR_UV_BLOCKED"; case FIDO_ERR_ERR_OTHER: return "FIDO_ERR_ERR_OTHER"; case FIDO_ERR_SPEC_LAST: diff --git a/src/es256.c b/src/es256.c index 020ecaa..5b4e6d6 100644 --- a/src/es256.c +++ b/src/es256.c @@ -92,7 +92,7 @@ es256_pk_encode(const es256_pk_t *pk, int ecdh) /* alg */ if ((argv[1].key = cbor_build_uint8(3)) == NULL || - (argv[1].value = cbor_build_negint8(-alg - 1)) == NULL || + (argv[1].value = cbor_build_negint8((uint8_t)(-alg - 1))) == NULL || !cbor_map_add(item, argv[1])) goto fail; diff --git a/src/export.gnu b/src/export.gnu index cbfa69f..007b5b9 100644 --- a/src/export.gnu +++ b/src/export.gnu @@ -76,6 +76,8 @@ fido_cbor_info_extensions_ptr; fido_cbor_info_free; fido_cbor_info_maxmsgsiz; + fido_cbor_info_maxcredcntlst; + fido_cbor_info_maxcredidlen; fido_cbor_info_fwversion; fido_cbor_info_new; fido_cbor_info_options_len; @@ -96,6 +98,8 @@ fido_cred_free; fido_cred_id_len; fido_cred_id_ptr; + fido_cred_aaguid_len; + fido_cred_aaguid_ptr; fido_credman_del_dev_rk; fido_credman_get_dev_metadata; fido_credman_get_dev_rk; @@ -155,6 +159,9 @@ fido_dev_get_assert; fido_dev_get_cbor_info; fido_dev_get_retry_count; + fido_dev_get_touch_begin; + fido_dev_get_touch_status; + fido_dev_has_pin; fido_dev_info_free; fido_dev_info_manifest; fido_dev_info_manufacturer_string; @@ -175,6 +182,8 @@ fido_dev_set_io_functions; fido_dev_set_pin; fido_dev_set_transport_functions; + fido_dev_supports_cred_prot; + fido_dev_supports_pin; fido_init; fido_set_log_handler; fido_strerr; diff --git a/src/export.llvm b/src/export.llvm index abde2e9..ffbc157 100644 --- a/src/export.llvm +++ b/src/export.llvm @@ -74,6 +74,8 @@ _fido_cbor_info_extensions_len _fido_cbor_info_extensions_ptr _fido_cbor_info_free _fido_cbor_info_maxmsgsiz +_fido_cbor_info_maxcredcntlst +_fido_cbor_info_maxcredidlen _fido_cbor_info_fwversion _fido_cbor_info_new _fido_cbor_info_options_len @@ -94,6 +96,8 @@ _fido_cred_fmt _fido_cred_free _fido_cred_id_len _fido_cred_id_ptr +_fido_cred_aaguid_len +_fido_cred_aaguid_ptr _fido_credman_del_dev_rk _fido_credman_get_dev_metadata _fido_credman_get_dev_rk @@ -153,6 +157,9 @@ _fido_dev_free _fido_dev_get_assert _fido_dev_get_cbor_info _fido_dev_get_retry_count +_fido_dev_get_touch_begin +_fido_dev_get_touch_status +_fido_dev_has_pin _fido_dev_info_free _fido_dev_info_manifest _fido_dev_info_manufacturer_string @@ -173,6 +180,8 @@ _fido_dev_reset _fido_dev_set_io_functions _fido_dev_set_pin _fido_dev_set_transport_functions +_fido_dev_supports_cred_prot +_fido_dev_supports_pin _fido_init _fido_set_log_handler _fido_strerr diff --git a/src/export.msvc b/src/export.msvc index 06ec69a..1a2a0b7 100644 --- a/src/export.msvc +++ b/src/export.msvc @@ -75,6 +75,8 @@ fido_cbor_info_extensions_len fido_cbor_info_extensions_ptr fido_cbor_info_free fido_cbor_info_maxmsgsiz +fido_cbor_info_maxcredcntlst +fido_cbor_info_maxcredidlen fido_cbor_info_fwversion fido_cbor_info_new fido_cbor_info_options_len @@ -95,6 +97,8 @@ fido_cred_fmt fido_cred_free fido_cred_id_len fido_cred_id_ptr +fido_cred_aaguid_len +fido_cred_aaguid_ptr fido_credman_del_dev_rk fido_credman_get_dev_metadata fido_credman_get_dev_rk @@ -154,6 +158,9 @@ fido_dev_free fido_dev_get_assert fido_dev_get_cbor_info fido_dev_get_retry_count +fido_dev_get_touch_begin +fido_dev_get_touch_status +fido_dev_has_pin fido_dev_info_free fido_dev_info_manifest fido_dev_info_manufacturer_string @@ -174,6 +181,8 @@ fido_dev_reset fido_dev_set_io_functions fido_dev_set_pin fido_dev_set_transport_functions +fido_dev_supports_cred_prot +fido_dev_supports_pin fido_init fido_set_log_handler fido_strerr diff --git a/src/extern.h b/src/extern.h index fc0a49d..4c036cb 100644 --- a/src/extern.h +++ b/src/extern.h @@ -88,6 +88,8 @@ void *fido_hid_open(const char *); void fido_hid_close(void *); int fido_hid_read(void *, unsigned char *, size_t, int); int fido_hid_write(void *, const unsigned char *, size_t); +size_t fido_hid_report_in_len(void *); +size_t fido_hid_report_out_len(void *); /* generic i/o */ int fido_rx_cbor_status(fido_dev_t *, int); @@ -115,6 +117,8 @@ void fido_log_xxd(const void *, size_t); /* u2f */ int u2f_register(fido_dev_t *, fido_cred_t *, int); int u2f_authenticate(fido_dev_t *, fido_assert_t *, int); +int u2f_get_touch_begin(fido_dev_t *); +int u2f_get_touch_status(fido_dev_t *, int *, int); /* unexposed fido ops */ int fido_dev_authkey(fido_dev_t *, es256_pk_t *); @@ -149,6 +153,22 @@ 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); +/* fuzzing instrumentation */ +#ifdef FIDO_FUZZ +uint32_t uniform_random(uint32_t); +#endif + +/* internal device capability flags */ +#define FIDO_DEV_PIN_SET 0x01 +#define FIDO_DEV_PIN_UNSET 0x02 +#define FIDO_DEV_CRED_PROT 0x04 + +/* miscellanea */ +#define FIDO_DUMMY_CLIENTDATA "" +#define FIDO_DUMMY_RP_ID "localhost" +#define FIDO_DUMMY_USER_NAME "dummy" +#define FIDO_DUMMY_USER_ID 1 + #ifdef __cplusplus } /* extern "C" */ #endif /* __cplusplus */ diff --git a/src/fido.h b/src/fido.h index e41de89..baa2928 100644 --- a/src/fido.h +++ b/src/fido.h @@ -32,6 +32,12 @@ extern "C" { #endif /* __cplusplus */ +#ifdef _MSC_VER +#define FIDO_DEPRECATED(reason) __declspec(deprecated(reason)) +#else +#define FIDO_DEPRECATED(reason) __attribute__((__deprecated__(reason))) +#endif + fido_assert_t *fido_assert_new(void); fido_cred_t *fido_cred_new(void); fido_dev_t *fido_dev_new(void); @@ -82,6 +88,7 @@ const unsigned char *fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *); const unsigned char *fido_cred_authdata_ptr(const fido_cred_t *); const unsigned char *fido_cred_clientdata_hash_ptr(const fido_cred_t *); const unsigned char *fido_cred_id_ptr(const fido_cred_t *); +const unsigned char *fido_cred_aaguid_ptr(const fido_cred_t *); const unsigned char *fido_cred_user_id_ptr(const fido_cred_t *); const unsigned char *fido_cred_pubkey_ptr(const fido_cred_t *); const unsigned char *fido_cred_sig_ptr(const fido_cred_t *); @@ -97,8 +104,8 @@ int fido_assert_set_clientdata_hash(fido_assert_t *, const unsigned char *, int fido_assert_set_count(fido_assert_t *, size_t); int fido_assert_set_extensions(fido_assert_t *, int); int fido_assert_set_hmac_salt(fido_assert_t *, const unsigned char *, size_t); -int fido_assert_set_options(fido_assert_t *, bool, bool) - __attribute__((__deprecated__("use fido_assert_set_up/fido_assert_set_uv"))); +FIDO_DEPRECATED("use fido_assert_set_up/fido_assert_set_uv") +int fido_assert_set_options(fido_assert_t *, bool, bool); int fido_assert_set_rp(fido_assert_t *, const char *); int fido_assert_set_up(fido_assert_t *, fido_opt_t); int fido_assert_set_uv(fido_assert_t *, fido_opt_t); @@ -111,8 +118,8 @@ int fido_cred_set_authdata_raw(fido_cred_t *, const unsigned char *, size_t); int fido_cred_set_clientdata_hash(fido_cred_t *, const unsigned char *, size_t); int fido_cred_set_extensions(fido_cred_t *, int); int fido_cred_set_fmt(fido_cred_t *, const char *); -int fido_cred_set_options(fido_cred_t *, bool, bool) - __attribute__((__deprecated__("use fido_cred_set_rk/fido_cred_set_uv"))); +FIDO_DEPRECATED("use fido_cred_set_rk/fido_cred_set_uv") +int fido_cred_set_options(fido_cred_t *, bool, bool); int fido_cred_set_prot(fido_cred_t *, int); int fido_cred_set_rk(fido_cred_t *, fido_opt_t); int fido_cred_set_rp(fido_cred_t *, const char *, const char *); @@ -130,6 +137,8 @@ int fido_dev_close(fido_dev_t *); int fido_dev_get_assert(fido_dev_t *, fido_assert_t *, const char *); int fido_dev_get_cbor_info(fido_dev_t *, fido_cbor_info_t *); int fido_dev_get_retry_count(fido_dev_t *, int *); +int fido_dev_get_touch_begin(fido_dev_t *); +int fido_dev_get_touch_status(fido_dev_t *, int *, int); int fido_dev_info_manifest(fido_dev_info_t *, size_t, size_t *); int fido_dev_make_cred(fido_dev_t *, fido_cred_t *, const char *); int fido_dev_open_with_info(fido_dev_t *); @@ -154,6 +163,7 @@ size_t fido_cbor_info_versions_len(const fido_cbor_info_t *); size_t fido_cred_authdata_len(const fido_cred_t *); size_t fido_cred_clientdata_hash_len(const fido_cred_t *); size_t fido_cred_id_len(const fido_cred_t *); +size_t fido_cred_aaguid_len(const fido_cred_t *); size_t fido_cred_user_id_len(const fido_cred_t *); size_t fido_cred_pubkey_len(const fido_cred_t *); size_t fido_cred_sig_len(const fido_cred_t *); @@ -170,9 +180,14 @@ 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_maxcredcntlst(const fido_cbor_info_t *); +uint64_t fido_cbor_info_maxcredidlen(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 *); bool fido_dev_is_fido2(const fido_dev_t *); +bool fido_dev_supports_pin(const fido_dev_t *); +bool fido_dev_supports_cred_prot(const fido_dev_t *); #ifdef __cplusplus } /* extern "C" */ diff --git a/src/fido/err.h b/src/fido/err.h index d7453fc..253914f 100644 --- a/src/fido/err.h +++ b/src/fido/err.h @@ -21,6 +21,7 @@ #define FIDO_ERR_MISSING_PARAMETER 0x14 #define FIDO_ERR_LIMIT_EXCEEDED 0x15 #define FIDO_ERR_UNSUPPORTED_EXTENSION 0x16 +#define FIDO_ERR_FP_DATABASE_FULL 0x17 #define FIDO_ERR_CREDENTIAL_EXCLUDED 0x19 #define FIDO_ERR_PROCESSING 0x21 #define FIDO_ERR_INVALID_CREDENTIAL 0x22 @@ -49,6 +50,7 @@ #define FIDO_ERR_REQUEST_TOO_LARGE 0x39 #define FIDO_ERR_ACTION_TIMEOUT 0x3a #define FIDO_ERR_UP_REQUIRED 0x3b +#define FIDO_ERR_UV_BLOCKED 0x3c #define FIDO_ERR_ERR_OTHER 0x7f #define FIDO_ERR_SPEC_LAST 0xdf diff --git a/src/fido/param.h b/src/fido/param.h index 7d3c0cc..14ee74e 100644 --- a/src/fido/param.h +++ b/src/fido/param.h @@ -50,8 +50,14 @@ /* HID Broadcast channel ID. */ #define CTAP_CID_BROADCAST 0xffffffff -/* Expected size of a HID report in bytes. */ -#define CTAP_RPT_SIZE 64 +#define CTAP_INIT_HEADER_LEN 7 +#define CTAP_CONT_HEADER_LEN 5 + +/* Maximum length of a CTAP HID report in bytes. */ +#define CTAP_MAX_REPORT_LEN 64 + +/* Minimum length of a CTAP HID report in bytes. */ +#define CTAP_MIN_REPORT_LEN (CTAP_INIT_HEADER_LEN + 1) /* Randomness device on UNIX-like platforms. */ #ifndef FIDO_RANDOM_DEV @@ -60,7 +66,7 @@ /* Maximum message size in bytes. */ #ifndef FIDO_MAXMSG -#define FIDO_MAXMSG 1200 +#define FIDO_MAXMSG 2048 #endif /* CTAP capability bits. */ diff --git a/src/fido/types.h b/src/fido/types.h index 5df5e36..cce1a44 100644 --- a/src/fido/types.h +++ b/src/fido/types.h @@ -175,13 +175,15 @@ typedef struct fido_byte_array { } fido_byte_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 */ - 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 */ - uint64_t fwversion; /* firmware version */ + fido_str_array_t versions; /* supported versions: fido2|u2f */ + fido_str_array_t extensions; /* list of supported extensions */ + 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 */ + uint64_t maxcredcntlst; /* max number of credentials in list */ + uint64_t maxcredidlen; /* max credential ID length */ + uint64_t fwversion; /* firmware version */ } fido_cbor_info_t; typedef struct fido_dev_info { @@ -213,6 +215,10 @@ typedef struct fido_dev { char *path; /* device path */ void *io_handle; /* abstract i/o handle */ fido_dev_io_t io; /* i/o functions */ + bool io_own; /* device has own io/transport */ + size_t rx_len; /* length of HID input reports */ + size_t tx_len; /* length of HID output reports */ + int flags; /* internal flags; see FIDO_DEV_* */ fido_dev_transport_t transport; /* transport functions */ } fido_dev_t; diff --git a/src/hid_hidapi.c b/src/hid_hidapi.c index 915621f..898fd9e 100644 --- a/src/hid_hidapi.c +++ b/src/hid_hidapi.c @@ -4,14 +4,26 @@ * license that can be found in the LICENSE file. */ -#include +#ifdef __linux__ +#include +#include +#include +#include +#endif +#include #include #include #include #include "fido.h" +struct hid_hidapi { + void *handle; + size_t report_in_len; + size_t report_out_len; +}; + static size_t fido_wcslen(const wchar_t *wcs) { @@ -27,7 +39,7 @@ wcs_to_cs(const wchar_t *wcs) char *cs; size_t i; - if (wcs == NULL || (cs = calloc(fido_wcslen(wcs) + 1, 1)) == NULL) + if (wcs == NULL || (cs = calloc(fido_wcslen(wcs) + 1, 1)) == NULL) return NULL; for (i = 0; i < fido_wcslen(wcs); i++) { @@ -68,11 +80,12 @@ copy_info(fido_dev_info_t *di, const struct hid_device_info *d) free(di->path); free(di->manufacturer); free(di->product); + explicit_bzero(di, sizeof(*di)); return -1; } - di->product_id = d->product_id; - di->vendor_id = d->vendor_id; + di->product_id = (int16_t)d->product_id; + di->vendor_id = (int16_t)d->vendor_id; di->io = (fido_dev_io_t) { &fido_hid_open, &fido_hid_close, @@ -83,28 +96,199 @@ copy_info(fido_dev_info_t *di, const struct hid_device_info *d) return 0; } +#ifdef __linux__ +static int +get_key_len(uint8_t tag, uint8_t *key, size_t *key_len) +{ + *key = tag & 0xfc; + if ((*key & 0xf0) == 0xf0) { + fido_log_debug("%s: *key=0x%02x", __func__, *key); + return -1; + } + + *key_len = tag & 0x3; + if (*key_len == 3) { + *key_len = 4; + } + + return 0; +} + +static int +get_key_val(const void *body, size_t key_len, uint32_t *val) +{ + const uint8_t *ptr = body; + + switch (key_len) { + case 0: + *val = 0; + break; + case 1: + *val = ptr[0]; + break; + case 2: + *val = (uint32_t)((ptr[1] << 8) | ptr[0]); + break; + default: + fido_log_debug("%s: key_len=%zu", __func__, key_len); + return -1; + } + + return 0; +} + +static int +get_usage_info(const struct hidraw_report_descriptor *hrd, uint32_t *usage_page, + uint32_t *usage) +{ + const uint8_t *ptr = hrd->value; + size_t len = hrd->size; + + while (len > 0) { + const uint8_t tag = ptr[0]; + + ptr++; + len--; + + uint8_t key; + size_t key_len; + uint32_t key_val; + + if (get_key_len(tag, &key, &key_len) < 0 || key_len > len || + get_key_val(ptr, key_len, &key_val) < 0) { + return -1; + } + + if (key == 0x4) { + *usage_page = key_val; + } else if (key == 0x8) { + *usage = key_val; + } + + ptr += key_len; + len -= key_len; + } + + return 0; +} + +static int +get_report_descriptor(const char *path, struct hidraw_report_descriptor *hrd) +{ + int fd; + int s = -1; + int ok = -1; + + if ((fd = open(path, O_RDONLY)) < 0) { + fido_log_debug("%s: open", __func__); + return -1; + } + + if (ioctl(fd, HIDIOCGRDESCSIZE, &s) < 0 || s < 0 || + (unsigned)s > HID_MAX_DESCRIPTOR_SIZE) { + fido_log_debug("%s: ioctl HIDIOCGRDESCSIZE", __func__); + goto fail; + } + + hrd->size = (unsigned)s; + + if (ioctl(fd, HIDIOCGRDESC, hrd) < 0) { + fido_log_debug("%s: ioctl HIDIOCGRDESC", __func__); + goto fail; + } + + ok = 0; +fail: + if (fd != -1) + close(fd); + + return ok; +} + +static bool +is_fido(const struct hid_device_info *hdi) +{ + uint32_t usage = 0; + uint32_t usage_page = 0; + struct hidraw_report_descriptor hrd; + + memset(&hrd, 0, sizeof(hrd)); + + if (get_report_descriptor(hdi->path, &hrd) < 0 || + get_usage_info(&hrd, &usage_page, &usage) < 0) { + return false; + } + + return usage_page == 0xf1d0; +} +#elif defined(_WIN32) || defined(__APPLE__) +static bool +is_fido(const struct hid_device_info *hdi) +{ + return hdi->usage_page == 0xf1d0; +} +#else +static bool +is_fido(const struct hid_device_info *hdi) +{ + (void)hdi; + fido_log_debug("%s: assuming FIDO HID", __func__); + return true; +} +#endif + void * fido_hid_open(const char *path) { - return hid_open_path(path); + struct hid_hidapi *ctx; + + if ((ctx = calloc(1, sizeof(*ctx))) == NULL) { + return (NULL); + } + + if ((ctx->handle = hid_open_path(path)) == NULL) { + free(ctx); + return (NULL); + } + + ctx->report_in_len = ctx->report_out_len = CTAP_MAX_REPORT_LEN; + + return ctx; } void -fido_hid_close(void *hid_dev_handle) +fido_hid_close(void *handle) { - hid_close(hid_dev_handle); + struct hid_hidapi *ctx = handle; + + hid_close(ctx->handle); + free(ctx); } int -fido_hid_read(void *hid_dev_handle, unsigned char *buf, size_t len, int ms) +fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) { - return hid_read_timeout(hid_dev_handle, buf, len, ms); + struct hid_hidapi *ctx = handle; + + if (len != ctx->report_in_len) { + fido_log_debug("%s: len %zu", __func__, len); + return -1; + } + + return hid_read_timeout(ctx->handle, buf, len, ms); } int -fido_hid_write(void *hid_dev_handle, const unsigned char *buf, size_t len) +fido_hid_write(void *handle, const unsigned char *buf, size_t len) { - return hid_write(hid_dev_handle, buf, len); + struct hid_hidapi *ctx = handle; + + if (len != ctx->report_out_len + 1) { + fido_log_debug("%s: len %zu", __func__, len); + return -1; + } + + return hid_write(ctx->handle, buf, len); } int @@ -122,10 +306,8 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) return FIDO_OK; /* nothing to do */ for (struct hid_device_info *d = hdi; d != NULL; d = d->next) { -#if defined(_WIN32) || defined(__APPLE__) - if (d->usage_page != 0xf1d0) + if (is_fido(d) == false) continue; -#endif if (copy_info(&devlist[*olen], d) == 0) { if (++(*olen) == ilen) break; @@ -136,3 +318,19 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) return FIDO_OK; } + +size_t +fido_hid_report_in_len(void *handle) +{ + struct hid_hidapi *ctx = handle; + + return (ctx->report_in_len); +} + +size_t +fido_hid_report_out_len(void *handle) +{ + struct hid_hidapi *ctx = handle; + + return (ctx->report_out_len); +} diff --git a/src/hid_linux.c b/src/hid_linux.c index 99c5afb..9788012 100644 --- a/src/hid_linux.c +++ b/src/hid_linux.c @@ -8,16 +8,22 @@ #include #include +#include +#include #include #include +#include #include #include -#include #include "fido.h" -#define REPORT_LEN 65 +struct hid_linux { + int fd; + size_t report_in_len; + size_t report_out_len; +}; static int get_key_len(uint8_t tag, uint8_t *key, size_t *key_len) @@ -63,11 +69,8 @@ static int get_usage_info(const struct hidraw_report_descriptor *hrd, uint32_t *usage_page, uint32_t *usage) { - const uint8_t *ptr; - size_t len; - - ptr = hrd->value; - len = hrd->size; + const uint8_t *ptr = hrd->value; + size_t len = hrd->size; while (len > 0) { const uint8_t tag = ptr[0]; @@ -97,80 +100,113 @@ get_usage_info(const struct hidraw_report_descriptor *hrd, uint32_t *usage_page, } static int -get_report_descriptor(const char *path, struct hidraw_report_descriptor *hrd) +get_report_sizes(const struct hidraw_report_descriptor *hrd, + size_t *report_in_len, size_t *report_out_len) { - int s = -1; - int fd; - int ok = -1; + const uint8_t *ptr = hrd->value; + size_t len = hrd->size; + uint32_t report_size = 0; - if ((fd = open(path, O_RDONLY)) < 0) { - fido_log_debug("%s: open", __func__); - return (-1); + while (len > 0) { + const uint8_t tag = ptr[0]; + ptr++; + len--; + + uint8_t key; + size_t key_len; + uint32_t key_val; + + if (get_key_len(tag, &key, &key_len) < 0 || key_len > len || + get_key_val(ptr, key_len, &key_val) < 0) { + return (-1); + } + + if (key == 0x94) { + report_size = key_val; + } else if (key == 0x80) { + *report_in_len = (size_t)report_size; + } else if (key == 0x90) { + *report_out_len = (size_t)report_size; + } + + ptr += key_len; + len -= key_len; } + return (0); +} + +static int +get_report_descriptor(int fd, struct hidraw_report_descriptor *hrd) +{ + int s = -1; + if (ioctl(fd, HIDIOCGRDESCSIZE, &s) < 0 || s < 0 || (unsigned)s > HID_MAX_DESCRIPTOR_SIZE) { fido_log_debug("%s: ioctl HIDIOCGRDESCSIZE", __func__); - goto fail; + return (-1); } - hrd->size = s; + hrd->size = (unsigned)s; if (ioctl(fd, HIDIOCGRDESC, hrd) < 0) { fido_log_debug("%s: ioctl HIDIOCGRDESC", __func__); - goto fail; + return (-1); } - ok = 0; -fail: - if (fd != -1) - close(fd); - - return (ok); + return (0); } static bool is_fido(const char *path) { + int fd; uint32_t usage = 0; uint32_t usage_page = 0; struct hidraw_report_descriptor hrd; memset(&hrd, 0, sizeof(hrd)); - if (get_report_descriptor(path, &hrd) < 0 || + if ((fd = open(path, O_RDONLY)) == -1) { + fido_log_debug("%s: open", __func__); + return (false); + } + + if (get_report_descriptor(fd, &hrd) < 0 || get_usage_info(&hrd, &usage_page, &usage) < 0) { + close(fd); return (false); } + close(fd); + return (usage_page == 0xf1d0); } static int -parse_uevent(struct udev_device *dev, int16_t *vendor_id, int16_t *product_id) +parse_uevent(const char *uevent, int *bus, int16_t *vendor_id, + int16_t *product_id) { - const char *uevent; char *cp; char *p; char *s; int ok = -1; short unsigned int x; short unsigned int y; - - if ((uevent = udev_device_get_sysattr_value(dev, "uevent")) == NULL) - return (-1); + short unsigned int z; if ((s = cp = strdup(uevent)) == NULL) return (-1); - for ((p = strsep(&cp, "\n")); p && *p != '\0'; (p = strsep(&cp, "\n"))) { + while ((p = strsep(&cp, "\n")) != NULL && *p != '\0') { if (strncmp(p, "HID_ID=", 7) == 0) { - if (sscanf(p + 7, "%*x:%hx:%hx", &x, &y) == 2) { - *vendor_id = (int16_t)x; - *product_id = (int16_t)y; + if (sscanf(p + 7, "%hx:%hx:%hx", &x, &y, &z) == 3) { + *bus = (int)x; + *vendor_id = (int16_t)y; + *product_id = (int16_t)z; ok = 0; + break; } - break; } } @@ -179,17 +215,36 @@ parse_uevent(struct udev_device *dev, int16_t *vendor_id, int16_t *product_id) return (ok); } +static char * +get_parent_attr(struct udev_device *dev, const char *subsystem, + const char *devtype, const char *attr) +{ + struct udev_device *parent; + const char *value; + + 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 (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 copy_info(fido_dev_info_t *di, struct udev *udev, struct udev_list_entry *udev_entry) { const char *name; const char *path; - const char *manufacturer; - const char *product; + char *uevent = NULL; struct udev_device *dev = NULL; - struct udev_device *hid_parent; - struct udev_device *usb_parent; + int bus = 0; int ok = -1; memset(di, 0, sizeof(*di)); @@ -200,28 +255,24 @@ copy_info(fido_dev_info_t *di, struct udev *udev, is_fido(path) == 0) goto fail; - if ((hid_parent = udev_device_get_parent_with_subsystem_devtype(dev, - "hid", NULL)) == NULL) - goto fail; - - if ((usb_parent = udev_device_get_parent_with_subsystem_devtype(dev, - "usb", "usb_device")) == NULL) + if ((uevent = get_parent_attr(dev, "hid", NULL, "uevent")) == NULL || + parse_uevent(uevent, &bus, &di->vendor_id, &di->product_id) < 0) { + fido_log_debug("%s: uevent", __func__); goto fail; + } - if (parse_uevent(hid_parent, &di->vendor_id, &di->product_id) < 0 || - (manufacturer = udev_device_get_sysattr_value(usb_parent, - "manufacturer")) == NULL || - (product = udev_device_get_sysattr_value(usb_parent, - "product")) == NULL) +#ifndef FIDO_HID_ANY + if (bus != BUS_USB) { + fido_log_debug("%s: bus", __func__); goto fail; + } +#endif di->path = strdup(path); - di->manufacturer = strdup(manufacturer); - di->product = strdup(product); + di->manufacturer = get_usb_attr(dev, "manufacturer"); + di->product = get_usb_attr(dev, "product"); - if (di->path == NULL || - di->manufacturer == NULL || - di->product == NULL) + if (di->path == NULL || di->manufacturer == NULL || di->product == NULL) goto fail; ok = 0; @@ -229,6 +280,8 @@ fail: if (dev != NULL) udev_device_unref(dev); + free(uevent); + if (ok < 0) { free(di->path); free(di->manufacturer); @@ -261,9 +314,13 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) goto fail; if (udev_enumerate_add_match_subsystem(udev_enum, "hidraw") < 0 || - udev_enumerate_scan_devices(udev_enum) < 0 || - (udev_list = udev_enumerate_get_list_entry(udev_enum)) == NULL) + udev_enumerate_scan_devices(udev_enum) < 0) + goto fail; + + if ((udev_list = udev_enumerate_get_list_entry(udev_enum)) == NULL) { + r = FIDO_OK; /* zero hidraw devices */ goto fail; + } udev_list_entry_foreach(udev_entry, udev_list) { if (copy_info(&devlist[*olen], udev, udev_entry) == 0) { @@ -291,60 +348,157 @@ fail: void * fido_hid_open(const char *path) { - int *fd; + struct hid_linux *ctx; + struct hidraw_report_descriptor hrd; + + if ((ctx = calloc(1, sizeof(*ctx))) == NULL) + return (NULL); - if ((fd = malloc(sizeof(*fd))) == NULL || - (*fd = open(path, O_RDWR)) < 0) { - free(fd); + if ((ctx->fd = open(path, O_RDWR)) < 0) { + free(ctx); return (NULL); } - return (fd); + if (get_report_descriptor(ctx->fd, &hrd) < 0 || get_report_sizes(&hrd, + &ctx->report_in_len, &ctx->report_out_len) < 0 || + ctx->report_in_len == 0 || ctx->report_out_len == 0) { + fido_log_debug("%s: using default report sizes", __func__); + ctx->report_in_len = CTAP_MAX_REPORT_LEN; + ctx->report_out_len = CTAP_MAX_REPORT_LEN; + } + + return (ctx); } void fido_hid_close(void *handle) { - int *fd = handle; + struct hid_linux *ctx = handle; + + close(ctx->fd); + free(ctx); +} + +static int +timespec_to_ms(const struct timespec *ts, int upper_bound) +{ + int64_t x; + int64_t y; + + if (ts->tv_sec < 0 || ts->tv_sec > INT64_MAX / 1000LL || + ts->tv_nsec < 0 || ts->tv_nsec / 1000000LL > INT64_MAX) + return (upper_bound); + + x = ts->tv_sec * 1000LL; + y = ts->tv_nsec / 1000000LL; + + if (INT64_MAX - x < y || x + y > upper_bound) + return (upper_bound); + + return (int)(x + y); +} + +static int +waitfd(int fd, int ms) +{ + struct timespec ts_start; + struct timespec ts_now; + struct timespec ts_delta; + struct pollfd pfd; + int ms_remain; + int r; + + if (ms < 0) + return (0); + + memset(&pfd, 0, sizeof(pfd)); + pfd.events = POLLIN; + pfd.fd = fd; + + if (clock_gettime(CLOCK_MONOTONIC, &ts_start) != 0) { + fido_log_debug("%s: clock_gettime: %s", __func__, + strerror(errno)); + return (-1); + } + + for (ms_remain = ms; ms_remain > 0;) { + if ((r = poll(&pfd, 1, ms_remain)) > 0) + return (0); + else if (r == 0) + break; + else if (errno != EINTR) { + fido_log_debug("%s: poll: %s", __func__, + strerror(errno)); + return (-1); + } + /* poll interrupted - subtract time already waited */ + if (clock_gettime(CLOCK_MONOTONIC, &ts_now) != 0) { + fido_log_debug("%s: clock_gettime: %s", __func__, + strerror(errno)); + return (-1); + } + timespecsub(&ts_now, &ts_start, &ts_delta); + ms_remain = ms - timespec_to_ms(&ts_delta, ms); + } - close(*fd); - free(fd); + return (-1); } int fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) { - int *fd = handle; - ssize_t r; + struct hid_linux *ctx = handle; + ssize_t r; - (void)ms; /* XXX */ + if (len != ctx->report_in_len) { + fido_log_debug("%s: len %zu", __func__, len); + return (-1); + } - if (len != REPORT_LEN - 1) { - fido_log_debug("%s: invalid len", __func__); + if (waitfd(ctx->fd, ms) < 0) { + fido_log_debug("%s: fd not ready", __func__); return (-1); } - if ((r = read(*fd, buf, len)) < 0 || r != REPORT_LEN - 1) + if ((r = read(ctx->fd, buf, len)) < 0 || (size_t)r != len) { + fido_log_debug("%s: read", __func__); return (-1); + } - return (REPORT_LEN - 1); + return ((int)r); } int fido_hid_write(void *handle, const unsigned char *buf, size_t len) { - int *fd = handle; - ssize_t r; + struct hid_linux *ctx = handle; + ssize_t r; - if (len != REPORT_LEN) { - fido_log_debug("%s: invalid len", __func__); + if (len != ctx->report_out_len + 1) { + fido_log_debug("%s: len %zu", __func__, len); return (-1); } - if ((r = write(*fd, buf, len)) < 0 || r != REPORT_LEN) { + if ((r = write(ctx->fd, buf, len)) < 0 || (size_t)r != len) { fido_log_debug("%s: write", __func__); return (-1); } - return (REPORT_LEN); + return ((int)r); +} + +size_t +fido_hid_report_in_len(void *handle) +{ + struct hid_linux *ctx = handle; + + return (ctx->report_in_len); +} + +size_t +fido_hid_report_out_len(void *handle) +{ + struct hid_linux *ctx = handle; + + return (ctx->report_out_len); } diff --git a/src/hid_openbsd.c b/src/hid_openbsd.c index 2b31dba..319f7b8 100644 --- a/src/hid_openbsd.c +++ b/src/hid_openbsd.c @@ -8,19 +8,16 @@ #include #include -#include #include #include #include #include -#include #include #include "fido.h" #define MAX_UHID 64 -#define MAX_REPORT_LEN (sizeof(((struct usb_ctl_report *)(NULL))->ucr_data)) struct hid_openbsd { int fd; @@ -33,11 +30,8 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) { size_t i; char path[64]; - int is_fido, fd; + int fd; struct usb_device_info udi; - report_desc_t rdesc = NULL; - hid_data_t hdata = NULL; - hid_item_t hitem; fido_dev_info_t *di; if (ilen == 0) @@ -47,7 +41,7 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) return (FIDO_ERR_INVALID_ARGUMENT); for (i = *olen = 0; i < MAX_UHID && *olen < ilen; i++) { - snprintf(path, sizeof(path), "/dev/uhid%zu", i); + snprintf(path, sizeof(path), "/dev/fido/%zu", i); if ((fd = open(path, O_RDWR)) == -1) { if (errno != ENOENT && errno != ENXIO) { fido_log_debug("%s: open %s: %s", __func__, @@ -55,6 +49,7 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) } continue; } + memset(&udi, 0, sizeof(udi)); if (ioctl(fd, USB_GET_DEVICEINFO, &udi) != 0) { fido_log_debug("%s: get device info %s: %s", __func__, @@ -62,35 +57,8 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) close(fd); continue; } - if ((rdesc = hid_get_report_desc(fd)) == NULL) { - fido_log_debug("%s: failed to get report descriptor: %s", - __func__, path); - close(fd); - continue; - } - if ((hdata = hid_start_parse(rdesc, - 1<vendor_id = udi.udi_vendorNo; - di->product_id = udi.udi_productNo; + di->vendor_id = (int16_t)udi.udi_vendorNo; + di->product_id = (int16_t)udi.udi_productNo; (*olen)++; } @@ -184,42 +152,15 @@ void * fido_hid_open(const char *path) { struct hid_openbsd *ret = NULL; - report_desc_t rdesc = NULL; - int len, usb_report_id = 0; if ((ret = calloc(1, sizeof(*ret))) == NULL || (ret->fd = open(path, O_RDWR)) < 0) { free(ret); return (NULL); } - if (ioctl(ret->fd, USB_GET_REPORT_ID, &usb_report_id) != 0) { - fido_log_debug("%s: failed to get report ID: %s", __func__, - strerror(errno)); - goto fail; - } - if ((rdesc = hid_get_report_desc(ret->fd)) == NULL) { - fido_log_debug("%s: failed to get report descriptor", __func__); - goto fail; - } - if ((len = hid_report_size(rdesc, hid_input, usb_report_id)) <= 0 || - (size_t)len > MAX_REPORT_LEN) { - fido_log_debug("%s: bad input report size %d", __func__, len); - goto fail; - } - ret->report_in_len = (size_t)len; - if ((len = hid_report_size(rdesc, hid_output, usb_report_id)) <= 0 || - (size_t)len > MAX_REPORT_LEN) { - fido_log_debug("%s: bad output report size %d", __func__, len); - fail: - hid_dispose_report_desc(rdesc); - close(ret->fd); - free(ret); - return NULL; - } - ret->report_out_len = (size_t)len; - hid_dispose_report_desc(rdesc); - fido_log_debug("%s: USB report ID %d, inlen = %zu outlen = %zu", - __func__, usb_report_id, ret->report_in_len, ret->report_out_len); + ret->report_in_len = ret->report_out_len = CTAP_MAX_REPORT_LEN; + fido_log_debug("%s: inlen = %zu outlen = %zu", __func__, + ret->report_in_len, ret->report_out_len); /* * OpenBSD (as of 201910) has a bug that causes it to lose @@ -281,3 +222,19 @@ fido_hid_write(void *handle, const unsigned char *buf, size_t len) } return ((int)len); } + +size_t +fido_hid_report_in_len(void *handle) +{ + struct hid_openbsd *ctx = handle; + + return (ctx->report_in_len); +} + +size_t +fido_hid_report_out_len(void *handle) +{ + struct hid_openbsd *ctx = handle; + + return (ctx->report_out_len); +} diff --git a/src/hid_osx.c b/src/hid_osx.c index 5c40747..6be5cd7 100644 --- a/src/hid_osx.c +++ b/src/hid_osx.c @@ -19,11 +19,13 @@ #include "fido.h" -#define REPORT_LEN 65 - -struct dev { +struct hid_osx { IOHIDDeviceRef ref; CFStringRef loop_id; + int report_pipe[2]; + size_t report_in_len; + size_t report_out_len; + unsigned char report[CTAP_MAX_REPORT_LEN]; }; static int @@ -64,7 +66,8 @@ get_utf8(IOHIDDeviceRef dev, CFStringRef key, void *buf, size_t len) return (-1); } - if (CFStringGetCString(ref, buf, len, kCFStringEncodingUTF8) == false) { + if (CFStringGetCString(ref, buf, (long)len, + kCFStringEncodingUTF8) == false) { fido_log_debug("%s: CFStringGetCString", __func__); return (-1); } @@ -72,30 +75,35 @@ get_utf8(IOHIDDeviceRef dev, CFStringRef key, void *buf, size_t len) return (0); } -static bool -is_fido(IOHIDDeviceRef dev) +static int +get_report_len(IOHIDDeviceRef dev, int dir, size_t *report_len) { - uint32_t usage_page; - int32_t report_len; + CFStringRef key; + int32_t v; - if (get_int32(dev, CFSTR(kIOHIDPrimaryUsagePageKey), - (int32_t *)&usage_page) != 0 || usage_page != 0xf1d0) - return (false); + if (dir == 0) + key = CFSTR(kIOHIDMaxInputReportSizeKey); + else + key = CFSTR(kIOHIDMaxOutputReportSizeKey); - if (get_int32(dev, CFSTR(kIOHIDMaxInputReportSizeKey), - &report_len) < 0 || report_len != REPORT_LEN - 1) { - fido_log_debug("%s: unsupported report len", __func__); - return (false); + if (get_int32(dev, key, &v) < 0) { + fido_log_debug("%s: get_int32/%d", __func__, dir); + return (-1); } - return (true); + if ((*report_len = (size_t)v) > CTAP_MAX_REPORT_LEN) { + fido_log_debug("%s: report_len=%zu", __func__, *report_len); + return (-1); + } + + return (0); } static int get_id(IOHIDDeviceRef dev, int16_t *vendor_id, int16_t *product_id) { int32_t vendor; - int32_t product; + int32_t product; if (get_int32(dev, CFSTR(kIOHIDVendorIDKey), &vendor) < 0 || vendor > UINT16_MAX) { @@ -175,6 +183,31 @@ get_path(IOHIDDeviceRef dev) return (strdup(path)); } +static bool +is_fido(IOHIDDeviceRef dev) +{ + char buf[32]; + uint32_t usage_page; + + if (get_int32(dev, CFSTR(kIOHIDPrimaryUsagePageKey), + (int32_t *)&usage_page) < 0 || usage_page != 0xf1d0) + return (false); + + if (get_utf8(dev, CFSTR(kIOHIDTransportKey), buf, sizeof(buf)) < 0) { + fido_log_debug("%s: get_utf8 transport", __func__); + return (false); + } + +#ifndef FIDO_HID_ANY + if (strcasecmp(buf, "usb") != 0) { + fido_log_debug("%s: transport", __func__); + return (false); + } +#endif + + return (true); +} + static int copy_info(fido_dev_info_t *di, IOHIDDeviceRef dev) { @@ -199,11 +232,12 @@ copy_info(fido_dev_info_t *di, IOHIDDeviceRef dev) int fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) { - IOHIDManagerRef manager = NULL; - CFSetRef devset = NULL; - CFIndex devcnt; - IOHIDDeviceRef *devs = NULL; - int r = FIDO_ERR_INTERNAL; + IOHIDManagerRef manager = NULL; + CFSetRef devset = NULL; + size_t devcnt; + CFIndex n; + IOHIDDeviceRef *devs = NULL; + int r = FIDO_ERR_INTERNAL; *olen = 0; @@ -226,11 +260,13 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) goto fail; } - if ((devcnt = CFSetGetCount(devset)) < 0) { + if ((n = CFSetGetCount(devset)) < 0) { fido_log_debug("%s: CFSetGetCount", __func__); goto fail; } + devcnt = (size_t)n; + if ((devs = calloc(devcnt, sizeof(*devs))) == NULL) { fido_log_debug("%s: calloc", __func__); goto fail; @@ -238,7 +274,7 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) CFSetGetValues(devset, (void *)devs); - for (CFIndex i = 0; i < devcnt; i++) { + for (size_t i = 0; i < devcnt; i++) { if (copy_info(&devlist[*olen], devs[i]) == 0) { devlist[*olen].io = (fido_dev_io_t) { fido_hid_open, @@ -263,157 +299,258 @@ fail: return (r); } +static void +report_callback(void *context, IOReturn result, void *dev, IOHIDReportType type, + uint32_t id, uint8_t *ptr, CFIndex len) +{ + struct hid_osx *ctx = context; + ssize_t r; + + (void)dev; + + if (result != kIOReturnSuccess || type != kIOHIDReportTypeInput || + id != 0 || len < 0 || (size_t)len != ctx->report_in_len) { + fido_log_debug("%s: io error", __func__); + return; + } + + if ((r = write(ctx->report_pipe[1], ptr, (size_t)len)) < 0 || + (size_t)r != (size_t)len) { + fido_log_debug("%s: write", __func__); + return; + } +} + +static void +removal_callback(void *context, IOReturn result, void *sender) +{ + (void)context; + (void)result; + (void)sender; + + CFRunLoopStop(CFRunLoopGetMain()); +} + +static int +set_nonblock(int fd) +{ + int flags; + + if ((flags = fcntl(fd, F_GETFL)) == -1) { + fido_log_debug("%s: fcntl F_GETFL", __func__); + return (-1); + } + + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { + fido_log_debug("%s: fcntl, F_SETFL", __func__); + return (-1); + } + + return (0); +} + +static int +disable_sigpipe(int fd) +{ + int disabled = 1; + + if (fcntl(fd, F_SETNOSIGPIPE, &disabled) == -1) { + fido_log_debug("%s: fcntl F_SETNOSIGPIPE", __func__); + return (-1); + } + + return (0); +} + void * fido_hid_open(const char *path) { + struct hid_osx *ctx; io_registry_entry_t entry = MACH_PORT_NULL; - struct dev *dev = NULL; + char loop_id[32]; int ok = -1; int r; - char loop_id[32]; - if ((dev = calloc(1, sizeof(*dev))) == NULL) { + if ((ctx = calloc(1, sizeof(*ctx))) == NULL) { fido_log_debug("%s: calloc", __func__); goto fail; } + ctx->report_pipe[0] = -1; + ctx->report_pipe[1] = -1; + + if (pipe(ctx->report_pipe) == -1) { + fido_log_debug("%s: pipe", __func__); + goto fail; + } + + if (set_nonblock(ctx->report_pipe[0]) < 0 || + set_nonblock(ctx->report_pipe[1]) < 0) { + fido_log_debug("%s: set_nonblock", __func__); + goto fail; + } + + if (disable_sigpipe(ctx->report_pipe[1]) < 0) { + fido_log_debug("%s: disable_sigpipe", __func__); + goto fail; + } + if ((entry = IORegistryEntryFromPath(kIOMasterPortDefault, path)) == MACH_PORT_NULL) { fido_log_debug("%s: IORegistryEntryFromPath", __func__); goto fail; } - if ((dev->ref = IOHIDDeviceCreate(kCFAllocatorDefault, + if ((ctx->ref = IOHIDDeviceCreate(kCFAllocatorDefault, entry)) == NULL) { fido_log_debug("%s: IOHIDDeviceCreate", __func__); goto fail; } - if (IOHIDDeviceOpen(dev->ref, + if (get_report_len(ctx->ref, 0, &ctx->report_in_len) < 0 || + get_report_len(ctx->ref, 1, &ctx->report_out_len) < 0) { + fido_log_debug("%s: get_report_len", __func__); + goto fail; + } + + if (ctx->report_in_len > sizeof(ctx->report)) { + fido_log_debug("%s: report_in_len=%zu", __func__, + ctx->report_in_len); + goto fail; + } + + if (IOHIDDeviceOpen(ctx->ref, kIOHIDOptionsTypeSeizeDevice) != kIOReturnSuccess) { fido_log_debug("%s: IOHIDDeviceOpen", __func__); goto fail; } if ((r = snprintf(loop_id, sizeof(loop_id), "fido2-%p", - (void *)dev->ref)) < 0 || (size_t)r >= sizeof(loop_id)) { + (void *)ctx->ref)) < 0 || (size_t)r >= sizeof(loop_id)) { fido_log_debug("%s: snprintf", __func__); goto fail; } - if ((dev->loop_id = CFStringCreateWithCString(NULL, loop_id, + if ((ctx->loop_id = CFStringCreateWithCString(NULL, loop_id, kCFStringEncodingASCII)) == NULL) { fido_log_debug("%s: CFStringCreateWithCString", __func__); goto fail; } + IOHIDDeviceRegisterInputReportCallback(ctx->ref, ctx->report, + (long)ctx->report_in_len, &report_callback, ctx); + IOHIDDeviceRegisterRemovalCallback(ctx->ref, &removal_callback, ctx); + IOHIDDeviceScheduleWithRunLoop(ctx->ref, CFRunLoopGetMain(), + ctx->loop_id); + ok = 0; fail: if (entry != MACH_PORT_NULL) IOObjectRelease(entry); - if (ok < 0 && dev != NULL) { - if (dev->ref != NULL) - CFRelease(dev->ref); - if (dev->loop_id != NULL) - CFRelease(dev->loop_id); - free(dev); - dev = NULL; + if (ok < 0 && ctx != NULL) { + if (ctx->ref != NULL) + CFRelease(ctx->ref); + if (ctx->loop_id != NULL) + CFRelease(ctx->loop_id); + if (ctx->report_pipe[0] != -1) + close(ctx->report_pipe[0]); + if (ctx->report_pipe[1] != -1) + close(ctx->report_pipe[1]); + free(ctx); + ctx = NULL; } - return (dev); + return (ctx); } void fido_hid_close(void *handle) { - struct dev *dev = handle; + struct hid_osx *ctx = handle; + + IOHIDDeviceRegisterInputReportCallback(ctx->ref, ctx->report, + (long)ctx->report_in_len, NULL, ctx); + IOHIDDeviceRegisterRemovalCallback(ctx->ref, NULL, NULL); + IOHIDDeviceUnscheduleFromRunLoop(ctx->ref, CFRunLoopGetMain(), + ctx->loop_id); - if (IOHIDDeviceClose(dev->ref, + if (IOHIDDeviceClose(ctx->ref, kIOHIDOptionsTypeSeizeDevice) != kIOReturnSuccess) fido_log_debug("%s: IOHIDDeviceClose", __func__); - CFRelease(dev->ref); - CFRelease(dev->loop_id); - - free(dev); -} + CFRelease(ctx->ref); + CFRelease(ctx->loop_id); -static void -read_callback(void *context, IOReturn result, void *dev, IOHIDReportType type, - uint32_t report_id, uint8_t *report, CFIndex report_len) -{ - (void)context; - (void)dev; - (void)report; + explicit_bzero(ctx->report, sizeof(ctx->report)); + close(ctx->report_pipe[0]); + close(ctx->report_pipe[1]); - if (result != kIOReturnSuccess || type != kIOHIDReportTypeInput || - report_id != 0 || report_len != REPORT_LEN - 1) { - fido_log_debug("%s: io error", __func__); - } -} - -static void -removal_callback(void *context, IOReturn result, void *sender) -{ - (void)context; - (void)result; - (void)sender; - - CFRunLoopStop(CFRunLoopGetCurrent()); + free(ctx); } int fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) { - struct dev *dev = handle; - CFRunLoopRunResult r; + struct hid_osx *ctx = handle; + ssize_t r; - (void)ms; /* XXX */ + explicit_bzero(buf, len); + explicit_bzero(ctx->report, sizeof(ctx->report)); - if (len != REPORT_LEN - 1) { - fido_log_debug("%s: invalid len", __func__); + if (len != ctx->report_in_len || len > sizeof(ctx->report)) { + fido_log_debug("%s: len %zu", __func__, len); return (-1); } - explicit_bzero(buf, len); - - IOHIDDeviceRegisterInputReportCallback(dev->ref, buf, len, - &read_callback, NULL); - IOHIDDeviceRegisterRemovalCallback(dev->ref, &removal_callback, dev); - IOHIDDeviceScheduleWithRunLoop(dev->ref, CFRunLoopGetCurrent(), - dev->loop_id); + if (ms == -1) + ms = 5000; /* wait 5 seconds by default */ - r = CFRunLoopRunInMode(dev->loop_id, 0.3, true); + if (CFRunLoopGetCurrent() != CFRunLoopGetMain()) + fido_log_debug("%s: CFRunLoopGetCurrent != CFRunLoopGetMain", + __func__); - IOHIDDeviceRegisterInputReportCallback(dev->ref, buf, len, NULL, NULL); - IOHIDDeviceRegisterRemovalCallback(dev->ref, NULL, NULL); - IOHIDDeviceUnscheduleFromRunLoop(dev->ref, CFRunLoopGetCurrent(), - dev->loop_id); + CFRunLoopRunInMode(ctx->loop_id, (double)ms/1000.0, true); - if (r != kCFRunLoopRunHandledSource) { - fido_log_debug("%s: CFRunLoopRunInMode=%d", __func__, (int)r); + if ((r = read(ctx->report_pipe[0], buf, len)) < 0 || (size_t)r != len) { + fido_log_debug("%s: read", __func__); return (-1); } - return (REPORT_LEN - 1); + return ((int)len); } int fido_hid_write(void *handle, const unsigned char *buf, size_t len) { - struct dev *dev = handle; + struct hid_osx *ctx = handle; - if (len != REPORT_LEN) { - fido_log_debug("%s: invalid len", __func__); + if (len != ctx->report_out_len + 1 || len > LONG_MAX) { + fido_log_debug("%s: len %zu", __func__, len); return (-1); } - if (IOHIDDeviceSetReport(dev->ref, kIOHIDReportTypeOutput, 0, buf + 1, - len - 1) != kIOReturnSuccess) { + if (IOHIDDeviceSetReport(ctx->ref, kIOHIDReportTypeOutput, 0, buf + 1, + (long)(len - 1)) != kIOReturnSuccess) { fido_log_debug("%s: IOHIDDeviceSetReport", __func__); return (-1); } - return (REPORT_LEN); + return ((int)len); +} + +size_t +fido_hid_report_in_len(void *handle) +{ + struct hid_osx *ctx = handle; + + return (ctx->report_in_len); +} + +size_t +fido_hid_report_out_len(void *handle) +{ + struct hid_osx *ctx = handle; + + return (ctx->report_out_len); } diff --git a/src/hid_win.c b/src/hid_win.c index f970589..018b4d9 100644 --- a/src/hid_win.c +++ b/src/hid_win.c @@ -14,19 +14,39 @@ #include #include #include +#include +#include #include #include #include "fido.h" -#define REPORT_LEN 65 +#if defined(__MINGW32__) && __MINGW64_VERSION_MAJOR < 6 +WINSETUPAPI WINBOOL WINAPI SetupDiGetDevicePropertyW(HDEVINFO, + PSP_DEVINFO_DATA, const DEVPROPKEY *, DEVPROPTYPE *, PBYTE, + DWORD, PDWORD, DWORD); +#endif + +#if defined(__MINGW32__) +DEFINE_DEVPROPKEY(DEVPKEY_Device_Parent, 0x4340a6c5, 0x93fa, 0x4706, 0x97, + 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 8); +#endif + +struct hid_win { + HANDLE dev; + OVERLAPPED overlap; + int report_pending; + size_t report_in_len; + size_t report_out_len; + unsigned char report[1 + CTAP_MAX_REPORT_LEN]; +}; static bool is_fido(HANDLE dev) { PHIDP_PREPARSED_DATA data = NULL; HIDP_CAPS caps; - uint16_t usage_page = 0; + int fido = 0; if (HidD_GetPreparsedData(dev, &data) == false) { fido_log_debug("%s: HidD_GetPreparsedData", __func__); @@ -38,18 +58,48 @@ is_fido(HANDLE dev) goto fail; } - if (caps.OutputReportByteLength != REPORT_LEN || - caps.InputReportByteLength != REPORT_LEN) { - fido_log_debug("%s: unsupported report len", __func__); + fido = (uint16_t)caps.UsagePage == 0xf1d0; +fail: + if (data != NULL) + HidD_FreePreparsedData(data); + + return (fido); +} + +static int +get_report_len(HANDLE dev, int dir, size_t *report_len) +{ + PHIDP_PREPARSED_DATA data = NULL; + HIDP_CAPS caps; + USHORT v; + int ok = -1; + + if (HidD_GetPreparsedData(dev, &data) == false) { + fido_log_debug("%s: HidD_GetPreparsedData/%d", __func__, dir); goto fail; } - usage_page = caps.UsagePage; + if (HidP_GetCaps(data, &caps) != HIDP_STATUS_SUCCESS) { + fido_log_debug("%s: HidP_GetCaps/%d", __func__, dir); + goto fail; + } + + if (dir == 0) + v = caps.InputReportByteLength; + else + v = caps.OutputReportByteLength; + + if ((*report_len = (size_t)v) == 0) { + fido_log_debug("%s: report_len == 0", __func__); + goto fail; + } + + ok = 0; fail: if (data != NULL) HidD_FreePreparsedData(data); - return (usage_page == 0xf1d0); + return (ok); } static int @@ -59,13 +109,14 @@ get_int(HANDLE dev, int16_t *vendor_id, int16_t *product_id) attr.Size = sizeof(attr); - if (HidD_GetAttributes(dev, &attr) == false) { + if (HidD_GetAttributes(dev, &attr) == false || + attr.VendorID > INT16_MAX || attr.ProductID > INT16_MAX) { fido_log_debug("%s: HidD_GetAttributes", __func__); return (-1); } - *vendor_id = attr.VendorID; - *product_id = attr.ProductID; + *vendor_id = (int16_t)attr.VendorID; + *product_id = (int16_t)attr.ProductID; return (0); } @@ -91,7 +142,7 @@ get_str(HANDLE dev, char **manufacturer, char **product) goto fail; } - if ((*manufacturer = malloc(utf8_len)) == NULL) { + if ((*manufacturer = malloc((size_t)utf8_len)) == NULL) { fido_log_debug("%s: malloc", __func__); goto fail; } @@ -113,7 +164,7 @@ get_str(HANDLE dev, char **manufacturer, char **product) goto fail; } - if ((*product = malloc(utf8_len)) == NULL) { + if ((*product = malloc((size_t)utf8_len)) == NULL) { fido_log_debug("%s: malloc", __func__); goto fail; } @@ -136,25 +187,138 @@ fail: return (ok); } +static char * +get_path(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *ifdata) +{ + SP_DEVICE_INTERFACE_DETAIL_DATA_A *ifdetail = NULL; + char *path = NULL; + DWORD len = 0; + + /* + * "Get the required buffer size. Call SetupDiGetDeviceInterfaceDetail + * with a NULL DeviceInterfaceDetailData pointer, a + * DeviceInterfaceDetailDataSize of zero, and a valid RequiredSize + * variable. In response to such a call, this function returns the + * required buffer size at RequiredSize and fails with GetLastError + * returning ERROR_INSUFFICIENT_BUFFER." + */ + if (SetupDiGetDeviceInterfaceDetailA(devinfo, ifdata, NULL, 0, &len, + NULL) != false || GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + fido_log_debug("%s: SetupDiGetDeviceInterfaceDetailA 1", + __func__); + goto fail; + } + + if ((ifdetail = malloc(len)) == NULL) { + fido_log_debug("%s: malloc", __func__); + goto fail; + } + + ifdetail->cbSize = sizeof(*ifdetail); + + if (SetupDiGetDeviceInterfaceDetailA(devinfo, ifdata, ifdetail, len, + NULL, NULL) == false) { + fido_log_debug("%s: SetupDiGetDeviceInterfaceDetailA 2", + __func__); + goto fail; + } + + if ((path = strdup(ifdetail->DevicePath)) == NULL) { + fido_log_debug("%s: strdup", __func__); + goto fail; + } + +fail: + free(ifdetail); + + return (path); +} + +#ifndef FIDO_HID_ANY +static bool +hid_ok(HDEVINFO devinfo, DWORD idx) +{ + SP_DEVINFO_DATA devinfo_data; + wchar_t *parent = NULL; + DWORD parent_type = DEVPROP_TYPE_STRING; + DWORD len = 0; + bool ok = false; + + memset(&devinfo_data, 0, sizeof(devinfo_data)); + devinfo_data.cbSize = sizeof(devinfo_data); + + if (SetupDiEnumDeviceInfo(devinfo, idx, &devinfo_data) == false) { + fido_log_debug("%s: SetupDiEnumDeviceInfo", __func__); + goto fail; + } + + if (SetupDiGetDevicePropertyW(devinfo, &devinfo_data, + &DEVPKEY_Device_Parent, &parent_type, NULL, 0, &len, 0) != false || + GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + fido_log_debug("%s: SetupDiGetDevicePropertyW 1", __func__); + goto fail; + } + + if ((parent = malloc(len)) == NULL) { + fido_log_debug("%s: malloc", __func__); + goto fail; + } + + if (SetupDiGetDevicePropertyW(devinfo, &devinfo_data, + &DEVPKEY_Device_Parent, &parent_type, (PBYTE)parent, len, NULL, + 0) == false) { + fido_log_debug("%s: SetupDiGetDevicePropertyW 2", __func__); + goto fail; + } + + ok = wcsncmp(parent, L"USB\\", 4) == 0; +fail: + free(parent); + + return (ok); +} +#endif + static int -copy_info(fido_dev_info_t *di, const char *path) +copy_info(fido_dev_info_t *di, HDEVINFO devinfo, DWORD idx, + SP_DEVICE_INTERFACE_DATA *ifdata) { HANDLE dev = INVALID_HANDLE_VALUE; int ok = -1; memset(di, 0, sizeof(*di)); - dev = CreateFileA(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (dev == INVALID_HANDLE_VALUE || is_fido(dev) == 0) + if ((di->path = get_path(devinfo, ifdata)) == NULL) { + fido_log_debug("%s: get_path", __func__); goto fail; + } - if (get_int(dev, &di->vendor_id, &di->product_id) < 0 || - get_str(dev, &di->manufacturer, &di->product) < 0) + fido_log_debug("%s: path=%s", __func__, di->path); + +#ifndef FIDO_HID_ANY + if (hid_ok(devinfo, idx) == false) { + fido_log_debug("%s: hid_ok", __func__); goto fail; + } +#endif - if ((di->path = strdup(path)) == NULL) + dev = CreateFileA(di->path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (dev == INVALID_HANDLE_VALUE) { + fido_log_debug("%s: CreateFileA", __func__); goto fail; + } + + if (is_fido(dev) == false) { + fido_log_debug("%s: is_fido", __func__); + goto fail; + } + + if (get_int(dev, &di->vendor_id, &di->product_id) < 0 || + get_str(dev, &di->manufacturer, &di->product) < 0) { + fido_log_debug("%s: get_int/get_str", __func__); + goto fail; + } ok = 0; fail: @@ -174,66 +338,30 @@ fail: int fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) { - GUID hid_guid = GUID_DEVINTERFACE_HID; - HDEVINFO devinfo = INVALID_HANDLE_VALUE; - SP_DEVICE_INTERFACE_DATA ifdata; - SP_DEVICE_INTERFACE_DETAIL_DATA_A *ifdetail = NULL; - DWORD len = 0; - DWORD idx = 0; - int r = FIDO_ERR_INTERNAL; + GUID hid_guid = GUID_DEVINTERFACE_HID; + HDEVINFO devinfo = INVALID_HANDLE_VALUE; + SP_DEVICE_INTERFACE_DATA ifdata; + DWORD idx; + int r = FIDO_ERR_INTERNAL; *olen = 0; if (ilen == 0) return (FIDO_OK); /* nothing to do */ - if (devlist == NULL) return (FIDO_ERR_INVALID_ARGUMENT); - devinfo = SetupDiGetClassDevsA(&hid_guid, NULL, NULL, - DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); - if (devinfo == INVALID_HANDLE_VALUE) { + if ((devinfo = SetupDiGetClassDevsA(&hid_guid, NULL, NULL, + DIGCF_DEVICEINTERFACE | DIGCF_PRESENT)) == INVALID_HANDLE_VALUE) { fido_log_debug("%s: SetupDiGetClassDevsA", __func__); goto fail; } ifdata.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); - while (SetupDiEnumDeviceInterfaces(devinfo, NULL, &hid_guid, idx++, - &ifdata) == true) { - /* - * "Get the required buffer size. Call - * SetupDiGetDeviceInterfaceDetail with a NULL - * DeviceInterfaceDetailData pointer, a - * DeviceInterfaceDetailDataSize of zero, and a valid - * RequiredSize variable. In response to such a call, this - * function returns the required buffer size at RequiredSize - * and fails with GetLastError returning - * ERROR_INSUFFICIENT_BUFFER." - */ - if (SetupDiGetDeviceInterfaceDetailA(devinfo, &ifdata, NULL, 0, - &len, NULL) != false || - GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - fido_log_debug("%s: SetupDiGetDeviceInterfaceDetailA 1", - __func__); - goto fail; - } - - if ((ifdetail = malloc(len)) == NULL) { - fido_log_debug("%s: malloc", __func__); - goto fail; - } - - ifdetail->cbSize = sizeof(*ifdetail); - - if (SetupDiGetDeviceInterfaceDetailA(devinfo, &ifdata, ifdetail, - len, NULL, NULL) == false) { - fido_log_debug("%s: SetupDiGetDeviceInterfaceDetailA 2", - __func__); - goto fail; - } - - if (copy_info(&devlist[*olen], ifdetail->DevicePath) == 0) { + for (idx = 0; SetupDiEnumDeviceInterfaces(devinfo, NULL, &hid_guid, + idx, &ifdata) == true; idx++) { + if (copy_info(&devlist[*olen], devinfo, idx, &ifdata) == 0) { devlist[*olen].io = (fido_dev_io_t) { fido_hid_open, fido_hid_close, @@ -243,9 +371,6 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) if (++(*olen) == ilen) break; } - - free(ifdetail); - ifdetail = NULL; } r = FIDO_OK; @@ -253,78 +378,153 @@ fail: if (devinfo != INVALID_HANDLE_VALUE) SetupDiDestroyDeviceInfoList(devinfo); - free(ifdetail); - return (r); } void * fido_hid_open(const char *path) { - HANDLE dev; + struct hid_win *ctx; + + if ((ctx = calloc(1, sizeof(*ctx))) == NULL) + return (NULL); - dev = CreateFileA(path, GENERIC_READ | GENERIC_WRITE, + ctx->dev = CreateFileA(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL); + FILE_FLAG_OVERLAPPED, NULL); + + if (ctx->dev == INVALID_HANDLE_VALUE) { + free(ctx); + return (NULL); + } - if (dev == INVALID_HANDLE_VALUE) + if ((ctx->overlap.hEvent = CreateEventA(NULL, FALSE, FALSE, + NULL)) == NULL) { + fido_log_debug("%s: CreateEventA", __func__); + fido_hid_close(ctx); return (NULL); + } - return (dev); + if (get_report_len(ctx->dev, 0, &ctx->report_in_len) < 0 || + get_report_len(ctx->dev, 1, &ctx->report_out_len) < 0) { + fido_log_debug("%s: get_report_len", __func__); + fido_hid_close(ctx); + return (NULL); + } + + return (ctx); } void fido_hid_close(void *handle) { - CloseHandle(handle); + struct hid_win *ctx = handle; + + if (ctx->overlap.hEvent != NULL) { + if (ctx->report_pending) { + fido_log_debug("%s: report_pending", __func__); + CancelIo(ctx->dev); + } + CloseHandle(ctx->overlap.hEvent); + } + + explicit_bzero(ctx->report, sizeof(ctx->report)); + CloseHandle(ctx->dev); + free(ctx); } int fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) { - DWORD n; - int r = -1; - uint8_t report[REPORT_LEN]; + struct hid_win *ctx = handle; + DWORD n; - (void)ms; /* XXX */ + if (len != ctx->report_in_len - 1 || len > sizeof(ctx->report) - 1) { + fido_log_debug("%s: len %zu", __func__, len); + return (-1); + } + + if (ctx->report_pending == 0) { + memset(&ctx->report, 0, sizeof(ctx->report)); + ResetEvent(ctx->overlap.hEvent); + if (ReadFile(ctx->dev, ctx->report, (DWORD)(len + 1), &n, + &ctx->overlap) == 0 && GetLastError() != ERROR_IO_PENDING) { + CancelIo(ctx->dev); + fido_log_debug("%s: ReadFile", __func__); + return (-1); + } + ctx->report_pending = 1; + } - memset(report, 0, sizeof(report)); + if (ms > -1 && WaitForSingleObject(ctx->overlap.hEvent, + (DWORD)ms) != WAIT_OBJECT_0) + return (0); - if (len != sizeof(report) - 1) { - fido_log_debug("%s: invalid len", __func__); + ctx->report_pending = 0; + + if (GetOverlappedResult(ctx->dev, &ctx->overlap, &n, TRUE) == 0) { + fido_log_debug("%s: GetOverlappedResult", __func__); return (-1); } - if (ReadFile(handle, report, sizeof(report), &n, NULL) == false || - n != sizeof(report)) { - fido_log_debug("%s: ReadFile", __func__); - goto fail; + if (n != len + 1) { + fido_log_debug("%s: expected %zu, got %zu", __func__, + len + 1, (size_t)n); + return (-1); } - r = sizeof(report) - 1; - memcpy(buf, report + 1, len); - -fail: - explicit_bzero(report, sizeof(report)); + memcpy(buf, ctx->report + 1, len); + explicit_bzero(ctx->report, sizeof(ctx->report)); - return (r); + return ((int)len); } int fido_hid_write(void *handle, const unsigned char *buf, size_t len) { - DWORD n; + struct hid_win *ctx = handle; + OVERLAPPED overlap; + DWORD n; + + memset(&overlap, 0, sizeof(overlap)); - if (len != REPORT_LEN) { - fido_log_debug("%s: invalid len", __func__); + if (len != ctx->report_out_len) { + fido_log_debug("%s: len %zu", __func__, len); return (-1); } - if (WriteFile(handle, buf, (DWORD)len, &n, NULL) == false || - n != REPORT_LEN) { + if (WriteFile(ctx->dev, buf, (DWORD)len, NULL, &overlap) == 0 && + GetLastError() != ERROR_IO_PENDING) { fido_log_debug("%s: WriteFile", __func__); return (-1); } - return (REPORT_LEN); + if (GetOverlappedResult(ctx->dev, &overlap, &n, TRUE) == 0) { + fido_log_debug("%s: GetOverlappedResult", __func__); + return (-1); + } + + if (n != len) { + fido_log_debug("%s: expected %zu, got %zu", __func__, len, + (size_t)n); + return (-1); + } + + return ((int)len); +} + +size_t +fido_hid_report_in_len(void *handle) +{ + struct hid_win *ctx = handle; + + return (ctx->report_in_len - 1); +} + +size_t +fido_hid_report_out_len(void *handle) +{ + struct hid_win *ctx = handle; + + return (ctx->report_out_len - 1); } diff --git a/src/info.c b/src/info.c index 8e256fa..3199ac2 100644 --- a/src/info.c +++ b/src/info.c @@ -217,6 +217,10 @@ parse_reply_element(const cbor_item_t *key, const cbor_item_t *val, void *arg) return (cbor_decode_uint64(val, &ci->maxmsgsiz)); case 6: /* pinProtocols */ return (decode_protocols(val, &ci->protocols)); + case 7: /* maxCredentialCountInList */ + return (cbor_decode_uint64(val, &ci->maxcredcntlst)); + case 8: /* maxCredentialIdLength */ + return (cbor_decode_uint64(val, &ci->maxcredidlen)); case 14: /* fwVersion */ return (cbor_decode_uint64(val, &ci->fwversion)); default: /* ignore */ @@ -398,6 +402,18 @@ fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *ci) return (ci->maxmsgsiz); } +uint64_t +fido_cbor_info_maxcredcntlst(const fido_cbor_info_t *ci) +{ + return (ci->maxcredcntlst); +} + +uint64_t +fido_cbor_info_maxcredidlen(const fido_cbor_info_t *ci) +{ + return (ci->maxcredidlen); +} + uint64_t fido_cbor_info_fwversion(const fido_cbor_info_t *ci) { diff --git a/src/io.c b/src/io.c index af2f49a..9d2de88 100644 --- a/src/io.c +++ b/src/io.c @@ -20,11 +20,11 @@ struct frame { uint8_t cmd; uint8_t bcnth; uint8_t bcntl; - uint8_t data[CTAP_RPT_SIZE - 7]; + uint8_t data[CTAP_MAX_REPORT_LEN - CTAP_INIT_HEADER_LEN]; } init; struct { uint8_t seq; - uint8_t data[CTAP_RPT_SIZE - 5]; + uint8_t data[CTAP_MAX_REPORT_LEN - CTAP_CONT_HEADER_LEN]; } cont; } body; }) @@ -38,6 +38,7 @@ tx_empty(fido_dev_t *d, uint8_t cmd) { struct frame *fp; unsigned char pkt[sizeof(*fp) + 1]; + const size_t len = d->tx_len + 1; int n; memset(&pkt, 0, sizeof(pkt)); @@ -45,8 +46,8 @@ tx_empty(fido_dev_t *d, uint8_t cmd) fp->cid = d->cid; fp->body.init.cmd = CTAP_FRAME_INIT | cmd; - n = d->io.write(d->io_handle, pkt, sizeof(pkt)); - if (n < 0 || (size_t)n != sizeof(pkt)) + if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt, + len)) < 0 || (size_t)n != len) return (-1); return (0); @@ -57,19 +58,23 @@ tx_preamble(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count) { struct frame *fp; unsigned char pkt[sizeof(*fp) + 1]; + const size_t len = d->tx_len + 1; int n; + if (d->tx_len - CTAP_INIT_HEADER_LEN > sizeof(fp->body.init.data)) + return (0); + memset(&pkt, 0, sizeof(pkt)); fp = (struct frame *)(pkt + 1); fp->cid = d->cid; fp->body.init.cmd = CTAP_FRAME_INIT | cmd; fp->body.init.bcnth = (count >> 8) & 0xff; fp->body.init.bcntl = count & 0xff; - count = MIN(count, sizeof(fp->body.init.data)); + count = MIN(count, d->tx_len - CTAP_INIT_HEADER_LEN); memcpy(&fp->body.init.data, buf, count); - n = d->io.write(d->io_handle, pkt, sizeof(pkt)); - if (n < 0 || (size_t)n != sizeof(pkt)) + if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt, + len)) < 0 || (size_t)n != len) return (0); return (count); @@ -80,17 +85,21 @@ tx_frame(fido_dev_t *d, uint8_t seq, const void *buf, size_t count) { struct frame *fp; unsigned char pkt[sizeof(*fp) + 1]; + const size_t len = d->tx_len + 1; int n; + if (d->tx_len - CTAP_CONT_HEADER_LEN > sizeof(fp->body.cont.data)) + return (0); + memset(&pkt, 0, sizeof(pkt)); fp = (struct frame *)(pkt + 1); fp->cid = d->cid; fp->body.cont.seq = seq; - count = MIN(count, sizeof(fp->body.cont.data)); + count = MIN(count, d->tx_len - CTAP_CONT_HEADER_LEN); memcpy(&fp->body.cont.data, buf, count); - n = d->io.write(d->io_handle, pkt, sizeof(pkt)); - if (n < 0 || (size_t)n != sizeof(pkt)) + if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt, + len)) < 0 || (size_t)n != len) return (0); return (count); @@ -129,16 +138,12 @@ fido_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count) if (d->transport.tx != NULL) return (d->transport.tx(d, cmd, buf, count)); - if (d->io_handle == NULL || d->io.write == NULL || count > UINT16_MAX) { fido_log_debug("%s: invalid argument", __func__); return (-1); } - if (count == 0) - return (tx_empty(d, cmd)); - - return (tx(d, cmd, buf, count)); + return (count == 0 ? tx_empty(d, cmd) : tx(d, cmd, buf, count)); } static int @@ -146,8 +151,10 @@ rx_frame(fido_dev_t *d, struct frame *fp, int ms) { int n; - n = d->io.read(d->io_handle, (unsigned char *)fp, sizeof(*fp), ms); - if (n < 0 || (size_t)n != sizeof(*fp)) + memset(fp, 0, sizeof(*fp)); + + if (d->rx_len > sizeof(*fp) || (n = d->io.read(d->io_handle, + (unsigned char *)fp, d->rx_len, ms)) < 0 || (size_t)n != d->rx_len) return (-1); return (0); @@ -165,8 +172,11 @@ rx_preamble(fido_dev_t *d, uint8_t cmd, struct frame *fp, int ms) } while (fp->cid == d->cid && fp->body.init.cmd == (CTAP_FRAME_INIT | CTAP_KEEPALIVE)); + if (d->rx_len > sizeof(*fp)) + return (-1); + fido_log_debug("%s: initiation frame at %p", __func__, (void *)fp); - fido_log_xxd(fp, sizeof(*fp)); + fido_log_xxd(fp, d->rx_len); #ifdef FIDO_FUZZ fp->body.init.cmd = (CTAP_FRAME_INIT | cmd); @@ -185,30 +195,41 @@ static int rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms) { struct frame f; - uint16_t r, payload_len; + size_t r, payload_len, init_data_len, cont_data_len; + + if (d->rx_len <= CTAP_INIT_HEADER_LEN || + d->rx_len <= CTAP_CONT_HEADER_LEN) + return (-1); + + init_data_len = d->rx_len - CTAP_INIT_HEADER_LEN; + cont_data_len = d->rx_len - CTAP_CONT_HEADER_LEN; + + if (init_data_len > sizeof(f.body.init.data) || + cont_data_len > sizeof(f.body.cont.data)) + return (-1); if (rx_preamble(d, cmd, &f, ms) < 0) { fido_log_debug("%s: rx_preamble", __func__); return (-1); } - payload_len = (f.body.init.bcnth << 8) | f.body.init.bcntl; - fido_log_debug("%s: payload_len=%zu", __func__, (size_t)payload_len); + payload_len = (size_t)((f.body.init.bcnth << 8) | f.body.init.bcntl); + fido_log_debug("%s: payload_len=%zu", __func__, payload_len); - if (count < (size_t)payload_len) { + if (count < payload_len) { fido_log_debug("%s: count < payload_len", __func__); return (-1); } - if (payload_len < sizeof(f.body.init.data)) { + if (payload_len < init_data_len) { memcpy(buf, f.body.init.data, payload_len); - return (payload_len); + return ((int)payload_len); } - memcpy(buf, f.body.init.data, sizeof(f.body.init.data)); - r = sizeof(f.body.init.data); + memcpy(buf, f.body.init.data, init_data_len); + r = init_data_len; - for (int seq = 0; (size_t)r < payload_len; seq++) { + for (int seq = 0; r < payload_len; seq++) { if (rx_frame(d, &f, ms) < 0) { fido_log_debug("%s: rx_frame", __func__); return (-1); @@ -216,11 +237,11 @@ rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms) fido_log_debug("%s: continuation frame at %p", __func__, (void *)&f); - fido_log_xxd(&f, sizeof(f)); + fido_log_xxd(&f, d->rx_len); #ifdef FIDO_FUZZ f.cid = d->cid; - f.body.cont.seq = seq; + f.body.cont.seq = (uint8_t)seq; #endif if (f.cid != d->cid || f.body.cont.seq != seq) { @@ -229,17 +250,16 @@ rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms) return (-1); } - if ((size_t)(payload_len - r) > sizeof(f.body.cont.data)) { - memcpy(buf + r, f.body.cont.data, - sizeof(f.body.cont.data)); - r += sizeof(f.body.cont.data); + if (payload_len - r > cont_data_len) { + memcpy(buf + r, f.body.cont.data, cont_data_len); + r += cont_data_len; } else { memcpy(buf + r, f.body.cont.data, payload_len - r); - r += (payload_len - r); /* break */ + r += payload_len - r; /* break */ } } - return (r); + return ((int)r); } int @@ -252,15 +272,13 @@ fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int ms) if (d->transport.rx != NULL) return (d->transport.rx(d, cmd, buf, count, ms)); - if (d->io_handle == NULL || d->io.read == NULL || count > UINT16_MAX) { fido_log_debug("%s: invalid argument", __func__); return (-1); } - if ((n = rx(d, cmd, buf, count, ms)) >= 0) { fido_log_debug("%s: buf=%p, len=%d", __func__, (void *)buf, n); - fido_log_xxd(buf, n); + fido_log_xxd(buf, (size_t)n); } return (n); diff --git a/src/iso7816.c b/src/iso7816.c index a3fd280..4fe6329 100644 --- a/src/iso7816.c +++ b/src/iso7816.c @@ -23,8 +23,8 @@ iso7816_new(uint8_t ins, uint8_t p1, uint16_t payload_len) apdu->payload_ptr = apdu->payload; apdu->header.ins = ins; apdu->header.p1 = p1; - apdu->header.lc2 = (payload_len >> 8) & 0xff; - apdu->header.lc3 = payload_len & 0xff; + apdu->header.lc2 = (uint8_t)((payload_len >> 8) & 0xff); + apdu->header.lc3 = (uint8_t)(payload_len & 0xff); return (apdu); } @@ -51,7 +51,7 @@ iso7816_add(iso7816_apdu_t *apdu, const void *buf, size_t cnt) memcpy(apdu->payload_ptr, buf, cnt); apdu->payload_ptr += cnt; - apdu->payload_len -= (uint16_t)cnt; + apdu->payload_len = (uint16_t)(apdu->payload_len - cnt); return (0); } diff --git a/src/pin.c b/src/pin.c index 36acbe4..8b23ae3 100644 --- a/src/pin.c +++ b/src/pin.c @@ -53,7 +53,7 @@ fido_dev_get_pin_token_tx(fido_dev_t *dev, const char *pin, if ((argv[0] = cbor_build_uint8(1)) == NULL || (argv[1] = cbor_build_uint8(5)) == NULL || - (argv[2] = es256_pk_encode(pk, 0)) == NULL || + (argv[2] = es256_pk_encode(pk, 1)) == NULL || (argv[5] = cbor_encode_pin_hash_enc(ecdh, p)) == NULL) { fido_log_debug("%s: cbor encode", __func__); r = FIDO_ERR_INTERNAL; @@ -89,7 +89,7 @@ fido_dev_get_uv_token_tx(fido_dev_t *dev, const es256_pk_t *pk) if ((argv[0] = cbor_build_uint8(1)) == NULL || (argv[1] = cbor_build_uint8(6)) == NULL || - (argv[2] = es256_pk_encode(pk, 0)) == NULL) { + (argv[2] = es256_pk_encode(pk, 1)) == NULL) { fido_log_debug("%s: cbor encode", __func__); r = FIDO_ERR_INTERNAL; goto fail; @@ -240,7 +240,7 @@ pad64(const char *pin, fido_blob_t **ppin) if ((*ppin = fido_blob_new()) == NULL) return (FIDO_ERR_INTERNAL); - ppin_len = (pin_len + 63) & ~63; + ppin_len = (pin_len + 63U) & ~63U; if (ppin_len < pin_len || ((*ppin)->ptr = calloc(1, ppin_len)) == NULL) { fido_blob_free(ppin); return (FIDO_ERR_INTERNAL); @@ -285,7 +285,7 @@ fido_dev_change_pin_tx(fido_dev_t *dev, const char *pin, const char *oldpin) if ((argv[0] = cbor_build_uint8(1)) == NULL || (argv[1] = cbor_build_uint8(4)) == NULL || - (argv[2] = es256_pk_encode(pk, 0)) == NULL || + (argv[2] = es256_pk_encode(pk, 1)) == NULL || (argv[3] = cbor_encode_change_pin_auth(ecdh, ppin, opin)) == NULL || (argv[4] = cbor_encode_pin_enc(ecdh, ppin)) == NULL || (argv[5] = cbor_encode_pin_hash_enc(ecdh, opin)) == NULL) { @@ -339,7 +339,7 @@ fido_dev_set_pin_tx(fido_dev_t *dev, const char *pin) if ((argv[0] = cbor_build_uint8(1)) == NULL || (argv[1] = cbor_build_uint8(3)) == NULL || - (argv[2] = es256_pk_encode(pk, 0)) == NULL || + (argv[2] = es256_pk_encode(pk, 1)) == NULL || (argv[3] = cbor_encode_set_pin_auth(ecdh, ppin)) == NULL || (argv[4] = cbor_encode_pin_enc(ecdh, ppin)) == NULL) { fido_log_debug("%s: cbor encode", __func__); diff --git a/src/u2f.c b/src/u2f.c index 19a959d..3c6ea82 100644 --- a/src/u2f.c +++ b/src/u2f.c @@ -122,6 +122,7 @@ authdata_fake(const char *rp_id, uint8_t flags, uint32_t sigcount, return (0); } +/* TODO: use u2f_get_touch_begin & u2f_get_touch_status instead */ static int send_dummy_register(fido_dev_t *dev, int ms) { @@ -160,7 +161,7 @@ send_dummy_register(fido_dev_t *dev, int ms) r = FIDO_ERR_RX; goto fail; } - if (usleep((ms == -1 ? 100 : ms) * 1000) < 0) { + if (usleep((unsigned)(ms == -1 ? 100 : ms) * 1000) < 0) { fido_log_debug("%s: usleep", __func__); r = FIDO_ERR_RX; goto fail; @@ -204,8 +205,8 @@ key_lookup(fido_dev_t *dev, const char *rp_id, const fido_blob_t *key_id, key_id_len = (uint8_t)key_id->len; - if ((apdu = iso7816_new(U2F_CMD_AUTH, U2F_AUTH_CHECK, 2 * - SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len)) == NULL || + if ((apdu = iso7816_new(U2F_CMD_AUTH, U2F_AUTH_CHECK, (uint16_t)(2 * + SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len))) == NULL || iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 || iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 || iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 || @@ -312,8 +313,8 @@ do_auth(fido_dev_t *dev, const fido_blob_t *cdh, const char *rp_id, key_id_len = (uint8_t)key_id->len; - if ((apdu = iso7816_new(U2F_CMD_AUTH, U2F_AUTH_SIGN, 2 * - SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len)) == NULL || + if ((apdu = iso7816_new(U2F_CMD_AUTH, U2F_AUTH_SIGN, (uint16_t)(2 * + SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len))) == NULL || iso7816_add(apdu, cdh->ptr, cdh->len) < 0 || iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 || iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 || @@ -336,7 +337,7 @@ do_auth(fido_dev_t *dev, const fido_blob_t *cdh, const char *rp_id, r = FIDO_ERR_RX; goto fail; } - if (usleep((ms == -1 ? 100 : ms) * 1000) < 0) { + if (usleep((unsigned)(ms == -1 ? 100 : ms) * 1000) < 0) { fido_log_debug("%s: usleep", __func__); r = FIDO_ERR_RX; goto fail; @@ -643,7 +644,7 @@ u2f_register(fido_dev_t *dev, fido_cred_t *cred, int ms) r = FIDO_ERR_RX; goto fail; } - if (usleep((ms == -1 ? 100 : ms) * 1000) < 0) { + if (usleep((unsigned)(ms == -1 ? 100 : ms) * 1000) < 0) { fido_log_debug("%s: usleep", __func__); r = FIDO_ERR_RX; goto fail; @@ -726,8 +727,8 @@ fail: int u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int ms) { - int nfound = 0; - int nauth_ok = 0; + size_t nfound = 0; + size_t nauth_ok = 0; int r; if (fa->uv == FIDO_OPT_TRUE || fa->allow_list.ptr == NULL) { @@ -769,3 +770,84 @@ u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int ms) return (FIDO_OK); } + +int +u2f_get_touch_begin(fido_dev_t *dev) +{ + iso7816_apdu_t *apdu = NULL; + const char *clientdata = FIDO_DUMMY_CLIENTDATA; + const char *rp_id = FIDO_DUMMY_RP_ID; + unsigned char clientdata_hash[SHA256_DIGEST_LENGTH]; + unsigned char rp_id_hash[SHA256_DIGEST_LENGTH]; + unsigned char reply[FIDO_MAXMSG]; + int r; + + memset(&clientdata_hash, 0, sizeof(clientdata_hash)); + memset(&rp_id_hash, 0, sizeof(rp_id_hash)); + + if (SHA256((const void *)clientdata, strlen(clientdata), + clientdata_hash) != clientdata_hash || SHA256((const void *)rp_id, + strlen(rp_id), rp_id_hash) != rp_id_hash) { + fido_log_debug("%s: sha256", __func__); + return (FIDO_ERR_INTERNAL); + } + + if ((apdu = iso7816_new(U2F_CMD_REGISTER, 0, 2 * + SHA256_DIGEST_LENGTH)) == NULL || + iso7816_add(apdu, clientdata_hash, sizeof(clientdata_hash)) < 0 || + iso7816_add(apdu, rp_id_hash, sizeof(rp_id_hash)) < 0) { + fido_log_debug("%s: iso7816", __func__); + r = FIDO_ERR_INTERNAL; + goto fail; + } + + if (dev->attr.flags & FIDO_CAP_WINK) { + fido_tx(dev, CTAP_CMD_WINK, NULL, 0); + fido_rx(dev, CTAP_CMD_WINK, &reply, sizeof(reply), 200); + } + + if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu), + iso7816_len(apdu)) < 0) { + fido_log_debug("%s: fido_tx", __func__); + r = FIDO_ERR_TX; + goto fail; + } + + r = FIDO_OK; +fail: + iso7816_free(&apdu); + + return (r); +} + +int +u2f_get_touch_status(fido_dev_t *dev, int *touched, int ms) +{ + unsigned char reply[FIDO_MAXMSG]; + int reply_len; + int r; + + if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, &reply, sizeof(reply), + ms)) < 2) { + fido_log_debug("%s: fido_rx", __func__); + return (FIDO_OK); /* ignore */ + } + + switch ((reply[reply_len - 2] << 8) | reply[reply_len - 1]) { + case SW_CONDITIONS_NOT_SATISFIED: + if ((r = u2f_get_touch_begin(dev)) != FIDO_OK) { + fido_log_debug("%s: u2f_get_touch_begin", __func__); + return (r); + } + *touched = 0; + break; + case SW_NO_ERROR: + *touched = 1; + break; + default: + fido_log_debug("%s: unexpected sw", __func__); + return (FIDO_ERR_RX); + } + + return (FIDO_OK); +} diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 274a799..4d08be9 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -20,6 +20,13 @@ else() list(APPEND COMPAT_SOURCES ../openbsd-compat/readpassphrase.c) endif() +if(NOT MSVC) + set_source_files_properties(assert_get.c assert_verify.c base64.c bio.c + cred_make.c cred_verify.c credman.c fido2-assert.c fido2-cred.c + fido2-token.c pin.c token.c util.c PROPERTIES COMPILE_FLAGS + "-Wconversion -Wsign-conversion") +endif() + add_executable(fido2-cred fido2-cred.c cred_make.c diff --git a/tools/assert_get.c b/tools/assert_get.c index 5e209cd..d52cd06 100644 --- a/tools/assert_get.c +++ b/tools/assert_get.c @@ -15,8 +15,67 @@ #include "../openbsd-compat/openbsd-compat.h" #include "extern.h" +struct toggle { + fido_opt_t up; + fido_opt_t uv; + fido_opt_t pin; +}; + +static const char * +opt2str(fido_opt_t v) +{ + switch (v) { + case FIDO_OPT_OMIT: + return "omit"; + case FIDO_OPT_TRUE: + return "true"; + case FIDO_OPT_FALSE: + return "false"; + default: + return "unknown"; + } +} + +static void +parse_toggle(const char *str, struct toggle *opt) +{ + fido_opt_t *k; + fido_opt_t v; + char *assignment; + char *key; + char *val; + + if ((assignment = strdup(str)) == NULL) + err(1, "strdup"); + if ((val = strchr(assignment, '=')) == NULL) + errx(1, "invalid assignment '%s'", assignment); + + key = assignment; + *val++ = '\0'; + + if (!strcmp(val, "true")) + v = FIDO_OPT_TRUE; + else if (!strcmp(val, "false")) + v = FIDO_OPT_FALSE; + else + errx(1, "unknown value '%s'", val); + + if (!strcmp(key, "up")) + k = &opt->up; + else if (!strcmp(key, "uv")) + k = &opt->uv; + else if (!strcmp(key, "pin")) + k = &opt->pin; + else + errx(1, "unknown key '%s'", key); + + free(assignment); + + *k = v; +} + static fido_assert_t * -prepare_assert(FILE *in_f, int flags) +prepare_assert(FILE *in_f, int flags, const struct toggle *opt) { fido_assert_t *assert = NULL; struct blob cdh; @@ -46,6 +105,9 @@ prepare_assert(FILE *in_f, int flags) fprintf(stderr, "credential id:\n"); xxd(id.ptr, id.len); } + fprintf(stderr, "up=%s\n", opt2str(opt->up)); + fprintf(stderr, "uv=%s\n", opt2str(opt->uv)); + fprintf(stderr, "pin=%s\n", opt2str(opt->pin)); } if ((assert = fido_assert_new()) == NULL) @@ -55,15 +117,11 @@ prepare_assert(FILE *in_f, int flags) cdh.len)) != FIDO_OK || (r = fido_assert_set_rp(assert, rpid)) != FIDO_OK) errx(1, "fido_assert_set: %s", fido_strerr(r)); + if ((r = fido_assert_set_up(assert, opt->up)) != FIDO_OK) + errx(1, "fido_assert_set_up: %s", fido_strerr(r)); + if ((r = fido_assert_set_uv(assert, opt->uv)) != FIDO_OK) + errx(1, "fido_assert_set_uv: %s", fido_strerr(r)); - if (flags & FLAG_UP) { - if ((r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK) - errx(1, "fido_assert_set_up: %s", fido_strerr(r)); - } - if (flags & FLAG_UV) { - if ((r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) - errx(1, "fido_assert_set_uv: %s", fido_strerr(r)); - } if (flags & FLAG_HMAC) { if ((r = fido_assert_set_extensions(assert, FIDO_EXT_HMAC_SECRET)) != FIDO_OK) @@ -136,6 +194,7 @@ assert_get(int argc, char **argv) { fido_dev_t *dev = NULL; fido_assert_t *assert = NULL; + struct toggle opt; char pin[1024]; char prompt[1024]; char *in_path = NULL; @@ -146,7 +205,9 @@ assert_get(int argc, char **argv) int ch; int r; - while ((ch = getopt(argc, argv, "dhi:o:pruv")) != -1) { + opt.up = opt.uv = opt.pin = FIDO_OPT_OMIT; + + while ((ch = getopt(argc, argv, "dhi:o:prt:uv")) != -1) { switch (ch) { case 'd': flags |= FLAG_DEBUG; @@ -161,16 +222,21 @@ assert_get(int argc, char **argv) out_path = optarg; break; case 'p': - flags |= FLAG_UP; + opt.up = FIDO_OPT_TRUE; break; case 'r': flags |= FLAG_RK; break; + case 't' : + parse_toggle(optarg, &opt); + break; case 'u': flags |= FLAG_U2F; break; case 'v': - flags |= FLAG_UV; + /* -v implies both pin and uv for historical reasons */ + opt.pin = FIDO_OPT_TRUE; + opt.uv = FIDO_OPT_TRUE; break; default: usage(); @@ -188,13 +254,13 @@ assert_get(int argc, char **argv) fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); - assert = prepare_assert(in_f, flags); + assert = prepare_assert(in_f, flags, &opt); dev = open_dev(argv[0]); if (flags & FLAG_U2F) fido_dev_force_u2f(dev); - if (flags & FLAG_UV) { + if (opt.pin == FIDO_OPT_TRUE) { r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", argv[0]); if (r < 0 || (size_t)r >= sizeof(prompt)) diff --git a/tools/assert_verify.c b/tools/assert_verify.c index ccff57a..fb96b65 100644 --- a/tools/assert_verify.c +++ b/tools/assert_verify.c @@ -175,16 +175,8 @@ assert_verify(int argc, char **argv) in_f = open_read(in_path); - if (argc > 1) { - if (strcmp(argv[1], "es256") == 0) - type = COSE_ES256; - else if (strcmp(argv[1], "rs256") == 0) - type = COSE_RS256; - else if (strcmp(argv[1], "eddsa") == 0) - type = COSE_EDDSA; - else - errx(1, "unknown type %s", argv[1]); - } + if (argc > 1 && cose_type(argv[1], &type) < 0) + errx(1, "unknown type %s", argv[1]); fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); diff --git a/tools/base64.c b/tools/base64.c index 9f31def..e131198 100644 --- a/tools/base64.c +++ b/tools/base64.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include @@ -62,7 +61,7 @@ fail: } int -base64_decode(char *in, void **ptr, size_t *len) +base64_decode(const char *in, void **ptr, size_t *len) { BIO *bio_mem = NULL; BIO *bio_b64 = NULL; @@ -78,7 +77,7 @@ base64_decode(char *in, void **ptr, size_t *len) if ((bio_b64 = BIO_new(BIO_f_base64())) == NULL) goto fail; - if ((bio_mem = BIO_new_mem_buf((void *)in, -1)) == NULL) + if ((bio_mem = BIO_new_mem_buf((const void *)in, -1)) == NULL) goto fail; BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL); diff --git a/tools/cred_make.c b/tools/cred_make.c index 380c67a..255a488 100644 --- a/tools/cred_make.c +++ b/tools/cred_make.c @@ -130,11 +130,16 @@ cred_make(int argc, char **argv) FILE *out_f = NULL; int type = COSE_ES256; int flags = 0; + int cred_protect = -1; int ch; int r; - while ((ch = getopt(argc, argv, "dhi:o:qruv")) != -1) { + while ((ch = getopt(argc, argv, "c:dhi:o:qruv")) != -1) { switch (ch) { + case 'c': + if ((cred_protect = base10(optarg)) < 0) + errx(1, "-c: invalid argument '%s'", optarg); + break; case 'd': flags |= FLAG_DEBUG; break; @@ -173,16 +178,8 @@ cred_make(int argc, char **argv) in_f = open_read(in_path); out_f = open_write(out_path); - if (argc > 1) { - if (strcmp(argv[1], "es256") == 0) - type = COSE_ES256; - else if (strcmp(argv[1], "rs256") == 0) - type = COSE_RS256; - else if (strcmp(argv[1], "eddsa") == 0) - type = COSE_EDDSA; - else - errx(1, "unknown type %s", argv[1]); - } + if (argc > 1 && cose_type(argv[1], &type) < 0) + errx(1, "unknown type %s", argv[1]); fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); @@ -192,6 +189,13 @@ cred_make(int argc, char **argv) if (flags & FLAG_U2F) fido_dev_force_u2f(dev); + if (cred_protect > 0) { + r = fido_cred_set_prot(cred, cred_protect); + if (r != FIDO_OK) { + errx(1, "fido_cred_set_prot: %s", fido_strerr(r)); + } + } + r = fido_dev_make_cred(dev, cred, NULL); if (r == FIDO_ERR_PIN_REQUIRED && !(flags & FLAG_QUIET)) { r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", diff --git a/tools/cred_verify.c b/tools/cred_verify.c index 3f7a400..d622ed7 100644 --- a/tools/cred_verify.c +++ b/tools/cred_verify.c @@ -109,11 +109,16 @@ cred_verify(int argc, char **argv) FILE *out_f = NULL; int type = COSE_ES256; int flags = 0; + int cred_prot = -1; int ch; int r; - while ((ch = getopt(argc, argv, "dhi:o:v")) != -1) { + while ((ch = getopt(argc, argv, "c:dhi:o:v")) != -1) { switch (ch) { + case 'c': + if ((cred_prot = base10(optarg)) < 0) + errx(1, "-c: invalid argument '%s'", optarg); + break; case 'd': flags |= FLAG_DEBUG; break; @@ -143,20 +148,19 @@ cred_verify(int argc, char **argv) in_f = open_read(in_path); out_f = open_write(out_path); - if (argc > 0) { - if (strcmp(argv[0], "es256") == 0) - type = COSE_ES256; - else if (strcmp(argv[0], "rs256") == 0) - type = COSE_RS256; - else if (strcmp(argv[0], "eddsa") == 0) - type = COSE_EDDSA; - else - errx(1, "unknown type %s", argv[0]); - } + if (argc > 0 && cose_type(argv[0], &type) < 0) + errx(1, "unknown type %s", argv[0]); fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); cred = prepare_cred(in_f, type, flags); + if (cred_prot > 0) { + r = fido_cred_set_prot(cred, cred_prot); + if (r != FIDO_OK) { + errx(1, "fido_cred_set_prot: %s", fido_strerr(r)); + } + } + if (fido_cred_x5c_ptr(cred) == NULL) { if ((r = fido_cred_verify_self(cred)) != FIDO_OK) errx(1, "fido_cred_verify_self: %s", fido_strerr(r)); diff --git a/tools/credman.c b/tools/credman.c index 6eda245..ea913bb 100644 --- a/tools/credman.c +++ b/tools/credman.c @@ -101,6 +101,7 @@ print_rk(const fido_credman_rk_t *rk, size_t idx) char *id = NULL; char *user_id = NULL; const char *type; + const char *prot; if ((cred = fido_credman_rk(rk, idx)) == NULL) errx(1, "fido_credman_rk"); @@ -109,23 +110,11 @@ print_rk(const fido_credman_rk_t *rk, size_t idx) fido_cred_user_id_len(cred), &user_id) < 0) errx(1, "output error"); - switch (fido_cred_type(cred)) { - case COSE_EDDSA: - type = "eddsa"; - break; - case COSE_ES256: - type = "es256"; - break; - case COSE_RS256: - type = "rs256"; - break; - default: - type = "unknown"; - break; - } + type = cose_string(fido_cred_type(cred)); + prot = prot_string(fido_cred_prot(cred)); - printf("%02u: %s %s (%s) %s\n", (unsigned)idx, id, - fido_cred_display_name(cred), user_id, type); + printf("%02u: %s %s %s %s %s\n", (unsigned)idx, id, + fido_cred_display_name(cred), user_id, type, prot); free(user_id); free(id); diff --git a/tools/extern.h b/tools/extern.h index be01046..df5fcd8 100644 --- a/tools/extern.h +++ b/tools/extern.h @@ -32,9 +32,11 @@ EC_KEY *read_ec_pubkey(const char *); fido_dev_t *open_dev(const char *); FILE *open_read(const char *); FILE *open_write(const char *); +const char *cose_string(int); +const char *prot_string(int); int assert_get(int, char **); int assert_verify(int, char **); -int base64_decode(char *, void **, size_t *); +int base64_decode(const char *, void **, size_t *); int base64_encode(const void *, size_t, char **); int base64_read(FILE *, struct blob *); int bio_delete(fido_dev_t *, char *, char *); @@ -42,6 +44,7 @@ int bio_enroll(char *); void bio_info(fido_dev_t *); int bio_list(char *); int bio_set_name(char *, char *, char *); +int cose_type(const char *, int *); int cred_make(int, char **); int cred_verify(int, char **); int credman_delete_rk(fido_dev_t *, const char *, char *); @@ -66,5 +69,6 @@ void print_cred(FILE *, int, const fido_cred_t *); void read_pin(const char *, char *, size_t); void usage(void); void xxd(const void *, size_t); +int base10(const char *); #endif /* _EXTERN_H_ */ diff --git a/tools/fido2-assert.c b/tools/fido2-assert.c index 9ce537a..7fd7632 100644 --- a/tools/fido2-assert.c +++ b/tools/fido2-assert.c @@ -11,10 +11,10 @@ * $ echo relying party >> assert_param * $ head -1 cred >> assert_param # credential id * $ tail -n +2 cred > pubkey # credential pubkey - * $ fido2-assert -G -i assert_param /dev/hidraw5 | fido2-assert -V pubkey rs256 + * $ fido2-assert -G -i assert_param /dev/hidraw5 | fido2-assert -V pubkey rs256 * * See blurb in fido2-cred.c on how to obtain cred. - */ + */ #include #include @@ -28,7 +28,7 @@ void usage(void) { fprintf(stderr, -"usage: fido2-assert -G [-dhpruv] [-i input_file] [-o output_file] device\n" +"usage: fido2-assert -G [-dhpruv] [-t option] [-i input_file] [-o output_file] device\n" " fido2-assert -V [-dhpv] [-i input_file] key_file [type]\n" ); diff --git a/tools/fido2-attach.sh b/tools/fido2-attach.sh new file mode 100755 index 0000000..d4bc449 --- /dev/null +++ b/tools/fido2-attach.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +# Copyright (c) 2020 Yubico AB. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +DEV="" + +while [ -z "${DEV}" ]; do + sleep .5 + DEV="$(fido2-token -L | sed 's/^\(.*\): .*$/\1/;q')" +done + +printf '%s\n' "${DEV}" diff --git a/tools/fido2-cred.c b/tools/fido2-cred.c index 45efca0..ce277f5 100644 --- a/tools/fido2-cred.c +++ b/tools/fido2-cred.c @@ -12,7 +12,7 @@ * $ echo user name >> cred_param * $ dd if=/dev/urandom bs=1 count=32 | base64 >> cred_param * $ fido2-cred -M -i cred_param /dev/hidraw5 | fido2-cred -V -o cred - */ + */ #include #include @@ -26,8 +26,8 @@ void usage(void) { fprintf(stderr, -"usage: fido2-cred -M [-dhqruv] [-i input_file] [-o output_file] device [type]\n" -" fido2-cred -V [-dhv] [-i input_file] [-o output_file] [type]\n" +"usage: fido2-cred -M [-dhqruv] [-c cred_protect] [-i input_file] [-o output_file] device [type]\n" +" fido2-cred -V [-dhv] [-c cred_protect] [-i input_file] [-o output_file] [type]\n" ); exit(1); diff --git a/tools/fido2-detach.sh b/tools/fido2-detach.sh new file mode 100755 index 0000000..9cd2e64 --- /dev/null +++ b/tools/fido2-detach.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +# Copyright (c) 2020 Yubico AB. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +DEV="$(fido2-token -L | sed 's/^\(.*\): .*$/\1/;q')" + +while [ -n "${DEV}" ]; do + sleep .5 + DEV="$(fido2-token -L | sed 's/^\(.*\): .*$/\1/;q')" +done diff --git a/tools/fido2-token.c b/tools/fido2-token.c index 0b02fea..a1e6594 100644 --- a/tools/fido2-token.c +++ b/tools/fido2-token.c @@ -19,11 +19,11 @@ usage(void) { fprintf(stderr, "usage: fido2-token [-CR] [-d] device\n" -" fido2-token -D [-de] -i id device\n" +" fido2-token -D [-de] -i id device\n" " fido2-token -I [-cd] [-k rp_id -i cred_id] device\n" -" fido2-token -L [-der] [-k rp_id] [device]\n" +" fido2-token -L [-der] [-k rp_id] [device]\n" " fido2-token -S [-de] [-i template_id -n template_name] device\n" -" fido2-token -V\n" +" fido2-token -V\n" ); exit(1); diff --git a/tools/fido2-unprot.sh b/tools/fido2-unprot.sh new file mode 100755 index 0000000..44b28b8 --- /dev/null +++ b/tools/fido2-unprot.sh @@ -0,0 +1,75 @@ +#!/bin/sh + +# Copyright (c) 2020 Fabian Henneke. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + + +if [ $(uname) != "Linux" ] ; then + echo "Can only run on Linux" + exit 1 +fi + +TOKEN_VERSION=$(${FIDO_TOOLS_PREFIX}fido2-token -V 2>&1) +if [ $? -ne 0 ] ; then + echo "Please install libfido2 1.5.0 or higher" + exit +fi + +TOKEN_VERSION_MAJOR=$(echo "$TOKEN_VERSION" | cut -d. -f1) +TOKEN_VERSION_MINOR=$(echo "$TOKEN_VERSION" | cut -d. -f2) +if [ $TOKEN_VERSION_MAJOR -eq 0 -o $TOKEN_VERSION_MAJOR -eq 1 -a $TOKEN_VERSION_MINOR -lt 5 ] ; then + echo "Please install libfido2 1.5.0 or higher (current version: $TOKEN_VERSION)" + exit 1 +fi + +set -e + +TOKEN_OUTPUT=$(${FIDO_TOOLS_PREFIX}fido2-token -L) +DEV_PATH_NAMES=$(echo "$TOKEN_OUTPUT" | sed -r 's/^(.*): .*\((.*)\)$/\1 \2/g') +DEV_COUNT=$(echo "$DEV_PATH_NAMES" | wc -l) + +for i in $(seq 1 $DEV_COUNT) +do + DEV_PATH_NAME=$(echo "$DEV_PATH_NAMES" | sed "${i}q;d") + DEV_PATH=$(echo "$DEV_PATH_NAME" | cut -d' ' -f1) + DEV_NAME=$(echo "$DEV_PATH_NAME" | cut -d' ' -f1 --complement) + DEV_PRETTY=$(echo "$DEV_NAME (at '$DEV_PATH')") + if expr match "$(${FIDO_TOOLS_PREFIX}fido2-token -I $DEV_PATH)" ".* credMgmt.* clientPin.*\|.* clientPin.* credMgmt.*" > /dev/null ; then + printf "Enter PIN for $DEV_PRETTY once (ignore further prompts): " + stty -echo + read PIN + stty echo + printf "\n" + RESIDENT_RPS=$(echo "${PIN}\n" | setsid -w ${FIDO_TOOLS_PREFIX}fido2-token -L -r $DEV_PATH | cut -d' ' -f3) + printf "\n" + RESIDENT_RPS_COUNT=$(echo "$RESIDENT_RPS" | wc -l) + FOUND=0 + for j in $(seq 1 $DEV_RESIDENT_RPS_COUNT) + do + RESIDENT_RP=$(echo "$RESIDENT_RPS" | sed "${j}q;d") + UNPROT_CREDS=$(echo "${PIN}\n" | setsid -w ${FIDO_TOOLS_PREFIX}fido2-token -L -k $RESIDENT_RP $DEV_PATH | grep ' uvopt$' | cut -d' ' -f2,3,4) + printf "\n" + UNPROT_CREDS_COUNT=$(echo "$UNPROT_CREDS" | wc -l) + if [ $UNPROT_CREDS_COUNT -gt 0 ] ; then + FOUND=1 + echo "Unprotected credentials on $DEV_PRETTY for '$RESIDENT_RP':" + echo "$UNPROT_CREDS" + fi + done + if [ $FOUND -eq 0 ] ; then + echo "No unprotected credentials on $DEV_PRETTY" + fi + else + echo "$DEV_PRETTY cannot enumerate credentials" + echo "Discovering unprotected SSH credentials only..." + STUB_HASH=$(echo -n "" | openssl sha256 -binary | base64) + printf "$STUB_HASH\nssh:\n" | ${FIDO_TOOLS_PREFIX}fido2-assert -G -r -t up=false $DEV_PATH 2> /dev/null || ASSERT_EXIT_CODE=$? + if [ $ASSERT_EXIT_CODE -eq 0 ] ; then + echo "Found an unprotected SSH credential on $DEV_PRETTY!" + else + echo "No unprotected SSH credentials (default settings) on $DEV_PRETTY" + fi + fi + printf "\n" +done diff --git a/tools/include_check.sh b/tools/include_check.sh index 9958c9a..e684d0b 100755 --- a/tools/include_check.sh +++ b/tools/include_check.sh @@ -1,5 +1,5 @@ -#!/bin/bash -# +#!/bin/sh + # Copyright (c) 2019 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. @@ -8,14 +8,14 @@ check() { for f in $(find $1 -maxdepth 1 -name '*.h'); do echo "#include \"$f\"" | \ cc $CFLAGS -Isrc -xc -c - -o /dev/null 2>&1 - echo $f $CFLAGS $? + echo "$f $CFLAGS $?" done } check examples check fuzz check openbsd-compat -CFLAGS=-D_FIDO_INTERNAL check src +CFLAGS="${CFLAGS} -D_FIDO_INTERNAL" check src check src/fido.h check src/fido check tools diff --git a/tools/macos_pkg.sh b/tools/macos_pkg.sh deleted file mode 100755 index 4313c27..0000000 --- a/tools/macos_pkg.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash -e -# Copyright (c) 2019 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 [[ "$#" -ne 2 ]]; then - echo usage: $0 version directory 1>&2 - exit 1 -fi - -V=$1 -D=$2 - -FIDO_PATH=$(realpath ${D}/lib/libfido2.${V}.dylib) -CBOR_PATH=$(otool -L "${FIDO_PATH}" | grep cbor | awk '{ print $1 }') -CRYPTO_PATH=$(otool -L "${FIDO_PATH}" | grep crypto | awk '{ print $1 }') - -cp -p "${CBOR_PATH}" "${CRYPTO_PATH}" "${D}/lib" -chmod 755 "${D}/lib/"*dylib -rm "${D}/lib/pkgconfig/libfido2.pc" -rmdir "${D}/lib/pkgconfig" - -CBOR_NAME=$(echo "${CBOR_PATH}" | grep -o 'libcbor.*dylib') -CRYPTO_NAME=$(echo "${CRYPTO_PATH}" | grep -o 'libcrypto.*dylib') -FIDO_NAME="libfido2.${V}.dylib" - -install_name_tool -id "@loader_path/${CBOR_NAME}" "${D}/lib/${CBOR_NAME}" -install_name_tool -id "@loader_path/${CRYPTO_NAME}" "${D}/lib/${CRYPTO_NAME}" -install_name_tool -id "@loader_path/libfido2.${V}.dylib" "${FIDO_PATH}" - -install_name_tool -change "${CBOR_PATH}" "@loader_path/${CBOR_NAME}" \ - "${FIDO_PATH}" -install_name_tool -change "${CRYPTO_PATH}" "@loader_path/${CRYPTO_NAME}" \ - "${FIDO_PATH}" - -for f in $(find "${D}/bin" -type f); do - FIDO_PATH=$(otool -L "${f}" | grep libfido2 | awk '{ print $1 }') - install_name_tool -change "${CBOR_PATH}" \ - "@executable_path/../lib/${CBOR_NAME}" "${f}" - install_name_tool -change "${CRYPTO_PATH}" \ - "@executable_path/../lib/${CRYPTO_NAME}" "${f}" - install_name_tool -change "${FIDO_PATH}" \ - "@executable_path/../lib/${FIDO_NAME}" "${f}" -done diff --git a/tools/token.c b/tools/token.c index e65f09f..28e4512 100644 --- a/tools/token.c +++ b/tools/token.c @@ -111,6 +111,18 @@ print_maxmsgsiz(uint64_t maxmsgsiz) printf("maxmsgsiz: %d\n", (int)maxmsgsiz); } +static void +print_maxcredcntlst(uint64_t maxcredcntlst) +{ + printf("maxcredcntlst: %d\n", (int)maxcredcntlst); +} + +static void +print_maxcredidlen(uint64_t maxcredidlen) +{ + printf("maxcredlen: %d\n", (int)maxcredidlen); +} + static void print_fwversion(uint64_t fwversion) { @@ -202,6 +214,12 @@ token_info(int argc, char **argv, char *path) /* print maximum message size */ print_maxmsgsiz(fido_cbor_info_maxmsgsiz(ci)); + /* print maximum number of credentials allowed in credential lists */ + print_maxcredcntlst(fido_cbor_info_maxcredcntlst(ci)); + + /* print maximum length of a credential ID */ + print_maxcredidlen(fido_cbor_info_maxcredidlen(ci)); + /* print firmware version */ print_fwversion(fido_cbor_info_fwversion(ci)); diff --git a/tools/util.c b/tools/util.c index de70388..7ed59e4 100644 --- a/tools/util.c +++ b/tools/util.c @@ -16,7 +16,9 @@ #include #include +#include #include +#include #include #include #include @@ -78,6 +80,25 @@ open_read(const char *file) return (f); } +int +base10(const char *str) +{ + char *ep; + long long ll; + + ll = strtoll(str, &ep, 10); + 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); +} + void xxd(const void *buf, size_t count) { @@ -362,3 +383,50 @@ print_cred(FILE *out_f, int type, const fido_cred_t *cred) free(id); } + +int +cose_type(const char *str, int *type) +{ + if (strcmp(str, "es256") == 0) + *type = COSE_ES256; + else if (strcmp(str, "rs256") == 0) + *type = COSE_RS256; + else if (strcmp(str, "eddsa") == 0) + *type = COSE_EDDSA; + else { + *type = 0; + return (-1); + } + + return (0); +} + +const char * +cose_string(int type) +{ + switch (type) { + case COSE_EDDSA: + return ("eddsa"); + case COSE_ES256: + return ("es256"); + case COSE_RS256: + return ("rs256"); + default: + return ("unknown"); + } +} + +const char * +prot_string(int prot) +{ + switch (prot) { + case FIDO_CRED_PROT_UV_OPTIONAL: + return ("uvopt"); + case FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID: + return ("uvopt+id"); + case FIDO_CRED_PROT_UV_REQUIRED: + return ("uvreq"); + default: + return ("unknown"); + } +} diff --git a/udev/70-u2f.rules b/udev/70-u2f.rules index 22b47c9..be02043 100644 --- a/udev/70-u2f.rules +++ b/udev/70-u2f.rules @@ -1,75 +1,175 @@ -# Copyright (c) 2018 Yubico AB. All rights reserved. +# Copyright (c) 2020 Yubico AB. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. -# this udev file should be used with udev 188 and newer -ACTION!="add|change", GOTO="u2f_end" +# This file is automatically generated, and should +# be used with udev 188 or newer. -# Yubico YubiKey -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0113|0114|0115|0116|0120|0121|0200|0402|0403|0406|0407|0410", TAG+="uaccess", GROUP="plugdev", MODE="0660" +ACTION!="add|change", GOTO="fido_end" -# Happlink (formerly Plug-Up) Security KEY -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2581", ATTRS{idProduct}=="f1d0", TAG+="uaccess", GROUP="plugdev", MODE="0660" +# ellipticSecure MIRKey by STMicroelectronics +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ac", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# Unknown product by STMicroelectronics +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# Unknown product by STMicroelectronics +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="cdab", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# Infineon FIDO by Infineon Technologies +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="058b", ATTRS{idProduct}=="022d", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# Kensington VeriMark by Synaptics Inc. +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="06cb", ATTRS{idProduct}=="0088", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# FS ePass FIDO by Feitian Technologies Co., Ltd. +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0850", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# Unknown product by Feitian Technologies Co., Ltd. +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0852", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# Unknown product by Feitian Technologies Co., Ltd. +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0853", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# Unknown product by Feitian Technologies Co., Ltd. +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0854", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# Unknown product by Feitian Technologies Co., Ltd. +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0856", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# Unknown product by Feitian Technologies Co., Ltd. +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0858", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# FS MultiPass FIDO U2F by Feitian Technologies Co., Ltd. +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="085a", TAG+="uaccess", GROUP="plugdev", MODE="0660" -# Neowave Keydo and Keydo AES -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1e0d", ATTRS{idProduct}=="f1d0|f1ae", TAG+="uaccess", GROUP="plugdev", MODE="0660" +# Unknown product by Feitian Technologies Co., Ltd. +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="085b", TAG+="uaccess", GROUP="plugdev", MODE="0660" -# HyperSecu HyperFIDO -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e|2ccf", ATTRS{idProduct}=="0880", TAG+="uaccess", GROUP="plugdev", MODE="0660" +# Unknown product by Feitian Technologies Co., Ltd. +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="085d", TAG+="uaccess", GROUP="plugdev", MODE="0660" -# Feitian ePass FIDO, BioPass FIDO2 -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0850|0852|0853|0854|0856|0858|085a|085b|085d", TAG+="uaccess", GROUP="plugdev", MODE="0660" +# Hypersecu HyperFIDO by Feitian Technologies Co., Ltd. +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0880", TAG+="uaccess", GROUP="plugdev", MODE="0660" -# JaCarta U2F -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="24dc", ATTRS{idProduct}=="0101|0501", TAG+="uaccess", GROUP="plugdev", MODE="0660" +# YubiKey NEO FIDO by Yubico AB +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0113", TAG+="uaccess", GROUP="plugdev", MODE="0660" -# U2F Zero +# YubiKey NEO OTP+FIDO by Yubico AB +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0114", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# YubiKey NEO FIDO+CCID by Yubico AB +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0115", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# YubiKey NEO OTP+FIDO+CCID by Yubico AB +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0116", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# Security Key by Yubico by Yubico AB +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0120", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# Unknown product by Yubico AB +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0121", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# Gnubby U2F by Yubico AB +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0200", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# YubiKey 4 FIDO by Yubico AB +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0402", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# YubiKey 4 OTP+FIDO by Yubico AB +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0403", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# YubiKey 4 FIDO+CCID by Yubico AB +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0406", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# YubiKey 4 OTP+FIDO+CCID by Yubico AB +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0407", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# YubiKey Plus by Yubico AB +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0410", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# U2F Zero by Silicon Laboratories, Inc. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess", GROUP="plugdev", MODE="0660" -# VASCO SecureClick +# SoloKeys SoloHacker by pid.codes +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="5070", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# SoloKeys SoloBoot by pid.codes +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="50b0", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# SatoshiLabs TREZOR by pid.codes +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="53c1", 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" + +# VASCO SecureClick by VASCO Data Security NV KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1a44", ATTRS{idProduct}=="00bb", TAG+="uaccess", GROUP="plugdev", MODE="0660" -# Bluink Key -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2abe", ATTRS{idProduct}=="1002", TAG+="uaccess", GROUP="plugdev", MODE="0660" +# OnlyKey (FIDO2/U2F) by OpenMoko, Inc. +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="60fc", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# Neowave Keydo AES by NEOWAVE +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1e0d", ATTRS{idProduct}=="f1ae", TAG+="uaccess", GROUP="plugdev", MODE="0660" -# Thetis Key +# Neowave Keydo by NEOWAVE +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1e0d", ATTRS{idProduct}=="f1d0", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# Thethis Key by Shenzhen Excelsecu Data Technology Co., Ltd. KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1ea8", ATTRS{idProduct}=="f025", TAG+="uaccess", GROUP="plugdev", MODE="0660" -# Nitrokey FIDO U2F, Nitrokey FIDO2, Safetech SafeKey -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4287|42b1|42b3", TAG+="uaccess", GROUP="plugdev", MODE="0660" +# ExcelSecu FIDO2 Security Key by Shenzhen Excelsecu Data Technology Co., Ltd. +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1ea8", ATTRS{idProduct}=="fc25", TAG+="uaccess", GROUP="plugdev", MODE="0660" -# Google Titan U2F -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="5026", TAG+="uaccess", GROUP="plugdev", MODE="0660" +# GoTrust Idem Key by NXP Semiconductors +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1fc9", ATTRS{idProduct}=="f143", TAG+="uaccess", GROUP="plugdev", MODE="0660" -# Tomu board + chopstx U2F + SoloKeys -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="cdab|a2ca", TAG+="uaccess", GROUP="plugdev", MODE="0660" +# Nitrokey FIDO U2F by Flirc +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4287", TAG+="uaccess", GROUP="plugdev", MODE="0660" -# SoloKeys -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="5070|50b0", TAG+="uaccess", GROUP="plugdev", MODE="0660" +# Nitrokey FIDO2 by Flirc +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b1", TAG+="uaccess", GROUP="plugdev", MODE="0660" -# Trezor -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="534c", ATTRS{idProduct}=="0001", TAG+="uaccess", GROUP="plugdev", MODE="0660" -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="53c1", TAG+="uaccess", GROUP="plugdev", MODE="0660" +# Safetech SafeKey by Flirc +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b3", TAG+="uaccess", GROUP="plugdev", MODE="0660" -# Infineon FIDO -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="058b", ATTRS{idProduct}=="022d", TAG+="uaccess", GROUP="plugdev", MODE="0660" +# JaCarta U2F by Aladdin Software Security R.D. +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="24dc", ATTRS{idProduct}=="0101", TAG+="uaccess", GROUP="plugdev", MODE="0660" -# Ledger Nano S and Nano X -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="0001|0004", TAG+="uaccess", GROUP="plugdev", MODE="0660" +# JaCarta U2F by Aladdin Software Security R.D. +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="24dc", ATTRS{idProduct}=="0501", TAG+="uaccess", GROUP="plugdev", MODE="0660" -# Kensington VeriMark -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="06cb", ATTRS{idProduct}=="0088", TAG+="uaccess", GROUP="plugdev", MODE="0660" +# Happlink Security Key by Plug‐up +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2581", ATTRS{idProduct}=="f1d0", TAG+="uaccess", GROUP="plugdev", MODE="0660" -# Longmai mFIDO -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="4c4d", ATTRS{idProduct}=="f703", TAG+="uaccess", GROUP="plugdev", MODE="0660" +# Bluink Key by Bluink Ltd +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2abe", ATTRS{idProduct}=="1002", TAG+="uaccess", GROUP="plugdev", MODE="0660" -# eWBM FIDO2 - Goldengate 310, 320, 500, 450 -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="4a1a|4c2a|5c2f|f47c", TAG+="uaccess", GROUP="plugdev", MODE="0660" +# Ledger Nano S by LEDGER +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="0001", TAG+="uaccess", GROUP="plugdev", MODE="0660" -# OnlyKey (FIDO2 / U2F) -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="60fc", TAG+="uaccess", GROUP="plugdev", MODE="0660" +# Ledger Nano X by LEDGER +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="0004", TAG+="uaccess", GROUP="plugdev", MODE="0660" -# GoTrust Idem Key -KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1fc9", ATTRS{idProduct}=="f143", TAG+="uaccess", GROUP="plugdev", MODE="0660" +# Hypersecu HyperFIDO by Hypersecu Information Systems, Inc. +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2ccf", ATTRS{idProduct}=="0880", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# eWBM FIDO2 Goldengate 310 by eWBM Co., Ltd. +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="4a1a", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# eWBM FIDO2 Goldengate 320 by eWBM Co., Ltd. +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="4c2a", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# eWBM FIDO2 Goldengate 500 by eWBM Co., Ltd. +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="5c2f", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# eWBM FIDO2 Goldengate 450 by eWBM Co., Ltd. +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="f47c", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# Longmai mFIDO by Unknown vendor +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="4c4d", ATTRS{idProduct}=="f703", TAG+="uaccess", GROUP="plugdev", MODE="0660" + +# SatoshiLabs TREZOR by SatoshiLabs +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="534c", ATTRS{idProduct}=="0001", TAG+="uaccess", GROUP="plugdev", MODE="0660" -LABEL="u2f_end" +LABEL="fido_end" diff --git a/udev/check.sh b/udev/check.sh new file mode 100755 index 0000000..97bbb97 --- /dev/null +++ b/udev/check.sh @@ -0,0 +1,31 @@ +#!/bin/sh -u + +# Copyright (c) 2020 Yubico AB. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +sort_by_id() { + awk '{ printf "%d\n", $3 }' | sort -Cnu +} + +if ! grep '^vendor' "$1" | sort_by_id; then + echo unsorted vendor section 1>&2 + exit 1 +fi + +VENDORS=$(grep '^vendor' "$1" | awk '{ print $2 }') +PRODUCTS=$(grep '^product' "$1" | awk '{ print $2 }' | uniq) + +if [ "${VENDORS}" != "${PRODUCTS}" ]; then + echo vendors: "$(echo "${VENDORS}" | tr '\n' ',')" 1>&2 + echo products: "$(echo "${PRODUCTS}" | tr '\n' ',')" 1>&2 + echo vendors and products in different order 1>&2 + exit 2 +fi + +for v in ${VENDORS}; do + if ! grep "^product ${v}" "$1" | sort_by_id; then + echo "${v}": unsorted product section 1>&2 + exit 3 + fi +done diff --git a/udev/fidodevs b/udev/fidodevs new file mode 100644 index 0000000..e149964 --- /dev/null +++ b/udev/fidodevs @@ -0,0 +1,110 @@ +# Copyright (c) 2020 Yubico AB. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +# After modifying this file, regenerate 70-u2f.rules: +# ./genrules.awk fidodevs > 70-u2f.rules + +# List of known vendors. Sorted by vendor ID. + +vendor STMICRO 0x0483 STMicroelectronics +vendor INFINEON 0x058b Infineon Technologies +vendor SYNAPTICS 0x06cb Synaptics Inc. +vendor FEITIAN 0x096e Feitian Technologies Co., Ltd. +vendor YUBICO 0x1050 Yubico AB +vendor SILICON 0x10c4 Silicon Laboratories, Inc. +vendor PIDCODES 0x1209 pid.codes +vendor GOOGLE 0x18d1 Google Inc. +vendor VASCO 0x1a44 VASCO Data Security NV +vendor OPENMOKO 0x1d50 OpenMoko, Inc. +vendor NEOWAVE 0x1e0d NEOWAVE +vendor EXCELSECU 0x1ea8 Shenzhen Excelsecu Data Technology Co., Ltd. +vendor NXP 0x1fc9 NXP Semiconductors +vendor FLIRC 0x20a0 Flirc +vendor ALLADIN 0x24dc Aladdin Software Security R.D. +vendor PLUGUP 0x2581 Plug‐up +vendor BLUINK 0x2abe Bluink Ltd +vendor LEDGER 0x2c97 LEDGER +vendor HYPERSECU 0x2ccf Hypersecu Information Systems, Inc. +vendor EWBM 0x311f eWBM Co., Ltd. +vendor UNKNOWN1 0x4c4d Unknown vendor +vendor SATOSHI 0x534c SatoshiLabs + +# List of known products. Grouped by vendor; sorted by product ID. + +product STMICRO 0xa2ac ellipticSecure MIRKey +product STMICRO 0xa2ca Unknown product +product STMICRO 0xcdab Unknown product + +product INFINEON 0x022d Infineon FIDO + +product SYNAPTICS 0x0088 Kensington VeriMark + +product FEITIAN 0x0850 FS ePass FIDO +product FEITIAN 0x0852 Unknown product +product FEITIAN 0x0853 Unknown product +product FEITIAN 0x0854 Unknown product +product FEITIAN 0x0856 Unknown product +product FEITIAN 0x0858 Unknown product +product FEITIAN 0x085a FS MultiPass FIDO U2F +product FEITIAN 0x085b Unknown product +product FEITIAN 0x085d Unknown product +product FEITIAN 0x0880 Hypersecu HyperFIDO + +product YUBICO 0x0113 YubiKey NEO FIDO +product YUBICO 0x0114 YubiKey NEO OTP+FIDO +product YUBICO 0x0115 YubiKey NEO FIDO+CCID +product YUBICO 0x0116 YubiKey NEO OTP+FIDO+CCID +product YUBICO 0x0120 Security Key by Yubico +product YUBICO 0x0121 Unknown product +product YUBICO 0x0200 Gnubby U2F +product YUBICO 0x0402 YubiKey 4 FIDO +product YUBICO 0x0403 YubiKey 4 OTP+FIDO +product YUBICO 0x0406 YubiKey 4 FIDO+CCID +product YUBICO 0x0407 YubiKey 4 OTP+FIDO+CCID +product YUBICO 0x0410 YubiKey Plus + +product SILICON 0x8acf U2F Zero + +product PIDCODES 0x5070 SoloKeys SoloHacker +product PIDCODES 0x50b0 SoloKeys SoloBoot +product PIDCODES 0x53c1 SatoshiLabs TREZOR + +product GOOGLE 0x5026 Google Titan U2F + +product VASCO 0x00bb VASCO SecureClick + +product OPENMOKO 0x60fc OnlyKey (FIDO2/U2F) + +product NEOWAVE 0xf1ae Neowave Keydo AES +product NEOWAVE 0xf1d0 Neowave Keydo + +product EXCELSECU 0xf025 Thethis Key +product EXCELSECU 0xfc25 ExcelSecu FIDO2 Security Key + +product NXP 0xf143 GoTrust Idem Key + +product FLIRC 0x4287 Nitrokey FIDO U2F +product FLIRC 0x42b1 Nitrokey FIDO2 +product FLIRC 0x42b3 Safetech SafeKey + +product ALLADIN 0x0101 JaCarta U2F +product ALLADIN 0x0501 JaCarta U2F + +product PLUGUP 0xf1d0 Happlink Security Key + +product BLUINK 0x1002 Bluink Key + +product LEDGER 0x0001 Ledger Nano S +product LEDGER 0x0004 Ledger Nano X + +product HYPERSECU 0x0880 Hypersecu HyperFIDO + +product EWBM 0x4a1a eWBM FIDO2 Goldengate 310 +product EWBM 0x4c2a eWBM FIDO2 Goldengate 320 +product EWBM 0x5c2f eWBM FIDO2 Goldengate 500 +product EWBM 0xf47c eWBM FIDO2 Goldengate 450 + +product UNKNOWN1 0xf703 Longmai mFIDO + +product SATOSHI 0x0001 SatoshiLabs TREZOR diff --git a/udev/genrules.awk b/udev/genrules.awk new file mode 100755 index 0000000..2a85c7c --- /dev/null +++ b/udev/genrules.awk @@ -0,0 +1,55 @@ +#!/usr/bin/awk -f + +# Copyright (c) 2020 Yubico AB. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +NR == 1 { + print "# Copyright (c) 2020 Yubico AB. All rights reserved." + print "# Use of this source code is governed by a BSD-style" + print "# license that can be found in the LICENSE file." + print "" + print "# This file is automatically generated, and should" + print "# be used with udev 188 or newer." + print "" + print "ACTION!=\"add|change\", GOTO=\"fido_end\"" + + next +} + +$1 == "vendor" { + sub("0x", "", $3) + vendors[$2, "id"] = $3 + + f = 4 + while (f <= NF) { + vendors[$2, "name"] = vendors[$2, "name"] " " $f + f++ + } +} + +$1 == "product" { + sub("0x", "", $3) + name = "" + + f = 4 + while (f <= NF) { + name = name " " $f + f++ + } + + line = "\n#" name " by" vendors[$2, "name"]"\n" + line = line"KERNEL==\"hidraw*\"" + line = line", SUBSYSTEM==\"hidraw\"" + line = line", ATTRS{idVendor}==\""vendors[$2, "id"]"\"" + line = line", ATTRS{idProduct}==\""$3"\"" + line = line", TAG+=\"uaccess\"" + line = line", GROUP=\"plugdev\"" + line = line", MODE=\"0660\"" + + print line +} + +END { + print "\nLABEL=\"fido_end\"" +} diff --git a/windows/build.ps1 b/windows/build.ps1 index aaa848d..a65fdd9 100644 --- a/windows/build.ps1 +++ b/windows/build.ps1 @@ -12,11 +12,11 @@ $ErrorActionPreference = "Continue" # LibreSSL coordinates. New-Variable -Name 'LIBRESSL_URL' ` -Value 'https://ftp.openbsd.org/pub/OpenBSD/LibreSSL' -Option Constant -New-Variable -Name 'LIBRESSL' -Value 'libressl-3.0.2' -Option Constant +New-Variable -Name 'LIBRESSL' -Value 'libressl-3.1.4' -Option Constant # libcbor coordinates. -New-Variable -Name 'LIBCBOR' -Value 'libcbor-0.5.0' -Option Constant -New-Variable -Name 'LIBCBOR_BRANCH' -Value 'v0.5.0' -Option Constant +New-Variable -Name 'LIBCBOR' -Value 'libcbor-0.7.0' -Option Constant +New-Variable -Name 'LIBCBOR_BRANCH' -Value 'v0.7.0' -Option Constant New-Variable -Name 'LIBCBOR_GIT' -Value 'https://github.com/pjk/libcbor' ` -Option Constant @@ -149,7 +149,7 @@ Function Build(${OUTPUT}, ${GENERATOR}, ${ARCH}) { -DCMAKE_INSTALL_PREFIX="${OUTPUT}" & $CMake --build . --config Release & $CMake --build . --config Release --target install - "cbor.dll", "crypto-45.dll" | %{ Copy-Item "${OUTPUT}\bin\$_" ` + "cbor.dll", "crypto-46.dll" | %{ Copy-Item "${OUTPUT}\bin\$_" ` -Destination "examples\Release" } } @@ -161,15 +161,15 @@ Function Package-Headers() { Function Package-Libraries(${SRC}, ${DEST}) { Copy-Item "${SRC}\bin\cbor.dll" "${DEST}" -ErrorAction Stop Copy-Item "${SRC}\lib\cbor.lib" "${DEST}" -ErrorAction Stop - Copy-Item "${SRC}\bin\crypto-45.dll" "${DEST}" -ErrorAction Stop - Copy-Item "${SRC}\lib\crypto-45.lib" "${DEST}" -ErrorAction Stop + Copy-Item "${SRC}\bin\crypto-46.dll" "${DEST}" -ErrorAction Stop + Copy-Item "${SRC}\lib\crypto-46.lib" "${DEST}" -ErrorAction Stop Copy-Item "${SRC}\lib\fido2.dll" "${DEST}" -ErrorAction Stop Copy-Item "${SRC}\lib\fido2.lib" "${DEST}" -ErrorAction Stop } Function Package-PDBs(${SRC}, ${DEST}) { Copy-Item "${SRC}\${LIBRESSL}\crypto\crypto.dir\Release\vc142.pdb" ` - "${DEST}\crypto-45.pdb" -ErrorAction Stop + "${DEST}\crypto-46.pdb" -ErrorAction Stop Copy-Item "${SRC}\${LIBCBOR}\src\cbor_shared.dir\Release\vc142.pdb" ` "${DEST}\cbor.pdb" -ErrorAction Stop Copy-Item "${SRC}\src\fido2_shared.dir\Release\vc142.pdb" ` -- cgit v1.2.3