summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2020-09-20 16:14:20 +0100
committerColin Watson <cjwatson@debian.org>2020-09-20 16:14:20 +0100
commit173bfbf7886608a4a7abbfac6a42ac4bf4a3432d (patch)
treeb97833d8754f257f92d99dd2f5c9e9d557e3f689
parent75073d0a8478441cc97a6efa10b566c5fb1dac81 (diff)
New upstream version 1.5.0
-rw-r--r--.github/workflows/cifuzz_oss.yml23
-rw-r--r--.github/workflows/scan.yml36
-rw-r--r--.github/workflows/windows.yml14
-rw-r--r--.gitignore9
-rw-r--r--.travis.yml86
-rw-r--r--.travis/build-linux-clang22
-rw-r--r--.travis/build-linux-gcc19
-rw-r--r--.travis/build-linux-mingw47
-rw-r--r--.travis/build-osx-clang24
-rw-r--r--.travis/fuzz-linux-asan59
-rw-r--r--.travis/fuzz-linux-msan59
-rw-r--r--CMakeLists.txt111
-rw-r--r--NEWS18
-rw-r--r--README.adoc27
-rw-r--r--debian/changelog80
-rw-r--r--debian/compat1
-rw-r--r--debian/control53
-rw-r--r--debian/copyright85
-rw-r--r--debian/fido2-tools.install1
-rw-r--r--debian/fido2-tools.manpages3
-rw-r--r--debian/libfido2-1.install1
-rw-r--r--debian/libfido2-1.symbols148
-rw-r--r--debian/libfido2-dev.install29
-rw-r--r--debian/libfido2-dev.links276
-rw-r--r--debian/libfido2-dev.manpages25
-rw-r--r--debian/libfido2-udev.install1
-rwxr-xr-xdebian/rules9
-rw-r--r--debian/source/format1
-rw-r--r--docker/bionic/Dockerfile14
-rw-r--r--examples/CMakeLists.txt16
-rw-r--r--examples/README.adoc9
-rw-r--r--examples/assert.c15
-rw-r--r--examples/cred.c15
-rw-r--r--examples/extern.h1
-rw-r--r--examples/info.c31
-rw-r--r--examples/manifest.c5
-rw-r--r--examples/reset.c9
-rw-r--r--examples/retries.c5
-rw-r--r--examples/select.c215
-rw-r--r--examples/setpin.c5
-rw-r--r--examples/util.c3
-rw-r--r--fuzz/CMakeLists.txt1
-rw-r--r--fuzz/Dockerfile9
-rw-r--r--fuzz/Makefile20
-rw-r--r--fuzz/README130
-rwxr-xr-xfuzz/build-coverage33
-rw-r--r--fuzz/dummy.h4
-rw-r--r--fuzz/export.gnu10
-rw-r--r--fuzz/functions.txt197
-rw-r--r--fuzz/fuzz_assert.c455
-rw-r--r--fuzz/fuzz_bio.c335
-rw-r--r--fuzz/fuzz_cred.c458
-rw-r--r--fuzz/fuzz_credman.c314
-rw-r--r--fuzz/fuzz_mgmt.c321
-rw-r--r--fuzz/libfuzzer.c174
-rw-r--r--fuzz/mutator_aux.c253
-rw-r--r--fuzz/mutator_aux.h49
-rw-r--r--[-rwxr-xr-x]fuzz/prng.c3
-rw-r--r--fuzz/report.tgzbin211709 -> 222723 bytes
-rw-r--r--fuzz/summary.txt31
-rw-r--r--man/CMakeLists.txt55
-rw-r--r--man/NOTES3
-rw-r--r--man/fido2-assert.133
-rw-r--r--man/fido2-cred.18
-rw-r--r--man/fido_assert_new.335
-rw-r--r--man/fido_cbor_info_new.322
-rw-r--r--man/fido_cred_new.365
-rw-r--r--man/fido_dev_get_touch_begin.373
-rw-r--r--man/fido_dev_open.333
-rw-r--r--openbsd-compat/clock_gettime.c32
-rwxr-xr-xopenbsd-compat/diff.sh24
-rw-r--r--openbsd-compat/openbsd-compat.h2
-rw-r--r--openbsd-compat/time.h46
-rw-r--r--openbsd-compat/types.h7
-rw-r--r--regress/assert.c16
-rw-r--r--regress/cred.c78
-rw-r--r--src/CMakeLists.txt17
-rw-r--r--src/assert.c2
-rw-r--r--src/cbor.c25
-rw-r--r--src/cred.c12
-rw-r--r--src/credman.c8
-rw-r--r--src/dev.c207
-rwxr-xr-xsrc/diff_exports.sh29
-rw-r--r--src/err.c4
-rw-r--r--src/es256.c2
-rw-r--r--src/export.gnu9
-rw-r--r--src/export.llvm9
-rw-r--r--src/export.msvc9
-rw-r--r--src/extern.h20
-rw-r--r--src/fido.h23
-rw-r--r--src/fido/err.h2
-rw-r--r--src/fido/param.h12
-rw-r--r--src/fido/types.h20
-rw-r--r--src/hid_hidapi.c226
-rw-r--r--src/hid_linux.c308
-rw-r--r--src/hid_openbsd.c91
-rw-r--r--src/hid_osx.c323
-rw-r--r--src/hid_win.c398
-rw-r--r--src/info.c16
-rw-r--r--src/io.c94
-rw-r--r--src/iso7816.c6
-rw-r--r--src/pin.c10
-rw-r--r--src/u2f.c100
-rw-r--r--tools/CMakeLists.txt7
-rw-r--r--tools/assert_get.c94
-rw-r--r--tools/assert_verify.c12
-rw-r--r--tools/base64.c5
-rw-r--r--tools/cred_make.c26
-rw-r--r--tools/cred_verify.c26
-rw-r--r--tools/credman.c21
-rw-r--r--tools/extern.h6
-rw-r--r--tools/fido2-assert.c6
-rwxr-xr-xtools/fido2-attach.sh14
-rw-r--r--tools/fido2-cred.c6
-rwxr-xr-xtools/fido2-detach.sh12
-rw-r--r--tools/fido2-token.c6
-rwxr-xr-xtools/fido2-unprot.sh75
-rwxr-xr-xtools/include_check.sh8
-rwxr-xr-xtools/macos_pkg.sh44
-rw-r--r--tools/token.c18
-rw-r--r--tools/util.c68
-rw-r--r--udev/70-u2f.rules192
-rwxr-xr-xudev/check.sh31
-rw-r--r--udev/fidodevs110
-rwxr-xr-xudev/genrules.awk55
-rw-r--r--windows/build.ps114
126 files changed, 4474 insertions, 3303 deletions
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 @@
1name: CIFuzz
2on: [pull_request]
3jobs:
4 Fuzzing:
5 runs-on: ubuntu-latest
6 steps:
7 - name: Build Fuzzers
8 uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
9 with:
10 oss-fuzz-project-name: 'libfido2'
11 dry-run: false
12 - name: Run Fuzzers
13 uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
14 with:
15 oss-fuzz-project-name: 'libfido2'
16 fuzz-seconds: 600
17 dry-run: false
18 - name: Upload Crash
19 uses: actions/upload-artifact@v1
20 if: failure()
21 with:
22 name: artifacts
23 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 @@
1name: static code analysis
2
3on:
4 push:
5 schedule:
6 - cron: '0 0 * * 1'
7
8env:
9 SCAN_IMG:
10 yes-docker-local.artifactory.in.yubico.org/static-code-analysis/c:v1
11 SECRET: ${{ secrets.ARTIFACTORY_READER_TOKEN }}
12
13jobs:
14 build:
15 runs-on: ubuntu-latest
16
17 steps:
18 - uses: actions/checkout@master
19
20 - name: Scan but do not fail on warnings
21 run: |
22 if [ "${SECRET}" != "" ]; then
23 docker login yes-docker-local.artifactory.in.yubico.org/ \
24 -u svc-static-code-analysis-reader \
25 -p ${{ secrets.ARTIFACTORY_READER_TOKEN }}
26 docker pull ${SCAN_IMG}
27 docker run -v${PWD}:/k -e COMPILE_DEPS="${COMPILE_DEPS}" \
28 -e PROJECT_NAME=${GITHUB_REPOSITORY#Yubico/} -t ${SCAN_IMG}
29 fi
30 continue-on-error: true
31
32 - uses: actions/upload-artifact@master
33 if: failure()
34 with:
35 name: suppression_files
36 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 @@
1name: windows
2
3on: [push]
4
5jobs:
6 build:
7
8 runs-on: windows-latest
9
10 steps:
11 - uses: actions/checkout@v1
12 - name: build
13 run: .\windows\build.ps1
14
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 0915625..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,9 +0,0 @@
1build/
2cscope.out
3fuzz/build/
4fuzz/corpus.tgz-
5fuzz/fuzz_*/
6fuzz/obj/
7fuzz/report
8fuzz/*.so
9output/
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index c2bff78..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,86 +0,0 @@
1language: c
2
3matrix:
4 include:
5 - os: linux
6 compiler: clang-7
7 dist: xenial
8 sudo: required
9 addons:
10 apt:
11 sources:
12 - ubuntu-toolchain-r-test
13 - llvm-toolchain-xenial-7
14 packages:
15 - clang-7
16 - cmake
17 - libssl-dev
18 - libudev-dev
19 script: /bin/sh -eux .travis/build-linux-clang
20 - os: linux
21 compiler: gcc-7
22 dist: xenial
23 sudo: required
24 addons:
25 apt:
26 sources:
27 - ubuntu-toolchain-r-test
28 packages:
29 - gcc-7
30 - cmake
31 - libssl-dev
32 - libudev-dev
33 script: /bin/sh -eux .travis/build-linux-gcc
34 - os: linux
35 compiler: i686-w64-mingw32-gcc-4.8
36 dist: xenial
37 sudo: required
38 addons:
39 apt:
40 sources:
41 - ubuntu-toolchain-r-test
42 packages:
43 - binutils-mingw-w64-i686
44 - gcc-mingw-w64
45 - g++-mingw-w64
46 - mingw-w64-i686-dev
47 - cmake
48 script: /bin/sh -eux .travis/build-linux-mingw
49 - os: osx
50 osx_image: xcode10.2
51 compiler: clang
52 sudo: required
53 script: /bin/sh -eux .travis/build-osx-clang
54 - os: linux
55 compiler: clang-7
56 dist: bionic
57 sudo: required
58 addons:
59 apt:
60 sources:
61 - ubuntu-toolchain-r-test
62 - llvm-toolchain-xenial-7
63 packages:
64 - clang-7
65 - cmake
66 - libssl-dev
67 - libudev-dev
68 script: /bin/sh -eux .travis/fuzz-linux-asan
69 - os: linux
70 compiler: clang-7
71 dist: bionic
72 sudo: required
73 addons:
74 apt:
75 sources:
76 - ubuntu-toolchain-r-test
77 - llvm-toolchain-xenial-7
78 packages:
79 - clang-7
80 - cmake
81 - libssl-dev
82 - libudev-dev
83 script: /bin/sh -eux .travis/fuzz-linux-msan
84
85notifications:
86 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 @@
1#!/bin/sh -eux
2
3${CC} --version
4
5# Check exports.
6(cd src && ./diff_exports.sh)
7
8# Build and install libcbor.
9git clone git://github.com/pjk/libcbor
10cd libcbor
11git checkout v0.5.0
12mkdir build
13(cd build && cmake ..)
14make -C build
15sudo make -C build install
16cd ..
17
18# Build, analyze, and install libfido2.
19mkdir build
20(cd build && scan-build cmake -DCMAKE_BUILD_TYPE=Debug ..)
21scan-build --status-bugs make -C build
22sudo 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 @@
1#!/bin/sh -eux
2
3${CC} --version
4
5# Build and install libcbor.
6git clone git://github.com/pjk/libcbor
7cd libcbor
8git checkout v0.5.0
9mkdir build
10(cd build && cmake ..)
11make -C build
12sudo make -C build install
13cd ..
14
15# Build and install libfido2.
16mkdir build
17(cd build && cmake -DCMAKE_BUILD_TYPE=Debug ..)
18make -C build
19sudo 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 @@
1#!/bin/sh -eux
2
3# XXX defining CC and cross-compiling confuses OpenSSL's build.
4unset CC
5
6sudo mkdir /fakeroot
7sudo chmod 755 /fakeroot
8
9cat << EOF > /tmp/mingw.cmake
10SET(CMAKE_SYSTEM_NAME Windows)
11SET(CMAKE_C_COMPILER i686-w64-mingw32-gcc)
12SET(CMAKE_CXX_COMPILER i686-w64-mingw32-g++)
13SET(CMAKE_RC_COMPILER i686-w64-mingw32-windres)
14SET(CMAKE_FIND_ROOT_PATH /fakeroot)
15SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
16SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
17SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
18EOF
19
20# Build and install libcbor.
21git clone git://github.com/pjk/libcbor
22cd libcbor
23git checkout v0.5.0
24mkdir build
25(cd build && cmake -DCMAKE_TOOLCHAIN_FILE=/tmp/mingw.cmake \
26 -DCMAKE_INSTALL_PREFIX=/fakeroot ..)
27make -C build
28sudo make -C build install
29cd ..
30
31# Build and install OpenSSL 1.1.0j.
32git clone git://github.com/openssl/openssl
33cd openssl
34git checkout OpenSSL_1_1_0j
35./Configure mingw --prefix=/fakeroot --openssldir=/fakeroot/openssl \
36 --cross-compile-prefix=i686-w64-mingw32-
37make
38sudo make install_sw
39cd ..
40
41# Build and install libfido2.
42export PKG_CONFIG_PATH=/fakeroot/lib/pkgconfig
43mkdir build
44(cd build && cmake -DCMAKE_TOOLCHAIN_FILE=/tmp/mingw.cmake \
45 -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=/fakeroot ..)
46make -C build
47sudo 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 @@
1#!/bin/sh -eux
2
3${CC} --version
4
5# Build and install libcbor.
6git clone git://github.com/pjk/libcbor
7cd libcbor
8git checkout v0.5.0
9mkdir build
10(cd build && cmake ..)
11make -C build
12sudo make -C build install
13cd ..
14
15# Install mandoc from Homebrew.
16brew install mandoc
17
18# Build and install libfido2.
19export PKG_CONFIG_PATH=/usr/local/opt/openssl@1.1/lib/pkgconfig
20mkdir build
21(cd build && cmake -DCMAKE_BUILD_TYPE=Debug ..)
22make -C build
23make -C build man_symlink_html
24sudo 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 @@
1#!/bin/sh -eux
2
3${CC} --version
4
5FAKEROOT=/fakeroot
6sudo mkdir ${FAKEROOT}
7sudo chmod 755 ${FAKEROOT}
8
9# Build and install libcbor.
10git clone git://github.com/pjk/libcbor
11cd libcbor
12patch -p0 < ../fuzz/README
13mkdir build
14cd build
15cmake -DCMAKE_C_FLAGS_DEBUG="-g2 -fno-omit-frame-pointer" \
16 -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=Debug \
17 -DCMAKE_INSTALL_PREFIX=${FAKEROOT} -DSANITIZE=ON \
18 -DCMAKE_INSTALL_LIBDIR=lib ..
19make
20sudo make install
21cd ../..
22
23# Build and install OpenSSL 1.1.1b.
24git clone git://github.com/openssl/openssl
25cd openssl
26git checkout OpenSSL_1_1_1b
27./Configure linux-x86_64-clang enable-asan --prefix=${FAKEROOT} \
28 --openssldir=${FAKEROOT}/openssl
29make clean
30make
31sudo make install_sw
32cd ..
33
34# Build libfido2.
35mkdir build
36cd build
37export PKG_CONFIG_PATH=/fakeroot/lib/pkgconfig
38cmake -DFUZZ=1 -DLIBFUZZER=1 -DASAN=1 -DUBSAN=1 -DCMAKE_C_COMPILER=clang \
39 -DCRYPTO_INCLUDE_DIRS=${FAKEROOT}/include \
40 -DCRYPTO_LIBRARY_DIRS=${FAKEROOT}/lib \
41 -DCBOR_INCLUDE_DIRS=${FAKEROOT}/include \
42 -DCBOR_LIBRARY_DIRS=${FAKEROOT}/lib \
43 -DCMAKE_BUILD_TYPE=Debug ..
44make
45
46# Fuzz with ASAN.
47mkdir corpus
48curl -s https://ambientworks.net/tmp/corpus.tgz > ../fuzz/corpus.tgz
49tar -C corpus -zxf ../fuzz/corpus.tgz
50fuzz/fuzz_cred -use_value_profile=1 -reload=30 -print_pcs=1 \
51 -print_funcs=30 -timeout=10 -runs=1 corpus/fuzz_cred
52fuzz/fuzz_assert -use_value_profile=1 -reload=30 -print_pcs=1 \
53 -print_funcs=30 -timeout=10 -runs=1 corpus/fuzz_assert
54fuzz/fuzz_credman -use_value_profile=1 -reload=30 -print_pcs=1 \
55 -print_funcs=30 -timeout=10 -runs=1 corpus/fuzz_credman
56fuzz/fuzz_mgmt -use_value_profile=1 -reload=30 -print_pcs=1 \
57 -print_funcs=30 -timeout=10 -runs=1 corpus/fuzz_mgmt
58fuzz/fuzz_bio -use_value_profile=1 -reload=30 -print_pcs=1 \
59 -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 @@
1#!/bin/sh -eux
2
3${CC} --version
4
5FAKEROOT=/fakeroot
6sudo mkdir ${FAKEROOT}
7sudo chmod 755 ${FAKEROOT}
8
9# Build and install libcbor.
10git clone git://github.com/pjk/libcbor
11cd libcbor
12patch -p0 < ../fuzz/README
13mkdir build
14cd build
15cmake -DCMAKE_C_FLAGS_DEBUG="-fsanitize=memory,undefined -g2 -fno-omit-frame-pointer" \
16 -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=Debug \
17 -DCMAKE_INSTALL_PREFIX=${FAKEROOT} -DSANITIZE=OFF \
18 -DCMAKE_INSTALL_LIBDIR=lib ..
19make
20sudo make install
21cd ../..
22
23# Build and install OpenSSL 1.1.1b.
24git clone git://github.com/openssl/openssl
25cd openssl
26git checkout OpenSSL_1_1_1b
27./Configure linux-x86_64-clang enable-msan --prefix=${FAKEROOT} \
28 --openssldir=${FAKEROOT}/openssl
29make clean
30make
31sudo make install_sw
32cd ..
33
34# Build libfido2.
35mkdir build
36cd build
37export PKG_CONFIG_PATH=/fakeroot/lib/pkgconfig
38cmake -DFUZZ=1 -DLIBFUZZER=1 -DMSAN=1 -DUBSAN=1 -DCMAKE_C_COMPILER=clang \
39 -DCRYPTO_INCLUDE_DIRS=${FAKEROOT}/include \
40 -DCRYPTO_LIBRARY_DIRS=${FAKEROOT}/lib \
41 -DCBOR_INCLUDE_DIRS=${FAKEROOT}/include \
42 -DCBOR_LIBRARY_DIRS=${FAKEROOT}/lib \
43 -DCMAKE_BUILD_TYPE=Debug ..
44make
45
46# Fuzz with MSAN.
47mkdir corpus
48curl -s https://ambientworks.net/tmp/corpus.tgz > ../fuzz/corpus.tgz
49tar -C corpus -zxf ../fuzz/corpus.tgz
50fuzz/fuzz_cred -use_value_profile=1 -reload=30 -print_pcs=1 \
51 -print_funcs=30 -timeout=10 -runs=1 corpus/fuzz_cred
52fuzz/fuzz_assert -use_value_profile=1 -reload=30 -print_pcs=1 \
53 -print_funcs=30 -timeout=10 -runs=1 corpus/fuzz_assert
54fuzz/fuzz_credman -use_value_profile=1 -reload=30 -print_pcs=1 \
55 -print_funcs=30 -timeout=10 -runs=1 corpus/fuzz_credman
56fuzz/fuzz_mgmt -use_value_profile=1 -reload=30 -print_pcs=1 \
57 -print_funcs=30 -timeout=10 -runs=1 corpus/fuzz_mgmt
58fuzz/fuzz_bio -use_value_profile=1 -reload=30 -print_pcs=1 \
59 -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)
10 10
11include(CheckCCompilerFlag) 11include(CheckCCompilerFlag)
12include(CheckFunctionExists) 12include(CheckFunctionExists)
13include(CheckLibraryExists)
14include(CheckSymbolExists)
13include(CheckIncludeFiles) 15include(CheckIncludeFiles)
14include(CheckTypeSize) 16include(CheckTypeSize)
15include(GNUInstallDirs) 17include(GNUInstallDirs)
@@ -19,7 +21,7 @@ set(CMAKE_VERBOSE_MAKEFILE on)
19set(CMAKE_POSITION_INDEPENDENT_CODE ON) 21set(CMAKE_POSITION_INDEPENDENT_CODE ON)
20 22
21set(FIDO_MAJOR "1") 23set(FIDO_MAJOR "1")
22set(FIDO_MINOR "4") 24set(FIDO_MINOR "5")
23set(FIDO_PATCH "0") 25set(FIDO_PATCH "0")
24set(FIDO_VERSION ${FIDO_MAJOR}.${FIDO_MINOR}.${FIDO_PATCH}) 26set(FIDO_VERSION ${FIDO_MAJOR}.${FIDO_MINOR}.${FIDO_PATCH})
25 27
@@ -33,21 +35,12 @@ if(CYGWIN OR MSYS)
33endif() 35endif()
34 36
35if(WIN32) 37if(WIN32)
36 add_definitions(-DWIN32_LEAN_AND_MEAN) 38 add_definitions(-DWIN32_LEAN_AND_MEAN -D_WIN32_WINNT=0x0600)
37endif() 39endif()
38 40
39if(APPLE) 41if(APPLE)
40 set(CMAKE_INSTALL_NAME_DIR 42 set(CMAKE_INSTALL_NAME_DIR
41 "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") 43 "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
42endif()
43
44# Observe OpenBSD's library versioning scheme.
45if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
46 set(LIB_VERSION ${FIDO_MAJOR}.${FIDO_MINOR})
47 set(LIB_SOVERSION ${LIB_VERSION})
48else()
49 set(LIB_VERSION ${FIDO_VERSION})
50 set(LIB_SOVERSION ${FIDO_MAJOR})
51endif() 44endif()
52 45
53if(MSVC) 46if(MSVC)
@@ -58,7 +51,7 @@ if(MSVC)
58 "under msvc") 51 "under msvc")
59 endif() 52 endif()
60 set(CBOR_LIBRARIES cbor) 53 set(CBOR_LIBRARIES cbor)
61 set(CRYPTO_LIBRARIES crypto-45) 54 set(CRYPTO_LIBRARIES crypto-46)
62 set(MSVC_DISABLED_WARNINGS_LIST 55 set(MSVC_DISABLED_WARNINGS_LIST
63 "C4200" # nonstandard extension used: zero-sized array in 56 "C4200" # nonstandard extension used: zero-sized array in
64 # struct/union; 57 # struct/union;
@@ -71,9 +64,9 @@ if(MSVC)
71 # The construction in the following 3 lines was taken from LibreSSL's 64 # The construction in the following 3 lines was taken from LibreSSL's
72 # CMakeLists.txt. 65 # CMakeLists.txt.
73 string(REPLACE "C" " -wd" MSVC_DISABLED_WARNINGS_STR 66 string(REPLACE "C" " -wd" MSVC_DISABLED_WARNINGS_STR
74 ${MSVC_DISABLED_WARNINGS_LIST}) 67 ${MSVC_DISABLED_WARNINGS_LIST})
75 string(REGEX REPLACE "[/-]W[1234][ ]?" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS}) 68 string(REGEX REPLACE "[/-]W[1234][ ]?" "" CMAKE_C_FLAGS ${CMAKE_C_FLAGS})
76 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -MP -W4 ${MSVC_DISABLED_WARNINGS_STR}") 69 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -MP -W4 -WX ${MSVC_DISABLED_WARNINGS_STR}")
77 set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Z7") 70 set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Z7")
78 set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zi") 71 set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /Zi")
79else() 72else()
@@ -102,13 +95,18 @@ else()
102 if(CMAKE_SYSTEM_NAME STREQUAL "Linux") 95 if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
103 pkg_search_module(UDEV libudev REQUIRED) 96 pkg_search_module(UDEV libudev REQUIRED)
104 set(UDEV_NAME "udev") 97 set(UDEV_NAME "udev")
98 include_directories(${UDEV_INCLUDE_DIRS})
99 link_directories(${UDEV_LIBRARY_DIRS})
105 # Define be32toh(). 100 # Define be32toh().
106 add_definitions(-D_GNU_SOURCE) 101 add_definitions(-D_GNU_SOURCE)
107 # If using hidapi, use hidapi-hidraw. 102 # If using hidapi, use hidapi-hidraw.
108 set(HIDAPI_SUFFIX -hidraw) 103 set(HIDAPI_SUFFIX -hidraw)
109 elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR 104 # Look for clock_gettime in librt.
110 CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") 105 check_library_exists(rt clock_gettime "time.h" HAVE_CLOCK_GETTIME)
111 set(BASE_LIBRARIES usbhid) 106 if(HAVE_CLOCK_GETTIME)
107 set(BASE_LIBRARIES ${BASE_LIBRARIES} rt)
108 add_definitions(-DHAVE_CLOCK_GETTIME)
109 endif()
112 endif() 110 endif()
113 111
114 if(MINGW) 112 if(MINGW)
@@ -122,6 +120,8 @@ else()
122 add_definitions(-DUSE_HIDAPI) 120 add_definitions(-DUSE_HIDAPI)
123 pkg_search_module(HIDAPI hidapi${HIDAPI_SUFFIX} REQUIRED) 121 pkg_search_module(HIDAPI hidapi${HIDAPI_SUFFIX} REQUIRED)
124 if(HIDAPI_FOUND) 122 if(HIDAPI_FOUND)
123 include_directories(${HIDAPI_INCLUDE_DIRS})
124 link_directories(${HIDAPI_LIBRARY_DIRS})
125 set(HIDAPI_LIBRARIES hidapi${HIDAPI_SUFFIX}) 125 set(HIDAPI_LIBRARIES hidapi${HIDAPI_SUFFIX})
126 endif() 126 endif()
127 endif() 127 endif()
@@ -153,24 +153,6 @@ else()
153 endif() 153 endif()
154 add_definitions(-DFIDO_FUZZ) 154 add_definitions(-DFIDO_FUZZ)
155 endif() 155 endif()
156
157 if(ASAN)
158 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address,leak")
159 endif()
160
161 if(MSAN)
162 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=memory")
163 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-memory-track-origins")
164 endif()
165
166 if(UBSAN)
167 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined")
168 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize-trap=undefined")
169 endif()
170
171 if(COVERAGE)
172 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-instr-generate -fcoverage-mapping")
173 endif()
174endif() 156endif()
175 157
176# Use -Wshorten-64-to-32 if available. 158# Use -Wshorten-64-to-32 if available.
@@ -333,6 +315,20 @@ if(UNIX)
333 add_definitions(-DHAVE_DEV_URANDOM) 315 add_definitions(-DHAVE_DEV_URANDOM)
334endif() 316endif()
335 317
318# clock_gettime
319if(NOT HAVE_CLOCK_GETTIME)
320 check_function_exists(clock_gettime HAVE_CLOCK_GETTIME)
321 if(HAVE_CLOCK_GETTIME)
322 add_definitions(-DHAVE_CLOCK_GETTIME)
323 endif()
324endif()
325
326# timespecsub
327check_symbol_exists(timespecsub sys/time.h HAVE_TIMESPECSUB)
328if(HAVE_TIMESPECSUB)
329 add_definitions(-DHAVE_TIMESPECSUB)
330endif()
331
336# export list 332# export list
337if(APPLE AND (CMAKE_C_COMPILER_ID STREQUAL "Clang" OR 333if(APPLE AND (CMAKE_C_COMPILER_ID STREQUAL "Clang" OR
338 CMAKE_C_COMPILER_ID STREQUAL "AppleClang")) 334 CMAKE_C_COMPILER_ID STREQUAL "AppleClang"))
@@ -366,7 +362,7 @@ elseif(NOT MSVC)
366 endif() 362 endif()
367else() 363else()
368 string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} 364 string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS}
369 " /def:\"${CMAKE_CURRENT_SOURCE_DIR}/src/export.msvc\"") 365 " /def:\"${CMAKE_CURRENT_SOURCE_DIR}/src/export.msvc\"")
370endif() 366endif()
371 367
372include_directories(${CMAKE_SOURCE_DIR}/src) 368include_directories(${CMAKE_SOURCE_DIR}/src)
@@ -376,38 +372,33 @@ include_directories(${CRYPTO_INCLUDE_DIRS})
376link_directories(${CBOR_LIBRARY_DIRS}) 372link_directories(${CBOR_LIBRARY_DIRS})
377link_directories(${CRYPTO_LIBRARY_DIRS}) 373link_directories(${CRYPTO_LIBRARY_DIRS})
378 374
375message(STATUS "BASE_LIBRARIES: ${BASE_LIBRARIES}")
376message(STATUS "CBOR_INCLUDE_DIRS: ${CBOR_INCLUDE_DIRS}")
377message(STATUS "CBOR_LIBRARIES: ${CBOR_LIBRARIES}")
378message(STATUS "CBOR_LIBRARY_DIRS: ${CBOR_LIBRARY_DIRS}")
379message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
379message(STATUS "CMAKE_C_COMPILER: ${CMAKE_C_COMPILER}") 380message(STATUS "CMAKE_C_COMPILER: ${CMAKE_C_COMPILER}")
380message(STATUS "CMAKE_C_COMPILER_ID: ${CMAKE_C_COMPILER_ID}") 381message(STATUS "CMAKE_C_COMPILER_ID: ${CMAKE_C_COMPILER_ID}")
381message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}")
382message(STATUS "CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR}") 382message(STATUS "CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR}")
383message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") 383message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}")
384message(STATUS "CBOR_INCLUDE_DIRS: ${CBOR_INCLUDE_DIRS}")
385message(STATUS "CBOR_LIBRARY_DIRS: ${CBOR_LIBRARY_DIRS}")
386message(STATUS "CBOR_LIBRARIES: ${CBOR_LIBRARIES}")
387message(STATUS "CRYPTO_INCLUDE_DIRS: ${CRYPTO_INCLUDE_DIRS}") 384message(STATUS "CRYPTO_INCLUDE_DIRS: ${CRYPTO_INCLUDE_DIRS}")
388message(STATUS "CRYPTO_LIBRARY_DIRS: ${CRYPTO_LIBRARY_DIRS}")
389message(STATUS "CRYPTO_LIBRARIES: ${CRYPTO_LIBRARIES}") 385message(STATUS "CRYPTO_LIBRARIES: ${CRYPTO_LIBRARIES}")
390message(STATUS "BASE_LIBRARIES: ${BASE_LIBRARIES}") 386message(STATUS "CRYPTO_LIBRARY_DIRS: ${CRYPTO_LIBRARY_DIRS}")
391message(STATUS "HIDAPI_LIBRARIES: ${HIDAPI_LIBRARIES}") 387message(STATUS "FIDO_VERSION: ${FIDO_VERSION}")
392message(STATUS "VERSION: ${FIDO_VERSION}")
393message(STATUS "LIB_VERSION: ${LIB_VERSION}")
394message(STATUS "LIB_SOVERSION: ${LIB_SOVERSION}")
395message(STATUS "FUZZ: ${FUZZ}") 388message(STATUS "FUZZ: ${FUZZ}")
396message(STATUS "AFL: ${AFL}") 389if(USE_HIDAPI)
390 message(STATUS "HIDAPI_INCLUDE_DIRS: ${HIDAPI_INCLUDE_DIRS}")
391 message(STATUS "HIDAPI_LIBRARIES: ${HIDAPI_LIBRARIES}")
392 message(STATUS "HIDAPI_LIBRARY_DIRS: ${HIDAPI_LIBRARY_DIRS}")
393endif()
397message(STATUS "LIBFUZZER: ${LIBFUZZER}") 394message(STATUS "LIBFUZZER: ${LIBFUZZER}")
398message(STATUS "ASAN: ${ASAN}")
399message(STATUS "MSAN: ${MSAN}")
400message(STATUS "COVERAGE: ${COVERAGE}")
401message(STATUS "TLS: ${TLS}") 395message(STATUS "TLS: ${TLS}")
396message(STATUS "UDEV_INCLUDE_DIRS: ${UDEV_INCLUDE_DIRS}")
397message(STATUS "UDEV_LIBRARIES: ${UDEV_LIBRARIES}")
398message(STATUS "UDEV_LIBRARY_DIRS: ${UDEV_LIBRARY_DIRS}")
399message(STATUS "UDEV_RULES_DIR: ${UDEV_RULES_DIR}")
402message(STATUS "USE_HIDAPI: ${USE_HIDAPI}") 400message(STATUS "USE_HIDAPI: ${USE_HIDAPI}")
403 401
404if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
405 message(STATUS "UDEV_INCLUDE_DIRS: ${UDEV_INCLUDE_DIRS}")
406 message(STATUS "UDEV_LIBRARY_DIRS: ${UDEV_LIBRARY_DIRS}")
407 message(STATUS "UDEV_LIBRARIES: ${UDEV_LIBRARIES}")
408 message(STATUS "UDEV_RULES_DIR: ${UDEV_RULES_DIR}")
409endif()
410
411subdirs(src) 402subdirs(src)
412subdirs(examples) 403subdirs(examples)
413subdirs(tools) 404subdirs(tools)
@@ -415,7 +406,7 @@ subdirs(man)
415 406
416if(NOT WIN32) 407if(NOT WIN32)
417 if(CMAKE_BUILD_TYPE STREQUAL "Debug") 408 if(CMAKE_BUILD_TYPE STREQUAL "Debug")
418 if(NOT MSAN AND NOT LIBFUZZER) 409 if(NOT LIBFUZZER AND NOT FUZZ)
419 subdirs(regress) 410 subdirs(regress)
420 endif() 411 endif()
421 endif() 412 endif()
diff --git a/NEWS b/NEWS
index 153ff71..b651ca0 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,21 @@
1* Version 1.5.0 (2020-09-01)
2 ** hid_linux: return FIDO_OK if no devices are found.
3 ** hid_osx:
4 - repair communication with U2F tokens, gh#166;
5 - reliability fixes.
6 ** fido2-{assert,cred}: new options to explicitly toggle UP, UV.
7 ** Support for configurable report lengths.
8 ** New API calls:
9 - fido_cbor_info_maxcredcntlst;
10 - fido_cbor_info_maxcredidlen;
11 - fido_cred_aaguid_len;
12 - fido_cred_aaguid_ptr;
13 - fido_dev_get_touch_begin;
14 - fido_dev_get_touch_status.
15 ** Use COSE_ECDH_ES256 with CTAP_CBOR_CLIENT_PIN; gh#154.
16 ** Allow CTAP messages up to 2048 bytes; gh#171.
17 ** Ensure we only list USB devices by default.
18
1* Version 1.4.0 (2020-04-15) 19* Version 1.4.0 (2020-04-15)
2 ** hid_hidapi: hidapi backend; enable with -DUSE_HIDAPI=1. 20 ** hid_hidapi: hidapi backend; enable with -DUSE_HIDAPI=1.
3 ** Fall back to U2F if the key claims to, but does not support FIDO2. 21 ** 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 @@
1== libfido2 1== libfido2
2 2
3image:https://api.travis-ci.org/Yubico/libfido2.svg?branch=master["Build Status (Travis)", link="https://travis-ci.org/Yubico/libfido2"] 3image:https://github.com/yubico/libfido2/workflows/linux/badge.svg["Linux Build Status (github actions)", link="https://github.com/Yubico/libfido2/actions"]
4image:https://github.com/yubico/libfido2/workflows/windows/badge.svg["windows build status (github actions)", link="https://github.com/Yubico/libfido2/actions"] 4image:https://github.com/yubico/libfido2/workflows/macos/badge.svg["macOS Build Status (github actions)", link="https://github.com/Yubico/libfido2/actions"]
5image:https://img.shields.io/badge/license-BSD-blue.svg["License", link="https://raw.githubusercontent.com/Yubico/libfido2/master/LICENSE"] 5image:https://github.com/yubico/libfido2/workflows/windows/badge.svg["Windows Build Status (github actions)", link="https://github.com/Yubico/libfido2/actions"]
6image:https://github.com/yubico/libfido2/workflows/fuzzer/badge.svg["Fuzz Status (github actions)", link="https://github.com/Yubico/libfido2/actions"]
7image: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"]
6 8
7*libfido2* provides library functionality and command-line tools to 9*libfido2* provides library functionality and command-line tools to
8communicate with a FIDO device over USB, and to verify attestation and 10communicate with a FIDO device over USB, and to verify attestation and
@@ -14,7 +16,7 @@ For usage, see the `examples/` directory.
14 16
15=== License 17=== License
16 18
17*libfido2* is licensed under the BSD 2-clause license. See the _LICENSE_ 19*libfido2* is licensed under the BSD 2-clause license. See the LICENSE
18file for the full license text. 20file for the full license text.
19 21
20=== Supported Platforms 22=== Supported Platforms
@@ -31,11 +33,17 @@ is also available.
31 33
32==== Releases 34==== Releases
33 35
34The current release of *libfido2* is 1.4.0. Please consult Yubico's 36The current release of *libfido2* is 1.5.0. Please consult Yubico's
35https://developers.yubico.com/libfido2/Releases[release page] for source 37https://developers.yubico.com/libfido2/Releases[release page] for source
36and binary releases. 38and binary releases.
37 39
38==== Ubuntu 40==== Ubuntu 20.04 (Focal)
41
42 $ sudo apt install libfido2-1
43 $ sudo apt install libfido2-dev
44 $ sudo apt install libfido2-doc
45
46==== Ubuntu 18.04 (Bionic) and 16.04 (Xenial)
39 47
40 $ sudo apt install software-properties-common 48 $ sudo apt install software-properties-common
41 $ sudo apt-add-repository ppa:yubico/stable 49 $ sudo apt-add-repository ppa:yubico/stable
@@ -52,15 +60,16 @@ Or from source, on UNIX-like systems:
52 $ make -C build 60 $ make -C build
53 $ sudo make -C build install 61 $ sudo make -C build install
54 62
55Depending on the platform, the PKG_CONFIG_PATH environment variable may need to 63Depending on the platform,
56be set. 64https://www.freedesktop.org/wiki/Software/pkg-config/[pkg-config] may need to
65be installed, or the PKG_CONFIG_PATH environment variable set.
57 66
58*libfido2* depends on https://github.com/pjk/libcbor[libcbor] and 67*libfido2* depends on https://github.com/pjk/libcbor[libcbor] and
59https://www.openssl.org[OpenSSL]. On Linux, libudev (part of 68https://www.openssl.org[OpenSSL]. On Linux, libudev (part of
60https://www.freedesktop.org/wiki/Software/systemd[systemd]) is also required. 69https://www.freedesktop.org/wiki/Software/systemd[systemd]) is also required.
61 70
62For complete, OS-specific installation instructions, please refer to the 71For complete, OS-specific installation instructions, please refer to the
63`.travis/` (Linux, MacOS) and `windows/` directories. 72`.actions/` (Linux, MacOS) and `windows/` directories.
64 73
65On Linux, you will need to add a udev rule to be able to access the FIDO 74On Linux, you will need to add a udev rule to be able to access the FIDO
66device, or run as root. For example, the udev rule may contain the following: 75device, 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 @@
1libfido2 (1.2.0~ppa1~bionic1) bionic; urgency=low
2
3 * Credential management support.
4 * New API reflecting FIDO's 3-state booleans (true, false, absent):
5 - fido_assert_set_up;
6 - fido_assert_set_uv;
7 - fido_cred_set_rk;
8 - fido_cred_set_uv.
9 * Command-line tools for Windows.
10 * Documentation and reliability fixes.
11 * fido_{assert,cred}_set_options() are now marked as deprecated.
12
13 -- pedro martelletto <pedro@yubico.com> Fri, 23 Aug 2019 12:08:02 +0000
14
15libfido2 (1.1.0) bionic; urgency=low
16
17 * MacOS: fix IOKit crash on HID read.
18 * Windows: fix contents of release file.
19 * EdDSA (Ed25519) support.
20 * fido_dev_make_cred: fix order of CBOR map keys.
21 * fido_dev_get_assert: plug memory leak when operating on U2F devices.
22
23 -- pedro martelletto <pedro@yubico.com> Tue, 07 May 2019 08:03:21 +0000
24
25libfido2 (1.0.0) bionic; urgency=low
26
27 * Native HID support on Linux, MacOS, and Windows.
28 * fido2-{assert,cred}: new -u option to force U2F on dual authenticators.
29 * fido2-assert: support for multiple resident keys with the same RP.
30 * Strict checks for CTAP2 compliance on received CBOR payloads.
31 * Better fuzzing harnesses.
32 * Documentation and reliability fixes.
33
34 -- pedro martelletto <pedro@yubico.com> Tue, 19 Mar 2019 07:38:36 +0000
35
36libfido2 (0.4.0) bionic; urgency=low
37
38 * fido2-assert: print the user id for resident credentials.
39 * Fix encoding of COSE algorithms when making a credential.
40 * Rework purpose of fido_cred_set_type; no ABI change.
41 * Minor documentation and code fixes.
42
43 -- pedro martelletto <pedro@yubico.com> Mon, 07 Jan 2019 08:22:01 +0000
44
45libfido2 (0.3.0) bionic; urgency=low
46
47 * Various reliability fixes.
48 * Merged fuzzing instrumentation.
49 * Added regress tests.
50 * Added support for FIDO 2's hmac-secret extension.
51 * New API calls:
52 - fido_assert_hmac_secret_len;
53 - fido_assert_hmac_secret_ptr;
54 - fido_assert_set_extensions;
55 - fido_assert_set_hmac_salt;
56 - fido_cred_set_extensions;
57 - fido_dev_force_fido2.
58 * Support for native builds with Microsoft Visual Studio 17.
59
60 -- pedro martelletto <pedro@yubico.com> Tue, 11 Sep 2018 09:05:32 +0000
61
62libfido2 (0.2.0) bionic; urgency=low
63
64 * Added command-line tools.
65 * Added a couple of missing get functions.
66
67 -- pedro martelletto <pedro@yubico.com> Mon, 18 Jun 2018 10:44:11 +0000
68
69libfido2 (0.1.1~dev) bionic; urgency=low
70
71 * Added documentation.
72 * Minor fixes.
73
74 -- pedro martelletto <pedro@yubico.com> Wed, 30 May 2018 13:16:28 +0000
75
76libfido2 (0.1.0~dev) bionic; urgency=low
77
78 * Initial release.
79
80 -- pedro martelletto <pedro@yubico.com> 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 @@
19
diff --git a/debian/control b/debian/control
deleted file mode 100644
index 50b9482..0000000
--- a/debian/control
+++ /dev/null
@@ -1,53 +0,0 @@
1Source: libfido2
2Priority: optional
3Maintainer: Yubico Open Source Maintainers <ossmaint@yubico.com>
4Uploaders: pedro martelletto <pedro@yubico.com>
5Standards-Version: 4.1.2
6Section: libs
7Homepage: https://github.com/yubico/libfido2
8Build-Depends: debhelper (>= 9),
9 pkg-config,
10 cmake,
11 mandoc,
12 libcbor-dev,
13 libssl-dev,
14 libudev-dev
15
16Package: libfido2-1
17Architecture: any
18Multi-Arch: same
19Depends: libcbor0, libssl1.1, libudev1, ${shlibs:Depends}, ${misc:Depends}
20Description: library for generating and verifying FIDO 2.0 objects
21 A library for communicating with a FIDO device over USB, and for verifying
22 attestation and assertion signatures. FIDO U2F (CTAP 1) and FIDO 2.0 (CTAP 2)
23 are supported. This package contains the runtime library.
24
25Package: libfido2-dev
26Section: libdevel
27Architecture: any
28Multi-Arch: same
29Depends: libfido2-1 (= ${binary:Version}), ${misc:Depends}
30Suggests: libssl-dev
31Description: library for generating and verifying FIDO 2.0 objects (development headers)
32 A library for communicating with a FIDO device over USB, and for verifying
33 attestation and assertion signatures. FIDO U2F (CTAP 1) and FIDO 2.0 (CTAP 2)
34 are supported. This package contains the development headers.
35
36Package: fido2-tools
37Section: utils
38Architecture: any
39Multi-Arch: foreign
40Depends: libfido2-1 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends}
41Description: command-line tools to configure and use a FIDO 2 token
42 A set of tools to manage a FIDO 2 token, generate credentials and
43 assertions, and verify them.
44
45Package: libfido2-udev
46Section: libs
47Architecture: all
48Multi-Arch: foreign
49Depends: ${misc:Depends}
50Conflicts: libu2f-udev
51Description: udev rules for access to U2F and FIDO2 devices
52 A set of udev rules allowing unprivileged system-level access
53 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 @@
1Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
2Upstream-Name: libfido2
3Source: https://github.com/yubico/libfido2
4
5Files: *
6Copyright: Copyright (c) 2018 Yubico AB. All rights reserved.
7License: BSD-2-clause
8
9Files: openbsd-compat/strlcpy.c openbsd-compat/strlcat.c
10Copyright: Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
11License: ISC
12
13Files: src/compat/timingsafe_bcmp.c
14Copyright: Copyright (c) 2010 Damien Miller. All rights reserved.
15License: ISC
16
17Files:
18 openbsd-compat/bsd-getpagesize.c
19 openbsd-compat/err.h
20 openbsd-compat/explicit_bzero.c
21 openbsd-compat/explicit_bzero_win32.c
22 openbsd-compat/types.h
23Copyright: Public domain
24License: public-domain
25
26Files: openbsd-compat/recallocarray.c
27Copyright: Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net>
28License: ISC
29
30Files: openbsd-compat/readpassphrase.h
31Copyright: Copyright (c) 2000, 2002 Todd C. Miller <Todd.Miller@courtesan.com>
32License: ISC
33
34Files: openbsd-compat/readpassphrase.c
35Copyright: Copyright (c) 2000-2002, 2007, 2010 Todd C. Miller <Todd.Miller@courtesan.com>
36License: ISC
37
38Files: openbsd-compat/getopt.h
39Copyright: Copyright (c) 2000 The NetBSD Foundation, Inc. All rights reserved.
40License: BSD-2-clause
41
42Files: openbsd-compat/getopt_long.c
43Copyright: Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
44 Copyright (c) 2000 The NetBSD Foundation, Inc. All rights reserved.
45License: ISC and BSD-2-clause
46
47License: BSD-2-clause
48 Redistribution and use in source and binary forms, with or without
49 modification, are permitted provided that the following conditions are
50 met:
51 .
52 1. Redistributions of source code must retain the above copyright
53 notice, this list of conditions and the following disclaimer.
54 2. Redistributions in binary form must reproduce the above copyright
55 notice, this list of conditions and the following disclaimer in
56 the documentation and/or other materials provided with the
57 distribution.
58 .
59 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
60 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
61 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
62 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
63 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
64 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
65 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
66 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
67 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
68 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
69 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
70
71License: public-domain
72 Public domain.
73
74License: ISC
75 Permission to use, copy, modify, and distribute this software for any
76 purpose with or without fee is hereby granted, provided that the above
77 copyright notice and this permission notice appear in all copies.
78 .
79 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
80 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
81 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
82 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
83 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
84 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
85 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 @@
1usr/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 @@
1man/fido2-assert.1
2man/fido2-cred.1
3man/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 @@
1usr/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 @@
1libfido2.so.1 libfido2-1 #MINVER#
2 eddsa_pk_free@Base 1.1.0
3 eddsa_pk_from_EVP_PKEY@Base 1.1.0
4 eddsa_pk_from_ptr@Base 1.1.0
5 eddsa_pk_new@Base 1.1.0
6 eddsa_pk_to_EVP_PKEY@Base 1.1.0
7 es256_pk_free@Base 1.1.0
8 es256_pk_from_EC_KEY@Base 1.1.0
9 es256_pk_from_ptr@Base 1.1.0
10 es256_pk_new@Base 1.1.0
11 es256_pk_to_EVP_PKEY@Base 1.1.0
12 fido_assert_allow_cred@Base 1.1.0
13 fido_assert_authdata_len@Base 1.1.0
14 fido_assert_authdata_ptr@Base 1.1.0
15 fido_assert_clientdata_hash_len@Base 1.1.0
16 fido_assert_clientdata_hash_ptr@Base 1.1.0
17 fido_assert_count@Base 1.1.0
18 fido_assert_flags@Base 1.1.0
19 fido_assert_free@Base 1.1.0
20 fido_assert_hmac_secret_len@Base 1.1.0
21 fido_assert_hmac_secret_ptr@Base 1.1.0
22 fido_assert_id_len@Base 1.1.0
23 fido_assert_id_ptr@Base 1.1.0
24 fido_assert_new@Base 1.1.0
25 fido_assert_rp_id@Base 1.1.0
26 fido_assert_set_authdata@Base 1.1.0
27 fido_assert_set_clientdata_hash@Base 1.1.0
28 fido_assert_set_count@Base 1.1.0
29 fido_assert_set_extensions@Base 1.1.0
30 fido_assert_set_hmac_salt@Base 1.1.0
31 fido_assert_set_options@Base 1.1.0
32 fido_assert_set_rp@Base 1.1.0
33 fido_assert_set_sig@Base 1.1.0
34 fido_assert_set_up@Base 1.2.0
35 fido_assert_set_uv@Base 1.2.0
36 fido_assert_sig_len@Base 1.1.0
37 fido_assert_sig_ptr@Base 1.1.0
38 fido_assert_user_display_name@Base 1.1.0
39 fido_assert_user_icon@Base 1.1.0
40 fido_assert_user_id_len@Base 1.1.0
41 fido_assert_user_id_ptr@Base 1.1.0
42 fido_assert_user_name@Base 1.1.0
43 fido_assert_verify@Base 1.1.0
44 fido_cbor_info_aaguid_len@Base 1.1.0
45 fido_cbor_info_aaguid_ptr@Base 1.1.0
46 fido_cbor_info_extensions_len@Base 1.1.0
47 fido_cbor_info_extensions_ptr@Base 1.1.0
48 fido_cbor_info_free@Base 1.1.0
49 fido_cbor_info_maxmsgsiz@Base 1.1.0
50 fido_cbor_info_new@Base 1.1.0
51 fido_cbor_info_options_len@Base 1.1.0
52 fido_cbor_info_options_name_ptr@Base 1.1.0
53 fido_cbor_info_options_value_ptr@Base 1.1.0
54 fido_cbor_info_protocols_len@Base 1.1.0
55 fido_cbor_info_protocols_ptr@Base 1.1.0
56 fido_cbor_info_versions_len@Base 1.1.0
57 fido_cbor_info_versions_ptr@Base 1.1.0
58 fido_cred_authdata_len@Base 1.1.0
59 fido_cred_authdata_ptr@Base 1.1.0
60 fido_cred_clientdata_hash_len@Base 1.1.0
61 fido_cred_clientdata_hash_ptr@Base 1.1.0
62 fido_cred_display_name@Base 1.2.0
63 fido_cred_exclude@Base 1.1.0
64 fido_cred_flags@Base 1.1.0
65 fido_cred_fmt@Base 1.1.0
66 fido_cred_free@Base 1.1.0
67 fido_cred_id_len@Base 1.1.0
68 fido_cred_id_ptr@Base 1.1.0
69 fido_cred_new@Base 1.1.0
70 fido_cred_pubkey_len@Base 1.1.0
71 fido_cred_pubkey_ptr@Base 1.1.0
72 fido_cred_rp_id@Base 1.1.0
73 fido_cred_rp_name@Base 1.1.0
74 fido_cred_set_authdata@Base 1.1.0
75 fido_cred_set_clientdata_hash@Base 1.1.0
76 fido_cred_set_extensions@Base 1.1.0
77 fido_cred_set_fmt@Base 1.1.0
78 fido_cred_set_options@Base 1.1.0
79 fido_cred_set_rk@Base 1.2.0
80 fido_cred_set_rp@Base 1.1.0
81 fido_cred_set_sig@Base 1.1.0
82 fido_cred_set_type@Base 1.1.0
83 fido_cred_set_user@Base 1.1.0
84 fido_cred_set_uv@Base 1.2.0
85 fido_cred_set_x509@Base 1.1.0
86 fido_cred_sig_len@Base 1.1.0
87 fido_cred_sig_ptr@Base 1.1.0
88 fido_cred_type@Base 1.2.0
89 fido_cred_user_id_len@Base 1.2.0
90 fido_cred_user_id_ptr@Base 1.2.0
91 fido_cred_user_name@Base 1.2.0
92 fido_cred_verify@Base 1.1.0
93 fido_cred_x5c_len@Base 1.1.0
94 fido_cred_x5c_ptr@Base 1.1.0
95 fido_credman_del_dev_rk@Base 1.2.0
96 fido_credman_get_dev_metadata@Base 1.2.0
97 fido_credman_get_dev_rk@Base 1.2.0
98 fido_credman_get_dev_rp@Base 1.2.0
99 fido_credman_metadata_free@Base 1.2.0
100 fido_credman_metadata_new@Base 1.2.0
101 fido_credman_rk@Base 1.2.0
102 fido_credman_rk_count@Base 1.2.0
103 fido_credman_rk_existing@Base 1.2.0
104 fido_credman_rk_free@Base 1.2.0
105 fido_credman_rk_new@Base 1.2.0
106 fido_credman_rk_remaining@Base 1.2.0
107 fido_credman_rp_count@Base 1.2.0
108 fido_credman_rp_free@Base 1.2.0
109 fido_credman_rp_id@Base 1.2.0
110 fido_credman_rp_id_hash_len@Base 1.2.0
111 fido_credman_rp_id_hash_ptr@Base 1.2.0
112 fido_credman_rp_name@Base 1.2.0
113 fido_credman_rp_new@Base 1.2.0
114 fido_dev_build@Base 1.1.0
115 fido_dev_close@Base 1.1.0
116 fido_dev_flags@Base 1.1.0
117 fido_dev_force_fido2@Base 1.1.0
118 fido_dev_force_u2f@Base 1.1.0
119 fido_dev_free@Base 1.1.0
120 fido_dev_get_assert@Base 1.1.0
121 fido_dev_get_cbor_info@Base 1.1.0
122 fido_dev_get_retry_count@Base 1.1.0
123 fido_dev_info_free@Base 1.1.0
124 fido_dev_info_manifest@Base 1.1.0
125 fido_dev_info_manufacturer_string@Base 1.1.0
126 fido_dev_info_new@Base 1.1.0
127 fido_dev_info_path@Base 1.1.0
128 fido_dev_info_product@Base 1.1.0
129 fido_dev_info_product_string@Base 1.1.0
130 fido_dev_info_ptr@Base 1.1.0
131 fido_dev_info_vendor@Base 1.1.0
132 fido_dev_is_fido2@Base 1.1.0
133 fido_dev_major@Base 1.1.0
134 fido_dev_make_cred@Base 1.1.0
135 fido_dev_minor@Base 1.1.0
136 fido_dev_new@Base 1.1.0
137 fido_dev_open@Base 1.1.0
138 fido_dev_protocol@Base 1.1.0
139 fido_dev_reset@Base 1.1.0
140 fido_dev_set_io_functions@Base 1.1.0
141 fido_dev_set_pin@Base 1.1.0
142 fido_init@Base 1.1.0
143 fido_strerr@Base 1.1.0
144 rs256_pk_free@Base 1.1.0
145 rs256_pk_from_RSA@Base 1.1.0
146 rs256_pk_from_ptr@Base 1.1.0
147 rs256_pk_new@Base 1.1.0
148 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 @@
1usr/include
2usr/lib/*/*.so
3usr/lib/*/pkgconfig/*.pc
4usr/share/doc/libfido2/html/eddsa_pk_new.html
5usr/share/doc/libfido2/html/es256_pk_new.html
6usr/share/doc/libfido2/html/fido_init.html
7usr/share/doc/libfido2/html/fido_assert_new.html
8usr/share/doc/libfido2/html/fido_assert_allow_cred.html
9usr/share/doc/libfido2/html/fido_assert_set_authdata.html
10usr/share/doc/libfido2/html/fido_assert_verify.html
11usr/share/doc/libfido2/html/fido_bio_dev_get_info.html
12usr/share/doc/libfido2/html/fido_bio_enroll_new.html
13usr/share/doc/libfido2/html/fido_bio_info_new.html
14usr/share/doc/libfido2/html/fido_bio_template.html
15usr/share/doc/libfido2/html/fido_cbor_info_new.html
16usr/share/doc/libfido2/html/fido_cred_new.html
17usr/share/doc/libfido2/html/fido_cred_exclude.html
18usr/share/doc/libfido2/html/fido_credman_metadata_new.html
19usr/share/doc/libfido2/html/fido_cred_set_authdata.html
20usr/share/doc/libfido2/html/fido_cred_verify.html
21usr/share/doc/libfido2/html/fido_dev_get_assert.html
22usr/share/doc/libfido2/html/fido_dev_info_manifest.html
23usr/share/doc/libfido2/html/fido_dev_make_cred.html
24usr/share/doc/libfido2/html/fido_dev_open.html
25usr/share/doc/libfido2/html/fido_dev_set_io_functions.html
26usr/share/doc/libfido2/html/fido_dev_set_pin.html
27usr/share/doc/libfido2/html/fido_strerr.html
28usr/share/doc/libfido2/html/rs256_pk_new.html
29usr/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 @@
1/usr/share/man/man3/eddsa_pk_new.3 /usr/share/man/man3/eddsa_pk_free.3
2/usr/share/man/man3/eddsa_pk_new.3 /usr/share/man/man3/eddsa_pk_from_ptr.3
3/usr/share/man/man3/eddsa_pk_new.3 /usr/share/man/man3/eddsa_pk_to_EVP_PKEY.3
4/usr/share/man/man3/es256_pk_new.3 /usr/share/man/man3/es256_pk_free.3
5/usr/share/man/man3/es256_pk_new.3 /usr/share/man/man3/es256_pk_from_EC_KEY.3
6/usr/share/man/man3/es256_pk_new.3 /usr/share/man/man3/es256_pk_from_ptr.3
7/usr/share/man/man3/es256_pk_new.3 /usr/share/man/man3/es256_pk_to_EVP_PKEY.3
8/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_authdata_len.3
9/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_authdata_ptr.3
10/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_clientdata_hash_len.3
11/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_clientdata_hash_ptr.3
12/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_count.3
13/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_free.3
14/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_hmac_secret_len.3
15/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_hmac_secret_ptr.3
16/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_sigcount.3
17/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_sig_len.3
18/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_sig_ptr.3
19/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_user_display_name.3
20/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_user_icon.3
21/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_user_id_len.3
22/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_user_id_ptr.3
23/usr/share/man/man3/fido_assert_new.3 /usr/share/man/man3/fido_assert_user_name.3
24/usr/share/man/man3/fido_assert_set_authdata.3 /usr/share/man/man3/fido_assert_set_clientdata_hash.3
25/usr/share/man/man3/fido_assert_set_authdata.3 /usr/share/man/man3/fido_assert_set_count.3
26/usr/share/man/man3/fido_assert_set_authdata.3 /usr/share/man/man3/fido_assert_set_extensions.3
27/usr/share/man/man3/fido_assert_set_authdata.3 /usr/share/man/man3/fido_assert_set_hmac_salt.3
28/usr/share/man/man3/fido_assert_set_authdata.3 /usr/share/man/man3/fido_assert_set_rp.3
29/usr/share/man/man3/fido_assert_set_authdata.3 /usr/share/man/man3/fido_assert_set_sig.3
30/usr/share/man/man3/fido_assert_set_authdata.3 /usr/share/man/man3/fido_assert_set_up.3
31/usr/share/man/man3/fido_assert_set_authdata.3 /usr/share/man/man3/fido_assert_set_uv.3
32/usr/share/man/man3/fido_bio_dev_get_info.3 /usr/share/man/man3/fido_bio_dev_enroll_begin.3
33/usr/share/man/man3/fido_bio_dev_get_info.3 /usr/share/man/man3/fido_bio_dev_enroll_cancel.3
34/usr/share/man/man3/fido_bio_dev_get_info.3 /usr/share/man/man3/fido_bio_dev_enroll_continue.3
35/usr/share/man/man3/fido_bio_dev_get_info.3 /usr/share/man/man3/fido_bio_dev_enroll_remove.3
36/usr/share/man/man3/fido_bio_dev_get_info.3 /usr/share/man/man3/fido_bio_dev_get_template_array.3
37/usr/share/man/man3/fido_bio_dev_get_info.3 /usr/share/man/man3/fido_bio_dev_set_template_name.3
38/usr/share/man/man3/fido_bio_enroll_new.3 /usr/share/man/man3/fido_bio_enroll_free.3
39/usr/share/man/man3/fido_bio_enroll_new.3 /usr/share/man/man3/fido_bio_enroll_last_status.3
40/usr/share/man/man3/fido_bio_enroll_new.3 /usr/share/man/man3/fido_bio_enroll_remaining_samples.3
41/usr/share/man/man3/fido_bio_info_new.3 /usr/share/man/man3/fido_bio_info_free.3
42/usr/share/man/man3/fido_bio_info_new.3 /usr/share/man/man3/fido_bio_info_max_samples.3
43/usr/share/man/man3/fido_bio_info_new.3 /usr/share/man/man3/fido_bio_info_type.3
44/usr/share/man/man3/fido_bio_template.3 /usr/share/man/man3/fido_bio_template_array_count.3
45/usr/share/man/man3/fido_bio_template.3 /usr/share/man/man3/fido_bio_template_array_free.3
46/usr/share/man/man3/fido_bio_template.3 /usr/share/man/man3/fido_bio_template_array_new.3
47/usr/share/man/man3/fido_bio_template.3 /usr/share/man/man3/fido_bio_template_free.3
48/usr/share/man/man3/fido_bio_template.3 /usr/share/man/man3/fido_bio_template_id_len.3
49/usr/share/man/man3/fido_bio_template.3 /usr/share/man/man3/fido_bio_template_id_ptr.3
50/usr/share/man/man3/fido_bio_template.3 /usr/share/man/man3/fido_bio_template_name.3
51/usr/share/man/man3/fido_bio_template.3 /usr/share/man/man3/fido_bio_template_new.3
52/usr/share/man/man3/fido_bio_template.3 /usr/share/man/man3/fido_bio_template_set_id.3
53/usr/share/man/man3/fido_bio_template.3 /usr/share/man/man3/fido_bio_template_set_name.3
54/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_aaguid_len.3
55/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_aaguid_ptr.3
56/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_extensions_len.3
57/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_extensions_ptr.3
58/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_free.3
59/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_maxmsgsiz.3
60/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_options_len.3
61/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_options_name_ptr.3
62/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_options_value_ptr.3
63/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_protocols_len.3
64/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_protocols_ptr.3
65/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_versions_len.3
66/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_cbor_info_versions_ptr.3
67/usr/share/man/man3/fido_cbor_info_new.3 /usr/share/man/man3/fido_dev_get_cbor_info.3
68/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_authdata_len.3
69/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_authdata_ptr.3
70/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_clientdata_hash_len.3
71/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_clientdata_hash_ptr.3
72/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_fmt.3
73/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_free.3
74/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_id_len.3
75/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_id_ptr.3
76/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_prot.3
77/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_pubkey_len.3
78/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_pubkey_ptr.3
79/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_sig_len.3
80/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_sig_ptr.3
81/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_x5c_len.3
82/usr/share/man/man3/fido_cred_new.3 /usr/share/man/man3/fido_cred_x5c_ptr.3
83/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_del_dev_rk.3
84/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_get_dev_metadata.3
85/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_get_dev_rk.3
86/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_get_dev_rp.3
87/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_metadata_free.3
88/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rk.3
89/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rk_count.3
90/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rk_existing.3
91/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rk_free.3
92/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rk_new.3
93/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rk_remaining.3
94/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rp_count.3
95/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rp_free.3
96/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rp_id.3
97/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rp_id_hash_len.3
98/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rp_id_hash_ptr.3
99/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rp_name.3
100/usr/share/man/man3/fido_credman_metadata_new.3 /usr/share/man/man3/fido_credman_rp_new.3
101/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_authdata_raw.3
102/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_clientdata_hash.3
103/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_extensions.3
104/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_fmt.3
105/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_prot.3
106/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_rk.3
107/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_rp.3
108/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_sig.3
109/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_type.3
110/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_user.3
111/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_uv.3
112/usr/share/man/man3/fido_cred_set_authdata.3 /usr/share/man/man3/fido_cred_set_x509.3
113/usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_free.3
114/usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_manufacturer_string.3
115/usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_new.3
116/usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_path.3
117/usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_product.3
118/usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_product_string.3
119/usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_ptr.3
120/usr/share/man/man3/fido_dev_info_manifest.3 /usr/share/man/man3/fido_dev_info_vendor.3
121/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_build.3
122/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_cancel.3
123/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_close.3
124/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_flags.3
125/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_force_fido2.3
126/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_force_u2f.3
127/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_free.3
128/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_is_fido2.3
129/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_major.3
130/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_minor.3
131/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_new.3
132/usr/share/man/man3/fido_dev_open.3 /usr/share/man/man3/fido_dev_protocol.3
133/usr/share/man/man3/fido_dev_set_pin.3 /usr/share/man/man3/fido_dev_get_retry_count.3
134/usr/share/man/man3/fido_dev_set_pin.3 /usr/share/man/man3/fido_dev_reset.3
135/usr/share/man/man3/rs256_pk_new.3 /usr/share/man/man3/rs256_pk_free.3
136/usr/share/man/man3/rs256_pk_new.3 /usr/share/man/man3/rs256_pk_from_ptr.3
137/usr/share/man/man3/rs256_pk_new.3 /usr/share/man/man3/rs256_pk_from_RSA.3
138/usr/share/man/man3/rs256_pk_new.3 /usr/share/man/man3/rs256_pk_to_EVP_PKEY.3
139/usr/share/doc/libfido2/eddsa_pk_new.html /usr/share/doc/libfido2/eddsa_pk_free.html
140/usr/share/doc/libfido2/eddsa_pk_new.html /usr/share/doc/libfido2/eddsa_pk_from_ptr.html
141/usr/share/doc/libfido2/eddsa_pk_new.html /usr/share/doc/libfido2/eddsa_pk_to_EVP_PKEY.html
142/usr/share/doc/libfido2/es256_pk_new.html /usr/share/doc/libfido2/es256_pk_free.html
143/usr/share/doc/libfido2/es256_pk_new.html /usr/share/doc/libfido2/es256_pk_from_EC_KEY.html
144/usr/share/doc/libfido2/es256_pk_new.html /usr/share/doc/libfido2/es256_pk_from_ptr.html
145/usr/share/doc/libfido2/es256_pk_new.html /usr/share/doc/libfido2/es256_pk_to_EVP_PKEY.html
146/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_authdata_len.html
147/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_authdata_ptr.html
148/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_clientdata_hash_len.html
149/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_clientdata_hash_ptr.html
150/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_count.html
151/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_free.html
152/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_hmac_secret_len.html
153/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_hmac_secret_ptr.html
154/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_sigcount.html
155/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_sig_len.html
156/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_sig_ptr.html
157/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_user_display_name.html
158/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_user_icon.html
159/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_user_id_len.html
160/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_user_id_ptr.html
161/usr/share/doc/libfido2/fido_assert_new.html /usr/share/doc/libfido2/fido_assert_user_name.html
162/usr/share/doc/libfido2/fido_assert_set_authdata.html /usr/share/doc/libfido2/fido_assert_set_clientdata_hash.html
163/usr/share/doc/libfido2/fido_assert_set_authdata.html /usr/share/doc/libfido2/fido_assert_set_count.html
164/usr/share/doc/libfido2/fido_assert_set_authdata.html /usr/share/doc/libfido2/fido_assert_set_extensions.html
165/usr/share/doc/libfido2/fido_assert_set_authdata.html /usr/share/doc/libfido2/fido_assert_set_hmac_salt.html
166/usr/share/doc/libfido2/fido_assert_set_authdata.html /usr/share/doc/libfido2/fido_assert_set_rp.html
167/usr/share/doc/libfido2/fido_assert_set_authdata.html /usr/share/doc/libfido2/fido_assert_set_sig.html
168/usr/share/doc/libfido2/fido_assert_set_authdata.html /usr/share/doc/libfido2/fido_assert_set_up.html
169/usr/share/doc/libfido2/fido_assert_set_authdata.html /usr/share/doc/libfido2/fido_assert_set_uv.html
170/usr/share/doc/libfido2/fido_bio_dev_get_info.html /usr/share/doc/libfido2/fido_bio_dev_enroll_begin.html
171/usr/share/doc/libfido2/fido_bio_dev_get_info.html /usr/share/doc/libfido2/fido_bio_dev_enroll_cancel.html
172/usr/share/doc/libfido2/fido_bio_dev_get_info.html /usr/share/doc/libfido2/fido_bio_dev_enroll_continue.html
173/usr/share/doc/libfido2/fido_bio_dev_get_info.html /usr/share/doc/libfido2/fido_bio_dev_enroll_remove.html
174/usr/share/doc/libfido2/fido_bio_dev_get_info.html /usr/share/doc/libfido2/fido_bio_dev_get_template_array.html
175/usr/share/doc/libfido2/fido_bio_dev_get_info.html /usr/share/doc/libfido2/fido_bio_dev_set_template_name.html
176/usr/share/doc/libfido2/fido_bio_enroll_new.html /usr/share/doc/libfido2/fido_bio_enroll_free.html
177/usr/share/doc/libfido2/fido_bio_enroll_new.html /usr/share/doc/libfido2/fido_bio_enroll_last_status.html
178/usr/share/doc/libfido2/fido_bio_enroll_new.html /usr/share/doc/libfido2/fido_bio_enroll_remaining_samples.html
179/usr/share/doc/libfido2/fido_bio_info_new.html /usr/share/doc/libfido2/fido_bio_info_free.html
180/usr/share/doc/libfido2/fido_bio_info_new.html /usr/share/doc/libfido2/fido_bio_info_max_samples.html
181/usr/share/doc/libfido2/fido_bio_info_new.html /usr/share/doc/libfido2/fido_bio_info_type.html
182/usr/share/doc/libfido2/fido_bio_template.html /usr/share/doc/libfido2/fido_bio_template_array_count.html
183/usr/share/doc/libfido2/fido_bio_template.html /usr/share/doc/libfido2/fido_bio_template_array_free.html
184/usr/share/doc/libfido2/fido_bio_template.html /usr/share/doc/libfido2/fido_bio_template_array_new.html
185/usr/share/doc/libfido2/fido_bio_template.html /usr/share/doc/libfido2/fido_bio_template_free.html
186/usr/share/doc/libfido2/fido_bio_template.html /usr/share/doc/libfido2/fido_bio_template_id_len.html
187/usr/share/doc/libfido2/fido_bio_template.html /usr/share/doc/libfido2/fido_bio_template_id_ptr.html
188/usr/share/doc/libfido2/fido_bio_template.html /usr/share/doc/libfido2/fido_bio_template_name.html
189/usr/share/doc/libfido2/fido_bio_template.html /usr/share/doc/libfido2/fido_bio_template_new.html
190/usr/share/doc/libfido2/fido_bio_template.html /usr/share/doc/libfido2/fido_bio_template_set_id.html
191/usr/share/doc/libfido2/fido_bio_template.html /usr/share/doc/libfido2/fido_bio_template_set_name.html
192/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_aaguid_len.html
193/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_aaguid_ptr.html
194/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_extensions_len.html
195/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_extensions_ptr.html
196/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_free.html
197/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_maxmsgsiz.html
198/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_options_len.html
199/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_options_name_ptr.html
200/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_options_value_ptr.html
201/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_protocols_len.html
202/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_protocols_ptr.html
203/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_versions_len.html
204/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_cbor_info_versions_ptr.html
205/usr/share/doc/libfido2/fido_cbor_info_new.html /usr/share/doc/libfido2/fido_dev_get_cbor_info.html
206/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_authdata_len.html
207/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_authdata_ptr.html
208/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_clientdata_hash_len.html
209/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_clientdata_hash_ptr.html
210/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_fmt.html
211/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_free.html
212/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_id_len.html
213/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_id_ptr.html
214/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_prot.html
215/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_pubkey_len.html
216/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_pubkey_ptr.html
217/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_sig_len.html
218/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_sig_ptr.html
219/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_x5c_len.html
220/usr/share/doc/libfido2/fido_cred_new.html /usr/share/doc/libfido2/fido_cred_x5c_ptr.html
221/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_del_dev_rk.html
222/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_get_dev_metadata.html
223/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_get_dev_rk.html
224/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_get_dev_rp.html
225/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_metadata_free.html
226/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rk.html
227/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rk_count.html
228/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rk_existing.html
229/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rk_free.html
230/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rk_new.html
231/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rk_remaining.html
232/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rp_count.html
233/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rp_free.html
234/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rp_id.html
235/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rp_id_hash_len.html
236/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rp_id_hash_ptr.html
237/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rp_name.html
238/usr/share/doc/libfido2/fido_credman_metadata_new.html /usr/share/doc/libfido2/fido_credman_rp_new.html
239/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_authdata_raw.html
240/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_clientdata_hash.html
241/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_extensions.html
242/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_fmt.html
243/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_prot.html
244/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_rk.html
245/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_rp.html
246/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_sig.html
247/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_type.html
248/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_user.html
249/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_uv.html
250/usr/share/doc/libfido2/fido_cred_set_authdata.html /usr/share/doc/libfido2/fido_cred_set_x509.html
251/usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_free.html
252/usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_manufacturer_string.html
253/usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_new.html
254/usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_path.html
255/usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_product.html
256/usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_product_string.html
257/usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_ptr.html
258/usr/share/doc/libfido2/fido_dev_info_manifest.html /usr/share/doc/libfido2/fido_dev_info_vendor.html
259/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_build.html
260/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_cancel.html
261/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_close.html
262/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_flags.html
263/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_force_fido2.html
264/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_force_u2f.html
265/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_free.html
266/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_is_fido2.html
267/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_major.html
268/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_minor.html
269/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_new.html
270/usr/share/doc/libfido2/fido_dev_open.html /usr/share/doc/libfido2/fido_dev_protocol.html
271/usr/share/doc/libfido2/fido_dev_set_pin.html /usr/share/doc/libfido2/fido_dev_get_retry_count.html
272/usr/share/doc/libfido2/fido_dev_set_pin.html /usr/share/doc/libfido2/fido_dev_reset.html
273/usr/share/doc/libfido2/rs256_pk_new.html /usr/share/doc/libfido2/rs256_pk_free.html
274/usr/share/doc/libfido2/rs256_pk_new.html /usr/share/doc/libfido2/rs256_pk_from_ptr.html
275/usr/share/doc/libfido2/rs256_pk_new.html /usr/share/doc/libfido2/rs256_pk_from_RSA.html
276/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 @@
1man/eddsa_pk_new.3
2man/es256_pk_new.3
3man/fido_init.3
4man/fido_assert_new.3
5man/fido_assert_allow_cred.3
6man/fido_assert_set_authdata.3
7man/fido_assert_verify.3
8man/fido_bio_dev_get_info.3
9man/fido_bio_enroll_new.3
10man/fido_bio_info_new.3
11man/fido_bio_template.3
12man/fido_cbor_info_new.3
13man/fido_cred_new.3
14man/fido_cred_exclude.3
15man/fido_credman_metadata_new.3
16man/fido_cred_set_authdata.3
17man/fido_cred_verify.3
18man/fido_dev_get_assert.3
19man/fido_dev_info_manifest.3
20man/fido_dev_make_cred.3
21man/fido_dev_open.3
22man/fido_dev_set_io_functions.3
23man/fido_dev_set_pin.3
24man/fido_strerr.3
25man/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 @@
1lib/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 @@
1#!/usr/bin/make -f
2
3DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
4
5%:
6 dh $@
7
8override_dh_auto_configure:
9 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 @@
13.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 @@
1# unlock-yk
2# docker run --rm --volume=/home/pedro/projects/libfido2:/workdir \
3# --volume=$(gpgconf --list-dirs socketdir):/root/.gnupg \
4# --volume=$(gpgconf --list-dirs homedir)/pubring.kbx:/root/.gnupg/pubring.kbx \
5# -it libfido2-staging --install-deps --ppa martelletto/ppa \
6# --key pedro@yubico.com
7FROM ubuntu:bionic
8ENV DEBIAN_FRONTEND noninteractive
9RUN apt-get -qq update && apt-get -qq upgrade
10RUN apt-get install -qq packaging-dev debian-keyring devscripts equivs gnupg python sudo
11ADD https://raw.githubusercontent.com/dainnilsson/scripts/master/make-ppa /make-ppa
12RUN chmod +x /make-ppa
13WORKDIR /workdir
14ENTRYPOINT ["/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 @@
3# license that can be found in the LICENSE file. 3# license that can be found in the LICENSE file.
4 4
5list(APPEND COMPAT_SOURCES 5list(APPEND COMPAT_SOURCES
6 ../openbsd-compat/clock_gettime.c
6 ../openbsd-compat/getopt_long.c 7 ../openbsd-compat/getopt_long.c
7 ../openbsd-compat/strlcat.c 8 ../openbsd-compat/strlcat.c
8 ../openbsd-compat/strlcpy.c 9 ../openbsd-compat/strlcpy.c
@@ -15,6 +16,13 @@ endif()
15# drop -rdynamic 16# drop -rdynamic
16set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") 17set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
17 18
19# enable -Wconversion -Wsign-conversion
20if(NOT MSVC)
21 set_source_files_properties(assert.c cred.c info.c manifest.c reset.c
22 retries.c setpin.c util.c PROPERTIES COMPILE_FLAGS
23 "-Wconversion -Wsign-conversion")
24endif()
25
18# manifest 26# manifest
19add_executable(manifest manifest.c ${COMPAT_SOURCES}) 27add_executable(manifest manifest.c ${COMPAT_SOURCES})
20target_link_libraries(manifest fido2) 28target_link_libraries(manifest fido2)
@@ -42,3 +50,11 @@ target_link_libraries(setpin fido2)
42# retries 50# retries
43add_executable(retries retries.c ${COMPAT_SOURCES}) 51add_executable(retries retries.c ${COMPAT_SOURCES})
44target_link_libraries(retries fido2) 52target_link_libraries(retries fido2)
53
54# select
55add_executable(select select.c ${COMPAT_SOURCES})
56target_link_libraries(select fido2)
57if(MINGW)
58 # needed for nanosleep() in mingw
59 target_link_libraries(select winpthread)
60endif()
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:
77- retries <device> 77- retries <device>
78 Get the number of PIN attempts left on <device> before lockout. 78 Get the number of PIN attempts left on <device> before lockout.
79 79
80- select
81
82 Enumerates available FIDO devices and, if more than one is present,
83 simultaneously requests touch on all of them, printing information
84 about the device touched.
85
80Debugging is possible through the use of the FIDO_DEBUG environment variable. 86Debugging is possible through the use of the FIDO_DEBUG environment variable.
81If set, libfido2 will produce a log of its transactions with the authenticator. 87If set, libfido2 will produce a log of its transactions with the authenticator.
88
89Additionally, an example of a WebAuthn client using libfido2 is available at
90https://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 @@
14#include <unistd.h> 14#include <unistd.h>
15#endif 15#endif
16 16
17#include "../openbsd-compat/openbsd-compat.h"
18
19#include "fido.h" 17#include "fido.h"
20#include "fido/es256.h" 18#include "fido/es256.h"
21#include "fido/rs256.h" 19#include "fido/rs256.h"
22#include "fido/eddsa.h" 20#include "fido/eddsa.h"
23#include "extern.h" 21#include "extern.h"
24 22#include "../openbsd-compat/openbsd-compat.h"
25#ifdef SIGNAL_EXAMPLE
26extern volatile sig_atomic_t got_signal;
27#endif
28 23
29static const unsigned char cdh[32] = { 24static const unsigned char cdh[32] = {
30 0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7, 25 0xec, 0x8d, 0x8f, 0x78, 0x42, 0x4a, 0x2b, 0xb7,
@@ -188,13 +183,15 @@ main(int argc, char **argv)
188 break; 183 break;
189 case 'T': 184 case 'T':
190#ifndef SIGNAL_EXAMPLE 185#ifndef SIGNAL_EXAMPLE
186 (void)seconds;
191 errx(1, "-T not supported"); 187 errx(1, "-T not supported");
192#endif 188#else
193 if (base10(optarg, &seconds) < 0) 189 if (base10(optarg, &seconds) < 0)
194 errx(1, "base10: %s", optarg); 190 errx(1, "base10: %s", optarg);
195 if (seconds <= 0 || seconds > 30) 191 if (seconds <= 0 || seconds > 30)
196 errx(1, "-T: %s must be in (0,30]", optarg); 192 errx(1, "-T: %s must be in (0,30]", optarg);
197 break; 193 break;
194#endif
198 case 'a': 195 case 'a':
199 if (read_blob(optarg, &body, &len) < 0) 196 if (read_blob(optarg, &body, &len) < 0)
200 errx(1, "read_blob: %s", optarg); 197 errx(1, "read_blob: %s", optarg);
@@ -312,6 +309,10 @@ main(int argc, char **argv)
312 errx(1, "fido_assert_count: %d signatures returned", 309 errx(1, "fido_assert_count: %d signatures returned",
313 (int)fido_assert_count(assert)); 310 (int)fido_assert_count(assert));
314 311
312 /* when verifying, pin implies uv */
313 if (pin)
314 uv = true;
315
315 verify_assert(type, fido_assert_authdata_ptr(assert, 0), 316 verify_assert(type, fido_assert_authdata_ptr(assert, 0),
316 fido_assert_authdata_len(assert, 0), fido_assert_sig_ptr(assert, 0), 317 fido_assert_authdata_len(assert, 0), fido_assert_sig_ptr(assert, 0),
317 fido_assert_sig_len(assert, 0), up, uv, ext, argv[0]); 318 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 @@
16#include <unistd.h> 16#include <unistd.h>
17#endif 17#endif
18 18
19#include "../openbsd-compat/openbsd-compat.h"
20
21#include "fido.h" 19#include "fido.h"
22#include "extern.h" 20#include "extern.h"
23 21#include "../openbsd-compat/openbsd-compat.h"
24#ifdef SIGNAL_EXAMPLE
25extern volatile sig_atomic_t got_signal;
26#endif
27 22
28static const unsigned char cdh[32] = { 23static const unsigned char cdh[32] = {
29 0xf9, 0x64, 0x57, 0xe7, 0x2d, 0x97, 0xf6, 0xbb, 24 0xf9, 0x64, 0x57, 0xe7, 0x2d, 0x97, 0xf6, 0xbb,
@@ -192,13 +187,15 @@ main(int argc, char **argv)
192 break; 187 break;
193 case 'T': 188 case 'T':
194#ifndef SIGNAL_EXAMPLE 189#ifndef SIGNAL_EXAMPLE
190 (void)seconds;
195 errx(1, "-T not supported"); 191 errx(1, "-T not supported");
196#endif 192#else
197 if (base10(optarg, &seconds) < 0) 193 if (base10(optarg, &seconds) < 0)
198 errx(1, "base10: %s", optarg); 194 errx(1, "base10: %s", optarg);
199 if (seconds <= 0 || seconds > 30) 195 if (seconds <= 0 || seconds > 30)
200 errx(1, "-T: %s must be in (0,30]", optarg); 196 errx(1, "-T: %s must be in (0,30]", optarg);
201 break; 197 break;
198#endif
202 case 'e': 199 case 'e':
203 if (read_blob(optarg, &body, &len) < 0) 200 if (read_blob(optarg, &body, &len) < 0)
204 errx(1, "read_blob: %s", optarg); 201 errx(1, "read_blob: %s", optarg);
@@ -318,6 +315,10 @@ main(int argc, char **argv)
318 315
319 fido_dev_free(&dev); 316 fido_dev_free(&dev);
320 317
318 /* when verifying, pin implies uv */
319 if (pin)
320 uv = true;
321
321 verify_cred(type, fido_cred_fmt(cred), fido_cred_authdata_ptr(cred), 322 verify_cred(type, fido_cred_fmt(cred), fido_cred_authdata_ptr(cred),
322 fido_cred_authdata_len(cred), fido_cred_x5c_ptr(cred), 323 fido_cred_authdata_len(cred), fido_cred_x5c_ptr(cred),
323 fido_cred_x5c_len(cred), fido_cred_sig_ptr(cred), 324 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);
27int write_eddsa_pubkey(const char *, const void *, size_t); 27int write_eddsa_pubkey(const char *, const void *, size_t);
28#ifdef SIGNAL_EXAMPLE 28#ifdef SIGNAL_EXAMPLE
29void prepare_signal_handler(int); 29void prepare_signal_handler(int);
30extern volatile sig_atomic_t got_signal;
30#endif 31#endif
31 32
32#endif /* _EXTERN_H_ */ 33#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 @@
4 * license that can be found in the LICENSE file. 4 * license that can be found in the LICENSE file.
5 */ 5 */
6 6
7#include <openssl/ec.h>
8
9#include <stdbool.h> 7#include <stdbool.h>
10#include <stdint.h> 8#include <stdint.h>
11#include <stdio.h> 9#include <stdio.h>
12#include <stdlib.h> 10#include <stdlib.h>
13#include <string.h> 11#include <string.h>
14 12
15#include "../openbsd-compat/openbsd-compat.h"
16
17#include "fido.h" 13#include "fido.h"
14#include "../openbsd-compat/openbsd-compat.h"
18 15
19/* 16/*
20 * Pretty-print a device's capabilities flags and return the result. 17 * Pretty-print a device's capabilities flags and return the result.
@@ -131,6 +128,26 @@ print_maxmsgsiz(uint64_t maxmsgsiz)
131} 128}
132 129
133/* 130/*
131 * Auxiliary function to print an authenticator's maximum number of credentials
132 * in a credential list on stdout.
133 */
134static void
135print_maxcredcntlst(uint64_t maxcredcntlst)
136{
137 printf("maxcredcntlst: %d\n", (int)maxcredcntlst);
138}
139
140/*
141 * Auxiliary function to print an authenticator's maximum credential ID length
142 * on stdout.
143 */
144static void
145print_maxcredidlen(uint64_t maxcredidlen)
146{
147 printf("maxcredlen: %d\n", (int)maxcredidlen);
148}
149
150/*
134 * Auxiliary function to print an authenticator's firmware version on stdout. 151 * Auxiliary function to print an authenticator's firmware version on stdout.
135 */ 152 */
136static void 153static void
@@ -199,6 +216,12 @@ getinfo(const char *path)
199 /* print maximum message size */ 216 /* print maximum message size */
200 print_maxmsgsiz(fido_cbor_info_maxmsgsiz(ci)); 217 print_maxmsgsiz(fido_cbor_info_maxmsgsiz(ci));
201 218
219 /* print maximum number of credentials allowed in credential lists */
220 print_maxcredcntlst(fido_cbor_info_maxcredcntlst(ci));
221
222 /* print maximum length of a credential ID */
223 print_maxcredidlen(fido_cbor_info_maxcredidlen(ci));
224
202 /* print firmware version */ 225 /* print firmware version */
203 print_fwversion(fido_cbor_info_fwversion(ci)); 226 print_fwversion(fido_cbor_info_fwversion(ci));
204 227
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 @@
4 * license that can be found in the LICENSE file. 4 * license that can be found in the LICENSE file.
5 */ 5 */
6 6
7#include <openssl/ec.h>
8
9#include <stdbool.h> 7#include <stdbool.h>
10#include <stdio.h> 8#include <stdio.h>
11#include <stdlib.h> 9#include <stdlib.h>
12 10
13#include "../openbsd-compat/openbsd-compat.h"
14
15#include "fido.h" 11#include "fido.h"
12#include "../openbsd-compat/openbsd-compat.h"
16 13
17int 14int
18main(void) 15main(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 @@
8 * Perform a factory reset on a given authenticator. 8 * Perform a factory reset on a given authenticator.
9 */ 9 */
10 10
11#include <openssl/ec.h>
12
13#include <stdbool.h> 11#include <stdbool.h>
14#include <stdint.h> 12#include <stdint.h>
15#include <stdio.h> 13#include <stdio.h>
16#include <stdlib.h> 14#include <stdlib.h>
17 15
18#include "../openbsd-compat/openbsd-compat.h"
19
20#include "fido.h" 16#include "fido.h"
21#include "extern.h" 17#include "extern.h"
22 18#include "../openbsd-compat/openbsd-compat.h"
23#ifdef SIGNAL_EXAMPLE
24extern volatile sig_atomic_t got_signal;
25#endif
26 19
27int 20int
28main(int argc, char **argv) 21main(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 @@
8 * Get an authenticator's number of PIN attempts left. 8 * Get an authenticator's number of PIN attempts left.
9 */ 9 */
10 10
11#include <openssl/ec.h>
12
13#include <stdbool.h> 11#include <stdbool.h>
14#include <stdio.h> 12#include <stdio.h>
15#include <stdlib.h> 13#include <stdlib.h>
16 14
17#include "../openbsd-compat/openbsd-compat.h"
18
19#include "fido.h" 15#include "fido.h"
16#include "../openbsd-compat/openbsd-compat.h"
20 17
21int 18int
22main(int argc, char **argv) 19main(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 @@
1/*
2 * Copyright (c) 2020 Yubico AB. All rights reserved.
3 * Use of this source code is governed by a BSD-style
4 * license that can be found in the LICENSE file.
5 */
6
7#include <errno.h>
8#include <stdbool.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <time.h>
12
13#include "fido.h"
14#include "../openbsd-compat/openbsd-compat.h"
15
16#define FIDO_POLL_MS 50
17
18#if defined(_MSC_VER)
19static int
20nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
21{
22 if (rmtp != NULL) {
23 errno = EINVAL;
24 return (-1);
25 }
26
27 Sleep(rqtp->tv_nsec / 1000000);
28
29 return (0);
30}
31#endif
32
33static fido_dev_t *
34open_dev(const fido_dev_info_t *di)
35{
36 fido_dev_t *dev;
37 int r;
38
39 if ((dev = fido_dev_new()) == NULL) {
40 warnx("%s: fido_dev_new", __func__);
41 return (NULL);
42 }
43
44 if ((r = fido_dev_open(dev, fido_dev_info_path(di))) != FIDO_OK) {
45 warnx("%s: fido_dev_open %s: %s", __func__,
46 fido_dev_info_path(di), fido_strerr(r));
47 fido_dev_free(&dev);
48 return (NULL);
49 }
50
51 printf("%s (0x%04x:0x%04x) is %s\n", fido_dev_info_path(di),
52 fido_dev_info_vendor(di), fido_dev_info_product(di),
53 fido_dev_is_fido2(dev) ? "fido2" : "u2f");
54
55 return (dev);
56}
57
58static int
59select_dev(const fido_dev_info_t *devlist, size_t ndevs, fido_dev_t **dev,
60 size_t *idx, int secs)
61{
62 const fido_dev_info_t *di;
63 fido_dev_t **devtab;
64 struct timespec ts_start;
65 struct timespec ts_now;
66 struct timespec ts_delta;
67 struct timespec ts_pause;
68 size_t nopen = 0;
69 int touched;
70 int r;
71 long ms_remain;
72
73 *dev = NULL;
74 *idx = 0;
75
76 printf("%u authenticator(s) detected\n", (unsigned)ndevs);
77
78 if (ndevs == 0)
79 return (0); /* nothing to do */
80
81 if ((devtab = calloc(ndevs, sizeof(*devtab))) == NULL) {
82 warn("%s: calloc", __func__);
83 return (-1);
84 }
85
86 for (size_t i = 0; i < ndevs; i++) {
87 di = fido_dev_info_ptr(devlist, i);
88 if ((devtab[i] = open_dev(di)) != NULL) {
89 *idx = i;
90 nopen++;
91 }
92 }
93
94 printf("%u authenticator(s) opened\n", (unsigned)nopen);
95
96 if (nopen < 2) {
97 if (nopen == 1)
98 *dev = devtab[*idx]; /* single candidate */
99 r = 0;
100 goto out;
101 }
102
103 for (size_t i = 0; i < ndevs; i++) {
104 di = fido_dev_info_ptr(devlist, i);
105 if (devtab[i] == NULL)
106 continue; /* failed to open */
107 if ((r = fido_dev_get_touch_begin(devtab[i])) != FIDO_OK) {
108 warnx("%s: fido_dev_get_touch_begin %s: %s", __func__,
109 fido_dev_info_path(di), fido_strerr(r));
110 r = -1;
111 goto out;
112 }
113 }
114
115 if (clock_gettime(CLOCK_MONOTONIC, &ts_start) != 0) {
116 warn("%s: clock_gettime", __func__);
117 r = -1;
118 goto out;
119 }
120
121 ts_pause.tv_sec = 0;
122 ts_pause.tv_nsec = 200000000; /* 200ms */
123
124 do {
125 nanosleep(&ts_pause, NULL);
126
127 for (size_t i = 0; i < ndevs; i++) {
128 di = fido_dev_info_ptr(devlist, i);
129 if (devtab[i] == NULL) {
130 /* failed to open or discarded */
131 continue;
132 }
133 if ((r = fido_dev_get_touch_status(devtab[i], &touched,
134 FIDO_POLL_MS)) != FIDO_OK) {
135 warnx("%s: fido_dev_get_touch_status %s: %s",
136 __func__, fido_dev_info_path(di),
137 fido_strerr(r));
138 fido_dev_close(devtab[i]);
139 fido_dev_free(&devtab[i]);
140 continue; /* discard */
141 }
142 if (touched) {
143 *dev = devtab[i];
144 *idx = i;
145 r = 0;
146 goto out;
147 }
148 }
149
150 if (clock_gettime(CLOCK_MONOTONIC, &ts_now) != 0) {
151 warn("%s: clock_gettime", __func__);
152 r = -1;
153 goto out;
154 }
155
156 timespecsub(&ts_now, &ts_start, &ts_delta);
157 ms_remain = (secs * 1000) - ((long)ts_delta.tv_sec * 1000) +
158 ((long)ts_delta.tv_nsec / 1000000);
159 } while (ms_remain > FIDO_POLL_MS);
160
161 printf("timeout after %d seconds\n", secs);
162 r = -1;
163out:
164 if (r != 0) {
165 *dev = NULL;
166 *idx = 0;
167 }
168
169 for (size_t i = 0; i < ndevs; i++) {
170 if (devtab[i] && devtab[i] != *dev) {
171 fido_dev_cancel(devtab[i]);
172 fido_dev_close(devtab[i]);
173 fido_dev_free(&devtab[i]);
174 }
175 }
176
177 free(devtab);
178
179 return (r);
180}
181
182int
183main(void)
184{
185 const fido_dev_info_t *di;
186 fido_dev_info_t *devlist;
187 fido_dev_t *dev;
188 size_t idx;
189 size_t ndevs;
190 int r;
191
192 fido_init(0);
193
194 if ((devlist = fido_dev_info_new(64)) == NULL)
195 errx(1, "fido_dev_info_new");
196
197 if ((r = fido_dev_info_manifest(devlist, 64, &ndevs)) != FIDO_OK)
198 errx(1, "fido_dev_info_manifest: %s (0x%x)", fido_strerr(r), r);
199 if (select_dev(devlist, ndevs, &dev, &idx, 15) != 0)
200 errx(1, "select_dev");
201 if (dev == NULL)
202 errx(1, "no authenticator found");
203
204 di = fido_dev_info_ptr(devlist, idx);
205 printf("%s: %s by %s (PIN %sset)\n", fido_dev_info_path(di),
206 fido_dev_info_product_string(di),
207 fido_dev_info_manufacturer_string(di),
208 fido_dev_has_pin(dev) ? "" : "un");
209
210 fido_dev_close(dev);
211 fido_dev_free(&dev);
212 fido_dev_info_free(&devlist, ndevs);
213
214 exit(0);
215}
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 @@
8 * Configure a PIN on a given authenticator. 8 * Configure a PIN on a given authenticator.
9 */ 9 */
10 10
11#include <openssl/ec.h>
12
13#include <stdbool.h> 11#include <stdbool.h>
14#include <stdint.h> 12#include <stdint.h>
15#include <stdio.h> 13#include <stdio.h>
16#include <stdlib.h> 14#include <stdlib.h>
17 15
18#include "../openbsd-compat/openbsd-compat.h"
19
20#include "fido.h" 16#include "fido.h"
17#include "../openbsd-compat/openbsd-compat.h"
21 18
22static void 19static void
23setpin(const char *path, const char *pin, const char *oldpin) 20setpin(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 @@
27#include "../openbsd-compat/posix_win.h" 27#include "../openbsd-compat/posix_win.h"
28#endif 28#endif
29 29
30#include "../openbsd-compat/openbsd-compat.h"
31
32#include "fido.h" 30#include "fido.h"
33#include "fido/es256.h" 31#include "fido/es256.h"
34#include "fido/rs256.h" 32#include "fido/rs256.h"
35#include "fido/eddsa.h" 33#include "fido/eddsa.h"
36#include "extern.h" 34#include "extern.h"
35#include "../openbsd-compat/openbsd-compat.h"
37 36
38#ifdef SIGNAL_EXAMPLE 37#ifdef SIGNAL_EXAMPLE
39volatile sig_atomic_t got_signal = 0; 38volatile 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
8) 8)
9 9
10list(APPEND COMMON_SOURCES 10list(APPEND COMMON_SOURCES
11 libfuzzer.c
11 mutator_aux.c 12 mutator_aux.c
12) 13)
13 14
diff --git a/fuzz/Dockerfile b/fuzz/Dockerfile
index 68afd99..f9152f8 100644
--- a/fuzz/Dockerfile
+++ b/fuzz/Dockerfile
@@ -2,9 +2,10 @@
2# Use of this source code is governed by a BSD-style 2# Use of this source code is governed by a BSD-style
3# license that can be found in the LICENSE file. 3# license that can be found in the LICENSE file.
4 4
5FROM ubuntu:bionic 5FROM ubuntu:focal
6ENV DEBIAN_FRONTEND=noninteractive
6RUN apt-get update 7RUN apt-get update
7RUN apt-get install -y clang-9 cmake git libssl-dev libudev-dev make pkg-config 8RUN apt-get install -y clang-10 cmake git libssl-dev libudev-dev make pkg-config
8RUN git clone --branch v0.5.0 https://github.com/PJK/libcbor 9RUN git clone --branch v0.7.0 https://github.com/PJK/libcbor
9RUN git clone https://github.com/yubico/libfido2 10RUN git clone https://github.com/yubico/libfido2
10RUN CC=clang-9 /libfido2/fuzz/build-coverage /libcbor /libfido2 11RUN 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 @@
2# Use of this source code is governed by a BSD-style 2# Use of this source code is governed by a BSD-style
3# license that can be found in the LICENSE file. 3# license that can be found in the LICENSE file.
4 4
5IMAGE := libfido2-coverage:1.3.0 5IMAGE := libfido2-coverage:1.5.0
6RUNNER := libfido2-runner 6RUNNER := libfido2-runner
7PROFDATA := llvm-profdata-9 7PROFDATA := llvm-profdata-10
8COV := llvm-cov-9 8COV := llvm-cov-10
9TARGETS := fuzz_assert fuzz_bio fuzz_cred fuzz_credman fuzz_mgmt 9TARGETS := fuzz_assert fuzz_bio fuzz_cred fuzz_credman fuzz_mgmt
10CORPORA := $(foreach f,${TARGETS},${f}/corpus) 10CORPORA := $(foreach f,${TARGETS},${f}/corpus)
11MINIFY := $(foreach f,${TARGETS},/minify/${f}/corpus) 11MINIFY := $(foreach f,${TARGETS},/minify/${f}/corpus)
@@ -26,16 +26,16 @@ sync: run
26 docker exec ${RUNNER} make -C libfido2/build 26 docker exec ${RUNNER} make -C libfido2/build
27 27
28corpus: sync 28corpus: sync
29 docker exec ${RUNNER} /bin/bash -c 'cd /libfido2/fuzz && rm -rf ${TARGETS}' 29 docker exec ${RUNNER} /bin/sh -c 'cd /libfido2/fuzz && rm -rf ${TARGETS}'
30 docker exec ${RUNNER} tar Czxf /libfido2/fuzz /libfido2/fuzz/corpus.tgz 30 docker exec ${RUNNER} tar Czxf /libfido2/fuzz /libfido2/fuzz/corpus.tgz
31 31
32${TARGETS}: corpus sync 32${TARGETS}: corpus sync
33 docker exec -e LLVM_PROFILE_FILE=/profraw/$@ ${RUNNER} \ 33 docker exec -e LLVM_PROFILE_FILE=/profraw/$@ ${RUNNER} \
34 /bin/bash -c 'rm -f /profraw/$@ && /libfido2/build/fuzz/$@ \ 34 /bin/sh -c 'rm -f /profraw/$@ && /libfido2/build/fuzz/$@ \
35 -runs=1 /libfido2/fuzz/$@' 35 -runs=1 /libfido2/fuzz/$@'
36 36
37${MINIFY}: /minify/%/corpus: % 37${MINIFY}: /minify/%/corpus: %
38 docker exec ${RUNNER} /bin/bash -c 'rm -rf $@ && mkdir -p $@ && \ 38 docker exec ${RUNNER} /bin/sh -c 'rm -rf $@ && mkdir -p $@ && \
39 /libfido2/build/fuzz/$< -use_value_profile=1 -merge=1 $@ \ 39 /libfido2/build/fuzz/$< -use_value_profile=1 -merge=1 $@ \
40 /libfido2/fuzz/$</corpus' 40 /libfido2/fuzz/$</corpus'
41 41
@@ -43,11 +43,11 @@ corpus.tgz-: ${MINIFY}
43 docker exec -i ${RUNNER} tar Czcf /minify - ${TARGETS} > $@ 43 docker exec -i ${RUNNER} tar Czcf /minify - ${TARGETS} > $@
44 44
45profdata: run 45profdata: run
46 docker exec ${RUNNER} /bin/bash -c 'rm -f /$@ && ${PROFDATA} \ 46 docker exec ${RUNNER} /bin/sh -c 'rm -f /$@ && ${PROFDATA} \
47 merge -sparse profraw/* -o $@' 47 merge -sparse profraw/* -o $@'
48 48
49report.tgz: profdata 49report.tgz: profdata
50 docker exec ${RUNNER} /bin/bash -c 'rm -rf /report && mkdir /report && \ 50 docker exec ${RUNNER} /bin/sh -c 'rm -rf /report && mkdir /report && \
51 ${COV} show -format=html -tab-size=8 -instr-profile=/$< \ 51 ${COV} show -format=html -tab-size=8 -instr-profile=/$< \
52 -output-dir=/report /libfido2/build/src/libfido2.so' 52 -output-dir=/report /libfido2/build/src/libfido2.so'
53 docker exec -i ${RUNNER} tar Czcf / - report > $@ 53 docker exec -i ${RUNNER} tar Czcf / - report > $@
@@ -57,12 +57,12 @@ summary.txt: profdata
57 /libfido2/build/src/libfido2.so -instr-profile=/$< > $@ 57 /libfido2/build/src/libfido2.so -instr-profile=/$< > $@
58 58
59functions.txt: profdata 59functions.txt: profdata
60 docker exec ${RUNNER} /bin/bash -c '${COV} report -use-color=false \ 60 docker exec ${RUNNER} /bin/sh -c '${COV} report -use-color=false \
61 -show-functions -instr-profile=/$< \ 61 -show-functions -instr-profile=/$< \
62 /libfido2/build/src/libfido2.so /libfido2/src/*.[ch]' > $@ 62 /libfido2/build/src/libfido2.so /libfido2/src/*.[ch]' > $@
63 63
64clean: run 64clean: run
65 docker exec ${RUNNER} /bin/bash -c 'rm -rf /profraw /profdata && \ 65 docker exec ${RUNNER} /bin/sh -c 'rm -rf /profraw /profdata && \
66 make -C /libfido2/build clean' 66 make -C /libfido2/build clean'
67 -docker stop ${RUNNER} 67 -docker stop ${RUNNER}
68 rm -rf ${TARGETS} 68 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.
3 3
4AFL is more convenient when fuzzing the path from the authenticator to 4AFL is more convenient when fuzzing the path from the authenticator to
5libfido2 in an existing application. To do so, use preload-snoop.c with a real 5libfido2 in an existing application. To do so, use preload-snoop.c with a real
6authenticator to obtain an initial corpus, rebuild libfido2 with -DFUZZ=1 6authenticator to obtain an initial corpus, rebuild libfido2 with -DFUZZ=1, and
7-DAFL=1, and use preload-fuzz.c to read device data from stdin. Examples of 7use preload-fuzz.c to read device data from stdin.
8this approach can be found in the harnesses under fuzz/harnesses/ that fuzz
9the standalone examples and tools bundled with libfido2.
10 8
11libFuzzer is better suited for bespoke fuzzers; see fuzz_cred.c, fuzz_credman.c, 9libFuzzer is better suited for bespoke fuzzers; see fuzz_cred.c, fuzz_credman.c,
12fuzz_assert.c, and fuzz_mgmt.c for examples. To build these harnesses, 10fuzz_assert.c, and fuzz_mgmt.c for examples. To build these harnesses,
@@ -15,129 +13,7 @@ use -DFUZZ=1 -DLIBFUZZER=1.
15To run under ASAN/MSAN/UBSAN, libfido2 needs to be linked against flavours of 13To run under ASAN/MSAN/UBSAN, libfido2 needs to be linked against flavours of
16libcbor and OpenSSL built with the respective sanitiser. In order to keep 14libcbor and OpenSSL built with the respective sanitiser. In order to keep
17memory utilisation at a manageable level, you can either enforce limits at 15memory utilisation at a manageable level, you can either enforce limits at
18the OS level (e.g. cgroups on Linux) or, alternatively, patch libcbor with 16the OS level (e.g. cgroups on Linux), or patch libcbor with the diff below.
19the diff at the bottom of this file.
20
211. Using ASAN + UBSAN
22
23- Make sure you have libcbor built with -fsanitize=address;
24- Make sure you have OpenSSL built with -fsanitize=address;
25- Rebuild libfido2 with -DASAN=1 -DUBSAN=1.
26
271.1 Decide where your workspace will live
28
29$ export FAKEROOT=/home/pedro/fakeroot
30$ mkdir -p ${FAKEROOT}/src
31
321.2 Building libcbor with ASAN
33
34$ git clone https://github.com/pjk/libcbor ${FAKEROOT}/src/libcbor
35$ cd ${FAKEROOT}/src/libcbor
36
37Assuming libfido2 is under ${FAKEROOT}/src/libfido2:
38
39$ patch -p0 < ${FAKEROOT}/src/libfido2/fuzz/README
40$ mkdir build
41$ cd build
42$ cmake -DCMAKE_C_FLAGS_DEBUG="-g2 -fno-omit-frame-pointer" \
43 -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=Debug \
44 -DCMAKE_INSTALL_PREFIX=${FAKEROOT} -DSANITIZE=ON \
45 -DCMAKE_INSTALL_LIBDIR=lib ..
46$ make
47$ make install
48
491.3 Building OpenSSL with ASAN
50
51$ git clone https://github.com/openssl/openssl ${FAKEROOT}/src/openssl
52$ cd ${FAKEROOT}/src/openssl
53$ ./Configure linux-x86_64-clang enable-asan --prefix=${FAKEROOT} \
54 --openssldir=${FAKEROOT}/openssl
55$ make clean
56$ make
57$ make install_sw
58
591.4 Building libfido2 with libFuzzer and ASAN + UBSAN
60
61$ cd ${FAKEROOT}/src/libfido2
62$ mkdir build
63$ cd build
64$ cmake -DFUZZ=1 -DLIBFUZZER=1 -DASAN=1 -DUBSAN=1 -DCMAKE_C_COMPILER=clang \
65 -DCRYPTO_INCLUDE_DIRS=${FAKEROOT}/include \
66 -DCRYPTO_LIBRARY_DIRS=${FAKEROOT}/lib \
67 -DCBOR_INCLUDE_DIRS=${FAKEROOT}/include \
68 -DCBOR_LIBRARY_DIRS=${FAKEROOT}/lib \
69 -DCMAKE_BUILD_TYPE=Debug ..
70$ make
71
722. Using MSAN + UBSAN
73
74- Make sure you have libcbor built with -fsanitize=memory;
75- Make sure you have OpenSSL built with -fsanitize=memory;
76- Rebuild libfido2 with -DMSAN=1 -DUBSAN=1.
77
782.1 Decide where your workspace will live
79
80$ export FAKEROOT=/home/pedro/fakeroot
81$ mkdir -p ${FAKEROOT}/src
82
832.2 Building libcbor with MSAN
84
85$ git clone https://github.com/pjk/libcbor ${FAKEROOT}/src/libcbor
86$ cd ${FAKEROOT}/src/libcbor
87
88Assuming libfido2 is under ${FAKEROOT}/src/libfido2:
89
90$ patch -p0 < ${FAKEROOT}/src/libfido2/fuzz/README
91$ mkdir build
92$ cd build
93$ cmake -DCMAKE_C_FLAGS_DEBUG="-fsanitize=memory,undefined -g2 -fno-omit-frame-pointer" \
94 -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=Debug \
95 -DCMAKE_INSTALL_PREFIX=${FAKEROOT} -DSANITIZE=OFF \
96 -DCMAKE_INSTALL_LIBDIR=lib ..
97$ make
98$ make install
99
1002.2 Building OpenSSL with MSAN
101
102$ mkdir -p ${FAKEROOT}/src
103$ git clone https://github.com/openssl/openssl ${FAKEROOT}/src/openssl
104$ cd ${FAKEROOT}/src/openssl
105$ ./Configure linux-x86_64-clang enable-msan --prefix=${FAKEROOT} \
106 --openssldir=${FAKEROOT}/openssl
107$ make clean
108$ make
109$ make install_sw
110
1112.3 Building libfido2 with libFuzzer and MSAN + UBSAN
112
113$ cd ${FAKEROOT}/src/libfido2
114$ mkdir build
115$ cd build
116$ cmake -DFUZZ=1 -DLIBFUZZER=1 -DMSAN=1 -DUBSAN=1 -DCMAKE_C_COMPILER=clang \
117 -DCRYPTO_INCLUDE_DIRS=${FAKEROOT}/include \
118 -DCRYPTO_LIBRARY_DIRS=${FAKEROOT}/lib \
119 -DCBOR_INCLUDE_DIRS=${FAKEROOT}/include \
120 -DCBOR_LIBRARY_DIRS=${FAKEROOT}/lib \
121 -DCMAKE_BUILD_TYPE=Debug ..
122$ make
123
1243. Running the libFuzzer harnesses
125
126When running under ASAN, you may want to set ASAN_OPTIONS to
127'allocator_may_return_null=1:detect_stack_use_after_return=1'.
128
129The recommended way to run the harnesses is:
130
131$ fuzz_{assert,cred,credman,mgmt} -use_value_profile=1 -reload=30 \
132 -print_pcs=1 -print_funcs=30 -timeout=10 CORPUS_DIR
133
134You may want to use -jobs or -workers depending on the number of logical
135cores available for fuzzing.
136
1374. Auxiliary scripts
138
139A set of harnesses and auxiliary scripts can be found under harnesses/. To
140compile coverage reports, adjust the harnesses to your setup and run 'report'.
141 17
142diff --git src/cbor/internal/memory_utils.c src/cbor/internal/memory_utils.c 18diff --git src/cbor/internal/memory_utils.c src/cbor/internal/memory_utils.c
143index aa049a2..e294b38 100644 19index 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 @@
1#!/bin/bash -eux 1#!/bin/sh -eux
2# 2
3# Copyright (c) 2019 Yubico AB. All rights reserved. 3# Copyright (c) 2019 Yubico AB. All rights reserved.
4# Use of this source code is governed by a BSD-style 4# Use of this source code is governed by a BSD-style
5# license that can be found in the LICENSE file. 5# license that can be found in the LICENSE file.
6 6
7LIBCBOR=$1 7LIBCBOR="$1"
8LIBFIDO2=$2 8LIBFIDO2="$2"
9 9
10CC=${CC:-clang} 10CC="${CC:-clang}"
11PKG_CONFIG_PATH=${PKG_CONFIG_PATH:-${LIBCBOR}/install/lib/pkgconfig} 11CXX="${CXX:-clang++}"
12PKG_CONFIG_PATH="${PKG_CONFIG_PATH:-${LIBCBOR}/install/lib/pkgconfig}"
12export CC PKG_CONFIG_PATH 13export CC PKG_CONFIG_PATH
13 14
14# Clean up. 15# Clean up.
15rm -rf ${LIBCBOR}/build ${LIBCBOR}/install ${LIBFIDO2}/build 16rm -rf "${LIBCBOR}/build" "${LIBCBOR}/install" "${LIBFIDO2}/build"
16 17
17# Patch, build, and install libcbor. 18# Patch, build, and install libcbor.
18(cd ${LIBCBOR} && patch -N -l -s -p0 < ${LIBFIDO2}/fuzz/README) || true 19(cd "${LIBCBOR}" && patch -N -l -s -p0 < "${LIBFIDO2}/fuzz/README") || true
19mkdir ${LIBCBOR}/build ${LIBCBOR}/install 20mkdir "${LIBCBOR}/build" "${LIBCBOR}/install"
20(cd ${LIBCBOR}/build && cmake -DCMAKE_INSTALL_PREFIX=${LIBCBOR}/install ..) 21(cd "${LIBCBOR}/build" && cmake -DCMAKE_INSTALL_PREFIX="${LIBCBOR}/install" ..)
21make -C ${LIBCBOR}/build all install 22make -C "${LIBCBOR}/build" all install
22 23
23# Build libfido2. 24# Build libfido2.
24mkdir -p ${LIBFIDO2}/build 25mkdir -p "${LIBFIDO2}/build"
25(cd ${LIBFIDO2}/build && cmake -DFUZZ=1 -DLIBFUZZER=1 -DCOVERAGE=1 \ 26export CFLAGS="-fprofile-instr-generate -fcoverage-mapping"
26 -DCMAKE_BUILD_TYPE=Debug ..) 27export LDFLAGS="${CFLAGS}"
27make -C ${LIBFIDO2}/build 28(cd "${LIBFIDO2}/build" && cmake -DFUZZ=1 -DLIBFUZZER=1 \
29 -DCMAKE_BUILD_TYPE=Debug ..)
30make -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 @@
10#include <stdint.h> 10#include <stdint.h>
11 11
12const char dummy_name[] = "finger1"; 12const char dummy_name[] = "finger1";
13const char dummy_pin1[] = "skepp cg0u3;Y..";
14const char dummy_pin2[] = "bastilha 6rJrfQZI.";
13const char dummy_pin[] = "9}4gT:8d=A37Dh}U"; 15const char dummy_pin[] = "9}4gT:8d=A37Dh}U";
14const char dummy_rp_id[] = "localhost"; 16const char dummy_rp_id[] = "localhost";
15const char dummy_rp_name[] = "sweet home localhost"; 17const char dummy_rp_name[] = "sweet home localhost";
@@ -17,8 +19,6 @@ const char dummy_user_icon[] = "an icon";
17const char dummy_user_name[] = "john smith"; 19const char dummy_user_name[] = "john smith";
18const char dummy_user_nick[] = "jsmith"; 20const char dummy_user_nick[] = "jsmith";
19const uint8_t dummy_id[] = { 0x5e, 0xd2 }; 21const uint8_t dummy_id[] = { 0x5e, 0xd2 };
20const char dummy_pin1[] = "skepp cg0u3;Y..";
21const char dummy_pin2[] = "bastilha 6rJrfQZI.";
22 22
23const uint8_t dummy_user_id[] = { 23const uint8_t dummy_user_id[] = {
24 0x78, 0x1c, 0x78, 0x60, 0xad, 0x88, 0xd2, 0x63, 24 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 @@
76 fido_cbor_info_extensions_ptr; 76 fido_cbor_info_extensions_ptr;
77 fido_cbor_info_free; 77 fido_cbor_info_free;
78 fido_cbor_info_maxmsgsiz; 78 fido_cbor_info_maxmsgsiz;
79 fido_cbor_info_maxcredcntlst;
80 fido_cbor_info_maxcredidlen;
79 fido_cbor_info_fwversion; 81 fido_cbor_info_fwversion;
80 fido_cbor_info_new; 82 fido_cbor_info_new;
81 fido_cbor_info_options_len; 83 fido_cbor_info_options_len;
@@ -96,6 +98,8 @@
96 fido_cred_free; 98 fido_cred_free;
97 fido_cred_id_len; 99 fido_cred_id_len;
98 fido_cred_id_ptr; 100 fido_cred_id_ptr;
101 fido_cred_aaguid_len;
102 fido_cred_aaguid_ptr;
99 fido_credman_del_dev_rk; 103 fido_credman_del_dev_rk;
100 fido_credman_get_dev_metadata; 104 fido_credman_get_dev_metadata;
101 fido_credman_get_dev_rk; 105 fido_credman_get_dev_rk;
@@ -155,6 +159,9 @@
155 fido_dev_get_assert; 159 fido_dev_get_assert;
156 fido_dev_get_cbor_info; 160 fido_dev_get_cbor_info;
157 fido_dev_get_retry_count; 161 fido_dev_get_retry_count;
162 fido_dev_get_touch_begin;
163 fido_dev_get_touch_status;
164 fido_dev_has_pin;
158 fido_dev_info_free; 165 fido_dev_info_free;
159 fido_dev_info_manifest; 166 fido_dev_info_manifest;
160 fido_dev_info_manufacturer_string; 167 fido_dev_info_manufacturer_string;
@@ -174,6 +181,9 @@
174 fido_dev_reset; 181 fido_dev_reset;
175 fido_dev_set_io_functions; 182 fido_dev_set_io_functions;
176 fido_dev_set_pin; 183 fido_dev_set_pin;
184 fido_dev_set_transport_functions;
185 fido_dev_supports_cred_prot;
186 fido_dev_supports_pin;
177 fido_init; 187 fido_init;
178 fido_set_log_handler; 188 fido_set_log_handler;
179 fido_strerr; 189 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%
9File '/libfido2/src/assert.c': 9File '/libfido2/src/assert.c':
10Name Regions Miss Cover Lines Miss Cover 10Name Regions Miss Cover Lines Miss Cover
11--------------------------------------------------------------------------------------- 11---------------------------------------------------------------------------------------
12fido_dev_get_assert 35 3 91.43% 38 4 89.47% 12fido_dev_get_assert 35 0 100.00% 38 0 100.00%
13fido_check_flags 13 0 100.00% 18 0 100.00% 13fido_check_flags 13 0 100.00% 18 0 100.00%
14fido_get_signed_hash 32 0 100.00% 46 0 100.00% 14fido_get_signed_hash 32 0 100.00% 46 0 100.00%
15fido_verify_sig_es256 17 2 88.24% 31 7 77.42% 15fido_verify_sig_es256 17 2 88.24% 31 7 77.42%
16fido_verify_sig_rs256 17 2 88.24% 31 7 77.42% 16fido_verify_sig_rs256 17 2 88.24% 31 7 77.42%
17fido_verify_sig_eddsa 23 4 82.61% 43 13 69.77% 17fido_verify_sig_eddsa 23 2 91.30% 43 7 83.72%
18fido_assert_verify 48 4 91.67% 79 4 94.94% 18fido_assert_verify 48 4 91.67% 79 5 93.67%
19fido_assert_set_clientdata_hash 6 0 100.00% 6 0 100.00% 19fido_assert_set_clientdata_hash 6 0 100.00% 6 0 100.00%
20fido_assert_set_hmac_salt 10 0 100.00% 7 0 100.00% 20fido_assert_set_hmac_salt 10 0 100.00% 7 0 100.00%
21fido_assert_set_rp 12 1 91.67% 14 3 78.57% 21fido_assert_set_rp 12 0 100.00% 14 0 100.00%
22fido_assert_allow_cred 13 2 84.62% 29 3 89.66% 22fido_assert_allow_cred 13 2 84.62% 29 3 89.66%
23fido_assert_set_extensions 9 0 100.00% 8 0 100.00% 23fido_assert_set_extensions 9 0 100.00% 8 0 100.00%
24fido_assert_set_options 6 6 0.00% 6 6 0.00% 24fido_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
28fido_assert_clientdata_hash_len 1 0 100.00% 3 0 100.00% 28fido_assert_clientdata_hash_len 1 0 100.00% 3 0 100.00%
29fido_assert_new 1 0 100.00% 3 0 100.00% 29fido_assert_new 1 0 100.00% 3 0 100.00%
30fido_assert_reset_tx 1 0 100.00% 15 0 100.00% 30fido_assert_reset_tx 1 0 100.00% 15 0 100.00%
31fido_assert_reset_rx 6 1 83.33% 24 3 87.50% 31fido_assert_reset_rx 6 0 100.00% 24 0 100.00%
32fido_assert_free 6 0 100.00% 13 0 100.00% 32fido_assert_free 6 0 100.00% 13 0 100.00%
33fido_assert_count 1 0 100.00% 3 0 100.00% 33fido_assert_count 1 0 100.00% 3 0 100.00%
34fido_assert_rp_id 1 0 100.00% 3 0 100.00% 34fido_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
48fido_assert_hmac_secret_ptr 4 0 100.00% 6 0 100.00% 48fido_assert_hmac_secret_ptr 4 0 100.00% 6 0 100.00%
49fido_assert_hmac_secret_len 4 0 100.00% 6 0 100.00% 49fido_assert_hmac_secret_len 4 0 100.00% 6 0 100.00%
50fido_assert_set_authdata 24 0 100.00% 35 0 100.00% 50fido_assert_set_authdata 24 0 100.00% 35 0 100.00%
51fido_assert_set_authdata_raw 24 4 83.33% 34 7 79.41% 51fido_assert_set_authdata_raw 24 0 100.00% 34 0 100.00%
52fido_assert_set_sig 14 0 100.00% 17 0 100.00% 52fido_assert_set_sig 14 0 100.00% 17 0 100.00%
53fido_assert_set_count 10 0 100.00% 21 0 100.00% 53fido_assert_set_count 10 0 100.00% 21 0 100.00%
54assert.c:fido_dev_get_assert_wait 21 1 95.24% 16 2 87.50% 54assert.c:fido_dev_get_assert_wait 21 0 100.00% 16 0 100.00%
55assert.c:fido_dev_get_assert_tx 58 4 93.10% 84 11 86.90% 55assert.c:fido_dev_get_assert_tx 58 4 93.10% 84 11 86.90%
56assert.c:fido_dev_get_assert_rx 19 0 100.00% 38 0 100.00% 56assert.c:fido_dev_get_assert_rx 19 0 100.00% 38 0 100.00%
57assert.c:adjust_assert_count 24 0 100.00% 33 0 100.00% 57assert.c:adjust_assert_count 24 0 100.00% 33 0 100.00%
58assert.c:parse_assert_reply 11 0 100.00% 25 0 100.00% 58assert.c:parse_assert_reply 11 0 100.00% 25 0 100.00%
59assert.c:fido_get_next_assert_tx 8 2 75.00% 10 3 70.00% 59assert.c:fido_get_next_assert_tx 8 0 100.00% 10 0 100.00%
60assert.c:fido_get_next_assert_rx 15 4 73.33% 26 7 73.08% 60assert.c:fido_get_next_assert_rx 15 2 86.67% 26 4 84.62%
61assert.c:decrypt_hmac_secrets 9 3 66.67% 15 7 53.33% 61assert.c:decrypt_hmac_secrets 9 0 100.00% 15 0 100.00%
62assert.c:check_extensions 4 0 100.00% 9 0 100.00% 62assert.c:check_extensions 4 0 100.00% 9 0 100.00%
63assert.c:fido_assert_clean_authdata 1 0 100.00% 9 0 100.00% 63assert.c:fido_assert_clean_authdata 1 0 100.00% 9 0 100.00%
64assert.c:fido_assert_clean_sig 1 0 100.00% 5 0 100.00% 64assert.c:fido_assert_clean_sig 1 0 100.00% 5 0 100.00%
65--------------------------------------------------------------------------------------- 65---------------------------------------------------------------------------------------
66TOTAL 566 43 92.40% 900 87 90.33% 66TOTAL 566 24 95.76% 900 50 94.44%
67 67
68File '/libfido2/src/authkey.c': 68File '/libfido2/src/authkey.c':
69Name Regions Miss Cover Lines Miss Cover 69Name Regions Miss Cover Lines Miss Cover
@@ -135,14 +135,14 @@ File '/libfido2/src/blob.c':
135Name Regions Miss Cover Lines Miss Cover 135Name Regions Miss Cover Lines Miss Cover
136--------------------------------------------------------------------------------------- 136---------------------------------------------------------------------------------------
137fido_blob_new 1 0 100.00% 3 0 100.00% 137fido_blob_new 1 0 100.00% 3 0 100.00%
138fido_blob_set 11 1 90.91% 25 4 84.00% 138fido_blob_set 11 0 100.00% 25 0 100.00%
139fido_blob_free 8 0 100.00% 16 0 100.00% 139fido_blob_free 8 0 100.00% 16 0 100.00%
140fido_free_blob_array 9 0 100.00% 17 0 100.00% 140fido_free_blob_array 9 0 100.00% 17 0 100.00%
141fido_blob_encode 6 0 100.00% 6 0 100.00% 141fido_blob_encode 6 0 100.00% 6 0 100.00%
142fido_blob_decode 1 0 100.00% 3 0 100.00% 142fido_blob_decode 1 0 100.00% 3 0 100.00%
143fido_blob_is_empty 3 0 100.00% 3 0 100.00% 143fido_blob_is_empty 3 0 100.00% 3 0 100.00%
144--------------------------------------------------------------------------------------- 144---------------------------------------------------------------------------------------
145TOTAL 39 1 97.44% 73 4 94.52% 145TOTAL 39 0 100.00% 73 0 100.00%
146 146
147File '/libfido2/src/buf.c': 147File '/libfido2/src/buf.c':
148Name Regions Miss Cover Lines Miss Cover 148Name Regions Miss Cover Lines Miss Cover
@@ -155,7 +155,7 @@ TOTAL 8 1 87.50% 20 1
155File '/libfido2/src/cbor.c': 155File '/libfido2/src/cbor.c':
156Name Regions Miss Cover Lines Miss Cover 156Name Regions Miss Cover Lines Miss Cover
157--------------------------------------------------------------------------------------- 157---------------------------------------------------------------------------------------
158cbor_map_iter 20 0 100.00% 30 0 100.00% 158cbor_map_iter 20 1 95.00% 30 4 86.67%
159cbor_array_iter 12 0 100.00% 20 0 100.00% 159cbor_array_iter 12 0 100.00% 20 0 100.00%
160cbor_parse_reply 27 0 100.00% 43 0 100.00% 160cbor_parse_reply 27 0 100.00% 43 0 100.00%
161cbor_vector_free 6 0 100.00% 5 0 100.00% 161cbor_vector_free 6 0 100.00% 5 0 100.00%
@@ -168,23 +168,23 @@ cbor_flatten_vector 14 1 92.86% 21 1
168cbor_build_frame 15 0 100.00% 32 0 100.00% 168cbor_build_frame 15 0 100.00% 32 0 100.00%
169cbor_encode_rp_entity 13 0 100.00% 14 0 100.00% 169cbor_encode_rp_entity 13 0 100.00% 14 0 100.00%
170cbor_encode_user_entity 21 0 100.00% 18 0 100.00% 170cbor_encode_user_entity 21 0 100.00% 18 0 100.00%
171cbor_encode_pubkey_param 36 1 97.22% 48 0 100.00% 171cbor_encode_pubkey_param 36 0 100.00% 48 0 100.00%
172cbor_encode_pubkey 10 0 100.00% 13 0 100.00% 172cbor_encode_pubkey 10 0 100.00% 13 0 100.00%
173cbor_encode_pubkey_list 18 1 94.44% 23 0 100.00% 173cbor_encode_pubkey_list 18 0 100.00% 23 0 100.00%
174cbor_encode_extensions 24 2 91.67% 26 3 88.46% 174cbor_encode_extensions 28 0 100.00% 28 0 100.00%
175cbor_encode_options 13 0 100.00% 14 0 100.00% 175cbor_encode_options 13 0 100.00% 14 0 100.00%
176cbor_encode_assert_options 13 0 100.00% 14 0 100.00% 176cbor_encode_assert_options 13 0 100.00% 14 0 100.00%
177cbor_encode_pin_auth 8 0 100.00% 12 0 100.00% 177cbor_encode_pin_auth 8 0 100.00% 12 0 100.00%
178cbor_encode_pin_opt 1 0 100.00% 3 0 100.00% 178cbor_encode_pin_opt 1 0 100.00% 3 0 100.00%
179cbor_encode_pin_enc 4 0 100.00% 12 0 100.00% 179cbor_encode_pin_enc 4 0 100.00% 12 0 100.00%
180cbor_encode_change_pin_auth 44 1 97.73% 69 3 95.65% 180cbor_encode_change_pin_auth 39 0 100.00% 60 0 100.00%
181cbor_encode_set_pin_auth 17 0 100.00% 28 0 100.00% 181cbor_encode_set_pin_auth 17 0 100.00% 28 0 100.00%
182cbor_encode_pin_hash_enc 15 0 100.00% 27 0 100.00% 182cbor_encode_pin_hash_enc 15 0 100.00% 27 0 100.00%
183cbor_encode_hmac_secret_param 41 2 95.12% 66 9 86.36% 183cbor_encode_hmac_secret_param 41 1 97.56% 66 4 93.94%
184cbor_decode_fmt 9 0 100.00% 18 0 100.00% 184cbor_decode_fmt 9 0 100.00% 18 0 100.00%
185cbor_decode_pubkey 21 6 71.43% 32 7 78.12% 185cbor_decode_pubkey 21 1 95.24% 32 2 93.75%
186cbor_decode_cred_authdata 31 0 100.00% 47 0 100.00% 186cbor_decode_cred_authdata 31 0 100.00% 47 0 100.00%
187cbor_decode_assert_authdata 23 2 91.30% 44 2 95.45% 187cbor_decode_assert_authdata 23 0 100.00% 44 0 100.00%
188cbor_decode_attstmt 8 0 100.00% 10 0 100.00% 188cbor_decode_attstmt 8 0 100.00% 10 0 100.00%
189cbor_decode_uint64 4 0 100.00% 10 0 100.00% 189cbor_decode_uint64 4 0 100.00% 10 0 100.00%
190cbor_decode_cred_id 8 0 100.00% 10 0 100.00% 190cbor_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
193cbor.c:ctap_check_cbor 28 0 100.00% 32 0 100.00% 193cbor.c:ctap_check_cbor 28 0 100.00% 32 0 100.00%
194cbor.c:check_key_type 8 0 100.00% 9 0 100.00% 194cbor.c:check_key_type 8 0 100.00% 9 0 100.00%
195cbor.c:cbor_add_arg 13 0 100.00% 28 0 100.00% 195cbor.c:cbor_add_arg 13 0 100.00% 28 0 100.00%
196cbor.c:cbor_add_uint8 14 1 92.86% 26 3 88.46% 196cbor.c:cbor_add_uint8 14 0 100.00% 26 0 100.00%
197cbor.c:sha256 7 0 100.00% 15 0 100.00% 197cbor.c:sha256 7 0 100.00% 15 0 100.00%
198cbor.c:get_cose_alg 36 6 83.33% 48 6 87.50% 198cbor.c:get_cose_alg 36 0 100.00% 48 0 100.00%
199cbor.c:find_cose_alg 35 0 100.00% 40 0 100.00% 199cbor.c:find_cose_alg 35 0 100.00% 40 0 100.00%
200cbor.c:decode_attcred 25 0 100.00% 58 0 100.00% 200cbor.c:decode_attcred 25 0 100.00% 58 0 100.00%
201cbor.c:decode_extensions 14 9 35.71% 34 13 61.76% 201cbor.c:decode_extensions 14 0 100.00% 34 0 100.00%
202cbor.c:decode_extension 27 27 0.00% 36 36 0.00% 202cbor.c:decode_extension 27 2 92.59% 36 6 83.33%
203cbor.c:decode_hmac_secret 16 4 75.00% 32 6 81.25% 203cbor.c:decode_hmac_secret 16 0 100.00% 32 0 100.00%
204cbor.c:decode_hmac_secret_aux 7 7 0.00% 17 17 0.00% 204cbor.c:decode_hmac_secret_aux 7 0 100.00% 17 0 100.00%
205cbor.c:decode_attstmt_entry 38 0 100.00% 45 0 100.00% 205cbor.c:decode_attstmt_entry 38 0 100.00% 45 0 100.00%
206cbor.c:decode_x5c 4 0 100.00% 8 0 100.00% 206cbor.c:decode_x5c 4 0 100.00% 8 0 100.00%
207cbor.c:decode_cred_id_entry 10 0 100.00% 23 0 100.00% 207cbor.c:decode_cred_id_entry 10 0 100.00% 23 0 100.00%
208cbor.c:decode_user_entry 25 0 100.00% 39 0 100.00% 208cbor.c:decode_user_entry 25 0 100.00% 39 0 100.00%
209cbor.c:decode_rp_entity_entry 15 0 100.00% 29 0 100.00% 209cbor.c:decode_rp_entity_entry 15 0 100.00% 29 0 100.00%
210--------------------------------------------------------------------------------------- 210---------------------------------------------------------------------------------------
211TOTAL 884 70 92.08% 1371 106 92.27% 211TOTAL 883 6 99.32% 1364 17 98.75%
212 212
213File '/libfido2/src/cred.c': 213File '/libfido2/src/cred.c':
214Name Regions Miss Cover Lines Miss Cover 214Name Regions Miss Cover Lines Miss Cover
215--------------------------------------------------------------------------------------- 215---------------------------------------------------------------------------------------
216fido_dev_make_cred 12 0 100.00% 10 0 100.00% 216fido_dev_make_cred 12 0 100.00% 10 0 100.00%
217fido_check_rp_id 4 0 100.00% 14 0 100.00% 217fido_check_rp_id 4 0 100.00% 14 0 100.00%
218fido_cred_verify 46 6 86.96% 71 11 84.51% 218fido_cred_verify 46 2 95.65% 71 3 95.77%
219fido_cred_verify_self 54 14 74.07% 90 22 75.56% 219fido_cred_verify_self 54 4 92.59% 90 5 94.44%
220fido_cred_new 1 0 100.00% 3 0 100.00% 220fido_cred_new 1 0 100.00% 3 0 100.00%
221fido_cred_reset_tx 1 0 100.00% 20 0 100.00% 221fido_cred_reset_tx 1 0 100.00% 20 0 100.00%
222fido_cred_reset_rx 1 0 100.00% 8 0 100.00% 222fido_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
227fido_cred_set_sig 12 0 100.00% 16 0 100.00% 227fido_cred_set_sig 12 0 100.00% 16 0 100.00%
228fido_cred_exclude 14 2 85.71% 25 3 88.00% 228fido_cred_exclude 14 2 85.71% 25 3 88.00%
229fido_cred_set_clientdata_hash 6 0 100.00% 6 0 100.00% 229fido_cred_set_clientdata_hash 6 0 100.00% 6 0 100.00%
230fido_cred_set_rp 18 2 88.89% 26 6 76.92% 230fido_cred_set_rp 18 0 100.00% 26 0 100.00%
231fido_cred_set_user 33 4 87.88% 50 13 74.00% 231fido_cred_set_user 33 0 100.00% 50 0 100.00%
232fido_cred_set_extensions 15 0 100.00% 12 0 100.00% 232fido_cred_set_extensions 15 0 100.00% 12 0 100.00%
233fido_cred_set_options 6 6 0.00% 6 6 0.00% 233fido_cred_set_options 6 6 0.00% 6 6 0.00%
234fido_cred_set_rk 2 0 100.00% 5 0 100.00% 234fido_cred_set_rk 2 0 100.00% 5 0 100.00%
235fido_cred_set_uv 2 0 100.00% 5 0 100.00% 235fido_cred_set_uv 2 0 100.00% 5 0 100.00%
236fido_cred_set_prot 21 2 90.48% 16 0 100.00% 236fido_cred_set_prot 21 0 100.00% 16 0 100.00%
237fido_cred_set_fmt 16 4 75.00% 15 1 93.33% 237fido_cred_set_fmt 16 4 75.00% 15 1 93.33%
238fido_cred_set_type 17 2 88.24% 9 1 88.89% 238fido_cred_set_type 17 0 100.00% 9 0 100.00%
239fido_cred_type 1 0 100.00% 3 0 100.00% 239fido_cred_type 1 0 100.00% 3 0 100.00%
240fido_cred_flags 1 0 100.00% 3 0 100.00% 240fido_cred_flags 1 0 100.00% 3 0 100.00%
241fido_cred_clientdata_hash_ptr 1 0 100.00% 3 0 100.00% 241fido_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
246fido_cred_sig_len 1 0 100.00% 3 0 100.00% 246fido_cred_sig_len 1 0 100.00% 3 0 100.00%
247fido_cred_authdata_ptr 1 0 100.00% 3 0 100.00% 247fido_cred_authdata_ptr 1 0 100.00% 3 0 100.00%
248fido_cred_authdata_len 1 0 100.00% 3 0 100.00% 248fido_cred_authdata_len 1 0 100.00% 3 0 100.00%
249fido_cred_pubkey_ptr 9 2 77.78% 20 2 90.00% 249fido_cred_pubkey_ptr 9 0 100.00% 20 0 100.00%
250fido_cred_pubkey_len 9 2 77.78% 20 2 90.00% 250fido_cred_pubkey_len 9 0 100.00% 20 0 100.00%
251fido_cred_id_ptr 1 0 100.00% 3 0 100.00% 251fido_cred_id_ptr 1 0 100.00% 3 0 100.00%
252fido_cred_id_len 1 0 100.00% 3 0 100.00% 252fido_cred_id_len 1 0 100.00% 3 0 100.00%
253fido_cred_aaguid_ptr 1 0 100.00% 3 0 100.00%
254fido_cred_aaguid_len 1 0 100.00% 3 0 100.00%
253fido_cred_prot 1 0 100.00% 3 0 100.00% 255fido_cred_prot 1 0 100.00% 3 0 100.00%
254fido_cred_fmt 1 0 100.00% 3 0 100.00% 256fido_cred_fmt 1 0 100.00% 3 0 100.00%
255fido_cred_rp_id 1 0 100.00% 3 0 100.00% 257fido_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
269cred.c:fido_cred_clean_x509 1 0 100.00% 5 0 100.00% 271cred.c:fido_cred_clean_x509 1 0 100.00% 5 0 100.00%
270cred.c:fido_cred_clean_sig 1 0 100.00% 5 0 100.00% 272cred.c:fido_cred_clean_sig 1 0 100.00% 5 0 100.00%
271--------------------------------------------------------------------------------------- 273---------------------------------------------------------------------------------------
272TOTAL 534 51 90.45% 830 78 90.60% 274TOTAL 536 23 95.71% 836 29 96.53%
273 275
274File '/libfido2/src/credman.c': 276File '/libfido2/src/credman.c':
275Name Regions Miss Cover Lines Miss Cover 277Name Regions Miss Cover Lines Miss Cover
@@ -295,14 +297,14 @@ fido_credman_rp_id_hash_len 4 0 100.00% 6 0
295fido_credman_rp_id_hash_ptr 4 0 100.00% 6 0 100.00% 297fido_credman_rp_id_hash_ptr 4 0 100.00% 6 0 100.00%
296credman.c:credman_get_metadata_wait 11 0 100.00% 9 0 100.00% 298credman.c:credman_get_metadata_wait 11 0 100.00% 9 0 100.00%
297credman.c:credman_tx 30 0 100.00% 53 0 100.00% 299credman.c:credman_tx 30 0 100.00% 53 0 100.00%
298credman.c:credman_prepare_hmac 21 1 95.24% 43 2 95.35% 300credman.c:credman_prepare_hmac 21 1 95.24% 43 3 93.02%
299credman.c:credman_rx_metadata 11 0 100.00% 21 0 100.00% 301credman.c:credman_rx_metadata 11 0 100.00% 21 0 100.00%
300credman.c:credman_parse_metadata 9 0 100.00% 19 0 100.00% 302credman.c:credman_parse_metadata 9 0 100.00% 19 0 100.00%
301credman.c:credman_get_rk_wait 27 0 100.00% 26 0 100.00% 303credman.c:credman_get_rk_wait 27 0 100.00% 26 0 100.00%
302credman.c:credman_rx_rk 19 0 100.00% 36 0 100.00% 304credman.c:credman_rx_rk 19 0 100.00% 36 0 100.00%
303credman.c:credman_parse_rk_count 16 0 100.00% 25 0 100.00% 305credman.c:credman_parse_rk_count 16 0 100.00% 25 0 100.00%
304credman.c:credman_grow_array 17 2 88.24% 28 5 82.14% 306credman.c:credman_grow_array 17 2 88.24% 28 5 82.14%
305credman.c:credman_parse_rk 13 0 100.00% 25 0 100.00% 307credman.c:credman_parse_rk 22 0 100.00% 31 0 100.00%
306credman.c:credman_rx_next_rk 15 2 86.67% 26 4 84.62% 308credman.c:credman_rx_next_rk 15 2 86.67% 26 4 84.62%
307credman.c:credman_del_rk_wait 16 0 100.00% 19 0 100.00% 309credman.c:credman_del_rk_wait 16 0 100.00% 19 0 100.00%
308credman.c:credman_get_rp_wait 23 0 100.00% 16 0 100.00% 310credman.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
313credman.c:credman_reset_rk 4 0 100.00% 10 0 100.00% 315credman.c:credman_reset_rk 4 0 100.00% 10 0 100.00%
314credman.c:credman_reset_rp 4 0 100.00% 15 0 100.00% 316credman.c:credman_reset_rp 4 0 100.00% 15 0 100.00%
315--------------------------------------------------------------------------------------- 317---------------------------------------------------------------------------------------
316TOTAL 376 18 95.21% 589 15 97.45% 318TOTAL 385 18 95.32% 595 16 97.31%
317 319
318File '/libfido2/src/dev.c': 320File '/libfido2/src/dev.c':
319Name Regions Miss Cover Lines Miss Cover 321Name Regions Miss Cover Lines Miss Cover
@@ -324,9 +326,11 @@ fido_dev_info_manifest 17 17 0.00% 24 24
324fido_dev_open_with_info 5 5 0.00% 6 6 0.00% 326fido_dev_open_with_info 5 5 0.00% 6 6 0.00%
325fido_dev_open 1 0 100.00% 3 0 100.00% 327fido_dev_open 1 0 100.00% 3 0 100.00%
326fido_dev_close 8 2 75.00% 9 0 100.00% 328fido_dev_close 8 2 75.00% 9 0 100.00%
327fido_dev_cancel 7 0 100.00% 6 0 100.00% 329fido_dev_cancel 11 0 100.00% 9 0 100.00%
328fido_dev_set_io_functions 18 4 77.78% 16 6 62.50% 330fido_dev_get_touch_begin 50 0 100.00% 68 0 100.00%
329fido_dev_set_transport_functions 6 6 0.00% 10 10 0.00% 331fido_dev_get_touch_status 17 0 100.00% 25 0 100.00%
332fido_dev_set_io_functions 18 4 77.78% 17 6 64.71%
333fido_dev_set_transport_functions 6 6 0.00% 11 11 0.00%
330fido_init 7 1 85.71% 4 0 100.00% 334fido_init 7 1 85.71% 4 0 100.00%
331fido_dev_new 5 0 100.00% 16 0 100.00% 335fido_dev_new 5 0 100.00% 16 0 100.00%
332fido_dev_new_with_info 17 17 0.00% 26 26 0.00% 336fido_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
337fido_dev_build 1 0 100.00% 3 0 100.00% 341fido_dev_build 1 0 100.00% 3 0 100.00%
338fido_dev_flags 1 0 100.00% 3 0 100.00% 342fido_dev_flags 1 0 100.00% 3 0 100.00%
339fido_dev_is_fido2 2 0 100.00% 3 0 100.00% 343fido_dev_is_fido2 2 0 100.00% 3 0 100.00%
340fido_dev_force_u2f 2 0 100.00% 3 0 100.00% 344fido_dev_supports_pin 3 0 100.00% 3 0 100.00%
345fido_dev_has_pin 2 0 100.00% 3 0 100.00%
346fido_dev_supports_cred_prot 2 0 100.00% 3 0 100.00%
347fido_dev_force_u2f 2 0 100.00% 4 0 100.00%
341fido_dev_force_fido2 2 2 0.00% 3 3 0.00% 348fido_dev_force_fido2 2 2 0.00% 3 3 0.00%
342dev.c:find_manifest_func_node 5 5 0.00% 9 9 0.00% 349dev.c:find_manifest_func_node 5 5 0.00% 9 9 0.00%
343dev.c:fido_dev_open_wait 10 0 100.00% 9 0 100.00% 350dev.c:fido_dev_open_wait 10 0 100.00% 9 0 100.00%
344dev.c:fido_dev_open_tx 25 8 68.00% 32 12 62.50% 351dev.c:fido_dev_open_tx 51 13 74.51% 63 23 63.49%
345dev.c:obtain_nonce 4 1 75.00% 5 1 80.00% 352dev.c:obtain_nonce 4 1 75.00% 5 1 80.00%
346dev.c:fido_dev_open_rx 32 0 100.00% 53 0 100.00% 353dev.c:set_random_report_len 11 0 100.00% 6 0 100.00%
354dev.c:fido_dev_open_rx 33 0 100.00% 56 0 100.00%
355dev.c:fido_dev_set_flags 17 0 100.00% 24 0 100.00%
347--------------------------------------------------------------------------------------- 356---------------------------------------------------------------------------------------
348TOTAL 201 85 57.71% 294 128 56.46% 357TOTAL 334 90 73.05% 466 140 69.96%
349 358
350File '/libfido2/src/ecdh.c': 359File '/libfido2/src/ecdh.c':
351Name Regions Miss Cover Lines Miss Cover 360Name Regions Miss Cover Lines Miss Cover
@@ -372,9 +381,9 @@ TOTAL 54 0 100.00% 79 0
372File '/libfido2/src/err.c': 381File '/libfido2/src/err.c':
373Name Regions Miss Cover Lines Miss Cover 382Name Regions Miss Cover Lines Miss Cover
374--------------------------------------------------------------------------------------- 383---------------------------------------------------------------------------------------
375fido_strerr 108 108 0.00% 112 112 0.00% 384fido_strerr 112 8 92.86% 116 8 93.10%
376--------------------------------------------------------------------------------------- 385---------------------------------------------------------------------------------------
377TOTAL 108 108 0.00% 112 112 0.00% 386TOTAL 112 8 92.86% 116 8 93.10%
378 387
379File '/libfido2/src/es256.c': 388File '/libfido2/src/es256.c':
380Name Regions Miss Cover Lines Miss Cover 389Name Regions Miss Cover Lines Miss Cover
@@ -389,14 +398,14 @@ es256_pk_from_ptr 11 0 100.00% 13 0
389es256_pk_set_x 1 0 100.00% 5 0 100.00% 398es256_pk_set_x 1 0 100.00% 5 0 100.00%
390es256_pk_set_y 1 0 100.00% 5 0 100.00% 399es256_pk_set_y 1 0 100.00% 5 0 100.00%
391es256_sk_create 39 0 100.00% 46 0 100.00% 400es256_sk_create 39 0 100.00% 46 0 100.00%
392es256_pk_to_EVP_PKEY 41 0 100.00% 58 0 100.00% 401es256_pk_to_EVP_PKEY 42 0 100.00% 66 0 100.00%
393es256_pk_from_EC_KEY 38 0 100.00% 39 0 100.00% 402es256_pk_from_EC_KEY 38 0 100.00% 43 0 100.00%
394es256_sk_to_EVP_PKEY 27 0 100.00% 41 0 100.00% 403es256_sk_to_EVP_PKEY 28 0 100.00% 50 0 100.00%
395es256_derive_pk 25 0 100.00% 34 0 100.00% 404es256_derive_pk 25 0 100.00% 34 0 100.00%
396es256.c:decode_pubkey_point 9 0 100.00% 16 0 100.00% 405es256.c:decode_pubkey_point 9 0 100.00% 16 0 100.00%
397es256.c:decode_coord 8 0 100.00% 12 0 100.00% 406es256.c:decode_coord 8 0 100.00% 12 0 100.00%
398--------------------------------------------------------------------------------------- 407---------------------------------------------------------------------------------------
399TOTAL 278 0 100.00% 377 0 100.00% 408TOTAL 280 0 100.00% 398 0 100.00%
400 409
401File '/libfido2/src/extern.h': 410File '/libfido2/src/extern.h':
402Name Regions Miss Cover Lines Miss Cover 411Name Regions Miss Cover Lines Miss Cover
@@ -423,20 +432,27 @@ TOTAL 16 16 0.00% 38 38
423File '/libfido2/src/hid_linux.c': 432File '/libfido2/src/hid_linux.c':
424Name Regions Miss Cover Lines Miss Cover 433Name Regions Miss Cover Lines Miss Cover
425--------------------------------------------------------------------------------------- 434---------------------------------------------------------------------------------------
426fido_hid_manifest 33 33 0.00% 46 46 0.00% 435fido_hid_manifest 35 35 0.00% 50 50 0.00%
427fido_hid_open 6 6 0.00% 11 11 0.00% 436fido_hid_open 17 17 0.00% 22 22 0.00%
428fido_hid_close 1 1 0.00% 6 6 0.00% 437fido_hid_close 1 1 0.00% 6 6 0.00%
429fido_hid_read 12 12 0.00% 16 16 0.00% 438fido_hid_read 12 12 0.00% 21 21 0.00%
430fido_hid_write 12 12 0.00% 16 16 0.00% 439fido_hid_write 9 9 0.00% 16 16 0.00%
431hid_linux.c:copy_info 35 35 0.00% 56 56 0.00% 440fido_hid_report_in_len 1 1 0.00% 5 5 0.00%
432hid_linux.c:is_fido 6 6 0.00% 14 14 0.00% 441fido_hid_report_out_len 1 1 0.00% 5 5 0.00%
433hid_linux.c:get_report_descriptor 17 17 0.00% 30 30 0.00% 442hid_linux.c:copy_info 30 30 0.00% 52 52 0.00%
434hid_linux.c:get_usage_info 16 16 0.00% 33 33 0.00% 443hid_linux.c:is_fido 9 9 0.00% 23 23 0.00%
444hid_linux.c:get_usage_info 16 16 0.00% 30 30 0.00%
435hid_linux.c:get_key_len 6 6 0.00% 14 14 0.00% 445hid_linux.c:get_key_len 6 6 0.00% 14 14 0.00%
436hid_linux.c:get_key_val 6 6 0.00% 20 20 0.00% 446hid_linux.c:get_key_val 6 6 0.00% 20 20 0.00%
437hid_linux.c:parse_uevent 16 16 0.00% 30 30 0.00% 447hid_linux.c:get_parent_attr 6 6 0.00% 11 11 0.00%
438--------------------------------------------------------------------------------------- 448hid_linux.c:parse_uevent 12 12 0.00% 28 28 0.00%
439TOTAL 166 166 0.00% 292 292 0.00% 449hid_linux.c:get_usb_attr 1 1 0.00% 3 3 0.00%
450hid_linux.c:get_report_descriptor 11 11 0.00% 18 18 0.00%
451hid_linux.c:get_report_sizes 19 19 0.00% 33 33 0.00%
452hid_linux.c:waitfd 28 28 0.00% 43 43 0.00%
453hid_linux.c:timespec_to_ms 15 15 0.00% 16 16 0.00%
454---------------------------------------------------------------------------------------
455TOTAL 235 235 0.00% 416 416 0.00%
440 456
441File '/libfido2/src/info.c': 457File '/libfido2/src/info.c':
442Name Regions Miss Cover Lines Miss Cover 458Name Regions Miss Cover Lines Miss Cover
@@ -455,11 +471,14 @@ fido_cbor_info_options_name_ptr 1 0 100.00% 3 0
455fido_cbor_info_options_value_ptr 1 0 100.00% 3 0 100.00% 471fido_cbor_info_options_value_ptr 1 0 100.00% 3 0 100.00%
456fido_cbor_info_options_len 1 0 100.00% 3 0 100.00% 472fido_cbor_info_options_len 1 0 100.00% 3 0 100.00%
457fido_cbor_info_maxmsgsiz 1 0 100.00% 3 0 100.00% 473fido_cbor_info_maxmsgsiz 1 0 100.00% 3 0 100.00%
474fido_cbor_info_maxcredcntlst 1 0 100.00% 3 0 100.00%
475fido_cbor_info_maxcredidlen 1 0 100.00% 3 0 100.00%
476fido_cbor_info_fwversion 1 0 100.00% 3 0 100.00%
458fido_cbor_info_protocols_ptr 1 0 100.00% 3 0 100.00% 477fido_cbor_info_protocols_ptr 1 0 100.00% 3 0 100.00%
459fido_cbor_info_protocols_len 1 0 100.00% 3 0 100.00% 478fido_cbor_info_protocols_len 1 0 100.00% 3 0 100.00%
460info.c:fido_dev_get_cbor_info_tx 8 0 100.00% 12 0 100.00% 479info.c:fido_dev_get_cbor_info_tx 8 0 100.00% 12 0 100.00%
461info.c:fido_dev_get_cbor_info_rx 6 0 100.00% 18 0 100.00% 480info.c:fido_dev_get_cbor_info_rx 6 0 100.00% 18 0 100.00%
462info.c:parse_reply_element 13 0 100.00% 27 0 100.00% 481info.c:parse_reply_element 16 0 100.00% 33 0 100.00%
463info.c:decode_versions 12 0 100.00% 21 0 100.00% 482info.c:decode_versions 12 0 100.00% 21 0 100.00%
464info.c:decode_version 4 0 100.00% 14 0 100.00% 483info.c:decode_version 4 0 100.00% 14 0 100.00%
465info.c:decode_extensions 12 0 100.00% 21 0 100.00% 484info.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
473info.c:free_opt_array 4 0 100.00% 9 0 100.00% 492info.c:free_opt_array 4 0 100.00% 9 0 100.00%
474info.c:free_byte_array 1 0 100.00% 6 0 100.00% 493info.c:free_byte_array 1 0 100.00% 6 0 100.00%
475--------------------------------------------------------------------------------------- 494---------------------------------------------------------------------------------------
476TOTAL 146 0 100.00% 304 0 100.00% 495TOTAL 152 0 100.00% 319 0 100.00%
477 496
478File '/libfido2/src/io.c': 497File '/libfido2/src/io.c':
479Name Regions Miss Cover Lines Miss Cover 498Name Regions Miss Cover Lines Miss Cover
480--------------------------------------------------------------------------------------- 499---------------------------------------------------------------------------------------
481fido_tx 14 1 92.86% 18 0 100.00% 500fido_tx 13 1 92.31% 14 0 100.00%
482fido_rx 13 2 84.62% 21 3 85.71% 501fido_rx 13 2 84.62% 19 3 84.21%
483fido_rx_cbor_status 8 0 100.00% 12 0 100.00% 502fido_rx_cbor_status 8 0 100.00% 12 0 100.00%
484io.c:tx_empty 7 0 100.00% 16 0 100.00% 503io.c:tx_empty 9 0 100.00% 17 0 100.00%
485io.c:tx 13 0 100.00% 21 0 100.00% 504io.c:tx 13 0 100.00% 21 0 100.00%
486io.c:tx_preamble 10 0 100.00% 20 0 100.00% 505io.c:tx_preamble 16 1 93.75% 24 1 95.83%
487io.c:tx_frame 9 0 100.00% 18 0 100.00% 506io.c:tx_frame 15 1 93.33% 22 1 95.45%
488io.c:rx 25 1 96.00% 58 4 93.10% 507io.c:rx 40 2 95.00% 68 1 98.53%
489io.c:rx_preamble 18 1 94.44% 25 4 84.00% 508io.c:rx_preamble 21 2 90.48% 28 5 82.14%
490io.c:rx_frame 6 0 100.00% 9 0 100.00% 509io.c:rx_frame 8 0 100.00% 11 0 100.00%
491--------------------------------------------------------------------------------------- 510---------------------------------------------------------------------------------------
492TOTAL 123 5 95.93% 218 11 94.95% 511TOTAL 156 9 94.23% 236 11 95.34%
493 512
494File '/libfido2/src/iso7816.c': 513File '/libfido2/src/iso7816.c':
495Name Regions Miss Cover Lines Miss Cover 514Name Regions Miss Cover Lines Miss Cover
@@ -547,32 +566,34 @@ TOTAL 19 0 100.00% 22 0
547File '/libfido2/src/rs256.c': 566File '/libfido2/src/rs256.c':
548Name Regions Miss Cover Lines Miss Cover 567Name Regions Miss Cover Lines Miss Cover
549--------------------------------------------------------------------------------------- 568---------------------------------------------------------------------------------------
550rs256_pk_decode 8 8 0.00% 10 10 0.00% 569rs256_pk_decode 8 0 100.00% 10 0 100.00%
551rs256_pk_new 1 0 100.00% 3 0 100.00% 570rs256_pk_new 1 0 100.00% 3 0 100.00%
552rs256_pk_free 6 0 100.00% 11 0 100.00% 571rs256_pk_free 6 0 100.00% 11 0 100.00%
553rs256_pk_from_ptr 6 0 100.00% 8 0 100.00% 572rs256_pk_from_ptr 6 0 100.00% 8 0 100.00%
554rs256_pk_to_EVP_PKEY 32 0 100.00% 48 0 100.00% 573rs256_pk_to_EVP_PKEY 32 0 100.00% 48 0 100.00%
555rs256_pk_from_RSA 32 4 87.50% 32 6 81.25% 574rs256_pk_from_RSA 32 4 87.50% 32 6 81.25%
556rs256.c:decode_rsa_pubkey 9 9 0.00% 16 16 0.00% 575rs256.c:decode_rsa_pubkey 9 1 88.89% 16 4 75.00%
557rs256.c:decode_bignum 8 8 0.00% 12 12 0.00% 576rs256.c:decode_bignum 8 1 87.50% 12 3 75.00%
558--------------------------------------------------------------------------------------- 577---------------------------------------------------------------------------------------
559TOTAL 102 29 71.57% 140 44 68.57% 578TOTAL 102 6 94.12% 140 13 90.71%
560 579
561File '/libfido2/src/u2f.c': 580File '/libfido2/src/u2f.c':
562Name Regions Miss Cover Lines Miss Cover 581Name Regions Miss Cover Lines Miss Cover
563--------------------------------------------------------------------------------------- 582---------------------------------------------------------------------------------------
564u2f_register 70 5 92.86% 88 7 92.05% 583u2f_register 70 1 98.57% 88 0 100.00%
565u2f_authenticate 32 4 87.50% 44 2 95.45% 584u2f_authenticate 32 0 100.00% 44 0 100.00%
585u2f_get_touch_begin 30 0 100.00% 46 0 100.00%
586u2f_get_touch_status 18 0 100.00% 29 0 100.00%
566u2f.c:key_lookup 44 0 100.00% 69 0 100.00% 587u2f.c:key_lookup 44 0 100.00% 69 0 100.00%
567u2f.c:send_dummy_register 31 5 83.87% 49 8 83.67% 588u2f.c:send_dummy_register 31 1 96.77% 49 0 100.00%
568u2f.c:parse_register_reply 57 0 100.00% 83 0 100.00% 589u2f.c:parse_register_reply 57 0 100.00% 83 0 100.00%
569u2f.c:x5c_get 21 2 90.48% 37 6 83.78% 590u2f.c:x5c_get 21 1 95.24% 37 3 91.89%
570u2f.c:sig_get 8 1 87.50% 16 6 62.50% 591u2f.c:sig_get 8 1 87.50% 16 6 62.50%
571u2f.c:encode_cred_authdata 37 3 91.89% 82 9 89.02% 592u2f.c:encode_cred_authdata 37 2 94.59% 82 6 92.68%
572u2f.c:cbor_blob_from_ec_point 22 1 95.45% 39 3 92.31% 593u2f.c:cbor_blob_from_ec_point 22 0 100.00% 39 0 100.00%
573u2f.c:u2f_authenticate_single 36 2 94.44% 58 4 93.10% 594u2f.c:u2f_authenticate_single 36 0 100.00% 58 0 100.00%
574u2f.c:do_auth 50 3 94.00% 71 4 94.37% 595u2f.c:do_auth 50 1 98.00% 71 0 100.00%
575u2f.c:parse_auth_reply 23 2 91.30% 29 3 89.66% 596u2f.c:parse_auth_reply 23 2 91.30% 29 3 89.66%
576u2f.c:authdata_fake 12 0 100.00% 34 0 100.00% 597u2f.c:authdata_fake 12 0 100.00% 34 0 100.00%
577--------------------------------------------------------------------------------------- 598---------------------------------------------------------------------------------------
578TOTAL 443 28 93.68% 699 52 92.56% 599TOTAL 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 @@
23 23
24#include "../openbsd-compat/openbsd-compat.h" 24#include "../openbsd-compat/openbsd-compat.h"
25 25
26#define TAG_U2F 0x01
27#define TAG_TYPE 0x02
28#define TAG_CDH 0x03
29#define TAG_RP_ID 0x04
30#define TAG_EXT 0x05
31#define TAG_SEED 0x06
32#define TAG_UP 0x07
33#define TAG_UV 0x08
34#define TAG_WIRE_DATA 0x09
35#define TAG_CRED_COUNT 0x0a
36#define TAG_CRED 0x0b
37#define TAG_ES256 0x0c
38#define TAG_RS256 0x0d
39#define TAG_PIN 0x0e
40#define TAG_EDDSA 0x0f
41
42/* Parameter set defining a FIDO2 get assertion operation. */ 26/* Parameter set defining a FIDO2 get assertion operation. */
43struct param { 27struct param {
44 char pin[MAXSTR]; 28 char pin[MAXSTR];
45 char rp_id[MAXSTR]; 29 char rp_id[MAXSTR];
46 int ext; 30 int ext;
47 int seed; 31 int seed;
48 struct blob cdh; 32 struct blob cdh;
49 struct blob cred; 33 struct blob cred;
50 struct blob es256; 34 struct blob es256;
51 struct blob rs256; 35 struct blob rs256;
52 struct blob eddsa; 36 struct blob eddsa;
53 struct blob wire_data; 37 struct blob wire_data;
54 uint8_t cred_count; 38 uint8_t cred_count;
55 uint8_t type; 39 uint8_t type;
56 uint8_t u2f; 40 uint8_t u2f;
57 uint8_t up; 41 uint8_t up;
58 uint8_t uv; 42 uint8_t uv;
59}; 43};
60 44
61/* 45/*
@@ -83,73 +67,153 @@ static const uint8_t dummy_wire_data_u2f[] = {
83 WIREDATA_CTAP_U2F_AUTH, 67 WIREDATA_CTAP_U2F_AUTH,
84}; 68};
85 69
86int LLVMFuzzerTestOneInput(const uint8_t *, size_t); 70struct param *
87size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); 71unpack(const uint8_t *ptr, size_t len)
88
89static int
90unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN
91{ 72{
92 uint8_t **pp = (void *)&ptr; 73 cbor_item_t *item = NULL, **v;
93 74 struct cbor_load_result cbor;
94 if (unpack_byte(TAG_UV, pp, &len, &p->uv) < 0 || 75 struct param *p;
95 unpack_byte(TAG_UP, pp, &len, &p->up) < 0 || 76 int ok = -1;
96 unpack_byte(TAG_U2F, pp, &len, &p->u2f) < 0 || 77
97 unpack_byte(TAG_TYPE, pp, &len, &p->type) < 0 || 78 if ((p = calloc(1, sizeof(*p))) == NULL ||
98 unpack_byte(TAG_CRED_COUNT, pp, &len, &p->cred_count) < 0 || 79 (item = cbor_load(ptr, len, &cbor)) == NULL ||
99 unpack_int(TAG_EXT, pp, &len, &p->ext) < 0 || 80 cbor.read != len ||
100 unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || 81 cbor_isa_array(item) == false ||
101 unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || 82 cbor_array_is_definite(item) == false ||
102 unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || 83 cbor_array_size(item) != 15 ||
103 unpack_blob(TAG_WIRE_DATA, pp, &len, &p->wire_data) < 0 || 84 (v = cbor_array_handle(item)) == NULL)
104 unpack_blob(TAG_RS256, pp, &len, &p->rs256) < 0 || 85 goto fail;
105 unpack_blob(TAG_ES256, pp, &len, &p->es256) < 0 || 86
106 unpack_blob(TAG_EDDSA, pp, &len, &p->eddsa) < 0 || 87 if (unpack_byte(v[0], &p->uv) < 0 ||
107 unpack_blob(TAG_CRED, pp, &len, &p->cred) < 0 || 88 unpack_byte(v[1], &p->up) < 0 ||
108 unpack_blob(TAG_CDH, pp, &len, &p->cdh) < 0) 89 unpack_byte(v[2], &p->u2f) < 0 ||
109 return (-1); 90 unpack_byte(v[3], &p->type) < 0 ||
110 91 unpack_byte(v[4], &p->cred_count) < 0 ||
111 return (0); 92 unpack_int(v[5], &p->ext) < 0 ||
93 unpack_int(v[6], &p->seed) < 0 ||
94 unpack_string(v[7], p->rp_id) < 0 ||
95 unpack_string(v[8], p->pin) < 0 ||
96 unpack_blob(v[9], &p->wire_data) < 0 ||
97 unpack_blob(v[10], &p->rs256) < 0 ||
98 unpack_blob(v[11], &p->es256) < 0 ||
99 unpack_blob(v[12], &p->eddsa) < 0 ||
100 unpack_blob(v[13], &p->cred) < 0 ||
101 unpack_blob(v[14], &p->cdh) < 0)
102 goto fail;
103
104 ok = 0;
105fail:
106 if (ok < 0) {
107 free(p);
108 p = NULL;
109 }
110
111 if (item)
112 cbor_decref(&item);
113
114 return p;
112} 115}
113 116
114static size_t 117size_t
115pack(uint8_t *ptr, size_t len, const struct param *p) 118pack(uint8_t *ptr, size_t len, const struct param *p)
116{ 119{
117 const size_t max = len; 120 cbor_item_t *argv[15], *array = NULL;
118 121 size_t cbor_alloc_len, cbor_len = 0;
119 if (pack_byte(TAG_UV, &ptr, &len, p->uv) < 0 || 122 unsigned char *cbor = NULL;
120 pack_byte(TAG_UP, &ptr, &len, p->up) < 0 || 123
121 pack_byte(TAG_U2F, &ptr, &len, p->u2f) < 0 || 124 memset(argv, 0, sizeof(argv));
122 pack_byte(TAG_TYPE, &ptr, &len, p->type) < 0 || 125
123 pack_byte(TAG_CRED_COUNT, &ptr, &len, p->cred_count) < 0 || 126 if ((array = cbor_new_definite_array(15)) == NULL ||
124 pack_int(TAG_EXT, &ptr, &len, p->ext) < 0 || 127 (argv[0] = pack_byte(p->uv)) == NULL ||
125 pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || 128 (argv[1] = pack_byte(p->up)) == NULL ||
126 pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || 129 (argv[2] = pack_byte(p->u2f)) == NULL ||
127 pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || 130 (argv[3] = pack_byte(p->type)) == NULL ||
128 pack_blob(TAG_WIRE_DATA, &ptr, &len, &p->wire_data) < 0 || 131 (argv[4] = pack_byte(p->cred_count)) == NULL ||
129 pack_blob(TAG_RS256, &ptr, &len, &p->rs256) < 0 || 132 (argv[5] = pack_int(p->ext)) == NULL ||
130 pack_blob(TAG_ES256, &ptr, &len, &p->es256) < 0 || 133 (argv[6] = pack_int(p->seed)) == NULL ||
131 pack_blob(TAG_EDDSA, &ptr, &len, &p->eddsa) < 0 || 134 (argv[7] = pack_string(p->rp_id)) == NULL ||
132 pack_blob(TAG_CRED, &ptr, &len, &p->cred) < 0 || 135 (argv[8] = pack_string(p->pin)) == NULL ||
133 pack_blob(TAG_CDH, &ptr, &len, &p->cdh) < 0) 136 (argv[9] = pack_blob(&p->wire_data)) == NULL ||
134 return (0); 137 (argv[10] = pack_blob(&p->rs256)) == NULL ||
135 138 (argv[11] = pack_blob(&p->es256)) == NULL ||
136 return (max - len); 139 (argv[12] = pack_blob(&p->eddsa)) == NULL ||
140 (argv[13] = pack_blob(&p->cred)) == NULL ||
141 (argv[14] = pack_blob(&p->cdh)) == NULL)
142 goto fail;
143
144 for (size_t i = 0; i < 15; i++)
145 if (cbor_array_push(array, argv[i]) == false)
146 goto fail;
147
148 if ((cbor_len = cbor_serialize_alloc(array, &cbor,
149 &cbor_alloc_len)) > len) {
150 cbor_len = 0;
151 goto fail;
152 }
153
154 memcpy(ptr, cbor, cbor_len);
155fail:
156 for (size_t i = 0; i < 15; i++)
157 if (argv[i])
158 cbor_decref(&argv[i]);
159
160 if (array)
161 cbor_decref(&array);
162
163 free(cbor);
164
165 return cbor_len;
137} 166}
138 167
139static size_t 168size_t
140input_len(int max) 169pack_dummy(uint8_t *ptr, size_t len)
141{ 170{
142 return (5 * len_byte() + 2 * len_int() + 2 * len_string(max) + 171 struct param dummy;
143 6 * len_blob(max)); 172 uint8_t blob[4096];
173 size_t blob_len;
174
175 memset(&dummy, 0, sizeof(dummy));
176
177 dummy.type = 1; /* rsa */
178 dummy.ext = FIDO_EXT_HMAC_SECRET;
179
180 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
181 strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id));
182
183 dummy.cred.len = sizeof(dummy_cdh); /* XXX */
184 dummy.cdh.len = sizeof(dummy_cdh);
185 dummy.es256.len = sizeof(dummy_es256);
186 dummy.rs256.len = sizeof(dummy_rs256);
187 dummy.eddsa.len = sizeof(dummy_eddsa);
188 dummy.wire_data.len = sizeof(dummy_wire_data_fido);
189
190 memcpy(&dummy.cred.body, &dummy_cdh, dummy.cred.len); /* XXX */
191 memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len);
192 memcpy(&dummy.wire_data.body, &dummy_wire_data_fido,
193 dummy.wire_data.len);
194 memcpy(&dummy.es256.body, &dummy_es256, dummy.es256.len);
195 memcpy(&dummy.rs256.body, &dummy_rs256, dummy.rs256.len);
196 memcpy(&dummy.eddsa.body, &dummy_eddsa, dummy.eddsa.len);
197
198 assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
199
200 if (blob_len > len) {
201 memcpy(ptr, blob, len);
202 return len;
203 }
204
205 memcpy(ptr, blob, blob_len);
206
207 return blob_len;
144} 208}
145 209
146static void 210static void
147get_assert(fido_assert_t *assert, uint8_t u2f, const struct blob *cdh, 211get_assert(fido_assert_t *assert, uint8_t u2f, const struct blob *cdh,
148 const char *rp_id, int ext, uint8_t up, uint8_t uv, const char *pin, 212 const char *rp_id, int ext, uint8_t up, uint8_t uv, const char *pin,
149 uint8_t cred_count, struct blob *cred) 213 uint8_t cred_count, const struct blob *cred)
150{ 214{
151 fido_dev_t *dev; 215 fido_dev_t *dev;
152 fido_dev_io_t io; 216 fido_dev_io_t io;
153 217
154 memset(&io, 0, sizeof(io)); 218 memset(&io, 0, sizeof(io));
155 219
@@ -166,21 +230,31 @@ get_assert(fido_assert_t *assert, uint8_t u2f, const struct blob *cdh,
166 230
167 if (u2f & 1) 231 if (u2f & 1)
168 fido_dev_force_u2f(dev); 232 fido_dev_force_u2f(dev);
169
170 for (uint8_t i = 0; i < cred_count; i++)
171 fido_assert_allow_cred(assert, cred->body, cred->len);
172
173 fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len);
174 fido_assert_set_rp(assert, rp_id);
175 if (ext & 1) 233 if (ext & 1)
176 fido_assert_set_extensions(assert, FIDO_EXT_HMAC_SECRET); 234 fido_assert_set_extensions(assert, FIDO_EXT_HMAC_SECRET);
177 if (up & 1) 235 if (up & 1)
178 fido_assert_set_up(assert, FIDO_OPT_TRUE); 236 fido_assert_set_up(assert, FIDO_OPT_TRUE);
237 else if (u2f &1)
238 fido_assert_set_up(assert, FIDO_OPT_FALSE);
179 if (uv & 1) 239 if (uv & 1)
180 fido_assert_set_uv(assert, FIDO_OPT_TRUE); 240 fido_assert_set_uv(assert, FIDO_OPT_TRUE);
181 /* XXX reuse cred as hmac salt to keep struct param small */ 241
242 for (uint8_t i = 0; i < cred_count; i++)
243 fido_assert_allow_cred(assert, cred->body, cred->len);
244
245 fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len);
246 fido_assert_set_rp(assert, rp_id);
247 /* XXX reuse cred as hmac salt */
182 fido_assert_set_hmac_salt(assert, cred->body, cred->len); 248 fido_assert_set_hmac_salt(assert, cred->body, cred->len);
183 249
250 /* repeat memory operations to trigger reallocation paths */
251 fido_assert_set_clientdata_hash(assert, cdh->body, cdh->len);
252 fido_assert_set_rp(assert, rp_id);
253 fido_assert_set_hmac_salt(assert, cred->body, cred->len);
254
255 if (strlen(pin) == 0)
256 pin = NULL;
257
184 fido_dev_get_assert(dev, assert, u2f & 1 ? NULL : pin); 258 fido_dev_get_assert(dev, assert, u2f & 1 ? NULL : pin);
185 259
186 fido_dev_cancel(dev); 260 fido_dev_cancel(dev);
@@ -194,7 +268,7 @@ verify_assert(int type, const unsigned char *cdh_ptr, size_t cdh_len,
194 const unsigned char *sig_ptr, size_t sig_len, uint8_t up, uint8_t uv, 268 const unsigned char *sig_ptr, size_t sig_len, uint8_t up, uint8_t uv,
195 int ext, void *pk) 269 int ext, void *pk)
196{ 270{
197 fido_assert_t *assert = NULL; 271 fido_assert_t *assert = NULL;
198 272
199 if ((assert = fido_assert_new()) == NULL) 273 if ((assert = fido_assert_new()) == NULL)
200 return; 274 return;
@@ -202,16 +276,30 @@ verify_assert(int type, const unsigned char *cdh_ptr, size_t cdh_len,
202 fido_assert_set_clientdata_hash(assert, cdh_ptr, cdh_len); 276 fido_assert_set_clientdata_hash(assert, cdh_ptr, cdh_len);
203 fido_assert_set_rp(assert, rp_id); 277 fido_assert_set_rp(assert, rp_id);
204 fido_assert_set_count(assert, 1); 278 fido_assert_set_count(assert, 1);
279
205 if (fido_assert_set_authdata(assert, 0, authdata_ptr, 280 if (fido_assert_set_authdata(assert, 0, authdata_ptr,
206 authdata_len) != FIDO_OK) { 281 authdata_len) != FIDO_OK) {
207 fido_assert_set_authdata_raw(assert, 0, authdata_ptr, 282 fido_assert_set_authdata_raw(assert, 0, authdata_ptr,
208 authdata_len); 283 authdata_len);
209 } 284 }
285
286 if (up & 1)
287 fido_assert_set_up(assert, FIDO_OPT_TRUE);
288 if (uv & 1)
289 fido_assert_set_uv(assert, FIDO_OPT_TRUE);
290
210 fido_assert_set_extensions(assert, ext); 291 fido_assert_set_extensions(assert, ext);
211 if (up & 1) fido_assert_set_up(assert, FIDO_OPT_TRUE);
212 if (uv & 1) fido_assert_set_uv(assert, FIDO_OPT_TRUE);
213 fido_assert_set_sig(assert, 0, sig_ptr, sig_len); 292 fido_assert_set_sig(assert, 0, sig_ptr, sig_len);
214 fido_assert_verify(assert, 0, type, pk); 293
294 /* repeat memory operations to trigger reallocation paths */
295 if (fido_assert_set_authdata(assert, 0, authdata_ptr,
296 authdata_len) != FIDO_OK) {
297 fido_assert_set_authdata_raw(assert, 0, authdata_ptr,
298 authdata_len);
299 }
300 fido_assert_set_sig(assert, 0, sig_ptr, sig_len);
301
302 assert(fido_assert_verify(assert, 0, type, pk) != FIDO_OK);
215 303
216 fido_assert_free(&assert); 304 fido_assert_free(&assert);
217} 305}
@@ -262,38 +350,30 @@ out:
262 EVP_PKEY_free(pkey); 350 EVP_PKEY_free(pkey);
263} 351}
264 352
265int 353void
266LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 354test(const struct param *p)
267{ 355{
268 struct param p; 356 fido_assert_t *assert = NULL;
269 fido_assert_t *assert = NULL; 357 es256_pk_t *es256_pk = NULL;
270 es256_pk_t *es256_pk = NULL; 358 rs256_pk_t *rs256_pk = NULL;
271 rs256_pk_t *rs256_pk = NULL; 359 eddsa_pk_t *eddsa_pk = NULL;
272 eddsa_pk_t *eddsa_pk = NULL; 360 uint8_t flags;
273 uint8_t flags; 361 uint32_t sigcount;
274 uint32_t sigcount; 362 int cose_alg = 0;
275 int cose_alg = 0; 363 void *pk;
276 void *pk; 364
277 365 prng_init((unsigned int)p->seed);
278 memset(&p, 0, sizeof(p));
279
280 if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) ||
281 unpack(data, size, &p) < 0)
282 return (0);
283
284 prng_init((unsigned int)p.seed);
285
286 fido_init(FIDO_DEBUG); 366 fido_init(FIDO_DEBUG);
287 fido_set_log_handler(consume_str); 367 fido_set_log_handler(consume_str);
288 368
289 switch (p.type & 3) { 369 switch (p->type & 3) {
290 case 0: 370 case 0:
291 cose_alg = COSE_ES256; 371 cose_alg = COSE_ES256;
292 372
293 if ((es256_pk = es256_pk_new()) == NULL) 373 if ((es256_pk = es256_pk_new()) == NULL)
294 return (0); 374 return;
295 375
296 es256_pk_from_ptr(es256_pk, p.es256.body, p.es256.len); 376 es256_pk_from_ptr(es256_pk, p->es256.body, p->es256.len);
297 pk = es256_pk; 377 pk = es256_pk;
298 378
299 break; 379 break;
@@ -301,9 +381,9 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
301 cose_alg = COSE_RS256; 381 cose_alg = COSE_RS256;
302 382
303 if ((rs256_pk = rs256_pk_new()) == NULL) 383 if ((rs256_pk = rs256_pk_new()) == NULL)
304 return (0); 384 return;
305 385
306 rs256_pk_from_ptr(rs256_pk, p.rs256.body, p.rs256.len); 386 rs256_pk_from_ptr(rs256_pk, p->rs256.body, p->rs256.len);
307 pk = rs256_pk; 387 pk = rs256_pk;
308 388
309 rs256_convert(pk); 389 rs256_convert(pk);
@@ -313,9 +393,9 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
313 cose_alg = COSE_EDDSA; 393 cose_alg = COSE_EDDSA;
314 394
315 if ((eddsa_pk = eddsa_pk_new()) == NULL) 395 if ((eddsa_pk = eddsa_pk_new()) == NULL)
316 return (0); 396 return;
317 397
318 eddsa_pk_from_ptr(eddsa_pk, p.eddsa.body, p.eddsa.len); 398 eddsa_pk_from_ptr(eddsa_pk, p->eddsa.body, p->eddsa.len);
319 pk = eddsa_pk; 399 pk = eddsa_pk;
320 400
321 eddsa_convert(pk); 401 eddsa_convert(pk);
@@ -326,10 +406,10 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
326 if ((assert = fido_assert_new()) == NULL) 406 if ((assert = fido_assert_new()) == NULL)
327 goto out; 407 goto out;
328 408
329 set_wire_data(p.wire_data.body, p.wire_data.len); 409 set_wire_data(p->wire_data.body, p->wire_data.len);
330 410
331 get_assert(assert, p.u2f, &p.cdh, p.rp_id, p.ext, p.up, p.uv, p.pin, 411 get_assert(assert, p->u2f, &p->cdh, p->rp_id, p->ext, p->up, p->uv,
332 p.cred_count, &p.cred); 412 p->pin, p->cred_count, &p->cred);
333 413
334 /* XXX +1 on purpose */ 414 /* XXX +1 on purpose */
335 for (size_t i = 0; i <= fido_assert_count(assert); i++) { 415 for (size_t i = 0; i <= fido_assert_count(assert); i++) {
@@ -340,7 +420,7 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
340 fido_assert_authdata_ptr(assert, i), 420 fido_assert_authdata_ptr(assert, i),
341 fido_assert_authdata_len(assert, i), 421 fido_assert_authdata_len(assert, i),
342 fido_assert_sig_ptr(assert, i), 422 fido_assert_sig_ptr(assert, i),
343 fido_assert_sig_len(assert, i), p.up, p.uv, p.ext, pk); 423 fido_assert_sig_len(assert, i), p->up, p->uv, p->ext, pk);
344 consume(fido_assert_id_ptr(assert, i), 424 consume(fido_assert_id_ptr(assert, i),
345 fido_assert_id_len(assert, i)); 425 fido_assert_id_len(assert, i));
346 consume(fido_assert_user_id_ptr(assert, i), 426 consume(fido_assert_user_id_ptr(assert, i),
@@ -365,103 +445,40 @@ out:
365 eddsa_pk_free(&eddsa_pk); 445 eddsa_pk_free(&eddsa_pk);
366 446
367 fido_assert_free(&assert); 447 fido_assert_free(&assert);
368
369 return (0);
370} 448}
371 449
372static size_t 450void
373pack_dummy(uint8_t *ptr, size_t len) 451mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
374{ 452{
375 struct param dummy; 453 if (flags & MUTATE_SEED)
376 uint8_t blob[16384]; 454 p->seed = (int)seed;
377 size_t blob_len; 455
378 456 if (flags & MUTATE_PARAM) {
379 memset(&dummy, 0, sizeof(dummy)); 457 mutate_byte(&p->uv);
380 458 mutate_byte(&p->up);
381 dummy.type = 1; /* rsa */ 459 mutate_byte(&p->u2f);
382 dummy.ext = FIDO_EXT_HMAC_SECRET; 460 mutate_byte(&p->type);
383 461 mutate_byte(&p->cred_count);
384 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); 462 mutate_int(&p->ext);
385 strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id)); 463 mutate_blob(&p->rs256);
386 464 mutate_blob(&p->es256);
387 dummy.cred.len = sizeof(dummy_cdh); /* XXX */ 465 mutate_blob(&p->eddsa);
388 dummy.cdh.len = sizeof(dummy_cdh); 466 mutate_blob(&p->cred);
389 dummy.es256.len = sizeof(dummy_es256); 467 mutate_blob(&p->cdh);
390 dummy.rs256.len = sizeof(dummy_rs256); 468 mutate_string(p->rp_id);
391 dummy.eddsa.len = sizeof(dummy_eddsa); 469 mutate_string(p->pin);
392 dummy.wire_data.len = sizeof(dummy_wire_data_fido);
393
394 memcpy(&dummy.cred.body, &dummy_cdh, dummy.cred.len); /* XXX */
395 memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len);
396 memcpy(&dummy.wire_data.body, &dummy_wire_data_fido,
397 dummy.wire_data.len);
398 memcpy(&dummy.es256.body, &dummy_es256, dummy.es256.len);
399 memcpy(&dummy.rs256.body, &dummy_rs256, dummy.rs256.len);
400 memcpy(&dummy.eddsa.body, &dummy_eddsa, dummy.eddsa.len);
401
402 blob_len = pack(blob, sizeof(blob), &dummy);
403 assert(blob_len != 0);
404
405 if (blob_len > len) {
406 memcpy(ptr, blob, len);
407 return (len);
408 } 470 }
409 471
410 memcpy(ptr, blob, blob_len); 472 if (flags & MUTATE_WIREDATA) {
411 473 if (p->u2f & 1) {
412 return (blob_len); 474 p->wire_data.len = sizeof(dummy_wire_data_u2f);
413} 475 memcpy(&p->wire_data.body, &dummy_wire_data_u2f,
414 476 p->wire_data.len);
415size_t 477 } else {
416LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, 478 p->wire_data.len = sizeof(dummy_wire_data_fido);
417 unsigned int seed) NO_MSAN 479 memcpy(&p->wire_data.body, &dummy_wire_data_fido,
418{ 480 p->wire_data.len);
419 struct param p; 481 }
420 uint8_t blob[16384]; 482 mutate_blob(&p->wire_data);
421 size_t blob_len;
422
423 (void)seed;
424
425 memset(&p, 0, sizeof(p));
426
427 if (unpack(data, size, &p) < 0)
428 return (pack_dummy(data, maxsize));
429
430 mutate_byte(&p.uv);
431 mutate_byte(&p.up);
432 mutate_byte(&p.u2f);
433 mutate_byte(&p.type);
434 mutate_byte(&p.cred_count);
435
436 mutate_int(&p.ext);
437 p.seed = (int)seed;
438
439 if (p.u2f & 1) {
440 p.wire_data.len = sizeof(dummy_wire_data_u2f);
441 memcpy(&p.wire_data.body, &dummy_wire_data_u2f,
442 p.wire_data.len);
443 } else {
444 p.wire_data.len = sizeof(dummy_wire_data_fido);
445 memcpy(&p.wire_data.body, &dummy_wire_data_fido,
446 p.wire_data.len);
447 } 483 }
448
449 mutate_blob(&p.wire_data);
450 mutate_blob(&p.rs256);
451 mutate_blob(&p.es256);
452 mutate_blob(&p.eddsa);
453 mutate_blob(&p.cred);
454 mutate_blob(&p.cdh);
455
456 mutate_string(p.rp_id);
457 mutate_string(p.pin);
458
459 blob_len = pack(blob, sizeof(blob), &p);
460
461 if (blob_len == 0 || blob_len > maxsize)
462 return (0);
463
464 memcpy(data, blob, blob_len);
465
466 return (blob_len);
467} 484}
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 @@
19 19
20#include "../openbsd-compat/openbsd-compat.h" 20#include "../openbsd-compat/openbsd-compat.h"
21 21
22#define TAG_PIN 0x01
23#define TAG_NAME 0x02
24#define TAG_SEED 0x03
25#define TAG_ID 0x04
26#define TAG_INFO_WIRE_DATA 0x05
27#define TAG_ENROLL_WIRE_DATA 0x06
28#define TAG_LIST_WIRE_DATA 0x07
29#define TAG_SET_NAME_WIRE_DATA 0x08
30#define TAG_REMOVE_WIRE_DATA 0x09
31
32/* Parameter set defining a FIDO2 credential management operation. */ 22/* Parameter set defining a FIDO2 credential management operation. */
33struct param { 23struct param {
34 char pin[MAXSTR]; 24 char pin[MAXSTR];
35 char name[MAXSTR]; 25 char name[MAXSTR];
36 int seed; 26 int seed;
37 struct blob id; 27 struct blob id;
38 struct blob info_wire_data; 28 struct blob info_wire_data;
39 struct blob enroll_wire_data; 29 struct blob enroll_wire_data;
40 struct blob list_wire_data; 30 struct blob list_wire_data;
41 struct blob set_name_wire_data; 31 struct blob set_name_wire_data;
42 struct blob remove_wire_data; 32 struct blob remove_wire_data;
43}; 33};
44 34
45/* 35/*
@@ -100,58 +90,141 @@ static const uint8_t dummy_remove_wire_data[] = {
100 WIREDATA_CTAP_CBOR_STATUS, 90 WIREDATA_CTAP_CBOR_STATUS,
101}; 91};
102 92
103int LLVMFuzzerTestOneInput(const uint8_t *, size_t); 93struct param *
104size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); 94unpack(const uint8_t *ptr, size_t len)
105
106static int
107unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN
108{ 95{
109 uint8_t **pp = (void *)&ptr; 96 cbor_item_t *item = NULL, **v;
110 97 struct cbor_load_result cbor;
111 if (unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || 98 struct param *p;
112 unpack_string(TAG_NAME, pp, &len, p->name) < 0 || 99 int ok = -1;
113 unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || 100
114 unpack_blob(TAG_ID, pp, &len, &p->id) < 0 || 101 if ((p = calloc(1, sizeof(*p))) == NULL ||
115 unpack_blob(TAG_INFO_WIRE_DATA, pp, &len, &p->info_wire_data) < 0 || 102 (item = cbor_load(ptr, len, &cbor)) == NULL ||
116 unpack_blob(TAG_ENROLL_WIRE_DATA, pp, &len, &p->enroll_wire_data) < 0 || 103 cbor.read != len ||
117 unpack_blob(TAG_LIST_WIRE_DATA, pp, &len, &p->list_wire_data) < 0 || 104 cbor_isa_array(item) == false ||
118 unpack_blob(TAG_SET_NAME_WIRE_DATA, pp, &len, &p->set_name_wire_data) < 0 || 105 cbor_array_is_definite(item) == false ||
119 unpack_blob(TAG_REMOVE_WIRE_DATA, pp, &len, &p->remove_wire_data) < 0) 106 cbor_array_size(item) != 9 ||
120 return (-1); 107 (v = cbor_array_handle(item)) == NULL)
121 108 goto fail;
122 return (0); 109
110 if (unpack_int(v[0], &p->seed) < 0 ||
111 unpack_string(v[1], p->pin) < 0 ||
112 unpack_string(v[2], p->name) < 0 ||
113 unpack_blob(v[3], &p->id) < 0 ||
114 unpack_blob(v[4], &p->info_wire_data) < 0 ||
115 unpack_blob(v[5], &p->enroll_wire_data) < 0 ||
116 unpack_blob(v[6], &p->list_wire_data) < 0 ||
117 unpack_blob(v[7], &p->set_name_wire_data) < 0 ||
118 unpack_blob(v[8], &p->remove_wire_data) < 0)
119 goto fail;
120
121 ok = 0;
122fail:
123 if (ok < 0) {
124 free(p);
125 p = NULL;
126 }
127
128 if (item)
129 cbor_decref(&item);
130
131 return p;
123} 132}
124 133
125static size_t 134size_t
126pack(uint8_t *ptr, size_t len, const struct param *p) 135pack(uint8_t *ptr, size_t len, const struct param *p)
127{ 136{
128 const size_t max = len; 137 cbor_item_t *argv[9], *array = NULL;
129 138 size_t cbor_alloc_len, cbor_len = 0;
130 if (pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || 139 unsigned char *cbor = NULL;
131 pack_string(TAG_NAME, &ptr, &len, p->name) < 0 || 140
132 pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || 141 memset(argv, 0, sizeof(argv));
133 pack_blob(TAG_ID, &ptr, &len, &p->id) < 0 || 142
134 pack_blob(TAG_INFO_WIRE_DATA, &ptr, &len, &p->info_wire_data) < 0 || 143 if ((array = cbor_new_definite_array(9)) == NULL ||
135 pack_blob(TAG_ENROLL_WIRE_DATA, &ptr, &len, &p->enroll_wire_data) < 0 || 144 (argv[0] = pack_int(p->seed)) == NULL ||
136 pack_blob(TAG_LIST_WIRE_DATA, &ptr, &len, &p->list_wire_data) < 0 || 145 (argv[1] = pack_string(p->pin)) == NULL ||
137 pack_blob(TAG_SET_NAME_WIRE_DATA, &ptr, &len, &p->set_name_wire_data) < 0 || 146 (argv[2] = pack_string(p->name)) == NULL ||
138 pack_blob(TAG_REMOVE_WIRE_DATA, &ptr, &len, &p->remove_wire_data) < 0) 147 (argv[3] = pack_blob(&p->id)) == NULL ||
139 return (0); 148 (argv[4] = pack_blob(&p->info_wire_data)) == NULL ||
140 149 (argv[5] = pack_blob(&p->enroll_wire_data)) == NULL ||
141 return (max - len); 150 (argv[6] = pack_blob(&p->list_wire_data)) == NULL ||
151 (argv[7] = pack_blob(&p->set_name_wire_data)) == NULL ||
152 (argv[8] = pack_blob(&p->remove_wire_data)) == NULL)
153 goto fail;
154
155 for (size_t i = 0; i < 9; i++)
156 if (cbor_array_push(array, argv[i]) == false)
157 goto fail;
158
159 if ((cbor_len = cbor_serialize_alloc(array, &cbor,
160 &cbor_alloc_len)) > len) {
161 cbor_len = 0;
162 goto fail;
163 }
164
165 memcpy(ptr, cbor, cbor_len);
166fail:
167 for (size_t i = 0; i < 9; i++)
168 if (argv[i])
169 cbor_decref(&argv[i]);
170
171 if (array)
172 cbor_decref(&array);
173
174 free(cbor);
175
176 return cbor_len;
142} 177}
143 178
144static size_t 179size_t
145input_len(int max) 180pack_dummy(uint8_t *ptr, size_t len)
146{ 181{
147 return (2 * len_string(max) + len_int() + 6 * len_blob(max)); 182 struct param dummy;
183 uint8_t blob[4096];
184 size_t blob_len;
185
186 memset(&dummy, 0, sizeof(dummy));
187
188 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
189 strlcpy(dummy.name, dummy_name, sizeof(dummy.name));
190
191 dummy.info_wire_data.len = sizeof(dummy_info_wire_data);
192 dummy.enroll_wire_data.len = sizeof(dummy_enroll_wire_data);
193 dummy.list_wire_data.len = sizeof(dummy_list_wire_data);
194 dummy.set_name_wire_data.len = sizeof(dummy_set_name_wire_data);
195 dummy.remove_wire_data.len = sizeof(dummy_remove_wire_data);
196 dummy.id.len = sizeof(dummy_id);
197
198 memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data,
199 dummy.info_wire_data.len);
200 memcpy(&dummy.enroll_wire_data.body, &dummy_enroll_wire_data,
201 dummy.enroll_wire_data.len);
202 memcpy(&dummy.list_wire_data.body, &dummy_list_wire_data,
203 dummy.list_wire_data.len);
204 memcpy(&dummy.set_name_wire_data.body, &dummy_set_name_wire_data,
205 dummy.set_name_wire_data.len);
206 memcpy(&dummy.remove_wire_data.body, &dummy_remove_wire_data,
207 dummy.remove_wire_data.len);
208 memcpy(&dummy.id.body, &dummy_id, dummy.id.len);
209
210 assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
211
212 if (blob_len > len) {
213 memcpy(ptr, blob, len);
214 return len;
215 }
216
217 memcpy(ptr, blob, blob_len);
218
219 return blob_len;
148} 220}
149 221
150static fido_dev_t * 222static fido_dev_t *
151prepare_dev() 223prepare_dev(void)
152{ 224{
153 fido_dev_t *dev; 225 fido_dev_t *dev;
154 fido_dev_io_t io; 226 fido_dev_io_t io;
227 bool x;
155 228
156 memset(&io, 0, sizeof(io)); 229 memset(&io, 0, sizeof(io));
157 230
@@ -163,26 +236,35 @@ prepare_dev()
163 if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, 236 if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev,
164 &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { 237 &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) {
165 fido_dev_free(&dev); 238 fido_dev_free(&dev);
166 return (NULL); 239 return NULL;
167 } 240 }
168 241
169 return (dev); 242 x = fido_dev_is_fido2(dev);
243 consume(&x, sizeof(x));
244 x = fido_dev_supports_pin(dev);
245 consume(&x, sizeof(x));
246 x = fido_dev_has_pin(dev);
247 consume(&x, sizeof(x));
248
249 return dev;
170} 250}
171 251
172static void 252static void
173get_info(struct param *p) 253get_info(const struct param *p)
174{ 254{
175 fido_dev_t *dev = NULL; 255 fido_dev_t *dev = NULL;
176 fido_bio_info_t *i = NULL; 256 fido_bio_info_t *i = NULL;
177 uint8_t type; 257 uint8_t type;
178 uint8_t max_samples; 258 uint8_t max_samples;
259 int r;
179 260
180 set_wire_data(p->info_wire_data.body, p->info_wire_data.len); 261 set_wire_data(p->info_wire_data.body, p->info_wire_data.len);
181 262
182 if ((dev = prepare_dev()) == NULL || (i = fido_bio_info_new()) == NULL) 263 if ((dev = prepare_dev()) == NULL || (i = fido_bio_info_new()) == NULL)
183 goto done; 264 goto done;
184 265
185 fido_bio_dev_get_info(dev, i); 266 r = fido_bio_dev_get_info(dev, i);
267 consume_str(fido_strerr(r));
186 268
187 type = fido_bio_info_type(i); 269 type = fido_bio_info_type(i);
188 max_samples = fido_bio_info_max_samples(i); 270 max_samples = fido_bio_info_max_samples(i);
@@ -217,7 +299,7 @@ consume_enroll(fido_bio_enroll_t *e)
217} 299}
218 300
219static void 301static void
220enroll(struct param *p) 302enroll(const struct param *p)
221{ 303{
222 fido_dev_t *dev = NULL; 304 fido_dev_t *dev = NULL;
223 fido_bio_template_t *t = NULL; 305 fido_bio_template_t *t = NULL;
@@ -252,7 +334,7 @@ done:
252} 334}
253 335
254static void 336static void
255list(struct param *p) 337list(const struct param *p)
256{ 338{
257 fido_dev_t *dev = NULL; 339 fido_dev_t *dev = NULL;
258 fido_bio_template_array_t *ta = NULL; 340 fido_bio_template_array_t *ta = NULL;
@@ -280,7 +362,7 @@ done:
280} 362}
281 363
282static void 364static void
283set_name(struct param *p) 365set_name(const struct param *p)
284{ 366{
285 fido_dev_t *dev = NULL; 367 fido_dev_t *dev = NULL;
286 fido_bio_template_t *t = NULL; 368 fido_bio_template_t *t = NULL;
@@ -306,10 +388,11 @@ done:
306} 388}
307 389
308static void 390static void
309del(struct param *p) 391del(const struct param *p)
310{ 392{
311 fido_dev_t *dev = NULL; 393 fido_dev_t *dev = NULL;
312 fido_bio_template_t *t = NULL; 394 fido_bio_template_t *t = NULL;
395 int r;
313 396
314 set_wire_data(p->remove_wire_data.body, p->remove_wire_data.len); 397 set_wire_data(p->remove_wire_data.body, p->remove_wire_data.len);
315 398
@@ -317,8 +400,9 @@ del(struct param *p)
317 (t = fido_bio_template_new()) == NULL) 400 (t = fido_bio_template_new()) == NULL)
318 goto done; 401 goto done;
319 402
320 fido_bio_template_set_id(t, p->id.body, p->id.len); 403 r = fido_bio_template_set_id(t, p->id.body, p->id.len);
321 consume_template(t); 404 consume_template(t);
405 consume_str(fido_strerr(r));
322 406
323 fido_bio_dev_enroll_remove(dev, t, p->pin); 407 fido_bio_dev_enroll_remove(dev, t, p->pin);
324 408
@@ -330,106 +414,37 @@ done:
330 fido_bio_template_free(&t); 414 fido_bio_template_free(&t);
331} 415}
332 416
333int 417void
334LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 418test(const struct param *p)
335{ 419{
336 struct param p; 420 prng_init((unsigned int)p->seed);
337
338 memset(&p, 0, sizeof(p));
339
340 if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) ||
341 unpack(data, size, &p) < 0)
342 return (0);
343
344 prng_init((unsigned int)p.seed);
345
346 fido_init(FIDO_DEBUG); 421 fido_init(FIDO_DEBUG);
347 fido_set_log_handler(consume_str); 422 fido_set_log_handler(consume_str);
348 423
349 get_info(&p); 424 get_info(p);
350 enroll(&p); 425 enroll(p);
351 list(&p); 426 list(p);
352 set_name(&p); 427 set_name(p);
353 del(&p); 428 del(p);
354
355 return (0);
356} 429}
357 430
358static size_t 431void
359pack_dummy(uint8_t *ptr, size_t len) 432mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
360{ 433{
361 struct param dummy; 434 if (flags & MUTATE_SEED)
362 uint8_t blob[32768]; 435 p->seed = (int)seed;
363 size_t blob_len;
364
365 memset(&dummy, 0, sizeof(dummy));
366
367 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
368 strlcpy(dummy.name, dummy_name, sizeof(dummy.name));
369
370 dummy.info_wire_data.len = sizeof(dummy_info_wire_data);
371 dummy.enroll_wire_data.len = sizeof(dummy_enroll_wire_data);
372 dummy.list_wire_data.len = sizeof(dummy_list_wire_data);
373 dummy.set_name_wire_data.len = sizeof(dummy_set_name_wire_data);
374 dummy.remove_wire_data.len = sizeof(dummy_remove_wire_data);
375 dummy.id.len = sizeof(dummy_id);
376
377 memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data,
378 dummy.info_wire_data.len);
379 memcpy(&dummy.enroll_wire_data.body, &dummy_enroll_wire_data,
380 dummy.enroll_wire_data.len);
381 memcpy(&dummy.list_wire_data.body, &dummy_list_wire_data,
382 dummy.list_wire_data.len);
383 memcpy(&dummy.set_name_wire_data.body, &dummy_set_name_wire_data,
384 dummy.set_name_wire_data.len);
385 memcpy(&dummy.remove_wire_data.body, &dummy_remove_wire_data,
386 dummy.remove_wire_data.len);
387 memcpy(&dummy.id.body, &dummy_id, dummy.id.len);
388
389 blob_len = pack(blob, sizeof(blob), &dummy);
390 assert(blob_len != 0);
391 436
392 if (blob_len > len) { 437 if (flags & MUTATE_PARAM) {
393 memcpy(ptr, blob, len); 438 mutate_blob(&p->id);
394 return (len); 439 mutate_string(p->pin);
440 mutate_string(p->name);
395 } 441 }
396 442
397 memcpy(ptr, blob, blob_len); 443 if (flags & MUTATE_WIREDATA) {
398 444 mutate_blob(&p->info_wire_data);
399 return (blob_len); 445 mutate_blob(&p->enroll_wire_data);
400} 446 mutate_blob(&p->list_wire_data);
401 447 mutate_blob(&p->set_name_wire_data);
402size_t 448 mutate_blob(&p->remove_wire_data);
403LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, 449 }
404 unsigned int seed) NO_MSAN
405{
406 struct param p;
407 uint8_t blob[16384];
408 size_t blob_len;
409
410 memset(&p, 0, sizeof(p));
411
412 if (unpack(data, size, &p) < 0)
413 return (pack_dummy(data, maxsize));
414
415 p.seed = (int)seed;
416
417 mutate_blob(&p.id);
418 mutate_blob(&p.info_wire_data);
419 mutate_blob(&p.enroll_wire_data);
420 mutate_blob(&p.list_wire_data);
421 mutate_blob(&p.set_name_wire_data);
422 mutate_blob(&p.remove_wire_data);
423
424 mutate_string(p.pin);
425 mutate_string(p.name);
426
427 blob_len = pack(blob, sizeof(blob), &p);
428
429 if (blob_len == 0 || blob_len > maxsize)
430 return (0);
431
432 memcpy(data, blob, blob_len);
433
434 return (blob_len);
435} 450}
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 @@
18 18
19#include "../openbsd-compat/openbsd-compat.h" 19#include "../openbsd-compat/openbsd-compat.h"
20 20
21#define TAG_U2F 0x01
22#define TAG_TYPE 0x02
23#define TAG_CDH 0x03
24#define TAG_RP_ID 0x04
25#define TAG_RP_NAME 0x05
26#define TAG_USER_ID 0x06
27#define TAG_USER_NAME 0x07
28#define TAG_USER_NICK 0x08
29#define TAG_USER_ICON 0x09
30#define TAG_EXT 0x0a
31#define TAG_SEED 0x0b
32#define TAG_RK 0x0c
33#define TAG_UV 0x0d
34#define TAG_PIN 0x0e
35#define TAG_WIRE_DATA 0x0f
36#define TAG_EXCL_COUNT 0x10
37#define TAG_EXCL_CRED 0x11
38
39/* Parameter set defining a FIDO2 make credential operation. */ 21/* Parameter set defining a FIDO2 make credential operation. */
40struct param { 22struct param {
41 char pin[MAXSTR]; 23 char pin[MAXSTR];
42 char rp_id[MAXSTR]; 24 char rp_id[MAXSTR];
43 char rp_name[MAXSTR]; 25 char rp_name[MAXSTR];
44 char user_icon[MAXSTR]; 26 char user_icon[MAXSTR];
45 char user_name[MAXSTR]; 27 char user_name[MAXSTR];
46 char user_nick[MAXSTR]; 28 char user_nick[MAXSTR];
47 int ext; 29 int ext;
48 int seed; 30 int seed;
49 struct blob cdh; 31 struct blob cdh;
50 struct blob excl_cred; 32 struct blob excl_cred;
51 struct blob user_id; 33 struct blob user_id;
52 struct blob wire_data; 34 struct blob wire_data;
53 uint8_t excl_count; 35 uint8_t excl_count;
54 uint8_t rk; 36 uint8_t rk;
55 uint8_t type; 37 uint8_t type;
56 uint8_t u2f; 38 uint8_t u2f;
57 uint8_t uv; 39 uint8_t uv;
58}; 40};
59 41
60/* 42/*
@@ -86,79 +68,157 @@ static const uint8_t dummy_wire_data_u2f[] = {
86 WIREDATA_CTAP_U2F_REGISTER, 68 WIREDATA_CTAP_U2F_REGISTER,
87}; 69};
88 70
89int LLVMFuzzerTestOneInput(const uint8_t *, size_t); 71struct param *
90size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); 72unpack(const uint8_t *ptr, size_t len)
91
92static int
93unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN
94{ 73{
95 uint8_t **pp = (void *)&ptr; 74 cbor_item_t *item = NULL, **v;
96 75 struct cbor_load_result cbor;
97 if (unpack_byte(TAG_RK, pp, &len, &p->rk) < 0 || 76 struct param *p;
98 unpack_byte(TAG_TYPE, pp, &len, &p->type) < 0 || 77 int ok = -1;
99 unpack_byte(TAG_U2F, pp, &len, &p->u2f) < 0 || 78
100 unpack_byte(TAG_UV, pp, &len, &p->uv) < 0 || 79 if ((p = calloc(1, sizeof(*p))) == NULL ||
101 unpack_byte(TAG_EXCL_COUNT, pp, &len, &p->excl_count) < 0 || 80 (item = cbor_load(ptr, len, &cbor)) == NULL ||
102 unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || 81 cbor.read != len ||
103 unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || 82 cbor_isa_array(item) == false ||
104 unpack_string(TAG_RP_NAME, pp, &len, p->rp_name) < 0 || 83 cbor_array_is_definite(item) == false ||
105 unpack_string(TAG_USER_ICON, pp, &len, p->user_icon) < 0 || 84 cbor_array_size(item) != 17 ||
106 unpack_string(TAG_USER_NAME, pp, &len, p->user_name) < 0 || 85 (v = cbor_array_handle(item)) == NULL)
107 unpack_string(TAG_USER_NICK, pp, &len, p->user_nick) < 0 || 86 goto fail;
108 unpack_int(TAG_EXT, pp, &len, &p->ext) < 0 || 87
109 unpack_int(TAG_SEED, pp, &len, &p->seed) < 0 || 88 if (unpack_byte(v[0], &p->rk) < 0 ||
110 unpack_blob(TAG_CDH, pp, &len, &p->cdh) < 0 || 89 unpack_byte(v[1], &p->type) < 0 ||
111 unpack_blob(TAG_USER_ID, pp, &len, &p->user_id) < 0 || 90 unpack_byte(v[2], &p->u2f) < 0 ||
112 unpack_blob(TAG_WIRE_DATA, pp, &len, &p->wire_data) < 0 || 91 unpack_byte(v[3], &p->uv) < 0 ||
113 unpack_blob(TAG_EXCL_CRED, pp, &len, &p->excl_cred) < 0) 92 unpack_byte(v[4], &p->excl_count) < 0 ||
114 return (-1); 93 unpack_int(v[5], &p->ext) < 0 ||
115 94 unpack_int(v[6], &p->seed) < 0 ||
116 return (0); 95 unpack_string(v[7], p->pin) < 0 ||
96 unpack_string(v[8], p->rp_id) < 0 ||
97 unpack_string(v[9], p->rp_name) < 0 ||
98 unpack_string(v[10], p->user_icon) < 0 ||
99 unpack_string(v[11], p->user_name) < 0 ||
100 unpack_string(v[12], p->user_nick) < 0 ||
101 unpack_blob(v[13], &p->cdh) < 0 ||
102 unpack_blob(v[14], &p->user_id) < 0 ||
103 unpack_blob(v[15], &p->wire_data) < 0 ||
104 unpack_blob(v[16], &p->excl_cred) < 0)
105 goto fail;
106
107 ok = 0;
108fail:
109 if (ok < 0) {
110 free(p);
111 p = NULL;
112 }
113
114 if (item)
115 cbor_decref(&item);
116
117 return p;
117} 118}
118 119
119static size_t 120size_t
120pack(uint8_t *ptr, size_t len, const struct param *p) 121pack(uint8_t *ptr, size_t len, const struct param *p)
121{ 122{
122 const size_t max = len; 123 cbor_item_t *argv[17], *array = NULL;
123 124 size_t cbor_alloc_len, cbor_len = 0;
124 if (pack_byte(TAG_RK, &ptr, &len, p->rk) < 0 || 125 unsigned char *cbor = NULL;
125 pack_byte(TAG_TYPE, &ptr, &len, p->type) < 0 || 126
126 pack_byte(TAG_U2F, &ptr, &len, p->u2f) < 0 || 127 memset(argv, 0, sizeof(argv));
127 pack_byte(TAG_UV, &ptr, &len, p->uv) < 0 || 128
128 pack_byte(TAG_EXCL_COUNT, &ptr, &len, p->excl_count) < 0 || 129 if ((array = cbor_new_definite_array(17)) == NULL ||
129 pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || 130 (argv[0] = pack_byte(p->rk)) == NULL ||
130 pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || 131 (argv[1] = pack_byte(p->type)) == NULL ||
131 pack_string(TAG_RP_NAME, &ptr, &len, p->rp_name) < 0 || 132 (argv[2] = pack_byte(p->u2f)) == NULL ||
132 pack_string(TAG_USER_ICON, &ptr, &len, p->user_icon) < 0 || 133 (argv[3] = pack_byte(p->uv)) == NULL ||
133 pack_string(TAG_USER_NAME, &ptr, &len, p->user_name) < 0 || 134 (argv[4] = pack_byte(p->excl_count)) == NULL ||
134 pack_string(TAG_USER_NICK, &ptr, &len, p->user_nick) < 0 || 135 (argv[5] = pack_int(p->ext)) == NULL ||
135 pack_int(TAG_EXT, &ptr, &len, p->ext) < 0 || 136 (argv[6] = pack_int(p->seed)) == NULL ||
136 pack_int(TAG_SEED, &ptr, &len, p->seed) < 0 || 137 (argv[7] = pack_string(p->pin)) == NULL ||
137 pack_blob(TAG_CDH, &ptr, &len, &p->cdh) < 0 || 138 (argv[8] = pack_string(p->rp_id)) == NULL ||
138 pack_blob(TAG_USER_ID, &ptr, &len, &p->user_id) < 0 || 139 (argv[9] = pack_string(p->rp_name)) == NULL ||
139 pack_blob(TAG_WIRE_DATA, &ptr, &len, &p->wire_data) < 0 || 140 (argv[10] = pack_string(p->user_icon)) == NULL ||
140 pack_blob(TAG_EXCL_CRED, &ptr, &len, &p->excl_cred) < 0) 141 (argv[11] = pack_string(p->user_name)) == NULL ||
141 return (0); 142 (argv[12] = pack_string(p->user_nick)) == NULL ||
142 143 (argv[13] = pack_blob(&p->cdh)) == NULL ||
143 return (max - len); 144 (argv[14] = pack_blob(&p->user_id)) == NULL ||
145 (argv[15] = pack_blob(&p->wire_data)) == NULL ||
146 (argv[16] = pack_blob(&p->excl_cred)) == NULL)
147 goto fail;
148
149 for (size_t i = 0; i < 17; i++)
150 if (cbor_array_push(array, argv[i]) == false)
151 goto fail;
152
153 if ((cbor_len = cbor_serialize_alloc(array, &cbor,
154 &cbor_alloc_len)) > len) {
155 cbor_len = 0;
156 goto fail;
157 }
158
159 memcpy(ptr, cbor, cbor_len);
160fail:
161 for (size_t i = 0; i < 17; i++)
162 if (argv[i])
163 cbor_decref(&argv[i]);
164
165 if (array)
166 cbor_decref(&array);
167
168 free(cbor);
169
170 return cbor_len;
144} 171}
145 172
146static size_t 173size_t
147input_len(int max) 174pack_dummy(uint8_t *ptr, size_t len)
148{ 175{
149 return (5 * len_byte() + 6 * len_string(max) + 2 * len_int() + 176 struct param dummy;
150 4 * len_blob(max)); 177 uint8_t blob[4096];
178 size_t blob_len;
179
180 memset(&dummy, 0, sizeof(dummy));
181
182 dummy.type = 1;
183 dummy.ext = FIDO_EXT_HMAC_SECRET;
184
185 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
186 strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id));
187 strlcpy(dummy.rp_name, dummy_rp_name, sizeof(dummy.rp_name));
188 strlcpy(dummy.user_icon, dummy_user_icon, sizeof(dummy.user_icon));
189 strlcpy(dummy.user_name, dummy_user_name, sizeof(dummy.user_name));
190 strlcpy(dummy.user_nick, dummy_user_nick, sizeof(dummy.user_nick));
191
192 dummy.cdh.len = sizeof(dummy_cdh);
193 dummy.user_id.len = sizeof(dummy_user_id);
194 dummy.wire_data.len = sizeof(dummy_wire_data_fido);
195
196 memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len);
197 memcpy(&dummy.user_id.body, &dummy_user_id, dummy.user_id.len);
198 memcpy(&dummy.wire_data.body, &dummy_wire_data_fido,
199 dummy.wire_data.len);
200
201 assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
202
203 if (blob_len > len) {
204 memcpy(ptr, blob, len);
205 return len;
206 }
207
208 memcpy(ptr, blob, blob_len);
209
210 return blob_len;
151} 211}
152 212
153static void 213static void
154make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh, 214make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh,
155 const char *rp_id, const char *rp_name, struct blob *user_id, 215 const char *rp_id, const char *rp_name, const struct blob *user_id,
156 const char *user_name, const char *user_nick, const char *user_icon, 216 const char *user_name, const char *user_nick, const char *user_icon,
157 int ext, uint8_t rk, uint8_t uv, const char *pin, uint8_t excl_count, 217 int ext, uint8_t rk, uint8_t uv, const char *pin, uint8_t excl_count,
158 struct blob *excl_cred) 218 const struct blob *excl_cred)
159{ 219{
160 fido_dev_t *dev; 220 fido_dev_t *dev;
161 fido_dev_io_t io; 221 fido_dev_io_t io;
162 222
163 memset(&io, 0, sizeof(io)); 223 memset(&io, 0, sizeof(io));
164 224
@@ -185,6 +245,7 @@ make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh,
185 fido_cred_set_user(cred, user_id->body, user_id->len, user_name, 245 fido_cred_set_user(cred, user_id->body, user_id->len, user_name,
186 user_nick, user_icon); 246 user_nick, user_icon);
187 fido_cred_set_extensions(cred, ext); 247 fido_cred_set_extensions(cred, ext);
248
188 if (rk & 1) 249 if (rk & 1)
189 fido_cred_set_rk(cred, FIDO_OPT_TRUE); 250 fido_cred_set_rk(cred, FIDO_OPT_TRUE);
190 if (uv & 1) 251 if (uv & 1)
@@ -192,6 +253,16 @@ make_cred(fido_cred_t *cred, uint8_t u2f, int type, const struct blob *cdh,
192 if (user_id->len) 253 if (user_id->len)
193 fido_cred_set_prot(cred, user_id->body[0] & 0x03); 254 fido_cred_set_prot(cred, user_id->body[0] & 0x03);
194 255
256 /* repeat memory operations to trigger reallocation paths */
257 fido_cred_set_type(cred, type);
258 fido_cred_set_clientdata_hash(cred, cdh->body, cdh->len);
259 fido_cred_set_rp(cred, rp_id, rp_name);
260 fido_cred_set_user(cred, user_id->body, user_id->len, user_name,
261 user_nick, user_icon);
262
263 if (strlen(pin) == 0)
264 pin = NULL;
265
195 fido_dev_make_cred(dev, cred, u2f & 1 ? NULL : pin); 266 fido_dev_make_cred(dev, cred, u2f & 1 ? NULL : pin);
196 267
197 fido_dev_cancel(dev); 268 fido_dev_cancel(dev);
@@ -206,8 +277,8 @@ verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len,
206 const unsigned char *x5c_ptr, size_t x5c_len, const unsigned char *sig_ptr, 277 const unsigned char *x5c_ptr, size_t x5c_len, const unsigned char *sig_ptr,
207 size_t sig_len, const char *fmt, int prot) 278 size_t sig_len, const char *fmt, int prot)
208{ 279{
209 fido_cred_t *cred; 280 fido_cred_t *cred;
210 uint8_t flags; 281 uint8_t flags;
211 282
212 if ((cred = fido_cred_new()) == NULL) 283 if ((cred = fido_cred_new()) == NULL)
213 return; 284 return;
@@ -229,11 +300,18 @@ verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len,
229 if (fmt) 300 if (fmt)
230 fido_cred_set_fmt(cred, fmt); 301 fido_cred_set_fmt(cred, fmt);
231 302
232 fido_cred_verify(cred); 303 /* repeat memory operations to trigger reallocation paths */
233 fido_cred_verify_self(cred); 304 if (fido_cred_set_authdata(cred, authdata_ptr, authdata_len) != FIDO_OK)
305 fido_cred_set_authdata_raw(cred, authdata_ptr, authdata_len);
306 fido_cred_set_x509(cred, x5c_ptr, x5c_len);
307 fido_cred_set_sig(cred, sig_ptr, sig_len);
308
309 assert(fido_cred_verify(cred) != FIDO_OK);
310 assert(fido_cred_verify_self(cred) != FIDO_OK);
234 311
235 consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); 312 consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred));
236 consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); 313 consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred));
314 consume(fido_cred_aaguid_ptr(cred), fido_cred_aaguid_len(cred));
237 consume(fido_cred_user_id_ptr(cred), fido_cred_user_id_len(cred)); 315 consume(fido_cred_user_id_ptr(cred), fido_cred_user_id_len(cred));
238 consume(fido_cred_user_name(cred), xstrlen(fido_cred_user_name(cred))); 316 consume(fido_cred_user_name(cred), xstrlen(fido_cred_user_name(cred)));
239 consume(fido_cred_display_name(cred), 317 consume(fido_cred_display_name(cred),
@@ -247,30 +325,16 @@ verify_cred(int type, const unsigned char *cdh_ptr, size_t cdh_len,
247 fido_cred_free(&cred); 325 fido_cred_free(&cred);
248} 326}
249 327
250int 328static void
251LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 329test_cred(const struct param *p)
252{ 330{
253 struct param p; 331 fido_cred_t *cred = NULL;
254 fido_cred_t *cred = NULL; 332 int cose_alg = 0;
255 int cose_alg = 0;
256
257 memset(&p, 0, sizeof(p));
258
259 if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) ||
260 unpack(data, size, &p) < 0)
261 return (0);
262
263 prng_init((unsigned int)p.seed);
264
265 fido_init(FIDO_DEBUG);
266 fido_set_log_handler(consume_str);
267 333
268 if ((cred = fido_cred_new()) == NULL) 334 if ((cred = fido_cred_new()) == NULL)
269 return (0); 335 return;
270
271 set_wire_data(p.wire_data.body, p.wire_data.len);
272 336
273 switch (p.type & 3) { 337 switch (p->type & 3) {
274 case 0: 338 case 0:
275 cose_alg = COSE_ES256; 339 cose_alg = COSE_ES256;
276 break; 340 break;
@@ -282,116 +346,106 @@ LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
282 break; 346 break;
283 } 347 }
284 348
285 make_cred(cred, p.u2f, cose_alg, &p.cdh, p.rp_id, p.rp_name, 349 set_wire_data(p->wire_data.body, p->wire_data.len);
286 &p.user_id, p.user_name, p.user_nick, p.user_icon, p.ext, p.rk, 350
287 p.uv, p.pin, p.excl_count, &p.excl_cred); 351 make_cred(cred, p->u2f, cose_alg, &p->cdh, p->rp_id, p->rp_name,
352 &p->user_id, p->user_name, p->user_nick, p->user_icon, p->ext,
353 p->rk, p->uv, p->pin, p->excl_count, &p->excl_cred);
288 354
289 verify_cred(cose_alg, 355 verify_cred(cose_alg,
290 fido_cred_clientdata_hash_ptr(cred), 356 fido_cred_clientdata_hash_ptr(cred),
291 fido_cred_clientdata_hash_len(cred), fido_cred_rp_id(cred), 357 fido_cred_clientdata_hash_len(cred), fido_cred_rp_id(cred),
292 fido_cred_rp_name(cred), fido_cred_authdata_ptr(cred), 358 fido_cred_rp_name(cred), fido_cred_authdata_ptr(cred),
293 fido_cred_authdata_len(cred), p.ext, p.rk, p.uv, 359 fido_cred_authdata_len(cred), p->ext, p->rk, p->uv,
294 fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred), 360 fido_cred_x5c_ptr(cred), fido_cred_x5c_len(cred),
295 fido_cred_sig_ptr(cred), fido_cred_sig_len(cred), 361 fido_cred_sig_ptr(cred), fido_cred_sig_len(cred),
296 fido_cred_fmt(cred), fido_cred_prot(cred)); 362 fido_cred_fmt(cred), fido_cred_prot(cred));
297 363
298 fido_cred_free(&cred); 364 fido_cred_free(&cred);
299
300 return (0);
301} 365}
302 366
303static size_t 367static void
304pack_dummy(uint8_t *ptr, size_t len) 368test_touch(const struct param *p)
305{ 369{
306 struct param dummy; 370 fido_dev_t *dev;
307 uint8_t blob[16384]; 371 fido_dev_io_t io;
308 size_t blob_len; 372 int r;
373 int touched;
309 374
310 memset(&dummy, 0, sizeof(dummy)); 375 memset(&io, 0, sizeof(io));
311 376
312 dummy.type = 1; 377 io.open = dev_open;
313 dummy.ext = FIDO_EXT_HMAC_SECRET; 378 io.close = dev_close;
379 io.read = dev_read;
380 io.write = dev_write;
314 381
315 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin)); 382 set_wire_data(p->wire_data.body, p->wire_data.len);
316 strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id));
317 strlcpy(dummy.rp_name, dummy_rp_name, sizeof(dummy.rp_name));
318 strlcpy(dummy.user_icon, dummy_user_icon, sizeof(dummy.user_icon));
319 strlcpy(dummy.user_name, dummy_user_name, sizeof(dummy.user_name));
320 strlcpy(dummy.user_nick, dummy_user_nick, sizeof(dummy.user_nick));
321 383
322 dummy.cdh.len = sizeof(dummy_cdh); 384 if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev,
323 dummy.user_id.len = sizeof(dummy_user_id); 385 &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) {
324 dummy.wire_data.len = sizeof(dummy_wire_data_fido); 386 fido_dev_free(&dev);
387 return;
388 }
325 389
326 memcpy(&dummy.cdh.body, &dummy_cdh, dummy.cdh.len); 390 if (p->u2f & 1)
327 memcpy(&dummy.user_id.body, &dummy_user_id, dummy.user_id.len); 391 fido_dev_force_u2f(dev);
328 memcpy(&dummy.wire_data.body, &dummy_wire_data_fido,
329 dummy.wire_data.len);
330 392
331 blob_len = pack(blob, sizeof(blob), &dummy); 393 r = fido_dev_get_touch_begin(dev);
332 assert(blob_len != 0); 394 consume_str(fido_strerr(r));
395 r = fido_dev_get_touch_status(dev, &touched, -1);
396 consume_str(fido_strerr(r));
397 consume(&touched, sizeof(touched));
333 398
334 if (blob_len > len) { 399 fido_dev_cancel(dev);
335 memcpy(ptr, blob, len); 400 fido_dev_close(dev);
336 return (len); 401 fido_dev_free(&dev);
337 } 402}
338 403
339 memcpy(ptr, blob, blob_len); 404void
405test(const struct param *p)
406{
407 prng_init((unsigned int)p->seed);
408 fido_init(FIDO_DEBUG);
409 fido_set_log_handler(consume_str);
340 410
341 return (blob_len); 411 test_cred(p);
412 test_touch(p);
342} 413}
343 414
344size_t 415void
345LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, 416mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
346 unsigned int seed) NO_MSAN
347{ 417{
348 struct param p; 418 if (flags & MUTATE_SEED)
349 uint8_t blob[16384]; 419 p->seed = (int)seed;
350 size_t blob_len; 420
351 421 if (flags & MUTATE_PARAM) {
352 memset(&p, 0, sizeof(p)); 422 mutate_byte(&p->rk);
353 423 mutate_byte(&p->type);
354 if (unpack(data, size, &p) < 0) 424 mutate_byte(&p->u2f);
355 return (pack_dummy(data, maxsize)); 425 mutate_byte(&p->uv);
356 426 mutate_byte(&p->excl_count);
357 mutate_byte(&p.rk); 427 mutate_int(&p->ext);
358 mutate_byte(&p.type); 428 mutate_blob(&p->cdh);
359 mutate_byte(&p.u2f); 429 mutate_blob(&p->user_id);
360 mutate_byte(&p.uv); 430 mutate_blob(&p->excl_cred);
361 mutate_byte(&p.excl_count); 431 mutate_string(p->pin);
362 432 mutate_string(p->user_icon);
363 mutate_int(&p.ext); 433 mutate_string(p->user_name);
364 p.seed = (int)seed; 434 mutate_string(p->user_nick);
365 435 mutate_string(p->rp_id);
366 mutate_blob(&p.cdh); 436 mutate_string(p->rp_name);
367 mutate_blob(&p.user_id);
368
369 if (p.u2f & 1) {
370 p.wire_data.len = sizeof(dummy_wire_data_u2f);
371 memcpy(&p.wire_data.body, &dummy_wire_data_u2f,
372 p.wire_data.len);
373 } else {
374 p.wire_data.len = sizeof(dummy_wire_data_fido);
375 memcpy(&p.wire_data.body, &dummy_wire_data_fido,
376 p.wire_data.len);
377 } 437 }
378 438
379 mutate_blob(&p.wire_data); 439 if (flags & MUTATE_WIREDATA) {
380 mutate_blob(&p.excl_cred); 440 if (p->u2f & 1) {
381 441 p->wire_data.len = sizeof(dummy_wire_data_u2f);
382 mutate_string(p.pin); 442 memcpy(&p->wire_data.body, &dummy_wire_data_u2f,
383 mutate_string(p.user_icon); 443 p->wire_data.len);
384 mutate_string(p.user_name); 444 } else {
385 mutate_string(p.user_nick); 445 p->wire_data.len = sizeof(dummy_wire_data_fido);
386 mutate_string(p.rp_id); 446 memcpy(&p->wire_data.body, &dummy_wire_data_fido,
387 mutate_string(p.rp_name); 447 p->wire_data.len);
388 448 }
389 blob_len = pack(blob, sizeof(blob), &p); 449 mutate_blob(&p->wire_data);
390 450 }
391 if (blob_len == 0 || blob_len > maxsize)
392 return (0);
393
394 memcpy(data, blob, blob_len);
395
396 return (blob_len);
397} 451}
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 @@
19 19
20#include "../openbsd-compat/openbsd-compat.h" 20#include "../openbsd-compat/openbsd-compat.h"
21 21
22#define TAG_META_WIRE_DATA 0x01
23#define TAG_RP_WIRE_DATA 0x02
24#define TAG_RK_WIRE_DATA 0x03
25#define TAG_DEL_WIRE_DATA 0x04
26#define TAG_CRED_ID 0x05
27#define TAG_PIN 0x06
28#define TAG_RP_ID 0x07
29#define TAG_SEED 0x08
30
31/* Parameter set defining a FIDO2 credential management operation. */ 22/* Parameter set defining a FIDO2 credential management operation. */
32struct param { 23struct param {
33 char pin[MAXSTR]; 24 char pin[MAXSTR];
34 char rp_id[MAXSTR]; 25 char rp_id[MAXSTR];
35 int seed; 26 int seed;
36 struct blob cred_id; 27 struct blob cred_id;
37 struct blob del_wire_data; 28 struct blob del_wire_data;
38 struct blob meta_wire_data; 29 struct blob meta_wire_data;
39 struct blob rk_wire_data; 30 struct blob rk_wire_data;
40 struct blob rp_wire_data; 31 struct blob rp_wire_data;
41}; 32};
42 33
43/* 34/*
@@ -88,56 +79,136 @@ static const uint8_t dummy_del_wire_data[] = {
88 WIREDATA_CTAP_CBOR_STATUS, 79 WIREDATA_CTAP_CBOR_STATUS,
89}; 80};
90 81
91int LLVMFuzzerTestOneInput(const uint8_t *, size_t); 82struct param *
92size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); 83unpack(const uint8_t *ptr, size_t len)
93
94static int
95unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN
96{ 84{
97 uint8_t **pp = (void *)&ptr; 85 cbor_item_t *item = NULL, **v;
98 86 struct cbor_load_result cbor;
99 if (unpack_string(TAG_PIN, pp, &len, p->pin) < 0 || 87 struct param *p;
100 unpack_string(TAG_RP_ID, pp, &len, p->rp_id) < 0 || 88 int ok = -1;
101 unpack_blob(TAG_CRED_ID, pp, &len, &p->cred_id) < 0 || 89
102 unpack_blob(TAG_META_WIRE_DATA, pp, &len, &p->meta_wire_data) < 0 || 90 if ((p = calloc(1, sizeof(*p))) == NULL ||
103 unpack_blob(TAG_RP_WIRE_DATA, pp, &len, &p->rp_wire_data) < 0 || 91 (item = cbor_load(ptr, len, &cbor)) == NULL ||
104 unpack_blob(TAG_RK_WIRE_DATA, pp, &len, &p->rk_wire_data) < 0 || 92 cbor.read != len ||
105 unpack_blob(TAG_DEL_WIRE_DATA, pp, &len, &p->del_wire_data) < 0 || 93 cbor_isa_array(item) == false ||
106 unpack_int(TAG_SEED, pp, &len, &p->seed) < 0) 94 cbor_array_is_definite(item) == false ||
107 return (-1); 95 cbor_array_size(item) != 8 ||
108 96 (v = cbor_array_handle(item)) == NULL)
109 return (0); 97 goto fail;
98
99 if (unpack_int(v[0], &p->seed) < 0 ||
100 unpack_string(v[1], p->pin) < 0 ||
101 unpack_string(v[2], p->rp_id) < 0 ||
102 unpack_blob(v[3], &p->cred_id) < 0 ||
103 unpack_blob(v[4], &p->meta_wire_data) < 0 ||
104 unpack_blob(v[5], &p->rp_wire_data) < 0 ||
105 unpack_blob(v[6], &p->rk_wire_data) < 0 ||
106 unpack_blob(v[7], &p->del_wire_data) < 0)
107 goto fail;
108
109 ok = 0;
110fail:
111 if (ok < 0) {
112 free(p);
113 p = NULL;
114 }
115
116 if (item)
117 cbor_decref(&item);
118
119 return p;
110} 120}
111 121
112static size_t 122size_t
113pack(uint8_t *ptr, size_t len, const struct param *p) 123pack(uint8_t *ptr, size_t len, const struct param *p)
114{ 124{
115 const size_t max = len; 125 cbor_item_t *argv[8], *array = NULL;
116 126 size_t cbor_alloc_len, cbor_len = 0;
117 if (pack_string(TAG_PIN, &ptr, &len, p->pin) < 0 || 127 unsigned char *cbor = NULL;
118 pack_string(TAG_RP_ID, &ptr, &len, p->rp_id) < 0 || 128
119 pack_blob(TAG_CRED_ID, &ptr, &len, &p->cred_id) < 0 || 129 memset(argv, 0, sizeof(argv));
120 pack_blob(TAG_META_WIRE_DATA, &ptr, &len, &p->meta_wire_data) < 0 || 130
121 pack_blob(TAG_RP_WIRE_DATA, &ptr, &len, &p->rp_wire_data) < 0 || 131 if ((array = cbor_new_definite_array(8)) == NULL ||
122 pack_blob(TAG_RK_WIRE_DATA, &ptr, &len, &p->rk_wire_data) < 0 || 132 (argv[0] = pack_int(p->seed)) == NULL ||
123 pack_blob(TAG_DEL_WIRE_DATA, &ptr, &len, &p->del_wire_data) < 0 || 133 (argv[1] = pack_string(p->pin)) == NULL ||
124 pack_int(TAG_SEED, &ptr, &len, p->seed) < 0) 134 (argv[2] = pack_string(p->rp_id)) == NULL ||
125 return (0); 135 (argv[3] = pack_blob(&p->cred_id)) == NULL ||
126 136 (argv[4] = pack_blob(&p->meta_wire_data)) == NULL ||
127 return (max - len); 137 (argv[5] = pack_blob(&p->rp_wire_data)) == NULL ||
138 (argv[6] = pack_blob(&p->rk_wire_data)) == NULL ||
139 (argv[7] = pack_blob(&p->del_wire_data)) == NULL)
140 goto fail;
141
142 for (size_t i = 0; i < 8; i++)
143 if (cbor_array_push(array, argv[i]) == false)
144 goto fail;
145
146 if ((cbor_len = cbor_serialize_alloc(array, &cbor,
147 &cbor_alloc_len)) > len) {
148 cbor_len = 0;
149 goto fail;
150 }
151
152 memcpy(ptr, cbor, cbor_len);
153fail:
154 for (size_t i = 0; i < 8; i++)
155 if (argv[i])
156 cbor_decref(&argv[i]);
157
158 if (array)
159 cbor_decref(&array);
160
161 free(cbor);
162
163 return cbor_len;
128} 164}
129 165
130static size_t 166size_t
131input_len(int max) 167pack_dummy(uint8_t *ptr, size_t len)
132{ 168{
133 return (2 * len_string(max) + 5 * len_blob(max) + len_int()); 169 struct param dummy;
170 uint8_t blob[4096];
171 size_t blob_len;
172
173 memset(&dummy, 0, sizeof(dummy));
174
175 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
176 strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id));
177
178 dummy.meta_wire_data.len = sizeof(dummy_meta_wire_data);
179 dummy.rp_wire_data.len = sizeof(dummy_rp_wire_data);
180 dummy.rk_wire_data.len = sizeof(dummy_rk_wire_data);
181 dummy.del_wire_data.len = sizeof(dummy_del_wire_data);
182 dummy.cred_id.len = sizeof(dummy_cred_id);
183
184 memcpy(&dummy.meta_wire_data.body, &dummy_meta_wire_data,
185 dummy.meta_wire_data.len);
186 memcpy(&dummy.rp_wire_data.body, &dummy_rp_wire_data,
187 dummy.rp_wire_data.len);
188 memcpy(&dummy.rk_wire_data.body, &dummy_rk_wire_data,
189 dummy.rk_wire_data.len);
190 memcpy(&dummy.del_wire_data.body, &dummy_del_wire_data,
191 dummy.del_wire_data.len);
192 memcpy(&dummy.cred_id.body, &dummy_cred_id, dummy.cred_id.len);
193
194 assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
195
196 if (blob_len > len) {
197 memcpy(ptr, blob, len);
198 return len;
199 }
200
201 memcpy(ptr, blob, blob_len);
202
203 return blob_len;
134} 204}
135 205
136static fido_dev_t * 206static fido_dev_t *
137prepare_dev() 207prepare_dev(void)
138{ 208{
139 fido_dev_t *dev; 209 fido_dev_t *dev;
140 fido_dev_io_t io; 210 fido_dev_io_t io;
211 bool x;
141 212
142 memset(&io, 0, sizeof(io)); 213 memset(&io, 0, sizeof(io));
143 214
@@ -149,14 +220,19 @@ prepare_dev()
149 if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, 220 if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev,
150 &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { 221 &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) {
151 fido_dev_free(&dev); 222 fido_dev_free(&dev);
152 return (NULL); 223 return NULL;
153 } 224 }
154 225
155 return (dev); 226 x = fido_dev_is_fido2(dev);
227 consume(&x, sizeof(x));
228 x = fido_dev_supports_cred_prot(dev);
229 consume(&x, sizeof(x));
230
231 return dev;
156} 232}
157 233
158static void 234static void
159get_metadata(struct param *p) 235get_metadata(const struct param *p)
160{ 236{
161 fido_dev_t *dev; 237 fido_dev_t *dev;
162 fido_credman_metadata_t *metadata; 238 fido_credman_metadata_t *metadata;
@@ -187,7 +263,7 @@ get_metadata(struct param *p)
187} 263}
188 264
189static void 265static void
190get_rp_list(struct param *p) 266get_rp_list(const struct param *p)
191{ 267{
192 fido_dev_t *dev; 268 fido_dev_t *dev;
193 fido_credman_rp_t *rp; 269 fido_credman_rp_t *rp;
@@ -221,12 +297,12 @@ get_rp_list(struct param *p)
221} 297}
222 298
223static void 299static void
224get_rk_list(struct param *p) 300get_rk_list(const struct param *p)
225{ 301{
226 fido_dev_t *dev; 302 fido_dev_t *dev;
227 fido_credman_rk_t *rk; 303 fido_credman_rk_t *rk;
228 const fido_cred_t *cred; 304 const fido_cred_t *cred;
229 int type; 305 int val;
230 306
231 set_wire_data(p->rk_wire_data.body, p->rk_wire_data.len); 307 set_wire_data(p->rk_wire_data.body, p->rk_wire_data.len);
232 308
@@ -247,8 +323,8 @@ get_rk_list(struct param *p)
247 assert(i >= fido_credman_rk_count(rk)); 323 assert(i >= fido_credman_rk_count(rk));
248 continue; 324 continue;
249 } 325 }
250 type = fido_cred_type(cred); 326 val = fido_cred_type(cred);
251 consume(&type, sizeof(type)); 327 consume(&val, sizeof(val));
252 consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred)); 328 consume(fido_cred_id_ptr(cred), fido_cred_id_len(cred));
253 consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred)); 329 consume(fido_cred_pubkey_ptr(cred), fido_cred_pubkey_len(cred));
254 consume(fido_cred_user_id_ptr(cred), 330 consume(fido_cred_user_id_ptr(cred),
@@ -257,6 +333,8 @@ get_rk_list(struct param *p)
257 xstrlen(fido_cred_user_name(cred))); 333 xstrlen(fido_cred_user_name(cred)));
258 consume(fido_cred_display_name(cred), 334 consume(fido_cred_display_name(cred),
259 xstrlen(fido_cred_display_name(cred))); 335 xstrlen(fido_cred_display_name(cred)));
336 val = fido_cred_prot(cred);
337 consume(&val, sizeof(val));
260 } 338 }
261 339
262 fido_credman_rk_free(&rk); 340 fido_credman_rk_free(&rk);
@@ -265,7 +343,7 @@ get_rk_list(struct param *p)
265} 343}
266 344
267static void 345static void
268del_rk(struct param *p) 346del_rk(const struct param *p)
269{ 347{
270 fido_dev_t *dev; 348 fido_dev_t *dev;
271 349
@@ -279,101 +357,35 @@ del_rk(struct param *p)
279 fido_dev_free(&dev); 357 fido_dev_free(&dev);
280} 358}
281 359
282int 360void
283LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 361test(const struct param *p)
284{ 362{
285 struct param p; 363 prng_init((unsigned int)p->seed);
286
287 memset(&p, 0, sizeof(p));
288
289 if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) ||
290 unpack(data, size, &p) < 0)
291 return (0);
292
293 prng_init((unsigned int)p.seed);
294
295 fido_init(FIDO_DEBUG); 364 fido_init(FIDO_DEBUG);
296 fido_set_log_handler(consume_str); 365 fido_set_log_handler(consume_str);
297 366
298 get_metadata(&p); 367 get_metadata(p);
299 get_rp_list(&p); 368 get_rp_list(p);
300 get_rk_list(&p); 369 get_rk_list(p);
301 del_rk(&p); 370 del_rk(p);
302
303 return (0);
304} 371}
305 372
306static size_t 373void
307pack_dummy(uint8_t *ptr, size_t len) 374mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
308{ 375{
309 struct param dummy; 376 if (flags & MUTATE_SEED)
310 uint8_t blob[32768]; 377 p->seed = (int)seed;
311 size_t blob_len;
312
313 memset(&dummy, 0, sizeof(dummy));
314
315 strlcpy(dummy.pin, dummy_pin, sizeof(dummy.pin));
316 strlcpy(dummy.rp_id, dummy_rp_id, sizeof(dummy.rp_id));
317 378
318 dummy.meta_wire_data.len = sizeof(dummy_meta_wire_data); 379 if (flags & MUTATE_PARAM) {
319 dummy.rp_wire_data.len = sizeof(dummy_rp_wire_data); 380 mutate_blob(&p->cred_id);
320 dummy.rk_wire_data.len = sizeof(dummy_rk_wire_data); 381 mutate_string(p->pin);
321 dummy.del_wire_data.len = sizeof(dummy_del_wire_data); 382 mutate_string(p->rp_id);
322 dummy.cred_id.len = sizeof(dummy_cred_id);
323
324 memcpy(&dummy.meta_wire_data.body, &dummy_meta_wire_data,
325 dummy.meta_wire_data.len);
326 memcpy(&dummy.rp_wire_data.body, &dummy_rp_wire_data,
327 dummy.rp_wire_data.len);
328 memcpy(&dummy.rk_wire_data.body, &dummy_rk_wire_data,
329 dummy.rk_wire_data.len);
330 memcpy(&dummy.del_wire_data.body, &dummy_del_wire_data,
331 dummy.del_wire_data.len);
332 memcpy(&dummy.cred_id.body, &dummy_cred_id, dummy.cred_id.len);
333
334 blob_len = pack(blob, sizeof(blob), &dummy);
335 assert(blob_len != 0);
336
337 if (blob_len > len) {
338 memcpy(ptr, blob, len);
339 return (len);
340 } 383 }
341 384
342 memcpy(ptr, blob, blob_len); 385 if (flags & MUTATE_WIREDATA) {
343 386 mutate_blob(&p->meta_wire_data);
344 return (blob_len); 387 mutate_blob(&p->rp_wire_data);
345} 388 mutate_blob(&p->rk_wire_data);
346 389 mutate_blob(&p->del_wire_data);
347size_t 390 }
348LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize,
349 unsigned int seed) NO_MSAN
350{
351 struct param p;
352 uint8_t blob[16384];
353 size_t blob_len;
354
355 memset(&p, 0, sizeof(p));
356
357 if (unpack(data, size, &p) < 0)
358 return (pack_dummy(data, maxsize));
359
360 p.seed = (int)seed;
361
362 mutate_blob(&p.cred_id);
363 mutate_blob(&p.meta_wire_data);
364 mutate_blob(&p.rp_wire_data);
365 mutate_blob(&p.rk_wire_data);
366 mutate_blob(&p.del_wire_data);
367
368 mutate_string(p.pin);
369 mutate_string(p.rp_id);
370
371 blob_len = pack(blob, sizeof(blob), &p);
372
373 if (blob_len == 0 || blob_len > maxsize)
374 return (0);
375
376 memcpy(data, blob, blob_len);
377
378 return (blob_len);
379} 391}
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 @@
17 17
18#include "../openbsd-compat/openbsd-compat.h" 18#include "../openbsd-compat/openbsd-compat.h"
19 19
20#define TAG_PIN1 0x01
21#define TAG_PIN2 0x02
22#define TAG_RESET_WIRE_DATA 0x03
23#define TAG_INFO_WIRE_DATA 0x04
24#define TAG_SET_PIN_WIRE_DATA 0x05
25#define TAG_CHANGE_PIN_WIRE_DATA 0x06
26#define TAG_RETRY_WIRE_DATA 0x07
27#define TAG_SEED 0x08
28
29struct param { 20struct param {
30 char pin1[MAXSTR]; 21 char pin1[MAXSTR];
31 char pin2[MAXSTR]; 22 char pin2[MAXSTR];
32 struct blob reset_wire_data; 23 struct blob reset_wire_data;
33 struct blob info_wire_data; 24 struct blob info_wire_data;
34 struct blob set_pin_wire_data; 25 struct blob set_pin_wire_data;
35 struct blob change_pin_wire_data; 26 struct blob change_pin_wire_data;
36 struct blob retry_wire_data; 27 struct blob retry_wire_data;
37 int seed; 28 int seed;
38}; 29};
39 30
40static const uint8_t dummy_reset_wire_data[] = { 31static const uint8_t dummy_reset_wire_data[] = {
@@ -72,56 +63,136 @@ static const uint8_t dummy_retry_wire_data[] = {
72 WIREDATA_CTAP_CBOR_RETRIES, 63 WIREDATA_CTAP_CBOR_RETRIES,
73}; 64};
74 65
75int LLVMFuzzerTestOneInput(const uint8_t *, size_t); 66struct param *
76size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int); 67unpack(const uint8_t *ptr, size_t len)
77
78static int
79unpack(const uint8_t *ptr, size_t len, struct param *p) NO_MSAN
80{ 68{
81 uint8_t **pp = (void *)&ptr; 69 cbor_item_t *item = NULL, **v;
82 70 struct cbor_load_result cbor;
83 if (unpack_string(TAG_PIN1, pp, &len, p->pin1) < 0 || 71 struct param *p;
84 unpack_string(TAG_PIN2, pp, &len, p->pin2) < 0 || 72 int ok = -1;
85 unpack_blob(TAG_RESET_WIRE_DATA, pp, &len, &p->reset_wire_data) < 0 || 73
86 unpack_blob(TAG_INFO_WIRE_DATA, pp, &len, &p->info_wire_data) < 0 || 74 if ((p = calloc(1, sizeof(*p))) == NULL ||
87 unpack_blob(TAG_SET_PIN_WIRE_DATA, pp, &len, &p->set_pin_wire_data) < 0 || 75 (item = cbor_load(ptr, len, &cbor)) == NULL ||
88 unpack_blob(TAG_CHANGE_PIN_WIRE_DATA, pp, &len, &p->change_pin_wire_data) < 0 || 76 cbor.read != len ||
89 unpack_blob(TAG_RETRY_WIRE_DATA, pp, &len, &p->retry_wire_data) < 0 || 77 cbor_isa_array(item) == false ||
90 unpack_int(TAG_SEED, pp, &len, &p->seed) < 0) 78 cbor_array_is_definite(item) == false ||
91 return (-1); 79 cbor_array_size(item) != 8 ||
92 80 (v = cbor_array_handle(item)) == NULL)
93 return (0); 81 goto fail;
82
83 if (unpack_int(v[0], &p->seed) < 0 ||
84 unpack_string(v[1], p->pin1) < 0 ||
85 unpack_string(v[2], p->pin2) < 0 ||
86 unpack_blob(v[3], &p->reset_wire_data) < 0 ||
87 unpack_blob(v[4], &p->info_wire_data) < 0 ||
88 unpack_blob(v[5], &p->set_pin_wire_data) < 0 ||
89 unpack_blob(v[6], &p->change_pin_wire_data) < 0 ||
90 unpack_blob(v[7], &p->retry_wire_data) < 0)
91 goto fail;
92
93 ok = 0;
94fail:
95 if (ok < 0) {
96 free(p);
97 p = NULL;
98 }
99
100 if (item)
101 cbor_decref(&item);
102
103 return p;
94} 104}
95 105
96static size_t 106size_t
97pack(uint8_t *ptr, size_t len, const struct param *p) 107pack(uint8_t *ptr, size_t len, const struct param *p)
98{ 108{
99 const size_t max = len; 109 cbor_item_t *argv[8], *array = NULL;
100 110 size_t cbor_alloc_len, cbor_len = 0;
101 if (pack_string(TAG_PIN1, &ptr, &len, p->pin1) < 0 || 111 unsigned char *cbor = NULL;
102 pack_string(TAG_PIN2, &ptr, &len, p->pin2) < 0 || 112
103 pack_blob(TAG_RESET_WIRE_DATA, &ptr, &len, &p->reset_wire_data) < 0 || 113 memset(argv, 0, sizeof(argv));
104 pack_blob(TAG_INFO_WIRE_DATA, &ptr, &len, &p->info_wire_data) < 0 || 114
105 pack_blob(TAG_SET_PIN_WIRE_DATA, &ptr, &len, &p->set_pin_wire_data) < 0 || 115 if ((array = cbor_new_definite_array(8)) == NULL ||
106 pack_blob(TAG_CHANGE_PIN_WIRE_DATA, &ptr, &len, &p->change_pin_wire_data) < 0 || 116 (argv[0] = pack_int(p->seed)) == NULL ||
107 pack_blob(TAG_RETRY_WIRE_DATA, &ptr, &len, &p->retry_wire_data) < 0 || 117 (argv[1] = pack_string(p->pin1)) == NULL ||
108 pack_int(TAG_SEED, &ptr, &len, p->seed) < 0) 118 (argv[2] = pack_string(p->pin2)) == NULL ||
109 return (0); 119 (argv[3] = pack_blob(&p->reset_wire_data)) == NULL ||
110 120 (argv[4] = pack_blob(&p->info_wire_data)) == NULL ||
111 return (max - len); 121 (argv[5] = pack_blob(&p->set_pin_wire_data)) == NULL ||
122 (argv[6] = pack_blob(&p->change_pin_wire_data)) == NULL ||
123 (argv[7] = pack_blob(&p->retry_wire_data)) == NULL)
124 goto fail;
125
126 for (size_t i = 0; i < 8; i++)
127 if (cbor_array_push(array, argv[i]) == false)
128 goto fail;
129
130 if ((cbor_len = cbor_serialize_alloc(array, &cbor,
131 &cbor_alloc_len)) > len) {
132 cbor_len = 0;
133 goto fail;
134 }
135
136 memcpy(ptr, cbor, cbor_len);
137fail:
138 for (size_t i = 0; i < 8; i++)
139 if (argv[i])
140 cbor_decref(&argv[i]);
141
142 if (array)
143 cbor_decref(&array);
144
145 free(cbor);
146
147 return cbor_len;
112} 148}
113 149
114static size_t 150size_t
115input_len(int max) 151pack_dummy(uint8_t *ptr, size_t len)
116{ 152{
117 return (2 * len_string(max) + 5 * len_blob(max) + len_int()); 153 struct param dummy;
154 uint8_t blob[4096];
155 size_t blob_len;
156
157 memset(&dummy, 0, sizeof(dummy));
158
159 strlcpy(dummy.pin1, dummy_pin1, sizeof(dummy.pin1));
160 strlcpy(dummy.pin2, dummy_pin2, sizeof(dummy.pin2));
161
162 dummy.reset_wire_data.len = sizeof(dummy_reset_wire_data);
163 dummy.info_wire_data.len = sizeof(dummy_info_wire_data);
164 dummy.set_pin_wire_data.len = sizeof(dummy_set_pin_wire_data);
165 dummy.change_pin_wire_data.len = sizeof(dummy_change_pin_wire_data);
166 dummy.retry_wire_data.len = sizeof(dummy_retry_wire_data);
167
168 memcpy(&dummy.reset_wire_data.body, &dummy_reset_wire_data,
169 dummy.reset_wire_data.len);
170 memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data,
171 dummy.info_wire_data.len);
172 memcpy(&dummy.set_pin_wire_data.body, &dummy_set_pin_wire_data,
173 dummy.set_pin_wire_data.len);
174 memcpy(&dummy.change_pin_wire_data.body, &dummy_change_pin_wire_data,
175 dummy.change_pin_wire_data.len);
176 memcpy(&dummy.retry_wire_data.body, &dummy_retry_wire_data,
177 dummy.retry_wire_data.len);
178
179 assert((blob_len = pack(blob, sizeof(blob), &dummy)) != 0);
180
181 if (blob_len > len) {
182 memcpy(ptr, blob, len);
183 return len;
184 }
185
186 memcpy(ptr, blob, blob_len);
187
188 return blob_len;
118} 189}
119 190
120static fido_dev_t * 191static fido_dev_t *
121prepare_dev() 192prepare_dev(void)
122{ 193{
123 fido_dev_t *dev; 194 fido_dev_t *dev;
124 fido_dev_io_t io; 195 fido_dev_io_t io;
125 196
126 memset(&io, 0, sizeof(io)); 197 memset(&io, 0, sizeof(io));
127 198
@@ -133,14 +204,14 @@ prepare_dev()
133 if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev, 204 if ((dev = fido_dev_new()) == NULL || fido_dev_set_io_functions(dev,
134 &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) { 205 &io) != FIDO_OK || fido_dev_open(dev, "nodev") != FIDO_OK) {
135 fido_dev_free(&dev); 206 fido_dev_free(&dev);
136 return (NULL); 207 return NULL;
137 } 208 }
138 209
139 return (dev); 210 return dev;
140} 211}
141 212
142static void 213static void
143dev_reset(struct param *p) 214dev_reset(const struct param *p)
144{ 215{
145 fido_dev_t *dev; 216 fido_dev_t *dev;
146 217
@@ -155,16 +226,12 @@ dev_reset(struct param *p)
155} 226}
156 227
157static void 228static void
158dev_get_cbor_info(struct param *p) 229dev_get_cbor_info(const struct param *p)
159{ 230{
160 fido_dev_t *dev; 231 fido_dev_t *dev;
161 fido_cbor_info_t *ci; 232 fido_cbor_info_t *ci;
162 uint64_t n; 233 uint64_t n;
163 uint8_t proto; 234 uint8_t proto, major, minor, build, flags;
164 uint8_t major;
165 uint8_t minor;
166 uint8_t build;
167 uint8_t flags;
168 235
169 set_wire_data(p->info_wire_data.body, p->info_wire_data.len); 236 set_wire_data(p->info_wire_data.body, p->info_wire_data.len);
170 237
@@ -192,6 +259,7 @@ dev_get_cbor_info(struct param *p)
192 char * const *sa = fido_cbor_info_versions_ptr(ci); 259 char * const *sa = fido_cbor_info_versions_ptr(ci);
193 consume(sa[i], strlen(sa[i])); 260 consume(sa[i], strlen(sa[i]));
194 } 261 }
262
195 for (size_t i = 0; i < fido_cbor_info_extensions_len(ci); i++) { 263 for (size_t i = 0; i < fido_cbor_info_extensions_len(ci); i++) {
196 char * const *sa = fido_cbor_info_extensions_ptr(ci); 264 char * const *sa = fido_cbor_info_extensions_ptr(ci);
197 consume(sa[i], strlen(sa[i])); 265 consume(sa[i], strlen(sa[i]));
@@ -207,6 +275,12 @@ dev_get_cbor_info(struct param *p)
207 n = fido_cbor_info_maxmsgsiz(ci); 275 n = fido_cbor_info_maxmsgsiz(ci);
208 consume(&n, sizeof(n)); 276 consume(&n, sizeof(n));
209 277
278 n = fido_cbor_info_maxcredcntlst(ci);
279 consume(&n, sizeof(n));
280
281 n = fido_cbor_info_maxcredidlen(ci);
282 consume(&n, sizeof(n));
283
210 n = fido_cbor_info_fwversion(ci); 284 n = fido_cbor_info_fwversion(ci);
211 consume(&n, sizeof(n)); 285 consume(&n, sizeof(n));
212 286
@@ -222,7 +296,7 @@ out:
222} 296}
223 297
224static void 298static void
225dev_set_pin(struct param *p) 299dev_set_pin(const struct param *p)
226{ 300{
227 fido_dev_t *dev; 301 fido_dev_t *dev;
228 302
@@ -237,7 +311,7 @@ dev_set_pin(struct param *p)
237} 311}
238 312
239static void 313static void
240dev_change_pin(struct param *p) 314dev_change_pin(const struct param *p)
241{ 315{
242 fido_dev_t *dev; 316 fido_dev_t *dev;
243 317
@@ -252,10 +326,10 @@ dev_change_pin(struct param *p)
252} 326}
253 327
254static void 328static void
255dev_get_retry_count(struct param *p) 329dev_get_retry_count(const struct param *p)
256{ 330{
257 fido_dev_t *dev; 331 fido_dev_t *dev;
258 int n; 332 int n = 0;
259 333
260 set_wire_data(p->retry_wire_data.body, p->retry_wire_data.len); 334 set_wire_data(p->retry_wire_data.body, p->retry_wire_data.len);
261 335
@@ -268,103 +342,36 @@ dev_get_retry_count(struct param *p)
268 fido_dev_free(&dev); 342 fido_dev_free(&dev);
269} 343}
270 344
271int 345void
272LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 346test(const struct param *p)
273{ 347{
274 struct param p; 348 prng_init((unsigned int)p->seed);
275
276 memset(&p, 0, sizeof(p));
277
278 if (size < input_len(GETLEN_MIN) || size > input_len(GETLEN_MAX) ||
279 unpack(data, size, &p) < 0)
280 return (0);
281
282 prng_init((unsigned int)p.seed);
283
284 fido_init(FIDO_DEBUG); 349 fido_init(FIDO_DEBUG);
285 fido_set_log_handler(consume_str); 350 fido_set_log_handler(consume_str);
286 351
287 dev_reset(&p); 352 dev_reset(p);
288 dev_get_cbor_info(&p); 353 dev_get_cbor_info(p);
289 dev_set_pin(&p); 354 dev_set_pin(p);
290 dev_change_pin(&p); 355 dev_change_pin(p);
291 dev_get_retry_count(&p); 356 dev_get_retry_count(p);
292
293 return (0);
294} 357}
295 358
296static size_t 359void
297pack_dummy(uint8_t *ptr, size_t len) 360mutate(struct param *p, unsigned int seed, unsigned int flags) NO_MSAN
298{ 361{
299 struct param dummy; 362 if (flags & MUTATE_SEED)
300 uint8_t blob[16384]; 363 p->seed = (int)seed;
301 size_t blob_len;
302
303 memset(&dummy, 0, sizeof(dummy));
304
305 strlcpy(dummy.pin1, dummy_pin1, sizeof(dummy.pin1));
306 strlcpy(dummy.pin2, dummy_pin2, sizeof(dummy.pin2));
307
308 dummy.reset_wire_data.len = sizeof(dummy_reset_wire_data);
309 dummy.info_wire_data.len = sizeof(dummy_info_wire_data);
310 dummy.set_pin_wire_data.len = sizeof(dummy_set_pin_wire_data);
311 dummy.change_pin_wire_data.len = sizeof(dummy_change_pin_wire_data);
312 dummy.retry_wire_data.len = sizeof(dummy_retry_wire_data);
313
314 memcpy(&dummy.reset_wire_data.body, &dummy_reset_wire_data,
315 dummy.reset_wire_data.len);
316 memcpy(&dummy.info_wire_data.body, &dummy_info_wire_data,
317 dummy.info_wire_data.len);
318 memcpy(&dummy.set_pin_wire_data.body, &dummy_set_pin_wire_data,
319 dummy.set_pin_wire_data.len);
320 memcpy(&dummy.change_pin_wire_data.body, &dummy_change_pin_wire_data,
321 dummy.change_pin_wire_data.len);
322 memcpy(&dummy.retry_wire_data.body, &dummy_retry_wire_data,
323 dummy.retry_wire_data.len);
324
325 blob_len = pack(blob, sizeof(blob), &dummy);
326 assert(blob_len != 0);
327 364
328 if (blob_len > len) { 365 if (flags & MUTATE_PARAM) {
329 memcpy(ptr, blob, len); 366 mutate_string(p->pin1);
330 return (len); 367 mutate_string(p->pin2);
331 } 368 }
332 369
333 memcpy(ptr, blob, blob_len); 370 if (flags & MUTATE_WIREDATA) {
334 371 mutate_blob(&p->reset_wire_data);
335 return (blob_len); 372 mutate_blob(&p->info_wire_data);
336} 373 mutate_blob(&p->set_pin_wire_data);
337 374 mutate_blob(&p->change_pin_wire_data);
338size_t 375 mutate_blob(&p->retry_wire_data);
339LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize, 376 }
340 unsigned int seed)
341{
342 struct param p;
343 uint8_t blob[16384];
344 size_t blob_len;
345
346 memset(&p, 0, sizeof(p));
347
348 if (unpack(data, size, &p) < 0)
349 return (pack_dummy(data, maxsize));
350
351 p.seed = (int)seed;
352
353 mutate_string(p.pin1);
354 mutate_string(p.pin2);
355
356 mutate_blob(&p.reset_wire_data);
357 mutate_blob(&p.info_wire_data);
358 mutate_blob(&p.set_pin_wire_data);
359 mutate_blob(&p.change_pin_wire_data);
360 mutate_blob(&p.retry_wire_data);
361
362 blob_len = pack(blob, sizeof(blob), &p);
363
364 if (blob_len == 0 || blob_len > maxsize)
365 return (0);
366
367 memcpy(data, blob, blob_len);
368
369 return (blob_len);
370} 377}
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 @@
1/*
2 * Copyright (c) 2019 Yubico AB. All rights reserved.
3 * Use of this source code is governed by a BSD-style
4 * license that can be found in the LICENSE file.
5 */
6
7#include <err.h>
8#include <fcntl.h>
9#include <stdbool.h>
10#include <stdint.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <unistd.h>
15
16#include "mutator_aux.h"
17
18static bool debug;
19static unsigned int flags = MUTATE_ALL;
20static unsigned long long test_fail;
21static unsigned long long test_total;
22static unsigned long long mutate_fail;
23static unsigned long long mutate_total;
24
25int LLVMFuzzerInitialize(int *, char ***);
26int LLVMFuzzerTestOneInput(const uint8_t *, size_t);
27size_t LLVMFuzzerCustomMutator(uint8_t *, size_t, size_t, unsigned int);
28
29static int
30save_seed(const char *opt)
31{
32 const char *path;
33 int fd = -1, status = 1;
34 void *buf = NULL;
35 const size_t buflen = 4096;
36 size_t n;
37 struct param *p = NULL;
38
39 if ((path = strchr(opt, '=')) == NULL || strlen(++path) == 0) {
40 warnx("usage: --fido-save-seed=<path>");
41 goto fail;
42 }
43
44 if ((fd = open(path, O_CREAT|O_TRUNC|O_WRONLY, 0644)) == -1) {
45 warn("open %s", path);
46 goto fail;
47 }
48
49 if ((buf = malloc(buflen)) == NULL) {
50 warn("malloc");
51 goto fail;
52 }
53
54 n = pack_dummy(buf, buflen);
55
56 if ((p = unpack(buf, n)) == NULL) {
57 warnx("unpack");
58 goto fail;
59 }
60
61 if (write(fd, buf, n) != (ssize_t)n) {
62 warn("write %s", path);
63 goto fail;
64 }
65
66 status = 0;
67fail:
68 if (fd != -1)
69 close(fd);
70 free(buf);
71 free(p);
72
73 return status;
74}
75
76static void
77parse_mutate_flags(const char *opt, unsigned int *mutate_flags)
78{
79 const char *f;
80
81 if ((f = strchr(opt, '=')) == NULL || strlen(++f) == 0)
82 errx(1, "usage: --fido-mutate=<flag>");
83
84 if (strcmp(f, "seed") == 0)
85 *mutate_flags |= MUTATE_SEED;
86 else if (strcmp(f, "param") == 0)
87 *mutate_flags |= MUTATE_PARAM;
88 else if (strcmp(f, "wiredata") == 0)
89 *mutate_flags |= MUTATE_WIREDATA;
90 else
91 errx(1, "--fido-mutate: unknown flag '%s'", f);
92}
93
94int
95LLVMFuzzerInitialize(int *argc, char ***argv)
96{
97 unsigned int mutate_flags = 0;
98
99 for (int i = 0; i < *argc; i++)
100 if (strcmp((*argv)[i], "--fido-debug") == 0) {
101 debug = 1;
102 } else if (strncmp((*argv)[i], "--fido-save-seed=", 17) == 0) {
103 exit(save_seed((*argv)[i]));
104 } else if (strncmp((*argv)[i], "--fido-mutate=", 14) == 0) {
105 parse_mutate_flags((*argv)[i], &mutate_flags);
106 }
107
108 if (mutate_flags)
109 flags = mutate_flags;
110
111 return 0;
112}
113
114int
115LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
116{
117 struct param *p;
118
119 if (++test_total % 100000 == 0 && debug) {
120 double r = (double)test_fail/(double)test_total * 100.0;
121 fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__,
122 test_fail, test_total, r);
123 }
124
125 if (size > 4096 || (p = unpack(data, size)) == NULL)
126 test_fail++;
127 else {
128 test(p);
129 free(p);
130 }
131
132 return 0;
133}
134
135size_t
136LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t maxsize,
137 unsigned int seed) NO_MSAN
138{
139 struct param *p;
140 uint8_t blob[4096];
141 size_t blob_len;
142
143 memset(&p, 0, sizeof(p));
144
145#ifdef WITH_MSAN
146 __msan_unpoison(data, maxsize);
147#endif
148
149 if (++mutate_total % 100000 == 0 && debug) {
150 double r = (double)mutate_fail/(double)mutate_total * 100.0;
151 fprintf(stderr, "%s: %llu/%llu (%.2f%%)\n", __func__,
152 mutate_fail, mutate_total, r);
153 }
154
155 if ((p = unpack(data, size)) == NULL) {
156 mutate_fail++;
157 return pack_dummy(data, maxsize);
158 }
159
160 mutate(p, seed, flags);
161
162 if ((blob_len = pack(blob, sizeof(blob), p)) == 0 ||
163 blob_len > sizeof(blob) || blob_len > maxsize) {
164 mutate_fail++;
165 free(p);
166 return 0;
167 }
168
169 free(p);
170
171 memcpy(data, blob, blob_len);
172
173 return blob_len;
174}
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 @@
5 */ 5 */
6 6
7#include <assert.h> 7#include <assert.h>
8#include <cbor.h>
8#include <stddef.h> 9#include <stddef.h>
9#include <stdint.h> 10#include <stdint.h>
10#include <stdio.h> 11#include <stdio.h>
11#include <stdlib.h> 12#include <stdlib.h>
12#include <string.h> 13#include <string.h>
13 14
15#include "fido.h"
14#include "mutator_aux.h" 16#include "mutator_aux.h"
15 17
16size_t LLVMFuzzerMutate(uint8_t *, size_t, size_t); 18size_t LLVMFuzzerMutate(uint8_t *, size_t, size_t);
17 19
18static uint8_t *wire_data_ptr = NULL; 20static const uint8_t *wire_data_ptr = NULL;
19static size_t wire_data_len = 0; 21static size_t wire_data_len = 0;
20 22
21size_t 23size_t
22xstrlen(const char *s) 24xstrlen(const char *s)
23{ 25{
24 if (s == NULL) 26 if (s == NULL)
25 return (0); 27 return 0;
26 28
27 return (strlen(s)); 29 return strlen(s);
28} 30}
29 31
30void 32void
@@ -33,6 +35,10 @@ consume(const void *body, size_t len)
33 const volatile uint8_t *ptr = body; 35 const volatile uint8_t *ptr = body;
34 volatile uint8_t x = 0; 36 volatile uint8_t x = 0;
35 37
38#ifdef WITH_MSAN
39 __msan_check_mem_is_initialized(body, len);
40#endif
41
36 while (len--) 42 while (len--)
37 x ^= *ptr++; 43 x ^= *ptr++;
38} 44}
@@ -44,217 +50,87 @@ consume_str(const char *str)
44} 50}
45 51
46int 52int
47unpack_int(uint8_t t, uint8_t **ptr, size_t *len, int *v) NO_MSAN 53unpack_int(cbor_item_t *item, int *v)
48{
49 size_t l;
50
51 if (*len < sizeof(t) || **ptr != t)
52 return (-1);
53
54 *ptr += sizeof(t);
55 *len -= sizeof(t);
56
57 if (*len < sizeof(l))
58 return (-1);
59
60 memcpy(&l, *ptr, sizeof(l));
61 *ptr += sizeof(l);
62 *len -= sizeof(l);
63
64 if (l != sizeof(*v) || *len < l)
65 return (-1);
66
67 memcpy(v, *ptr, sizeof(*v));
68 *ptr += sizeof(*v);
69 *len -= sizeof(*v);
70
71 return (0);
72}
73
74int
75unpack_string(uint8_t t, uint8_t **ptr, size_t *len, char *v) NO_MSAN
76{ 54{
77 size_t l; 55 if (cbor_is_int(item) == false ||
78 56 cbor_int_get_width(item) != CBOR_INT_64)
79 if (*len < sizeof(t) || **ptr != t) 57 return -1;
80 return (-1);
81
82 *ptr += sizeof(t);
83 *len -= sizeof(t);
84
85 if (*len < sizeof(l))
86 return (-1);
87
88 memcpy(&l, *ptr, sizeof(l));
89 *ptr += sizeof(l);
90 *len -= sizeof(l);
91 58
92 if (*len < l || l >= MAXSTR) 59 if (cbor_isa_uint(item))
93 return (-1); 60 *v = (int)cbor_get_uint64(item);
94 61 else
95 memcpy(v, *ptr, l); 62 *v = (int)(-cbor_get_uint64(item) - 1);
96 v[l] = '\0';
97
98 *ptr += l;
99 *len -= l;
100
101 return (0);
102}
103
104int
105unpack_byte(uint8_t t, uint8_t **ptr, size_t *len, uint8_t *v) NO_MSAN
106{
107 size_t l;
108
109 if (*len < sizeof(t) || **ptr != t)
110 return (-1);
111
112 *ptr += sizeof(t);
113 *len -= sizeof(t);
114
115 if (*len < sizeof(l))
116 return (-1);
117
118 memcpy(&l, *ptr, sizeof(l));
119 *ptr += sizeof(l);
120 *len -= sizeof(l);
121
122 if (l != sizeof(*v) || *len < l)
123 return (-1);
124
125 memcpy(v, *ptr, sizeof(*v));
126 *ptr += sizeof(*v);
127 *len -= sizeof(*v);
128
129 return (0);
130}
131
132int
133unpack_blob(uint8_t t, uint8_t **ptr, size_t *len, struct blob *v) NO_MSAN
134{
135 size_t l;
136
137 v->len = 0;
138
139 if (*len < sizeof(t) || **ptr != t)
140 return (-1);
141
142 *ptr += sizeof(t);
143 *len -= sizeof(t);
144
145 if (*len < sizeof(l))
146 return (-1);
147
148 memcpy(&l, *ptr, sizeof(l));
149 *ptr += sizeof(l);
150 *len -= sizeof(l);
151
152 if (*len < l || l > sizeof(v->body))
153 return (-1);
154
155 memcpy(v->body, *ptr, l);
156 *ptr += l;
157 *len -= l;
158
159 v->len = l;
160 63
161 return (0); 64 return 0;
162} 65}
163 66
164int 67int
165pack_int(uint8_t t, uint8_t **ptr, size_t *len, int v) NO_MSAN 68unpack_string(cbor_item_t *item, char *v)
166{ 69{
167 const size_t l = sizeof(v); 70 size_t len;
168 71
169 if (*len < sizeof(t) + sizeof(l) + l) 72 if (cbor_isa_bytestring(item) == false ||
170 return (-1); 73 (len = cbor_bytestring_length(item)) >= MAXSTR)
74 return -1;
171 75
172 (*ptr)[0] = t; 76 memcpy(v, cbor_bytestring_handle(item), len);
173 memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l)); 77 v[len] = '\0';
174 memcpy(&(*ptr)[sizeof(t) + sizeof(l)], &v, l);
175 78
176 *ptr += sizeof(t) + sizeof(l) + l; 79 return 0;
177 *len -= sizeof(t) + sizeof(l) + l;
178
179 return (0);
180} 80}
181 81
182int 82int
183pack_string(uint8_t t, uint8_t **ptr, size_t *len, const char *v) NO_MSAN 83unpack_byte(cbor_item_t *item, uint8_t *v)
184{ 84{
185 const size_t l = strlen(v); 85 if (cbor_isa_uint(item) == false ||
186 86 cbor_int_get_width(item) != CBOR_INT_8)
187 if (*len < sizeof(t) + sizeof(l) + l) 87 return -1;
188 return (-1);
189
190 (*ptr)[0] = t;
191 memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l));
192 memcpy(&(*ptr)[sizeof(t) + sizeof(l)], v, l);
193 88
194 *ptr += sizeof(t) + sizeof(l) + l; 89 *v = cbor_get_uint8(item);
195 *len -= sizeof(t) + sizeof(l) + l;
196 90
197 return (0); 91 return 0;
198} 92}
199 93
200int 94int
201pack_byte(uint8_t t, uint8_t **ptr, size_t *len, uint8_t v) NO_MSAN 95unpack_blob(cbor_item_t *item, struct blob *v)
202{ 96{
203 const size_t l = sizeof(v); 97 if (cbor_isa_bytestring(item) == false ||
98 (v->len = cbor_bytestring_length(item)) > sizeof(v->body))
99 return -1;
204 100
205 if (*len < sizeof(t) + sizeof(l) + l) 101 memcpy(v->body, cbor_bytestring_handle(item), v->len);
206 return (-1);
207 102
208 (*ptr)[0] = t; 103 return 0;
209 memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l));
210 memcpy(&(*ptr)[sizeof(t) + sizeof(l)], &v, l);
211
212 *ptr += sizeof(t) + sizeof(l) + l;
213 *len -= sizeof(t) + sizeof(l) + l;
214
215 return (0);
216} 104}
217 105
218int 106cbor_item_t *
219pack_blob(uint8_t t, uint8_t **ptr, size_t *len, const struct blob *v) NO_MSAN 107pack_int(int v) NO_MSAN
220{ 108{
221 const size_t l = v->len; 109 if (v < 0)
222 110 return cbor_build_negint64((uint64_t)(-(int64_t)v - 1));
223 if (*len < sizeof(t) + sizeof(l) + l) 111 else
224 return (-1); 112 return cbor_build_uint64((uint64_t)v);
225
226 (*ptr)[0] = t;
227 memcpy(&(*ptr)[sizeof(t)], &l, sizeof(l));
228 memcpy(&(*ptr)[sizeof(t) + sizeof(l)], v->body, l);
229
230 *ptr += sizeof(t) + sizeof(l) + l;
231 *len -= sizeof(t) + sizeof(l) + l;
232
233 return (0);
234} 113}
235 114
236size_t 115cbor_item_t *
237len_int(void) 116pack_string(const char *v) NO_MSAN
238{ 117{
239 return (sizeof(uint8_t) + sizeof(size_t) + sizeof(int)); 118 if (strlen(v) >= MAXSTR)
240} 119 return NULL;
241 120
242size_t 121 return cbor_build_bytestring((const unsigned char *)v, strlen(v));
243len_string(int max)
244{
245 return ((sizeof(uint8_t) + sizeof(size_t)) + (max ? MAXSTR - 1 : 0));
246} 122}
247 123
248size_t 124cbor_item_t *
249len_byte(void) 125pack_byte(uint8_t v) NO_MSAN
250{ 126{
251 return (sizeof(uint8_t) + sizeof(size_t) + sizeof(uint8_t)); 127 return cbor_build_uint8(v);
252} 128}
253 129
254size_t 130cbor_item_t *
255len_blob(int max) 131pack_blob(const struct blob *v) NO_MSAN
256{ 132{
257 return (sizeof(uint8_t) + sizeof(size_t) + (max ? MAXBLOB : 0)); 133 return cbor_build_bytestring(v->body, v->len);
258} 134}
259 135
260void 136void
@@ -284,13 +160,13 @@ mutate_string(char *s)
284 n = LLVMFuzzerMutate((uint8_t *)s, strlen(s), MAXSTR - 1); 160 n = LLVMFuzzerMutate((uint8_t *)s, strlen(s), MAXSTR - 1);
285 s[n] = '\0'; 161 s[n] = '\0';
286} 162}
287 163
288void * 164void *
289dev_open(const char *path) 165dev_open(const char *path)
290{ 166{
291 (void)path; 167 (void)path;
292 168
293 return ((void *)0xdeadbeef); 169 return (void *)0xdeadbeef;
294} 170}
295 171
296void 172void
@@ -307,7 +183,7 @@ dev_read(void *handle, unsigned char *ptr, size_t len, int ms)
307 (void)ms; 183 (void)ms;
308 184
309 assert(handle == (void *)0xdeadbeef); 185 assert(handle == (void *)0xdeadbeef);
310 assert(len == 64); 186 assert(len >= CTAP_MIN_REPORT_LEN && len <= CTAP_MAX_REPORT_LEN);
311 187
312 if (wire_data_len < len) 188 if (wire_data_len < len)
313 n = wire_data_len; 189 n = wire_data_len;
@@ -319,25 +195,26 @@ dev_read(void *handle, unsigned char *ptr, size_t len, int ms)
319 wire_data_ptr += n; 195 wire_data_ptr += n;
320 wire_data_len -= n; 196 wire_data_len -= n;
321 197
322 return ((int)n); 198 return (int)n;
323} 199}
324 200
325int 201int
326dev_write(void *handle, const unsigned char *ptr, size_t len) 202dev_write(void *handle, const unsigned char *ptr, size_t len)
327{ 203{
328 assert(handle == (void *)0xdeadbeef); 204 assert(handle == (void *)0xdeadbeef);
329 assert(len == 64 + 1); 205 assert(len >= CTAP_MIN_REPORT_LEN + 1 &&
206 len <= CTAP_MAX_REPORT_LEN + 1);
330 207
331 consume(ptr, len); 208 consume(ptr, len);
332 209
333 if (uniform_random(400) < 1) 210 if (uniform_random(400) < 1)
334 return (-1); 211 return -1;
335 212
336 return ((int)len); 213 return (int)len;
337} 214}
338 215
339void 216void
340set_wire_data(uint8_t *ptr, size_t len) 217set_wire_data(const uint8_t *ptr, size_t len)
341{ 218{
342 wire_data_ptr = ptr; 219 wire_data_ptr = ptr;
343 wire_data_len = len; 220 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 @@
9 9
10#include <stddef.h> 10#include <stddef.h>
11#include <stdint.h> 11#include <stdint.h>
12#include <cbor.h>
12 13
13/* 14/*
14 * As of LLVM 7.0.1, MSAN support in libFuzzer was still experimental. 15 * As of LLVM 10.0.0, MSAN support in libFuzzer was still experimental.
15 * We therefore have to be careful when using our custom mutator, or 16 * We therefore have to be careful when using our custom mutator, or
16 * MSAN will flag uninitialised reads on memory populated by libFuzzer. 17 * MSAN will flag uninitialised reads on memory populated by libFuzzer.
17 * Since there is no way to suppress MSAN without regenerating object 18 * Since there is no way to suppress MSAN without regenerating object
@@ -22,6 +23,7 @@
22 23
23#if defined(__has_feature) 24#if defined(__has_feature)
24# if __has_feature(memory_sanitizer) 25# if __has_feature(memory_sanitizer)
26# include <sanitizer/msan_interface.h>
25# define NO_MSAN __attribute__((no_sanitize("memory"))) 27# define NO_MSAN __attribute__((no_sanitize("memory")))
26# define WITH_MSAN 1 28# define WITH_MSAN 1
27# endif 29# endif
@@ -31,44 +33,49 @@
31# define NO_MSAN 33# define NO_MSAN
32#endif 34#endif
33 35
36#define MUTATE_SEED 0x01
37#define MUTATE_PARAM 0x02
38#define MUTATE_WIREDATA 0x04
39#define MUTATE_ALL (MUTATE_SEED | MUTATE_PARAM | MUTATE_WIREDATA)
40
34#define MAXSTR 1024 41#define MAXSTR 1024
35#define MAXBLOB 3072 42#define MAXBLOB 3072
36 43
37#define GETLEN_MIN 0
38#define GETLEN_MAX 1
39
40struct blob { 44struct blob {
41 uint8_t body[MAXBLOB]; 45 uint8_t body[MAXBLOB];
42 size_t len; 46 size_t len;
43}; 47};
44 48
49struct param;
50
51struct param *unpack(const uint8_t *, size_t);
52size_t pack(uint8_t *, size_t, const struct param *);
53size_t pack_dummy(uint8_t *, size_t);
54void mutate(struct param *, unsigned int, unsigned int);
55void test(const struct param *);
56
45size_t xstrlen(const char *); 57size_t xstrlen(const char *);
46void consume(const void *, size_t); 58void consume(const void *, size_t);
47void consume_str(const char *); 59void consume_str(const char *);
48 60
49int unpack_blob(uint8_t, uint8_t **, size_t *, struct blob *); 61int unpack_blob(cbor_item_t *, struct blob *);
50int unpack_byte(uint8_t, uint8_t **, size_t *, uint8_t *); 62int unpack_byte(cbor_item_t *, uint8_t *);
51int unpack_int(uint8_t, uint8_t **, size_t *, int *); 63int unpack_int(cbor_item_t *, int *);
52int unpack_string(uint8_t, uint8_t **, size_t *, char *); 64int unpack_string(cbor_item_t *, char *);
53
54int pack_blob(uint8_t, uint8_t **, size_t *, const struct blob *);
55int pack_byte(uint8_t, uint8_t **, size_t *, uint8_t);
56int pack_int(uint8_t, uint8_t **, size_t *, int);
57int pack_string(uint8_t, uint8_t **, size_t *, const char *);
58 65
59size_t len_int(void); 66cbor_item_t *pack_blob(const struct blob *);
60size_t len_string(int); 67cbor_item_t *pack_byte(uint8_t);
61size_t len_byte(void); 68cbor_item_t *pack_int(int);
62size_t len_blob(int); 69cbor_item_t *pack_string(const char *);
63 70
64void mutate_byte(uint8_t *); 71void mutate_byte(uint8_t *);
65void mutate_int(int *); 72void mutate_int(int *);
66void mutate_blob(struct blob *); 73void mutate_blob(struct blob *);
67void mutate_string(char *); 74void mutate_string(char *);
68 75
69void * dev_open(const char *); 76void *dev_open(const char *);
70void dev_close(void *); 77void dev_close(void *);
71void set_wire_data(uint8_t *, size_t); 78void set_wire_data(const uint8_t *, size_t);
72int dev_read(void *, unsigned char *, size_t, int); 79int dev_read(void *, unsigned char *, size_t, int);
73int dev_write(void *, const unsigned char *, size_t); 80int dev_write(void *, const unsigned char *, size_t);
74 81
diff --git a/fuzz/prng.c b/fuzz/prng.c
index fa6d4e4..61114ac 100755..100644
--- a/fuzz/prng.c
+++ b/fuzz/prng.c
@@ -63,7 +63,8 @@ void init_genrand(unsigned long s)
63 mt[0]= s & 0xffffffffUL; 63 mt[0]= s & 0xffffffffUL;
64 for (mti=1; mti<N; mti++) { 64 for (mti=1; mti<N; mti++) {
65 mt[mti] = 65 mt[mti] =
66 (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); 66 (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) +
67 (unsigned long)mti);
67 /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ 68 /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
68 /* In the previous versions, MSBs of the seed affect */ 69 /* In the previous versions, MSBs of the seed affect */
69 /* only MSBs of the array mt[]. */ 70 /* only MSBs of the array mt[]. */
diff --git a/fuzz/report.tgz b/fuzz/report.tgz
index 8a002f0..6f02fc5 100644
--- a/fuzz/report.tgz
+++ b/fuzz/report.tgz
Binary files 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 @@
1Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover 1Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover
2-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 2--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
3fuzz/prng.c 31 0 100.00% 2 0 100.00% 48 0 100.00% 3fuzz/prng.c 31 0 100.00% 2 0 100.00% 49 0 100.00%
4fuzz/uniform_random.c 7 1 85.71% 1 0 100.00% 23 1 95.65% 4fuzz/uniform_random.c 7 1 85.71% 1 0 100.00% 23 1 95.65%
5fuzz/wrap.c 6 0 100.00% 1 0 100.00% 7 0 100.00% 5fuzz/wrap.c 6 0 100.00% 1 0 100.00% 7 0 100.00%
6openbsd-compat/explicit_bzero.c 4 0 100.00% 1 0 100.00% 12 0 100.00% 6openbsd-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%
8openbsd-compat/strlcat.c 12 1 91.67% 1 0 100.00% 25 1 96.00% 8openbsd-compat/strlcat.c 12 1 91.67% 1 0 100.00% 25 1 96.00%
9openbsd-compat/timingsafe_bcmp.c 4 0 100.00% 1 0 100.00% 8 0 100.00% 9openbsd-compat/timingsafe_bcmp.c 4 0 100.00% 1 0 100.00% 8 0 100.00%
10src/aes256.c 56 0 100.00% 2 0 100.00% 82 0 100.00% 10src/aes256.c 56 0 100.00% 2 0 100.00% 82 0 100.00%
11src/assert.c 566 43 92.40% 53 1 98.11% 900 87 90.33% 11src/assert.c 566 24 95.76% 53 1 98.11% 900 50 94.44%
12src/authkey.c 44 0 100.00% 5 0 100.00% 75 0 100.00% 12src/authkey.c 44 0 100.00% 5 0 100.00% 75 0 100.00%
13src/bio.c 418 20 95.22% 49 2 95.92% 661 22 96.67% 13src/bio.c 418 20 95.22% 49 2 95.92% 661 22 96.67%
14src/blob.c 39 1 97.44% 7 0 100.00% 73 4 94.52% 14src/blob.c 39 0 100.00% 7 0 100.00% 73 0 100.00%
15src/buf.c 8 1 87.50% 2 0 100.00% 20 1 95.00% 15src/buf.c 8 1 87.50% 2 0 100.00% 20 1 95.00%
16src/cbor.c 884 70 92.08% 52 2 96.15% 1371 106 92.27% 16src/cbor.c 883 6 99.32% 52 0 100.00% 1364 17 98.75%
17src/cred.c 534 51 90.45% 55 1 98.18% 830 78 90.60% 17src/cred.c 536 23 95.71% 57 1 98.25% 836 29 96.53%
18src/credman.c 376 18 95.21% 38 0 100.00% 589 15 97.45% 18src/credman.c 385 18 95.32% 38 0 100.00% 595 16 97.31%
19src/dev.c 201 85 57.71% 26 8 69.23% 294 128 56.46% 19src/dev.c 334 90 73.05% 33 8 75.76% 466 140 69.96%
20src/ecdh.c 68 0 100.00% 2 0 100.00% 104 0 100.00% 20src/ecdh.c 68 0 100.00% 2 0 100.00% 104 0 100.00%
21src/eddsa.c 54 0 100.00% 8 0 100.00% 79 0 100.00% 21src/eddsa.c 54 0 100.00% 8 0 100.00% 79 0 100.00%
22src/err.c 108 108 0.00% 1 1 0.00% 112 112 0.00% 22src/err.c 112 8 92.86% 1 0 100.00% 116 8 93.10%
23src/es256.c 278 0 100.00% 16 0 100.00% 377 0 100.00% 23src/es256.c 280 0 100.00% 16 0 100.00% 398 0 100.00%
24src/hid.c 16 16 0.00% 8 8 0.00% 38 38 0.00% 24src/hid.c 16 16 0.00% 8 8 0.00% 38 38 0.00%
25src/hid_linux.c 166 166 0.00% 12 12 0.00% 292 292 0.00% 25src/hid_linux.c 235 235 0.00% 19 19 0.00% 416 416 0.00%
26src/info.c 146 0 100.00% 31 0 100.00% 304 0 100.00% 26src/info.c 152 0 100.00% 34 0 100.00% 319 0 100.00%
27src/io.c 123 5 95.93% 10 0 100.00% 218 11 94.95% 27src/io.c 156 9 94.23% 10 0 100.00% 236 11 95.34%
28src/iso7816.c 18 1 94.44% 5 0 100.00% 47 0 100.00% 28src/iso7816.c 18 1 94.44% 5 0 100.00% 47 0 100.00%
29src/log.c 34 2 94.12% 5 1 80.00% 50 3 94.00% 29src/log.c 34 2 94.12% 5 1 80.00% 50 3 94.00%
30src/pin.c 248 0 100.00% 16 0 100.00% 365 0 100.00% 30src/pin.c 248 0 100.00% 16 0 100.00% 365 0 100.00%
31src/reset.c 19 0 100.00% 3 0 100.00% 22 0 100.00% 31src/reset.c 19 0 100.00% 3 0 100.00% 22 0 100.00%
32src/rs256.c 102 29 71.57% 8 3 62.50% 140 44 68.57% 32src/rs256.c 102 6 94.12% 8 0 100.00% 140 13 90.71%
33src/u2f.c 443 28 93.68% 13 0 100.00% 699 52 92.56% 33src/u2f.c 491 9 98.17% 15 0 100.00% 774 18 97.67%
34 34
35Files which contain no functions: 35Files which contain no functions:
36openbsd-compat/time.h 0 0 - 0 0 - 0 0 -
36src/extern.h 0 0 - 0 0 - 0 0 - 37src/extern.h 0 0 - 0 0 - 0 0 -
37src/fido.h 0 0 - 0 0 - 0 0 - 38src/fido.h 0 0 - 0 0 - 0 0 -
38src/fido/err.h 0 0 - 0 0 - 0 0 - 39src/fido/err.h 0 0 - 0 0 - 0 0 -
39src/fido/param.h 0 0 - 0 0 - 0 0 - 40src/fido/param.h 0 0 - 0 0 - 0 0 -
40-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 41--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
41TOTAL 5054 653 87.08% 435 39 91.03% 7914 1002 87.34% 42TOTAL 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 @@
3# license that can be found in the LICENSE file. 3# license that can be found in the LICENSE file.
4 4
5find_program(MANDOC_PATH mandoc) 5find_program(MANDOC_PATH mandoc)
6message(STATUS "MANDOC_PATH: ${MANDOC_PATH}") 6find_program(GZIP_PATH gzip)
7 7
8if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR CMAKE_SYSTEM_NAME STREQUAL "Linux") 8message(STATUS "MANDOC_PATH: ${MANDOC_PATH}")
9 find_program(GZIP_PATH gzip) 9message(STATUS "GZIP_PATH: ${GZIP_PATH}")
10 message(STATUS "GZIP_PATH: ${GZIP_PATH}")
11endif()
12 10
13list(APPEND MAN_SOURCES 11list(APPEND MAN_SOURCES
14 eddsa_pk_new.3 12 eddsa_pk_new.3
@@ -32,6 +30,7 @@ list(APPEND MAN_SOURCES
32 fido_cred_set_authdata.3 30 fido_cred_set_authdata.3
33 fido_cred_verify.3 31 fido_cred_verify.3
34 fido_dev_get_assert.3 32 fido_dev_get_assert.3
33 fido_dev_get_touch_begin.3
35 fido_dev_info_manifest.3 34 fido_dev_info_manifest.3
36 fido_dev_make_cred.3 35 fido_dev_make_cred.3
37 fido_dev_open.3 36 fido_dev_open.3
@@ -54,9 +53,13 @@ list(APPEND MAN_ALIAS
54 fido_assert_new fido_assert_clientdata_hash_len 53 fido_assert_new fido_assert_clientdata_hash_len
55 fido_assert_new fido_assert_clientdata_hash_ptr 54 fido_assert_new fido_assert_clientdata_hash_ptr
56 fido_assert_new fido_assert_count 55 fido_assert_new fido_assert_count
56 fido_assert_new fido_assert_flags
57 fido_assert_new fido_assert_free 57 fido_assert_new fido_assert_free
58 fido_assert_new fido_assert_hmac_secret_len 58 fido_assert_new fido_assert_hmac_secret_len
59 fido_assert_new fido_assert_hmac_secret_ptr 59 fido_assert_new fido_assert_hmac_secret_ptr
60 fido_assert_new fido_assert_id_len
61 fido_assert_new fido_assert_id_ptr
62 fido_assert_new fido_assert_rp_id
60 fido_assert_new fido_assert_sigcount 63 fido_assert_new fido_assert_sigcount
61 fido_assert_new fido_assert_sig_len 64 fido_assert_new fido_assert_sig_len
62 fido_assert_new fido_assert_sig_ptr 65 fido_assert_new fido_assert_sig_ptr
@@ -95,34 +98,46 @@ list(APPEND MAN_ALIAS
95 fido_bio_template fido_bio_template_new 98 fido_bio_template fido_bio_template_new
96 fido_bio_template fido_bio_template_set_id 99 fido_bio_template fido_bio_template_set_id
97 fido_bio_template fido_bio_template_set_name 100 fido_bio_template fido_bio_template_set_name
98 fido_cbor_info_new fido_cbor_info_aaguid_len 101 fido_cbor_info_new fido_cbor_info_aaguid_len
99 fido_cbor_info_new fido_cbor_info_aaguid_ptr 102 fido_cbor_info_new fido_cbor_info_aaguid_ptr
100 fido_cbor_info_new fido_cbor_info_extensions_len 103 fido_cbor_info_new fido_cbor_info_extensions_len
101 fido_cbor_info_new fido_cbor_info_extensions_ptr 104 fido_cbor_info_new fido_cbor_info_extensions_ptr
102 fido_cbor_info_new fido_cbor_info_free 105 fido_cbor_info_new fido_cbor_info_free
103 fido_cbor_info_new fido_cbor_info_maxmsgsiz 106 fido_cbor_info_new fido_cbor_info_maxmsgsiz
107 fido_cbor_info_new fido_cbor_info_maxcredcntlst;
108 fido_cbor_info_new fido_cbor_info_maxcredidlen;
104 fido_cbor_info_new fido_cbor_info_fwversion 109 fido_cbor_info_new fido_cbor_info_fwversion
105 fido_cbor_info_new fido_cbor_info_options_len 110 fido_cbor_info_new fido_cbor_info_options_len
106 fido_cbor_info_new fido_cbor_info_options_name_ptr 111 fido_cbor_info_new fido_cbor_info_options_name_ptr
107 fido_cbor_info_new fido_cbor_info_options_value_ptr 112 fido_cbor_info_new fido_cbor_info_options_value_ptr
108 fido_cbor_info_new fido_cbor_info_protocols_len 113 fido_cbor_info_new fido_cbor_info_protocols_len
109 fido_cbor_info_new fido_cbor_info_protocols_ptr 114 fido_cbor_info_new fido_cbor_info_protocols_ptr
110 fido_cbor_info_new fido_cbor_info_versions_len 115 fido_cbor_info_new fido_cbor_info_versions_len
111 fido_cbor_info_new fido_cbor_info_versions_ptr 116 fido_cbor_info_new fido_cbor_info_versions_ptr
112 fido_cbor_info_new fido_dev_get_cbor_info 117 fido_cbor_info_new fido_dev_get_cbor_info
113 fido_cred_new fido_cred_authdata_len 118 fido_cred_new fido_cred_authdata_len
114 fido_cred_new fido_cred_authdata_ptr 119 fido_cred_new fido_cred_authdata_ptr
115 fido_cred_new fido_cred_clientdata_hash_len 120 fido_cred_new fido_cred_clientdata_hash_len
116 fido_cred_new fido_cred_clientdata_hash_ptr 121 fido_cred_new fido_cred_clientdata_hash_ptr
122 fido_cred_new fido_cred_display_name
123 fido_cred_new fido_cred_flags
117 fido_cred_new fido_cred_fmt 124 fido_cred_new fido_cred_fmt
118 fido_cred_new fido_cred_free 125 fido_cred_new fido_cred_free
119 fido_cred_new fido_cred_id_len 126 fido_cred_new fido_cred_id_len
120 fido_cred_new fido_cred_id_ptr 127 fido_cred_new fido_cred_id_ptr
128 fido_cred_new fido_cred_aaguid_len
129 fido_cred_new fido_cred_aaguid_ptr
121 fido_cred_new fido_cred_prot 130 fido_cred_new fido_cred_prot
122 fido_cred_new fido_cred_pubkey_len 131 fido_cred_new fido_cred_pubkey_len
123 fido_cred_new fido_cred_pubkey_ptr 132 fido_cred_new fido_cred_pubkey_ptr
133 fido_cred_new fido_cred_rp_id
134 fido_cred_new fido_cred_rp_name
124 fido_cred_new fido_cred_sig_len 135 fido_cred_new fido_cred_sig_len
125 fido_cred_new fido_cred_sig_ptr 136 fido_cred_new fido_cred_sig_ptr
137 fido_cred_new fido_cred_type
138 fido_cred_new fido_cred_user_name
139 fido_cred_new fido_cred_user_id_len
140 fido_cred_new fido_cred_user_id_ptr
126 fido_cred_new fido_cred_x5c_len 141 fido_cred_new fido_cred_x5c_len
127 fido_cred_new fido_cred_x5c_ptr 142 fido_cred_new fido_cred_x5c_ptr
128 fido_credman_metadata_new fido_credman_del_dev_rk 143 fido_credman_metadata_new fido_credman_del_dev_rk
@@ -171,6 +186,8 @@ list(APPEND MAN_ALIAS
171 fido_dev_open fido_dev_force_u2f 186 fido_dev_open fido_dev_force_u2f
172 fido_dev_open fido_dev_free 187 fido_dev_open fido_dev_free
173 fido_dev_open fido_dev_is_fido2 188 fido_dev_open fido_dev_is_fido2
189 fido_dev_open fido_dev_supports_cred_prot
190 fido_dev_open fido_dev_supports_pin
174 fido_dev_open fido_dev_major 191 fido_dev_open fido_dev_major
175 fido_dev_open fido_dev_minor 192 fido_dev_open fido_dev_minor
176 fido_dev_open fido_dev_new 193 fido_dev_open fido_dev_new
@@ -224,7 +241,7 @@ endforeach()
224# man_gzip 241# man_gzip
225foreach(f ${MAN_SOURCES}) 242foreach(f ${MAN_SOURCES})
226 add_custom_command(OUTPUT ${f}.gz 243 add_custom_command(OUTPUT ${f}.gz
227 COMMAND gzip -c ${f} > ${f}.gz 244 COMMAND gzip -cn ${f} > ${f}.gz
228 DEPENDS ${f}) 245 DEPENDS ${f})
229 list(APPEND GZ_FILES ${f}.gz) 246 list(APPEND GZ_FILES ${f}.gz)
230endforeach() 247endforeach()
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/:
2 2
3$ make -C build man_symlink_html_partial 3$ make -C build man_symlink_html_partial
4$ (cd build/man && pax -p p -r -w *.partial /tmp/partial) 4$ (cd build/man && pax -p p -r -w *.partial /tmp/partial)
5
6Use mandoc 1.14.4. Otherwise, adjust dyc.css to mandoc's HTML
7output.
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 @@
12.Nm 12.Nm
13.Fl G 13.Fl G
14.Op Fl dhpruv 14.Op Fl dhpruv
15.Op Fl t Ar option
15.Op Fl i Ar input_file 16.Op Fl i Ar input_file
16.Op Fl o Ar output_file 17.Op Fl o Ar output_file
17.Ar device 18.Ar device
@@ -110,6 +111,29 @@ is specified,
110.Nm 111.Nm
111will not expect a credential id in its input, and may output 112will not expect a credential id in its input, and may output
112multiple assertions. 113multiple assertions.
114.It Fl t Ar option
115Toggles a key/value
116.Ar option ,
117where
118.Ar option
119is a string of the form
120.Dq key=value .
121The options supported at present are:
122.Bl -tag -width Ds
123.It Cm up Ns = Ns Ar true|false
124Asks the authenticator for user presence to be enabled or disabled.
125.It Cm uv Ns = Ns Ar true|false
126Asks the authenticator for user verification to be enabled or
127disabled.
128.It Cm pin Ns = Ns Ar true|false
129Tells
130.Nm
131whether to prompt for a PIN and request user verification.
132.El
133.Pp
134The
135.Fl t
136option may be specified multiple times.
113.It Fl u 137.It Fl u
114Obtain an assertion using U2F. 138Obtain an assertion using U2F.
115By default, 139By default,
@@ -119,6 +143,10 @@ U2F otherwise.
119.It Fl v 143.It Fl v
120If obtaining an assertion, prompt the user for a PIN and request 144If obtaining an assertion, prompt the user for a PIN and request
121user verification from the authenticator. 145user verification from the authenticator.
146If verifying an assertion, check whether the user verification bit
147was signed by the authenticator.
148.El
149.Pp
122If a 150If a
123.Em tty 151.Em tty
124is available, 152is available,
@@ -127,9 +155,6 @@ will use it to obtain the PIN.
127Otherwise, 155Otherwise,
128.Em stdin 156.Em stdin
129is used. 157is used.
130If verifying an assertion, check whether the user verification bit
131was signed by the authenticator.
132.El
133.Sh INPUT FORMAT 158.Sh INPUT FORMAT
134The input of 159The input of
135.Nm 160.Nm
@@ -140,7 +165,7 @@ When obtaining an assertion,
140.Nm 165.Nm
141expects its input to consist of: 166expects its input to consist of:
142.Pp 167.Pp
143.Bl -enum -offset indent -compact 168.Bl -enum -offset indent -compact
144.It 169.It
145client data hash (base64 blob); 170client data hash (base64 blob);
146.It 171.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 @@
12.Nm 12.Nm
13.Fl M 13.Fl M
14.Op Fl dhqruv 14.Op Fl dhqruv
15.Op Fl c Ar cred_protect
15.Op Fl i Ar input_file 16.Op Fl i Ar input_file
16.Op Fl o Ar output_file 17.Op Fl o Ar output_file
17.Ar device 18.Ar device
@@ -19,6 +20,7 @@
19.Nm 20.Nm
20.Fl V 21.Fl V
21.Op Fl dhv 22.Op Fl dhv
23.Op Fl c Ar cred_protect
22.Op Fl i Ar input_file 24.Op Fl i Ar input_file
23.Op Fl o Ar output_file 25.Op Fl o Ar output_file
24.Op Ar type 26.Op Ar type
@@ -89,6 +91,12 @@ to make a new credential on
89Tells 91Tells
90.Nm 92.Nm
91to verify a credential. 93to verify a credential.
94.It Fl c Ar cred_protect
95If making a credential, set the credential's protection level to
96.Ar cred_protect .
97If verifying a credential, check whether the credential's protection
98level was signed by the authenticator as
99.Ar cred_protect .
92.It Fl d 100.It Fl d
93Causes 101Causes
94.Nm 102.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 @@
9.Nm fido_assert_new , 9.Nm fido_assert_new ,
10.Nm fido_assert_free , 10.Nm fido_assert_free ,
11.Nm fido_assert_count , 11.Nm fido_assert_count ,
12.Nm fido_assert_rp_id ,
12.Nm fido_assert_user_display_name , 13.Nm fido_assert_user_display_name ,
13.Nm fido_assert_user_icon , 14.Nm fido_assert_user_icon ,
14.Nm fido_assert_user_name , 15.Nm fido_assert_user_name ,
@@ -17,12 +18,15 @@
17.Nm fido_assert_hmac_secret_ptr , 18.Nm fido_assert_hmac_secret_ptr ,
18.Nm fido_assert_user_id_ptr , 19.Nm fido_assert_user_id_ptr ,
19.Nm fido_assert_sig_ptr , 20.Nm fido_assert_sig_ptr ,
21.Nm fido_assert_id_ptr ,
20.Nm fido_assert_authdata_len , 22.Nm fido_assert_authdata_len ,
21.Nm fido_assert_clientdata_hash_len , 23.Nm fido_assert_clientdata_hash_len ,
22.Nm fido_assert_hmac_secret_len , 24.Nm fido_assert_hmac_secret_len ,
23.Nm fido_assert_user_id_len , 25.Nm fido_assert_user_id_len ,
24.Nm fido_assert_sig_len , 26.Nm fido_assert_sig_len ,
25.Nm fido_assert_sigcount 27.Nm fido_assert_id_len ,
28.Nm fido_assert_sigcount ,
29.Nm fido_assert_flags
26.Nd FIDO 2 assertion API 30.Nd FIDO 2 assertion API
27.Sh SYNOPSIS 31.Sh SYNOPSIS
28.In fido.h 32.In fido.h
@@ -33,6 +37,8 @@
33.Ft size_t 37.Ft size_t
34.Fn fido_assert_count "const fido_assert_t *assert" 38.Fn fido_assert_count "const fido_assert_t *assert"
35.Ft const char * 39.Ft const char *
40.Fn fido_assert_rp_id "const fido_assert_t *assert"
41.Ft const char *
36.Fn fido_assert_user_display_name "const fido_assert_t *assert" "size_t idx" 42.Fn fido_assert_user_display_name "const fido_assert_t *assert" "size_t idx"
37.Ft const char * 43.Ft const char *
38.Fn fido_assert_user_icon "const fido_assert_t *assert" "size_t idx" 44.Fn fido_assert_user_icon "const fido_assert_t *assert" "size_t idx"
@@ -48,6 +54,8 @@
48.Fn fido_assert_user_id_ptr "const fido_assert_t *assert" "size_t idx" 54.Fn fido_assert_user_id_ptr "const fido_assert_t *assert" "size_t idx"
49.Ft const unsigned char * 55.Ft const unsigned char *
50.Fn fido_assert_sig_ptr "const fido_assert_t *assert" "size_t idx" 56.Fn fido_assert_sig_ptr "const fido_assert_t *assert" "size_t idx"
57.Ft const unsigned char *
58.Fn fido_assert_id_ptr "const fido_assert_t *assert" "size_t idx"
51.Ft size_t 59.Ft size_t
52.Fn fido_assert_authdata_len "const fido_assert_t *assert" "size_t idx" 60.Fn fido_assert_authdata_len "const fido_assert_t *assert" "size_t idx"
53.Ft size_t 61.Ft size_t
@@ -58,8 +66,12 @@
58.Fn fido_assert_user_id_len "const fido_assert_t *assert" "size_t idx" 66.Fn fido_assert_user_id_len "const fido_assert_t *assert" "size_t idx"
59.Ft size_t 67.Ft size_t
60.Fn fido_assert_sig_len "const fido_assert_t *assert" "size_t idx" 68.Fn fido_assert_sig_len "const fido_assert_t *assert" "size_t idx"
69.Ft size_t
70.Fn fido_assert_id_len "const fido_assert_t *assert" "size_t idx"
61.Ft uint32_t 71.Ft uint32_t
62.Fn fido_assert_sigcount "const fido_assert_t *assert" "size_t idx" 72.Fn fido_assert_sigcount "const fido_assert_t *assert" "size_t idx"
73.Ft uint8_t
74.Fn fido_assert_flags "const fido_assert_t *assert" "size_t idx"
63.Sh DESCRIPTION 75.Sh DESCRIPTION
64FIDO 2 assertions are abstracted in 76FIDO 2 assertions are abstracted in
65.Em libfido2 77.Em libfido2
@@ -110,6 +122,12 @@ function returns the number of statements in
110.Fa assert . 122.Fa assert .
111.Pp 123.Pp
112The 124The
125.Fn fido_assert_rp_id
126function returns a pointer to a NUL-terminated string holding the
127relying party ID of
128.Fa assert .
129.Pp
130The
113.Fn fido_assert_user_display_name , 131.Fn fido_assert_user_display_name ,
114.Fn fido_assert_user_icon , 132.Fn fido_assert_user_icon ,
115and 133and
@@ -126,10 +144,11 @@ The
126.Fn fido_assert_user_id_ptr , 144.Fn fido_assert_user_id_ptr ,
127.Fn fido_assert_authdata_ptr , 145.Fn fido_assert_authdata_ptr ,
128.Fn fido_assert_hmac_secret_ptr , 146.Fn fido_assert_hmac_secret_ptr ,
147.Fn fido_assert_sig_ptr ,
129and 148and
130.Fn fido_assert_sig_ptr 149.Fn fido_assert_id_ptr
131functions return pointers to the user ID, authenticator data, 150functions return pointers to the user ID, authenticator data,
132hmac-secret, and signature attributes of statement 151hmac-secret, signature, and credential ID attributes of statement
133.Fa idx 152.Fa idx
134in 153in
135.Fa assert . 154.Fa assert .
@@ -137,8 +156,9 @@ The
137.Fn fido_assert_user_id_len , 156.Fn fido_assert_user_id_len ,
138.Fn fido_assert_authdata_len , 157.Fn fido_assert_authdata_len ,
139.Fn fido_assert_hmac_secret_len , 158.Fn fido_assert_hmac_secret_len ,
159.Fn fido_assert_sig_len ,
140and 160and
141.Fn fido_assert_sig_len 161.Fn fido_assert_id_len
142functions can be used to retrieve the corresponding length of a 162functions can be used to retrieve the corresponding length of a
143specific attribute. 163specific attribute.
144.Pp 164.Pp
@@ -149,6 +169,13 @@ function can be used to obtain the signature counter of statement
149in 169in
150.Fa assert . 170.Fa assert .
151.Pp 171.Pp
172The
173.Fn fido_assert_flags
174function returns the authenticator data flags of statement
175.Fa idx
176in
177.Fa assert .
178.Pp
152Please note that the first statement in 179Please note that the first statement in
153.Fa assert 180.Fa assert
154has an 181has 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 @@
21.Nm fido_cbor_info_versions_len , 21.Nm fido_cbor_info_versions_len ,
22.Nm fido_cbor_info_options_len , 22.Nm fido_cbor_info_options_len ,
23.Nm fido_cbor_info_maxmsgsiz , 23.Nm fido_cbor_info_maxmsgsiz ,
24.Nm fido_cbor_info_maxcredcntlst ,
25.Nm fido_cbor_info_maxcredidlen ,
24.Nm fido_cbor_info_fwversion 26.Nm fido_cbor_info_fwversion
25.Nd FIDO 2 CBOR Info API 27.Nd FIDO 2 CBOR Info API
26.Sh SYNOPSIS 28.Sh SYNOPSIS
@@ -56,6 +58,10 @@
56.Ft uint64_t 58.Ft uint64_t
57.Fn fido_cbor_info_maxmsgsiz "const fido_cbor_info_t *ci" 59.Fn fido_cbor_info_maxmsgsiz "const fido_cbor_info_t *ci"
58.Ft uint64_t 60.Ft uint64_t
61.Fn fido_cbor_info_maxcredcntlst "const fido_cbor_info_t *ci"
62.Ft uint64_t
63.Fn fido_cbor_info_maxcredidlen "const fido_cbor_info_t *ci"
64.Ft uint64_t
59.Fn fido_cbor_info_fwversion "const fido_cbor_info_t *ci" 65.Fn fido_cbor_info_fwversion "const fido_cbor_info_t *ci"
60.Sh DESCRIPTION 66.Sh DESCRIPTION
61The 67The
@@ -103,8 +109,8 @@ The
103.Fn fido_cbor_info_protocols_ptr , 109.Fn fido_cbor_info_protocols_ptr ,
104and 110and
105.Fn fido_cbor_info_versions_ptr 111.Fn fido_cbor_info_versions_ptr
106functions return pointers to the AAGUID, supported extensions, 112functions return pointers to the authenticator attestation GUID,
107PIN protocol and CTAP version strings of 113supported extensions, PIN protocol and CTAP version strings of
108.Fa ci . 114.Fa ci .
109The corresponding length of a given attribute can be 115The corresponding length of a given attribute can be
110obtained by 116obtained by
@@ -131,6 +137,18 @@ function returns the maximum message size attribute of
131.Fa ci . 137.Fa ci .
132.Pp 138.Pp
133The 139The
140.Fn fido_cbor_info_maxcredcntlst
141function returns the maximum supported number of credentials in
142a single credential ID list as reported in
143.Fa ci .
144.Pp
145The
146.Fn fido_cbor_info_maxcredidlen
147function returns the maximum supported length of a credential ID
148as reported in
149.Fa ci .
150.Pp
151The
134.Fn fido_cbor_info_fwversion 152.Fn fido_cbor_info_fwversion
135function returns the firmware version attribute of 153function returns the firmware version attribute of
136.Fa ci . 154.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 @@
10.Nm fido_cred_free , 10.Nm fido_cred_free ,
11.Nm fido_cred_prot , 11.Nm fido_cred_prot ,
12.Nm fido_cred_fmt , 12.Nm fido_cred_fmt ,
13.Nm fido_cred_rp_id ,
14.Nm fido_cred_rp_name ,
15.Nm fido_cred_user_name ,
16.Nm fido_cred_display_name ,
13.Nm fido_cred_authdata_ptr , 17.Nm fido_cred_authdata_ptr ,
14.Nm fido_cred_clientdata_hash_ptr , 18.Nm fido_cred_clientdata_hash_ptr ,
15.Nm fido_cred_id_ptr , 19.Nm fido_cred_id_ptr ,
20.Nm fido_cred_aaguid_ptr ,
16.Nm fido_cred_pubkey_ptr , 21.Nm fido_cred_pubkey_ptr ,
17.Nm fido_cred_sig_ptr , 22.Nm fido_cred_sig_ptr ,
23.Nm fido_cred_user_id_ptr ,
18.Nm fido_cred_x5c_ptr , 24.Nm fido_cred_x5c_ptr ,
19.Nm fido_cred_authdata_len , 25.Nm fido_cred_authdata_len ,
20.Nm fido_cred_clientdata_hash_len , 26.Nm fido_cred_clientdata_hash_len ,
21.Nm fido_cred_id_len , 27.Nm fido_cred_id_len ,
28.Nm fido_cred_aaguid_len ,
22.Nm fido_cred_pubkey_len , 29.Nm fido_cred_pubkey_len ,
23.Nm fido_cred_sig_len , 30.Nm fido_cred_sig_len ,
24.Nm fido_cred_x5c_len 31.Nm fido_cred_user_id_len ,
32.Nm fido_cred_x5c_len ,
33.Nm fido_cred_type ,
34.Nm fido_cred_flags
25.Nd FIDO 2 credential API 35.Nd FIDO 2 credential API
26.Sh SYNOPSIS 36.Sh SYNOPSIS
27.In fido.h 37.In fido.h
@@ -33,6 +43,14 @@
33.Fn fido_cred_prot "fido_cred_t *cred" 43.Fn fido_cred_prot "fido_cred_t *cred"
34.Ft const char * 44.Ft const char *
35.Fn fido_cred_fmt "const fido_cred_t *cred" 45.Fn fido_cred_fmt "const fido_cred_t *cred"
46.Ft const char *
47.Fn fido_cred_rp_id "const fido_cred_t *cred"
48.Ft const char *
49.Fn fido_cred_rp_name "const fido_cred_t *cred"
50.Ft const char *
51.Fn fido_cred_user_name "const fido_cred_t *cred"
52.Ft const char *
53.Fn fido_cred_display_name "const fido_cred_t *cred"
36.Ft const unsigned char * 54.Ft const unsigned char *
37.Fn fido_cred_authdata_ptr "const fido_cred_t *cred" 55.Fn fido_cred_authdata_ptr "const fido_cred_t *cred"
38.Ft const unsigned char * 56.Ft const unsigned char *
@@ -40,10 +58,14 @@
40.Ft const unsigned char * 58.Ft const unsigned char *
41.Fn fido_cred_id_ptr "const fido_cred_t *cred" 59.Fn fido_cred_id_ptr "const fido_cred_t *cred"
42.Ft const unsigned char * 60.Ft const unsigned char *
61.Fn fido_cred_aaguid_ptr "const fido_cred_t *cred"
62.Ft const unsigned char *
43.Fn fido_cred_pubkey_ptr "const fido_cred_t *cred" 63.Fn fido_cred_pubkey_ptr "const fido_cred_t *cred"
44.Ft const unsigned char * 64.Ft const unsigned char *
45.Fn fido_cred_sig_ptr "const fido_cred_t *cred" 65.Fn fido_cred_sig_ptr "const fido_cred_t *cred"
46.Ft const unsigned char * 66.Ft const unsigned char *
67.Fn fido_cred_user_id_ptr "const fido_cred_t *cred"
68.Ft const unsigned char *
47.Fn fido_cred_x5c_ptr "const fido_cred_t *cred" 69.Fn fido_cred_x5c_ptr "const fido_cred_t *cred"
48.Ft size_t 70.Ft size_t
49.Fn fido_cred_authdata_len "const fido_cred_t *cred" 71.Fn fido_cred_authdata_len "const fido_cred_t *cred"
@@ -52,11 +74,19 @@
52.Ft size_t 74.Ft size_t
53.Fn fido_cred_id_len "const fido_cred_t *cred" 75.Fn fido_cred_id_len "const fido_cred_t *cred"
54.Ft size_t 76.Ft size_t
77.Fn fido_cred_aaguid_len "const fido_cred_t *cred"
78.Ft size_t
55.Fn fido_cred_pubkey_len "const fido_cred_t *cred" 79.Fn fido_cred_pubkey_len "const fido_cred_t *cred"
56.Ft size_t 80.Ft size_t
57.Fn fido_cred_sig_len "const fido_cred_t *cred" 81.Fn fido_cred_sig_len "const fido_cred_t *cred"
58.Ft size_t 82.Ft size_t
83.Fn fido_cred_user_id_len "const fido_cred_t *cred"
84.Ft size_t
59.Fn fido_cred_x5c_len "const fido_cred_t *cred" 85.Fn fido_cred_x5c_len "const fido_cred_t *cred"
86.Ft int
87.Fn fido_cred_type "const fido_cred_t *cred"
88.Ft uint8_t
89.Fn fido_cred_flags "const fido_cred_t *cred"
60.Sh DESCRIPTION 90.Sh DESCRIPTION
61FIDO 2 credentials are abstracted in 91FIDO 2 credentials are abstracted in
62.Em libfido2 92.Em libfido2
@@ -120,15 +150,30 @@ or NULL if
120does not have a format set. 150does not have a format set.
121.Pp 151.Pp
122The 152The
153.Fn fido_cred_rp_id ,
154.Fn fido_cred_rp_name ,
155.Fn fido_cred_user_name ,
156and
157.Fn fido_cred_display_name
158functions return pointers to NUL-terminated strings holding the
159relying party ID, relying party name, user name, and user display
160name attributes of
161.Fa cred ,
162or NULL if the respective entry is not set.
163.Pp
164The
123.Fn fido_cred_authdata_ptr , 165.Fn fido_cred_authdata_ptr ,
124.Fn fido_cred_clientdata_hash_ptr , 166.Fn fido_cred_clientdata_hash_ptr ,
125.Fn fido_cred_id_ptr , 167.Fn fido_cred_id_ptr ,
168.Fn fido_cred_aaguid_ptr ,
126.Fn fido_cred_pubkey_ptr , 169.Fn fido_cred_pubkey_ptr ,
127.Fn fido_cred_sig_ptr , 170.Fn fido_cred_sig_ptr ,
171.Fn fido_cred_user_id_ptr ,
128and 172and
129.Fn fido_cred_x5c_ptr 173.Fn fido_cred_x5c_ptr
130functions return pointers to the authenticator data, client data 174functions return pointers to the authenticator data, client data
131hash, ID, public key, signature and x509 certificate parts of 175hash, ID, authenticator attestation GUID, public key, signature,
176user ID, and x509 certificate parts of
132.Fa cred , 177.Fa cred ,
133or NULL if the respective entry is not set. 178or NULL if the respective entry is not set.
134.Pp 179.Pp
@@ -136,12 +181,25 @@ The corresponding length can be obtained by
136.Fn fido_cred_authdata_len , 181.Fn fido_cred_authdata_len ,
137.Fn fido_cred_clientdata_hash_len , 182.Fn fido_cred_clientdata_hash_len ,
138.Fn fido_cred_id_len , 183.Fn fido_cred_id_len ,
184.Fn fido_cred_aaguid_len ,
139.Fn fido_cred_pubkey_len , 185.Fn fido_cred_pubkey_len ,
186.Fn fido_cred_sig_len ,
187.Fn fido_cred_user_id_len ,
140and 188and
141.Fn fido_cred_sig_len . 189.Fn fido_cred_x5c_len .
142.Pp 190.Pp
143The authenticator data, x509 certificate, and signature parts of a 191The authenticator data, x509 certificate, and signature parts of a
144credential are typically passed to a FIDO 2 server for verification. 192credential are typically passed to a FIDO 2 server for verification.
193.Pp
194The
195.Fn fido_cred_type
196function returns the COSE algorithm of
197.Fa cred .
198.Pp
199The
200.Fn fido_cred_flags
201function returns the authenticator data flags of
202.Fa cred .
145.Sh RETURN VALUES 203.Sh RETURN VALUES
146The authenticator data returned by 204The authenticator data returned by
147.Fn fido_cred_authdata_ptr 205.Fn fido_cred_authdata_ptr
@@ -152,6 +210,7 @@ If not NULL, pointers returned by
152.Fn fido_cred_authdata_ptr , 210.Fn fido_cred_authdata_ptr ,
153.Fn fido_cred_clientdata_hash_ptr , 211.Fn fido_cred_clientdata_hash_ptr ,
154.Fn fido_cred_id_ptr , 212.Fn fido_cred_id_ptr ,
213.Fn fido_cred_aaguid_ptr ,
155.Fn fido_cred_pubkey_ptr , 214.Fn fido_cred_pubkey_ptr ,
156.Fn fido_cred_sig_ptr , 215.Fn fido_cred_sig_ptr ,
157and 216and
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 @@
1.\" Copyright (c) 2020 Yubico AB. All rights reserved.
2.\" Use of this source code is governed by a BSD-style
3.\" license that can be found in the LICENSE file.
4.\"
5.Dd $Mdocdate: August 5 2020 $
6.Dt FIDO_DEV_GET_TOUCH_BEGIN 3
7.Os
8.Sh NAME
9.Nm fido_dev_get_touch_begin ,
10.Nm fido_dev_get_touch_status
11.Nd asynchronously wait for touch on a FIDO 2 authenticator
12.Sh SYNOPSIS
13.In fido.h
14.Ft int
15.Fn fido_dev_get_touch_begin "fido_dev_t *dev"
16.Ft int
17.Fn fido_dev_get_touch_status "fido_dev_t *dev" "int *touched" "int ms"
18.Sh DESCRIPTION
19The functions described in this page allow an application to
20asynchronously wait for touch on a FIDO authenticator.
21This is useful when multiple authenticators are present and
22the application needs to know which one to use.
23.Pp
24The
25.Fn fido_dev_get_touch_begin
26function initiates a touch request on
27.Fa dev .
28.Pp
29The
30.Fn fido_dev_get_touch_status
31function continues an ongoing touch request on
32.Fa dev ,
33blocking up to
34.Fa ms
35milliseconds.
36On success,
37.Fa touched
38will be updated to reflect the touch request status.
39If
40.Fa touched
41is 1, the device was touched, and the touch request is
42terminated.
43If
44.Fa touched
45is 0, the application may call
46.Fn fido_dev_get_touch_status
47to continue the touch request, or
48.Fn fido_dev_cancel
49to terminate it.
50.Sh RETURN VALUES
51The error codes returned by
52.Fn fido_dev_get_touch_begin
53and
54.Fn fido_dev_get_touch_status
55are defined in
56.In fido/err.h .
57On success,
58.Dv FIDO_OK
59is returned.
60.Sh EXAMPLES
61Please refer to
62.Em examples/select.c
63in
64.Em libfido2's
65source tree.
66.Sh SEE ALSO
67.Xr fido_dev_cancel 3
68.Sh CAVEATS
69The
70.Fn fido_dev_get_touch_status
71function will cause a command to be transmitted to U2F
72authenticators.
73These 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 @@
14.Nm fido_dev_force_fido2 , 14.Nm fido_dev_force_fido2 ,
15.Nm fido_dev_force_u2f , 15.Nm fido_dev_force_u2f ,
16.Nm fido_dev_is_fido2 , 16.Nm fido_dev_is_fido2 ,
17.Nm fido_dev_supports_cred_prot ,
18.Nm fido_dev_supports_pin ,
19.Nm fido_dev_has_pin ,
17.Nm fido_dev_protocol , 20.Nm fido_dev_protocol ,
18.Nm fido_dev_build , 21.Nm fido_dev_build ,
19.Nm fido_dev_flags , 22.Nm fido_dev_flags ,
@@ -38,6 +41,12 @@
38.Fn fido_dev_force_u2f "fido_dev_t *dev" 41.Fn fido_dev_force_u2f "fido_dev_t *dev"
39.Ft bool 42.Ft bool
40.Fn fido_dev_is_fido2 "const fido_dev_t *dev" 43.Fn fido_dev_is_fido2 "const fido_dev_t *dev"
44.Ft bool
45.Fn fido_dev_supports_cred_prot "const fido_dev_t *dev"
46.Ft bool
47.Fn fido_dev_supports_pin "const fido_dev_t *dev"
48.Ft bool
49.Fn fido_dev_has_pin "const fido_dev_t *dev"
41.Ft uint8_t 50.Ft uint8_t
42.Fn fido_dev_protocol "const fido_dev_t *dev" 51.Fn fido_dev_protocol "const fido_dev_t *dev"
43.Ft uint8_t 52.Ft uint8_t
@@ -117,6 +126,30 @@ if
117is a FIDO 2 device. 126is a FIDO 2 device.
118.Pp 127.Pp
119The 128The
129.Fn fido_dev_supports_cred_prot
130function returns
131.Dv true
132if
133.Fa dev
134supports FIDO 2.1 Credential Protection.
135.Pp
136The
137.Fn fido_dev_supports_pin
138function returns
139.Dv true
140if
141.Fa dev
142supports FIDO 2.0 Client PINs.
143.Pp
144The
145.Fn fido_dev_has_pin
146function returns
147.Dv true
148if
149.Fa dev
150has a FIDO 2.0 Client PIN set.
151.Pp
152The
120.Fn fido_dev_protocol 153.Fn fido_dev_protocol
121function returns the CTAPHID protocol version identifier of 154function returns the CTAPHID protocol version identifier of
122.Fa dev . 155.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 @@
1/*
2 * Copyright (c) 2020 Yubico AB. All rights reserved.
3 * Use of this source code is governed by a BSD-style
4 * license that can be found in the LICENSE file.
5 */
6
7#include "openbsd-compat.h"
8
9#if !defined(HAVE_CLOCK_GETTIME)
10
11#if _WIN32
12int
13clock_gettime(clockid_t clock_id, struct timespec *tp)
14{
15 ULONGLONG ms;
16
17 if (clock_id != CLOCK_MONOTONIC) {
18 errno = EINVAL;
19 return (-1);
20 }
21
22 ms = GetTickCount64();
23 tp->tv_sec = ms / 1000L;
24 tp->tv_nsec = (ms % 1000L) * 1000000L;
25
26 return (0);
27}
28#else
29#error "please provide an implementation of clock_gettime() for your platform"
30#endif /* _WIN32 */
31
32#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 @@
1#!/bin/bash -u
2
3# Copyright (c) 2019 Yubico AB. All rights reserved.
4# Use of this source code is governed by a BSD-style
5# license that can be found in the LICENSE file.
6
7OPENSSH=$(realpath ../../openssh)
8LIBRESSL=$(realpath ../../libressl-2.8.3)
9[[ ! -d "${OPENSSH}" || ! -d "${LIBRESSL}" ]] && exit 1
10
11diff -pu bsd-getpagesize.c ${OPENSSH}/openbsd-compat/bsd-getpagesize.c
12diff -pu err.h ${LIBRESSL}/include/compat/err.h
13diff -pu explicit_bzero.c ${OPENSSH}/openbsd-compat/explicit_bzero.c
14diff -pu explicit_bzero_win32.c ${LIBRESSL}/crypto/compat/explicit_bzero_win.c
15diff -pu getopt.h ${OPENSSH}/openbsd-compat/getopt.h
16diff -pu getopt_long.c ${OPENSSH}/openbsd-compat/getopt_long.c
17diff -pu posix_win.c ${LIBRESSL}/crypto/compat/posix_win.c
18diff -pu readpassphrase.c ${OPENSSH}/openbsd-compat/readpassphrase.c
19diff -pu readpassphrase.h ${OPENSSH}/openbsd-compat/readpassphrase.h
20diff -pu recallocarray.c ${OPENSSH}/openbsd-compat/recallocarray.c
21diff -pu strlcat.c ${OPENSSH}/openbsd-compat/strlcat.c
22diff -pu strlcpy.c ${OPENSSH}/openbsd-compat/strlcpy.c
23diff -pu timingsafe_bcmp.c ${OPENSSH}/openbsd-compat/timingsafe_bcmp.c
24diff -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);
90ssize_t getline(char **, size_t *, FILE *); 90ssize_t getline(char **, size_t *, FILE *);
91#endif 91#endif
92 92
93#include "time.h"
94
93#endif /* !_OPENBSD_COMPAT_H */ 95#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 @@
1/*
2 * Public domain
3 * sys/time.h compatibility shim
4 */
5
6#if defined(_MSC_VER) && (_MSC_VER >= 1900)
7#include <../ucrt/time.h>
8#elif defined(_MSC_VER) && (_MSC_VER < 1900)
9#include <../include/time.h>
10#else
11#include <time.h>
12#endif
13
14#ifndef _COMPAT_TIME_H
15#define _COMPAT_TIME_H
16
17#ifndef CLOCK_MONOTONIC
18#define CLOCK_MONOTONIC CLOCK_REALTIME
19#endif
20
21#ifndef CLOCK_REALTIME
22#define CLOCK_REALTIME 0
23#endif
24
25#ifndef HAVE_CLOCK_GETTIME
26typedef int clockid_t;
27int clock_gettime(clockid_t, struct timespec *);
28#endif
29
30#ifdef HAVE_TIMESPECSUB
31#include <sys/time.h>
32#endif
33
34#ifndef HAVE_TIMESPECSUB
35#define timespecsub(tsp, usp, vsp) \
36 do { \
37 (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \
38 (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \
39 if ((vsp)->tv_nsec < 0) { \
40 (vsp)->tv_sec--; \
41 (vsp)->tv_nsec += 1000000000L; \
42 } \
43 } while (0)
44#endif
45
46#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;
23#endif 23#endif
24 24
25#ifdef _MSC_VER 25#ifdef _MSC_VER
26typedef unsigned char u_char;
27typedef unsigned short u_short;
28typedef unsigned int u_int;
29typedef uint32_t in_addr_t;
30typedef uint32_t mode_t;
31typedef uint32_t uid_t;
32
33#include <basetsd.h> 26#include <basetsd.h>
34typedef SSIZE_T ssize_t; 27typedef SSIZE_T ssize_t;
35 28
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)
160} 160}
161 161
162static void 162static void
163empty_assert(fido_dev_t *d, fido_assert_t *a, int idx) 163empty_assert(fido_dev_t *d, fido_assert_t *a, size_t idx)
164{ 164{
165 es256_pk_t *es256; 165 es256_pk_t *es256;
166 rs256_pk_t *rs256; 166 rs256_pk_t *rs256;
@@ -187,21 +187,21 @@ empty_assert(fido_dev_t *d, fido_assert_t *a, int idx)
187 fido_dev_force_u2f(d); 187 fido_dev_force_u2f(d);
188 assert(fido_dev_get_assert(d, a, NULL) == FIDO_ERR_INVALID_ARGUMENT); 188 assert(fido_dev_get_assert(d, a, NULL) == FIDO_ERR_INVALID_ARGUMENT);
189 assert(fido_dev_get_assert(d, a, "") == FIDO_ERR_INVALID_ARGUMENT); 189 assert(fido_dev_get_assert(d, a, "") == FIDO_ERR_INVALID_ARGUMENT);
190 assert(fido_assert_verify(a, COSE_ES256, idx, 190 assert(fido_assert_verify(a, idx, COSE_ES256,
191 NULL) == FIDO_ERR_INVALID_ARGUMENT); 191 NULL) == FIDO_ERR_INVALID_ARGUMENT);
192 assert(fido_assert_verify(a, COSE_ES256, idx, 192 assert(fido_assert_verify(a, idx, COSE_ES256,
193 es256) == FIDO_ERR_INVALID_ARGUMENT); 193 es256) == FIDO_ERR_INVALID_ARGUMENT);
194 assert(fido_assert_verify(a, COSE_RS256, idx, 194 assert(fido_assert_verify(a, idx, COSE_RS256,
195 rs256) == FIDO_ERR_INVALID_ARGUMENT); 195 rs256) == FIDO_ERR_INVALID_ARGUMENT);
196 196
197 fido_dev_force_fido2(d); 197 fido_dev_force_fido2(d);
198 assert(fido_dev_get_assert(d, a, NULL) == FIDO_ERR_INVALID_ARGUMENT); 198 assert(fido_dev_get_assert(d, a, NULL) == FIDO_ERR_INVALID_ARGUMENT);
199 assert(fido_dev_get_assert(d, a, "") == FIDO_ERR_INVALID_ARGUMENT); 199 assert(fido_dev_get_assert(d, a, "") == FIDO_ERR_INVALID_ARGUMENT);
200 assert(fido_assert_verify(a, COSE_ES256, idx, 200 assert(fido_assert_verify(a, idx, COSE_ES256,
201 NULL) == FIDO_ERR_INVALID_ARGUMENT); 201 NULL) == FIDO_ERR_INVALID_ARGUMENT);
202 assert(fido_assert_verify(a, COSE_ES256, idx, 202 assert(fido_assert_verify(a, idx, COSE_ES256,
203 es256) == FIDO_ERR_INVALID_ARGUMENT); 203 es256) == FIDO_ERR_INVALID_ARGUMENT);
204 assert(fido_assert_verify(a, COSE_RS256, idx, 204 assert(fido_assert_verify(a, idx, COSE_RS256,
205 rs256) == FIDO_ERR_INVALID_ARGUMENT); 205 rs256) == FIDO_ERR_INVALID_ARGUMENT);
206 206
207 free_es256_pk(es256); 207 free_es256_pk(es256);
@@ -214,7 +214,7 @@ empty_assert_tests(void)
214 fido_assert_t *a; 214 fido_assert_t *a;
215 fido_dev_t *d; 215 fido_dev_t *d;
216 fido_dev_io_t io_f; 216 fido_dev_io_t io_f;
217 int i; 217 size_t i;
218 218
219 memset(&io_f, 0, sizeof(io_f)); 219 memset(&io_f, 0, sizeof(io_f));
220 220
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] = {
231 0x34, 0xe3, 0x83, 0xe7, 0xd1, 0xbd, 0x9f, 0x25, 231 0x34, 0xe3, 0x83, 0xe7, 0xd1, 0xbd, 0x9f, 0x25,
232}; 232};
233 233
234/*
235 * Security Key By Yubico
236 * 5.1.X
237 * f8a011f3-8c0a-4d15-8006-17111f9edc7d
238*/
239const unsigned char aaguid[16] = {
240 0xf8, 0xa0, 0x11, 0xf3, 0x8c, 0x0a, 0x4d, 0x15,
241 0x80, 0x06, 0x17, 0x11, 0x1f, 0x9e, 0xdc, 0x7d,
242};
243
234const char rp_id[] = "localhost"; 244const char rp_id[] = "localhost";
235const char rp_name[] = "sweet home localhost"; 245const char rp_name[] = "sweet home localhost";
236 246
@@ -323,6 +333,7 @@ empty_cred(void)
323 assert(fido_cred_fmt(c) == NULL); 333 assert(fido_cred_fmt(c) == NULL);
324 assert(fido_cred_id_len(c) == 0); 334 assert(fido_cred_id_len(c) == 0);
325 assert(fido_cred_id_ptr(c) == NULL); 335 assert(fido_cred_id_ptr(c) == NULL);
336 assert(fido_cred_prot(c) == 0);
326 assert(fido_cred_pubkey_len(c) == 0); 337 assert(fido_cred_pubkey_len(c) == 0);
327 assert(fido_cred_pubkey_ptr(c) == NULL); 338 assert(fido_cred_pubkey_ptr(c) == NULL);
328 assert(fido_cred_rp_id(c) == NULL); 339 assert(fido_cred_rp_id(c) == NULL);
@@ -374,10 +385,13 @@ valid_cred(void)
374 assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK); 385 assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK);
375 assert(fido_cred_set_fmt(c, "packed") == FIDO_OK); 386 assert(fido_cred_set_fmt(c, "packed") == FIDO_OK);
376 assert(fido_cred_verify(c) == FIDO_OK); 387 assert(fido_cred_verify(c) == FIDO_OK);
388 assert(fido_cred_prot(c) == 0);
377 assert(fido_cred_pubkey_len(c) == sizeof(pubkey)); 389 assert(fido_cred_pubkey_len(c) == sizeof(pubkey));
378 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); 390 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
379 assert(fido_cred_id_len(c) == sizeof(id)); 391 assert(fido_cred_id_len(c) == sizeof(id));
380 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); 392 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
393 assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
394 assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
381 free_cred(c); 395 free_cred(c);
382} 396}
383 397
@@ -400,6 +414,8 @@ no_cdh(void)
400 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); 414 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
401 assert(fido_cred_id_len(c) == sizeof(id)); 415 assert(fido_cred_id_len(c) == sizeof(id));
402 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); 416 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
417 assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
418 assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
403 free_cred(c); 419 free_cred(c);
404} 420}
405 421
@@ -422,6 +438,8 @@ no_rp_id(void)
422 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); 438 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
423 assert(fido_cred_id_len(c) == sizeof(id)); 439 assert(fido_cred_id_len(c) == sizeof(id));
424 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); 440 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
441 assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
442 assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
425 free_cred(c); 443 free_cred(c);
426} 444}
427 445
@@ -445,6 +463,8 @@ no_rp_name(void)
445 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); 463 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
446 assert(fido_cred_id_len(c) == sizeof(id)); 464 assert(fido_cred_id_len(c) == sizeof(id));
447 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); 465 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
466 assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
467 assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
448 free_cred(c); 468 free_cred(c);
449} 469}
450 470
@@ -452,6 +472,10 @@ static void
452no_authdata(void) 472no_authdata(void)
453{ 473{
454 fido_cred_t *c; 474 fido_cred_t *c;
475 unsigned char *unset;
476
477 unset = calloc(1, sizeof(aaguid));
478 assert(unset != NULL);
455 479
456 c = alloc_cred(); 480 c = alloc_cred();
457 assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK); 481 assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
@@ -467,7 +491,10 @@ no_authdata(void)
467 assert(fido_cred_pubkey_ptr(c) == NULL); 491 assert(fido_cred_pubkey_ptr(c) == NULL);
468 assert(fido_cred_id_len(c) == 0); 492 assert(fido_cred_id_len(c) == 0);
469 assert(fido_cred_id_ptr(c) == NULL); 493 assert(fido_cred_id_ptr(c) == NULL);
494 assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
495 assert(memcmp(fido_cred_aaguid_ptr(c), unset, sizeof(aaguid)) == 0);
470 free_cred(c); 496 free_cred(c);
497 free(unset);
471} 498}
472 499
473static void 500static void
@@ -489,6 +516,8 @@ no_x509(void)
489 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); 516 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
490 assert(fido_cred_id_len(c) == sizeof(id)); 517 assert(fido_cred_id_len(c) == sizeof(id));
491 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); 518 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
519 assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
520 assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
492 free_cred(c); 521 free_cred(c);
493} 522}
494 523
@@ -511,6 +540,8 @@ no_sig(void)
511 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); 540 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
512 assert(fido_cred_id_len(c) == sizeof(id)); 541 assert(fido_cred_id_len(c) == sizeof(id));
513 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); 542 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
543 assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
544 assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
514 free_cred(c); 545 free_cred(c);
515} 546}
516 547
@@ -533,6 +564,8 @@ no_fmt(void)
533 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); 564 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
534 assert(fido_cred_id_len(c) == sizeof(id)); 565 assert(fido_cred_id_len(c) == sizeof(id));
535 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); 566 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
567 assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
568 assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
536 free_cred(c); 569 free_cred(c);
537} 570}
538 571
@@ -556,6 +589,8 @@ wrong_options(void)
556 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); 589 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
557 assert(fido_cred_id_len(c) == sizeof(id)); 590 assert(fido_cred_id_len(c) == sizeof(id));
558 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); 591 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
592 assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
593 assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
559 free_cred(c); 594 free_cred(c);
560} 595}
561 596
@@ -585,6 +620,8 @@ junk_cdh(void)
585 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); 620 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
586 assert(fido_cred_id_len(c) == sizeof(id)); 621 assert(fido_cred_id_len(c) == sizeof(id));
587 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); 622 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
623 assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
624 assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
588 free_cred(c); 625 free_cred(c);
589 free(junk); 626 free(junk);
590} 627}
@@ -609,6 +646,8 @@ junk_rp_id(void)
609 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); 646 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
610 assert(fido_cred_id_len(c) == sizeof(id)); 647 assert(fido_cred_id_len(c) == sizeof(id));
611 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); 648 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
649 assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
650 assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
612 free_cred(c); 651 free_cred(c);
613} 652}
614 653
@@ -632,6 +671,8 @@ junk_rp_name(void)
632 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); 671 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
633 assert(fido_cred_id_len(c) == sizeof(id)); 672 assert(fido_cred_id_len(c) == sizeof(id));
634 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); 673 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
674 assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
675 assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
635 free_cred(c); 676 free_cred(c);
636} 677}
637 678
@@ -640,12 +681,16 @@ junk_authdata(void)
640{ 681{
641 fido_cred_t *c; 682 fido_cred_t *c;
642 unsigned char *junk; 683 unsigned char *junk;
684 unsigned char *unset;
643 685
644 junk = malloc(sizeof(authdata)); 686 junk = malloc(sizeof(authdata));
645 assert(junk != NULL); 687 assert(junk != NULL);
646 memcpy(junk, authdata, sizeof(authdata)); 688 memcpy(junk, authdata, sizeof(authdata));
647 junk[0] = ~junk[0]; 689 junk[0] = ~junk[0];
648 690
691 unset = calloc(1, sizeof(aaguid));
692 assert(unset != NULL);
693
649 c = alloc_cred(); 694 c = alloc_cred();
650 assert(fido_cred_set_authdata(c, junk, 695 assert(fido_cred_set_authdata(c, junk,
651 sizeof(authdata)) == FIDO_ERR_INVALID_ARGUMENT); 696 sizeof(authdata)) == FIDO_ERR_INVALID_ARGUMENT);
@@ -663,9 +708,12 @@ junk_authdata(void)
663 assert(fido_cred_sig_ptr(c) == NULL); 708 assert(fido_cred_sig_ptr(c) == NULL);
664 assert(fido_cred_x5c_len(c) == 0); 709 assert(fido_cred_x5c_len(c) == 0);
665 assert(fido_cred_x5c_ptr(c) == NULL); 710 assert(fido_cred_x5c_ptr(c) == NULL);
711 assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
712 assert(memcmp(fido_cred_aaguid_ptr(c), unset, sizeof(aaguid)) == 0);
666 assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT); 713 assert(fido_cred_verify(c) == FIDO_ERR_INVALID_ARGUMENT);
667 free_cred(c); 714 free_cred(c);
668 free(junk); 715 free(junk);
716 free(unset);
669} 717}
670 718
671static void 719static void
@@ -694,6 +742,8 @@ junk_sig(void)
694 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); 742 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
695 assert(fido_cred_id_len(c) == sizeof(id)); 743 assert(fido_cred_id_len(c) == sizeof(id));
696 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); 744 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
745 assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
746 assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
697 free_cred(c); 747 free_cred(c);
698 free(junk); 748 free(junk);
699} 749}
@@ -724,6 +774,8 @@ junk_x509(void)
724 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0); 774 assert(memcmp(fido_cred_pubkey_ptr(c), pubkey, sizeof(pubkey)) == 0);
725 assert(fido_cred_id_len(c) == sizeof(id)); 775 assert(fido_cred_id_len(c) == sizeof(id));
726 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0); 776 assert(memcmp(fido_cred_id_ptr(c), id, sizeof(id)) == 0);
777 assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
778 assert(memcmp(fido_cred_aaguid_ptr(c), aaguid, sizeof(aaguid)) == 0);
727 free_cred(c); 779 free_cred(c);
728 free(junk); 780 free(junk);
729} 781}
@@ -733,6 +785,10 @@ static void
733invalid_type(void) 785invalid_type(void)
734{ 786{
735 fido_cred_t *c; 787 fido_cred_t *c;
788 unsigned char *unset;
789
790 unset = calloc(1, sizeof(aaguid));
791 assert(unset != NULL);
736 792
737 c = alloc_cred(); 793 c = alloc_cred();
738 assert(fido_cred_set_type(c, COSE_RS256) == FIDO_OK); 794 assert(fido_cred_set_type(c, COSE_RS256) == FIDO_OK);
@@ -749,7 +805,10 @@ invalid_type(void)
749 assert(fido_cred_pubkey_ptr(c) == NULL); 805 assert(fido_cred_pubkey_ptr(c) == NULL);
750 assert(fido_cred_id_len(c) == 0); 806 assert(fido_cred_id_len(c) == 0);
751 assert(fido_cred_id_ptr(c) == NULL); 807 assert(fido_cred_id_ptr(c) == NULL);
808 assert(fido_cred_aaguid_len(c) == sizeof(aaguid));
809 assert(memcmp(fido_cred_aaguid_ptr(c), unset, sizeof(aaguid)) == 0);
752 free_cred(c); 810 free_cred(c);
811 free(unset);
753} 812}
754 813
755/* cbor_serialize_alloc misuse */ 814/* cbor_serialize_alloc misuse */
@@ -789,6 +848,24 @@ unsorted_keys(void)
789 free_cred(c); 848 free_cred(c);
790} 849}
791 850
851static void
852wrong_credprot(void)
853{
854 fido_cred_t *c;
855
856 c = alloc_cred();
857 assert(fido_cred_set_type(c, COSE_ES256) == FIDO_OK);
858 assert(fido_cred_set_clientdata_hash(c, cdh, sizeof(cdh)) == FIDO_OK);
859 assert(fido_cred_set_rp(c, rp_id, rp_name) == FIDO_OK);
860 assert(fido_cred_set_x509(c, x509, sizeof(x509)) == FIDO_OK);
861 assert(fido_cred_set_sig(c, sig, sizeof(sig)) == FIDO_OK);
862 assert(fido_cred_set_fmt(c, "packed") == FIDO_OK);
863 assert(fido_cred_set_prot(c, FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID) == FIDO_OK);
864 assert(fido_cred_set_authdata(c, authdata, sizeof(authdata)) == FIDO_OK);
865 assert(fido_cred_verify(c) == FIDO_ERR_INVALID_PARAM);
866 free_cred(c);
867}
868
792int 869int
793main(void) 870main(void)
794{ 871{
@@ -814,6 +891,7 @@ main(void)
814 bad_cbor_serialize(); 891 bad_cbor_serialize();
815 duplicate_keys(); 892 duplicate_keys();
816 unsorted_keys(); 893 unsorted_keys();
894 wrong_credprot();
817 895
818 exit(0); 896 exit(0);
819} 897}
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)
37endif() 37endif()
38 38
39if(USE_HIDAPI) 39if(USE_HIDAPI)
40 list(APPEND COMPAT_SOURCES hid_hidapi.c) 40 list(APPEND FIDO_SOURCES hid_hidapi.c)
41elseif(WIN32) 41elseif(WIN32)
42 list(APPEND COMPAT_SOURCES hid_win.c) 42 list(APPEND FIDO_SOURCES hid_win.c)
43elseif(APPLE) 43elseif(APPLE)
44 list(APPEND COMPAT_SOURCES hid_osx.c) 44 list(APPEND FIDO_SOURCES hid_osx.c)
45elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") 45elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
46 list(APPEND COMPAT_SOURCES hid_linux.c) 46 list(APPEND FIDO_SOURCES hid_linux.c)
47elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") 47elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
48 list(APPEND COMPAT_SOURCES hid_openbsd.c) 48 list(APPEND FIDO_SOURCES hid_openbsd.c)
49else() 49else()
50 message(FATAL_ERROR "please define a hid backend for your platform") 50 message(FATAL_ERROR "please define a hid backend for your platform")
51endif() 51endif()
52 52
53if(NOT MSVC)
54 set_source_files_properties(${FIDO_SOURCES} PROPERTIES COMPILE_FLAGS
55 "-Wconversion -Wsign-conversion")
56endif()
57
53list(APPEND COMPAT_SOURCES 58list(APPEND COMPAT_SOURCES
54 ../openbsd-compat/bsd-getpagesize.c 59 ../openbsd-compat/bsd-getpagesize.c
55 ../openbsd-compat/explicit_bzero.c 60 ../openbsd-compat/explicit_bzero.c
@@ -94,7 +99,7 @@ elseif(APPLE)
94 "-framework IOKit") 99 "-framework IOKit")
95endif() 100endif()
96set_target_properties(fido2_shared PROPERTIES OUTPUT_NAME fido2 101set_target_properties(fido2_shared PROPERTIES OUTPUT_NAME fido2
97 VERSION ${LIB_VERSION} SOVERSION ${LIB_SOVERSION}) 102 VERSION ${FIDO_VERSION} SOVERSION ${FIDO_MAJOR})
98install(TARGETS fido2_shared 103install(TARGETS fido2_shared
99 ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 104 ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
100 LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 105 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)
313 goto fail; 313 goto fail;
314 } 314 }
315 } 315 }
316 316
317 r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, -1); 317 r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, -1);
318 if (r == FIDO_OK && assert->ext & FIDO_EXT_HMAC_SECRET) 318 if (r == FIDO_OK && assert->ext & FIDO_EXT_HMAC_SECRET)
319 if (decrypt_hmac_secrets(assert, ecdh) < 0) { 319 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)
386 return (NULL); 386 return (NULL);
387 387
388 for (i = 0; i < argc; i++) 388 for (i = 0; i < argc; i++)
389 if (cbor_add_arg(map, i + 1, argv[i]) < 0) 389 if (cbor_add_arg(map, (uint8_t)(i + 1), argv[i]) < 0)
390 break; 390 break;
391 391
392 if (i != argc) { 392 if (i != argc) {
@@ -583,7 +583,9 @@ cbor_encode_extensions(const fido_cred_ext_t *ext)
583 } 583 }
584 } 584 }
585 if (ext->mask & FIDO_EXT_CRED_PROTECT) { 585 if (ext->mask & FIDO_EXT_CRED_PROTECT) {
586 if (cbor_add_uint8(item, "credProtect", ext->prot) < 0) { 586 if (ext->prot < 0 || ext->prot > UINT8_MAX ||
587 cbor_add_uint8(item, "credProtect",
588 (uint8_t)ext->prot) < 0) {
587 cbor_decref(&item); 589 cbor_decref(&item);
588 return (NULL); 590 return (NULL);
589 } 591 }
@@ -634,7 +636,7 @@ cbor_encode_pin_auth(const fido_blob_t *hmac_key, const fido_blob_t *data)
634 unsigned int dgst_len; 636 unsigned int dgst_len;
635 637
636 if ((md = EVP_sha256()) == NULL || HMAC(md, hmac_key->ptr, 638 if ((md = EVP_sha256()) == NULL || HMAC(md, hmac_key->ptr,
637 (int)hmac_key->len, data->ptr, (int)data->len, dgst, 639 (int)hmac_key->len, data->ptr, data->len, dgst,
638 &dgst_len) == NULL || dgst_len != SHA256_DIGEST_LENGTH) 640 &dgst_len) == NULL || dgst_len != SHA256_DIGEST_LENGTH)
639 return (NULL); 641 return (NULL);
640 642
@@ -696,7 +698,6 @@ cbor_encode_change_pin_auth(const fido_blob_t *key, const fido_blob_t *new_pin,
696 fido_blob_t *npe = NULL; /* new pin, encrypted */ 698 fido_blob_t *npe = NULL; /* new pin, encrypted */
697 fido_blob_t *ph = NULL; /* pin hash */ 699 fido_blob_t *ph = NULL; /* pin hash */
698 fido_blob_t *phe = NULL; /* pin hash, encrypted */ 700 fido_blob_t *phe = NULL; /* pin hash, encrypted */
699 int ok = -1;
700 701
701 if ((npe = fido_blob_new()) == NULL || 702 if ((npe = fido_blob_new()) == NULL ||
702 (ph = fido_blob_new()) == NULL || 703 (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,
735 if ((ctx = HMAC_CTX_new()) == NULL || 736 if ((ctx = HMAC_CTX_new()) == NULL ||
736 (md = EVP_sha256()) == NULL || 737 (md = EVP_sha256()) == NULL ||
737 HMAC_Init_ex(ctx, key->ptr, (int)key->len, md, NULL) == 0 || 738 HMAC_Init_ex(ctx, key->ptr, (int)key->len, md, NULL) == 0 ||
738 HMAC_Update(ctx, npe->ptr, (int)npe->len) == 0 || 739 HMAC_Update(ctx, npe->ptr, npe->len) == 0 ||
739 HMAC_Update(ctx, phe->ptr, (int)phe->len) == 0 || 740 HMAC_Update(ctx, phe->ptr, phe->len) == 0 ||
740 HMAC_Final(ctx, dgst, &dgst_len) == 0 || dgst_len != 32) { 741 HMAC_Final(ctx, dgst, &dgst_len) == 0 || dgst_len != 32) {
741 fido_log_debug("%s: HMAC", __func__); 742 fido_log_debug("%s: HMAC", __func__);
742 goto fail; 743 goto fail;
@@ -748,7 +749,6 @@ cbor_encode_change_pin_auth(const fido_blob_t *key, const fido_blob_t *new_pin,
748 goto fail; 749 goto fail;
749 } 750 }
750 751
751 ok = 0;
752fail: 752fail:
753 fido_blob_free(&npe); 753 fido_blob_free(&npe);
754 fido_blob_free(&ph); 754 fido_blob_free(&ph);
@@ -759,13 +759,6 @@ fail:
759 HMAC_CTX_free(ctx); 759 HMAC_CTX_free(ctx);
760#endif 760#endif
761 761
762 if (ok < 0) {
763 if (item != NULL) {
764 cbor_decref(&item);
765 item = NULL;
766 }
767 }
768
769 return (item); 762 return (item);
770} 763}
771 764
@@ -787,7 +780,7 @@ cbor_encode_set_pin_auth(const fido_blob_t *key, const fido_blob_t *pin)
787 } 780 }
788 781
789 if ((md = EVP_sha256()) == NULL || key->len != 32 || HMAC(md, key->ptr, 782 if ((md = EVP_sha256()) == NULL || key->len != 32 || HMAC(md, key->ptr,
790 (int)key->len, pe->ptr, (int)pe->len, dgst, &dgst_len) == NULL || 783 (int)key->len, pe->ptr, pe->len, dgst, &dgst_len) == NULL ||
791 dgst_len != SHA256_DIGEST_LENGTH) { 784 dgst_len != SHA256_DIGEST_LENGTH) {
792 fido_log_debug("%s: HMAC", __func__); 785 fido_log_debug("%s: HMAC", __func__);
793 goto fail; 786 goto fail;
@@ -1292,7 +1285,7 @@ cbor_decode_cred_authdata(const cbor_item_t *item, int cose_alg,
1292 } 1285 }
1293 1286
1294 if (authdata_ext != NULL) { 1287 if (authdata_ext != NULL) {
1295 if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0 && 1288 if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0 &&
1296 decode_extensions(&buf, &len, authdata_ext) < 0) 1289 decode_extensions(&buf, &len, authdata_ext) < 0)
1297 return (-1); 1290 return (-1);
1298 } 1291 }
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)
967 return (cred->attcred.id.len); 967 return (cred->attcred.id.len);
968} 968}
969 969
970const unsigned char *
971fido_cred_aaguid_ptr(const fido_cred_t *cred)
972{
973 return (cred->attcred.aaguid);
974}
975
976size_t
977fido_cred_aaguid_len(const fido_cred_t *cred)
978{
979 return (sizeof(cred->attcred.aaguid));
980}
981
970int 982int
971fido_cred_prot(const fido_cred_t *cred) 983fido_cred_prot(const fido_cred_t *cred)
972{ 984{
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
230static int 230static int
231credman_parse_rk(const cbor_item_t *key, const cbor_item_t *val, void *arg) 231credman_parse_rk(const cbor_item_t *key, const cbor_item_t *val, void *arg)
232{ 232{
233 fido_cred_t *cred = arg; 233 fido_cred_t *cred = arg;
234 uint64_t prot;
234 235
235 if (cbor_isa_uint(key) == false || 236 if (cbor_isa_uint(key) == false ||
236 cbor_int_get_width(key) != CBOR_INT_8) { 237 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)
249 return (-1); 250 return (-1);
250 cred->type = cred->attcred.type; /* XXX */ 251 cred->type = cred->attcred.type; /* XXX */
251 return (0); 252 return (0);
253 case 10:
254 if (cbor_decode_uint64(val, &prot) < 0 || prot > INT_MAX ||
255 fido_cred_set_prot(cred, (int)prot) != FIDO_OK)
256 return (-1);
257 return (0);
252 default: 258 default:
253 fido_log_debug("%s: cbor type", __func__); 259 fido_log_debug("%s: cbor type", __func__);
254 return (0); /* ignore */ 260 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 @@
10#include <sys/random.h> 10#include <sys/random.h>
11#endif 11#endif
12 12
13#include <openssl/sha.h>
14
13#include <fcntl.h> 15#include <fcntl.h>
14#include <stdint.h> 16#include <stdint.h>
15#include <stdlib.h> 17#include <stdlib.h>
@@ -106,10 +108,49 @@ find_manifest_func_node(dev_manifest_func_t f, dev_manifest_func_node_t **curr,
106 } 108 }
107} 109}
108 110
111#ifdef FIDO_FUZZ
112static void
113set_random_report_len(fido_dev_t *dev)
114{
115 dev->rx_len = CTAP_MIN_REPORT_LEN +
116 uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1);
117 dev->tx_len = CTAP_MIN_REPORT_LEN +
118 uniform_random(CTAP_MAX_REPORT_LEN - CTAP_MIN_REPORT_LEN + 1);
119}
120#endif
121
122static void
123fido_dev_set_flags(fido_dev_t *dev, const fido_cbor_info_t *info)
124{
125 char * const *ptr;
126 const bool *val;
127 size_t len;
128
129 ptr = fido_cbor_info_extensions_ptr(info);
130 len = fido_cbor_info_extensions_len(info);
131
132 for (size_t i = 0; i < len; i++)
133 if (strcmp(ptr[i], "credProtect") == 0)
134 dev->flags |= FIDO_DEV_CRED_PROT;
135
136 ptr = fido_cbor_info_options_name_ptr(info);
137 val = fido_cbor_info_options_value_ptr(info);
138 len = fido_cbor_info_options_len(info);
139
140 for (size_t i = 0; i < len; i++)
141 if (strcmp(ptr[i], "clientPin") == 0) {
142 if (val[i] == true)
143 dev->flags |= FIDO_DEV_PIN_SET;
144 else
145 dev->flags |= FIDO_DEV_PIN_UNSET;
146 }
147}
148
109static int 149static int
110fido_dev_open_tx(fido_dev_t *dev, const char *path) 150fido_dev_open_tx(fido_dev_t *dev, const char *path)
111{ 151{
112 const uint8_t cmd = CTAP_CMD_INIT; 152 const uint8_t cmd = CTAP_CMD_INIT;
153 int r;
113 154
114 if (dev->io_handle != NULL) { 155 if (dev->io_handle != NULL) {
115 fido_log_debug("%s: handle=%p", __func__, dev->io_handle); 156 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)
131 return (FIDO_ERR_INTERNAL); 172 return (FIDO_ERR_INTERNAL);
132 } 173 }
133 174
175 if (dev->io_own) {
176 dev->rx_len = CTAP_MAX_REPORT_LEN;
177 dev->tx_len = CTAP_MAX_REPORT_LEN;
178 } else {
179 dev->rx_len = fido_hid_report_in_len(dev->io_handle);
180 dev->tx_len = fido_hid_report_out_len(dev->io_handle);
181 }
182
183#ifdef FIDO_FUZZ
184 set_random_report_len(dev);
185#endif
186
187 if (dev->rx_len < CTAP_MIN_REPORT_LEN ||
188 dev->rx_len > CTAP_MAX_REPORT_LEN) {
189 fido_log_debug("%s: invalid rx_len %zu", __func__, dev->rx_len);
190 r = FIDO_ERR_RX;
191 goto fail;
192 }
193
194 if (dev->tx_len < CTAP_MIN_REPORT_LEN ||
195 dev->tx_len > CTAP_MAX_REPORT_LEN) {
196 fido_log_debug("%s: invalid tx_len %zu", __func__, dev->tx_len);
197 r = FIDO_ERR_TX;
198 goto fail;
199 }
200
134 if (fido_tx(dev, cmd, &dev->nonce, sizeof(dev->nonce)) < 0) { 201 if (fido_tx(dev, cmd, &dev->nonce, sizeof(dev->nonce)) < 0) {
135 fido_log_debug("%s: fido_tx", __func__); 202 fido_log_debug("%s: fido_tx", __func__);
136 dev->io.close(dev->io_handle); 203 r = FIDO_ERR_TX;
137 dev->io_handle = NULL; 204 goto fail;
138 return (FIDO_ERR_TX);
139 } 205 }
140 206
141 return (FIDO_OK); 207 return (FIDO_OK);
208fail:
209 dev->io.close(dev->io_handle);
210 dev->io_handle = NULL;
211
212 return (r);
142} 213}
143 214
144static int 215static int
@@ -166,6 +237,7 @@ fido_dev_open_rx(fido_dev_t *dev, int ms)
166 goto fail; 237 goto fail;
167 } 238 }
168 239
240 dev->flags = 0;
169 dev->cid = dev->attr.cid; 241 dev->cid = dev->attr.cid;
170 242
171 if (fido_dev_is_fido2(dev)) { 243 if (fido_dev_is_fido2(dev)) {
@@ -177,6 +249,8 @@ fido_dev_open_rx(fido_dev_t *dev, int ms)
177 if (fido_dev_get_cbor_info_wait(dev, info, ms) != FIDO_OK) { 249 if (fido_dev_get_cbor_info_wait(dev, info, ms) != FIDO_OK) {
178 fido_log_debug("%s: falling back to u2f", __func__); 250 fido_log_debug("%s: falling back to u2f", __func__);
179 fido_dev_force_u2f(dev); 251 fido_dev_force_u2f(dev);
252 } else {
253 fido_dev_set_flags(dev, info);
180 } 254 }
181 } 255 }
182 256
@@ -303,6 +377,9 @@ fido_dev_close(fido_dev_t *dev)
303int 377int
304fido_dev_cancel(fido_dev_t *dev) 378fido_dev_cancel(fido_dev_t *dev)
305{ 379{
380 if (fido_dev_is_fido2(dev) == false)
381 return (FIDO_ERR_INVALID_ARGUMENT);
382
306 if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0) < 0) 383 if (fido_tx(dev, CTAP_CMD_CANCEL, NULL, 0) < 0)
307 return (FIDO_ERR_TX); 384 return (FIDO_ERR_TX);
308 385
@@ -310,6 +387,105 @@ fido_dev_cancel(fido_dev_t *dev)
310} 387}
311 388
312int 389int
390fido_dev_get_touch_begin(fido_dev_t *dev)
391{
392 fido_blob_t f;
393 cbor_item_t *argv[9];
394 const char *clientdata = FIDO_DUMMY_CLIENTDATA;
395 const uint8_t user_id = FIDO_DUMMY_USER_ID;
396 unsigned char cdh[SHA256_DIGEST_LENGTH];
397 fido_rp_t rp;
398 fido_user_t user;
399 int r = FIDO_ERR_INTERNAL;
400
401 memset(&f, 0, sizeof(f));
402 memset(argv, 0, sizeof(argv));
403 memset(cdh, 0, sizeof(cdh));
404 memset(&rp, 0, sizeof(rp));
405 memset(&user, 0, sizeof(user));
406
407 if (fido_dev_is_fido2(dev) == false)
408 return (u2f_get_touch_begin(dev));
409
410 if (SHA256((const void *)clientdata, strlen(clientdata), cdh) != cdh) {
411 fido_log_debug("%s: sha256", __func__);
412 return (FIDO_ERR_INTERNAL);
413 }
414
415 if ((rp.id = strdup(FIDO_DUMMY_RP_ID)) == NULL ||
416 (user.name = strdup(FIDO_DUMMY_USER_NAME)) == NULL) {
417 fido_log_debug("%s: strdup", __func__);
418 goto fail;
419 }
420
421 if (fido_blob_set(&user.id, &user_id, sizeof(user_id)) < 0) {
422 fido_log_debug("%s: fido_blob_set", __func__);
423 goto fail;
424 }
425
426 if ((argv[0] = cbor_build_bytestring(cdh, sizeof(cdh))) == NULL ||
427 (argv[1] = cbor_encode_rp_entity(&rp)) == NULL ||
428 (argv[2] = cbor_encode_user_entity(&user)) == NULL ||
429 (argv[3] = cbor_encode_pubkey_param(COSE_ES256)) == NULL) {
430 fido_log_debug("%s: cbor encode", __func__);
431 goto fail;
432 }
433
434 if (fido_dev_supports_pin(dev)) {
435 if ((argv[7] = cbor_new_definite_bytestring()) == NULL ||
436 (argv[8] = cbor_encode_pin_opt()) == NULL) {
437 fido_log_debug("%s: cbor encode", __func__);
438 goto fail;
439 }
440 }
441
442 if (cbor_build_frame(CTAP_CBOR_MAKECRED, argv, nitems(argv), &f) < 0 ||
443 fido_tx(dev, CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
444 fido_log_debug("%s: fido_tx", __func__);
445 r = FIDO_ERR_TX;
446 goto fail;
447 }
448
449 r = FIDO_OK;
450fail:
451 cbor_vector_free(argv, nitems(argv));
452 free(f.ptr);
453 free(rp.id);
454 free(user.name);
455 free(user.id.ptr);
456
457 return (r);
458}
459
460int
461fido_dev_get_touch_status(fido_dev_t *dev, int *touched, int ms)
462{
463 int r;
464
465 *touched = 0;
466
467 if (fido_dev_is_fido2(dev) == false)
468 return (u2f_get_touch_status(dev, touched, ms));
469
470 switch ((r = fido_rx_cbor_status(dev, ms))) {
471 case FIDO_ERR_PIN_AUTH_INVALID:
472 case FIDO_ERR_PIN_INVALID:
473 case FIDO_ERR_PIN_NOT_SET:
474 case FIDO_ERR_SUCCESS:
475 *touched = 1;
476 break;
477 case FIDO_ERR_RX:
478 /* ignore */
479 break;
480 default:
481 fido_log_debug("%s: fido_rx_cbor_status", __func__);
482 return (r);
483 }
484
485 return (FIDO_OK);
486}
487
488int
313fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io) 489fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io)
314{ 490{
315 if (dev->io_handle != NULL) { 491 if (dev->io_handle != NULL) {
@@ -324,6 +500,7 @@ fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io)
324 } 500 }
325 501
326 dev->io = *io; 502 dev->io = *io;
503 dev->io_own = true;
327 504
328 return (FIDO_OK); 505 return (FIDO_OK);
329} 506}
@@ -337,6 +514,7 @@ fido_dev_set_transport_functions(fido_dev_t *dev, const fido_dev_transport_t *t)
337 } 514 }
338 515
339 dev->transport = *t; 516 dev->transport = *t;
517 dev->io_own = true;
340 518
341 return (FIDO_OK); 519 return (FIDO_OK);
342} 520}
@@ -446,10 +624,29 @@ fido_dev_is_fido2(const fido_dev_t *dev)
446 return (dev->attr.flags & FIDO_CAP_CBOR); 624 return (dev->attr.flags & FIDO_CAP_CBOR);
447} 625}
448 626
627bool
628fido_dev_supports_pin(const fido_dev_t *dev)
629{
630 return (dev->flags & (FIDO_DEV_PIN_SET|FIDO_DEV_PIN_UNSET));
631}
632
633bool
634fido_dev_has_pin(const fido_dev_t *dev)
635{
636 return (dev->flags & FIDO_DEV_PIN_SET);
637}
638
639bool
640fido_dev_supports_cred_prot(const fido_dev_t *dev)
641{
642 return (dev->flags & FIDO_DEV_CRED_PROT);
643}
644
449void 645void
450fido_dev_force_u2f(fido_dev_t *dev) 646fido_dev_force_u2f(fido_dev_t *dev)
451{ 647{
452 dev->attr.flags &= ~FIDO_CAP_CBOR; 648 dev->attr.flags &= (uint8_t)~FIDO_CAP_CBOR;
649 dev->flags = 0;
453} 650}
454 651
455void 652void
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 @@
1#!/bin/bash -u 1#!/bin/sh -u
2 2
3# Copyright (c) 2018 Yubico AB. All rights reserved. 3# Copyright (c) 2018 Yubico AB. All rights reserved.
4# Use of this source code is governed by a BSD-style 4# Use of this source code is governed by a BSD-style
5# license that can be found in the LICENSE file. 5# license that can be found in the LICENSE file.
6 6
7[[ ! -f export.gnu || ! -f export.llvm || ! -f export.msvc ]] && exit 1 7for f in export.gnu export.llvm export.msvc; do
8 if [ ! -f "${f}" ]; then
9 exit 1
10 fi
11done
8 12
9TMPDIR=$(mktemp -d) 13TMPDIR="$(mktemp -d)"
10GNU=${TMPDIR}/gnu 14GNU="${TMPDIR}/gnu"
11LLVM=${TMPDIR}/llvm 15LLVM="${TMPDIR}/llvm"
12MSVC=${TMPDIR}/msvc 16MSVC="${TMPDIR}/msvc"
13 17
14egrep -o $'([^*{}\t]+);$' export.gnu | tr -d ';' | sort > ${GNU} 18awk '/^[^*{}]+;$/' export.gnu | tr -d '\t;' | sort > "${GNU}"
15sed 's/^_//g' export.llvm | sort > ${LLVM} 19sed 's/^_//' export.llvm | sort > "${LLVM}"
16egrep -v "^EXPORTS$" export.msvc | sort > ${MSVC} 20grep -v '^EXPORTS$' export.msvc | sort > "${MSVC}"
17diff -u ${GNU} ${LLVM} && diff -u ${MSVC} ${LLVM} 21diff -u "${GNU}" "${LLVM}" && diff -u "${MSVC}" "${LLVM}"
18ERROR=$? 22ERROR=$?
19 23rm "${GNU}" "${LLVM}" "${MSVC}"
20rm ${GNU} ${LLVM} ${MSVC} 24rmdir "${TMPDIR}"
21rmdir ${TMPDIR}
22 25
23exit ${ERROR} 26exit ${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)
38 return "FIDO_ERR_LIMIT_EXCEEDED"; 38 return "FIDO_ERR_LIMIT_EXCEEDED";
39 case FIDO_ERR_UNSUPPORTED_EXTENSION: 39 case FIDO_ERR_UNSUPPORTED_EXTENSION:
40 return "FIDO_ERR_UNSUPPORTED_EXTENSION"; 40 return "FIDO_ERR_UNSUPPORTED_EXTENSION";
41 case FIDO_ERR_FP_DATABASE_FULL:
42 return "FIDO_ERR_FP_DATABASE_FULL";
41 case FIDO_ERR_CREDENTIAL_EXCLUDED: 43 case FIDO_ERR_CREDENTIAL_EXCLUDED:
42 return "FIDO_ERR_CREDENTIAL_EXCLUDED"; 44 return "FIDO_ERR_CREDENTIAL_EXCLUDED";
43 case FIDO_ERR_PROCESSING: 45 case FIDO_ERR_PROCESSING:
@@ -94,6 +96,8 @@ fido_strerr(int n)
94 return "FIDO_ERR_ACTION_TIMEOUT"; 96 return "FIDO_ERR_ACTION_TIMEOUT";
95 case FIDO_ERR_UP_REQUIRED: 97 case FIDO_ERR_UP_REQUIRED:
96 return "FIDO_ERR_UP_REQUIRED"; 98 return "FIDO_ERR_UP_REQUIRED";
99 case FIDO_ERR_UV_BLOCKED:
100 return "FIDO_ERR_UV_BLOCKED";
97 case FIDO_ERR_ERR_OTHER: 101 case FIDO_ERR_ERR_OTHER:
98 return "FIDO_ERR_ERR_OTHER"; 102 return "FIDO_ERR_ERR_OTHER";
99 case FIDO_ERR_SPEC_LAST: 103 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)
92 92
93 /* alg */ 93 /* alg */
94 if ((argv[1].key = cbor_build_uint8(3)) == NULL || 94 if ((argv[1].key = cbor_build_uint8(3)) == NULL ||
95 (argv[1].value = cbor_build_negint8(-alg - 1)) == NULL || 95 (argv[1].value = cbor_build_negint8((uint8_t)(-alg - 1))) == NULL ||
96 !cbor_map_add(item, argv[1])) 96 !cbor_map_add(item, argv[1]))
97 goto fail; 97 goto fail;
98 98
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 @@
76 fido_cbor_info_extensions_ptr; 76 fido_cbor_info_extensions_ptr;
77 fido_cbor_info_free; 77 fido_cbor_info_free;
78 fido_cbor_info_maxmsgsiz; 78 fido_cbor_info_maxmsgsiz;
79 fido_cbor_info_maxcredcntlst;
80 fido_cbor_info_maxcredidlen;
79 fido_cbor_info_fwversion; 81 fido_cbor_info_fwversion;
80 fido_cbor_info_new; 82 fido_cbor_info_new;
81 fido_cbor_info_options_len; 83 fido_cbor_info_options_len;
@@ -96,6 +98,8 @@
96 fido_cred_free; 98 fido_cred_free;
97 fido_cred_id_len; 99 fido_cred_id_len;
98 fido_cred_id_ptr; 100 fido_cred_id_ptr;
101 fido_cred_aaguid_len;
102 fido_cred_aaguid_ptr;
99 fido_credman_del_dev_rk; 103 fido_credman_del_dev_rk;
100 fido_credman_get_dev_metadata; 104 fido_credman_get_dev_metadata;
101 fido_credman_get_dev_rk; 105 fido_credman_get_dev_rk;
@@ -155,6 +159,9 @@
155 fido_dev_get_assert; 159 fido_dev_get_assert;
156 fido_dev_get_cbor_info; 160 fido_dev_get_cbor_info;
157 fido_dev_get_retry_count; 161 fido_dev_get_retry_count;
162 fido_dev_get_touch_begin;
163 fido_dev_get_touch_status;
164 fido_dev_has_pin;
158 fido_dev_info_free; 165 fido_dev_info_free;
159 fido_dev_info_manifest; 166 fido_dev_info_manifest;
160 fido_dev_info_manufacturer_string; 167 fido_dev_info_manufacturer_string;
@@ -175,6 +182,8 @@
175 fido_dev_set_io_functions; 182 fido_dev_set_io_functions;
176 fido_dev_set_pin; 183 fido_dev_set_pin;
177 fido_dev_set_transport_functions; 184 fido_dev_set_transport_functions;
185 fido_dev_supports_cred_prot;
186 fido_dev_supports_pin;
178 fido_init; 187 fido_init;
179 fido_set_log_handler; 188 fido_set_log_handler;
180 fido_strerr; 189 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
74_fido_cbor_info_extensions_ptr 74_fido_cbor_info_extensions_ptr
75_fido_cbor_info_free 75_fido_cbor_info_free
76_fido_cbor_info_maxmsgsiz 76_fido_cbor_info_maxmsgsiz
77_fido_cbor_info_maxcredcntlst
78_fido_cbor_info_maxcredidlen
77_fido_cbor_info_fwversion 79_fido_cbor_info_fwversion
78_fido_cbor_info_new 80_fido_cbor_info_new
79_fido_cbor_info_options_len 81_fido_cbor_info_options_len
@@ -94,6 +96,8 @@ _fido_cred_fmt
94_fido_cred_free 96_fido_cred_free
95_fido_cred_id_len 97_fido_cred_id_len
96_fido_cred_id_ptr 98_fido_cred_id_ptr
99_fido_cred_aaguid_len
100_fido_cred_aaguid_ptr
97_fido_credman_del_dev_rk 101_fido_credman_del_dev_rk
98_fido_credman_get_dev_metadata 102_fido_credman_get_dev_metadata
99_fido_credman_get_dev_rk 103_fido_credman_get_dev_rk
@@ -153,6 +157,9 @@ _fido_dev_free
153_fido_dev_get_assert 157_fido_dev_get_assert
154_fido_dev_get_cbor_info 158_fido_dev_get_cbor_info
155_fido_dev_get_retry_count 159_fido_dev_get_retry_count
160_fido_dev_get_touch_begin
161_fido_dev_get_touch_status
162_fido_dev_has_pin
156_fido_dev_info_free 163_fido_dev_info_free
157_fido_dev_info_manifest 164_fido_dev_info_manifest
158_fido_dev_info_manufacturer_string 165_fido_dev_info_manufacturer_string
@@ -173,6 +180,8 @@ _fido_dev_reset
173_fido_dev_set_io_functions 180_fido_dev_set_io_functions
174_fido_dev_set_pin 181_fido_dev_set_pin
175_fido_dev_set_transport_functions 182_fido_dev_set_transport_functions
183_fido_dev_supports_cred_prot
184_fido_dev_supports_pin
176_fido_init 185_fido_init
177_fido_set_log_handler 186_fido_set_log_handler
178_fido_strerr 187_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
75fido_cbor_info_extensions_ptr 75fido_cbor_info_extensions_ptr
76fido_cbor_info_free 76fido_cbor_info_free
77fido_cbor_info_maxmsgsiz 77fido_cbor_info_maxmsgsiz
78fido_cbor_info_maxcredcntlst
79fido_cbor_info_maxcredidlen
78fido_cbor_info_fwversion 80fido_cbor_info_fwversion
79fido_cbor_info_new 81fido_cbor_info_new
80fido_cbor_info_options_len 82fido_cbor_info_options_len
@@ -95,6 +97,8 @@ fido_cred_fmt
95fido_cred_free 97fido_cred_free
96fido_cred_id_len 98fido_cred_id_len
97fido_cred_id_ptr 99fido_cred_id_ptr
100fido_cred_aaguid_len
101fido_cred_aaguid_ptr
98fido_credman_del_dev_rk 102fido_credman_del_dev_rk
99fido_credman_get_dev_metadata 103fido_credman_get_dev_metadata
100fido_credman_get_dev_rk 104fido_credman_get_dev_rk
@@ -154,6 +158,9 @@ fido_dev_free
154fido_dev_get_assert 158fido_dev_get_assert
155fido_dev_get_cbor_info 159fido_dev_get_cbor_info
156fido_dev_get_retry_count 160fido_dev_get_retry_count
161fido_dev_get_touch_begin
162fido_dev_get_touch_status
163fido_dev_has_pin
157fido_dev_info_free 164fido_dev_info_free
158fido_dev_info_manifest 165fido_dev_info_manifest
159fido_dev_info_manufacturer_string 166fido_dev_info_manufacturer_string
@@ -174,6 +181,8 @@ fido_dev_reset
174fido_dev_set_io_functions 181fido_dev_set_io_functions
175fido_dev_set_pin 182fido_dev_set_pin
176fido_dev_set_transport_functions 183fido_dev_set_transport_functions
184fido_dev_supports_cred_prot
185fido_dev_supports_pin
177fido_init 186fido_init
178fido_set_log_handler 187fido_set_log_handler
179fido_strerr 188fido_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 *);
88void fido_hid_close(void *); 88void fido_hid_close(void *);
89int fido_hid_read(void *, unsigned char *, size_t, int); 89int fido_hid_read(void *, unsigned char *, size_t, int);
90int fido_hid_write(void *, const unsigned char *, size_t); 90int fido_hid_write(void *, const unsigned char *, size_t);
91size_t fido_hid_report_in_len(void *);
92size_t fido_hid_report_out_len(void *);
91 93
92/* generic i/o */ 94/* generic i/o */
93int fido_rx_cbor_status(fido_dev_t *, int); 95int fido_rx_cbor_status(fido_dev_t *, int);
@@ -115,6 +117,8 @@ void fido_log_xxd(const void *, size_t);
115/* u2f */ 117/* u2f */
116int u2f_register(fido_dev_t *, fido_cred_t *, int); 118int u2f_register(fido_dev_t *, fido_cred_t *, int);
117int u2f_authenticate(fido_dev_t *, fido_assert_t *, int); 119int u2f_authenticate(fido_dev_t *, fido_assert_t *, int);
120int u2f_get_touch_begin(fido_dev_t *);
121int u2f_get_touch_status(fido_dev_t *, int *, int);
118 122
119/* unexposed fido ops */ 123/* unexposed fido ops */
120int fido_dev_authkey(fido_dev_t *, es256_pk_t *); 124int 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 *);
149int fido_dev_register_manifest_func(const dev_manifest_func_t); 153int fido_dev_register_manifest_func(const dev_manifest_func_t);
150void fido_dev_unregister_manifest_func(const dev_manifest_func_t); 154void fido_dev_unregister_manifest_func(const dev_manifest_func_t);
151 155
156/* fuzzing instrumentation */
157#ifdef FIDO_FUZZ
158uint32_t uniform_random(uint32_t);
159#endif
160
161/* internal device capability flags */
162#define FIDO_DEV_PIN_SET 0x01
163#define FIDO_DEV_PIN_UNSET 0x02
164#define FIDO_DEV_CRED_PROT 0x04
165
166/* miscellanea */
167#define FIDO_DUMMY_CLIENTDATA ""
168#define FIDO_DUMMY_RP_ID "localhost"
169#define FIDO_DUMMY_USER_NAME "dummy"
170#define FIDO_DUMMY_USER_ID 1
171
152#ifdef __cplusplus 172#ifdef __cplusplus
153} /* extern "C" */ 173} /* extern "C" */
154#endif /* __cplusplus */ 174#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 @@
32extern "C" { 32extern "C" {
33#endif /* __cplusplus */ 33#endif /* __cplusplus */
34 34
35#ifdef _MSC_VER
36#define FIDO_DEPRECATED(reason) __declspec(deprecated(reason))
37#else
38#define FIDO_DEPRECATED(reason) __attribute__((__deprecated__(reason)))
39#endif
40
35fido_assert_t *fido_assert_new(void); 41fido_assert_t *fido_assert_new(void);
36fido_cred_t *fido_cred_new(void); 42fido_cred_t *fido_cred_new(void);
37fido_dev_t *fido_dev_new(void); 43fido_dev_t *fido_dev_new(void);
@@ -82,6 +88,7 @@ const unsigned char *fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *);
82const unsigned char *fido_cred_authdata_ptr(const fido_cred_t *); 88const unsigned char *fido_cred_authdata_ptr(const fido_cred_t *);
83const unsigned char *fido_cred_clientdata_hash_ptr(const fido_cred_t *); 89const unsigned char *fido_cred_clientdata_hash_ptr(const fido_cred_t *);
84const unsigned char *fido_cred_id_ptr(const fido_cred_t *); 90const unsigned char *fido_cred_id_ptr(const fido_cred_t *);
91const unsigned char *fido_cred_aaguid_ptr(const fido_cred_t *);
85const unsigned char *fido_cred_user_id_ptr(const fido_cred_t *); 92const unsigned char *fido_cred_user_id_ptr(const fido_cred_t *);
86const unsigned char *fido_cred_pubkey_ptr(const fido_cred_t *); 93const unsigned char *fido_cred_pubkey_ptr(const fido_cred_t *);
87const unsigned char *fido_cred_sig_ptr(const fido_cred_t *); 94const 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 *,
97int fido_assert_set_count(fido_assert_t *, size_t); 104int fido_assert_set_count(fido_assert_t *, size_t);
98int fido_assert_set_extensions(fido_assert_t *, int); 105int fido_assert_set_extensions(fido_assert_t *, int);
99int fido_assert_set_hmac_salt(fido_assert_t *, const unsigned char *, size_t); 106int fido_assert_set_hmac_salt(fido_assert_t *, const unsigned char *, size_t);
100int fido_assert_set_options(fido_assert_t *, bool, bool) 107FIDO_DEPRECATED("use fido_assert_set_up/fido_assert_set_uv")
101 __attribute__((__deprecated__("use fido_assert_set_up/fido_assert_set_uv"))); 108int fido_assert_set_options(fido_assert_t *, bool, bool);
102int fido_assert_set_rp(fido_assert_t *, const char *); 109int fido_assert_set_rp(fido_assert_t *, const char *);
103int fido_assert_set_up(fido_assert_t *, fido_opt_t); 110int fido_assert_set_up(fido_assert_t *, fido_opt_t);
104int fido_assert_set_uv(fido_assert_t *, fido_opt_t); 111int 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);
111int fido_cred_set_clientdata_hash(fido_cred_t *, const unsigned char *, size_t); 118int fido_cred_set_clientdata_hash(fido_cred_t *, const unsigned char *, size_t);
112int fido_cred_set_extensions(fido_cred_t *, int); 119int fido_cred_set_extensions(fido_cred_t *, int);
113int fido_cred_set_fmt(fido_cred_t *, const char *); 120int fido_cred_set_fmt(fido_cred_t *, const char *);
114int fido_cred_set_options(fido_cred_t *, bool, bool) 121FIDO_DEPRECATED("use fido_cred_set_rk/fido_cred_set_uv")
115 __attribute__((__deprecated__("use fido_cred_set_rk/fido_cred_set_uv"))); 122int fido_cred_set_options(fido_cred_t *, bool, bool);
116int fido_cred_set_prot(fido_cred_t *, int); 123int fido_cred_set_prot(fido_cred_t *, int);
117int fido_cred_set_rk(fido_cred_t *, fido_opt_t); 124int fido_cred_set_rk(fido_cred_t *, fido_opt_t);
118int fido_cred_set_rp(fido_cred_t *, const char *, const char *); 125int fido_cred_set_rp(fido_cred_t *, const char *, const char *);
@@ -130,6 +137,8 @@ int fido_dev_close(fido_dev_t *);
130int fido_dev_get_assert(fido_dev_t *, fido_assert_t *, const char *); 137int fido_dev_get_assert(fido_dev_t *, fido_assert_t *, const char *);
131int fido_dev_get_cbor_info(fido_dev_t *, fido_cbor_info_t *); 138int fido_dev_get_cbor_info(fido_dev_t *, fido_cbor_info_t *);
132int fido_dev_get_retry_count(fido_dev_t *, int *); 139int fido_dev_get_retry_count(fido_dev_t *, int *);
140int fido_dev_get_touch_begin(fido_dev_t *);
141int fido_dev_get_touch_status(fido_dev_t *, int *, int);
133int fido_dev_info_manifest(fido_dev_info_t *, size_t, size_t *); 142int fido_dev_info_manifest(fido_dev_info_t *, size_t, size_t *);
134int fido_dev_make_cred(fido_dev_t *, fido_cred_t *, const char *); 143int fido_dev_make_cred(fido_dev_t *, fido_cred_t *, const char *);
135int fido_dev_open_with_info(fido_dev_t *); 144int fido_dev_open_with_info(fido_dev_t *);
@@ -154,6 +163,7 @@ size_t fido_cbor_info_versions_len(const fido_cbor_info_t *);
154size_t fido_cred_authdata_len(const fido_cred_t *); 163size_t fido_cred_authdata_len(const fido_cred_t *);
155size_t fido_cred_clientdata_hash_len(const fido_cred_t *); 164size_t fido_cred_clientdata_hash_len(const fido_cred_t *);
156size_t fido_cred_id_len(const fido_cred_t *); 165size_t fido_cred_id_len(const fido_cred_t *);
166size_t fido_cred_aaguid_len(const fido_cred_t *);
157size_t fido_cred_user_id_len(const fido_cred_t *); 167size_t fido_cred_user_id_len(const fido_cred_t *);
158size_t fido_cred_pubkey_len(const fido_cred_t *); 168size_t fido_cred_pubkey_len(const fido_cred_t *);
159size_t fido_cred_sig_len(const fido_cred_t *); 169size_t fido_cred_sig_len(const fido_cred_t *);
@@ -170,9 +180,14 @@ uint8_t fido_dev_flags(const fido_dev_t *);
170int16_t fido_dev_info_vendor(const fido_dev_info_t *); 180int16_t fido_dev_info_vendor(const fido_dev_info_t *);
171int16_t fido_dev_info_product(const fido_dev_info_t *); 181int16_t fido_dev_info_product(const fido_dev_info_t *);
172uint64_t fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *); 182uint64_t fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *);
183uint64_t fido_cbor_info_maxcredcntlst(const fido_cbor_info_t *);
184uint64_t fido_cbor_info_maxcredidlen(const fido_cbor_info_t *);
173uint64_t fido_cbor_info_fwversion(const fido_cbor_info_t *); 185uint64_t fido_cbor_info_fwversion(const fido_cbor_info_t *);
174 186
187bool fido_dev_has_pin(const fido_dev_t *);
175bool fido_dev_is_fido2(const fido_dev_t *); 188bool fido_dev_is_fido2(const fido_dev_t *);
189bool fido_dev_supports_pin(const fido_dev_t *);
190bool fido_dev_supports_cred_prot(const fido_dev_t *);
176 191
177#ifdef __cplusplus 192#ifdef __cplusplus
178} /* extern "C" */ 193} /* 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 @@
21#define FIDO_ERR_MISSING_PARAMETER 0x14 21#define FIDO_ERR_MISSING_PARAMETER 0x14
22#define FIDO_ERR_LIMIT_EXCEEDED 0x15 22#define FIDO_ERR_LIMIT_EXCEEDED 0x15
23#define FIDO_ERR_UNSUPPORTED_EXTENSION 0x16 23#define FIDO_ERR_UNSUPPORTED_EXTENSION 0x16
24#define FIDO_ERR_FP_DATABASE_FULL 0x17
24#define FIDO_ERR_CREDENTIAL_EXCLUDED 0x19 25#define FIDO_ERR_CREDENTIAL_EXCLUDED 0x19
25#define FIDO_ERR_PROCESSING 0x21 26#define FIDO_ERR_PROCESSING 0x21
26#define FIDO_ERR_INVALID_CREDENTIAL 0x22 27#define FIDO_ERR_INVALID_CREDENTIAL 0x22
@@ -49,6 +50,7 @@
49#define FIDO_ERR_REQUEST_TOO_LARGE 0x39 50#define FIDO_ERR_REQUEST_TOO_LARGE 0x39
50#define FIDO_ERR_ACTION_TIMEOUT 0x3a 51#define FIDO_ERR_ACTION_TIMEOUT 0x3a
51#define FIDO_ERR_UP_REQUIRED 0x3b 52#define FIDO_ERR_UP_REQUIRED 0x3b
53#define FIDO_ERR_UV_BLOCKED 0x3c
52#define FIDO_ERR_ERR_OTHER 0x7f 54#define FIDO_ERR_ERR_OTHER 0x7f
53#define FIDO_ERR_SPEC_LAST 0xdf 55#define FIDO_ERR_SPEC_LAST 0xdf
54 56
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 @@
50/* HID Broadcast channel ID. */ 50/* HID Broadcast channel ID. */
51#define CTAP_CID_BROADCAST 0xffffffff 51#define CTAP_CID_BROADCAST 0xffffffff
52 52
53/* Expected size of a HID report in bytes. */ 53#define CTAP_INIT_HEADER_LEN 7
54#define CTAP_RPT_SIZE 64 54#define CTAP_CONT_HEADER_LEN 5
55
56/* Maximum length of a CTAP HID report in bytes. */
57#define CTAP_MAX_REPORT_LEN 64
58
59/* Minimum length of a CTAP HID report in bytes. */
60#define CTAP_MIN_REPORT_LEN (CTAP_INIT_HEADER_LEN + 1)
55 61
56/* Randomness device on UNIX-like platforms. */ 62/* Randomness device on UNIX-like platforms. */
57#ifndef FIDO_RANDOM_DEV 63#ifndef FIDO_RANDOM_DEV
@@ -60,7 +66,7 @@
60 66
61/* Maximum message size in bytes. */ 67/* Maximum message size in bytes. */
62#ifndef FIDO_MAXMSG 68#ifndef FIDO_MAXMSG
63#define FIDO_MAXMSG 1200 69#define FIDO_MAXMSG 2048
64#endif 70#endif
65 71
66/* CTAP capability bits. */ 72/* 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 {
175} fido_byte_array_t; 175} fido_byte_array_t;
176 176
177typedef struct fido_cbor_info { 177typedef struct fido_cbor_info {
178 fido_str_array_t versions; /* supported versions: fido2|u2f */ 178 fido_str_array_t versions; /* supported versions: fido2|u2f */
179 fido_str_array_t extensions; /* list of supported extensions */ 179 fido_str_array_t extensions; /* list of supported extensions */
180 unsigned char aaguid[16]; /* aaguid */ 180 unsigned char aaguid[16]; /* aaguid */
181 fido_opt_array_t options; /* list of supported options */ 181 fido_opt_array_t options; /* list of supported options */
182 uint64_t maxmsgsiz; /* maximum message size */ 182 uint64_t maxmsgsiz; /* maximum message size */
183 fido_byte_array_t protocols; /* supported pin protocols */ 183 fido_byte_array_t protocols; /* supported pin protocols */
184 uint64_t fwversion; /* firmware version */ 184 uint64_t maxcredcntlst; /* max number of credentials in list */
185 uint64_t maxcredidlen; /* max credential ID length */
186 uint64_t fwversion; /* firmware version */
185} fido_cbor_info_t; 187} fido_cbor_info_t;
186 188
187typedef struct fido_dev_info { 189typedef struct fido_dev_info {
@@ -213,6 +215,10 @@ typedef struct fido_dev {
213 char *path; /* device path */ 215 char *path; /* device path */
214 void *io_handle; /* abstract i/o handle */ 216 void *io_handle; /* abstract i/o handle */
215 fido_dev_io_t io; /* i/o functions */ 217 fido_dev_io_t io; /* i/o functions */
218 bool io_own; /* device has own io/transport */
219 size_t rx_len; /* length of HID input reports */
220 size_t tx_len; /* length of HID output reports */
221 int flags; /* internal flags; see FIDO_DEV_* */
216 fido_dev_transport_t transport; /* transport functions */ 222 fido_dev_transport_t transport; /* transport functions */
217} fido_dev_t; 223} fido_dev_t;
218 224
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 @@
4 * license that can be found in the LICENSE file. 4 * license that can be found in the LICENSE file.
5 */ 5 */
6 6
7#include <hidapi/hidapi.h> 7#ifdef __linux__
8#include <sys/ioctl.h>
9#include <linux/hidraw.h>
10#include <linux/input.h>
11#include <fcntl.h>
12#endif
8 13
14#include <hidapi.h>
9#include <stdlib.h> 15#include <stdlib.h>
10#include <string.h> 16#include <string.h>
11#include <wchar.h> 17#include <wchar.h>
12 18
13#include "fido.h" 19#include "fido.h"
14 20
21struct hid_hidapi {
22 void *handle;
23 size_t report_in_len;
24 size_t report_out_len;
25};
26
15static size_t 27static size_t
16fido_wcslen(const wchar_t *wcs) 28fido_wcslen(const wchar_t *wcs)
17{ 29{
@@ -27,7 +39,7 @@ wcs_to_cs(const wchar_t *wcs)
27 char *cs; 39 char *cs;
28 size_t i; 40 size_t i;
29 41
30 if (wcs == NULL || (cs = calloc(fido_wcslen(wcs) + 1, 1)) == NULL) 42 if (wcs == NULL || (cs = calloc(fido_wcslen(wcs) + 1, 1)) == NULL)
31 return NULL; 43 return NULL;
32 44
33 for (i = 0; i < fido_wcslen(wcs); i++) { 45 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)
68 free(di->path); 80 free(di->path);
69 free(di->manufacturer); 81 free(di->manufacturer);
70 free(di->product); 82 free(di->product);
83 explicit_bzero(di, sizeof(*di));
71 return -1; 84 return -1;
72 } 85 }
73 86
74 di->product_id = d->product_id; 87 di->product_id = (int16_t)d->product_id;
75 di->vendor_id = d->vendor_id; 88 di->vendor_id = (int16_t)d->vendor_id;
76 di->io = (fido_dev_io_t) { 89 di->io = (fido_dev_io_t) {
77 &fido_hid_open, 90 &fido_hid_open,
78 &fido_hid_close, 91 &fido_hid_close,
@@ -83,28 +96,199 @@ copy_info(fido_dev_info_t *di, const struct hid_device_info *d)
83 return 0; 96 return 0;
84} 97}
85 98
99#ifdef __linux__
100static int
101get_key_len(uint8_t tag, uint8_t *key, size_t *key_len)
102{
103 *key = tag & 0xfc;
104 if ((*key & 0xf0) == 0xf0) {
105 fido_log_debug("%s: *key=0x%02x", __func__, *key);
106 return -1;
107 }
108
109 *key_len = tag & 0x3;
110 if (*key_len == 3) {
111 *key_len = 4;
112 }
113
114 return 0;
115}
116
117static int
118get_key_val(const void *body, size_t key_len, uint32_t *val)
119{
120 const uint8_t *ptr = body;
121
122 switch (key_len) {
123 case 0:
124 *val = 0;
125 break;
126 case 1:
127 *val = ptr[0];
128 break;
129 case 2:
130 *val = (uint32_t)((ptr[1] << 8) | ptr[0]);
131 break;
132 default:
133 fido_log_debug("%s: key_len=%zu", __func__, key_len);
134 return -1;
135 }
136
137 return 0;
138}
139
140static int
141get_usage_info(const struct hidraw_report_descriptor *hrd, uint32_t *usage_page,
142 uint32_t *usage)
143{
144 const uint8_t *ptr = hrd->value;
145 size_t len = hrd->size;
146
147 while (len > 0) {
148 const uint8_t tag = ptr[0];
149
150 ptr++;
151 len--;
152
153 uint8_t key;
154 size_t key_len;
155 uint32_t key_val;
156
157 if (get_key_len(tag, &key, &key_len) < 0 || key_len > len ||
158 get_key_val(ptr, key_len, &key_val) < 0) {
159 return -1;
160 }
161
162 if (key == 0x4) {
163 *usage_page = key_val;
164 } else if (key == 0x8) {
165 *usage = key_val;
166 }
167
168 ptr += key_len;
169 len -= key_len;
170 }
171
172 return 0;
173}
174
175static int
176get_report_descriptor(const char *path, struct hidraw_report_descriptor *hrd)
177{
178 int fd;
179 int s = -1;
180 int ok = -1;
181
182 if ((fd = open(path, O_RDONLY)) < 0) {
183 fido_log_debug("%s: open", __func__);
184 return -1;
185 }
186
187 if (ioctl(fd, HIDIOCGRDESCSIZE, &s) < 0 || s < 0 ||
188 (unsigned)s > HID_MAX_DESCRIPTOR_SIZE) {
189 fido_log_debug("%s: ioctl HIDIOCGRDESCSIZE", __func__);
190 goto fail;
191 }
192
193 hrd->size = (unsigned)s;
194
195 if (ioctl(fd, HIDIOCGRDESC, hrd) < 0) {
196 fido_log_debug("%s: ioctl HIDIOCGRDESC", __func__);
197 goto fail;
198 }
199
200 ok = 0;
201fail:
202 if (fd != -1)
203 close(fd);
204
205 return ok;
206}
207
208static bool
209is_fido(const struct hid_device_info *hdi)
210{
211 uint32_t usage = 0;
212 uint32_t usage_page = 0;
213 struct hidraw_report_descriptor hrd;
214
215 memset(&hrd, 0, sizeof(hrd));
216
217 if (get_report_descriptor(hdi->path, &hrd) < 0 ||
218 get_usage_info(&hrd, &usage_page, &usage) < 0) {
219 return false;
220 }
221
222 return usage_page == 0xf1d0;
223}
224#elif defined(_WIN32) || defined(__APPLE__)
225static bool
226is_fido(const struct hid_device_info *hdi)
227{
228 return hdi->usage_page == 0xf1d0;
229}
230#else
231static bool
232is_fido(const struct hid_device_info *hdi)
233{
234 (void)hdi;
235 fido_log_debug("%s: assuming FIDO HID", __func__);
236 return true;
237}
238#endif
239
86void * 240void *
87fido_hid_open(const char *path) 241fido_hid_open(const char *path)
88{ 242{
89 return hid_open_path(path); 243 struct hid_hidapi *ctx;
244
245 if ((ctx = calloc(1, sizeof(*ctx))) == NULL) {
246 return (NULL);
247 }
248
249 if ((ctx->handle = hid_open_path(path)) == NULL) {
250 free(ctx);
251 return (NULL);
252 }
253
254 ctx->report_in_len = ctx->report_out_len = CTAP_MAX_REPORT_LEN;
255
256 return ctx;
90} 257}
91 258
92void 259void
93fido_hid_close(void *hid_dev_handle) 260fido_hid_close(void *handle)
94{ 261{
95 hid_close(hid_dev_handle); 262 struct hid_hidapi *ctx = handle;
263
264 hid_close(ctx->handle);
265 free(ctx);
96} 266}
97 267
98int 268int
99fido_hid_read(void *hid_dev_handle, unsigned char *buf, size_t len, int ms) 269fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms)
100{ 270{
101 return hid_read_timeout(hid_dev_handle, buf, len, ms); 271 struct hid_hidapi *ctx = handle;
272
273 if (len != ctx->report_in_len) {
274 fido_log_debug("%s: len %zu", __func__, len);
275 return -1;
276 }
277
278 return hid_read_timeout(ctx->handle, buf, len, ms);
102} 279}
103 280
104int 281int
105fido_hid_write(void *hid_dev_handle, const unsigned char *buf, size_t len) 282fido_hid_write(void *handle, const unsigned char *buf, size_t len)
106{ 283{
107 return hid_write(hid_dev_handle, buf, len); 284 struct hid_hidapi *ctx = handle;
285
286 if (len != ctx->report_out_len + 1) {
287 fido_log_debug("%s: len %zu", __func__, len);
288 return -1;
289 }
290
291 return hid_write(ctx->handle, buf, len);
108} 292}
109 293
110int 294int
@@ -122,10 +306,8 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
122 return FIDO_OK; /* nothing to do */ 306 return FIDO_OK; /* nothing to do */
123 307
124 for (struct hid_device_info *d = hdi; d != NULL; d = d->next) { 308 for (struct hid_device_info *d = hdi; d != NULL; d = d->next) {
125#if defined(_WIN32) || defined(__APPLE__) 309 if (is_fido(d) == false)
126 if (d->usage_page != 0xf1d0)
127 continue; 310 continue;
128#endif
129 if (copy_info(&devlist[*olen], d) == 0) { 311 if (copy_info(&devlist[*olen], d) == 0) {
130 if (++(*olen) == ilen) 312 if (++(*olen) == ilen)
131 break; 313 break;
@@ -136,3 +318,19 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
136 318
137 return FIDO_OK; 319 return FIDO_OK;
138} 320}
321
322size_t
323fido_hid_report_in_len(void *handle)
324{
325 struct hid_hidapi *ctx = handle;
326
327 return (ctx->report_in_len);
328}
329
330size_t
331fido_hid_report_out_len(void *handle)
332{
333 struct hid_hidapi *ctx = handle;
334
335 return (ctx->report_out_len);
336}
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 @@
8 8
9#include <sys/ioctl.h> 9#include <sys/ioctl.h>
10#include <linux/hidraw.h> 10#include <linux/hidraw.h>
11#include <linux/input.h>
11 12
13#include <errno.h>
12#include <fcntl.h> 14#include <fcntl.h>
13#include <libudev.h> 15#include <libudev.h>
16#include <poll.h>
14#include <string.h> 17#include <string.h>
15#include <unistd.h> 18#include <unistd.h>
16#include <errno.h>
17 19
18#include "fido.h" 20#include "fido.h"
19 21
20#define REPORT_LEN 65 22struct hid_linux {
23 int fd;
24 size_t report_in_len;
25 size_t report_out_len;
26};
21 27
22static int 28static int
23get_key_len(uint8_t tag, uint8_t *key, size_t *key_len) 29get_key_len(uint8_t tag, uint8_t *key, size_t *key_len)
@@ -63,11 +69,8 @@ static int
63get_usage_info(const struct hidraw_report_descriptor *hrd, uint32_t *usage_page, 69get_usage_info(const struct hidraw_report_descriptor *hrd, uint32_t *usage_page,
64 uint32_t *usage) 70 uint32_t *usage)
65{ 71{
66 const uint8_t *ptr; 72 const uint8_t *ptr = hrd->value;
67 size_t len; 73 size_t len = hrd->size;
68
69 ptr = hrd->value;
70 len = hrd->size;
71 74
72 while (len > 0) { 75 while (len > 0) {
73 const uint8_t tag = ptr[0]; 76 const uint8_t tag = ptr[0];
@@ -97,80 +100,113 @@ get_usage_info(const struct hidraw_report_descriptor *hrd, uint32_t *usage_page,
97} 100}
98 101
99static int 102static int
100get_report_descriptor(const char *path, struct hidraw_report_descriptor *hrd) 103get_report_sizes(const struct hidraw_report_descriptor *hrd,
104 size_t *report_in_len, size_t *report_out_len)
101{ 105{
102 int s = -1; 106 const uint8_t *ptr = hrd->value;
103 int fd; 107 size_t len = hrd->size;
104 int ok = -1; 108 uint32_t report_size = 0;
105 109
106 if ((fd = open(path, O_RDONLY)) < 0) { 110 while (len > 0) {
107 fido_log_debug("%s: open", __func__); 111 const uint8_t tag = ptr[0];
108 return (-1); 112 ptr++;
113 len--;
114
115 uint8_t key;
116 size_t key_len;
117 uint32_t key_val;
118
119 if (get_key_len(tag, &key, &key_len) < 0 || key_len > len ||
120 get_key_val(ptr, key_len, &key_val) < 0) {
121 return (-1);
122 }
123
124 if (key == 0x94) {
125 report_size = key_val;
126 } else if (key == 0x80) {
127 *report_in_len = (size_t)report_size;
128 } else if (key == 0x90) {
129 *report_out_len = (size_t)report_size;
130 }
131
132 ptr += key_len;
133 len -= key_len;
109 } 134 }
110 135
136 return (0);
137}
138
139static int
140get_report_descriptor(int fd, struct hidraw_report_descriptor *hrd)
141{
142 int s = -1;
143
111 if (ioctl(fd, HIDIOCGRDESCSIZE, &s) < 0 || s < 0 || 144 if (ioctl(fd, HIDIOCGRDESCSIZE, &s) < 0 || s < 0 ||
112 (unsigned)s > HID_MAX_DESCRIPTOR_SIZE) { 145 (unsigned)s > HID_MAX_DESCRIPTOR_SIZE) {
113 fido_log_debug("%s: ioctl HIDIOCGRDESCSIZE", __func__); 146 fido_log_debug("%s: ioctl HIDIOCGRDESCSIZE", __func__);
114 goto fail; 147 return (-1);
115 } 148 }
116 149
117 hrd->size = s; 150 hrd->size = (unsigned)s;
118 151
119 if (ioctl(fd, HIDIOCGRDESC, hrd) < 0) { 152 if (ioctl(fd, HIDIOCGRDESC, hrd) < 0) {
120 fido_log_debug("%s: ioctl HIDIOCGRDESC", __func__); 153 fido_log_debug("%s: ioctl HIDIOCGRDESC", __func__);
121 goto fail; 154 return (-1);
122 } 155 }
123 156
124 ok = 0; 157 return (0);
125fail:
126 if (fd != -1)
127 close(fd);
128
129 return (ok);
130} 158}
131 159
132static bool 160static bool
133is_fido(const char *path) 161is_fido(const char *path)
134{ 162{
163 int fd;
135 uint32_t usage = 0; 164 uint32_t usage = 0;
136 uint32_t usage_page = 0; 165 uint32_t usage_page = 0;
137 struct hidraw_report_descriptor hrd; 166 struct hidraw_report_descriptor hrd;
138 167
139 memset(&hrd, 0, sizeof(hrd)); 168 memset(&hrd, 0, sizeof(hrd));
140 169
141 if (get_report_descriptor(path, &hrd) < 0 || 170 if ((fd = open(path, O_RDONLY)) == -1) {
171 fido_log_debug("%s: open", __func__);
172 return (false);
173 }
174
175 if (get_report_descriptor(fd, &hrd) < 0 ||
142 get_usage_info(&hrd, &usage_page, &usage) < 0) { 176 get_usage_info(&hrd, &usage_page, &usage) < 0) {
177 close(fd);
143 return (false); 178 return (false);
144 } 179 }
145 180
181 close(fd);
182
146 return (usage_page == 0xf1d0); 183 return (usage_page == 0xf1d0);
147} 184}
148 185
149static int 186static int
150parse_uevent(struct udev_device *dev, int16_t *vendor_id, int16_t *product_id) 187parse_uevent(const char *uevent, int *bus, int16_t *vendor_id,
188 int16_t *product_id)
151{ 189{
152 const char *uevent;
153 char *cp; 190 char *cp;
154 char *p; 191 char *p;
155 char *s; 192 char *s;
156 int ok = -1; 193 int ok = -1;
157 short unsigned int x; 194 short unsigned int x;
158 short unsigned int y; 195 short unsigned int y;
159 196 short unsigned int z;
160 if ((uevent = udev_device_get_sysattr_value(dev, "uevent")) == NULL)
161 return (-1);
162 197
163 if ((s = cp = strdup(uevent)) == NULL) 198 if ((s = cp = strdup(uevent)) == NULL)
164 return (-1); 199 return (-1);
165 200
166 for ((p = strsep(&cp, "\n")); p && *p != '\0'; (p = strsep(&cp, "\n"))) { 201 while ((p = strsep(&cp, "\n")) != NULL && *p != '\0') {
167 if (strncmp(p, "HID_ID=", 7) == 0) { 202 if (strncmp(p, "HID_ID=", 7) == 0) {
168 if (sscanf(p + 7, "%*x:%hx:%hx", &x, &y) == 2) { 203 if (sscanf(p + 7, "%hx:%hx:%hx", &x, &y, &z) == 3) {
169 *vendor_id = (int16_t)x; 204 *bus = (int)x;
170 *product_id = (int16_t)y; 205 *vendor_id = (int16_t)y;
206 *product_id = (int16_t)z;
171 ok = 0; 207 ok = 0;
208 break;
172 } 209 }
173 break;
174 } 210 }
175 } 211 }
176 212
@@ -179,17 +215,36 @@ parse_uevent(struct udev_device *dev, int16_t *vendor_id, int16_t *product_id)
179 return (ok); 215 return (ok);
180} 216}
181 217
218static char *
219get_parent_attr(struct udev_device *dev, const char *subsystem,
220 const char *devtype, const char *attr)
221{
222 struct udev_device *parent;
223 const char *value;
224
225 if ((parent = udev_device_get_parent_with_subsystem_devtype(dev,
226 subsystem, devtype)) == NULL || (value =
227 udev_device_get_sysattr_value(parent, attr)) == NULL)
228 return (NULL);
229
230 return (strdup(value));
231}
232
233static char *
234get_usb_attr(struct udev_device *dev, const char *attr)
235{
236 return (get_parent_attr(dev, "usb", "usb_device", attr));
237}
238
182static int 239static int
183copy_info(fido_dev_info_t *di, struct udev *udev, 240copy_info(fido_dev_info_t *di, struct udev *udev,
184 struct udev_list_entry *udev_entry) 241 struct udev_list_entry *udev_entry)
185{ 242{
186 const char *name; 243 const char *name;
187 const char *path; 244 const char *path;
188 const char *manufacturer; 245 char *uevent = NULL;
189 const char *product;
190 struct udev_device *dev = NULL; 246 struct udev_device *dev = NULL;
191 struct udev_device *hid_parent; 247 int bus = 0;
192 struct udev_device *usb_parent;
193 int ok = -1; 248 int ok = -1;
194 249
195 memset(di, 0, sizeof(*di)); 250 memset(di, 0, sizeof(*di));
@@ -200,28 +255,24 @@ copy_info(fido_dev_info_t *di, struct udev *udev,
200 is_fido(path) == 0) 255 is_fido(path) == 0)
201 goto fail; 256 goto fail;
202 257
203 if ((hid_parent = udev_device_get_parent_with_subsystem_devtype(dev, 258 if ((uevent = get_parent_attr(dev, "hid", NULL, "uevent")) == NULL ||
204 "hid", NULL)) == NULL) 259 parse_uevent(uevent, &bus, &di->vendor_id, &di->product_id) < 0) {
205 goto fail; 260 fido_log_debug("%s: uevent", __func__);
206
207 if ((usb_parent = udev_device_get_parent_with_subsystem_devtype(dev,
208 "usb", "usb_device")) == NULL)
209 goto fail; 261 goto fail;
262 }
210 263
211 if (parse_uevent(hid_parent, &di->vendor_id, &di->product_id) < 0 || 264#ifndef FIDO_HID_ANY
212 (manufacturer = udev_device_get_sysattr_value(usb_parent, 265 if (bus != BUS_USB) {
213 "manufacturer")) == NULL || 266 fido_log_debug("%s: bus", __func__);
214 (product = udev_device_get_sysattr_value(usb_parent,
215 "product")) == NULL)
216 goto fail; 267 goto fail;
268 }
269#endif
217 270
218 di->path = strdup(path); 271 di->path = strdup(path);
219 di->manufacturer = strdup(manufacturer); 272 di->manufacturer = get_usb_attr(dev, "manufacturer");
220 di->product = strdup(product); 273 di->product = get_usb_attr(dev, "product");
221 274
222 if (di->path == NULL || 275 if (di->path == NULL || di->manufacturer == NULL || di->product == NULL)
223 di->manufacturer == NULL ||
224 di->product == NULL)
225 goto fail; 276 goto fail;
226 277
227 ok = 0; 278 ok = 0;
@@ -229,6 +280,8 @@ fail:
229 if (dev != NULL) 280 if (dev != NULL)
230 udev_device_unref(dev); 281 udev_device_unref(dev);
231 282
283 free(uevent);
284
232 if (ok < 0) { 285 if (ok < 0) {
233 free(di->path); 286 free(di->path);
234 free(di->manufacturer); 287 free(di->manufacturer);
@@ -261,9 +314,13 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
261 goto fail; 314 goto fail;
262 315
263 if (udev_enumerate_add_match_subsystem(udev_enum, "hidraw") < 0 || 316 if (udev_enumerate_add_match_subsystem(udev_enum, "hidraw") < 0 ||
264 udev_enumerate_scan_devices(udev_enum) < 0 || 317 udev_enumerate_scan_devices(udev_enum) < 0)
265 (udev_list = udev_enumerate_get_list_entry(udev_enum)) == NULL) 318 goto fail;
319
320 if ((udev_list = udev_enumerate_get_list_entry(udev_enum)) == NULL) {
321 r = FIDO_OK; /* zero hidraw devices */
266 goto fail; 322 goto fail;
323 }
267 324
268 udev_list_entry_foreach(udev_entry, udev_list) { 325 udev_list_entry_foreach(udev_entry, udev_list) {
269 if (copy_info(&devlist[*olen], udev, udev_entry) == 0) { 326 if (copy_info(&devlist[*olen], udev, udev_entry) == 0) {
@@ -291,60 +348,157 @@ fail:
291void * 348void *
292fido_hid_open(const char *path) 349fido_hid_open(const char *path)
293{ 350{
294 int *fd; 351 struct hid_linux *ctx;
352 struct hidraw_report_descriptor hrd;
353
354 if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
355 return (NULL);
295 356
296 if ((fd = malloc(sizeof(*fd))) == NULL || 357 if ((ctx->fd = open(path, O_RDWR)) < 0) {
297 (*fd = open(path, O_RDWR)) < 0) { 358 free(ctx);
298 free(fd);
299 return (NULL); 359 return (NULL);
300 } 360 }
301 361
302 return (fd); 362 if (get_report_descriptor(ctx->fd, &hrd) < 0 || get_report_sizes(&hrd,
363 &ctx->report_in_len, &ctx->report_out_len) < 0 ||
364 ctx->report_in_len == 0 || ctx->report_out_len == 0) {
365 fido_log_debug("%s: using default report sizes", __func__);
366 ctx->report_in_len = CTAP_MAX_REPORT_LEN;
367 ctx->report_out_len = CTAP_MAX_REPORT_LEN;
368 }
369
370 return (ctx);
303} 371}
304 372
305void 373void
306fido_hid_close(void *handle) 374fido_hid_close(void *handle)
307{ 375{
308 int *fd = handle; 376 struct hid_linux *ctx = handle;
377
378 close(ctx->fd);
379 free(ctx);
380}
381
382static int
383timespec_to_ms(const struct timespec *ts, int upper_bound)
384{
385 int64_t x;
386 int64_t y;
387
388 if (ts->tv_sec < 0 || ts->tv_sec > INT64_MAX / 1000LL ||
389 ts->tv_nsec < 0 || ts->tv_nsec / 1000000LL > INT64_MAX)
390 return (upper_bound);
391
392 x = ts->tv_sec * 1000LL;
393 y = ts->tv_nsec / 1000000LL;
394
395 if (INT64_MAX - x < y || x + y > upper_bound)
396 return (upper_bound);
397
398 return (int)(x + y);
399}
400
401static int
402waitfd(int fd, int ms)
403{
404 struct timespec ts_start;
405 struct timespec ts_now;
406 struct timespec ts_delta;
407 struct pollfd pfd;
408 int ms_remain;
409 int r;
410
411 if (ms < 0)
412 return (0);
413
414 memset(&pfd, 0, sizeof(pfd));
415 pfd.events = POLLIN;
416 pfd.fd = fd;
417
418 if (clock_gettime(CLOCK_MONOTONIC, &ts_start) != 0) {
419 fido_log_debug("%s: clock_gettime: %s", __func__,
420 strerror(errno));
421 return (-1);
422 }
423
424 for (ms_remain = ms; ms_remain > 0;) {
425 if ((r = poll(&pfd, 1, ms_remain)) > 0)
426 return (0);
427 else if (r == 0)
428 break;
429 else if (errno != EINTR) {
430 fido_log_debug("%s: poll: %s", __func__,
431 strerror(errno));
432 return (-1);
433 }
434 /* poll interrupted - subtract time already waited */
435 if (clock_gettime(CLOCK_MONOTONIC, &ts_now) != 0) {
436 fido_log_debug("%s: clock_gettime: %s", __func__,
437 strerror(errno));
438 return (-1);
439 }
440 timespecsub(&ts_now, &ts_start, &ts_delta);
441 ms_remain = ms - timespec_to_ms(&ts_delta, ms);
442 }
309 443
310 close(*fd); 444 return (-1);
311 free(fd);
312} 445}
313 446
314int 447int
315fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) 448fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms)
316{ 449{
317 int *fd = handle; 450 struct hid_linux *ctx = handle;
318 ssize_t r; 451 ssize_t r;
319 452
320 (void)ms; /* XXX */ 453 if (len != ctx->report_in_len) {
454 fido_log_debug("%s: len %zu", __func__, len);
455 return (-1);
456 }
321 457
322 if (len != REPORT_LEN - 1) { 458 if (waitfd(ctx->fd, ms) < 0) {
323 fido_log_debug("%s: invalid len", __func__); 459 fido_log_debug("%s: fd not ready", __func__);
324 return (-1); 460 return (-1);
325 } 461 }
326 462
327 if ((r = read(*fd, buf, len)) < 0 || r != REPORT_LEN - 1) 463 if ((r = read(ctx->fd, buf, len)) < 0 || (size_t)r != len) {
464 fido_log_debug("%s: read", __func__);
328 return (-1); 465 return (-1);
466 }
329 467
330 return (REPORT_LEN - 1); 468 return ((int)r);
331} 469}
332 470
333int 471int
334fido_hid_write(void *handle, const unsigned char *buf, size_t len) 472fido_hid_write(void *handle, const unsigned char *buf, size_t len)
335{ 473{
336 int *fd = handle; 474 struct hid_linux *ctx = handle;
337 ssize_t r; 475 ssize_t r;
338 476
339 if (len != REPORT_LEN) { 477 if (len != ctx->report_out_len + 1) {
340 fido_log_debug("%s: invalid len", __func__); 478 fido_log_debug("%s: len %zu", __func__, len);
341 return (-1); 479 return (-1);
342 } 480 }
343 481
344 if ((r = write(*fd, buf, len)) < 0 || r != REPORT_LEN) { 482 if ((r = write(ctx->fd, buf, len)) < 0 || (size_t)r != len) {
345 fido_log_debug("%s: write", __func__); 483 fido_log_debug("%s: write", __func__);
346 return (-1); 484 return (-1);
347 } 485 }
348 486
349 return (REPORT_LEN); 487 return ((int)r);
488}
489
490size_t
491fido_hid_report_in_len(void *handle)
492{
493 struct hid_linux *ctx = handle;
494
495 return (ctx->report_in_len);
496}
497
498size_t
499fido_hid_report_out_len(void *handle)
500{
501 struct hid_linux *ctx = handle;
502
503 return (ctx->report_out_len);
350} 504}
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 @@
8 8
9#include <sys/ioctl.h> 9#include <sys/ioctl.h>
10#include <dev/usb/usb.h> 10#include <dev/usb/usb.h>
11#include <dev/usb/usbhid.h>
12 11
13#include <errno.h> 12#include <errno.h>
14#include <fcntl.h> 13#include <fcntl.h>
15#include <string.h> 14#include <string.h>
16#include <unistd.h> 15#include <unistd.h>
17#include <usbhid.h>
18#include <poll.h> 16#include <poll.h>
19 17
20#include "fido.h" 18#include "fido.h"
21 19
22#define MAX_UHID 64 20#define MAX_UHID 64
23#define MAX_REPORT_LEN (sizeof(((struct usb_ctl_report *)(NULL))->ucr_data))
24 21
25struct hid_openbsd { 22struct hid_openbsd {
26 int fd; 23 int fd;
@@ -33,11 +30,8 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
33{ 30{
34 size_t i; 31 size_t i;
35 char path[64]; 32 char path[64];
36 int is_fido, fd; 33 int fd;
37 struct usb_device_info udi; 34 struct usb_device_info udi;
38 report_desc_t rdesc = NULL;
39 hid_data_t hdata = NULL;
40 hid_item_t hitem;
41 fido_dev_info_t *di; 35 fido_dev_info_t *di;
42 36
43 if (ilen == 0) 37 if (ilen == 0)
@@ -47,7 +41,7 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
47 return (FIDO_ERR_INVALID_ARGUMENT); 41 return (FIDO_ERR_INVALID_ARGUMENT);
48 42
49 for (i = *olen = 0; i < MAX_UHID && *olen < ilen; i++) { 43 for (i = *olen = 0; i < MAX_UHID && *olen < ilen; i++) {
50 snprintf(path, sizeof(path), "/dev/uhid%zu", i); 44 snprintf(path, sizeof(path), "/dev/fido/%zu", i);
51 if ((fd = open(path, O_RDWR)) == -1) { 45 if ((fd = open(path, O_RDWR)) == -1) {
52 if (errno != ENOENT && errno != ENXIO) { 46 if (errno != ENOENT && errno != ENXIO) {
53 fido_log_debug("%s: open %s: %s", __func__, 47 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)
55 } 49 }
56 continue; 50 continue;
57 } 51 }
52
58 memset(&udi, 0, sizeof(udi)); 53 memset(&udi, 0, sizeof(udi));
59 if (ioctl(fd, USB_GET_DEVICEINFO, &udi) != 0) { 54 if (ioctl(fd, USB_GET_DEVICEINFO, &udi) != 0) {
60 fido_log_debug("%s: get device info %s: %s", __func__, 55 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)
62 close(fd); 57 close(fd);
63 continue; 58 continue;
64 } 59 }
65 if ((rdesc = hid_get_report_desc(fd)) == NULL) {
66 fido_log_debug("%s: failed to get report descriptor: %s",
67 __func__, path);
68 close(fd);
69 continue;
70 }
71 if ((hdata = hid_start_parse(rdesc,
72 1<<hid_collection, -1)) == NULL) {
73 fido_log_debug("%s: failed to parse report descriptor: %s",
74 __func__, path);
75 hid_dispose_report_desc(rdesc);
76 close(fd);
77 continue;
78 }
79 is_fido = 0;
80 for (is_fido = 0; !is_fido;) {
81 memset(&hitem, 0, sizeof(hitem));
82 if (hid_get_item(hdata, &hitem) <= 0)
83 break;
84 if ((hitem._usage_page & 0xFFFF0000) == 0xf1d00000)
85 is_fido = 1;
86 }
87 hid_end_parse(hdata);
88 hid_dispose_report_desc(rdesc);
89 close(fd); 60 close(fd);
90 61
91 if (!is_fido)
92 continue;
93
94 fido_log_debug("%s: %s: bus = 0x%02x, addr = 0x%02x", 62 fido_log_debug("%s: %s: bus = 0x%02x, addr = 0x%02x",
95 __func__, path, udi.udi_bus, udi.udi_addr); 63 __func__, path, udi.udi_bus, udi.udi_addr);
96 fido_log_debug("%s: %s: vendor = \"%s\", product = \"%s\"", 64 fido_log_debug("%s: %s: vendor = \"%s\", product = \"%s\"",
@@ -116,8 +84,8 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
116 explicit_bzero(di, sizeof(*di)); 84 explicit_bzero(di, sizeof(*di));
117 return FIDO_ERR_INTERNAL; 85 return FIDO_ERR_INTERNAL;
118 } 86 }
119 di->vendor_id = udi.udi_vendorNo; 87 di->vendor_id = (int16_t)udi.udi_vendorNo;
120 di->product_id = udi.udi_productNo; 88 di->product_id = (int16_t)udi.udi_productNo;
121 (*olen)++; 89 (*olen)++;
122 } 90 }
123 91
@@ -184,42 +152,15 @@ void *
184fido_hid_open(const char *path) 152fido_hid_open(const char *path)
185{ 153{
186 struct hid_openbsd *ret = NULL; 154 struct hid_openbsd *ret = NULL;
187 report_desc_t rdesc = NULL;
188 int len, usb_report_id = 0;
189 155
190 if ((ret = calloc(1, sizeof(*ret))) == NULL || 156 if ((ret = calloc(1, sizeof(*ret))) == NULL ||
191 (ret->fd = open(path, O_RDWR)) < 0) { 157 (ret->fd = open(path, O_RDWR)) < 0) {
192 free(ret); 158 free(ret);
193 return (NULL); 159 return (NULL);
194 } 160 }
195 if (ioctl(ret->fd, USB_GET_REPORT_ID, &usb_report_id) != 0) { 161 ret->report_in_len = ret->report_out_len = CTAP_MAX_REPORT_LEN;
196 fido_log_debug("%s: failed to get report ID: %s", __func__, 162 fido_log_debug("%s: inlen = %zu outlen = %zu", __func__,
197 strerror(errno)); 163 ret->report_in_len, ret->report_out_len);
198 goto fail;
199 }
200 if ((rdesc = hid_get_report_desc(ret->fd)) == NULL) {
201 fido_log_debug("%s: failed to get report descriptor", __func__);
202 goto fail;
203 }
204 if ((len = hid_report_size(rdesc, hid_input, usb_report_id)) <= 0 ||
205 (size_t)len > MAX_REPORT_LEN) {
206 fido_log_debug("%s: bad input report size %d", __func__, len);
207 goto fail;
208 }
209 ret->report_in_len = (size_t)len;
210 if ((len = hid_report_size(rdesc, hid_output, usb_report_id)) <= 0 ||
211 (size_t)len > MAX_REPORT_LEN) {
212 fido_log_debug("%s: bad output report size %d", __func__, len);
213 fail:
214 hid_dispose_report_desc(rdesc);
215 close(ret->fd);
216 free(ret);
217 return NULL;
218 }
219 ret->report_out_len = (size_t)len;
220 hid_dispose_report_desc(rdesc);
221 fido_log_debug("%s: USB report ID %d, inlen = %zu outlen = %zu",
222 __func__, usb_report_id, ret->report_in_len, ret->report_out_len);
223 164
224 /* 165 /*
225 * OpenBSD (as of 201910) has a bug that causes it to lose 166 * 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)
281 } 222 }
282 return ((int)len); 223 return ((int)len);
283} 224}
225
226size_t
227fido_hid_report_in_len(void *handle)
228{
229 struct hid_openbsd *ctx = handle;
230
231 return (ctx->report_in_len);
232}
233
234size_t
235fido_hid_report_out_len(void *handle)
236{
237 struct hid_openbsd *ctx = handle;
238
239 return (ctx->report_out_len);
240}
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 @@
19 19
20#include "fido.h" 20#include "fido.h"
21 21
22#define REPORT_LEN 65 22struct hid_osx {
23
24struct dev {
25 IOHIDDeviceRef ref; 23 IOHIDDeviceRef ref;
26 CFStringRef loop_id; 24 CFStringRef loop_id;
25 int report_pipe[2];
26 size_t report_in_len;
27 size_t report_out_len;
28 unsigned char report[CTAP_MAX_REPORT_LEN];
27}; 29};
28 30
29static int 31static int
@@ -64,7 +66,8 @@ get_utf8(IOHIDDeviceRef dev, CFStringRef key, void *buf, size_t len)
64 return (-1); 66 return (-1);
65 } 67 }
66 68
67 if (CFStringGetCString(ref, buf, len, kCFStringEncodingUTF8) == false) { 69 if (CFStringGetCString(ref, buf, (long)len,
70 kCFStringEncodingUTF8) == false) {
68 fido_log_debug("%s: CFStringGetCString", __func__); 71 fido_log_debug("%s: CFStringGetCString", __func__);
69 return (-1); 72 return (-1);
70 } 73 }
@@ -72,30 +75,35 @@ get_utf8(IOHIDDeviceRef dev, CFStringRef key, void *buf, size_t len)
72 return (0); 75 return (0);
73} 76}
74 77
75static bool 78static int
76is_fido(IOHIDDeviceRef dev) 79get_report_len(IOHIDDeviceRef dev, int dir, size_t *report_len)
77{ 80{
78 uint32_t usage_page; 81 CFStringRef key;
79 int32_t report_len; 82 int32_t v;
80 83
81 if (get_int32(dev, CFSTR(kIOHIDPrimaryUsagePageKey), 84 if (dir == 0)
82 (int32_t *)&usage_page) != 0 || usage_page != 0xf1d0) 85 key = CFSTR(kIOHIDMaxInputReportSizeKey);
83 return (false); 86 else
87 key = CFSTR(kIOHIDMaxOutputReportSizeKey);
84 88
85 if (get_int32(dev, CFSTR(kIOHIDMaxInputReportSizeKey), 89 if (get_int32(dev, key, &v) < 0) {
86 &report_len) < 0 || report_len != REPORT_LEN - 1) { 90 fido_log_debug("%s: get_int32/%d", __func__, dir);
87 fido_log_debug("%s: unsupported report len", __func__); 91 return (-1);
88 return (false);
89 } 92 }
90 93
91 return (true); 94 if ((*report_len = (size_t)v) > CTAP_MAX_REPORT_LEN) {
95 fido_log_debug("%s: report_len=%zu", __func__, *report_len);
96 return (-1);
97 }
98
99 return (0);
92} 100}
93 101
94static int 102static int
95get_id(IOHIDDeviceRef dev, int16_t *vendor_id, int16_t *product_id) 103get_id(IOHIDDeviceRef dev, int16_t *vendor_id, int16_t *product_id)
96{ 104{
97 int32_t vendor; 105 int32_t vendor;
98 int32_t product; 106 int32_t product;
99 107
100 if (get_int32(dev, CFSTR(kIOHIDVendorIDKey), &vendor) < 0 || 108 if (get_int32(dev, CFSTR(kIOHIDVendorIDKey), &vendor) < 0 ||
101 vendor > UINT16_MAX) { 109 vendor > UINT16_MAX) {
@@ -175,6 +183,31 @@ get_path(IOHIDDeviceRef dev)
175 return (strdup(path)); 183 return (strdup(path));
176} 184}
177 185
186static bool
187is_fido(IOHIDDeviceRef dev)
188{
189 char buf[32];
190 uint32_t usage_page;
191
192 if (get_int32(dev, CFSTR(kIOHIDPrimaryUsagePageKey),
193 (int32_t *)&usage_page) < 0 || usage_page != 0xf1d0)
194 return (false);
195
196 if (get_utf8(dev, CFSTR(kIOHIDTransportKey), buf, sizeof(buf)) < 0) {
197 fido_log_debug("%s: get_utf8 transport", __func__);
198 return (false);
199 }
200
201#ifndef FIDO_HID_ANY
202 if (strcasecmp(buf, "usb") != 0) {
203 fido_log_debug("%s: transport", __func__);
204 return (false);
205 }
206#endif
207
208 return (true);
209}
210
178static int 211static int
179copy_info(fido_dev_info_t *di, IOHIDDeviceRef dev) 212copy_info(fido_dev_info_t *di, IOHIDDeviceRef dev)
180{ 213{
@@ -199,11 +232,12 @@ copy_info(fido_dev_info_t *di, IOHIDDeviceRef dev)
199int 232int
200fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) 233fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
201{ 234{
202 IOHIDManagerRef manager = NULL; 235 IOHIDManagerRef manager = NULL;
203 CFSetRef devset = NULL; 236 CFSetRef devset = NULL;
204 CFIndex devcnt; 237 size_t devcnt;
205 IOHIDDeviceRef *devs = NULL; 238 CFIndex n;
206 int r = FIDO_ERR_INTERNAL; 239 IOHIDDeviceRef *devs = NULL;
240 int r = FIDO_ERR_INTERNAL;
207 241
208 *olen = 0; 242 *olen = 0;
209 243
@@ -226,11 +260,13 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
226 goto fail; 260 goto fail;
227 } 261 }
228 262
229 if ((devcnt = CFSetGetCount(devset)) < 0) { 263 if ((n = CFSetGetCount(devset)) < 0) {
230 fido_log_debug("%s: CFSetGetCount", __func__); 264 fido_log_debug("%s: CFSetGetCount", __func__);
231 goto fail; 265 goto fail;
232 } 266 }
233 267
268 devcnt = (size_t)n;
269
234 if ((devs = calloc(devcnt, sizeof(*devs))) == NULL) { 270 if ((devs = calloc(devcnt, sizeof(*devs))) == NULL) {
235 fido_log_debug("%s: calloc", __func__); 271 fido_log_debug("%s: calloc", __func__);
236 goto fail; 272 goto fail;
@@ -238,7 +274,7 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
238 274
239 CFSetGetValues(devset, (void *)devs); 275 CFSetGetValues(devset, (void *)devs);
240 276
241 for (CFIndex i = 0; i < devcnt; i++) { 277 for (size_t i = 0; i < devcnt; i++) {
242 if (copy_info(&devlist[*olen], devs[i]) == 0) { 278 if (copy_info(&devlist[*olen], devs[i]) == 0) {
243 devlist[*olen].io = (fido_dev_io_t) { 279 devlist[*olen].io = (fido_dev_io_t) {
244 fido_hid_open, 280 fido_hid_open,
@@ -263,157 +299,258 @@ fail:
263 return (r); 299 return (r);
264} 300}
265 301
302static void
303report_callback(void *context, IOReturn result, void *dev, IOHIDReportType type,
304 uint32_t id, uint8_t *ptr, CFIndex len)
305{
306 struct hid_osx *ctx = context;
307 ssize_t r;
308
309 (void)dev;
310
311 if (result != kIOReturnSuccess || type != kIOHIDReportTypeInput ||
312 id != 0 || len < 0 || (size_t)len != ctx->report_in_len) {
313 fido_log_debug("%s: io error", __func__);
314 return;
315 }
316
317 if ((r = write(ctx->report_pipe[1], ptr, (size_t)len)) < 0 ||
318 (size_t)r != (size_t)len) {
319 fido_log_debug("%s: write", __func__);
320 return;
321 }
322}
323
324static void
325removal_callback(void *context, IOReturn result, void *sender)
326{
327 (void)context;
328 (void)result;
329 (void)sender;
330
331 CFRunLoopStop(CFRunLoopGetMain());
332}
333
334static int
335set_nonblock(int fd)
336{
337 int flags;
338
339 if ((flags = fcntl(fd, F_GETFL)) == -1) {
340 fido_log_debug("%s: fcntl F_GETFL", __func__);
341 return (-1);
342 }
343
344 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
345 fido_log_debug("%s: fcntl, F_SETFL", __func__);
346 return (-1);
347 }
348
349 return (0);
350}
351
352static int
353disable_sigpipe(int fd)
354{
355 int disabled = 1;
356
357 if (fcntl(fd, F_SETNOSIGPIPE, &disabled) == -1) {
358 fido_log_debug("%s: fcntl F_SETNOSIGPIPE", __func__);
359 return (-1);
360 }
361
362 return (0);
363}
364
266void * 365void *
267fido_hid_open(const char *path) 366fido_hid_open(const char *path)
268{ 367{
368 struct hid_osx *ctx;
269 io_registry_entry_t entry = MACH_PORT_NULL; 369 io_registry_entry_t entry = MACH_PORT_NULL;
270 struct dev *dev = NULL; 370 char loop_id[32];
271 int ok = -1; 371 int ok = -1;
272 int r; 372 int r;
273 char loop_id[32];
274 373
275 if ((dev = calloc(1, sizeof(*dev))) == NULL) { 374 if ((ctx = calloc(1, sizeof(*ctx))) == NULL) {
276 fido_log_debug("%s: calloc", __func__); 375 fido_log_debug("%s: calloc", __func__);
277 goto fail; 376 goto fail;
278 } 377 }
279 378
379 ctx->report_pipe[0] = -1;
380 ctx->report_pipe[1] = -1;
381
382 if (pipe(ctx->report_pipe) == -1) {
383 fido_log_debug("%s: pipe", __func__);
384 goto fail;
385 }
386
387 if (set_nonblock(ctx->report_pipe[0]) < 0 ||
388 set_nonblock(ctx->report_pipe[1]) < 0) {
389 fido_log_debug("%s: set_nonblock", __func__);
390 goto fail;
391 }
392
393 if (disable_sigpipe(ctx->report_pipe[1]) < 0) {
394 fido_log_debug("%s: disable_sigpipe", __func__);
395 goto fail;
396 }
397
280 if ((entry = IORegistryEntryFromPath(kIOMasterPortDefault, 398 if ((entry = IORegistryEntryFromPath(kIOMasterPortDefault,
281 path)) == MACH_PORT_NULL) { 399 path)) == MACH_PORT_NULL) {
282 fido_log_debug("%s: IORegistryEntryFromPath", __func__); 400 fido_log_debug("%s: IORegistryEntryFromPath", __func__);
283 goto fail; 401 goto fail;
284 } 402 }
285 403
286 if ((dev->ref = IOHIDDeviceCreate(kCFAllocatorDefault, 404 if ((ctx->ref = IOHIDDeviceCreate(kCFAllocatorDefault,
287 entry)) == NULL) { 405 entry)) == NULL) {
288 fido_log_debug("%s: IOHIDDeviceCreate", __func__); 406 fido_log_debug("%s: IOHIDDeviceCreate", __func__);
289 goto fail; 407 goto fail;
290 } 408 }
291 409
292 if (IOHIDDeviceOpen(dev->ref, 410 if (get_report_len(ctx->ref, 0, &ctx->report_in_len) < 0 ||
411 get_report_len(ctx->ref, 1, &ctx->report_out_len) < 0) {
412 fido_log_debug("%s: get_report_len", __func__);
413 goto fail;
414 }
415
416 if (ctx->report_in_len > sizeof(ctx->report)) {
417 fido_log_debug("%s: report_in_len=%zu", __func__,
418 ctx->report_in_len);
419 goto fail;
420 }
421
422 if (IOHIDDeviceOpen(ctx->ref,
293 kIOHIDOptionsTypeSeizeDevice) != kIOReturnSuccess) { 423 kIOHIDOptionsTypeSeizeDevice) != kIOReturnSuccess) {
294 fido_log_debug("%s: IOHIDDeviceOpen", __func__); 424 fido_log_debug("%s: IOHIDDeviceOpen", __func__);
295 goto fail; 425 goto fail;
296 } 426 }
297 427
298 if ((r = snprintf(loop_id, sizeof(loop_id), "fido2-%p", 428 if ((r = snprintf(loop_id, sizeof(loop_id), "fido2-%p",
299 (void *)dev->ref)) < 0 || (size_t)r >= sizeof(loop_id)) { 429 (void *)ctx->ref)) < 0 || (size_t)r >= sizeof(loop_id)) {
300 fido_log_debug("%s: snprintf", __func__); 430 fido_log_debug("%s: snprintf", __func__);
301 goto fail; 431 goto fail;
302 } 432 }
303 433
304 if ((dev->loop_id = CFStringCreateWithCString(NULL, loop_id, 434 if ((ctx->loop_id = CFStringCreateWithCString(NULL, loop_id,
305 kCFStringEncodingASCII)) == NULL) { 435 kCFStringEncodingASCII)) == NULL) {
306 fido_log_debug("%s: CFStringCreateWithCString", __func__); 436 fido_log_debug("%s: CFStringCreateWithCString", __func__);
307 goto fail; 437 goto fail;
308 } 438 }
309 439
440 IOHIDDeviceRegisterInputReportCallback(ctx->ref, ctx->report,
441 (long)ctx->report_in_len, &report_callback, ctx);
442 IOHIDDeviceRegisterRemovalCallback(ctx->ref, &removal_callback, ctx);
443 IOHIDDeviceScheduleWithRunLoop(ctx->ref, CFRunLoopGetMain(),
444 ctx->loop_id);
445
310 ok = 0; 446 ok = 0;
311fail: 447fail:
312 if (entry != MACH_PORT_NULL) 448 if (entry != MACH_PORT_NULL)
313 IOObjectRelease(entry); 449 IOObjectRelease(entry);
314 450
315 if (ok < 0 && dev != NULL) { 451 if (ok < 0 && ctx != NULL) {
316 if (dev->ref != NULL) 452 if (ctx->ref != NULL)
317 CFRelease(dev->ref); 453 CFRelease(ctx->ref);
318 if (dev->loop_id != NULL) 454 if (ctx->loop_id != NULL)
319 CFRelease(dev->loop_id); 455 CFRelease(ctx->loop_id);
320 free(dev); 456 if (ctx->report_pipe[0] != -1)
321 dev = NULL; 457 close(ctx->report_pipe[0]);
458 if (ctx->report_pipe[1] != -1)
459 close(ctx->report_pipe[1]);
460 free(ctx);
461 ctx = NULL;
322 } 462 }
323 463
324 return (dev); 464 return (ctx);
325} 465}
326 466
327void 467void
328fido_hid_close(void *handle) 468fido_hid_close(void *handle)
329{ 469{
330 struct dev *dev = handle; 470 struct hid_osx *ctx = handle;
471
472 IOHIDDeviceRegisterInputReportCallback(ctx->ref, ctx->report,
473 (long)ctx->report_in_len, NULL, ctx);
474 IOHIDDeviceRegisterRemovalCallback(ctx->ref, NULL, NULL);
475 IOHIDDeviceUnscheduleFromRunLoop(ctx->ref, CFRunLoopGetMain(),
476 ctx->loop_id);
331 477
332 if (IOHIDDeviceClose(dev->ref, 478 if (IOHIDDeviceClose(ctx->ref,
333 kIOHIDOptionsTypeSeizeDevice) != kIOReturnSuccess) 479 kIOHIDOptionsTypeSeizeDevice) != kIOReturnSuccess)
334 fido_log_debug("%s: IOHIDDeviceClose", __func__); 480 fido_log_debug("%s: IOHIDDeviceClose", __func__);
335 481
336 CFRelease(dev->ref); 482 CFRelease(ctx->ref);
337 CFRelease(dev->loop_id); 483 CFRelease(ctx->loop_id);
338
339 free(dev);
340}
341 484
342static void 485 explicit_bzero(ctx->report, sizeof(ctx->report));
343read_callback(void *context, IOReturn result, void *dev, IOHIDReportType type, 486 close(ctx->report_pipe[0]);
344 uint32_t report_id, uint8_t *report, CFIndex report_len) 487 close(ctx->report_pipe[1]);
345{
346 (void)context;
347 (void)dev;
348 (void)report;
349 488
350 if (result != kIOReturnSuccess || type != kIOHIDReportTypeInput || 489 free(ctx);
351 report_id != 0 || report_len != REPORT_LEN - 1) {
352 fido_log_debug("%s: io error", __func__);
353 }
354}
355
356static void
357removal_callback(void *context, IOReturn result, void *sender)
358{
359 (void)context;
360 (void)result;
361 (void)sender;
362
363 CFRunLoopStop(CFRunLoopGetCurrent());
364} 490}
365 491
366int 492int
367fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) 493fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms)
368{ 494{
369 struct dev *dev = handle; 495 struct hid_osx *ctx = handle;
370 CFRunLoopRunResult r; 496 ssize_t r;
371 497
372 (void)ms; /* XXX */ 498 explicit_bzero(buf, len);
499 explicit_bzero(ctx->report, sizeof(ctx->report));
373 500
374 if (len != REPORT_LEN - 1) { 501 if (len != ctx->report_in_len || len > sizeof(ctx->report)) {
375 fido_log_debug("%s: invalid len", __func__); 502 fido_log_debug("%s: len %zu", __func__, len);
376 return (-1); 503 return (-1);
377 } 504 }
378 505
379 explicit_bzero(buf, len); 506 if (ms == -1)
380 507 ms = 5000; /* wait 5 seconds by default */
381 IOHIDDeviceRegisterInputReportCallback(dev->ref, buf, len,
382 &read_callback, NULL);
383 IOHIDDeviceRegisterRemovalCallback(dev->ref, &removal_callback, dev);
384 IOHIDDeviceScheduleWithRunLoop(dev->ref, CFRunLoopGetCurrent(),
385 dev->loop_id);
386 508
387 r = CFRunLoopRunInMode(dev->loop_id, 0.3, true); 509 if (CFRunLoopGetCurrent() != CFRunLoopGetMain())
510 fido_log_debug("%s: CFRunLoopGetCurrent != CFRunLoopGetMain",
511 __func__);
388 512
389 IOHIDDeviceRegisterInputReportCallback(dev->ref, buf, len, NULL, NULL); 513 CFRunLoopRunInMode(ctx->loop_id, (double)ms/1000.0, true);
390 IOHIDDeviceRegisterRemovalCallback(dev->ref, NULL, NULL);
391 IOHIDDeviceUnscheduleFromRunLoop(dev->ref, CFRunLoopGetCurrent(),
392 dev->loop_id);
393 514
394 if (r != kCFRunLoopRunHandledSource) { 515 if ((r = read(ctx->report_pipe[0], buf, len)) < 0 || (size_t)r != len) {
395 fido_log_debug("%s: CFRunLoopRunInMode=%d", __func__, (int)r); 516 fido_log_debug("%s: read", __func__);
396 return (-1); 517 return (-1);
397 } 518 }
398 519
399 return (REPORT_LEN - 1); 520 return ((int)len);
400} 521}
401 522
402int 523int
403fido_hid_write(void *handle, const unsigned char *buf, size_t len) 524fido_hid_write(void *handle, const unsigned char *buf, size_t len)
404{ 525{
405 struct dev *dev = handle; 526 struct hid_osx *ctx = handle;
406 527
407 if (len != REPORT_LEN) { 528 if (len != ctx->report_out_len + 1 || len > LONG_MAX) {
408 fido_log_debug("%s: invalid len", __func__); 529 fido_log_debug("%s: len %zu", __func__, len);
409 return (-1); 530 return (-1);
410 } 531 }
411 532
412 if (IOHIDDeviceSetReport(dev->ref, kIOHIDReportTypeOutput, 0, buf + 1, 533 if (IOHIDDeviceSetReport(ctx->ref, kIOHIDReportTypeOutput, 0, buf + 1,
413 len - 1) != kIOReturnSuccess) { 534 (long)(len - 1)) != kIOReturnSuccess) {
414 fido_log_debug("%s: IOHIDDeviceSetReport", __func__); 535 fido_log_debug("%s: IOHIDDeviceSetReport", __func__);
415 return (-1); 536 return (-1);
416 } 537 }
417 538
418 return (REPORT_LEN); 539 return ((int)len);
540}
541
542size_t
543fido_hid_report_in_len(void *handle)
544{
545 struct hid_osx *ctx = handle;
546
547 return (ctx->report_in_len);
548}
549
550size_t
551fido_hid_report_out_len(void *handle)
552{
553 struct hid_osx *ctx = handle;
554
555 return (ctx->report_out_len);
419} 556}
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 @@
14#include <windows.h> 14#include <windows.h>
15#include <setupapi.h> 15#include <setupapi.h>
16#include <initguid.h> 16#include <initguid.h>
17#include <devpkey.h>
18#include <devpropdef.h>
17#include <hidclass.h> 19#include <hidclass.h>
18#include <hidsdi.h> 20#include <hidsdi.h>
19 21
20#include "fido.h" 22#include "fido.h"
21 23
22#define REPORT_LEN 65 24#if defined(__MINGW32__) && __MINGW64_VERSION_MAJOR < 6
25WINSETUPAPI WINBOOL WINAPI SetupDiGetDevicePropertyW(HDEVINFO,
26 PSP_DEVINFO_DATA, const DEVPROPKEY *, DEVPROPTYPE *, PBYTE,
27 DWORD, PDWORD, DWORD);
28#endif
29
30#if defined(__MINGW32__)
31DEFINE_DEVPROPKEY(DEVPKEY_Device_Parent, 0x4340a6c5, 0x93fa, 0x4706, 0x97,
32 0x2c, 0x7b, 0x64, 0x80, 0x08, 0xa5, 0xa7, 8);
33#endif
34
35struct hid_win {
36 HANDLE dev;
37 OVERLAPPED overlap;
38 int report_pending;
39 size_t report_in_len;
40 size_t report_out_len;
41 unsigned char report[1 + CTAP_MAX_REPORT_LEN];
42};
23 43
24static bool 44static bool
25is_fido(HANDLE dev) 45is_fido(HANDLE dev)
26{ 46{
27 PHIDP_PREPARSED_DATA data = NULL; 47 PHIDP_PREPARSED_DATA data = NULL;
28 HIDP_CAPS caps; 48 HIDP_CAPS caps;
29 uint16_t usage_page = 0; 49 int fido = 0;
30 50
31 if (HidD_GetPreparsedData(dev, &data) == false) { 51 if (HidD_GetPreparsedData(dev, &data) == false) {
32 fido_log_debug("%s: HidD_GetPreparsedData", __func__); 52 fido_log_debug("%s: HidD_GetPreparsedData", __func__);
@@ -38,18 +58,48 @@ is_fido(HANDLE dev)
38 goto fail; 58 goto fail;
39 } 59 }
40 60
41 if (caps.OutputReportByteLength != REPORT_LEN || 61 fido = (uint16_t)caps.UsagePage == 0xf1d0;
42 caps.InputReportByteLength != REPORT_LEN) { 62fail:
43 fido_log_debug("%s: unsupported report len", __func__); 63 if (data != NULL)
64 HidD_FreePreparsedData(data);
65
66 return (fido);
67}
68
69static int
70get_report_len(HANDLE dev, int dir, size_t *report_len)
71{
72 PHIDP_PREPARSED_DATA data = NULL;
73 HIDP_CAPS caps;
74 USHORT v;
75 int ok = -1;
76
77 if (HidD_GetPreparsedData(dev, &data) == false) {
78 fido_log_debug("%s: HidD_GetPreparsedData/%d", __func__, dir);
44 goto fail; 79 goto fail;
45 } 80 }
46 81
47 usage_page = caps.UsagePage; 82 if (HidP_GetCaps(data, &caps) != HIDP_STATUS_SUCCESS) {
83 fido_log_debug("%s: HidP_GetCaps/%d", __func__, dir);
84 goto fail;
85 }
86
87 if (dir == 0)
88 v = caps.InputReportByteLength;
89 else
90 v = caps.OutputReportByteLength;
91
92 if ((*report_len = (size_t)v) == 0) {
93 fido_log_debug("%s: report_len == 0", __func__);
94 goto fail;
95 }
96
97 ok = 0;
48fail: 98fail:
49 if (data != NULL) 99 if (data != NULL)
50 HidD_FreePreparsedData(data); 100 HidD_FreePreparsedData(data);
51 101
52 return (usage_page == 0xf1d0); 102 return (ok);
53} 103}
54 104
55static int 105static int
@@ -59,13 +109,14 @@ get_int(HANDLE dev, int16_t *vendor_id, int16_t *product_id)
59 109
60 attr.Size = sizeof(attr); 110 attr.Size = sizeof(attr);
61 111
62 if (HidD_GetAttributes(dev, &attr) == false) { 112 if (HidD_GetAttributes(dev, &attr) == false ||
113 attr.VendorID > INT16_MAX || attr.ProductID > INT16_MAX) {
63 fido_log_debug("%s: HidD_GetAttributes", __func__); 114 fido_log_debug("%s: HidD_GetAttributes", __func__);
64 return (-1); 115 return (-1);
65 } 116 }
66 117
67 *vendor_id = attr.VendorID; 118 *vendor_id = (int16_t)attr.VendorID;
68 *product_id = attr.ProductID; 119 *product_id = (int16_t)attr.ProductID;
69 120
70 return (0); 121 return (0);
71} 122}
@@ -91,7 +142,7 @@ get_str(HANDLE dev, char **manufacturer, char **product)
91 goto fail; 142 goto fail;
92 } 143 }
93 144
94 if ((*manufacturer = malloc(utf8_len)) == NULL) { 145 if ((*manufacturer = malloc((size_t)utf8_len)) == NULL) {
95 fido_log_debug("%s: malloc", __func__); 146 fido_log_debug("%s: malloc", __func__);
96 goto fail; 147 goto fail;
97 } 148 }
@@ -113,7 +164,7 @@ get_str(HANDLE dev, char **manufacturer, char **product)
113 goto fail; 164 goto fail;
114 } 165 }
115 166
116 if ((*product = malloc(utf8_len)) == NULL) { 167 if ((*product = malloc((size_t)utf8_len)) == NULL) {
117 fido_log_debug("%s: malloc", __func__); 168 fido_log_debug("%s: malloc", __func__);
118 goto fail; 169 goto fail;
119 } 170 }
@@ -136,25 +187,138 @@ fail:
136 return (ok); 187 return (ok);
137} 188}
138 189
190static char *
191get_path(HDEVINFO devinfo, SP_DEVICE_INTERFACE_DATA *ifdata)
192{
193 SP_DEVICE_INTERFACE_DETAIL_DATA_A *ifdetail = NULL;
194 char *path = NULL;
195 DWORD len = 0;
196
197 /*
198 * "Get the required buffer size. Call SetupDiGetDeviceInterfaceDetail
199 * with a NULL DeviceInterfaceDetailData pointer, a
200 * DeviceInterfaceDetailDataSize of zero, and a valid RequiredSize
201 * variable. In response to such a call, this function returns the
202 * required buffer size at RequiredSize and fails with GetLastError
203 * returning ERROR_INSUFFICIENT_BUFFER."
204 */
205 if (SetupDiGetDeviceInterfaceDetailA(devinfo, ifdata, NULL, 0, &len,
206 NULL) != false || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
207 fido_log_debug("%s: SetupDiGetDeviceInterfaceDetailA 1",
208 __func__);
209 goto fail;
210 }
211
212 if ((ifdetail = malloc(len)) == NULL) {
213 fido_log_debug("%s: malloc", __func__);
214 goto fail;
215 }
216
217 ifdetail->cbSize = sizeof(*ifdetail);
218
219 if (SetupDiGetDeviceInterfaceDetailA(devinfo, ifdata, ifdetail, len,
220 NULL, NULL) == false) {
221 fido_log_debug("%s: SetupDiGetDeviceInterfaceDetailA 2",
222 __func__);
223 goto fail;
224 }
225
226 if ((path = strdup(ifdetail->DevicePath)) == NULL) {
227 fido_log_debug("%s: strdup", __func__);
228 goto fail;
229 }
230
231fail:
232 free(ifdetail);
233
234 return (path);
235}
236
237#ifndef FIDO_HID_ANY
238static bool
239hid_ok(HDEVINFO devinfo, DWORD idx)
240{
241 SP_DEVINFO_DATA devinfo_data;
242 wchar_t *parent = NULL;
243 DWORD parent_type = DEVPROP_TYPE_STRING;
244 DWORD len = 0;
245 bool ok = false;
246
247 memset(&devinfo_data, 0, sizeof(devinfo_data));
248 devinfo_data.cbSize = sizeof(devinfo_data);
249
250 if (SetupDiEnumDeviceInfo(devinfo, idx, &devinfo_data) == false) {
251 fido_log_debug("%s: SetupDiEnumDeviceInfo", __func__);
252 goto fail;
253 }
254
255 if (SetupDiGetDevicePropertyW(devinfo, &devinfo_data,
256 &DEVPKEY_Device_Parent, &parent_type, NULL, 0, &len, 0) != false ||
257 GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
258 fido_log_debug("%s: SetupDiGetDevicePropertyW 1", __func__);
259 goto fail;
260 }
261
262 if ((parent = malloc(len)) == NULL) {
263 fido_log_debug("%s: malloc", __func__);
264 goto fail;
265 }
266
267 if (SetupDiGetDevicePropertyW(devinfo, &devinfo_data,
268 &DEVPKEY_Device_Parent, &parent_type, (PBYTE)parent, len, NULL,
269 0) == false) {
270 fido_log_debug("%s: SetupDiGetDevicePropertyW 2", __func__);
271 goto fail;
272 }
273
274 ok = wcsncmp(parent, L"USB\\", 4) == 0;
275fail:
276 free(parent);
277
278 return (ok);
279}
280#endif
281
139static int 282static int
140copy_info(fido_dev_info_t *di, const char *path) 283copy_info(fido_dev_info_t *di, HDEVINFO devinfo, DWORD idx,
284 SP_DEVICE_INTERFACE_DATA *ifdata)
141{ 285{
142 HANDLE dev = INVALID_HANDLE_VALUE; 286 HANDLE dev = INVALID_HANDLE_VALUE;
143 int ok = -1; 287 int ok = -1;
144 288
145 memset(di, 0, sizeof(*di)); 289 memset(di, 0, sizeof(*di));
146 290
147 dev = CreateFileA(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 291 if ((di->path = get_path(devinfo, ifdata)) == NULL) {
148 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 292 fido_log_debug("%s: get_path", __func__);
149 if (dev == INVALID_HANDLE_VALUE || is_fido(dev) == 0)
150 goto fail; 293 goto fail;
294 }
151 295
152 if (get_int(dev, &di->vendor_id, &di->product_id) < 0 || 296 fido_log_debug("%s: path=%s", __func__, di->path);
153 get_str(dev, &di->manufacturer, &di->product) < 0) 297
298#ifndef FIDO_HID_ANY
299 if (hid_ok(devinfo, idx) == false) {
300 fido_log_debug("%s: hid_ok", __func__);
154 goto fail; 301 goto fail;
302 }
303#endif
155 304
156 if ((di->path = strdup(path)) == NULL) 305 dev = CreateFileA(di->path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
306 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
307 if (dev == INVALID_HANDLE_VALUE) {
308 fido_log_debug("%s: CreateFileA", __func__);
157 goto fail; 309 goto fail;
310 }
311
312 if (is_fido(dev) == false) {
313 fido_log_debug("%s: is_fido", __func__);
314 goto fail;
315 }
316
317 if (get_int(dev, &di->vendor_id, &di->product_id) < 0 ||
318 get_str(dev, &di->manufacturer, &di->product) < 0) {
319 fido_log_debug("%s: get_int/get_str", __func__);
320 goto fail;
321 }
158 322
159 ok = 0; 323 ok = 0;
160fail: 324fail:
@@ -174,66 +338,30 @@ fail:
174int 338int
175fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) 339fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
176{ 340{
177 GUID hid_guid = GUID_DEVINTERFACE_HID; 341 GUID hid_guid = GUID_DEVINTERFACE_HID;
178 HDEVINFO devinfo = INVALID_HANDLE_VALUE; 342 HDEVINFO devinfo = INVALID_HANDLE_VALUE;
179 SP_DEVICE_INTERFACE_DATA ifdata; 343 SP_DEVICE_INTERFACE_DATA ifdata;
180 SP_DEVICE_INTERFACE_DETAIL_DATA_A *ifdetail = NULL; 344 DWORD idx;
181 DWORD len = 0; 345 int r = FIDO_ERR_INTERNAL;
182 DWORD idx = 0;
183 int r = FIDO_ERR_INTERNAL;
184 346
185 *olen = 0; 347 *olen = 0;
186 348
187 if (ilen == 0) 349 if (ilen == 0)
188 return (FIDO_OK); /* nothing to do */ 350 return (FIDO_OK); /* nothing to do */
189
190 if (devlist == NULL) 351 if (devlist == NULL)
191 return (FIDO_ERR_INVALID_ARGUMENT); 352 return (FIDO_ERR_INVALID_ARGUMENT);
192 353
193 devinfo = SetupDiGetClassDevsA(&hid_guid, NULL, NULL, 354 if ((devinfo = SetupDiGetClassDevsA(&hid_guid, NULL, NULL,
194 DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); 355 DIGCF_DEVICEINTERFACE | DIGCF_PRESENT)) == INVALID_HANDLE_VALUE) {
195 if (devinfo == INVALID_HANDLE_VALUE) {
196 fido_log_debug("%s: SetupDiGetClassDevsA", __func__); 356 fido_log_debug("%s: SetupDiGetClassDevsA", __func__);
197 goto fail; 357 goto fail;
198 } 358 }
199 359
200 ifdata.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); 360 ifdata.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
201 361
202 while (SetupDiEnumDeviceInterfaces(devinfo, NULL, &hid_guid, idx++, 362 for (idx = 0; SetupDiEnumDeviceInterfaces(devinfo, NULL, &hid_guid,
203 &ifdata) == true) { 363 idx, &ifdata) == true; idx++) {
204 /* 364 if (copy_info(&devlist[*olen], devinfo, idx, &ifdata) == 0) {
205 * "Get the required buffer size. Call
206 * SetupDiGetDeviceInterfaceDetail with a NULL
207 * DeviceInterfaceDetailData pointer, a
208 * DeviceInterfaceDetailDataSize of zero, and a valid
209 * RequiredSize variable. In response to such a call, this
210 * function returns the required buffer size at RequiredSize
211 * and fails with GetLastError returning
212 * ERROR_INSUFFICIENT_BUFFER."
213 */
214 if (SetupDiGetDeviceInterfaceDetailA(devinfo, &ifdata, NULL, 0,
215 &len, NULL) != false ||
216 GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
217 fido_log_debug("%s: SetupDiGetDeviceInterfaceDetailA 1",
218 __func__);
219 goto fail;
220 }
221
222 if ((ifdetail = malloc(len)) == NULL) {
223 fido_log_debug("%s: malloc", __func__);
224 goto fail;
225 }
226
227 ifdetail->cbSize = sizeof(*ifdetail);
228
229 if (SetupDiGetDeviceInterfaceDetailA(devinfo, &ifdata, ifdetail,
230 len, NULL, NULL) == false) {
231 fido_log_debug("%s: SetupDiGetDeviceInterfaceDetailA 2",
232 __func__);
233 goto fail;
234 }
235
236 if (copy_info(&devlist[*olen], ifdetail->DevicePath) == 0) {
237 devlist[*olen].io = (fido_dev_io_t) { 365 devlist[*olen].io = (fido_dev_io_t) {
238 fido_hid_open, 366 fido_hid_open,
239 fido_hid_close, 367 fido_hid_close,
@@ -243,9 +371,6 @@ fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
243 if (++(*olen) == ilen) 371 if (++(*olen) == ilen)
244 break; 372 break;
245 } 373 }
246
247 free(ifdetail);
248 ifdetail = NULL;
249 } 374 }
250 375
251 r = FIDO_OK; 376 r = FIDO_OK;
@@ -253,78 +378,153 @@ fail:
253 if (devinfo != INVALID_HANDLE_VALUE) 378 if (devinfo != INVALID_HANDLE_VALUE)
254 SetupDiDestroyDeviceInfoList(devinfo); 379 SetupDiDestroyDeviceInfoList(devinfo);
255 380
256 free(ifdetail);
257
258 return (r); 381 return (r);
259} 382}
260 383
261void * 384void *
262fido_hid_open(const char *path) 385fido_hid_open(const char *path)
263{ 386{
264 HANDLE dev; 387 struct hid_win *ctx;
388
389 if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
390 return (NULL);
265 391
266 dev = CreateFileA(path, GENERIC_READ | GENERIC_WRITE, 392 ctx->dev = CreateFileA(path, GENERIC_READ | GENERIC_WRITE,
267 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 393 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
268 FILE_ATTRIBUTE_NORMAL, NULL); 394 FILE_FLAG_OVERLAPPED, NULL);
395
396 if (ctx->dev == INVALID_HANDLE_VALUE) {
397 free(ctx);
398 return (NULL);
399 }
269 400
270 if (dev == INVALID_HANDLE_VALUE) 401 if ((ctx->overlap.hEvent = CreateEventA(NULL, FALSE, FALSE,
402 NULL)) == NULL) {
403 fido_log_debug("%s: CreateEventA", __func__);
404 fido_hid_close(ctx);
271 return (NULL); 405 return (NULL);
406 }
272 407
273 return (dev); 408 if (get_report_len(ctx->dev, 0, &ctx->report_in_len) < 0 ||
409 get_report_len(ctx->dev, 1, &ctx->report_out_len) < 0) {
410 fido_log_debug("%s: get_report_len", __func__);
411 fido_hid_close(ctx);
412 return (NULL);
413 }
414
415 return (ctx);
274} 416}
275 417
276void 418void
277fido_hid_close(void *handle) 419fido_hid_close(void *handle)
278{ 420{
279 CloseHandle(handle); 421 struct hid_win *ctx = handle;
422
423 if (ctx->overlap.hEvent != NULL) {
424 if (ctx->report_pending) {
425 fido_log_debug("%s: report_pending", __func__);
426 CancelIo(ctx->dev);
427 }
428 CloseHandle(ctx->overlap.hEvent);
429 }
430
431 explicit_bzero(ctx->report, sizeof(ctx->report));
432 CloseHandle(ctx->dev);
433 free(ctx);
280} 434}
281 435
282int 436int
283fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms) 437fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms)
284{ 438{
285 DWORD n; 439 struct hid_win *ctx = handle;
286 int r = -1; 440 DWORD n;
287 uint8_t report[REPORT_LEN];
288 441
289 (void)ms; /* XXX */ 442 if (len != ctx->report_in_len - 1 || len > sizeof(ctx->report) - 1) {
443 fido_log_debug("%s: len %zu", __func__, len);
444 return (-1);
445 }
446
447 if (ctx->report_pending == 0) {
448 memset(&ctx->report, 0, sizeof(ctx->report));
449 ResetEvent(ctx->overlap.hEvent);
450 if (ReadFile(ctx->dev, ctx->report, (DWORD)(len + 1), &n,
451 &ctx->overlap) == 0 && GetLastError() != ERROR_IO_PENDING) {
452 CancelIo(ctx->dev);
453 fido_log_debug("%s: ReadFile", __func__);
454 return (-1);
455 }
456 ctx->report_pending = 1;
457 }
290 458
291 memset(report, 0, sizeof(report)); 459 if (ms > -1 && WaitForSingleObject(ctx->overlap.hEvent,
460 (DWORD)ms) != WAIT_OBJECT_0)
461 return (0);
292 462
293 if (len != sizeof(report) - 1) { 463 ctx->report_pending = 0;
294 fido_log_debug("%s: invalid len", __func__); 464
465 if (GetOverlappedResult(ctx->dev, &ctx->overlap, &n, TRUE) == 0) {
466 fido_log_debug("%s: GetOverlappedResult", __func__);
295 return (-1); 467 return (-1);
296 } 468 }
297 469
298 if (ReadFile(handle, report, sizeof(report), &n, NULL) == false || 470 if (n != len + 1) {
299 n != sizeof(report)) { 471 fido_log_debug("%s: expected %zu, got %zu", __func__,
300 fido_log_debug("%s: ReadFile", __func__); 472 len + 1, (size_t)n);
301 goto fail; 473 return (-1);
302 } 474 }
303 475
304 r = sizeof(report) - 1; 476 memcpy(buf, ctx->report + 1, len);
305 memcpy(buf, report + 1, len); 477 explicit_bzero(ctx->report, sizeof(ctx->report));
306
307fail:
308 explicit_bzero(report, sizeof(report));
309 478
310 return (r); 479 return ((int)len);
311} 480}
312 481
313int 482int
314fido_hid_write(void *handle, const unsigned char *buf, size_t len) 483fido_hid_write(void *handle, const unsigned char *buf, size_t len)
315{ 484{
316 DWORD n; 485 struct hid_win *ctx = handle;
486 OVERLAPPED overlap;
487 DWORD n;
488
489 memset(&overlap, 0, sizeof(overlap));
317 490
318 if (len != REPORT_LEN) { 491 if (len != ctx->report_out_len) {
319 fido_log_debug("%s: invalid len", __func__); 492 fido_log_debug("%s: len %zu", __func__, len);
320 return (-1); 493 return (-1);
321 } 494 }
322 495
323 if (WriteFile(handle, buf, (DWORD)len, &n, NULL) == false || 496 if (WriteFile(ctx->dev, buf, (DWORD)len, NULL, &overlap) == 0 &&
324 n != REPORT_LEN) { 497 GetLastError() != ERROR_IO_PENDING) {
325 fido_log_debug("%s: WriteFile", __func__); 498 fido_log_debug("%s: WriteFile", __func__);
326 return (-1); 499 return (-1);
327 } 500 }
328 501
329 return (REPORT_LEN); 502 if (GetOverlappedResult(ctx->dev, &overlap, &n, TRUE) == 0) {
503 fido_log_debug("%s: GetOverlappedResult", __func__);
504 return (-1);
505 }
506
507 if (n != len) {
508 fido_log_debug("%s: expected %zu, got %zu", __func__, len,
509 (size_t)n);
510 return (-1);
511 }
512
513 return ((int)len);
514}
515
516size_t
517fido_hid_report_in_len(void *handle)
518{
519 struct hid_win *ctx = handle;
520
521 return (ctx->report_in_len - 1);
522}
523
524size_t
525fido_hid_report_out_len(void *handle)
526{
527 struct hid_win *ctx = handle;
528
529 return (ctx->report_out_len - 1);
330} 530}
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)
217 return (cbor_decode_uint64(val, &ci->maxmsgsiz)); 217 return (cbor_decode_uint64(val, &ci->maxmsgsiz));
218 case 6: /* pinProtocols */ 218 case 6: /* pinProtocols */
219 return (decode_protocols(val, &ci->protocols)); 219 return (decode_protocols(val, &ci->protocols));
220 case 7: /* maxCredentialCountInList */
221 return (cbor_decode_uint64(val, &ci->maxcredcntlst));
222 case 8: /* maxCredentialIdLength */
223 return (cbor_decode_uint64(val, &ci->maxcredidlen));
220 case 14: /* fwVersion */ 224 case 14: /* fwVersion */
221 return (cbor_decode_uint64(val, &ci->fwversion)); 225 return (cbor_decode_uint64(val, &ci->fwversion));
222 default: /* ignore */ 226 default: /* ignore */
@@ -399,6 +403,18 @@ fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *ci)
399} 403}
400 404
401uint64_t 405uint64_t
406fido_cbor_info_maxcredcntlst(const fido_cbor_info_t *ci)
407{
408 return (ci->maxcredcntlst);
409}
410
411uint64_t
412fido_cbor_info_maxcredidlen(const fido_cbor_info_t *ci)
413{
414 return (ci->maxcredidlen);
415}
416
417uint64_t
402fido_cbor_info_fwversion(const fido_cbor_info_t *ci) 418fido_cbor_info_fwversion(const fido_cbor_info_t *ci)
403{ 419{
404 return (ci->fwversion); 420 return (ci->fwversion);
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 {
20 uint8_t cmd; 20 uint8_t cmd;
21 uint8_t bcnth; 21 uint8_t bcnth;
22 uint8_t bcntl; 22 uint8_t bcntl;
23 uint8_t data[CTAP_RPT_SIZE - 7]; 23 uint8_t data[CTAP_MAX_REPORT_LEN - CTAP_INIT_HEADER_LEN];
24 } init; 24 } init;
25 struct { 25 struct {
26 uint8_t seq; 26 uint8_t seq;
27 uint8_t data[CTAP_RPT_SIZE - 5]; 27 uint8_t data[CTAP_MAX_REPORT_LEN - CTAP_CONT_HEADER_LEN];
28 } cont; 28 } cont;
29 } body; 29 } body;
30}) 30})
@@ -38,6 +38,7 @@ tx_empty(fido_dev_t *d, uint8_t cmd)
38{ 38{
39 struct frame *fp; 39 struct frame *fp;
40 unsigned char pkt[sizeof(*fp) + 1]; 40 unsigned char pkt[sizeof(*fp) + 1];
41 const size_t len = d->tx_len + 1;
41 int n; 42 int n;
42 43
43 memset(&pkt, 0, sizeof(pkt)); 44 memset(&pkt, 0, sizeof(pkt));
@@ -45,8 +46,8 @@ tx_empty(fido_dev_t *d, uint8_t cmd)
45 fp->cid = d->cid; 46 fp->cid = d->cid;
46 fp->body.init.cmd = CTAP_FRAME_INIT | cmd; 47 fp->body.init.cmd = CTAP_FRAME_INIT | cmd;
47 48
48 n = d->io.write(d->io_handle, pkt, sizeof(pkt)); 49 if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt,
49 if (n < 0 || (size_t)n != sizeof(pkt)) 50 len)) < 0 || (size_t)n != len)
50 return (-1); 51 return (-1);
51 52
52 return (0); 53 return (0);
@@ -57,19 +58,23 @@ tx_preamble(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count)
57{ 58{
58 struct frame *fp; 59 struct frame *fp;
59 unsigned char pkt[sizeof(*fp) + 1]; 60 unsigned char pkt[sizeof(*fp) + 1];
61 const size_t len = d->tx_len + 1;
60 int n; 62 int n;
61 63
64 if (d->tx_len - CTAP_INIT_HEADER_LEN > sizeof(fp->body.init.data))
65 return (0);
66
62 memset(&pkt, 0, sizeof(pkt)); 67 memset(&pkt, 0, sizeof(pkt));
63 fp = (struct frame *)(pkt + 1); 68 fp = (struct frame *)(pkt + 1);
64 fp->cid = d->cid; 69 fp->cid = d->cid;
65 fp->body.init.cmd = CTAP_FRAME_INIT | cmd; 70 fp->body.init.cmd = CTAP_FRAME_INIT | cmd;
66 fp->body.init.bcnth = (count >> 8) & 0xff; 71 fp->body.init.bcnth = (count >> 8) & 0xff;
67 fp->body.init.bcntl = count & 0xff; 72 fp->body.init.bcntl = count & 0xff;
68 count = MIN(count, sizeof(fp->body.init.data)); 73 count = MIN(count, d->tx_len - CTAP_INIT_HEADER_LEN);
69 memcpy(&fp->body.init.data, buf, count); 74 memcpy(&fp->body.init.data, buf, count);
70 75
71 n = d->io.write(d->io_handle, pkt, sizeof(pkt)); 76 if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt,
72 if (n < 0 || (size_t)n != sizeof(pkt)) 77 len)) < 0 || (size_t)n != len)
73 return (0); 78 return (0);
74 79
75 return (count); 80 return (count);
@@ -80,17 +85,21 @@ tx_frame(fido_dev_t *d, uint8_t seq, const void *buf, size_t count)
80{ 85{
81 struct frame *fp; 86 struct frame *fp;
82 unsigned char pkt[sizeof(*fp) + 1]; 87 unsigned char pkt[sizeof(*fp) + 1];
88 const size_t len = d->tx_len + 1;
83 int n; 89 int n;
84 90
91 if (d->tx_len - CTAP_CONT_HEADER_LEN > sizeof(fp->body.cont.data))
92 return (0);
93
85 memset(&pkt, 0, sizeof(pkt)); 94 memset(&pkt, 0, sizeof(pkt));
86 fp = (struct frame *)(pkt + 1); 95 fp = (struct frame *)(pkt + 1);
87 fp->cid = d->cid; 96 fp->cid = d->cid;
88 fp->body.cont.seq = seq; 97 fp->body.cont.seq = seq;
89 count = MIN(count, sizeof(fp->body.cont.data)); 98 count = MIN(count, d->tx_len - CTAP_CONT_HEADER_LEN);
90 memcpy(&fp->body.cont.data, buf, count); 99 memcpy(&fp->body.cont.data, buf, count);
91 100
92 n = d->io.write(d->io_handle, pkt, sizeof(pkt)); 101 if (len > sizeof(pkt) || (n = d->io.write(d->io_handle, pkt,
93 if (n < 0 || (size_t)n != sizeof(pkt)) 102 len)) < 0 || (size_t)n != len)
94 return (0); 103 return (0);
95 104
96 return (count); 105 return (count);
@@ -129,16 +138,12 @@ fido_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count)
129 138
130 if (d->transport.tx != NULL) 139 if (d->transport.tx != NULL)
131 return (d->transport.tx(d, cmd, buf, count)); 140 return (d->transport.tx(d, cmd, buf, count));
132
133 if (d->io_handle == NULL || d->io.write == NULL || count > UINT16_MAX) { 141 if (d->io_handle == NULL || d->io.write == NULL || count > UINT16_MAX) {
134 fido_log_debug("%s: invalid argument", __func__); 142 fido_log_debug("%s: invalid argument", __func__);
135 return (-1); 143 return (-1);
136 } 144 }
137 145
138 if (count == 0) 146 return (count == 0 ? tx_empty(d, cmd) : tx(d, cmd, buf, count));
139 return (tx_empty(d, cmd));
140
141 return (tx(d, cmd, buf, count));
142} 147}
143 148
144static int 149static int
@@ -146,8 +151,10 @@ rx_frame(fido_dev_t *d, struct frame *fp, int ms)
146{ 151{
147 int n; 152 int n;
148 153
149 n = d->io.read(d->io_handle, (unsigned char *)fp, sizeof(*fp), ms); 154 memset(fp, 0, sizeof(*fp));
150 if (n < 0 || (size_t)n != sizeof(*fp)) 155
156 if (d->rx_len > sizeof(*fp) || (n = d->io.read(d->io_handle,
157 (unsigned char *)fp, d->rx_len, ms)) < 0 || (size_t)n != d->rx_len)
151 return (-1); 158 return (-1);
152 159
153 return (0); 160 return (0);
@@ -165,8 +172,11 @@ rx_preamble(fido_dev_t *d, uint8_t cmd, struct frame *fp, int ms)
165 } while (fp->cid == d->cid && 172 } while (fp->cid == d->cid &&
166 fp->body.init.cmd == (CTAP_FRAME_INIT | CTAP_KEEPALIVE)); 173 fp->body.init.cmd == (CTAP_FRAME_INIT | CTAP_KEEPALIVE));
167 174
175 if (d->rx_len > sizeof(*fp))
176 return (-1);
177
168 fido_log_debug("%s: initiation frame at %p", __func__, (void *)fp); 178 fido_log_debug("%s: initiation frame at %p", __func__, (void *)fp);
169 fido_log_xxd(fp, sizeof(*fp)); 179 fido_log_xxd(fp, d->rx_len);
170 180
171#ifdef FIDO_FUZZ 181#ifdef FIDO_FUZZ
172 fp->body.init.cmd = (CTAP_FRAME_INIT | cmd); 182 fp->body.init.cmd = (CTAP_FRAME_INIT | cmd);
@@ -185,30 +195,41 @@ static int
185rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms) 195rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms)
186{ 196{
187 struct frame f; 197 struct frame f;
188 uint16_t r, payload_len; 198 size_t r, payload_len, init_data_len, cont_data_len;
199
200 if (d->rx_len <= CTAP_INIT_HEADER_LEN ||
201 d->rx_len <= CTAP_CONT_HEADER_LEN)
202 return (-1);
203
204 init_data_len = d->rx_len - CTAP_INIT_HEADER_LEN;
205 cont_data_len = d->rx_len - CTAP_CONT_HEADER_LEN;
206
207 if (init_data_len > sizeof(f.body.init.data) ||
208 cont_data_len > sizeof(f.body.cont.data))
209 return (-1);
189 210
190 if (rx_preamble(d, cmd, &f, ms) < 0) { 211 if (rx_preamble(d, cmd, &f, ms) < 0) {
191 fido_log_debug("%s: rx_preamble", __func__); 212 fido_log_debug("%s: rx_preamble", __func__);
192 return (-1); 213 return (-1);
193 } 214 }
194 215
195 payload_len = (f.body.init.bcnth << 8) | f.body.init.bcntl; 216 payload_len = (size_t)((f.body.init.bcnth << 8) | f.body.init.bcntl);
196 fido_log_debug("%s: payload_len=%zu", __func__, (size_t)payload_len); 217 fido_log_debug("%s: payload_len=%zu", __func__, payload_len);
197 218
198 if (count < (size_t)payload_len) { 219 if (count < payload_len) {
199 fido_log_debug("%s: count < payload_len", __func__); 220 fido_log_debug("%s: count < payload_len", __func__);
200 return (-1); 221 return (-1);
201 } 222 }
202 223
203 if (payload_len < sizeof(f.body.init.data)) { 224 if (payload_len < init_data_len) {
204 memcpy(buf, f.body.init.data, payload_len); 225 memcpy(buf, f.body.init.data, payload_len);
205 return (payload_len); 226 return ((int)payload_len);
206 } 227 }
207 228
208 memcpy(buf, f.body.init.data, sizeof(f.body.init.data)); 229 memcpy(buf, f.body.init.data, init_data_len);
209 r = sizeof(f.body.init.data); 230 r = init_data_len;
210 231
211 for (int seq = 0; (size_t)r < payload_len; seq++) { 232 for (int seq = 0; r < payload_len; seq++) {
212 if (rx_frame(d, &f, ms) < 0) { 233 if (rx_frame(d, &f, ms) < 0) {
213 fido_log_debug("%s: rx_frame", __func__); 234 fido_log_debug("%s: rx_frame", __func__);
214 return (-1); 235 return (-1);
@@ -216,11 +237,11 @@ rx(fido_dev_t *d, uint8_t cmd, unsigned char *buf, size_t count, int ms)
216 237
217 fido_log_debug("%s: continuation frame at %p", __func__, 238 fido_log_debug("%s: continuation frame at %p", __func__,
218 (void *)&f); 239 (void *)&f);
219 fido_log_xxd(&f, sizeof(f)); 240 fido_log_xxd(&f, d->rx_len);
220 241
221#ifdef FIDO_FUZZ 242#ifdef FIDO_FUZZ
222 f.cid = d->cid; 243 f.cid = d->cid;
223 f.body.cont.seq = seq; 244 f.body.cont.seq = (uint8_t)seq;
224#endif 245#endif
225 246
226 if (f.cid != d->cid || f.body.cont.seq != seq) { 247 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)
229 return (-1); 250 return (-1);
230 } 251 }
231 252
232 if ((size_t)(payload_len - r) > sizeof(f.body.cont.data)) { 253 if (payload_len - r > cont_data_len) {
233 memcpy(buf + r, f.body.cont.data, 254 memcpy(buf + r, f.body.cont.data, cont_data_len);
234 sizeof(f.body.cont.data)); 255 r += cont_data_len;
235 r += sizeof(f.body.cont.data);
236 } else { 256 } else {
237 memcpy(buf + r, f.body.cont.data, payload_len - r); 257 memcpy(buf + r, f.body.cont.data, payload_len - r);
238 r += (payload_len - r); /* break */ 258 r += payload_len - r; /* break */
239 } 259 }
240 } 260 }
241 261
242 return (r); 262 return ((int)r);
243} 263}
244 264
245int 265int
@@ -252,15 +272,13 @@ fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int ms)
252 272
253 if (d->transport.rx != NULL) 273 if (d->transport.rx != NULL)
254 return (d->transport.rx(d, cmd, buf, count, ms)); 274 return (d->transport.rx(d, cmd, buf, count, ms));
255
256 if (d->io_handle == NULL || d->io.read == NULL || count > UINT16_MAX) { 275 if (d->io_handle == NULL || d->io.read == NULL || count > UINT16_MAX) {
257 fido_log_debug("%s: invalid argument", __func__); 276 fido_log_debug("%s: invalid argument", __func__);
258 return (-1); 277 return (-1);
259 } 278 }
260
261 if ((n = rx(d, cmd, buf, count, ms)) >= 0) { 279 if ((n = rx(d, cmd, buf, count, ms)) >= 0) {
262 fido_log_debug("%s: buf=%p, len=%d", __func__, (void *)buf, n); 280 fido_log_debug("%s: buf=%p, len=%d", __func__, (void *)buf, n);
263 fido_log_xxd(buf, n); 281 fido_log_xxd(buf, (size_t)n);
264 } 282 }
265 283
266 return (n); 284 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)
23 apdu->payload_ptr = apdu->payload; 23 apdu->payload_ptr = apdu->payload;
24 apdu->header.ins = ins; 24 apdu->header.ins = ins;
25 apdu->header.p1 = p1; 25 apdu->header.p1 = p1;
26 apdu->header.lc2 = (payload_len >> 8) & 0xff; 26 apdu->header.lc2 = (uint8_t)((payload_len >> 8) & 0xff);
27 apdu->header.lc3 = payload_len & 0xff; 27 apdu->header.lc3 = (uint8_t)(payload_len & 0xff);
28 28
29 return (apdu); 29 return (apdu);
30} 30}
@@ -51,7 +51,7 @@ iso7816_add(iso7816_apdu_t *apdu, const void *buf, size_t cnt)
51 51
52 memcpy(apdu->payload_ptr, buf, cnt); 52 memcpy(apdu->payload_ptr, buf, cnt);
53 apdu->payload_ptr += cnt; 53 apdu->payload_ptr += cnt;
54 apdu->payload_len -= (uint16_t)cnt; 54 apdu->payload_len = (uint16_t)(apdu->payload_len - cnt);
55 55
56 return (0); 56 return (0);
57} 57}
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,
53 53
54 if ((argv[0] = cbor_build_uint8(1)) == NULL || 54 if ((argv[0] = cbor_build_uint8(1)) == NULL ||
55 (argv[1] = cbor_build_uint8(5)) == NULL || 55 (argv[1] = cbor_build_uint8(5)) == NULL ||
56 (argv[2] = es256_pk_encode(pk, 0)) == NULL || 56 (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
57 (argv[5] = cbor_encode_pin_hash_enc(ecdh, p)) == NULL) { 57 (argv[5] = cbor_encode_pin_hash_enc(ecdh, p)) == NULL) {
58 fido_log_debug("%s: cbor encode", __func__); 58 fido_log_debug("%s: cbor encode", __func__);
59 r = FIDO_ERR_INTERNAL; 59 r = FIDO_ERR_INTERNAL;
@@ -89,7 +89,7 @@ fido_dev_get_uv_token_tx(fido_dev_t *dev, const es256_pk_t *pk)
89 89
90 if ((argv[0] = cbor_build_uint8(1)) == NULL || 90 if ((argv[0] = cbor_build_uint8(1)) == NULL ||
91 (argv[1] = cbor_build_uint8(6)) == NULL || 91 (argv[1] = cbor_build_uint8(6)) == NULL ||
92 (argv[2] = es256_pk_encode(pk, 0)) == NULL) { 92 (argv[2] = es256_pk_encode(pk, 1)) == NULL) {
93 fido_log_debug("%s: cbor encode", __func__); 93 fido_log_debug("%s: cbor encode", __func__);
94 r = FIDO_ERR_INTERNAL; 94 r = FIDO_ERR_INTERNAL;
95 goto fail; 95 goto fail;
@@ -240,7 +240,7 @@ pad64(const char *pin, fido_blob_t **ppin)
240 if ((*ppin = fido_blob_new()) == NULL) 240 if ((*ppin = fido_blob_new()) == NULL)
241 return (FIDO_ERR_INTERNAL); 241 return (FIDO_ERR_INTERNAL);
242 242
243 ppin_len = (pin_len + 63) & ~63; 243 ppin_len = (pin_len + 63U) & ~63U;
244 if (ppin_len < pin_len || ((*ppin)->ptr = calloc(1, ppin_len)) == NULL) { 244 if (ppin_len < pin_len || ((*ppin)->ptr = calloc(1, ppin_len)) == NULL) {
245 fido_blob_free(ppin); 245 fido_blob_free(ppin);
246 return (FIDO_ERR_INTERNAL); 246 return (FIDO_ERR_INTERNAL);
@@ -285,7 +285,7 @@ fido_dev_change_pin_tx(fido_dev_t *dev, const char *pin, const char *oldpin)
285 285
286 if ((argv[0] = cbor_build_uint8(1)) == NULL || 286 if ((argv[0] = cbor_build_uint8(1)) == NULL ||
287 (argv[1] = cbor_build_uint8(4)) == NULL || 287 (argv[1] = cbor_build_uint8(4)) == NULL ||
288 (argv[2] = es256_pk_encode(pk, 0)) == NULL || 288 (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
289 (argv[3] = cbor_encode_change_pin_auth(ecdh, ppin, opin)) == NULL || 289 (argv[3] = cbor_encode_change_pin_auth(ecdh, ppin, opin)) == NULL ||
290 (argv[4] = cbor_encode_pin_enc(ecdh, ppin)) == NULL || 290 (argv[4] = cbor_encode_pin_enc(ecdh, ppin)) == NULL ||
291 (argv[5] = cbor_encode_pin_hash_enc(ecdh, opin)) == NULL) { 291 (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)
339 339
340 if ((argv[0] = cbor_build_uint8(1)) == NULL || 340 if ((argv[0] = cbor_build_uint8(1)) == NULL ||
341 (argv[1] = cbor_build_uint8(3)) == NULL || 341 (argv[1] = cbor_build_uint8(3)) == NULL ||
342 (argv[2] = es256_pk_encode(pk, 0)) == NULL || 342 (argv[2] = es256_pk_encode(pk, 1)) == NULL ||
343 (argv[3] = cbor_encode_set_pin_auth(ecdh, ppin)) == NULL || 343 (argv[3] = cbor_encode_set_pin_auth(ecdh, ppin)) == NULL ||
344 (argv[4] = cbor_encode_pin_enc(ecdh, ppin)) == NULL) { 344 (argv[4] = cbor_encode_pin_enc(ecdh, ppin)) == NULL) {
345 fido_log_debug("%s: cbor encode", __func__); 345 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,
122 return (0); 122 return (0);
123} 123}
124 124
125/* TODO: use u2f_get_touch_begin & u2f_get_touch_status instead */
125static int 126static int
126send_dummy_register(fido_dev_t *dev, int ms) 127send_dummy_register(fido_dev_t *dev, int ms)
127{ 128{
@@ -160,7 +161,7 @@ send_dummy_register(fido_dev_t *dev, int ms)
160 r = FIDO_ERR_RX; 161 r = FIDO_ERR_RX;
161 goto fail; 162 goto fail;
162 } 163 }
163 if (usleep((ms == -1 ? 100 : ms) * 1000) < 0) { 164 if (usleep((unsigned)(ms == -1 ? 100 : ms) * 1000) < 0) {
164 fido_log_debug("%s: usleep", __func__); 165 fido_log_debug("%s: usleep", __func__);
165 r = FIDO_ERR_RX; 166 r = FIDO_ERR_RX;
166 goto fail; 167 goto fail;
@@ -204,8 +205,8 @@ key_lookup(fido_dev_t *dev, const char *rp_id, const fido_blob_t *key_id,
204 205
205 key_id_len = (uint8_t)key_id->len; 206 key_id_len = (uint8_t)key_id->len;
206 207
207 if ((apdu = iso7816_new(U2F_CMD_AUTH, U2F_AUTH_CHECK, 2 * 208 if ((apdu = iso7816_new(U2F_CMD_AUTH, U2F_AUTH_CHECK, (uint16_t)(2 *
208 SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len)) == NULL || 209 SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len))) == NULL ||
209 iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 || 210 iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 ||
210 iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 || 211 iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 ||
211 iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 || 212 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,
312 313
313 key_id_len = (uint8_t)key_id->len; 314 key_id_len = (uint8_t)key_id->len;
314 315
315 if ((apdu = iso7816_new(U2F_CMD_AUTH, U2F_AUTH_SIGN, 2 * 316 if ((apdu = iso7816_new(U2F_CMD_AUTH, U2F_AUTH_SIGN, (uint16_t)(2 *
316 SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len)) == NULL || 317 SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len))) == NULL ||
317 iso7816_add(apdu, cdh->ptr, cdh->len) < 0 || 318 iso7816_add(apdu, cdh->ptr, cdh->len) < 0 ||
318 iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 || 319 iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 ||
319 iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 || 320 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,
336 r = FIDO_ERR_RX; 337 r = FIDO_ERR_RX;
337 goto fail; 338 goto fail;
338 } 339 }
339 if (usleep((ms == -1 ? 100 : ms) * 1000) < 0) { 340 if (usleep((unsigned)(ms == -1 ? 100 : ms) * 1000) < 0) {
340 fido_log_debug("%s: usleep", __func__); 341 fido_log_debug("%s: usleep", __func__);
341 r = FIDO_ERR_RX; 342 r = FIDO_ERR_RX;
342 goto fail; 343 goto fail;
@@ -643,7 +644,7 @@ u2f_register(fido_dev_t *dev, fido_cred_t *cred, int ms)
643 r = FIDO_ERR_RX; 644 r = FIDO_ERR_RX;
644 goto fail; 645 goto fail;
645 } 646 }
646 if (usleep((ms == -1 ? 100 : ms) * 1000) < 0) { 647 if (usleep((unsigned)(ms == -1 ? 100 : ms) * 1000) < 0) {
647 fido_log_debug("%s: usleep", __func__); 648 fido_log_debug("%s: usleep", __func__);
648 r = FIDO_ERR_RX; 649 r = FIDO_ERR_RX;
649 goto fail; 650 goto fail;
@@ -726,8 +727,8 @@ fail:
726int 727int
727u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int ms) 728u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int ms)
728{ 729{
729 int nfound = 0; 730 size_t nfound = 0;
730 int nauth_ok = 0; 731 size_t nauth_ok = 0;
731 int r; 732 int r;
732 733
733 if (fa->uv == FIDO_OPT_TRUE || fa->allow_list.ptr == NULL) { 734 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)
769 770
770 return (FIDO_OK); 771 return (FIDO_OK);
771} 772}
773
774int
775u2f_get_touch_begin(fido_dev_t *dev)
776{
777 iso7816_apdu_t *apdu = NULL;
778 const char *clientdata = FIDO_DUMMY_CLIENTDATA;
779 const char *rp_id = FIDO_DUMMY_RP_ID;
780 unsigned char clientdata_hash[SHA256_DIGEST_LENGTH];
781 unsigned char rp_id_hash[SHA256_DIGEST_LENGTH];
782 unsigned char reply[FIDO_MAXMSG];
783 int r;
784
785 memset(&clientdata_hash, 0, sizeof(clientdata_hash));
786 memset(&rp_id_hash, 0, sizeof(rp_id_hash));
787
788 if (SHA256((const void *)clientdata, strlen(clientdata),
789 clientdata_hash) != clientdata_hash || SHA256((const void *)rp_id,
790 strlen(rp_id), rp_id_hash) != rp_id_hash) {
791 fido_log_debug("%s: sha256", __func__);
792 return (FIDO_ERR_INTERNAL);
793 }
794
795 if ((apdu = iso7816_new(U2F_CMD_REGISTER, 0, 2 *
796 SHA256_DIGEST_LENGTH)) == NULL ||
797 iso7816_add(apdu, clientdata_hash, sizeof(clientdata_hash)) < 0 ||
798 iso7816_add(apdu, rp_id_hash, sizeof(rp_id_hash)) < 0) {
799 fido_log_debug("%s: iso7816", __func__);
800 r = FIDO_ERR_INTERNAL;
801 goto fail;
802 }
803
804 if (dev->attr.flags & FIDO_CAP_WINK) {
805 fido_tx(dev, CTAP_CMD_WINK, NULL, 0);
806 fido_rx(dev, CTAP_CMD_WINK, &reply, sizeof(reply), 200);
807 }
808
809 if (fido_tx(dev, CTAP_CMD_MSG, iso7816_ptr(apdu),
810 iso7816_len(apdu)) < 0) {
811 fido_log_debug("%s: fido_tx", __func__);
812 r = FIDO_ERR_TX;
813 goto fail;
814 }
815
816 r = FIDO_OK;
817fail:
818 iso7816_free(&apdu);
819
820 return (r);
821}
822
823int
824u2f_get_touch_status(fido_dev_t *dev, int *touched, int ms)
825{
826 unsigned char reply[FIDO_MAXMSG];
827 int reply_len;
828 int r;
829
830 if ((reply_len = fido_rx(dev, CTAP_CMD_MSG, &reply, sizeof(reply),
831 ms)) < 2) {
832 fido_log_debug("%s: fido_rx", __func__);
833 return (FIDO_OK); /* ignore */
834 }
835
836 switch ((reply[reply_len - 2] << 8) | reply[reply_len - 1]) {
837 case SW_CONDITIONS_NOT_SATISFIED:
838 if ((r = u2f_get_touch_begin(dev)) != FIDO_OK) {
839 fido_log_debug("%s: u2f_get_touch_begin", __func__);
840 return (r);
841 }
842 *touched = 0;
843 break;
844 case SW_NO_ERROR:
845 *touched = 1;
846 break;
847 default:
848 fido_log_debug("%s: unexpected sw", __func__);
849 return (FIDO_ERR_RX);
850 }
851
852 return (FIDO_OK);
853}
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()
20 list(APPEND COMPAT_SOURCES ../openbsd-compat/readpassphrase.c) 20 list(APPEND COMPAT_SOURCES ../openbsd-compat/readpassphrase.c)
21endif() 21endif()
22 22
23if(NOT MSVC)
24 set_source_files_properties(assert_get.c assert_verify.c base64.c bio.c
25 cred_make.c cred_verify.c credman.c fido2-assert.c fido2-cred.c
26 fido2-token.c pin.c token.c util.c PROPERTIES COMPILE_FLAGS
27 "-Wconversion -Wsign-conversion")
28endif()
29
23add_executable(fido2-cred 30add_executable(fido2-cred
24 fido2-cred.c 31 fido2-cred.c
25 cred_make.c 32 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 @@
15#include "../openbsd-compat/openbsd-compat.h" 15#include "../openbsd-compat/openbsd-compat.h"
16#include "extern.h" 16#include "extern.h"
17 17
18struct toggle {
19 fido_opt_t up;
20 fido_opt_t uv;
21 fido_opt_t pin;
22};
23
24static const char *
25opt2str(fido_opt_t v)
26{
27 switch (v) {
28 case FIDO_OPT_OMIT:
29 return "omit";
30 case FIDO_OPT_TRUE:
31 return "true";
32 case FIDO_OPT_FALSE:
33 return "false";
34 default:
35 return "unknown";
36 }
37}
38
39static void
40parse_toggle(const char *str, struct toggle *opt)
41{
42 fido_opt_t *k;
43 fido_opt_t v;
44 char *assignment;
45 char *key;
46 char *val;
47
48 if ((assignment = strdup(str)) == NULL)
49 err(1, "strdup");
50 if ((val = strchr(assignment, '=')) == NULL)
51 errx(1, "invalid assignment '%s'", assignment);
52
53 key = assignment;
54 *val++ = '\0';
55
56 if (!strcmp(val, "true"))
57 v = FIDO_OPT_TRUE;
58 else if (!strcmp(val, "false"))
59 v = FIDO_OPT_FALSE;
60 else
61 errx(1, "unknown value '%s'", val);
62
63 if (!strcmp(key, "up"))
64 k = &opt->up;
65 else if (!strcmp(key, "uv"))
66 k = &opt->uv;
67 else if (!strcmp(key, "pin"))
68 k = &opt->pin;
69 else
70 errx(1, "unknown key '%s'", key);
71
72 free(assignment);
73
74 *k = v;
75}
76
18static fido_assert_t * 77static fido_assert_t *
19prepare_assert(FILE *in_f, int flags) 78prepare_assert(FILE *in_f, int flags, const struct toggle *opt)
20{ 79{
21 fido_assert_t *assert = NULL; 80 fido_assert_t *assert = NULL;
22 struct blob cdh; 81 struct blob cdh;
@@ -46,6 +105,9 @@ prepare_assert(FILE *in_f, int flags)
46 fprintf(stderr, "credential id:\n"); 105 fprintf(stderr, "credential id:\n");
47 xxd(id.ptr, id.len); 106 xxd(id.ptr, id.len);
48 } 107 }
108 fprintf(stderr, "up=%s\n", opt2str(opt->up));
109 fprintf(stderr, "uv=%s\n", opt2str(opt->uv));
110 fprintf(stderr, "pin=%s\n", opt2str(opt->pin));
49 } 111 }
50 112
51 if ((assert = fido_assert_new()) == NULL) 113 if ((assert = fido_assert_new()) == NULL)
@@ -55,15 +117,11 @@ prepare_assert(FILE *in_f, int flags)
55 cdh.len)) != FIDO_OK || 117 cdh.len)) != FIDO_OK ||
56 (r = fido_assert_set_rp(assert, rpid)) != FIDO_OK) 118 (r = fido_assert_set_rp(assert, rpid)) != FIDO_OK)
57 errx(1, "fido_assert_set: %s", fido_strerr(r)); 119 errx(1, "fido_assert_set: %s", fido_strerr(r));
120 if ((r = fido_assert_set_up(assert, opt->up)) != FIDO_OK)
121 errx(1, "fido_assert_set_up: %s", fido_strerr(r));
122 if ((r = fido_assert_set_uv(assert, opt->uv)) != FIDO_OK)
123 errx(1, "fido_assert_set_uv: %s", fido_strerr(r));
58 124
59 if (flags & FLAG_UP) {
60 if ((r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK)
61 errx(1, "fido_assert_set_up: %s", fido_strerr(r));
62 }
63 if (flags & FLAG_UV) {
64 if ((r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK)
65 errx(1, "fido_assert_set_uv: %s", fido_strerr(r));
66 }
67 if (flags & FLAG_HMAC) { 125 if (flags & FLAG_HMAC) {
68 if ((r = fido_assert_set_extensions(assert, 126 if ((r = fido_assert_set_extensions(assert,
69 FIDO_EXT_HMAC_SECRET)) != FIDO_OK) 127 FIDO_EXT_HMAC_SECRET)) != FIDO_OK)
@@ -136,6 +194,7 @@ assert_get(int argc, char **argv)
136{ 194{
137 fido_dev_t *dev = NULL; 195 fido_dev_t *dev = NULL;
138 fido_assert_t *assert = NULL; 196 fido_assert_t *assert = NULL;
197 struct toggle opt;
139 char pin[1024]; 198 char pin[1024];
140 char prompt[1024]; 199 char prompt[1024];
141 char *in_path = NULL; 200 char *in_path = NULL;
@@ -146,7 +205,9 @@ assert_get(int argc, char **argv)
146 int ch; 205 int ch;
147 int r; 206 int r;
148 207
149 while ((ch = getopt(argc, argv, "dhi:o:pruv")) != -1) { 208 opt.up = opt.uv = opt.pin = FIDO_OPT_OMIT;
209
210 while ((ch = getopt(argc, argv, "dhi:o:prt:uv")) != -1) {
150 switch (ch) { 211 switch (ch) {
151 case 'd': 212 case 'd':
152 flags |= FLAG_DEBUG; 213 flags |= FLAG_DEBUG;
@@ -161,16 +222,21 @@ assert_get(int argc, char **argv)
161 out_path = optarg; 222 out_path = optarg;
162 break; 223 break;
163 case 'p': 224 case 'p':
164 flags |= FLAG_UP; 225 opt.up = FIDO_OPT_TRUE;
165 break; 226 break;
166 case 'r': 227 case 'r':
167 flags |= FLAG_RK; 228 flags |= FLAG_RK;
168 break; 229 break;
230 case 't' :
231 parse_toggle(optarg, &opt);
232 break;
169 case 'u': 233 case 'u':
170 flags |= FLAG_U2F; 234 flags |= FLAG_U2F;
171 break; 235 break;
172 case 'v': 236 case 'v':
173 flags |= FLAG_UV; 237 /* -v implies both pin and uv for historical reasons */
238 opt.pin = FIDO_OPT_TRUE;
239 opt.uv = FIDO_OPT_TRUE;
174 break; 240 break;
175 default: 241 default:
176 usage(); 242 usage();
@@ -188,13 +254,13 @@ assert_get(int argc, char **argv)
188 254
189 fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); 255 fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0);
190 256
191 assert = prepare_assert(in_f, flags); 257 assert = prepare_assert(in_f, flags, &opt);
192 258
193 dev = open_dev(argv[0]); 259 dev = open_dev(argv[0]);
194 if (flags & FLAG_U2F) 260 if (flags & FLAG_U2F)
195 fido_dev_force_u2f(dev); 261 fido_dev_force_u2f(dev);
196 262
197 if (flags & FLAG_UV) { 263 if (opt.pin == FIDO_OPT_TRUE) {
198 r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", 264 r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ",
199 argv[0]); 265 argv[0]);
200 if (r < 0 || (size_t)r >= sizeof(prompt)) 266 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)
175 175
176 in_f = open_read(in_path); 176 in_f = open_read(in_path);
177 177
178 if (argc > 1) { 178 if (argc > 1 && cose_type(argv[1], &type) < 0)
179 if (strcmp(argv[1], "es256") == 0) 179 errx(1, "unknown type %s", argv[1]);
180 type = COSE_ES256;
181 else if (strcmp(argv[1], "rs256") == 0)
182 type = COSE_RS256;
183 else if (strcmp(argv[1], "eddsa") == 0)
184 type = COSE_EDDSA;
185 else
186 errx(1, "unknown type %s", argv[1]);
187 }
188 180
189 fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); 181 fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0);
190 182
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 @@
7#include <openssl/bio.h> 7#include <openssl/bio.h>
8#include <openssl/evp.h> 8#include <openssl/evp.h>
9 9
10#include <fido.h>
11#include <limits.h> 10#include <limits.h>
12#include <stdint.h> 11#include <stdint.h>
13#include <string.h> 12#include <string.h>
@@ -62,7 +61,7 @@ fail:
62} 61}
63 62
64int 63int
65base64_decode(char *in, void **ptr, size_t *len) 64base64_decode(const char *in, void **ptr, size_t *len)
66{ 65{
67 BIO *bio_mem = NULL; 66 BIO *bio_mem = NULL;
68 BIO *bio_b64 = NULL; 67 BIO *bio_b64 = NULL;
@@ -78,7 +77,7 @@ base64_decode(char *in, void **ptr, size_t *len)
78 77
79 if ((bio_b64 = BIO_new(BIO_f_base64())) == NULL) 78 if ((bio_b64 = BIO_new(BIO_f_base64())) == NULL)
80 goto fail; 79 goto fail;
81 if ((bio_mem = BIO_new_mem_buf((void *)in, -1)) == NULL) 80 if ((bio_mem = BIO_new_mem_buf((const void *)in, -1)) == NULL)
82 goto fail; 81 goto fail;
83 82
84 BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL); 83 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)
130 FILE *out_f = NULL; 130 FILE *out_f = NULL;
131 int type = COSE_ES256; 131 int type = COSE_ES256;
132 int flags = 0; 132 int flags = 0;
133 int cred_protect = -1;
133 int ch; 134 int ch;
134 int r; 135 int r;
135 136
136 while ((ch = getopt(argc, argv, "dhi:o:qruv")) != -1) { 137 while ((ch = getopt(argc, argv, "c:dhi:o:qruv")) != -1) {
137 switch (ch) { 138 switch (ch) {
139 case 'c':
140 if ((cred_protect = base10(optarg)) < 0)
141 errx(1, "-c: invalid argument '%s'", optarg);
142 break;
138 case 'd': 143 case 'd':
139 flags |= FLAG_DEBUG; 144 flags |= FLAG_DEBUG;
140 break; 145 break;
@@ -173,16 +178,8 @@ cred_make(int argc, char **argv)
173 in_f = open_read(in_path); 178 in_f = open_read(in_path);
174 out_f = open_write(out_path); 179 out_f = open_write(out_path);
175 180
176 if (argc > 1) { 181 if (argc > 1 && cose_type(argv[1], &type) < 0)
177 if (strcmp(argv[1], "es256") == 0) 182 errx(1, "unknown type %s", argv[1]);
178 type = COSE_ES256;
179 else if (strcmp(argv[1], "rs256") == 0)
180 type = COSE_RS256;
181 else if (strcmp(argv[1], "eddsa") == 0)
182 type = COSE_EDDSA;
183 else
184 errx(1, "unknown type %s", argv[1]);
185 }
186 183
187 fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); 184 fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0);
188 185
@@ -192,6 +189,13 @@ cred_make(int argc, char **argv)
192 if (flags & FLAG_U2F) 189 if (flags & FLAG_U2F)
193 fido_dev_force_u2f(dev); 190 fido_dev_force_u2f(dev);
194 191
192 if (cred_protect > 0) {
193 r = fido_cred_set_prot(cred, cred_protect);
194 if (r != FIDO_OK) {
195 errx(1, "fido_cred_set_prot: %s", fido_strerr(r));
196 }
197 }
198
195 r = fido_dev_make_cred(dev, cred, NULL); 199 r = fido_dev_make_cred(dev, cred, NULL);
196 if (r == FIDO_ERR_PIN_REQUIRED && !(flags & FLAG_QUIET)) { 200 if (r == FIDO_ERR_PIN_REQUIRED && !(flags & FLAG_QUIET)) {
197 r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", 201 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)
109 FILE *out_f = NULL; 109 FILE *out_f = NULL;
110 int type = COSE_ES256; 110 int type = COSE_ES256;
111 int flags = 0; 111 int flags = 0;
112 int cred_prot = -1;
112 int ch; 113 int ch;
113 int r; 114 int r;
114 115
115 while ((ch = getopt(argc, argv, "dhi:o:v")) != -1) { 116 while ((ch = getopt(argc, argv, "c:dhi:o:v")) != -1) {
116 switch (ch) { 117 switch (ch) {
118 case 'c':
119 if ((cred_prot = base10(optarg)) < 0)
120 errx(1, "-c: invalid argument '%s'", optarg);
121 break;
117 case 'd': 122 case 'd':
118 flags |= FLAG_DEBUG; 123 flags |= FLAG_DEBUG;
119 break; 124 break;
@@ -143,20 +148,19 @@ cred_verify(int argc, char **argv)
143 in_f = open_read(in_path); 148 in_f = open_read(in_path);
144 out_f = open_write(out_path); 149 out_f = open_write(out_path);
145 150
146 if (argc > 0) { 151 if (argc > 0 && cose_type(argv[0], &type) < 0)
147 if (strcmp(argv[0], "es256") == 0) 152 errx(1, "unknown type %s", argv[0]);
148 type = COSE_ES256;
149 else if (strcmp(argv[0], "rs256") == 0)
150 type = COSE_RS256;
151 else if (strcmp(argv[0], "eddsa") == 0)
152 type = COSE_EDDSA;
153 else
154 errx(1, "unknown type %s", argv[0]);
155 }
156 153
157 fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); 154 fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0);
158 cred = prepare_cred(in_f, type, flags); 155 cred = prepare_cred(in_f, type, flags);
159 156
157 if (cred_prot > 0) {
158 r = fido_cred_set_prot(cred, cred_prot);
159 if (r != FIDO_OK) {
160 errx(1, "fido_cred_set_prot: %s", fido_strerr(r));
161 }
162 }
163
160 if (fido_cred_x5c_ptr(cred) == NULL) { 164 if (fido_cred_x5c_ptr(cred) == NULL) {
161 if ((r = fido_cred_verify_self(cred)) != FIDO_OK) 165 if ((r = fido_cred_verify_self(cred)) != FIDO_OK)
162 errx(1, "fido_cred_verify_self: %s", fido_strerr(r)); 166 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)
101 char *id = NULL; 101 char *id = NULL;
102 char *user_id = NULL; 102 char *user_id = NULL;
103 const char *type; 103 const char *type;
104 const char *prot;
104 105
105 if ((cred = fido_credman_rk(rk, idx)) == NULL) 106 if ((cred = fido_credman_rk(rk, idx)) == NULL)
106 errx(1, "fido_credman_rk"); 107 errx(1, "fido_credman_rk");
@@ -109,23 +110,11 @@ print_rk(const fido_credman_rk_t *rk, size_t idx)
109 fido_cred_user_id_len(cred), &user_id) < 0) 110 fido_cred_user_id_len(cred), &user_id) < 0)
110 errx(1, "output error"); 111 errx(1, "output error");
111 112
112 switch (fido_cred_type(cred)) { 113 type = cose_string(fido_cred_type(cred));
113 case COSE_EDDSA: 114 prot = prot_string(fido_cred_prot(cred));
114 type = "eddsa";
115 break;
116 case COSE_ES256:
117 type = "es256";
118 break;
119 case COSE_RS256:
120 type = "rs256";
121 break;
122 default:
123 type = "unknown";
124 break;
125 }
126 115
127 printf("%02u: %s %s (%s) %s\n", (unsigned)idx, id, 116 printf("%02u: %s %s %s %s %s\n", (unsigned)idx, id,
128 fido_cred_display_name(cred), user_id, type); 117 fido_cred_display_name(cred), user_id, type, prot);
129 118
130 free(user_id); 119 free(user_id);
131 free(id); 120 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 *);
32fido_dev_t *open_dev(const char *); 32fido_dev_t *open_dev(const char *);
33FILE *open_read(const char *); 33FILE *open_read(const char *);
34FILE *open_write(const char *); 34FILE *open_write(const char *);
35const char *cose_string(int);
36const char *prot_string(int);
35int assert_get(int, char **); 37int assert_get(int, char **);
36int assert_verify(int, char **); 38int assert_verify(int, char **);
37int base64_decode(char *, void **, size_t *); 39int base64_decode(const char *, void **, size_t *);
38int base64_encode(const void *, size_t, char **); 40int base64_encode(const void *, size_t, char **);
39int base64_read(FILE *, struct blob *); 41int base64_read(FILE *, struct blob *);
40int bio_delete(fido_dev_t *, char *, char *); 42int bio_delete(fido_dev_t *, char *, char *);
@@ -42,6 +44,7 @@ int bio_enroll(char *);
42void bio_info(fido_dev_t *); 44void bio_info(fido_dev_t *);
43int bio_list(char *); 45int bio_list(char *);
44int bio_set_name(char *, char *, char *); 46int bio_set_name(char *, char *, char *);
47int cose_type(const char *, int *);
45int cred_make(int, char **); 48int cred_make(int, char **);
46int cred_verify(int, char **); 49int cred_verify(int, char **);
47int credman_delete_rk(fido_dev_t *, const char *, char *); 50int credman_delete_rk(fido_dev_t *, const char *, char *);
@@ -66,5 +69,6 @@ void print_cred(FILE *, int, const fido_cred_t *);
66void read_pin(const char *, char *, size_t); 69void read_pin(const char *, char *, size_t);
67void usage(void); 70void usage(void);
68void xxd(const void *, size_t); 71void xxd(const void *, size_t);
72int base10(const char *);
69 73
70#endif /* _EXTERN_H_ */ 74#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 @@
11 * $ echo relying party >> assert_param 11 * $ echo relying party >> assert_param
12 * $ head -1 cred >> assert_param # credential id 12 * $ head -1 cred >> assert_param # credential id
13 * $ tail -n +2 cred > pubkey # credential pubkey 13 * $ tail -n +2 cred > pubkey # credential pubkey
14 * $ fido2-assert -G -i assert_param /dev/hidraw5 | fido2-assert -V pubkey rs256 14 * $ fido2-assert -G -i assert_param /dev/hidraw5 | fido2-assert -V pubkey rs256
15 * 15 *
16 * See blurb in fido2-cred.c on how to obtain cred. 16 * See blurb in fido2-cred.c on how to obtain cred.
17 */ 17 */
18 18
19#include <fido.h> 19#include <fido.h>
20#include <stdio.h> 20#include <stdio.h>
@@ -28,7 +28,7 @@ void
28usage(void) 28usage(void)
29{ 29{
30 fprintf(stderr, 30 fprintf(stderr,
31"usage: fido2-assert -G [-dhpruv] [-i input_file] [-o output_file] device\n" 31"usage: fido2-assert -G [-dhpruv] [-t option] [-i input_file] [-o output_file] device\n"
32" fido2-assert -V [-dhpv] [-i input_file] key_file [type]\n" 32" fido2-assert -V [-dhpv] [-i input_file] key_file [type]\n"
33 ); 33 );
34 34
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 @@
1#!/bin/sh
2
3# Copyright (c) 2020 Yubico AB. All rights reserved.
4# Use of this source code is governed by a BSD-style
5# license that can be found in the LICENSE file.
6
7DEV=""
8
9while [ -z "${DEV}" ]; do
10 sleep .5
11 DEV="$(fido2-token -L | sed 's/^\(.*\): .*$/\1/;q')"
12done
13
14printf '%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 @@
12 * $ echo user name >> cred_param 12 * $ echo user name >> cred_param
13 * $ dd if=/dev/urandom bs=1 count=32 | base64 >> cred_param 13 * $ dd if=/dev/urandom bs=1 count=32 | base64 >> cred_param
14 * $ fido2-cred -M -i cred_param /dev/hidraw5 | fido2-cred -V -o cred 14 * $ fido2-cred -M -i cred_param /dev/hidraw5 | fido2-cred -V -o cred
15 */ 15 */
16 16
17#include <fido.h> 17#include <fido.h>
18#include <stdio.h> 18#include <stdio.h>
@@ -26,8 +26,8 @@ void
26usage(void) 26usage(void)
27{ 27{
28 fprintf(stderr, 28 fprintf(stderr,
29"usage: fido2-cred -M [-dhqruv] [-i input_file] [-o output_file] device [type]\n" 29"usage: fido2-cred -M [-dhqruv] [-c cred_protect] [-i input_file] [-o output_file] device [type]\n"
30" fido2-cred -V [-dhv] [-i input_file] [-o output_file] [type]\n" 30" fido2-cred -V [-dhv] [-c cred_protect] [-i input_file] [-o output_file] [type]\n"
31 ); 31 );
32 32
33 exit(1); 33 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 @@
1#!/bin/sh
2
3# Copyright (c) 2020 Yubico AB. All rights reserved.
4# Use of this source code is governed by a BSD-style
5# license that can be found in the LICENSE file.
6
7DEV="$(fido2-token -L | sed 's/^\(.*\): .*$/\1/;q')"
8
9while [ -n "${DEV}" ]; do
10 sleep .5
11 DEV="$(fido2-token -L | sed 's/^\(.*\): .*$/\1/;q')"
12done
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)
19{ 19{
20 fprintf(stderr, 20 fprintf(stderr,
21"usage: fido2-token [-CR] [-d] device\n" 21"usage: fido2-token [-CR] [-d] device\n"
22" fido2-token -D [-de] -i id device\n" 22" fido2-token -D [-de] -i id device\n"
23" fido2-token -I [-cd] [-k rp_id -i cred_id] device\n" 23" fido2-token -I [-cd] [-k rp_id -i cred_id] device\n"
24" fido2-token -L [-der] [-k rp_id] [device]\n" 24" fido2-token -L [-der] [-k rp_id] [device]\n"
25" fido2-token -S [-de] [-i template_id -n template_name] device\n" 25" fido2-token -S [-de] [-i template_id -n template_name] device\n"
26" fido2-token -V\n" 26" fido2-token -V\n"
27 ); 27 );
28 28
29 exit(1); 29 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 @@
1#!/bin/sh
2
3# Copyright (c) 2020 Fabian Henneke.
4# Use of this source code is governed by a BSD-style
5# license that can be found in the LICENSE file.
6
7
8if [ $(uname) != "Linux" ] ; then
9 echo "Can only run on Linux"
10 exit 1
11fi
12
13TOKEN_VERSION=$(${FIDO_TOOLS_PREFIX}fido2-token -V 2>&1)
14if [ $? -ne 0 ] ; then
15 echo "Please install libfido2 1.5.0 or higher"
16 exit
17fi
18
19TOKEN_VERSION_MAJOR=$(echo "$TOKEN_VERSION" | cut -d. -f1)
20TOKEN_VERSION_MINOR=$(echo "$TOKEN_VERSION" | cut -d. -f2)
21if [ $TOKEN_VERSION_MAJOR -eq 0 -o $TOKEN_VERSION_MAJOR -eq 1 -a $TOKEN_VERSION_MINOR -lt 5 ] ; then
22 echo "Please install libfido2 1.5.0 or higher (current version: $TOKEN_VERSION)"
23 exit 1
24fi
25
26set -e
27
28TOKEN_OUTPUT=$(${FIDO_TOOLS_PREFIX}fido2-token -L)
29DEV_PATH_NAMES=$(echo "$TOKEN_OUTPUT" | sed -r 's/^(.*): .*\((.*)\)$/\1 \2/g')
30DEV_COUNT=$(echo "$DEV_PATH_NAMES" | wc -l)
31
32for i in $(seq 1 $DEV_COUNT)
33do
34 DEV_PATH_NAME=$(echo "$DEV_PATH_NAMES" | sed "${i}q;d")
35 DEV_PATH=$(echo "$DEV_PATH_NAME" | cut -d' ' -f1)
36 DEV_NAME=$(echo "$DEV_PATH_NAME" | cut -d' ' -f1 --complement)
37 DEV_PRETTY=$(echo "$DEV_NAME (at '$DEV_PATH')")
38 if expr match "$(${FIDO_TOOLS_PREFIX}fido2-token -I $DEV_PATH)" ".* credMgmt.* clientPin.*\|.* clientPin.* credMgmt.*" > /dev/null ; then
39 printf "Enter PIN for $DEV_PRETTY once (ignore further prompts): "
40 stty -echo
41 read PIN
42 stty echo
43 printf "\n"
44 RESIDENT_RPS=$(echo "${PIN}\n" | setsid -w ${FIDO_TOOLS_PREFIX}fido2-token -L -r $DEV_PATH | cut -d' ' -f3)
45 printf "\n"
46 RESIDENT_RPS_COUNT=$(echo "$RESIDENT_RPS" | wc -l)
47 FOUND=0
48 for j in $(seq 1 $DEV_RESIDENT_RPS_COUNT)
49 do
50 RESIDENT_RP=$(echo "$RESIDENT_RPS" | sed "${j}q;d")
51 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)
52 printf "\n"
53 UNPROT_CREDS_COUNT=$(echo "$UNPROT_CREDS" | wc -l)
54 if [ $UNPROT_CREDS_COUNT -gt 0 ] ; then
55 FOUND=1
56 echo "Unprotected credentials on $DEV_PRETTY for '$RESIDENT_RP':"
57 echo "$UNPROT_CREDS"
58 fi
59 done
60 if [ $FOUND -eq 0 ] ; then
61 echo "No unprotected credentials on $DEV_PRETTY"
62 fi
63 else
64 echo "$DEV_PRETTY cannot enumerate credentials"
65 echo "Discovering unprotected SSH credentials only..."
66 STUB_HASH=$(echo -n "" | openssl sha256 -binary | base64)
67 printf "$STUB_HASH\nssh:\n" | ${FIDO_TOOLS_PREFIX}fido2-assert -G -r -t up=false $DEV_PATH 2> /dev/null || ASSERT_EXIT_CODE=$?
68 if [ $ASSERT_EXIT_CODE -eq 0 ] ; then
69 echo "Found an unprotected SSH credential on $DEV_PRETTY!"
70 else
71 echo "No unprotected SSH credentials (default settings) on $DEV_PRETTY"
72 fi
73 fi
74 printf "\n"
75done
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 @@
1#!/bin/bash 1#!/bin/sh
2# 2
3# Copyright (c) 2019 Yubico AB. All rights reserved. 3# Copyright (c) 2019 Yubico AB. All rights reserved.
4# Use of this source code is governed by a BSD-style 4# Use of this source code is governed by a BSD-style
5# license that can be found in the LICENSE file. 5# license that can be found in the LICENSE file.
@@ -8,14 +8,14 @@ check() {
8 for f in $(find $1 -maxdepth 1 -name '*.h'); do 8 for f in $(find $1 -maxdepth 1 -name '*.h'); do
9 echo "#include \"$f\"" | \ 9 echo "#include \"$f\"" | \
10 cc $CFLAGS -Isrc -xc -c - -o /dev/null 2>&1 10 cc $CFLAGS -Isrc -xc -c - -o /dev/null 2>&1
11 echo $f $CFLAGS $? 11 echo "$f $CFLAGS $?"
12 done 12 done
13} 13}
14 14
15check examples 15check examples
16check fuzz 16check fuzz
17check openbsd-compat 17check openbsd-compat
18CFLAGS=-D_FIDO_INTERNAL check src 18CFLAGS="${CFLAGS} -D_FIDO_INTERNAL" check src
19check src/fido.h 19check src/fido.h
20check src/fido 20check src/fido
21check tools 21check 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 @@
1#!/bin/bash -e
2# Copyright (c) 2019 Yubico AB. All rights reserved.
3# Use of this source code is governed by a BSD-style
4# license that can be found in the LICENSE file.
5
6if [[ "$#" -ne 2 ]]; then
7 echo usage: $0 version directory 1>&2
8 exit 1
9fi
10
11V=$1
12D=$2
13
14FIDO_PATH=$(realpath ${D}/lib/libfido2.${V}.dylib)
15CBOR_PATH=$(otool -L "${FIDO_PATH}" | grep cbor | awk '{ print $1 }')
16CRYPTO_PATH=$(otool -L "${FIDO_PATH}" | grep crypto | awk '{ print $1 }')
17
18cp -p "${CBOR_PATH}" "${CRYPTO_PATH}" "${D}/lib"
19chmod 755 "${D}/lib/"*dylib
20rm "${D}/lib/pkgconfig/libfido2.pc"
21rmdir "${D}/lib/pkgconfig"
22
23CBOR_NAME=$(echo "${CBOR_PATH}" | grep -o 'libcbor.*dylib')
24CRYPTO_NAME=$(echo "${CRYPTO_PATH}" | grep -o 'libcrypto.*dylib')
25FIDO_NAME="libfido2.${V}.dylib"
26
27install_name_tool -id "@loader_path/${CBOR_NAME}" "${D}/lib/${CBOR_NAME}"
28install_name_tool -id "@loader_path/${CRYPTO_NAME}" "${D}/lib/${CRYPTO_NAME}"
29install_name_tool -id "@loader_path/libfido2.${V}.dylib" "${FIDO_PATH}"
30
31install_name_tool -change "${CBOR_PATH}" "@loader_path/${CBOR_NAME}" \
32 "${FIDO_PATH}"
33install_name_tool -change "${CRYPTO_PATH}" "@loader_path/${CRYPTO_NAME}" \
34 "${FIDO_PATH}"
35
36for f in $(find "${D}/bin" -type f); do
37 FIDO_PATH=$(otool -L "${f}" | grep libfido2 | awk '{ print $1 }')
38 install_name_tool -change "${CBOR_PATH}" \
39 "@executable_path/../lib/${CBOR_NAME}" "${f}"
40 install_name_tool -change "${CRYPTO_PATH}" \
41 "@executable_path/../lib/${CRYPTO_NAME}" "${f}"
42 install_name_tool -change "${FIDO_PATH}" \
43 "@executable_path/../lib/${FIDO_NAME}" "${f}"
44done
diff --git a/tools/token.c b/tools/token.c
index e65f09f..28e4512 100644
--- a/tools/token.c
+++ b/tools/token.c
@@ -112,6 +112,18 @@ print_maxmsgsiz(uint64_t maxmsgsiz)
112} 112}
113 113
114static void 114static void
115print_maxcredcntlst(uint64_t maxcredcntlst)
116{
117 printf("maxcredcntlst: %d\n", (int)maxcredcntlst);
118}
119
120static void
121print_maxcredidlen(uint64_t maxcredidlen)
122{
123 printf("maxcredlen: %d\n", (int)maxcredidlen);
124}
125
126static void
115print_fwversion(uint64_t fwversion) 127print_fwversion(uint64_t fwversion)
116{ 128{
117 printf("fwversion: 0x%x\n", (int)fwversion); 129 printf("fwversion: 0x%x\n", (int)fwversion);
@@ -202,6 +214,12 @@ token_info(int argc, char **argv, char *path)
202 /* print maximum message size */ 214 /* print maximum message size */
203 print_maxmsgsiz(fido_cbor_info_maxmsgsiz(ci)); 215 print_maxmsgsiz(fido_cbor_info_maxmsgsiz(ci));
204 216
217 /* print maximum number of credentials allowed in credential lists */
218 print_maxcredcntlst(fido_cbor_info_maxcredcntlst(ci));
219
220 /* print maximum length of a credential ID */
221 print_maxcredidlen(fido_cbor_info_maxcredidlen(ci));
222
205 /* print firmware version */ 223 /* print firmware version */
206 print_fwversion(fido_cbor_info_fwversion(ci)); 224 print_fwversion(fido_cbor_info_fwversion(ci));
207 225
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 @@
16#include <fido/rs256.h> 16#include <fido/rs256.h>
17#include <fido/eddsa.h> 17#include <fido/eddsa.h>
18 18
19#include <errno.h>
19#include <fcntl.h> 20#include <fcntl.h>
21#include <limits.h>
20#include <stdint.h> 22#include <stdint.h>
21#include <stdio.h> 23#include <stdio.h>
22#include <stdlib.h> 24#include <stdlib.h>
@@ -78,6 +80,25 @@ open_read(const char *file)
78 return (f); 80 return (f);
79} 81}
80 82
83int
84base10(const char *str)
85{
86 char *ep;
87 long long ll;
88
89 ll = strtoll(str, &ep, 10);
90 if (str == ep || *ep != '\0')
91 return (-1);
92 else if (ll == LLONG_MIN && errno == ERANGE)
93 return (-1);
94 else if (ll == LLONG_MAX && errno == ERANGE)
95 return (-1);
96 else if (ll < 0 || ll > INT_MAX)
97 return (-1);
98
99 return ((int)ll);
100}
101
81void 102void
82xxd(const void *buf, size_t count) 103xxd(const void *buf, size_t count)
83{ 104{
@@ -362,3 +383,50 @@ print_cred(FILE *out_f, int type, const fido_cred_t *cred)
362 383
363 free(id); 384 free(id);
364} 385}
386
387int
388cose_type(const char *str, int *type)
389{
390 if (strcmp(str, "es256") == 0)
391 *type = COSE_ES256;
392 else if (strcmp(str, "rs256") == 0)
393 *type = COSE_RS256;
394 else if (strcmp(str, "eddsa") == 0)
395 *type = COSE_EDDSA;
396 else {
397 *type = 0;
398 return (-1);
399 }
400
401 return (0);
402}
403
404const char *
405cose_string(int type)
406{
407 switch (type) {
408 case COSE_EDDSA:
409 return ("eddsa");
410 case COSE_ES256:
411 return ("es256");
412 case COSE_RS256:
413 return ("rs256");
414 default:
415 return ("unknown");
416 }
417}
418
419const char *
420prot_string(int prot)
421{
422 switch (prot) {
423 case FIDO_CRED_PROT_UV_OPTIONAL:
424 return ("uvopt");
425 case FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID:
426 return ("uvopt+id");
427 case FIDO_CRED_PROT_UV_REQUIRED:
428 return ("uvreq");
429 default:
430 return ("unknown");
431 }
432}
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 @@
1# Copyright (c) 2018 Yubico AB. All rights reserved. 1# Copyright (c) 2020 Yubico AB. All rights reserved.
2# Use of this source code is governed by a BSD-style 2# Use of this source code is governed by a BSD-style
3# license that can be found in the LICENSE file. 3# license that can be found in the LICENSE file.
4 4
5# this udev file should be used with udev 188 and newer 5# This file is automatically generated, and should
6ACTION!="add|change", GOTO="u2f_end" 6# be used with udev 188 or newer.
7 7
8# Yubico YubiKey 8ACTION!="add|change", GOTO="fido_end"
9KERNEL=="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"
10 9
11# Happlink (formerly Plug-Up) Security KEY 10# ellipticSecure MIRKey by STMicroelectronics
12KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2581", ATTRS{idProduct}=="f1d0", TAG+="uaccess", GROUP="plugdev", MODE="0660" 11KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ac", TAG+="uaccess", GROUP="plugdev", MODE="0660"
12
13# Unknown product by STMicroelectronics
14KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="a2ca", TAG+="uaccess", GROUP="plugdev", MODE="0660"
15
16# Unknown product by STMicroelectronics
17KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="cdab", TAG+="uaccess", GROUP="plugdev", MODE="0660"
18
19# Infineon FIDO by Infineon Technologies
20KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="058b", ATTRS{idProduct}=="022d", TAG+="uaccess", GROUP="plugdev", MODE="0660"
21
22# Kensington VeriMark by Synaptics Inc.
23KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="06cb", ATTRS{idProduct}=="0088", TAG+="uaccess", GROUP="plugdev", MODE="0660"
24
25# FS ePass FIDO by Feitian Technologies Co., Ltd.
26KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0850", TAG+="uaccess", GROUP="plugdev", MODE="0660"
27
28# Unknown product by Feitian Technologies Co., Ltd.
29KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0852", TAG+="uaccess", GROUP="plugdev", MODE="0660"
30
31# Unknown product by Feitian Technologies Co., Ltd.
32KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0853", TAG+="uaccess", GROUP="plugdev", MODE="0660"
33
34# Unknown product by Feitian Technologies Co., Ltd.
35KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0854", TAG+="uaccess", GROUP="plugdev", MODE="0660"
36
37# Unknown product by Feitian Technologies Co., Ltd.
38KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0856", TAG+="uaccess", GROUP="plugdev", MODE="0660"
39
40# Unknown product by Feitian Technologies Co., Ltd.
41KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0858", TAG+="uaccess", GROUP="plugdev", MODE="0660"
42
43# FS MultiPass FIDO U2F by Feitian Technologies Co., Ltd.
44KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="085a", TAG+="uaccess", GROUP="plugdev", MODE="0660"
13 45
14# Neowave Keydo and Keydo AES 46# Unknown product by Feitian Technologies Co., Ltd.
15KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1e0d", ATTRS{idProduct}=="f1d0|f1ae", TAG+="uaccess", GROUP="plugdev", MODE="0660" 47KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="085b", TAG+="uaccess", GROUP="plugdev", MODE="0660"
16 48
17# HyperSecu HyperFIDO 49# Unknown product by Feitian Technologies Co., Ltd.
18KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e|2ccf", ATTRS{idProduct}=="0880", TAG+="uaccess", GROUP="plugdev", MODE="0660" 50KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="085d", TAG+="uaccess", GROUP="plugdev", MODE="0660"
19 51
20# Feitian ePass FIDO, BioPass FIDO2 52# Hypersecu HyperFIDO by Feitian Technologies Co., Ltd.
21KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0850|0852|0853|0854|0856|0858|085a|085b|085d", TAG+="uaccess", GROUP="plugdev", MODE="0660" 53KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="096e", ATTRS{idProduct}=="0880", TAG+="uaccess", GROUP="plugdev", MODE="0660"
22 54
23# JaCarta U2F 55# YubiKey NEO FIDO by Yubico AB
24KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="24dc", ATTRS{idProduct}=="0101|0501", TAG+="uaccess", GROUP="plugdev", MODE="0660" 56KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0113", TAG+="uaccess", GROUP="plugdev", MODE="0660"
25 57
26# U2F Zero 58# YubiKey NEO OTP+FIDO by Yubico AB
59KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0114", TAG+="uaccess", GROUP="plugdev", MODE="0660"
60
61# YubiKey NEO FIDO+CCID by Yubico AB
62KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0115", TAG+="uaccess", GROUP="plugdev", MODE="0660"
63
64# YubiKey NEO OTP+FIDO+CCID by Yubico AB
65KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0116", TAG+="uaccess", GROUP="plugdev", MODE="0660"
66
67# Security Key by Yubico by Yubico AB
68KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0120", TAG+="uaccess", GROUP="plugdev", MODE="0660"
69
70# Unknown product by Yubico AB
71KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0121", TAG+="uaccess", GROUP="plugdev", MODE="0660"
72
73# Gnubby U2F by Yubico AB
74KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0200", TAG+="uaccess", GROUP="plugdev", MODE="0660"
75
76# YubiKey 4 FIDO by Yubico AB
77KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0402", TAG+="uaccess", GROUP="plugdev", MODE="0660"
78
79# YubiKey 4 OTP+FIDO by Yubico AB
80KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0403", TAG+="uaccess", GROUP="plugdev", MODE="0660"
81
82# YubiKey 4 FIDO+CCID by Yubico AB
83KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0406", TAG+="uaccess", GROUP="plugdev", MODE="0660"
84
85# YubiKey 4 OTP+FIDO+CCID by Yubico AB
86KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0407", TAG+="uaccess", GROUP="plugdev", MODE="0660"
87
88# YubiKey Plus by Yubico AB
89KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0410", TAG+="uaccess", GROUP="plugdev", MODE="0660"
90
91# U2F Zero by Silicon Laboratories, Inc.
27KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess", GROUP="plugdev", MODE="0660" 92KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="8acf", TAG+="uaccess", GROUP="plugdev", MODE="0660"
28 93
29# VASCO SecureClick 94# SoloKeys SoloHacker by pid.codes
95KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="5070", TAG+="uaccess", GROUP="plugdev", MODE="0660"
96
97# SoloKeys SoloBoot by pid.codes
98KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="50b0", TAG+="uaccess", GROUP="plugdev", MODE="0660"
99
100# SatoshiLabs TREZOR by pid.codes
101KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="53c1", TAG+="uaccess", GROUP="plugdev", MODE="0660"
102
103# Google Titan U2F by Google Inc.
104KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="5026", TAG+="uaccess", GROUP="plugdev", MODE="0660"
105
106# VASCO SecureClick by VASCO Data Security NV
30KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1a44", ATTRS{idProduct}=="00bb", TAG+="uaccess", GROUP="plugdev", MODE="0660" 107KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1a44", ATTRS{idProduct}=="00bb", TAG+="uaccess", GROUP="plugdev", MODE="0660"
31 108
32# Bluink Key 109# OnlyKey (FIDO2/U2F) by OpenMoko, Inc.
33KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2abe", ATTRS{idProduct}=="1002", TAG+="uaccess", GROUP="plugdev", MODE="0660" 110KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="60fc", TAG+="uaccess", GROUP="plugdev", MODE="0660"
111
112# Neowave Keydo AES by NEOWAVE
113KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1e0d", ATTRS{idProduct}=="f1ae", TAG+="uaccess", GROUP="plugdev", MODE="0660"
34 114
35# Thetis Key 115# Neowave Keydo by NEOWAVE
116KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1e0d", ATTRS{idProduct}=="f1d0", TAG+="uaccess", GROUP="plugdev", MODE="0660"
117
118# Thethis Key by Shenzhen Excelsecu Data Technology Co., Ltd.
36KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1ea8", ATTRS{idProduct}=="f025", TAG+="uaccess", GROUP="plugdev", MODE="0660" 119KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1ea8", ATTRS{idProduct}=="f025", TAG+="uaccess", GROUP="plugdev", MODE="0660"
37 120
38# Nitrokey FIDO U2F, Nitrokey FIDO2, Safetech SafeKey 121# ExcelSecu FIDO2 Security Key by Shenzhen Excelsecu Data Technology Co., Ltd.
39KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4287|42b1|42b3", TAG+="uaccess", GROUP="plugdev", MODE="0660" 122KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1ea8", ATTRS{idProduct}=="fc25", TAG+="uaccess", GROUP="plugdev", MODE="0660"
40 123
41# Google Titan U2F 124# GoTrust Idem Key by NXP Semiconductors
42KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="5026", TAG+="uaccess", GROUP="plugdev", MODE="0660" 125KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1fc9", ATTRS{idProduct}=="f143", TAG+="uaccess", GROUP="plugdev", MODE="0660"
43 126
44# Tomu board + chopstx U2F + SoloKeys 127# Nitrokey FIDO U2F by Flirc
45KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="cdab|a2ca", TAG+="uaccess", GROUP="plugdev", MODE="0660" 128KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4287", TAG+="uaccess", GROUP="plugdev", MODE="0660"
46 129
47# SoloKeys 130# Nitrokey FIDO2 by Flirc
48KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="5070|50b0", TAG+="uaccess", GROUP="plugdev", MODE="0660" 131KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b1", TAG+="uaccess", GROUP="plugdev", MODE="0660"
49 132
50# Trezor 133# Safetech SafeKey by Flirc
51KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="534c", ATTRS{idProduct}=="0001", TAG+="uaccess", GROUP="plugdev", MODE="0660" 134KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b3", TAG+="uaccess", GROUP="plugdev", MODE="0660"
52KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="53c1", TAG+="uaccess", GROUP="plugdev", MODE="0660"
53 135
54# Infineon FIDO 136# JaCarta U2F by Aladdin Software Security R.D.
55KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="058b", ATTRS{idProduct}=="022d", TAG+="uaccess", GROUP="plugdev", MODE="0660" 137KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="24dc", ATTRS{idProduct}=="0101", TAG+="uaccess", GROUP="plugdev", MODE="0660"
56 138
57# Ledger Nano S and Nano X 139# JaCarta U2F by Aladdin Software Security R.D.
58KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="0001|0004", TAG+="uaccess", GROUP="plugdev", MODE="0660" 140KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="24dc", ATTRS{idProduct}=="0501", TAG+="uaccess", GROUP="plugdev", MODE="0660"
59 141
60# Kensington VeriMark 142# Happlink Security Key by Plugā€up
61KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="06cb", ATTRS{idProduct}=="0088", TAG+="uaccess", GROUP="plugdev", MODE="0660" 143KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2581", ATTRS{idProduct}=="f1d0", TAG+="uaccess", GROUP="plugdev", MODE="0660"
62 144
63# Longmai mFIDO 145# Bluink Key by Bluink Ltd
64KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="4c4d", ATTRS{idProduct}=="f703", TAG+="uaccess", GROUP="plugdev", MODE="0660" 146KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2abe", ATTRS{idProduct}=="1002", TAG+="uaccess", GROUP="plugdev", MODE="0660"
65 147
66# eWBM FIDO2 - Goldengate 310, 320, 500, 450 148# Ledger Nano S by LEDGER
67KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="4a1a|4c2a|5c2f|f47c", TAG+="uaccess", GROUP="plugdev", MODE="0660" 149KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="0001", TAG+="uaccess", GROUP="plugdev", MODE="0660"
68 150
69# OnlyKey (FIDO2 / U2F) 151# Ledger Nano X by LEDGER
70KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="60fc", TAG+="uaccess", GROUP="plugdev", MODE="0660" 152KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2c97", ATTRS{idProduct}=="0004", TAG+="uaccess", GROUP="plugdev", MODE="0660"
71 153
72# GoTrust Idem Key 154# Hypersecu HyperFIDO by Hypersecu Information Systems, Inc.
73KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1fc9", ATTRS{idProduct}=="f143", TAG+="uaccess", GROUP="plugdev", MODE="0660" 155KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2ccf", ATTRS{idProduct}=="0880", TAG+="uaccess", GROUP="plugdev", MODE="0660"
156
157# eWBM FIDO2 Goldengate 310 by eWBM Co., Ltd.
158KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="4a1a", TAG+="uaccess", GROUP="plugdev", MODE="0660"
159
160# eWBM FIDO2 Goldengate 320 by eWBM Co., Ltd.
161KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="4c2a", TAG+="uaccess", GROUP="plugdev", MODE="0660"
162
163# eWBM FIDO2 Goldengate 500 by eWBM Co., Ltd.
164KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="5c2f", TAG+="uaccess", GROUP="plugdev", MODE="0660"
165
166# eWBM FIDO2 Goldengate 450 by eWBM Co., Ltd.
167KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="311f", ATTRS{idProduct}=="f47c", TAG+="uaccess", GROUP="plugdev", MODE="0660"
168
169# Longmai mFIDO by Unknown vendor
170KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="4c4d", ATTRS{idProduct}=="f703", TAG+="uaccess", GROUP="plugdev", MODE="0660"
171
172# SatoshiLabs TREZOR by SatoshiLabs
173KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="534c", ATTRS{idProduct}=="0001", TAG+="uaccess", GROUP="plugdev", MODE="0660"
74 174
75LABEL="u2f_end" 175LABEL="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 @@
1#!/bin/sh -u
2
3# Copyright (c) 2020 Yubico AB. All rights reserved.
4# Use of this source code is governed by a BSD-style
5# license that can be found in the LICENSE file.
6
7sort_by_id() {
8 awk '{ printf "%d\n", $3 }' | sort -Cnu
9}
10
11if ! grep '^vendor' "$1" | sort_by_id; then
12 echo unsorted vendor section 1>&2
13 exit 1
14fi
15
16VENDORS=$(grep '^vendor' "$1" | awk '{ print $2 }')
17PRODUCTS=$(grep '^product' "$1" | awk '{ print $2 }' | uniq)
18
19if [ "${VENDORS}" != "${PRODUCTS}" ]; then
20 echo vendors: "$(echo "${VENDORS}" | tr '\n' ',')" 1>&2
21 echo products: "$(echo "${PRODUCTS}" | tr '\n' ',')" 1>&2
22 echo vendors and products in different order 1>&2
23 exit 2
24fi
25
26for v in ${VENDORS}; do
27 if ! grep "^product ${v}" "$1" | sort_by_id; then
28 echo "${v}": unsorted product section 1>&2
29 exit 3
30 fi
31done
diff --git a/udev/fidodevs b/udev/fidodevs
new file mode 100644
index 0000000..e149964
--- /dev/null
+++ b/udev/fidodevs
@@ -0,0 +1,110 @@
1# Copyright (c) 2020 Yubico AB. All rights reserved.
2# Use of this source code is governed by a BSD-style
3# license that can be found in the LICENSE file.
4
5# After modifying this file, regenerate 70-u2f.rules:
6# ./genrules.awk fidodevs > 70-u2f.rules
7
8# List of known vendors. Sorted by vendor ID.
9
10vendor STMICRO 0x0483 STMicroelectronics
11vendor INFINEON 0x058b Infineon Technologies
12vendor SYNAPTICS 0x06cb Synaptics Inc.
13vendor FEITIAN 0x096e Feitian Technologies Co., Ltd.
14vendor YUBICO 0x1050 Yubico AB
15vendor SILICON 0x10c4 Silicon Laboratories, Inc.
16vendor PIDCODES 0x1209 pid.codes
17vendor GOOGLE 0x18d1 Google Inc.
18vendor VASCO 0x1a44 VASCO Data Security NV
19vendor OPENMOKO 0x1d50 OpenMoko, Inc.
20vendor NEOWAVE 0x1e0d NEOWAVE
21vendor EXCELSECU 0x1ea8 Shenzhen Excelsecu Data Technology Co., Ltd.
22vendor NXP 0x1fc9 NXP Semiconductors
23vendor FLIRC 0x20a0 Flirc
24vendor ALLADIN 0x24dc Aladdin Software Security R.D.
25vendor PLUGUP 0x2581 Plugā€up
26vendor BLUINK 0x2abe Bluink Ltd
27vendor LEDGER 0x2c97 LEDGER
28vendor HYPERSECU 0x2ccf Hypersecu Information Systems, Inc.
29vendor EWBM 0x311f eWBM Co., Ltd.
30vendor UNKNOWN1 0x4c4d Unknown vendor
31vendor SATOSHI 0x534c SatoshiLabs
32
33# List of known products. Grouped by vendor; sorted by product ID.
34
35product STMICRO 0xa2ac ellipticSecure MIRKey
36product STMICRO 0xa2ca Unknown product
37product STMICRO 0xcdab Unknown product
38
39product INFINEON 0x022d Infineon FIDO
40
41product SYNAPTICS 0x0088 Kensington VeriMark
42
43product FEITIAN 0x0850 FS ePass FIDO
44product FEITIAN 0x0852 Unknown product
45product FEITIAN 0x0853 Unknown product
46product FEITIAN 0x0854 Unknown product
47product FEITIAN 0x0856 Unknown product
48product FEITIAN 0x0858 Unknown product
49product FEITIAN 0x085a FS MultiPass FIDO U2F
50product FEITIAN 0x085b Unknown product
51product FEITIAN 0x085d Unknown product
52product FEITIAN 0x0880 Hypersecu HyperFIDO
53
54product YUBICO 0x0113 YubiKey NEO FIDO
55product YUBICO 0x0114 YubiKey NEO OTP+FIDO
56product YUBICO 0x0115 YubiKey NEO FIDO+CCID
57product YUBICO 0x0116 YubiKey NEO OTP+FIDO+CCID
58product YUBICO 0x0120 Security Key by Yubico
59product YUBICO 0x0121 Unknown product
60product YUBICO 0x0200 Gnubby U2F
61product YUBICO 0x0402 YubiKey 4 FIDO
62product YUBICO 0x0403 YubiKey 4 OTP+FIDO
63product YUBICO 0x0406 YubiKey 4 FIDO+CCID
64product YUBICO 0x0407 YubiKey 4 OTP+FIDO+CCID
65product YUBICO 0x0410 YubiKey Plus
66
67product SILICON 0x8acf U2F Zero
68
69product PIDCODES 0x5070 SoloKeys SoloHacker
70product PIDCODES 0x50b0 SoloKeys SoloBoot
71product PIDCODES 0x53c1 SatoshiLabs TREZOR
72
73product GOOGLE 0x5026 Google Titan U2F
74
75product VASCO 0x00bb VASCO SecureClick
76
77product OPENMOKO 0x60fc OnlyKey (FIDO2/U2F)
78
79product NEOWAVE 0xf1ae Neowave Keydo AES
80product NEOWAVE 0xf1d0 Neowave Keydo
81
82product EXCELSECU 0xf025 Thethis Key
83product EXCELSECU 0xfc25 ExcelSecu FIDO2 Security Key
84
85product NXP 0xf143 GoTrust Idem Key
86
87product FLIRC 0x4287 Nitrokey FIDO U2F
88product FLIRC 0x42b1 Nitrokey FIDO2
89product FLIRC 0x42b3 Safetech SafeKey
90
91product ALLADIN 0x0101 JaCarta U2F
92product ALLADIN 0x0501 JaCarta U2F
93
94product PLUGUP 0xf1d0 Happlink Security Key
95
96product BLUINK 0x1002 Bluink Key
97
98product LEDGER 0x0001 Ledger Nano S
99product LEDGER 0x0004 Ledger Nano X
100
101product HYPERSECU 0x0880 Hypersecu HyperFIDO
102
103product EWBM 0x4a1a eWBM FIDO2 Goldengate 310
104product EWBM 0x4c2a eWBM FIDO2 Goldengate 320
105product EWBM 0x5c2f eWBM FIDO2 Goldengate 500
106product EWBM 0xf47c eWBM FIDO2 Goldengate 450
107
108product UNKNOWN1 0xf703 Longmai mFIDO
109
110product 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 @@
1#!/usr/bin/awk -f
2
3# Copyright (c) 2020 Yubico AB. All rights reserved.
4# Use of this source code is governed by a BSD-style
5# license that can be found in the LICENSE file.
6
7NR == 1 {
8 print "# Copyright (c) 2020 Yubico AB. All rights reserved."
9 print "# Use of this source code is governed by a BSD-style"
10 print "# license that can be found in the LICENSE file."
11 print ""
12 print "# This file is automatically generated, and should"
13 print "# be used with udev 188 or newer."
14 print ""
15 print "ACTION!=\"add|change\", GOTO=\"fido_end\""
16
17 next
18}
19
20$1 == "vendor" {
21 sub("0x", "", $3)
22 vendors[$2, "id"] = $3
23
24 f = 4
25 while (f <= NF) {
26 vendors[$2, "name"] = vendors[$2, "name"] " " $f
27 f++
28 }
29}
30
31$1 == "product" {
32 sub("0x", "", $3)
33 name = ""
34
35 f = 4
36 while (f <= NF) {
37 name = name " " $f
38 f++
39 }
40
41 line = "\n#" name " by" vendors[$2, "name"]"\n"
42 line = line"KERNEL==\"hidraw*\""
43 line = line", SUBSYSTEM==\"hidraw\""
44 line = line", ATTRS{idVendor}==\""vendors[$2, "id"]"\""
45 line = line", ATTRS{idProduct}==\""$3"\""
46 line = line", TAG+=\"uaccess\""
47 line = line", GROUP=\"plugdev\""
48 line = line", MODE=\"0660\""
49
50 print line
51}
52
53END {
54 print "\nLABEL=\"fido_end\""
55}
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"
12# LibreSSL coordinates. 12# LibreSSL coordinates.
13New-Variable -Name 'LIBRESSL_URL' ` 13New-Variable -Name 'LIBRESSL_URL' `
14 -Value 'https://ftp.openbsd.org/pub/OpenBSD/LibreSSL' -Option Constant 14 -Value 'https://ftp.openbsd.org/pub/OpenBSD/LibreSSL' -Option Constant
15New-Variable -Name 'LIBRESSL' -Value 'libressl-3.0.2' -Option Constant 15New-Variable -Name 'LIBRESSL' -Value 'libressl-3.1.4' -Option Constant
16 16
17# libcbor coordinates. 17# libcbor coordinates.
18New-Variable -Name 'LIBCBOR' -Value 'libcbor-0.5.0' -Option Constant 18New-Variable -Name 'LIBCBOR' -Value 'libcbor-0.7.0' -Option Constant
19New-Variable -Name 'LIBCBOR_BRANCH' -Value 'v0.5.0' -Option Constant 19New-Variable -Name 'LIBCBOR_BRANCH' -Value 'v0.7.0' -Option Constant
20New-Variable -Name 'LIBCBOR_GIT' -Value 'https://github.com/pjk/libcbor' ` 20New-Variable -Name 'LIBCBOR_GIT' -Value 'https://github.com/pjk/libcbor' `
21 -Option Constant 21 -Option Constant
22 22
@@ -149,7 +149,7 @@ Function Build(${OUTPUT}, ${GENERATOR}, ${ARCH}) {
149 -DCMAKE_INSTALL_PREFIX="${OUTPUT}" 149 -DCMAKE_INSTALL_PREFIX="${OUTPUT}"
150 & $CMake --build . --config Release 150 & $CMake --build . --config Release
151 & $CMake --build . --config Release --target install 151 & $CMake --build . --config Release --target install
152 "cbor.dll", "crypto-45.dll" | %{ Copy-Item "${OUTPUT}\bin\$_" ` 152 "cbor.dll", "crypto-46.dll" | %{ Copy-Item "${OUTPUT}\bin\$_" `
153 -Destination "examples\Release" } 153 -Destination "examples\Release" }
154} 154}
155 155
@@ -161,15 +161,15 @@ Function Package-Headers() {
161Function Package-Libraries(${SRC}, ${DEST}) { 161Function Package-Libraries(${SRC}, ${DEST}) {
162 Copy-Item "${SRC}\bin\cbor.dll" "${DEST}" -ErrorAction Stop 162 Copy-Item "${SRC}\bin\cbor.dll" "${DEST}" -ErrorAction Stop
163 Copy-Item "${SRC}\lib\cbor.lib" "${DEST}" -ErrorAction Stop 163 Copy-Item "${SRC}\lib\cbor.lib" "${DEST}" -ErrorAction Stop
164 Copy-Item "${SRC}\bin\crypto-45.dll" "${DEST}" -ErrorAction Stop 164 Copy-Item "${SRC}\bin\crypto-46.dll" "${DEST}" -ErrorAction Stop
165 Copy-Item "${SRC}\lib\crypto-45.lib" "${DEST}" -ErrorAction Stop 165 Copy-Item "${SRC}\lib\crypto-46.lib" "${DEST}" -ErrorAction Stop
166 Copy-Item "${SRC}\lib\fido2.dll" "${DEST}" -ErrorAction Stop 166 Copy-Item "${SRC}\lib\fido2.dll" "${DEST}" -ErrorAction Stop
167 Copy-Item "${SRC}\lib\fido2.lib" "${DEST}" -ErrorAction Stop 167 Copy-Item "${SRC}\lib\fido2.lib" "${DEST}" -ErrorAction Stop
168} 168}
169 169
170Function Package-PDBs(${SRC}, ${DEST}) { 170Function Package-PDBs(${SRC}, ${DEST}) {
171 Copy-Item "${SRC}\${LIBRESSL}\crypto\crypto.dir\Release\vc142.pdb" ` 171 Copy-Item "${SRC}\${LIBRESSL}\crypto\crypto.dir\Release\vc142.pdb" `
172 "${DEST}\crypto-45.pdb" -ErrorAction Stop 172 "${DEST}\crypto-46.pdb" -ErrorAction Stop
173 Copy-Item "${SRC}\${LIBCBOR}\src\cbor_shared.dir\Release\vc142.pdb" ` 173 Copy-Item "${SRC}\${LIBCBOR}\src\cbor_shared.dir\Release\vc142.pdb" `
174 "${DEST}\cbor.pdb" -ErrorAction Stop 174 "${DEST}\cbor.pdb" -ErrorAction Stop
175 Copy-Item "${SRC}\src\fido2_shared.dir\Release\vc142.pdb" ` 175 Copy-Item "${SRC}\src\fido2_shared.dir\Release\vc142.pdb" `