summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornicoo <nicoo@debian.org>2020-02-23 14:46:35 +0000
committernicoo <nicoo@debian.org>2020-02-23 14:46:35 +0000
commitf794345c2d734f593da8ed7754e5dbb5809c688d (patch)
tree32889c9b7bd26656242cc5e4b483c8a1deba88e1
parent28215e6c161c70cb1bcae7d01195fefcffb09d32 (diff)
parent400533f0af0b8119c84e574387ed05e500f63861 (diff)
Merge branch 'prep-v1.3.1-1' into 'debian/sid'
Prepare upload v1.3.1-1 See merge request auth-team/libfido2!3
-rw-r--r--.github/workflows/windows.yml14
-rw-r--r--.gitignore6
-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-asan58
-rw-r--r--.travis/fuzz-linux-msan58
-rw-r--r--CMakeLists.txt4
-rw-r--r--NEWS4
-rw-r--r--README.adoc17
-rw-r--r--debian/changelog14
-rw-r--r--fuzz/report.html.gzbin0 -> 206440 bytes
-rw-r--r--openbsd-compat/openbsd-compat.h2
-rw-r--r--src/iso7816.c2
-rw-r--r--src/u2f.c2
-rw-r--r--tools/CMakeLists.txt7
-rw-r--r--tools/sk-libfido2.c784
-rw-r--r--udev/70-u2f.rules7
20 files changed, 359 insertions, 818 deletions
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
new file mode 100644
index 0000000..eb953db
--- /dev/null
+++ b/.github/workflows/windows.yml
@@ -0,0 +1,14 @@
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
new file mode 100644
index 0000000..329c184
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
1build/
2cscope.out
3fuzz/build/
4fuzz/obj/
5fuzz/*.so
6output/
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..5ddf36f
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,86 @@
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: xenial
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: xenial
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
new file mode 100644
index 0000000..8938461
--- /dev/null
+++ b/.travis/build-linux-clang
@@ -0,0 +1,22 @@
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
new file mode 100644
index 0000000..be1e0a9
--- /dev/null
+++ b/.travis/build-linux-gcc
@@ -0,0 +1,19 @@
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
new file mode 100644
index 0000000..c88ddca
--- /dev/null
+++ b/.travis/build-linux-mingw
@@ -0,0 +1,47 @@
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
new file mode 100644
index 0000000..69a784c
--- /dev/null
+++ b/.travis/build-osx-clang
@@ -0,0 +1,24 @@
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
new file mode 100644
index 0000000..0a0aebb
--- /dev/null
+++ b/.travis/fuzz-linux-asan
@@ -0,0 +1,58 @@
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
48tar -C corpus -zxf ../fuzz/corpus.tgz
49fuzz/fuzz_cred -use_value_profile=1 -reload=30 -print_pcs=1 \
50 -print_funcs=30 -timeout=10 -max_len=17408 -runs=1 corpus/fuzz_cred
51fuzz/fuzz_assert -use_value_profile=1 -reload=30 -print_pcs=1 \
52 -print_funcs=30 -timeout=10 -max_len=17408 -runs=1 corpus/fuzz_assert
53fuzz/fuzz_credman -use_value_profile=1 -reload=30 -print_pcs=1 \
54 -print_funcs=30 -timeout=10 -max_len=17408 -runs=1 corpus/fuzz_credman
55fuzz/fuzz_mgmt -use_value_profile=1 -reload=30 -print_pcs=1 \
56 -print_funcs=30 -timeout=10 -max_len=17408 -runs=1 corpus/fuzz_mgmt
57fuzz/fuzz_bio -use_value_profile=1 -reload=30 -print_pcs=1 \
58 -print_funcs=30 -timeout=10 -max_len=17408 -runs=1 corpus/fuzz_bio
diff --git a/.travis/fuzz-linux-msan b/.travis/fuzz-linux-msan
new file mode 100644
index 0000000..fd7b2ac
--- /dev/null
+++ b/.travis/fuzz-linux-msan
@@ -0,0 +1,58 @@
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
48tar -C corpus -zxf ../fuzz/corpus.tgz
49fuzz/fuzz_cred -use_value_profile=1 -reload=30 -print_pcs=1 \
50 -print_funcs=30 -timeout=10 -max_len=17408 -runs=1 corpus/fuzz_cred
51fuzz/fuzz_assert -use_value_profile=1 -reload=30 -print_pcs=1 \
52 -print_funcs=30 -timeout=10 -max_len=17408 -runs=1 corpus/fuzz_assert
53fuzz/fuzz_credman -use_value_profile=1 -reload=30 -print_pcs=1 \
54 -print_funcs=30 -timeout=10 -max_len=17408 -runs=1 corpus/fuzz_credman
55fuzz/fuzz_mgmt -use_value_profile=1 -reload=30 -print_pcs=1 \
56 -print_funcs=30 -timeout=10 -max_len=17408 -runs=1 corpus/fuzz_mgmt
57fuzz/fuzz_bio -use_value_profile=1 -reload=30 -print_pcs=1 \
58 -print_funcs=30 -timeout=10 -max_len=17408 -runs=1 corpus/fuzz_bio
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c7c5991..9481c46 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -20,7 +20,7 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
20 20
21set(FIDO_MAJOR "1") 21set(FIDO_MAJOR "1")
22set(FIDO_MINOR "3") 22set(FIDO_MINOR "3")
23set(FIDO_PATCH "0") 23set(FIDO_PATCH "1")
24set(FIDO_VERSION ${FIDO_MAJOR}.${FIDO_MINOR}.${FIDO_PATCH}) 24set(FIDO_VERSION ${FIDO_MAJOR}.${FIDO_MINOR}.${FIDO_PATCH})
25 25
26add_definitions(-D_FIDO_MAJOR=${FIDO_MAJOR}) 26add_definitions(-D_FIDO_MAJOR=${FIDO_MAJOR})
@@ -322,7 +322,7 @@ elseif(NOT MSVC)
322 endif() 322 endif()
323else() 323else()
324 string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} 324 string(CONCAT CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS}
325 " /def:${CMAKE_CURRENT_SOURCE_DIR}/src/export.msvc") 325 " /def:\"${CMAKE_CURRENT_SOURCE_DIR}/src/export.msvc\"")
326endif() 326endif()
327 327
328include_directories(${CMAKE_SOURCE_DIR}/src) 328include_directories(${CMAKE_SOURCE_DIR}/src)
diff --git a/NEWS b/NEWS
index 1b78c7c..8b96d39 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,7 @@
1* Version 1.3.1 (2020-02-19)
2 ** fix zero-ing of le1 and le2 when talking to a U2F device.
3 ** dropping sk-libfido2 middleware, please find it in the openssh tree.
4
1* Version 1.3.0 (2019-11-28) 5* Version 1.3.0 (2019-11-28)
2 ** assert/hmac: encode public key as per spec, gh#60. 6 ** assert/hmac: encode public key as per spec, gh#60.
3 ** fido2-cred: fix creation of resident keys. 7 ** fido2-cred: fix creation of resident keys.
diff --git a/README.adoc b/README.adoc
index 8693417..ce8ac1e 100644
--- a/README.adoc
+++ b/README.adoc
@@ -31,7 +31,7 @@ is also available.
31 31
32==== Releases 32==== Releases
33 33
34The current release of *libfido2* is 1.3.0. Please consult Yubico's 34The current release of *libfido2* is 1.3.1. Please consult Yubico's
35https://developers.yubico.com/libfido2/Releases[release page] for source 35https://developers.yubico.com/libfido2/Releases[release page] for source
36and binary releases. 36and binary releases.
37 37
@@ -71,18 +71,3 @@ KERNEL=="hidraw*", SUBSYSTEM=="hidraw", \
71On Windows 1903 and newer versions, access to FIDO devices has been restricted 71On Windows 1903 and newer versions, access to FIDO devices has been restricted
72to applications using the operating system's native API. Use of *libfido2* 72to applications using the operating system's native API. Use of *libfido2*
73is still possible in privileged applications. 73is still possible in privileged applications.
74
75=== OpenSSH Integration
76
77*libfido2* includes middleware allowing https://www.openssh.com[OpenSSH] to
78talk to U2F/FIDO2 devices. Note that server support is required for
79authentication. In a nutshell:
80
81==== Key Generation
82
83 $ ssh-keygen -t [ecdsa-sk|ed25519-sk] -w /path/to/libsk-libfido2.so
84
85==== Authentication
86
87 $ ssh-agent -P /path/to/libsk-libfido2.so
88 $ ssh-add -S /path/to/libsk-libfido2.so
diff --git a/debian/changelog b/debian/changelog
index 3cf1a4d..d3ef6dd 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,14 +1,18 @@
1libfido2 (1.3.0-2) UNRELEASED; urgency=medium 1libfido2 (1.3.1-1) unstable; urgency=medium
2
3 [ Colin Watson ]
4 * Fix pattern in debian/watch.
5 2
6 [ nicoo ] 3 [ nicoo ]
4 * New upstream version 1.3.1 (released 2020-02-19)
5 Correctly zero part of the APDU when communicating with U2F devices
6
7 * Fix non-determinism in the build 7 * Fix non-determinism in the build
8 Set CMAKE_BUILD_RPATH_USE_ORIGIN, require cmake >= 3.14 8 Set CMAKE_BUILD_RPATH_USE_ORIGIN, require cmake >= 3.14
9 * Add CI, based on salsa-ci-team's pipeline 9 * Add CI, based on salsa-ci-team's pipeline
10 10
11 -- nicoo <nicoo@debian.org> Sat, 15 Feb 2020 17:47:54 +0100 11 [ Colin Watson ]
12 * Fix pattern in debian/watch.
13 * Only use -fstack-protector-all if it is supported
14
15 -- nicoo <nicoo@debian.org> Sun, 23 Feb 2020 15:36:41 +0100
12 16
13libfido2 (1.3.0-1) unstable; urgency=low 17libfido2 (1.3.0-1) unstable; urgency=low
14 18
diff --git a/fuzz/report.html.gz b/fuzz/report.html.gz
new file mode 100644
index 0000000..9f07223
--- /dev/null
+++ b/fuzz/report.html.gz
Binary files differ
diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h
index d1d8652..bee126c 100644
--- a/openbsd-compat/openbsd-compat.h
+++ b/openbsd-compat/openbsd-compat.h
@@ -18,6 +18,7 @@
18#if defined(__APPLE__) && !defined(HAVE_ENDIAN_H) 18#if defined(__APPLE__) && !defined(HAVE_ENDIAN_H)
19#include <libkern/OSByteOrder.h> 19#include <libkern/OSByteOrder.h>
20#define be16toh(x) OSSwapBigToHostInt16((x)) 20#define be16toh(x) OSSwapBigToHostInt16((x))
21#define htobe16(x) OSSwapHostToBigInt16((x))
21#define be32toh(x) OSSwapBigToHostInt32((x)) 22#define be32toh(x) OSSwapBigToHostInt32((x))
22#endif /* __APPLE__ && !HAVE_ENDIAN_H */ 23#endif /* __APPLE__ && !HAVE_ENDIAN_H */
23 24
@@ -27,6 +28,7 @@
27#include <sys/param.h> 28#include <sys/param.h>
28#endif 29#endif
29#define be16toh(x) ntohs((x)) 30#define be16toh(x) ntohs((x))
31#define htobe16(x) htons((x))
30#define be32toh(x) ntohl((x)) 32#define be32toh(x) ntohl((x))
31#endif /* _WIN32 && !HAVE_ENDIAN_H */ 33#endif /* _WIN32 && !HAVE_ENDIAN_H */
32 34
diff --git a/src/iso7816.c b/src/iso7816.c
index e2ea281..a3fd280 100644
--- a/src/iso7816.c
+++ b/src/iso7816.c
@@ -13,7 +13,7 @@ iso7816_new(uint8_t ins, uint8_t p1, uint16_t payload_len)
13 iso7816_apdu_t *apdu; 13 iso7816_apdu_t *apdu;
14 size_t alloc_len; 14 size_t alloc_len;
15 15
16 alloc_len = sizeof(iso7816_apdu_t) + payload_len; 16 alloc_len = sizeof(iso7816_apdu_t) + payload_len + 2; /* le1 le2 */
17 17
18 if ((apdu = calloc(1, alloc_len)) == NULL) 18 if ((apdu = calloc(1, alloc_len)) == NULL)
19 return (NULL); 19 return (NULL);
diff --git a/src/u2f.c b/src/u2f.c
index 3f2d9aa..82b289f 100644
--- a/src/u2f.c
+++ b/src/u2f.c
@@ -439,7 +439,7 @@ encode_cred_authdata(const char *rp_id, const uint8_t *kh, uint8_t kh_len,
439 authdata.sigcount = 0; 439 authdata.sigcount = 0;
440 440
441 memset(&attcred_raw.aaguid, 0, sizeof(attcred_raw.aaguid)); 441 memset(&attcred_raw.aaguid, 0, sizeof(attcred_raw.aaguid));
442 attcred_raw.id_len = (uint16_t)(kh_len << 8); /* XXX */ 442 attcred_raw.id_len = htobe16(kh_len);
443 443
444 len = authdata_blob.len = sizeof(authdata) + sizeof(attcred_raw) + 444 len = authdata_blob.len = sizeof(authdata) + sizeof(attcred_raw) +
445 kh_len + pk_blob.len; 445 kh_len + pk_blob.len;
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 5f27e88..4b8ef32 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -49,17 +49,10 @@ add_executable(fido2-token
49 ${COMPAT_SOURCES} 49 ${COMPAT_SOURCES}
50) 50)
51 51
52add_library(sk-libfido2 MODULE sk-libfido2.c)
53set_target_properties(sk-libfido2 PROPERTIES
54 COMPILE_FLAGS "-DSK_STANDALONE -DWITH_OPENSSL"
55 OUTPUT_NAME sk-libfido2
56)
57 52
58target_link_libraries(fido2-cred ${CRYPTO_LIBRARIES} fido2_shared) 53target_link_libraries(fido2-cred ${CRYPTO_LIBRARIES} fido2_shared)
59target_link_libraries(fido2-assert ${CRYPTO_LIBRARIES} fido2_shared) 54target_link_libraries(fido2-assert ${CRYPTO_LIBRARIES} fido2_shared)
60target_link_libraries(fido2-token ${CRYPTO_LIBRARIES} fido2_shared) 55target_link_libraries(fido2-token ${CRYPTO_LIBRARIES} fido2_shared)
61target_link_libraries(sk-libfido2 ${CRYPTO_LIBRARIES} fido2_shared)
62 56
63install(TARGETS fido2-cred fido2-assert fido2-token 57install(TARGETS fido2-cred fido2-assert fido2-token
64 DESTINATION ${CMAKE_INSTALL_BINDIR}) 58 DESTINATION ${CMAKE_INSTALL_BINDIR})
65install(TARGETS sk-libfido2 DESTINATION ${CMAKE_INSTALL_LIBDIR})
diff --git a/tools/sk-libfido2.c b/tools/sk-libfido2.c
deleted file mode 100644
index 15aa813..0000000
--- a/tools/sk-libfido2.c
+++ /dev/null
@@ -1,784 +0,0 @@
1/*
2 * Copyright (c) 2019 Markus Friedl
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <fcntl.h>
18#include <stdint.h>
19#include <stdlib.h>
20#include <string.h>
21#include <stdio.h>
22#include <stddef.h>
23#include <stdarg.h>
24#ifdef HAVE_UNISTD_H
25#include <unistd.h>
26#endif
27
28#ifdef WITH_OPENSSL
29#include <openssl/opensslv.h>
30#include <openssl/crypto.h>
31#include <openssl/bn.h>
32#include <openssl/ec.h>
33#include <openssl/ecdsa.h>
34#endif /* WITH_OPENSSL */
35
36#include <fido.h>
37
38#ifndef SK_STANDALONE
39#include "log.h"
40#include "xmalloc.h"
41#endif
42
43/* #define SK_DEBUG 1 */
44
45#if defined(_WIN32)
46#include <windows.h>
47#include <winternl.h>
48#include <winerror.h>
49#include <bcrypt.h>
50#include <sal.h>
51#endif
52
53#define MAX_FIDO_DEVICES 256
54
55/* Compatibility with OpenSSL 1.0.x */
56#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
57#define ECDSA_SIG_get0(sig, pr, ps) \
58 do { \
59 (*pr) = sig->r; \
60 (*ps) = sig->s; \
61 } while (0)
62#endif
63
64#define SK_VERSION_MAJOR 0x00020000 /* current API version */
65
66/* Flags */
67#define SK_USER_PRESENCE_REQD 0x01
68
69/* Algs */
70#define SK_ECDSA 0x00
71#define SK_ED25519 0x01
72
73struct sk_enroll_response {
74 uint8_t *public_key;
75 size_t public_key_len;
76 uint8_t *key_handle;
77 size_t key_handle_len;
78 uint8_t *signature;
79 size_t signature_len;
80 uint8_t *attestation_cert;
81 size_t attestation_cert_len;
82};
83
84struct sk_sign_response {
85 uint8_t flags;
86 uint32_t counter;
87 uint8_t *sig_r;
88 size_t sig_r_len;
89 uint8_t *sig_s;
90 size_t sig_s_len;
91};
92
93/* If building as part of OpenSSH, then rename exported functions */
94#if !defined(SK_STANDALONE)
95#define sk_api_version ssh_sk_api_version
96#define sk_enroll ssh_sk_enroll
97#define sk_sign ssh_sk_sign
98#endif
99
100/* Return the version of the middleware API */
101uint32_t sk_api_version(void);
102
103/* Enroll a U2F key (private key generation) */
104int sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len,
105 const char *application, uint8_t flags,
106 struct sk_enroll_response **enroll_response);
107
108/* Sign a challenge */
109int sk_sign(int alg, const uint8_t *message, size_t message_len,
110 const char *application, const uint8_t *key_handle, size_t key_handle_len,
111 uint8_t flags, struct sk_sign_response **sign_response);
112
113#ifdef SK_DEBUG
114static void skdebug(const char *func, const char *fmt, ...)
115 __attribute__((__format__ (printf, 2, 3)));
116
117static void
118skdebug(const char *func, const char *fmt, ...)
119{
120#if !defined(SK_STANDALONE)
121 char *msg;
122 va_list ap;
123
124 va_start(ap, fmt);
125 xvasprintf(&msg, fmt, ap);
126 va_end(ap);
127 debug("%s: %s", func, msg);
128 free(msg);
129#else
130 va_list ap;
131
132 va_start(ap, fmt);
133 fprintf(stderr, "%s: ", func);
134 vfprintf(stderr, fmt, ap);
135 fputc('\n', stderr);
136 va_end(ap);
137#endif /* !SK_STANDALONE */
138}
139#else
140#define skdebug(...) do { /* nothing */ } while (0)
141#endif /* SK_DEBUG */
142
143uint32_t
144sk_api_version(void)
145{
146 return SK_VERSION_MAJOR;
147}
148
149/* Select the first identified FIDO device attached to the system */
150static char *
151pick_first_device(void)
152{
153 char *ret = NULL;
154 fido_dev_info_t *devlist = NULL;
155 size_t olen = 0;
156 int r;
157 const fido_dev_info_t *di;
158
159 if ((devlist = fido_dev_info_new(1)) == NULL) {
160 skdebug(__func__, "fido_dev_info_new failed");
161 goto out;
162 }
163 if ((r = fido_dev_info_manifest(devlist, 1, &olen)) != FIDO_OK) {
164 skdebug(__func__, "fido_dev_info_manifest failed: %s",
165 fido_strerr(r));
166 goto out;
167 }
168 if (olen != 1) {
169 skdebug(__func__, "fido_dev_info_manifest bad len %zu", olen);
170 goto out;
171 }
172 di = fido_dev_info_ptr(devlist, 0);
173 if ((ret = strdup(fido_dev_info_path(di))) == NULL) {
174 skdebug(__func__, "fido_dev_info_path failed");
175 goto out;
176 }
177 out:
178 fido_dev_info_free(&devlist, 1);
179 return ret;
180}
181
182#if defined(HAVE_ARC4RANDOM_BUF)
183static int
184get_random_challenge(uint8_t *ptr, size_t len)
185{
186 arc4random_buf(ptr, len);
187
188 return 0;
189}
190#elif defined(HAVE_GETENTROPY)
191static int
192get_random_challenge(uint8_t *ptr, size_t len)
193{
194 if (getentropy(ptr, len) == -1) {
195 skdebug(__func__, "getentropy failed");
196 return -1;
197 }
198
199 return 0;
200}
201#elif defined(HAS_DEV_URANDOM)
202static int
203get_random_challenge(uint8_t *ptr, size_t len)
204{
205 int fd;
206 ssize_t n;
207
208 if ((fd = open(FIDO_RANDOM_DEV, O_RDONLY)) < 0) {
209 skdebug(__func__, "open %s failed", FIDO_RANDOM_DEV);
210 return -1;
211 }
212
213 n = read(fd, ptr, len);
214 close(fd);
215
216 if (n < 0 || (size_t)n != len) {
217 skdebug(__func__, "read from %s failed", FIDO_RANDOM_DEV);
218 return -1;
219 }
220
221 return 0;
222}
223#elif defined(_WIN32)
224static int
225get_random_challenge(uint8_t *ptr, size_t len)
226{
227 NTSTATUS status;
228
229 status = BCryptGenRandom(NULL, ptr, len,
230 BCRYPT_USE_SYSTEM_PREFERRED_RNG);
231 if (!NT_SUCCESS(status))
232 return -1;
233
234 return 0;
235}
236#else
237#error "please provide an implementation of get_random_challenge() for your platform"
238#endif
239
240/* Check if the specified key handle exists on a given device. */
241static int
242try_device(fido_dev_t *dev, const char *application,
243 const uint8_t *key_handle, size_t key_handle_len)
244{
245 fido_assert_t *assert = NULL;
246 uint8_t challenge[32];
247 int r = FIDO_ERR_INTERNAL;
248
249 if (get_random_challenge(challenge, sizeof(challenge)) == -1) {
250 skdebug(__func__, "get_random_challenge failed");
251 goto out;
252 }
253
254 if ((assert = fido_assert_new()) == NULL) {
255 skdebug(__func__, "fido_assert_new failed");
256 goto out;
257 }
258 if ((r = fido_assert_set_clientdata_hash(assert, challenge,
259 sizeof(challenge))) != FIDO_OK) {
260 skdebug(__func__, "fido_assert_set_clientdata_hash: %s",
261 fido_strerr(r));
262 goto out;
263 }
264 if ((r = fido_assert_set_rp(assert, application)) != FIDO_OK) {
265 skdebug(__func__, "fido_assert_set_rp: %s", fido_strerr(r));
266 goto out;
267 }
268 if ((r = fido_assert_allow_cred(assert, key_handle,
269 key_handle_len)) != FIDO_OK) {
270 skdebug(__func__, "fido_assert_allow_cred: %s", fido_strerr(r));
271 goto out;
272 }
273 if ((r = fido_assert_set_up(assert, FIDO_OPT_FALSE)) != FIDO_OK) {
274 skdebug(__func__, "fido_assert_up: %s", fido_strerr(r));
275 goto out;
276 }
277 r = fido_dev_get_assert(dev, assert, NULL);
278 skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
279 if (r == FIDO_ERR_USER_PRESENCE_REQUIRED) {
280 /* U2F tokens may return this */
281 r = FIDO_OK;
282 }
283 out:
284 fido_assert_free(&assert);
285
286 return r != FIDO_OK ? -1 : 0;
287}
288
289/* Iterate over configured devices looking for a specific key handle */
290static fido_dev_t *
291find_device(const char *application, const uint8_t *key_handle,
292 size_t key_handle_len)
293{
294 fido_dev_info_t *devlist = NULL;
295 fido_dev_t *dev = NULL;
296 size_t devlist_len = 0, i;
297 const char *path;
298 int r;
299
300 if ((devlist = fido_dev_info_new(MAX_FIDO_DEVICES)) == NULL) {
301 skdebug(__func__, "fido_dev_info_new failed");
302 goto out;
303 }
304 if ((r = fido_dev_info_manifest(devlist, MAX_FIDO_DEVICES,
305 &devlist_len)) != FIDO_OK) {
306 skdebug(__func__, "fido_dev_info_manifest: %s", fido_strerr(r));
307 goto out;
308 }
309
310 skdebug(__func__, "found %zu device(s)", devlist_len);
311
312 for (i = 0; i < devlist_len; i++) {
313 const fido_dev_info_t *di = fido_dev_info_ptr(devlist, i);
314
315 if (di == NULL) {
316 skdebug(__func__, "fido_dev_info_ptr %zu failed", i);
317 continue;
318 }
319 if ((path = fido_dev_info_path(di)) == NULL) {
320 skdebug(__func__, "fido_dev_info_path %zu failed", i);
321 continue;
322 }
323 skdebug(__func__, "trying device %zu: %s", i, path);
324 if ((dev = fido_dev_new()) == NULL) {
325 skdebug(__func__, "fido_dev_new failed");
326 continue;
327 }
328 if ((r = fido_dev_open(dev, path)) != FIDO_OK) {
329 skdebug(__func__, "fido_dev_open failed");
330 fido_dev_free(&dev);
331 continue;
332 }
333 if (try_device(dev, application, key_handle,
334 key_handle_len) == 0) {
335 skdebug(__func__, "found key");
336 break;
337 }
338 fido_dev_close(dev);
339 fido_dev_free(&dev);
340 }
341
342 out:
343 if (devlist != NULL)
344 fido_dev_info_free(&devlist, MAX_FIDO_DEVICES);
345
346 return dev;
347}
348
349#ifdef WITH_OPENSSL
350/*
351 * The key returned via fido_cred_pubkey_ptr() is in affine coordinates,
352 * but the API expects a SEC1 octet string.
353 */
354static int
355pack_public_key_ecdsa(fido_cred_t *cred, struct sk_enroll_response *response)
356{
357 const uint8_t *ptr;
358 BIGNUM *x = NULL, *y = NULL;
359 EC_POINT *q = NULL;
360 EC_GROUP *g = NULL;
361 int ret = -1;
362
363 response->public_key = NULL;
364 response->public_key_len = 0;
365
366 if ((x = BN_new()) == NULL ||
367 (y = BN_new()) == NULL ||
368 (g = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)) == NULL ||
369 (q = EC_POINT_new(g)) == NULL) {
370 skdebug(__func__, "libcrypto setup failed");
371 goto out;
372 }
373 if ((ptr = fido_cred_pubkey_ptr(cred)) == NULL) {
374 skdebug(__func__, "fido_cred_pubkey_ptr failed");
375 goto out;
376 }
377 if (fido_cred_pubkey_len(cred) != 64) {
378 skdebug(__func__, "bad fido_cred_pubkey_len %zu",
379 fido_cred_pubkey_len(cred));
380 goto out;
381 }
382
383 if (BN_bin2bn(ptr, 32, x) == NULL ||
384 BN_bin2bn(ptr + 32, 32, y) == NULL) {
385 skdebug(__func__, "BN_bin2bn failed");
386 goto out;
387 }
388 if (EC_POINT_set_affine_coordinates_GFp(g, q, x, y, NULL) != 1) {
389 skdebug(__func__, "EC_POINT_set_affine_coordinates_GFp failed");
390 goto out;
391 }
392 response->public_key_len = EC_POINT_point2oct(g, q,
393 POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
394 if (response->public_key_len == 0 || response->public_key_len > 2048) {
395 skdebug(__func__, "bad pubkey length %zu",
396 response->public_key_len);
397 goto out;
398 }
399 if ((response->public_key = malloc(response->public_key_len)) == NULL) {
400 skdebug(__func__, "malloc pubkey failed");
401 goto out;
402 }
403 if (EC_POINT_point2oct(g, q, POINT_CONVERSION_UNCOMPRESSED,
404 response->public_key, response->public_key_len, NULL) == 0) {
405 skdebug(__func__, "EC_POINT_point2oct failed");
406 goto out;
407 }
408 /* success */
409 ret = 0;
410 out:
411 if (ret != 0 && response->public_key != NULL) {
412 memset(response->public_key, 0, response->public_key_len);
413 free(response->public_key);
414 response->public_key = NULL;
415 }
416 EC_POINT_free(q);
417 EC_GROUP_free(g);
418 BN_clear_free(x);
419 BN_clear_free(y);
420 return ret;
421}
422#endif /* WITH_OPENSSL */
423
424static int
425pack_public_key_ed25519(fido_cred_t *cred, struct sk_enroll_response *response)
426{
427 const uint8_t *ptr;
428 size_t len;
429 int ret = -1;
430
431 response->public_key = NULL;
432 response->public_key_len = 0;
433
434 if ((len = fido_cred_pubkey_len(cred)) != 32) {
435 skdebug(__func__, "bad fido_cred_pubkey_len len %zu", len);
436 goto out;
437 }
438 if ((ptr = fido_cred_pubkey_ptr(cred)) == NULL) {
439 skdebug(__func__, "fido_cred_pubkey_ptr failed");
440 goto out;
441 }
442 response->public_key_len = len;
443 if ((response->public_key = malloc(response->public_key_len)) == NULL) {
444 skdebug(__func__, "malloc pubkey failed");
445 goto out;
446 }
447 memcpy(response->public_key, ptr, len);
448 ret = 0;
449 out:
450 if (ret != 0)
451 free(response->public_key);
452 return ret;
453}
454
455static int
456pack_public_key(int alg, fido_cred_t *cred, struct sk_enroll_response *response)
457{
458 switch(alg) {
459#ifdef WITH_OPENSSL
460 case SK_ECDSA:
461 return pack_public_key_ecdsa(cred, response);
462#endif /* WITH_OPENSSL */
463 case SK_ED25519:
464 return pack_public_key_ed25519(cred, response);
465 default:
466 return -1;
467 }
468}
469
470int
471sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len,
472 const char *application, uint8_t flags,
473 struct sk_enroll_response **enroll_response)
474{
475 fido_cred_t *cred = NULL;
476 fido_dev_t *dev = NULL;
477 const uint8_t *ptr;
478 uint8_t user_id[32];
479 struct sk_enroll_response *response = NULL;
480 size_t len;
481 int cose_alg;
482 int ret = -1;
483 int r;
484 char *device = NULL;
485
486 (void)flags; /* XXX; unused */
487#ifdef SK_DEBUG
488 fido_init(FIDO_DEBUG);
489#endif
490 if (enroll_response == NULL) {
491 skdebug(__func__, "enroll_response == NULL");
492 goto out;
493 }
494 *enroll_response = NULL;
495 switch(alg) {
496#ifdef WITH_OPENSSL
497 case SK_ECDSA:
498 cose_alg = COSE_ES256;
499 break;
500#endif /* WITH_OPENSSL */
501 case SK_ED25519:
502 cose_alg = COSE_EDDSA;
503 break;
504 default:
505 skdebug(__func__, "unsupported key type %d", alg);
506 goto out;
507 }
508 if ((device = pick_first_device()) == NULL) {
509 skdebug(__func__, "pick_first_device failed");
510 goto out;
511 }
512 skdebug(__func__, "using device %s", device);
513 if ((cred = fido_cred_new()) == NULL) {
514 skdebug(__func__, "fido_cred_new failed");
515 goto out;
516 }
517 memset(user_id, 0, sizeof(user_id));
518 if ((r = fido_cred_set_type(cred, cose_alg)) != FIDO_OK) {
519 skdebug(__func__, "fido_cred_set_type: %s", fido_strerr(r));
520 goto out;
521 }
522 if ((r = fido_cred_set_clientdata_hash(cred, challenge,
523 challenge_len)) != FIDO_OK) {
524 skdebug(__func__, "fido_cred_set_clientdata_hash: %s",
525 fido_strerr(r));
526 goto out;
527 }
528 if ((r = fido_cred_set_user(cred, user_id, sizeof(user_id),
529 "openssh", "openssh", NULL)) != FIDO_OK) {
530 skdebug(__func__, "fido_cred_set_user: %s", fido_strerr(r));
531 goto out;
532 }
533 if ((r = fido_cred_set_rp(cred, application, NULL)) != FIDO_OK) {
534 skdebug(__func__, "fido_cred_set_rp: %s", fido_strerr(r));
535 goto out;
536 }
537 if ((dev = fido_dev_new()) == NULL) {
538 skdebug(__func__, "fido_dev_new failed");
539 goto out;
540 }
541 if ((r = fido_dev_open(dev, device)) != FIDO_OK) {
542 skdebug(__func__, "fido_dev_open: %s", fido_strerr(r));
543 goto out;
544 }
545 if ((r = fido_dev_make_cred(dev, cred, NULL)) != FIDO_OK) {
546 skdebug(__func__, "fido_dev_make_cred: %s", fido_strerr(r));
547 goto out;
548 }
549 if (fido_cred_x5c_ptr(cred) != NULL) {
550 if ((r = fido_cred_verify(cred)) != FIDO_OK) {
551 skdebug(__func__, "fido_cred_verify: %s",
552 fido_strerr(r));
553 goto out;
554 }
555 } else {
556 skdebug(__func__, "self-attested credential");
557 if ((r = fido_cred_verify_self(cred)) != FIDO_OK) {
558 skdebug(__func__, "fido_cred_verify_self: %s",
559 fido_strerr(r));
560 goto out;
561 }
562 }
563 if ((response = calloc(1, sizeof(*response))) == NULL) {
564 skdebug(__func__, "calloc response failed");
565 goto out;
566 }
567 if (pack_public_key(alg, cred, response) != 0) {
568 skdebug(__func__, "pack_public_key failed");
569 goto out;
570 }
571 if ((ptr = fido_cred_id_ptr(cred)) != NULL) {
572 len = fido_cred_id_len(cred);
573 if ((response->key_handle = calloc(1, len)) == NULL) {
574 skdebug(__func__, "calloc key handle failed");
575 goto out;
576 }
577 memcpy(response->key_handle, ptr, len);
578 response->key_handle_len = len;
579 }
580 if ((ptr = fido_cred_sig_ptr(cred)) != NULL) {
581 len = fido_cred_sig_len(cred);
582 if ((response->signature = calloc(1, len)) == NULL) {
583 skdebug(__func__, "calloc signature failed");
584 goto out;
585 }
586 memcpy(response->signature, ptr, len);
587 response->signature_len = len;
588 }
589 if ((ptr = fido_cred_x5c_ptr(cred)) != NULL) {
590 len = fido_cred_x5c_len(cred);
591 if ((response->attestation_cert = calloc(1, len)) == NULL) {
592 skdebug(__func__, "calloc attestation cert failed");
593 goto out;
594 }
595 memcpy(response->attestation_cert, ptr, len);
596 response->attestation_cert_len = len;
597 }
598 *enroll_response = response;
599 response = NULL;
600 ret = 0;
601 out:
602 free(device);
603 if (response != NULL) {
604 free(response->public_key);
605 free(response->key_handle);
606 free(response->signature);
607 free(response->attestation_cert);
608 free(response);
609 }
610 if (dev != NULL) {
611 fido_dev_close(dev);
612 fido_dev_free(&dev);
613 }
614 if (cred != NULL) {
615 fido_cred_free(&cred);
616 }
617 return ret;
618}
619
620#ifdef WITH_OPENSSL
621static int
622pack_sig_ecdsa(fido_assert_t *assert, struct sk_sign_response *response)
623{
624 ECDSA_SIG *sig = NULL;
625 const BIGNUM *sig_r, *sig_s;
626 const unsigned char *cp;
627 size_t sig_len;
628 int ret = -1;
629
630 cp = fido_assert_sig_ptr(assert, 0);
631 sig_len = fido_assert_sig_len(assert, 0);
632 if ((sig = d2i_ECDSA_SIG(NULL, &cp, sig_len)) == NULL) {
633 skdebug(__func__, "d2i_ECDSA_SIG failed");
634 goto out;
635 }
636 ECDSA_SIG_get0(sig, &sig_r, &sig_s);
637 response->sig_r_len = BN_num_bytes(sig_r);
638 response->sig_s_len = BN_num_bytes(sig_s);
639 if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL ||
640 (response->sig_s = calloc(1, response->sig_s_len)) == NULL) {
641 skdebug(__func__, "calloc signature failed");
642 goto out;
643 }
644 BN_bn2bin(sig_r, response->sig_r);
645 BN_bn2bin(sig_s, response->sig_s);
646 ret = 0;
647 out:
648 ECDSA_SIG_free(sig);
649 if (ret != 0) {
650 free(response->sig_r);
651 free(response->sig_s);
652 response->sig_r = NULL;
653 response->sig_s = NULL;
654 }
655 return ret;
656}
657#endif /* WITH_OPENSSL */
658
659static int
660pack_sig_ed25519(fido_assert_t *assert, struct sk_sign_response *response)
661{
662 const unsigned char *ptr;
663 size_t len;
664 int ret = -1;
665
666 ptr = fido_assert_sig_ptr(assert, 0);
667 len = fido_assert_sig_len(assert, 0);
668 if (len != 64) {
669 skdebug(__func__, "bad length %zu", len);
670 goto out;
671 }
672 response->sig_r_len = len;
673 if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL) {
674 skdebug(__func__, "calloc signature failed");
675 goto out;
676 }
677 memcpy(response->sig_r, ptr, len);
678 ret = 0;
679 out:
680 if (ret != 0) {
681 free(response->sig_r);
682 response->sig_r = NULL;
683 }
684 return ret;
685}
686
687static int
688pack_sig(int alg, fido_assert_t *assert, struct sk_sign_response *response)
689{
690 switch(alg) {
691#ifdef WITH_OPENSSL
692 case SK_ECDSA:
693 return pack_sig_ecdsa(assert, response);
694#endif /* WITH_OPENSSL */
695 case SK_ED25519:
696 return pack_sig_ed25519(assert, response);
697 default:
698 return -1;
699 }
700}
701
702int
703sk_sign(int alg, const uint8_t *message, size_t message_len,
704 const char *application,
705 const uint8_t *key_handle, size_t key_handle_len,
706 uint8_t flags, struct sk_sign_response **sign_response)
707{
708 fido_assert_t *assert = NULL;
709 fido_dev_t *dev = NULL;
710 struct sk_sign_response *response = NULL;
711 int ret = -1;
712 int r;
713
714#ifdef SK_DEBUG
715 fido_init(FIDO_DEBUG);
716#endif
717
718 if (sign_response == NULL) {
719 skdebug(__func__, "sign_response == NULL");
720 goto out;
721 }
722 *sign_response = NULL;
723 if ((dev = find_device(application, key_handle,
724 key_handle_len)) == NULL) {
725 skdebug(__func__, "couldn't find device for key handle");
726 goto out;
727 }
728 if ((assert = fido_assert_new()) == NULL) {
729 skdebug(__func__, "fido_assert_new failed");
730 goto out;
731 }
732 if ((r = fido_assert_set_clientdata_hash(assert, message,
733 message_len)) != FIDO_OK) {
734 skdebug(__func__, "fido_assert_set_clientdata_hash: %s",
735 fido_strerr(r));
736 goto out;
737 }
738 if ((r = fido_assert_set_rp(assert, application)) != FIDO_OK) {
739 skdebug(__func__, "fido_assert_set_rp: %s", fido_strerr(r));
740 goto out;
741 }
742 if ((r = fido_assert_allow_cred(assert, key_handle,
743 key_handle_len)) != FIDO_OK) {
744 skdebug(__func__, "fido_assert_allow_cred: %s", fido_strerr(r));
745 goto out;
746 }
747 if ((r = fido_assert_set_up(assert,
748 (flags & SK_USER_PRESENCE_REQD) ?
749 FIDO_OPT_TRUE : FIDO_OPT_FALSE)) != FIDO_OK) {
750 skdebug(__func__, "fido_assert_set_up: %s", fido_strerr(r));
751 goto out;
752 }
753 if ((r = fido_dev_get_assert(dev, assert, NULL)) != FIDO_OK) {
754 skdebug(__func__, "fido_dev_get_assert: %s", fido_strerr(r));
755 goto out;
756 }
757 if ((response = calloc(1, sizeof(*response))) == NULL) {
758 skdebug(__func__, "calloc response failed");
759 goto out;
760 }
761 response->flags = fido_assert_flags(assert, 0);
762 response->counter = fido_assert_sigcount(assert, 0);
763 if (pack_sig(alg, assert, response) != 0) {
764 skdebug(__func__, "pack_sig failed");
765 goto out;
766 }
767 *sign_response = response;
768 response = NULL;
769 ret = 0;
770 out:
771 if (response != NULL) {
772 free(response->sig_r);
773 free(response->sig_s);
774 free(response);
775 }
776 if (dev != NULL) {
777 fido_dev_close(dev);
778 fido_dev_free(&dev);
779 }
780 if (assert != NULL) {
781 fido_assert_free(&assert);
782 }
783 return ret;
784}
diff --git a/udev/70-u2f.rules b/udev/70-u2f.rules
index 8dc20a1..3932270 100644
--- a/udev/70-u2f.rules
+++ b/udev/70-u2f.rules
@@ -35,8 +35,11 @@ KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="2abe", ATTRS{idProduct
35# Thetis Key 35# Thetis Key
36KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1ea8", ATTRS{idProduct}=="f025", TAG+="uaccess", GROUP="plugdev", MODE="0660" 36KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1ea8", ATTRS{idProduct}=="f025", TAG+="uaccess", GROUP="plugdev", MODE="0660"
37 37
38# Nitrokey FIDO U2F 38# Nitrokey FIDO U2F, Nitrokey FIDO2
39KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4287", TAG+="uaccess", GROUP="plugdev", MODE="0660" 39KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4287|42b1", TAG+="uaccess", GROUP="plugdev", MODE="0660"
40
41# Safetech SafeKey
42KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="42b3", TAG+="uaccess", GROUP="plugdev", MODE="0660"
40 43
41# Google Titan U2F 44# Google Titan U2F
42KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="5026", TAG+="uaccess", GROUP="plugdev", MODE="0660" 45KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="5026", TAG+="uaccess", GROUP="plugdev", MODE="0660"